blob: 943745e283d76ec50977e268bfd0f0f6476559a8 [file] [log] [blame]
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001/*
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00002 * Another fast dependencies generator for Makefiles, Version 4.2
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00003 *
Rob Landley7bfa88f2006-02-13 19:16:41 +00004 * Copyright (C) 2005,2006 by Vladimir Oleynik <dzo@simtreas.ru>
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00005 *
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00006 * mmaping file may be originally by Linus Torvalds.
7 *
Rob Landley7bfa88f2006-02-13 19:16:41 +00008 * 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 *
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000013 * 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 *
Rob Landley7bfa88f2006-02-13 19:16:41 +000023 * (c) 2005,2006 Bernhard Fischer:
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +000024 * - commentary typos,
25 * - move "memory exhausted" into msg_enomem,
26 * - more verbose --help output.
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000027 *
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000028 * This program does:
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +000029 * 1) find #define KEY VALUE or #undef KEY from include/bb_config.h
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000030 * 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
"Vladimir N. Oleynik"664c6e72005-10-06 14:53:43 +000033 * pwd/file.o: include/config/key*.h found_include_*.h
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000034 * path/inc.h: include/config/key*.h found_included_include_*.h
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000035 * 5) save include/config/key*.h if changed after previous usage
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +000036 * This program does not generate dependencies for #include <...>
Rob Landley7bfa88f2006-02-13 19:16:41 +000037 * Config file can have #if #elif #else #ifdef #ifndef #endif lines
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000038 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000039
40#define LOCAL_INCLUDE_PATH "include"
41#define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config"
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +000042#define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/bb_config.h"
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000043
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000044#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
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000057#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>
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000070#include <limits.h>
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000071
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000072
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000073/* partial and simplified libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000074static void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
75static char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000076static char *bb_simplify_path(const char *path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000077
78/* stolen from libbb as is */
79typedef struct llist_s {
80 char *data;
81 struct llist_s *link;
82} llist_t;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000083
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000084static const char msg_enomem[] = "memory exhausted";
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000085
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000086/* inline realization for fast works */
87static 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
96static 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
106static int dontgenerate_dep; /* flag -d usaged */
107static int noiwarning; /* flag -w usaged */
108static llist_t *configs; /* list of -c usaged and them stat() after parsed */
109static llist_t *Iop; /* list of -I include usaged */
110
111static char *pwd; /* current work directory */
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +0000112static size_t replace; /* replace current work directory with build dir */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000113
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +0000114static const char *kp; /* KEY path, argument of -k used */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000115static size_t kp_len;
116static struct stat st_kp; /* stat(kp) */
117
118typedef 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
128static bb_key_t *key_top; /* list of found KEYs */
129static bb_key_t *Ifound; /* list of parsed includes */
130
131
132static void parse_conf_opt(const char *opt, const char *val, size_t key_sz);
133static void parse_inc(const char *include, const char *fname);
134
135static 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
Rob Landley7bfa88f2006-02-13 19:16:41 +0000148static 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
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000160/* for lexical analyser */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000161static int pagesizem1; /* padding mask = getpagesize() - 1 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000162
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000163/* for speed tricks */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000164static char first_chars[1+UCHAR_MAX]; /* + L_EOF */
165static char isalnums[1+UCHAR_MAX]; /* + L_EOF */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000166
167/* trick for fast find "define", "include", "undef",
168"if((n)def)" "else", "endif" */
169static 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" };
172static 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 */
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +0000177};
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000178
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000179#define CONFIG_MODE 0
Rob Landley7bfa88f2006-02-13 19:16:41 +0000180#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)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000186
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000187#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 */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000193#define REM '/' /* block comment */
194#define BS '\\' /* back slash */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000195#define POUND '#' /* # */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000196#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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000205#define DK 'K' /* #define KEY... (config mode) */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000206#define ANY '*' /* any unparsed chars */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000207
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
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000213#define L_EOF (1+UCHAR_MAX)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000214
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000215#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
222static 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)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000225
Rob Landley7bfa88f2006-02-13 19:16:41 +0000226static char ifcpp_stack[1024];
227static 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)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000233
Rob Landley7bfa88f2006-02-13 19:16:41 +0000234#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 */
241typedef long long arith_t;
242
243static 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
256typedef 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
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +0000311#define SPEC_PREC (UNARYPREC+2)
Rob Landley7bfa88f2006-02-13 19:16:41 +0000312
313#define TOK_NUM tok_decl(SPEC_PREC, 0)
314#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
315
316#define NUMPTR (*numstackptr)
317
318typedef 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
325typedef 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
331static chk_var_recursive_looped_t *prev_chk_var_recursive;
332
333
334static 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 */
372static inline int
373arith_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;
468err: return(-1);
469}
470
471/* longest must first */
472static 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
508static inline char *
509endofname(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
Rob Landley7bfa88f2006-02-13 19:16:41 +0000524static 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. */
552err:
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 */
712static void c_lex_config(const char *fname, long fsize)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000713{
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000714 int c;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000715 int state;
716 int line;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000717 char *id = id_s;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +0000718 size_t id_len = 0; /* stupid initialization */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000719 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 }
1007too_long:
1008 yy_error_d("phrase too long");
1009}
1010
1011/* trick for fast find "define", "include", "undef" */
1012static 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 */
1026static void c_lex_src(const char *fname, long fsize)
1027{
1028 int c;
1029 int state;
1030 int line;
1031 char *id = id_s;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001032 size_t id_len = 0; /* stupid initialization */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001033 unsigned char *optr, *oend;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001034
1035 int fd;
1036 char *map;
1037 int mapsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001038
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001039 if(fsize == 0) {
1040 fprintf(stderr, "Warning: %s is empty\n", fname);
1041 return;
1042 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001043 fd = open(fname, O_RDONLY);
1044 if(fd < 0) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001045 perror(fname);
1046 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001047 }
1048 mapsize = (fsize+pagesizem1) & ~pagesizem1;
1049 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
1050 if ((long) map == -1)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001051 bb_error_d("%s: mmap: %m", fname);
1052
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001053 optr = (unsigned char *)map;
1054 oend = optr + fsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001055
1056 line = 1;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001057 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001058
1059 for(;;) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001060 getc1();
1061 for(;;) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001062 /* [ \t]+ eat first space */
1063 while(c == ' ' || c == '\t')
1064 getc1();
1065
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001066 if(state == S) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001067 while(first_chars[c] == ANY) {
1068 /* <S>unparsed */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001069 if(c == '\n')
1070 line++;
1071 getc1();
1072 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001073 if(c == L_EOF) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001074 /* <S><<EOF>> */
1075 munmap(map, mapsize);
1076 close(fd);
1077 return;
1078 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001079 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001080 /* <S>/ */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001081 getc0();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001082 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001083 /* <S>"//"[^\n]* */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001084 do getc0(); while(c != '\n' && c != L_EOF);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001085 } else if(c == '*') {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001086 /* <S>[/][*] goto parse block comments */
1087 break;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001088 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001089 } else if(c == POUND) {
1090 /* <S># */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001091 state = c;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001092 getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001093 } else if(c == STR || c == CHR) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001094 /* <S>\"|\' */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001095 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 {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001113 /* <S>[A-Z_a-z0-9] */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001114
1115 /* trick for fast drop id
1116 if key with this first char undefined */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001117 if(first_chars[c] == 0) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001118 /* skip <S>[A-Z_a-z0-9]+ */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001119 do getc1(); while(isalnums[c]);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001120 } else {
1121 id_len = 0;
1122 do {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001123 /* <S>[A-Z_a-z0-9]+ */
1124 put_id(c);
1125 getc1();
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001126 } while(isalnums[c]);
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001127 check_key(key_top, id, id_len);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001128 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001129 }
1130 continue;
1131 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001132 /* begin preprocessor states */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001133 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001134 yy_error_d("unexpected EOF");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001135 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001136 /* <#.*>/ */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001137 getc0();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001138 if(c == REM)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001139 yy_error_d("detected // in preprocessor line");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001140 if(c == '*') {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001141 /* <#.*>[/][*] goto parse block comments */
1142 break;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001143 }
1144 /* hmm, #.*[/] */
1145 yy_error_d("strange preprocessor line");
1146 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001147 if(state == POUND) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001148 /* tricks */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001149 static const char * const p_preproc[] = {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001150 /* 0 1 2 3 4 5 6 */
1151 "", "", "", "", "ndef", "efine", "nclude"
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001152 };
Rob Landley7bfa88f2006-02-13 19:16:41 +00001153 size_t diu = first_chars_diu[c]; /* strlen and p_preproc ptr */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001154
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001155 state = S;
1156 if(diu != S) {
1157 getc1();
1158 id_len = 0;
1159 while(isalnums[c]) {
1160 put_id(c);
1161 getc1();
1162 }
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001163 /* str begins with c, read == strlen key and compared */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001164 if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001165 state = diu + '0';
1166 id_len = 0; /* common for save */
1167 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001168 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001169 while(isalnums[c]) getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001170 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001171 } else if(state == I) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001172 if(c == STR) {
1173 /* <I>\" */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001174 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();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001186 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001187 /* else another (may be wrong) #include ... */
1188 state = S;
Rob Landley7bfa88f2006-02-13 19:16:41 +00001189 } else /* if(state == D || state == U) */ {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001190 /* ignore depend with #define or #undef KEY */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001191 while(isalnums[c]) getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001192 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001193 }
1194 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001195
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 }
1218too_long:
1219 yy_error_d("phrase too long");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001220}
1221
1222
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001223/* bb_simplify_path special variant for absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001224static size_t bb_qa_simplify_path(char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001225{
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001226 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);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001255}
1256
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001257static void parse_inc(const char *include, const char *fname)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001258{
1259 bb_key_t *cur;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001260 const char *p_i;
1261 llist_t *lo;
1262 char *ap;
1263 size_t key_sz;
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001264 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001265
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001266 if(*include == '/') {
1267 lo = NULL;
1268 ap = bb_xstrdup(include);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001269 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001270 int w;
1271 const char *p;
1272
1273 lo = Iop;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001274 p = strrchr(fname, '/'); /* fname has absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001275 w = (p-fname);
1276 /* find from current directory of source file */
1277 ap = bb_asprint("%.*s/%s", w, fname, include);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001278 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001279
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001280 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);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001286 return;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001287 }
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001288 if(stat(ap, &st) == 0) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001289 /* found */
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001290 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 NULL;
1298 }
1299 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001300 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);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001309 /* lo->data has absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001310 ap = bb_asprint("%s/%s", lo->data, include);
1311 lo = lo->link;
1312 }
1313
1314 cur = xmalloc(sizeof(bb_key_t));
Rob Landley7bfa88f2006-02-13 19:16:41 +00001315 cur->keyname = ap;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001316 cur->key_sz = key_sz;
Rob Landley7bfa88f2006-02-13 19:16:41 +00001317 cur->stored_path = ap;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001318 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;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001323}
1324
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001325static size_t max_rec_sz;
1326
1327static void parse_conf_opt(const char *opt, const char *val, size_t key_sz)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001328{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001329 bb_key_t *cur;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001330 char *k;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001331 char *p;
1332 size_t val_sz = 0;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001333
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001334 cur = check_key(key_top, opt, key_sz);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001335 if(cur != NULL) {
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001336 /* already present */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001337 cur->checked = NULL; /* store only */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001338 if(cur->value == NULL && val == NULL)
1339 return;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001340 if(cur->value != NULL && val != NULL && !strcmp(cur->value, val))
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001341 return;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001342 k = cur->keyname;
1343 fprintf(stderr, "Warning: redefined %s\n", k);
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001344 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001345 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;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001360 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001361 /* save VAL */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001362 if(val) {
1363 if(*val == '\0') {
1364 cur->value = "";
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001365 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001366 cur->value = p = cur->keyname + key_sz + 1;
1367 memcpy(p, val, val_sz);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001368 }
1369 } else {
1370 cur->value = NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001371 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001372 /* trick, save first char KEY for do fast identify id */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001373 first_chars[(int)*k] = *k;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001374
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001375 cur->stored_path = k = bb_asprint("%s/%s.h", kp, k);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001376 /* key conversion [A-Z_] -> [a-z/] */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001377 for(p = k + kp_len + 1; *p; p++) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001378 if(*p >= 'A' && *p <= 'Z')
1379 *p = *p - 'A' + 'a';
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001380 else if(*p == '_' && p[1] > '9') /* do not change A_1 to A/1 */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001381 *p = '/';
1382 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001383}
1384
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001385static 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 {
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +00001407 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);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001411 }
1412 }
1413 /* size_t -> ssize_t :( */
1414 rw_ret = (ssize_t)recordsz;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001415 /* check kp/key.h, compare after previous use */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001416 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}
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001455
1456static int show_dep(int first, bb_key_t *k, const char *name, const char *f)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001457{
1458 bb_key_t *cur;
1459
1460 for(cur = k; cur; cur = cur->next) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001461 if(cur->checked) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001462 if(first >= 0) {
1463 if(first) {
1464 if(f == NULL)
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001465 printf("\n%s:", name);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001466 else
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001467 printf("\n%s/%s:", pwd, name);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001468 first = 0;
1469 } else {
1470 printf(" \\\n ");
1471 }
1472 printf(" %s", cur->checked);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001473 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001474 cur->src_have_this_key = cur->checked;
1475 cur->checked = NULL;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001476 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001477 }
1478 return first;
1479}
1480
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001481static char *
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001482parse_chd(const char *fe, const char *p, size_t dirlen)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001483{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001484 struct stat st;
1485 char *fp;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001486 size_t df_sz;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001487 static char dir_and_entry[4096];
1488 size_t fe_sz = strlen(fe) + 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001489
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001490 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);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001493 fp = dir_and_entry;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001494 /* sprintf(fp, "%s/%s", p, fe); */
1495 memcpy(fp, p, dirlen);
1496 fp[dirlen] = '/';
1497 memcpy(fp + dirlen + 1, fe, fe_sz);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001498
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001499 if(stat(fp, &st)) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001500 fprintf(stderr, "Warning: stat(%s): %m\n", fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001501 return NULL;
1502 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001503 if(S_ISREG(st.st_mode)) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001504 llist_t *cfl;
1505 char *e = fp + df_sz - 3;
1506
1507 if(*e++ != '.' || (*e != 'c' && *e != 'h')) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001508 /* direntry is regular file, but is not *.[ch] */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001509 return NULL;
1510 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001511 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) {
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001515 /* skip already parsed bb_configs.h */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001516 return NULL;
1517 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001518 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001519 /* direntry is *.[ch] regular file and is not configs */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001520 c_lex_src(fp, st.st_size);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001521 if(!dontgenerate_dep) {
1522 int first;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001523 if(*e == 'c') {
1524 /* *.c -> *.o */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001525 *e = 'o';
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001526 /* /src_dir/path/file.o to path/file.o */
1527 fp += replace;
1528 if(*fp == '/')
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001529 fp++;
"Vladimir N. Oleynik"d5f2a182005-10-06 14:47:16 +00001530 } else {
1531 e = NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001532 }
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001533 first = show_dep(1, Ifound, fp, e);
1534 first = show_dep(first, key_top, fp, e);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001535 if(first == 0)
1536 putchar('\n');
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001537 } else {
1538 show_dep(-1, key_top, NULL, NULL);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001539 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001540 return NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001541 } 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 */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001544 /* direntry is directory. buff is returned */
1545 return bb_xstrdup(fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001546 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001547 /* hmm, direntry is device! */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001548 return NULL;
1549}
1550
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001551/* from libbb but inlined for speed considerations */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001552static 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
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001563static void scan_dir_find_ch_files(const char *p)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001564{
1565 llist_t *dirs;
1566 llist_t *d_add;
1567 llist_t *d;
1568 struct dirent *de;
1569 DIR *dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001570 size_t dirlen;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001571
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001572 dirs = llist_add_to(NULL, bb_simplify_path(p));
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001573 replace = strlen(dirs->data);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001574 /* emulate recursion */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001575 while(dirs) {
1576 d_add = NULL;
1577 while(dirs) {
1578 dir = opendir(dirs->data);
1579 if (dir == NULL)
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001580 fprintf(stderr, "Warning: opendir(%s): %m\n", dirs->data);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001581 dirlen = strlen(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001582 while ((de = readdir(dir)) != NULL) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001583 char *found_dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001584
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001585 if (de->d_name[0] == '.')
1586 continue;
1587 found_dir = parse_chd(de->d_name, dirs->data, dirlen);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001588 if(found_dir)
1589 d_add = llist_add_to(d_add, found_dir);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001590 }
1591 closedir(dir);
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001592 free(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001593 d = dirs;
1594 dirs = dirs->link;
1595 free(d);
1596 }
1597 dirs = d_add;
1598 }
1599}
1600
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001601static void show_usage(void) __attribute__ ((noreturn));
1602static void show_usage(void)
1603{
1604 bb_error_d("%s\n%s\n", bb_mkdep_terse_options, bb_mkdep_full_options);
1605}
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001606
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001607int main(int argc, char **argv)
1608{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001609 char *s;
1610 int i;
1611 llist_t *fl;
1612
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001613 {
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +00001614 /* for bb_simplify_path, this program has no chdir() */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001615 /* libbb-like my xgetcwd() */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001616 unsigned path_max = 512;
1617
1618 s = xmalloc (path_max);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001619 while (getcwd (s, path_max) == NULL) {
1620 if(errno != ERANGE)
1621 bb_error_d("getcwd: %m");
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001622 free(s);
1623 s = xmalloc(path_max *= 2);
1624 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001625 pwd = s;
1626 }
1627
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001628 while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
1629 switch(i) {
1630 case 'I':
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001631 s = bb_simplify_path(optarg);
1632 Iop = llist_add_to(Iop, s);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001633 break;
1634 case 'c':
1635 s = bb_simplify_path(optarg);
1636 configs = llist_add_to(configs, s);
1637 break;
1638 case 'd':
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001639 dontgenerate_dep = 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001640 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 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001653 /* default kp */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001654 if(kp == NULL)
1655 kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001656 /* 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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001663 if(Iop == NULL)
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001664 Iop = llist_add_to(Iop, bb_simplify_path(LOCAL_INCLUDE_PATH));
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001665 if(configs == NULL) {
1666 s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
1667 configs = llist_add_to(configs, s);
1668 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001669 /* for c_lex */
1670 pagesizem1 = getpagesize() - 1;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001671 for(i = 0; i < UCHAR_MAX; i++) {
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001672 if(ISALNUM(i))
1673 isalnums[i] = i;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001674 /* set unparsed chars to speed up the parser */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001675 else if(i != CHR && i != STR && i != POUND && i != REM)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001676 first_chars[i] = ANY;
1677 }
1678 first_chars[i] = '-'; /* L_EOF */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001679
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001680 /* parse configs */
1681 for(fl = configs; fl; fl = fl->link) {
1682 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001683
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001684 if(stat(fl->data, &st))
1685 bb_error_d("stat(%s): %m", fl->data);
Rob Landley7bfa88f2006-02-13 19:16:41 +00001686 c_lex_config(fl->data, st.st_size);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001687 free(fl->data);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001688 /* trick for fast comparing found files with configs */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001689 fl->data = xmalloc(sizeof(struct stat));
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001690 memcpy(fl->data, &st, sizeof(struct stat));
1691 }
1692
1693 /* main loop */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001694 argv += optind;
1695 if(*argv) {
1696 while(*argv)
1697 scan_dir_find_ch_files(*argv++);
1698 } else {
1699 scan_dir_find_ch_files(".");
1700 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001701 store_keys();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001702 return 0;
1703}
1704
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001705/* partial and simplified libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001706static void bb_error_d(const char *s, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001707{
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
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001717static char *bb_asprint(const char *format, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001718{
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
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001732/* partial libbb routine as is */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001733
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001734static char *bb_simplify_path(const char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001735{
1736 char *s, *start, *p;
1737
1738 if (path[0] == '/')
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001739 start = bb_xstrdup(path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001740 else {
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +00001741 /* is not libbb, but this program has no chdir() */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001742 start = bb_asprint("%s/%s", pwd, path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001743 }
1744 p = s = start;
1745
1746 do {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001747 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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001757 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001758 continue;
1759 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001760 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001761 }
1762 *++p = *s;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001763 } while (*++s);
1764
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001765 if ((p == start) || (*p != '/')) { /* not a trailing slash */
1766 ++p; /* so keep last character */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001767 }
1768 *p = 0;
1769
1770 return start;
1771}