diff options
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | scripts/bb_mkdep.c | 855 | ||||
-rw-r--r-- | scripts/mkdep.c | 628 | ||||
-rw-r--r-- | scripts/split-include.c | 226 |
5 files changed, 867 insertions, 876 deletions
@@ -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. @@ -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 0000000..4083973 --- /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 ae3cc74..0000000 --- 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 624a0d6..0000000 --- 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; -} |