• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unistd.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <ctype.h>
15 
16 struct flag {
17   struct flag *next;
18   char *command;
19   struct flag *lopt;
20 };
21 
22 // replace chopped out USE_BLAH() sections with low-ascii characters
23 // showing how many flags got skipped
24 
mark_gaps(char * flags,char * all)25 char *mark_gaps(char *flags, char *all)
26 {
27   char *n, *new, c;
28 
29   // Shell feeds in " " for blank args, leading space not meaningful.
30   while (isspace(*flags)) flags++;
31   while (isspace(*all)) all++;
32 
33   n = new = strdup(all);
34   while (*all) {
35     if (*flags == *all) {
36       *(new++) = *(all++);
37       *flags++;
38       continue;
39     }
40 
41     c = *(all++);
42     if (strchr("?&^-:#|@*; ", c));
43     else if (strchr("=<>", c)) while (isdigit(*all)) all++;
44     else if (c == '(') while(*(all++) != ')');
45     else *(new++) = 1;
46   }
47   *new = 0;
48 
49   return n;
50 }
51 
52 // Break down a command string into struct flag list.
53 
digest(char * string)54 struct flag *digest(char *string)
55 {
56   struct flag *list = NULL;
57   char *err = string;
58 
59   while (*string) {
60     // Groups must be at end.
61     if (*string == '[') break;
62 
63     // Longopts
64     if (*string == '(') {
65       struct flag *new = calloc(sizeof(struct flag), 1);
66 
67       new->command = ++string;
68 
69       // Attach longopt to previous short opt, if any.
70       if (list && list->command) {
71         new->next = list->lopt;
72         list->lopt = new;
73       } else {
74         struct flag *blank = calloc(sizeof(struct flag), 1);
75 
76         blank->next = list;
77         blank->lopt = new;
78         list = blank;
79       }
80       // An empty longopt () would break this.
81       while (*++string != ')') if (*string == '-') *string = '_';
82       *(string++) = 0;
83       continue;
84     }
85 
86     if (strchr("?&^-:#|@*; ", *string)) string++;
87     else if (strchr("=<>", *string)) {
88       if (!isdigit(string[1])) {
89         fprintf(stderr, "%c without number in '%s'", *string, err);
90         exit(1);
91       }
92       while (isdigit(*++string)) {
93         if (!list) {
94            string++;
95            break;
96         }
97       }
98     } else {
99       struct flag *new = calloc(sizeof(struct flag), 1);
100 
101       new->command = string++;
102       new->next = list;
103       list = new;
104     }
105   }
106 
107   return list;
108 }
109 
main(int argc,char * argv[])110 int main(int argc, char *argv[])
111 {
112   char command[256], flags[1023], allflags[1024];
113   char *out, *outbuf = malloc(1024*1024);
114 
115   // Yes, the output buffer is 1 megabyte with no bounds checking.
116   // See "intentionally crappy", above.
117   if (!(out = outbuf)) return 1;
118 
119   printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
120     "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n"
121     "#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n");
122 
123   for (;;) {
124     struct flag *flist, *aflist, *offlist;
125     char *gaps, *mgaps, c;
126     unsigned bit;
127 
128     *command = *flags = *allflags = 0;
129     bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
130                     command, flags, allflags);
131 
132     if (getenv("DEBUG"))
133       fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
134         command, flags, allflags);
135 
136     if (!*command) break;
137     if (bit != 3) {
138       fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
139       exit(1);
140     }
141 
142     bit = 0;
143     printf("// %s %s %s\n", command, flags, allflags);
144     mgaps = mark_gaps(flags, allflags);
145     for (gaps = mgaps; *gaps == 1; gaps++);
146     if (*gaps) c = '"';
147     else {
148       c = ' ';
149       gaps = "0";
150     }
151     printf("#undef OPTSTR_%s\n#define OPTSTR_%s %c%s%c\n",
152             command, command, c, gaps, c);
153     free(mgaps);
154 
155     flist = digest(flags);
156     offlist = aflist = digest(allflags);
157 
158     printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
159            command, command, command);
160 
161     while (offlist) {
162       struct flag *f = offlist->lopt;
163       while (f) {
164         printf("#undef FLAG_%s\n", f->command);
165         f = f->next;
166       }
167       if (offlist->command) printf("#undef FLAG_%c\n", *offlist->command);
168       offlist = offlist->next;
169     }
170     printf("#endif\n\n");
171 
172     sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
173             command, command);
174     out += strlen(out);
175 
176     while (aflist) {
177       char *llstr = bit>31 ? "LL" : "";
178 
179       // Output flag macro for bare longopts
180       if (aflist->lopt) {
181         if (flist && flist->lopt &&
182             !strcmp(flist->lopt->command, aflist->lopt->command))
183         {
184           sprintf(out, "#define FLAG_%s (1%s<<%d)\n", flist->lopt->command,
185             llstr, bit);
186           flist->lopt = flist->lopt->next;
187         } else sprintf(out, "#define FLAG_%s (FORCED_FLAG%s<<%d)\n",
188                        aflist->lopt->command, llstr, bit);
189         aflist->lopt = aflist->lopt->next;
190         if (!aflist->command) {
191           aflist = aflist->next;
192           bit++;
193           if (flist) flist = flist->next;
194         }
195       // Output normal flag macro
196       } else if (aflist->command) {
197         if (flist && (!flist->command || *aflist->command == *flist->command)) {
198           if (aflist->command)
199             sprintf(out, "#define FLAG_%c (1%s<<%d)\n", *aflist->command,
200               llstr, bit);
201           flist = flist->next;
202         } else sprintf(out, "#define FLAG_%c (FORCED_FLAG%s<<%d)\n",
203                        *aflist->command, llstr, bit);
204         bit++;
205         aflist = aflist->next;
206       }
207       out += strlen(out);
208     }
209     out = stpcpy(out, "#endif\n\n");
210   }
211 
212   if (fflush(0) && ferror(stdout)) return 1;
213 
214   out = outbuf;
215   while (*out) {
216     int i = write(1, outbuf, strlen(outbuf));
217 
218     if (i<0) return 1;
219     out += i;
220   }
221 
222   return 0;
223 }
224