xref: /aosp_15_r20/external/toybox/scripts/config2help.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* config2.help.c - config2hep Config.in .config > help.h
2*cf5a6c84SAndroid Build Coastguard Worker 
3*cf5a6c84SAndroid Build Coastguard Worker    function parse() reads Config.in data into *sym list, then
4*cf5a6c84SAndroid Build Coastguard Worker    we read .config and set sym->try on each enabled symbol.
5*cf5a6c84SAndroid Build Coastguard Worker 
6*cf5a6c84SAndroid Build Coastguard Worker */
7*cf5a6c84SAndroid Build Coastguard Worker 
8*cf5a6c84SAndroid Build Coastguard Worker #include <ctype.h>
9*cf5a6c84SAndroid Build Coastguard Worker #include <stdio.h>
10*cf5a6c84SAndroid Build Coastguard Worker #include <string.h>
11*cf5a6c84SAndroid Build Coastguard Worker #include <stdarg.h>
12*cf5a6c84SAndroid Build Coastguard Worker #include <stdlib.h>
13*cf5a6c84SAndroid Build Coastguard Worker #include <sys/types.h>
14*cf5a6c84SAndroid Build Coastguard Worker #include <sys/stat.h>
15*cf5a6c84SAndroid Build Coastguard Worker #include <unistd.h>
16*cf5a6c84SAndroid Build Coastguard Worker #include <regex.h>
17*cf5a6c84SAndroid Build Coastguard Worker #include <inttypes.h>
18*cf5a6c84SAndroid Build Coastguard Worker #include <termios.h>
19*cf5a6c84SAndroid Build Coastguard Worker #include <poll.h>
20*cf5a6c84SAndroid Build Coastguard Worker #include <sys/socket.h>
21*cf5a6c84SAndroid Build Coastguard Worker 
22*cf5a6c84SAndroid Build Coastguard Worker //****************** functions copied from lib/*.c ********************
23*cf5a6c84SAndroid Build Coastguard Worker 
24*cf5a6c84SAndroid Build Coastguard Worker struct double_list {
25*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *next, *prev;
26*cf5a6c84SAndroid Build Coastguard Worker   char *data;
27*cf5a6c84SAndroid Build Coastguard Worker };
28*cf5a6c84SAndroid Build Coastguard Worker 
29*cf5a6c84SAndroid Build Coastguard Worker // Die unless we can allocate memory.
xmalloc(size_t size)30*cf5a6c84SAndroid Build Coastguard Worker void *xmalloc(size_t size)
31*cf5a6c84SAndroid Build Coastguard Worker {
32*cf5a6c84SAndroid Build Coastguard Worker   void *ret = malloc(size);
33*cf5a6c84SAndroid Build Coastguard Worker   if (!ret) {
34*cf5a6c84SAndroid Build Coastguard Worker     fprintf(stderr, "xmalloc(%ld)", (long)size);
35*cf5a6c84SAndroid Build Coastguard Worker     exit(1);
36*cf5a6c84SAndroid Build Coastguard Worker   }
37*cf5a6c84SAndroid Build Coastguard Worker 
38*cf5a6c84SAndroid Build Coastguard Worker   return ret;
39*cf5a6c84SAndroid Build Coastguard Worker }
40*cf5a6c84SAndroid Build Coastguard Worker 
41*cf5a6c84SAndroid Build Coastguard Worker // Die unless we can allocate enough space to sprintf() into.
xmprintf(char * format,...)42*cf5a6c84SAndroid Build Coastguard Worker char *xmprintf(char *format, ...)
43*cf5a6c84SAndroid Build Coastguard Worker {
44*cf5a6c84SAndroid Build Coastguard Worker   va_list va, va2;
45*cf5a6c84SAndroid Build Coastguard Worker   int len;
46*cf5a6c84SAndroid Build Coastguard Worker   char *ret;
47*cf5a6c84SAndroid Build Coastguard Worker 
48*cf5a6c84SAndroid Build Coastguard Worker   va_start(va, format);
49*cf5a6c84SAndroid Build Coastguard Worker   va_copy(va2, va);
50*cf5a6c84SAndroid Build Coastguard Worker 
51*cf5a6c84SAndroid Build Coastguard Worker   // How long is it?
52*cf5a6c84SAndroid Build Coastguard Worker   len = vsnprintf(0, 0, format, va);
53*cf5a6c84SAndroid Build Coastguard Worker   len++;
54*cf5a6c84SAndroid Build Coastguard Worker   va_end(va);
55*cf5a6c84SAndroid Build Coastguard Worker 
56*cf5a6c84SAndroid Build Coastguard Worker   // Allocate and do the sprintf()
57*cf5a6c84SAndroid Build Coastguard Worker   ret = xmalloc(len);
58*cf5a6c84SAndroid Build Coastguard Worker   vsnprintf(ret, len, format, va2);
59*cf5a6c84SAndroid Build Coastguard Worker   va_end(va2);
60*cf5a6c84SAndroid Build Coastguard Worker 
61*cf5a6c84SAndroid Build Coastguard Worker   return ret;
62*cf5a6c84SAndroid Build Coastguard Worker }
63*cf5a6c84SAndroid Build Coastguard Worker 
64*cf5a6c84SAndroid Build Coastguard Worker // Die unless we can open/create a file, returning FILE *.
xfopen(char * path,char * mode)65*cf5a6c84SAndroid Build Coastguard Worker FILE *xfopen(char *path, char *mode)
66*cf5a6c84SAndroid Build Coastguard Worker {
67*cf5a6c84SAndroid Build Coastguard Worker   FILE *f = fopen(path, mode);
68*cf5a6c84SAndroid Build Coastguard Worker   if (!f) {
69*cf5a6c84SAndroid Build Coastguard Worker     fprintf(stderr, "No file %s", path);
70*cf5a6c84SAndroid Build Coastguard Worker     exit(1);
71*cf5a6c84SAndroid Build Coastguard Worker   }
72*cf5a6c84SAndroid Build Coastguard Worker   return f;
73*cf5a6c84SAndroid Build Coastguard Worker }
74*cf5a6c84SAndroid Build Coastguard Worker 
dlist_pop(void * list)75*cf5a6c84SAndroid Build Coastguard Worker void *dlist_pop(void *list)
76*cf5a6c84SAndroid Build Coastguard Worker {
77*cf5a6c84SAndroid Build Coastguard Worker   struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
78*cf5a6c84SAndroid Build Coastguard Worker 
79*cf5a6c84SAndroid Build Coastguard Worker   if (dlist->next == dlist) *pdlist = 0;
80*cf5a6c84SAndroid Build Coastguard Worker   else {
81*cf5a6c84SAndroid Build Coastguard Worker     dlist->next->prev = dlist->prev;
82*cf5a6c84SAndroid Build Coastguard Worker     dlist->prev->next = *pdlist = dlist->next;
83*cf5a6c84SAndroid Build Coastguard Worker   }
84*cf5a6c84SAndroid Build Coastguard Worker 
85*cf5a6c84SAndroid Build Coastguard Worker   return dlist;
86*cf5a6c84SAndroid Build Coastguard Worker }
87*cf5a6c84SAndroid Build Coastguard Worker 
dlist_add_nomalloc(struct double_list ** list,struct double_list * new)88*cf5a6c84SAndroid Build Coastguard Worker void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
89*cf5a6c84SAndroid Build Coastguard Worker {
90*cf5a6c84SAndroid Build Coastguard Worker   if (*list) {
91*cf5a6c84SAndroid Build Coastguard Worker     new->next = *list;
92*cf5a6c84SAndroid Build Coastguard Worker     new->prev = (*list)->prev;
93*cf5a6c84SAndroid Build Coastguard Worker     (*list)->prev->next = new;
94*cf5a6c84SAndroid Build Coastguard Worker     (*list)->prev = new;
95*cf5a6c84SAndroid Build Coastguard Worker   } else *list = new->next = new->prev = new;
96*cf5a6c84SAndroid Build Coastguard Worker }
97*cf5a6c84SAndroid Build Coastguard Worker 
98*cf5a6c84SAndroid Build Coastguard Worker 
99*cf5a6c84SAndroid Build Coastguard Worker // Add an entry to the end of a doubly linked list
dlist_add(struct double_list ** list,char * data)100*cf5a6c84SAndroid Build Coastguard Worker struct double_list *dlist_add(struct double_list **list, char *data)
101*cf5a6c84SAndroid Build Coastguard Worker {
102*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *new = xmalloc(sizeof(struct double_list));
103*cf5a6c84SAndroid Build Coastguard Worker 
104*cf5a6c84SAndroid Build Coastguard Worker   new->data = data;
105*cf5a6c84SAndroid Build Coastguard Worker   dlist_add_nomalloc(list, new);
106*cf5a6c84SAndroid Build Coastguard Worker 
107*cf5a6c84SAndroid Build Coastguard Worker   return new;
108*cf5a6c84SAndroid Build Coastguard Worker }
109*cf5a6c84SAndroid Build Coastguard Worker 
110*cf5a6c84SAndroid Build Coastguard Worker //****************** end copies of lib/*.c *************
111*cf5a6c84SAndroid Build Coastguard Worker 
112*cf5a6c84SAndroid Build Coastguard Worker // Parse config files into data structures.
113*cf5a6c84SAndroid Build Coastguard Worker 
114*cf5a6c84SAndroid Build Coastguard Worker struct symbol {
115*cf5a6c84SAndroid Build Coastguard Worker   struct symbol *next;
116*cf5a6c84SAndroid Build Coastguard Worker   int enabled, help_indent;
117*cf5a6c84SAndroid Build Coastguard Worker   char *name, *depends;
118*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *help;
119*cf5a6c84SAndroid Build Coastguard Worker } *sym;
120*cf5a6c84SAndroid Build Coastguard Worker 
121*cf5a6c84SAndroid Build Coastguard Worker // remove leading spaces
skip_spaces(char * s)122*cf5a6c84SAndroid Build Coastguard Worker char *skip_spaces(char *s)
123*cf5a6c84SAndroid Build Coastguard Worker {
124*cf5a6c84SAndroid Build Coastguard Worker   while (isspace(*s)) s++;
125*cf5a6c84SAndroid Build Coastguard Worker 
126*cf5a6c84SAndroid Build Coastguard Worker   return s;
127*cf5a6c84SAndroid Build Coastguard Worker }
128*cf5a6c84SAndroid Build Coastguard Worker 
129*cf5a6c84SAndroid Build Coastguard Worker // if line starts with name (as whole word) return pointer after it, else NULL
keyword(char * name,char * line)130*cf5a6c84SAndroid Build Coastguard Worker char *keyword(char *name, char *line)
131*cf5a6c84SAndroid Build Coastguard Worker {
132*cf5a6c84SAndroid Build Coastguard Worker   int len = strlen(name);
133*cf5a6c84SAndroid Build Coastguard Worker 
134*cf5a6c84SAndroid Build Coastguard Worker   line = skip_spaces(line);
135*cf5a6c84SAndroid Build Coastguard Worker   if (strncmp(name, line, len)) return 0;
136*cf5a6c84SAndroid Build Coastguard Worker   line += len;
137*cf5a6c84SAndroid Build Coastguard Worker   if (*line && !isspace(*line)) return 0;
138*cf5a6c84SAndroid Build Coastguard Worker   line = skip_spaces(line);
139*cf5a6c84SAndroid Build Coastguard Worker 
140*cf5a6c84SAndroid Build Coastguard Worker   return line;
141*cf5a6c84SAndroid Build Coastguard Worker }
142*cf5a6c84SAndroid Build Coastguard Worker 
143*cf5a6c84SAndroid Build Coastguard Worker // dlist_pop() freeing wrapper structure for you.
dlist_zap(struct double_list ** help)144*cf5a6c84SAndroid Build Coastguard Worker char *dlist_zap(struct double_list **help)
145*cf5a6c84SAndroid Build Coastguard Worker {
146*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *dd = dlist_pop(help);
147*cf5a6c84SAndroid Build Coastguard Worker   char *s = dd->data;
148*cf5a6c84SAndroid Build Coastguard Worker 
149*cf5a6c84SAndroid Build Coastguard Worker   free(dd);
150*cf5a6c84SAndroid Build Coastguard Worker 
151*cf5a6c84SAndroid Build Coastguard Worker   return s;
152*cf5a6c84SAndroid Build Coastguard Worker }
153*cf5a6c84SAndroid Build Coastguard Worker 
zap_blank_lines(struct double_list ** help)154*cf5a6c84SAndroid Build Coastguard Worker int zap_blank_lines(struct double_list **help)
155*cf5a6c84SAndroid Build Coastguard Worker {
156*cf5a6c84SAndroid Build Coastguard Worker   int got = 0;
157*cf5a6c84SAndroid Build Coastguard Worker 
158*cf5a6c84SAndroid Build Coastguard Worker   while (*help) {
159*cf5a6c84SAndroid Build Coastguard Worker     char *s;
160*cf5a6c84SAndroid Build Coastguard Worker 
161*cf5a6c84SAndroid Build Coastguard Worker     s = skip_spaces((*help)->data);
162*cf5a6c84SAndroid Build Coastguard Worker 
163*cf5a6c84SAndroid Build Coastguard Worker     if (*s) break;
164*cf5a6c84SAndroid Build Coastguard Worker     got++;
165*cf5a6c84SAndroid Build Coastguard Worker     free(dlist_zap(help));
166*cf5a6c84SAndroid Build Coastguard Worker   }
167*cf5a6c84SAndroid Build Coastguard Worker 
168*cf5a6c84SAndroid Build Coastguard Worker   return got;
169*cf5a6c84SAndroid Build Coastguard Worker }
170*cf5a6c84SAndroid Build Coastguard Worker 
171*cf5a6c84SAndroid Build Coastguard Worker // Collect "-a blah" description lines following a blank line (or start).
172*cf5a6c84SAndroid Build Coastguard Worker // Returns array of removed lines with *len entries (0 for none).
173*cf5a6c84SAndroid Build Coastguard Worker 
174*cf5a6c84SAndroid Build Coastguard Worker // Moves *help to new start of text (in case dash lines were at beginning).
175*cf5a6c84SAndroid Build Coastguard Worker // Sets *from to where dash lines removed from (in case they weren't).
176*cf5a6c84SAndroid Build Coastguard Worker // Discards blank lines before and after dashlines.
177*cf5a6c84SAndroid Build Coastguard Worker 
178*cf5a6c84SAndroid Build Coastguard Worker // If no prefix, *help NULL. If no postfix, *from == *help
179*cf5a6c84SAndroid Build Coastguard Worker // if no dashlines returned *from == *help.
180*cf5a6c84SAndroid Build Coastguard Worker 
grab_dashlines(struct double_list ** help,struct double_list ** from,int * len)181*cf5a6c84SAndroid Build Coastguard Worker char **grab_dashlines(struct double_list **help, struct double_list **from,
182*cf5a6c84SAndroid Build Coastguard Worker                       int *len)
183*cf5a6c84SAndroid Build Coastguard Worker {
184*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *dd;
185*cf5a6c84SAndroid Build Coastguard Worker   char *s, **list;
186*cf5a6c84SAndroid Build Coastguard Worker   int count = 0;
187*cf5a6c84SAndroid Build Coastguard Worker 
188*cf5a6c84SAndroid Build Coastguard Worker   *len = 0;
189*cf5a6c84SAndroid Build Coastguard Worker   zap_blank_lines(help);
190*cf5a6c84SAndroid Build Coastguard Worker   *from = *help;
191*cf5a6c84SAndroid Build Coastguard Worker 
192*cf5a6c84SAndroid Build Coastguard Worker   // Find start of dash block. Must be at start or after blank line.
193*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
194*cf5a6c84SAndroid Build Coastguard Worker     s = skip_spaces((*from)->data);
195*cf5a6c84SAndroid Build Coastguard Worker     if (*s == '-' && s[1] != '-' && !count) break;
196*cf5a6c84SAndroid Build Coastguard Worker 
197*cf5a6c84SAndroid Build Coastguard Worker     if (!*s) count = 0;
198*cf5a6c84SAndroid Build Coastguard Worker     else count++;
199*cf5a6c84SAndroid Build Coastguard Worker 
200*cf5a6c84SAndroid Build Coastguard Worker     *from = (*from)->next;
201*cf5a6c84SAndroid Build Coastguard Worker     if (*from == *help) return 0;
202*cf5a6c84SAndroid Build Coastguard Worker   }
203*cf5a6c84SAndroid Build Coastguard Worker 
204*cf5a6c84SAndroid Build Coastguard Worker   // If there was whitespace before this, zap it. This can't take out *help
205*cf5a6c84SAndroid Build Coastguard Worker   // because zap_blank_lines skipped blank lines, and we had to have at least
206*cf5a6c84SAndroid Build Coastguard Worker   // one non-blank line (a dash line) to get this far.
207*cf5a6c84SAndroid Build Coastguard Worker   while (!*skip_spaces((*from)->prev->data)) {
208*cf5a6c84SAndroid Build Coastguard Worker     *from = (*from)->prev;
209*cf5a6c84SAndroid Build Coastguard Worker     free(dlist_zap(from));
210*cf5a6c84SAndroid Build Coastguard Worker   }
211*cf5a6c84SAndroid Build Coastguard Worker 
212*cf5a6c84SAndroid Build Coastguard Worker   // Count number of dashlines, copy out to array, zap trailing whitespace
213*cf5a6c84SAndroid Build Coastguard Worker   // If *help was at start of dashblock, move it with *from
214*cf5a6c84SAndroid Build Coastguard Worker   count = 0;
215*cf5a6c84SAndroid Build Coastguard Worker   dd = *from;
216*cf5a6c84SAndroid Build Coastguard Worker   if (*help == *from) *help = 0;
217*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
218*cf5a6c84SAndroid Build Coastguard Worker    if (*skip_spaces(dd->data) != '-') break;
219*cf5a6c84SAndroid Build Coastguard Worker    count++;
220*cf5a6c84SAndroid Build Coastguard Worker    if (*from == (dd = dd->next)) break;
221*cf5a6c84SAndroid Build Coastguard Worker   }
222*cf5a6c84SAndroid Build Coastguard Worker 
223*cf5a6c84SAndroid Build Coastguard Worker   list = xmalloc(sizeof(char *)*count);
224*cf5a6c84SAndroid Build Coastguard Worker   *len = count;
225*cf5a6c84SAndroid Build Coastguard Worker   while (count) list[--count] = dlist_zap(from);
226*cf5a6c84SAndroid Build Coastguard Worker 
227*cf5a6c84SAndroid Build Coastguard Worker   return list;
228*cf5a6c84SAndroid Build Coastguard Worker }
229*cf5a6c84SAndroid Build Coastguard Worker 
230*cf5a6c84SAndroid Build Coastguard Worker // Read Config.in (and includes) to populate global struct symbol *sym list.
parse(char * filename)231*cf5a6c84SAndroid Build Coastguard Worker void parse(char *filename)
232*cf5a6c84SAndroid Build Coastguard Worker {
233*cf5a6c84SAndroid Build Coastguard Worker   FILE *fp = xfopen(filename, "r");
234*cf5a6c84SAndroid Build Coastguard Worker   struct symbol *new = 0;
235*cf5a6c84SAndroid Build Coastguard Worker 
236*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
237*cf5a6c84SAndroid Build Coastguard Worker     char *s, *line = NULL;
238*cf5a6c84SAndroid Build Coastguard Worker     size_t len;
239*cf5a6c84SAndroid Build Coastguard Worker 
240*cf5a6c84SAndroid Build Coastguard Worker     // Read line, trim whitespace at right edge.
241*cf5a6c84SAndroid Build Coastguard Worker     if (getline(&line, &len, fp) < 1) break;
242*cf5a6c84SAndroid Build Coastguard Worker     s = line+strlen(line);
243*cf5a6c84SAndroid Build Coastguard Worker     while (--s >= line) {
244*cf5a6c84SAndroid Build Coastguard Worker       if (!isspace(*s)) break;
245*cf5a6c84SAndroid Build Coastguard Worker       *s = 0;
246*cf5a6c84SAndroid Build Coastguard Worker     }
247*cf5a6c84SAndroid Build Coastguard Worker 
248*cf5a6c84SAndroid Build Coastguard Worker     // source or config keyword at left edge?
249*cf5a6c84SAndroid Build Coastguard Worker     if (*line && !isspace(*line)) {
250*cf5a6c84SAndroid Build Coastguard Worker       if ((s = keyword("config", line))) {
251*cf5a6c84SAndroid Build Coastguard Worker         memset(new = xmalloc(sizeof(struct symbol)), 0, sizeof(struct symbol));
252*cf5a6c84SAndroid Build Coastguard Worker         new->next = sym;
253*cf5a6c84SAndroid Build Coastguard Worker         new->name = s;
254*cf5a6c84SAndroid Build Coastguard Worker         sym = new;
255*cf5a6c84SAndroid Build Coastguard Worker       } else if ((s = keyword("source", line))) parse(s);
256*cf5a6c84SAndroid Build Coastguard Worker 
257*cf5a6c84SAndroid Build Coastguard Worker       continue;
258*cf5a6c84SAndroid Build Coastguard Worker     }
259*cf5a6c84SAndroid Build Coastguard Worker     if (!new) continue;
260*cf5a6c84SAndroid Build Coastguard Worker 
261*cf5a6c84SAndroid Build Coastguard Worker     if (sym && sym->help_indent) {
262*cf5a6c84SAndroid Build Coastguard Worker       dlist_add(&(new->help), line);
263*cf5a6c84SAndroid Build Coastguard Worker       if (sym->help_indent < 0) {
264*cf5a6c84SAndroid Build Coastguard Worker         sym->help_indent = 0;
265*cf5a6c84SAndroid Build Coastguard Worker         while (isspace(line[sym->help_indent])) sym->help_indent++;
266*cf5a6c84SAndroid Build Coastguard Worker       }
267*cf5a6c84SAndroid Build Coastguard Worker     }
268*cf5a6c84SAndroid Build Coastguard Worker     else if ((s = keyword("depends", line)) && (s = keyword("on", s)))
269*cf5a6c84SAndroid Build Coastguard Worker       new->depends = s;
270*cf5a6c84SAndroid Build Coastguard Worker     else if (keyword("help", line)) sym->help_indent = -1;
271*cf5a6c84SAndroid Build Coastguard Worker   }
272*cf5a6c84SAndroid Build Coastguard Worker 
273*cf5a6c84SAndroid Build Coastguard Worker   fclose(fp);
274*cf5a6c84SAndroid Build Coastguard Worker }
275*cf5a6c84SAndroid Build Coastguard Worker 
charsort(void * a,void * b)276*cf5a6c84SAndroid Build Coastguard Worker int charsort(void *a, void *b)
277*cf5a6c84SAndroid Build Coastguard Worker {
278*cf5a6c84SAndroid Build Coastguard Worker   char *aa = a, *bb = b;
279*cf5a6c84SAndroid Build Coastguard Worker 
280*cf5a6c84SAndroid Build Coastguard Worker   if (*aa < *bb) return -1;
281*cf5a6c84SAndroid Build Coastguard Worker   if (*aa > *bb) return 1;
282*cf5a6c84SAndroid Build Coastguard Worker   return 0;
283*cf5a6c84SAndroid Build Coastguard Worker }
284*cf5a6c84SAndroid Build Coastguard Worker 
dashsort(char ** a,char ** b)285*cf5a6c84SAndroid Build Coastguard Worker int dashsort(char **a, char **b)
286*cf5a6c84SAndroid Build Coastguard Worker {
287*cf5a6c84SAndroid Build Coastguard Worker   char *aa = *a, *bb = *b;
288*cf5a6c84SAndroid Build Coastguard Worker 
289*cf5a6c84SAndroid Build Coastguard Worker   if (aa[1] < bb[1]) return -1;
290*cf5a6c84SAndroid Build Coastguard Worker   if (aa[1] > bb[1]) return 1;
291*cf5a6c84SAndroid Build Coastguard Worker   return 0;
292*cf5a6c84SAndroid Build Coastguard Worker }
293*cf5a6c84SAndroid Build Coastguard Worker 
dashlinesort(char ** a,char ** b)294*cf5a6c84SAndroid Build Coastguard Worker int dashlinesort(char **a, char **b)
295*cf5a6c84SAndroid Build Coastguard Worker {
296*cf5a6c84SAndroid Build Coastguard Worker   return strcmp(*a, *b);
297*cf5a6c84SAndroid Build Coastguard Worker }
298*cf5a6c84SAndroid Build Coastguard Worker 
299*cf5a6c84SAndroid Build Coastguard Worker // Three stages: read data, collate entries, output results.
300*cf5a6c84SAndroid Build Coastguard Worker 
main(int argc,char * argv[])301*cf5a6c84SAndroid Build Coastguard Worker int main(int argc, char *argv[])
302*cf5a6c84SAndroid Build Coastguard Worker {
303*cf5a6c84SAndroid Build Coastguard Worker   FILE *fp;
304*cf5a6c84SAndroid Build Coastguard Worker 
305*cf5a6c84SAndroid Build Coastguard Worker   if (argc != 3) {
306*cf5a6c84SAndroid Build Coastguard Worker     fprintf(stderr, "usage: config2help Config.in .config\n");
307*cf5a6c84SAndroid Build Coastguard Worker     exit(1);
308*cf5a6c84SAndroid Build Coastguard Worker   }
309*cf5a6c84SAndroid Build Coastguard Worker 
310*cf5a6c84SAndroid Build Coastguard Worker   // Stage 1: read data. Read Config.in to global 'struct symbol *sym' list,
311*cf5a6c84SAndroid Build Coastguard Worker   // then read .config to set "enabled" member of each enabled symbol.
312*cf5a6c84SAndroid Build Coastguard Worker 
313*cf5a6c84SAndroid Build Coastguard Worker   // Read Config.in
314*cf5a6c84SAndroid Build Coastguard Worker   parse(argv[1]);
315*cf5a6c84SAndroid Build Coastguard Worker 
316*cf5a6c84SAndroid Build Coastguard Worker   // read .config
317*cf5a6c84SAndroid Build Coastguard Worker   fp = xfopen(argv[2], "r");
318*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
319*cf5a6c84SAndroid Build Coastguard Worker     char *line = NULL;
320*cf5a6c84SAndroid Build Coastguard Worker     size_t len;
321*cf5a6c84SAndroid Build Coastguard Worker 
322*cf5a6c84SAndroid Build Coastguard Worker     if (getline(&line, &len, fp) < 1) break;
323*cf5a6c84SAndroid Build Coastguard Worker     if (!strncmp("CONFIG_", line, 7)) {
324*cf5a6c84SAndroid Build Coastguard Worker       struct symbol *try;
325*cf5a6c84SAndroid Build Coastguard Worker       char *s = line+7;
326*cf5a6c84SAndroid Build Coastguard Worker 
327*cf5a6c84SAndroid Build Coastguard Worker       for (try=sym; try; try=try->next) {
328*cf5a6c84SAndroid Build Coastguard Worker         len = strlen(try->name);
329*cf5a6c84SAndroid Build Coastguard Worker         if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') {
330*cf5a6c84SAndroid Build Coastguard Worker           try->enabled++;
331*cf5a6c84SAndroid Build Coastguard Worker           break;
332*cf5a6c84SAndroid Build Coastguard Worker         }
333*cf5a6c84SAndroid Build Coastguard Worker       }
334*cf5a6c84SAndroid Build Coastguard Worker     }
335*cf5a6c84SAndroid Build Coastguard Worker   }
336*cf5a6c84SAndroid Build Coastguard Worker 
337*cf5a6c84SAndroid Build Coastguard Worker   // Stage 2: process data.
338*cf5a6c84SAndroid Build Coastguard Worker 
339*cf5a6c84SAndroid Build Coastguard Worker   // Collate help according to usage, depends, and .config
340*cf5a6c84SAndroid Build Coastguard Worker 
341*cf5a6c84SAndroid Build Coastguard Worker   // Loop through each entry, finding duplicate enabled "usage:" names
342*cf5a6c84SAndroid Build Coastguard Worker   // This is in reverse order, so last entry gets collated with previous
343*cf5a6c84SAndroid Build Coastguard Worker   // entry until we run out of matching pairs.
344*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
345*cf5a6c84SAndroid Build Coastguard Worker     struct symbol *throw = 0, *catch;
346*cf5a6c84SAndroid Build Coastguard Worker     char *this, *that, *cusage, *tusage, *name = 0;
347*cf5a6c84SAndroid Build Coastguard Worker     int len;
348*cf5a6c84SAndroid Build Coastguard Worker 
349*cf5a6c84SAndroid Build Coastguard Worker     // find a usage: name and collate all enabled entries with that name
350*cf5a6c84SAndroid Build Coastguard Worker     for (catch = sym; catch; catch = catch->next) {
351*cf5a6c84SAndroid Build Coastguard Worker       if (catch->enabled != 1) continue;
352*cf5a6c84SAndroid Build Coastguard Worker       if (catch->help && (that = keyword("usage:", catch->help->data))) {
353*cf5a6c84SAndroid Build Coastguard Worker         struct double_list *cfrom, *tfrom, *anchor;
354*cf5a6c84SAndroid Build Coastguard Worker         char *try, **cdashlines, **tdashlines, *usage;
355*cf5a6c84SAndroid Build Coastguard Worker         int clen, tlen;
356*cf5a6c84SAndroid Build Coastguard Worker 
357*cf5a6c84SAndroid Build Coastguard Worker         // Align usage: lines, finding a matching pair so we can suck help
358*cf5a6c84SAndroid Build Coastguard Worker         // text out of throw into catch, copying from this to that
359*cf5a6c84SAndroid Build Coastguard Worker         if (!throw) usage = that;
360*cf5a6c84SAndroid Build Coastguard Worker         else if (strncmp(name, that, len) || !isspace(that[len])) continue;
361*cf5a6c84SAndroid Build Coastguard Worker         catch->enabled++;
362*cf5a6c84SAndroid Build Coastguard Worker         while (!isspace(*that) && *that) that++;
363*cf5a6c84SAndroid Build Coastguard Worker         if (!throw) len = that-usage;
364*cf5a6c84SAndroid Build Coastguard Worker         free(name);
365*cf5a6c84SAndroid Build Coastguard Worker         name = strndup(usage, len);
366*cf5a6c84SAndroid Build Coastguard Worker         that = skip_spaces(that);
367*cf5a6c84SAndroid Build Coastguard Worker         if (!throw) {
368*cf5a6c84SAndroid Build Coastguard Worker           throw = catch;
369*cf5a6c84SAndroid Build Coastguard Worker           this = that;
370*cf5a6c84SAndroid Build Coastguard Worker 
371*cf5a6c84SAndroid Build Coastguard Worker           continue;
372*cf5a6c84SAndroid Build Coastguard Worker         }
373*cf5a6c84SAndroid Build Coastguard Worker 
374*cf5a6c84SAndroid Build Coastguard Worker         // Grab option description lines to collate from catch and throw
375*cf5a6c84SAndroid Build Coastguard Worker         tusage = dlist_zap(&throw->help);
376*cf5a6c84SAndroid Build Coastguard Worker         tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen);
377*cf5a6c84SAndroid Build Coastguard Worker         cusage = dlist_zap(&catch->help);
378*cf5a6c84SAndroid Build Coastguard Worker         cdashlines = grab_dashlines(&catch->help, &cfrom, &clen);
379*cf5a6c84SAndroid Build Coastguard Worker         anchor = catch->help;
380*cf5a6c84SAndroid Build Coastguard Worker 
381*cf5a6c84SAndroid Build Coastguard Worker         // If we've got both, collate and alphebetize
382*cf5a6c84SAndroid Build Coastguard Worker         if (cdashlines && tdashlines) {
383*cf5a6c84SAndroid Build Coastguard Worker           char **new = xmalloc(sizeof(char *)*(clen+tlen));
384*cf5a6c84SAndroid Build Coastguard Worker 
385*cf5a6c84SAndroid Build Coastguard Worker           memcpy(new, cdashlines, sizeof(char *)*clen);
386*cf5a6c84SAndroid Build Coastguard Worker           memcpy(new+clen, tdashlines, sizeof(char *)*tlen);
387*cf5a6c84SAndroid Build Coastguard Worker           free(cdashlines);
388*cf5a6c84SAndroid Build Coastguard Worker           free(tdashlines);
389*cf5a6c84SAndroid Build Coastguard Worker           qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort);
390*cf5a6c84SAndroid Build Coastguard Worker           cdashlines = new;
391*cf5a6c84SAndroid Build Coastguard Worker 
392*cf5a6c84SAndroid Build Coastguard Worker         // If just one, make sure it's in catch.
393*cf5a6c84SAndroid Build Coastguard Worker         } else if (tdashlines) cdashlines = tdashlines;
394*cf5a6c84SAndroid Build Coastguard Worker 
395*cf5a6c84SAndroid Build Coastguard Worker         // If throw had a prefix, insert it before dashlines, with a
396*cf5a6c84SAndroid Build Coastguard Worker         // blank line if catch had a prefix.
397*cf5a6c84SAndroid Build Coastguard Worker         if (tfrom && tfrom != throw->help) {
398*cf5a6c84SAndroid Build Coastguard Worker           if (throw->help || catch->help) dlist_add(&cfrom, strdup(""));
399*cf5a6c84SAndroid Build Coastguard Worker           else {
400*cf5a6c84SAndroid Build Coastguard Worker             dlist_add(&cfrom, 0);
401*cf5a6c84SAndroid Build Coastguard Worker             anchor = cfrom->prev;
402*cf5a6c84SAndroid Build Coastguard Worker           }
403*cf5a6c84SAndroid Build Coastguard Worker           while (throw->help && throw->help != tfrom)
404*cf5a6c84SAndroid Build Coastguard Worker             dlist_add(&cfrom, dlist_zap(&throw->help));
405*cf5a6c84SAndroid Build Coastguard Worker           if (cfrom && cfrom->prev->data && *skip_spaces(cfrom->prev->data))
406*cf5a6c84SAndroid Build Coastguard Worker             dlist_add(&cfrom, strdup(""));
407*cf5a6c84SAndroid Build Coastguard Worker         }
408*cf5a6c84SAndroid Build Coastguard Worker         if (!anchor) {
409*cf5a6c84SAndroid Build Coastguard Worker           dlist_add(&cfrom, 0);
410*cf5a6c84SAndroid Build Coastguard Worker           anchor = cfrom->prev;
411*cf5a6c84SAndroid Build Coastguard Worker         }
412*cf5a6c84SAndroid Build Coastguard Worker 
413*cf5a6c84SAndroid Build Coastguard Worker         // Splice sorted lines back in place
414*cf5a6c84SAndroid Build Coastguard Worker         if (cdashlines) {
415*cf5a6c84SAndroid Build Coastguard Worker           tlen += clen;
416*cf5a6c84SAndroid Build Coastguard Worker 
417*cf5a6c84SAndroid Build Coastguard Worker           for (clen = 0; clen < tlen; clen++)
418*cf5a6c84SAndroid Build Coastguard Worker             dlist_add(&cfrom, cdashlines[clen]);
419*cf5a6c84SAndroid Build Coastguard Worker         }
420*cf5a6c84SAndroid Build Coastguard Worker 
421*cf5a6c84SAndroid Build Coastguard Worker         // If there were no dashlines, text would be considered prefix, so
422*cf5a6c84SAndroid Build Coastguard Worker         // the list is definitely no longer empty, so discard placeholder.
423*cf5a6c84SAndroid Build Coastguard Worker         if (!anchor->data) dlist_zap(&anchor);
424*cf5a6c84SAndroid Build Coastguard Worker 
425*cf5a6c84SAndroid Build Coastguard Worker         // zap whitespace at end of catch help text
426*cf5a6c84SAndroid Build Coastguard Worker         while (!*skip_spaces(anchor->prev->data)) {
427*cf5a6c84SAndroid Build Coastguard Worker           anchor = anchor->prev;
428*cf5a6c84SAndroid Build Coastguard Worker           free(dlist_zap(&anchor));
429*cf5a6c84SAndroid Build Coastguard Worker         }
430*cf5a6c84SAndroid Build Coastguard Worker 
431*cf5a6c84SAndroid Build Coastguard Worker         // Append trailing lines.
432*cf5a6c84SAndroid Build Coastguard Worker         while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom));
433*cf5a6c84SAndroid Build Coastguard Worker 
434*cf5a6c84SAndroid Build Coastguard Worker         // Collate first [-abc] option block in usage: lines
435*cf5a6c84SAndroid Build Coastguard Worker         try = 0;
436*cf5a6c84SAndroid Build Coastguard Worker         if (*this == '[' && this[1] == '-' && this[2] != '-' &&
437*cf5a6c84SAndroid Build Coastguard Worker             *that == '[' && that[1] == '-' && that[2] != '-')
438*cf5a6c84SAndroid Build Coastguard Worker         {
439*cf5a6c84SAndroid Build Coastguard Worker           char *from = this+2, *to = that+2;
440*cf5a6c84SAndroid Build Coastguard Worker           int ff = strcspn(from, " ]"), tt = strcspn(to, " ]");
441*cf5a6c84SAndroid Build Coastguard Worker 
442*cf5a6c84SAndroid Build Coastguard Worker           if (from[ff] == ']' && to[tt] == ']') {
443*cf5a6c84SAndroid Build Coastguard Worker             try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to);
444*cf5a6c84SAndroid Build Coastguard Worker             qsort(try+2, ff+tt, 1, (void *)charsort);
445*cf5a6c84SAndroid Build Coastguard Worker             this = skip_spaces(this+ff+3);
446*cf5a6c84SAndroid Build Coastguard Worker             that = skip_spaces(that+tt+3);
447*cf5a6c84SAndroid Build Coastguard Worker           }
448*cf5a6c84SAndroid Build Coastguard Worker         }
449*cf5a6c84SAndroid Build Coastguard Worker 
450*cf5a6c84SAndroid Build Coastguard Worker         // The list is definitely no longer empty, so discard placeholder.
451*cf5a6c84SAndroid Build Coastguard Worker         if (!anchor->data) dlist_zap(&anchor);
452*cf5a6c84SAndroid Build Coastguard Worker 
453*cf5a6c84SAndroid Build Coastguard Worker         // Add new collated line (and whitespace).
454*cf5a6c84SAndroid Build Coastguard Worker         dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s",
455*cf5a6c84SAndroid Build Coastguard Worker                   catch->help_indent, ' ', len, name, try ? try : "",
456*cf5a6c84SAndroid Build Coastguard Worker                   this, *this ? " " : "", that));
457*cf5a6c84SAndroid Build Coastguard Worker         free(try);
458*cf5a6c84SAndroid Build Coastguard Worker         dlist_add(&anchor, strdup(""));
459*cf5a6c84SAndroid Build Coastguard Worker         free(cusage);
460*cf5a6c84SAndroid Build Coastguard Worker         free(tusage);
461*cf5a6c84SAndroid Build Coastguard Worker         throw->enabled = 0;
462*cf5a6c84SAndroid Build Coastguard Worker         throw = catch;
463*cf5a6c84SAndroid Build Coastguard Worker         throw->help = anchor->prev->prev;
464*cf5a6c84SAndroid Build Coastguard Worker 
465*cf5a6c84SAndroid Build Coastguard Worker         throw = catch;
466*cf5a6c84SAndroid Build Coastguard Worker         this = throw->help->data + throw->help_indent + 8 + len;
467*cf5a6c84SAndroid Build Coastguard Worker       }
468*cf5a6c84SAndroid Build Coastguard Worker     }
469*cf5a6c84SAndroid Build Coastguard Worker 
470*cf5a6c84SAndroid Build Coastguard Worker     // Did we find one?
471*cf5a6c84SAndroid Build Coastguard Worker 
472*cf5a6c84SAndroid Build Coastguard Worker     if (!throw) break;
473*cf5a6c84SAndroid Build Coastguard Worker   }
474*cf5a6c84SAndroid Build Coastguard Worker 
475*cf5a6c84SAndroid Build Coastguard Worker   // Stage 3: output results to stdout.
476*cf5a6c84SAndroid Build Coastguard Worker 
477*cf5a6c84SAndroid Build Coastguard Worker   // Print out help #defines
478*cf5a6c84SAndroid Build Coastguard Worker   while (sym) {
479*cf5a6c84SAndroid Build Coastguard Worker     struct double_list *dd;
480*cf5a6c84SAndroid Build Coastguard Worker 
481*cf5a6c84SAndroid Build Coastguard Worker     if (sym->help) {
482*cf5a6c84SAndroid Build Coastguard Worker       int i, blank;
483*cf5a6c84SAndroid Build Coastguard Worker       char *s;
484*cf5a6c84SAndroid Build Coastguard Worker 
485*cf5a6c84SAndroid Build Coastguard Worker       strcpy(s = xmalloc(strlen(sym->name)+1), sym->name);
486*cf5a6c84SAndroid Build Coastguard Worker 
487*cf5a6c84SAndroid Build Coastguard Worker       for (i = 0; s[i]; i++) s[i] = tolower(s[i]);
488*cf5a6c84SAndroid Build Coastguard Worker       printf("#define HELP_%s \"", s);
489*cf5a6c84SAndroid Build Coastguard Worker       free(s);
490*cf5a6c84SAndroid Build Coastguard Worker 
491*cf5a6c84SAndroid Build Coastguard Worker       dd = sym->help;
492*cf5a6c84SAndroid Build Coastguard Worker       blank = 0;
493*cf5a6c84SAndroid Build Coastguard Worker       for (;;) {
494*cf5a6c84SAndroid Build Coastguard Worker 
495*cf5a6c84SAndroid Build Coastguard Worker         // Trim leading whitespace
496*cf5a6c84SAndroid Build Coastguard Worker         s = dd->data;
497*cf5a6c84SAndroid Build Coastguard Worker         i = sym->help_indent;
498*cf5a6c84SAndroid Build Coastguard Worker         while (isspace(*s) && i--) s++;
499*cf5a6c84SAndroid Build Coastguard Worker 
500*cf5a6c84SAndroid Build Coastguard Worker         // Only one blank line between nonblank lines, not at start or end.
501*cf5a6c84SAndroid Build Coastguard Worker         if (!*s) blank = 2;
502*cf5a6c84SAndroid Build Coastguard Worker         else {
503*cf5a6c84SAndroid Build Coastguard Worker           while (blank--) {
504*cf5a6c84SAndroid Build Coastguard Worker             putchar('\\');
505*cf5a6c84SAndroid Build Coastguard Worker             putchar('n');
506*cf5a6c84SAndroid Build Coastguard Worker           }
507*cf5a6c84SAndroid Build Coastguard Worker           blank = 1;
508*cf5a6c84SAndroid Build Coastguard Worker         }
509*cf5a6c84SAndroid Build Coastguard Worker 
510*cf5a6c84SAndroid Build Coastguard Worker         for (i=0; s[i]; i++) {
511*cf5a6c84SAndroid Build Coastguard Worker           if (s[i] == '"' || s[i] == '\\') putchar('\\');
512*cf5a6c84SAndroid Build Coastguard Worker           putchar(s[i]);
513*cf5a6c84SAndroid Build Coastguard Worker         }
514*cf5a6c84SAndroid Build Coastguard Worker         dd = dd->next;
515*cf5a6c84SAndroid Build Coastguard Worker         if (dd == sym->help) break;
516*cf5a6c84SAndroid Build Coastguard Worker       }
517*cf5a6c84SAndroid Build Coastguard Worker       printf("\"\n\n");
518*cf5a6c84SAndroid Build Coastguard Worker     }
519*cf5a6c84SAndroid Build Coastguard Worker     sym = sym->next;
520*cf5a6c84SAndroid Build Coastguard Worker   }
521*cf5a6c84SAndroid Build Coastguard Worker 
522*cf5a6c84SAndroid Build Coastguard Worker   return 0;
523*cf5a6c84SAndroid Build Coastguard Worker }
524