# HG changeset patch # User Rob Landley # Date 1391060873 21600 # Node ID cb62f7090473fe372d5d3c10bba1b7c019023c08 # Parent 18cc63376e6650425bb5b068e3bc6796dedf3d88 More elaborate help text collating logic. diff -r 18cc63376e66 -r cb62f7090473 scripts/config2help.c --- a/scripts/config2help.c Tue Jan 28 17:46:14 2014 -0600 +++ b/scripts/config2help.c Wed Jan 29 23:47:53 2014 -0600 @@ -41,17 +41,84 @@ char *s = dd->data; free(dd); + return s; } -void zap_blank_lines(struct double_list **help) +int zap_blank_lines(struct double_list **help) { - for(;;) { - char *s = trim((*help)->data);; + int got = 0; + + while (*help) { + char *s; + + s = trim((*help)->data); if (*s) break; + got++; free(dlist_zap(help)); } + + return got; +} + +// Collect "-a blah" description lines following a blank line (or start). +// Returns array of removed lines with *len entries (0 for none). + +// Moves *help to new start of text (in case dash lines were at beginning). +// Sets *from to where dash lines removed from (in case they weren't). +// Discards blank lines before and after dashlines. + +// If no prefix, *help NULL. If no postfix, *from == *help +// if no dashlines returned *from == *help. + +char **grab_dashlines(struct double_list **help, struct double_list **from, + int *len) +{ + struct double_list *dd; + char *s, **list; + int count = 0; + + *len = 0; + zap_blank_lines(help); + *from = *help; + + // Find start of dash block. Must be at start or after blank line. + for (;;) { + s = trim((*from)->data); + if (*s == '-' && s[1] != '-' && !count) break; + + if (!*s) count = 0; + else count++; + + *from = (*from)->next; + if (*from == *help) return 0; + } + + // If there was whitespace before this, zap it. This can't take out *help + // because zap_blank_lines skipped blank lines, and we had to have at least + // one non-blank line (a dash line) to get this far. + while (!*trim((*from)->prev->data)) { + *from = (*from)->prev; + free(dlist_zap(from)); + } + + // Count number of dashlines, copy out to array, zap trailing whitespace + // If *help was at start of dashblock, move it with *from + count = 0; + dd = *from; + if (*help == *from) *help = 0; + for (;;) { + if (*trim(dd->data) != '-') break; + count++; + if (*from == (dd = dd->next)) break; + } + + list = xmalloc(sizeof(char *)*count); + *len = count; + while (count) list[--count] = dlist_zap(from); + + return list; } void parse(char *filename) @@ -108,15 +175,20 @@ return 0; } -int dashsort(void *a, void *b) +int dashsort(char **a, char **b) { - char *aa = *(char **)a, *bb = *(char **)b; + char *aa = *a, *bb = *b; if (aa[1] < bb[1]) return -1; if (aa[1] > bb[1]) return 1; return 0; } +int dashlinesort(char **a, char **b) +{ + return strcmp(*a, *b); +} + int main(int argc, char *argv[]) { FILE *fp; @@ -154,7 +226,8 @@ // Collate help according to usage, depends, and .config // Loop through each entry, finding duplicate enabled "usage:" names - + // This is in reverse order, so last entry gets collated with previous + // entry until we run out of matching pairs. for (;;) { struct symbol *throw = 0, *catch; char *this, *that, *cusage, *tusage, *name; @@ -164,11 +237,12 @@ for (catch = sym; catch; catch = catch->next) { if (catch->enabled != 1) continue; if (catch->help && (that = keyword("usage:", catch->help->data))) { - struct double_list *bang; - char *try; + struct double_list *cfrom, *tfrom, *anchor; + char *try, **cdashlines, **tdashlines; + int clen, tlen; - // Suck help text out of throw into catch, copying from this to that - + // Align usage: lines, finding a matching pair so we can suck help + // text out of throw into catch, copying from this to that if (!throw) name = that; else if (strncmp(name, that, len) || !isspace(that[len])) continue; catch->enabled++; @@ -182,14 +256,67 @@ continue; } - // Grab usage: lines to collate - cusage = dlist_zap(&catch->help); - zap_blank_lines(&catch->help); + // Grab option description lines to collate from catch and throw tusage = dlist_zap(&throw->help); - zap_blank_lines(&throw->help); + tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen); + cusage = dlist_zap(&catch->help); + cdashlines = grab_dashlines(&catch->help, &cfrom, &clen); + anchor = catch->help; + + // If we've got both, collate and alphebetize + if (cdashlines && tdashlines) { + char **new = xmalloc(sizeof(char *)*(clen+tlen)); + + memcpy(new, cdashlines, sizeof(char *)*clen); + memcpy(new+clen, tdashlines, sizeof(char *)*tlen); + free(cdashlines); + free(tdashlines); + qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort); + cdashlines = new; + + // If just one, make sure it's in catch. + } else if (tdashlines) cdashlines = tdashlines; - // Collate first [-abc] option block + // If throw had a prefix, insert it before dashlines, with a + // blank line if catch had a prefix. + if (tfrom && tfrom != throw->help) { + if (throw->help || catch->help) dlist_add(&cfrom, strdup("")); + else { + dlist_add(&cfrom, 0); + anchor = cfrom->prev; + } + while (throw->help && throw->help != tfrom) + dlist_add(&cfrom, dlist_zap(&throw->help)); + if (cfrom && cfrom->prev->data && *trim(cfrom->prev->data)) + dlist_add(&cfrom, strdup("")); + } + if (!anchor) { + dlist_add(&cfrom, 0); + anchor = cfrom->prev; + } + // Splice sorted lines back in place + if (cdashlines) { + tlen += clen; + + for (clen = 0; clen < tlen; clen++) + dlist_add(&cfrom, cdashlines[clen]); + } + + // If there were no dashlines, text would be considered prefix, so + // the list is definitely no longer empty, so discard placeholder. + if (!anchor->data) dlist_zap(&anchor); + + // zap whitespace at end of catch help text + while (!*trim(anchor->prev->data)) { + anchor = anchor->prev; + free(dlist_zap(&anchor)); + } + + // Append trailing lines. + while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom)); + + // Collate first [-abc] option block in usage: lines try = 0; if (*this == '[' && this[1] == '-' && this[2] != '-' && *that == '[' && that[1] == '-' && that[2] != '-') @@ -205,27 +332,21 @@ } } + // The list is definitely no longer empty, so discard placeholder. + if (!anchor->data) dlist_zap(&anchor); + // Add new collated line (and whitespace). - dlist_add(&catch->help, xmprintf("%*cusage: %.*s %s%s%s%s", + dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s", catch->help_indent, ' ', len, name, try ? try : "", this, *this ? " " : "", that)); - dlist_add(&catch->help, strdup("")); - catch->help = catch->help->prev->prev; - + free(try); + dlist_add(&anchor, strdup("")); free(cusage); free(tusage); - free(try); - throw->enabled = 0; + throw = catch; + throw->help = anchor->prev->prev; - // splice together circularly linked lists - bang = throw->help->prev; - throw->help->prev->next = catch->help; - throw->help->prev = catch->help->prev; - catch->help->prev->next = throw->help; - catch->help->prev = bang; - - throw->help = 0; throw = catch; this = throw->help->data + throw->help_indent + 8 + len; } diff -r 18cc63376e66 -r cb62f7090473 toys/posix/sort.c --- a/toys/posix/sort.c Tue Jan 28 17:46:14 2014 -0600 +++ b/toys/posix/sort.c Wed Jan 29 23:47:53 2014 -0600 @@ -52,10 +52,9 @@ help usage: sort [-g] - This version of sort requires floating point. - -g general numeric sort (double precision with nan and inf) + This version of sort requires floating point. */ #define FOR_sort