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