From fdce5fc592b08c117df114d544a9be2e372b1789 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 11 Jul 2014 07:42:28 +0000 Subject: [PATCH] migrated rand(), srand(), system() to modules --- qse/cmd/sed/sed.c | 2 +- qse/include/qse/awk/StdAwk.hpp | 15 +--- qse/lib/awk/Awk.cpp | 2 +- qse/lib/awk/StdAwk.cpp | 83 ++------------------ qse/lib/awk/mod-math.c | 110 ++++++++++++++++++++++++-- qse/lib/awk/mod-str.c | 5 +- qse/lib/awk/mod-sys.c | 55 ++++++++++++- qse/lib/awk/parse.c | 2 +- qse/lib/awk/std.c | 139 ++------------------------------- 9 files changed, 176 insertions(+), 237 deletions(-) diff --git a/qse/cmd/sed/sed.c b/qse/cmd/sed/sed.c index b5eacaa4..ba592df4 100644 --- a/qse/cmd/sed/sed.c +++ b/qse/cmd/sed/sed.c @@ -802,7 +802,7 @@ static int sed_main (int argc, qse_char_t* argv[]) #endif qse_memset (&xarg, 0, QSE_SIZEOF(xarg)); - xarg.mmgr = qse_sed_getmmgr(sed); + xarg.mmgr = qse_sed_getmmgr(sed); xarg_inited = 1; if (g_separate && g_infile_pos > 0) diff --git a/qse/include/qse/awk/StdAwk.hpp b/qse/include/qse/awk/StdAwk.hpp index 9f32ab95..7eb89d62 100644 --- a/qse/include/qse/awk/StdAwk.hpp +++ b/qse/include/qse/awk/StdAwk.hpp @@ -115,13 +115,6 @@ protected: int __build_environ (Run* run, void* envptr); // intrinsic functions - int rand (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len); - int srand (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len); - int system (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len); - qse_cmgr_t* getcmgr (const char_t* ioname); int setioattr (Run& run, Value& ret, Value* args, size_t nargs, @@ -159,13 +152,11 @@ protected: flt_t pow (flt_t x, flt_t y); flt_t mod (flt_t x, flt_t y); - void* modopen (const mod_spec_t* spec); - void modclose (void* handle); - void* modsym (void* handle, const char_t* name); + void* modopen (const mod_spec_t* spec); + void modclose (void* handle); + void* modsym (void* handle, const char_t* name); protected: - int_t seed; - uint_t prand; qse_htb_t cmgrtab; bool cmgrtab_inited; diff --git a/qse/lib/awk/Awk.cpp b/qse/lib/awk/Awk.cpp index 1e710e9e..d9fd7347 100644 --- a/qse/lib/awk/Awk.cpp +++ b/qse/lib/awk/Awk.cpp @@ -1623,7 +1623,7 @@ int Awk::addFunction ( spec.arg.min = minArgs; spec.arg.max = maxArgs; spec.arg.spec = argSpec; - spec.impl = functionHandler; + spec.impl = this->functionHandler; spec.trait = validOpts; qse_awk_fnc_t* fnc = qse_awk_addfnc (awk, name, &spec); diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp index 9b04d399..84c6b445 100644 --- a/qse/lib/awk/StdAwk.cpp +++ b/qse/lib/awk/StdAwk.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include "awk.h" #include @@ -128,11 +127,11 @@ int StdAwk::open () goto oops; } - if (addFunction (QSE_T("rand"), 0, 0, QSE_NULL, (FunctionHandler)&StdAwk::rand, 0) <= -1 || - addFunction (QSE_T("srand"), 0, 1, QSE_NULL, (FunctionHandler)&StdAwk::srand, 0) <= -1 || - addFunction (QSE_T("system"), 1, 1, QSE_NULL, (FunctionHandler)&StdAwk::system, 0) <= -1 || - addFunction (QSE_T("setioattr"), 3, 3, QSE_NULL, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 || - addFunction (QSE_T("getioattr"), 3, 3, QSE_T("vvr"), (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1) + if (addFunction (QSE_T("rand"), 1, 0, QSE_T("math"), QSE_NULL, 0) <= -1 || + addFunction (QSE_T("srand"), 1, 0, QSE_T("math"), QSE_NULL, 0) <= -1 || + addFunction (QSE_T("system"), 1, 0, QSE_T("sys"), QSE_NULL, 0) <= -1 || + addFunction (QSE_T("setioattr"), 3, 3, QSE_NULL, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 || + addFunction (QSE_T("getioattr"), 3, 3, QSE_T("vvr"), (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1) { goto oops; } @@ -145,15 +144,6 @@ int StdAwk::open () if (lt_dlinit() != 0) goto oops; #endif - qse_ntime_t now; - - this->seed = (qse_gettime(&now) <= -1)? 0u: ((int_t)now.sec + (int_t)now.nsec); - /* i don't care if the seed becomes negative or overflows. - * i just convert the signed value to the unsigned one. */ - this->prand = (uint_t)(this->seed * this->seed * this->seed); - /* make sure that the actual seeding is not 0 */ - if (this->prand == 0) this->prand++; - this->cmgrtab_inited = false; return 0; @@ -336,69 +326,6 @@ int StdAwk::make_additional_globals (Run* run) return 0; } -int StdAwk::rand (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len) -{ -#define RANDV_MAX QSE_TYPE_MAX(int_t) - -#if defined(QSE_USE_AWK_INTMAX) - this->prand = qse_randxsuintmax (this->prand); -#else - this->prand = qse_randxsulong (this->prand); -#endif - - int_t randv = this->prand % RANDV_MAX; - return ret.setFlt ((flt_t)randv / RANDV_MAX); -#undef RANDV_MAX -} - -int StdAwk::srand (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len) -{ - int_t prevSeed = (int_t)this->seed; - - qse_ntime_t now; - - if (nargs <= 0) - { - this->seed = (qse_gettime (&now) <= -1)? - (this->seed * this->seed): ((int_t)now.sec + (int_t)now.nsec); - } - else - { - this->seed = args[0].toInt(); - } - - /* i don't care if the seed becomes negative or overflows. - * i just convert the signed value to the unsigned one. */ - this->prand = (uint_t)(this->seed * this->seed * this->seed); - /* make sure that the actual seeding is not 0 */ - if (this->prand == 0) this->prand++; - - return ret.setInt ((int_t)prevSeed); -} - -int StdAwk::system (Run& run, Value& ret, Value* args, size_t nargs, - const char_t* name, size_t len) -{ - size_t l; - const char_t* ptr = args[0].toStr(&l); - -#if defined(_WIN32) - return ret.setInt ((int_t)::_tsystem(ptr)); -#elif defined(QSE_CHAR_IS_MCHAR) - return ret.setInt ((int_t)::system(ptr)); -#else - - qse_mchar_t* mbs; - mbs = qse_wcstombsdup (ptr, QSE_NULL, ((Awk*)run)->getMmgr()); - if (mbs == QSE_NULL) return -1; - int n = ret.setInt ((int_t)::system(mbs)); - QSE_MMGR_FREE (((Awk*)run)->getMmgr(), mbs); - return n; -#endif -} - qse_cmgr_t* StdAwk::getcmgr (const char_t* ioname) { QSE_ASSERT (this->cmgrtab_inited == true); diff --git a/qse/lib/awk/mod-math.c b/qse/lib/awk/mod-math.c index 0ba40b25..5ea986c7 100644 --- a/qse/lib/awk/mod-math.c +++ b/qse/lib/awk/mod-math.c @@ -21,6 +21,8 @@ #include "mod-str.h" #include #include +#include +#include #include "../cmn/mem.h" #include "fnc.h" @@ -53,6 +55,12 @@ # endif #endif +typedef struct modctx_t +{ + qse_awk_int_t seed; + qse_awk_uint_t prand; /* last random value returned */ +} modctx_t; + static int fnc_math_1 ( qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi, qse_awk_math1_t f) { @@ -454,6 +462,73 @@ static int fnc_sqrt (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) return fnc_math_1 (rtx, fi, math_sqrt); } +/* ----------------------------------------------------------------------- */ + +static int fnc_rand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) +{ +#define RANDV_MAX QSE_TYPE_MAX(qse_awk_int_t) + qse_awk_val_t* r; + qse_awk_int_t randv; + modctx_t* modctx; + + modctx = (modctx_t*)fi->mod->ctx; + +#if defined(QSE_USE_AWK_INTMAX) + modctx->prand = qse_randxsuintmax (modctx->prand); +#else + modctx->prand = qse_randxsulong (modctx->prand); +#endif + randv = modctx->prand % RANDV_MAX; + + r = qse_awk_rtx_makefltval (rtx, (qse_awk_flt_t)randv / RANDV_MAX); + if (r == QSE_NULL) return -1; + + qse_awk_rtx_setretval (rtx, r); + return 0; +#undef RANDV_MAX +} + +static int fnc_srand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) +{ + qse_size_t nargs; + qse_awk_val_t* a0; + qse_awk_int_t lv; + qse_awk_val_t* r; + int n; + qse_awk_int_t prev; + qse_ntime_t now; + modctx_t* modctx; + + modctx = (modctx_t*)fi->mod->ctx; + nargs = qse_awk_rtx_getnargs (rtx); + QSE_ASSERT (nargs == 0 || nargs == 1); + + prev = modctx->seed; + + if (nargs <= 0) + { + modctx->seed = (qse_gettime (&now) <= -1)? + (modctx->seed * modctx->seed): ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec); + } + else + { + a0 = qse_awk_rtx_getarg (rtx, 0); + n = qse_awk_rtx_valtoint (rtx, a0, &lv); + if (n <= -1) return -1; + modctx->seed = lv; + } + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + modctx->prand = (qse_awk_uint_t)(modctx->seed * modctx->seed * modctx->seed); + /* make sure that the actual seeding is not 0 */ + if (modctx->prand == 0) modctx->prand++; + + r = qse_awk_rtx_makeintval (rtx, prev); + if (r == QSE_NULL) return -1; + + qse_awk_rtx_setretval (rtx, r); + return 0; +} /* ----------------------------------------------------------------------- */ @@ -478,10 +553,12 @@ static fnctab_t fnctab[] = { QSE_T("floor"), { { 1, 1, QSE_NULL }, fnc_floor, 0 } }, { QSE_T("log"), { { 1, 1, QSE_NULL }, fnc_log, 0 } }, { QSE_T("log10"), { { 1, 1, QSE_NULL }, fnc_log10, 0 } }, + { QSE_T("rand"), { { 0, 0, QSE_NULL }, fnc_rand, 0 } }, { QSE_T("round"), { { 1, 1, QSE_NULL }, fnc_round, 0 } }, { QSE_T("sin"), { { 1, 1, QSE_NULL }, fnc_sin, 0 } }, { QSE_T("sinh"), { { 1, 1, QSE_NULL }, fnc_sinh, 0 } }, { QSE_T("sqrt"), { { 1, 1, QSE_NULL }, fnc_sqrt, 0 } }, + { QSE_T("srand"), { { 0, 1, QSE_NULL }, fnc_srand, 0 } }, { QSE_T("tan"), { { 1, 1, QSE_NULL }, fnc_tan, 0 } }, { QSE_T("tanh"), { { 1, 1, QSE_NULL }, fnc_tanh, 0 } } }; @@ -541,27 +618,44 @@ static int init (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx) static void fini (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx) { - /* TODO: - for (each pid for rtx) kill (pid, SIGKILL); - for (each pid for rtx) waitpid (pid, QSE_NULL, 0); - */ + /* TODO: anything */ } static void unload (qse_awk_mod_t* mod, qse_awk_t* awk) { - /* TODO: anything */ + modctx_t* modctx; + + modctx = (modctx_t*)mod->ctx; + qse_awk_freemem (awk, modctx); } int qse_awk_mod_math (qse_awk_mod_t* mod, qse_awk_t* awk) { + modctx_t* modctx; + qse_ntime_t now; + + modctx = qse_awk_allocmem (awk, QSE_SIZEOF(*modctx)); + if (modctx == QSE_NULL) + { + qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL); + return -1; + } + + QSE_MEMSET (modctx, 0, QSE_SIZEOF(*modctx)); + + modctx->seed = (qse_gettime (&now) <= -1)? 0u: ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec); + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + modctx->prand = (qse_awk_uint_t)(modctx->seed * modctx->seed * modctx->seed); + /* make sure that the actual seeding is not 0 */ + if (modctx->prand == 0) modctx->prand++; + mod->query = query; mod->unload = unload; mod->init = init; mod->fini = fini; - /* - mod->ctx... - */ + mod->ctx = modctx; return 0; } diff --git a/qse/lib/awk/mod-str.c b/qse/lib/awk/mod-str.c index d92a83be..a9b0335d 100644 --- a/qse/lib/awk/mod-str.c +++ b/qse/lib/awk/mod-str.c @@ -301,10 +301,7 @@ static int init (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx) static void fini (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx) { - /* TODO: - for (each pid for rtx) kill (pid, SIGKILL); - for (each pid for rtx) waitpid (pid, QSE_NULL, 0); - */ + /* TODO: anything */ } static void unload (qse_awk_mod_t* mod, qse_awk_t* awk) diff --git a/qse/lib/awk/mod-sys.c b/qse/lib/awk/mod-sys.c index e7a15d70..87cc33e2 100644 --- a/qse/lib/awk/mod-sys.c +++ b/qse/lib/awk/mod-sys.c @@ -23,11 +23,13 @@ #include #include #include +#include #include "../cmn/mem.h" #if defined(_WIN32) # include # include +# include #elif defined(__OS2__) # define INCL_DOSPROCESS # define INCL_DOSEXCEPTIONS @@ -42,7 +44,7 @@ # endif #endif -#include /* getenv */ +#include /* getenv, system */ static int fnc_fork (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { @@ -597,6 +599,56 @@ static int fnc_getnwifcfg (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) return 0; } +static int fnc_system (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) +{ + qse_awk_val_t* v, * a0; + qse_char_t* str; + qse_size_t len; + int n = 0; + + a0 = qse_awk_rtx_getarg (rtx, 0); + str = qse_awk_rtx_getvalstr (rtx, a0, &len); + if (str == QSE_NULL) return -1; + + /* the target name contains a null character. + * make system return -1 */ + if (qse_strxchr (str, len, QSE_T('\0'))) + { + n = -1; + goto skip_system; + } + +#if defined(_WIN32) + n = _tsystem (str); +#elif defined(QSE_CHAR_IS_MCHAR) + n = system (str); +#else + + { + qse_mchar_t* mbs; + mbs = qse_wcstombsdup (str, QSE_NULL, qse_awk_rtx_getmmgr(rtx)); + if (mbs == QSE_NULL) + { + n = -1; + goto skip_system; + } + n = system (mbs); + qse_awk_rtx_freemem (rtx, mbs); + } + +#endif + +skip_system: + qse_awk_rtx_freevalstr (rtx, a0, str); + + v = qse_awk_rtx_makeintval (rtx, (qse_awk_int_t)n); + if (v == QSE_NULL) return -1; + + qse_awk_rtx_setretval (rtx, v); + return 0; +} + + typedef struct fnctab_t fnctab_t; struct fnctab_t { @@ -630,6 +682,7 @@ static fnctab_t fnctab[] = { QSE_T("kill"), { { 2, 2, QSE_NULL }, fnc_kill, 0 } }, { QSE_T("settime"), { { 1, 1, QSE_NULL }, fnc_settime, 0 } }, { QSE_T("sleep"), { { 1, 1, QSE_NULL }, fnc_sleep, 0 } }, + { QSE_T("system"), { { 1, 1, QSE_NULL }, fnc_system, 0 } }, { QSE_T("wait"), { { 1, 1, QSE_NULL }, fnc_wait, 0 } } }; diff --git a/qse/lib/awk/parse.c b/qse/lib/awk/parse.c index 428b91fb..a0d6576a 100644 --- a/qse/lib/awk/parse.c +++ b/qse/lib/awk/parse.c @@ -2089,7 +2089,7 @@ static qse_awk_nde_t* parse_if (qse_awk_t* awk, const qse_awk_loc_t* xloc) goto oops; } -/* TODO: optimization. if you know 'tese' evaluates to true or false, +/* TODO: optimization. if you know 'test' evaluates to true or false, * you can drop the 'if' statement and take either the 'then_part' * or 'else_part'. */ diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index f1dd220c..284e028a 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "../cmn/mem.h" #include @@ -113,9 +112,6 @@ typedef struct xtn_t typedef struct rxtn_t { - qse_awk_int_t seed; - qse_awk_uint_t prand; /* last random value returned */ - struct { struct { @@ -1903,7 +1899,6 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( qse_awk_rio_t rio; rxtn_t* rxtn; xtn_t* xtn; - qse_ntime_t now; xtn = (xtn_t*)QSE_XTN (awk); @@ -1938,13 +1933,6 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( rxtn->ecb.close = fini_rxtn; qse_awk_rtx_pushecb (rtx, &rxtn->ecb); - rxtn->seed = (qse_gettime (&now) <= -1)? 0u: ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec); - /* i don't care if the seed becomes negative or overflows. - * i just convert the signed value to the unsigned one. */ - rxtn->prand = (qse_awk_uint_t)(rxtn->seed * rxtn->seed * rxtn->seed); - /* make sure that the actual seeding is not 0 */ - if (rxtn->prand == 0) rxtn->prand++; - rxtn->c.in.files = icf; rxtn->c.in.index = 0; rxtn->c.in.count = 0; @@ -1990,120 +1978,6 @@ void* qse_awk_rtx_getxtnstd (qse_awk_rtx_t* rtx) return (void*)((rxtn_t*)QSE_XTN(rtx) + 1); } -static int fnc_rand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) -{ -#define RANDV_MAX QSE_TYPE_MAX(qse_awk_int_t) - qse_awk_val_t* r; - qse_awk_int_t randv; - rxtn_t* rxtn; - - rxtn = (rxtn_t*) QSE_XTN (rtx); - -#if defined(QSE_USE_AWK_INTMAX) - rxtn->prand = qse_randxsuintmax (rxtn->prand); -#else - rxtn->prand = qse_randxsulong (rxtn->prand); -#endif - randv = rxtn->prand % RANDV_MAX; - - r = qse_awk_rtx_makefltval (rtx, (qse_awk_flt_t)randv / RANDV_MAX); - if (r == QSE_NULL) return -1; - - qse_awk_rtx_setretval (rtx, r); - return 0; -#undef RANDV_MAX -} - -static int fnc_srand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) -{ - qse_size_t nargs; - qse_awk_val_t* a0; - qse_awk_int_t lv; - qse_awk_val_t* r; - int n; - qse_awk_int_t prev; - qse_ntime_t now; - rxtn_t* rxtn; - - rxtn = (rxtn_t*) QSE_XTN (rtx); - nargs = qse_awk_rtx_getnargs (rtx); - QSE_ASSERT (nargs == 0 || nargs == 1); - - prev = rxtn->seed; - - if (nargs <= 0) - { - rxtn->seed = (qse_gettime (&now) <= -1)? - (rxtn->seed * rxtn->seed): ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec); - } - else - { - a0 = qse_awk_rtx_getarg (rtx, 0); - n = qse_awk_rtx_valtoint (rtx, a0, &lv); - if (n <= -1) return -1; - rxtn->seed = lv; - } - /* i don't care if the seed becomes negative or overflows. - * i just convert the signed value to the unsigned one. */ - rxtn->prand = (qse_awk_uint_t)(rxtn->seed * rxtn->seed * rxtn->seed); - /* make sure that the actual seeding is not 0 */ - if (rxtn->prand == 0) rxtn->prand++; - - r = qse_awk_rtx_makeintval (rtx, prev); - if (r == QSE_NULL) return -1; - - qse_awk_rtx_setretval (rtx, r); - return 0; -} - -static int fnc_system (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) -{ - qse_awk_val_t* v, * a0; - qse_char_t* str; - qse_size_t len; - int n = 0; - - a0 = qse_awk_rtx_getarg (rtx, 0); - str = qse_awk_rtx_getvalstr (rtx, a0, &len); - if (str == QSE_NULL) return -1; - - /* the target name contains a null character. - * make system return -1 */ - if (qse_strxchr (str, len, QSE_T('\0'))) - { - n = -1; - goto skip_system; - } - -#if defined(_WIN32) - n = _tsystem (str); -#elif defined(QSE_CHAR_IS_MCHAR) - n = system (str); -#else - - { - qse_mchar_t* mbs; - mbs = qse_wcstombsdup (str, QSE_NULL, rtx->awk->mmgr); - if (mbs == QSE_NULL) - { - n = -1; - goto skip_system; - } - n = system (mbs); - QSE_AWK_FREE (rtx->awk, mbs); - } - -#endif - -skip_system: - qse_awk_rtx_freevalstr (rtx, a0, str); - - v = qse_awk_rtx_makeintval (rtx, (qse_awk_int_t)n); - if (v == QSE_NULL) return -1; - - qse_awk_rtx_setretval (rtx, v); - return 0; -} static int timeout_code (const qse_char_t* name) { @@ -2407,11 +2281,14 @@ 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"), { {3, 3, QSE_T("vvr")}, fnc_getioattr, QSE_AWK_RIO } } + /* additional aliases to module functions */ + { QSE_T("rand"), { {1, 0, QSE_T("math")}, QSE_NULL, 0 } }, + { QSE_T("srand"), { {1, 0, QSE_T("math")}, QSE_NULL, 0 } }, + { QSE_T("system"), { {1, 0, QSE_T("sys")}, QSE_NULL , 0 } }, + + /* additional functions */ + { 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)