Home | History | Annotate | Download | only in scripts
      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