new my scripts/mm_mkdep, dependences work now
This commit is contained in:
parent
ba50217281
commit
5e60dc4a20
2
AUTHORS
2
AUTHORS
@ -110,7 +110,7 @@ Manuel Novoa III <mjn3@codepoet.org>
|
||||
interface, dutmp, ifconfig, route
|
||||
|
||||
Vladimir Oleynik <dzo@simtreas.ru>
|
||||
cmdedit; xargs(current), httpd(current);
|
||||
cmdedit; bb_mkdep, xargs(current), httpd(current);
|
||||
ports: ash, crond, fdisk, inetd, stty, traceroute, top;
|
||||
locale, various fixes
|
||||
and irreconcilable critic of everything not perfect.
|
||||
|
32
Makefile
32
Makefile
@ -110,7 +110,7 @@ $(ALL_MAKEFILES): %/Makefile: $(top_srcdir)/%/Makefile
|
||||
include $(patsubst %,%/Makefile.in, $(SRC_DIRS))
|
||||
-include $(top_builddir)/.depend
|
||||
|
||||
busybox: $(ALL_MAKEFILES) .depend include/bb_config.h $(libraries-y)
|
||||
busybox: $(ALL_MAKEFILES) .depend $(libraries-y)
|
||||
$(CC) $(LDFLAGS) -o $@ -Wl,--start-group $(libraries-y) $(LIBRARIES) -Wl,--end-group
|
||||
$(STRIPCMD) $@
|
||||
|
||||
@ -180,24 +180,14 @@ docs/busybox.net/BusyBox.html: docs/busybox.pod
|
||||
-@ rm -f pod2htm*
|
||||
|
||||
# The nifty new buildsystem stuff
|
||||
scripts/mkdep: $(top_srcdir)/scripts/mkdep.c
|
||||
$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
|
||||
|
||||
scripts/split-include: $(top_srcdir)/scripts/split-include.c
|
||||
scripts/bb_mkdep: $(top_srcdir)/scripts/bb_mkdep.c
|
||||
$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
|
||||
|
||||
depend dep: .depend
|
||||
.depend: scripts/mkdep include/config.h include/bbconfigopts.h
|
||||
rm -f .depend .hdepend;
|
||||
mkdir -p include/config;
|
||||
scripts/mkdep -I include -- \
|
||||
`find $(top_srcdir) -name \*.c -print | sed -e "s,^./,,"` >> .depend;
|
||||
scripts/mkdep -I include -- \
|
||||
`find $(top_srcdir) -name \*.h -print | sed -e "s,^./,,"` >> .hdepend;
|
||||
|
||||
include/config/MARKER: depend scripts/split-include
|
||||
scripts/split-include include/config.h include/config
|
||||
@ touch include/config/MARKER
|
||||
.depend: scripts/bb_mkdep include/config.h include/bb_config.h
|
||||
@rm -f .depend
|
||||
@mkdir -p include/config
|
||||
scripts/bb_mkdep -c include/config.h -c include/bb_config.h > $@
|
||||
|
||||
include/config.h: .config
|
||||
@if [ ! -x $(top_builddir)/scripts/config/conf ] ; then \
|
||||
@ -206,11 +196,11 @@ include/config.h: .config
|
||||
@$(top_builddir)/scripts/config/conf -o $(CONFIG_CONFIG_IN)
|
||||
|
||||
include/bb_config.h: include/config.h
|
||||
echo -e "#ifndef BB_CONFIG_H\n#define BB_CONFIG_H" > $@
|
||||
sed -e 's/#undef CONFIG_\(.*\)/#define ENABLE_\1 0/' \
|
||||
@echo -e "#ifndef BB_CONFIG_H\n#define BB_CONFIG_H" > $@
|
||||
@sed -e 's/#undef CONFIG_\(.*\)/#define ENABLE_\1 0/' \
|
||||
-e 's/#define CONFIG_\(.*\)/#define CONFIG_\1\n#define ENABLE_\1/' \
|
||||
< $< >> $@
|
||||
echo "#endif" >> $@
|
||||
@echo "#endif" >> $@
|
||||
|
||||
include/bbconfigopts.h: .config
|
||||
@[ -d $(@D) ] || mkdir -v $(@D)
|
||||
@ -270,14 +260,14 @@ clean:
|
||||
docs/busybox pod2htm* *.gdb *.elf *~ core .*config.log \
|
||||
docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \
|
||||
docs/busybox.net/BusyBox.html busybox.links libbb/loop.h \
|
||||
.config.old .hdepend busybox testsuite/links/*
|
||||
.config.old busybox testsuite/links/*
|
||||
- rm -rf _install
|
||||
- find . -name .\*.flags -exec rm -f {} \;
|
||||
- find . -name \*.o -exec rm -f {} \;
|
||||
- find . -name \*.a -exec rm -f {} \;
|
||||
|
||||
distclean: clean
|
||||
- rm -f scripts/split-include scripts/mkdep
|
||||
- rm -f scripts/bb_mkdep
|
||||
- rm -rf include/config include/config.h include/bb_config.h include/bbconfigopts.h
|
||||
- find . -name .depend -exec rm -f {} \;
|
||||
rm -f .config .config.old .config.cmd
|
||||
|
855
scripts/bb_mkdep.c
Normal file
855
scripts/bb_mkdep.c
Normal file
@ -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;
|
||||
}
|
628
scripts/mkdep.c
628
scripts/mkdep.c
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user