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 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 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 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