diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-10-19 22:17:44 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-10-19 22:17:44 +0000 |
commit | b79b87a30f9c96edc49b05f04b087ae22a2f4736 (patch) | |
tree | c2fddc0c7b4f2ac88a7432f9d2bb477572d3631d /scripts/bb_mkdep.c | |
parent | 9fa9950784a0399b03473281de0109214552dbdf (diff) |
build system: (try to) get rid of bb_config.h hack
Diffstat (limited to 'scripts/bb_mkdep.c')
-rw-r--r-- | scripts/bb_mkdep.c | 1788 |
1 files changed, 0 insertions, 1788 deletions
diff --git a/scripts/bb_mkdep.c b/scripts/bb_mkdep.c deleted file mode 100644 index 39d4605af..000000000 --- a/scripts/bb_mkdep.c +++ /dev/null @@ -1,1788 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Another fast dependencies generator for Makefiles, Version 4.2 - * - * Copyright (C) 2005,2006 by Vladimir Oleynik <dzo@simtreas.ru> - * - * mmaping file may be originally by Linus Torvalds. - * - * infix parser/evaluator for #if expression - * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> - * Copyright (c) 2001 Manuel Novoa III <mjn3@codepoet.org> - * Copyright (c) 2003 Vladimir Oleynik <dzo@simtreas.ru> - * - * bb_simplify_path() - * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org> - * - * xmalloc() bb_xstrdup() bb_error_d(): - * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> - * - * llist routine - * Copyright (C) 2003 Glenn McGrath - * Copyright (C) Vladimir Oleynik <dzo@simtreas.ru> - * - * (c) 2005,2006 Bernhard Fischer: - * - commentary typos, - * - move "memory exhausted" into msg_enomem, - * - more verbose --help output. - * - * This program does: - * 1) find #define KEY VALUE or #undef KEY from include/bb_config.h - * 2) recursive find and scan *.[ch] files, but skips scan of include/config/ - * 3) find #include "*.h" and KEYs using, if not as #define and #undef - * 4) generate dependencies to stdout - * pwd/file.o: include/config/key*.h found_include_*.h - * path/inc.h: include/config/key*.h found_included_include_*.h - * 5) save include/config/key*.h if changed after previous usage - * This program does not generate dependencies for #include <...> - * Config file can have #if #elif #else #ifdef #ifndef #endif lines - */ - -#define LOCAL_INCLUDE_PATH "include" -#define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config" -#define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/bb_config.h" - -#define bb_mkdep_full_options \ -"\nOptions:" \ -"\n\t-I local_include_path include paths, default: \"" LOCAL_INCLUDE_PATH "\"" \ -"\n\t-d don't generate depend" \ -"\n\t-w show warning if include files not found" \ -"\n\t-k include/config default: \"" INCLUDE_CONFIG_PATH "\"" \ -"\n\t-c include/config.h configs, default: \"" INCLUDE_CONFIG_KEYS_PATH "\"" \ -"\n\tdirs_to_scan default \".\"" - -#define bb_mkdep_terse_options "Usage: [-I local_include_paths] [-dw] " \ - "[-k path_for_stored_keys] [dirs]" - - -#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> -#include <limits.h> - -#ifdef __GNUC__ -#define ATTRIBUTE __attribute__ -#else -#define ATTRIBUTE(a) /* nothing */ -#endif - -#if !(defined __USE_ISOC99 || (defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC)) -#define strtoll strtol -#endif - -/* partial and simplified libbb routine */ -static void bb_error_d(const char *s, ...) ATTRIBUTE ((noreturn, format (printf, 1, 2))); -static char * bb_asprint(const char *format, ...) ATTRIBUTE ((format (printf, 1, 2))); -static char *bb_simplify_path(const char *path); - -/* stolen from libbb as is */ -typedef struct llist_s { - char *data; - struct llist_s *link; -} llist_t; - -static const char msg_enomem[] = "memory exhausted"; - -/* inline realization for fast works */ -static inline void *xmalloc(size_t size) -{ - void *p = malloc(size); - - if(p == NULL) - bb_error_d(msg_enomem); - return p; -} - -static inline char *bb_xstrdup(const char *s) -{ - char *r = strdup(s); - - if(r == NULL) - bb_error_d(msg_enomem); - return r; -} - - -static int dontgenerate_dep; /* flag -d usaged */ -static int noiwarning; /* flag -w usaged */ -static llist_t *configs; /* list of -c usaged and them stat() after parsed */ -static llist_t *Iop; /* list of -I include usaged */ - -static char *pwd; /* current work directory */ -static size_t replace; /* replace current work directory with build dir */ - -static const char *kp; /* KEY path, argument of -k used */ -static size_t kp_len; -static struct stat st_kp; /* stat(kp) */ - -typedef struct BB_KEYS { - char *keyname; - size_t key_sz; - const char *value; - const char *checked; - char *stored_path; - const char *src_have_this_key; - struct BB_KEYS *next; -} bb_key_t; - -static bb_key_t *key_top; /* list of found KEYs */ -static bb_key_t *Ifound; /* list of parsed includes */ - - -static void parse_conf_opt(const char *opt, const char *val, size_t key_sz); -static void parse_inc(const char *include, const char *fname); - -static inline bb_key_t *check_key(bb_key_t *k, const char *nk, size_t key_sz) -{ - bb_key_t *cur; - - for(cur = k; cur; cur = cur->next) { - if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) { - cur->checked = cur->stored_path; - return cur; - } - } - return NULL; -} - -static inline const char *lookup_key(const char *nk, size_t key_sz) -{ - bb_key_t *cur; - - for(cur = key_top; cur; cur = cur->next) { - if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) { - return cur->value; - } - } - return NULL; -} - -/* for lexical analyser */ -static int pagesizem1; /* padding mask = getpagesize() - 1 */ - -/* for speed tricks */ -static char first_chars[1+UCHAR_MAX]; /* + L_EOF */ -static char isalnums[1+UCHAR_MAX]; /* + L_EOF */ - -/* trick for fast find "define", "include", "undef", -"if((n)def)" "else", "endif" */ -static const char * const preproc[] = { -/* 0 1 2 3 4 5 6 7 8 9 */ -"", "efine", "lif", "lse", "ndif", "f", "fdef", "fndef", "nclude", "ndef" }; -static const unsigned char first_chars_deiu[UCHAR_MAX] = { - [(int)'d'] = (unsigned char)(1|0x10), /* define */ - [(int)'e'] = (unsigned char)(2|0x40), /* elif, else, endif */ - [(int)'i'] = (unsigned char)(5|0x80), /* if ifdef ifndef include */ - [(int)'u'] = (unsigned char)(9|0x90), /* undef */ -}; - -#define CONFIG_MODE 0 -#define IF0_MODE 1 /* #if 0 */ -#define IF1_MODE 2 /* #if 1 */ -#define ELSE0_MODE 4 /* #else found after #if 0 */ -#define ELSE1_MODE 8 /* #else found after #if 1 */ -#define ELIF1_MODE 16 /* #elif found after #if 1 */ -#define FALSE_MODES (IF0_MODE|ELSE1_MODE|ELIF1_MODE) - -#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 BS '\\' /* back slash */ -#define POUND '#' /* # */ -#define D '1' /* #define preprocessor's directive */ -#define EI '2' /* #elif preprocessor's directive */ -#define E '3' /* #else preprocessor's directive */ -#define EF '4' /* #endif preprocessor's directive */ -#define F '5' /* #if preprocessor's directive */ -#define IFD '6' /* #ifdef preprocessor's directive */ -#define IFND '7' /* #ifndef preprocessor's directive */ -#define I '8' /* #include preprocessor's directive */ -#define U '9' /* #undef preprocessor's directive */ -#define DK 'K' /* #define KEY... (config mode) */ -#define ANY '*' /* any unparsed chars */ - -/* [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 L_EOF (1+UCHAR_MAX) - -#define getc0() do { c = (optr >= oend) ? L_EOF : *optr++; } while(0) - -#define getc1() do { getc0(); if(c == BS) { getc0(); \ - if(c == '\n') { line++; continue; } \ - else { optr--; c = BS; } \ - } break; } while(1) - -static char id_s[4096]; -#define put_id(ic) do { if(id_len == sizeof(id_s)) goto too_long; \ - id[id_len++] = ic; } while(0) - -static char ifcpp_stack[1024]; -static int ptr_ifcpp_stack; -#define push_mode() do { \ - if(ptr_ifcpp_stack == (int)sizeof(ifcpp_stack)) \ - yy_error_d("#if* stack overflow"); \ - ifcpp_stack[ptr_ifcpp_stack++] = (char)mode; \ - } while(0) - -#define pop_mode() do { \ - if(ptr_ifcpp_stack == 0) \ - yy_error_d("unexpected #endif"); \ - mode = ifcpp_stack[--ptr_ifcpp_stack]; \ - } while(0) - -/* #if expression */ -typedef long long arith_t; - -static arith_t arith (const char *expr, int *perrcode); - -/* The code uses a simple two-stack algorithm. See - * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html - * for a detailed explanation of the infix-to-postfix algorithm on which - * this is based (this code differs in that it applies operators immediately - * to the stack instead of adding them to a queue to end up with an - * expression). */ - -#define arith_isspace(arithval) \ - (arithval == ' ' || arithval == '\v' || arithval == '\t' || arithval == '\f') - - -typedef unsigned char operator; - -/* An operator's token id is a bit of a bitfield. The lower 5 bits are the - * precedence, and 3 high bits are an ID unique across operators of that - * precedence. The ID portion is so that multiple operators can have the - * same precedence, ensuring that the leftmost one is evaluated first. - * Consider * and /. */ - -#define tok_decl(prec,id) (((id)<<5)|(prec)) -#define PREC(op) ((op) & 0x1F) - -#define TOK_LPAREN tok_decl(0,0) - -#define TOK_COMMA tok_decl(1,0) - -/* conditional is right associativity too */ -#define TOK_CONDITIONAL tok_decl(2,0) -#define TOK_CONDITIONAL_SEP tok_decl(2,1) - -#define TOK_OR tok_decl(3,0) - -#define TOK_AND tok_decl(4,0) - -#define TOK_BOR tok_decl(5,0) - -#define TOK_BXOR tok_decl(6,0) - -#define TOK_BAND tok_decl(7,0) - -#define TOK_EQ tok_decl(8,0) -#define TOK_NE tok_decl(8,1) - -#define TOK_LT tok_decl(9,0) -#define TOK_GT tok_decl(9,1) -#define TOK_GE tok_decl(9,2) -#define TOK_LE tok_decl(9,3) - -#define TOK_LSHIFT tok_decl(10,0) -#define TOK_RSHIFT tok_decl(10,1) - -#define TOK_ADD tok_decl(11,0) -#define TOK_SUB tok_decl(11,1) - -#define TOK_MUL tok_decl(12,0) -#define TOK_DIV tok_decl(12,1) -#define TOK_REM tok_decl(12,2) - -/* For now unary operators. */ -#define UNARYPREC 13 -#define TOK_BNOT tok_decl(UNARYPREC,0) -#define TOK_NOT tok_decl(UNARYPREC,1) - -#define TOK_UMINUS tok_decl(UNARYPREC+1,0) -#define TOK_UPLUS tok_decl(UNARYPREC+1,1) - -#define SPEC_PREC (UNARYPREC+2) - -#define TOK_NUM tok_decl(SPEC_PREC, 0) -#define TOK_RPAREN tok_decl(SPEC_PREC, 1) - -#define NUMPTR (*numstackptr) - -typedef struct ARITCH_VAR_NUM { - arith_t val; - arith_t contidional_second_val; - char contidional_second_val_initialized; -} v_n_t; - - -typedef struct CHK_VAR_RECURSIVE_LOOPED { - const char *var; - size_t var_sz; - struct CHK_VAR_RECURSIVE_LOOPED *next; -} chk_var_recursive_looped_t; - -static chk_var_recursive_looped_t *prev_chk_var_recursive; - - -static int arith_lookup_val(const char *var, size_t key_sz, arith_t *pval) -{ - const char * p = lookup_key(var, key_sz); - - if(p) { - int errcode; - - /* recursive try as expression */ - chk_var_recursive_looped_t *cur; - chk_var_recursive_looped_t cur_save; - - for(cur = prev_chk_var_recursive; cur; cur = cur->next) { - if(cur->var_sz == key_sz && memcmp(cur->var, var, key_sz) == 0) { - /* expression recursion loop detected */ - return -5; - } - } - /* save current lookuped var name */ - cur = prev_chk_var_recursive; - cur_save.var = var; - cur_save.var_sz = key_sz; - cur_save.next = cur; - prev_chk_var_recursive = &cur_save; - - *pval = arith (p, &errcode); - /* restore previous ptr after recursiving */ - prev_chk_var_recursive = cur; - return errcode; - } else { - /* disallow undefined var */ - fprintf(stderr, "%.*s ", (int)key_sz, var); - return -4; - } -} - -/* "applying" a token means performing it on the top elements on the integer - * stack. For a unary operator it will only change the top element, but a - * binary operator will pop two arguments and push a result */ -static inline int -arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) -{ - v_n_t *numptr_m1; - arith_t numptr_val, rez; - - if (NUMPTR == numstack) goto err; /* There is no operator that can work - without arguments */ - numptr_m1 = NUMPTR - 1; - - rez = numptr_m1->val; - if (op == TOK_UMINUS) - rez *= -1; - else if (op == TOK_NOT) - rez = !rez; - else if (op == TOK_BNOT) - rez = ~rez; - else if (op != TOK_UPLUS) { - /* Binary operators */ - - /* check and binary operators need two arguments */ - if (numptr_m1 == numstack) goto err; - - /* ... and they pop one */ - --NUMPTR; - numptr_val = rez; - if (op == TOK_CONDITIONAL) { - if(! numptr_m1->contidional_second_val_initialized) { - /* protect $((expr1 ? expr2)) without ": expr" */ - goto err; - } - rez = numptr_m1->contidional_second_val; - } else if(numptr_m1->contidional_second_val_initialized) { - /* protect $((expr1 : expr2)) without "expr ? " */ - goto err; - } - numptr_m1 = NUMPTR - 1; - if (op == TOK_CONDITIONAL) { - numptr_m1->contidional_second_val = rez; - } - rez = numptr_m1->val; - if (op == TOK_BOR) - rez |= numptr_val; - else if (op == TOK_OR) - rez = numptr_val || rez; - else if (op == TOK_BAND) - rez &= numptr_val; - else if (op == TOK_BXOR) - rez ^= numptr_val; - else if (op == TOK_AND) - rez = rez && numptr_val; - else if (op == TOK_EQ) - rez = (rez == numptr_val); - else if (op == TOK_NE) - rez = (rez != numptr_val); - else if (op == TOK_GE) - rez = (rez >= numptr_val); - else if (op == TOK_RSHIFT) - rez >>= numptr_val; - else if (op == TOK_LSHIFT) - rez <<= numptr_val; - else if (op == TOK_GT) - rez = (rez > numptr_val); - else if (op == TOK_LT) - rez = (rez < numptr_val); - else if (op == TOK_LE) - rez = (rez <= numptr_val); - else if (op == TOK_MUL) - rez *= numptr_val; - else if (op == TOK_ADD) - rez += numptr_val; - else if (op == TOK_SUB) - rez -= numptr_val; - else if (op == TOK_COMMA) - rez = numptr_val; - else if (op == TOK_CONDITIONAL_SEP) { - if (numptr_m1 == numstack) { - /* protect $((expr : expr)) without "expr ? " */ - goto err; - } - numptr_m1->contidional_second_val_initialized = op; - numptr_m1->contidional_second_val = numptr_val; - } - else if (op == TOK_CONDITIONAL) { - rez = rez ? - numptr_val : numptr_m1->contidional_second_val; - } - else if(numptr_val==0) /* zero divisor check */ - return -2; - else if (op == TOK_DIV) - rez /= numptr_val; - else if (op == TOK_REM) - rez %= numptr_val; - } - numptr_m1->val = rez; - return 0; -err: return(-1); -} - -/* longest must first */ -static const char op_tokens[] = { - '<','<', 0, TOK_LSHIFT, - '>','>', 0, TOK_RSHIFT, - '|','|', 0, TOK_OR, - '&','&', 0, TOK_AND, - '!','=', 0, TOK_NE, - '<','=', 0, TOK_LE, - '>','=', 0, TOK_GE, - '=','=', 0, TOK_EQ, - '!', 0, TOK_NOT, - '<', 0, TOK_LT, - '>', 0, TOK_GT, - '|', 0, TOK_BOR, - '&', 0, TOK_BAND, - '*', 0, TOK_MUL, - '/', 0, TOK_DIV, - '%', 0, TOK_REM, - '+', 0, TOK_ADD, - '-', 0, TOK_SUB, - '^', 0, TOK_BXOR, - '~', 0, TOK_BNOT, - ',', 0, TOK_COMMA, - '?', 0, TOK_CONDITIONAL, - ':', 0, TOK_CONDITIONAL_SEP, - ')', 0, TOK_RPAREN, - '(', 0, TOK_LPAREN, - 0 -}; -/* ptr to ")" */ -#define endexpression &op_tokens[sizeof(op_tokens)-7] - -/* - * Return of a legal variable name (a letter or underscore followed by zero or - * more letters, underscores, and digits). - */ - -static inline char * -endofname(const char *name) -{ - char *p; - - p = (char *) name; - if (! ID(*p)) - return p; - while (*++p) { - if (! ISALNUM(*p)) - break; - } - return p; -} - - -static arith_t arith (const char *expr, int *perrcode) -{ - char arithval; /* Current character under analysis */ - operator lasttok, op; - operator prec; - - const char *p = endexpression; - int errcode; - - size_t datasizes = strlen(expr) + 2; - - /* Stack of integers */ - /* The proof that there can be no more than strlen(startbuf)/2+1 integers - * in any given correct or incorrect expression is left as an exercise to - * the reader. */ - v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), - *numstackptr = numstack; - /* Stack of operator tokens */ - operator *stack = alloca((datasizes) * sizeof(operator)), - *stackptr = stack; - - *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ - *perrcode = errcode = 0; - - while(1) { - if ((arithval = *expr) == 0) { - if (p == endexpression) { - /* Null expression. */ -err: - return (*perrcode = -1); - } - - /* This is only reached after all tokens have been extracted from the - * input stream. If there are still tokens on the operator stack, they - * are to be applied in order. At the end, there should be a final - * result on the integer stack */ - - if (expr != endexpression + 1) { - /* If we haven't done so already, */ - /* append a closing right paren */ - expr = endexpression; - /* and let the loop process it. */ - continue; - } - /* At this point, we're done with the expression. */ - if (numstackptr != numstack+1) { - /* ... but if there isn't, it's bad */ - goto err; - } - ret: - *perrcode = errcode; - return numstack->val; - } else { - /* Continue processing the expression. */ - if (arith_isspace(arithval)) { - /* Skip whitespace */ - goto prologue; - } - if((p = endofname(expr)) != expr) { - size_t var_name_size = (p-expr); - - if(var_name_size == 7 && - strncmp(expr, "defined", var_name_size) == 0) { - int brace_form = 0; - const char *v; - - while(arith_isspace(*p)) p++; - if(*p == '(') { - p++; - while(arith_isspace(*p)) p++; - brace_form = 1; - } - expr = p; - if((p = endofname(expr)) == expr) - goto err; - var_name_size = (p-expr); - while(arith_isspace(*p)) p++; - if(brace_form && *p++ != ')') - goto err; - v = lookup_key(expr, var_name_size); - numstackptr->val = (v != NULL) ? 1 : 0; - } else { - errcode = arith_lookup_val(expr, var_name_size, - &(numstackptr->val)); - if(errcode) goto ret; - } - expr = p; - num: - numstackptr->contidional_second_val_initialized = 0; - numstackptr++; - lasttok = TOK_NUM; - continue; - } else if (arithval >= '0' && arithval <= '9') { - numstackptr->val = strtoll(expr, (char **) &expr, 0); - while(*expr == 'l' || *expr == 'L' || *expr == 'u' || - *expr == 'U') - expr++; - goto num; - } - for(p = op_tokens; ; p++) { - const char *o; - - if(*p == 0) { - /* strange operator not found */ - goto err; - } - for(o = expr; *p && *o == *p; p++) - o++; - if(! *p) { - /* found */ - expr = o - 1; - break; - } - /* skip tail uncompared token */ - while(*p) - p++; - /* skip zero delim */ - p++; - } - op = p[1]; - - /* Plus and minus are binary (not unary) _only_ if the last - * token was as number, or a right paren (which pretends to be - * a number, since it evaluates to one). Think about it. - * It makes sense. */ - if (lasttok != TOK_NUM) { - if(op == TOK_ADD) - op = TOK_UPLUS; - else if(op == TOK_SUB) - op = TOK_UMINUS; - } - /* We don't want a unary operator to cause recursive descent on the - * stack, because there can be many in a row and it could cause an - * operator to be evaluated before its argument is pushed onto the - * integer stack. */ - /* But for binary operators, "apply" everything on the operator - * stack until we find an operator with a lesser priority than the - * one we have just extracted. */ - /* Left paren is given the lowest priority so it will never be - * "applied" in this way. - * if associativity is right and priority eq, applied also skip - */ - prec = PREC(op); - if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { - /* not left paren or unary */ - if (lasttok != TOK_NUM) { - /* binary op must be preceded by a num */ - goto err; - } - while (stackptr != stack) { - if (op == TOK_RPAREN) { - /* The algorithm employed here is simple: while we don't - * hit an open paren nor the bottom of the stack, pop - * tokens and apply them */ - if (stackptr[-1] == TOK_LPAREN) { - --stackptr; - /* Any operator directly after a */ - lasttok = TOK_NUM; - /* close paren should consider itself binary */ - goto prologue; - } - } else { - operator prev_prec = PREC(stackptr[-1]); - - if (prev_prec < prec) - break; - /* check right assoc */ - if(prev_prec == prec && prec == PREC(TOK_CONDITIONAL)) - break; - } - errcode = arith_apply(*--stackptr, numstack, &numstackptr); - if(errcode) goto ret; - } - if (op == TOK_RPAREN) { - goto err; - } - } - - /* Push this operator to the stack and remember it. */ - *stackptr++ = lasttok = op; - - prologue: - ++expr; - } - } -} - -/* stupid C lexical analyser for configs.h */ -static void c_lex_config(const char *fname, long fsize) -{ - int c; - int state; - int line; - char *id = id_s; - size_t id_len = 0; /* stupid initialization */ - unsigned char *optr, *oend; - int mode = CONFIG_MODE; - - int fd; - char *map; - int mapsize; - - if(fsize == 0) { - fprintf(stderr, "Warning: %s is empty\n", fname); - return; - } - fd = open(fname, O_RDONLY); - if(fd < 0) { - perror(fname); - return; - } - mapsize = (fsize+pagesizem1) & ~pagesizem1; - map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); - if ((long) map == -1) - bb_error_d("%s: mmap: %m", fname); - - optr = (unsigned char *)map; - oend = optr + fsize; - - line = 1; - state = S; - - for(;;) { - getc1(); - for(;;) { - /* [ \t]+ eat first space */ - while(c == ' ' || c == '\t') - getc1(); - - if(state == S) { - while(first_chars[c] == ANY) { - /* <S>unparsed */ - if(c == '\n') - line++; - getc1(); - } - if(c == L_EOF) { - /* <S><<EOF>> */ - munmap(map, mapsize); - close(fd); - if(mode != CONFIG_MODE) - yy_error_d("expected #endif"); - return; - } - if(c == REM) { - /* <S>/ */ - getc0(); - if(c == REM) { - /* <S>"//"[^\n]* */ - do getc0(); while(c != '\n' && c != L_EOF); - } else if(c == '*') { - /* <S>[/][*] goto parse block comments */ - break; - } - } else if(c == POUND) { - /* <S># */ - state = c; - getc1(); - } else if(c == STR || c == CHR) { - /* <S>\"|\' */ - int qc = c; - - for(;;) { - /* <STR,CHR>. */ - getc1(); - if(c == qc) { - /* <STR>\" or <CHR>\' */ - break; - } - if(c == BS) { - /* <STR,CHR>\\ but is not <STR,CHR>\\\n */ - getc0(); - } - if(c == '\n' || c == L_EOF) - yy_error_d("unterminated"); - } - getc1(); - } else { - /* <S>[A-Z_a-z0-9] */ - - /* trick for fast drop id - if key with this first char undefined */ - if(first_chars[c] == 0 || (mode & FALSE_MODES) != 0) { - /* skip <S>[A-Z_a-z0-9]+ */ - do getc1(); while(isalnums[c]); - } else { - id_len = 0; - do { - /* <S>[A-Z_a-z0-9]+ */ - put_id(c); - getc1(); - } while(isalnums[c]); - check_key(key_top, id, id_len); - } - } - continue; - } - /* begin preprocessor states */ - if(c == L_EOF) - yy_error_d("unexpected EOF"); - if(c == REM) { - /* <#.*>/ */ - getc0(); - if(c == REM) - yy_error_d("detected // in preprocessor line"); - if(c == '*') { - /* <#.*>[/][*] goto parse block comments */ - break; - } - /* hmm, #.*[/] */ - yy_error_d("strange preprocessor line"); - } - if(state == POUND) { - /* tricks */ - int diu = (int)first_chars_deiu[c]; /* preproc ptr */ - - state = S; - if(diu != S) { - int p_num_str, p_num_max; - - getc1(); - id_len = 0; - while(isalnums[c]) { - put_id(c); - getc1(); - } - put_id(0); - p_num_str = diu & 0xf; - p_num_max = diu >> 4; - for(diu = p_num_str; diu <= p_num_max; diu++) - if(!strcmp(id, preproc[diu])) { - state = (diu + '0'); - /* common */ - id_len = 0; - break; - } - } else { - while(isalnums[c]) getc1(); - } - } else if(state == EF) { - /* #endif */ - pop_mode(); - state = S; - } else if(state == I) { - if(c == STR && (mode & FALSE_MODES) == 0) { - /* <I>\" */ - for(;;) { - getc1(); - if(c == STR) - break; - if(c == L_EOF) - yy_error_d("unexpected EOF"); - put_id(c); - } - put_id(0); - /* store "include.h" */ - parse_inc(id, fname); - getc1(); - } - /* else another (may be wrong) #include ... */ - state = S; - } else if(state == F) { - arith_t t; - int errcode; - - while(c != '\n' && c != L_EOF) { - put_id(c); - getc1(); - } - put_id(0); - t = arith(id, &errcode); - if (errcode < 0) { - if (errcode == -2) - yy_error_d("divide by zero"); - else if (errcode == -4) - yy_error_d("undefined"); - else if (errcode == -5) - yy_error_d("expression recursion loop detected"); - else - yy_error_d("syntax error"); - } - push_mode(); - mode = t != 0 ? IF1_MODE : IF0_MODE; - state = S; - } else if(state == IFD || state == IFND) { - /* save KEY from #if(n)def KEY ... */ - const char *v; - - push_mode(); - while(isalnums[c]) { - put_id(c); - getc1(); - } - if(!id_len) - yy_error_d("expected identifier"); - v = lookup_key(id, id_len); - mode = IF1_MODE; - if(state == IFD && v == NULL) - mode = IF0_MODE; - else if(state == IFND && v != NULL) - mode = IF0_MODE; - state = S; - } else if(state == EI) { - /* #elif */ - if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE) - yy_error_d("unexpected #elif"); - if(mode == IF0_MODE) { - pop_mode(); - state = F; - } else { - mode = ELIF1_MODE; - state = S; - } - } else if(state == E) { - if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE) - yy_error_d("unexpected #else"); - if(mode == IF0_MODE) - mode = ELSE0_MODE; - else if(mode == IF1_MODE) - mode = ELSE1_MODE; - state = S; - } else if(state == D || state == U) { - /* save KEY from #"define"|"undef" ... */ - while(isalnums[c]) { - put_id(c); - getc1(); - } - if(!id_len) - yy_error_d("expected identifier"); - if(state == U) { - if((mode & FALSE_MODES) == 0) - parse_conf_opt(id, NULL, id_len); - state = S; - } else { - /* D -> DK */ - state = DK; - } - } else { - /* state==<DK> #define KEY[ ] */ - size_t opt_len = id_len; - char *val = id + opt_len; - char *sp; - - for(;;) { - if(c == L_EOF || c == '\n') - break; - put_id(c); - getc1(); - } - sp = id + id_len; - put_id(0); - /* trim tail spaces */ - while(--sp >= val && (*sp == ' ' || *sp == '\t' - || *sp == '\f' || *sp == '\v')) - *sp = '\0'; - if((mode & FALSE_MODES) == 0) - parse_conf_opt(id, val, opt_len); - state = S; - } - } - - /* <REM> */ - getc0(); - for(;;) { - /* <REM>[^*]+ */ - while(c != '*') { - if(c == '\n') { - /* <REM>\n */ - if(state != S) - yy_error_d("unexpected newline"); - line++; - } else if(c == L_EOF) - yy_error_d("unexpected EOF"); - getc0(); - } - /* <REM>[*] */ - getc0(); - if(c == REM) { - /* <REM>[*][/] */ - break; - } - } - } -too_long: - yy_error_d("phrase too long"); -} - -/* trick for fast find "define", "include", "undef" */ -static const char first_chars_diu[UCHAR_MAX] = { - [(int)'d'] = (char)5, /* strlen("define") - 1; */ - [(int)'i'] = (char)6, /* strlen("include") - 1; */ - [(int)'u'] = (char)4, /* strlen("undef") - 1; */ -}; - -#undef D -#undef I -#undef U -#define D '5' /* #define preprocessor's directive */ -#define I '6' /* #include preprocessor's directive */ -#define U '4' /* #undef preprocessor's directive */ - -/* stupid C lexical analyser for sources */ -static void c_lex_src(const char *fname, long fsize) -{ - int c; - int state; - int line; - char *id = id_s; - size_t id_len = 0; /* stupid initialization */ - unsigned char *optr, *oend; - - int fd; - char *map; - int mapsize; - - if(fsize == 0) { - fprintf(stderr, "Warning: %s is empty\n", fname); - return; - } - fd = open(fname, O_RDONLY); - if(fd < 0) { - perror(fname); - return; - } - mapsize = (fsize+pagesizem1) & ~pagesizem1; - map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); - if ((long) map == -1) - bb_error_d("%s: mmap: %m", fname); - - optr = (unsigned char *)map; - oend = optr + fsize; - - line = 1; - state = S; - - for(;;) { - getc1(); - for(;;) { - /* [ \t]+ eat first space */ - while(c == ' ' || c == '\t') - getc1(); - - if(state == S) { - while(first_chars[c] == ANY) { - /* <S>unparsed */ - if(c == '\n') - line++; - getc1(); - } - if(c == L_EOF) { - /* <S><<EOF>> */ - munmap(map, mapsize); - close(fd); - return; - } - if(c == REM) { - /* <S>/ */ - getc0(); - if(c == REM) { - /* <S>"//"[^\n]* */ - do getc0(); while(c != '\n' && c != L_EOF); - } else if(c == '*') { - /* <S>[/][*] goto parse block comments */ - break; - } - } else if(c == POUND) { - /* <S># */ - state = c; - getc1(); - } else if(c == STR || c == CHR) { - /* <S>\"|\' */ - int qc = c; - - for(;;) { - /* <STR,CHR>. */ - getc1(); - if(c == qc) { - /* <STR>\" or <CHR>\' */ - break; - } - if(c == BS) { - /* <STR,CHR>\\ but is not <STR,CHR>\\\n */ - getc0(); - } - if(c == '\n' || c == L_EOF) - yy_error_d("unterminated"); - } - getc1(); - } else { - /* <S>[A-Z_a-z0-9] */ - - /* trick for fast drop id - if key with this first char undefined */ - if(first_chars[c] == 0) { - /* skip <S>[A-Z_a-z0-9]+ */ - do getc1(); while(isalnums[c]); - } else { - id_len = 0; - do { - /* <S>[A-Z_a-z0-9]+ */ - put_id(c); - getc1(); - } while(isalnums[c]); - check_key(key_top, id, id_len); - } - } - continue; - } - /* begin preprocessor states */ - if(c == L_EOF) - yy_error_d("unexpected EOF"); - if(c == REM) { - /* <#.*>/ */ - getc0(); - if(c == REM) - yy_error_d("detected // in preprocessor line"); - if(c == '*') { - /* <#.*>[/][*] goto parse block comments */ - break; - } - /* hmm, #.*[/] */ - yy_error_d("strange preprocessor line"); - } - if(state == POUND) { - /* tricks */ - static const char * const p_preproc[] = { - /* 0 1 2 3 4 5 6 */ - "", "", "", "", "ndef", "efine", "nclude" - }; - size_t diu = first_chars_diu[c]; /* strlen and p_preproc ptr */ - - state = S; - if(diu != S) { - getc1(); - id_len = 0; - while(isalnums[c]) { - put_id(c); - getc1(); - } - /* str begins with c, read == strlen key and compared */ - if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) { - state = diu + '0'; - id_len = 0; /* common for save */ - } - } else { - while(isalnums[c]) getc1(); - } - } else if(state == I) { - if(c == STR) { - /* <I>\" */ - for(;;) { - getc1(); - if(c == STR) - break; - if(c == L_EOF) - yy_error_d("unexpected EOF"); - put_id(c); - } - put_id(0); - /* store "include.h" */ - parse_inc(id, fname); - getc1(); - } - /* else another (may be wrong) #include ... */ - state = S; - } else /* if(state == D || state == U) */ { - /* ignore depend with #define or #undef KEY */ - while(isalnums[c]) getc1(); - state = S; - } - } - - /* <REM> */ - getc0(); - for(;;) { - /* <REM>[^*]+ */ - while(c != '*') { - if(c == '\n') { - /* <REM>\n */ - if(state != S) - yy_error_d("unexpected newline"); - line++; - } else if(c == L_EOF) - yy_error_d("unexpected EOF"); - getc0(); - } - /* <REM>[*] */ - getc0(); - if(c == REM) { - /* <REM>[*][/] */ - break; - } - } - } -too_long: - yy_error_d("phrase too long"); -} - - -/* bb_simplify_path special variant for absolute pathname */ -static size_t bb_qa_simplify_path(char *path) -{ - char *s, *p; - - p = s = path; - - 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 > path) { - while (*--p != '/'); /* omit previous dir */ - } - continue; - } - } - } - *++p = *s; - } while (*++s); - - if ((p == path) || (*p != '/')) { /* not a trailing slash */ - ++p; /* so keep last character */ - } - *p = 0; - - return (p - path); -} - -static void parse_inc(const char *include, const char *fname) -{ - bb_key_t *cur; - const char *p_i; - llist_t *lo; - char *ap; - size_t key_sz; - struct stat st; - - if(*include == '/') { - lo = NULL; - ap = bb_xstrdup(include); - } else { - int w; - const char *p; - - lo = Iop; - p = strrchr(fname, '/'); /* fname has absolute pathname */ - w = (p-fname); - /* find from current directory of source file */ - ap = bb_asprint("%.*s/%s", w, fname, include); - } - - for(;;) { - key_sz = bb_qa_simplify_path(ap); - cur = check_key(Ifound, ap, key_sz); - if(cur) { - cur->checked = cur->value; - free(ap); - return; - } - if(stat(ap, &st) == 0) { - /* found */ - llist_t *cfl; - - for(cfl = configs; cfl; cfl = cfl->link) { - struct stat *config = (struct stat *)cfl->data; - - if (st.st_dev == config->st_dev && st.st_ino == config->st_ino) { - /* skip depend with bb_configs.h */ - return; - } - } - p_i = ap; - break; - } else if(lo == NULL) { - p_i = NULL; - break; - } - - /* find from "-I include" specified directories */ - free(ap); - /* lo->data has absolute pathname */ - ap = bb_asprint("%s/%s", lo->data, include); - lo = lo->link; - } - - cur = xmalloc(sizeof(bb_key_t)); - cur->keyname = ap; - cur->key_sz = key_sz; - cur->stored_path = ap; - cur->value = cur->checked = p_i; - if(p_i == NULL && noiwarning) - fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include); - cur->next = Ifound; - Ifound = cur; -} - -static size_t max_rec_sz; - -static void parse_conf_opt(const char *opt, const char *val, size_t key_sz) -{ - bb_key_t *cur; - char *k; - char *p; - size_t val_sz = 0; - - cur = check_key(key_top, opt, key_sz); - if(cur != NULL) { - /* already present */ - cur->checked = NULL; /* store only */ - if(cur->value == NULL && val == NULL) - return; - if(cur->value != NULL && val != NULL && !strcmp(cur->value, val)) - return; - k = cur->keyname; - fprintf(stderr, "Warning: redefined %s\n", k); - } else { - size_t recordsz; - - if(val && *val) - val_sz = strlen(val) + 1; - recordsz = key_sz + val_sz + 1; - if(max_rec_sz < recordsz) - max_rec_sz = recordsz; - cur = xmalloc(sizeof(bb_key_t) + recordsz); - k = cur->keyname = memcpy(cur + 1, opt, key_sz); - cur->keyname[key_sz] = '\0'; - cur->key_sz = key_sz; - cur->checked = NULL; - cur->src_have_this_key = NULL; - cur->next = key_top; - key_top = cur; - } - /* save VAL */ - if(val) { - if(*val == '\0') { - cur->value = ""; - } else { - cur->value = p = cur->keyname + key_sz + 1; - memcpy(p, val, val_sz); - } - } else { - cur->value = NULL; - } - /* trick, save first char KEY for do fast identify id */ - first_chars[(int)*k] = *k; - - cur->stored_path = k = bb_asprint("%s/%s.h", kp, k); - /* key conversion [A-Z_] -> [a-z/] */ - for(p = k + kp_len + 1; *p; p++) { - if(*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - else if(*p == '_' && p[1] > '9') /* do not change A_1 to A/1 */ - *p = '/'; - } -} - -static void store_keys(void) -{ - bb_key_t *cur; - char *k; - struct stat st; - int cmp_ok; - ssize_t rw_ret; - size_t recordsz = max_rec_sz * 2 + 10 * 2 + 16; - /* buffer for double "#define KEY VAL\n" */ - char *record_buf = xmalloc(recordsz); - - for(cur = key_top; cur; cur = cur->next) { - if(cur->src_have_this_key) { - /* do generate record */ - k = cur->keyname; - if(cur->value == NULL) { - recordsz = sprintf(record_buf, "#undef %s\n", k); - } else { - const char *val = cur->value; - if(*val == '\0') { - recordsz = sprintf(record_buf, "#define %s\n", k); - } else { - if(val[0] != '(') - recordsz = sprintf(record_buf, "#define %s %s\n", k, val); - else - recordsz = sprintf(record_buf, "#define %s%s\n", k, val); - } - } - /* size_t -> ssize_t :( */ - rw_ret = (ssize_t)recordsz; - /* check kp/key.h, compare after previous use */ - cmp_ok = 0; - k = cur->stored_path; - if(stat(k, &st)) { - char *p; - for(p = k + kp_len + 1; *p; p++) { - /* Auto-create directories. */ - if (*p == '/') { - *p = '\0'; - if (access(k, F_OK) != 0 && mkdir(k, 0755) != 0) - bb_error_d("mkdir(%s): %m", k); - *p = '/'; - } - } - } else { - /* found */ - if(st.st_size == (off_t)recordsz) { - char *r_cmp; - int fd; - size_t padded = recordsz; - - /* 16-byte padding for read(2) and memcmp(3) */ - padded = (padded+15) & ~15; - r_cmp = record_buf + padded; - fd = open(k, O_RDONLY); - if(fd < 0 || read(fd, r_cmp, recordsz) < rw_ret) - bb_error_d("%s: %m", k); - close(fd); - cmp_ok = memcmp(record_buf, r_cmp, recordsz) == 0; - } - } - if(!cmp_ok) { - int fd = open(k, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if(fd < 0 || write(fd, record_buf, recordsz) < rw_ret) - bb_error_d("%s: %m", k); - close(fd); - } - } - } -} - -static int show_dep(int first, bb_key_t *k, const char *name, const char *f) -{ - bb_key_t *cur; - - for(cur = k; cur; cur = cur->next) { - if(cur->checked) { - if(first >= 0) { - if(first) { - if(f == NULL) - printf("\n%s:", name); - else - printf("\n%s/%s:", pwd, name); - first = 0; - } else { - printf(" \\\n "); - } - printf(" %s", cur->checked); - } - cur->src_have_this_key = cur->checked; - cur->checked = NULL; - } - } - return first; -} - -static char * -parse_chd(const char *fe, const char *p, size_t dirlen) -{ - struct stat st; - char *fp; - size_t df_sz; - static char dir_and_entry[4096]; - size_t fe_sz = strlen(fe) + 1; - - df_sz = dirlen + fe_sz + 1; /* dir/file\0 */ - if(df_sz > sizeof(dir_and_entry)) - bb_error_d("%s: file name too long", fe); - fp = dir_and_entry; - /* sprintf(fp, "%s/%s", p, fe); */ - memcpy(fp, p, dirlen); - fp[dirlen] = '/'; - memcpy(fp + dirlen + 1, fe, fe_sz); - - if(stat(fp, &st)) { - fprintf(stderr, "Warning: stat(%s): %m\n", fp); - return NULL; - } - if(S_ISREG(st.st_mode)) { - llist_t *cfl; - char *e = fp + df_sz - 3; - - if(*e++ != '.' || (*e != 'c' && *e != 'h')) { - /* direntry is regular file, but is not *.[ch] */ - return NULL; - } - for(cfl = configs; cfl; cfl = cfl->link) { - struct stat *config = (struct stat *)cfl->data; - - if (st.st_dev == config->st_dev && st.st_ino == config->st_ino) { - /* skip already parsed bb_configs.h */ - return NULL; - } - } - /* direntry is *.[ch] regular file and is not configs */ - c_lex_src(fp, st.st_size); - if(!dontgenerate_dep) { - int first; - if(*e == 'c') { - /* *.c -> *.o */ - *e = 'o'; - /* /src_dir/path/file.o to path/file.o */ - fp += replace; - if(*fp == '/') - fp++; - } else { - e = NULL; - } - first = show_dep(1, Ifound, fp, e); - first = show_dep(first, key_top, fp, e); - if(first == 0) - putchar('\n'); - } else { - show_dep(-1, key_top, NULL, NULL); - } - return NULL; - } else if(S_ISDIR(st.st_mode)) { - if (st.st_dev == st_kp.st_dev && st.st_ino == st_kp.st_ino) - return NULL; /* drop scan kp/ directory */ - /* direntry is directory. buff is returned */ - return bb_xstrdup(fp); - } - /* hmm, direntry is device! */ - return NULL; -} - -/* from libbb but inlined for speed considerations */ -static inline 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); -} - -static void scan_dir_find_ch_files(const char *p) -{ - llist_t *dirs; - llist_t *d_add; - llist_t *d; - struct dirent *de; - DIR *dir; - size_t dirlen; - - dirs = llist_add_to(NULL, bb_simplify_path(p)); - replace = strlen(dirs->data); - /* emulate recursion */ - while(dirs) { - d_add = NULL; - while(dirs) { - dir = opendir(dirs->data); - if (dir == NULL) - fprintf(stderr, "Warning: opendir(%s): %m\n", dirs->data); - dirlen = strlen(dirs->data); - while ((de = readdir(dir)) != NULL) { - char *found_dir; - - if (de->d_name[0] == '.') - continue; - found_dir = parse_chd(de->d_name, dirs->data, dirlen); - if(found_dir) - d_add = llist_add_to(d_add, found_dir); - } - closedir(dir); - free(dirs->data); - d = dirs; - dirs = dirs->link; - free(d); - } - dirs = d_add; - } -} - -static void show_usage(void) ATTRIBUTE ((noreturn)); -static void show_usage(void) -{ - bb_error_d("%s\n%s\n", bb_mkdep_terse_options, bb_mkdep_full_options); -} - -int main(int argc, char **argv) -{ - char *s; - int i; - llist_t *fl; - - { - /* for bb_simplify_path, this program has no chdir() */ - /* libbb-like my xgetcwd() */ - unsigned path_max = 512; - - s = xmalloc (path_max); - while (getcwd (s, path_max) == NULL) { - if(errno != ERANGE) - bb_error_d("getcwd: %m"); - free(s); - s = xmalloc(path_max *= 2); - } - pwd = s; - } - - while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) { - switch(i) { - case 'I': - s = bb_simplify_path(optarg); - Iop = llist_add_to(Iop, s); - break; - case 'c': - s = bb_simplify_path(optarg); - configs = llist_add_to(configs, s); - break; - case 'd': - dontgenerate_dep = 1; - 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(); - } - } - /* default kp */ - if(kp == NULL) - kp = bb_simplify_path(INCLUDE_CONFIG_PATH); - /* globals initialize */ - kp_len = strlen(kp); - if(stat(kp, &st_kp)) - bb_error_d("stat(%s): %m", kp); - if(!S_ISDIR(st_kp.st_mode)) - bb_error_d("%s is not directory", kp); - /* defaults */ - if(Iop == NULL) - Iop = llist_add_to(Iop, bb_simplify_path(LOCAL_INCLUDE_PATH)); - if(configs == NULL) { - s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH); - configs = llist_add_to(configs, s); - } - /* for c_lex */ - pagesizem1 = getpagesize() - 1; - for(i = 0; i < UCHAR_MAX; i++) { - if(ISALNUM(i)) - isalnums[i] = i; - /* set unparsed chars to speed up the parser */ - else if(i != CHR && i != STR && i != POUND && i != REM) - first_chars[i] = ANY; - } - first_chars[i] = '-'; /* L_EOF */ - - /* parse configs */ - for(fl = configs; fl; fl = fl->link) { - struct stat st; - - if(stat(fl->data, &st)) - bb_error_d("stat(%s): %m", fl->data); - c_lex_config(fl->data, st.st_size); - free(fl->data); - /* trick for fast comparing found files with configs */ - fl->data = xmalloc(sizeof(struct stat)); - memcpy(fl->data, &st, sizeof(struct stat)); - } - - /* main loop */ - argv += optind; - if(*argv) { - while(*argv) - scan_dir_find_ch_files(*argv++); - } else { - scan_dir_find_ch_files("."); - } - store_keys(); - return 0; -} - -/* partial and simplified libbb routine */ -static 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); -} - -static char *bb_asprint(const char *format, ...) -{ - va_list p; - int r; - char *out; - -#ifdef __USE_GNU - va_start(p, format); - r = vasprintf(&out, format, p); - va_end(p); -#else - out = xmalloc(BUFSIZ); - va_start(p, format); - r = vsprintf(out, format, p); - va_end(p); -#endif - - if (r < 0) - bb_error_d("bb_asprint: %m"); - return out; -} - -/* partial libbb routine as is */ - -static char *bb_simplify_path(const char *path) -{ - char *s, *start, *p; - - if (path[0] == '/') - start = bb_xstrdup(path); - else { - /* is not libbb, but this program has no chdir() */ - 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; -} |