aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2012-06-18 23:00:58 +0300
committerArnold D. Robbins <arnold@skeeve.com>2012-06-18 23:00:58 +0300
commit1e3ac8a49caeeb991d8163042a576a66db51c74b (patch)
tree81fe5ffd621c6cba3f98d2997f2f930a3f66343d
parentb0f08ac2443e239b0ed9cc4421758f0ed3f7a94f (diff)
downloadegawk-1e3ac8a49caeeb991d8163042a576a66db51c74b.tar.gz
egawk-1e3ac8a49caeeb991d8163042a576a66db51c74b.tar.bz2
egawk-1e3ac8a49caeeb991d8163042a576a66db51c74b.zip
Get most of array flattening done.
-rw-r--r--ChangeLog6
-rw-r--r--extension/ChangeLog8
-rw-r--r--extension/filefuncs.c2
-rw-r--r--extension/fork.c2
-rw-r--r--extension/testext.c137
-rw-r--r--gawkapi.c80
-rw-r--r--gawkapi.h37
-rw-r--r--test/ChangeLog2
-rw-r--r--test/testext.ok10
9 files changed, 234 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index dd143a87..2e4c8cbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 },
diff --git a/gawkapi.c b/gawkapi.c
index b616fbfc..b1fba48a 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -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 */
}
diff --git a/gawkapi.h b/gawkapi.h
index 7fdd7634..8102f70e 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -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