Replace python help converter with C implementation.
authorRob Landley <rob@landley.net>
Sat, 4 Jan 2014 00:23:09 +0000 (18:23 -0600)
committerRob Landley <rob@landley.net>
Sat, 4 Jan 2014 00:23:09 +0000 (18:23 -0600)
Makefile
scripts/config2help.c [new file with mode: 0644]
scripts/config2help.py [deleted file]
scripts/config2help.sh [deleted file]
scripts/make.sh

index 6494a01..13c8ec4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -42,13 +42,14 @@ uninstall:
 
 clean::
        rm -rf toybox toybox_unstripped generated/config.h generated/Config.in \
-               generated/newtoys.h generated/globals.h testdir \
+               generated/newtoys.h generated/globals.htestdir \
                generated/Config.probed generated/oldtoys.h generated/flags.h \
                generated/portability.h .singleconfig .singleconfig.old \
-               generated/instlist generated/mkflags
+               generated/instlist generated/mkflags generated/config2help \
+               generated/help.h
 
 distclean: clean
-       rm -f toybox_old .config* generated/help.h
+       rm -f toybox_old .config*
 
 test: tests
 
diff --git a/scripts/config2help.c b/scripts/config2help.c
new file mode 100644 (file)
index 0000000..337db9a
--- /dev/null
@@ -0,0 +1,141 @@
+#include "toys.h"
+
+// Humor toys.h
+struct toy_context toys;
+char libbuf[4096], toybuf[4096];
+void show_help(void) {;}
+void toy_exec(char *argv[]) {;}
+
+// Parse config files into data structures.
+
+struct symbol {
+  struct symbol *next;
+  int enabled;
+  char *name, *depends;
+  struct double_list *help;
+} *sym;
+
+char *keyword(char *name, char *line)
+{
+  int len = strlen(name);
+
+  while (isspace(*line)) line++;
+  if (strncmp(name, line, len)) return 0;
+  line += len;
+  if (*line && !isspace(*line)) return 0;
+  while (isspace(*line)) line++;
+
+  return line;
+}
+
+void parse(char *filename)
+{
+  FILE *fp = xfopen(filename, "r");
+  struct symbol *new = 0;
+  int help = 0;
+
+  for (;;) {
+    char *s, *line = NULL;
+    size_t len;
+
+    // Read line, trim whitespace at right edge.
+    if (getline(&line, &len, fp) < 1) break;
+    s = line+strlen(line);
+    while (--s >= line) {
+      if (!isspace(*s)) break;
+      *s = 0;
+    }
+
+    // source or config keyword at left edge?
+    if (*line && !isspace(*line)) {
+      help = 0;
+      if ((s = keyword("config", line))) {
+        new = xzalloc(sizeof(struct symbol));
+        new->next = sym;
+        new->name = s;
+        sym = new;
+      } else if ((s = keyword("source", line))) parse(s);
+
+      continue;
+    }
+    if (!new) continue;
+
+    if (help) dlist_add(&(new->help), line);
+    else if ((s = keyword("depends", line)) && (s = keyword("on", s)))
+      new->depends = s;
+    else if (keyword("help", line)) help++;
+  }
+
+  fclose(fp);
+}
+
+int main(int argc, char *argv[])
+{
+  FILE *fp;
+  struct symbol *try;
+  char *s, *file;
+
+  if (argc != 3) {
+    fprintf(stderr, "usage: config2help Config.in .config\n");
+    exit(1);
+  }
+
+  // Read Config.in
+  parse(argv[1]);
+
+  // read .config
+  fp = xfopen(argv[2], "r");
+  for (;;) {
+    char *line = NULL;
+    size_t len;
+
+    if (getline(&line, &len, fp) < 1) break;
+    if (!strncmp("CONFIG_", line, 7)) {
+      s = line+7;
+      for (try=sym; try; try=try->next) {
+        len = strlen(try->name);
+        if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') {
+          try->enabled++;
+          break;
+        } 
+      }
+    }
+  }
+
+  // Print out help #defines
+  while (sym) {
+    struct double_list *dd;
+
+    if (sym->help) {
+      int i, padlen = 0;
+
+      s = xstrdup(sym->name);
+      for (i = 0; s[i]; i++) s[i] = tolower(s[i]);
+      printf("#define help_%s \"", s);
+      free(s);
+
+      // Measure leading whitespace of first line
+      dd = sym->help;
+      while (isspace(dd->data[padlen])) padlen++;
+
+      for (;;) {
+        i = padlen;
+
+        // Trim leading whitespace
+        s = dd->data;
+        while (isspace(*s) && i) {
+          s++;
+          i--;
+        }
+        for (i=0; s[i]; i++) {
+          if (s[i] == '"' || s[i] == '\\') putchar('\\');
+          putchar(s[i]);
+        }
+        dd = dd->next;
+        if (dd == sym->help) break;
+      }
+      printf("\"\n");
+    }
+    sym = sym->next;
+  }
+}
diff --git a/scripts/config2help.py b/scripts/config2help.py
deleted file mode 100755 (executable)
index 2573d08..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/python
-
-import os,sys
-
-def zapquotes(str):
-  if str[0]=='"': str = str[1:str.rfind('"')]
-  return str
-
-def escapequotes(str):
-  return str.strip().replace("\\","\\\\").replace('"','\\"')
-
-helplen = morelines = 0
-out = sys.stdout
-
-def readfile(filename):
-  global helplen, morelines
-  #sys.stderr.write("Reading %s\n" % filename)
-  try:
-    lines = open(filename).read().split("\n")
-  except IOError:
-    sys.stderr.write("File %s missing\n" % filename)
-    return
-  config = None
-  description = None
-  for i in lines:
-    if helplen:
-      i = i.expandtabs()
-      if not len(i) or i[:helplen].isspace():
-        if morelines: out.write('\\n')
-        morelines = 1
-        out.write(escapequotes(i))
-        continue
-      else:
-        helplen = morelines = 0
-        out.write('"\n')
-
-    words = i.strip().split(None,1)
-    if not len(words): continue
-
-    if words[0] in ("config", "menuconfig"):
-      config = words[1]
-      description = ""
-    elif words[0] in ("bool", "boolean", "tristate", "string", "hex", "int"):
-       if len(words)>1: description = zapquotes(words[1])
-    elif words[0]=="prompt":
-      description = htmlescape(zapquotes(words[1]))
-    elif words[0] in ("help", "---help---"):
-      out.write('#define help_%s "' % config.lower())
-      helplen = len(i[:i.find(words[0])].expandtabs())
-    elif words[0] == "source": readfile(zapquotes(words[1]))
-    elif words[0] in ("default","depends", "select", "if", "endif", "#", "comment", "menu", "endmenu"): pass
-
-readfile(sys.argv[1])
-if helplen: out.write('"\n')
diff --git a/scripts/config2help.sh b/scripts/config2help.sh
deleted file mode 100755 (executable)
index 8f96e39..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash -e
-
-function firstmajor() {
-       declare -i n j=$1
-       test $j -gt 0 || return -1
-       for j in $@; do
-               if [ $j -gt $1 ]; then
-                       echo $j
-                       return 0
-               fi
-       done
-       return 1
-}; export -f firstmajor
-
-function print_h() {
-       declare -i i c=$2 s=$3 e=$4
-       local str="$(echo "$1" | head -n$c | tail -n1 | sed -e "s,config[\t ]*,,")"
-       echo -n "#define help_"$str" \"" | tr [A-Z] [a-z]
-       echo -n "$1\\n" | head -n$e | tail -n$[e-s+1] | sed -e "s,\$,\r," | tr \\n\\r n\\
-       echo \"
-}; export -f print_h
-
-file="$1"
-if test "$0" != "bash"; then
-       if test -r "$file"; then
-#              echo "$file..." >&2
-               filetxt="$(sed -e "s,^[\t ]*,," -e "s,\([\"\\\\]\),\\\\\\1,g" "$file")"
-               helps=$(echo "$filetxt" | egrep -ne "^help *" -e "^---help--- *" | cut -d\:  -f1)
-               configs=$(echo "$filetxt" | egrep -ne "^config *" | cut -d\:  -f1)
-               endmenus=$(echo "$filetxt" | egrep -ne "^endmenu *" | cut -d\:  -f1)
-               let last=$(echo "$filetxt" | wc -l)+2
-
-               declare -i i c s e
-               for i in $configs; do
-#                      echo -n "c:$i" >&2
-                       s=$(firstmajor $i $helps)
-                       test $s -gt 0
-                       e=$(firstmajor $s $configs || firstmajor $s $endmenus $last)
-                       let s++ e-=2
-                       test $e -ge $s
-#                      echo " s:$s e:$e" >&2
-                       print_h "$filetxt" $i $s $e
-               done
-               for fle in $(cat "$file" | egrep -e "^[ \t]*source " | sed -e "s,^[ \t]*source *\(.*\),\\1,"); do
-                       $0 $fle
-               done
-       else
-               echo
-               echo "USAGE EXAMPLE: $(basename $0) Config.in > generated/help.h"
-               echo
-               false
-       fi | sed -e "s,\\\\n\\\\n\"$,\\\\n\","
-fi
-
index e4f0b35..9fdadc4 100755 (executable)
@@ -13,6 +13,13 @@ then
   exit 1
 fi
 
+# Respond to V= by echoing command lines as well as running them
+do_loudly()
+{
+  [ ! -z "$V" ] && echo "$@"
+  "$@"
+}
+
 echo "Make generated/config.h from $KCONFIG_CONFIG."
 
 # This long and roundabout sed invocation is to make old versions of sed happy.
@@ -59,10 +66,7 @@ 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
 
-if [ ! -e generated/mkflags ]
-then
-  $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
-fi
+do_loudly $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
 
 echo -n "generated/flags.h "
 
@@ -125,21 +129,9 @@ GLOBSTRUCT="$(getglobals)"
 ) > generated/globals.h
 
 echo "generated/help.h"
-# Only recreate generated/help.h if python2 is installed. Does not work with 3.
-[ -z "$(python --version 2>&1 | grep 'Python 2')" ] &&
-  PYTHON="$(which python2 || which python2.6 || which python2.7)" ||
-  PYTHON=python
-if [ ! -z "$(grep 'CONFIG_TOYBOX_HELP=y' $KCONFIG_CONFIG)" ];
-then
-  if [ -z "$PYTHON" ];
-  then
-    echo "Python 2.x required to rebuild generated/help.h"
-    # exit 1
-  else
-    echo "Extract help text from Config.in."
-    "$PYTHON" scripts/config2help.py Config.in > generated/help.h || exit 1
-  fi
-fi
+do_loudly $HOSTCC scripts/config2help.c -I . lib/xwrap.c lib/llist.c lib/lib.c \
+  -o generated/config2help && \
+generated/config2help Config.in .config > generated/help.h || exit 1
 
 # Extract a list of toys/*/*.c files to compile from the data in $KCONFIG_CONFIG