diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | extension/ChangeLog | 8 | ||||
-rw-r--r-- | extension/filefuncs.c | 2 | ||||
-rw-r--r-- | extension/fork.c | 2 | ||||
-rw-r--r-- | extension/testext.c | 137 | ||||
-rw-r--r-- | gawkapi.c | 80 | ||||
-rw-r--r-- | gawkapi.h | 37 | ||||
-rw-r--r-- | test/ChangeLog | 2 | ||||
-rw-r--r-- | test/testext.ok | 10 |
9 files changed, 234 insertions, 50 deletions
@@ -1,9 +1,15 @@ 2012-06-18 Arnold D. Robbins <arnold@skeeve.com> * gawkapi.h (get_array_element): Restore `wanted' paramater. + (awk_element_t): Use awk_value_t for index. Add awk_flat_array_t. + (flatten_array): Change signature to use awk_flat_array_t; + (release_flattened_array): Change signature to use awk_flat_array_t; * gawkapi.c (api_sym_update): Handle case where variable exists already. (api_get_array_element): Restore `wanted' paramater and pass it on to node_to_awk_value. + (api_set_array_element): Revisse to match changed element type. + (api_flatten_array): Revise signature, implement. + (api_release_flattened_array): Revise signature, implement. 2012-06-17 Arnold D. Robbins <arnold@skeeve.com> diff --git a/extension/ChangeLog b/extension/ChangeLog index 4315086a..54bf3f8a 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,6 +1,12 @@ 2012-06-18 Arnold D. Robbins <arnold@skeeve.com> - * testext.c (test_array_elem): Add AWK_UNDEFINED for `wanted'. + * filefuncs.c (do_chdir): Change element use to match change types. + * fork.c (array_set_numeric): Ditto. + * testext.c (valrep2str): New function. + (test_array_elem): Add AWK_UNDEFINED for `wanted'. Use valrep2str. + Adjust use of element index. + (dump_array): Renamed from `dump_procinfo' and implemented. + (func_table): Updated. 2012-06-17 Arnold D. Robbins <arnold@skeeve.com> diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 433a0ea9..d4e1b57c 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -216,7 +216,7 @@ array_set(awk_array_t array, const char *sub, awk_value_t *value) memset(& element, 0, sizeof(element)); - element.index = dup_string(sub, strlen(sub), & tmp)->str_value; + element.index = *make_string(sub, strlen(sub), & tmp); element.value = *value; set_array_element(array, & element); diff --git a/extension/fork.c b/extension/fork.c index 21a4145f..58089d55 100644 --- a/extension/fork.c +++ b/extension/fork.c @@ -55,7 +55,7 @@ array_set_numeric(awk_array_t array, const char *sub, double num) memset(& element, 0, sizeof(element)); - element.index = dup_string(sub, strlen(sub), & tmp)->str_value; + element.index = *make_string(sub, strlen(sub), & tmp); make_number(num, &element.value); set_array_element(array, & element); diff --git a/extension/testext.c b/extension/testext.c index 743a1c2f..f5e16ba1 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -42,6 +42,35 @@ static awk_ext_id_t *ext_id; int plugin_is_GPL_compatible; +/* valrep2str --- turn a value into a string */ + +static const char * +valrep2str(const awk_value_t *value) +{ + static char buf[BUFSIZ]; + int size = BUFSIZ - 3; + + switch (value->val_type) { + case AWK_UNDEFINED: + strcpy(buf, "<undefined>"); + break; + case AWK_ARRAY: + strcpy(buf, "<array>"); + break; + case AWK_STRING: + if (value->str_value.len < size) + size = value->str_value.len; + sprintf(buf, "\"%.*s\"", + size, + value->str_value.str); + break; + case AWK_NUMBER: + sprintf(buf, "%g", value->num_value); + break; + } + return buf; +} + /* * The awk code for these tests is embedded in this file and then extracted * dynamically to create the script that is run together with this extension. @@ -51,22 +80,84 @@ int plugin_is_GPL_compatible; */ /* -#@load "testext" -#BEGIN { -# dump_procinfo() -# print "" -#} +@load "testext" +BEGIN { + n = split("blacky rusty sophie raincloud lucky", pets) + printf "pets has %d elements\n", length(pets) + ret = dump_array("pets") + printf "dump_array(pets) returned %d\n", ret + print "" +} */ static awk_value_t * -dump_procinfo(int nargs, awk_value_t *result) +dump_array(int nargs, awk_value_t *result) { + awk_value_t value, value2; + awk_flat_array_t *flat_array; + size_t count; + int i; + char *name; + assert(result != NULL); - /* get PROCINFO as flat array and print it */ + make_number(0.0, result); + + if (nargs != 1) { + printf("dump_array: nargs not right (%d should be 1)\n", nargs); + goto out; + } + + /* get argument named array as flat array and print it */ + if (get_argument(0, AWK_STRING, & value)) { + name = value.str_value.str; + if (sym_lookup(name, AWK_ARRAY, & value2)) + printf("dump_array: sym_lookup of %s passed\n", name); + else { + printf("dump_array: sym_lookup of %s failed\n", name); + goto out; + } + } else { + printf("dump_array: get_argument(0) failed\n"); + goto out; + } + + if (! get_element_count(value2.array_cookie, & count)) { + printf("dump_array: get_element_count failed\n"); + goto out; + } + + printf("dump_array: incoming size is %lu\n", (unsigned long) count); + + if (! flatten_array(value2.array_cookie, & flat_array)) { + printf("dump_array: could not flatten array\n"); + goto out; + } + + if (flat_array->count != count) { + printf("dump_array: 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++) { + 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 (! release_flattened_array(value2.array_cookie, flat_array)) { + printf("dump_array: could not release flattened array\n"); + goto out; + } + + make_number(1.0, result); +out: return result; } /* -@load "testext" BEGIN { testvar = "One Adam Twelve" ret = var_test("testvar") @@ -243,25 +334,13 @@ test_array_elem(int nargs, awk_value_t *result) printf("test_array_elem: get_array_element failed\n"); goto out; } - printf("test_array_elem: a[\"%.*s\"] = ", (int) index.str_value.len, - index.str_value.str); - switch (value.val_type) { - case AWK_UNDEFINED: - printf("<undefined>\n"); - break; - case AWK_ARRAY: - printf("<array>\n"); - break; - case AWK_STRING: - printf("\"%.*s\"\n", (int) value.str_value.len, value.str_value.str); - break; - case AWK_NUMBER: - printf("%g\n", value.num_value); - break; - } + printf("test_array_elem: a[\"%.*s\"] = %s\n", + (int) index.str_value.len, + index.str_value.str, + valrep2str(& value)); /* change the element - "3" */ - element.index = index.str_value; + element.index = index; (void) make_number(42.0, & element.value); if (! set_array_element(array.array_cookie, & element)) { printf("test_array_elem: set_array_element failed\n"); @@ -277,7 +356,7 @@ test_array_elem(int nargs, awk_value_t *result) /* add a new element - "7" */ (void) make_string("7", 1, & index); - element.index = index.str_value; + element.index = index; (void) make_string("seven", 5, & element.value); if (! set_array_element(array.array_cookie, & element)) { printf("test_array_elem: set_array_element failed\n"); @@ -364,7 +443,7 @@ create_new_array() a_cookie = create_array(); (void) make_string("hello", 5, & index); - element.index = index.str_value; + element.index = index; (void) make_string("world", 5, & element.value); if (! set_array_element(a_cookie, & element)) { printf("create_new_array:%d: set_array_element failed\n", __LINE__); @@ -372,7 +451,7 @@ create_new_array() } (void) make_string("answer", 6, & index); - element.index = index.str_value; + element.index = index; (void) make_number(42.0, & element.value); if (! set_array_element(a_cookie, & element)) { printf("create_new_array:%d: set_array_element failed\n", __LINE__); @@ -425,7 +504,7 @@ static void at_exit2(void *data, int exit_status) } static awk_ext_func_t func_table[] = { - { "dump_procinfo", dump_procinfo, 0 }, + { "dump_array", dump_array, 1 }, { "var_test", var_test, 1 }, { "test_errno", test_errno, 0 }, { "test_array_size", test_array_size, 1 }, @@ -478,10 +478,11 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie, if ( array == NULL || array->type != Node_var_array || element == NULL - || element->index.str == NULL) + || element->index.str_value.str == NULL) return false; - tmp = make_string(element->index.str, element->index.len); + tmp = make_string(element->index.str_value.str, + element->index.str_value.len); aptr = assoc_lookup(array, tmp); unref(tmp); unref(*aptr); @@ -570,14 +571,56 @@ api_clear_array(awk_ext_id_t id, awk_array_t a_cookie) return true; } -/* Flatten out an array so that it can be looped over easily. */ +/* api_flatten_array --- flatten out an array so that it can be looped over easily. */ + static awk_bool_t api_flatten_array(awk_ext_id_t id, awk_array_t a_cookie, - size_t *count, - awk_element_t **data) + awk_flat_array_t **data) { - return true; /* for now */ + NODE **list; + size_t i, j; + NODE *array = (NODE *) a_cookie; + size_t alloc_size; + + if ( array == NULL + || array->type != Node_var_array + || array->table_size == 0 + || data == NULL) + return false; + + alloc_size = sizeof(awk_flat_array_t) + + (array->table_size - 1) * sizeof(awk_element_t); + + emalloc(*data, awk_flat_array_t *, alloc_size, + "api_flatten_array"); + memset(*data, 0, alloc_size); + + list = assoc_list(array, "@unsorted", ASORTI); + + (*data)->opaque1 = array; + (*data)->opaque2 = list; + (*data)->count = array->table_size; + + for (i = j = 0; i < 2 * array->table_size; i += 2, j++) { + NODE *index, *value; + + index = force_string(list[i]); + value = list[i + 1]; /* number or string or subarray */ + + /* convert index and value to ext types */ + if (! node_to_awk_value(index, + & (*data)->elements[j].index, AWK_UNDEFINED)) { + fatal(_("api_flatten_array: could not convert index %d\n"), + (int) i); + } + if (! node_to_awk_value(value, + & (*data)->elements[j].value, AWK_UNDEFINED)) { + fatal(_("api_flatten_array: could not convert value %d\n"), + (int) i); + } + } + return true; } /* @@ -587,9 +630,30 @@ api_flatten_array(awk_ext_id_t id, static awk_bool_t api_release_flattened_array(awk_ext_id_t id, awk_array_t a_cookie, - size_t count, - awk_element_t *data) + awk_flat_array_t *data) { + NODE *array = a_cookie; + NODE **list; + size_t i; + + if ( array == NULL + || array->type != Node_var_array + || data == NULL + || array != (NODE *) data->opaque1 + || data->count != array->table_size + || data->opaque2 == NULL) + return false; + + list = (NODE **) data->opaque2; + + /* FIXME: Delete items flagged for delete. */ + + /* free index nodes */ + for (i = 0; i < 2 * array->table_size; i += 2) + unref(list[i]); + + efree(list); + return true; /* for now */ } @@ -145,10 +145,23 @@ typedef struct awk_element { AWK_ELEMENT_DELETE = 1 /* set by extension if should be deleted */ } flags; - awk_string_t index; + awk_value_t index; awk_value_t value; } awk_element_t; +#ifdef GAWK +#define awk_const +#else +#define awk_const const +#endif + +typedef struct awk_flat_array { + void *opaque1; /* private data for use by gawk */ + void *opaque2; /* private data for use by gawk */ + awk_const size_t count; /* how many elements */ + awk_element_t elements[1]; /* will be extended */ +} awk_flat_array_t; + /* * A record describing an extension function. Upon being * loaded, the extension should pass in one of these for @@ -222,6 +235,11 @@ typedef struct gawk_api { awk_valtype_t wanted, awk_value_t *result); + /* + * FIXME: Missing update_argument to convert an undefined + * argument into an array or scalar. + */ + /* Functions to print messages */ void (*api_fatal)(awk_ext_id_t id, const char *format, ...); void (*api_warning)(awk_ext_id_t id, const char *format, ...); @@ -257,7 +275,8 @@ typedef struct gawk_api { * returned. Returns false if the variable doesn't exist * or the wrong type was requested. * In the latter case, fills in vaule->val_type with the real type. - * Built-in variables (except PROCINFO) may not be accessed by an extension. + * Built-in variables (except PROCINFO) may not be accessed by an + * extension. * * awk_value_t val; * if (! api->sym_lookup(id, name, wanted, & val)) @@ -322,8 +341,7 @@ typedef struct gawk_api { /* Flatten out an array so that it can be looped over easily. */ awk_bool_t (*flatten_array)(awk_ext_id_t id, awk_array_t a_cookie, - size_t *count, - awk_element_t **data); + awk_flat_array_t **data); /* * When done, delete any marked elements, release the memory. @@ -332,8 +350,7 @@ typedef struct gawk_api { */ awk_bool_t (*release_flattened_array)(awk_ext_id_t id, awk_array_t a_cookie, - size_t count, - awk_element_t *data); + awk_flat_array_t *data); } gawk_api_t; #ifndef GAWK /* these are not for the gawk code itself! */ @@ -385,11 +402,11 @@ typedef struct gawk_api { #define clear_array(array) (api->clear_array(ext_id, array)) -#define flatten_array(array, count, data) \ - (api->flatten_array(ext_id, array, count, data)) +#define flatten_array(array, data) \ + (api->flatten_array(ext_id, array, data)) -#define release_flattened_array(array, count, data) \ - (api->release_flattened_array(ext_id, array, count, data)) +#define release_flattened_array(array, data) \ + (api->release_flattened_array(ext_id, array, data)) #define emalloc(pointer, type, size, message) \ do { \ diff --git a/test/ChangeLog b/test/ChangeLog index a1717010..f8fc382e 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,6 +1,8 @@ 2012-06-18 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (testext): New test. + (EXTRA_DIST): Add new file testext.ok. + (SHLIB_TESTS): Add testext. (clean): Add testext.awk to the list. * testext.ok: New file. diff --git a/test/testext.ok b/test/testext.ok index 9cac57ad..83711a7b 100644 --- a/test/testext.ok +++ b/test/testext.ok @@ -1,3 +1,13 @@ +pets has 5 elements +dump_array: sym_lookup of pets passed +dump_array: incoming size is 5 + pets["1"] = "blacky" + pets["2"] = "rusty" + pets["3"] = "sophie" + pets["4"] = "raincloud" + pets["5"] = "lucky" +dump_array(pets) returned 1 + var_test: sym_lookup of ARGC passed - did not get a value var_test: sym_update("testvar") succeeded var_test() returned 1, test_var = 42 |