new my scripts/mm_mkdep, dependences work now
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -110,7 +110,7 @@ Manuel Novoa III <[email protected]> | |
| interface, dutmp, ifconfig, route | |
| Vladimir Oleynik <[email protected]> | |
| - | 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 | |
| @@ -0,0 +1,855 @@ | |
| + | /* |
| + | * Another dependences for Makefile mashine generator |
| + | * |
| + | * Copyright (C) 2005 by Vladimir Oleynik <[email protected]> |
| + | * |
| + | * 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; |
| + | } |
| @@ -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, <[email protected]> |
| - | * - 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 <[email protected]> |
| - | * - 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 <[email protected]> |
| - | * - 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; |
| - | } |
| @@ -1,226 +0,0 @@ | |
| - | /* |
| - | * split-include.c |
| - | * |
| - | * Copyright abandoned, Michael Chastain, <mailto:[email protected]>. |
| - | * 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; |
| - | } |