new my scripts/mm_mkdep, dependences work now
author"Vladimir N. Oleynik" <dzo@simtreas.ru>
Mon, 12 Sep 2005 12:33:27 +0000 (12:33 -0000)
committer"Vladimir N. Oleynik" <dzo@simtreas.ru>
Mon, 12 Sep 2005 12:33:27 +0000 (12:33 -0000)
AUTHORS
Makefile
scripts/bb_mkdep.c [new file with mode: 0644]
scripts/mkdep.c [deleted file]
scripts/split-include.c [deleted file]

diff --git a/AUTHORS b/AUTHORS
index 383ab1a..279b1b6 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -110,7 +110,7 @@ Manuel Novoa III <mjn3@codepoet.org>
     interface, dutmp, ifconfig, route
 
 Vladimir Oleynik <dzo@simtreas.ru>
-    cmdedit; xargs(current), httpd(current);
+    cmdedit; bb_mkdep, xargs(current), httpd(current);
     ports: ash, crond, fdisk, inetd, stty, traceroute, top;
     locale, various fixes
     and irreconcilable critic of everything not perfect.
index a6356b7..c8b6d79 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ $(ALL_MAKEFILES): %/Makefile: $(top_srcdir)/%/Makefile
 include $(patsubst %,%/Makefile.in, $(SRC_DIRS))
 -include $(top_builddir)/.depend
 
-busybox: $(ALL_MAKEFILES) .depend include/bb_config.h $(libraries-y)
+busybox: $(ALL_MAKEFILES) .depend $(libraries-y)
        $(CC) $(LDFLAGS) -o $@ -Wl,--start-group $(libraries-y) $(LIBRARIES) -Wl,--end-group
        $(STRIPCMD) $@
 
@@ -180,24 +180,14 @@ docs/busybox.net/BusyBox.html: docs/busybox.pod
        -@ rm -f pod2htm*
 
 # The nifty new buildsystem stuff
-scripts/mkdep: $(top_srcdir)/scripts/mkdep.c
-       $(HOSTCC) $(HOSTCFLAGS) -o $@ $<
-
-scripts/split-include: $(top_srcdir)/scripts/split-include.c
+scripts/bb_mkdep: $(top_srcdir)/scripts/bb_mkdep.c
        $(HOSTCC) $(HOSTCFLAGS) -o $@ $<
 
 depend dep: .depend
-.depend: scripts/mkdep include/config.h include/bbconfigopts.h
-       rm -f .depend .hdepend;
-       mkdir -p include/config;
-       scripts/mkdep -I include -- \
-         `find $(top_srcdir) -name \*.c -print | sed -e "s,^./,,"` >> .depend;
-       scripts/mkdep -I include -- \
-         `find $(top_srcdir) -name \*.h -print | sed -e "s,^./,,"` >> .hdepend;
-
-include/config/MARKER: depend scripts/split-include
-       scripts/split-include include/config.h include/config
-       @ touch include/config/MARKER
+.depend: scripts/bb_mkdep include/config.h include/bb_config.h
+       @rm -f .depend
+       @mkdir -p include/config
+       scripts/bb_mkdep -c include/config.h -c include/bb_config.h > $@
 
 include/config.h: .config
        @if [ ! -x $(top_builddir)/scripts/config/conf ] ; then \
@@ -206,11 +196,11 @@ include/config.h: .config
        @$(top_builddir)/scripts/config/conf -o $(CONFIG_CONFIG_IN)
 
 include/bb_config.h: include/config.h
-       echo -e "#ifndef BB_CONFIG_H\n#define BB_CONFIG_H" > $@
-       sed -e 's/#undef CONFIG_\(.*\)/#define ENABLE_\1 0/' \
+       @echo -e "#ifndef BB_CONFIG_H\n#define BB_CONFIG_H" > $@
+       @sed -e 's/#undef CONFIG_\(.*\)/#define ENABLE_\1 0/' \
            -e 's/#define CONFIG_\(.*\)/#define CONFIG_\1\n#define ENABLE_\1/' \
                < $< >> $@
-       echo "#endif" >> $@
+       @echo "#endif" >> $@
 
 include/bbconfigopts.h: .config
        @[ -d $(@D) ] || mkdir -v $(@D)
@@ -270,14 +260,14 @@ clean:
            docs/busybox pod2htm* *.gdb *.elf *~ core .*config.log \
            docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \
            docs/busybox.net/BusyBox.html busybox.links libbb/loop.h \
-           .config.old .hdepend busybox testsuite/links/*
+           .config.old busybox testsuite/links/*
        - rm -rf _install
        - find . -name .\*.flags -exec rm -f {} \;
        - find . -name \*.o -exec rm -f {} \;
        - find . -name \*.a -exec rm -f {} \;
 
 distclean: clean
-       - rm -f scripts/split-include scripts/mkdep
+       - rm -f scripts/bb_mkdep
        - rm -rf include/config include/config.h include/bb_config.h include/bbconfigopts.h
        - find . -name .depend -exec rm -f {} \;
        rm -f .config .config.old .config.cmd
diff --git a/scripts/bb_mkdep.c b/scripts/bb_mkdep.c
new file mode 100644 (file)
index 0000000..4083973
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * Another dependences for Makefile mashine generator
+ *
+ * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This programm do
+ * 1) find #define KEY VALUE or #undef KEY from include/config.h
+ * 2) save include/config/key*.h if changed after previous usage
+ * 3) recursive scan from "./" *.[ch] files, but skip scan include/config/...
+ * 4) find #include "*.h" and KEYs using, if not as #define and #undef
+ * 5) generate depend to stdout
+ *    path/file.o: include/config/key*.h found_include_*.h
+ *    path/inc.h: include/config/key*.h found_included_include_*.h
+ * This programm do not generate dependences for #include <...>
+ *
+ * Options:
+ * -I local_include_path  (include`s paths, default: LOCAL_INCLUDE_PATH)
+ * -d                     (don`t generate depend)
+ * -w                     (show warning if include files not found)
+ * -k include/config      (default: INCLUDE_CONFIG_PATH)
+ * -c include/config.h    (configs, default: INCLUDE_CONFIG_KEYS_PATH)
+*/
+
+#define LOCAL_INCLUDE_PATH          "include"
+#define INCLUDE_CONFIG_PATH         LOCAL_INCLUDE_PATH"/config"
+#define INCLUDE_CONFIG_KEYS_PATH    LOCAL_INCLUDE_PATH"/config.h"
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+typedef struct BB_KEYS {
+       char *keyname;
+       const char *value;
+       char *stored_path;
+       int  checked;
+       struct BB_KEYS *next;
+} bb_key_t;
+
+
+/* partial and simplify libbb routine */
+
+void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+/* stolen from libbb as is */
+typedef struct llist_s {
+       char *data;
+       struct llist_s *link;
+} llist_t;
+llist_t *llist_add_to(llist_t *old_head, char *new_item);
+void *xrealloc(void *p, size_t size);
+void *xmalloc(size_t size);
+char *bb_xstrdup(const char *s);
+char *bb_simplify_path(const char *path);
+
+/* for lexical analyzier */
+static bb_key_t *key_top;
+
+static void parse_inc(const char *include, const char *fname);
+static void parse_conf_opt(char *opt, const char *val, size_t rsz);
+
+#define CHECK_ONLY  0
+#define MAKE_NEW    1
+static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new);
+
+#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
+
+/* state */
+#define S      0        /* start state */
+#define STR    '"'      /* string */
+#define CHR    '\''     /* char */
+#define REM    '*'      /* block comment */
+#define POUND  '#'      /* # */
+#define I      'i'      /* #include preprocessor`s directive */
+#define D      'd'      /* #define preprocessor`s directive */
+#define U      'u'      /* #undef preprocessor`s directive */
+#define LI     'I'      /* #include "... */
+#define DK     'K'      /* #define KEY... (config mode) */
+#define DV     'V'      /* #define KEY "... or #define KEY '... */
+#define NLC    'n'      /* \+\n */
+#define ANY    '?'      /* skip unparsed . */
+
+/* [A-Z_a-z] */
+#define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
+/* [A-Z_a-z0-9] */
+#define ISALNUM(c)  (ID(c) || (c >= '0' && c <= '9'))
+
+#define getc1()     do { c = (optr >= oend) ? EOF : *optr++; } while(0)
+#define ungetc1()   optr--
+
+#define put_id(c)   do {    if(id_len == mema_id)                 \
+                               id = xrealloc(id, mema_id += 16); \
+                           id[id_len++] = c; } while(0)
+
+/* stupid C lexical analizator */
+static void c_lex(const char *fname, int flg_config_include)
+{
+  int c = EOF;                      /* stupid initialize */
+  int prev_state = EOF;
+  int called;
+  int state;
+  int line;
+  static size_t mema_id;
+  char *id = xmalloc(mema_id=128);  /* fist allocate */
+  size_t id_len = 0;                /* stupid initialize */
+  char *val = NULL;
+  unsigned char *optr, *oend;
+  unsigned char *start = NULL;      /* stupid initialize */
+
+  int fd;
+  char *map;
+  int mapsize;
+  {
+    /* stolen from mkdep by Linus Torvalds */
+    int pagesizem1 = getpagesize() - 1;
+    struct stat st;
+
+    fd = open(fname, O_RDONLY);
+    if(fd < 0) {
+       perror(fname);
+       return;
+    }
+    fstat(fd, &st);
+    if (st.st_size == 0)
+       bb_error_d("%s is empty", fname);
+    mapsize = st.st_size;
+    mapsize = (mapsize+pagesizem1) & ~pagesizem1;
+    map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+    if ((long) map == -1)
+       bb_error_d("%s: mmap: %m", fname);
+
+    /* hereinafter is my */
+    optr = (unsigned char *)map;
+    oend = optr + st.st_size;
+  }
+
+  line = 1;
+  called = state = S;
+
+  for(;;) {
+       if(state == LI || state == DV) {
+           /* store "include.h" or config mode #define KEY "|'..."|'  */
+           put_id(0);
+           if(state == LI) {
+               parse_inc(id, fname);
+           } else {
+               /*
+               if(val[0] == '\0')
+                   yy_error_d("expected value");
+               */
+               parse_conf_opt(id, val, (optr - start));
+           }
+           state = S;
+       }
+       if(prev_state != state) {
+           prev_state = state;
+           getc1();
+       }
+
+       /* [ \t]+ eat first space */
+       while(c == ' ' || c == '\t')
+           getc1();
+
+       if(c == '\\') {
+               getc1();
+               if(c == '\n') {
+                       /* \\\n eat continued */
+                       line++;
+                       prev_state = NLC;
+                       continue;
+               }
+               ungetc1();
+               c = '\\';
+       }
+
+       if(state == S) {
+               while(c <= ' ' && c != EOF) {
+                   /* <S>[\000- ]+ */
+                   if(c == '\n')
+                       line++;
+                   getc1();
+               }
+               if(c == EOF) {
+                       /* <S><<EOF>> */
+                       munmap(map, mapsize);
+                       close(fd);
+                       return;
+               }
+               if(c == '/') {
+                       /* <S>/ */
+                       getc1();
+                       if(c == '/') {
+                               /* <S>"//"[^\n]* */
+                               do getc1(); while(c != '\n' && c != EOF);
+                       } else if(c == '*') {
+                               /* <S>[/][*] */
+                               called = S;
+                               state = REM;
+                       }
+                       /* eat <S>/ */
+               } else if(c == '#') {
+                       /* <S>\"|\'|# */
+                       start = optr - 1;
+                       state = c;
+               } else if(c == STR || c == CHR) {
+                       /* <S>\"|\'|# */
+                       val = NULL;
+                       called = S;
+                       state = c;
+               } else if(ISALNUM(c)) {
+                       /* <S>[A-Z_a-z0-9] */
+                       id_len = 0;
+                       do {
+                               /* <S>[A-Z_a-z0-9]+ */
+                               put_id(c);
+                               getc1();
+                       } while(ISALNUM(c));
+                       put_id(0);
+                       find_already(key_top, id, CHECK_ONLY);
+               } else {
+                   /* <S>. */
+                   prev_state = ANY;
+               }
+               continue;
+       }
+       if(state == REM) {
+         for(;;) {
+               /* <REM>[^*]+ */
+               while(c != '*') {
+                       if(c == '\n') {
+                               /* <REM>\n */
+                               if(called != S)
+                                   yy_error_d("unexpected newline");
+                               line++;
+                       } else if(c == EOF)
+                               yy_error_d("unexpected EOF");
+                       getc1();
+               }
+               /* <REM>[*] */
+               getc1();
+               if(c == '/') {
+                       /* <REM>[*][/] */
+                       state = called;
+                       break;
+               }
+         }
+         continue;
+       }
+       if(state == STR || state == CHR) {
+           for(;;) {
+               /* <STR,CHR>\n|<<EOF>> */
+               if(c == '\n' || c == EOF)
+                       yy_error_d("unterminating");
+               if(c == '\\') {
+                       /* <STR,CHR>\\ */
+                       getc1();
+                       if(c != '\\' && c != '\n' && c != state) {
+                           /* another usage \ in str or char */
+                           if(c == EOF)
+                               yy_error_d("unexpected EOF");
+                           if(val)
+                               put_id(c);
+                           continue;
+                       }
+                       /* <STR,CHR>\\[\\\n] or <STR>\\\" or <CHR>\\\' */
+                       /* eat 2 char */
+                       if(c == '\n')
+                           line++;
+                       else if(val)
+                           put_id(c);
+               } else if(c == state) {
+                       /* <STR>\" or <CHR>\' */
+                       if(called == DV)
+                           put_id(c);
+                       state = called;
+                       break;
+               } else if(val)
+                       put_id(c);
+               /* <STR,CHR>. */
+               getc1();
+           }
+           continue;
+       }
+
+       /* begin preprocessor states */
+       if(c == EOF)
+           yy_error_d("unexpected EOF");
+       if(c == '/') {
+               /* <#.*>/ */
+               getc1();
+               if(c == '/')
+                       yy_error_d("detect // in preprocessor line");
+               if(c == '*') {
+                       /* <#.*>[/][*] */
+                       called = state;
+                       state = REM;
+                       continue;
+               }
+               /* hmm, #.*[/] */
+               yy_error_d("strange preprocessor line");
+       }
+       if(state == '#') {
+               static const char * const preproc[] = {
+                   "define", "undef", "include", ""
+               };
+               const char * const *str_type;
+
+               id_len = 0;
+               while(ISALNUM(c)) {
+                   put_id(c);
+                   getc1();
+               }
+               put_id(0);
+               for(str_type = preproc; (state = **str_type); str_type++) {
+                   if(*id == state && strcmp(id, *str_type) == 0)
+                       break;
+               }
+               /* to S if another #directive */
+               ungetc1();
+               id_len = 0; /* common for save */
+               continue;
+       }
+       if(state == I) {
+               if(c == STR) {
+                       /* <I>\" */
+                       val = id;
+                       state = STR;
+                       called = LI;
+                       continue;
+               }
+               /* another (may be wrong) #include ... */
+               ungetc1();
+               state = S;
+               continue;
+       }
+       if(state == D || state == U) {
+           while(ISALNUM(c)) {
+               if(flg_config_include) {
+                   /* save KEY from #"define"|"undef" ... */
+                   put_id(c);
+               }
+               getc1();
+           }
+           if(!flg_config_include) {
+               state = S;
+           } else {
+               if(!id_len)
+                   yy_error_d("expected identificator");
+               put_id(0);
+               if(state == U) {
+                   parse_conf_opt(id, NULL, (optr - start));
+                   state = S;
+               } else {
+                   /* D -> DK */
+                   state = DK;
+               }
+           }
+           ungetc1();
+           continue;
+       }
+       if(state == DK) {
+           /* #define (config mode) */
+           val = id + id_len;
+           if(c == STR || c == CHR) {
+               /* define KEY "... or define KEY '... */
+               put_id(c);
+               called = DV;
+               state = c;
+               continue;
+           }
+           while(ISALNUM(c)) {
+               put_id(c);
+               getc1();
+           }
+           ungetc1();
+           state = DV;
+           continue;
+       }
+    }
+}
+
+
+static void show_usage(void) __attribute__ ((noreturn));
+static void show_usage(void)
+{
+       bb_error_d("Usage: [-I local_include_path] [-dw] "
+                       "[-k path_for_store_keys] [-s skip_file]");
+}
+
+static const char *kp;
+static llist_t *Iop;
+static bb_key_t *Ifound;
+static int noiwarning;
+static llist_t *configs;
+
+static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new)
+{
+       bb_key_t *cur;
+
+       for(cur = k; cur; cur = cur->next) {
+           if(strcmp(cur->keyname, nk) == 0) {
+               cur->checked = 1;
+               return NULL;
+           }
+       }
+       if(flg_save_new == CHECK_ONLY)
+           return NULL;
+       cur = xmalloc(sizeof(bb_key_t));
+       cur->keyname = bb_xstrdup(nk);
+       cur->checked = 1;
+       cur->next = k;
+       return cur;
+}
+
+static int store_include_fullpath(char *p_i, bb_key_t *li)
+{
+    struct stat st;
+    int ok = 0;
+
+    if(stat(p_i, &st) == 0) {
+       li->stored_path = bb_simplify_path(p_i);
+       ok = 1;
+    }
+    free(p_i);
+    return ok;
+}
+
+static void parse_inc(const char *include, const char *fname)
+{
+       bb_key_t *li;
+       char *p_i;
+       llist_t *lo;
+
+       if((li = find_already(Ifound, include, MAKE_NEW)) == NULL)
+           return;
+       Ifound = li;
+       if(include[0] != '/') {
+           /* relative */
+           int w;
+           const char *p;
+
+           p_i = strrchr(fname, '/');
+           if(p_i == NULL) {
+               p = ".";
+               w = 1;
+           } else {
+               w = (p_i-fname);
+               p = fname;
+           }
+           p_i = bb_asprint("%.*s/%s", w, p, include);
+           if(store_include_fullpath(p_i, li))
+               return;
+       }
+       for(lo = Iop; lo; lo = lo->link) {
+           p_i = bb_asprint("%s/%s", lo->data, include);
+           if(store_include_fullpath(p_i, li))
+               return;
+       }
+       li->stored_path = NULL;
+       if(noiwarning)
+           fprintf(stderr, "%s: Warning: #include \"%s\" not found in specified paths\n", fname, include);
+}
+
+static void parse_conf_opt(char *opt, const char *val, size_t recordsz)
+{
+       bb_key_t *cur = find_already(key_top, opt, MAKE_NEW);
+
+       if(cur != NULL) {
+           /* new key, check old key if present after previous usage */
+           char *s, *p;
+           struct stat st;
+           int fd;
+           int cmp_ok = 0;
+           static char *record_buf;
+           static char *r_cmp;
+           static size_t r_sz;
+
+           recordsz += 2;  /* \n\0 */
+           if(recordsz > r_sz) {
+               record_buf = xrealloc(record_buf, r_sz=recordsz);
+               r_cmp = xrealloc(r_cmp, recordsz);
+           }
+           s = record_buf;
+           if(val)
+               sprintf(s, "#define %s%s%s\n", opt, (*val ? " " : ""), val);
+           else
+               sprintf(s, "#undef %s\n", opt);
+           /* may be short count " " */
+           recordsz = strlen(s);
+           /* key converting [A-Z] -> [a-z] */
+           for(p = opt; *p; p++) {
+               if(*p >= 'A' && *p <= 'Z')
+                       *p = *p - 'A' + 'a';
+               if(*p == '_')
+                   *p = '/';
+           }
+           p = bb_asprint("%s/%s.h", kp, opt);
+           cur->stored_path = opt = p;
+           while(*++p) {
+               /* Auto-create directories. */
+               if (*p == '/') {
+                   *p = '\0';
+                   if (stat(opt, &st) != 0 && mkdir(opt, 0755) != 0)
+                       bb_error_d("mkdir(%s): %m", opt);
+                   *p = '/';
+               }
+           }
+           if(stat(opt, &st) == 0) {
+                   /* found */
+                   if(st.st_size == recordsz) {
+                       fd = open(opt, O_RDONLY);
+                       if(fd < 0 || read(fd, r_cmp, recordsz) != recordsz)
+                           bb_error_d("%s: %m", opt);
+                       close(fd);
+                       cmp_ok = memcmp(s, r_cmp, recordsz) == 0;
+                   }
+           }
+           if(!cmp_ok) {
+               fd = open(opt, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+               if(fd < 0 || write(fd, s, recordsz) != recordsz)
+                   bb_error_d("%s: %m", opt);
+               close(fd);
+           }
+           /* store only */
+           cur->checked = 0;
+           if(val) {
+               if(*val == '\0') {
+                   cur->value = "";
+               } else {
+                   cur->value = bb_xstrdup(val);
+               }
+           } else {
+               cur->value = NULL;
+           }
+           key_top = cur;
+       } else {
+           /* present already */
+           for(cur = key_top; cur; cur = cur->next) {
+               if(strcmp(cur->keyname, opt) == 0) {
+                   cur->checked = 0;
+                   if(cur->value == NULL && val == NULL)
+                       return;
+                   if((cur->value == NULL && val != NULL) ||
+                           (cur->value != NULL && val == NULL) ||
+                           strcmp(cur->value, val))
+                       fprintf(stderr, "Warning: redefined %s\n", opt);
+                   return;
+               }
+           }
+       }
+}
+
+static int show_dep(int first, bb_key_t *k, const char *a)
+{
+    bb_key_t *cur;
+
+    for(cur = k; cur; cur = cur->next) {
+       if(cur->checked && cur->stored_path) {
+           if(first) {
+               const char *ext;
+
+               if(*a == '.' && a[1] == '/')
+                   a += 2;
+               ext = strrchr(a, '.');
+               if(ext && ext[1] == 'c' && ext[2] == '\0') {
+                   /* *.c -> *.o */
+                   printf("\n%.*s.o:", (ext - a), a);
+               } else {
+                   printf("\n%s:", a);
+               }
+               first = 0;
+           } else {
+               printf(" \\\n  ");
+           }
+           printf(" %s", cur->stored_path);
+       }
+       cur->checked = 0;
+    }
+    return first;
+}
+
+static llist_t *files;
+
+static llist_t *filter_chd(const char *fe, const char *p, llist_t *pdirs)
+{
+    const char *e;
+    struct stat st;
+    char *fp;
+    char *afp;
+    llist_t *cfl;
+
+    if (*fe == '.')
+       return NULL;
+    fp = bb_asprint("%s/%s", p, fe);
+    if(stat(fp, &st)) {
+       fprintf(stderr, "Warning: stat(%s): %m", fp);
+       free(fp);
+       return NULL;
+    }
+    afp = bb_simplify_path(fp);
+    if(S_ISDIR(st.st_mode)) {
+       if(strcmp(kp, afp) == 0) {
+           /* is autogenerated to kp/key* by previous usage */
+           free(afp);
+           free(fp);
+           /* drop scan kp/ directory */
+           return NULL;
+       }
+       free(afp);
+       return llist_add_to(pdirs, fp);
+    }
+    if(!S_ISREG(st.st_mode)) {
+       /* hmm, is device! */
+       free(afp);
+       free(fp);
+       return NULL;
+    }
+    e = strrchr(fe, '.');
+    if(e == NULL || !((e[1]=='c' || e[1]=='h') && e[2]=='\0')) {
+       /* direntry is not directory or *.[ch] */
+       free(afp);
+       free(fp);
+       return NULL;
+    }
+    for(cfl = configs; cfl; cfl = cfl->link) {
+       if(cfl->data && strcmp(cfl->data, afp) == 0) {
+           /* parse configs.h */
+           free(afp);
+           c_lex(fp, 1);
+           free(fp);
+           free(cfl->data);
+           cfl->data = NULL;
+           return NULL;
+       }
+    }
+    free(fp);
+    /* direntry is *.[ch] regular file */
+    files = llist_add_to(files, afp);
+    return NULL;
+}
+
+static void scan_dir_find_ch_files(char *p)
+{
+    llist_t *dirs;
+    llist_t *d_add;
+    llist_t *d;
+    struct dirent *de;
+    DIR *dir;
+
+    dirs = llist_add_to(NULL, p);
+    /* emulate recursive */
+    while(dirs) {
+       d_add = NULL;
+       while(dirs) {
+           dir = opendir(dirs->data);
+           if (dir == NULL)
+               fprintf(stderr, "Warning: opendir(%s): %m", dirs->data);
+           while ((de = readdir(dir)) != NULL) {
+               d = filter_chd(de->d_name, dirs->data, d_add);
+               if(d)
+                   d_add = d;
+           }
+           closedir(dir);
+           if(dirs->data != p)
+               free(dirs->data);
+           d = dirs;
+           dirs = dirs->link;
+           free(d);
+       }
+       dirs = d_add;
+    }
+}
+
+int main(int argc, char **argv)
+{
+       int generate_dep = 1;
+       char *s;
+       int i;
+       llist_t *fl;
+
+       while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
+               switch(i) {
+                   case 'I':
+                           Iop = llist_add_to(Iop, optarg);
+                           break;
+                   case 'c':
+                           s = bb_simplify_path(optarg);
+                           configs = llist_add_to(configs, s);
+                           break;
+                   case 'd':
+                           generate_dep = 0;
+                           break;
+                   case 'k':
+                           if(kp)
+                               bb_error_d("Hmm, why multiple -k?");
+                           kp = bb_simplify_path(optarg);
+                           break;
+                   case 'w':
+                           noiwarning = 1;
+                           break;
+                   default:
+                           show_usage();
+               }
+       }
+       if(argc > optind)
+           show_usage();
+
+       /* defaults */
+       if(kp == NULL)
+           kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
+       if(Iop == NULL)
+           Iop = llist_add_to(Iop, LOCAL_INCLUDE_PATH);
+       if(configs == NULL) {
+           s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
+           configs = llist_add_to(configs, s);
+       }
+       scan_dir_find_ch_files(".");
+
+       for(fl = files; fl; fl = fl->link) {
+               c_lex(fl->data, 0);
+               if(generate_dep) {
+                       i = show_dep(1, Ifound, fl->data);
+                       i = show_dep(i, key_top, fl->data);
+                       if(i == 0)
+                               putchar('\n');
+               }
+       }
+       return 0;
+}
+
+void bb_error_d(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       vfprintf(stderr, s, p);
+       va_end(p);
+       putc('\n', stderr);
+       exit(1);
+}
+
+
+void *xmalloc(size_t size)
+{
+       void *p = malloc(size);
+
+       if(p == NULL)
+               bb_error_d("memory exhausted");
+       return p;
+}
+
+void *xrealloc(void *p, size_t size) {
+       p = realloc(p, size);
+       if(p == NULL)
+               bb_error_d("memory exhausted");
+       return p;
+}
+
+char *bb_asprint(const char *format, ...)
+{
+       va_list p;
+       int r;
+       char *out;
+
+       va_start(p, format);
+       r = vasprintf(&out, format, p);
+       va_end(p);
+
+       if (r < 0)
+               bb_error_d("bb_asprint: %m");
+       return out;
+}
+
+llist_t *llist_add_to(llist_t *old_head, char *new_item)
+{
+       llist_t *new_head;
+
+       new_head = xmalloc(sizeof(llist_t));
+       new_head->data = new_item;
+       new_head->link = old_head;
+
+       return(new_head);
+}
+
+char *bb_xstrdup(const char *s)
+{
+    char *r = strdup(s);
+    if(r == NULL)
+       bb_error_d("memory exhausted");
+    return r;
+}
+
+char *bb_simplify_path(const char *path)
+{
+       char *s, *start, *p;
+
+       if (path[0] == '/')
+             start = bb_xstrdup(path);
+       else {
+             static char *pwd;
+
+             if(pwd == NULL) {
+                   /* is not libbb, but this program have not chdir() */
+                   unsigned path_max = 512;
+                   char *cwd = xmalloc (path_max);
+#define PATH_INCR 32
+                   while (getcwd (cwd, path_max) == NULL) {
+                       if(errno != ERANGE)
+                           bb_error_d("getcwd: %m");
+                       path_max += PATH_INCR;
+                       cwd = xrealloc (cwd, path_max);
+                   }
+                   pwd = cwd;
+           }
+           start = bb_asprint("%s/%s", pwd, path);
+       }
+       p = s = start;
+
+       do {
+               if (*p == '/') {
+                       if (*s == '/') {        /* skip duplicate (or initial) slash */
+                               continue;
+                       } else if (*s == '.') {
+                               if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
+                                       continue;
+                               } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
+                                       ++s;
+                                       if (p > start) {
+                                               while (*--p != '/');    /* omit previous dir */
+                                       }
+                                       continue;
+                               }
+                       }
+               }
+               *++p = *s;
+       } while (*++s);
+
+       if ((p == start) || (*p != '/')) {      /* not a trailing slash */
+               ++p;                            /* so keep last character */
+       }
+       *p = 0;
+
+       return start;
+}
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
deleted file mode 100644 (file)
index ae3cc74..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Originally by Linus Torvalds.
- * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
- *
- * Usage: mkdep cflags -- file ...
- *
- * Read source files and output makefile dependency lines for them.
- * I make simple dependency lines for #include <*.h> and #include "*.h".
- * I also find instances of CONFIG_FOO and generate dependencies
- *    like include/config/foo.h.
- *
- * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Keith Owens reported a bug in smart config processing.  There used
- *   to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
- *   so that the file would not depend on CONFIG_FOO because the file defines
- *   this symbol itself.  But this optimization is bogus!  Consider this code:
- *   "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO".  Here
- *   the definition is inactivated, but I still used it.  It turns out this
- *   actually happens a few times in the kernel source.  The simple way to
- *   fix this problem is to remove this particular optimization.
- *
- * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
- * - Changed so that 'filename.o' depends upon 'filename.[cS]'.  This is so that
- *   missing source files are noticed, rather than silently ignored.
- *
- * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
- * - Accept cflags followed by '--' followed by filenames.  mkdep extracts -I
- *   options from cflags and looks in the specified directories as well as the
- *   defaults.   Only -I is supported, no attempt is made to handle -idirafter,
- *   -isystem, -I- etc.
- */
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-
-char depname[512];
-int hasdep;
-
-struct path_struct {
-       int len;
-       char *buffer;
-};
-struct path_struct *path_array;
-int paths;
-
-
-/* Current input file */
-static const char *g_filename;
-
-/*
- * This records all the configuration options seen.
- * In perl this would be a hash, but here it's a long string
- * of values separated by newlines.  This is simple and
- * extremely fast.
- */
-char * str_config  = NULL;
-int    size_config = 0;
-int    len_config  = 0;
-
-static void
-do_depname(void)
-{
-       if (!hasdep) {
-               hasdep = 1;
-               if (g_filename) {
-                       /* Source file (*.[cS]) */
-                       printf("%s:", depname);
-                       printf(" %s", g_filename);
-               } else {
-                       /* header file (*.h) */
-                       printf("dep_%s +=", depname);
-               }
-       }
-}
-
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_config(int len)
-{
-       while (len_config + len > size_config) {
-               if (size_config == 0)
-                       size_config = 2048;
-               str_config = realloc(str_config, size_config *= 2);
-               if (str_config == NULL)
-                       { perror("malloc config"); exit(1); }
-       }
-}
-
-
-
-/*
- * Lookup a value in the configuration string.
- */
-int is_defined_config(const char * name, int len)
-{
-       const char * pconfig;
-       const char * plast = str_config + len_config - len;
-       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
-               if (pconfig[ -1] == '\n'
-               &&  pconfig[len] == '\n'
-               &&  !memcmp(pconfig, name, len))
-                       return 1;
-       }
-       return 0;
-}
-
-
-
-/*
- * Add a new value to the configuration string.
- */
-void define_config(const char * name, int len)
-{
-       grow_config(len + 1);
-
-       memcpy(str_config+len_config, name, len);
-       len_config += len;
-       str_config[len_config++] = '\n';
-}
-
-
-
-/*
- * Clear the set of configuration strings.
- */
-void clear_config(void)
-{
-       len_config = 0;
-       define_config("", 0);
-}
-
-
-
-/*
- * This records all the precious .h filenames.  No need for a hash,
- * it's a long string of values enclosed in tab and newline.
- */
-char * str_precious  = NULL;
-int    size_precious = 0;
-int    len_precious  = 0;
-
-
-
-/*
- * Grow the precious string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_precious(int len)
-{
-       while (len_precious + len > size_precious) {
-               if (size_precious == 0)
-                       size_precious = 2048;
-               str_precious = realloc(str_precious, size_precious *= 2);
-               if (str_precious == NULL)
-                       { perror("malloc"); exit(1); }
-       }
-}
-
-
-
-/*
- * Add a new value to the precious string.
- */
-void define_precious(const char * filename)
-{
-       int len = strlen(filename);
-       grow_precious(len + 4);
-       *(str_precious+len_precious++) = '\t';
-       memcpy(str_precious+len_precious, filename, len);
-       len_precious += len;
-       memcpy(str_precious+len_precious, " \\\n", 3);
-       len_precious += 3;
-}
-
-
-
-/*
- * Handle an #include line.
- */
-void handle_include(int start, const char * name, int len)
-{
-       struct path_struct *path;
-       int i;
-
-       if (len == 14 && !memcmp(name, "include/config.h", len))
-               return;
-
-       if (len >= 7 && !memcmp(name, "config/", 7))
-               define_config(name+7, len-7-2);
-
-       for (i = start, path = path_array+start; i < paths; ++i, ++path) {
-               memcpy(path->buffer+path->len, name, len);
-               path->buffer[path->len+len] = '\0';
-               if (access(path->buffer, F_OK) == 0) {
-                       do_depname();
-                       printf(" \\\n %s $(dep_%s)", path->buffer, path->buffer);
-                       return;
-               }
-       }
-
-}
-
-
-
-/*
- * Add a path to the list of include paths.
- */
-void add_path(const char * name)
-{
-       struct path_struct *path;
-       char resolved_path[PATH_MAX+1];
-       const char *name2;
-
-       if (strcmp(name, ".")) {
-               name2 = realpath(name, resolved_path);
-               if (!name2) {
-                       fprintf(stderr, "realpath(%s) failed, %m\n", name);
-                       exit(1);
-               }
-       }
-       else {
-               name2 = "";
-       }
-
-       path_array = realloc(path_array, (++paths)*sizeof(*path_array));
-       if (!path_array) {
-               fprintf(stderr, "cannot expand path_arry\n");
-               exit(1);
-       }
-
-       path = path_array+paths-1;
-       path->len = strlen(name2);
-       path->buffer = malloc(path->len+1+256+1);
-       if (!path->buffer) {
-               fprintf(stderr, "cannot allocate path buffer\n");
-               exit(1);
-       }
-       strcpy(path->buffer, name2);
-       if (path->len && *(path->buffer+path->len-1) != '/') {
-               *(path->buffer+path->len) = '/';
-               *(path->buffer+(++(path->len))) = '\0';
-       }
-}
-
-
-
-/*
- * Record the use of a CONFIG_* word.
- */
-void use_config(const char * name, int len)
-{
-       char *pc;
-       int i;
-
-       pc = path_array[paths-1].buffer + path_array[paths-1].len;
-       memcpy(pc, "config/", 7);
-       pc += 7;
-
-       for (i = 0; i < len; i++) {
-           char c = name[i];
-           if (isupper((int)c)) c = tolower((int)c);
-           if (c == '_')   c = '/';
-           pc[i] = c;
-       }
-       pc[len] = '\0';
-
-       if (is_defined_config(pc, len))
-           return;
-
-       define_config(pc, len);
-
-       do_depname();
-       printf(" \\\n   $(wildcard %s.h)", path_array[paths-1].buffer);
-}
-
-
-
-/*
- * Macros for stunningly fast map-based character access.
- * __buf is a register which holds the current word of the input.
- * Thus, there is one memory access per sizeof(unsigned long) characters.
- */
-
-#if defined(__alpha__) || defined(__i386__) || defined(__ia64__)  || defined(__x86_64__) || defined(__MIPSEL__)        \
-    || defined(__arm__)
-#define LE_MACHINE
-#endif
-
-#ifdef LE_MACHINE
-#define next_byte(x) (x >>= 8)
-#define current ((unsigned char) __buf)
-#else
-#define next_byte(x) (x <<= 8)
-#define current (__buf >> 8*(sizeof(unsigned long)-1))
-#endif
-
-#define GETNEXT { \
-       next_byte(__buf); \
-       if ((unsigned long) next % sizeof(unsigned long) == 0) { \
-               if (next >= end) \
-                       break; \
-               __buf = * (unsigned long *) next; \
-       } \
-       next++; \
-}
-
-/*
- * State machine macros.
- */
-#define CASE(c,label) if (current == c) goto label
-#define NOTCASE(c,label) if (current != c) goto label
-
-/*
- * Yet another state machine speedup.
- */
-#define MAX2(a,b) ((a)>(b)?(a):(b))
-#define MIN2(a,b) ((a)<(b)?(a):(b))
-#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
-#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
-
-
-
-/*
- * The state machine looks for (approximately) these Perl regular expressions:
- *
- *    m|\/\*.*?\*\/|
- *    m|\/\/.*|
- *    m|'.*?'|
- *    m|".*?"|
- *    m|#\s*include\s*"(.*?)"|
- *    m|#\s*include\s*<(.*?>"|
- *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
- *    m|(?!\w)CONFIG_|
- *
- * About 98% of the CPU time is spent here, and most of that is in
- * the 'start' paragraph.  Because the current characters are
- * in a register, the start loop usually eats 4 or 8 characters
- * per memory read.  The MAX5 and MIN5 tests dispose of most
- * input characters with 1 or 2 comparisons.
- */
-void state_machine(const char * map, const char * end)
-{
-       const char * next = map;
-       const char * map_dot;
-       unsigned long __buf = 0;
-
-       for (;;) {
-start:
-       GETNEXT
-__start:
-       if (current > MAX5('/','\'','"','#','C')) goto start;
-       if (current < MIN5('/','\'','"','#','C')) goto start;
-       CASE('/',  slash);
-       CASE('\'', squote);
-       CASE('"',  dquote);
-       CASE('#',  pound);
-       CASE('C',  cee);
-       goto start;
-
-/* // */
-slash_slash:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('\\', slash_slash);
-       GETNEXT
-       goto slash_slash;
-
-/* / */
-slash:
-       GETNEXT
-       CASE('/',  slash_slash);
-       NOTCASE('*', __start);
-slash_star_dot_star:
-       GETNEXT
-__slash_star_dot_star:
-       NOTCASE('*', slash_star_dot_star);
-       GETNEXT
-       NOTCASE('/', __slash_star_dot_star);
-       goto start;
-
-/* '.*?' */
-squote:
-       GETNEXT
-       CASE('\'', start);
-       NOTCASE('\\', squote);
-       GETNEXT
-       goto squote;
-
-/* ".*?" */
-dquote:
-       GETNEXT
-       CASE('"', start);
-       NOTCASE('\\', dquote);
-       GETNEXT
-       goto dquote;
-
-/* #\s* */
-pound:
-       GETNEXT
-       CASE(' ',  pound);
-       CASE('\t', pound);
-       CASE('i',  pound_i);
-       CASE('d',  pound_d);
-       CASE('u',  pound_u);
-       goto __start;
-
-/* #\s*i */
-pound_i:
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('c', __start);
-       GETNEXT NOTCASE('l', __start);
-       GETNEXT NOTCASE('u', __start);
-       GETNEXT NOTCASE('d', __start);
-       GETNEXT NOTCASE('e', __start);
-       goto pound_include;
-
-/* #\s*include\s* */
-pound_include:
-       GETNEXT
-       CASE(' ',  pound_include);
-       CASE('\t', pound_include);
-       map_dot = next;
-       CASE('"',  pound_include_dquote);
-       CASE('<',  pound_include_langle);
-       goto __start;
-
-/* #\s*include\s*"(.*)" */
-pound_include_dquote:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('"', pound_include_dquote);
-       handle_include(0, map_dot, next - map_dot - 1);
-       goto start;
-
-/* #\s*include\s*<(.*)> */
-pound_include_langle:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('>', pound_include_langle);
-       handle_include(1, map_dot, next - map_dot - 1);
-       goto start;
-
-/* #\s*d */
-pound_d:
-       GETNEXT NOTCASE('e', __start);
-       GETNEXT NOTCASE('f', __start);
-       GETNEXT NOTCASE('i', __start);
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('e', __start);
-       goto pound_define_undef;
-
-/* #\s*u */
-pound_u:
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('d', __start);
-       GETNEXT NOTCASE('e', __start);
-       GETNEXT NOTCASE('f', __start);
-       goto pound_define_undef;
-
-/*
- * #\s*(define|undef)\s*CONFIG_(\w*)
- *
- * this does not define the word, because it could be inside another
- * conditional (#if 0).  But I do parse the word so that this instance
- * does not count as a use.  -- mec
- */
-pound_define_undef:
-       GETNEXT
-       CASE(' ',  pound_define_undef);
-       CASE('\t', pound_define_undef);
-
-               NOTCASE('C', __start);
-       GETNEXT NOTCASE('O', __start);
-       GETNEXT NOTCASE('N', __start);
-       GETNEXT NOTCASE('F', __start);
-       GETNEXT NOTCASE('I', __start);
-       GETNEXT NOTCASE('G', __start);
-       GETNEXT NOTCASE('_', __start);
-
-       map_dot = next;
-pound_define_undef_CONFIG_word:
-       GETNEXT
-       if (isalnum(current) || current == '_')
-               goto pound_define_undef_CONFIG_word;
-       goto __start;
-
-/* \<CONFIG_(\w*) */
-cee:
-       if (next >= map+2 && (isalnum((int)next[-2]) || next[-2] == '_'))
-               goto start;
-       GETNEXT NOTCASE('O', __start);
-       GETNEXT NOTCASE('N', __start);
-       GETNEXT NOTCASE('F', __start);
-       GETNEXT NOTCASE('I', __start);
-       GETNEXT NOTCASE('G', __start);
-       GETNEXT NOTCASE('_', __start);
-
-       map_dot = next;
-cee_CONFIG_word:
-       GETNEXT
-       if (isalnum(current) || current == '_')
-               goto cee_CONFIG_word;
-       use_config(map_dot, next - map_dot - 1);
-       goto __start;
-    }
-}
-
-
-
-/*
- * Generate dependencies for one file.
- */
-void do_depend(const char * filename)
-{
-       int mapsize;
-       int pagesizem1 = getpagesize()-1;
-       int fd;
-       struct stat st;
-       char * map;
-
-       fd = open(filename, O_RDONLY);
-       if (fd < 0) {
-               perror(filename);
-               return;
-       }
-
-       fstat(fd, &st);
-       if (st.st_size == 0) {
-               fprintf(stderr,"%s is empty\n",filename);
-               close(fd);
-               return;
-       }
-
-       mapsize = st.st_size;
-       mapsize = (mapsize+pagesizem1) & ~pagesizem1;
-       map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
-       if ((long) map == -1) {
-               perror("mkdep: mmap");
-               close(fd);
-               return;
-       }
-       if ((unsigned long) map % sizeof(unsigned long) != 0)
-       {
-               fprintf(stderr, "do_depend: map not aligned\n");
-               exit(1);
-       }
-
-       hasdep = 0;
-       clear_config();
-       state_machine(map, map+st.st_size);
-       if (hasdep) {
-               puts("");
-       }
-
-       munmap(map, mapsize);
-       close(fd);
-}
-
-
-
-/*
- * Generate dependencies for all files.
- */
-int main(int argc, char **argv)
-{
-       int len;
-       const char *hpath;
-
-       hpath = getenv("TOPDIR");
-       if (!hpath) {
-               fputs("mkdep: TOPDIR not set in environment.  "
-                     "Don't bypass the top level Makefile.\n", stderr);
-               return 1;
-       }
-
-       add_path(".");          /* for #include "..." */
-
-       while (++argv, --argc > 0) {
-               if (strncmp(*argv, "-I", 2) == 0) {
-                       if (*((*argv)+2)) {
-                               add_path((*argv)+2);
-                       }
-                       else {
-                               ++argv;
-                               --argc;
-                               add_path(*argv);
-                       }
-               }
-               else if (strcmp(*argv, "--") == 0) {
-                       break;
-               }
-       }
-
-       add_path(hpath);        /* must be last entry, for config files */
-
-       while (--argc > 0) {
-               const char * filename = *++argv;
-               g_filename = 0;
-               len = strlen(filename);
-               memcpy(depname, filename, len+1);
-               if (len > 2 && filename[len-2] == '.') {
-                       if (filename[len-1] == 'c' || filename[len-1] == 'S') {
-                           depname[len-1] = 'o';
-                           g_filename = filename;
-                       }
-               }
-               do_depend(filename);
-       }
-       if (len_precious) {
-               *(str_precious+len_precious) = '\0';
-               printf(".PRECIOUS:%s\n", str_precious);
-       }
-       return 0;
-}
diff --git a/scripts/split-include.c b/scripts/split-include.c
deleted file mode 100644 (file)
index 624a0d6..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * split-include.c
- *
- * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
- * This is a C version of syncdep.pl by Werner Almesberger.
- *
- * This program takes autoconf.h as input and outputs a directory full
- * of one-line include files, merging onto the old values.
- *
- * Think of the configuration options as key-value pairs.  Then there
- * are five cases:
- *
- *    key      old value   new value   action
- *
- *    KEY-1    VALUE-1     VALUE-1     leave file alone
- *    KEY-2    VALUE-2A    VALUE-2B    write VALUE-2B into file
- *    KEY-3    -           VALUE-3     write VALUE-3  into file
- *    KEY-4    VALUE-4     -           write an empty file
- *    KEY-5    (empty)     -           leave old empty file alone
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define ERROR_EXIT(strExit)                                            \
-    {                                                                  \
-       const int errnoSave = errno;                                    \
-       fprintf(stderr, "%s: ", str_my_name);                           \
-       errno = errnoSave;                                              \
-       perror((strExit));                                              \
-       exit(1);                                                        \
-    }
-
-
-
-int main(int argc, const char * argv [])
-{
-    const char * str_my_name;
-    const char * str_file_autoconf;
-    const char * str_dir_config;
-
-    FILE * fp_config;
-    FILE * fp_target;
-    FILE * fp_find;
-
-    int buffer_size;
-
-    char * line;
-    char * old_line;
-    char * list_target;
-    char * ptarget;
-
-    struct stat stat_buf;
-
-    /* Check arg count. */
-    if (argc != 3)
-    {
-       fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
-       exit(1);
-    }
-
-    str_my_name       = argv[0];
-    str_file_autoconf = argv[1];
-    str_dir_config    = argv[2];
-
-    /* Find a buffer size. */
-    if (stat(str_file_autoconf, &stat_buf) != 0)
-       ERROR_EXIT(str_file_autoconf);
-    buffer_size = 2 * stat_buf.st_size + 4096;
-
-    /* Allocate buffers. */
-    if ( (line        = malloc(buffer_size)) == NULL
-    ||   (old_line    = malloc(buffer_size)) == NULL
-    ||   (list_target = malloc(buffer_size)) == NULL )
-       ERROR_EXIT(str_file_autoconf);
-
-    /* Open autoconfig file. */
-    if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
-       ERROR_EXIT(str_file_autoconf);
-
-    /* Make output directory if needed. */
-    if (stat(str_dir_config, &stat_buf) != 0)
-    {
-       if (mkdir(str_dir_config, 0755) != 0)
-           ERROR_EXIT(str_dir_config);
-    }
-
-    /* Change to output directory. */
-    if (chdir(str_dir_config) != 0)
-       ERROR_EXIT(str_dir_config);
-
-    /* Put initial separator into target list. */
-    ptarget = list_target;
-    *ptarget++ = '\n';
-
-    /* Read config lines. */
-    while (fgets(line, buffer_size, fp_config))
-    {
-       const char * str_config;
-       int is_same;
-       int itarget;
-
-       if (line[0] != '#')
-           continue;
-       if ((str_config = strstr(line, "CONFIG_")) == NULL)
-           continue;
-
-       /* Make the output file name. */
-       str_config += sizeof("CONFIG_") - 1;
-       for (itarget = 0; !isspace(str_config[itarget]); itarget++)
-       {
-           char c = str_config[itarget];
-           if (isupper(c)) c = tolower(c);
-           if (c == '_')   c = '/';
-           ptarget[itarget] = c;
-       }
-       ptarget[itarget++] = '.';
-       ptarget[itarget++] = 'h';
-       ptarget[itarget++] = '\0';
-
-       /* Check for existing file. */
-       is_same = 0;
-       if ((fp_target = fopen(ptarget, "r")) != NULL)
-       {
-           fgets(old_line, buffer_size, fp_target);
-           if (fclose(fp_target) != 0)
-               ERROR_EXIT(ptarget);
-           if (!strcmp(line, old_line))
-               is_same = 1;
-       }
-
-       if (!is_same)
-       {
-           /* Auto-create directories. */
-           int islash;
-           for (islash = 0; islash < itarget; islash++)
-           {
-               if (ptarget[islash] == '/')
-               {
-                   ptarget[islash] = '\0';
-                   if (stat(ptarget, &stat_buf) != 0
-                   &&  mkdir(ptarget, 0755)     != 0)
-                       ERROR_EXIT( ptarget );
-                   ptarget[islash] = '/';
-               }
-           }
-
-           /* Write the file. */
-           if ((fp_target = fopen(ptarget, "w" )) == NULL)
-               ERROR_EXIT(ptarget);
-           fputs(line, fp_target);
-           if (ferror(fp_target) || fclose(fp_target) != 0)
-               ERROR_EXIT(ptarget);
-       }
-
-       /* Update target list */
-       ptarget += itarget;
-       *(ptarget-1) = '\n';
-    }
-
-    /*
-     * Close autoconfig file.
-     * Terminate the target list.
-     */
-    if (fclose(fp_config) != 0)
-       ERROR_EXIT(str_file_autoconf);
-    *ptarget = '\0';
-
-    /*
-     * Fix up existing files which have no new value.
-     * This is Case 4 and Case 5.
-     *
-     * I re-read the tree and filter it against list_target.
-     * This is crude.  But it avoids data copies.  Also, list_target
-     * is compact and contiguous, so it easily fits into cache.
-     *
-     * Notice that list_target contains strings separated by \n,
-     * with a \n before the first string and after the last.
-     * fgets gives the incoming names a terminating \n.
-     * So by having an initial \n, strstr will find exact matches.
-     */
-
-    fp_find = popen("find * -type f -name \"*.h\" -print", "r");
-    if (fp_find == 0)
-       ERROR_EXIT( "find" );
-
-    line[0] = '\n';
-    while (fgets(line+1, buffer_size, fp_find))
-    {
-       if (strstr(list_target, line) == NULL)
-       {
-           /*
-            * This is an old file with no CONFIG_* flag in autoconf.h.
-            */
-
-           /* First strip the \n. */
-           line[strlen(line)-1] = '\0';
-
-           /* Grab size. */
-           if (stat(line+1, &stat_buf) != 0)
-               ERROR_EXIT(line);
-
-           /* If file is not empty, make it empty and give it a fresh date. */
-           if (stat_buf.st_size != 0)
-           {
-               if ((fp_target = fopen(line+1, "w")) == NULL)
-                   ERROR_EXIT(line);
-               if (fclose(fp_target) != 0)
-                   ERROR_EXIT(line);
-           }
-       }
-    }
-
-    if (pclose(fp_find) != 0)
-       ERROR_EXIT("find");
-
-    return 0;
-}