diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2011-05-08 20:52:33 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2011-05-08 20:52:33 +0300 |
commit | 783ae783275b5fab9104b711ac3d531dcc454d96 (patch) | |
tree | 6ca6498b6b62e8a744990b65fa09fba71f63daad /array.c | |
parent | 7c20cc42ca1b77a2f3caddab543839efe897eeb0 (diff) | |
download | egawk-783ae783275b5fab9104b711ac3d531dcc454d96.tar.gz egawk-783ae783275b5fab9104b711ac3d531dcc454d96.tar.bz2 egawk-783ae783275b5fab9104b711ac3d531dcc454d96.zip |
More array sorting fixes.
Diffstat (limited to 'array.c')
-rw-r--r-- | array.c | 155 |
1 files changed, 100 insertions, 55 deletions
@@ -85,6 +85,41 @@ array_init() hash = gst_hash_string; } +/* make_aname --- construct a 'vname' for a (sub)array */ + +static char * +make_aname(const NODE *symbol) +{ + static char *aname = NULL; + static size_t alen; + static size_t max_alen; +#define SLEN 256 + + if (symbol->parent_array != NULL) { + size_t slen; + + (void) make_aname(symbol->parent_array); + slen = strlen(symbol->vname); /* subscript in parent array */ + if (alen + slen + 4 > max_alen) { /* sizeof("[\"\"]") = 4 */ + max_alen = alen + slen + 4 + SLEN; + erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } + alen += sprintf(aname + alen, "[\"%s\"]", symbol->vname); + } else { + alen = strlen(symbol->vname); + if (aname == NULL) { + max_alen = alen + SLEN; + emalloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } else if (alen > max_alen) { + max_alen = alen + SLEN; + erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } + memcpy(aname, symbol->vname, alen + 1); + } + return aname; +#undef SLEN +} + /* * array_vname --- print the name of the array * @@ -103,18 +138,33 @@ array_vname(const NODE *symbol) int n; const NODE *save_symbol = symbol; const char *from = _("from %s"); + const char *aname; - if (symbol->type != Node_array_ref || symbol->orig_array->type != Node_var_array) - return symbol->vname; + if (symbol->type != Node_array_ref + || symbol->orig_array->type != Node_var_array + ) { + if (symbol->type != Node_var_array || symbol->parent_array == NULL) + return symbol->vname; + return make_aname(symbol); + } /* First, we have to compute the length of the string: */ - len = strlen(symbol->vname) + 2; /* "%s (" */ + + len = 2; /* " (" */ n = 0; - do { - symbol = symbol->prev_array; + while (symbol->type == Node_array_ref) { len += strlen(symbol->vname); n++; - } while (symbol->type == Node_array_ref); + symbol = symbol->prev_array; + } + + /* Get the (sub)array name */ + if (symbol->parent_array == NULL) + aname = symbol->vname; + else + aname = make_aname(symbol); + len += strlen(aname); + /* * Each node contributes by strlen(from) minus the length * of "%s" in the translation (which is at least 2) @@ -139,42 +189,21 @@ array_vname(const NODE *symbol) * Ancient systems have sprintf() returning char *, not int. * If you have one of those, use sprintf(..); s += strlen(s) instead. */ + s += sprintf(s, "%s (", symbol->vname); for (;;) { symbol = symbol->prev_array; - sprintf(s, from, symbol->vname); - s += strlen(s); if (symbol->type != Node_array_ref) break; - sprintf(s, ", "); - s += strlen(s); + s += sprintf(s, from, symbol->vname); + s += sprintf(s, ", "); } + s += sprintf(s, from, aname); strcpy(s, ")"); return message; } -/* make_aname --- construct a sub-array name for multi-dimensional array */ - -char * -make_aname(NODE *array, NODE *subs) -{ - static char *aname = NULL; - static size_t aname_len; - size_t slen; - - slen = strlen(array->vname) + subs->stlen + 6; - if (aname == NULL) { - emalloc(aname, char *, slen, "make_aname"); - aname_len = slen; - } else if (slen > aname_len) { - erealloc(aname, char *, slen, "make_aname"); - aname_len = slen; - } - sprintf(aname, "%s[\"%.*s\"]", array->vname, (int) subs->stlen, subs->stptr); - return aname; -} - /* * get_array --- proceed to the actual Node_var_array, @@ -702,7 +731,7 @@ do { \ /* e.g.: a[1] = 1; delete a[1][1] */ free_subs(i); fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"), - symbol->vname, + array_vname(symbol), (int) bucket->ahname_len, bucket->ahname_str); } @@ -994,14 +1023,9 @@ dup_table(NODE *symbol, NODE *newsymb) if (chain->ahvalue->type == Node_var_array) { NODE *r; - char *aname; - size_t aname_len; getnode(r); r->type = Node_var_array; - aname_len = strlen(newsymb->vname) + chain->ahname_len + 4; - emalloc(aname, char *, aname_len + 2, "dup_table"); - sprintf(aname, "%s[\"%.*s\"]", newsymb->vname, (int) chain->ahname_len, chain->ahname_str); - r->vname = aname; + r->vname = estrdup(chain->ahname_str, chain->ahname_len); r->parent_array = newsymb; bucket->ahvalue = dup_table(chain->ahvalue, r); } else @@ -1136,23 +1160,34 @@ asort_actual(int nargs, SORT_CTXT ctxt) /* We want the values of the source array. */ val = r->ahvalue; - if (val->type == Node_val) - *assoc_lookup(result, subs, FALSE) = dupnode(val); - else { - const char *arr_name = make_aname(result, subs); - NODE *arr; - - /* - * There isn't any reference counting for - * subarrays, so recursively copy subarrays - * using dup_table(). - */ - getnode(arr); - arr->type = Node_var_array; - arr->var_array = NULL; - arr->vname = estrdup(arr_name, strlen(arr_name)); - arr->parent_array = array; /* actual parent, not the temporary one. */ - *assoc_lookup(result, subs, FALSE) = dup_table(val, arr); + if (result != dest) { + /* optimization for dest = NULL or dest = array */ + + if (val->type == Node_var_array) { + /* update subarray index in parent array */ + efree(val->vname); + val->vname = estrdup(subs->stptr, subs->stlen); + } + *assoc_lookup(result, subs, FALSE) = val; + r->ahvalue = Nnull_string; + } else { + if (val->type == Node_val) + *assoc_lookup(result, subs, FALSE) = dupnode(val); + else { + NODE *arr; + + /* + * There isn't any reference counting for + * subarrays, so recursively copy subarrays + * using dup_table(). + */ + getnode(arr); + arr->type = Node_var_array; + arr->var_array = NULL; + arr->vname = estrdup(subs->stptr, subs->stlen); + arr->parent_array = array; /* actual parent, not the temporary one. */ + *assoc_lookup(result, subs, FALSE) = dup_table(val, arr); + } } } @@ -1383,6 +1418,16 @@ sort_up_value_number(const void *p1, const void *p2) else ret = (n1->numbr > n2->numbr); + if (ret == 0) { + /* + * Use string value to guarantee same sort order on all + * versions of qsort(). + */ + n1 = force_string(n1); + n2 = force_string(n2); + ret = cmp_string(n1, n2); + } + return ret; } |