aboutsummaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2011-03-29 20:51:30 +0200
committerArnold D. Robbins <arnold@skeeve.com>2011-03-29 20:51:30 +0200
commit2400cc5143383a881356a9f55e93b60037d851e5 (patch)
tree3ba75f8b1225bf50e48b4f6c381e7772f1ab6c5b /eval.c
parent4fe569fb78dd1b25822c16c9cac515a0fc6702a4 (diff)
downloadegawk-2400cc5143383a881356a9f55e93b60037d851e5.tar.gz
egawk-2400cc5143383a881356a9f55e93b60037d851e5.tar.bz2
egawk-2400cc5143383a881356a9f55e93b60037d851e5.zip
Revise array sorting for PROCINFO["sorted_in"].
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c260
1 files changed, 11 insertions, 249 deletions
diff --git a/eval.c b/eval.c
index 5b3b2f45..a9928735 100644
--- a/eval.c
+++ b/eval.c
@@ -1055,254 +1055,6 @@ update_FNR()
}
-typedef int (*qsort_compfunc)(const void *,const void *);
-
-static qsort_compfunc sorted_in(void);
-static int sort_ignrcase(const char *, size_t,const char *,size_t);
-static int sort_up_index_str(const void *, const void *);
-static int sort_down_index_str(const void *, const void *);
-static int sort_up_index_ignrcase(const void *, const void *);
-static int sort_down_index_ignrcase(const void *, const void *);
-
-/* comp_func --- array index comparison function for qsort, used in debug.c */
-
-int
-comp_func(const void *p1, const void *p2)
-{
- return sort_up_index_str(p1, p2);
-}
-
-/* sort_ignorecase --- case insensitive string comparison from cmp_nodes() */
-
-static int
-sort_ignorecase(const char *s1, size_t l1, const char *s2, size_t l2)
-{
- size_t l;
- int ret;
-
- l = (l1 < l2) ? l1 : l2;
-#ifdef MBS_SUPPORT
- if (gawk_mb_cur_max > 1) {
- ret = strncasecmpmbs((const unsigned char *) s1,
- (const unsigned char *) s2, l);
- } else
-#endif
- for (ret = 0; l-- > 0 && ret == 0; s1++, s2++)
- ret = casetable[*(unsigned char *) s1]
- - casetable[*(unsigned char *) s2];
- if (ret == 0 && l1 != l2)
- ret = (l1 < l2) ? -1 : 1;
- return ret;
-}
-
-/*
- * sort_up_index_str --- qsort comparison function; ascending index strings;
- * index strings are distinct within an array, so no comparisons will yield
- * equal and warrant disambiguation
- */
-
-static int
-sort_up_index_str(const void *p1, const void *p2)
-{
- const NODE *t1, *t2;
- const char *str1, *str2;
- size_t len1, len2;
- int ret;
-
- /* Array indexes are strings and distinct, never equal */
- t1 = *((const NODE *const *) p1);
- t2 = *((const NODE *const *) p2);
-
- str1 = t1->ahname_str;
- len1 = t1->ahname_len;
- str2 = t2->ahname_str;
- len2 = t2->ahname_len;
-
- ret = memcmp(str1, str2, (len1 < len2) ? len1 : len2);
- /*
- * if they compared equal but their lengths differ, the
- * shorter one is a prefix of the longer and compares as less
- */
- if (ret == 0 && len1 != len2)
- ret = (len1 < len2) ? -1 : 1;
-
- /* indices are unique within an array, so result should never be 0 */
- assert(ret != 0);
- return ret;
-}
-
-/* sort_down_index_str --- descending index strings */
-
-static int
-sort_down_index_str(const void *p1, const void *p2)
-{
- /*
- * Negation versus transposed arguments: when all keys are
- * distinct, as with array indices here, either method will
- * transform an ascending sort into a descending one. But if
- * there are equal keys--such as when IGNORECASE is honored--
- * that get disambiguated into a determisitc order, negation
- * will reverse those but transposed arguments would retain
- * their relative order within the rest of the reversed sort.
- */
- return -sort_up_index_str(p1, p2);
-}
-
-/*
- * sort_up_index_ignrcase --- ascending index string, case insensitive;
- * case insensitive comparison can cause distinct index strings to compare
- * equal, so disambiguation in necessary
- */
-
-static int
-sort_up_index_ignrcase(const void *p1, const void *p2)
-{
- const NODE *t1, *t2;
- int ret;
-
- t1 = *((const NODE *const *) p1);
- t2 = *((const NODE *const *) p2);
-
- ret = sort_ignorecase(t1->ahname_str, t1->ahname_len,
- t2->ahname_str, t2->ahname_len);
-
- /*
- * if case insensitive result is "they're the same",
- * use case sensitive comparison to force distinct order
- */
- if (ret == 0)
- ret = sort_up_index_str(p1, p2);
- return ret;
-}
-
-/* sort_down_index_ignrcase --- descending index strings, case insensitive */
-
-static int
-sort_down_index_ignrcase(const void *p1, const void *p2)
-{
- return -sort_up_index_ignrcase(p1, p2);
-}
-
-struct sort_option {
- qsort_compfunc func;
- const char *keydescr;
-};
-
-/*
- * sorted_in --- fetch and parse value of PROCINFO["sorted_in"] to decide
- * whether to sort the traversal of ``for (index in array) {}'', and
- * if so, what ordering to generate; returns a qsort comparison function
- */
-
-static qsort_compfunc
-sorted_in(void)
-{
- static struct sort_option sorts[] = {
- /* explicit no-op */
- { (qsort_compfunc) NULL, "unsorted" },
- /* also matches "ascending index" and "ascending" */
- { sort_up_index_str, "ascending index string" },
- /* also matches "descending index" and "descending" */
- { sort_down_index_str, "descending index string" },
- /*
- * to come
- */
- /* also matches "ascending value"; "ascending" won't get here */
- /* { sort_up_value_str, "ascending value string" },
- * { sort_down_value_str, "descending value string" },
- * { sort_up_index_num, "ascending index number" },
- * { sort_down_index_num, "descending index number" },
- * { sort_up_value_num, "ascending value number" },
- * { sort_down_value_num, "descending value number" },
- * and possibly
- * { sort_as_inserted, "insertion-order" },
- */
- };
- static NODE *sorted_str = NULL;
- static short warned_extension = FALSE, warned_unrecognized = FALSE;
-
- NODE *r;
- const char *s, *descr;
- size_t i, k, l;
- short is_number;
- qsort_compfunc sort_func;
-
- /* if there's no PROCINFO[], there can be no ["sorted_in"], so no sorting */
- if (PROCINFO_node == NULL)
- return (qsort_compfunc) NULL;
-
- if (sorted_str == NULL) /* do this once */
- sorted_str = make_string("sorted_in", 9);
-
- r = (NODE *) NULL;
- if (in_array(PROCINFO_node, sorted_str))
- r = *assoc_lookup(PROCINFO_node, sorted_str, TRUE);
- /* if there's no PROCINFO["sorted_in"], there's no sorting */
- if (!r)
- return (qsort_compfunc) 0;
-
- /* we're going to make use of PROCINFO["sorted_in"] */
- if (do_lint && ! warned_extension) {
- warned_extension = TRUE;
- lintwarn(_("sorted array traversal is a gawk extension"));
- }
-
- /* default result is no sorting */
- sort_func = (qsort_compfunc) NULL;
-
- /* undocumented synonyms: 0 is "unsorted", 1 is "ascending index" */
- if (r->flags & MAYBE_NUM)
- (void) force_number(r);
- is_number = ((r->flags & NUMBER) != 0);
- if (is_number) {
- if (r->numbr == 1)
- sort_func = sort_up_index_str;
- if (r->numbr == 0 || r->numbr == 1)
- goto got_func;
- /*
- * using PROCINFO["sorted_in"] as a number is not a general
- * index into sorts[]; entries beyond [1] may get reordered
- */
- }
-
- r = force_string(r);
- s = r->stptr;
- l = r->stlen;
- while (l > 0 && *s == ' ')
- ++s, --l;
-
- /* treat empty string the same as 0, a synonym for no sorting */
- if (l == 0)
- goto got_func; /* sort_func is still 0 */
-
- /* scan the list of available sorting orders */
- for (i = 0; i < (sizeof sorts / sizeof *sorts); ++i) {
- descr = sorts[i].keydescr;
- if (((k = strlen(descr)) == l || (k > l && descr[l] == ' '))
- && !strncasecmp(s, descr, l)) {
- sort_func = sorts[i].func;
- goto got_func;
- }
- }
-
- /* we didn't match any key description; sort_func is still 0 */
- if ((do_lint || is_number) && ! warned_unrecognized) {
- warned_unrecognized = TRUE;
- lintwarn(_("`PROCINFO[\"sorted_in\"]' value is not recognized"));
- }
-
-got_func:
- if (IGNORECASE) {
- if (sort_func == sort_up_index_str)
- sort_func = sort_up_index_ignrcase;
- if (sort_func == sort_down_index_str)
- sort_func = sort_down_index_ignrcase;
- }
-
- return sort_func;
-}
-
-
NODE *frame_ptr; /* current frame */
STACK_ITEM *stack_ptr = NULL;
@@ -2444,9 +2196,19 @@ post:
}
sort_compare = sorted_in();
- if (sort_compare)
+ if (sort_compare) {
+ /* ordering might be "* index number"
+ in which case we want more than just
+ a simple array of element nodes */
+ sort_maybe_numeric_index(sort_compare, list,
+ num_elems, TRUE);
+ /* sort the array of element pointers */
qsort(list, num_elems, sizeof(NODE *),
sort_compare); /* shazzam! */
+ /* clean up by-index as-number */
+ sort_maybe_numeric_index(sort_compare, list,
+ num_elems, FALSE);
+ }
list[num_elems] = array; /* actual array for use in
* lint warning in Op_arrayfor_incr
*/