1
2
3
4
5
6
7
8#include <ctype.h>
9#include <stdio.h>
10#include <string.h>
11#include <stdarg.h>
12#include <stdlib.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16#include <regex.h>
17#include <inttypes.h>
18#include <termios.h>
19#include <poll.h>
20#include <sys/socket.h>
21
22
23
24struct double_list {
25 struct double_list *next, *prev;
26 char *data;
27};
28
29
30void *xmalloc(size_t size)
31{
32 void *ret = malloc(size);
33 if (!ret) {
34 fprintf(stderr, "xmalloc(%ld)", (long)size);
35 exit(1);
36 }
37
38 return ret;
39}
40
41
42char *xmprintf(char *format, ...)
43{
44 va_list va, va2;
45 int len;
46 char *ret;
47
48 va_start(va, format);
49 va_copy(va2, va);
50
51
52 len = vsnprintf(0, 0, format, va);
53 len++;
54 va_end(va);
55
56
57 ret = xmalloc(len);
58 vsnprintf(ret, len, format, va2);
59 va_end(va2);
60
61 return ret;
62}
63
64
65FILE *xfopen(char *path, char *mode)
66{
67 FILE *f = fopen(path, mode);
68 if (!f) {
69 fprintf(stderr, "No file %s", path);
70 exit(1);
71 }
72 return f;
73}
74
75void *dlist_pop(void *list)
76{
77 struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
78
79 if (dlist->next == dlist) *pdlist = 0;
80 else {
81 dlist->next->prev = dlist->prev;
82 dlist->prev->next = *pdlist = dlist->next;
83 }
84
85 return dlist;
86}
87
88void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
89{
90 if (*list) {
91 new->next = *list;
92 new->prev = (*list)->prev;
93 (*list)->prev->next = new;
94 (*list)->prev = new;
95 } else *list = new->next = new->prev = new;
96}
97
98
99
100struct double_list *dlist_add(struct double_list **list, char *data)
101{
102 struct double_list *new = xmalloc(sizeof(struct double_list));
103
104 new->data = data;
105 dlist_add_nomalloc(list, new);
106
107 return new;
108}
109
110
111
112
113
114struct symbol {
115 struct symbol *next;
116 int enabled, help_indent;
117 char *name, *depends;
118 struct double_list *help;
119} *sym;
120
121
122char *skip_spaces(char *s)
123{
124 while (isspace(*s)) s++;
125
126 return s;
127}
128
129
130char *keyword(char *name, char *line)
131{
132 int len = strlen(name);
133
134 line = skip_spaces(line);
135 if (strncmp(name, line, len)) return 0;
136 line += len;
137 if (*line && !isspace(*line)) return 0;
138 line = skip_spaces(line);
139
140 return line;
141}
142
143
144char *dlist_zap(struct double_list **help)
145{
146 struct double_list *dd = dlist_pop(help);
147 char *s = dd->data;
148
149 free(dd);
150
151 return s;
152}
153
154int zap_blank_lines(struct double_list **help)
155{
156 int got = 0;
157
158 while (*help) {
159 char *s;
160
161 s = skip_spaces((*help)->data);
162
163 if (*s) break;
164 got++;
165 free(dlist_zap(help));
166 }
167
168 return got;
169}
170
171
172
173
174
175
176
177
178
179
180
181char **grab_dashlines(struct double_list **help, struct double_list **from,
182 int *len)
183{
184 struct double_list *dd;
185 char *s, **list;
186 int count = 0;
187
188 *len = 0;
189 zap_blank_lines(help);
190 *from = *help;
191
192
193 for (;;) {
194 s = skip_spaces((*from)->data);
195 if (*s == '-' && s[1] != '-' && !count) break;
196
197 if (!*s) count = 0;
198 else count++;
199
200 *from = (*from)->next;
201 if (*from == *help) return 0;
202 }
203
204
205
206
207 while (!*skip_spaces((*from)->prev->data)) {
208 *from = (*from)->prev;
209 free(dlist_zap(from));
210 }
211
212
213
214 count = 0;
215 dd = *from;
216 if (*help == *from) *help = 0;
217 for (;;) {
218 if (*skip_spaces(dd->data) != '-') break;
219 count++;
220 if (*from == (dd = dd->next)) break;
221 }
222
223 list = xmalloc(sizeof(char *)*count);
224 *len = count;
225 while (count) list[--count] = dlist_zap(from);
226
227 return list;
228}
229
230
231void parse(char *filename)
232{
233 FILE *fp = xfopen(filename, "r");
234 struct symbol *new = 0;
235
236 for (;;) {
237 char *s, *line = NULL;
238 size_t len;
239
240
241 if (getline(&line, &len, fp) < 1) break;
242 s = line+strlen(line);
243 while (--s >= line) {
244 if (!isspace(*s)) break;
245 *s = 0;
246 }
247
248
249 if (*line && !isspace(*line)) {
250 if ((s = keyword("config", line))) {
251 memset(new = xmalloc(sizeof(struct symbol)), 0, sizeof(struct symbol));
252 new->next = sym;
253 new->name = s;
254 sym = new;
255 } else if ((s = keyword("source", line))) parse(s);
256
257 continue;
258 }
259 if (!new) continue;
260
261 if (sym && sym->help_indent) {
262 dlist_add(&(new->help), line);
263 if (sym->help_indent < 0) {
264 sym->help_indent = 0;
265 while (isspace(line[sym->help_indent])) sym->help_indent++;
266 }
267 }
268 else if ((s = keyword("depends", line)) && (s = keyword("on", s)))
269 new->depends = s;
270 else if (keyword("help", line)) sym->help_indent = -1;
271 }
272
273 fclose(fp);
274}
275
276int charsort(void *a, void *b)
277{
278 char *aa = a, *bb = b;
279
280 if (*aa < *bb) return -1;
281 if (*aa > *bb) return 1;
282 return 0;
283}
284
285int dashsort(char **a, char **b)
286{
287 char *aa = *a, *bb = *b;
288
289 if (aa[1] < bb[1]) return -1;
290 if (aa[1] > bb[1]) return 1;
291 return 0;
292}
293
294int dashlinesort(char **a, char **b)
295{
296 return strcmp(*a, *b);
297}
298
299
300
301int main(int argc, char *argv[])
302{
303 FILE *fp;
304
305 if (argc != 3) {
306 fprintf(stderr, "usage: config2help Config.in .config\n");
307 exit(1);
308 }
309
310
311
312
313
314 parse(argv[1]);
315
316
317 fp = xfopen(argv[2], "r");
318 for (;;) {
319 char *line = NULL;
320 size_t len;
321
322 if (getline(&line, &len, fp) < 1) break;
323 if (!strncmp("CONFIG_", line, 7)) {
324 struct symbol *try;
325 char *s = line+7;
326
327 for (try=sym; try; try=try->next) {
328 len = strlen(try->name);
329 if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') {
330 try->enabled++;
331 break;
332 }
333 }
334 }
335 }
336
337
338
339
340
341
342
343
344 for (;;) {
345 struct symbol *throw = 0, *catch;
346 char *this, *that, *cusage, *tusage, *name = 0;
347 int len;
348
349
350 for (catch = sym; catch; catch = catch->next) {
351 if (catch->enabled != 1) continue;
352 if (catch->help && (that = keyword("usage:", catch->help->data))) {
353 struct double_list *cfrom, *tfrom, *anchor;
354 char *try, **cdashlines, **tdashlines, *usage;
355 int clen, tlen;
356
357
358
359 if (!throw) usage = that;
360 else if (strncmp(name, that, len) || !isspace(that[len])) continue;
361 catch->enabled++;
362 while (!isspace(*that) && *that) that++;
363 if (!throw) len = that-usage;
364 free(name);
365 name = strndup(usage, len);
366 that = skip_spaces(that);
367 if (!throw) {
368 throw = catch;
369 this = that;
370
371 continue;
372 }
373
374
375 tusage = dlist_zap(&throw->help);
376 tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen);
377 cusage = dlist_zap(&catch->help);
378 cdashlines = grab_dashlines(&catch->help, &cfrom, &clen);
379 anchor = catch->help;
380
381
382 if (cdashlines && tdashlines) {
383 char **new = xmalloc(sizeof(char *)*(clen+tlen));
384
385 memcpy(new, cdashlines, sizeof(char *)*clen);
386 memcpy(new+clen, tdashlines, sizeof(char *)*tlen);
387 free(cdashlines);
388 free(tdashlines);
389 qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort);
390 cdashlines = new;
391
392
393 } else if (tdashlines) cdashlines = tdashlines;
394
395
396
397 if (tfrom && tfrom != throw->help) {
398 if (throw->help || catch->help) dlist_add(&cfrom, strdup(""));
399 else {
400 dlist_add(&cfrom, 0);
401 anchor = cfrom->prev;
402 }
403 while (throw->help && throw->help != tfrom)
404 dlist_add(&cfrom, dlist_zap(&throw->help));
405 if (cfrom && cfrom->prev->data && *skip_spaces(cfrom->prev->data))
406 dlist_add(&cfrom, strdup(""));
407 }
408 if (!anchor) {
409 dlist_add(&cfrom, 0);
410 anchor = cfrom->prev;
411 }
412
413
414 if (cdashlines) {
415 tlen += clen;
416
417 for (clen = 0; clen < tlen; clen++)
418 dlist_add(&cfrom, cdashlines[clen]);
419 }
420
421
422
423 if (!anchor->data) dlist_zap(&anchor);
424
425
426 while (!*skip_spaces(anchor->prev->data)) {
427 anchor = anchor->prev;
428 free(dlist_zap(&anchor));
429 }
430
431
432 while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom));
433
434
435 try = 0;
436 if (*this == '[' && this[1] == '-' && this[2] != '-' &&
437 *that == '[' && that[1] == '-' && that[2] != '-')
438 {
439 char *from = this+2, *to = that+2;
440 int ff = strcspn(from, " ]"), tt = strcspn(to, " ]");
441
442 if (from[ff] == ']' && to[tt] == ']') {
443 try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to);
444 qsort(try+2, ff+tt, 1, (void *)charsort);
445 this = skip_spaces(this+ff+3);
446 that = skip_spaces(that+tt+3);
447 }
448 }
449
450
451 if (!anchor->data) dlist_zap(&anchor);
452
453
454 dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s",
455 catch->help_indent, ' ', len, name, try ? try : "",
456 this, *this ? " " : "", that));
457 free(try);
458 dlist_add(&anchor, strdup(""));
459 free(cusage);
460 free(tusage);
461 throw->enabled = 0;
462 throw = catch;
463 throw->help = anchor->prev->prev;
464
465 throw = catch;
466 this = throw->help->data + throw->help_indent + 8 + len;
467 }
468 }
469
470
471
472 if (!throw) break;
473 }
474
475
476
477
478 while (sym) {
479 struct double_list *dd;
480
481 if (sym->help) {
482 int i;
483 char *s;
484
485 strcpy(s = xmalloc(strlen(sym->name)+1), sym->name);
486
487 for (i = 0; s[i]; i++) s[i] = tolower(s[i]);
488 printf("#define HELP_%s \"", s);
489 free(s);
490
491 dd = sym->help;
492 for (;;) {
493 i = sym->help_indent;
494
495
496 s = dd->data;
497 while (isspace(*s) && i) {
498 s++;
499 i--;
500 }
501 for (i=0; s[i]; i++) {
502 if (s[i] == '"' || s[i] == '\\') putchar('\\');
503 putchar(s[i]);
504 }
505 putchar('\\');
506 putchar('n');
507 dd = dd->next;
508 if (dd == sym->help) break;
509 }
510 printf("\"\n\n");
511 }
512 sym = sym->next;
513 }
514
515 return 0;
516}
517