From d3181e1cf79d78b20bf4205a5d8678556defba98 Mon Sep 17 00:00:00 2001
From: vodz <vodz@69ca8d6d-28ef-0310-b511-8ec308f3f277>
Date: Mon, 12 Sep 2005 12:33:27 +0000
Subject: new my scripts/mm_mkdep, dependences work now

git-svn-id: svn://busybox.net/trunk/busybox@11425 69ca8d6d-28ef-0310-b511-8ec308f3f277
---
 AUTHORS                 |   2 +-
 Makefile                |  32 +-
 scripts/bb_mkdep.c      | 855 ++++++++++++++++++++++++++++++++++++++++++++++++
 scripts/mkdep.c         | 628 -----------------------------------
 scripts/split-include.c | 226 -------------
 5 files changed, 867 insertions(+), 876 deletions(-)
 create mode 100644 scripts/bb_mkdep.c
 delete mode 100644 scripts/mkdep.c
 delete mode 100644 scripts/split-include.c

diff --git a/AUTHORS b/AUTHORS
index 383ab1aef..279b1b684 100644
--- 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.
diff --git a/Makefile b/Makefile
index a6356b70b..c8b6d79d2 100644
--- 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
index 000000000..408397332
--- /dev/null
+++ b/scripts/bb_mkdep.c
@@ -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
index ae3cc74e0..000000000
--- a/scripts/mkdep.c
+++ /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
index 624a0d62b..000000000
--- a/scripts/split-include.c
+++ /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;
-}
-- 
cgit v1.2.3-55-g6feb