1
2
3
4
5
6
7
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
16struct flag {
17 struct flag *next, *lopt;
18 char *command;
19};
20
21int chrtype(char c)
22{
23
24 if (strchr("^-:#|@*; %.", c)) return 1;
25
26
27 if (strchr("=<>", c)) return 2;
28
29 if (strchr("?&0", c)) return 3;
30
31 return 0;
32}
33
34
35
36
37char *mark_gaps(char *flags, char *all)
38{
39 char *n, *new, c;
40 int bare = 1;
41
42
43 while (isspace(*flags)) flags++;
44 while (isspace(*all)) all++;
45
46 n = new = strdup(all);
47 while (*all) {
48
49 if (*all == '(') {
50 int len = 0;
51
52 while (all[len]) if (all[len++] == ')') break;
53 if (strncmp(flags, all, len)) {
54
55 if (bare) *(new++) = 1;
56 } else {
57 memcpy(new, all, len);
58 new += len;
59 flags += len;
60 }
61 all += len;
62 continue;
63 }
64 c = *(all++);
65 if (bare && !chrtype(c)) bare = 0;
66 if (*flags == c) {
67 *(new++) = c;
68 flags++;
69 continue;
70 }
71
72 c = chrtype(c);
73 if (!c || (!bare && c==3)) *(new++) = 1;
74 else if (c==2) while (isdigit(*all)) all++;
75 }
76 *new = 0;
77
78 return n;
79}
80
81
82
83struct flag *digest(char *string)
84{
85 struct flag *list = 0;
86 char *err = string, c;
87
88 while (*string) {
89
90 if (*string == '[') break;
91
92
93 if (*string == '(') {
94 struct flag *new = calloc(sizeof(struct flag), 1);
95
96 if (string[1]==')') {
97 fprintf(stderr, "empty () longopt in '%s'", err);
98 exit(1);
99 }
100 new->command = ++string;
101
102
103 if (list && list->command) {
104 new->next = list->lopt;
105 list->lopt = new;
106 } else {
107 struct flag *blank = calloc(sizeof(struct flag), 1);
108
109 blank->next = list;
110 blank->lopt = new;
111 list = blank;
112 }
113
114 while (*++string != ')') if (*string == '-') *string = '_';
115 *(string++) = 0;
116 continue;
117 }
118
119 c = chrtype(*string);
120 if (c == 1 || (c == 3 && !list)) string++;
121 else if (c == 2) {
122 if (string[1]=='-') string++;
123 if (!isdigit(string[1])) {
124 fprintf(stderr, "%c without number in '%s'", *string, err);
125 exit(1);
126 }
127 while (isdigit(*++string)) {
128 if (!list) {
129 string++;
130 break;
131 }
132 }
133 } else {
134 struct flag *new = calloc(sizeof(struct flag), 1);
135
136 if (string[0]=='~' && string[1]!='(') {
137 fprintf(stderr, "~ without (longopt) in '%s'", err);
138 exit(1);
139 }
140 new->command = string++;
141 new->next = list;
142 list = new;
143 }
144 }
145
146 return list;
147}
148
149
150void octane(char *from)
151{
152 unsigned char *to = (void *)from;
153
154 while (*from) {
155 if (*from == '\\') {
156 *to = 0;
157 while (isdigit(*++from)) *to = (8**to)+*from-'0';
158 to++;
159 } else *to++ = *from++;
160 }
161 *to = 0;
162}
163
164int main(int argc, char *argv[])
165{
166 char command[256], flags[1024], allflags[1024];
167 char *out, *outbuf = malloc(1024*1024);
168
169
170
171 if (!(out = outbuf)) return 1;
172
173 printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
174 "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1ULL\n"
175 "#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0LL\n#endif\n\n");
176
177 for (;;) {
178 struct flag *flist, *aflist, *offlist;
179 char *mgaps = 0;
180 unsigned bit;
181
182 *command = *flags = *allflags = 0;
183 bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
184 command, flags, allflags);
185 octane(flags);
186 octane(allflags);
187
188 if (getenv("DEBUG"))
189 fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
190 command, flags, allflags);
191
192 if (!*command) break;
193 if (bit != 3) {
194 fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
195 exit(1);
196 }
197
198 bit = 0;
199 printf("// %s %s %s\n", command, flags, allflags);
200 if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
201 else if (*allflags != ' ') mgaps = allflags;
202
203 printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
204 if (mgaps) printf("\"%s\"\n", mgaps);
205 else printf("0\n");
206 if (mgaps != allflags) free(mgaps);
207
208 flist = digest(flags);
209 offlist = aflist = digest(allflags);
210
211 printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
212 command, command, command);
213
214 while (offlist) {
215 char *s = (char []){0, 0, 0, 0};
216
217 if (!offlist->command || *offlist->command=='~')
218 s = offlist->lopt->command;
219 else {
220 *s = *offlist->command;
221 if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
222 }
223 printf("#undef FLAG_%s\n", s);
224 offlist = offlist->next;
225 }
226 printf("#endif\n\n");
227
228 sprintf(out, "#ifdef FOR_%s\n#define CLEANUP_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
229 command, command, command);
230 out += strlen(out);
231
232 while (aflist) {
233 char *llstr = bit>30 ? "LL" : "", *s = (char []){0, 0, 0, 0};
234 int enabled = 0;
235
236
237 if (!aflist->command || *aflist->command=='~') {
238 s = aflist->lopt->command;
239 if (flist && flist->lopt &&
240 !strcmp(flist->lopt->command, aflist->lopt->command)) enabled++;
241
242 } else {
243 *s = *aflist->command;
244 if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
245 if (flist && flist->command && *aflist->command == *flist->command)
246 enabled++;
247 }
248 out += sprintf(out, "#define FLAG_%s (%s%s<<%d)\n",
249 s, enabled ? "1" : "FORCED_FLAG", llstr, bit++);
250 aflist = aflist->next;
251 if (enabled) flist = flist->next;
252 }
253 out = stpcpy(out, "#endif\n\n");
254 }
255
256 if (fflush(0) && ferror(stdout)) return 1;
257
258 out = outbuf;
259 while (*out) {
260 int i = write(1, outbuf, strlen(outbuf));
261
262 if (i<0) return 1;
263 out += i;
264 }
265
266 return 0;
267}
268