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