blob: 0c0b09dac20b74edf83d457509277ddadf9e9b93 [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
Bernhard Reutner-Fischerd2933752006-05-26 19:58:58 +000072#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
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000081
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000082/* partial and simplified libbb routine */
Bernhard Reutner-Fischerd2933752006-05-26 19:58:58 +000083static 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)));
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000085static char *bb_simplify_path(const char *path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000086
87/* stolen from libbb as is */
88typedef struct llist_s {
89 char *data;
90 struct llist_s *link;
91} llist_t;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000092
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000093static const char msg_enomem[] = "memory exhausted";
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000094
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +000095/* 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 */
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +0000121static size_t replace; /* replace current work directory with build dir */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000122
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +0000123static const char *kp; /* KEY path, argument of -k used */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000124static 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
Rob Landley7bfa88f2006-02-13 19:16:41 +0000157static 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
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000169/* for lexical analyser */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000170static int pagesizem1; /* padding mask = getpagesize() - 1 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000171
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000172/* for speed tricks */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000173static char first_chars[1+UCHAR_MAX]; /* + L_EOF */
174static char isalnums[1+UCHAR_MAX]; /* + L_EOF */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000175
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 */
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +0000186};
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000187
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000188#define CONFIG_MODE 0
Rob Landley7bfa88f2006-02-13 19:16:41 +0000189#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)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000195
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000196#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 */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000202#define REM '/' /* block comment */
203#define BS '\\' /* back slash */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000204#define POUND '#' /* # */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000205#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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000214#define DK 'K' /* #define KEY... (config mode) */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000215#define ANY '*' /* any unparsed chars */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000216
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
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000222#define L_EOF (1+UCHAR_MAX)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000223
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000224#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)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000234
Rob Landley7bfa88f2006-02-13 19:16:41 +0000235static 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)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000242
Rob Landley7bfa88f2006-02-13 19:16:41 +0000243#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
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +0000320#define SPEC_PREC (UNARYPREC+2)
Rob Landley7bfa88f2006-02-13 19:16:41 +0000321
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
Rob Landley7bfa88f2006-02-13 19:16:41 +0000533static 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)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000722{
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +0000723 int c;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000724 int state;
725 int line;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000726 char *id = id_s;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +0000727 size_t id_len = 0; /* stupid initialization */
Rob Landley7bfa88f2006-02-13 19:16:41 +0000728 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;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001041 size_t id_len = 0; /* stupid initialization */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001042 unsigned char *optr, *oend;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001043
1044 int fd;
1045 char *map;
1046 int mapsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001047
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001048 if(fsize == 0) {
1049 fprintf(stderr, "Warning: %s is empty\n", fname);
1050 return;
1051 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001052 fd = open(fname, O_RDONLY);
1053 if(fd < 0) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001054 perror(fname);
1055 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001056 }
1057 mapsize = (fsize+pagesizem1) & ~pagesizem1;
1058 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
1059 if ((long) map == -1)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001060 bb_error_d("%s: mmap: %m", fname);
1061
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001062 optr = (unsigned char *)map;
1063 oend = optr + fsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001064
1065 line = 1;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001066 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001067
1068 for(;;) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001069 getc1();
1070 for(;;) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001071 /* [ \t]+ eat first space */
1072 while(c == ' ' || c == '\t')
1073 getc1();
1074
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001075 if(state == S) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001076 while(first_chars[c] == ANY) {
1077 /* <S>unparsed */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001078 if(c == '\n')
1079 line++;
1080 getc1();
1081 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001082 if(c == L_EOF) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001083 /* <S><<EOF>> */
1084 munmap(map, mapsize);
1085 close(fd);
1086 return;
1087 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001088 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001089 /* <S>/ */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001090 getc0();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001091 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001092 /* <S>"//"[^\n]* */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001093 do getc0(); while(c != '\n' && c != L_EOF);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001094 } else if(c == '*') {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001095 /* <S>[/][*] goto parse block comments */
1096 break;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001097 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001098 } else if(c == POUND) {
1099 /* <S># */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001100 state = c;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001101 getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001102 } else if(c == STR || c == CHR) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001103 /* <S>\"|\' */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001104 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 {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001122 /* <S>[A-Z_a-z0-9] */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001123
1124 /* trick for fast drop id
1125 if key with this first char undefined */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001126 if(first_chars[c] == 0) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001127 /* skip <S>[A-Z_a-z0-9]+ */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001128 do getc1(); while(isalnums[c]);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001129 } else {
1130 id_len = 0;
1131 do {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001132 /* <S>[A-Z_a-z0-9]+ */
1133 put_id(c);
1134 getc1();
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001135 } while(isalnums[c]);
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001136 check_key(key_top, id, id_len);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001137 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001138 }
1139 continue;
1140 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001141 /* begin preprocessor states */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001142 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001143 yy_error_d("unexpected EOF");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001144 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001145 /* <#.*>/ */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001146 getc0();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001147 if(c == REM)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001148 yy_error_d("detected // in preprocessor line");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001149 if(c == '*') {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001150 /* <#.*>[/][*] goto parse block comments */
1151 break;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001152 }
1153 /* hmm, #.*[/] */
1154 yy_error_d("strange preprocessor line");
1155 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001156 if(state == POUND) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001157 /* tricks */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001158 static const char * const p_preproc[] = {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001159 /* 0 1 2 3 4 5 6 */
1160 "", "", "", "", "ndef", "efine", "nclude"
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001161 };
Rob Landley7bfa88f2006-02-13 19:16:41 +00001162 size_t diu = first_chars_diu[c]; /* strlen and p_preproc ptr */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001163
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001164 state = S;
1165 if(diu != S) {
1166 getc1();
1167 id_len = 0;
1168 while(isalnums[c]) {
1169 put_id(c);
1170 getc1();
1171 }
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001172 /* str begins with c, read == strlen key and compared */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001173 if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001174 state = diu + '0';
1175 id_len = 0; /* common for save */
1176 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001177 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001178 while(isalnums[c]) getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001179 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001180 } else if(state == I) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001181 if(c == STR) {
1182 /* <I>\" */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001183 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();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001195 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001196 /* else another (may be wrong) #include ... */
1197 state = S;
Rob Landley7bfa88f2006-02-13 19:16:41 +00001198 } else /* if(state == D || state == U) */ {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001199 /* ignore depend with #define or #undef KEY */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001200 while(isalnums[c]) getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001201 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001202 }
1203 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001204
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");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001229}
1230
1231
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001232/* bb_simplify_path special variant for absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001233static size_t bb_qa_simplify_path(char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001234{
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001235 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);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001264}
1265
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001266static void parse_inc(const char *include, const char *fname)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001267{
1268 bb_key_t *cur;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001269 const char *p_i;
1270 llist_t *lo;
1271 char *ap;
1272 size_t key_sz;
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001273 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001274
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001275 if(*include == '/') {
1276 lo = NULL;
1277 ap = bb_xstrdup(include);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001278 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001279 int w;
1280 const char *p;
1281
1282 lo = Iop;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001283 p = strrchr(fname, '/'); /* fname has absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001284 w = (p-fname);
1285 /* find from current directory of source file */
1286 ap = bb_asprint("%.*s/%s", w, fname, include);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001287 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001288
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001289 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);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001295 return;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001296 }
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001297 if(stat(ap, &st) == 0) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001298 /* found */
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001299 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 */
"Vladimir N. Oleynik"b267f132006-02-17 09:05:41 +00001306 return;
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001307 }
1308 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001309 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);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001318 /* lo->data has absolute pathname */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001319 ap = bb_asprint("%s/%s", lo->data, include);
1320 lo = lo->link;
1321 }
1322
1323 cur = xmalloc(sizeof(bb_key_t));
Rob Landley7bfa88f2006-02-13 19:16:41 +00001324 cur->keyname = ap;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001325 cur->key_sz = key_sz;
Rob Landley7bfa88f2006-02-13 19:16:41 +00001326 cur->stored_path = ap;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001327 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;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001332}
1333
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001334static size_t max_rec_sz;
1335
1336static void parse_conf_opt(const char *opt, const char *val, size_t key_sz)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001337{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001338 bb_key_t *cur;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001339 char *k;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001340 char *p;
1341 size_t val_sz = 0;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001342
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001343 cur = check_key(key_top, opt, key_sz);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001344 if(cur != NULL) {
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001345 /* already present */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001346 cur->checked = NULL; /* store only */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001347 if(cur->value == NULL && val == NULL)
1348 return;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001349 if(cur->value != NULL && val != NULL && !strcmp(cur->value, val))
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001350 return;
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001351 k = cur->keyname;
1352 fprintf(stderr, "Warning: redefined %s\n", k);
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001353 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001354 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;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001369 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001370 /* save VAL */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001371 if(val) {
1372 if(*val == '\0') {
1373 cur->value = "";
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001374 } else {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001375 cur->value = p = cur->keyname + key_sz + 1;
1376 memcpy(p, val, val_sz);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001377 }
1378 } else {
1379 cur->value = NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001380 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001381 /* trick, save first char KEY for do fast identify id */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001382 first_chars[(int)*k] = *k;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001383
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001384 cur->stored_path = k = bb_asprint("%s/%s.h", kp, k);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001385 /* key conversion [A-Z_] -> [a-z/] */
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001386 for(p = k + kp_len + 1; *p; p++) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001387 if(*p >= 'A' && *p <= 'Z')
1388 *p = *p - 'A' + 'a';
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001389 else if(*p == '_' && p[1] > '9') /* do not change A_1 to A/1 */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001390 *p = '/';
1391 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001392}
1393
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001394static 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 {
"Vladimir N. Oleynik"6732af22006-02-15 12:29:37 +00001416 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);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001420 }
1421 }
1422 /* size_t -> ssize_t :( */
1423 rw_ret = (ssize_t)recordsz;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001424 /* check kp/key.h, compare after previous use */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001425 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}
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001464
1465static int show_dep(int first, bb_key_t *k, const char *name, const char *f)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001466{
1467 bb_key_t *cur;
1468
1469 for(cur = k; cur; cur = cur->next) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001470 if(cur->checked) {
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001471 if(first >= 0) {
1472 if(first) {
1473 if(f == NULL)
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001474 printf("\n%s:", name);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001475 else
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001476 printf("\n%s/%s:", pwd, name);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001477 first = 0;
1478 } else {
1479 printf(" \\\n ");
1480 }
1481 printf(" %s", cur->checked);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001482 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001483 cur->src_have_this_key = cur->checked;
1484 cur->checked = NULL;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001485 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001486 }
1487 return first;
1488}
1489
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001490static char *
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001491parse_chd(const char *fe, const char *p, size_t dirlen)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001492{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001493 struct stat st;
1494 char *fp;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001495 size_t df_sz;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001496 static char dir_and_entry[4096];
1497 size_t fe_sz = strlen(fe) + 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001498
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001499 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);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001502 fp = dir_and_entry;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001503 /* sprintf(fp, "%s/%s", p, fe); */
1504 memcpy(fp, p, dirlen);
1505 fp[dirlen] = '/';
1506 memcpy(fp + dirlen + 1, fe, fe_sz);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001507
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001508 if(stat(fp, &st)) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001509 fprintf(stderr, "Warning: stat(%s): %m\n", fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001510 return NULL;
1511 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001512 if(S_ISREG(st.st_mode)) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001513 llist_t *cfl;
1514 char *e = fp + df_sz - 3;
1515
1516 if(*e++ != '.' || (*e != 'c' && *e != 'h')) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001517 /* direntry is regular file, but is not *.[ch] */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001518 return NULL;
1519 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001520 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) {
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +00001524 /* skip already parsed bb_configs.h */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001525 return NULL;
1526 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001527 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001528 /* direntry is *.[ch] regular file and is not configs */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001529 c_lex_src(fp, st.st_size);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001530 if(!dontgenerate_dep) {
1531 int first;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001532 if(*e == 'c') {
1533 /* *.c -> *.o */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001534 *e = 'o';
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001535 /* /src_dir/path/file.o to path/file.o */
1536 fp += replace;
1537 if(*fp == '/')
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001538 fp++;
"Vladimir N. Oleynik"d5f2a182005-10-06 14:47:16 +00001539 } else {
1540 e = NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001541 }
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001542 first = show_dep(1, Ifound, fp, e);
1543 first = show_dep(first, key_top, fp, e);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001544 if(first == 0)
1545 putchar('\n');
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001546 } else {
1547 show_dep(-1, key_top, NULL, NULL);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001548 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001549 return NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001550 } 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 */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001553 /* direntry is directory. buff is returned */
1554 return bb_xstrdup(fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001555 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001556 /* hmm, direntry is device! */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001557 return NULL;
1558}
1559
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001560/* from libbb but inlined for speed considerations */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001561static 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
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001572static void scan_dir_find_ch_files(const char *p)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001573{
1574 llist_t *dirs;
1575 llist_t *d_add;
1576 llist_t *d;
1577 struct dirent *de;
1578 DIR *dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001579 size_t dirlen;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001580
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001581 dirs = llist_add_to(NULL, bb_simplify_path(p));
"Vladimir N. Oleynik"6c0642d2005-10-07 15:36:26 +00001582 replace = strlen(dirs->data);
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001583 /* emulate recursion */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001584 while(dirs) {
1585 d_add = NULL;
1586 while(dirs) {
1587 dir = opendir(dirs->data);
1588 if (dir == NULL)
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001589 fprintf(stderr, "Warning: opendir(%s): %m\n", dirs->data);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001590 dirlen = strlen(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001591 while ((de = readdir(dir)) != NULL) {
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001592 char *found_dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001593
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001594 if (de->d_name[0] == '.')
1595 continue;
1596 found_dir = parse_chd(de->d_name, dirs->data, dirlen);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001597 if(found_dir)
1598 d_add = llist_add_to(d_add, found_dir);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001599 }
1600 closedir(dir);
"Vladimir N. Oleynik"d128b712005-10-03 10:08:46 +00001601 free(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001602 d = dirs;
1603 dirs = dirs->link;
1604 free(d);
1605 }
1606 dirs = d_add;
1607 }
1608}
1609
Bernhard Reutner-Fischerd2933752006-05-26 19:58:58 +00001610static void show_usage(void) ATTRIBUTE ((noreturn));
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001611static void show_usage(void)
1612{
1613 bb_error_d("%s\n%s\n", bb_mkdep_terse_options, bb_mkdep_full_options);
1614}
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001615
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001616int main(int argc, char **argv)
1617{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001618 char *s;
1619 int i;
1620 llist_t *fl;
1621
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001622 {
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +00001623 /* for bb_simplify_path, this program has no chdir() */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001624 /* libbb-like my xgetcwd() */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001625 unsigned path_max = 512;
1626
1627 s = xmalloc (path_max);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001628 while (getcwd (s, path_max) == NULL) {
1629 if(errno != ERANGE)
1630 bb_error_d("getcwd: %m");
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001631 free(s);
1632 s = xmalloc(path_max *= 2);
1633 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001634 pwd = s;
1635 }
1636
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001637 while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
1638 switch(i) {
1639 case 'I':
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001640 s = bb_simplify_path(optarg);
1641 Iop = llist_add_to(Iop, s);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001642 break;
1643 case 'c':
1644 s = bb_simplify_path(optarg);
1645 configs = llist_add_to(configs, s);
1646 break;
1647 case 'd':
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001648 dontgenerate_dep = 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001649 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 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001662 /* default kp */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001663 if(kp == NULL)
1664 kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001665 /* 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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001672 if(Iop == NULL)
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001673 Iop = llist_add_to(Iop, bb_simplify_path(LOCAL_INCLUDE_PATH));
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001674 if(configs == NULL) {
1675 s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
1676 configs = llist_add_to(configs, s);
1677 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001678 /* for c_lex */
1679 pagesizem1 = getpagesize() - 1;
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001680 for(i = 0; i < UCHAR_MAX; i++) {
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00001681 if(ISALNUM(i))
1682 isalnums[i] = i;
"Vladimir N. Oleynik"63ca3bf2006-02-14 09:23:25 +00001683 /* set unparsed chars to speed up the parser */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001684 else if(i != CHR && i != STR && i != POUND && i != REM)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001685 first_chars[i] = ANY;
1686 }
1687 first_chars[i] = '-'; /* L_EOF */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001688
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001689 /* parse configs */
1690 for(fl = configs; fl; fl = fl->link) {
1691 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001692
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001693 if(stat(fl->data, &st))
1694 bb_error_d("stat(%s): %m", fl->data);
Rob Landley7bfa88f2006-02-13 19:16:41 +00001695 c_lex_config(fl->data, st.st_size);
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001696 free(fl->data);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001697 /* trick for fast comparing found files with configs */
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001698 fl->data = xmalloc(sizeof(struct stat));
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001699 memcpy(fl->data, &st, sizeof(struct stat));
1700 }
1701
1702 /* main loop */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001703 argv += optind;
1704 if(*argv) {
1705 while(*argv)
1706 scan_dir_find_ch_files(*argv++);
1707 } else {
1708 scan_dir_find_ch_files(".");
1709 }
"Vladimir N. Oleynik"083d3f42005-10-10 11:35:17 +00001710 store_keys();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001711 return 0;
1712}
1713
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001714/* partial and simplified libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001715static void bb_error_d(const char *s, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001716{
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
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001726static char *bb_asprint(const char *format, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001727{
1728 va_list p;
1729 int r;
1730 char *out;
1731
Bernhard Reutner-Fischerd2933752006-05-26 19:58:58 +00001732#ifdef __USE_GNU
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001733 va_start(p, format);
1734 r = vasprintf(&out, format, p);
1735 va_end(p);
Bernhard Reutner-Fischerd2933752006-05-26 19:58:58 +00001736#else
1737 out = xmalloc(BUFSIZ);
1738 va_start(p, format);
1739 r = vsprintf(out, format, p);
1740 va_end(p);
1741#endif
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001742
1743 if (r < 0)
1744 bb_error_d("bb_asprint: %m");
1745 return out;
1746}
1747
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +00001748/* partial libbb routine as is */
Rob Landley7bfa88f2006-02-13 19:16:41 +00001749
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001750static char *bb_simplify_path(const char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001751{
1752 char *s, *start, *p;
1753
1754 if (path[0] == '/')
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001755 start = bb_xstrdup(path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001756 else {
Bernhard Reutner-Fischer5ba53c02006-02-14 10:43:40 +00001757 /* is not libbb, but this program has no chdir() */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00001758 start = bb_asprint("%s/%s", pwd, path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001759 }
1760 p = s = start;
1761
1762 do {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001763 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 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001773 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001774 continue;
1775 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001776 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001777 }
1778 *++p = *s;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001779 } while (*++s);
1780
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +00001781 if ((p == start) || (*p != '/')) { /* not a trailing slash */
1782 ++p; /* so keep last character */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001783 }
1784 *p = 0;
1785
1786 return start;
1787}