From 2624acb30804d8c465f81c34c89b6d1e67c8b826 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 7 Jan 2013 08:33:48 +0000 Subject: [PATCH] enhanced Awk and StdAwk to be able to handle argument reference --- qse/include/qse/awk/Awk.hpp | 3 +- qse/include/qse/awk/StdAwk.hpp | 10 ++-- qse/lib/awk/Awk.cpp | 86 +++++++++++++++++++++------------- qse/lib/awk/StdAwk.cpp | 80 ++++++++++++++----------------- qse/lib/awk/std.c | 6 +-- qse/lib/awk/val.c | 9 ++-- qse/samples/awk/awk08.cpp | 12 ++--- 7 files changed, 108 insertions(+), 98 deletions(-) diff --git a/qse/include/qse/awk/Awk.hpp b/qse/include/qse/awk/Awk.hpp index b4d38a80..a253fe92 100644 --- a/qse/include/qse/awk/Awk.hpp +++ b/qse/include/qse/awk/Awk.hpp @@ -1085,7 +1085,7 @@ public: typedef int (Awk::*FunctionHandler) ( Run& run, Value& ret, - const Value* args, + Value* args, size_t nargs, const fnc_info_t* fi ); @@ -1098,6 +1098,7 @@ public: const char_t* name, ///< function name size_t minArgs, ///< minimum numbers of arguments size_t maxArgs, ///< maximum numbers of arguments + const char_t* argSpec, ///< argument specification FunctionHandler handler, ///< function handler int validOpts = 0 ///< valid if these options are set ); diff --git a/qse/include/qse/awk/StdAwk.hpp b/qse/include/qse/awk/StdAwk.hpp index e21797b4..f5332e0f 100644 --- a/qse/include/qse/awk/StdAwk.hpp +++ b/qse/include/qse/awk/StdAwk.hpp @@ -142,18 +142,18 @@ protected: int __build_environ (Run* run, void* envptr); // intrinsic functions - int rand (Run& run, Value& ret, const Value* args, size_t nargs, + int rand (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len); - int srand (Run& run, Value& ret, const Value* args, size_t nargs, + int srand (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len); - int system (Run& run, Value& ret, const Value* args, size_t nargs, + 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, const Value* args, size_t nargs, + int setioattr (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len); - int getioattr (Run& run, Value& ret, const Value* args, size_t nargs, + int getioattr (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len); // pipe io handlers diff --git a/qse/lib/awk/Awk.cpp b/qse/lib/awk/Awk.cpp index 44100059..6fe7e631 100644 --- a/qse/lib/awk/Awk.cpp +++ b/qse/lib/awk/Awk.cpp @@ -23,9 +23,6 @@ #include "../cmn/mem.h" #include "awk.h" -// enable this once addFunction() is extended with argument spec (rxv...). -//#define PASS_BY_REFERENCE - ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// @@ -1359,6 +1356,7 @@ void Awk::setMaxDepth (depth_t id, size_t depth) int Awk::dispatch_function (Run* run, const fnc_info_t* fi) { pair_t* pair; + bool has_ref_arg = false; pair = qse_htb_search (functionMap, fi->name.ptr, fi->name.len); if (pair == QSE_NULL) @@ -1387,24 +1385,51 @@ int Awk::dispatch_function (Run* run, const fnc_info_t* fi) for (i = 0; i < nargs; i++) { + int xx; val_t* v = qse_awk_rtx_getarg (run->rtx, i); -#ifdef PASS_BY_REFERENCE - QSE_ASSERT (v->type == QSE_AWK_VAL_REF); - val_t** ref = (val_t**)((qse_awk_val_ref_t*)v)->adr; - if (args[i].setVal (run, *ref) == -1) + + if (v->type == QSE_AWK_VAL_REF) + { + qse_awk_val_ref_t* ref = (qse_awk_val_ref_t*)v; + + if (ref->id == qse_awk_val_ref_t::QSE_AWK_VAL_REF_POS) + { + qse_size_t idx = (qse_size_t)ref->adr; + + if (idx == 0) + { + xx = args[i].setStr (run, + QSE_STR_PTR(&run->rtx->inrec.line), + QSE_STR_LEN(&run->rtx->inrec.line)); + } + else if (idx <= run->rtx->inrec.nflds) + { + xx = args[i].setStr (run, + run->rtx->inrec.flds[idx-1].ptr, + run->rtx->inrec.flds[idx-1].len); + } + else + { + xx = args[i].setStr (run, QSE_T(""), 0); + } + } + else + { + xx = args[i].setVal (run, *(ref->adr)); + } + has_ref_arg = true; + } + else + { + xx = args[i].setVal (run, v); + } + + if (xx <= -1) { run->setError (QSE_AWK_ENOMEM); if (args != buf) delete[] args; return -1; } -#else - if (args[i].setVal (run, v) == -1) - { - run->setError (QSE_AWK_ENOMEM); - if (args != buf) delete[] args; - return -1; - } -#endif } Value ret (run); @@ -1414,28 +1439,25 @@ int Awk::dispatch_function (Run* run, const fnc_info_t* fi) try { n = (this->*handler) (*run, ret, args, nargs, fi); } catch (...) { n = -1; } -#ifdef PASS_BY_REFERENCE - if (n >= 0) + if (n >= 0 && has_ref_arg) { for (i = 0; i < nargs; i++) { QSE_ASSERTX (args[i].run == run, - "Do NOT change Run from function handler"); + "Do NOT change the run field from function handler"); val_t* v = qse_awk_rtx_getarg (run->rtx, i); - val_t* nv = args[i].toVal(); - - if (nv == v) continue; - - QSE_ASSERT (v->type == QSE_AWK_VAL_REF); - val_t** ref = (val_t**)((qse_awk_val_ref_t*)v)->adr; - - qse_awk_rtx_refdownval (run->rtx, *ref); - *ref = nv; - qse_awk_rtx_refupval (run->rtx, *ref); + if (v->type == QSE_AWK_VAL_REF) + { + if (qse_awk_rtx_setrefval (run->rtx, (qse_awk_val_ref_t*)v, args[i].toVal()) <= -1) + { + n = -1; + break; + } + } } } -#endif + if (args != buf) delete[] args; if (n <= -1) @@ -1559,7 +1581,7 @@ int Awk::getGlobal (int id, Value& v) int Awk::addFunction ( const char_t* name, size_t minArgs, size_t maxArgs, - FunctionHandler handler, int validOpts) + const char_t* argSpec, FunctionHandler handler, int validOpts) { QSE_ASSERT (awk != QSE_NULL); @@ -1578,9 +1600,7 @@ int Awk::addFunction ( QSE_MEMSET (&spec, 0, QSE_SIZEOF(spec)); spec.arg.min = minArgs; spec.arg.max = maxArgs; -#ifdef PASS_BY_REFERENCE - spec.arg.spec = QSE_T("R"); // pass all arguments by reference -#endif + spec.arg.spec = argSpec; spec.impl = functionHandler; spec.trait = validOpts; diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp index 8aef7c05..f95c4779 100644 --- a/qse/lib/awk/StdAwk.cpp +++ b/qse/lib/awk/StdAwk.cpp @@ -73,17 +73,6 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// -#define ADDFNC(name,min,max,impl,vopts) \ - do { \ - if (addFunction (name, min, max, \ - (FunctionHandler)impl, vopts) == -1) \ - { \ - Awk::close (); \ - return -1; \ - } \ - } while (0) - - StdAwk::ioattr_t StdAwk::default_ioattr; static qse_sio_t* open_sio (Awk* awk, StdAwk::Run* run, const qse_char_t* file, int flags) @@ -141,11 +130,11 @@ int StdAwk::open () goto oops; } - if (addFunction (QSE_T("rand"), 0, 0, (FunctionHandler)&StdAwk::rand, 0) <= -1 || - addFunction (QSE_T("srand"), 0, 1, (FunctionHandler)&StdAwk::srand, 0) <= -1 || - addFunction (QSE_T("system"), 1, 1, (FunctionHandler)&StdAwk::system, 0) <= -1 || - addFunction (QSE_T("setioattr"), 3, 3, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 || - addFunction (QSE_T("getioattr"), 2, 2, (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1) + 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) { goto oops; } @@ -348,7 +337,7 @@ int StdAwk::make_additional_globals (Run* run) return 0; } -int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs, +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(long_t) @@ -358,7 +347,7 @@ int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs, #undef RANDV_MAX } -int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs, +int StdAwk::srand (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { long_t prevSeed = (long_t)this->seed; @@ -384,7 +373,7 @@ int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs, return ret.setInt ((long_t)prevSeed); } -int StdAwk::system (Run& run, Value& ret, const Value* args, size_t nargs, +int StdAwk::system (Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { size_t l; @@ -457,7 +446,7 @@ static int timeout_code (const qse_char_t* name) } int StdAwk::setioattr ( - Run& run, Value& ret, const Value* args, size_t nargs, + Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { QSE_ASSERT (this->cmgrtab_inited == true); @@ -531,7 +520,7 @@ int StdAwk::setioattr ( } int StdAwk::getioattr ( - Run& run, Value& ret, const Value* args, size_t nargs, + Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { QSE_ASSERT (this->cmgrtab_inited == true); @@ -541,34 +530,33 @@ int StdAwk::getioattr ( ptr[0] = args[0].toStr(&l[0]); ptr[1] = args[1].toStr(&l[1]); - if (qse_strxchr (ptr[0], l[0], QSE_T('\0')) || - qse_strxchr (ptr[1], l[1], QSE_T('\0'))) + int xx = -1; + + /* ionames must not contains a null character */ + if (qse_strxchr (ptr[0], l[0], QSE_T('\0')) == QSE_NULL && + qse_strxchr (ptr[1], l[1], QSE_T('\0')) == QSE_NULL) { - return ret.setInt ((long_t)-1); + ioattr_t* ioattr = get_ioattr (ptr[0], l[0]); + if (ioattr == QSE_NULL) ioattr = &StdAwk::default_ioattr; + + int tmout; + if ((tmout = timeout_code(ptr[1])) >= 0) + { + if (ioattr->tmout[tmout].nsec == 0) + xx = args[2].setInt ((long_t)ioattr->tmout[tmout].sec); + else + xx = args[2].setFlt ((qse_flt_t)ioattr->tmout[tmout].sec + QSE_NSEC_TO_SEC((qse_flt_t)ioattr->tmout[tmout].nsec)); + } + #if defined(QSE_CHAR_IS_WCHAR) + else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0) + { + xx = args[2].setStr (ioattr->cmgr_name); + } + #endif } - ioattr_t* ioattr = get_ioattr (ptr[0], l[0]); - if (ioattr == QSE_NULL) ioattr = &StdAwk::default_ioattr; - - int tmout; - if ((tmout = timeout_code(ptr[1])) >= 0) - { - if (ioattr->tmout[tmout].nsec == 0) - return ret.setInt ((long_t)ioattr->tmout[tmout].sec); - else - return ret.setFlt ((qse_flt_t)ioattr->tmout[tmout].sec + QSE_NSEC_TO_SEC((qse_flt_t)ioattr->tmout[tmout].nsec)); - } -#if defined(QSE_CHAR_IS_WCHAR) - else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0) - { - return ret.setStr (ioattr->cmgr_name); - } -#endif - else - { - // unknown attribute name - return ret.setInt ((long_t)-1); - } + // unknown attribute name or errors + return ret.setInt ((long_t)xx); } int StdAwk::open_nwio (Pipe& io, int flags, void* nwad) diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 48ad24da..d1ecbe07 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -2520,15 +2520,13 @@ done: while (i > 0) { i--; - if (v[i]->type != QSE_AWK_VAL_STR) - QSE_AWK_FREE (rtx->awk, ptr[i]); + if (v[i]->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, ptr[i]); } if (ret >= 0) { - if (rv) + if (rv && qse_awk_rtx_setrefval (rtx, qse_awk_rtx_getarg (rtx, 2), rv) >= 0) { - qse_awk_rtx_setrefval (rtx, qse_awk_rtx_getarg (rtx, 2), rv); qse_awk_rtx_setretval (rtx, qse_awk_val_zero); } else diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index 4a27e554..8f808524 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -1703,9 +1703,12 @@ 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); + if (*rref != val) + { + qse_awk_rtx_refdownval (rtx, *rref); + *rref = val; + qse_awk_rtx_refupval (rtx, *rref); + } return 0; } } diff --git a/qse/samples/awk/awk08.cpp b/qse/samples/awk/awk08.cpp index 13768dea..51a0b432 100644 --- a/qse/samples/awk/awk08.cpp +++ b/qse/samples/awk/awk08.cpp @@ -58,13 +58,13 @@ public: /* this is for demonstration only. * you can use sys::sleep() instead */ - if (addFunction (QSE_T("sleep"), 1, 1, + if (addFunction (QSE_T("sleep"), 1, 1, QSE_NULL, (FunctionHandler)&MyAwk::sleep) <= -1) goto oops; - if (addFunction (QSE_T("sumintarray"), 1, 1, + if (addFunction (QSE_T("sumintarray"), 1, 1, QSE_NULL, (FunctionHandler)&MyAwk::sumintarray) <= -1) goto oops; - if (addFunction (QSE_T("arrayindices"), 1, 1, + if (addFunction (QSE_T("arrayindices"), 1, 1, QSE_NULL, (FunctionHandler)&MyAwk::arrayindices) <= -1) goto oops; return 0; @@ -75,7 +75,7 @@ public: } int sleep ( - Run& run, Value& ret, const Value* args, size_t nargs, + Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { if (args[0].isIndexed()) @@ -106,7 +106,7 @@ public: } int sumintarray ( - Run& run, Value& ret, const Value* args, size_t nargs, + Run& run, Value& ret, Value* args, size_t nargs, const char_t* name, size_t len) { // BEGIN { @@ -138,7 +138,7 @@ public: int arrayindices ( Run& run, Value& ret, - const Value* args, + Value* args, size_t nargs, const char_t* name, size_t len)