diff --git a/qse/Makefile.am b/qse/Makefile.am index 1ea00580..ac97f8dd 100644 --- a/qse/Makefile.am +++ b/qse/Makefile.am @@ -1,7 +1,10 @@ AUTOMAKE_OPTION = foreign ACLOCAL_AMFLAGS = -I m4 -EXTRA_DIST = LICENSE +EXTRA_DIST = LICENSE \ + bld/qse.bkl bld/readme.txt bld/os2.bkgen bld/win32.bkgen \ + bld/os2-watcom/makefile bld/win32-watcom/makefile \ + bld/win32-msvc/makefile bld/win32-borland/makefile SUBDIRS = libltdl include lib cmd mod DIST_SUBDIRS = $(SUBDIRS) regress samples doc tools diff --git a/qse/Makefile.in b/qse/Makefile.in index cedd306d..1ad22da5 100644 --- a/qse/Makefile.in +++ b/qse/Makefile.in @@ -282,7 +282,11 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTION = foreign ACLOCAL_AMFLAGS = -I m4 -EXTRA_DIST = LICENSE +EXTRA_DIST = LICENSE \ + bld/qse.bkl bld/readme.txt bld/os2.bkgen bld/win32.bkgen \ + bld/os2-watcom/makefile bld/win32-watcom/makefile \ + bld/win32-msvc/makefile bld/win32-borland/makefile + SUBDIRS = libltdl include lib cmd mod DIST_SUBDIRS = $(SUBDIRS) regress samples doc tools all: all-recursive diff --git a/qse/cmd/awk/awk.c b/qse/cmd/awk/awk.c index c0063fd5..287f50cc 100644 --- a/qse/cmd/awk/awk.c +++ b/qse/cmd/awk/awk.c @@ -355,7 +355,7 @@ static void on_statement (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde) static void print_version (void) { - qse_printf (QSE_T("QSEAWK version %hs\n"), QSE_PACKAGE_VERSION); + qse_fprintf (QSE_STDOUT, QSE_T("QSEAWK version %hs\n"), QSE_PACKAGE_VERSION); } static void print_error (const qse_char_t* fmt, ...) diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index d23b4485..01fc09ad 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -2005,7 +2005,8 @@ QSE_EXPORT qse_size_t qse_awk_rtx_getnargs ( ); /** - * The qse_awk_rtx_getarg() function gets an argument passed to qse_awk_run(). + * The qse_awk_rtx_getarg() function gets an argument passed to an intrinsic + * function. it doesn't touch the reference count of the value. */ QSE_EXPORT qse_awk_val_t* qse_awk_rtx_getarg ( qse_awk_rtx_t* rtx, @@ -2642,7 +2643,7 @@ QSE_EXPORT int qse_awk_rtx_strtonum ( ); /** - * The qse_awk_rtx_hashval() functions hashes a simple value + * The qse_awk_rtx_hashval() function hashes a simple value * to a positive integer. It returns -1 for a inhashable value. */ QSE_EXPORT qse_long_t qse_awk_rtx_hashval ( @@ -2650,6 +2651,16 @@ QSE_EXPORT qse_long_t qse_awk_rtx_hashval ( qse_awk_val_t* v ); +/** + * The qse_awk_rtx_setrefval() function changes the value + * of a variable referenced in @a ref. + * @return 0 on success, -1 on failure. + */ +QSE_EXPORT int qse_awk_rtx_setrefval ( + qse_awk_rtx_t* rtx, + qse_awk_val_ref_t* ref, + qse_awk_val_t* val +); QSE_EXPORT void qse_awk_rtx_setnrflt ( qse_awk_rtx_t* rtx, diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index 537a857b..89dc088f 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -5887,7 +5887,7 @@ static qse_size_t push_arg_from_nde ( (fnc_arg_spec != QSE_NULL && qse_strlen(fnc_arg_spec) > nargs)); - if (fnc_arg_spec != QSE_NULL && + if (fnc_arg_spec && (fnc_arg_spec[nargs] == QSE_T('r') || fnc_arg_spec[0] == QSE_T('R'))) { @@ -5904,7 +5904,7 @@ static qse_size_t push_arg_from_nde ( v = qse_awk_rtx_makerefval ( rtx, p->type-QSE_AWK_NDE_NAMED, ref); } - else if (fnc_arg_spec != QSE_NULL && + else if (fnc_arg_spec && fnc_arg_spec[nargs] == QSE_T('x')) { /* a regular expression is passed to diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 8da475d6..bf4ab924 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -2208,15 +2208,11 @@ static int fnc_srand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) static int fnc_system (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { - qse_size_t nargs; qse_awk_val_t* v; qse_char_t* str; qse_size_t len; int n = 0; - nargs = qse_awk_rtx_getnargs (rtx); - QSE_ASSERT (nargs == 1); - v = qse_awk_rtx_getarg (rtx, 0); if (v->type == QSE_AWK_VAL_STR) { @@ -2324,7 +2320,6 @@ static ioattr_t* find_or_make_ioattr ( static int fnc_setioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { rxtn_t* rxtn; - qse_size_t nargs; qse_awk_val_t* v[3]; qse_char_t* ptr[3]; qse_size_t len[3]; @@ -2334,9 +2329,6 @@ static int fnc_setioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) rxtn = (rxtn_t*) QSE_XTN (rtx); QSE_ASSERT (rxtn->cmgrtab_inited == 1); - nargs = qse_awk_rtx_getnargs (rtx); - QSE_ASSERT (nargs == 3); - for (i = 0; i < 3; i++) { v[i] = qse_awk_rtx_getarg (rtx, i); @@ -2454,7 +2446,6 @@ done: static int fnc_getioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { rxtn_t* rxtn; - qse_size_t nargs; qse_awk_val_t* v[2]; qse_char_t* ptr[2]; qse_size_t len[2]; @@ -2468,9 +2459,6 @@ static int fnc_getioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) rxtn = (rxtn_t*) QSE_XTN (rtx); QSE_ASSERT (rxtn->cmgrtab_inited == 1); - nargs = qse_awk_rtx_getnargs (rtx); - QSE_ASSERT (nargs == 2); - for (i = 0; i < 2; i++) { v[i] = qse_awk_rtx_getarg (rtx, i); @@ -2492,7 +2480,7 @@ static int fnc_getioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) if (qse_strxchr (ptr[i], len[i], QSE_T('\0'))) goto done; } - ioattr = get_ioattr (&rxtn->cmgrtab, ptr[0], len[0]); + ioattr = get_ioattr (&rxtn->cmgrtab, ptr[0], len[0]); if (ioattr == QSE_NULL) { init_ioattr (&ioattr_buf); @@ -2538,11 +2526,15 @@ done: if (ret >= 0) { - /* the return value of -1 for an error may be confusing since - * a literal value of -1 can be returned for some attribute - * names */ - if (rv == QSE_NULL) rv = qse_awk_val_negone; - qse_awk_rtx_setretval (rtx, rv); + if (rv) + { + qse_awk_rtx_setrefval (rtx, qse_awk_rtx_getarg (rtx, 2), rv); + qse_awk_rtx_setretval (rtx, qse_awk_val_zero); + } + else + { + qse_awk_rtx_setretval (rtx, qse_awk_val_negone); + } } return ret; @@ -2586,11 +2578,11 @@ struct fnctab_t static struct fnctab_t fnctab[] = { - { QSE_T("rand"), { {0, 0, QSE_NULL}, fnc_rand, 0 } }, - { QSE_T("srand"), { {0, 1, QSE_NULL}, fnc_srand, 0 } }, - { QSE_T("system"), { {1, 1, QSE_NULL}, fnc_system , 0 } }, - { QSE_T("setioattr"), { {3, 3, QSE_NULL}, fnc_setioattr, QSE_AWK_RIO } }, - { QSE_T("getioattr"), { {2, 2, QSE_NULL}, fnc_getioattr, QSE_AWK_RIO } } + { QSE_T("rand"), { {0, 0, QSE_NULL}, fnc_rand, 0 } }, + { QSE_T("srand"), { {0, 1, QSE_NULL}, fnc_srand, 0 } }, + { QSE_T("system"), { {1, 1, QSE_NULL}, fnc_system , 0 } }, + { QSE_T("setioattr"), { {3, 3, QSE_NULL}, fnc_setioattr, QSE_AWK_RIO } }, + { QSE_T("getioattr"), { {3, 3, QSE_T("vvr")}, fnc_getioattr, QSE_AWK_RIO } } }; static int add_functions (qse_awk_t* awk) diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index 6c04310d..4a27e554 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -910,7 +910,45 @@ void qse_awk_rtx_freevalchunk (qse_awk_rtx_t* rtx, qse_awk_val_chunk_t* chunk) } } -int qse_awk_rtx_valtobool (qse_awk_rtx_t* run, const qse_awk_val_t* val) +static int val_ref_to_bool ( + qse_awk_rtx_t* rtx, const qse_awk_val_ref_t* ref) +{ + if (ref->id == QSE_AWK_VAL_REF_POS) + { + qse_size_t idx; + + idx = (qse_size_t)ref->adr; + if (idx == 0) + { + return QSE_STR_LEN(&rtx->inrec.line) > 0; + } + else if (idx <= rtx->inrec.nflds) + { + return rtx->inrec.flds[idx-1].len > 0; + } + else + { + /* the index is greater than the number of records. + * it's an empty string. so false */ + return 0; + } + } + else + { + qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr; + + /* A reference value is not able to point to another + * refernce value for the way values are represented + * in QSEAWK */ + QSE_ASSERT ((*xref)->type != QSE_AWK_VAL_REF); + + /* make a recursive call back to the caller */ + return qse_awk_rtx_valtobool (rtx, *xref); + } +} + + +int qse_awk_rtx_valtobool (qse_awk_rtx_t* rtx, const qse_awk_val_t* val) { if (val == QSE_NULL) return 0; @@ -929,7 +967,8 @@ int qse_awk_rtx_valtobool (qse_awk_rtx_t* run, const qse_awk_val_t* val) case QSE_AWK_VAL_MAP: return 0; /* TODO: is this correct? */ case QSE_AWK_VAL_REF: - return 0; /* TODO: is this correct? */ + return val_ref_to_bool (rtx, (qse_awk_val_ref_t*)val); + } QSE_ASSERTX ( @@ -1253,6 +1292,55 @@ oops: return -1; } +static int val_ref_to_str ( + qse_awk_rtx_t* rtx, const qse_awk_val_ref_t* ref, + qse_awk_rtx_valtostr_out_t* out) +{ + if (ref->id == QSE_AWK_VAL_REF_POS) + { + qse_size_t idx; + + /* special case when the reference value is + * pointing to the positional */ + + idx = (qse_size_t)ref->adr; + if (idx == 0) + { + return str_to_str ( + rtx, + QSE_STR_PTR(&rtx->inrec.line), + QSE_STR_LEN(&rtx->inrec.line), + out + ); + } + else if (idx <= rtx->inrec.nflds) + { + return str_to_str ( + rtx, + rtx->inrec.flds[idx-1].ptr, + rtx->inrec.flds[idx-1].len, + out + ); + } + else + { + return str_to_str (rtx, QSE_T(""), 0, out); + } + } + else + { + qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr; + + /* A reference value is not able to point to another + * refernce value for the way values are represented + * in QSEAWK */ + QSE_ASSERT ((*xref)->type != QSE_AWK_VAL_REF); + + /* make a recursive call back to the caller */ + return qse_awk_rtx_valtostr (rtx, *xref, out); + } +} + int qse_awk_rtx_valtostr ( qse_awk_rtx_t* rtx, const qse_awk_val_t* v, qse_awk_rtx_valtostr_out_t* out) @@ -1288,8 +1376,15 @@ int qse_awk_rtx_valtostr ( return str_to_str (rtx, QSE_T("#MAP"), 4, out); break; } + + case QSE_AWK_VAL_REF: + { + return val_ref_to_str ( + rtx, (qse_awk_val_ref_t*)v, out); + } } + #ifdef DEBUG_VAL qse_dprintf ( QSE_T(">>WRONG VALUE TYPE [%d] in qse_awk_rtx_valtostr\n"), @@ -1360,6 +1455,54 @@ qse_wchar_t* qse_awk_rtx_valtowcsdup ( #endif } +static int val_ref_to_num ( + qse_awk_rtx_t* rtx, const qse_awk_val_ref_t* ref, qse_long_t* l, qse_flt_t* r) +{ + if (ref->id == QSE_AWK_VAL_REF_POS) + { + qse_size_t idx; + + idx = (qse_size_t)ref->adr; + if (idx == 0) + { + return qse_awk_rtx_strtonum ( + rtx, 0, + QSE_STR_PTR(&rtx->inrec.line), + QSE_STR_LEN(&rtx->inrec.line), + l, r + ); + } + else if (idx <= rtx->inrec.nflds) + { + return qse_awk_rtx_strtonum ( + rtx, 0, + rtx->inrec.flds[idx-1].ptr, + rtx->inrec.flds[idx-1].len, + l, r + ); + } + else + { + return qse_awk_rtx_strtonum ( + rtx, 0, QSE_T(""), 0, l, r + ); + } + } + else + { + qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr; + + /* A reference value is not able to point to another + * refernce value for the way values are represented + * in QSEAWK */ + QSE_ASSERT ((*xref)->type != QSE_AWK_VAL_REF); + + /* make a recursive call back to the caller */ + return qse_awk_rtx_valtonum (rtx, *xref, l, r); + } +} + + int qse_awk_rtx_valtonum ( qse_awk_rtx_t* rtx, const qse_awk_val_t* v, qse_long_t* l, qse_flt_t* r) { @@ -1392,6 +1535,11 @@ int qse_awk_rtx_valtonum ( l, r ); } + + case QSE_AWK_VAL_REF: + { + return val_ref_to_num (rtx, (qse_awk_val_str_t*)v, l, r); + } } #ifdef DEBUG_VAL @@ -1509,6 +1657,59 @@ qse_long_t qse_awk_rtx_hashval (qse_awk_rtx_t* rtx, qse_awk_val_t* v) return hv & ~(((qse_ulong_t)1) << ((QSE_SIZEOF(qse_ulong_t) * 8) - 1)); } +int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_val_t* val) +{ + if (val->type == QSE_AWK_VAL_REX) + { + /* though it is possible that an intrinsic function handler + * can accept a regular expression withtout evaluation when 'x' + * is specified for the parameter, this function doesn't allow + * regular expression to be set to a reference variable to + * avoid potential chaos. the nature of performing '/rex/ ~ $0' + * for a regular expression without the match operator + * makes it difficult to be implemented. */ + qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); + return -1; + } + + if (ref->id == QSE_AWK_VAL_REF_POS) + { + if (val->type == QSE_AWK_VAL_STR) + { + return qse_awk_rtx_setrec ( + rtx, (qse_size_t)ref->adr, + &((qse_awk_val_str_t*)val)->val + ); + } + else + { + qse_xstr_t str; + int x; + + str.ptr = qse_awk_rtx_valtostrdup (rtx, val, &str.len); + x = qse_awk_rtx_setrec (rtx, (qse_size_t)ref->adr, &str); + QSE_AWK_FREE (rtx->awk, str.ptr); + return x; + } + } + else + { + qse_awk_val_t** rref; + +/* TODO: handle QSE_AWK_FLEXMAP... +if FLEXMAP is not set.. check if rref is nil or map if value is map. +also check if rref is nil... scalar if valeu is scalar.. +but is this really necessary? i feel all these awk quarkiness is nasty.. +*/ + + rref = (qse_awk_val_t**)ref->adr; + qse_awk_rtx_refdownval (rtx, *rref); + *rref = val; + qse_awk_rtx_refupval (rtx, *rref); + return 0; + } +} + #if 0 #define DPRINTF run->awk->prmfns->dprintf