summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2015-01-06 14:20:19 -0500
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2015-01-06 14:20:19 -0500
commit9121c3059288f36e004108e02ed4d826b84604e7 (patch)
tree43448e2604b114c073e32e1155385f9536d12c90
parentcb5838c3c261f9a775fae45adfa70e1514e8bfe0 (diff)
downloadgawk-9121c3059288f36e004108e02ed4d826b84604e7.tar.gz
Fix bug so that extensions can create deferred arrays PROCINFO and ENVIRON properly.
-rw-r--r--ChangeLog13
-rw-r--r--awk.h1
-rw-r--r--awkgram.c36
-rw-r--r--awkgram.y36
-rw-r--r--gawkapi.c28
5 files changed, 76 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index f0c3dc4e..098031ab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+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.
+ (variable): Call new function variable_create if the variable is
+ not found.
+ * gawkapi.c (api_sym_update): If an array is being created, then
+ call new function variable_create instead of install_symbol. If this
+ is the first reference to a deferred variable, than the new array
+ may contain elements that must be merged into the array provided by
+ the extension.
+
2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
* io.c (wait_any): If the `interesting' argument is non-zero, then we
diff --git a/awk.h b/awk.h
index bb63f65a..5ecc13fa 100644
--- a/awk.h
+++ b/awk.h
@@ -1318,6 +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(int location, char *name, NODETYPE type);
extern int parse_program(INSTRUCTION **pcode);
extern void track_ext_func(const char *name);
diff --git a/awkgram.c b/awkgram.c
index adb31d9c..2257ee35 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -7052,6 +7052,20 @@ is_deferred_variable(const char *name)
return false;
}
+/* variable_create --- create a new variable */
+NODE *
+variable_create(char *name, NODETYPE type)
+{
+ struct deferred_variable *dv;
+
+ for (dv = deferred_variables; dv != NULL; dv = dv->next) {
+ if (strcmp(name, dv->name) == 0) {
+ efree(name);
+ return (*dv->load_func)();
+ }
+ }
+ return install_symbol(name, type);
+}
/* variable --- make sure NAME is in the symbol table */
@@ -7066,25 +7080,11 @@ variable(int location, char *name, NODETYPE type)
r->vname);
if (r == symbol_table)
symtab_used = true;
- } else {
- /* not found */
- struct deferred_variable *dv;
-
- for (dv = deferred_variables; true; dv = dv->next) {
- if (dv == NULL) {
- /*
- * This is the only case in which we may not free the string.
- */
- return install_symbol(name, type);
- }
- if (strcmp(name, dv->name) == 0) {
- r = (*dv->load_func)();
- break;
- }
- }
+ efree(name);
+ return r;
}
- efree(name);
- return r;
+ /* not found */
+ return variable_create(name, type);
}
/* process_deferred --- if the program uses SYMTAB, load deferred variables */
diff --git a/awkgram.y b/awkgram.y
index 52284af4..6575e0f0 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -4714,6 +4714,20 @@ is_deferred_variable(const char *name)
return false;
}
+/* variable_create --- create a new variable */
+NODE *
+variable_create(char *name, NODETYPE type)
+{
+ struct deferred_variable *dv;
+
+ for (dv = deferred_variables; dv != NULL; dv = dv->next) {
+ if (strcmp(name, dv->name) == 0) {
+ efree(name);
+ return (*dv->load_func)();
+ }
+ }
+ return install_symbol(name, type);
+}
/* variable --- make sure NAME is in the symbol table */
@@ -4728,25 +4742,11 @@ variable(int location, char *name, NODETYPE type)
r->vname);
if (r == symbol_table)
symtab_used = true;
- } else {
- /* not found */
- struct deferred_variable *dv;
-
- for (dv = deferred_variables; true; dv = dv->next) {
- if (dv == NULL) {
- /*
- * This is the only case in which we may not free the string.
- */
- return install_symbol(name, type);
- }
- if (strcmp(name, dv->name) == 0) {
- r = (*dv->load_func)();
- break;
- }
- }
+ efree(name);
+ return r;
}
- efree(name);
- return r;
+ /* not found */
+ return variable_create(name, type);
}
/* process_deferred --- if the program uses SYMTAB, load deferred variables */
diff --git a/gawkapi.c b/gawkapi.c
index a693621e..5630185c 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -579,10 +579,34 @@ 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;
+
array_node = awk_value_to_node(value);
- node = install_symbol(estrdup((char *) name, strlen(name)),
- Node_var_array);
+ /*
+ * use variable_create instead of install_symbol in
+ * 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 **list;
+ NODE akind;
+ unsigned long i;
+
+ akind.flags = (AINDEX|AVALUE);
+ list = node->alist(node, & akind);
+ for (i = 0; i < nel; i++) {
+ NODE **aptr;
+ aptr = assoc_lookup(array_node, list[2*i]);
+ unref(*aptr);
+ unref(list[2*i]); /* alist duped it */
+ *aptr = dupnode(list[2*i+1]);
+ }
+ efree(list);
+ assoc_clear(node);
+ }
*node = *array_node;
freenode(array_node);
value->array_cookie = node; /* pass new cookie back to extension */