10f66f451Sopenharmony_ci// Take three word input lines on stdin and produce flag #defines to stdout. 20f66f451Sopenharmony_ci// The three words on each input lnie are command name, option string with 30f66f451Sopenharmony_ci// current config, option string from allyesconfig. The three are space 40f66f451Sopenharmony_ci// separated and the last two are in double quotes. 50f66f451Sopenharmony_ci 60f66f451Sopenharmony_ci// This is intentionally crappy code because we control the inputs. It leaks 70f66f451Sopenharmony_ci// memory like a sieve and segfaults if malloc returns null, but does the job. 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ci#include <unistd.h> 100f66f451Sopenharmony_ci#include <stdio.h> 110f66f451Sopenharmony_ci#include <stdlib.h> 120f66f451Sopenharmony_ci#include <string.h> 130f66f451Sopenharmony_ci#include <errno.h> 140f66f451Sopenharmony_ci#include <ctype.h> 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_cistruct flag { 170f66f451Sopenharmony_ci struct flag *next; 180f66f451Sopenharmony_ci char *command; 190f66f451Sopenharmony_ci struct flag *lopt; 200f66f451Sopenharmony_ci}; 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ciint chrtype(char c) 230f66f451Sopenharmony_ci{ 240f66f451Sopenharmony_ci // Does this populate a GLOBALS() variable? 250f66f451Sopenharmony_ci if (strchr("?&^-:#|@*; %", c)) return 1; 260f66f451Sopenharmony_ci 270f66f451Sopenharmony_ci // Is this followed by a numeric argument in optstr? 280f66f451Sopenharmony_ci if (strchr("=<>", c)) return 2; 290f66f451Sopenharmony_ci 300f66f451Sopenharmony_ci return 0; 310f66f451Sopenharmony_ci} 320f66f451Sopenharmony_ci 330f66f451Sopenharmony_ci// replace chopped out USE_BLAH() sections with low-ascii characters 340f66f451Sopenharmony_ci// showing how many flags got skipped 350f66f451Sopenharmony_ci 360f66f451Sopenharmony_cichar *mark_gaps(char *flags, char *all) 370f66f451Sopenharmony_ci{ 380f66f451Sopenharmony_ci char *n, *new, c; 390f66f451Sopenharmony_ci int bare = 1; 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci // Shell feeds in " " for blank args, leading space not meaningful. 420f66f451Sopenharmony_ci while (isspace(*flags)) flags++; 430f66f451Sopenharmony_ci while (isspace(*all)) all++; 440f66f451Sopenharmony_ci 450f66f451Sopenharmony_ci n = new = strdup(all); 460f66f451Sopenharmony_ci while (*all) { 470f66f451Sopenharmony_ci // --longopt parentheticals dealt with as a unit 480f66f451Sopenharmony_ci if (*all == '(') { 490f66f451Sopenharmony_ci int len = 0; 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci while (all[len++] != ')'); 520f66f451Sopenharmony_ci if (strncmp(flags, all, len)) { 530f66f451Sopenharmony_ci // bare longopts need their own skip placeholders 540f66f451Sopenharmony_ci if (bare) *(new++) = 1; 550f66f451Sopenharmony_ci } else { 560f66f451Sopenharmony_ci memcpy(new, all, len); 570f66f451Sopenharmony_ci new += len; 580f66f451Sopenharmony_ci flags += len; 590f66f451Sopenharmony_ci } 600f66f451Sopenharmony_ci all += len; 610f66f451Sopenharmony_ci continue; 620f66f451Sopenharmony_ci } 630f66f451Sopenharmony_ci c = *(all++); 640f66f451Sopenharmony_ci if (bare) bare = chrtype(c); 650f66f451Sopenharmony_ci if (*flags == c) { 660f66f451Sopenharmony_ci *(new++) = c; 670f66f451Sopenharmony_ci flags++; 680f66f451Sopenharmony_ci continue; 690f66f451Sopenharmony_ci } 700f66f451Sopenharmony_ci 710f66f451Sopenharmony_ci c = chrtype(c); 720f66f451Sopenharmony_ci if (!c) *(new++) = 1; 730f66f451Sopenharmony_ci else if (c==2) while (isdigit(*all)) all++; 740f66f451Sopenharmony_ci } 750f66f451Sopenharmony_ci *new = 0; 760f66f451Sopenharmony_ci 770f66f451Sopenharmony_ci return n; 780f66f451Sopenharmony_ci} 790f66f451Sopenharmony_ci 800f66f451Sopenharmony_ci// Break down a command string into linked list of "struct flag". 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_cistruct flag *digest(char *string) 830f66f451Sopenharmony_ci{ 840f66f451Sopenharmony_ci struct flag *list = NULL; 850f66f451Sopenharmony_ci char *err = string, c; 860f66f451Sopenharmony_ci 870f66f451Sopenharmony_ci while (*string) { 880f66f451Sopenharmony_ci // Groups must be at end. 890f66f451Sopenharmony_ci if (*string == '[') break; 900f66f451Sopenharmony_ci 910f66f451Sopenharmony_ci // Longopts 920f66f451Sopenharmony_ci if (*string == '(') { 930f66f451Sopenharmony_ci struct flag *new = calloc(sizeof(struct flag), 1); 940f66f451Sopenharmony_ci 950f66f451Sopenharmony_ci new->command = ++string; 960f66f451Sopenharmony_ci 970f66f451Sopenharmony_ci // Attach longopt to previous short opt, if any. 980f66f451Sopenharmony_ci if (list && list->command) { 990f66f451Sopenharmony_ci new->next = list->lopt; 1000f66f451Sopenharmony_ci list->lopt = new; 1010f66f451Sopenharmony_ci } else { 1020f66f451Sopenharmony_ci struct flag *blank = calloc(sizeof(struct flag), 1); 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci blank->next = list; 1050f66f451Sopenharmony_ci blank->lopt = new; 1060f66f451Sopenharmony_ci list = blank; 1070f66f451Sopenharmony_ci } 1080f66f451Sopenharmony_ci // An empty longopt () would break this. 1090f66f451Sopenharmony_ci while (*++string != ')') if (*string == '-') *string = '_'; 1100f66f451Sopenharmony_ci *(string++) = 0; 1110f66f451Sopenharmony_ci continue; 1120f66f451Sopenharmony_ci } 1130f66f451Sopenharmony_ci 1140f66f451Sopenharmony_ci c = chrtype(*string); 1150f66f451Sopenharmony_ci if (c == 1) string++; 1160f66f451Sopenharmony_ci else if (c == 2) { 1170f66f451Sopenharmony_ci if (string[1]=='-') string++; 1180f66f451Sopenharmony_ci if (!isdigit(string[1])) { 1190f66f451Sopenharmony_ci fprintf(stderr, "%c without number in '%s'", *string, err); 1200f66f451Sopenharmony_ci exit(1); 1210f66f451Sopenharmony_ci } 1220f66f451Sopenharmony_ci while (isdigit(*++string)) { 1230f66f451Sopenharmony_ci if (!list) { 1240f66f451Sopenharmony_ci string++; 1250f66f451Sopenharmony_ci break; 1260f66f451Sopenharmony_ci } 1270f66f451Sopenharmony_ci } 1280f66f451Sopenharmony_ci } else { 1290f66f451Sopenharmony_ci struct flag *new = calloc(sizeof(struct flag), 1); 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_ci new->command = string++; 1320f66f451Sopenharmony_ci new->next = list; 1330f66f451Sopenharmony_ci list = new; 1340f66f451Sopenharmony_ci } 1350f66f451Sopenharmony_ci } 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci return list; 1380f66f451Sopenharmony_ci} 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci// Parse C-style octal escape 1410f66f451Sopenharmony_civoid octane(char *from) 1420f66f451Sopenharmony_ci{ 1430f66f451Sopenharmony_ci unsigned char *to = (void *)from; 1440f66f451Sopenharmony_ci 1450f66f451Sopenharmony_ci while (*from) { 1460f66f451Sopenharmony_ci if (*from == '\\') { 1470f66f451Sopenharmony_ci *to = 0; 1480f66f451Sopenharmony_ci while (isdigit(*++from)) *to = (8**to)+*from-'0'; 1490f66f451Sopenharmony_ci to++; 1500f66f451Sopenharmony_ci } else *to++ = *from++; 1510f66f451Sopenharmony_ci } 1520f66f451Sopenharmony_ci *to = 0; 1530f66f451Sopenharmony_ci} 1540f66f451Sopenharmony_ci 1550f66f451Sopenharmony_ciint main(int argc, char *argv[]) 1560f66f451Sopenharmony_ci{ 1570f66f451Sopenharmony_ci char command[256], flags[1023], allflags[1024]; 1580f66f451Sopenharmony_ci char *out, *outbuf = malloc(1024*1024); 1590f66f451Sopenharmony_ci 1600f66f451Sopenharmony_ci // Yes, the output buffer is 1 megabyte with no bounds checking. 1610f66f451Sopenharmony_ci // See "intentionally crappy", above. 1620f66f451Sopenharmony_ci if (!(out = outbuf)) return 1; 1630f66f451Sopenharmony_ci 1640f66f451Sopenharmony_ci printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n" 1650f66f451Sopenharmony_ci "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n" 1660f66f451Sopenharmony_ci "#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n"); 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_ci for (;;) { 1690f66f451Sopenharmony_ci struct flag *flist, *aflist, *offlist; 1700f66f451Sopenharmony_ci char *mgaps = 0; 1710f66f451Sopenharmony_ci unsigned bit; 1720f66f451Sopenharmony_ci 1730f66f451Sopenharmony_ci *command = *flags = *allflags = 0; 1740f66f451Sopenharmony_ci bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n", 1750f66f451Sopenharmony_ci command, flags, allflags); 1760f66f451Sopenharmony_ci octane(flags); 1770f66f451Sopenharmony_ci octane(allflags); 1780f66f451Sopenharmony_ci 1790f66f451Sopenharmony_ci if (getenv("DEBUG")) 1800f66f451Sopenharmony_ci fprintf(stderr, "command=%s, flags=%s, allflags=%s\n", 1810f66f451Sopenharmony_ci command, flags, allflags); 1820f66f451Sopenharmony_ci 1830f66f451Sopenharmony_ci if (!*command) break; 1840f66f451Sopenharmony_ci if (bit != 3) { 1850f66f451Sopenharmony_ci fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command); 1860f66f451Sopenharmony_ci exit(1); 1870f66f451Sopenharmony_ci } 1880f66f451Sopenharmony_ci 1890f66f451Sopenharmony_ci bit = 0; 1900f66f451Sopenharmony_ci printf("// %s %s %s\n", command, flags, allflags); 1910f66f451Sopenharmony_ci if (*flags != ' ') mgaps = mark_gaps(flags, allflags); 1920f66f451Sopenharmony_ci else if (*allflags != ' ') mgaps = allflags; 1930f66f451Sopenharmony_ci // If command disabled, use allflags for OLDTOY() 1940f66f451Sopenharmony_ci printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command); 1950f66f451Sopenharmony_ci if (mgaps) printf("\"%s\"\n", mgaps); 1960f66f451Sopenharmony_ci else printf("0\n"); 1970f66f451Sopenharmony_ci if (mgaps != allflags) free(mgaps); 1980f66f451Sopenharmony_ci 1990f66f451Sopenharmony_ci flist = digest(flags); 2000f66f451Sopenharmony_ci offlist = aflist = digest(allflags); 2010f66f451Sopenharmony_ci 2020f66f451Sopenharmony_ci printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n", 2030f66f451Sopenharmony_ci command, command, command); 2040f66f451Sopenharmony_ci 2050f66f451Sopenharmony_ci while (offlist) { 2060f66f451Sopenharmony_ci char *s = (char []){0, 0, 0, 0}; 2070f66f451Sopenharmony_ci 2080f66f451Sopenharmony_ci if (!offlist->command) s = offlist->lopt->command; 2090f66f451Sopenharmony_ci else { 2100f66f451Sopenharmony_ci *s = *offlist->command; 2110f66f451Sopenharmony_ci if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s); 2120f66f451Sopenharmony_ci } 2130f66f451Sopenharmony_ci printf("#undef FLAG_%s\n", s); 2140f66f451Sopenharmony_ci offlist = offlist->next; 2150f66f451Sopenharmony_ci } 2160f66f451Sopenharmony_ci printf("#endif\n\n"); 2170f66f451Sopenharmony_ci 2180f66f451Sopenharmony_ci sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n", 2190f66f451Sopenharmony_ci command, command); 2200f66f451Sopenharmony_ci out += strlen(out); 2210f66f451Sopenharmony_ci 2220f66f451Sopenharmony_ci while (aflist) { 2230f66f451Sopenharmony_ci char *llstr = bit>31 ? "LL" : "", *s = (char []){0, 0, 0, 0}; 2240f66f451Sopenharmony_ci int enabled = 0; 2250f66f451Sopenharmony_ci 2260f66f451Sopenharmony_ci // Output flag macro for bare longopts 2270f66f451Sopenharmony_ci if (!aflist->command) { 2280f66f451Sopenharmony_ci s = aflist->lopt->command; 2290f66f451Sopenharmony_ci if (flist && flist->lopt && 2300f66f451Sopenharmony_ci !strcmp(flist->lopt->command, aflist->lopt->command)) enabled++; 2310f66f451Sopenharmony_ci // Output normal flag macro 2320f66f451Sopenharmony_ci } else { 2330f66f451Sopenharmony_ci *s = *aflist->command; 2340f66f451Sopenharmony_ci if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s); 2350f66f451Sopenharmony_ci if (flist && flist->command && *aflist->command == *flist->command) 2360f66f451Sopenharmony_ci enabled++; 2370f66f451Sopenharmony_ci } 2380f66f451Sopenharmony_ci out += sprintf(out, "#define FLAG_%s (%s%s<<%d)\n", 2390f66f451Sopenharmony_ci s, enabled ? "1" : "FORCED_FLAG", llstr, bit++); 2400f66f451Sopenharmony_ci aflist = aflist->next; 2410f66f451Sopenharmony_ci if (enabled) flist = flist->next; 2420f66f451Sopenharmony_ci } 2430f66f451Sopenharmony_ci out = stpcpy(out, "#endif\n\n"); 2440f66f451Sopenharmony_ci } 2450f66f451Sopenharmony_ci 2460f66f451Sopenharmony_ci if (fflush(0) && ferror(stdout)) return 1; 2470f66f451Sopenharmony_ci 2480f66f451Sopenharmony_ci out = outbuf; 2490f66f451Sopenharmony_ci while (*out) { 2500f66f451Sopenharmony_ci int i = write(1, outbuf, strlen(outbuf)); 2510f66f451Sopenharmony_ci 2520f66f451Sopenharmony_ci if (i<0) return 1; 2530f66f451Sopenharmony_ci out += i; 2540f66f451Sopenharmony_ci } 2550f66f451Sopenharmony_ci 2560f66f451Sopenharmony_ci return 0; 2570f66f451Sopenharmony_ci} 258