source: MondoRescue/trunk/mindi-busybox/scripts/bb_mkdep.c@ 929

Last change on this file since 929 was 821, checked in by Bruno Cornec, 18 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.