blob: d87087bc5664cd802912886c58b5e52adb9d6a26 [file] [log] [blame]
Rob Landley207cada2013-10-03 03:18:00 -05001// Take three word input lines on stdin (the three space separated words are
2// command name, option string with current config, option string from
3// allyesconfig; space separated, the last two are and double quotes)
4// and produce flag #defines to stdout.
5
6// This is intentionally crappy code because we control the inputs. It leaks
7// memory like a sieve and segfaults if malloc returns null, but does the job.
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <errno.h>
13
14struct flag {
15 struct flag *next;
16 char *command;
17 struct flag *lopt;
18};
19
Rob Landleyf3e56f42014-12-31 21:30:59 -060020// replace chopped out USE_BLAH() sections with low-ascii characters
21// showing how many flags got skipped
22
23char *mark_gaps(char *flags, char *all)
24{
25 char *n, *new, c;
26
27 // Shell feeds in " " for blank args, leading space not meaningful.
28 while (isspace(*flags)) flags++;
29 while (isspace(*all)) all++;
30
31 n = new = strdup(all);
32 while (*all) {
33 if (*flags == *all) {
34 *(new++) = *(all++);
35 *flags++;
36 continue;
37 }
38
39 c = *(all++);
40 if (strchr("?&^-:#|@*; ", c));
41 else if (strchr("=<>", c)) while (isdigit(*all)) all++;
42 else if (c == '(') while(*(all++) != ')');
43 else *(new++) = 1;
44 }
45 *new = 0;
46
47 return n;
48}
49
Rob Landley207cada2013-10-03 03:18:00 -050050// Break down a command string into struct flag list.
51
52struct flag *digest(char *string)
53{
54 struct flag *list = NULL;
Rob Landleyf3e56f42014-12-31 21:30:59 -060055 char *err = string;
Rob Landley207cada2013-10-03 03:18:00 -050056
57 while (*string) {
58 // Groups must be at end.
59 if (*string == '[') break;
60
61 // Longopts
62 if (*string == '(') {
63 struct flag *new = calloc(sizeof(struct flag), 1);
64
65 new->command = ++string;
66
67 // Attach longopt to previous short opt, if any.
68 if (list && list->command) {
69 new->next = list->lopt;
70 list->lopt = new;
71 } else {
72 struct flag *blank = calloc(sizeof(struct flag), 1);
73
74 blank->next = list;
75 blank->lopt = new;
76 list = blank;
77 }
Rob Landley3a415412014-05-10 13:06:31 -050078 // An empty longopt () would break this.
79 while (*++string != ')') if (*string == '-') *string = '_';
Rob Landley207cada2013-10-03 03:18:00 -050080 *(string++) = 0;
81 continue;
82 }
83
84 if (strchr("?&^-:#|@*; ", *string)) string++;
85 else if (strchr("=<>", *string)) {
Rob Landleyf3e56f42014-12-31 21:30:59 -060086 if (!isdigit(string[1])) {
87 fprintf(stderr, "%c without number in '%s'", *string, err);
88 exit(1);
89 }
Rob Landley207cada2013-10-03 03:18:00 -050090 while (isdigit(*++string)) {
91 if (!list) {
92 string++;
93 break;
94 }
95 }
96 } else {
97 struct flag *new = calloc(sizeof(struct flag), 1);
98
99 new->command = string++;
100 new->next = list;
101 list = new;
102 }
103 }
104
105 return list;
106}
107
108int main(int argc, char *argv[])
109{
110 char command[256], flags[1023], allflags[1024];
Rob Landley6ebe03d2014-02-24 23:34:43 -0600111 char *out, *outbuf = malloc(1024*1024);
112
113 // Yes, the output buffer is 1 megabyte with no bounds checking.
114 // See "intentionally crappy", above.
115 if (!(out = outbuf)) return 1;
Rob Landley207cada2013-10-03 03:18:00 -0500116
Rob Landleyf3e56f42014-12-31 21:30:59 -0600117 printf("#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n"
118 "#else\n#define FORCED_FLAG 0\n#endif\n\n");
119
Rob Landley207cada2013-10-03 03:18:00 -0500120 for (;;) {
121 struct flag *flist, *aflist, *offlist;
Rob Landleyf3e56f42014-12-31 21:30:59 -0600122 char *gaps, *mgaps, c;
Rob Landley3a415412014-05-10 13:06:31 -0500123 unsigned bit;
Rob Landley207cada2013-10-03 03:18:00 -0500124
Rob Landley5640acb2015-05-03 12:41:05 -0500125 *command = *flags = *allflags = 0;
Rob Landley3a415412014-05-10 13:06:31 -0500126 bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
127 command, flags, allflags);
Rob Landley207cada2013-10-03 03:18:00 -0500128
Rob Landley5640acb2015-05-03 12:41:05 -0500129 if (getenv("DEBUG"))
130 fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
131 command, flags, allflags);
132
Rob Landley3a415412014-05-10 13:06:31 -0500133 if (!*command) break;
134 if (bit != 3) {
135 fprintf(stderr, "\nError in %s (duplicate command?)\n", command);
136 exit(1);
137 }
138
139 bit = 0;
Rob Landley207cada2013-10-03 03:18:00 -0500140 printf("// %s %s %s\n", command, flags, allflags);
Rob Landleyf3e56f42014-12-31 21:30:59 -0600141 mgaps = mark_gaps(flags, allflags);
142 for (gaps = mgaps; *gaps == 1; gaps++);
143 if (*gaps) c = '"';
144 else {
145 c = ' ';
146 gaps = "0";
147 }
148 printf("#undef OPTSTR_%s\n#define OPTSTR_%s %c%s%c\n",
149 command, command, c, gaps, c);
150 free(mgaps);
Rob Landley6ebe03d2014-02-24 23:34:43 -0600151
Rob Landley207cada2013-10-03 03:18:00 -0500152 flist = digest(flags);
153 offlist = aflist = digest(allflags);
154
Rob Landleya2359012014-02-16 17:31:33 -0600155 printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
Rob Landley207cada2013-10-03 03:18:00 -0500156 command, command, command);
157
158 while (offlist) {
159 struct flag *f = offlist->lopt;
160 while (f) {
161 printf("#undef FLAG_%s\n", f->command);
162 f = f->next;
163 }
164 if (offlist->command) printf("#undef FLAG_%c\n", *offlist->command);
165 offlist = offlist->next;
166 }
167 printf("#endif\n\n");
168
Rob Landley6ebe03d2014-02-24 23:34:43 -0600169 sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
170 command, command);
171 out += strlen(out);
Rob Landley207cada2013-10-03 03:18:00 -0500172
173 while (aflist) {
174 if (aflist->lopt) {
175 if (flist && flist->lopt &&
176 !strcmp(flist->lopt->command, aflist->lopt->command))
177 {
Rob Landley6ebe03d2014-02-24 23:34:43 -0600178 sprintf(out, "#define FLAG_%s (1<<%d)\n", flist->lopt->command, bit);
Rob Landley207cada2013-10-03 03:18:00 -0500179 flist->lopt = flist->lopt->next;
Rob Landleyf3e56f42014-12-31 21:30:59 -0600180 } else sprintf(out, "#define FLAG_%s (FORCED_FLAG<<%d)\n",
181 aflist->lopt->command, bit);
Rob Landley207cada2013-10-03 03:18:00 -0500182 aflist->lopt = aflist->lopt->next;
Ashwini Sharma882ca8b2014-04-09 07:40:02 -0500183 if (!aflist->command) {
184 aflist = aflist->next;
Rob Landleyf3e56f42014-12-31 21:30:59 -0600185 bit++;
186 if (flist) flist = flist->next;
Ashwini Sharma882ca8b2014-04-09 07:40:02 -0500187 }
Rob Landley5a2583a2014-02-08 10:53:26 -0600188 } else if (aflist->command) {
Rob Landley5640acb2015-05-03 12:41:05 -0500189 if (flist && (!flist->command || *aflist->command == *flist->command)) {
Rob Landley207cada2013-10-03 03:18:00 -0500190 if (aflist->command)
Rob Landley6ebe03d2014-02-24 23:34:43 -0600191 sprintf(out, "#define FLAG_%c (1<<%d)\n", *aflist->command, bit);
Rob Landley207cada2013-10-03 03:18:00 -0500192 flist = flist->next;
Rob Landleyf3e56f42014-12-31 21:30:59 -0600193 } else sprintf(out, "#define FLAG_%c (FORCED_FLAG<<%d)\n",
194 *aflist->command, bit);
195 bit++;
Rob Landley207cada2013-10-03 03:18:00 -0500196 aflist = aflist->next;
197 }
Rob Landley6ebe03d2014-02-24 23:34:43 -0600198 out += strlen(out);
Rob Landley207cada2013-10-03 03:18:00 -0500199 }
Rob Landleyf3e56f42014-12-31 21:30:59 -0600200 out = stpcpy(out, "#endif\n\n");
Rob Landley207cada2013-10-03 03:18:00 -0500201 }
202
Rob Landley6ebe03d2014-02-24 23:34:43 -0600203 if (fflush(0) && ferror(stdout)) return 1;
204
205 out = outbuf;
206 while (*out) {
207 int i = write(1, outbuf, strlen(outbuf));
208
209 if (i<0) return 1;
210 out += i;
211 }
Hyejin Kim3b741472015-03-04 07:29:57 -0600212
213 return 0;
Rob Landley207cada2013-10-03 03:18:00 -0500214}