// This is intentionally crappy code because we control the inputs. It leaks
// memory like a sieve and segfaults if malloc returns null, but does the job.
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
struct flag {
struct flag *next;
struct flag *lopt;
};
+int chrtype(char c)
+{
+ if (strchr("?&^-:#|@*; ", c)) return 1;
+ if (strchr("=<>", c)) return 2;
+
+ return 0;
+}
+
+// replace chopped out USE_BLAH() sections with low-ascii characters
+// showing how many flags got skipped
+
+char *mark_gaps(char *flags, char *all)
+{
+ char *n, *new, c;
+ int bare = 1;
+
+ // Shell feeds in " " for blank args, leading space not meaningful.
+ while (isspace(*flags)) flags++;
+ while (isspace(*all)) all++;
+
+ n = new = strdup(all);
+ while (*all) {
+ // --longopt parentheticals dealt with as a unit
+ if (*all == '(') {
+ int len = 0;
+
+ while (all[len++] != ')');
+ if (strncmp(flags, all, len)) {
+ // bare longopts need their own skip placeholders
+ if (bare) *(new++) = 1;
+ } else {
+ memcpy(new, all, len);
+ new += len;
+ flags += len;
+ }
+ all += len;
+ continue;
+ }
+ c = *(all++);
+ if (bare) bare = chrtype(c);
+ if (*flags == c) {
+ *(new++) = c;
+ *flags++;
+ continue;
+ }
+
+ c = chrtype(c);
+ if (!c) *(new++) = 1;
+ else if (c==2) while (isdigit(*all)) all++;
+ }
+ *new = 0;
+
+ return n;
+}
+
// Break down a command string into struct flag list.
struct flag *digest(char *string)
{
struct flag *list = NULL;
+ char *err = string;
while (*string) {
// Groups must be at end.
if (strchr("?&^-:#|@*; ", *string)) string++;
else if (strchr("=<>", *string)) {
+ if (!isdigit(string[1])) {
+ fprintf(stderr, "%c without number in '%s'", *string, err);
+ exit(1);
+ }
while (isdigit(*++string)) {
if (!list) {
string++;
// See "intentionally crappy", above.
if (!(out = outbuf)) return 1;
+ printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
+ "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n"
+ "#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n");
+
for (;;) {
struct flag *flist, *aflist, *offlist;
+ char *mgaps = 0;
unsigned bit;
- *command = 0;
+ *command = *flags = *allflags = 0;
bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
command, flags, allflags);
+ if (getenv("DEBUG"))
+ fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
+ command, flags, allflags);
+
if (!*command) break;
if (bit != 3) {
- fprintf(stderr, "\nError in %s (duplicate command?)\n", command);
+ fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
exit(1);
}
bit = 0;
printf("// %s %s %s\n", command, flags, allflags);
+ if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
+ else if (*allflags != ' ') mgaps = allflags;
+ // If command disabled, use allflags for OLDTOY()
+ printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
+ if (mgaps) printf("\"%s\"\n", mgaps);
+ else printf("0\n");
+ if (mgaps != allflags) free(mgaps);
flist = digest(flags);
offlist = aflist = digest(allflags);
out += strlen(out);
while (aflist) {
+ char *llstr = bit>31 ? "LL" : "";
+
+ // Output flag macro for bare longopts
if (aflist->lopt) {
if (flist && flist->lopt &&
!strcmp(flist->lopt->command, aflist->lopt->command))
{
- sprintf(out, "#define FLAG_%s (1<<%d)\n", flist->lopt->command, bit);
+ sprintf(out, "#define FLAG_%s (1%s<<%d)\n", flist->lopt->command,
+ llstr, bit);
flist->lopt = flist->lopt->next;
- } else sprintf(out, "#define FLAG_%s 0\n", aflist->lopt->command);
+ } else sprintf(out, "#define FLAG_%s (FORCED_FLAG%s<<%d)\n",
+ aflist->lopt->command, llstr, bit);
aflist->lopt = aflist->lopt->next;
if (!aflist->command) {
aflist = aflist->next;
- if (flist) {
- flist = flist->next;
- bit++;
- }
+ bit++;
+ if (flist) flist = flist->next;
}
+ // Output normal flag macro
} else if (aflist->command) {
- if (flist && (!aflist->command || *aflist->command == *flist->command))
- {
+ if (flist && flist->command && *aflist->command == *flist->command) {
if (aflist->command)
- sprintf(out, "#define FLAG_%c (1<<%d)\n", *aflist->command, bit);
- bit++;
+ sprintf(out, "#define FLAG_%c (1%s<<%d)\n", *aflist->command,
+ llstr, bit);
flist = flist->next;
- } else sprintf(out, "#define FLAG_%c 0\n", *aflist->command);
+ } else sprintf(out, "#define FLAG_%c (FORCED_FLAG%s<<%d)\n",
+ *aflist->command, llstr, bit);
+ bit++;
aflist = aflist->next;
}
out += strlen(out);
}
- sprintf(out, "#endif\n\n");
- out += strlen(out);
+ out = stpcpy(out, "#endif\n\n");
}
if (fflush(0) && ferror(stdout)) return 1;
if (i<0) return 1;
out += i;
}
+
+ return 0;
}