aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2013-10-03 03:18:00 -0500
committerRob Landley <rob@landley.net>2013-10-03 03:18:00 -0500
commit207cadacd3cef42fa918981423c951f49443f032 (patch)
tree2633a186220f6265f98a0e2f582ede612121e436 /scripts
parent7dc773bad5dc436518b822ba8c8ae400b5f36272 (diff)
downloadtoybox-207cadacd3cef42fa918981423c951f49443f032.tar.gz
Switch flag generation from shell to C.
This should actually generate FLAG_longopt 0 #defines for disabled bare longopts (ala ls without --color). Put temporary executables under "generated" (including instlist for install).
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/install.sh4
-rwxr-xr-xscripts/make.sh95
-rw-r--r--scripts/mkflags.c129
3 files changed, 172 insertions, 56 deletions
diff --git a/scripts/install.sh b/scripts/install.sh
index d9b56567..8891a314 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -35,8 +35,8 @@ done
echo "Compile instlist..."
-$DEBUG $HOSTCC -I . scripts/install.c -o instlist || exit 1
-COMMANDS="$(./instlist $LONG_PATH)"
+$DEBUG $HOSTCC -I . scripts/install.c -o generated/instlist || exit 1
+COMMANDS="$(generated/instlist $LONG_PATH)"
echo "Install commands..."
diff --git a/scripts/make.sh b/scripts/make.sh
index f5c4c273..61f2acfa 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -59,70 +59,57 @@ sed -n -e 's/^USE_[A-Z0-9_]*(/&/p' toys/*/*.c \
sed -n -e 's/.*(NEWTOY(\([^,]*\), *\(\("[^"]*"[^,]*\)*\),.*/#define OPTSTR_\1\t\2/p' \
generated/newtoys.h > generated/oldtoys.h
-# Extract list of command letters from processed header file
+if [ ! -e generated/mkflags ]
+then
+ $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
+fi
-function getflags()
-{
- FLX="$1"
- shift
- sed -n -e "s/.*TOY($FLX"',[ \t]*"\([^"]*\)"[ \t]*,.*)/\1/' \
- -e 't keep;d;:keep' -e 's/^[<>=][0-9]//' -e 's/[?&^]//' \
- -e 't keep' -e 's/[><=][0-9][0-9]*//g' -e 's/+.//g' \
- -e 's/\[[^]]*\]//g' -e 's/[-?^:&#|@* ;]//g' "$@" -e 'p'
-}
+echo generated/flags.h
+
+# Parse files through C preprocessor twice, once to get flags for current
+# .config and once to get flags for allyesconfig
+for I in A B
+do
+ (
+ # define macros and select header files with option string data
+
+ echo "#define NEWTOY(aa,bb,cc) aa $I bb"
+ echo '#define OLDTOY(...)'
+ if [ "$I" == A ]
+ then
+ cat generated/config.h
+ else
+ sed '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h
+ fi
+ cat generated/newtoys.h
+
+ # Run result through preprocessor, glue together " " gaps leftover from USE
+ # macros, delete comment lines, print any line with a quoted optstring,
+ # turn any non-quoted opstring (NULL or 0) into " " (because fscanf can't
+ # handle "" with nothing in it).
+
+ ) | $CC -E - | \
+ sed -n -e 's/" *"//g;/^#/d;s/"/"/p' -e 's/ *$//;s/ [^" ]*$/ " "/p'
+
+# Sort resulting line pairs and glue them together into triplets of
+# command "flags" "allflags"
+# to feed into mkflags C program that outputs actual flag macros
+
+done | sort | sed -n 's/ A / /;t skip;d;:skip;h;n;s/[^ ]* B //;H;g;s/\n/ /;p' |\
+generated/mkflags > generated/flags.h || exit 1
# Extract global structure definitions and flag definitions from toys/*/*.c
function getglobals()
{
- # Run newtoys.h through the compiler's preprocessor to resolve USE macros
- # against current config.
- NEWTOYS="$(cat generated/config.h generated/newtoys.h | $CC -E - | sed 's/" *"//g')"
-
- # Grab allyesconfig for comparison
- ALLTOYS="$((sed '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h && cat generated/newtoys.h) | $CC -E - | sed 's/" *"//g')"
-
for i in toys/*/*.c
do
NAME="$(echo $i | sed 's@.*/\(.*\)\.c@\1@')"
+ DATA="$(sed -n -e '/^GLOBALS(/,/^)/b got;b;:got' \
+ -e 's/^GLOBALS(/struct '"$NAME"'_data {/' \
+ -e 's/^)/};/' -e 'p' $i)"
- echo -e "// $i\n"
- sed -n -e '/^GLOBALS(/,/^)/b got;b;:got' \
- -e 's/^GLOBALS(/struct '"$NAME"'_data {/' \
- -e 's/^)/};/' -e 'p' $i
-
- LONGFLAGS="$(echo "$NEWTOYS" | getflags "$NAME" -e 's/\(\(([^)]*)\)*\).*/\1/' -e 's/(//g' -e 's/)/ /g')"
- FLAGS="$(echo "$NEWTOYS" | getflags "$NAME" -e 's/([^)]*)//g')"
- ZFLAGS="$(echo "$ALLTOYS" | getflags "$NAME" -e 's/([^)]*)//g' -e 's/[-'"$FLAGS"']//g')"
- LONGFLAGLEN="$(echo "$LONGFLAGS" | wc -w)"
-
- echo "#ifdef FOR_${NAME}"
- X=0
- # Provide values for --longopts with no corresponding short flags
- for i in $LONGFLAGS
- do
- X=$(($X+1))
- echo -e "#define FLAG_$i\t(1<<$(($LONGFLAGLEN+${#FLAGS}-$X)))"
- done
-
- # Provide values for active flags
- X=0
- while [ $X -lt ${#FLAGS} ]
- do
- echo -ne "#define FLAG_${FLAGS:$X:1}\t"
- X=$(($X+1))
- echo "(1<<$((${#FLAGS}-$X)))"
- done
-
- # Provide zeroes for inactive flags
- X=0
- while [ $X -lt ${#ZFLAGS} ]
- do
- echo "#define FLAG_${ZFLAGS:$X:1} 0"
- X=$(($X+1))
- done
- echo "#define TT this.${NAME}"
- echo "#endif"
+ [ ! -z "$DATA" ] && echo -e "// $i\n\n$DATA\n"
done
}
diff --git a/scripts/mkflags.c b/scripts/mkflags.c
new file mode 100644
index 00000000..eca59603
--- /dev/null
+++ b/scripts/mkflags.c
@@ -0,0 +1,129 @@
+// Take three word input lines on stdin (the three space separated words are
+// command name, option string with current config, option string from
+// allyesconfig; space separated, the last two are and double quotes)
+// and produce flag #defines to stdout.
+
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+struct flag {
+ struct flag *next;
+ char *command;
+ struct flag *lopt;
+};
+
+// Break down a command string into struct flag list.
+
+struct flag *digest(char *string)
+{
+ struct flag *list = NULL;
+
+ while (*string) {
+ // Groups must be at end.
+ if (*string == '[') break;
+
+ // Longopts
+ if (*string == '(') {
+ struct flag *new = calloc(sizeof(struct flag), 1);
+
+ new->command = ++string;
+
+ // Attach longopt to previous short opt, if any.
+ if (list && list->command) {
+ new->next = list->lopt;
+ list->lopt = new;
+ } else {
+ struct flag *blank = calloc(sizeof(struct flag), 1);
+
+ blank->next = list;
+ blank->lopt = new;
+ list = blank;
+ }
+ while (*++string != ')'); // An empty longopt () would break this.
+ *(string++) = 0;
+ continue;
+ }
+
+ if (strchr("?&^-:#|@*; ", *string)) string++;
+ else if (strchr("=<>", *string)) {
+ while (isdigit(*++string)) {
+ if (!list) {
+ string++;
+ break;
+ }
+ }
+ } else {
+ struct flag *new = calloc(sizeof(struct flag), 1);
+
+ new->command = string++;
+ new->next = list;
+ list = new;
+ }
+ }
+
+ return list;
+}
+
+int main(int argc, char *argv[])
+{
+ char command[256], flags[1023], allflags[1024];
+ unsigned bit;
+
+ for (;;) {
+ struct flag *flist, *aflist, *offlist;
+ unsigned bit = 0;
+
+ if (3 != fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
+ command, flags, allflags)) break;
+
+ printf("// %s %s %s\n", command, flags, allflags);
+ flist = digest(flags);
+ offlist = aflist = digest(allflags);
+
+
+ printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n#undef TT\n",
+ command, command, command);
+
+ while (offlist) {
+ struct flag *f = offlist->lopt;
+ while (f) {
+ printf("#undef FLAG_%s\n", f->command);
+ f = f->next;
+ }
+ if (offlist->command) printf("#undef FLAG_%c\n", *offlist->command);
+ offlist = offlist->next;
+ }
+ printf("#endif\n\n");
+
+ printf("#ifdef FOR_%s\n#define TT this.%s\n", command, command);
+
+ while (aflist) {
+ if (aflist->lopt) {
+ if (flist && flist->lopt &&
+ !strcmp(flist->lopt->command, aflist->lopt->command))
+ {
+ printf("#define FLAG_%s (1<<%d)\n", flist->lopt->command, bit);
+ flist->lopt = flist->lopt->next;
+ } else printf("#define FLAG_%s 0\n", aflist->lopt->command);
+ aflist->lopt = aflist->lopt->next;
+ } else {
+ if (flist && (!aflist->command || *aflist->command == *flist->command))
+ {
+ if (aflist->command)
+ printf("#define FLAG_%c (1<<%d)\n", *aflist->command, bit);
+ bit++;
+ flist = flist->next;
+ } else printf("#define FLAG_%c 0\n", *aflist->command);
+ aflist = aflist->next;
+ }
+ }
+ printf("#endif\n\n");
+ }
+
+ return fflush(0) && ferror(stdout);
+}