xref: /aosp_15_r20/external/toybox/scripts/mkflags.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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