diff options
| author | Rob Landley <rob@landley.net> | 2006-02-13 19:16:41 +0000 |
|---|---|---|
| committer | Rob Landley <rob@landley.net> | 2006-02-13 19:16:41 +0000 |
| commit | 7bfa88f315d71c7f7a1b76fcec3886c7506aca24 (patch) | |
| tree | 5995ddbb62eeda3512fa408b78bbd1eb8832ae4a /scripts | |
| parent | f251ec6847d28035ae42ad2c1ae94454d36c36d3 (diff) | |
| download | busybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.tar.gz busybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.tar.bz2 busybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.zip | |
New USE() macros
For each CONFIG_SYMBOL, include/bb_config.h now has both ENABLE_SYMBOL
and USE_SYMBOL(x). ENABLE_SYMBOL is still always defined (1 or 0) so that
if(ENABLE) should optimize out when it's zero. The USE_SYMBOL(X) will only
splice in X if the symbol is defined, otherwise it'll be empty.
Thus we can convert this:
#ifdef CONFIG_ARGS
opt = bb_getopt_ulflags(argc, argv, "ab:c"
#ifdef CONFIG_THINGY
"d:"
#endif
, &bvalue
#ifdef CONFIG_THINGY
, &thingy
#endif
);
#endif
into this:
if (ENABLE_ARGS) {
opt = bb_getopt_ulflags(argc, argv, "ab:c" USE_THINGY("d:"), &bvalue
USE_THINGY(, &thingy));
}
And it should produce the same code.
Unlike the old versions in include/_usage.h, the new USE_SYMBOL(x) can handle
commas in its arguments (as shown above). (The _usage.h file is obsolete and
no longer generated.)
Nobody should need to include config.h directly anymore, bb_config.h should
define all the configuration stuff we need. Someday, the CONFIG_SYMBOL
versions should go away in favor of ENABLE_SYMBOL and USE_SYMBOL().
Thanks to vodz for the new version of bb_mkdep.c that works with function
macros.
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/bb_mkdep.c | 931 |
1 files changed, 866 insertions, 65 deletions
diff --git a/scripts/bb_mkdep.c b/scripts/bb_mkdep.c index 3fea20aed..7219feef9 100644 --- a/scripts/bb_mkdep.c +++ b/scripts/bb_mkdep.c | |||
| @@ -1,10 +1,15 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Another fast dependencies generator for Makefiles, Version 3.0 | 2 | * Another fast dependencies generator for Makefiles, Version 4.0 |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru> | 4 | * Copyright (C) 2005,2006 by Vladimir Oleynik <dzo@simtreas.ru> |
| 5 | * | 5 | * |
| 6 | * mmaping file may be originally by Linus Torvalds. | 6 | * mmaping file may be originally by Linus Torvalds. |
| 7 | * | 7 | * |
| 8 | * infix parser/evaluator for #if expression | ||
| 9 | * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | ||
| 10 | * Copyright (c) 2001 Manuel Novoa III <mjn3@codepoet.org> | ||
| 11 | * Copyright (c) 2003 Vladimir Oleynik <dzo@simtreas.ru> | ||
| 12 | * | ||
| 8 | * bb_simplify_path() | 13 | * bb_simplify_path() |
| 9 | * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org> | 14 | * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org> |
| 10 | * | 15 | * |
| @@ -15,7 +20,7 @@ | |||
| 15 | * Copyright (C) 2003 Glenn McGrath | 20 | * Copyright (C) 2003 Glenn McGrath |
| 16 | * Copyright (C) Vladimir Oleynik <dzo@simtreas.ru> | 21 | * Copyright (C) Vladimir Oleynik <dzo@simtreas.ru> |
| 17 | * | 22 | * |
| 18 | * (c) 2005 Bernhard Fischer: | 23 | * (c) 2005,2006 Bernhard Fischer: |
| 19 | * - commentary typos, | 24 | * - commentary typos, |
| 20 | * - move "memory exhausted" into msg_enomem, | 25 | * - move "memory exhausted" into msg_enomem, |
| 21 | * - more verbose --help output. | 26 | * - more verbose --help output. |
| @@ -29,6 +34,7 @@ | |||
| 29 | * path/inc.h: include/config/key*.h found_included_include_*.h | 34 | * path/inc.h: include/config/key*.h found_included_include_*.h |
| 30 | * 5) save include/config/key*.h if changed after previous usage | 35 | * 5) save include/config/key*.h if changed after previous usage |
| 31 | * This program does not generate dependencies for #include <...> | 36 | * This program does not generate dependencies for #include <...> |
| 37 | * Config file can have #if #elif #else #ifdef #ifndef #endif lines | ||
| 32 | */ | 38 | */ |
| 33 | 39 | ||
| 34 | #define LOCAL_INCLUDE_PATH "include" | 40 | #define LOCAL_INCLUDE_PATH "include" |
| @@ -103,9 +109,9 @@ static llist_t *configs; /* list of -c usaged and them stat() after parsed */ | |||
| 103 | static llist_t *Iop; /* list of -I include usaged */ | 109 | static llist_t *Iop; /* list of -I include usaged */ |
| 104 | 110 | ||
| 105 | static char *pwd; /* current work directory */ | 111 | static char *pwd; /* current work directory */ |
| 106 | static size_t replace; /* replace current work directory with build dir */ | 112 | static size_t replace; /* replace current work derectory to build dir */ |
| 107 | 113 | ||
| 108 | static const char *kp; /* KEY path, argument of -k used */ | 114 | static const char *kp; /* KEY path, argument of -k usaged */ |
| 109 | static size_t kp_len; | 115 | static size_t kp_len; |
| 110 | static struct stat st_kp; /* stat(kp) */ | 116 | static struct stat st_kp; /* stat(kp) */ |
| 111 | 117 | ||
| @@ -139,22 +145,44 @@ static inline bb_key_t *check_key(bb_key_t *k, const char *nk, size_t key_sz) | |||
| 139 | return NULL; | 145 | return NULL; |
| 140 | } | 146 | } |
| 141 | 147 | ||
| 148 | static inline const char *lookup_key(const char *nk, size_t key_sz) | ||
| 149 | { | ||
| 150 | bb_key_t *cur; | ||
| 151 | |||
| 152 | for(cur = key_top; cur; cur = cur->next) { | ||
| 153 | if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) { | ||
| 154 | return cur->value; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | return NULL; | ||
| 158 | } | ||
| 159 | |||
| 142 | /* for lexical analyser */ | 160 | /* for lexical analyser */ |
| 143 | static int pagesizem1; /* padding mask = getpagesize() - 1 */ | 161 | static int pagesizem1; /* padding mask = getpagesize() - 1 */ |
| 144 | 162 | ||
| 145 | /* for speed tricks */ | 163 | /* for speed tricks */ |
| 146 | static char first_chars[1+UCHAR_MAX]; /* + L_EOF */ | 164 | static char first_chars[1+UCHAR_MAX]; /* + L_EOF */ |
| 147 | static char isalnums[1+UCHAR_MAX]; /* + L_EOF */ | 165 | static char isalnums[1+UCHAR_MAX]; /* + L_EOF */ |
| 148 | /* trick for fast find "define", "include", "undef" */ | 166 | |
| 149 | static const char first_chars_diu[UCHAR_MAX] = { | 167 | /* trick for fast find "define", "include", "undef", |
| 150 | [(int)'d'] = (char)5, /* strlen("define") - 1; */ | 168 | "if((n)def)" "else", "endif" */ |
| 151 | [(int)'i'] = (char)6, /* strlen("include") - 1; */ | 169 | static const char * const preproc[] = { |
| 152 | [(int)'u'] = (char)4, /* strlen("undef") - 1; */ | 170 | /* 0 1 2 3 4 5 6 7 8 9 */ |
| 171 | "", "efine", "lif", "lse", "ndif", "f", "fdef", "fndef", "nclude", "ndef" }; | ||
| 172 | static const unsigned char first_chars_deiu[UCHAR_MAX] = { | ||
| 173 | [(int)'d'] = (unsigned char)(1|0x10), /* define */ | ||
| 174 | [(int)'e'] = (unsigned char)(2|0x40), /* elif, else, endif */ | ||
| 175 | [(int)'i'] = (unsigned char)(5|0x80), /* if ifdef ifndef include */ | ||
| 176 | [(int)'u'] = (unsigned char)(9|0x90), /* undef */ | ||
| 153 | }; | 177 | }; |
| 154 | 178 | ||
| 155 | #define CONFIG_MODE 0 | 179 | #define CONFIG_MODE 0 |
| 156 | #define SOURCES_MODE 1 | 180 | #define IF0_MODE 1 /* #if 0 */ |
| 157 | static int mode; | 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) | ||
| 158 | 186 | ||
| 159 | #define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s) | 187 | #define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s) |
| 160 | 188 | ||
| @@ -165,9 +193,15 @@ static int mode; | |||
| 165 | #define REM '/' /* block comment */ | 193 | #define REM '/' /* block comment */ |
| 166 | #define BS '\\' /* back slash */ | 194 | #define BS '\\' /* back slash */ |
| 167 | #define POUND '#' /* # */ | 195 | #define POUND '#' /* # */ |
| 168 | #define D '5' /* #define preprocessor's directive */ | 196 | #define D '1' /* #define preprocessor's directive */ |
| 169 | #define I '6' /* #include preprocessor's directive */ | 197 | #define EI '2' /* #elif preprocessor's directive */ |
| 170 | #define U '4' /* #undef 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 */ | ||
| 171 | #define DK 'K' /* #define KEY... (config mode) */ | 205 | #define DK 'K' /* #define KEY... (config mode) */ |
| 172 | #define ANY '*' /* any unparsed chars */ | 206 | #define ANY '*' /* any unparsed chars */ |
| 173 | 207 | ||
| @@ -189,16 +223,508 @@ static char id_s[4096]; | |||
| 189 | #define put_id(ic) do { if(id_len == sizeof(id_s)) goto too_long; \ | 223 | #define put_id(ic) do { if(id_len == sizeof(id_s)) goto too_long; \ |
| 190 | id[id_len++] = ic; } while(0) | 224 | id[id_len++] = ic; } while(0) |
| 191 | 225 | ||
| 226 | static char ifcpp_stack[1024]; | ||
| 227 | static int ptr_ifcpp_stack; | ||
| 228 | #define push_mode() do { \ | ||
| 229 | if(ptr_ifcpp_stack == (int)sizeof(ifcpp_stack)) \ | ||
| 230 | yy_error_d("#if* stack overflow"); \ | ||
| 231 | ifcpp_stack[ptr_ifcpp_stack++] = (char)mode; \ | ||
| 232 | } while(0) | ||
| 233 | |||
| 234 | #define pop_mode() do { \ | ||
| 235 | if(ptr_ifcpp_stack == 0) \ | ||
| 236 | yy_error_d("unexpected #endif"); \ | ||
| 237 | mode = ifcpp_stack[--ptr_ifcpp_stack]; \ | ||
| 238 | } while(0) | ||
| 239 | |||
| 240 | /* #if expression */ | ||
| 241 | typedef long long arith_t; | ||
| 242 | |||
| 243 | static arith_t arith (const char *expr, int *perrcode); | ||
| 244 | |||
| 245 | /* The code uses a simple two-stack algorithm. See | ||
| 246 | * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html | ||
| 247 | * for a detailed explanation of the infix-to-postfix algorithm on which | ||
| 248 | * this is based (this code differs in that it applies operators immediately | ||
| 249 | * to the stack instead of adding them to a queue to end up with an | ||
| 250 | * expression). */ | ||
| 251 | |||
| 252 | #define arith_isspace(arithval) \ | ||
| 253 | (arithval == ' ' || arithval == '\v' || arithval == '\t' || arithval == '\f') | ||
| 254 | |||
| 255 | |||
| 256 | typedef unsigned char operator; | ||
| 257 | |||
| 258 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the | ||
| 259 | * precedence, and 3 high bits are an ID unique across operators of that | ||
| 260 | * precedence. The ID portion is so that multiple operators can have the | ||
| 261 | * same precedence, ensuring that the leftmost one is evaluated first. | ||
| 262 | * Consider * and /. */ | ||
| 263 | |||
| 264 | #define tok_decl(prec,id) (((id)<<5)|(prec)) | ||
| 265 | #define PREC(op) ((op) & 0x1F) | ||
| 266 | |||
| 267 | #define TOK_LPAREN tok_decl(0,0) | ||
| 268 | |||
| 269 | #define TOK_COMMA tok_decl(1,0) | ||
| 270 | |||
| 271 | /* conditional is right associativity too */ | ||
| 272 | #define TOK_CONDITIONAL tok_decl(2,0) | ||
| 273 | #define TOK_CONDITIONAL_SEP tok_decl(2,1) | ||
| 274 | |||
| 275 | #define TOK_OR tok_decl(3,0) | ||
| 276 | |||
| 277 | #define TOK_AND tok_decl(4,0) | ||
| 278 | |||
| 279 | #define TOK_BOR tok_decl(5,0) | ||
| 280 | |||
| 281 | #define TOK_BXOR tok_decl(6,0) | ||
| 282 | |||
| 283 | #define TOK_BAND tok_decl(7,0) | ||
| 284 | |||
| 285 | #define TOK_EQ tok_decl(8,0) | ||
| 286 | #define TOK_NE tok_decl(8,1) | ||
| 287 | |||
| 288 | #define TOK_LT tok_decl(9,0) | ||
| 289 | #define TOK_GT tok_decl(9,1) | ||
| 290 | #define TOK_GE tok_decl(9,2) | ||
| 291 | #define TOK_LE tok_decl(9,3) | ||
| 292 | |||
| 293 | #define TOK_LSHIFT tok_decl(10,0) | ||
| 294 | #define TOK_RSHIFT tok_decl(10,1) | ||
| 295 | |||
| 296 | #define TOK_ADD tok_decl(11,0) | ||
| 297 | #define TOK_SUB tok_decl(11,1) | ||
| 298 | |||
| 299 | #define TOK_MUL tok_decl(12,0) | ||
| 300 | #define TOK_DIV tok_decl(12,1) | ||
| 301 | #define TOK_REM tok_decl(12,2) | ||
| 302 | |||
| 303 | /* For now unary operators. */ | ||
| 304 | #define UNARYPREC 13 | ||
| 305 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
| 306 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
| 307 | |||
| 308 | #define TOK_UMINUS tok_decl(UNARYPREC+1,0) | ||
| 309 | #define TOK_UPLUS tok_decl(UNARYPREC+1,1) | ||
| 310 | |||
| 311 | #define SPEC_PREC (UNARYPREC+1) | ||
| 312 | |||
| 313 | #define TOK_NUM tok_decl(SPEC_PREC, 0) | ||
| 314 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | ||
| 192 | 315 | ||
| 193 | /* stupid C lexical analyser */ | 316 | #define NUMPTR (*numstackptr) |
| 194 | static void c_lex(const char *fname, long fsize) | 317 | |
| 318 | typedef struct ARITCH_VAR_NUM { | ||
| 319 | arith_t val; | ||
| 320 | arith_t contidional_second_val; | ||
| 321 | char contidional_second_val_initialized; | ||
| 322 | } v_n_t; | ||
| 323 | |||
| 324 | |||
| 325 | typedef struct CHK_VAR_RECURSIVE_LOOPED { | ||
| 326 | const char *var; | ||
| 327 | size_t var_sz; | ||
| 328 | struct CHK_VAR_RECURSIVE_LOOPED *next; | ||
| 329 | } chk_var_recursive_looped_t; | ||
| 330 | |||
| 331 | static chk_var_recursive_looped_t *prev_chk_var_recursive; | ||
| 332 | |||
| 333 | |||
| 334 | static int arith_lookup_val(const char *var, size_t key_sz, arith_t *pval) | ||
| 335 | { | ||
| 336 | const char * p = lookup_key(var, key_sz); | ||
| 337 | |||
| 338 | if(p) { | ||
| 339 | int errcode; | ||
| 340 | |||
| 341 | /* recursive try as expression */ | ||
| 342 | chk_var_recursive_looped_t *cur; | ||
| 343 | chk_var_recursive_looped_t cur_save; | ||
| 344 | |||
| 345 | for(cur = prev_chk_var_recursive; cur; cur = cur->next) { | ||
| 346 | if(cur->var_sz == key_sz && memcmp(cur->var, var, key_sz) == 0) { | ||
| 347 | /* expression recursion loop detected */ | ||
| 348 | return -5; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | /* save current lookuped var name */ | ||
| 352 | cur = prev_chk_var_recursive; | ||
| 353 | cur_save.var = var; | ||
| 354 | cur_save.var_sz = key_sz; | ||
| 355 | cur_save.next = cur; | ||
| 356 | prev_chk_var_recursive = &cur_save; | ||
| 357 | |||
| 358 | *pval = arith (p, &errcode); | ||
| 359 | /* restore previous ptr after recursiving */ | ||
| 360 | prev_chk_var_recursive = cur; | ||
| 361 | return errcode; | ||
| 362 | } else { | ||
| 363 | /* disallow undefined var */ | ||
| 364 | fprintf(stderr, "%.*s ", (int)key_sz, var); | ||
| 365 | return -4; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | /* "applying" a token means performing it on the top elements on the integer | ||
| 370 | * stack. For a unary operator it will only change the top element, but a | ||
| 371 | * binary operator will pop two arguments and push a result */ | ||
| 372 | static inline int | ||
| 373 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | ||
| 374 | { | ||
| 375 | v_n_t *numptr_m1; | ||
| 376 | arith_t numptr_val, rez; | ||
| 377 | |||
| 378 | if (NUMPTR == numstack) goto err; /* There is no operator that can work | ||
| 379 | without arguments */ | ||
| 380 | numptr_m1 = NUMPTR - 1; | ||
| 381 | |||
| 382 | rez = numptr_m1->val; | ||
| 383 | if (op == TOK_UMINUS) | ||
| 384 | rez *= -1; | ||
| 385 | else if (op == TOK_NOT) | ||
| 386 | rez = !rez; | ||
| 387 | else if (op == TOK_BNOT) | ||
| 388 | rez = ~rez; | ||
| 389 | else if (op != TOK_UPLUS) { | ||
| 390 | /* Binary operators */ | ||
| 391 | |||
| 392 | /* check and binary operators need two arguments */ | ||
| 393 | if (numptr_m1 == numstack) goto err; | ||
| 394 | |||
| 395 | /* ... and they pop one */ | ||
| 396 | --NUMPTR; | ||
| 397 | numptr_val = rez; | ||
| 398 | if (op == TOK_CONDITIONAL) { | ||
| 399 | if(! numptr_m1->contidional_second_val_initialized) { | ||
| 400 | /* protect $((expr1 ? expr2)) without ": expr" */ | ||
| 401 | goto err; | ||
| 402 | } | ||
| 403 | rez = numptr_m1->contidional_second_val; | ||
| 404 | } else if(numptr_m1->contidional_second_val_initialized) { | ||
| 405 | /* protect $((expr1 : expr2)) without "expr ? " */ | ||
| 406 | goto err; | ||
| 407 | } | ||
| 408 | numptr_m1 = NUMPTR - 1; | ||
| 409 | if (op == TOK_CONDITIONAL) { | ||
| 410 | numptr_m1->contidional_second_val = rez; | ||
| 411 | } | ||
| 412 | rez = numptr_m1->val; | ||
| 413 | if (op == TOK_BOR) | ||
| 414 | rez |= numptr_val; | ||
| 415 | else if (op == TOK_OR) | ||
| 416 | rez = numptr_val || rez; | ||
| 417 | else if (op == TOK_BAND) | ||
| 418 | rez &= numptr_val; | ||
| 419 | else if (op == TOK_BXOR) | ||
| 420 | rez ^= numptr_val; | ||
| 421 | else if (op == TOK_AND) | ||
| 422 | rez = rez && numptr_val; | ||
| 423 | else if (op == TOK_EQ) | ||
| 424 | rez = (rez == numptr_val); | ||
| 425 | else if (op == TOK_NE) | ||
| 426 | rez = (rez != numptr_val); | ||
| 427 | else if (op == TOK_GE) | ||
| 428 | rez = (rez >= numptr_val); | ||
| 429 | else if (op == TOK_RSHIFT) | ||
| 430 | rez >>= numptr_val; | ||
| 431 | else if (op == TOK_LSHIFT) | ||
| 432 | rez <<= numptr_val; | ||
| 433 | else if (op == TOK_GT) | ||
| 434 | rez = (rez > numptr_val); | ||
| 435 | else if (op == TOK_LT) | ||
| 436 | rez = (rez < numptr_val); | ||
| 437 | else if (op == TOK_LE) | ||
| 438 | rez = (rez <= numptr_val); | ||
| 439 | else if (op == TOK_MUL) | ||
| 440 | rez *= numptr_val; | ||
| 441 | else if (op == TOK_ADD) | ||
| 442 | rez += numptr_val; | ||
| 443 | else if (op == TOK_SUB) | ||
| 444 | rez -= numptr_val; | ||
| 445 | else if (op == TOK_COMMA) | ||
| 446 | rez = numptr_val; | ||
| 447 | else if (op == TOK_CONDITIONAL_SEP) { | ||
| 448 | if (numptr_m1 == numstack) { | ||
| 449 | /* protect $((expr : expr)) without "expr ? " */ | ||
| 450 | goto err; | ||
| 451 | } | ||
| 452 | numptr_m1->contidional_second_val_initialized = op; | ||
| 453 | numptr_m1->contidional_second_val = numptr_val; | ||
| 454 | } | ||
| 455 | else if (op == TOK_CONDITIONAL) { | ||
| 456 | rez = rez ? | ||
| 457 | numptr_val : numptr_m1->contidional_second_val; | ||
| 458 | } | ||
| 459 | else if(numptr_val==0) /* zero divisor check */ | ||
| 460 | return -2; | ||
| 461 | else if (op == TOK_DIV) | ||
| 462 | rez /= numptr_val; | ||
| 463 | else if (op == TOK_REM) | ||
| 464 | rez %= numptr_val; | ||
| 465 | } | ||
| 466 | numptr_m1->val = rez; | ||
| 467 | return 0; | ||
| 468 | err: return(-1); | ||
| 469 | } | ||
| 470 | |||
| 471 | /* longest must first */ | ||
| 472 | static const char op_tokens[] = { | ||
| 473 | '<','<', 0, TOK_LSHIFT, | ||
| 474 | '>','>', 0, TOK_RSHIFT, | ||
| 475 | '|','|', 0, TOK_OR, | ||
| 476 | '&','&', 0, TOK_AND, | ||
| 477 | '!','=', 0, TOK_NE, | ||
| 478 | '<','=', 0, TOK_LE, | ||
| 479 | '>','=', 0, TOK_GE, | ||
| 480 | '=','=', 0, TOK_EQ, | ||
| 481 | '!', 0, TOK_NOT, | ||
| 482 | '<', 0, TOK_LT, | ||
| 483 | '>', 0, TOK_GT, | ||
| 484 | '|', 0, TOK_BOR, | ||
| 485 | '&', 0, TOK_BAND, | ||
| 486 | '*', 0, TOK_MUL, | ||
| 487 | '/', 0, TOK_DIV, | ||
| 488 | '%', 0, TOK_REM, | ||
| 489 | '+', 0, TOK_ADD, | ||
| 490 | '-', 0, TOK_SUB, | ||
| 491 | '^', 0, TOK_BXOR, | ||
| 492 | '~', 0, TOK_BNOT, | ||
| 493 | ',', 0, TOK_COMMA, | ||
| 494 | '?', 0, TOK_CONDITIONAL, | ||
| 495 | ':', 0, TOK_CONDITIONAL_SEP, | ||
| 496 | ')', 0, TOK_RPAREN, | ||
| 497 | '(', 0, TOK_LPAREN, | ||
| 498 | 0 | ||
| 499 | }; | ||
| 500 | /* ptr to ")" */ | ||
| 501 | #define endexpression &op_tokens[sizeof(op_tokens)-7] | ||
| 502 | |||
| 503 | /* | ||
| 504 | * Return of a legal variable name (a letter or underscore followed by zero or | ||
| 505 | * more letters, underscores, and digits). | ||
| 506 | */ | ||
| 507 | |||
| 508 | static inline char * | ||
| 509 | endofname(const char *name) | ||
| 510 | { | ||
| 511 | char *p; | ||
| 512 | |||
| 513 | p = (char *) name; | ||
| 514 | if (! ID(*p)) | ||
| 515 | return p; | ||
| 516 | while (*++p) { | ||
| 517 | if (! ISALNUM(*p)) | ||
| 518 | break; | ||
| 519 | } | ||
| 520 | return p; | ||
| 521 | } | ||
| 522 | |||
| 523 | |||
| 524 | /* Like strncpy but make sure the resulting string is always 0 terminated. */ | ||
| 525 | static inline char * safe_strncpy(char *dst, const char *src, size_t size) | ||
| 526 | { | ||
| 527 | dst[size-1] = '\0'; | ||
| 528 | return strncpy(dst, src, size-1); | ||
| 529 | } | ||
| 530 | |||
| 531 | static arith_t arith (const char *expr, int *perrcode) | ||
| 532 | { | ||
| 533 | char arithval; /* Current character under analysis */ | ||
| 534 | operator lasttok, op; | ||
| 535 | operator prec; | ||
| 536 | |||
| 537 | const char *p = endexpression; | ||
| 538 | int errcode; | ||
| 539 | |||
| 540 | size_t datasizes = strlen(expr) + 2; | ||
| 541 | |||
| 542 | /* Stack of integers */ | ||
| 543 | /* The proof that there can be no more than strlen(startbuf)/2+1 integers | ||
| 544 | * in any given correct or incorrect expression is left as an exercise to | ||
| 545 | * the reader. */ | ||
| 546 | v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), | ||
| 547 | *numstackptr = numstack; | ||
| 548 | /* Stack of operator tokens */ | ||
| 549 | operator *stack = alloca((datasizes) * sizeof(operator)), | ||
| 550 | *stackptr = stack; | ||
| 551 | |||
| 552 | *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ | ||
| 553 | *perrcode = errcode = 0; | ||
| 554 | |||
| 555 | while(1) { | ||
| 556 | if ((arithval = *expr) == 0) { | ||
| 557 | if (p == endexpression) { | ||
| 558 | /* Null expression. */ | ||
| 559 | err: | ||
| 560 | return (*perrcode = -1); | ||
| 561 | } | ||
| 562 | |||
| 563 | /* This is only reached after all tokens have been extracted from the | ||
| 564 | * input stream. If there are still tokens on the operator stack, they | ||
| 565 | * are to be applied in order. At the end, there should be a final | ||
| 566 | * result on the integer stack */ | ||
| 567 | |||
| 568 | if (expr != endexpression + 1) { | ||
| 569 | /* If we haven't done so already, */ | ||
| 570 | /* append a closing right paren */ | ||
| 571 | expr = endexpression; | ||
| 572 | /* and let the loop process it. */ | ||
| 573 | continue; | ||
| 574 | } | ||
| 575 | /* At this point, we're done with the expression. */ | ||
| 576 | if (numstackptr != numstack+1) { | ||
| 577 | /* ... but if there isn't, it's bad */ | ||
| 578 | goto err; | ||
| 579 | } | ||
| 580 | ret: | ||
| 581 | *perrcode = errcode; | ||
| 582 | return numstack->val; | ||
| 583 | } else { | ||
| 584 | /* Continue processing the expression. */ | ||
| 585 | if (arith_isspace(arithval)) { | ||
| 586 | /* Skip whitespace */ | ||
| 587 | goto prologue; | ||
| 588 | } | ||
| 589 | if((p = endofname(expr)) != expr) { | ||
| 590 | size_t var_name_size = (p-expr); | ||
| 591 | |||
| 592 | if(var_name_size == 7 && | ||
| 593 | strncmp(expr, "defined", var_name_size) == 0) { | ||
| 594 | int brace_form = 0; | ||
| 595 | const char *v; | ||
| 596 | |||
| 597 | while(arith_isspace(*p)) p++; | ||
| 598 | if(*p == '(') { | ||
| 599 | p++; | ||
| 600 | while(arith_isspace(*p)) p++; | ||
| 601 | brace_form = 1; | ||
| 602 | } | ||
| 603 | expr = p; | ||
| 604 | if((p = endofname(expr)) == expr) | ||
| 605 | goto err; | ||
| 606 | var_name_size = (p-expr); | ||
| 607 | while(arith_isspace(*p)) p++; | ||
| 608 | if(brace_form && *p++ != ')') | ||
| 609 | goto err; | ||
| 610 | v = lookup_key(expr, var_name_size); | ||
| 611 | numstackptr->val = (v != NULL) ? 1 : 0; | ||
| 612 | } else { | ||
| 613 | errcode = arith_lookup_val(expr, var_name_size, | ||
| 614 | &(numstackptr->val)); | ||
| 615 | if(errcode) goto ret; | ||
| 616 | } | ||
| 617 | expr = p; | ||
| 618 | num: | ||
| 619 | numstackptr->contidional_second_val_initialized = 0; | ||
| 620 | numstackptr++; | ||
| 621 | lasttok = TOK_NUM; | ||
| 622 | continue; | ||
| 623 | } else if (arithval >= '0' && arithval <= '9') { | ||
| 624 | numstackptr->val = strtoll(expr, (char **) &expr, 0); | ||
| 625 | while(*expr == 'l' || *expr == 'L' || *expr == 'u' || | ||
| 626 | *expr == 'U') | ||
| 627 | expr++; | ||
| 628 | goto num; | ||
| 629 | } | ||
| 630 | for(p = op_tokens; ; p++) { | ||
| 631 | const char *o; | ||
| 632 | |||
| 633 | if(*p == 0) { | ||
| 634 | /* strange operator not found */ | ||
| 635 | goto err; | ||
| 636 | } | ||
| 637 | for(o = expr; *p && *o == *p; p++) | ||
| 638 | o++; | ||
| 639 | if(! *p) { | ||
| 640 | /* found */ | ||
| 641 | expr = o - 1; | ||
| 642 | break; | ||
| 643 | } | ||
| 644 | /* skip tail uncompared token */ | ||
| 645 | while(*p) | ||
| 646 | p++; | ||
| 647 | /* skip zero delim */ | ||
| 648 | p++; | ||
| 649 | } | ||
| 650 | op = p[1]; | ||
| 651 | |||
| 652 | /* Plus and minus are binary (not unary) _only_ if the last | ||
| 653 | * token was as number, or a right paren (which pretends to be | ||
| 654 | * a number, since it evaluates to one). Think about it. | ||
| 655 | * It makes sense. */ | ||
| 656 | if (lasttok != TOK_NUM) { | ||
| 657 | if(op == TOK_ADD) | ||
| 658 | op = TOK_UPLUS; | ||
| 659 | else if(op == TOK_SUB) | ||
| 660 | op = TOK_UMINUS; | ||
| 661 | } | ||
| 662 | /* We don't want a unary operator to cause recursive descent on the | ||
| 663 | * stack, because there can be many in a row and it could cause an | ||
| 664 | * operator to be evaluated before its argument is pushed onto the | ||
| 665 | * integer stack. */ | ||
| 666 | /* But for binary operators, "apply" everything on the operator | ||
| 667 | * stack until we find an operator with a lesser priority than the | ||
| 668 | * one we have just extracted. */ | ||
| 669 | /* Left paren is given the lowest priority so it will never be | ||
| 670 | * "applied" in this way. | ||
| 671 | * if associativity is right and priority eq, applied also skip | ||
| 672 | */ | ||
| 673 | prec = PREC(op); | ||
| 674 | if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { | ||
| 675 | /* not left paren or unary */ | ||
| 676 | if (lasttok != TOK_NUM) { | ||
| 677 | /* binary op must be preceded by a num */ | ||
| 678 | goto err; | ||
| 679 | } | ||
| 680 | while (stackptr != stack) { | ||
| 681 | if (op == TOK_RPAREN) { | ||
| 682 | /* The algorithm employed here is simple: while we don't | ||
| 683 | * hit an open paren nor the bottom of the stack, pop | ||
| 684 | * tokens and apply them */ | ||
| 685 | if (stackptr[-1] == TOK_LPAREN) { | ||
| 686 | --stackptr; | ||
| 687 | /* Any operator directly after a */ | ||
| 688 | lasttok = TOK_NUM; | ||
| 689 | /* close paren should consider itself binary */ | ||
| 690 | goto prologue; | ||
| 691 | } | ||
| 692 | } else { | ||
| 693 | operator prev_prec = PREC(stackptr[-1]); | ||
| 694 | |||
| 695 | if (prev_prec < prec) | ||
| 696 | break; | ||
| 697 | /* check right assoc */ | ||
| 698 | if(prev_prec == prec && prec == PREC(TOK_CONDITIONAL)) | ||
| 699 | break; | ||
| 700 | } | ||
| 701 | errcode = arith_apply(*--stackptr, numstack, &numstackptr); | ||
| 702 | if(errcode) goto ret; | ||
| 703 | } | ||
| 704 | if (op == TOK_RPAREN) { | ||
| 705 | goto err; | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | /* Push this operator to the stack and remember it. */ | ||
| 710 | *stackptr++ = lasttok = op; | ||
| 711 | |||
| 712 | prologue: | ||
| 713 | ++expr; | ||
| 714 | } | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 718 | /* stupid C lexical analyser for configs.h */ | ||
| 719 | static void c_lex_config(const char *fname, long fsize) | ||
| 195 | { | 720 | { |
| 196 | int c; | 721 | int c; |
| 197 | int state; | 722 | int state; |
| 198 | int line; | 723 | int line; |
| 199 | char *id = id_s; | 724 | char *id = id_s; |
| 200 | size_t id_len = 0; /* stupid initialization */ | 725 | size_t id_len = 0; /* stupid initialize */ |
| 201 | unsigned char *optr, *oend; | 726 | unsigned char *optr, *oend; |
| 727 | int mode = CONFIG_MODE; | ||
| 202 | 728 | ||
| 203 | int fd; | 729 | int fd; |
| 204 | char *map; | 730 | char *map; |
| @@ -242,6 +768,8 @@ static void c_lex(const char *fname, long fsize) | |||
| 242 | /* <S><<EOF>> */ | 768 | /* <S><<EOF>> */ |
| 243 | munmap(map, mapsize); | 769 | munmap(map, mapsize); |
| 244 | close(fd); | 770 | close(fd); |
| 771 | if(mode != CONFIG_MODE) | ||
| 772 | yy_error_d("expected #endif"); | ||
| 245 | return; | 773 | return; |
| 246 | } | 774 | } |
| 247 | if(c == REM) { | 775 | if(c == REM) { |
| @@ -282,7 +810,7 @@ static void c_lex(const char *fname, long fsize) | |||
| 282 | 810 | ||
| 283 | /* trick for fast drop id | 811 | /* trick for fast drop id |
| 284 | if key with this first char undefined */ | 812 | if key with this first char undefined */ |
| 285 | if(first_chars[c] == 0) { | 813 | if(first_chars[c] == 0 || (mode & FALSE_MODES) != 0) { |
| 286 | /* skip <S>[A-Z_a-z0-9]+ */ | 814 | /* skip <S>[A-Z_a-z0-9]+ */ |
| 287 | do getc1(); while(isalnums[c]); | 815 | do getc1(); while(isalnums[c]); |
| 288 | } else { | 816 | } else { |
| @@ -314,30 +842,37 @@ static void c_lex(const char *fname, long fsize) | |||
| 314 | } | 842 | } |
| 315 | if(state == POUND) { | 843 | if(state == POUND) { |
| 316 | /* tricks */ | 844 | /* tricks */ |
| 317 | static const char * const preproc[] = { | 845 | int diu = (int)first_chars_deiu[c]; /* preproc ptr */ |
| 318 | /* 0 1 2 3 4 5 6 */ | ||
| 319 | "", "", "", "", "ndef", "efine", "nclude" | ||
| 320 | }; | ||
| 321 | size_t diu = first_chars_diu[c]; /* strlen and preproc ptr */ | ||
| 322 | 846 | ||
| 323 | state = S; | 847 | state = S; |
| 324 | if(diu != S) { | 848 | if(diu != S) { |
| 849 | int p_num_str, p_num_max; | ||
| 850 | |||
| 325 | getc1(); | 851 | getc1(); |
| 326 | id_len = 0; | 852 | id_len = 0; |
| 327 | while(isalnums[c]) { | 853 | while(isalnums[c]) { |
| 328 | put_id(c); | 854 | put_id(c); |
| 329 | getc1(); | 855 | getc1(); |
| 330 | } | 856 | } |
| 331 | /* str begins with c, read == strlen key and compared */ | 857 | put_id(0); |
| 332 | if(diu == id_len && !memcmp(id, preproc[diu], diu)) { | 858 | p_num_str = diu & 0xf; |
| 333 | state = diu + '0'; | 859 | p_num_max = diu >> 4; |
| 334 | id_len = 0; /* common for save */ | 860 | for(diu = p_num_str; diu <= p_num_max; diu++) |
| 861 | if(!strcmp(id, preproc[diu])) { | ||
| 862 | state = (diu + '0'); | ||
| 863 | /* common */ | ||
| 864 | id_len = 0; | ||
| 865 | break; | ||
| 335 | } | 866 | } |
| 336 | } else { | 867 | } else { |
| 337 | while(isalnums[c]) getc1(); | 868 | while(isalnums[c]) getc1(); |
| 338 | } | 869 | } |
| 870 | } else if(state == EF) { | ||
| 871 | /* #endif */ | ||
| 872 | pop_mode(); | ||
| 873 | state = S; | ||
| 339 | } else if(state == I) { | 874 | } else if(state == I) { |
| 340 | if(c == STR) { | 875 | if(c == STR && (mode & FALSE_MODES) == 0) { |
| 341 | /* <I>\" */ | 876 | /* <I>\" */ |
| 342 | for(;;) { | 877 | for(;;) { |
| 343 | getc1(); | 878 | getc1(); |
| @@ -354,31 +889,84 @@ static void c_lex(const char *fname, long fsize) | |||
| 354 | } | 889 | } |
| 355 | /* else another (may be wrong) #include ... */ | 890 | /* else another (may be wrong) #include ... */ |
| 356 | state = S; | 891 | state = S; |
| 892 | } else if(state == F) { | ||
| 893 | arith_t t; | ||
| 894 | int errcode; | ||
| 895 | |||
| 896 | while(c != '\n' && c != L_EOF) { | ||
| 897 | put_id(c); | ||
| 898 | getc1(); | ||
| 899 | } | ||
| 900 | put_id(0); | ||
| 901 | t = arith(id, &errcode); | ||
| 902 | if (errcode < 0) { | ||
| 903 | if (errcode == -2) | ||
| 904 | yy_error_d("divide by zero"); | ||
| 905 | else if (errcode == -4) | ||
| 906 | yy_error_d("undefined"); | ||
| 907 | else if (errcode == -5) | ||
| 908 | yy_error_d("expression recursion loop detected"); | ||
| 909 | else | ||
| 910 | yy_error_d("syntax error"); | ||
| 911 | } | ||
| 912 | push_mode(); | ||
| 913 | mode = t != 0 ? IF1_MODE : IF0_MODE; | ||
| 914 | state = S; | ||
| 915 | } else if(state == IFD || state == IFND) { | ||
| 916 | /* save KEY from #if(n)def KEY ... */ | ||
| 917 | const char *v; | ||
| 918 | |||
| 919 | push_mode(); | ||
| 920 | while(isalnums[c]) { | ||
| 921 | put_id(c); | ||
| 922 | getc1(); | ||
| 923 | } | ||
| 924 | if(!id_len) | ||
| 925 | yy_error_d("expected identifier"); | ||
| 926 | v = lookup_key(id, id_len); | ||
| 927 | mode = IF1_MODE; | ||
| 928 | if(state == IFD && v == NULL) | ||
| 929 | mode = IF0_MODE; | ||
| 930 | else if(state == IFND && v != NULL) | ||
| 931 | mode = IF0_MODE; | ||
| 932 | state = S; | ||
| 933 | } else if(state == EI) { | ||
| 934 | /* #elif */ | ||
| 935 | if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE) | ||
| 936 | yy_error_d("unexpected #elif"); | ||
| 937 | if(mode == IF0_MODE) { | ||
| 938 | pop_mode(); | ||
| 939 | state = F; | ||
| 940 | } else { | ||
| 941 | mode = ELIF1_MODE; | ||
| 942 | state = S; | ||
| 943 | } | ||
| 944 | } else if(state == E) { | ||
| 945 | if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE) | ||
| 946 | yy_error_d("unexpected #else"); | ||
| 947 | if(mode == IF0_MODE) | ||
| 948 | mode = ELSE0_MODE; | ||
| 949 | else if(mode == IF1_MODE) | ||
| 950 | mode = ELSE1_MODE; | ||
| 951 | state = S; | ||
| 357 | } else if(state == D || state == U) { | 952 | } else if(state == D || state == U) { |
| 358 | if(mode == SOURCES_MODE) { | 953 | /* save KEY from #"define"|"undef" ... */ |
| 359 | /* ignore depend with #define or #undef KEY */ | 954 | while(isalnums[c]) { |
| 360 | while(isalnums[c]) getc1(); | 955 | put_id(c); |
| 956 | getc1(); | ||
| 957 | } | ||
| 958 | if(!id_len) | ||
| 959 | yy_error_d("expected identifier"); | ||
| 960 | if(state == U) { | ||
| 961 | if((mode & FALSE_MODES) == 0) | ||
| 962 | parse_conf_opt(id, NULL, id_len); | ||
| 361 | state = S; | 963 | state = S; |
| 362 | } else { | 964 | } else { |
| 363 | /* save KEY from #"define"|"undef" ... */ | 965 | /* D -> DK */ |
| 364 | while(isalnums[c]) { | 966 | state = DK; |
| 365 | put_id(c); | ||
| 366 | getc1(); | ||
| 367 | } | ||
| 368 | if(!id_len) | ||
| 369 | yy_error_d("expected identifier"); | ||
| 370 | if(state == U) { | ||
| 371 | parse_conf_opt(id, NULL, id_len); | ||
| 372 | state = S; | ||
| 373 | } else { | ||
| 374 | /* D -> DK */ | ||
| 375 | if(c == '(') | ||
| 376 | yy_error_d("unexpected function macro"); | ||
| 377 | state = DK; | ||
| 378 | } | ||
| 379 | } | 967 | } |
| 380 | } else { | 968 | } else { |
| 381 | /* state==<DK> #define KEY[ ] (config mode) */ | 969 | /* state==<DK> #define KEY[ ] */ |
| 382 | size_t opt_len = id_len; | 970 | size_t opt_len = id_len; |
| 383 | char *val = id + opt_len; | 971 | char *val = id + opt_len; |
| 384 | char *sp; | 972 | char *sp; |
| @@ -395,7 +983,8 @@ static void c_lex(const char *fname, long fsize) | |||
| 395 | while(--sp >= val && (*sp == ' ' || *sp == '\t' | 983 | while(--sp >= val && (*sp == ' ' || *sp == '\t' |
| 396 | || *sp == '\f' || *sp == '\v')) | 984 | || *sp == '\f' || *sp == '\v')) |
| 397 | *sp = '\0'; | 985 | *sp = '\0'; |
| 398 | parse_conf_opt(id, val, opt_len); | 986 | if((mode & FALSE_MODES) == 0) |
| 987 | parse_conf_opt(id, val, opt_len); | ||
| 399 | state = S; | 988 | state = S; |
| 400 | } | 989 | } |
| 401 | } | 990 | } |
| @@ -426,8 +1015,219 @@ too_long: | |||
| 426 | yy_error_d("phrase too long"); | 1015 | yy_error_d("phrase too long"); |
| 427 | } | 1016 | } |
| 428 | 1017 | ||
| 1018 | /* trick for fast find "define", "include", "undef" */ | ||
| 1019 | static const char first_chars_diu[UCHAR_MAX] = { | ||
| 1020 | [(int)'d'] = (char)5, /* strlen("define") - 1; */ | ||
| 1021 | [(int)'i'] = (char)6, /* strlen("include") - 1; */ | ||
| 1022 | [(int)'u'] = (char)4, /* strlen("undef") - 1; */ | ||
| 1023 | }; | ||
| 1024 | |||
| 1025 | #undef D | ||
| 1026 | #undef I | ||
| 1027 | #undef U | ||
| 1028 | #define D '5' /* #define preprocessor's directive */ | ||
| 1029 | #define I '6' /* #include preprocessor's directive */ | ||
| 1030 | #define U '4' /* #undef preprocessor's directive */ | ||
| 1031 | |||
| 1032 | /* stupid C lexical analyser for sources */ | ||
| 1033 | static void c_lex_src(const char *fname, long fsize) | ||
| 1034 | { | ||
| 1035 | int c; | ||
| 1036 | int state; | ||
| 1037 | int line; | ||
| 1038 | char *id = id_s; | ||
| 1039 | size_t id_len = 0; /* stupid initialize */ | ||
| 1040 | unsigned char *optr, *oend; | ||
| 1041 | |||
| 1042 | int fd; | ||
| 1043 | char *map; | ||
| 1044 | int mapsize; | ||
| 429 | 1045 | ||
| 430 | /* bb_simplify_path special variant for absolute pathname */ | 1046 | if(fsize == 0) { |
| 1047 | fprintf(stderr, "Warning: %s is empty\n", fname); | ||
| 1048 | return; | ||
| 1049 | } | ||
| 1050 | fd = open(fname, O_RDONLY); | ||
| 1051 | if(fd < 0) { | ||
| 1052 | perror(fname); | ||
| 1053 | return; | ||
| 1054 | } | ||
| 1055 | mapsize = (fsize+pagesizem1) & ~pagesizem1; | ||
| 1056 | map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); | ||
| 1057 | if ((long) map == -1) | ||
| 1058 | bb_error_d("%s: mmap: %m", fname); | ||
| 1059 | |||
| 1060 | optr = (unsigned char *)map; | ||
| 1061 | oend = optr + fsize; | ||
| 1062 | |||
| 1063 | line = 1; | ||
| 1064 | state = S; | ||
| 1065 | |||
| 1066 | for(;;) { | ||
| 1067 | getc1(); | ||
| 1068 | for(;;) { | ||
| 1069 | /* [ \t]+ eat first space */ | ||
| 1070 | while(c == ' ' || c == '\t') | ||
| 1071 | getc1(); | ||
| 1072 | |||
| 1073 | if(state == S) { | ||
| 1074 | while(first_chars[c] == ANY) { | ||
| 1075 | /* <S>unparsed */ | ||
| 1076 | if(c == '\n') | ||
| 1077 | line++; | ||
| 1078 | getc1(); | ||
| 1079 | } | ||
| 1080 | if(c == L_EOF) { | ||
| 1081 | /* <S><<EOF>> */ | ||
| 1082 | munmap(map, mapsize); | ||
| 1083 | close(fd); | ||
| 1084 | return; | ||
| 1085 | } | ||
| 1086 | if(c == REM) { | ||
| 1087 | /* <S>/ */ | ||
| 1088 | getc0(); | ||
| 1089 | if(c == REM) { | ||
| 1090 | /* <S>"//"[^\n]* */ | ||
| 1091 | do getc0(); while(c != '\n' && c != L_EOF); | ||
| 1092 | } else if(c == '*') { | ||
| 1093 | /* <S>[/][*] goto parse block comments */ | ||
| 1094 | break; | ||
| 1095 | } | ||
| 1096 | } else if(c == POUND) { | ||
| 1097 | /* <S># */ | ||
| 1098 | state = c; | ||
| 1099 | getc1(); | ||
| 1100 | } else if(c == STR || c == CHR) { | ||
| 1101 | /* <S>\"|\' */ | ||
| 1102 | int qc = c; | ||
| 1103 | |||
| 1104 | for(;;) { | ||
| 1105 | /* <STR,CHR>. */ | ||
| 1106 | getc1(); | ||
| 1107 | if(c == qc) { | ||
| 1108 | /* <STR>\" or <CHR>\' */ | ||
| 1109 | break; | ||
| 1110 | } | ||
| 1111 | if(c == BS) { | ||
| 1112 | /* <STR,CHR>\\ but is not <STR,CHR>\\\n */ | ||
| 1113 | getc0(); | ||
| 1114 | } | ||
| 1115 | if(c == '\n' || c == L_EOF) | ||
| 1116 | yy_error_d("unterminated"); | ||
| 1117 | } | ||
| 1118 | getc1(); | ||
| 1119 | } else { | ||
| 1120 | /* <S>[A-Z_a-z0-9] */ | ||
| 1121 | |||
| 1122 | /* trick for fast drop id | ||
| 1123 | if key with this first char undefined */ | ||
| 1124 | if(first_chars[c] == 0) { | ||
| 1125 | /* skip <S>[A-Z_a-z0-9]+ */ | ||
| 1126 | do getc1(); while(isalnums[c]); | ||
| 1127 | } else { | ||
| 1128 | id_len = 0; | ||
| 1129 | do { | ||
| 1130 | /* <S>[A-Z_a-z0-9]+ */ | ||
| 1131 | put_id(c); | ||
| 1132 | getc1(); | ||
| 1133 | } while(isalnums[c]); | ||
| 1134 | check_key(key_top, id, id_len); | ||
| 1135 | } | ||
| 1136 | } | ||
| 1137 | continue; | ||
| 1138 | } | ||
| 1139 | /* begin preprocessor states */ | ||
| 1140 | if(c == L_EOF) | ||
| 1141 | yy_error_d("unexpected EOF"); | ||
| 1142 | if(c == REM) { | ||
| 1143 | /* <#.*>/ */ | ||
| 1144 | getc0(); | ||
| 1145 | if(c == REM) | ||
| 1146 | yy_error_d("detected // in preprocessor line"); | ||
| 1147 | if(c == '*') { | ||
| 1148 | /* <#.*>[/][*] goto parse block comments */ | ||
| 1149 | break; | ||
| 1150 | } | ||
| 1151 | /* hmm, #.*[/] */ | ||
| 1152 | yy_error_d("strange preprocessor line"); | ||
| 1153 | } | ||
| 1154 | if(state == POUND) { | ||
| 1155 | /* tricks */ | ||
| 1156 | static const char * const p_preproc[] = { | ||
| 1157 | /* 0 1 2 3 4 5 6 */ | ||
| 1158 | "", "", "", "", "ndef", "efine", "nclude" | ||
| 1159 | }; | ||
| 1160 | size_t diu = first_chars_diu[c]; /* strlen and p_preproc ptr */ | ||
| 1161 | |||
| 1162 | state = S; | ||
| 1163 | if(diu != S) { | ||
| 1164 | getc1(); | ||
| 1165 | id_len = 0; | ||
| 1166 | while(isalnums[c]) { | ||
| 1167 | put_id(c); | ||
| 1168 | getc1(); | ||
| 1169 | } | ||
| 1170 | /* have str begined with c, readed == strlen key and compared */ | ||
| 1171 | if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) { | ||
| 1172 | state = diu + '0'; | ||
| 1173 | id_len = 0; /* common for save */ | ||
| 1174 | } | ||
| 1175 | } else { | ||
| 1176 | while(isalnums[c]) getc1(); | ||
| 1177 | } | ||
| 1178 | } else if(state == I) { | ||
| 1179 | if(c == STR) { | ||
| 1180 | /* <I>\" */ | ||
| 1181 | for(;;) { | ||
| 1182 | getc1(); | ||
| 1183 | if(c == STR) | ||
| 1184 | break; | ||
| 1185 | if(c == L_EOF) | ||
| 1186 | yy_error_d("unexpected EOF"); | ||
| 1187 | put_id(c); | ||
| 1188 | } | ||
| 1189 | put_id(0); | ||
| 1190 | /* store "include.h" */ | ||
| 1191 | parse_inc(id, fname); | ||
| 1192 | getc1(); | ||
| 1193 | } | ||
| 1194 | /* else another (may be wrong) #include ... */ | ||
| 1195 | state = S; | ||
| 1196 | } else /* if(state == D || state == U) */ { | ||
| 1197 | /* ignore depend with #define or #undef KEY */ | ||
| 1198 | while(isalnums[c]) getc1(); | ||
| 1199 | state = S; | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | /* <REM> */ | ||
| 1204 | getc0(); | ||
| 1205 | for(;;) { | ||
| 1206 | /* <REM>[^*]+ */ | ||
| 1207 | while(c != '*') { | ||
| 1208 | if(c == '\n') { | ||
| 1209 | /* <REM>\n */ | ||
| 1210 | if(state != S) | ||
| 1211 | yy_error_d("unexpected newline"); | ||
| 1212 | line++; | ||
| 1213 | } else if(c == L_EOF) | ||
| 1214 | yy_error_d("unexpected EOF"); | ||
| 1215 | getc0(); | ||
| 1216 | } | ||
| 1217 | /* <REM>[*] */ | ||
| 1218 | getc0(); | ||
| 1219 | if(c == REM) { | ||
| 1220 | /* <REM>[*][/] */ | ||
| 1221 | break; | ||
| 1222 | } | ||
| 1223 | } | ||
| 1224 | } | ||
| 1225 | too_long: | ||
| 1226 | yy_error_d("phrase too long"); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | |||
| 1230 | /* bb_simplify_path special variant for apsolute pathname */ | ||
| 431 | static size_t bb_qa_simplify_path(char *path) | 1231 | static size_t bb_qa_simplify_path(char *path) |
| 432 | { | 1232 | { |
| 433 | char *s, *p; | 1233 | char *s, *p; |
| @@ -477,7 +1277,7 @@ static void parse_inc(const char *include, const char *fname) | |||
| 477 | const char *p; | 1277 | const char *p; |
| 478 | 1278 | ||
| 479 | lo = Iop; | 1279 | lo = Iop; |
| 480 | p = strrchr(fname, '/'); /* fname has absolute pathname */ | 1280 | p = strrchr(fname, '/'); /* fname have absolute pathname */ |
| 481 | w = (p-fname); | 1281 | w = (p-fname); |
| 482 | /* find from current directory of source file */ | 1282 | /* find from current directory of source file */ |
| 483 | ap = bb_asprint("%.*s/%s", w, fname, include); | 1283 | ap = bb_asprint("%.*s/%s", w, fname, include); |
| @@ -502,14 +1302,15 @@ static void parse_inc(const char *include, const char *fname) | |||
| 502 | 1302 | ||
| 503 | /* find from "-I include" specified directories */ | 1303 | /* find from "-I include" specified directories */ |
| 504 | free(ap); | 1304 | free(ap); |
| 505 | /* lo->data has absolute pathname */ | 1305 | /* lo->data have absolute pathname */ |
| 506 | ap = bb_asprint("%s/%s", lo->data, include); | 1306 | ap = bb_asprint("%s/%s", lo->data, include); |
| 507 | lo = lo->link; | 1307 | lo = lo->link; |
| 508 | } | 1308 | } |
| 509 | 1309 | ||
| 510 | cur = xmalloc(sizeof(bb_key_t)); | 1310 | cur = xmalloc(sizeof(bb_key_t)); |
| 511 | cur->keyname = cur->stored_path = ap; | 1311 | cur->keyname = ap; |
| 512 | cur->key_sz = key_sz; | 1312 | cur->key_sz = key_sz; |
| 1313 | cur->stored_path = ap; | ||
| 513 | cur->value = cur->checked = p_i; | 1314 | cur->value = cur->checked = p_i; |
| 514 | if(p_i == NULL && noiwarning) | 1315 | if(p_i == NULL && noiwarning) |
| 515 | fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include); | 1316 | fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include); |
| @@ -528,7 +1329,7 @@ static void parse_conf_opt(const char *opt, const char *val, size_t key_sz) | |||
| 528 | 1329 | ||
| 529 | cur = check_key(key_top, opt, key_sz); | 1330 | cur = check_key(key_top, opt, key_sz); |
| 530 | if(cur != NULL) { | 1331 | if(cur != NULL) { |
| 531 | /* already present */ | 1332 | /* present already */ |
| 532 | cur->checked = NULL; /* store only */ | 1333 | cur->checked = NULL; /* store only */ |
| 533 | if(cur->value == NULL && val == NULL) | 1334 | if(cur->value == NULL && val == NULL) |
| 534 | return; | 1335 | return; |
| @@ -568,7 +1369,7 @@ static void parse_conf_opt(const char *opt, const char *val, size_t key_sz) | |||
| 568 | first_chars[(int)*k] = *k; | 1369 | first_chars[(int)*k] = *k; |
| 569 | 1370 | ||
| 570 | cur->stored_path = k = bb_asprint("%s/%s.h", kp, k); | 1371 | cur->stored_path = k = bb_asprint("%s/%s.h", kp, k); |
| 571 | /* key conversion [A-Z_] -> [a-z/] */ | 1372 | /* key converting [A-Z_] -> [a-z/] */ |
| 572 | for(p = k + kp_len + 1; *p; p++) { | 1373 | for(p = k + kp_len + 1; *p; p++) { |
| 573 | if(*p >= 'A' && *p <= 'Z') | 1374 | if(*p >= 'A' && *p <= 'Z') |
| 574 | *p = *p - 'A' + 'a'; | 1375 | *p = *p - 'A' + 'a'; |
| @@ -604,7 +1405,7 @@ static void store_keys(void) | |||
| 604 | } | 1405 | } |
| 605 | /* size_t -> ssize_t :( */ | 1406 | /* size_t -> ssize_t :( */ |
| 606 | rw_ret = (ssize_t)recordsz; | 1407 | rw_ret = (ssize_t)recordsz; |
| 607 | /* check kp/key.h, compare after previous use */ | 1408 | /* check kp/key.h, compare after previous usage */ |
| 608 | cmp_ok = 0; | 1409 | cmp_ok = 0; |
| 609 | k = cur->stored_path; | 1410 | k = cur->stored_path; |
| 610 | if(stat(k, &st)) { | 1411 | if(stat(k, &st)) { |
| @@ -709,7 +1510,7 @@ parse_chd(const char *fe, const char *p, size_t dirlen) | |||
| 709 | } | 1510 | } |
| 710 | } | 1511 | } |
| 711 | /* direntry is *.[ch] regular file and is not configs */ | 1512 | /* direntry is *.[ch] regular file and is not configs */ |
| 712 | c_lex(fp, st.st_size); | 1513 | c_lex_src(fp, st.st_size); |
| 713 | if(!dontgenerate_dep) { | 1514 | if(!dontgenerate_dep) { |
| 714 | int first; | 1515 | int first; |
| 715 | if(*e == 'c') { | 1516 | if(*e == 'c') { |
| @@ -740,7 +1541,7 @@ parse_chd(const char *fe, const char *p, size_t dirlen) | |||
| 740 | return NULL; | 1541 | return NULL; |
| 741 | } | 1542 | } |
| 742 | 1543 | ||
| 743 | /* from libbb but inlined for speed considerations */ | 1544 | /* from libbb but inline for fast */ |
| 744 | static inline llist_t *llist_add_to(llist_t *old_head, char *new_item) | 1545 | static inline llist_t *llist_add_to(llist_t *old_head, char *new_item) |
| 745 | { | 1546 | { |
| 746 | llist_t *new_head; | 1547 | llist_t *new_head; |
| @@ -763,7 +1564,7 @@ static void scan_dir_find_ch_files(const char *p) | |||
| 763 | 1564 | ||
| 764 | dirs = llist_add_to(NULL, bb_simplify_path(p)); | 1565 | dirs = llist_add_to(NULL, bb_simplify_path(p)); |
| 765 | replace = strlen(dirs->data); | 1566 | replace = strlen(dirs->data); |
| 766 | /* emulate recursion */ | 1567 | /* emulate recursive */ |
| 767 | while(dirs) { | 1568 | while(dirs) { |
| 768 | d_add = NULL; | 1569 | d_add = NULL; |
| 769 | while(dirs) { | 1570 | while(dirs) { |
| @@ -803,7 +1604,7 @@ int main(int argc, char **argv) | |||
| 803 | llist_t *fl; | 1604 | llist_t *fl; |
| 804 | 1605 | ||
| 805 | { | 1606 | { |
| 806 | /* for bb_simplify_path, this program has no chdir() */ | 1607 | /* for bb_simplify_path, this program have not chdir() */ |
| 807 | /* libbb-like my xgetcwd() */ | 1608 | /* libbb-like my xgetcwd() */ |
| 808 | unsigned path_max = 512; | 1609 | unsigned path_max = 512; |
| 809 | 1610 | ||
| @@ -863,7 +1664,7 @@ int main(int argc, char **argv) | |||
| 863 | for(i = 0; i < UCHAR_MAX; i++) { | 1664 | for(i = 0; i < UCHAR_MAX; i++) { |
| 864 | if(ISALNUM(i)) | 1665 | if(ISALNUM(i)) |
| 865 | isalnums[i] = i; | 1666 | isalnums[i] = i; |
| 866 | /* set unparsed chars to speed up the parser */ | 1667 | /* set unparsed chars for speed up of parser */ |
| 867 | else if(i != CHR && i != STR && i != POUND && i != REM) | 1668 | else if(i != CHR && i != STR && i != POUND && i != REM) |
| 868 | first_chars[i] = ANY; | 1669 | first_chars[i] = ANY; |
| 869 | } | 1670 | } |
| @@ -875,7 +1676,7 @@ int main(int argc, char **argv) | |||
| 875 | 1676 | ||
| 876 | if(stat(fl->data, &st)) | 1677 | if(stat(fl->data, &st)) |
| 877 | bb_error_d("stat(%s): %m", fl->data); | 1678 | bb_error_d("stat(%s): %m", fl->data); |
| 878 | c_lex(fl->data, st.st_size); | 1679 | c_lex_config(fl->data, st.st_size); |
| 879 | free(fl->data); | 1680 | free(fl->data); |
| 880 | /* trick for fast comparing found files with configs */ | 1681 | /* trick for fast comparing found files with configs */ |
| 881 | fl->data = xmalloc(sizeof(struct stat)); | 1682 | fl->data = xmalloc(sizeof(struct stat)); |
| @@ -883,7 +1684,6 @@ int main(int argc, char **argv) | |||
| 883 | } | 1684 | } |
| 884 | 1685 | ||
| 885 | /* main loop */ | 1686 | /* main loop */ |
| 886 | mode = SOURCES_MODE; | ||
| 887 | argv += optind; | 1687 | argv += optind; |
| 888 | if(*argv) { | 1688 | if(*argv) { |
| 889 | while(*argv) | 1689 | while(*argv) |
| @@ -923,6 +1723,7 @@ static char *bb_asprint(const char *format, ...) | |||
| 923 | } | 1723 | } |
| 924 | 1724 | ||
| 925 | /* partial libbb routine as is */ | 1725 | /* partial libbb routine as is */ |
| 1726 | |||
| 926 | static char *bb_simplify_path(const char *path) | 1727 | static char *bb_simplify_path(const char *path) |
| 927 | { | 1728 | { |
| 928 | char *s, *start, *p; | 1729 | char *s, *start, *p; |
| @@ -930,7 +1731,7 @@ static char *bb_simplify_path(const char *path) | |||
| 930 | if (path[0] == '/') | 1731 | if (path[0] == '/') |
| 931 | start = bb_xstrdup(path); | 1732 | start = bb_xstrdup(path); |
| 932 | else { | 1733 | else { |
| 933 | /* is not libbb, but this program has no chdir() */ | 1734 | /* is not libbb, but this program have not chdir() */ |
| 934 | start = bb_asprint("%s/%s", pwd, path); | 1735 | start = bb_asprint("%s/%s", pwd, path); |
| 935 | } | 1736 | } |
| 936 | p = s = start; | 1737 | p = s = start; |
