OSDN Git Service

Start of TAGGED_ARRAY() infrastructure.
authorRob Landley <rob@landley.net>
Sun, 13 Dec 2015 22:52:26 +0000 (16:52 -0600)
committerRob Landley <rob@landley.net>
Sun, 13 Dec 2015 22:52:26 +0000 (16:52 -0600)
This lets you have struct arrays with a string as the first member, ala:

  struct {char *name; int x, y} blah thingy[] = TAGGED_ARRAY(BLAH,
    {"one", 1, 2}, {"two", 3, 4}, {"three", 5, 6}
  );

And it produces #defines for the array index of each, ala:

  #define BLAH_one   0
  #define BLAH_two   1
  #define BLAH_three 2

So you can use thingy[BLAH_two].x and still reorder the elements at will.

Note: if you screw up the array initializers, temporarily replace
TAGGED_ARRAY(BLAH, with { and the ); with }; and the compiler will give you
better error messages. (With the macro the compiler reports errors on the
TAGGED_ARRAY line, not where the comma is missing in its contents.)

Currently the TAGGED_ARRAY( and ); must be on their own lines, and the
{ and start of each attached string must be on the same line.

scripts/make.sh
scripts/mktags.c [new file with mode: 0644]
toys.h

index 3dd4f90..e1bc399 100755 (executable)
@@ -210,6 +210,19 @@ then
   ) > generated/globals.h
 fi
 
+if [ generated/mktags -ot scripts/mktags.c ]
+then
+  do_loudly $HOSTCC scripts/mktags.c -o generated/mktags || exit 1
+fi
+
+if isnewer generated/tags.h toys
+then
+  echo -n "generated/tags.h "
+
+  sed -n '/TAGGED_ARRAY(/,/^)/{s/.*TAGGED_ARRAY[(]\([^,]*\),/\1/;p}' \
+    toys/*/*.c | generated/mktags > generated/tags.h
+fi
+
 echo "generated/help.h"
 if [ generated/config2help -ot scripts/config2help.c ]
 then
diff --git a/scripts/mktags.c b/scripts/mktags.c
new file mode 100644 (file)
index 0000000..e6fceea
--- /dev/null
@@ -0,0 +1,55 @@
+// Process TAGGED_ARRAY() macros to emit TAG_STRING index macros.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+  char *tag = 0;
+  int idx = 0;
+
+  for (;;) {
+    char *line = 0, *s;
+    ssize_t len;
+
+    len = getline(&line, &len, stdin);
+    if (len<0) break;
+    while (len && isspace(line[len-1])) line[--len]=0;
+
+    // Very simple parser: If we haven't got a TAG then first line is TAG.
+    // Then look for { followed by "str" (must be on same line, may have
+    // more than one per line), for each one emit #define. Current TAG ended
+    // by ) at start of line.
+
+    if (!tag) {
+      if (!isalpha(*line)) {
+        fprintf(stderr, "bad tag %s\n", line);
+        exit(1);
+      }
+      tag = strdup(line);
+      idx = 0;
+
+      continue;
+    }
+
+    for (s = line; isspace(*s); s++);
+    if (*s == ')') tag = 0;
+    else for (;;) {
+      char *start;
+
+      while (*s && *s != '{') s++;
+      while (*s && *s != '"') s++;
+      if (!*s) break;
+
+      start = ++s;
+      while (*s && *s != '"') {
+        if (!isalpha(*s) && !isdigit(*s)) *s = '_';
+        s++;
+      }
+      printf("% *d\n",
+        30-printf("#define %s_%.*s", tag, (int)(s-start), start), ++idx);
+    }
+    free(line);
+  }
+}
diff --git a/toys.h b/toys.h
index 6aa7d47..8bd3be2 100644 (file)
--- a/toys.h
+++ b/toys.h
@@ -78,6 +78,7 @@
 #include "generated/newtoys.h"
 #include "generated/flags.h"
 #include "generated/globals.h"
+#include "generated/tags.h"
 
 // These live in main.c