source: MondoRescue/branches/stable/mindi-busybox/scripts/bb_mkdep.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 42.9 KB
Line 
1/*
2 * Another fast dependencies generator for Makefiles, Version 4.2
3 *
4 * Copyright (C) 2005,2006 by Vladimir Oleynik <dzo@simtreas.ru>
5 *
6 * mmaping file may be originally by Linus Torvalds.
7 *
8 * infix parser/evaluator for #if expression
9 *      Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
10 *      Copyright (c) 2001 Manuel Novoa III <mjn3@codepoet.org>
11 *      Copyright (c) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12 *
13 * bb_simplify_path()
14 *      Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
15 *
16 * xmalloc() bb_xstrdup() bb_error_d():
17 *      Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
18 *
19 * llist routine
20 *      Copyright (C) 2003 Glenn McGrath
21 *      Copyright (C) Vladimir Oleynik <dzo@simtreas.ru>
22 *
23 * (c) 2005,2006 Bernhard Fischer:
24 *  - commentary typos,
25 *  - move "memory exhausted" into msg_enomem,
26 *  - more verbose --help output.
27 *
28 * This program does:
29 * 1) find #define KEY VALUE or #undef KEY from include/bb_config.h
30 * 2) recursive find and scan *.[ch] files, but skips scan of include/config/
31 * 3) find #include "*.h" and KEYs using, if not as #define and #undef
32 * 4) generate dependencies to stdout
33 *    pwd/file.o: include/config/key*.h found_include_*.h
34 *    path/inc.h: include/config/key*.h found_included_include_*.h
35 * 5) save include/config/key*.h if changed after previous usage
36 * This program does not generate dependencies for #include <...>
37 * Config file can have #if #elif #else #ifdef #ifndef #endif lines
38 */
39
40#define LOCAL_INCLUDE_PATH          "include"
41#define INCLUDE_CONFIG_PATH         LOCAL_INCLUDE_PATH"/config"
42#define INCLUDE_CONFIG_KEYS_PATH    LOCAL_INCLUDE_PATH"/bb_config.h"
43
44#define bb_mkdep_full_options \
45"\nOptions:" \
46"\n\t-I local_include_path  include paths, default: \"" LOCAL_INCLUDE_PATH "\"" \
47"\n\t-d                     don't generate depend" \
48"\n\t-w                     show warning if include files not found" \
49"\n\t-k include/config      default: \"" INCLUDE_CONFIG_PATH "\"" \
50"\n\t-c include/config.h    configs, default: \"" INCLUDE_CONFIG_KEYS_PATH "\"" \
51"\n\tdirs_to_scan           default \".\""
52
53#define bb_mkdep_terse_options "Usage: [-I local_include_paths] [-dw] " \
54           "[-k path_for_stored_keys] [dirs]"
55
56
57#define _GNU_SOURCE
58#include <sys/types.h>
59#include <sys/stat.h>
60#include <sys/mman.h>
61#include <getopt.h>
62#include <dirent.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include <stdarg.h>
67#include <unistd.h>
68#include <errno.h>
69#include <fcntl.h>
70#include <limits.h>
71
72#ifdef __GNUC__
73#define ATTRIBUTE __attribute__
74#else
75#define ATTRIBUTE(a) /* nothing */
76#endif
77
78#if !(defined __USE_ISOC99 || (defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC))
79#define strtoll strtol
80#endif
81
82/* partial and simplified libbb routine */
83static void bb_error_d(const char *s, ...) ATTRIBUTE ((noreturn, format (printf, 1, 2)));
84static char * bb_asprint(const char *format, ...) ATTRIBUTE ((format (printf, 1, 2)));
85static char *bb_simplify_path(const char *path);
86
87/* stolen from libbb as is */
88typedef struct llist_s {
89    char *data;
90    struct llist_s *link;
91} llist_t;
92
93static const char msg_enomem[] = "memory exhausted";
94
95/* inline realization for fast works */
96static inline void *xmalloc(size_t size)
97{
98    void *p = malloc(size);
99
100    if(p == NULL)
101        bb_error_d(msg_enomem);
102    return p;
103}
104
105static inline char *bb_xstrdup(const char *s)
106{
107    char *r = strdup(s);
108
109    if(r == NULL)
110        bb_error_d(msg_enomem);
111    return r;
112}
113
114
115static int dontgenerate_dep;    /* flag -d usaged */
116static int noiwarning;          /* flag -w usaged */
117static llist_t *configs;    /* list of -c usaged and them stat() after parsed */
118static llist_t *Iop;        /* list of -I include usaged */
119
120static char *pwd;           /* current work directory */
121static size_t replace;      /* replace current work directory with build dir */
122
123static const char *kp;      /* KEY path, argument of -k used */
124static size_t kp_len;
125static struct stat st_kp;   /* stat(kp) */
126
127typedef struct BB_KEYS {
128    char *keyname;
129    size_t key_sz;
130    const char *value;
131    const char *checked;
132    char *stored_path;
133    const char *src_have_this_key;
134    struct BB_KEYS *next;
135} bb_key_t;
136
137static bb_key_t *key_top;   /* list of found KEYs */
138static bb_key_t *Ifound;    /* list of parsed includes */
139
140
141static void parse_conf_opt(const char *opt, const char *val, size_t key_sz);
142static void parse_inc(const char *include, const char *fname);
143
144static inline bb_key_t *check_key(bb_key_t *k, const char *nk, size_t key_sz)
145{
146    bb_key_t *cur;
147
148    for(cur = k; cur; cur = cur->next) {
149    if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) {
150        cur->checked = cur->stored_path;
151        return cur;
152    }
153    }
154    return NULL;
155}
156
157static inline const char *lookup_key(const char *nk, size_t key_sz)
158{
159    bb_key_t *cur;
160
161    for(cur = key_top; cur; cur = cur->next) {
162    if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) {
163        return cur->value;
164    }
165    }
166    return NULL;
167}
168
169/* for lexical analyser */
170static int pagesizem1;      /* padding mask = getpagesize() - 1 */
171
172/* for speed tricks */
173static char first_chars[1+UCHAR_MAX];               /* + L_EOF */
174static char isalnums[1+UCHAR_MAX];                  /* + L_EOF */
175
176/* trick for fast find "define", "include", "undef",
177"if((n)def)" "else", "endif"  */
178static const char * const preproc[] = {
179/* 0   1       2      3       4     5       6        7         8      9 */
180"", "efine", "lif", "lse", "ndif", "f", "fdef", "fndef", "nclude", "ndef" };
181static const unsigned char first_chars_deiu[UCHAR_MAX] = {
182    [(int)'d'] = (unsigned char)(1|0x10),     /* define */
183    [(int)'e'] = (unsigned char)(2|0x40),     /* elif, else, endif  */
184    [(int)'i'] = (unsigned char)(5|0x80),     /* if ifdef ifndef include */
185    [(int)'u'] = (unsigned char)(9|0x90),     /* undef */
186};
187
188#define CONFIG_MODE  0
189#define IF0_MODE     1  /* #if 0  */
190#define IF1_MODE     2  /* #if 1 */
191#define ELSE0_MODE   4  /* #else found after #if 0 */
192#define ELSE1_MODE   8  /* #else found after #if 1 */
193#define ELIF1_MODE   16 /* #elif found after #if 1 */
194#define FALSE_MODES  (IF0_MODE|ELSE1_MODE|ELIF1_MODE)
195
196#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
197
198/* state */
199#define S      0        /* start state */
200#define STR    '"'      /* string */
201#define CHR    '\''     /* char */
202#define REM    '/'      /* block comment */
203#define BS     '\\'     /* back slash */
204#define POUND  '#'      /* # */
205#define D      '1'      /* #define preprocessor's directive */
206#define EI     '2'      /* #elif preprocessor's directive */
207#define E      '3'      /* #else preprocessor's directive */
208#define EF     '4'      /* #endif preprocessor's directive */
209#define F      '5'      /* #if preprocessor's directive */
210#define IFD    '6'      /* #ifdef preprocessor's directive */
211#define IFND   '7'      /* #ifndef preprocessor's directive */
212#define I      '8'      /* #include preprocessor's directive */
213#define U      '9'      /* #undef preprocessor's directive */
214#define DK     'K'      /* #define KEY... (config mode) */
215#define ANY    '*'      /* any unparsed chars */
216
217/* [A-Z_a-z] */
218#define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
219/* [A-Z_a-z0-9] */
220#define ISALNUM(c)  (ID(c) || (c >= '0' && c <= '9'))
221
222#define L_EOF  (1+UCHAR_MAX)
223
224#define getc0()     do { c = (optr >= oend) ? L_EOF : *optr++; } while(0)
225
226#define getc1()     do { getc0(); if(c == BS) { getc0(); \
227                    if(c == '\n') { line++; continue; } \
228                    else { optr--; c = BS; } \
229                  } break; } while(1)
230
231static char id_s[4096];
232#define put_id(ic)  do {    if(id_len == sizeof(id_s)) goto too_long; \
233                id[id_len++] = ic; } while(0)
234
235static char ifcpp_stack[1024];
236static int  ptr_ifcpp_stack;
237#define push_mode() do { \
238            if(ptr_ifcpp_stack == (int)sizeof(ifcpp_stack)) \
239                yy_error_d("#if* stack overflow"); \
240            ifcpp_stack[ptr_ifcpp_stack++] = (char)mode; \
241            } while(0)
242
243#define pop_mode()  do { \
244            if(ptr_ifcpp_stack == 0) \
245                yy_error_d("unexpected #endif"); \
246            mode = ifcpp_stack[--ptr_ifcpp_stack]; \
247            } while(0)
248
249/* #if expression */
250typedef long long arith_t;
251
252static arith_t arith (const char *expr, int *perrcode);
253
254/* The code uses a simple two-stack algorithm. See
255 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
256 * for a detailed explanation of the infix-to-postfix algorithm on which
257 * this is based (this code differs in that it applies operators immediately
258 * to the stack instead of adding them to a queue to end up with an
259 * expression). */
260
261#define arith_isspace(arithval) \
262    (arithval == ' ' || arithval == '\v' || arithval == '\t' || arithval == '\f')
263
264
265typedef unsigned char operator;
266
267/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
268 * precedence, and 3 high bits are an ID unique across operators of that
269 * precedence. The ID portion is so that multiple operators can have the
270 * same precedence, ensuring that the leftmost one is evaluated first.
271 * Consider * and /. */
272
273#define tok_decl(prec,id) (((id)<<5)|(prec))
274#define PREC(op) ((op) & 0x1F)
275
276#define TOK_LPAREN tok_decl(0,0)
277
278#define TOK_COMMA tok_decl(1,0)
279
280/* conditional is right associativity too */
281#define TOK_CONDITIONAL tok_decl(2,0)
282#define TOK_CONDITIONAL_SEP tok_decl(2,1)
283
284#define TOK_OR tok_decl(3,0)
285
286#define TOK_AND tok_decl(4,0)
287
288#define TOK_BOR tok_decl(5,0)
289
290#define TOK_BXOR tok_decl(6,0)
291
292#define TOK_BAND tok_decl(7,0)
293
294#define TOK_EQ tok_decl(8,0)
295#define TOK_NE tok_decl(8,1)
296
297#define TOK_LT tok_decl(9,0)
298#define TOK_GT tok_decl(9,1)
299#define TOK_GE tok_decl(9,2)
300#define TOK_LE tok_decl(9,3)
301
302#define TOK_LSHIFT tok_decl(10,0)
303#define TOK_RSHIFT tok_decl(10,1)
304
305#define TOK_ADD tok_decl(11,0)
306#define TOK_SUB tok_decl(11,1)
307
308#define TOK_MUL tok_decl(12,0)
309#define TOK_DIV tok_decl(12,1)
310#define TOK_REM tok_decl(12,2)
311
312/* For now unary operators. */
313#define UNARYPREC 13
314#define TOK_BNOT tok_decl(UNARYPREC,0)
315#define TOK_NOT tok_decl(UNARYPREC,1)
316
317#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
318#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
319
320#define SPEC_PREC (UNARYPREC+2)
321
322#define TOK_NUM tok_decl(SPEC_PREC, 0)
323#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
324
325#define NUMPTR (*numstackptr)
326
327typedef struct ARITCH_VAR_NUM {
328    arith_t val;
329    arith_t contidional_second_val;
330    char contidional_second_val_initialized;
331} v_n_t;
332
333
334typedef struct CHK_VAR_RECURSIVE_LOOPED {
335    const char *var;
336    size_t var_sz;
337    struct CHK_VAR_RECURSIVE_LOOPED *next;
338} chk_var_recursive_looped_t;
339
340static chk_var_recursive_looped_t *prev_chk_var_recursive;
341
342
343static int arith_lookup_val(const char *var, size_t key_sz, arith_t *pval)
344{
345    const char * p = lookup_key(var, key_sz);
346
347    if(p) {
348    int errcode;
349
350    /* recursive try as expression */
351    chk_var_recursive_looped_t *cur;
352    chk_var_recursive_looped_t cur_save;
353
354    for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
355        if(cur->var_sz == key_sz && memcmp(cur->var, var, key_sz) == 0) {
356        /* expression recursion loop detected */
357        return -5;
358        }
359    }
360    /* save current lookuped var name */
361    cur = prev_chk_var_recursive;
362    cur_save.var = var;
363    cur_save.var_sz = key_sz;
364    cur_save.next = cur;
365    prev_chk_var_recursive = &cur_save;
366
367    *pval = arith (p, &errcode);
368    /* restore previous ptr after recursiving */
369    prev_chk_var_recursive = cur;
370    return errcode;
371    } else {
372    /* disallow undefined var */
373    fprintf(stderr, "%.*s ", (int)key_sz, var);
374    return -4;
375    }
376}
377
378/* "applying" a token means performing it on the top elements on the integer
379 * stack. For a unary operator it will only change the top element, but a
380 * binary operator will pop two arguments and push a result */
381static inline int
382arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
383{
384    v_n_t *numptr_m1;
385    arith_t numptr_val, rez;
386
387    if (NUMPTR == numstack) goto err; /* There is no operator that can work
388                                         without arguments */
389    numptr_m1 = NUMPTR - 1;
390
391    rez = numptr_m1->val;
392    if (op == TOK_UMINUS)
393        rez *= -1;
394    else if (op == TOK_NOT)
395        rez = !rez;
396    else if (op == TOK_BNOT)
397        rez = ~rez;
398    else if (op != TOK_UPLUS) {
399        /* Binary operators */
400
401        /* check and binary operators need two arguments */
402        if (numptr_m1 == numstack) goto err;
403
404        /* ... and they pop one */
405        --NUMPTR;
406        numptr_val = rez;
407        if (op == TOK_CONDITIONAL) {
408        if(! numptr_m1->contidional_second_val_initialized) {
409            /* protect $((expr1 ? expr2)) without ": expr" */
410            goto err;
411        }
412        rez = numptr_m1->contidional_second_val;
413        } else if(numptr_m1->contidional_second_val_initialized) {
414            /* protect $((expr1 : expr2)) without "expr ? " */
415            goto err;
416        }
417        numptr_m1 = NUMPTR - 1;
418        if (op == TOK_CONDITIONAL) {
419            numptr_m1->contidional_second_val = rez;
420        }
421        rez = numptr_m1->val;
422        if (op == TOK_BOR)
423            rez |= numptr_val;
424        else if (op == TOK_OR)
425            rez = numptr_val || rez;
426        else if (op == TOK_BAND)
427            rez &= numptr_val;
428        else if (op == TOK_BXOR)
429            rez ^= numptr_val;
430        else if (op == TOK_AND)
431            rez = rez && numptr_val;
432        else if (op == TOK_EQ)
433            rez = (rez == numptr_val);
434        else if (op == TOK_NE)
435            rez = (rez != numptr_val);
436        else if (op == TOK_GE)
437            rez = (rez >= numptr_val);
438        else if (op == TOK_RSHIFT)
439            rez >>= numptr_val;
440        else if (op == TOK_LSHIFT)
441            rez <<= numptr_val;
442        else if (op == TOK_GT)
443            rez = (rez > numptr_val);
444        else if (op == TOK_LT)
445            rez = (rez < numptr_val);
446        else if (op == TOK_LE)
447            rez = (rez <= numptr_val);
448        else if (op == TOK_MUL)
449            rez *= numptr_val;
450        else if (op == TOK_ADD)
451            rez += numptr_val;
452        else if (op == TOK_SUB)
453            rez -= numptr_val;
454        else if (op == TOK_COMMA)
455            rez = numptr_val;
456        else if (op == TOK_CONDITIONAL_SEP) {
457            if (numptr_m1 == numstack) {
458                /* protect $((expr : expr)) without "expr ? " */
459                goto err;
460            }
461            numptr_m1->contidional_second_val_initialized = op;
462            numptr_m1->contidional_second_val = numptr_val;
463        }
464        else if (op == TOK_CONDITIONAL) {
465            rez = rez ?
466                  numptr_val : numptr_m1->contidional_second_val;
467        }
468        else if(numptr_val==0)          /* zero divisor check */
469            return -2;
470        else if (op == TOK_DIV)
471            rez /= numptr_val;
472        else if (op == TOK_REM)
473            rez %= numptr_val;
474    }
475    numptr_m1->val = rez;
476    return 0;
477err: return(-1);
478}
479
480/* longest must first */
481static const char op_tokens[] = {
482    '<','<',    0, TOK_LSHIFT,
483    '>','>',    0, TOK_RSHIFT,
484    '|','|',    0, TOK_OR,
485    '&','&',    0, TOK_AND,
486    '!','=',    0, TOK_NE,
487    '<','=',    0, TOK_LE,
488    '>','=',    0, TOK_GE,
489    '=','=',    0, TOK_EQ,
490    '!',        0, TOK_NOT,
491    '<',        0, TOK_LT,
492    '>',        0, TOK_GT,
493    '|',        0, TOK_BOR,
494    '&',        0, TOK_BAND,
495    '*',        0, TOK_MUL,
496    '/',        0, TOK_DIV,
497    '%',        0, TOK_REM,
498    '+',        0, TOK_ADD,
499    '-',        0, TOK_SUB,
500    '^',        0, TOK_BXOR,
501    '~',        0, TOK_BNOT,
502    ',',        0, TOK_COMMA,
503    '?',        0, TOK_CONDITIONAL,
504    ':',        0, TOK_CONDITIONAL_SEP,
505    ')',        0, TOK_RPAREN,
506    '(',        0, TOK_LPAREN,
507    0
508};
509/* ptr to ")" */
510#define endexpression &op_tokens[sizeof(op_tokens)-7]
511
512/*
513 * Return of a legal variable name (a letter or underscore followed by zero or
514 * more letters, underscores, and digits).
515 */
516
517static inline char *
518endofname(const char *name)
519{
520    char *p;
521
522    p = (char *) name;
523    if (! ID(*p))
524        return p;
525    while (*++p) {
526        if (! ISALNUM(*p))
527            break;
528    }
529    return p;
530}
531
532
533static arith_t arith (const char *expr, int *perrcode)
534{
535    char arithval;          /* Current character under analysis */
536    operator lasttok, op;
537    operator prec;
538
539    const char *p = endexpression;
540    int errcode;
541
542    size_t datasizes = strlen(expr) + 2;
543
544    /* Stack of integers */
545    /* The proof that there can be no more than strlen(startbuf)/2+1 integers
546     * in any given correct or incorrect expression is left as an exercise to
547     * the reader. */
548    v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
549        *numstackptr = numstack;
550    /* Stack of operator tokens */
551    operator *stack = alloca((datasizes) * sizeof(operator)),
552        *stackptr = stack;
553
554    *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
555    *perrcode = errcode = 0;
556
557    while(1) {
558    if ((arithval = *expr) == 0) {
559        if (p == endexpression) {
560            /* Null expression. */
561err:
562            return (*perrcode = -1);
563        }
564
565        /* This is only reached after all tokens have been extracted from the
566         * input stream. If there are still tokens on the operator stack, they
567         * are to be applied in order. At the end, there should be a final
568         * result on the integer stack */
569
570        if (expr != endexpression + 1) {
571            /* If we haven't done so already, */
572            /* append a closing right paren */
573            expr = endexpression;
574            /* and let the loop process it. */
575            continue;
576        }
577        /* At this point, we're done with the expression. */
578        if (numstackptr != numstack+1) {
579            /* ... but if there isn't, it's bad */
580            goto err;
581        }
582    ret:
583        *perrcode = errcode;
584        return numstack->val;
585    } else {
586        /* Continue processing the expression. */
587        if (arith_isspace(arithval)) {
588            /* Skip whitespace */
589            goto prologue;
590        }
591        if((p = endofname(expr)) != expr) {
592            size_t var_name_size = (p-expr);
593
594            if(var_name_size == 7 &&
595                strncmp(expr, "defined", var_name_size) == 0) {
596                int brace_form = 0;
597                const char *v;
598
599                while(arith_isspace(*p)) p++;
600                if(*p == '(') {
601                p++;
602                while(arith_isspace(*p)) p++;
603                brace_form = 1;
604                }
605                expr = p;
606                if((p = endofname(expr)) == expr)
607                goto err;
608                var_name_size = (p-expr);
609                while(arith_isspace(*p)) p++;
610                if(brace_form && *p++ != ')')
611                goto err;
612                v = lookup_key(expr, var_name_size);
613                numstackptr->val = (v != NULL) ? 1 : 0;
614            } else {
615                errcode = arith_lookup_val(expr, var_name_size,
616                    &(numstackptr->val));
617                if(errcode) goto ret;
618            }
619            expr = p;
620        num:
621            numstackptr->contidional_second_val_initialized = 0;
622            numstackptr++;
623            lasttok = TOK_NUM;
624            continue;
625        } else if (arithval >= '0' && arithval <= '9') {
626            numstackptr->val = strtoll(expr, (char **) &expr, 0);
627            while(*expr == 'l' || *expr == 'L' || *expr == 'u' ||
628                                *expr == 'U')
629                expr++;
630            goto num;
631        }
632        for(p = op_tokens; ; p++) {
633            const char *o;
634
635            if(*p == 0) {
636                /* strange operator not found */
637                goto err;
638            }
639            for(o = expr; *p && *o == *p; p++)
640                o++;
641            if(! *p) {
642                /* found */
643                expr = o - 1;
644                break;
645            }
646            /* skip tail uncompared token */
647            while(*p)
648                p++;
649            /* skip zero delim */
650            p++;
651        }
652        op = p[1];
653
654        /* Plus and minus are binary (not unary) _only_ if the last
655         * token was as number, or a right paren (which pretends to be
656         * a number, since it evaluates to one). Think about it.
657         * It makes sense. */
658        if (lasttok != TOK_NUM) {
659            if(op == TOK_ADD)
660                op = TOK_UPLUS;
661            else if(op == TOK_SUB)
662                op = TOK_UMINUS;
663        }
664        /* We don't want a unary operator to cause recursive descent on the
665         * stack, because there can be many in a row and it could cause an
666         * operator to be evaluated before its argument is pushed onto the
667         * integer stack. */
668        /* But for binary operators, "apply" everything on the operator
669         * stack until we find an operator with a lesser priority than the
670         * one we have just extracted. */
671        /* Left paren is given the lowest priority so it will never be
672         * "applied" in this way.
673         * if associativity is right and priority eq, applied also skip
674         */
675        prec = PREC(op);
676        if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
677            /* not left paren or unary */
678            if (lasttok != TOK_NUM) {
679                /* binary op must be preceded by a num */
680                goto err;
681            }
682            while (stackptr != stack) {
683                if (op == TOK_RPAREN) {
684                /* The algorithm employed here is simple: while we don't
685                 * hit an open paren nor the bottom of the stack, pop
686                 * tokens and apply them */
687                if (stackptr[-1] == TOK_LPAREN) {
688                    --stackptr;
689                    /* Any operator directly after a */
690                    lasttok = TOK_NUM;
691                    /* close paren should consider itself binary */
692                    goto prologue;
693                }
694                } else {
695                operator prev_prec = PREC(stackptr[-1]);
696
697                if (prev_prec < prec)
698                    break;
699                /* check right assoc */
700                if(prev_prec == prec && prec == PREC(TOK_CONDITIONAL))
701                    break;
702                }
703                errcode = arith_apply(*--stackptr, numstack, &numstackptr);
704                if(errcode) goto ret;
705            }
706            if (op == TOK_RPAREN) {
707                goto err;
708            }
709        }
710
711        /* Push this operator to the stack and remember it. */
712        *stackptr++ = lasttok = op;
713
714      prologue:
715        ++expr;
716    }
717    }
718}
719
720/* stupid C lexical analyser for configs.h */
721static void c_lex_config(const char *fname, long fsize)
722{
723  int c;
724  int state;
725  int line;
726  char *id = id_s;
727  size_t id_len = 0;                /* stupid initialization */
728  unsigned char *optr, *oend;
729  int mode = CONFIG_MODE;
730
731  int fd;
732  char *map;
733  int mapsize;
734
735  if(fsize == 0) {
736    fprintf(stderr, "Warning: %s is empty\n", fname);
737    return;
738  }
739  fd = open(fname, O_RDONLY);
740  if(fd < 0) {
741    perror(fname);
742    return;
743  }
744  mapsize = (fsize+pagesizem1) & ~pagesizem1;
745  map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
746  if ((long) map == -1)
747    bb_error_d("%s: mmap: %m", fname);
748
749  optr = (unsigned char *)map;
750  oend = optr + fsize;
751
752  line = 1;
753  state = S;
754
755  for(;;) {
756    getc1();
757    for(;;) {
758    /* [ \t]+ eat first space */
759    while(c == ' ' || c == '\t')
760        getc1();
761
762    if(state == S) {
763        while(first_chars[c] == ANY) {
764            /* <S>unparsed */
765            if(c == '\n')
766            line++;
767            getc1();
768        }
769        if(c == L_EOF) {
770            /* <S><<EOF>> */
771            munmap(map, mapsize);
772            close(fd);
773            if(mode != CONFIG_MODE)
774                yy_error_d("expected #endif");
775            return;
776        }
777        if(c == REM) {
778            /* <S>/ */
779            getc0();
780            if(c == REM) {
781                /* <S>"//"[^\n]* */
782                do getc0(); while(c != '\n' && c != L_EOF);
783            } else if(c == '*') {
784                /* <S>[/][*] goto parse block comments */
785                break;
786            }
787        } else if(c == POUND) {
788            /* <S># */
789            state = c;
790            getc1();
791        } else if(c == STR || c == CHR) {
792            /* <S>\"|\' */
793            int qc = c;
794
795            for(;;) {
796                /* <STR,CHR>. */
797                getc1();
798                if(c == qc) {
799                /* <STR>\" or <CHR>\' */
800                break;
801                }
802                if(c == BS) {
803                /* <STR,CHR>\\ but is not <STR,CHR>\\\n */
804                getc0();
805                }
806                if(c == '\n' || c == L_EOF)
807                yy_error_d("unterminated");
808            }
809            getc1();
810        } else {
811            /* <S>[A-Z_a-z0-9] */
812
813            /* trick for fast drop id
814               if key with this first char undefined */
815            if(first_chars[c] == 0 || (mode & FALSE_MODES) != 0) {
816                /* skip <S>[A-Z_a-z0-9]+ */
817                do getc1(); while(isalnums[c]);
818            } else {
819                id_len = 0;
820                do {
821                /* <S>[A-Z_a-z0-9]+ */
822                put_id(c);
823                getc1();
824                } while(isalnums[c]);
825                check_key(key_top, id, id_len);
826            }
827        }
828        continue;
829    }
830    /* begin preprocessor states */
831    if(c == L_EOF)
832        yy_error_d("unexpected EOF");
833    if(c == REM) {
834        /* <#.*>/ */
835        getc0();
836        if(c == REM)
837            yy_error_d("detected // in preprocessor line");
838        if(c == '*') {
839            /* <#.*>[/][*] goto parse block comments */
840            break;
841        }
842        /* hmm, #.*[/] */
843        yy_error_d("strange preprocessor line");
844    }
845    if(state == POUND) {
846        /* tricks */
847        int diu = (int)first_chars_deiu[c];   /* preproc ptr */
848
849        state = S;
850        if(diu != S) {
851        int p_num_str, p_num_max;
852
853        getc1();
854        id_len = 0;
855        while(isalnums[c]) {
856            put_id(c);
857            getc1();
858        }
859        put_id(0);
860        p_num_str = diu & 0xf;
861        p_num_max = diu >> 4;
862        for(diu = p_num_str; diu <= p_num_max; diu++)
863            if(!strcmp(id, preproc[diu])) {
864            state = (diu + '0');
865            /* common */
866            id_len = 0;
867            break;
868        }
869        } else {
870        while(isalnums[c]) getc1();
871        }
872    } else if(state == EF) {
873        /* #endif */
874        pop_mode();
875        state = S;
876    } else if(state == I) {
877        if(c == STR && (mode & FALSE_MODES) == 0) {
878            /* <I>\" */
879            for(;;) {
880                getc1();
881                if(c == STR)
882                break;
883                if(c == L_EOF)
884                yy_error_d("unexpected EOF");
885                put_id(c);
886            }
887            put_id(0);
888            /* store "include.h" */
889            parse_inc(id, fname);
890            getc1();
891        }
892        /* else another (may be wrong) #include ... */
893        state = S;
894    } else if(state == F) {
895        arith_t t;
896        int errcode;
897
898        while(c != '\n' && c != L_EOF) {
899        put_id(c);
900        getc1();
901        }
902        put_id(0);
903        t = arith(id, &errcode);
904        if (errcode < 0) {
905        if (errcode == -2)
906            yy_error_d("divide by zero");
907        else if (errcode == -4)
908            yy_error_d("undefined");
909        else if (errcode == -5)
910            yy_error_d("expression recursion loop detected");
911        else
912            yy_error_d("syntax error");
913        }
914        push_mode();
915        mode = t != 0 ? IF1_MODE : IF0_MODE;
916        state = S;
917    } else if(state == IFD || state == IFND) {
918        /* save KEY from #if(n)def KEY ... */
919        const char *v;
920
921        push_mode();
922        while(isalnums[c]) {
923        put_id(c);
924        getc1();
925        }
926        if(!id_len)
927        yy_error_d("expected identifier");
928        v = lookup_key(id, id_len);
929        mode = IF1_MODE;
930        if(state == IFD && v == NULL)
931        mode = IF0_MODE;
932        else if(state == IFND && v != NULL)
933            mode = IF0_MODE;
934        state = S;
935    } else if(state == EI) {
936        /* #elif */
937        if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE)
938        yy_error_d("unexpected #elif");
939        if(mode == IF0_MODE) {
940        pop_mode();
941        state = F;
942        } else {
943        mode = ELIF1_MODE;
944        state = S;
945        }
946    } else if(state == E) {
947        if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE)
948        yy_error_d("unexpected #else");
949        if(mode == IF0_MODE)
950        mode = ELSE0_MODE;
951        else if(mode == IF1_MODE)
952        mode = ELSE1_MODE;
953        state = S;
954    } else if(state == D || state == U) {
955        /* save KEY from #"define"|"undef" ... */
956        while(isalnums[c]) {
957        put_id(c);
958        getc1();
959        }
960        if(!id_len)
961        yy_error_d("expected identifier");
962        if(state == U) {
963        if((mode & FALSE_MODES) == 0)
964            parse_conf_opt(id, NULL, id_len);
965        state = S;
966        } else {
967        /* D -> DK */
968        state = DK;
969        }
970    } else {
971        /* state==<DK> #define KEY[ ] */
972        size_t opt_len = id_len;
973        char *val = id + opt_len;
974        char *sp;
975
976        for(;;) {
977        if(c == L_EOF || c == '\n')
978            break;
979        put_id(c);
980        getc1();
981        }
982        sp = id + id_len;
983        put_id(0);
984        /* trim tail spaces */
985        while(--sp >= val && (*sp == ' ' || *sp == '\t'
986                || *sp == '\f' || *sp == '\v'))
987        *sp = '\0';
988        if((mode & FALSE_MODES) == 0)
989        parse_conf_opt(id, val, opt_len);
990        state = S;
991    }
992    }
993
994    /* <REM> */
995    getc0();
996    for(;;) {
997      /* <REM>[^*]+ */
998      while(c != '*') {
999        if(c == '\n') {
1000            /* <REM>\n */
1001            if(state != S)
1002            yy_error_d("unexpected newline");
1003            line++;
1004        } else if(c == L_EOF)
1005            yy_error_d("unexpected EOF");
1006        getc0();
1007      }
1008      /* <REM>[*] */
1009      getc0();
1010      if(c == REM) {
1011        /* <REM>[*][/] */
1012        break;
1013      }
1014    }
1015  }
1016too_long:
1017  yy_error_d("phrase too long");
1018}
1019
1020/* trick for fast find "define", "include", "undef" */
1021static const char first_chars_diu[UCHAR_MAX] = {
1022    [(int)'d'] = (char)5,           /* strlen("define")  - 1; */
1023    [(int)'i'] = (char)6,           /* strlen("include") - 1; */
1024    [(int)'u'] = (char)4,           /* strlen("undef")   - 1; */
1025};
1026
1027#undef D
1028#undef I
1029#undef U
1030#define D      '5'      /* #define preprocessor's directive */
1031#define I      '6'      /* #include preprocessor's directive */
1032#define U      '4'      /* #undef preprocessor's directive */
1033
1034/* stupid C lexical analyser for sources */
1035static void c_lex_src(const char *fname, long fsize)
1036{
1037  int c;
1038  int state;
1039  int line;
1040  char *id = id_s;
1041  size_t id_len = 0;                /* stupid initialization */
1042  unsigned char *optr, *oend;
1043
1044  int fd;
1045  char *map;
1046  int mapsize;
1047
1048  if(fsize == 0) {
1049    fprintf(stderr, "Warning: %s is empty\n", fname);
1050    return;
1051  }
1052  fd = open(fname, O_RDONLY);
1053  if(fd < 0) {
1054    perror(fname);
1055    return;
1056  }
1057  mapsize = (fsize+pagesizem1) & ~pagesizem1;
1058  map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
1059  if ((long) map == -1)
1060    bb_error_d("%s: mmap: %m", fname);
1061
1062  optr = (unsigned char *)map;
1063  oend = optr + fsize;
1064
1065  line = 1;
1066  state = S;
1067
1068  for(;;) {
1069    getc1();
1070    for(;;) {
1071    /* [ \t]+ eat first space */
1072    while(c == ' ' || c == '\t')
1073        getc1();
1074
1075    if(state == S) {
1076        while(first_chars[c] == ANY) {
1077            /* <S>unparsed */
1078            if(c == '\n')
1079            line++;
1080            getc1();
1081        }
1082        if(c == L_EOF) {
1083            /* <S><<EOF>> */
1084            munmap(map, mapsize);
1085            close(fd);
1086            return;
1087        }
1088        if(c == REM) {
1089            /* <S>/ */
1090            getc0();
1091            if(c == REM) {
1092                /* <S>"//"[^\n]* */
1093                do getc0(); while(c != '\n' && c != L_EOF);
1094            } else if(c == '*') {
1095                /* <S>[/][*] goto parse block comments */
1096                break;
1097            }
1098        } else if(c == POUND) {
1099            /* <S># */
1100            state = c;
1101            getc1();
1102        } else if(c == STR || c == CHR) {
1103            /* <S>\"|\' */
1104            int qc = c;
1105
1106            for(;;) {
1107                /* <STR,CHR>. */
1108                getc1();
1109                if(c == qc) {
1110                /* <STR>\" or <CHR>\' */
1111                break;
1112                }
1113                if(c == BS) {
1114                /* <STR,CHR>\\ but is not <STR,CHR>\\\n */
1115                getc0();
1116                }
1117                if(c == '\n' || c == L_EOF)
1118                yy_error_d("unterminated");
1119            }
1120            getc1();
1121        } else {
1122            /* <S>[A-Z_a-z0-9] */
1123
1124            /* trick for fast drop id
1125               if key with this first char undefined */
1126            if(first_chars[c] == 0) {
1127                /* skip <S>[A-Z_a-z0-9]+ */
1128                do getc1(); while(isalnums[c]);
1129            } else {
1130                id_len = 0;
1131                do {
1132                /* <S>[A-Z_a-z0-9]+ */
1133                put_id(c);
1134                getc1();
1135                } while(isalnums[c]);
1136                check_key(key_top, id, id_len);
1137            }
1138        }
1139        continue;
1140    }
1141    /* begin preprocessor states */
1142    if(c == L_EOF)
1143        yy_error_d("unexpected EOF");
1144    if(c == REM) {
1145        /* <#.*>/ */
1146        getc0();
1147        if(c == REM)
1148            yy_error_d("detected // in preprocessor line");
1149        if(c == '*') {
1150            /* <#.*>[/][*] goto parse block comments */
1151            break;
1152        }
1153        /* hmm, #.*[/] */
1154        yy_error_d("strange preprocessor line");
1155    }
1156    if(state == POUND) {
1157        /* tricks */
1158        static const char * const p_preproc[] = {
1159            /* 0 1   2  3     4        5        6 */
1160            "", "", "", "", "ndef", "efine", "nclude"
1161        };
1162        size_t diu = first_chars_diu[c];   /* strlen and p_preproc ptr */
1163
1164        state = S;
1165        if(diu != S) {
1166        getc1();
1167        id_len = 0;
1168        while(isalnums[c]) {
1169            put_id(c);
1170            getc1();
1171        }
1172        /* str begins with c, read == strlen key and compared */
1173        if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) {
1174            state = diu + '0';
1175            id_len = 0; /* common for save */
1176        }
1177        } else {
1178        while(isalnums[c]) getc1();
1179        }
1180    } else if(state == I) {
1181        if(c == STR) {
1182            /* <I>\" */
1183            for(;;) {
1184                getc1();
1185                if(c == STR)
1186                break;
1187                if(c == L_EOF)
1188                yy_error_d("unexpected EOF");
1189                put_id(c);
1190            }
1191            put_id(0);
1192            /* store "include.h" */
1193            parse_inc(id, fname);
1194            getc1();
1195        }
1196        /* else another (may be wrong) #include ... */
1197        state = S;
1198    } else /* if(state == D || state == U) */ {
1199        /* ignore depend with #define or #undef KEY */
1200        while(isalnums[c]) getc1();
1201        state = S;
1202    }
1203    }
1204
1205    /* <REM> */
1206    getc0();
1207    for(;;) {
1208      /* <REM>[^*]+ */
1209      while(c != '*') {
1210        if(c == '\n') {
1211            /* <REM>\n */
1212            if(state != S)
1213            yy_error_d("unexpected newline");
1214            line++;
1215        } else if(c == L_EOF)
1216            yy_error_d("unexpected EOF");
1217        getc0();
1218      }
1219      /* <REM>[*] */
1220      getc0();
1221      if(c == REM) {
1222        /* <REM>[*][/] */
1223        break;
1224      }
1225    }
1226  }
1227too_long:
1228  yy_error_d("phrase too long");
1229}
1230
1231
1232/* bb_simplify_path special variant for absolute pathname */
1233static size_t bb_qa_simplify_path(char *path)
1234{
1235    char *s, *p;
1236
1237    p = s = path;
1238
1239    do {
1240        if (*p == '/') {
1241        if (*s == '/') {    /* skip duplicate (or initial) slash */
1242            continue;
1243        } else if (*s == '.') {
1244            if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
1245            continue;
1246            } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
1247            ++s;
1248            if (p > path) {
1249                while (*--p != '/');    /* omit previous dir */
1250            }
1251            continue;
1252            }
1253        }
1254        }
1255        *++p = *s;
1256    } while (*++s);
1257
1258    if ((p == path) || (*p != '/')) {  /* not a trailing slash */
1259        ++p;                            /* so keep last character */
1260    }
1261    *p = 0;
1262
1263    return (p - path);
1264}
1265
1266static void parse_inc(const char *include, const char *fname)
1267{
1268    bb_key_t *cur;
1269    const char *p_i;
1270    llist_t *lo;
1271    char *ap;
1272    size_t key_sz;
1273    struct stat st;
1274
1275    if(*include == '/') {
1276    lo = NULL;
1277    ap = bb_xstrdup(include);
1278    } else {
1279    int w;
1280    const char *p;
1281
1282    lo = Iop;
1283    p = strrchr(fname, '/');    /* fname has absolute pathname */
1284    w = (p-fname);
1285    /* find from current directory of source file */
1286    ap = bb_asprint("%.*s/%s", w, fname, include);
1287    }
1288
1289    for(;;) {
1290    key_sz = bb_qa_simplify_path(ap);
1291    cur = check_key(Ifound, ap, key_sz);
1292    if(cur) {
1293        cur->checked = cur->value;
1294        free(ap);
1295        return;
1296    }
1297    if(stat(ap, &st) == 0) {
1298        /* found */
1299        llist_t *cfl;
1300
1301        for(cfl = configs; cfl; cfl = cfl->link) {
1302        struct stat *config = (struct stat *)cfl->data;
1303
1304        if (st.st_dev == config->st_dev && st.st_ino == config->st_ino) {
1305            /* skip depend with bb_configs.h */
1306            return;
1307        }
1308        }
1309        p_i = ap;
1310        break;
1311    } else if(lo == NULL) {
1312        p_i = NULL;
1313        break;
1314    }
1315
1316    /* find from "-I include" specified directories */
1317    free(ap);
1318    /* lo->data has absolute pathname */
1319    ap = bb_asprint("%s/%s", lo->data, include);
1320    lo = lo->link;
1321    }
1322
1323    cur = xmalloc(sizeof(bb_key_t));
1324    cur->keyname = ap;
1325    cur->key_sz = key_sz;
1326    cur->stored_path = ap;
1327    cur->value = cur->checked = p_i;
1328    if(p_i == NULL && noiwarning)
1329    fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include);
1330    cur->next = Ifound;
1331    Ifound = cur;
1332}
1333
1334static size_t max_rec_sz;
1335
1336static void parse_conf_opt(const char *opt, const char *val, size_t key_sz)
1337{
1338    bb_key_t *cur;
1339    char *k;
1340    char *p;
1341    size_t val_sz = 0;
1342
1343    cur = check_key(key_top, opt, key_sz);
1344    if(cur != NULL) {
1345        /* already present */
1346        cur->checked = NULL;        /* store only */
1347        if(cur->value == NULL && val == NULL)
1348        return;
1349        if(cur->value != NULL && val != NULL && !strcmp(cur->value, val))
1350        return;
1351        k = cur->keyname;
1352        fprintf(stderr, "Warning: redefined %s\n", k);
1353    } else {
1354        size_t recordsz;
1355
1356        if(val && *val)
1357        val_sz = strlen(val) + 1;
1358        recordsz = key_sz + val_sz + 1;
1359        if(max_rec_sz < recordsz)
1360        max_rec_sz = recordsz;
1361        cur = xmalloc(sizeof(bb_key_t) + recordsz);
1362        k = cur->keyname = memcpy(cur + 1, opt, key_sz);
1363        cur->keyname[key_sz] = '\0';
1364        cur->key_sz = key_sz;
1365        cur->checked = NULL;
1366        cur->src_have_this_key = NULL;
1367        cur->next = key_top;
1368        key_top = cur;
1369    }
1370    /* save VAL */
1371    if(val) {
1372        if(*val == '\0') {
1373        cur->value = "";
1374        } else {
1375        cur->value = p = cur->keyname + key_sz + 1;
1376        memcpy(p, val, val_sz);
1377        }
1378    } else {
1379        cur->value = NULL;
1380    }
1381    /* trick, save first char KEY for do fast identify id */
1382    first_chars[(int)*k] = *k;
1383
1384    cur->stored_path = k = bb_asprint("%s/%s.h", kp, k);
1385    /* key conversion [A-Z_] -> [a-z/] */
1386    for(p = k + kp_len + 1; *p; p++) {
1387        if(*p >= 'A' && *p <= 'Z')
1388            *p = *p - 'A' + 'a';
1389        else if(*p == '_' && p[1] > '9')    /* do not change A_1 to A/1 */
1390            *p = '/';
1391    }
1392}
1393
1394static void store_keys(void)
1395{
1396    bb_key_t *cur;
1397    char *k;
1398    struct stat st;
1399    int cmp_ok;
1400    ssize_t rw_ret;
1401    size_t recordsz = max_rec_sz * 2 + 10 * 2 + 16;
1402    /* buffer for double "#define KEY VAL\n" */
1403    char *record_buf = xmalloc(recordsz);
1404
1405    for(cur = key_top; cur; cur = cur->next) {
1406    if(cur->src_have_this_key) {
1407        /* do generate record */
1408        k = cur->keyname;
1409        if(cur->value == NULL) {
1410        recordsz = sprintf(record_buf, "#undef %s\n", k);
1411        } else {
1412        const char *val = cur->value;
1413        if(*val == '\0') {
1414            recordsz = sprintf(record_buf, "#define %s\n", k);
1415        } else {
1416            if(val[0] != '(')
1417            recordsz = sprintf(record_buf, "#define %s %s\n", k, val);
1418            else
1419            recordsz = sprintf(record_buf, "#define %s%s\n", k, val);
1420        }
1421        }
1422        /* size_t -> ssize_t :( */
1423        rw_ret = (ssize_t)recordsz;
1424        /* check kp/key.h, compare after previous use */
1425        cmp_ok = 0;
1426        k = cur->stored_path;
1427        if(stat(k, &st)) {
1428        char *p;
1429        for(p = k + kp_len + 1; *p; p++) {
1430            /* Auto-create directories. */
1431            if (*p == '/') {
1432            *p = '\0';
1433            if (access(k, F_OK) != 0 && mkdir(k, 0755) != 0)
1434                bb_error_d("mkdir(%s): %m", k);
1435            *p = '/';
1436            }
1437        }
1438        } else {
1439            /* found */
1440            if(st.st_size == (off_t)recordsz) {
1441            char *r_cmp;
1442            int fd;
1443            size_t padded = recordsz;
1444
1445            /* 16-byte padding for read(2) and memcmp(3) */
1446            padded = (padded+15) & ~15;
1447            r_cmp = record_buf + padded;
1448            fd = open(k, O_RDONLY);
1449            if(fd < 0 || read(fd, r_cmp, recordsz) < rw_ret)
1450                bb_error_d("%s: %m", k);
1451            close(fd);
1452            cmp_ok = memcmp(record_buf, r_cmp, recordsz) == 0;
1453            }
1454        }
1455        if(!cmp_ok) {
1456        int fd = open(k, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1457        if(fd < 0 || write(fd, record_buf, recordsz) < rw_ret)
1458            bb_error_d("%s: %m", k);
1459        close(fd);
1460        }
1461    }
1462    }
1463}
1464
1465static int show_dep(int first, bb_key_t *k, const char *name, const char *f)
1466{
1467    bb_key_t *cur;
1468
1469    for(cur = k; cur; cur = cur->next) {
1470    if(cur->checked) {
1471        if(first >= 0) {
1472        if(first) {
1473            if(f == NULL)
1474            printf("\n%s:", name);
1475            else
1476            printf("\n%s/%s:", pwd, name);
1477            first = 0;
1478        } else {
1479            printf(" \\\n  ");
1480        }
1481        printf(" %s", cur->checked);
1482        }
1483        cur->src_have_this_key = cur->checked;
1484        cur->checked = NULL;
1485    }
1486    }
1487    return first;
1488}
1489
1490static char *
1491parse_chd(const char *fe, const char *p, size_t dirlen)
1492{
1493    struct stat st;
1494    char *fp;
1495    size_t df_sz;
1496    static char dir_and_entry[4096];
1497    size_t fe_sz = strlen(fe) + 1;
1498
1499    df_sz = dirlen + fe_sz + 1;         /* dir/file\0 */
1500    if(df_sz > sizeof(dir_and_entry))
1501    bb_error_d("%s: file name too long", fe);
1502    fp = dir_and_entry;
1503    /* sprintf(fp, "%s/%s", p, fe); */
1504    memcpy(fp, p, dirlen);
1505    fp[dirlen] = '/';
1506    memcpy(fp + dirlen + 1, fe, fe_sz);
1507
1508    if(stat(fp, &st)) {
1509    fprintf(stderr, "Warning: stat(%s): %m\n", fp);
1510    return NULL;
1511    }
1512    if(S_ISREG(st.st_mode)) {
1513    llist_t *cfl;
1514    char *e = fp + df_sz - 3;
1515
1516    if(*e++ != '.' || (*e != 'c' && *e != 'h')) {
1517        /* direntry is regular file, but is not *.[ch] */
1518        return NULL;
1519    }
1520    for(cfl = configs; cfl; cfl = cfl->link) {
1521        struct stat *config = (struct stat *)cfl->data;
1522
1523        if (st.st_dev == config->st_dev && st.st_ino == config->st_ino) {
1524        /* skip already parsed bb_configs.h */
1525        return NULL;
1526        }
1527    }
1528    /* direntry is *.[ch] regular file and is not configs */
1529    c_lex_src(fp, st.st_size);
1530    if(!dontgenerate_dep) {
1531        int first;
1532        if(*e == 'c') {
1533        /* *.c -> *.o */
1534        *e = 'o';
1535        /* /src_dir/path/file.o to path/file.o */
1536        fp += replace;
1537        if(*fp == '/')
1538            fp++;
1539        } else {
1540        e = NULL;
1541        }
1542        first = show_dep(1, Ifound, fp, e);
1543        first = show_dep(first, key_top, fp, e);
1544        if(first == 0)
1545        putchar('\n');
1546    } else {
1547        show_dep(-1, key_top, NULL, NULL);
1548    }
1549    return NULL;
1550    } else if(S_ISDIR(st.st_mode)) {
1551    if (st.st_dev == st_kp.st_dev && st.st_ino == st_kp.st_ino)
1552        return NULL;    /* drop scan kp/ directory */
1553    /* direntry is directory. buff is returned */
1554    return bb_xstrdup(fp);
1555    }
1556    /* hmm, direntry is device! */
1557    return NULL;
1558}
1559
1560/* from libbb but inlined for speed considerations */
1561static inline llist_t *llist_add_to(llist_t *old_head, char *new_item)
1562{
1563    llist_t *new_head;
1564
1565    new_head = xmalloc(sizeof(llist_t));
1566    new_head->data = new_item;
1567    new_head->link = old_head;
1568
1569    return(new_head);
1570}
1571
1572static void scan_dir_find_ch_files(const char *p)
1573{
1574    llist_t *dirs;
1575    llist_t *d_add;
1576    llist_t *d;
1577    struct dirent *de;
1578    DIR *dir;
1579    size_t dirlen;
1580
1581    dirs = llist_add_to(NULL, bb_simplify_path(p));
1582    replace = strlen(dirs->data);
1583    /* emulate recursion */
1584    while(dirs) {
1585    d_add = NULL;
1586    while(dirs) {
1587        dir = opendir(dirs->data);
1588        if (dir == NULL)
1589        fprintf(stderr, "Warning: opendir(%s): %m\n", dirs->data);
1590        dirlen = strlen(dirs->data);
1591        while ((de = readdir(dir)) != NULL) {
1592        char *found_dir;
1593
1594        if (de->d_name[0] == '.')
1595            continue;
1596        found_dir = parse_chd(de->d_name, dirs->data, dirlen);
1597        if(found_dir)
1598            d_add = llist_add_to(d_add, found_dir);
1599        }
1600        closedir(dir);
1601        free(dirs->data);
1602        d = dirs;
1603        dirs = dirs->link;
1604        free(d);
1605    }
1606    dirs = d_add;
1607    }
1608}
1609
1610static void show_usage(void) ATTRIBUTE ((noreturn));
1611static void show_usage(void)
1612{
1613    bb_error_d("%s\n%s\n", bb_mkdep_terse_options, bb_mkdep_full_options);
1614}
1615
1616int main(int argc, char **argv)
1617{
1618    char *s;
1619    int i;
1620    llist_t *fl;
1621
1622    {
1623        /* for bb_simplify_path, this program has no chdir() */
1624        /* libbb-like my xgetcwd() */
1625        unsigned path_max = 512;
1626
1627        s = xmalloc (path_max);
1628        while (getcwd (s, path_max) == NULL) {
1629        if(errno != ERANGE)
1630            bb_error_d("getcwd: %m");
1631        free(s);
1632        s = xmalloc(path_max *= 2);
1633        }
1634        pwd = s;
1635    }
1636
1637    while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
1638        switch(i) {
1639            case 'I':
1640                s = bb_simplify_path(optarg);
1641                Iop = llist_add_to(Iop, s);
1642                break;
1643            case 'c':
1644                s = bb_simplify_path(optarg);
1645                configs = llist_add_to(configs, s);
1646                break;
1647            case 'd':
1648                dontgenerate_dep = 1;
1649                break;
1650            case 'k':
1651                if(kp)
1652                bb_error_d("Hmm, why multiple -k?");
1653                kp = bb_simplify_path(optarg);
1654                break;
1655            case 'w':
1656                noiwarning = 1;
1657                break;
1658            default:
1659                show_usage();
1660        }
1661    }
1662    /* default kp */
1663    if(kp == NULL)
1664        kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
1665    /* globals initialize */
1666    kp_len = strlen(kp);
1667    if(stat(kp, &st_kp))
1668        bb_error_d("stat(%s): %m", kp);
1669    if(!S_ISDIR(st_kp.st_mode))
1670        bb_error_d("%s is not directory", kp);
1671    /* defaults */
1672    if(Iop == NULL)
1673        Iop = llist_add_to(Iop, bb_simplify_path(LOCAL_INCLUDE_PATH));
1674    if(configs == NULL) {
1675        s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
1676        configs = llist_add_to(configs, s);
1677    }
1678    /* for c_lex */
1679    pagesizem1 = getpagesize() - 1;
1680    for(i = 0; i < UCHAR_MAX; i++) {
1681        if(ISALNUM(i))
1682        isalnums[i] = i;
1683        /* set unparsed chars to speed up the parser */
1684        else if(i != CHR && i != STR && i != POUND && i != REM)
1685        first_chars[i] = ANY;
1686    }
1687    first_chars[i] = '-';   /* L_EOF */
1688
1689    /* parse configs */
1690    for(fl = configs; fl; fl = fl->link) {
1691        struct stat st;
1692
1693        if(stat(fl->data, &st))
1694        bb_error_d("stat(%s): %m", fl->data);
1695        c_lex_config(fl->data, st.st_size);
1696        free(fl->data);
1697        /* trick for fast comparing found files with configs */
1698        fl->data = xmalloc(sizeof(struct stat));
1699        memcpy(fl->data, &st, sizeof(struct stat));
1700    }
1701
1702    /* main loop */
1703    argv += optind;
1704    if(*argv) {
1705        while(*argv)
1706        scan_dir_find_ch_files(*argv++);
1707    } else {
1708        scan_dir_find_ch_files(".");
1709    }
1710    store_keys();
1711    return 0;
1712}
1713
1714/* partial and simplified libbb routine */
1715static void bb_error_d(const char *s, ...)
1716{
1717    va_list p;
1718
1719    va_start(p, s);
1720    vfprintf(stderr, s, p);
1721    va_end(p);
1722    putc('\n', stderr);
1723    exit(1);
1724}
1725
1726static char *bb_asprint(const char *format, ...)
1727{
1728    va_list p;
1729    int r;
1730    char *out;
1731
1732#ifdef __USE_GNU
1733    va_start(p, format);
1734    r = vasprintf(&out, format, p);
1735    va_end(p);
1736#else
1737    out = xmalloc(BUFSIZ);
1738    va_start(p, format);
1739    r = vsprintf(out, format, p);
1740    va_end(p);
1741#endif
1742
1743    if (r < 0)
1744        bb_error_d("bb_asprint: %m");
1745    return out;
1746}
1747
1748/* partial libbb routine as is */
1749
1750static char *bb_simplify_path(const char *path)
1751{
1752    char *s, *start, *p;
1753
1754    if (path[0] == '/')
1755        start = bb_xstrdup(path);
1756    else {
1757        /* is not libbb, but this program has no chdir() */
1758        start = bb_asprint("%s/%s", pwd, path);
1759    }
1760    p = s = start;
1761
1762    do {
1763        if (*p == '/') {
1764        if (*s == '/') {    /* skip duplicate (or initial) slash */
1765            continue;
1766        } else if (*s == '.') {
1767            if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
1768            continue;
1769            } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
1770            ++s;
1771            if (p > start) {
1772                while (*--p != '/');    /* omit previous dir */
1773            }
1774            continue;
1775            }
1776        }
1777        }
1778        *++p = *s;
1779    } while (*++s);
1780
1781    if ((p == start) || (*p != '/')) {  /* not a trailing slash */
1782        ++p;                            /* so keep last character */
1783    }
1784    *p = 0;
1785
1786    return start;
1787}
Note: See TracBrowser for help on using the repository browser.