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