Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/editors/awk.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/editors/awk.c
r1765 r2725 5 5 * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua> 6 6 * 7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 8 */ 9 9 … … 11 11 #include "xregex.h" 12 12 #include <math.h> 13 extern char **environ;14 13 15 14 /* This is a NOEXEC applet. Be very careful! */ 15 16 17 /* If you comment out one of these below, it will be #defined later 18 * to perform debug printfs to stderr: */ 19 #define debug_printf_walker(...) do {} while (0) 20 #define debug_printf_eval(...) do {} while (0) 21 22 #ifndef debug_printf_walker 23 # define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) 24 #endif 25 #ifndef debug_printf_eval 26 # define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) 27 #endif 28 16 29 17 30 … … 33 46 /* these flags are static, don't change them when value is changed */ 34 47 #define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) 48 49 typedef struct walker_list { 50 char *end; 51 char *cur; 52 struct walker_list *prev; 53 char wbuf[1]; 54 } walker_list; 35 55 36 56 /* Variable */ … … 43 63 struct xhash_s *array; /* array ptr */ 44 64 struct var_s *parent; /* for func args, ptr to actual parameter */ 45 char **walker;/* list of array elements (for..in) */65 walker_list *walker; /* list of array elements (for..in) */ 46 66 } x; 47 67 } var; … … 95 115 struct node_s *n; 96 116 var *v; 97 int i;98 char * s;117 int aidx; 118 char *new_progname; 99 119 regex_t *re; 100 120 } l; … … 103 123 regex_t *ire; 104 124 func *f; 105 int argno;106 125 } r; 107 126 union { … … 116 135 struct nvblock_s *prev; 117 136 struct nvblock_s *next; 118 var nv[ 0];137 var nv[]; 119 138 } nvblock; 120 139 … … 252 271 /* builtins */ 253 272 enum { 254 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,273 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_mt, B_lo, B_up, 255 274 B_ge, B_gs, B_su, 256 275 B_an, B_co, B_ls, B_or, B_rs, B_xo, … … 259 278 /* tokens and their corresponding info values */ 260 279 261 #define 262 #define 263 264 #define OC_BOC_BUILTIN280 #define NTC "\377" /* switch to next token class (tc<<1) */ 281 #define NTCC '\377' 282 283 #define OC_B OC_BUILTIN 265 284 266 285 static const char tokenlist[] ALIGN1 = 267 "\1(" NTC 268 "\1)" NTC 269 "\1/" NTC /* REGEXP */ 270 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 271 "\2++" "\2--" NTC /* UOPPOST */ 272 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 273 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 274 "\2*=" "\2/=" "\2%=" "\2^=" 275 "\1+" "\1-" "\3**=" "\2**" 276 "\1/" "\1%" "\1^" "\1*" 277 "\2!=" "\2>=" "\2<=" "\1>" 278 "\1<" "\2!~" "\1~" "\2&&" 279 "\2||" "\1?" "\1:" NTC 280 "\2in" NTC 281 "\1," NTC 282 "\1|" NTC 283 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 284 "\1]" NTC 285 "\1{" NTC 286 "\1}" NTC 287 "\1;" NTC 288 "\1\n" NTC 289 "\2if" "\2do" "\3for" "\5break" /* STATX */ 290 "\10continue" "\6delete" "\5print" 291 "\6printf" "\4next" "\10nextfile" 292 "\6return" "\4exit" NTC 293 "\5while" NTC 294 "\4else" NTC 295 296 "\3and" "\5compl" "\6lshift" "\2or" 297 "\6rshift" "\3xor" 298 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 299 "\3cos" "\3exp" "\3int" "\3log" 300 "\4rand" "\3sin" "\4sqrt" "\5srand" 301 "\6gensub" "\4gsub" "\5index" "\6length" 302 "\5match" "\5split" "\7sprintf" "\3sub" 303 "\6substr" "\7systime" "\10strftime" 304 "\7tolower" "\7toupper" NTC 305 "\7getline" NTC 306 "\4func" "\10function" NTC 307 "\5BEGIN" NTC 308 "\3END" "\0" 286 "\1(" NTC 287 "\1)" NTC 288 "\1/" NTC /* REGEXP */ 289 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 290 "\2++" "\2--" NTC /* UOPPOST */ 291 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 292 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 293 "\2*=" "\2/=" "\2%=" "\2^=" 294 "\1+" "\1-" "\3**=" "\2**" 295 "\1/" "\1%" "\1^" "\1*" 296 "\2!=" "\2>=" "\2<=" "\1>" 297 "\1<" "\2!~" "\1~" "\2&&" 298 "\2||" "\1?" "\1:" NTC 299 "\2in" NTC 300 "\1," NTC 301 "\1|" NTC 302 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 303 "\1]" NTC 304 "\1{" NTC 305 "\1}" NTC 306 "\1;" NTC 307 "\1\n" NTC 308 "\2if" "\2do" "\3for" "\5break" /* STATX */ 309 "\10continue" "\6delete" "\5print" 310 "\6printf" "\4next" "\10nextfile" 311 "\6return" "\4exit" NTC 312 "\5while" NTC 313 "\4else" NTC 314 315 "\3and" "\5compl" "\6lshift" "\2or" 316 "\6rshift" "\3xor" 317 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 318 "\3cos" "\3exp" "\3int" "\3log" 319 "\4rand" "\3sin" "\4sqrt" "\5srand" 320 "\6gensub" "\4gsub" "\5index" "\6length" 321 "\5match" "\5split" "\7sprintf" "\3sub" 322 "\6substr" "\7systime" "\10strftime" "\6mktime" 323 "\7tolower" "\7toupper" NTC 324 "\7getline" NTC 325 "\4func" "\10function" NTC 326 "\5BEGIN" NTC 327 "\3END" 328 /* compiler adds trailing "\0" */ 309 329 ; 310 330 … … 313 333 0, 314 334 OC_REGEXP, 315 xS|'a', xS|'w', xS|'|', 316 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', 317 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', 318 OC_FIELD|xV|P(5), 319 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), 320 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', 321 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', 322 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', 323 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', 324 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', 325 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', 326 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', 327 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, 328 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, 329 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', 330 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), 331 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', 332 OC_COLON|xx|P(67)|':', 333 OC_IN|SV|P(49), 335 xS|'a', xS|'w', xS|'|', 336 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', 337 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), 338 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', 339 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', 340 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', 341 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', 342 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, 343 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), 344 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', 345 OC_IN|SV|P(49), /* in */ 334 346 OC_COMMA|SS|P(80), 335 347 OC_PGETLINE|SV|P(37), 336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',337 OC_UNARY|xV|P(19)|'!',348 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', 349 0, /* ] */ 338 350 0, 339 351 0, 340 352 0, 341 0, 342 0, 343 ST_IF, ST_DO, ST_FOR, OC_BREAK, 344 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, 345 OC_PRINTF, OC_NEXT, OC_NEXTFILE, 346 OC_RETURN|Vx, OC_EXIT|Nx, 353 0, /* \n */ 354 ST_IF, ST_DO, ST_FOR, OC_BREAK, 355 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, 356 OC_PRINTF, OC_NEXT, OC_NEXTFILE, 357 OC_RETURN|Vx, OC_EXIT|Nx, 347 358 ST_WHILE, 348 0, 359 0, /* else */ 349 360 350 361 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), … … 355 366 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le, 356 367 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6), 357 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), 368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), 358 369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 359 370 OC_GETLINE|SV|P(0), 360 0, 371 0, 0, 361 372 0, 362 0 373 0 /* END */ 363 374 }; 364 375 … … 368 379 CONVFMT, OFMT, FS, OFS, 369 380 ORS, RS, RT, FILENAME, 370 SUBSEP, ARGIND, ARGC, ARGV, 371 ERRNO, FNR, 372 NR, NF, IGNORECASE, 373 ENVIRON, F0, NUM_INTERNAL_VARS 381 SUBSEP, F0, ARGIND, ARGC, 382 ARGV, ERRNO, FNR, NR, 383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS 374 384 }; 375 385 … … 377 387 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" 378 388 "ORS\0" "RS\0*" "RT\0" "FILENAME\0" 379 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0" 380 "ERRNO\0" "FNR\0" 381 "NR\0" "NF\0*" "IGNORECASE\0*" 382 "ENVIRON\0" "$\0*" "\0"; 389 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0" 390 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0" 391 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0"; 383 392 384 393 static const char vValues[] ALIGN1 = 385 394 "%.6g\0" "%.6g\0" " \0" " \0" 386 395 "\n\0" "\n\0" "\0" "\0" 387 "\034\0" 388 "\377"; 396 "\034\0" "\0" "\377"; 389 397 390 398 /* hash size may grow to these values */ … … 394 402 395 403 /* Globals. Split in two parts so that first one is addressed 396 * with (mostly short) negative offsets */ 404 * with (mostly short) negative offsets. 405 * NB: it's unsafe to put members of type "double" 406 * into globals2 (gcc may fail to align them). 407 */ 397 408 struct globals { 398 chain beginseq, mainseq, endseq, *seq; 409 double t_double; 410 chain beginseq, mainseq, endseq; 411 chain *seq; 399 412 node *break_ptr, *continue_ptr; 400 413 rstream *iF; … … 443 456 444 457 /* biggest and least used members go last */ 445 double t_double;446 458 tsplitter fsplitter, rsplitter; 447 459 }; 448 460 #define G1 (ptr_to_globals[-1]) 449 #define G (*(struct globals2 * const)ptr_to_globals)461 #define G (*(struct globals2 *)ptr_to_globals) 450 462 /* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */ 451 /* char G1size[sizeof(G1)]; - 0x6c*/452 /* char Gsize[sizeof(G)]; - 0x1cc*/463 /*char G1size[sizeof(G1)]; - 0x74 */ 464 /*char Gsize[sizeof(G)]; - 0x1c4 */ 453 465 /* Trying to keep most of members accessible with short offsets: */ 454 /* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ 466 /*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ 467 #define t_double (G1.t_double ) 455 468 #define beginseq (G1.beginseq ) 456 469 #define mainseq (G1.mainseq ) … … 480 493 #define t_tclass (G.t_tclass ) 481 494 #define t_string (G.t_string ) 482 #define t_double (G.t_double )483 495 #define t_lineno (G.t_lineno ) 484 496 #define t_rollback (G.t_rollback ) … … 487 499 #define rsplitter (G.rsplitter ) 488 500 #define INIT_G() do { \ 489 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \501 SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \ 490 502 G.next_token__ltclass = TC_OPTERM; \ 491 503 G.evaluate__seed = 1; \ … … 500 512 static rstream *next_input_file(void); 501 513 static int fmt_num(char *, int, const char *, double, int); 502 static int awk_exit(int) ATTRIBUTE_NORETURN;514 static int awk_exit(int) NORETURN; 503 515 504 516 /* ---- error handling ---- */ … … 513 525 static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 514 526 static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 515 #if !ENABLE_FEATURE_AWK_MATH516 527 static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 517 #endif 518 519 static void zero_out_var(var * vp) 528 529 static void zero_out_var(var *vp) 520 530 { 521 531 memset(vp, 0, sizeof(*vp)); 522 532 } 523 533 524 static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;525 static void syntax_error(const char * constmessage)534 static void syntax_error(const char *message) NORETURN; 535 static void syntax_error(const char *message) 526 536 { 527 537 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); … … 534 544 unsigned idx = 0; 535 545 536 while (*name) idx = *name++ + (idx << 6) - idx; 546 while (*name) 547 idx = *name++ + (idx << 6) - idx; 537 548 return idx; 538 549 } … … 543 554 xhash *newhash; 544 555 545 newhash = xzalloc(sizeof( xhash));556 newhash = xzalloc(sizeof(*newhash)); 546 557 newhash->csize = FIRST_PRIME; 547 newhash->items = xzalloc( newhash->csize * sizeof(hash_item *));558 newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0])); 548 559 549 560 return newhash; … … 555 566 hash_item *hi; 556 567 557 hi = hash->items [ hashidx(name) % hash->csize];568 hi = hash->items[hashidx(name) % hash->csize]; 558 569 while (hi) { 559 570 if (strcmp(hi->name, name) == 0) 560 return & (hi->data);571 return &hi->data; 561 572 hi = hi->next; 562 573 } … … 574 585 575 586 newsize = PRIMES[hash->nprime++]; 576 newitems = xzalloc(newsize * sizeof( hash_item *));587 newitems = xzalloc(newsize * sizeof(newitems[0])); 577 588 578 589 for (i = 0; i < hash->csize; i++) { … … 605 616 606 617 l = strlen(name) + 1; 607 hi = xzalloc(sizeof( hash_item) + l);608 memcpy(hi->name, name, l);618 hi = xzalloc(sizeof(*hi) + l); 619 strcpy(hi->name, name); 609 620 610 621 idx = hashidx(name) % hash->csize; … … 613 624 hash->glen += l; 614 625 } 615 return & (hi->data);626 return &hi->data; 616 627 } 617 628 … … 625 636 hash_item *hi, **phi; 626 637 627 phi = & (hash->items[hashidx(name) % hash->csize]);638 phi = &hash->items[hashidx(name) % hash->csize]; 628 639 while (*phi) { 629 640 hi = *phi; … … 635 646 break; 636 647 } 637 phi = & (hi->next);648 phi = &hi->next; 638 649 } 639 650 } … … 641 652 /* ------ some useful functions ------ */ 642 653 643 static void skip_spaces(char **s) 644 { 645 char *p = *s; 646 654 static char *skip_spaces(char *p) 655 { 647 656 while (1) { 648 657 if (*p == '\\' && p[1] == '\n') { … … 654 663 p++; 655 664 } 656 *s = p; 657 } 658 665 return p; 666 } 667 668 /* returns old *s, advances *s past word and terminating NUL */ 659 669 static char *nextword(char **s) 660 670 { 661 671 char *p = *s; 662 663 while (*(*s)++) /* */; 664 672 while (*(*s)++ != '\0') 673 continue; 665 674 return p; 666 675 } … … 670 679 char c, *pps; 671 680 672 c = *( (*s)++);681 c = *(*s)++; 673 682 pps = *s; 674 if (c == '\\') c = bb_process_escape_sequence((const char**)s); 675 if (c == '\\' && *s == pps) c = *((*s)++); 683 if (c == '\\') 684 c = bb_process_escape_sequence((const char**)s); 685 if (c == '\\' && *s == pps) { /* unrecognized \z? */ 686 c = *(*s); /* yes, fetch z */ 687 if (c) 688 (*s)++; /* advance unless z = NUL */ 689 } 676 690 return c; 677 691 } 678 692 679 static int ALWAYS_INLINEisalnum_(int c)693 static ALWAYS_INLINE int isalnum_(int c) 680 694 { 681 695 return (isalnum(c) || c == '_'); 682 696 } 683 697 684 static FILE *afopen(const char *path, const char *mode) 685 { 686 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode); 698 static double my_strtod(char **pp) 699 { 700 char *cp = *pp; 701 if (ENABLE_DESKTOP && cp[0] == '0') { 702 /* Might be hex or octal integer: 0x123abc or 07777 */ 703 char c = (cp[1] | 0x20); 704 if (c == 'x' || isdigit(cp[1])) { 705 unsigned long long ull = strtoull(cp, pp, 0); 706 if (c == 'x') 707 return ull; 708 c = **pp; 709 if (!isdigit(c) && c != '.') 710 return ull; 711 /* else: it may be a floating number. Examples: 712 * 009.123 (*pp points to '9') 713 * 000.123 (*pp points to '.') 714 * fall through to strtod. 715 */ 716 } 717 } 718 return strtod(cp, pp); 687 719 } 688 720 … … 748 780 } 749 781 750 /* same as setvar_s but set USER flag */782 /* same as setvar_s but sets USER flag */ 751 783 static var *setvar_u(var *v, const char *value) 752 784 { 753 setvar_s(v, value);785 v = setvar_s(v, value); 754 786 v->type |= VF_USER; 755 787 return v; … … 759 791 static void setari_u(var *a, int idx, const char *s) 760 792 { 761 char sidx[sizeof(int)*3 + 1];762 793 var *v; 763 794 764 sprintf(sidx, "%d", idx); 765 v = findvar(iamarray(a), sidx); 795 v = findvar(iamarray(a), itoa(idx)); 766 796 setvar_u(v, s); 767 797 } … … 796 826 s = v->string; 797 827 if (s && *s) { 798 v->number = strtod(s, &s); 828 debug_printf_eval("getvar_i: '%s'->", s); 829 v->number = my_strtod(&s); 830 debug_printf_eval("%f (s:'%s')\n", v->number, s); 799 831 if (v->type & VF_USER) { 800 s kip_spaces(&s);832 s = skip_spaces(s); 801 833 if (*s != '\0') 802 834 v->type &= ~VF_USER; 803 835 } 804 836 } else { 837 debug_printf_eval("getvar_i: '%s'->zero\n", s); 805 838 v->type &= ~VF_USER; 806 839 } 807 840 v->type |= VF_CACHED; 808 841 } 842 debug_printf_eval("getvar_i: %f\n", v->number); 809 843 return v->number; 844 } 845 846 /* Used for operands of bitwise ops */ 847 static unsigned long getvar_i_int(var *v) 848 { 849 double d = getvar_i(v); 850 851 /* Casting doubles to longs is undefined for values outside 852 * of target type range. Try to widen it as much as possible */ 853 if (d >= 0) 854 return (unsigned long)d; 855 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */ 856 return - (long) (unsigned long) (-d); 810 857 } 811 858 … … 815 862 clrvar(dest); 816 863 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); 864 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string); 817 865 dest->number = src->number; 818 866 if (src->string) … … 825 873 static var *incvar(var *v) 826 874 { 827 return setvar_i(v, getvar_i(v) + 1. );875 return setvar_i(v, getvar_i(v) + 1.0); 828 876 } 829 877 … … 839 887 { 840 888 if (is_numeric(v)) 841 return (v->number == 0) ? 0 : 1;842 return (v->string && *(v->string)) ? 1 : 0;889 return (v->number != 0); 890 return (v->string && v->string[0]); 843 891 } 844 892 … … 852 900 while (g_cb) { 853 901 pb = g_cb; 854 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break; 902 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) 903 break; 855 904 g_cb = g_cb->next; 856 905 } … … 858 907 if (!g_cb) { 859 908 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n; 860 g_cb = x malloc(sizeof(nvblock) + size * sizeof(var));909 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var)); 861 910 g_cb->size = size; 862 911 g_cb->pos = g_cb->nv; 863 912 g_cb->prev = pb; 864 g_cb->next = NULL; 865 if (pb) pb->next = g_cb; 913 /*g_cb->next = NULL; - xzalloc did it */ 914 if (pb) 915 pb->next = g_cb; 866 916 } 867 917 … … 891 941 free(p->x.array); 892 942 } 893 if (p->type & VF_WALK) 894 free(p->x.walker); 895 943 if (p->type & VF_WALK) { 944 walker_list *n; 945 walker_list *w = p->x.walker; 946 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker); 947 p->x.walker = NULL; 948 while (w) { 949 n = w->prev; 950 debug_printf_walker(" free(%p)\n", w); 951 free(w); 952 w = n; 953 } 954 } 896 955 clrvar(p); 897 956 } … … 916 975 #define ltclass (G.next_token__ltclass) 917 976 918 char *p, * pp, *s;977 char *p, *s; 919 978 const char *tl; 920 979 uint32_t tc; 921 980 const uint32_t *ti; 922 int l;923 981 924 982 if (t_rollback) { … … 933 991 p = g_pos; 934 992 readnext: 935 skip_spaces(&p);993 p = skip_spaces(p); 936 994 g_lineno = t_lineno; 937 995 if (*p == '#') … … 949 1007 t_string = s = ++p; 950 1008 while (*p != '\"') { 1009 char *pp; 951 1010 if (*p == '\0' || *p == '\n') 952 1011 syntax_error(EMSG_UNEXP_EOS); 953 *(s++) = nextchar(&p); 1012 pp = p; 1013 *s++ = nextchar(&pp); 1014 p = pp; 954 1015 } 955 1016 p++; … … 965 1026 *s = *p++; 966 1027 if (*s++ == '\\') { 967 pp = p;968 *(s-1) = bb_process_escape_sequence((const char **)&p);969 if (*p p== '\\')1028 char *pp = p; 1029 s[-1] = bb_process_escape_sequence((const char **)&pp); 1030 if (*p == '\\') 970 1031 *s++ = '\\'; 971 if (p == pp)1032 if (pp == p) 972 1033 *s++ = *p++; 1034 else 1035 p = pp; 973 1036 } 974 1037 } … … 979 1042 } else if (*p == '.' || isdigit(*p)) { 980 1043 /* it's a number */ 981 t_double = strtod(p, &p); 1044 char *pp = p; 1045 t_double = my_strtod(&pp); 1046 p = pp; 982 1047 if (*p == '.') 983 1048 syntax_error(EMSG_UNEXP_TOKEN); … … 990 1055 ti = tokeninfo; 991 1056 while (*tl) { 992 l = *(tl++);993 if (l == NTCC) {1057 int l = (unsigned char) *tl++; 1058 if (l == (unsigned char) NTCC) { 994 1059 tc <<= 1; 995 1060 continue; 996 1061 } 997 /* if token class is expected, token998 * matches and it's not a longer word,999 * then this is what we are looking for1062 /* if token class is expected, 1063 * token matches, 1064 * and it's not a longer word, 1000 1065 */ 1001 1066 if ((tc & (expected | TC_WORD | TC_NEWLINE)) 1002 && *tl == *p &&strncmp(p, tl, l) == 01067 && strncmp(p, tl, l) == 0 1003 1068 && !((tc & TC_WORD) && isalnum_(p[l])) 1004 1069 ) { 1070 /* then this is what we are looking for */ 1005 1071 t_info = *ti; 1006 1072 p += l; 1007 break;1073 goto token_found; 1008 1074 } 1009 1075 ti++; 1010 1076 tl += l; 1011 1077 } 1012 1013 if (!*tl) { 1014 /* it's a name (var/array/function), 1015 * otherwise it's something wrong 1016 */ 1017 if (!isalnum_(*p)) 1018 syntax_error(EMSG_UNEXP_TOKEN); 1019 1020 t_string = --p; 1021 while (isalnum_(*(++p))) { 1022 *(p-1) = *p; 1078 /* not a known token */ 1079 1080 /* is it a name? (var/array/function) */ 1081 if (!isalnum_(*p)) 1082 syntax_error(EMSG_UNEXP_TOKEN); /* no */ 1083 /* yes */ 1084 t_string = --p; 1085 while (isalnum_(*++p)) { 1086 p[-1] = *p; 1087 } 1088 p[-1] = '\0'; 1089 tc = TC_VARIABLE; 1090 /* also consume whitespace between functionname and bracket */ 1091 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY)) 1092 p = skip_spaces(p); 1093 if (*p == '(') { 1094 tc = TC_FUNCTION; 1095 } else { 1096 if (*p == '[') { 1097 p++; 1098 tc = TC_ARRAY; 1023 1099 } 1024 *(p-1) = '\0'; 1025 tc = TC_VARIABLE; 1026 /* also consume whitespace between functionname and bracket */ 1027 if (!(expected & TC_VARIABLE)) 1028 skip_spaces(&p); 1029 if (*p == '(') { 1030 tc = TC_FUNCTION; 1031 } else { 1032 if (*p == '[') { 1033 p++; 1034 tc = TC_ARRAY; 1035 } 1036 } 1037 } 1100 } 1101 token_found: ; 1038 1102 } 1039 1103 g_pos = p; … … 1083 1147 } 1084 1148 1085 static node *mk_re_node(const char *s, node *n, regex_t *re)1149 static void mk_re_node(const char *s, node *n, regex_t *re) 1086 1150 { 1087 1151 n->info = OC_REGEXP; … … 1090 1154 xregcomp(re, s, REG_EXTENDED); 1091 1155 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); 1092 1093 return n;1094 1156 } 1095 1157 … … 1115 1177 1116 1178 while (!((tc = next_token(xtc)) & iexp)) { 1179 1117 1180 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1118 1181 /* input redirection (<) attached to glptr node */ … … 1126 1189 * previous operators with higher priority */ 1127 1190 vn = cn; 1128 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) 1129 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) ) 1191 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) 1192 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) 1193 ) { 1130 1194 vn = vn->a.n; 1195 } 1131 1196 if ((t_info & OPCLSMASK) == OC_TERNARY) 1132 1197 t_info += P(6); … … 1167 1232 if (v != NULL) { 1168 1233 cn->info = OC_FNARG; 1169 cn->l. i= v->x.aidx;1234 cn->l.aidx = v->x.aidx; 1170 1235 } else { 1171 1236 cn->l.v = newvar(t_string); … … 1228 1293 seq->programname = g_progname; 1229 1294 n = chain_node(OC_NEWSOURCE); 1230 n->l. s= xstrdup(g_progname);1295 n->l.new_progname = xstrdup(g_progname); 1231 1296 } 1232 1297 … … 1283 1348 if (c & TC_GRPSTART) { 1284 1349 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1285 if (t_tclass & TC_NEWLINE) continue; 1350 if (t_tclass & TC_NEWLINE) 1351 continue; 1286 1352 rollback_token(); 1287 1353 chain_group(); … … 1405 1471 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 1406 1472 v = findvar(ahash, t_string); 1407 v->x.aidx = (f->nargs)++;1473 v->x.aidx = f->nargs++; 1408 1474 1409 1475 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) 1410 1476 break; 1411 1477 } 1412 seq = & (f->body);1478 seq = &f->body; 1413 1479 chain_group(); 1414 1480 clear_array(ahash); … … 1448 1514 regfree(ire); // TODO: nuke ire, use re+1? 1449 1515 } 1450 if (s trlen(s) > 1) {1516 if (s[0] && s[1]) { /* strlen(s) > 1 */ 1451 1517 mk_re_node(s, n, re); 1452 1518 } else { 1453 n->info = (uint32_t) *s;1519 n->info = (uint32_t) s[0]; 1454 1520 } 1455 1521 … … 1463 1529 static regex_t *as_regex(node *op, regex_t *preg) 1464 1530 { 1531 int cflags; 1465 1532 var *v; 1466 1533 const char *s; … … 1471 1538 v = nvalloc(1); 1472 1539 s = getvar_s(evaluate(op, v)); 1473 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); 1540 1541 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; 1542 /* Testcase where REG_EXTENDED fails (unpaired '{'): 1543 * echo Hi | awk 'gsub("@(samp|code|file)\{","");' 1544 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED 1545 * (maybe gsub is not supposed to use REG_EXTENDED?). 1546 */ 1547 if (regcomp(preg, s, cflags)) { 1548 cflags &= ~REG_EXTENDED; 1549 xregcomp(preg, s, cflags); 1550 } 1474 1551 nvfree(v); 1475 1552 return preg; 1476 1553 } 1477 1554 1478 /* gradually increasing buffer */ 1479 static void qrealloc(char **b, int n, int *size) 1480 { 1481 if (!*b || n >= *size) 1482 *b = xrealloc(*b, *size = n + (n>>1) + 80); 1555 /* gradually increasing buffer. 1556 * note that we reallocate even if n == old_size, 1557 * and thus there is at least one extra allocated byte. 1558 */ 1559 static char* qrealloc(char *b, int n, int *size) 1560 { 1561 if (!b || n >= *size) { 1562 *size = n + (n>>1) + 80; 1563 b = xrealloc(b, *size); 1564 } 1565 return b; 1483 1566 } 1484 1567 … … 1491 1574 i = maxfields; 1492 1575 maxfields = size + 16; 1493 Fields = xrealloc(Fields, maxfields * sizeof( var));1576 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0])); 1494 1577 for (; i < maxfields; i++) { 1495 1578 Fields[i].type = VF_SPECIAL; … … 1497 1580 } 1498 1581 } 1499 1500 if (size < nfields) { 1501 for (i = size; i < nfields; i++) { 1502 clrvar(Fields + i); 1503 } 1582 /* if size < nfields, clear extra field variables */ 1583 for (i = size; i < nfields; i++) { 1584 clrvar(Fields + i); 1504 1585 } 1505 1586 nfields = size; … … 1508 1589 static int awk_split(const char *s, node *spl, char **slist) 1509 1590 { 1510 int l, n = 0;1591 int l, n; 1511 1592 char c[4]; 1512 1593 char *s1; … … 1522 1603 c[2] = '\n'; 1523 1604 1605 n = 0; 1524 1606 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ 1525 1607 if (!*s) … … 1539 1621 } else { 1540 1622 pmatch[0].rm_eo = l; 1541 if (s[l]) pmatch[0].rm_eo++; 1623 if (s[l]) 1624 pmatch[0].rm_eo++; 1542 1625 } 1543 1626 memcpy(s1, s, l); 1544 s1[l] = '\0'; 1627 /* make sure we remove *all* of the separator chars */ 1628 do { 1629 s1[l] = '\0'; 1630 } while (++l < pmatch[0].rm_eo); 1545 1631 nextword(&s1); 1546 1632 s += pmatch[0].rm_eo; … … 1561 1647 c[1] = tolower(c[1]); 1562 1648 } 1563 if (*s1) n++; 1564 while ((s1 = strpbrk(s1, c))) { 1649 if (*s1) 1650 n++; 1651 while ((s1 = strpbrk(s1, c)) != NULL) { 1565 1652 *s1++ = '\0'; 1566 1653 n++; … … 1571 1658 while (*s) { 1572 1659 s = skip_whitespace(s); 1573 if (!*s) break; 1660 if (!*s) 1661 break; 1574 1662 n++; 1575 1663 while (*s && !isspace(*s)) … … 1636 1724 len += sl; 1637 1725 } 1638 qrealloc(&b, len+l+sl, &bsize);1726 b = qrealloc(b, len+l+sl, &bsize); 1639 1727 memcpy(b+len, s, l); 1640 1728 len += l; … … 1681 1769 static void hashwalk_init(var *v, xhash *array) 1682 1770 { 1683 char **w;1684 1771 hash_item *hi; 1685 int i; 1686 1687 if (v->type & VF_WALK) 1688 free(v->x.walker); 1689 1690 v->type |= VF_WALK; 1691 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen); 1692 w[0] = w[1] = (char *)(w + 2); 1772 unsigned i; 1773 walker_list *w; 1774 walker_list *prev_walker; 1775 1776 if (v->type & VF_WALK) { 1777 prev_walker = v->x.walker; 1778 } else { 1779 v->type |= VF_WALK; 1780 prev_walker = NULL; 1781 } 1782 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker); 1783 1784 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */ 1785 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w); 1786 w->cur = w->end = w->wbuf; 1787 w->prev = prev_walker; 1693 1788 for (i = 0; i < array->csize; i++) { 1694 1789 hi = array->items[i]; 1695 1790 while (hi) { 1696 strcpy( *w, hi->name);1697 nextword( w);1791 strcpy(w->end, hi->name); 1792 nextword(&w->end); 1698 1793 hi = hi->next; 1699 1794 } … … 1703 1798 static int hashwalk_next(var *v) 1704 1799 { 1705 char **w; 1706 1707 w = v->x.walker; 1708 if (w[1] == w[0]) 1800 walker_list *w = v->x.walker; 1801 1802 if (w->cur >= w->end) { 1803 walker_list *prev_walker = w->prev; 1804 1805 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker); 1806 free(w); 1807 v->x.walker = prev_walker; 1709 1808 return FALSE; 1710 1711 setvar_s(v, nextword(w+1)); 1809 } 1810 1811 setvar_s(v, nextword(&w->cur)); 1712 1812 return TRUE; 1713 1813 } … … 1725 1825 char *b; 1726 1826 regmatch_t pmatch[2]; 1727 int a, p, pp=0, size;1827 int size, a, p, pp = 0; 1728 1828 int fd, so, eo, r, rp; 1729 1829 char c, *m, *s; 1830 1831 debug_printf_eval("entered %s()\n", __func__); 1730 1832 1731 1833 /* we're using our own buffer since we need access to accumulating … … 1740 1842 rp = 0; 1741 1843 1742 if (!m) qrealloc(&m, 256, &size); 1844 if (!m) 1845 m = qrealloc(m, 256, &size); 1846 1743 1847 do { 1744 1848 b = m + a; … … 1756 1860 } else if (c != '\0') { 1757 1861 s = strchr(b+pp, c); 1758 if (!s) s = memchr(b+pp, '\0', p - pp); 1862 if (!s) 1863 s = memchr(b+pp, '\0', p - pp); 1759 1864 if (s) { 1760 1865 so = eo = s-b; … … 1768 1873 if (s) { 1769 1874 so = eo = s-b; 1770 while (b[eo] == '\n') eo++; 1875 while (b[eo] == '\n') 1876 eo++; 1771 1877 if (b[eo] != '\0') 1772 1878 break; … … 1776 1882 1777 1883 if (a > 0) { 1778 memmove(m, (const void *)(m+a), p+1);1884 memmove(m, m+a, p+1); 1779 1885 b = m; 1780 1886 a = 0; 1781 1887 } 1782 1888 1783 qrealloc(&m, a+p+128, &size);1889 m = qrealloc(m, a+p+128, &size); 1784 1890 b = m + a; 1785 1891 pp = p; … … 1811 1917 rsm->size = size; 1812 1918 1919 debug_printf_eval("returning from %s(): %d\n", __func__, r); 1920 1813 1921 return r; 1814 1922 } … … 1835 1943 } 1836 1944 1837 1838 1945 /* formatted output into an allocated buffer, return ptr to buffer */ 1839 1946 static char *awk_printf(node *n) … … 1852 1959 while (*f) { 1853 1960 s = f; 1854 while (*f && (*f != '%' || * (++f)== '%'))1961 while (*f && (*f != '%' || *++f == '%')) 1855 1962 f++; 1856 1963 while (*f && !isalpha(*f)) { … … 1861 1968 1862 1969 incr = (f - s) + MAXVARFMT; 1863 qrealloc(&b, incr + i, &bsize);1970 b = qrealloc(b, incr + i, &bsize); 1864 1971 c = *f; 1865 if (c != '\0') f++; 1972 if (c != '\0') 1973 f++; 1866 1974 c1 = *f; 1867 1975 *f = '\0'; … … 1874 1982 } else if (c == 's') { 1875 1983 s1 = getvar_s(arg); 1876 qrealloc(&b, incr+i+strlen(s1), &bsize);1984 b = qrealloc(b, incr+i+strlen(s1), &bsize); 1877 1985 i += sprintf(b+i, s, s1); 1878 1986 } else { … … 1882 1990 1883 1991 /* if there was an error while sprintf, return value is negative */ 1884 if (i < j) i = j;1885 }1886 1887 b = xrealloc(b, i + 1); 1992 if (i < j) 1993 i = j; 1994 } 1995 1888 1996 free(fmt); 1889 1997 nvfree(v); 1998 b = xrealloc(b, i + 1); 1890 1999 b[i] = '\0'; 1891 2000 return b; 1892 2001 } 1893 2002 1894 /* common substitution routine 1895 * replace (nm) substring of (src) that match (n) with (repl), store 1896 * result into (dest), return number of substitutions. If nm=0, replace 1897 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable 1898 * subexpression matching (\1-\9) 2003 /* Common substitution routine. 2004 * Replace (nm)'th substring of (src) that matches (rn) with (repl), 2005 * store result into (dest), return number of substitutions. 2006 * If nm = 0, replace all matches. 2007 * If src or dst is NULL, use $0. 2008 * If subexp != 0, enable subexpression matching (\1-\9). 1899 2009 */ 1900 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex) 1901 { 1902 char *ds = NULL; 1903 const char *s; 2010 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp) 2011 { 2012 char *resbuf; 1904 2013 const char *sp; 1905 int c, i, j, di, rl, so, eo, nbs, n, dssize; 2014 int match_no, residx, replen, resbufsize; 2015 int regexec_flags; 1906 2016 regmatch_t pmatch[10]; 1907 regex_t sreg, *re; 1908 1909 re = as_regex(rn, &sreg); 1910 if (!src) src = intvar[F0]; 1911 if (!dest) dest = intvar[F0]; 1912 1913 i = di = 0; 1914 sp = getvar_s(src); 1915 rl = strlen(repl); 1916 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) { 1917 so = pmatch[0].rm_so; 1918 eo = pmatch[0].rm_eo; 1919 1920 qrealloc(&ds, di + eo + rl, &dssize); 1921 memcpy(ds + di, sp, eo); 1922 di += eo; 1923 if (++i >= nm) { 2017 regex_t sreg, *regex; 2018 2019 resbuf = NULL; 2020 residx = 0; 2021 match_no = 0; 2022 regexec_flags = 0; 2023 regex = as_regex(rn, &sreg); 2024 sp = getvar_s(src ? src : intvar[F0]); 2025 replen = strlen(repl); 2026 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) { 2027 int so = pmatch[0].rm_so; 2028 int eo = pmatch[0].rm_eo; 2029 2030 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp); 2031 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize); 2032 memcpy(resbuf + residx, sp, eo); 2033 residx += eo; 2034 if (++match_no >= nm) { 2035 const char *s; 2036 int nbs; 2037 1924 2038 /* replace */ 1925 di-= (eo - so);2039 residx -= (eo - so); 1926 2040 nbs = 0; 1927 2041 for (s = repl; *s; s++) { 1928 ds[di++] = c= *s;2042 char c = resbuf[residx++] = *s; 1929 2043 if (c == '\\') { 1930 2044 nbs++; 1931 2045 continue; 1932 2046 } 1933 if (c == '&' || (ex && c >= '0' && c <= '9')) { 1934 di -= ((nbs + 3) >> 1); 2047 if (c == '&' || (subexp && c >= '0' && c <= '9')) { 2048 int j; 2049 residx -= ((nbs + 3) >> 1); 1935 2050 j = 0; 1936 2051 if (c != '&') { … … 1939 2054 } 1940 2055 if (nbs % 2) { 1941 ds[di++] = c;2056 resbuf[residx++] = c; 1942 2057 } else { 1943 n = pmatch[j].rm_eo - pmatch[j].rm_so;1944 qrealloc(&ds, di + rl + n, &dssize);1945 memcpy( ds + di, sp + pmatch[j].rm_so, n);1946 di+= n;2058 int n = pmatch[j].rm_eo - pmatch[j].rm_so; 2059 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize); 2060 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n); 2061 residx += n; 1947 2062 } 1948 2063 } … … 1951 2066 } 1952 2067 2068 regexec_flags = REG_NOTBOL; 1953 2069 sp += eo; 1954 if (i == nm) break; 2070 if (match_no == nm) 2071 break; 1955 2072 if (eo == so) { 1956 ds[di] = *sp++; 1957 if (!ds[di++]) break; 1958 } 1959 } 1960 1961 qrealloc(&ds, di + strlen(sp), &dssize); 1962 strcpy(ds + di, sp); 1963 setvar_p(dest, ds); 1964 if (re == &sreg) regfree(re); 1965 return i; 1966 } 1967 1968 static var *exec_builtin(node *op, var *res) 2073 /* Empty match (e.g. "b*" will match anywhere). 2074 * Advance by one char. */ 2075 //BUG (bug 1333): 2076 //gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc" 2077 //... and will erroneously match "b" even though it is NOT at the word start. 2078 //we need REG_NOTBOW but it does not exist... 2079 //TODO: if EXTRA_COMPAT=y, use GNU matching and re_search, 2080 //it should be able to do it correctly. 2081 /* Subtle: this is safe only because 2082 * qrealloc allocated at least one extra byte */ 2083 resbuf[residx] = *sp; 2084 if (*sp == '\0') 2085 goto ret; 2086 sp++; 2087 residx++; 2088 } 2089 } 2090 2091 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize); 2092 strcpy(resbuf + residx, sp); 2093 ret: 2094 //bb_error_msg("end sp:'%s'%p", sp,sp); 2095 setvar_p(dest ? dest : intvar[F0], resbuf); 2096 if (regex == &sreg) 2097 regfree(regex); 2098 return match_no; 2099 } 2100 2101 static NOINLINE int do_mktime(const char *ds) 2102 { 2103 struct tm then; 2104 int count; 2105 2106 /*memset(&then, 0, sizeof(then)); - not needed */ 2107 then.tm_isdst = -1; /* default is unknown */ 2108 2109 /* manpage of mktime says these fields are ints, 2110 * so we can sscanf stuff directly into them */ 2111 count = sscanf(ds, "%u %u %u %u %u %u %d", 2112 &then.tm_year, &then.tm_mon, &then.tm_mday, 2113 &then.tm_hour, &then.tm_min, &then.tm_sec, 2114 &then.tm_isdst); 2115 2116 if (count < 6 2117 || (unsigned)then.tm_mon < 1 2118 || (unsigned)then.tm_year < 1900 2119 ) { 2120 return -1; 2121 } 2122 2123 then.tm_mon -= 1; 2124 then.tm_year -= 1900; 2125 2126 return mktime(&then); 2127 } 2128 2129 static NOINLINE var *exec_builtin(node *op, var *res) 1969 2130 { 1970 2131 #define tspl (G.exec_builtin__tspl) 1971 2132 1972 int (*to_xxx)(int);1973 2133 var *tv; 1974 2134 node *an[4]; … … 1981 2141 int nargs; 1982 2142 time_t tt; 1983 char *s, *s1;1984 2143 int i, l, ll, n; 1985 2144 … … 1991 2150 for (i = 0; i < 4 && op; i++) { 1992 2151 an[i] = nextarg(&op); 1993 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); 1994 if (isr & 0x08000000) as[i] = getvar_s(av[i]); 2152 if (isr & 0x09000000) 2153 av[i] = evaluate(an[i], &tv[i]); 2154 if (isr & 0x08000000) 2155 as[i] = getvar_s(av[i]); 1995 2156 isr >>= 1; 1996 2157 } 1997 2158 1998 2159 nargs = i; 1999 if ( nargs < (info >> 30))2160 if ((uint32_t)nargs < (info >> 30)) 2000 2161 syntax_error(EMSG_TOO_FEW_ARGS); 2001 2162 2002 switch (info & OPNMASK) { 2163 info &= OPNMASK; 2164 switch (info) { 2003 2165 2004 2166 case B_a2: 2005 #if ENABLE_FEATURE_AWK_MATH 2006 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); 2007 #else 2008 syntax_error(EMSG_NO_MATH); 2009 #endif 2167 if (ENABLE_FEATURE_AWK_LIBM) 2168 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); 2169 else 2170 syntax_error(EMSG_NO_MATH); 2010 2171 break; 2011 2172 2012 case B_sp: 2173 case B_sp: { 2174 char *s, *s1; 2175 2013 2176 if (nargs > 2) { 2014 2177 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ? … … 2021 2184 s1 = s; 2022 2185 clear_array(iamarray(av[1])); 2023 for (i =1; i<=n; i++)2024 setari_u(av[1], i, nextword(&s 1));2025 free(s );2186 for (i = 1; i <= n; i++) 2187 setari_u(av[1], i, nextword(&s)); 2188 free(s1); 2026 2189 setvar_i(res, n); 2027 2190 break; 2028 2029 case B_ss: 2191 } 2192 2193 case B_ss: { 2194 char *s; 2195 2030 2196 l = strlen(as[0]); 2031 2197 i = getvar_i(av[1]) - 1; 2032 if (i > l) i = l; 2033 if (i < 0) i = 0; 2198 if (i > l) 2199 i = l; 2200 if (i < 0) 2201 i = 0; 2034 2202 n = (nargs > 2) ? getvar_i(av[2]) : l-i; 2035 if (n < 0) n = 0; 2036 s = xmalloc(n+1); 2037 strncpy(s, as[0]+i, n); 2038 s[n] = '\0'; 2203 if (n < 0) 2204 n = 0; 2205 s = xstrndup(as[0]+i, n); 2039 2206 setvar_p(res, s); 2040 2207 break; 2041 2208 } 2209 2210 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5: 2211 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */ 2042 2212 case B_an: 2043 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));2213 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1])); 2044 2214 break; 2045 2215 2046 2216 case B_co: 2047 setvar_i(res, ~ (long)getvar_i(av[0]));2217 setvar_i(res, ~getvar_i_int(av[0])); 2048 2218 break; 2049 2219 2050 2220 case B_ls: 2051 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));2221 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1])); 2052 2222 break; 2053 2223 2054 2224 case B_or: 2055 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));2225 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1])); 2056 2226 break; 2057 2227 2058 2228 case B_rs: 2059 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));2229 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1])); 2060 2230 break; 2061 2231 2062 2232 case B_xo: 2063 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));2233 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1])); 2064 2234 break; 2065 2235 2066 2236 case B_lo: 2067 to_xxx = tolower; 2068 goto lo_cont; 2069 2070 case B_up: 2071 to_xxx = toupper; 2072 lo_cont: 2237 case B_up: { 2238 char *s, *s1; 2073 2239 s1 = s = xstrdup(as[0]); 2074 2240 while (*s1) { 2075 *s1 = (*to_xxx)(*s1); 2241 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1); 2242 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a')) 2243 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20); 2076 2244 s1++; 2077 2245 } 2078 2246 setvar_p(res, s); 2079 2247 break; 2248 } 2080 2249 2081 2250 case B_ix: … … 2085 2254 if (ll > 0 && l >= 0) { 2086 2255 if (!icase) { 2087 s = strstr(as[0], as[1]); 2088 if (s) n = (s - as[0]) + 1; 2256 char *s = strstr(as[0], as[1]); 2257 if (s) 2258 n = (s - as[0]) + 1; 2089 2259 } else { 2090 2260 /* this piece of code is terribly slow and 2091 2261 * really should be rewritten 2092 2262 */ 2093 for (i =0; i<=l; i++) {2263 for (i = 0; i <= l; i++) { 2094 2264 if (strncasecmp(as[0]+i, as[1], ll) == 0) { 2095 2265 n = i+1; … … 2115 2285 break; 2116 2286 2287 case B_mt: 2288 setvar_i(res, do_mktime(as[0])); 2289 break; 2290 2117 2291 case B_ma: 2118 2292 re = as_regex(an[1], &sreg); … … 2128 2302 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so); 2129 2303 setvar_i(res, pmatch[0].rm_so); 2130 if (re == &sreg) regfree(re); 2304 if (re == &sreg) 2305 regfree(re); 2131 2306 break; 2132 2307 … … 2161 2336 /* seed is initialized to 1 */ 2162 2337 #define seed (G.evaluate__seed) 2163 #define sreg (G.evaluate__sreg) 2164 2165 node *op1; 2338 #define sreg (G.evaluate__sreg) 2339 2166 2340 var *v1; 2167 union {2168 var *v;2169 const char *s;2170 double d;2171 int i;2172 } L, R;2173 uint32_t opinfo;2174 int opn;2175 union {2176 char *s;2177 rstream *rsm;2178 FILE *F;2179 var *v;2180 regex_t *re;2181 uint32_t info;2182 } X;2183 2341 2184 2342 if (!op) 2185 2343 return setvar_s(res, NULL); 2186 2344 2345 debug_printf_eval("entered %s()\n", __func__); 2346 2187 2347 v1 = nvalloc(2); 2188 2348 2189 2349 while (op) { 2350 struct { 2351 var *v; 2352 const char *s; 2353 } L = L; /* for compiler */ 2354 struct { 2355 var *v; 2356 const char *s; 2357 } R = R; 2358 double L_d = L_d; 2359 uint32_t opinfo; 2360 int opn; 2361 node *op1; 2362 2190 2363 opinfo = op->info; 2191 2364 opn = (opinfo & OPNMASK); 2192 2365 g_lineno = op->lineno; 2366 op1 = op->l.n; 2367 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); 2193 2368 2194 2369 /* execute inevitable things */ 2195 op1 = op->l.n; 2196 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1); 2197 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1); 2198 if (opinfo & OF_STR1) L.s = getvar_s(L.v); 2199 if (opinfo & OF_STR2) R.s = getvar_s(R.v); 2200 if (opinfo & OF_NUM1) L.d = getvar_i(L.v); 2201 2370 if (opinfo & OF_RES1) 2371 L.v = evaluate(op1, v1); 2372 if (opinfo & OF_RES2) 2373 R.v = evaluate(op->r.n, v1+1); 2374 if (opinfo & OF_STR1) { 2375 L.s = getvar_s(L.v); 2376 debug_printf_eval("L.s:'%s'\n", L.s); 2377 } 2378 if (opinfo & OF_STR2) { 2379 R.s = getvar_s(R.v); 2380 debug_printf_eval("R.s:'%s'\n", R.s); 2381 } 2382 if (opinfo & OF_NUM1) { 2383 L_d = getvar_i(L.v); 2384 debug_printf_eval("L_d:%f\n", L_d); 2385 } 2386 2387 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); 2202 2388 switch (XC(opinfo & OPCLSMASK)) { 2203 2389 … … 2212 2398 if (ptest(op1->r.n)) 2213 2399 op->info &= ~OF_CHECKED; 2214 2215 2400 op = op->a.n; 2216 2401 } else { … … 2218 2403 } 2219 2404 } else { 2220 op = (ptest(op1)) ? op->a.n : op->r.n;2405 op = ptest(op1) ? op->a.n : op->r.n; 2221 2406 } 2222 2407 break; … … 2242 2427 2243 2428 case XC( OC_PRINT ): 2244 case XC( OC_PRINTF ): 2245 X.F = stdout; 2429 case XC( OC_PRINTF ): { 2430 FILE *F = stdout; 2431 2246 2432 if (op->r.n) { 2247 X.rsm = newfile(R.s);2248 if (! X.rsm->F) {2433 rstream *rsm = newfile(R.s); 2434 if (!rsm->F) { 2249 2435 if (opn == '|') { 2250 X.rsm->F = popen(R.s, "w");2251 if ( X.rsm->F == NULL)2436 rsm->F = popen(R.s, "w"); 2437 if (rsm->F == NULL) 2252 2438 bb_perror_msg_and_die("popen"); 2253 X.rsm->is_pipe = 1;2439 rsm->is_pipe = 1; 2254 2440 } else { 2255 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");2441 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a"); 2256 2442 } 2257 2443 } 2258 X.F = X.rsm->F;2444 F = rsm->F; 2259 2445 } 2260 2446 2261 2447 if ((opinfo & OPCLSMASK) == OC_PRINT) { 2262 2448 if (!op1) { 2263 fputs(getvar_s(intvar[F0]), X.F);2449 fputs(getvar_s(intvar[F0]), F); 2264 2450 } else { 2265 2451 while (op1) { 2266 L.v = evaluate(nextarg(&op1), v1);2267 if ( L.v->type & VF_NUMBER) {2452 var *v = evaluate(nextarg(&op1), v1); 2453 if (v->type & VF_NUMBER) { 2268 2454 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]), 2269 getvar_i( L.v), TRUE);2270 fputs(g_buf, X.F);2455 getvar_i(v), TRUE); 2456 fputs(g_buf, F); 2271 2457 } else { 2272 fputs(getvar_s( L.v), X.F);2458 fputs(getvar_s(v), F); 2273 2459 } 2274 2460 2275 if (op1) fputs(getvar_s(intvar[OFS]), X.F); 2461 if (op1) 2462 fputs(getvar_s(intvar[OFS]), F); 2276 2463 } 2277 2464 } 2278 fputs(getvar_s(intvar[ORS]), X.F);2465 fputs(getvar_s(intvar[ORS]), F); 2279 2466 2280 2467 } else { /* OC_PRINTF */ 2281 L.s = awk_printf(op1); 2282 fputs(L.s, X.F); 2283 free((char*)L.s); 2284 } 2285 fflush(X.F); 2286 break; 2287 2288 case XC( OC_DELETE ): 2289 X.info = op1->info & OPCLSMASK; 2290 if (X.info == OC_VAR) { 2291 R.v = op1->l.v; 2292 } else if (X.info == OC_FNARG) { 2293 R.v = &fnargs[op1->l.i]; 2468 char *s = awk_printf(op1); 2469 fputs(s, F); 2470 free(s); 2471 } 2472 fflush(F); 2473 break; 2474 } 2475 2476 case XC( OC_DELETE ): { 2477 uint32_t info = op1->info & OPCLSMASK; 2478 var *v; 2479 2480 if (info == OC_VAR) { 2481 v = op1->l.v; 2482 } else if (info == OC_FNARG) { 2483 v = &fnargs[op1->l.aidx]; 2294 2484 } else { 2295 2485 syntax_error(EMSG_NOT_ARRAY); … … 2297 2487 2298 2488 if (op1->r.n) { 2489 const char *s; 2299 2490 clrvar(L.v); 2300 L.s = getvar_s(evaluate(op1->r.n, v1));2301 hash_remove(iamarray( R.v), L.s);2491 s = getvar_s(evaluate(op1->r.n, v1)); 2492 hash_remove(iamarray(v), s); 2302 2493 } else { 2303 clear_array(iamarray(R.v)); 2304 } 2305 break; 2494 clear_array(iamarray(v)); 2495 } 2496 break; 2497 } 2306 2498 2307 2499 case XC( OC_NEWSOURCE ): 2308 g_progname = op->l. s;2500 g_progname = op->l.new_progname; 2309 2501 break; 2310 2502 … … 2322 2514 2323 2515 case XC( OC_EXIT ): 2324 awk_exit(L .d);2516 awk_exit(L_d); 2325 2517 2326 2518 /* -- recursive node type -- */ … … 2333 2525 2334 2526 case XC( OC_FNARG ): 2335 L.v = &fnargs[op->l. i];2527 L.v = &fnargs[op->l.aidx]; 2336 2528 v_cont: 2337 2529 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; … … 2350 2542 op1 = op->r.n; 2351 2543 re_cont: 2352 X.re = as_regex(op1, &sreg); 2353 R.i = regexec(X.re, L.s, 0, NULL, 0); 2354 if (X.re == &sreg) regfree(X.re); 2355 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0)); 2544 { 2545 regex_t *re = as_regex(op1, &sreg); 2546 int i = regexec(re, L.s, 0, NULL, 0); 2547 if (re == &sreg) 2548 regfree(re); 2549 setvar_i(res, (i == 0) ^ (opn == '!')); 2550 } 2356 2551 break; 2357 2552 2358 2553 case XC( OC_MOVE ): 2554 debug_printf_eval("MOVE\n"); 2359 2555 /* if source is a temporary string, jusk relink it to dest */ 2360 if (R.v == v1+1 && R.v->string) { 2361 res = setvar_p(L.v, R.v->string); 2362 R.v->string = NULL; 2363 } else { 2556 //Disabled: if R.v is numeric but happens to have cached R.v->string, 2557 //then L.v ends up being a string, which is wrong 2558 // if (R.v == v1+1 && R.v->string) { 2559 // res = setvar_p(L.v, R.v->string); 2560 // R.v->string = NULL; 2561 // } else { 2364 2562 res = copyvar(L.v, R.v); 2365 }2563 // } 2366 2564 break; 2367 2565 … … 2372 2570 break; 2373 2571 2374 case XC( OC_FUNC ): 2572 case XC( OC_FUNC ): { 2573 var *vbeg, *v; 2574 const char *sv_progname; 2575 2375 2576 if (!op->r.f->body.first) 2376 2577 syntax_error(EMSG_UNDEF_FUNC); 2377 2578 2378 X.v = R.v = nvalloc(op->r.f->nargs+1);2579 vbeg = v = nvalloc(op->r.f->nargs + 1); 2379 2580 while (op1) { 2380 L.v= evaluate(nextarg(&op1), v1);2381 copyvar( R.v, L.v);2382 R.v->type |= VF_CHILD;2383 R.v->x.parent = L.v;2384 if (++ R.v - X.v>= op->r.f->nargs)2581 var *arg = evaluate(nextarg(&op1), v1); 2582 copyvar(v, arg); 2583 v->type |= VF_CHILD; 2584 v->x.parent = arg; 2585 if (++v - vbeg >= op->r.f->nargs) 2385 2586 break; 2386 2587 } 2387 2588 2388 R.v = fnargs;2389 fnargs = X.v;2390 2391 L.s = g_progname; 2589 v = fnargs; 2590 fnargs = vbeg; 2591 sv_progname = g_progname; 2592 2392 2593 res = evaluate(op->r.f->body.first, res); 2393 g_progname = L.s; 2394 2594 2595 g_progname = sv_progname; 2395 2596 nvfree(fnargs); 2396 fnargs = R.v; 2397 break; 2597 fnargs = v; 2598 2599 break; 2600 } 2398 2601 2399 2602 case XC( OC_GETLINE ): 2400 case XC( OC_PGETLINE ): 2603 case XC( OC_PGETLINE ): { 2604 rstream *rsm; 2605 int i; 2606 2401 2607 if (op1) { 2402 X.rsm = newfile(L.s);2403 if (! X.rsm->F) {2608 rsm = newfile(L.s); 2609 if (!rsm->F) { 2404 2610 if ((opinfo & OPCLSMASK) == OC_PGETLINE) { 2405 X.rsm->F = popen(L.s, "r");2406 X.rsm->is_pipe = TRUE;2611 rsm->F = popen(L.s, "r"); 2612 rsm->is_pipe = TRUE; 2407 2613 } else { 2408 X.rsm->F = fopen(L.s, "r");/* not xfopen! */2614 rsm->F = fopen_for_read(L.s); /* not xfopen! */ 2409 2615 } 2410 2616 } 2411 2617 } else { 2412 if (!iF) iF = next_input_file(); 2413 X.rsm = iF; 2414 } 2415 2416 if (!X.rsm->F) { 2618 if (!iF) 2619 iF = next_input_file(); 2620 rsm = iF; 2621 } 2622 2623 if (!rsm->F) { 2417 2624 setvar_i(intvar[ERRNO], errno); 2418 2625 setvar_i(res, -1); … … 2423 2630 R.v = intvar[F0]; 2424 2631 2425 L.i = awk_getline(X.rsm, R.v); 2426 if (L.i > 0) { 2427 if (!op1) { 2428 incvar(intvar[FNR]); 2429 incvar(intvar[NR]); 2632 i = awk_getline(rsm, R.v); 2633 if (i > 0 && !op1) { 2634 incvar(intvar[FNR]); 2635 incvar(intvar[NR]); 2636 } 2637 setvar_i(res, i); 2638 break; 2639 } 2640 2641 /* simple builtins */ 2642 case XC( OC_FBLTIN ): { 2643 double R_d = R_d; /* for compiler */ 2644 2645 switch (opn) { 2646 case F_in: 2647 R_d = (int)L_d; 2648 break; 2649 2650 case F_rn: 2651 R_d = (double)rand() / (double)RAND_MAX; 2652 break; 2653 2654 case F_co: 2655 if (ENABLE_FEATURE_AWK_LIBM) { 2656 R_d = cos(L_d); 2657 break; 2430 2658 } 2431 }2432 setvar_i(res, L.i);2433 break;2434 2435 /* simple builtins */2436 case XC( OC_FBLTIN ):2437 switch (opn) {2438 2439 case F_in:2440 R.d = (int)L.d;2441 break;2442 2443 case F_rn:2444 R.d = (double)rand() / (double)RAND_MAX;2445 break;2446 #if ENABLE_FEATURE_AWK_MATH2447 case F_co:2448 R.d = cos(L.d);2449 break;2450 2659 2451 2660 case F_ex: 2452 R.d = exp(L.d); 2453 break; 2661 if (ENABLE_FEATURE_AWK_LIBM) { 2662 R_d = exp(L_d); 2663 break; 2664 } 2454 2665 2455 2666 case F_lg: 2456 R.d = log(L.d); 2457 break; 2667 if (ENABLE_FEATURE_AWK_LIBM) { 2668 R_d = log(L_d); 2669 break; 2670 } 2458 2671 2459 2672 case F_si: 2460 R.d = sin(L.d); 2461 break; 2673 if (ENABLE_FEATURE_AWK_LIBM) { 2674 R_d = sin(L_d); 2675 break; 2676 } 2462 2677 2463 2678 case F_sq: 2464 R.d = sqrt(L.d); 2465 break; 2466 #else 2467 case F_co: 2468 case F_ex: 2469 case F_lg: 2470 case F_si: 2471 case F_sq: 2679 if (ENABLE_FEATURE_AWK_LIBM) { 2680 R_d = sqrt(L_d); 2681 break; 2682 } 2683 2472 2684 syntax_error(EMSG_NO_MATH); 2473 2685 break; 2474 #endif 2686 2475 2687 case F_sr: 2476 R .d = (double)seed;2477 seed = op1 ? (unsigned)L .d : (unsigned)time(NULL);2688 R_d = (double)seed; 2689 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); 2478 2690 srand(seed); 2479 2691 break; 2480 2692 2481 2693 case F_ti: 2482 R .d = time(NULL);2694 R_d = time(NULL); 2483 2695 break; 2484 2696 … … 2486 2698 if (!op1) 2487 2699 L.s = getvar_s(intvar[F0]); 2488 R .d = strlen(L.s);2700 R_d = strlen(L.s); 2489 2701 break; 2490 2702 2491 2703 case F_sy: 2492 fflush (NULL);2493 R .d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)2704 fflush_all(); 2705 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s) 2494 2706 ? (system(L.s) >> 8) : 0; 2495 2707 break; 2496 2708 2497 2709 case F_ff: 2498 if (!op1) 2710 if (!op1) { 2499 2711 fflush(stdout); 2500 else { 2501 if (L.s && *L.s) { 2502 X.rsm = newfile(L.s); 2503 fflush(X.rsm->F); 2504 } else { 2505 fflush(NULL); 2506 } 2712 } else if (L.s && *L.s) { 2713 rstream *rsm = newfile(L.s); 2714 fflush(rsm->F); 2715 } else { 2716 fflush_all(); 2507 2717 } 2508 2718 break; 2509 2719 2510 case F_cl: 2511 X.rsm = (rstream *)hash_search(fdhash, L.s); 2512 if (X.rsm) { 2513 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F); 2514 free(X.rsm->buffer); 2720 case F_cl: { 2721 rstream *rsm; 2722 int err = 0; 2723 rsm = (rstream *)hash_search(fdhash, L.s); 2724 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm); 2725 if (rsm) { 2726 debug_printf_eval("OC_FBLTIN F_cl " 2727 "rsm->is_pipe:%d, ->F:%p\n", 2728 rsm->is_pipe, rsm->F); 2729 /* Can be NULL if open failed. Example: 2730 * getline line <"doesnt_exist"; 2731 * close("doesnt_exist"); <--- here rsm->F is NULL 2732 */ 2733 if (rsm->F) 2734 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); 2735 free(rsm->buffer); 2515 2736 hash_remove(fdhash, L.s); 2516 2737 } 2517 if ( R.i != 0)2738 if (err) 2518 2739 setvar_i(intvar[ERRNO], errno); 2519 R .d = (double)R.i;2740 R_d = (double)err; 2520 2741 break; 2521 2742 } 2522 setvar_i(res, R.d); 2523 break; 2743 } /* switch */ 2744 setvar_i(res, R_d); 2745 break; 2746 } 2524 2747 2525 2748 case XC( OC_BUILTIN ): … … 2531 2754 break; 2532 2755 2533 case XC( OC_UNARY ): 2534 X.v = R.v; 2535 L.d = R.d = getvar_i(R.v); 2756 case XC( OC_UNARY ): { 2757 double Ld, R_d; 2758 2759 Ld = R_d = getvar_i(R.v); 2536 2760 switch (opn) { 2537 2761 case 'P': 2538 L .d = ++R.d;2762 Ld = ++R_d; 2539 2763 goto r_op_change; 2540 2764 case 'p': 2541 R .d++;2765 R_d++; 2542 2766 goto r_op_change; 2543 2767 case 'M': 2544 L .d = --R.d;2768 Ld = --R_d; 2545 2769 goto r_op_change; 2546 2770 case 'm': 2547 R.d--; 2548 goto r_op_change; 2771 R_d--; 2772 r_op_change: 2773 setvar_i(R.v, R_d); 2774 break; 2549 2775 case '!': 2550 L .d = istrue(X.v) ? 0 : 1;2776 Ld = !istrue(R.v); 2551 2777 break; 2552 2778 case '-': 2553 L .d = -R.d;2779 Ld = -R_d; 2554 2780 break; 2555 r_op_change: 2556 setvar_i(X.v, R.d); 2557 } 2558 setvar_i(res, L.d); 2559 break; 2560 2561 case XC( OC_FIELD ): 2562 R.i = (int)getvar_i(R.v); 2563 if (R.i == 0) { 2781 } 2782 setvar_i(res, Ld); 2783 break; 2784 } 2785 2786 case XC( OC_FIELD ): { 2787 int i = (int)getvar_i(R.v); 2788 if (i == 0) { 2564 2789 res = intvar[F0]; 2565 2790 } else { 2566 2791 split_f0(); 2567 if (R.i > nfields) 2568 fsrealloc(R.i); 2569 res = &Fields[R.i - 1]; 2570 } 2571 break; 2792 if (i > nfields) 2793 fsrealloc(i); 2794 res = &Fields[i - 1]; 2795 } 2796 break; 2797 } 2572 2798 2573 2799 /* concatenation (" ") and index joining (",") */ 2574 2800 case XC( OC_CONCAT ): 2575 case XC( OC_COMMA ): 2576 opn = strlen(L.s) + strlen(R.s) + 2; 2577 X.s = xmalloc(opn); 2578 strcpy(X.s, L.s); 2579 if ((opinfo & OPCLSMASK) == OC_COMMA) { 2580 L.s = getvar_s(intvar[SUBSEP]); 2581 X.s = xrealloc(X.s, opn + strlen(L.s)); 2582 strcat(X.s, L.s); 2583 } 2584 strcat(X.s, R.s); 2585 setvar_p(res, X.s); 2586 break; 2801 case XC( OC_COMMA ): { 2802 const char *sep = ""; 2803 if ((opinfo & OPCLSMASK) == OC_COMMA) 2804 sep = getvar_s(intvar[SUBSEP]); 2805 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); 2806 break; 2807 } 2587 2808 2588 2809 case XC( OC_LAND ): … … 2595 2816 2596 2817 case XC( OC_BINARY ): 2597 case XC( OC_REPLACE ): 2598 R.d = getvar_i(R.v); 2818 case XC( OC_REPLACE ): { 2819 double R_d = getvar_i(R.v); 2820 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn); 2599 2821 switch (opn) { 2600 2822 case '+': 2601 L .d += R.d;2823 L_d += R_d; 2602 2824 break; 2603 2825 case '-': 2604 L .d -= R.d;2826 L_d -= R_d; 2605 2827 break; 2606 2828 case '*': 2607 L .d *= R.d;2829 L_d *= R_d; 2608 2830 break; 2609 2831 case '/': 2610 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2611 L.d /= R.d; 2832 if (R_d == 0) 2833 syntax_error(EMSG_DIV_BY_ZERO); 2834 L_d /= R_d; 2612 2835 break; 2613 2836 case '&': 2614 #if ENABLE_FEATURE_AWK_MATH 2615 L.d = pow(L.d, R.d); 2616 #else 2617 syntax_error(EMSG_NO_MATH); 2618 #endif 2837 if (ENABLE_FEATURE_AWK_LIBM) 2838 L_d = pow(L_d, R_d); 2839 else 2840 syntax_error(EMSG_NO_MATH); 2619 2841 break; 2620 2842 case '%': 2621 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2622 L.d -= (int)(L.d / R.d) * R.d; 2843 if (R_d == 0) 2844 syntax_error(EMSG_DIV_BY_ZERO); 2845 L_d -= (int)(L_d / R_d) * R_d; 2623 2846 break; 2624 2847 } 2625 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); 2626 break; 2627 2628 case XC( OC_COMPARE ): 2848 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d); 2849 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d); 2850 break; 2851 } 2852 2853 case XC( OC_COMPARE ): { 2854 int i = i; /* for compiler */ 2855 double Ld; 2856 2629 2857 if (is_numeric(L.v) && is_numeric(R.v)) { 2630 L .d = getvar_i(L.v) - getvar_i(R.v);2858 Ld = getvar_i(L.v) - getvar_i(R.v); 2631 2859 } else { 2632 L.s= getvar_s(L.v);2633 R.s= getvar_s(R.v);2634 L .d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);2860 const char *l = getvar_s(L.v); 2861 const char *r = getvar_s(R.v); 2862 Ld = icase ? strcasecmp(l, r) : strcmp(l, r); 2635 2863 } 2636 2864 switch (opn & 0xfe) { 2637 2865 case 0: 2638 R.i = (L.d > 0);2866 i = (Ld > 0); 2639 2867 break; 2640 2868 case 2: 2641 R.i = (L.d >= 0);2869 i = (Ld >= 0); 2642 2870 break; 2643 2871 case 4: 2644 R.i = (L.d == 0);2872 i = (Ld == 0); 2645 2873 break; 2646 2874 } 2647 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0); 2648 break; 2875 setvar_i(res, (i == 0) ^ (opn & 1)); 2876 break; 2877 } 2649 2878 2650 2879 default: … … 2657 2886 if (nextrec) 2658 2887 break; 2659 } 2888 } /* while (op) */ 2889 2660 2890 nvfree(v1); 2891 debug_printf_eval("returning from %s(): %p\n", __func__, res); 2661 2892 return res; 2662 2893 #undef fnargs … … 2699 2930 static int is_assignment(const char *expr) 2700 2931 { 2701 char *exprc, *s, *s0, *s1; 2932 char *exprc, *val, *s, *s1; 2933 2934 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { 2935 return FALSE; 2936 } 2702 2937 2703 2938 exprc = xstrdup(expr); 2704 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { 2705 free(exprc); 2706 return FALSE; 2707 } 2708 2709 *(s++) = '\0'; 2710 s0 = s1 = s; 2711 while (*s) 2712 *(s1++) = nextchar(&s); 2713 2714 *s1 = '\0'; 2715 setvar_u(newvar(exprc), s0); 2939 val = exprc + (val - expr); 2940 *val++ = '\0'; 2941 2942 s = s1 = val; 2943 while ((*s1 = nextchar(&s)) != '\0') 2944 s1++; 2945 2946 setvar_u(newvar(exprc), val); 2716 2947 free(exprc); 2717 2948 return TRUE; … … 2727 2958 const char *fname, *ind; 2728 2959 2729 if (rsm.F) fclose(rsm.F); 2960 if (rsm.F) 2961 fclose(rsm.F); 2730 2962 rsm.F = NULL; 2731 2963 rsm.pos = rsm.adv = 0; … … 2741 2973 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); 2742 2974 if (fname && *fname && !is_assignment(fname)) 2743 F = afopen(fname, "r");2975 F = xfopen_stdin(fname); 2744 2976 } 2745 2977 } while (!F); … … 2753 2985 } 2754 2986 2755 int awk_main(int argc, char **argv) ;2987 int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 2756 2988 int awk_main(int argc, char **argv) 2757 2989 { 2758 2990 unsigned opt; 2759 2991 char *opt_F, *opt_W; 2760 llist_t *opt_v = NULL; 2761 int i, j, flen; 2992 llist_t *list_v = NULL; 2993 llist_t *list_f = NULL; 2994 int i, j; 2762 2995 var *v; 2763 2996 var tv; … … 2817 3050 } 2818 3051 } 2819 opt_complementary = "v:: ";2820 opt = getopt32(argv, "F:v:f:W:", &opt_F, & opt_v, &g_progname, &opt_W);3052 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ 3053 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); 2821 3054 argv += optind; 2822 3055 argc -= optind; 2823 3056 if (opt & 0x1) 2824 3057 setvar_s(intvar[FS], opt_F); // -F 2825 while ( opt_v) { /* -v */2826 if (!is_assignment(llist_pop(& opt_v)))3058 while (list_v) { /* -v */ 3059 if (!is_assignment(llist_pop(&list_v))) 2827 3060 bb_show_usage(); 2828 3061 } 2829 if (opt & 0x4) { // -f 2830 char *s = s; /* die, gcc, die */ 2831 FILE *from_file = afopen(g_progname, "r"); 2832 /* one byte is reserved for some trick in next_token */ 2833 if (fseek(from_file, 0, SEEK_END) == 0) { 2834 flen = ftell(from_file); 2835 s = xmalloc(flen + 4); 2836 fseek(from_file, 0, SEEK_SET); 2837 i = 1 + fread(s + 1, 1, flen, from_file); 2838 } else { 3062 if (list_f) { /* -f */ 3063 do { 3064 char *s = NULL; 3065 FILE *from_file; 3066 3067 g_progname = llist_pop(&list_f); 3068 from_file = xfopen_stdin(g_progname); 3069 /* one byte is reserved for some trick in next_token */ 2839 3070 for (i = j = 1; j > 0; i += j) { 2840 3071 s = xrealloc(s, i + 4096); 2841 3072 j = fread(s + i, 1, 4094, from_file); 2842 3073 } 2843 } 2844 s[i] = '\0'; 2845 fclose(from_file); 2846 parse_program(s + 1); 2847 free(s); 3074 s[i] = '\0'; 3075 fclose(from_file); 3076 parse_program(s + 1); 3077 free(s); 3078 } while (list_f); 3079 argc++; 2848 3080 } else { // no -f: take program from 1st parameter 2849 3081 if (!argc) … … 2851 3083 g_progname = "cmd. line"; 2852 3084 parse_program(*argv++); 2853 argc--;2854 3085 } 2855 3086 if (opt & 0x8) // -W … … 2857 3088 2858 3089 /* fill in ARGV array */ 2859 setvar_i(intvar[ARGC], argc + 1);3090 setvar_i(intvar[ARGC], argc); 2860 3091 setari_u(intvar[ARGV], 0, "awk"); 2861 3092 i = 0; … … 2868 3099 2869 3100 /* input file could already be opened in BEGIN block */ 2870 if (!iF) iF = next_input_file(); 3101 if (!iF) 3102 iF = next_input_file(); 2871 3103 2872 3104 /* passing through input files */
Note:
See TracChangeset
for help on using the changeset viewer.