diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | awk.h | 2 | ||||
-rw-r--r-- | awkgram.c | 7 | ||||
-rw-r--r-- | awkgram.y | 7 | ||||
-rw-r--r-- | extension/ChangeLog | 7 | ||||
-rw-r--r-- | extension/testext.c | 71 | ||||
-rw-r--r-- | gawkapi.c | 26 | ||||
-rw-r--r-- | test/ChangeLog | 9 | ||||
-rw-r--r-- | test/Makefile.am | 9 | ||||
-rw-r--r-- | test/Makefile.in | 9 | ||||
-rw-r--r-- | test/defvar.awk | 3 | ||||
-rw-r--r-- | test/defvar.ok | 5 |
12 files changed, 149 insertions, 18 deletions
@@ -1,5 +1,17 @@ 2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + * awk.h (variable_create): Now takes a 3rd argument to tell caller + whether this is a deferred variable. + * awkgram.y (variable_create): Return indicator of whether this is + a deferred variable in a newly added 3rd arg. + (variable): Pass 3rd arg to variable_create. + * gawkapi.c (api_sym_update): If we triggered the creation of a deferred + variable, we must merge the extension's array elements into the deffered + array, not the other way around. The ENVIRON array has special funcs + to call setenv and unsetenv. + +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + * awk.h (variable_create): Declare new function. * awkgram.y (variable_create): New function to create a variable taking the deferred variable list into consideration. @@ -1318,7 +1318,7 @@ extern NODE *do_asorti(int nargs); extern unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code); extern void init_env_array(NODE *env_node); /* awkgram.c */ -extern NODE *variable_create(char *name, NODETYPE type); +extern NODE *variable_create(char *name, NODETYPE type, bool *is_deferred); extern NODE *variable(int location, char *name, NODETYPE type); extern int parse_program(INSTRUCTION **pcode); extern void track_ext_func(const char *name); @@ -7054,16 +7054,18 @@ is_deferred_variable(const char *name) /* variable_create --- create a new variable */ NODE * -variable_create(char *name, NODETYPE type) +variable_create(char *name, NODETYPE type, bool *is_deferred) { struct deferred_variable *dv; for (dv = deferred_variables; dv != NULL; dv = dv->next) { if (strcmp(name, dv->name) == 0) { efree(name); + *is_deferred = true; return (*dv->load_func)(); } } + *is_deferred = false; return install_symbol(name, type); } @@ -7073,6 +7075,7 @@ NODE * variable(int location, char *name, NODETYPE type) { NODE *r; + bool is_deferred; if ((r = lookup(name)) != NULL) { if (r->type == Node_func || r->type == Node_ext_func ) @@ -7084,7 +7087,7 @@ variable(int location, char *name, NODETYPE type) return r; } /* not found */ - return variable_create(name, type); + return variable_create(name, type, & is_deferred); } /* process_deferred --- if the program uses SYMTAB, load deferred variables */ @@ -4716,16 +4716,18 @@ is_deferred_variable(const char *name) /* variable_create --- create a new variable */ NODE * -variable_create(char *name, NODETYPE type) +variable_create(char *name, NODETYPE type, bool *is_deferred) { struct deferred_variable *dv; for (dv = deferred_variables; dv != NULL; dv = dv->next) { if (strcmp(name, dv->name) == 0) { efree(name); + *is_deferred = true; return (*dv->load_func)(); } } + *is_deferred = false; return install_symbol(name, type); } @@ -4735,6 +4737,7 @@ NODE * variable(int location, char *name, NODETYPE type) { NODE *r; + bool is_deferred; if ((r = lookup(name)) != NULL) { if (r->type == Node_func || r->type == Node_ext_func ) @@ -4746,7 +4749,7 @@ variable(int location, char *name, NODETYPE type) return r; } /* not found */ - return variable_create(name, type); + return variable_create(name, type, & is_deferred); } /* process_deferred --- if the program uses SYMTAB, load deferred variables */ diff --git a/extension/ChangeLog b/extension/ChangeLog index 617cc033..c8f77042 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,10 @@ +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.c (test_deferred): New function to help with testing + of deferred variable instantiation. + (do_get_file): Remove unused variable array. + (func_table): Add test_deferred. + 2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> * testext.c (test_get_file): Fix error message. diff --git a/extension/testext.c b/extension/testext.c index c931ed39..7c61bb0d 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -374,6 +374,75 @@ out: return result; } +static awk_value_t * +test_deferred(int nargs, awk_value_t *result) +{ + awk_value_t arr; + awk_value_t index, value; + const struct nval { + const char *name; + double val; + } seed[] = { + { "fubar", 9.0, }, + { "rumpus", -5.0, }, + }; + struct nval sysval[] = { + { "uid", getuid(), }, + { "api_major", GAWK_API_MAJOR_VERSION, }, + }; + size_t i; + + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 0) { + printf("test_deferred: nargs not right (%d should be 0)\n", nargs); + goto out; + } + arr.val_type = AWK_ARRAY; + arr.array_cookie = create_array(); + + for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) { + make_const_string(seed[i].name, strlen(seed[i].name), & index); + make_number(seed[i].val, & value); + if (! set_array_element(arr.array_cookie, & index, & value)) { + printf("test_deferred: %d: set_array_element(%s) failed\n", __LINE__, seed[i].name); + goto out; + } + } + + if (! sym_update("PROCINFO", & arr)) { + printf("test_deferred: %d: sym_update failed\n", __LINE__); + goto out; + } + + /* test that it still contains the values we loaded */ + for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) { + make_const_string(seed[i].name, strlen(seed[i].name), & index); + make_null_string(& value); + if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) { + printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, seed[i].name); + goto out; + } + printf("%s = %g\n", seed[i].name, value.num_value); + } + + /* check a few automatically-supplied values */ + for (i = 0; i < sizeof(sysval)/sizeof(sysval[0]); i++) { + make_const_string(sysval[i].name, strlen(sysval[i].name), & index); + make_null_string(& value); + if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) { + printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, sysval[i].name); + goto out; + } + printf("%s matches %d\n", sysval[i].name, (value.num_value == sysval[i].val)); + } + + make_number(1.0, result); +out: + return result; +} + /* BEGIN { for (i = 1; i <= 10; i++) @@ -809,7 +878,6 @@ do_get_file(int nargs, awk_value_t *result) awk_value_t filename, filetype, fd, res; const awk_input_buf_t *ibuf; const awk_output_buf_t *obuf; - awk_array_t array; if (nargs != 4) { printf("%s: nargs not right (%d should be 4)\n", "get_file", nargs); @@ -950,6 +1018,7 @@ static awk_ext_func_t func_table[] = { { "dump_array_and_delete", dump_array_and_delete, 2 }, { "try_modify_environ", try_modify_environ, 0 }, { "var_test", var_test, 1 }, + { "test_deferred", test_deferred, 0 }, { "test_errno", test_errno, 0 }, { "test_array_size", test_array_size, 1 }, { "test_array_elem", test_array_elem, 2 }, @@ -579,7 +579,7 @@ api_sym_update(awk_ext_id_t id, if (node == NULL) { /* new value to be installed */ if (value->val_type == AWK_ARRAY) { - unsigned long nel; + bool is_deferred; array_node = awk_value_to_node(value); /* @@ -587,27 +587,35 @@ api_sym_update(awk_ext_id_t id, * case this is a deferred variable such as PROCINFO * or ENVIRON */ - node = variable_create(estrdup((char *) name, strlen(name)), Node_var_array); - array_node->vname = node->vname; - if ((nel = assoc_length(node)) > 0) { - /* merge the 2 arrays */ + node = variable_create(estrdup((char *) name, strlen(name)), Node_var_array, & is_deferred); + if (is_deferred) { + /* + * merge the user-supplied elements into the + * already-existing array. Since ENVIRON + * has special array_funcs, we need to retain + * the auto-created array! + */ + unsigned long nel; NODE **list; NODE akind; unsigned long i; + nel = assoc_length(array_node); akind.flags = (AINDEX|AVALUE); - list = node->alist(node, & akind); + list = array_node->alist(array_node, & akind); for (i = 0; i < nel; i++) { NODE **aptr; - aptr = assoc_lookup(array_node, list[2*i]); + aptr = assoc_lookup(node, list[2*i]); unref(*aptr); unref(list[2*i]); /* alist duped it */ *aptr = dupnode(list[2*i+1]); } efree(list); - assoc_clear(node); + assoc_clear(array_node); + } else { + array_node->vname = node->vname; + *node = *array_node; } - *node = *array_node; freenode(array_node); value->array_cookie = node; /* pass new cookie back to extension */ } else { diff --git a/test/ChangeLog b/test/ChangeLog index 0fa59a65..7522f7aa 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,7 +1,14 @@ +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add defvar.awk and defvar.ok. + (SHLIB_TESTS): Add defvar. + (defvar): New test. + * defvar.awk, defvar.ok: New files. + 2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> * Makefile.am (EXTRA_DIST): Add getfile.awk and getfile.ok. - (SHLIB_TESTS): Add gefile. + (SHLIB_TESTS): Add getfile. (getfile): New test. * getfile.awk, getfile.ok: New files. diff --git a/test/Makefile.am b/test/Makefile.am index c31e8823..3d95f4cc 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -174,6 +174,8 @@ EXTRA_DIST = \ dbugeval.ok \ defref.awk \ defref.ok \ + defvar.awk \ + defvar.ok \ delargv.awk \ delargv.ok \ delarpm2.awk \ @@ -1059,7 +1061,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ + defvar fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time # List of the tests which should be run with --lint option: @@ -1900,6 +1902,11 @@ testext:: @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk +defvar: + @echo $@ + @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + getfile: @echo $@ @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Makefile.in b/test/Makefile.in index 1ab2c8a8..d2492d32 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -421,6 +421,8 @@ EXTRA_DIST = \ dbugeval.ok \ defref.awk \ defref.ok \ + defvar.awk \ + defvar.ok \ delargv.awk \ delargv.ok \ delarpm2.awk \ @@ -1302,7 +1304,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ + defvar fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time @@ -2325,6 +2327,11 @@ testext:: @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk +defvar: + @echo $@ + @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + getfile: @echo $@ @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/defvar.awk b/test/defvar.awk new file mode 100644 index 00000000..444b81c9 --- /dev/null +++ b/test/defvar.awk @@ -0,0 +1,3 @@ +BEGIN { + print "test_deferred returns", test_deferred() +} diff --git a/test/defvar.ok b/test/defvar.ok new file mode 100644 index 00000000..4c85427e --- /dev/null +++ b/test/defvar.ok @@ -0,0 +1,5 @@ +fubar = 9 +rumpus = -5 +uid matches 1 +api_major matches 1 +test_deferred returns 1 |