diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 12:33:03 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 12:33:03 +0300 |
commit | 2f83a4e72166e811a9f0b4726c19a3d5a0b17dcb (patch) | |
tree | 469bebda4e807139efb497edfca1ec0678b5ab8b /array.c | |
parent | 66b0bdd602e952f20fa98f6ce5430cea68d4f598 (diff) | |
download | egawk-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.c | 69 |
1 files changed, 51 insertions, 18 deletions
@@ -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; } |