From 785c95b1e65ef7c95d842ef10d8b198c032c4e3e Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 5 Aug 2012 08:56:42 +0000 Subject: [PATCH] moved ARGC and ARGV to base to std for simplication of the base implementation. note C++ wrappers need the same changes --- qse/include/qse/awk/awk.h | 23 ++--- qse/lib/awk/parse.c | 3 - qse/lib/awk/run.c | 123 +++----------------------- qse/lib/awk/std.c | 181 ++++++++++++++++++++++++++------------ 4 files changed, 149 insertions(+), 181 deletions(-) diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index a62a1da9..bbd3f3b2 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -71,11 +71,10 @@ * qse_awk_rtx_t* rtx; * qse_awk_sio_t sio; // need to initialize it with callback functions * qse_awk_rio_t rio; // need to initialize it with callback functions - * qse_cstr_t args[5]; // need to initialize it with strings * * awk = qse_awk_open (mmgr, 0, prm); // create an interpreter * qse_awk_parse (awk, &sio); // parse a script - * rtx = qse_awk_rtx_open (awk, 0, &rio, args); // create a runtime context + * rtx = qse_awk_rtx_open (awk, 0, &rio); // create a runtime context * retv = qse_awk_rtx_loop (rtx); // run a standard AWK loop * if (retv != QSE_NULL) * qse_awk_rtx_refdownval (rtx, retv); // free return value @@ -1029,10 +1028,15 @@ enum qse_awk_gbl_id_t { /* this table should match gtab in parse.c. * in addition, qse_awk_rtx_setgbl also counts - * on the order of these values */ + * on the order of these values. + * + * note that set_global() in run.c contains code + * preventing these global variables from being assigned + * with a map value. if you happen to add one that can + * be a map, don't forget to change code in set_global(). + * but is this check really necessary??? + */ - QSE_AWK_GBL_ARGC, - QSE_AWK_GBL_ARGV, QSE_AWK_GBL_CONVFMT, QSE_AWK_GBL_FILENAME, QSE_AWK_GBL_FNR, @@ -1052,7 +1056,7 @@ enum qse_awk_gbl_id_t /* these are not not the actual IDs and are used internally only * Make sure you update these values properly if you add more * ID definitions, however */ - QSE_AWK_MIN_GBL_ID = QSE_AWK_GBL_ARGC, + QSE_AWK_MIN_GBL_ID = QSE_AWK_GBL_CONVFMT, QSE_AWK_MAX_GBL_ID = QSE_AWK_GBL_SUBSEP }; typedef enum qse_awk_gbl_id_t qse_awk_gbl_id_t; @@ -1559,17 +1563,14 @@ qse_size_t qse_awk_longtostr ( * It also allocates an extra memory block as large as the @a xtn bytes. * You can get the pointer to the beginning of the block with * qse_awk_rtx_getxtn(). The block is destroyed when the runtime context is - * destroyed. The argument array @a arg, if not #QSE_NULL, is used to set - * @b ARGV. The @b ptr field and the @b len field of the last member of - * this array must be set to #QSE_NULL and 0 respectively. + * destroyed. * * @return new runtime context on success, #QSE_NULL on failure */ qse_awk_rtx_t* qse_awk_rtx_open ( qse_awk_t* awk, /**< awk */ qse_size_t xtn, /**< size of extension in bytes */ - qse_awk_rio_t* rio, /**< runtime IO handlers */ - const qse_cstr_t* arg /**< argument array to set ARGV */ + qse_awk_rio_t* rio /**< runtime IO handlers */ ); /** diff --git a/qse/lib/awk/parse.c b/qse/lib/awk/parse.c index 11ed35d0..de821be1 100644 --- a/qse/lib/awk/parse.c +++ b/qse/lib/awk/parse.c @@ -284,9 +284,6 @@ struct global_t static global_t gtab[] = { - { QSE_T("ARGC"), 4, 0 }, - { QSE_T("ARGV"), 4, 0 }, - /* output real-to-str conversion format for other cases than 'print' */ { QSE_T("CONVFMT"), 7, 0 }, diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index 59a03f6d..092d0bcb 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -101,7 +101,7 @@ static qse_size_t push_arg_from_vals ( static int init_rtx (qse_awk_rtx_t* rtx, qse_awk_t* awk, qse_awk_rio_t* rio); static void fini_rtx (qse_awk_rtx_t* rtx, int fini_globals); -static int init_globals (qse_awk_rtx_t* rtx, const qse_cstr_t* arg); +static int init_globals (qse_awk_rtx_t* rtx); static void refdown_globals (qse_awk_rtx_t* run, int pop); static int run_pblocks (qse_awk_rtx_t* rtx); @@ -326,10 +326,12 @@ static int set_global ( return -1; } - /* builtin variables except ARGV cannot be assigned a map */ - if (val->type == QSE_AWK_VAL_MAP && - (idx >= QSE_AWK_GBL_ARGC && idx <= QSE_AWK_GBL_SUBSEP) && - idx != QSE_AWK_GBL_ARGV) + /* all the basic builtin variables cannot be assigned a map. + * if you happen to add one and if that's allowed to be a map, + * you may have to change the condition here. + * but is this check really necessary??? */ + if (val->type == QSE_AWK_VAL_MAP && + idx >= QSE_AWK_MIN_GBL_ID && idx <= QSE_AWK_MAX_GBL_ID) { /* TODO: better error code */ SETERR_COD (rtx, QSE_AWK_ESCALARTOMAP); @@ -686,8 +688,7 @@ qse_htb_t* qse_awk_rtx_getnvmap (qse_awk_rtx_t* rtx) } qse_awk_rtx_t* qse_awk_rtx_open ( - qse_awk_t* awk, qse_size_t xtn, - qse_awk_rio_t* rio, const qse_cstr_t* arg) + qse_awk_t* awk, qse_size_t xtn, qse_awk_rio_t* rio) { qse_awk_rtx_t* rtx; @@ -726,7 +727,7 @@ qse_awk_rtx_t* qse_awk_rtx_open ( return QSE_NULL; } - if (init_globals (rtx, arg) <= -1) + if (init_globals (rtx) <= -1) { awk->errinf = rtx->errinf; /* transfer error info */ fini_rtx (rtx, 0); @@ -1078,101 +1079,6 @@ static void fini_rtx (qse_awk_rtx_t* rtx, int fini_globals) rtx->vmgr.rchunk = QSE_NULL; } -static int build_runarg ( - qse_awk_rtx_t* rtx, const qse_cstr_t* runarg, qse_size_t* nargs) -{ - const qse_cstr_t* p; - qse_size_t argc; - qse_awk_val_t* v_argc; - qse_awk_val_t* v_argv; - qse_awk_val_t* v_tmp; - qse_char_t key[QSE_SIZEOF(qse_long_t)*8+2]; - qse_size_t key_len; - - v_argv = qse_awk_rtx_makemapval (rtx); - if (v_argv == QSE_NULL) return -1; - - qse_awk_rtx_refupval (rtx, v_argv); - - if (runarg) - { - for (argc = 0, p = runarg; p->ptr != QSE_NULL; argc++, p++) - { - v_tmp = qse_awk_rtx_makestrval (rtx, p->ptr, p->len); - if (v_tmp == QSE_NULL) - { - qse_awk_rtx_refdownval (rtx, v_argv); - return -1; - } - - key_len = qse_awk_longtostr ( - rtx->awk, argc, 10, - QSE_NULL, key, QSE_COUNTOF(key)); - QSE_ASSERT (key_len != (qse_size_t)-1); - - /* increment reference count of v_tmp in advance as if - * it has successfully been assigned into ARGV. */ - qse_awk_rtx_refupval (rtx, v_tmp); - - if (qse_htb_upsert ( - ((qse_awk_val_map_t*)v_argv)->map, - key, key_len, v_tmp, 0) == QSE_NULL) - { - /* if the assignment operation fails, decrements - * the reference of v_tmp to free it */ - qse_awk_rtx_refdownval (rtx, v_tmp); - - /* the values previously assigned into the - * map will be freeed when v_argv is freed */ - qse_awk_rtx_refdownval (rtx, v_argv); - - SETERR_COD (rtx, QSE_AWK_ENOMEM); - return -1; - } - } - } - else argc = 0; - - v_argc = qse_awk_rtx_makeintval (rtx, (qse_long_t)argc); - if (v_argc == QSE_NULL) - { - qse_awk_rtx_refdownval (rtx, v_argv); - return -1; - } - - qse_awk_rtx_refupval (rtx, v_argc); - - QSE_ASSERT ( - STACK_GBL(rtx,QSE_AWK_GBL_ARGC) == qse_awk_val_nil); - - if (qse_awk_rtx_setgbl (rtx, QSE_AWK_GBL_ARGC, v_argc) == -1) - { - qse_awk_rtx_refdownval (rtx, v_argc); - qse_awk_rtx_refdownval (rtx, v_argv); - return -1; - } - - if (qse_awk_rtx_setgbl (rtx, QSE_AWK_GBL_ARGV, v_argv) == -1) - { - /* ARGC is assigned nil when ARGV assignment has failed. - * However, this requires preconditions, as follows: - * 1. build_runarg should be called in a proper place - * as it is not a generic-purpose routine. - * 2. ARGC should be nil before build_runarg is called - * If the restoration fails, nothing can salvage it. */ - qse_awk_rtx_setgbl (rtx, QSE_AWK_GBL_ARGC, qse_awk_val_nil); - qse_awk_rtx_refdownval (rtx, v_argc); - qse_awk_rtx_refdownval (rtx, v_argv); - return -1; - } - - qse_awk_rtx_refdownval (rtx, v_argc); - qse_awk_rtx_refdownval (rtx, v_argv); - - *nargs = argc; - return 0; -} - static int update_fnr (qse_awk_rtx_t* rtx, qse_long_t fnr, qse_long_t nr) { qse_awk_val_t* tmp1, * tmp2; @@ -1217,13 +1123,11 @@ static int update_fnr (qse_awk_rtx_t* rtx, qse_long_t fnr, qse_long_t nr) /* * create global variables into the runtime stack * each variable is initialized to nil or zero. - * ARGC and ARGV are built in this function */ -static int prepare_globals (qse_awk_rtx_t* rtx, const qse_cstr_t* runarg) +static int prepare_globals (qse_awk_rtx_t* rtx) { qse_size_t saved_stack_top; qse_size_t ngbls; - qse_size_t nrunargs; saved_stack_top = rtx->stack_top; ngbls = rtx->awk->tree.ngbls; @@ -1243,9 +1147,6 @@ static int prepare_globals (qse_awk_rtx_t* rtx, const qse_cstr_t* runarg) if (qse_awk_rtx_setgbl ( rtx, QSE_AWK_GBL_NF, qse_awk_val_zero) <= -1) goto oops; - /* override ARGC and ARGV if necessary */ - if (runarg && build_runarg (rtx, runarg, &nrunargs) <= -1) goto oops; - /* return success */ return 0; @@ -1337,13 +1238,13 @@ static void refdown_globals (qse_awk_rtx_t* run, int pop) } } -static int init_globals (qse_awk_rtx_t* rtx, const qse_cstr_t* arg) +static int init_globals (qse_awk_rtx_t* rtx) { /* the stack must be clean when this function is invoked */ QSE_ASSERTX (rtx->stack_base == 0, "stack not clean"); QSE_ASSERTX (rtx->stack_top == 0, "stack not clean"); - if (prepare_globals (rtx, arg) == -1) return -1; + if (prepare_globals (rtx) == -1) return -1; if (update_fnr (rtx, 0, 0) == -1) goto oops; if (defaultify_globals (rtx) == -1) goto oops; return 0; diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index e9afe3e5..c893f595 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -104,6 +104,8 @@ typedef struct xtn_t } out; } s; /* script/source handling */ + int gbl_argc; + int gbl_argv; int gbl_environ; int gbl_procinfo; } xtn_t; @@ -1179,6 +1181,8 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod) if (riod->mode == QSE_AWK_RIO_CONSOLE_READ) { + xtn_t* xtn = (xtn_t*)QSE_XTN (rtx->awk); + if (rxtn->c.in.files == QSE_NULL) { /* if no input files is specified, @@ -1254,7 +1258,7 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod) * 'BEGIN { ARGV[1]="file3"; } * { print $0; }' file1 file2 */ - argv = qse_awk_rtx_getgbl (rtx, QSE_AWK_GBL_ARGV); + argv = qse_awk_rtx_getgbl (rtx, xtn->gbl_argv); QSE_ASSERT (argv != QSE_NULL); QSE_ASSERT (argv->type == QSE_AWK_VAL_MAP); @@ -1482,6 +1486,112 @@ static void fini_rxtn (qse_awk_rtx_t* rtx, void* ctx) } } +static int build_argcv ( + qse_awk_rtx_t* rtx, int argc_id, int argv_id, + const qse_char_t* id, const qse_char_t*const icf[]) +{ + const qse_char_t*const* p; + qse_size_t argc; + qse_awk_val_t* v_argc; + qse_awk_val_t* v_argv; + qse_awk_val_t* v_tmp; + qse_char_t key[QSE_SIZEOF(qse_long_t)*8+2]; + qse_size_t key_len; + + v_argv = qse_awk_rtx_makemapval (rtx); + if (v_argv == QSE_NULL) return -1; + + qse_awk_rtx_refupval (rtx, v_argv); + + /* make ARGV[0] */ + v_tmp = qse_awk_rtx_makestrval0 (rtx, id); + if (v_tmp == QSE_NULL) + { + qse_awk_rtx_refdownval (rtx, v_argv); + return -1; + } + + /* increment reference count of v_tmp in advance as if + * it has successfully been assigned into ARGV. */ + qse_awk_rtx_refupval (rtx, v_tmp); + + key_len = qse_strxcpy (key, QSE_COUNTOF(key), QSE_T("0")); + if (qse_htb_upsert ( + ((qse_awk_val_map_t*)v_argv)->map, + key, key_len, v_tmp, 0) == QSE_NULL) + { + /* if the assignment operation fails, decrements + * the reference of v_tmp to free it */ + qse_awk_rtx_refdownval (rtx, v_tmp); + + /* the values previously assigned into the + * map will be freeed when v_argv is freed */ + qse_awk_rtx_refdownval (rtx, v_argv); + + qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); + return -1; + } + + if (icf) + { + for (argc = 1, p = icf; *p; p++, argc++) + { + v_tmp = qse_awk_rtx_makestrval0 (rtx, *p); + if (v_tmp == QSE_NULL) + { + qse_awk_rtx_refdownval (rtx, v_argv); + return -1; + } + + key_len = qse_awk_longtostr ( + rtx->awk, argc, 10, + QSE_NULL, key, QSE_COUNTOF(key)); + QSE_ASSERT (key_len != (qse_size_t)-1); + + qse_awk_rtx_refupval (rtx, v_tmp); + + if (qse_htb_upsert ( + ((qse_awk_val_map_t*)v_argv)->map, + key, key_len, v_tmp, 0) == QSE_NULL) + { + qse_awk_rtx_refdownval (rtx, v_tmp); + qse_awk_rtx_refdownval (rtx, v_argv); + qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); + return -1; + } + } + } + else argc = 1; + + v_argc = qse_awk_rtx_makeintval (rtx, (qse_long_t)argc); + if (v_argc == QSE_NULL) + { + qse_awk_rtx_refdownval (rtx, v_argv); + return -1; + } + + qse_awk_rtx_refupval (rtx, v_argc); + + if (qse_awk_rtx_setgbl (rtx, argc_id, v_argc) <= -1) + { + qse_awk_rtx_refdownval (rtx, v_argc); + qse_awk_rtx_refdownval (rtx, v_argv); + return -1; + } + + if (qse_awk_rtx_setgbl (rtx, argv_id, v_argv) <= -1) + { + qse_awk_rtx_refdownval (rtx, v_argc); + qse_awk_rtx_refdownval (rtx, v_argv); + return -1; + } + + qse_awk_rtx_refdownval (rtx, v_argc); + qse_awk_rtx_refdownval (rtx, v_argv); + + return 0; +} + static int __build_environ ( qse_awk_rtx_t* rtx, int gbl_id, qse_env_char_t* envarr[]) { @@ -1744,10 +1854,14 @@ static int build_procinfo (qse_awk_rtx_t* rtx, int gbl_id) return 0; } -static int make_additional_globals (qse_awk_rtx_t* rtx, xtn_t* xtn) +static int make_additional_globals ( + qse_awk_rtx_t* rtx, xtn_t* xtn, + const qse_char_t* id, const qse_char_t*const icf[]) { - if (build_environ (rtx, xtn->gbl_environ) <= -1) return -1; - if (build_procinfo (rtx, xtn->gbl_procinfo) <= -1) return -1; + if (build_argcv (rtx, xtn->gbl_argc, xtn->gbl_argv, id, icf) <= -1 || + build_environ (rtx, xtn->gbl_environ) <= -1 || + build_procinfo (rtx, xtn->gbl_procinfo) <= -1) return -1; + return 0; } @@ -1772,65 +1886,18 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( xtn_t* xtn; qse_ntime_t now; - const qse_char_t*const* p; - qse_cstr_t* p2; - - qse_size_t argc = 0; - qse_cstr_t argv[16]; - qse_cstr_t* argvp = QSE_NULL; - xtn = (xtn_t*)QSE_XTN (awk); rio.pipe = awk_rio_pipe; rio.file = awk_rio_file; rio.console = awk_rio_console; - if (icf) - { - 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) - { - for (p = icf; *p; 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 + &rio ); - if (argvp && argvp != argv) QSE_AWK_FREE (awk, argvp); if (rtx == QSE_NULL) return QSE_NULL; rxtn = (rxtn_t*) QSE_XTN (rtx); @@ -1887,7 +1954,7 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( } } - if (make_additional_globals (rtx, xtn) <= -1) + if (make_additional_globals (rtx, xtn, id, icf) <= -1) { awk->errinf = rtx->errinf; /* transfer error info */ qse_awk_rtx_close (rtx); @@ -2338,11 +2405,13 @@ static int add_globals (qse_awk_t* awk) xtn = (xtn_t*) QSE_XTN (awk); + xtn->gbl_argc = qse_awk_addgbl (awk, QSE_T("ARGC"), 4); + xtn->gbl_argv = qse_awk_addgbl (awk, QSE_T("ARGV"), 4); xtn->gbl_environ = qse_awk_addgbl (awk, QSE_T("ENVIRON"), 7); - if (xtn->gbl_environ <= -1) return -1; - xtn->gbl_procinfo = qse_awk_addgbl (awk, QSE_T("PROCINFO"), 8); - if (xtn->gbl_procinfo <= -1) return -1; + + if (xtn->gbl_argc <= -1 || xtn->gbl_argv <= -1 || + xtn->gbl_environ <= -1 || xtn->gbl_procinfo <= -1) return -1; return 0; }