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