1*cf5a6c84SAndroid Build Coastguard Worker // Read three word input lines from stdin and produce flag #defines to stdout.
2*cf5a6c84SAndroid Build Coastguard Worker // The three words on each input line are command name, option string with
3*cf5a6c84SAndroid Build Coastguard Worker // current config, option string from allyesconfig. The three are space
4*cf5a6c84SAndroid Build Coastguard Worker // separated and the last two are in double quotes.
5*cf5a6c84SAndroid Build Coastguard Worker
6*cf5a6c84SAndroid Build Coastguard Worker // This is intentionally crappy code because we control the inputs. It leaks
7*cf5a6c84SAndroid Build Coastguard Worker // memory like a sieve and segfaults if malloc returns null, but does the job.
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker #include <unistd.h>
10*cf5a6c84SAndroid Build Coastguard Worker #include <stdio.h>
11*cf5a6c84SAndroid Build Coastguard Worker #include <stdlib.h>
12*cf5a6c84SAndroid Build Coastguard Worker #include <string.h>
13*cf5a6c84SAndroid Build Coastguard Worker #include <errno.h>
14*cf5a6c84SAndroid Build Coastguard Worker #include <ctype.h>
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker struct flag {
17*cf5a6c84SAndroid Build Coastguard Worker struct flag *next, *lopt;
18*cf5a6c84SAndroid Build Coastguard Worker char *command;
19*cf5a6c84SAndroid Build Coastguard Worker };
20*cf5a6c84SAndroid Build Coastguard Worker
chrtype(char c)21*cf5a6c84SAndroid Build Coastguard Worker int chrtype(char c)
22*cf5a6c84SAndroid Build Coastguard Worker {
23*cf5a6c84SAndroid Build Coastguard Worker // Does this populate a GLOBALS() variable?
24*cf5a6c84SAndroid Build Coastguard Worker if (strchr("^-:#|@*; %.", c)) return 1;
25*cf5a6c84SAndroid Build Coastguard Worker
26*cf5a6c84SAndroid Build Coastguard Worker // Is this followed by a numeric argument in optstr?
27*cf5a6c84SAndroid Build Coastguard Worker if (strchr("=<>", c)) return 2;
28*cf5a6c84SAndroid Build Coastguard Worker
29*cf5a6c84SAndroid Build Coastguard Worker if (strchr("?&0", c)) return 3;
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker return 0;
32*cf5a6c84SAndroid Build Coastguard Worker }
33*cf5a6c84SAndroid Build Coastguard Worker
34*cf5a6c84SAndroid Build Coastguard Worker // replace chopped out USE_BLAH() sections with low-ascii characters
35*cf5a6c84SAndroid Build Coastguard Worker // showing how many flags got skipped so FLAG_ macros stay constant
36*cf5a6c84SAndroid Build Coastguard Worker
mark_gaps(char * flags,char * all)37*cf5a6c84SAndroid Build Coastguard Worker char *mark_gaps(char *flags, char *all)
38*cf5a6c84SAndroid Build Coastguard Worker {
39*cf5a6c84SAndroid Build Coastguard Worker char *n, *new, c;
40*cf5a6c84SAndroid Build Coastguard Worker int bare = 1;
41*cf5a6c84SAndroid Build Coastguard Worker
42*cf5a6c84SAndroid Build Coastguard Worker // Shell feeds in " " for blank args, leading space not meaningful.
43*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*flags)) flags++;
44*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*all)) all++;
45*cf5a6c84SAndroid Build Coastguard Worker
46*cf5a6c84SAndroid Build Coastguard Worker n = new = strdup(all);
47*cf5a6c84SAndroid Build Coastguard Worker while (*all) {
48*cf5a6c84SAndroid Build Coastguard Worker // --longopt parentheticals dealt with as a unit
49*cf5a6c84SAndroid Build Coastguard Worker if (*all == '(') {
50*cf5a6c84SAndroid Build Coastguard Worker int len = 0;
51*cf5a6c84SAndroid Build Coastguard Worker
52*cf5a6c84SAndroid Build Coastguard Worker while (all[len]) if (all[len++] == ')') break;
53*cf5a6c84SAndroid Build Coastguard Worker if (strncmp(flags, all, len)) {
54*cf5a6c84SAndroid Build Coastguard Worker // bare longopts need their own skip placeholders
55*cf5a6c84SAndroid Build Coastguard Worker if (bare) *(new++) = 1;
56*cf5a6c84SAndroid Build Coastguard Worker } else {
57*cf5a6c84SAndroid Build Coastguard Worker memcpy(new, all, len);
58*cf5a6c84SAndroid Build Coastguard Worker new += len;
59*cf5a6c84SAndroid Build Coastguard Worker flags += len;
60*cf5a6c84SAndroid Build Coastguard Worker }
61*cf5a6c84SAndroid Build Coastguard Worker all += len;
62*cf5a6c84SAndroid Build Coastguard Worker continue;
63*cf5a6c84SAndroid Build Coastguard Worker }
64*cf5a6c84SAndroid Build Coastguard Worker c = *(all++);
65*cf5a6c84SAndroid Build Coastguard Worker if (bare && !chrtype(c)) bare = 0;
66*cf5a6c84SAndroid Build Coastguard Worker if (*flags == c) {
67*cf5a6c84SAndroid Build Coastguard Worker *(new++) = c;
68*cf5a6c84SAndroid Build Coastguard Worker flags++;
69*cf5a6c84SAndroid Build Coastguard Worker continue;
70*cf5a6c84SAndroid Build Coastguard Worker }
71*cf5a6c84SAndroid Build Coastguard Worker
72*cf5a6c84SAndroid Build Coastguard Worker c = chrtype(c);
73*cf5a6c84SAndroid Build Coastguard Worker if (!c || (!bare && c==3)) *(new++) = 1;
74*cf5a6c84SAndroid Build Coastguard Worker else if (c==2) while (isdigit(*all)) all++;
75*cf5a6c84SAndroid Build Coastguard Worker }
76*cf5a6c84SAndroid Build Coastguard Worker *new = 0;
77*cf5a6c84SAndroid Build Coastguard Worker
78*cf5a6c84SAndroid Build Coastguard Worker return n;
79*cf5a6c84SAndroid Build Coastguard Worker }
80*cf5a6c84SAndroid Build Coastguard Worker
81*cf5a6c84SAndroid Build Coastguard Worker // Break down a command string into linked list of "struct flag".
82*cf5a6c84SAndroid Build Coastguard Worker
digest(char * string)83*cf5a6c84SAndroid Build Coastguard Worker struct flag *digest(char *string)
84*cf5a6c84SAndroid Build Coastguard Worker {
85*cf5a6c84SAndroid Build Coastguard Worker struct flag *list = 0;
86*cf5a6c84SAndroid Build Coastguard Worker char *err = string, c;
87*cf5a6c84SAndroid Build Coastguard Worker
88*cf5a6c84SAndroid Build Coastguard Worker while (*string) {
89*cf5a6c84SAndroid Build Coastguard Worker // Groups must be at end.
90*cf5a6c84SAndroid Build Coastguard Worker if (*string == '[') break;
91*cf5a6c84SAndroid Build Coastguard Worker
92*cf5a6c84SAndroid Build Coastguard Worker // Longopts
93*cf5a6c84SAndroid Build Coastguard Worker if (*string == '(') {
94*cf5a6c84SAndroid Build Coastguard Worker struct flag *new = calloc(sizeof(struct flag), 1);
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker if (string[1]==')') {
97*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "empty () longopt in '%s'", err);
98*cf5a6c84SAndroid Build Coastguard Worker exit(1);
99*cf5a6c84SAndroid Build Coastguard Worker }
100*cf5a6c84SAndroid Build Coastguard Worker new->command = ++string;
101*cf5a6c84SAndroid Build Coastguard Worker
102*cf5a6c84SAndroid Build Coastguard Worker // Attach longopt to previous short opt, if any.
103*cf5a6c84SAndroid Build Coastguard Worker if (list && list->command) {
104*cf5a6c84SAndroid Build Coastguard Worker new->next = list->lopt;
105*cf5a6c84SAndroid Build Coastguard Worker list->lopt = new;
106*cf5a6c84SAndroid Build Coastguard Worker } else {
107*cf5a6c84SAndroid Build Coastguard Worker struct flag *blank = calloc(sizeof(struct flag), 1);
108*cf5a6c84SAndroid Build Coastguard Worker
109*cf5a6c84SAndroid Build Coastguard Worker blank->next = list;
110*cf5a6c84SAndroid Build Coastguard Worker blank->lopt = new;
111*cf5a6c84SAndroid Build Coastguard Worker list = blank;
112*cf5a6c84SAndroid Build Coastguard Worker }
113*cf5a6c84SAndroid Build Coastguard Worker // An empty longopt () would break this.
114*cf5a6c84SAndroid Build Coastguard Worker while (*++string != ')') if (*string == '-') *string = '_';
115*cf5a6c84SAndroid Build Coastguard Worker *(string++) = 0;
116*cf5a6c84SAndroid Build Coastguard Worker continue;
117*cf5a6c84SAndroid Build Coastguard Worker }
118*cf5a6c84SAndroid Build Coastguard Worker
119*cf5a6c84SAndroid Build Coastguard Worker c = chrtype(*string);
120*cf5a6c84SAndroid Build Coastguard Worker if (c == 1 || (c == 3 && !list)) string++;
121*cf5a6c84SAndroid Build Coastguard Worker else if (c == 2) {
122*cf5a6c84SAndroid Build Coastguard Worker if (string[1]=='-') string++;
123*cf5a6c84SAndroid Build Coastguard Worker if (!isdigit(string[1])) {
124*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "%c without number in '%s'", *string, err);
125*cf5a6c84SAndroid Build Coastguard Worker exit(1);
126*cf5a6c84SAndroid Build Coastguard Worker }
127*cf5a6c84SAndroid Build Coastguard Worker while (isdigit(*++string)) {
128*cf5a6c84SAndroid Build Coastguard Worker if (!list) {
129*cf5a6c84SAndroid Build Coastguard Worker string++;
130*cf5a6c84SAndroid Build Coastguard Worker break;
131*cf5a6c84SAndroid Build Coastguard Worker }
132*cf5a6c84SAndroid Build Coastguard Worker }
133*cf5a6c84SAndroid Build Coastguard Worker } else {
134*cf5a6c84SAndroid Build Coastguard Worker struct flag *new = calloc(sizeof(struct flag), 1);
135*cf5a6c84SAndroid Build Coastguard Worker
136*cf5a6c84SAndroid Build Coastguard Worker if (string[0]=='~' && string[1]!='(') {
137*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "~ without (longopt) in '%s'", err);
138*cf5a6c84SAndroid Build Coastguard Worker exit(1);
139*cf5a6c84SAndroid Build Coastguard Worker }
140*cf5a6c84SAndroid Build Coastguard Worker new->command = string++;
141*cf5a6c84SAndroid Build Coastguard Worker new->next = list;
142*cf5a6c84SAndroid Build Coastguard Worker list = new;
143*cf5a6c84SAndroid Build Coastguard Worker }
144*cf5a6c84SAndroid Build Coastguard Worker }
145*cf5a6c84SAndroid Build Coastguard Worker
146*cf5a6c84SAndroid Build Coastguard Worker return list;
147*cf5a6c84SAndroid Build Coastguard Worker }
148*cf5a6c84SAndroid Build Coastguard Worker
149*cf5a6c84SAndroid Build Coastguard Worker // Parse C-style octal escape
octane(char * from)150*cf5a6c84SAndroid Build Coastguard Worker void octane(char *from)
151*cf5a6c84SAndroid Build Coastguard Worker {
152*cf5a6c84SAndroid Build Coastguard Worker unsigned char *to = (void *)from;
153*cf5a6c84SAndroid Build Coastguard Worker
154*cf5a6c84SAndroid Build Coastguard Worker while (*from) {
155*cf5a6c84SAndroid Build Coastguard Worker if (*from == '\\') {
156*cf5a6c84SAndroid Build Coastguard Worker *to = 0;
157*cf5a6c84SAndroid Build Coastguard Worker while (isdigit(*++from)) *to = (8**to)+*from-'0';
158*cf5a6c84SAndroid Build Coastguard Worker to++;
159*cf5a6c84SAndroid Build Coastguard Worker } else *to++ = *from++;
160*cf5a6c84SAndroid Build Coastguard Worker }
161*cf5a6c84SAndroid Build Coastguard Worker *to = 0;
162*cf5a6c84SAndroid Build Coastguard Worker }
163*cf5a6c84SAndroid Build Coastguard Worker
main(int argc,char * argv[])164*cf5a6c84SAndroid Build Coastguard Worker int main(int argc, char *argv[])
165*cf5a6c84SAndroid Build Coastguard Worker {
166*cf5a6c84SAndroid Build Coastguard Worker char command[256], flags[1024], allflags[1024];
167*cf5a6c84SAndroid Build Coastguard Worker char *out, *outbuf = malloc(1024*1024);
168*cf5a6c84SAndroid Build Coastguard Worker
169*cf5a6c84SAndroid Build Coastguard Worker // Yes, the output buffer is 1 megabyte with no bounds checking.
170*cf5a6c84SAndroid Build Coastguard Worker // See "intentionally crappy", above.
171*cf5a6c84SAndroid Build Coastguard Worker if (!(out = outbuf)) return 1;
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Worker printf("#undef FORCED_FLAG\n#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1LL\n"
174*cf5a6c84SAndroid Build Coastguard Worker "#else\n#define FORCED_FLAG 0LL\n#endif\n\n");
175*cf5a6c84SAndroid Build Coastguard Worker
176*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
177*cf5a6c84SAndroid Build Coastguard Worker struct flag *flist, *aflist, *offlist;
178*cf5a6c84SAndroid Build Coastguard Worker char *mgaps = 0;
179*cf5a6c84SAndroid Build Coastguard Worker unsigned bit;
180*cf5a6c84SAndroid Build Coastguard Worker
181*cf5a6c84SAndroid Build Coastguard Worker *command = *flags = *allflags = 0;
182*cf5a6c84SAndroid Build Coastguard Worker bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
183*cf5a6c84SAndroid Build Coastguard Worker command, flags, allflags);
184*cf5a6c84SAndroid Build Coastguard Worker octane(flags);
185*cf5a6c84SAndroid Build Coastguard Worker octane(allflags);
186*cf5a6c84SAndroid Build Coastguard Worker
187*cf5a6c84SAndroid Build Coastguard Worker if (getenv("DEBUG"))
188*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
189*cf5a6c84SAndroid Build Coastguard Worker command, flags, allflags);
190*cf5a6c84SAndroid Build Coastguard Worker
191*cf5a6c84SAndroid Build Coastguard Worker if (!*command) break;
192*cf5a6c84SAndroid Build Coastguard Worker if (bit != 3) {
193*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
194*cf5a6c84SAndroid Build Coastguard Worker exit(1);
195*cf5a6c84SAndroid Build Coastguard Worker }
196*cf5a6c84SAndroid Build Coastguard Worker
197*cf5a6c84SAndroid Build Coastguard Worker bit = 0;
198*cf5a6c84SAndroid Build Coastguard Worker printf("// %s %s %s\n", command, flags, allflags);
199*cf5a6c84SAndroid Build Coastguard Worker if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
200*cf5a6c84SAndroid Build Coastguard Worker else if (*allflags != ' ') mgaps = allflags;
201*cf5a6c84SAndroid Build Coastguard Worker // If command disabled, use allflags for OLDTOY()
202*cf5a6c84SAndroid Build Coastguard Worker printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
203*cf5a6c84SAndroid Build Coastguard Worker if (mgaps) printf("\"%s\"\n", mgaps);
204*cf5a6c84SAndroid Build Coastguard Worker else printf("0\n");
205*cf5a6c84SAndroid Build Coastguard Worker if (mgaps != allflags) free(mgaps);
206*cf5a6c84SAndroid Build Coastguard Worker
207*cf5a6c84SAndroid Build Coastguard Worker flist = digest(flags);
208*cf5a6c84SAndroid Build Coastguard Worker offlist = aflist = digest(allflags);
209*cf5a6c84SAndroid Build Coastguard Worker
210*cf5a6c84SAndroid Build Coastguard Worker printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
211*cf5a6c84SAndroid Build Coastguard Worker command, command, command);
212*cf5a6c84SAndroid Build Coastguard Worker
213*cf5a6c84SAndroid Build Coastguard Worker while (offlist) {
214*cf5a6c84SAndroid Build Coastguard Worker char *s = (char []){0, 0, 0, 0};
215*cf5a6c84SAndroid Build Coastguard Worker
216*cf5a6c84SAndroid Build Coastguard Worker if (!offlist->command || *offlist->command=='~')
217*cf5a6c84SAndroid Build Coastguard Worker s = offlist->lopt->command;
218*cf5a6c84SAndroid Build Coastguard Worker else {
219*cf5a6c84SAndroid Build Coastguard Worker *s = *offlist->command;
220*cf5a6c84SAndroid Build Coastguard Worker if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
221*cf5a6c84SAndroid Build Coastguard Worker }
222*cf5a6c84SAndroid Build Coastguard Worker printf("#undef FLAG_%s\n", s);
223*cf5a6c84SAndroid Build Coastguard Worker offlist = offlist->next;
224*cf5a6c84SAndroid Build Coastguard Worker }
225*cf5a6c84SAndroid Build Coastguard Worker printf("#endif\n\n");
226*cf5a6c84SAndroid Build Coastguard Worker
227*cf5a6c84SAndroid Build Coastguard Worker sprintf(out, "#ifdef FOR_%s\n#define CLEANUP_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
228*cf5a6c84SAndroid Build Coastguard Worker command, command, command);
229*cf5a6c84SAndroid Build Coastguard Worker out += strlen(out);
230*cf5a6c84SAndroid Build Coastguard Worker
231*cf5a6c84SAndroid Build Coastguard Worker while (aflist) {
232*cf5a6c84SAndroid Build Coastguard Worker char *s = (char []){0, 0, 0, 0};
233*cf5a6c84SAndroid Build Coastguard Worker int enabled = 0;
234*cf5a6c84SAndroid Build Coastguard Worker
235*cf5a6c84SAndroid Build Coastguard Worker // Output flag macro for bare longopts
236*cf5a6c84SAndroid Build Coastguard Worker if (!aflist->command || *aflist->command=='~') {
237*cf5a6c84SAndroid Build Coastguard Worker s = aflist->lopt->command;
238*cf5a6c84SAndroid Build Coastguard Worker if (flist && flist->lopt &&
239*cf5a6c84SAndroid Build Coastguard Worker !strcmp(flist->lopt->command, aflist->lopt->command)) enabled++;
240*cf5a6c84SAndroid Build Coastguard Worker // Output normal flag macro
241*cf5a6c84SAndroid Build Coastguard Worker } else {
242*cf5a6c84SAndroid Build Coastguard Worker *s = *aflist->command;
243*cf5a6c84SAndroid Build Coastguard Worker if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
244*cf5a6c84SAndroid Build Coastguard Worker if (flist && flist->command && *aflist->command == *flist->command)
245*cf5a6c84SAndroid Build Coastguard Worker enabled++;
246*cf5a6c84SAndroid Build Coastguard Worker }
247*cf5a6c84SAndroid Build Coastguard Worker out += sprintf(out, "#define FLAG_%s (%s<<%d)\n",
248*cf5a6c84SAndroid Build Coastguard Worker s, enabled ? "1LL" : "FORCED_FLAG", bit++);
249*cf5a6c84SAndroid Build Coastguard Worker aflist = aflist->next;
250*cf5a6c84SAndroid Build Coastguard Worker if (enabled) flist = flist->next;
251*cf5a6c84SAndroid Build Coastguard Worker }
252*cf5a6c84SAndroid Build Coastguard Worker out = stpcpy(out, "#endif\n\n");
253*cf5a6c84SAndroid Build Coastguard Worker }
254*cf5a6c84SAndroid Build Coastguard Worker
255*cf5a6c84SAndroid Build Coastguard Worker if (fflush(0) && ferror(stdout)) return 1;
256*cf5a6c84SAndroid Build Coastguard Worker
257*cf5a6c84SAndroid Build Coastguard Worker out = outbuf;
258*cf5a6c84SAndroid Build Coastguard Worker while (*out) {
259*cf5a6c84SAndroid Build Coastguard Worker int i = write(1, outbuf, strlen(outbuf));
260*cf5a6c84SAndroid Build Coastguard Worker
261*cf5a6c84SAndroid Build Coastguard Worker if (i<0) return 1;
262*cf5a6c84SAndroid Build Coastguard Worker out += i;
263*cf5a6c84SAndroid Build Coastguard Worker }
264*cf5a6c84SAndroid Build Coastguard Worker
265*cf5a6c84SAndroid Build Coastguard Worker return 0;
266*cf5a6c84SAndroid Build Coastguard Worker }
267