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#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1LL\n"
174 "#else\n#define FORCED_FLAG 0LL\n#endif\n\n");
175
176 for (;;) {
177 struct flag *flist, *aflist, *offlist;
178 char *mgaps = 0;
179 unsigned bit;
180
181 *command = *flags = *allflags = 0;
182 bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
183 command, flags, allflags);
184 octane(flags);
185 octane(allflags);
186
187 if (getenv("DEBUG"))
188 fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
189 command, flags, allflags);
190
191 if (!*command) break;
192 if (bit != 3) {
193 fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
194 exit(1);
195 }
196
197 bit = 0;
198 printf("// %s %s %s\n", command, flags, allflags);
199 if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
200 else if (*allflags != ' ') mgaps = allflags;
201
202 printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
203 if (mgaps) printf("\"%s\"\n", mgaps);
204 else printf("0\n");
205 if (mgaps != allflags) free(mgaps);
206
207 flist = digest(flags);
208 offlist = aflist = digest(allflags);
209
210 printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
211 command, command, command);
212
213 while (offlist) {
214 char *s = (char []){0, 0, 0, 0};
215
216 if (!offlist->command || *offlist->command=='~')
217 s = offlist->lopt->command;
218 else {
219 *s = *offlist->command;
220 if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
221 }
222 printf("#undef FLAG_%s\n", s);
223 offlist = offlist->next;
224 }
225 printf("#endif\n\n");
226
227 sprintf(out, "#ifdef FOR_%s\n#define CLEANUP_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
228 command, command, command);
229 out += strlen(out);
230
231 while (aflist) {
232 char *s = (char []){0, 0, 0, 0};
233 int enabled = 0;
234
235
236 if (!aflist->command || *aflist->command=='~') {
237 s = aflist->lopt->command;
238 if (flist && flist->lopt &&
239 !strcmp(flist->lopt->command, aflist->lopt->command)) enabled++;
240
241 } else {
242 *s = *aflist->command;
243 if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
244 if (flist && flist->command && *aflist->command == *flist->command)
245 enabled++;
246 }
247 out += sprintf(out, "#define FLAG_%s (%s<<%d)\n",
248 s, enabled ? "1LL" : "FORCED_FLAG", bit++);
249 aflist = aflist->next;
250 if (enabled) flist = flist->next;
251 }
252 out = stpcpy(out, "#endif\n\n");
253 }
254
255 if (fflush(0) && ferror(stdout)) return 1;
256
257 out = outbuf;
258 while (*out) {
259 int i = write(1, outbuf, strlen(outbuf));
260
261 if (i<0) return 1;
262 out += i;
263 }
264
265 return 0;
266}
267