/* * $Id: std.c 380 2011-01-31 13:46:52Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. QSE is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. QSE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with QSE. If not, see . */ #include "awk.h" #include #include #include #include #include #include #include /* TODO: remove dependency on qse_vsprintf */ #include "../cmn/mem.h" #include #include #include typedef struct xtn_t { struct { struct { qse_awk_parsestd_type_t type; union { const qse_char_t* file; const qse_char_t* cp; struct { const qse_char_t* ptr; const qse_char_t* end; } cpl; } u; qse_cstr_t dir; qse_sio_t* handle; /* the handle to an open file */ } in; struct { qse_awk_parsestd_type_t type; union { const qse_char_t* file; qse_char_t* cp; struct { qse_xstr_t* osp; qse_char_t* ptr; qse_char_t* end; } cpl; } u; qse_sio_t* handle; } out; } s; } xtn_t; typedef struct rxtn_t { unsigned int seed; struct { struct { const qse_char_t*const* files; qse_size_t index; qse_size_t count; } in; struct { const qse_char_t*const* files; qse_size_t index; qse_size_t count; } out; } c; /* console */ } rxtn_t; static qse_real_t custom_awk_pow (qse_awk_t* awk, qse_real_t x, qse_real_t y) { #if defined(HAVE_POWL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) return powl (x, y); #elif defined(HAVE_POW) return pow (x, y); #elif defined(HAVE_POWF) return powf (x, y); #else #error ### no pow function available ### #endif } static int custom_awk_sprintf ( qse_awk_t* awk, qse_char_t* buf, qse_size_t size, const qse_char_t* fmt, ...) { int n; va_list ap; va_start (ap, fmt); n = qse_vsprintf (buf, size, fmt, ap); va_end (ap); return n; } static int add_functions (qse_awk_t* awk); qse_awk_t* qse_awk_openstd (qse_size_t xtnsize) { return qse_awk_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize); } qse_awk_t* qse_awk_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) { qse_awk_t* awk; qse_awk_prm_t prm; xtn_t* xtn; prm.pow = custom_awk_pow; prm.sprintf = custom_awk_sprintf; /* create an object */ awk = qse_awk_open (mmgr, QSE_SIZEOF(xtn_t) + xtnsize, &prm); if (awk == QSE_NULL) return QSE_NULL; /* initialize extension */ xtn = (xtn_t*) QSE_XTN (awk); QSE_MEMSET (xtn, 0, QSE_SIZEOF(xtn_t)); /* add intrinsic functions */ if (add_functions (awk) == -1) { qse_awk_close (awk); return QSE_NULL; } return awk; } void* qse_awk_getxtnstd (qse_awk_t* awk) { return (void*)((xtn_t*)QSE_XTN(awk) + 1); } /*** PARSESTD ***/ static qse_ssize_t sf_in_open ( qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn) { if (arg == QSE_NULL || arg->name == QSE_NULL) { switch (xtn->s.in.type) { case QSE_AWK_PARSESTD_FILE: if (xtn->s.in.u.file == QSE_NULL) return -1; if (xtn->s.in.u.file[0] == QSE_T('-') && xtn->s.in.u.file[1] == QSE_T('\0')) { /* special file name '-' */ xtn->s.in.handle = qse_sio_in; } else { const qse_char_t* base; xtn->s.in.handle = qse_sio_open ( awk->mmgr, 0, xtn->s.in.u.file, QSE_SIO_READ ); if (xtn->s.in.handle == QSE_NULL) { qse_cstr_t ea; ea.ptr = xtn->s.in.u.file; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &ea); return -1; } base = qse_basename (xtn->s.in.u.file); if (base != xtn->s.in.u.file) { xtn->s.in.dir.ptr = xtn->s.in.u.file; xtn->s.in.dir.len = base - xtn->s.in.u.file; } } return 1; case QSE_AWK_PARSESTD_STDIO: xtn->s.in.handle = qse_sio_in; return 1; case QSE_AWK_PARSESTD_CP: case QSE_AWK_PARSESTD_CPL: xtn->s.in.handle = QSE_NULL; return 1; default: return -1; } } else { const qse_char_t* file = arg->name; qse_char_t fbuf[64]; qse_char_t* dbuf = QSE_NULL; if (xtn->s.in.dir.len > 0 && arg->name[0] != QSE_T('/')) { qse_size_t tmplen, totlen; totlen = qse_strlen(arg->name) + xtn->s.in.dir.len; if (totlen >= QSE_COUNTOF(fbuf)) { dbuf = QSE_MMGR_ALLOC ( awk->mmgr, QSE_SIZEOF(qse_char_t) * (totlen + 1) ); if (dbuf == QSE_NULL) { qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL); return -1; } file = dbuf; } else file = fbuf; tmplen = qse_strncpy ( (qse_char_t*)file, xtn->s.in.dir.ptr, xtn->s.in.dir.len ); qse_strcpy ((qse_char_t*)file + tmplen, arg->name); } arg->handle = qse_sio_open ( awk->mmgr, 0, file, QSE_SIO_READ ); if (dbuf != QSE_NULL) QSE_MMGR_FREE (awk->mmgr, dbuf); if (arg->handle == QSE_NULL) { qse_cstr_t ea; ea.ptr = arg->name; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &ea); return -1; } return 1; } } static qse_ssize_t sf_in_close ( qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn) { if (arg == QSE_NULL || arg->name == QSE_NULL) { if (xtn->s.in.handle != QSE_NULL && xtn->s.in.handle != qse_sio_in && xtn->s.in.handle != qse_sio_out && xtn->s.in.handle != qse_sio_err) { qse_sio_close (xtn->s.in.handle); } } else { qse_sio_close (arg->handle); } return 0; } static qse_ssize_t sf_in_read ( qse_awk_t* awk, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size, xtn_t* xtn) { if (arg == QSE_NULL || arg->name == QSE_NULL) { switch (xtn->s.in.type) { case QSE_AWK_PARSESTD_FILE: case QSE_AWK_PARSESTD_STDIO: { qse_ssize_t n; QSE_ASSERT (xtn->s.in.handle != QSE_NULL); n = qse_sio_getsn (xtn->s.in.handle, data, size); if (n == -1) { qse_cstr_t ea; ea.ptr = xtn->s.in.u.file; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EREAD, &ea); } return n; } case QSE_AWK_PARSESTD_CP: { qse_size_t n = 0; while (n < size && *xtn->s.in.u.cp != QSE_T('\0')) { data[n++] = *xtn->s.in.u.cp++; } return n; } case QSE_AWK_PARSESTD_CPL: { qse_size_t n = 0; while (n < size && xtn->s.in.u.cpl.ptr < xtn->s.in.u.cpl.end) { data[n++] = *xtn->s.in.u.cpl.ptr++; } return n; } default: return -1; } } else { qse_ssize_t n; QSE_ASSERT (arg->handle != QSE_NULL); n = qse_sio_getsn (arg->handle, data, size); if (n == -1) { qse_cstr_t ea; ea.ptr = arg->name; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EREAD, &ea); } return n; } } static qse_ssize_t sf_in ( qse_awk_t* awk, qse_awk_sio_cmd_t cmd, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size) { xtn_t* xtn = QSE_XTN (awk); switch (cmd) { case QSE_AWK_SIO_OPEN: return sf_in_open (awk, arg, xtn); case QSE_AWK_SIO_CLOSE: return sf_in_close (awk, arg, xtn); case QSE_AWK_SIO_READ: return sf_in_read (awk, arg, data, size, xtn); default: return -1; } } static qse_ssize_t sf_out ( qse_awk_t* awk, qse_awk_sio_cmd_t cmd, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size) { xtn_t* xtn = QSE_XTN (awk); if (cmd == QSE_AWK_SIO_OPEN) { switch (xtn->s.out.type) { case QSE_AWK_PARSESTD_FILE: if (xtn->s.out.u.file == QSE_NULL) return -1; if (xtn->s.out.u.file[0] == QSE_T('-') && xtn->s.out.u.file[1] == QSE_T('\0')) { /* special file name '-' */ xtn->s.out.handle = qse_sio_out; } else { xtn->s.out.handle = qse_sio_open ( awk->mmgr, 0, xtn->s.out.u.file, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE ); if (xtn->s.out.handle == QSE_NULL) { qse_cstr_t ea; ea.ptr = xtn->s.out.u.file; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &ea); return -1; } } return 1; case QSE_AWK_PARSESTD_STDIO: xtn->s.out.handle = qse_sio_out; return 1; case QSE_AWK_PARSESTD_CP: case QSE_AWK_PARSESTD_CPL: xtn->s.out.handle = QSE_NULL; return 1; } } else if (cmd == QSE_AWK_SIO_CLOSE) { switch (xtn->s.out.type) { case QSE_AWK_PARSESTD_FILE: case QSE_AWK_PARSESTD_STDIO: qse_sio_flush (xtn->s.out.handle); if (xtn->s.out.handle != qse_sio_in && xtn->s.out.handle != qse_sio_out && xtn->s.out.handle != qse_sio_err) { qse_sio_close (xtn->s.out.handle); } return 0; case QSE_AWK_PARSESTD_CP: *xtn->s.out.u.cp = QSE_T('\0'); return 0; case QSE_AWK_PARSESTD_CPL: xtn->s.out.u.cpl.osp->len = xtn->s.out.u.cpl.ptr - xtn->s.out.u.cpl.osp->ptr; return 0; } } else if (cmd == QSE_AWK_SIO_WRITE) { switch (xtn->s.out.type) { case QSE_AWK_PARSESTD_FILE: case QSE_AWK_PARSESTD_STDIO: { qse_ssize_t n; QSE_ASSERT (xtn->s.out.handle != QSE_NULL); n = qse_sio_putsn (xtn->s.out.handle, data, size); if (n == -1) { qse_cstr_t ea; ea.ptr = xtn->s.in.u.file; ea.len = qse_strlen(ea.ptr); qse_awk_seterrnum (awk, QSE_AWK_EWRITE, &ea); } return n; } case QSE_AWK_PARSESTD_CP: { qse_size_t n = 0; while (n < size && *xtn->s.out.u.cp != QSE_T('\0')) { *xtn->s.out.u.cp++ = data[n++]; } return n; } case QSE_AWK_PARSESTD_CPL: { qse_size_t n = 0; while (n < size && xtn->s.out.u.cpl.ptr < xtn->s.out.u.cpl.end) { *xtn->s.out.u.cpl.ptr++ = data[n++]; } return n; } } } return -1; } int qse_awk_parsestd ( qse_awk_t* awk, const qse_awk_parsestd_in_t* in, qse_awk_parsestd_out_t* out) { qse_awk_sio_t sio; xtn_t* xtn = (xtn_t*) QSE_XTN (awk); if (in == QSE_NULL) { /* the input is a must */ qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL); return -1; } switch (in->type) { case QSE_AWK_PARSESTD_FILE: xtn->s.in.u.file = in->u.file; break; case QSE_AWK_PARSESTD_CP: xtn->s.in.u.cp = in->u.cp; break; case QSE_AWK_PARSESTD_CPL: xtn->s.in.u.cpl.ptr = in->u.cpl.ptr; xtn->s.in.u.cpl.end = in->u.cpl.ptr + in->u.cpl.len; break; case QSE_AWK_PARSESTD_STDIO: /* nothing to do */ break; default: qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL); return -1; } xtn->s.in.type = in->type; xtn->s.in.handle = QSE_NULL; sio.in = sf_in; if (out == QSE_NULL) sio.out = QSE_NULL; else { switch (out->type) { case QSE_AWK_PARSESTD_FILE: xtn->s.out.u.file = out->u.file; break; case QSE_AWK_PARSESTD_CP: xtn->s.out.u.cp = out->u.cp; break; case QSE_AWK_PARSESTD_CPL: xtn->s.out.u.cpl.osp = &out->u.cpl; xtn->s.out.u.cpl.ptr = out->u.cpl.ptr; xtn->s.out.u.cpl.end = out->u.cpl.ptr + out->u.cpl.len; break; case QSE_AWK_PARSESTD_STDIO: /* nothing to do */ break; default: qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL); return -1; } xtn->s.out.type = out->type; xtn->s.out.handle = QSE_NULL; sio.out = sf_out; } return qse_awk_parse (awk, &sio); } /*** RTX_OPENSTD ***/ static qse_ssize_t awk_rio_pipe ( qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, qse_char_t* data, qse_size_t size) { switch (cmd) { case QSE_AWK_RIO_OPEN: { qse_pio_t* handle; int flags; if (riod->mode == QSE_AWK_RIO_PIPE_READ) { /* TODO: should we specify ERRTOOUT? */ flags = QSE_PIO_READOUT | QSE_PIO_ERRTOOUT; } else if (riod->mode == QSE_AWK_RIO_PIPE_WRITE) { flags = QSE_PIO_WRITEIN; } else if (riod->mode == QSE_AWK_RIO_PIPE_RW) { flags = QSE_PIO_READOUT | QSE_PIO_ERRTOOUT | QSE_PIO_WRITEIN; } else return -1; /* TODO: any way to set the error number? */ handle = qse_pio_open ( rtx->awk->mmgr, 0, riod->name, flags|QSE_PIO_SHELL|QSE_PIO_TEXT ); if (handle == QSE_NULL) return -1; riod->handle = (void*)handle; return 1; } case QSE_AWK_RIO_CLOSE: { qse_pio_t* pio = (qse_pio_t*)riod->handle; if (riod->mode == QSE_AWK_RIO_PIPE_RW) { /* specialy treatment is needef for rwpipe. * inspect rwcmode to see if partial closing is * requested. */ if (riod->rwcmode == QSE_AWK_RIO_CLOSE_READ) { qse_pio_end (pio, QSE_PIO_IN); return 0; } if (riod->rwcmode == QSE_AWK_RIO_CLOSE_WRITE) { qse_pio_end (pio, QSE_PIO_OUT); return 0; } } qse_pio_close (pio); riod->handle = QSE_NULL; return 0; } case QSE_AWK_RIO_READ: { return qse_pio_read ( (qse_pio_t*)riod->handle, data, size, QSE_PIO_OUT ); } case QSE_AWK_RIO_WRITE: { return qse_pio_write ( (qse_pio_t*)riod->handle, data, size, QSE_PIO_IN ); } case QSE_AWK_RIO_FLUSH: { /*if (riod->mode == QSE_AWK_RIO_PIPE_READ) return -1;*/ return qse_pio_flush ((qse_pio_t*)riod->handle, QSE_PIO_IN); } case QSE_AWK_RIO_NEXT: { return -1; } } return -1; } static qse_ssize_t awk_rio_file ( qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, qse_char_t* data, qse_size_t size) { switch (cmd) { case QSE_AWK_RIO_OPEN: { qse_fio_t* handle; int flags; if (riod->mode == QSE_AWK_RIO_FILE_READ) { flags = QSE_FIO_READ; } else if (riod->mode == QSE_AWK_RIO_FILE_WRITE) { flags = QSE_FIO_WRITE | QSE_FIO_CREATE | QSE_FIO_TRUNCATE; } else if (riod->mode == QSE_AWK_RIO_FILE_APPEND) { flags = QSE_FIO_APPEND | QSE_FIO_CREATE; } else return -1; /* TODO: any way to set the error number? */ handle = qse_fio_open ( rtx->awk->mmgr, 0, riod->name, flags | QSE_FIO_TEXT, QSE_FIO_RUSR | QSE_FIO_WUSR | QSE_FIO_RGRP | QSE_FIO_ROTH ); if (handle == QSE_NULL) { qse_cstr_t errarg; errarg.ptr = riod->name; errarg.len = qse_strlen(riod->name); qse_awk_rtx_seterrnum (rtx, QSE_AWK_EOPEN, &errarg); return -1; } riod->handle = (void*)handle; return 1; } case QSE_AWK_RIO_CLOSE: { qse_fio_close ((qse_fio_t*)riod->handle); riod->handle = QSE_NULL; return 0; } case QSE_AWK_RIO_READ: { return qse_fio_read ( (qse_fio_t*)riod->handle, data, size ); } case QSE_AWK_RIO_WRITE: { return qse_fio_write ( (qse_fio_t*)riod->handle, data, size ); } case QSE_AWK_RIO_FLUSH: { return qse_fio_flush ((qse_fio_t*)riod->handle); } case QSE_AWK_RIO_NEXT: { return -1; } } return -1; } static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod) { rxtn_t* rxtn = (rxtn_t*) QSE_XTN (rtx); if (riod->mode == QSE_AWK_RIO_CONSOLE_READ) { if (rxtn->c.in.files == QSE_NULL) { /* if no input files is specified, * open the standard input */ QSE_ASSERT (rxtn->c.in.index == 0); if (rxtn->c.in.count == 0) { riod->handle = qse_sio_in; rxtn->c.in.count++; return 1; } return 0; } else { /* a temporary variable sio is used here not to change * any fields of riod when the open operation fails */ qse_sio_t* sio; const qse_char_t* file; qse_awk_val_t* argv; qse_htb_t* map; qse_htb_pair_t* pair; qse_char_t ibuf[128]; qse_size_t ibuflen; qse_awk_val_t* v; qse_awk_rtx_valtostr_out_t out; nextfile: file = rxtn->c.in.files[rxtn->c.in.index]; if (file == QSE_NULL) { /* no more input file */ if (rxtn->c.in.count == 0) { /* all ARGVs are empty strings. * so no console files were opened. * open the standard input here. * * 'BEGIN { ARGV[1]=""; ARGV[2]=""; } * { print $0; }' file1 file2 */ riod->handle = qse_sio_in; rxtn->c.in.count++; return 1; } return 0; } /* handle special case when ARGV[x] has been altered. * so from here down, the file name gotten from * rxtn->c.in.files is not important and is overridden * from ARGV. * 'BEGIN { ARGV[1]="file3"; } * { print $0; }' file1 file2 */ argv = qse_awk_rtx_getgbl (rtx, QSE_AWK_GBL_ARGV); QSE_ASSERT (argv != QSE_NULL); QSE_ASSERT (argv->type == QSE_AWK_VAL_MAP); map = ((qse_awk_val_map_t*)argv)->map; QSE_ASSERT (map != QSE_NULL); ibuflen = qse_awk_longtostr ( rtx->awk, rxtn->c.in.index + 1, 10, QSE_NULL, ibuf, QSE_COUNTOF(ibuf)); pair = qse_htb_search (map, ibuf, ibuflen); QSE_ASSERT (pair != QSE_NULL); v = QSE_HTB_VPTR(pair); QSE_ASSERT (v != QSE_NULL); out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP; if (qse_awk_rtx_valtostr (rtx, v, &out) == QSE_NULL) return -1; if (out.u.cpldup.len == 0) { /* the name is empty */ qse_awk_rtx_free (rtx, out.u.cpldup.ptr); rxtn->c.in.index++; goto nextfile; } if (qse_strlen(out.u.cpldup.ptr) < out.u.cpldup.len) { /* the name contains one or more '\0' */ qse_cstr_t errarg; errarg.ptr = out.u.cpldup.ptr; /* use this length not to contains '\0' * in an error message */ errarg.len = qse_strlen(out.u.cpldup.ptr); qse_awk_rtx_seterrnum ( rtx, QSE_AWK_EIONMNL, &errarg); qse_awk_rtx_free (rtx, out.u.cpldup.ptr); return -1; } file = out.u.cpldup.ptr; if (file[0] == QSE_T('-') && file[1] == QSE_T('\0')) { /* special file name '-' */ sio = qse_sio_in; } else { sio = qse_sio_open ( rtx->awk->mmgr, 0, file, QSE_SIO_READ); if (sio == QSE_NULL) { qse_cstr_t errarg; errarg.ptr = file; errarg.len = qse_strlen(file); qse_awk_rtx_seterrnum ( rtx, QSE_AWK_EOPEN, &errarg); qse_awk_rtx_free (rtx, out.u.cpldup.ptr); return -1; } } if (qse_awk_rtx_setfilename ( rtx, file, qse_strlen(file)) == -1) { if (sio != qse_sio_in) qse_sio_close (sio); qse_awk_rtx_free (rtx, out.u.cpldup.ptr); return -1; } qse_awk_rtx_free (rtx, out.u.cpldup.ptr); riod->handle = sio; /* increment the counter of files successfully opened */ rxtn->c.in.count++; rxtn->c.in.index++; return 1; } } else if (riod->mode == QSE_AWK_RIO_CONSOLE_WRITE) { if (rxtn->c.out.files == QSE_NULL) { QSE_ASSERT (rxtn->c.out.index == 0); if (rxtn->c.out.count == 0) { riod->handle = qse_sio_out; rxtn->c.out.count++; return 1; } return 0; } else { /* a temporary variable sio is used here not to change * any fields of riod when the open operation fails */ qse_sio_t* sio; const qse_char_t* file; file = rxtn->c.out.files[rxtn->c.out.index]; if (file == QSE_NULL) { /* no more input file */ return 0; } if (file[0] == QSE_T('-') && file[1] == QSE_T('\0')) { /* special file name '-' */ sio = qse_sio_out; } else { sio = qse_sio_open ( rtx->awk->mmgr, 0, file, QSE_SIO_READ); if (sio == QSE_NULL) { qse_cstr_t errarg; errarg.ptr = file; errarg.len = qse_strlen(file); qse_awk_rtx_seterrnum ( rtx, QSE_AWK_EOPEN, &errarg); return -1; } } if (qse_awk_rtx_setofilename ( rtx, file, qse_strlen(file)) == -1) { qse_sio_close (sio); return -1; } riod->handle = sio; rxtn->c.out.index++; rxtn->c.out.count++; return 1; } } return -1; } static qse_ssize_t awk_rio_console ( qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, qse_char_t* data, qse_size_t size) { if (cmd == QSE_AWK_RIO_OPEN) { return open_rio_console (rtx, riod); } else if (cmd == QSE_AWK_RIO_CLOSE) { if (riod->handle != QSE_NULL && riod->handle != qse_sio_in && riod->handle != qse_sio_out && riod->handle != qse_sio_err) { qse_sio_close ((qse_sio_t*)riod->handle); } return 0; } else if (cmd == QSE_AWK_RIO_READ) { qse_ssize_t nn; while ((nn = qse_sio_getsn((qse_sio_t*)riod->handle,data,size)) == 0) { int n; qse_sio_t* sio = (qse_sio_t*)riod->handle; n = open_rio_console (rtx, riod); if (n == -1) return -1; if (n == 0) { /* no more input console */ return 0; } if (sio != QSE_NULL && sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) { qse_sio_close (sio); } } return nn; } else if (cmd == QSE_AWK_RIO_WRITE) { return qse_sio_putsn ( (qse_sio_t*)riod->handle, data, size ); } else if (cmd == QSE_AWK_RIO_FLUSH) { return qse_sio_flush ((qse_sio_t*)riod->handle); } else if (cmd == QSE_AWK_RIO_NEXT) { int n; qse_sio_t* sio = (qse_sio_t*)riod->handle; n = open_rio_console (rtx, riod); if (n == -1) return -1; if (n == 0) { /* if there is no more file, keep the previous handle */ return 0; } if (sio != QSE_NULL && sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) { qse_sio_close (sio); } return n; } return -1; } qse_awk_rtx_t* qse_awk_rtx_openstd ( qse_awk_t* awk, qse_size_t xtnsize, const qse_char_t* id, const qse_char_t*const icf[], const qse_char_t*const ocf[]) { qse_awk_rtx_t* rtx; qse_awk_rio_t rio; rxtn_t* rxtn; qse_ntime_t now; const qse_char_t*const* p; qse_size_t argc = 0; qse_cstr_t argv[16]; qse_cstr_t* argvp = QSE_NULL, * p2; rio.pipe = awk_rio_pipe; rio.file = awk_rio_file; rio.console = awk_rio_console; if (icf != QSE_NULL) { for (p = icf; *p != QSE_NULL; p++); argc = p - icf; } argc++; /* for id */ if (argc < QSE_COUNTOF(argv)) argvp = argv; else { argvp = QSE_AWK_ALLOC ( awk, QSE_SIZEOF(*argvp) * (argc + 1)); if (argvp == QSE_NULL) { qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL); return QSE_NULL; } } p2 = argvp; p2->ptr = id; p2->len = qse_strlen(id); p2++; if (icf != QSE_NULL) { for (p = icf; *p != QSE_NULL; p++, p2++) { p2->ptr = *p; p2->len = qse_strlen(*p); } } p2->ptr = QSE_NULL; p2->len = 0; rtx = qse_awk_rtx_open ( awk, QSE_SIZEOF(rxtn_t) + xtnsize, &rio, argvp ); if (argvp != QSE_NULL && argvp != argv) QSE_AWK_FREE (awk, argvp); if (rtx == QSE_NULL) return QSE_NULL; rxtn = (rxtn_t*) QSE_XTN (rtx); QSE_MEMSET (rxtn, 0, QSE_SIZEOF(rxtn_t)); if (qse_gettime (&now) == -1) rxtn->seed = 0; else rxtn->seed = (unsigned int) now; srand (rxtn->seed); rxtn->c.in.files = icf; rxtn->c.in.index = 0; rxtn->c.in.count = 0; rxtn->c.out.files = ocf; rxtn->c.out.index = 0; rxtn->c.out.count = 0; return rtx; } void* qse_awk_rtx_getxtnstd (qse_awk_rtx_t* rtx) { return (void*)((rxtn_t*)QSE_XTN(rtx) + 1); } /*** EXTRA BUILTIN FUNCTIONS ***/ enum { FNC_MATH_LD, FNC_MATH_D, FNC_MATH_F }; static int fnc_math_1 ( qse_awk_rtx_t* run, const qse_cstr_t* fnm, int type, void* f) { qse_size_t nargs; qse_awk_val_t* a0; qse_long_t lv; qse_real_t rv; qse_awk_val_t* r; int n; nargs = qse_awk_rtx_getnargs (run); QSE_ASSERT (nargs == 1); a0 = qse_awk_rtx_getarg (run, 0); n = qse_awk_rtx_valtonum (run, a0, &lv, &rv); if (n == -1) return -1; if (n == 0) rv = (qse_real_t)lv; if (type == FNC_MATH_LD) { long double (*rf) (long double) = (long double(*)(long double))f; r = qse_awk_rtx_makerealval (run, rf(rv)); } else if (type == FNC_MATH_D) { double (*rf) (double) = (double(*)(double))f; r = qse_awk_rtx_makerealval (run, rf(rv)); } else { float (*rf) (float); QSE_ASSERT (type == FNC_MATH_F); rf = (float(*)(float))f; r = qse_awk_rtx_makerealval (run, rf(rv)); } if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (run, r); return 0; } static int fnc_math_2 ( qse_awk_rtx_t* run, const qse_cstr_t* fnm, int type, void* f) { qse_size_t nargs; qse_awk_val_t* a0, * a1; qse_long_t lv0, lv1; qse_real_t rv0, rv1; qse_awk_val_t* r; int n; nargs = qse_awk_rtx_getnargs (run); QSE_ASSERT (nargs == 2); a0 = qse_awk_rtx_getarg (run, 0); a1 = qse_awk_rtx_getarg (run, 1); n = qse_awk_rtx_valtonum (run, a0, &lv0, &rv0); if (n == -1) return -1; if (n == 0) rv0 = (qse_real_t)lv0; n = qse_awk_rtx_valtonum (run, a1, &lv1, &rv1); if (n == -1) return -1; if (n == 0) rv1 = (qse_real_t)lv1; if (type == FNC_MATH_LD) { long double (*rf) (long double,long double) = (long double(*)(long double,long double))f; r = qse_awk_rtx_makerealval (run, rf(rv0,rv1)); } else if (type == FNC_MATH_D) { double (*rf) (double,double) = (double(*)(double,double))f; r = qse_awk_rtx_makerealval (run, rf(rv0,rv1)); } else { float (*rf) (float,float); QSE_ASSERT (type == FNC_MATH_F); rf = (float(*)(float,float))f; r = qse_awk_rtx_makerealval (run, rf(rv0,rv1)); } if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (run, r); return 0; } static int fnc_sin (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_SINL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)sinl #elif defined(HAVE_SIN) FNC_MATH_D, (void*)sin #elif defined(HAVE_SINF) FNC_MATH_F, (void*)sinf #else #error ### no sin function available ### #endif ); } static int fnc_cos (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_COSL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)cosl #elif defined(HAVE_COS) FNC_MATH_D, (void*)cos #elif defined(HAVE_COSF) FNC_MATH_F, (void*)cosf #else #error ### no cos function available ### #endif ); } static int fnc_tan (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_TANL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)tanl #elif defined(HAVE_TAN) FNC_MATH_D, (void*)tan #elif defined(HAVE_TANF) FNC_MATH_F, (void*)tanf #else #error ### no tan function available ### #endif ); } static int fnc_atan (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_ATANL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)atanl #elif defined(HAVE_ATAN) FNC_MATH_D, (void*)atan #elif defined(HAVE_ATANF) FNC_MATH_F, (void*)atanf #else #error ### no atan function available ### #endif ); } static int fnc_atan2 (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_2 ( run, fnm, #if defined(HAVE_ATAN2L) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)atan2l #elif defined(HAVE_ATAN2) FNC_MATH_D, (void*)atan2 #elif defined(HAVE_ATAN2F) FNC_MATH_F, (void*)atan2f #else #error ### no atan2 function available ### #endif ); } static int fnc_log (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_LOGL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)logl #elif defined(HAVE_LOG) FNC_MATH_D, (void*)log #elif defined(HAVE_LOGF) FNC_MATH_F, (void*)logf #else #error ### no log function available ### #endif ); } static int fnc_exp (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_EXPL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)expl #elif defined(HAVE_EXP) FNC_MATH_D, (void*)exp #elif defined(HAVE_EXPF) FNC_MATH_F, (void*)expf #else #error ### no exp function available ### #endif ); } static int fnc_sqrt (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { return fnc_math_1 ( run, fnm, #if defined(HAVE_SQRTL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) FNC_MATH_LD, (void*)sqrtl #elif defined(HAVE_SQRT) FNC_MATH_D, (void*)sqrt #elif defined(HAVE_SQRTF) FNC_MATH_F, (void*)sqrtf #else #error ### no sqrt function available ### #endif ); } static int fnc_int (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { qse_size_t nargs; qse_awk_val_t* a0; qse_long_t lv; qse_real_t rv; qse_awk_val_t* r; int n; nargs = qse_awk_rtx_getnargs (run); QSE_ASSERT (nargs == 1); a0 = qse_awk_rtx_getarg (run, 0); n = qse_awk_rtx_valtonum (run, a0, &lv, &rv); if (n == -1) return -1; if (n == 1) lv = (qse_long_t)rv; r = qse_awk_rtx_makeintval (run, lv); if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (run, r); return 0; } static int fnc_rand (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { qse_awk_val_t* r; /* rxtn_t* rxtn; rxtn = (rxtn_t*) QSE_XTN (run); r = qse_awk_rtx_makerealval ( run, (qse_real_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX ); */ r = qse_awk_rtx_makerealval ( run, (qse_real_t)(rand() % RAND_MAX) / RAND_MAX); if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (run, r); return 0; } static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { qse_size_t nargs; qse_awk_val_t* a0; qse_long_t lv; qse_real_t rv; qse_awk_val_t* r; int n; unsigned int prev; rxtn_t* rxtn; rxtn = (rxtn_t*) QSE_XTN (run); nargs = qse_awk_rtx_getnargs (run); QSE_ASSERT (nargs == 0 || nargs == 1); prev = rxtn->seed; if (nargs == 1) { a0 = qse_awk_rtx_getarg (run, 0); n = qse_awk_rtx_valtonum (run, a0, &lv, &rv); if (n <= -1) return -1; if (n >= 1) lv = (qse_long_t)rv; rxtn->seed = lv; } else { qse_ntime_t now; if (qse_gettime(&now) <= -1) rxtn->seed >>= 1; else rxtn->seed = (unsigned int)now; } srand (rxtn->seed); r = qse_awk_rtx_makeintval (run, prev); if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (run, r); return 0; } static int fnc_system (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { qse_size_t nargs; qse_awk_val_t* v; qse_char_t* str, * ptr, * end; qse_size_t len; int n = 0; nargs = qse_awk_rtx_getnargs (run); QSE_ASSERT (nargs == 1); v = qse_awk_rtx_getarg (run, 0); if (v->type == QSE_AWK_VAL_STR) { str = ((qse_awk_val_str_t*)v)->ptr; len = ((qse_awk_val_str_t*)v)->len; } else { str = qse_awk_rtx_valtocpldup (run, v, &len); if (str == QSE_NULL) return -1; } /* the target name contains a null character. * make system return -1 */ ptr = str; end = str + len; while (ptr < end) { if (*ptr == QSE_T('\0')) { n = -1; goto skip_system; } ptr++; } #if defined(_WIN32) n = _tsystem (str); #elif defined(QSE_CHAR_IS_MCHAR) n = system (str); #else { char* mbs; qse_size_t mbl; mbs = (char*) qse_awk_alloc (run->awk, len*5+1); if (mbs == QSE_NULL) { n = -1; goto skip_system; } /* at this point, the string is guaranteed to be * null-terminating. so qse_wcstombs() can be used to convert * the string, not qse_wcsntombsn(). */ mbl = len * 5; if (qse_wcstombs (str, mbs, &mbl) != len && mbl >= len * 5) { /* not the entire string is converted. * mbs is not null-terminated properly. */ n = -1; goto skip_system_mbs; } mbs[mbl] = '\0'; n = system (mbs); skip_system_mbs: qse_awk_free (run->awk, mbs); } #endif skip_system: if (v->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str); v = qse_awk_rtx_makeintval (run, (qse_long_t)n); if (v == QSE_NULL) return -1; qse_awk_rtx_setretval (run, v); return 0; } #define ADDFNC(awk,name,min,max,fnc) \ if (qse_awk_addfnc (\ (awk), (name), qse_strlen(name), \ 0, (min), (max), QSE_NULL, (fnc)) == QSE_NULL) return -1; static int add_functions (qse_awk_t* awk) { ADDFNC (awk, QSE_T("sin"), 1, 1, fnc_sin); ADDFNC (awk, QSE_T("cos"), 1, 1, fnc_cos); ADDFNC (awk, QSE_T("tan"), 1, 1, fnc_tan); ADDFNC (awk, QSE_T("atan"), 1, 1, fnc_atan); ADDFNC (awk, QSE_T("atan2"), 2, 2, fnc_atan2); ADDFNC (awk, QSE_T("log"), 1, 1, fnc_log); ADDFNC (awk, QSE_T("exp"), 1, 1, fnc_exp); ADDFNC (awk, QSE_T("sqrt"), 1, 1, fnc_sqrt); ADDFNC (awk, QSE_T("int"), 1, 1, fnc_int); ADDFNC (awk, QSE_T("rand"), 0, 0, fnc_rand); ADDFNC (awk, QSE_T("srand"), 0, 1, fnc_srand); ADDFNC (awk, QSE_T("system"), 1, 1, fnc_system); return 0; }