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