Revert back to upstream 0.6.0 and remove all except for dhcp related
[platform/upstream/toybox.git] / scripts / mkflags.c
1 // 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
14 struct flag {
15   struct flag *next;
16   char *command;
17   struct flag *lopt;
18 };
19
20 // replace chopped out USE_BLAH() sections with low-ascii characters
21 // showing how many flags got skipped
22
23 char *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
50 // Break down a command string into struct flag list.
51
52 struct flag *digest(char *string)
53 {
54   struct flag *list = NULL;
55   char *err = string;
56
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       }
78       // An empty longopt () would break this.
79       while (*++string != ')') if (*string == '-') *string = '_';
80       *(string++) = 0;
81       continue;
82     }
83
84     if (strchr("?&^-:#|@*; ", *string)) string++;
85     else if (strchr("=<>", *string)) {
86       if (!isdigit(string[1])) {
87         fprintf(stderr, "%c without number in '%s'", *string, err);
88         exit(1);
89       }
90       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
108 int main(int argc, char *argv[])
109 {
110   char command[256], flags[1023], allflags[1024];
111   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;
116
117   printf("#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n"
118          "#else\n#define FORCED_FLAG 0\n#endif\n\n");
119
120   for (;;) {
121     struct flag *flist, *aflist, *offlist;
122     char *gaps, *mgaps, c;
123     unsigned bit;
124
125     *command = *flags = *allflags = 0;
126     bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
127                     command, flags, allflags);
128
129     if (getenv("DEBUG"))
130       fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
131         command, flags, allflags);
132
133     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;
140     printf("// %s %s %s\n", command, flags, allflags);
141     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);
151
152     flist = digest(flags);
153     offlist = aflist = digest(allflags);
154
155     printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
156            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
169     sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
170             command, command);
171     out += strlen(out);
172
173     while (aflist) {
174       if (aflist->lopt) {
175         if (flist && flist->lopt &&
176             !strcmp(flist->lopt->command, aflist->lopt->command))
177         {
178           sprintf(out, "#define FLAG_%s (1<<%d)\n", flist->lopt->command, bit);
179           flist->lopt = flist->lopt->next;
180         } else sprintf(out, "#define FLAG_%s (FORCED_FLAG<<%d)\n",
181                        aflist->lopt->command, bit);
182         aflist->lopt = aflist->lopt->next;
183         if (!aflist->command) {
184           aflist = aflist->next;
185           bit++;
186           if (flist) flist = flist->next;
187         }
188       } else if (aflist->command) {
189         if (flist && (!flist->command || *aflist->command == *flist->command)) {
190           if (aflist->command)
191             sprintf(out, "#define FLAG_%c (1<<%d)\n", *aflist->command, bit);
192           flist = flist->next;
193         } else sprintf(out, "#define FLAG_%c (FORCED_FLAG<<%d)\n",
194                        *aflist->command, bit);
195         bit++;
196         aflist = aflist->next;
197       }
198       out += strlen(out);
199     }
200     out = stpcpy(out, "#endif\n\n");
201   }
202
203   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   }
212
213   return 0;
214 }