10f66f451Sopenharmony_ci/* config2.help.c - config2hep Config.in .config > help.h 20f66f451Sopenharmony_ci 30f66f451Sopenharmony_ci function parse() reads Config.in data into *sym list, then 40f66f451Sopenharmony_ci we read .config and set sym->try on each enabled symbol. 50f66f451Sopenharmony_ci 60f66f451Sopenharmony_ci*/ 70f66f451Sopenharmony_ci 80f66f451Sopenharmony_ci#include <ctype.h> 90f66f451Sopenharmony_ci#include <stdio.h> 100f66f451Sopenharmony_ci#include <string.h> 110f66f451Sopenharmony_ci#include <stdarg.h> 120f66f451Sopenharmony_ci#include <stdlib.h> 130f66f451Sopenharmony_ci#include <sys/types.h> 140f66f451Sopenharmony_ci#include <sys/stat.h> 150f66f451Sopenharmony_ci#include <unistd.h> 160f66f451Sopenharmony_ci#include <regex.h> 170f66f451Sopenharmony_ci#include <inttypes.h> 180f66f451Sopenharmony_ci#include <termios.h> 190f66f451Sopenharmony_ci#include <poll.h> 200f66f451Sopenharmony_ci#include <sys/socket.h> 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ci//****************** functions copied from lib/*.c ******************** 230f66f451Sopenharmony_ci 240f66f451Sopenharmony_cistruct double_list { 250f66f451Sopenharmony_ci struct double_list *next, *prev; 260f66f451Sopenharmony_ci char *data; 270f66f451Sopenharmony_ci}; 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ci// Die unless we can allocate memory. 300f66f451Sopenharmony_civoid *xmalloc(size_t size) 310f66f451Sopenharmony_ci{ 320f66f451Sopenharmony_ci void *ret = malloc(size); 330f66f451Sopenharmony_ci if (!ret) { 340f66f451Sopenharmony_ci fprintf(stderr, "xmalloc(%ld)", (long)size); 350f66f451Sopenharmony_ci exit(1); 360f66f451Sopenharmony_ci } 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci return ret; 390f66f451Sopenharmony_ci} 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci// Die unless we can allocate enough space to sprintf() into. 420f66f451Sopenharmony_cichar *xmprintf(char *format, ...) 430f66f451Sopenharmony_ci{ 440f66f451Sopenharmony_ci va_list va, va2; 450f66f451Sopenharmony_ci int len; 460f66f451Sopenharmony_ci char *ret; 470f66f451Sopenharmony_ci 480f66f451Sopenharmony_ci va_start(va, format); 490f66f451Sopenharmony_ci va_copy(va2, va); 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci // How long is it? 520f66f451Sopenharmony_ci len = vsnprintf(0, 0, format, va); 530f66f451Sopenharmony_ci len++; 540f66f451Sopenharmony_ci va_end(va); 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci // Allocate and do the sprintf() 570f66f451Sopenharmony_ci ret = xmalloc(len); 580f66f451Sopenharmony_ci vsnprintf(ret, len, format, va2); 590f66f451Sopenharmony_ci va_end(va2); 600f66f451Sopenharmony_ci 610f66f451Sopenharmony_ci return ret; 620f66f451Sopenharmony_ci} 630f66f451Sopenharmony_ci 640f66f451Sopenharmony_ci// Die unless we can open/create a file, returning FILE *. 650f66f451Sopenharmony_ciFILE *xfopen(char *path, char *mode) 660f66f451Sopenharmony_ci{ 670f66f451Sopenharmony_ci FILE *f = fopen(path, mode); 680f66f451Sopenharmony_ci if (!f) { 690f66f451Sopenharmony_ci fprintf(stderr, "No file %s", path); 700f66f451Sopenharmony_ci exit(1); 710f66f451Sopenharmony_ci } 720f66f451Sopenharmony_ci return f; 730f66f451Sopenharmony_ci} 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_civoid *dlist_pop(void *list) 760f66f451Sopenharmony_ci{ 770f66f451Sopenharmony_ci struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist; 780f66f451Sopenharmony_ci 790f66f451Sopenharmony_ci if (dlist->next == dlist) *pdlist = 0; 800f66f451Sopenharmony_ci else { 810f66f451Sopenharmony_ci dlist->next->prev = dlist->prev; 820f66f451Sopenharmony_ci dlist->prev->next = *pdlist = dlist->next; 830f66f451Sopenharmony_ci } 840f66f451Sopenharmony_ci 850f66f451Sopenharmony_ci return dlist; 860f66f451Sopenharmony_ci} 870f66f451Sopenharmony_ci 880f66f451Sopenharmony_civoid dlist_add_nomalloc(struct double_list **list, struct double_list *new) 890f66f451Sopenharmony_ci{ 900f66f451Sopenharmony_ci if (*list) { 910f66f451Sopenharmony_ci new->next = *list; 920f66f451Sopenharmony_ci new->prev = (*list)->prev; 930f66f451Sopenharmony_ci (*list)->prev->next = new; 940f66f451Sopenharmony_ci (*list)->prev = new; 950f66f451Sopenharmony_ci } else *list = new->next = new->prev = new; 960f66f451Sopenharmony_ci} 970f66f451Sopenharmony_ci 980f66f451Sopenharmony_ci 990f66f451Sopenharmony_ci// Add an entry to the end of a doubly linked list 1000f66f451Sopenharmony_cistruct double_list *dlist_add(struct double_list **list, char *data) 1010f66f451Sopenharmony_ci{ 1020f66f451Sopenharmony_ci struct double_list *new = xmalloc(sizeof(struct double_list)); 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci new->data = data; 1050f66f451Sopenharmony_ci dlist_add_nomalloc(list, new); 1060f66f451Sopenharmony_ci 1070f66f451Sopenharmony_ci return new; 1080f66f451Sopenharmony_ci} 1090f66f451Sopenharmony_ci 1100f66f451Sopenharmony_ci//****************** end copies of lib/*.c ************* 1110f66f451Sopenharmony_ci 1120f66f451Sopenharmony_ci// Parse config files into data structures. 1130f66f451Sopenharmony_ci 1140f66f451Sopenharmony_cistruct symbol { 1150f66f451Sopenharmony_ci struct symbol *next; 1160f66f451Sopenharmony_ci int enabled, help_indent; 1170f66f451Sopenharmony_ci char *name, *depends; 1180f66f451Sopenharmony_ci struct double_list *help; 1190f66f451Sopenharmony_ci} *sym; 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_ci// remove leading spaces 1220f66f451Sopenharmony_cichar *skip_spaces(char *s) 1230f66f451Sopenharmony_ci{ 1240f66f451Sopenharmony_ci while (isspace(*s)) s++; 1250f66f451Sopenharmony_ci 1260f66f451Sopenharmony_ci return s; 1270f66f451Sopenharmony_ci} 1280f66f451Sopenharmony_ci 1290f66f451Sopenharmony_ci// if line starts with name (as whole word) return pointer after it, else NULL 1300f66f451Sopenharmony_cichar *keyword(char *name, char *line) 1310f66f451Sopenharmony_ci{ 1320f66f451Sopenharmony_ci int len = strlen(name); 1330f66f451Sopenharmony_ci 1340f66f451Sopenharmony_ci line = skip_spaces(line); 1350f66f451Sopenharmony_ci if (strncmp(name, line, len)) return 0; 1360f66f451Sopenharmony_ci line += len; 1370f66f451Sopenharmony_ci if (*line && !isspace(*line)) return 0; 1380f66f451Sopenharmony_ci line = skip_spaces(line); 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci return line; 1410f66f451Sopenharmony_ci} 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci// dlist_pop() freeing wrapper structure for you. 1440f66f451Sopenharmony_cichar *dlist_zap(struct double_list **help) 1450f66f451Sopenharmony_ci{ 1460f66f451Sopenharmony_ci struct double_list *dd = dlist_pop(help); 1470f66f451Sopenharmony_ci char *s = dd->data; 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_ci free(dd); 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci return s; 1520f66f451Sopenharmony_ci} 1530f66f451Sopenharmony_ci 1540f66f451Sopenharmony_ciint zap_blank_lines(struct double_list **help) 1550f66f451Sopenharmony_ci{ 1560f66f451Sopenharmony_ci int got = 0; 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci while (*help) { 1590f66f451Sopenharmony_ci char *s; 1600f66f451Sopenharmony_ci 1610f66f451Sopenharmony_ci s = skip_spaces((*help)->data); 1620f66f451Sopenharmony_ci 1630f66f451Sopenharmony_ci if (*s) break; 1640f66f451Sopenharmony_ci got++; 1650f66f451Sopenharmony_ci free(dlist_zap(help)); 1660f66f451Sopenharmony_ci } 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_ci return got; 1690f66f451Sopenharmony_ci} 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_ci// Collect "-a blah" description lines following a blank line (or start). 1720f66f451Sopenharmony_ci// Returns array of removed lines with *len entries (0 for none). 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_ci// Moves *help to new start of text (in case dash lines were at beginning). 1750f66f451Sopenharmony_ci// Sets *from to where dash lines removed from (in case they weren't). 1760f66f451Sopenharmony_ci// Discards blank lines before and after dashlines. 1770f66f451Sopenharmony_ci 1780f66f451Sopenharmony_ci// If no prefix, *help NULL. If no postfix, *from == *help 1790f66f451Sopenharmony_ci// if no dashlines returned *from == *help. 1800f66f451Sopenharmony_ci 1810f66f451Sopenharmony_cichar **grab_dashlines(struct double_list **help, struct double_list **from, 1820f66f451Sopenharmony_ci int *len) 1830f66f451Sopenharmony_ci{ 1840f66f451Sopenharmony_ci struct double_list *dd; 1850f66f451Sopenharmony_ci char *s, **list; 1860f66f451Sopenharmony_ci int count = 0; 1870f66f451Sopenharmony_ci 1880f66f451Sopenharmony_ci *len = 0; 1890f66f451Sopenharmony_ci zap_blank_lines(help); 1900f66f451Sopenharmony_ci *from = *help; 1910f66f451Sopenharmony_ci 1920f66f451Sopenharmony_ci // Find start of dash block. Must be at start or after blank line. 1930f66f451Sopenharmony_ci for (;;) { 1940f66f451Sopenharmony_ci s = skip_spaces((*from)->data); 1950f66f451Sopenharmony_ci if (*s == '-' && s[1] != '-' && !count) break; 1960f66f451Sopenharmony_ci 1970f66f451Sopenharmony_ci if (!*s) count = 0; 1980f66f451Sopenharmony_ci else count++; 1990f66f451Sopenharmony_ci 2000f66f451Sopenharmony_ci *from = (*from)->next; 2010f66f451Sopenharmony_ci if (*from == *help) return 0; 2020f66f451Sopenharmony_ci } 2030f66f451Sopenharmony_ci 2040f66f451Sopenharmony_ci // If there was whitespace before this, zap it. This can't take out *help 2050f66f451Sopenharmony_ci // because zap_blank_lines skipped blank lines, and we had to have at least 2060f66f451Sopenharmony_ci // one non-blank line (a dash line) to get this far. 2070f66f451Sopenharmony_ci while (!*skip_spaces((*from)->prev->data)) { 2080f66f451Sopenharmony_ci *from = (*from)->prev; 2090f66f451Sopenharmony_ci free(dlist_zap(from)); 2100f66f451Sopenharmony_ci } 2110f66f451Sopenharmony_ci 2120f66f451Sopenharmony_ci // Count number of dashlines, copy out to array, zap trailing whitespace 2130f66f451Sopenharmony_ci // If *help was at start of dashblock, move it with *from 2140f66f451Sopenharmony_ci count = 0; 2150f66f451Sopenharmony_ci dd = *from; 2160f66f451Sopenharmony_ci if (*help == *from) *help = 0; 2170f66f451Sopenharmony_ci for (;;) { 2180f66f451Sopenharmony_ci if (*skip_spaces(dd->data) != '-') break; 2190f66f451Sopenharmony_ci count++; 2200f66f451Sopenharmony_ci if (*from == (dd = dd->next)) break; 2210f66f451Sopenharmony_ci } 2220f66f451Sopenharmony_ci 2230f66f451Sopenharmony_ci list = xmalloc(sizeof(char *)*count); 2240f66f451Sopenharmony_ci *len = count; 2250f66f451Sopenharmony_ci while (count) list[--count] = dlist_zap(from); 2260f66f451Sopenharmony_ci 2270f66f451Sopenharmony_ci return list; 2280f66f451Sopenharmony_ci} 2290f66f451Sopenharmony_ci 2300f66f451Sopenharmony_ci// Read Config.in (and includes) to populate global struct symbol *sym list. 2310f66f451Sopenharmony_civoid parse(char *filename) 2320f66f451Sopenharmony_ci{ 2330f66f451Sopenharmony_ci FILE *fp = xfopen(filename, "r"); 2340f66f451Sopenharmony_ci struct symbol *new = 0; 2350f66f451Sopenharmony_ci 2360f66f451Sopenharmony_ci for (;;) { 2370f66f451Sopenharmony_ci char *s, *line = NULL; 2380f66f451Sopenharmony_ci size_t len; 2390f66f451Sopenharmony_ci 2400f66f451Sopenharmony_ci // Read line, trim whitespace at right edge. 2410f66f451Sopenharmony_ci if (getline(&line, &len, fp) < 1) break; 2420f66f451Sopenharmony_ci s = line+strlen(line); 2430f66f451Sopenharmony_ci while (--s >= line) { 2440f66f451Sopenharmony_ci if (!isspace(*s)) break; 2450f66f451Sopenharmony_ci *s = 0; 2460f66f451Sopenharmony_ci } 2470f66f451Sopenharmony_ci 2480f66f451Sopenharmony_ci // source or config keyword at left edge? 2490f66f451Sopenharmony_ci if (*line && !isspace(*line)) { 2500f66f451Sopenharmony_ci if ((s = keyword("config", line))) { 2510f66f451Sopenharmony_ci memset(new = xmalloc(sizeof(struct symbol)), 0, sizeof(struct symbol)); 2520f66f451Sopenharmony_ci new->next = sym; 2530f66f451Sopenharmony_ci new->name = s; 2540f66f451Sopenharmony_ci sym = new; 2550f66f451Sopenharmony_ci } else if ((s = keyword("source", line))) parse(s); 2560f66f451Sopenharmony_ci 2570f66f451Sopenharmony_ci continue; 2580f66f451Sopenharmony_ci } 2590f66f451Sopenharmony_ci if (!new) continue; 2600f66f451Sopenharmony_ci 2610f66f451Sopenharmony_ci if (sym && sym->help_indent) { 2620f66f451Sopenharmony_ci dlist_add(&(new->help), line); 2630f66f451Sopenharmony_ci if (sym->help_indent < 0) { 2640f66f451Sopenharmony_ci sym->help_indent = 0; 2650f66f451Sopenharmony_ci while (isspace(line[sym->help_indent])) sym->help_indent++; 2660f66f451Sopenharmony_ci } 2670f66f451Sopenharmony_ci } 2680f66f451Sopenharmony_ci else if ((s = keyword("depends", line)) && (s = keyword("on", s))) 2690f66f451Sopenharmony_ci new->depends = s; 2700f66f451Sopenharmony_ci else if (keyword("help", line)) sym->help_indent = -1; 2710f66f451Sopenharmony_ci } 2720f66f451Sopenharmony_ci 2730f66f451Sopenharmony_ci fclose(fp); 2740f66f451Sopenharmony_ci} 2750f66f451Sopenharmony_ci 2760f66f451Sopenharmony_ciint charsort(void *a, void *b) 2770f66f451Sopenharmony_ci{ 2780f66f451Sopenharmony_ci char *aa = a, *bb = b; 2790f66f451Sopenharmony_ci 2800f66f451Sopenharmony_ci if (*aa < *bb) return -1; 2810f66f451Sopenharmony_ci if (*aa > *bb) return 1; 2820f66f451Sopenharmony_ci return 0; 2830f66f451Sopenharmony_ci} 2840f66f451Sopenharmony_ci 2850f66f451Sopenharmony_ciint dashsort(char **a, char **b) 2860f66f451Sopenharmony_ci{ 2870f66f451Sopenharmony_ci char *aa = *a, *bb = *b; 2880f66f451Sopenharmony_ci 2890f66f451Sopenharmony_ci if (aa[1] < bb[1]) return -1; 2900f66f451Sopenharmony_ci if (aa[1] > bb[1]) return 1; 2910f66f451Sopenharmony_ci return 0; 2920f66f451Sopenharmony_ci} 2930f66f451Sopenharmony_ci 2940f66f451Sopenharmony_ciint dashlinesort(char **a, char **b) 2950f66f451Sopenharmony_ci{ 2960f66f451Sopenharmony_ci return strcmp(*a, *b); 2970f66f451Sopenharmony_ci} 2980f66f451Sopenharmony_ci 2990f66f451Sopenharmony_ci// Three stages: read data, collate entries, output results. 3000f66f451Sopenharmony_ci 3010f66f451Sopenharmony_ciint main(int argc, char *argv[]) 3020f66f451Sopenharmony_ci{ 3030f66f451Sopenharmony_ci FILE *fp; 3040f66f451Sopenharmony_ci 3050f66f451Sopenharmony_ci if (argc != 3) { 3060f66f451Sopenharmony_ci fprintf(stderr, "usage: config2help Config.in .config\n"); 3070f66f451Sopenharmony_ci exit(1); 3080f66f451Sopenharmony_ci } 3090f66f451Sopenharmony_ci 3100f66f451Sopenharmony_ci // Stage 1: read data. Read Config.in to global 'struct symbol *sym' list, 3110f66f451Sopenharmony_ci // then read .config to set "enabled" member of each enabled symbol. 3120f66f451Sopenharmony_ci 3130f66f451Sopenharmony_ci // Read Config.in 3140f66f451Sopenharmony_ci parse(argv[1]); 3150f66f451Sopenharmony_ci 3160f66f451Sopenharmony_ci // read .config 3170f66f451Sopenharmony_ci fp = xfopen(argv[2], "r"); 3180f66f451Sopenharmony_ci for (;;) { 3190f66f451Sopenharmony_ci char *line = NULL; 3200f66f451Sopenharmony_ci size_t len; 3210f66f451Sopenharmony_ci 3220f66f451Sopenharmony_ci if (getline(&line, &len, fp) < 1) break; 3230f66f451Sopenharmony_ci if (!strncmp("CONFIG_", line, 7)) { 3240f66f451Sopenharmony_ci struct symbol *try; 3250f66f451Sopenharmony_ci char *s = line+7; 3260f66f451Sopenharmony_ci 3270f66f451Sopenharmony_ci for (try=sym; try; try=try->next) { 3280f66f451Sopenharmony_ci len = strlen(try->name); 3290f66f451Sopenharmony_ci if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') { 3300f66f451Sopenharmony_ci try->enabled++; 3310f66f451Sopenharmony_ci break; 3320f66f451Sopenharmony_ci } 3330f66f451Sopenharmony_ci } 3340f66f451Sopenharmony_ci } 3350f66f451Sopenharmony_ci } 3360f66f451Sopenharmony_ci 3370f66f451Sopenharmony_ci // Stage 2: process data. 3380f66f451Sopenharmony_ci 3390f66f451Sopenharmony_ci // Collate help according to usage, depends, and .config 3400f66f451Sopenharmony_ci 3410f66f451Sopenharmony_ci // Loop through each entry, finding duplicate enabled "usage:" names 3420f66f451Sopenharmony_ci // This is in reverse order, so last entry gets collated with previous 3430f66f451Sopenharmony_ci // entry until we run out of matching pairs. 3440f66f451Sopenharmony_ci for (;;) { 3450f66f451Sopenharmony_ci struct symbol *throw = 0, *catch; 3460f66f451Sopenharmony_ci char *this, *that, *cusage, *tusage, *name = 0; 3470f66f451Sopenharmony_ci int len; 3480f66f451Sopenharmony_ci 3490f66f451Sopenharmony_ci // find a usage: name and collate all enabled entries with that name 3500f66f451Sopenharmony_ci for (catch = sym; catch; catch = catch->next) { 3510f66f451Sopenharmony_ci if (catch->enabled != 1) continue; 3520f66f451Sopenharmony_ci if (catch->help && (that = keyword("usage:", catch->help->data))) { 3530f66f451Sopenharmony_ci struct double_list *cfrom, *tfrom, *anchor; 3540f66f451Sopenharmony_ci char *try, **cdashlines, **tdashlines, *usage; 3550f66f451Sopenharmony_ci int clen, tlen; 3560f66f451Sopenharmony_ci 3570f66f451Sopenharmony_ci // Align usage: lines, finding a matching pair so we can suck help 3580f66f451Sopenharmony_ci // text out of throw into catch, copying from this to that 3590f66f451Sopenharmony_ci if (!throw) usage = that; 3600f66f451Sopenharmony_ci else if (strncmp(name, that, len) || !isspace(that[len])) continue; 3610f66f451Sopenharmony_ci catch->enabled++; 3620f66f451Sopenharmony_ci while (!isspace(*that) && *that) that++; 3630f66f451Sopenharmony_ci if (!throw) len = that-usage; 3640f66f451Sopenharmony_ci free(name); 3650f66f451Sopenharmony_ci name = strndup(usage, len); 3660f66f451Sopenharmony_ci that = skip_spaces(that); 3670f66f451Sopenharmony_ci if (!throw) { 3680f66f451Sopenharmony_ci throw = catch; 3690f66f451Sopenharmony_ci this = that; 3700f66f451Sopenharmony_ci 3710f66f451Sopenharmony_ci continue; 3720f66f451Sopenharmony_ci } 3730f66f451Sopenharmony_ci 3740f66f451Sopenharmony_ci // Grab option description lines to collate from catch and throw 3750f66f451Sopenharmony_ci tusage = dlist_zap(&throw->help); 3760f66f451Sopenharmony_ci tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen); 3770f66f451Sopenharmony_ci cusage = dlist_zap(&catch->help); 3780f66f451Sopenharmony_ci cdashlines = grab_dashlines(&catch->help, &cfrom, &clen); 3790f66f451Sopenharmony_ci anchor = catch->help; 3800f66f451Sopenharmony_ci 3810f66f451Sopenharmony_ci // If we've got both, collate and alphebetize 3820f66f451Sopenharmony_ci if (cdashlines && tdashlines) { 3830f66f451Sopenharmony_ci char **new = xmalloc(sizeof(char *)*(clen+tlen)); 3840f66f451Sopenharmony_ci 3850f66f451Sopenharmony_ci memcpy(new, cdashlines, sizeof(char *)*clen); 3860f66f451Sopenharmony_ci memcpy(new+clen, tdashlines, sizeof(char *)*tlen); 3870f66f451Sopenharmony_ci free(cdashlines); 3880f66f451Sopenharmony_ci free(tdashlines); 3890f66f451Sopenharmony_ci qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort); 3900f66f451Sopenharmony_ci cdashlines = new; 3910f66f451Sopenharmony_ci 3920f66f451Sopenharmony_ci // If just one, make sure it's in catch. 3930f66f451Sopenharmony_ci } else if (tdashlines) cdashlines = tdashlines; 3940f66f451Sopenharmony_ci 3950f66f451Sopenharmony_ci // If throw had a prefix, insert it before dashlines, with a 3960f66f451Sopenharmony_ci // blank line if catch had a prefix. 3970f66f451Sopenharmony_ci if (tfrom && tfrom != throw->help) { 3980f66f451Sopenharmony_ci if (throw->help || catch->help) dlist_add(&cfrom, strdup("")); 3990f66f451Sopenharmony_ci else { 4000f66f451Sopenharmony_ci dlist_add(&cfrom, 0); 4010f66f451Sopenharmony_ci anchor = cfrom->prev; 4020f66f451Sopenharmony_ci } 4030f66f451Sopenharmony_ci while (throw->help && throw->help != tfrom) 4040f66f451Sopenharmony_ci dlist_add(&cfrom, dlist_zap(&throw->help)); 4050f66f451Sopenharmony_ci if (cfrom && cfrom->prev->data && *skip_spaces(cfrom->prev->data)) 4060f66f451Sopenharmony_ci dlist_add(&cfrom, strdup("")); 4070f66f451Sopenharmony_ci } 4080f66f451Sopenharmony_ci if (!anchor) { 4090f66f451Sopenharmony_ci dlist_add(&cfrom, 0); 4100f66f451Sopenharmony_ci anchor = cfrom->prev; 4110f66f451Sopenharmony_ci } 4120f66f451Sopenharmony_ci 4130f66f451Sopenharmony_ci // Splice sorted lines back in place 4140f66f451Sopenharmony_ci if (cdashlines) { 4150f66f451Sopenharmony_ci tlen += clen; 4160f66f451Sopenharmony_ci 4170f66f451Sopenharmony_ci for (clen = 0; clen < tlen; clen++) 4180f66f451Sopenharmony_ci dlist_add(&cfrom, cdashlines[clen]); 4190f66f451Sopenharmony_ci } 4200f66f451Sopenharmony_ci 4210f66f451Sopenharmony_ci // If there were no dashlines, text would be considered prefix, so 4220f66f451Sopenharmony_ci // the list is definitely no longer empty, so discard placeholder. 4230f66f451Sopenharmony_ci if (!anchor->data) dlist_zap(&anchor); 4240f66f451Sopenharmony_ci 4250f66f451Sopenharmony_ci // zap whitespace at end of catch help text 4260f66f451Sopenharmony_ci while (!*skip_spaces(anchor->prev->data)) { 4270f66f451Sopenharmony_ci anchor = anchor->prev; 4280f66f451Sopenharmony_ci free(dlist_zap(&anchor)); 4290f66f451Sopenharmony_ci } 4300f66f451Sopenharmony_ci 4310f66f451Sopenharmony_ci // Append trailing lines. 4320f66f451Sopenharmony_ci while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom)); 4330f66f451Sopenharmony_ci 4340f66f451Sopenharmony_ci // Collate first [-abc] option block in usage: lines 4350f66f451Sopenharmony_ci try = 0; 4360f66f451Sopenharmony_ci if (*this == '[' && this[1] == '-' && this[2] != '-' && 4370f66f451Sopenharmony_ci *that == '[' && that[1] == '-' && that[2] != '-') 4380f66f451Sopenharmony_ci { 4390f66f451Sopenharmony_ci char *from = this+2, *to = that+2; 4400f66f451Sopenharmony_ci int ff = strcspn(from, " ]"), tt = strcspn(to, " ]"); 4410f66f451Sopenharmony_ci 4420f66f451Sopenharmony_ci if (from[ff] == ']' && to[tt] == ']') { 4430f66f451Sopenharmony_ci try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to); 4440f66f451Sopenharmony_ci qsort(try+2, ff+tt, 1, (void *)charsort); 4450f66f451Sopenharmony_ci this = skip_spaces(this+ff+3); 4460f66f451Sopenharmony_ci that = skip_spaces(that+tt+3); 4470f66f451Sopenharmony_ci } 4480f66f451Sopenharmony_ci } 4490f66f451Sopenharmony_ci 4500f66f451Sopenharmony_ci // The list is definitely no longer empty, so discard placeholder. 4510f66f451Sopenharmony_ci if (!anchor->data) dlist_zap(&anchor); 4520f66f451Sopenharmony_ci 4530f66f451Sopenharmony_ci // Add new collated line (and whitespace). 4540f66f451Sopenharmony_ci dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s", 4550f66f451Sopenharmony_ci catch->help_indent, ' ', len, name, try ? try : "", 4560f66f451Sopenharmony_ci this, *this ? " " : "", that)); 4570f66f451Sopenharmony_ci free(try); 4580f66f451Sopenharmony_ci dlist_add(&anchor, strdup("")); 4590f66f451Sopenharmony_ci free(cusage); 4600f66f451Sopenharmony_ci free(tusage); 4610f66f451Sopenharmony_ci throw->enabled = 0; 4620f66f451Sopenharmony_ci throw = catch; 4630f66f451Sopenharmony_ci throw->help = anchor->prev->prev; 4640f66f451Sopenharmony_ci 4650f66f451Sopenharmony_ci throw = catch; 4660f66f451Sopenharmony_ci this = throw->help->data + throw->help_indent + 8 + len; 4670f66f451Sopenharmony_ci } 4680f66f451Sopenharmony_ci } 4690f66f451Sopenharmony_ci 4700f66f451Sopenharmony_ci // Did we find one? 4710f66f451Sopenharmony_ci 4720f66f451Sopenharmony_ci if (!throw) break; 4730f66f451Sopenharmony_ci } 4740f66f451Sopenharmony_ci 4750f66f451Sopenharmony_ci // Stage 3: output results to stdout. 4760f66f451Sopenharmony_ci 4770f66f451Sopenharmony_ci // Print out help #defines 4780f66f451Sopenharmony_ci while (sym) { 4790f66f451Sopenharmony_ci struct double_list *dd; 4800f66f451Sopenharmony_ci 4810f66f451Sopenharmony_ci if (sym->help) { 4820f66f451Sopenharmony_ci int i, blank; 4830f66f451Sopenharmony_ci char *s; 4840f66f451Sopenharmony_ci 4850f66f451Sopenharmony_ci strcpy(s = xmalloc(strlen(sym->name)+1), sym->name); 4860f66f451Sopenharmony_ci 4870f66f451Sopenharmony_ci for (i = 0; s[i]; i++) s[i] = tolower(s[i]); 4880f66f451Sopenharmony_ci printf("#define HELP_%s \"", s); 4890f66f451Sopenharmony_ci free(s); 4900f66f451Sopenharmony_ci 4910f66f451Sopenharmony_ci dd = sym->help; 4920f66f451Sopenharmony_ci blank = 0; 4930f66f451Sopenharmony_ci for (;;) { 4940f66f451Sopenharmony_ci 4950f66f451Sopenharmony_ci // Trim leading whitespace 4960f66f451Sopenharmony_ci s = dd->data; 4970f66f451Sopenharmony_ci i = sym->help_indent; 4980f66f451Sopenharmony_ci while (isspace(*s) && i--) s++; 4990f66f451Sopenharmony_ci 5000f66f451Sopenharmony_ci // Only one blank line between nonblank lines, not at start or end. 5010f66f451Sopenharmony_ci if (!*s) blank = 2; 5020f66f451Sopenharmony_ci else { 5030f66f451Sopenharmony_ci while (blank--) { 5040f66f451Sopenharmony_ci putchar('\\'); 5050f66f451Sopenharmony_ci putchar('n'); 5060f66f451Sopenharmony_ci } 5070f66f451Sopenharmony_ci blank = 1; 5080f66f451Sopenharmony_ci } 5090f66f451Sopenharmony_ci 5100f66f451Sopenharmony_ci for (i=0; s[i]; i++) { 5110f66f451Sopenharmony_ci if (s[i] == '"' || s[i] == '\\') putchar('\\'); 5120f66f451Sopenharmony_ci putchar(s[i]); 5130f66f451Sopenharmony_ci } 5140f66f451Sopenharmony_ci dd = dd->next; 5150f66f451Sopenharmony_ci if (dd == sym->help) break; 5160f66f451Sopenharmony_ci } 5170f66f451Sopenharmony_ci printf("\"\n\n"); 5180f66f451Sopenharmony_ci } 5190f66f451Sopenharmony_ci sym = sym->next; 5200f66f451Sopenharmony_ci } 5210f66f451Sopenharmony_ci 5220f66f451Sopenharmony_ci return 0; 5230f66f451Sopenharmony_ci} 524