changeset 1188:cb62f7090473 draft

More elaborate help text collating logic.
author Rob Landley <rob@landley.net>
date Wed, 29 Jan 2014 23:47:53 -0600
parents 18cc63376e66
children 95ae2805622f
files scripts/config2help.c toys/posix/sort.c
diffstat 2 files changed, 151 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- 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;
       }
--- 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