aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--awk.h1
-rw-r--r--extension/ChangeLog6
-rw-r--r--extension/testext.c151
-rw-r--r--gawkapi.c19
-rw-r--r--gawkapi.h10
-rw-r--r--test/ChangeLog4
-rw-r--r--test/testext.ok11
8 files changed, 202 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 2598c307..d7290276 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-09-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ Allow read-only access to built-in variables from extensions.
+
+ * awk.h (NO_EXT_SET): New flag.
+ * gawkapi.c (api_sym_lookup, api_sym_update_real): Set flag if off
+ limits variable instead of failing. Adjust logic.
+ (api_sym_update_scalar, api_set_array_element, api_del_array_element,
+ api_release_flattened_array): Adjust logic.
+ * gawkapi.h: Adjust documentation.
+
2012-09-13 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac: Determination of DYNAMIC adjusted. Hopefully is
diff --git a/awk.h b/awk.h
index de425290..b0208e54 100644
--- a/awk.h
+++ b/awk.h
@@ -447,6 +447,7 @@ typedef struct exp_node {
# define WSTRCUR 0x0400 /* wide str value is current */
# define MPFN 0x0800 /* arbitrary-precision floating-point number */
# define MPZN 0x1000 /* arbitrary-precision integer */
+# define NO_EXT_SET 0x2000 /* extension cannot set a value for this variable */
/* type = Node_var_array */
# define ARRAYMAXED 0x2000 /* array is at max size */
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 1a32961a..2552a383 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,9 @@
+2012-09-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testext.c (try_modify_environ): New function and test.
+ (var_test): Modified ARGC test, added additional.
+ (test_scalar_reserved): New function and test.
+
2012-09-13 Dave Pitts <dpitts@cozx.com>
* gawkfts.c: Add defines and ifdefs for z/OS.
diff --git a/extension/testext.c b/extension/testext.c
index bb62fa01..c11a4c85 100644
--- a/extension/testext.c
+++ b/extension/testext.c
@@ -186,6 +186,101 @@ out:
/*
BEGIN {
+ ENVIRON["testext"]++
+ try_modify_environ()
+ if ("testext" in ENVIRON)
+ print "try_del_environ() could not delete element - pass"
+ else
+ print "try_del_environ() deleted element! - fail"
+ if ("testext2" in ENVIRON)
+ print "try_del_environ() added an element - fail"
+ else
+ print "try_del_environ() could not add an element - pass"
+}
+*/
+
+static awk_value_t *
+try_modify_environ(int nargs, awk_value_t *result)
+{
+ awk_value_t value, index, newvalue;
+ awk_flat_array_t *flat_array;
+ size_t count;
+ int i;
+
+ assert(result != NULL);
+ make_number(0.0, result);
+
+ if (nargs != 0) {
+ printf("try_modify_environ: nargs not right (%d should be 0)\n", nargs);
+ goto out;
+ }
+
+ /* get ENVIRON array */
+ if (sym_lookup("ENVIRON", AWK_ARRAY, & value))
+ printf("try_modify_environ: sym_lookup of ENVIRON passed\n");
+ else {
+ printf("try_modify_environ: sym_lookup of ENVIRON failed\n");
+ goto out;
+ }
+
+ if (! get_element_count(value.array_cookie, & count)) {
+ printf("try_modify_environ: get_element_count failed\n");
+ goto out;
+ }
+
+ printf("try_modify_environ: incoming size is %lu\n", (unsigned long) count);
+
+ /* setting an array element should fail */
+ (void) make_const_string("testext2", 8, & index);
+ (void) make_const_string("a value", 7, & value);
+ if (set_array_element(value.array_cookie, & index, & newvalue)) {
+ printf("try_modify_environ: set_array_element of ENVIRON passed\n");
+ } else {
+ printf("try_modify_environ: set_array_element of ENVIRON failed\n");
+ free(index.str_value.str);
+ free(value.str_value.str);
+ }
+
+ if (! flatten_array(value.array_cookie, & flat_array)) {
+ printf("try_modify_environ: could not flatten array\n");
+ goto out;
+ }
+
+ if (flat_array->count != count) {
+ printf("try_modify_environ: flat_array->count (%lu) != count (%lu)\n",
+ (unsigned long) flat_array->count,
+ (unsigned long) count);
+ goto out;
+ }
+
+ for (i = 0; i < flat_array->count; i++) {
+ /* don't print */
+ /*
+ printf("\t%s[\"%.*s\"] = %s\n",
+ name,
+ (int) flat_array->elements[i].index.str_value.len,
+ flat_array->elements[i].index.str_value.str,
+ valrep2str(& flat_array->elements[i].value));
+ */
+ if (strcmp("testext", flat_array->elements[i].index.str_value.str) == 0) {
+ flat_array->elements[i].flags |= AWK_ELEMENT_DELETE;
+ printf("try_modify_environ: marking element \"%s\" for deletion\n",
+ flat_array->elements[i].index.str_value.str);
+ }
+ }
+
+ if (! release_flattened_array(value.array_cookie, flat_array)) {
+ printf("try_modify_environ: could not release flattened array\n");
+ goto out;
+ }
+
+ make_number(1.0, result);
+out:
+ return result;
+}
+
+/*
+BEGIN {
testvar = "One Adam Twelve"
ret = var_test("testvar")
printf "var_test() returned %d, test_var = %s\n", ret, testvar
@@ -207,11 +302,18 @@ var_test(int nargs, awk_value_t *result)
goto out;
}
- /* look up a reserved variable - should fail */
+ /* look up a reserved variable - should pass */
if (sym_lookup("ARGC", AWK_NUMBER, & value))
- printf("var_test: sym_lookup of ARGC failed - got a value!\n");
+ printf("var_test: sym_lookup of ARGC passed - got a value!\n");
+ else
+ printf("var_test: sym_lookup of ARGC failed - did not get a value\n");
+
+ /* now try to set it - should fail */
+ value.num_value++;
+ if (sym_update("ARGC", & value))
+ printf("var_test: sym_update of ARGC passed and should not have!\n");
else
- printf("var_test: sym_lookup of ARGC passed - did not get a value\n");
+ printf("var_test: sym_update of ARGC failed - correctly\n");
/* look up variable whose name is passed in, should pass */
if (get_argument(0, AWK_STRING, & value)) {
@@ -535,6 +637,47 @@ test_scalar(int nargs, awk_value_t *result)
}
if (! sym_update_scalar(the_scalar.scalar_cookie, & new_value2)) {
+ printf("test_scalar: could not update new_value2!\n");
+ goto out;
+ }
+
+ make_number(1.0, result);
+
+out:
+ return result;
+}
+
+/*
+BEGIN {
+ test_scalar_reserved()
+}
+*/
+
+/* test_scalar_reserved --- test scalar cookie on special variable */
+
+static awk_value_t *
+test_scalar_reserved(int nargs, awk_value_t *result)
+{
+ awk_value_t new_value;
+ awk_value_t the_scalar;
+
+ make_number(0.0, result);
+
+ /* look up a reserved variable - should pass */
+ if (sym_lookup("ARGC", AWK_SCALAR, & the_scalar)) {
+ printf("test_scalar_reserved: sym_lookup of ARGC passed - got a value!\n");
+ } else {
+ printf("test_scalar_reserved: sym_lookup of ARGC failed - did not get a value\n");
+ goto out;
+ }
+
+ /* updating it should fail */
+ make_number(42.0, & new_value);
+ if (! sym_update_scalar(the_scalar.scalar_cookie, & new_value)) {
+ printf("test_scalar_reserved: could not update new_value2 for ARGC - pass\n");
+ } else {
+ printf("test_scalar_reserved: was able to update new_value2 for ARGC - fail\n");
+ goto out;
}
make_number(1.0, result);
@@ -628,6 +771,7 @@ static void at_exit2(void *data, int exit_status)
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_errno", test_errno, 0 },
{ "test_array_size", test_array_size, 1 },
@@ -635,6 +779,7 @@ static awk_ext_func_t func_table[] = {
{ "test_array_param", test_array_param, 1 },
{ "print_do_lint", print_do_lint, 0 },
{ "test_scalar", test_scalar, 1 },
+ { "test_scalar_reserved", test_scalar_reserved, 0 },
};
/* init_testext --- additional initialization function */
diff --git a/gawkapi.c b/gawkapi.c
index 5d372bbe..dbb8549b 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -489,10 +489,12 @@ api_sym_lookup(awk_ext_id_t id,
if ( name == NULL
|| *name == '\0'
|| result == NULL
- || is_off_limits_var(name) /* most built-in vars not allowed */
|| (node = lookup(name)) == NULL)
return false;
+ if (is_off_limits_var(name)) /* a built-in variable */
+ node->flags |= NO_EXT_SET;
+
return node_to_awk_value(node, result, wanted);
}
@@ -527,7 +529,6 @@ sym_update_real(awk_ext_id_t id,
if ( name == NULL
|| *name == '\0'
- || is_off_limits_var(name) /* most built-in vars not allowed */
|| value == NULL)
return false;
@@ -573,6 +574,12 @@ sym_update_real(awk_ext_id_t id,
* If we get here, then it exists already. Any valid type is
* OK except for AWK_ARRAY.
*/
+ if ( (node->flags & NO_EXT_SET) != 0
+ || is_off_limits_var(name)) { /* most built-in vars not allowed */
+ node->flags |= NO_EXT_SET;
+ return false;
+ }
+
if ( value->val_type != AWK_ARRAY
&& (node->type == Node_var || node->type == Node_var_new)) {
unref(node->var_value);
@@ -618,7 +625,8 @@ api_sym_update_scalar(awk_ext_id_t id,
if (value == NULL
|| node == NULL
- || node->type != Node_var)
+ || node->type != Node_var
+ || (node->flags & NO_EXT_SET) != 0)
return false;
/*
@@ -766,6 +774,7 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie,
/* don't check for index len zero, null str is ok as index */
if ( array == NULL
|| array->type != Node_var_array
+ || (array->flags & NO_EXT_SET) != 0
|| index == NULL
|| value == NULL
|| ! valid_subscript_type(index->val_type))
@@ -825,6 +834,7 @@ api_del_array_element(awk_ext_id_t id,
array = (NODE *) a_cookie;
if ( array == NULL
|| array->type != Node_var_array
+ || (array->flags & NO_EXT_SET) != 0
|| index == NULL
|| ! valid_subscript_type(index->val_type))
return false;
@@ -957,7 +967,8 @@ api_release_flattened_array(awk_ext_id_t id,
/* free index nodes */
for (i = j = 0, k = 2 * array->table_size; i < k; i += 2, j++) {
/* Delete items flagged for delete. */
- if ((data->elements[j].flags & AWK_ELEMENT_DELETE) != 0) {
+ if ( (data->elements[j].flags & AWK_ELEMENT_DELETE) != 0
+ && (array->flags & NO_EXT_SET) == 0) {
remove_element(array, list[i]);
}
unref(list[i]);
diff --git a/gawkapi.h b/gawkapi.h
index 95effd9a..e8b7ebff 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -447,8 +447,8 @@ typedef struct gawk_api {
* or if the wrong type was requested.
* In the latter case, fills in vaule->val_type with the real type,
* as described above.
- * Built-in variables (except PROCINFO) may not be accessed by an
- * extension.
+ * Built-in variables may be accessed by an extension, but, with
+ * the exception of PROCINFO, they may not be modified.
*
* awk_value_t val;
* if (! api->sym_lookup(id, name, wanted, & val))
@@ -495,13 +495,15 @@ typedef struct gawk_api {
* Flow is
* sym_lookup with wanted == AWK_SCALAR
* if returns false
- * sym_update with real initial value
+ * sym_update with real initial value to install it
* sym_lookup again with AWK_SCALAR
* else
* use the scalar cookie
*
* Return will be false if the new value is not one of
* AWK_STRING or AWK_NUMBER.
+ *
+ * Here too, the built-in variables may not be updated.
*/
awk_bool_t (*api_sym_update_scalar)(awk_ext_id_t id,
awk_scalar_t cookie, awk_value_t *value);
@@ -522,6 +524,8 @@ typedef struct gawk_api {
/*
* Change (or create) element in existing array with
* element->index and element->value.
+ *
+ * ARGV and ENVIRON may not be updated.
*/
awk_bool_t (*api_set_array_element)(awk_ext_id_t id, awk_array_t a_cookie,
const awk_value_t *const index,
diff --git a/test/ChangeLog b/test/ChangeLog
index ff992365..4bab4796 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,7 @@
+2012-09-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testext.ok: Updated.
+
2012-09-11 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (shlib-tests): Check if DYNAMIC is enabled and
diff --git a/test/testext.ok b/test/testext.ok
index 132179c2..d291f721 100644
--- a/test/testext.ok
+++ b/test/testext.ok
@@ -10,7 +10,14 @@ dump_array_and_delete: marking element "3" for deletion
dump_array_and_delete(pets) returned 1
dump_array_and_delete() did remove index "3"!
-var_test: sym_lookup of ARGC passed - did not get a value
+try_modify_environ: sym_lookup of ENVIRON passed
+try_modify_environ: incoming size is 60
+try_modify_environ: set_array_element of ENVIRON failed
+try_modify_environ: could not flatten array
+try_del_environ() could not delete element - pass
+try_del_environ() could not add an element - pass
+var_test: sym_lookup of ARGC passed - got a value!
+var_test: sym_update of ARGC failed - correctly
var_test: sym_update("testvar") succeeded
var_test() returned 1, test_var = 42
@@ -57,6 +64,8 @@ test_scalar(over) returned 1, the_scalar is over
test_scalar(the) returned 1, the_scalar is the
test_scalar(lazy) returned 1, the_scalar is lazy
test_scalar(dog) returned 1, the_scalar is dog
+test_scalar_reserved: sym_lookup of ARGC passed - got a value!
+test_scalar_reserved: could not update new_value2 for ARGC - pass
answer_num = 42
message_string = hello, world
new_array["hello"] = "world"