aboutsummaryrefslogtreecommitdiffstats
path: root/array.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-16 12:33:03 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-16 12:33:03 +0300
commit2f83a4e72166e811a9f0b4726c19a3d5a0b17dcb (patch)
tree469bebda4e807139efb497edfca1ec0678b5ab8b /array.c
parent66b0bdd602e952f20fa98f6ce5430cea68d4f598 (diff)
downloadegawk-2f83a4e72166e811a9f0b4726c19a3d5a0b17dcb.tar.gz
egawk-2f83a4e72166e811a9f0b4726c19a3d5a0b17dcb.tar.bz2
egawk-2f83a4e72166e811a9f0b4726c19a3d5a0b17dcb.zip
Move to gawk-2.15.5.
Diffstat (limited to 'array.c')
-rw-r--r--array.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/array.c b/array.c
index 0ddc6644..d42f9a6c 100644
--- a/array.c
+++ b/array.c
@@ -111,6 +111,7 @@ NODE *symbol;
free(symbol->var_array);
symbol->var_array = NULL;
symbol->array_size = symbol->table_size = 0;
+ symbol->flags &= ~ARRAYMAXED;
}
/*
@@ -229,11 +230,19 @@ int hash1;
for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) {
if (cmp_nodes(bucket->ahname, subs) == 0) {
+#if 0
+ /*
+ * Disable this code for now. It screws things up if we have
+ * a ``for (iggy in foo)'' in progress. Interestingly enough,
+ * this was not a problem in 2.15.3, only in 2.15.4. I'm not
+ * sure why it works in 2.15.3.
+ */
if (prev) { /* move found to front of chain */
prev->ahnext = bucket->ahnext;
bucket->ahnext = symbol->var_array[hash1];
symbol->var_array[hash1] = bucket;
}
+#endif
return bucket;
} else
prev = bucket; /* save previous list entry */
@@ -284,6 +293,7 @@ NODE *symbol, *subs;
if (symbol->var_array == 0) {
symbol->type = Node_var_array;
symbol->array_size = symbol->table_size = 0; /* sanity */
+ symbol->flags &= ~ARRAYMAXED;
grow_table(symbol);
hash1 = hash(subs->stptr, subs->stlen,
(unsigned long) symbol->array_size);
@@ -368,7 +378,8 @@ NODE *symbol, *tree;
memset(symbol->var_array, '\0',
sizeof(NODE *) * symbol->array_size);
symbol->table_size = symbol->array_size = 0;
- free(symbol->var_array);
+ symbol->flags &= ~ARRAYMAXED;
+ free((char *) symbol->var_array);
symbol->var_array = NULL;
}
}
@@ -378,32 +389,54 @@ assoc_scan(symbol, lookat)
NODE *symbol;
struct search *lookat;
{
- if (symbol->var_array == NULL) {
- lookat->retval = NULL;
- return;
- }
- lookat->arr_ptr = symbol->var_array;
- lookat->arr_end = lookat->arr_ptr + symbol->array_size;
- lookat->bucket = symbol->var_array[0];
- assoc_next(lookat);
+ lookat->sym = symbol;
+ lookat->idx = 0;
+ lookat->bucket = NULL;
+ lookat->retval = NULL;
+ if (symbol->var_array != NULL)
+ assoc_next(lookat);
}
void
assoc_next(lookat)
struct search *lookat;
{
- while (lookat->arr_ptr < lookat->arr_end) {
- if (lookat->bucket != 0) {
- lookat->retval = lookat->bucket->ahname;
- lookat->bucket = lookat->bucket->ahnext;
+ register NODE *symbol = lookat->sym;
+
+ if (symbol == NULL)
+ fatal("null symbol in assoc_next");
+ if (symbol->var_array == NULL || lookat->idx > symbol->array_size) {
+ lookat->retval = NULL;
+ return;
+ }
+ /*
+ * This is theoretically unsafe. The element bucket might have
+ * been freed if the body of the scan did a delete on the next
+ * element of the bucket. The only way to do that is by array
+ * reference, which is unlikely. Basically, if the user is doing
+ * anything other than an operation on the current element of an
+ * assoc array while walking through it sequentially, all bets are
+ * off. (The safe way is to register all search structs on an
+ * array with the array, and update all of them on a delete or
+ * insert)
+ */
+ if (lookat->bucket != NULL) {
+ lookat->retval = lookat->bucket->ahname;
+ lookat->bucket = lookat->bucket->ahnext;
+ return;
+ }
+ for (; lookat->idx < symbol->array_size; lookat->idx++) {
+ NODE *bucket;
+
+ if ((bucket = symbol->var_array[lookat->idx]) != NULL) {
+ lookat->retval = bucket->ahname;
+ lookat->bucket = bucket->ahnext;
+ lookat->idx++;
return;
}
- lookat->arr_ptr++;
- if (lookat->arr_ptr < lookat->arr_end)
- lookat->bucket = *(lookat->arr_ptr);
- else
- lookat->retval = NULL;
}
+ lookat->retval = NULL;
+ lookat->bucket = NULL;
return;
}