diff options
author | Ron Yorston <rmy@pobox.com> | 2024-07-10 11:54:23 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-07-10 11:54:23 +0100 |
commit | 2dc17b7c80c803119dd2214bce4406b252ae2e9f (patch) | |
tree | 3eb11a8170e4164e2781a9be9925fc4bfa6f5053 | |
parent | 29a24869e403e7364301e6fd7c745d327ed2d8c6 (diff) | |
parent | 0af28b84e58307422f807ddbdafc67a68f71eb64 (diff) | |
download | busybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.tar.gz busybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.tar.bz2 busybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | editors/awk.c | 188 | ||||
-rw-r--r-- | libpwdgrp/uidgid_get.c | 6 | ||||
-rw-r--r-- | networking/wget.c | 2 | ||||
-rw-r--r-- | shell/ash.c | 33 | ||||
-rwxr-xr-x | testsuite/awk.tests | 31 |
5 files changed, 159 insertions, 101 deletions
diff --git a/editors/awk.c b/editors/awk.c index cb4b2958f..1feb49da1 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -180,11 +180,11 @@ typedef struct node_s { | |||
180 | var *v; | 180 | var *v; |
181 | int aidx; | 181 | int aidx; |
182 | const char *new_progname; | 182 | const char *new_progname; |
183 | /* if TI_REGEXP node, points to regex_t[2] array (case sensitive and insensitive) */ | ||
183 | regex_t *re; | 184 | regex_t *re; |
184 | } l; | 185 | } l; |
185 | union { | 186 | union { |
186 | struct node_s *n; | 187 | struct node_s *n; |
187 | regex_t *ire; | ||
188 | func *f; | 188 | func *f; |
189 | } r; | 189 | } r; |
190 | union { | 190 | union { |
@@ -307,13 +307,13 @@ static void debug_parse_print_tc(uint32_t n) | |||
307 | | TC_LENGTH) | 307 | | TC_LENGTH) |
308 | #define TS_CONCAT_R (TS_OPERAND | TS_UOPPRE) | 308 | #define TS_CONCAT_R (TS_OPERAND | TS_UOPPRE) |
309 | 309 | ||
310 | #define OF_RES1 0x010000 | 310 | #define OF_RES1 0x010000 /* evaluate(left_node) */ |
311 | #define OF_RES2 0x020000 | 311 | #define OF_RES2 0x020000 /* evaluate(right_node) */ |
312 | #define OF_STR1 0x040000 | 312 | #define OF_STR1 0x040000 /* ...and use its string value */ |
313 | #define OF_STR2 0x080000 | 313 | #define OF_STR2 0x080000 /* ...and use its string value */ |
314 | #define OF_NUM1 0x100000 | 314 | #define OF_NUM1 0x100000 /* ...and use its numeric value */ |
315 | #define OF_CHECKED 0x200000 | 315 | #define OF_REQUIRED 0x200000 /* left_node must not be NULL */ |
316 | #define OF_REQUIRED 0x400000 | 316 | #define OF_CHECKED 0x400000 /* range pattern flip-flop bit */ |
317 | 317 | ||
318 | /* combined operator flags */ | 318 | /* combined operator flags */ |
319 | #define xx 0 | 319 | #define xx 0 |
@@ -331,17 +331,18 @@ static void debug_parse_print_tc(uint32_t n) | |||
331 | #define OPCLSMASK 0xFF00 | 331 | #define OPCLSMASK 0xFF00 |
332 | #define OPNMASK 0x007F | 332 | #define OPNMASK 0x007F |
333 | 333 | ||
334 | /* operator priority is a highest byte (even: r->l, odd: l->r grouping) | 334 | /* operator precedence is the highest byte (even: r->l, odd: l->r grouping) |
335 | * (for builtins it has different meaning) | 335 | * (for builtins the byte has a different meaning) |
336 | */ | 336 | */ |
337 | #undef P | 337 | #undef P |
338 | #undef PRIMASK | 338 | #undef PRIMASK |
339 | #undef PRIMASK2 | 339 | #undef PRIMASK2 |
340 | #define PRIMASK 0x7F000000 | ||
341 | #define PRIMASK2 0x7E000000 | ||
340 | /* Smaller 'x' means _higher_ operator precedence */ | 342 | /* Smaller 'x' means _higher_ operator precedence */ |
341 | #define PRECEDENCE(x) (x << 24) | 343 | #define PRECEDENCE(x) (x << 24) |
342 | #define P(x) PRECEDENCE(x) | 344 | #define P(x) PRECEDENCE(x) |
343 | #define PRIMASK 0x7F000000 | 345 | #define LOWEST_PRECEDENCE PRIMASK |
344 | #define PRIMASK2 0x7E000000 | ||
345 | 346 | ||
346 | /* Operation classes */ | 347 | /* Operation classes */ |
347 | #define SHIFT_TIL_THIS 0x0600 | 348 | #define SHIFT_TIL_THIS 0x0600 |
@@ -433,36 +434,47 @@ static const char tokenlist[] ALIGN1 = | |||
433 | ; | 434 | ; |
434 | 435 | ||
435 | static const uint32_t tokeninfo[] ALIGN4 = { | 436 | static const uint32_t tokeninfo[] ALIGN4 = { |
436 | 0, | 437 | 0, /* ( */ |
437 | 0, | 438 | 0, /* ) */ |
438 | #define TI_REGEXP OC_REGEXP | 439 | #define TI_REGEXP OC_REGEXP |
439 | TI_REGEXP, | 440 | TI_REGEXP, /* / */ |
441 | /* >> > | */ | ||
440 | xS|'a', xS|'w', xS|'|', | 442 | xS|'a', xS|'w', xS|'|', |
443 | /* ++ -- */ | ||
441 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', | 444 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', |
442 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') | 445 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') |
443 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') | 446 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') |
447 | /* ++ -- $ */ | ||
444 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), | 448 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), |
445 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(38), OC_REPLACE|NV|P(38)|'+', OC_REPLACE|NV|P(38)|'-', | 449 | /* == = += -= */ |
446 | OC_REPLACE|NV|P(38)|'*', OC_REPLACE|NV|P(38)|'/', OC_REPLACE|NV|P(38)|'%', OC_REPLACE|NV|P(38)|'&', | 450 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', |
447 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(38)|'&', OC_BINARY|NV|P(15)|'&', | 451 | /* *= /= %= ^= (^ is exponentiation, NOT xor) */ |
452 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | ||
453 | /* + - **= ** */ | ||
454 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | ||
455 | /* / % ^ * */ | ||
448 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | 456 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
457 | /* != >= <= > */ | ||
449 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | 458 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
450 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) | 459 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) |
460 | /* < !~ ~ && */ | ||
451 | TI_LESS, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | 461 | TI_LESS, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), |
452 | #define TI_TERNARY (OC_TERNARY|Vx|P(64)|'?') | 462 | #define TI_TERNARY (OC_TERNARY|Vx|P(64)|'?') |
453 | #define TI_COLON (OC_COLON|xx|P(67)|':') | 463 | #define TI_COLON (OC_COLON|xx|P(67)|':') |
464 | /* || ? : */ | ||
454 | OC_LOR|Vx|P(59), TI_TERNARY, TI_COLON, | 465 | OC_LOR|Vx|P(59), TI_TERNARY, TI_COLON, |
455 | #define TI_IN (OC_IN|SV|P(49)) | 466 | #define TI_IN (OC_IN|SV|P(49)) |
456 | TI_IN, | 467 | TI_IN, |
457 | #define TI_COMMA (OC_COMMA|SS|P(80)) | 468 | #define TI_COMMA (OC_COMMA|SS|P(80)) |
458 | TI_COMMA, | 469 | TI_COMMA, |
459 | #define TI_PGETLINE (OC_PGETLINE|SV|P(37)) | 470 | #define TI_PGETLINE (OC_PGETLINE|SV|P(37)) |
460 | TI_PGETLINE, | 471 | TI_PGETLINE, /* | */ |
472 | /* + - ! */ | ||
461 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', | 473 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', |
462 | 0, /* ] */ | 474 | 0, /* ] */ |
463 | 0, | 475 | 0, /* { */ |
464 | 0, | 476 | 0, /* } */ |
465 | 0, | 477 | 0, /* ; */ |
466 | 0, /* \n */ | 478 | 0, /* \n */ |
467 | ST_IF, ST_DO, ST_FOR, OC_BREAK, | 479 | ST_IF, ST_DO, ST_FOR, OC_BREAK, |
468 | OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, | 480 | OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, |
@@ -497,7 +509,7 @@ static const uint32_t tokeninfo[] ALIGN4 = { | |||
497 | OC_F|F_rn, OC_F|F_si|Nx|Rx, OC_F|F_sq|Nx|Rx, OC_F|F_sr|Nx, // rand sin sqrt srand | 509 | OC_F|F_rn, OC_F|F_si|Nx|Rx, OC_F|F_sq|Nx|Rx, OC_F|F_sr|Nx, // rand sin sqrt srand |
498 | OC_B|B_ge|_s_vv_|A3,OC_B|B_gs|ss_vv_|A2,OC_B|B_ix|_ss_vv|A2, // gensub gsub index /*length was here*/ | 510 | OC_B|B_ge|_s_vv_|A3,OC_B|B_gs|ss_vv_|A2,OC_B|B_ix|_ss_vv|A2, // gensub gsub index /*length was here*/ |
499 | OC_B|B_ma|__s__v|A2,OC_B|B_sp|__s_vv|A2,OC_SPRINTF, OC_B|B_su|ss_vv_|A2,// match split sprintf sub | 511 | OC_B|B_ma|__s__v|A2,OC_B|B_sp|__s_vv|A2,OC_SPRINTF, OC_B|B_su|ss_vv_|A2,// match split sprintf sub |
500 | OC_B|B_ss|__svvv|A2,OC_F|F_ti, OC_B|B_ti|__s_vv, OC_B|B_mt|__s_vv, // substr systime strftime mktime | 512 | OC_B|B_ss|__svvv|A2,OC_F|F_ti, OC_B|B_ti|__s_vv, OC_B|B_mt|__s_vv|A1,// substr systime strftime mktime |
501 | OC_B|B_lo|__s__v|A1,OC_B|B_up|__s__v|A1, // tolower toupper | 513 | OC_B|B_lo|__s__v|A1,OC_B|B_up|__s__v|A1, // tolower toupper |
502 | OC_F|F_le|Sx, // length | 514 | OC_F|F_le|Sx, // length |
503 | OC_GETLINE|SV, // getline | 515 | OC_GETLINE|SV, // getline |
@@ -511,6 +523,38 @@ static const uint32_t tokeninfo[] ALIGN4 = { | |||
511 | #undef OC_F | 523 | #undef OC_F |
512 | }; | 524 | }; |
513 | 525 | ||
526 | /* gawk 5.1.1 manpage says the precedence of comparisons and assignments are as follows: | ||
527 | * ...... | ||
528 | * < > <= >= == != | ||
529 | * ~ !~ | ||
530 | * in | ||
531 | * && | ||
532 | * || | ||
533 | * ?: | ||
534 | * = += -= *= /= %= ^= | ||
535 | * But there are some abnormalities: | ||
536 | * awk 'BEGIN { print v=3==3,v }' - ok: | ||
537 | * 1 1 | ||
538 | * awk 'BEGIN { print 3==v=3,v }' - wrong, (3==v)=3 is not a valid assignment: | ||
539 | * 1 3 | ||
540 | * This also unexpectedly works: echo "foo" | awk '$1==$1="foo" {print $1}' | ||
541 | * More than one comparison op fails to parse: | ||
542 | * awk 'BEGIN { print 3==3==3 }' - syntax error (wrong, should work) | ||
543 | * awk 'BEGIN { print 3==3!=3 }' - syntax error (wrong, should work) | ||
544 | * | ||
545 | * The ternary a?b:c works as follows in gawk: "a" can't be assignment | ||
546 | * ("= has lower precedence than ?") but inside "b" or "c", assignment | ||
547 | * is higher precedence: | ||
548 | * awk 'BEGIN { u=v=w=1; print u=0?v=4:w=5; print u,v,w }' | ||
549 | * 5 | ||
550 | * 5 1 5 | ||
551 | * This differs from C and shell's "test" rules for ?: which have implicit () | ||
552 | * around "b" in ?:, but not around "c" - they would barf on "w=5" above. | ||
553 | * gawk allows nesting of ?: - this works: | ||
554 | * u=0?v=4?5:6:w=7?8:9 means u=0?(v=4?5:6):(w=7?8:9) | ||
555 | * bbox is buggy here, requires parens: "u=0?(v=4):(w=5)" | ||
556 | */ | ||
557 | |||
514 | /* internal variable names and their initial values */ | 558 | /* internal variable names and their initial values */ |
515 | /* asterisk marks SPECIAL vars; $ is just no-named Field0 */ | 559 | /* asterisk marks SPECIAL vars; $ is just no-named Field0 */ |
516 | enum { | 560 | enum { |
@@ -532,6 +576,7 @@ static const char vValues[] ALIGN1 = | |||
532 | "%.6g\0" "%.6g\0" " \0" " \0" | 576 | "%.6g\0" "%.6g\0" " \0" " \0" |
533 | "\n\0" "\n\0" "\0" "\0" | 577 | "\n\0" "\n\0" "\0" "\0" |
534 | "\034\0" "\0" "\377"; | 578 | "\034\0" "\0" "\377"; |
579 | #define str_percent_dot_6g vValues | ||
535 | 580 | ||
536 | /* hash size may grow to these values */ | 581 | /* hash size may grow to these values */ |
537 | #define FIRST_PRIME 61 | 582 | #define FIRST_PRIME 61 |
@@ -922,7 +967,7 @@ static double my_strtod_or_hexoct(char **pp) | |||
922 | 967 | ||
923 | /* -------- working with variables (set/get/copy/etc) -------- */ | 968 | /* -------- working with variables (set/get/copy/etc) -------- */ |
924 | 969 | ||
925 | static void fmt_num(const char *format, double n) | 970 | static const char *fmt_num(const char *format, double n) |
926 | { | 971 | { |
927 | if (n == (long long)n) { | 972 | if (n == (long long)n) { |
928 | snprintf(g_buf, MAXVARFMT, "%"LL_FMT"d", (long long)n); | 973 | snprintf(g_buf, MAXVARFMT, "%"LL_FMT"d", (long long)n); |
@@ -939,6 +984,7 @@ static void fmt_num(const char *format, double n) | |||
939 | syntax_error(EMSG_INV_FMT); | 984 | syntax_error(EMSG_INV_FMT); |
940 | } | 985 | } |
941 | } | 986 | } |
987 | return g_buf; | ||
942 | } | 988 | } |
943 | 989 | ||
944 | static xhash *iamarray(var *a) | 990 | static xhash *iamarray(var *a) |
@@ -1025,8 +1071,15 @@ static const char *getvar_s(var *v) | |||
1025 | { | 1071 | { |
1026 | /* if v is numeric and has no cached string, convert it to string */ | 1072 | /* if v is numeric and has no cached string, convert it to string */ |
1027 | if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { | 1073 | if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { |
1028 | fmt_num(getvar_s(intvar[CONVFMT]), v->number); | 1074 | const char *convfmt = str_percent_dot_6g; /* "%.6g" */ |
1029 | v->string = xstrdup(g_buf); | 1075 | /* Get CONVFMT, unless we already recursed on it: |
1076 | * someone might try to cause stack overflow by setting | ||
1077 | * CONVFMT=9 (a numeric, not string, value) | ||
1078 | */ | ||
1079 | if (v != intvar[CONVFMT]) | ||
1080 | convfmt = getvar_s(intvar[CONVFMT]); | ||
1081 | /* Convert the value */ | ||
1082 | v->string = xstrdup(fmt_num(convfmt, v->number)); | ||
1030 | v->type |= VF_CACHED; | 1083 | v->type |= VF_CACHED; |
1031 | } | 1084 | } |
1032 | return (v->string == NULL) ? "" : v->string; | 1085 | return (v->string == NULL) ? "" : v->string; |
@@ -1347,7 +1400,6 @@ static void mk_re_node(const char *s, node *n, regex_t *re) | |||
1347 | { | 1400 | { |
1348 | n->info = TI_REGEXP; | 1401 | n->info = TI_REGEXP; |
1349 | n->l.re = re; | 1402 | n->l.re = re; |
1350 | n->r.ire = re + 1; | ||
1351 | xregcomp(re, s, REG_EXTENDED); | 1403 | xregcomp(re, s, REG_EXTENDED); |
1352 | xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); | 1404 | xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); |
1353 | } | 1405 | } |
@@ -1360,39 +1412,39 @@ static node *parse_lrparen_list(void) | |||
1360 | return parse_expr(TC_RPAREN); | 1412 | return parse_expr(TC_RPAREN); |
1361 | } | 1413 | } |
1362 | 1414 | ||
1363 | /* parse expression terminated by given argument, return ptr | 1415 | /* Parse expression terminated by given token, return ptr |
1364 | * to built subtree. Terminator is eaten by parse_expr */ | 1416 | * to built subtree. Terminator is eaten by parse_expr */ |
1365 | static node *parse_expr(uint32_t term_tc) | 1417 | static node *parse_expr(uint32_t term_tc) |
1366 | { | 1418 | { |
1367 | node sn; | 1419 | node sn; |
1368 | node *cn = &sn; | 1420 | node *cn = &sn; |
1369 | node *glptr; | 1421 | node *getline_node; |
1370 | uint32_t tc, expected_tc; | 1422 | uint32_t tc, expected_tc; |
1371 | 1423 | ||
1372 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); | 1424 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); |
1373 | debug_parse_print_tc(term_tc); | 1425 | debug_parse_print_tc(term_tc); |
1374 | debug_printf_parse("\n"); | 1426 | debug_printf_parse("\n"); |
1375 | 1427 | ||
1376 | sn.info = PRIMASK; | 1428 | sn.info = LOWEST_PRECEDENCE; |
1377 | sn.r.n = sn.a.n = glptr = NULL; | 1429 | sn.r.n = sn.a.n = getline_node = NULL; |
1378 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP | term_tc; | 1430 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP | term_tc; |
1379 | 1431 | ||
1380 | while (!((tc = next_token(expected_tc)) & term_tc)) { | 1432 | while (!((tc = next_token(expected_tc)) & term_tc)) { |
1381 | node *vn; | 1433 | node *vn; |
1382 | 1434 | ||
1383 | if (glptr && (t_info == TI_LESS)) { | 1435 | if (getline_node && (t_info == TI_LESS)) { |
1384 | /* input redirection (<) attached to glptr node */ | 1436 | /* Attach input redirection (<) to getline node */ |
1385 | debug_printf_parse("%s: input redir\n", __func__); | 1437 | debug_printf_parse("%s: input redir\n", __func__); |
1386 | cn = glptr->l.n = new_node(OC_CONCAT | SS | PRECEDENCE(37)); | 1438 | cn = getline_node->l.n = new_node(OC_CONCAT | SS | PRECEDENCE(37)); |
1387 | cn->a.n = glptr; | 1439 | cn->a.n = getline_node; |
1388 | expected_tc = TS_OPERAND | TS_UOPPRE; | 1440 | expected_tc = TS_OPERAND | TS_UOPPRE; |
1389 | glptr = NULL; | 1441 | getline_node = NULL; |
1390 | continue; | 1442 | continue; |
1391 | } | 1443 | } |
1392 | if (tc & (TS_BINOP | TC_UOPPOST)) { | 1444 | if (tc & (TS_BINOP | TC_UOPPOST)) { |
1393 | debug_printf_parse("%s: TS_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); | 1445 | debug_printf_parse("%s: TS_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); |
1394 | /* for binary and postfix-unary operators, jump back over | 1446 | /* for binary and postfix-unary operators, jump back over |
1395 | * previous operators with higher priority */ | 1447 | * previous operators with higher precedence */ |
1396 | vn = cn; | 1448 | vn = cn; |
1397 | while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) | 1449 | while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) |
1398 | || (t_info == vn->info && t_info == TI_COLON) | 1450 | || (t_info == vn->info && t_info == TI_COLON) |
@@ -1400,7 +1452,7 @@ static node *parse_expr(uint32_t term_tc) | |||
1400 | vn = vn->a.n; | 1452 | vn = vn->a.n; |
1401 | if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); | 1453 | if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); |
1402 | } | 1454 | } |
1403 | if (t_info == TI_TERNARY) | 1455 | if (t_info == TI_TERNARY) /* "?" token */ |
1404 | //TODO: why? | 1456 | //TODO: why? |
1405 | t_info += PRECEDENCE(6); | 1457 | t_info += PRECEDENCE(6); |
1406 | cn = vn->a.n->r.n = new_node(t_info); | 1458 | cn = vn->a.n->r.n = new_node(t_info); |
@@ -1432,20 +1484,21 @@ static node *parse_expr(uint32_t term_tc) | |||
1432 | } | 1484 | } |
1433 | 1485 | ||
1434 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; | 1486 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; |
1435 | if (t_info == TI_PGETLINE) { | 1487 | if (t_info == TI_PGETLINE) { /* "|" token */ |
1436 | /* it's a pipe */ | 1488 | next_token(TC_GETLINE); /* must be folowed by "getline" */ |
1437 | next_token(TC_GETLINE); | 1489 | /* give maximum precedence to this pipe */ |
1438 | /* give maximum priority to this pipe */ | 1490 | cn->info &= ~PRIMASK; /* sets PRECEDENCE(0) */ |
1439 | cn->info &= ~PRIMASK; | ||
1440 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; | 1491 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; |
1441 | } | 1492 | } |
1442 | } else { | 1493 | } else { |
1494 | /* It was an unary postfix operator */ | ||
1443 | cn->r.n = vn; | 1495 | cn->r.n = vn; |
1444 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; | 1496 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; |
1445 | } | 1497 | } |
1446 | vn->a.n = cn; | 1498 | vn->a.n = cn; |
1447 | continue; | 1499 | continue; |
1448 | } | 1500 | } |
1501 | /* It wasn't a binary or postfix-unary operator */ | ||
1449 | 1502 | ||
1450 | debug_printf_parse("%s: other, t_info:%x\n", __func__, t_info); | 1503 | debug_printf_parse("%s: other, t_info:%x\n", __func__, t_info); |
1451 | /* for operands and prefix-unary operators, attach them | 1504 | /* for operands and prefix-unary operators, attach them |
@@ -1519,8 +1572,15 @@ static node *parse_expr(uint32_t term_tc) | |||
1519 | break; | 1572 | break; |
1520 | 1573 | ||
1521 | case TC_GETLINE: | 1574 | case TC_GETLINE: |
1575 | /* "getline" is a function, not a statement. | ||
1576 | * Works in gawk: | ||
1577 | * r = ["SHELL CMD" | ] getline [VAR] [<"FILE"] | ||
1578 | * if (getline <"FILE" < 0) print "Can't read FILE" | ||
1579 | * while ("SHELL CMD" | getline > 0) ... | ||
1580 | * Returns: 1 successful read, 0 EOF, -1 error (sets ERRNO) | ||
1581 | */ | ||
1522 | debug_printf_parse("%s: TC_GETLINE\n", __func__); | 1582 | debug_printf_parse("%s: TC_GETLINE\n", __func__); |
1523 | glptr = cn; | 1583 | getline_node = cn; |
1524 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; | 1584 | expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; |
1525 | break; | 1585 | break; |
1526 | 1586 | ||
@@ -1892,15 +1952,14 @@ static void nvfree(var *v, int sz) | |||
1892 | 1952 | ||
1893 | static node *mk_splitter(const char *s, tsplitter *spl) | 1953 | static node *mk_splitter(const char *s, tsplitter *spl) |
1894 | { | 1954 | { |
1895 | regex_t *re, *ire; | 1955 | regex_t *re; |
1896 | node *n; | 1956 | node *n; |
1897 | 1957 | ||
1898 | re = &spl->re[0]; | 1958 | re = spl->re; |
1899 | ire = &spl->re[1]; | ||
1900 | n = &spl->n; | 1959 | n = &spl->n; |
1901 | if (n->info == TI_REGEXP) { | 1960 | if (n->info == TI_REGEXP) { |
1902 | regfree(re); | 1961 | regfree(re); |
1903 | regfree(ire); // TODO: nuke ire, use re+1? | 1962 | regfree(re + 1); |
1904 | } | 1963 | } |
1905 | if (s[0] && s[1]) { /* strlen(s) > 1 */ | 1964 | if (s[0] && s[1]) { /* strlen(s) > 1 */ |
1906 | mk_re_node(s, n, re); | 1965 | mk_re_node(s, n, re); |
@@ -1923,7 +1982,7 @@ static regex_t *as_regex(node *op, regex_t *preg) | |||
1923 | const char *s; | 1982 | const char *s; |
1924 | 1983 | ||
1925 | if (op->info == TI_REGEXP) { | 1984 | if (op->info == TI_REGEXP) { |
1926 | return icase ? op->r.ire : op->l.re; | 1985 | return &op->l.re[icase]; |
1927 | } | 1986 | } |
1928 | 1987 | ||
1929 | //tmpvar = nvalloc(1); | 1988 | //tmpvar = nvalloc(1); |
@@ -2041,7 +2100,7 @@ static int awk_split(const char *s, node *spl, char **slist) | |||
2041 | regmatch_t pmatch[1]; | 2100 | regmatch_t pmatch[1]; |
2042 | 2101 | ||
2043 | l = strcspn(s, c+2); /* len till next NUL or \n */ | 2102 | l = strcspn(s, c+2); /* len till next NUL or \n */ |
2044 | if (regexec1_nonempty(icase ? spl->r.ire : spl->l.re, s, pmatch) == 0 | 2103 | if (regexec1_nonempty(&spl->l.re[icase], s, pmatch) == 0 |
2045 | && pmatch[0].rm_so <= l | 2104 | && pmatch[0].rm_so <= l |
2046 | ) { | 2105 | ) { |
2047 | /* if (pmatch[0].rm_eo == 0) ... - impossible */ | 2106 | /* if (pmatch[0].rm_eo == 0) ... - impossible */ |
@@ -2296,7 +2355,7 @@ static int awk_getline(rstream *rsm, var *v) | |||
2296 | if (p > 0) { | 2355 | if (p > 0) { |
2297 | char c = (char) rsplitter.n.info; | 2356 | char c = (char) rsplitter.n.info; |
2298 | if (rsplitter.n.info == TI_REGEXP) { | 2357 | if (rsplitter.n.info == TI_REGEXP) { |
2299 | if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, | 2358 | if (regexec(&rsplitter.n.l.re[icase], |
2300 | b, 1, pmatch, 0) == 0 | 2359 | b, 1, pmatch, 0) == 0 |
2301 | ) { | 2360 | ) { |
2302 | so = pmatch[0].rm_so; | 2361 | so = pmatch[0].rm_so; |
@@ -2811,7 +2870,6 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2811 | tt = getvar_i(av[1]); | 2870 | tt = getvar_i(av[1]); |
2812 | else | 2871 | else |
2813 | time(&tt); | 2872 | time(&tt); |
2814 | //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"; | ||
2815 | i = strftime(g_buf, MAXVARFMT, | 2873 | i = strftime(g_buf, MAXVARFMT, |
2816 | ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), | 2874 | ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), |
2817 | localtime(&tt)); | 2875 | localtime(&tt)); |
@@ -3004,19 +3062,14 @@ static var *evaluate(node *op, var *res) | |||
3004 | /* yes, remember where Fields[] is */ | 3062 | /* yes, remember where Fields[] is */ |
3005 | old_Fields_ptr = Fields; | 3063 | old_Fields_ptr = Fields; |
3006 | } | 3064 | } |
3007 | if (opinfo & OF_STR1) { | ||
3008 | L.s = getvar_s(L.v); | ||
3009 | debug_printf_eval("L.s:'%s'\n", L.s); | ||
3010 | } | ||
3011 | if (opinfo & OF_NUM1) { | 3065 | if (opinfo & OF_NUM1) { |
3012 | L_d = getvar_i(L.v); | 3066 | L_d = getvar_i(L.v); |
3013 | debug_printf_eval("L_d:%f\n", L_d); | 3067 | debug_printf_eval("L_d:%f\n", L_d); |
3014 | } | 3068 | } |
3015 | } | 3069 | } |
3016 | /* NB: Must get string/numeric values of L (done above) | 3070 | /* NB: if both L and R are $NNNs, and right one is large, |
3017 | * _before_ evaluate()'ing R.v: if both L and R are $NNNs, | 3071 | * then at this pint L.v points to Fields[NNN1], second |
3018 | * and right one is large, then L.v points to Fields[NNN1], | 3072 | * evaluate() below reallocates and moves (!) Fields[], |
3019 | * second evaluate() reallocates and moves (!) Fields[], | ||
3020 | * R.v points to Fields[NNN2] but L.v now points to freed mem! | 3073 | * R.v points to Fields[NNN2] but L.v now points to freed mem! |
3021 | * (Seen trying to evaluate "$444 $44444") | 3074 | * (Seen trying to evaluate "$444 $44444") |
3022 | */ | 3075 | */ |
@@ -3036,6 +3089,16 @@ static var *evaluate(node *op, var *res) | |||
3036 | debug_printf_eval("R.s:'%s'\n", R.s); | 3089 | debug_printf_eval("R.s:'%s'\n", R.s); |
3037 | } | 3090 | } |
3038 | } | 3091 | } |
3092 | /* Get L.s _after_ R.v is evaluated: it may have realloc'd L.v | ||
3093 | * so we must get the string after "old_Fields_ptr" correction | ||
3094 | * above. Testcase: x = (v = "abc", gsub("b", "X", v)); | ||
3095 | */ | ||
3096 | if (opinfo & OF_RES1) { | ||
3097 | if (opinfo & OF_STR1) { | ||
3098 | L.s = getvar_s(L.v); | ||
3099 | debug_printf_eval("L.s:'%s'\n", L.s); | ||
3100 | } | ||
3101 | } | ||
3039 | 3102 | ||
3040 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); | 3103 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); |
3041 | switch (XC(opinfo & OPCLSMASK)) { | 3104 | switch (XC(opinfo & OPCLSMASK)) { |
@@ -3115,9 +3178,8 @@ static var *evaluate(node *op, var *res) | |||
3115 | for (;;) { | 3178 | for (;;) { |
3116 | var *v = evaluate(nextarg(&op1), TMPVAR0); | 3179 | var *v = evaluate(nextarg(&op1), TMPVAR0); |
3117 | if (v->type & VF_NUMBER) { | 3180 | if (v->type & VF_NUMBER) { |
3118 | fmt_num(getvar_s(intvar[OFMT]), | 3181 | fputs(fmt_num(getvar_s(intvar[OFMT]), getvar_i(v)), |
3119 | getvar_i(v)); | 3182 | F); |
3120 | fputs(g_buf, F); | ||
3121 | } else { | 3183 | } else { |
3122 | fputs(getvar_s(v), F); | 3184 | fputs(getvar_s(v), F); |
3123 | } | 3185 | } |
diff --git a/libpwdgrp/uidgid_get.c b/libpwdgrp/uidgid_get.c index 283ac78fc..d76eb8298 100644 --- a/libpwdgrp/uidgid_get.c +++ b/libpwdgrp/uidgid_get.c | |||
@@ -93,11 +93,7 @@ void FAST_FUNC parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_gr | |||
93 | u->uid = u->gid = (gid_t)-1L; | 93 | u->uid = u->gid = (gid_t)-1L; |
94 | 94 | ||
95 | /* Check if there is a group name */ | 95 | /* Check if there is a group name */ |
96 | group = strchr(user_group, '.'); /* deprecated? */ | 96 | group = strchr(user_group, ':'); |
97 | if (!group) | ||
98 | group = strchr(user_group, ':'); | ||
99 | else | ||
100 | *group = ':'; /* replace '.' with ':' */ | ||
101 | 97 | ||
102 | /* Parse "user[:[group]]" */ | 98 | /* Parse "user[:[group]]" */ |
103 | if (!group) { /* "user" */ | 99 | if (!group) { /* "user" */ |
diff --git a/networking/wget.c b/networking/wget.c index f9e463f6c..f3c0c89f3 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -1635,7 +1635,7 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") | |||
1635 | bit = 1; | 1635 | bit = 1; |
1636 | words = wget_user_headers; | 1636 | words = wget_user_headers; |
1637 | while (*words) { | 1637 | while (*words) { |
1638 | if (strstr(hdr, words) == hdr) { | 1638 | if (strcasestr(hdr, words) == hdr) { |
1639 | G.user_headers |= bit; | 1639 | G.user_headers |= bit; |
1640 | break; | 1640 | break; |
1641 | } | 1641 | } |
diff --git a/shell/ash.c b/shell/ash.c index 64a8dd318..719f722a2 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -1061,13 +1061,13 @@ out2str(const char *p) | |||
1061 | #define CTLVAR ((unsigned char)'\202') /* variable defn */ | 1061 | #define CTLVAR ((unsigned char)'\202') /* variable defn */ |
1062 | #define CTLENDVAR ((unsigned char)'\203') | 1062 | #define CTLENDVAR ((unsigned char)'\203') |
1063 | #define CTLBACKQ ((unsigned char)'\204') | 1063 | #define CTLBACKQ ((unsigned char)'\204') |
1064 | #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ | 1064 | #define CTLARI ((unsigned char)'\205') /* arithmetic expression */ |
1065 | #define CTLENDARI ((unsigned char)'\207') | 1065 | #define CTLENDARI ((unsigned char)'\206') |
1066 | #define CTLQUOTEMARK ((unsigned char)'\210') | 1066 | #define CTLQUOTEMARK ((unsigned char)'\207') |
1067 | #define CTL_LAST CTLQUOTEMARK | 1067 | #define CTL_LAST CTLQUOTEMARK |
1068 | #if BASH_PROCESS_SUBST | 1068 | #if BASH_PROCESS_SUBST |
1069 | # define CTLTOPROC ((unsigned char)'\211') | 1069 | # define CTLTOPROC ((unsigned char)'\210') |
1070 | # define CTLFROMPROC ((unsigned char)'\212') | 1070 | # define CTLFROMPROC ((unsigned char)'\211') |
1071 | # undef CTL_LAST | 1071 | # undef CTL_LAST |
1072 | # define CTL_LAST CTLFROMPROC | 1072 | # define CTL_LAST CTLFROMPROC |
1073 | #endif | 1073 | #endif |
@@ -3827,17 +3827,17 @@ static const uint8_t syntax_index_table[] ALIGN1 = { | |||
3827 | /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL, | 3827 | /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL, |
3828 | /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, | 3828 | /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, |
3829 | /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, | 3829 | /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, |
3830 | /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, | 3830 | /* 133 CTLARI */ CCTL_CCTL_CCTL_CCTL, |
3831 | /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, | 3831 | /* 134 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, |
3832 | /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, | 3832 | /* 135 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, |
3833 | /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, | ||
3834 | #if BASH_PROCESS_SUBST | 3833 | #if BASH_PROCESS_SUBST |
3835 | /* 137 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL, | 3834 | /* 136 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL, |
3836 | /* 138 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL, | 3835 | /* 137 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL, |
3837 | #else | 3836 | #else |
3837 | /* 136 */ CWORD_CWORD_CWORD_CWORD, | ||
3838 | /* 137 */ CWORD_CWORD_CWORD_CWORD, | 3838 | /* 137 */ CWORD_CWORD_CWORD_CWORD, |
3839 | /* 138 */ CWORD_CWORD_CWORD_CWORD, | ||
3840 | #endif | 3839 | #endif |
3840 | /* 138 */ CWORD_CWORD_CWORD_CWORD, | ||
3841 | /* 139 */ CWORD_CWORD_CWORD_CWORD, | 3841 | /* 139 */ CWORD_CWORD_CWORD_CWORD, |
3842 | /* 140 */ CWORD_CWORD_CWORD_CWORD, | 3842 | /* 140 */ CWORD_CWORD_CWORD_CWORD, |
3843 | /* 141 */ CWORD_CWORD_CWORD_CWORD, | 3843 | /* 141 */ CWORD_CWORD_CWORD_CWORD, |
@@ -12181,13 +12181,6 @@ preadbuffer(void) | |||
12181 | char *q; | 12181 | char *q; |
12182 | int more; | 12182 | int more; |
12183 | 12183 | ||
12184 | #if !ENABLE_PLATFORM_MINGW32 | ||
12185 | if (unlikely(g_parsefile->strpush)) { | ||
12186 | popstring(); | ||
12187 | return __pgetc(); | ||
12188 | } | ||
12189 | #endif | ||
12190 | |||
12191 | if (g_parsefile->buf == NULL) { | 12184 | if (g_parsefile->buf == NULL) { |
12192 | pgetc_debug("preadbuffer PEOF1"); | 12185 | pgetc_debug("preadbuffer PEOF1"); |
12193 | return PEOF; | 12186 | return PEOF; |
@@ -12303,12 +12296,10 @@ static int __pgetc(void) | |||
12303 | if (--g_parsefile->left_in_line >= 0) | 12296 | if (--g_parsefile->left_in_line >= 0) |
12304 | c = (unsigned char)*g_parsefile->next_to_pgetc++; | 12297 | c = (unsigned char)*g_parsefile->next_to_pgetc++; |
12305 | else { | 12298 | else { |
12306 | #if ENABLE_PLATFORM_MINGW32 | ||
12307 | if (unlikely(g_parsefile->strpush)) { | 12299 | if (unlikely(g_parsefile->strpush)) { |
12308 | popstring(); | 12300 | popstring(); |
12309 | return __pgetc(); | 12301 | return __pgetc(); |
12310 | } | 12302 | } |
12311 | #endif | ||
12312 | c = preadbuffer(); | 12303 | c = preadbuffer(); |
12313 | } | 12304 | } |
12314 | 12305 | ||
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index afbde01c0..af9ed5359 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | . ./testing.sh | 6 | . ./testing.sh |
7 | 7 | ||
8 | sq="'" | ||
8 | # testing "description" "command" "result" "infile" "stdin" | 9 | # testing "description" "command" "result" "infile" "stdin" |
9 | 10 | ||
10 | testing "awk -F case 0" "awk -F '[#]' '{ print NF }'" "" "" "" | 11 | testing "awk -F case 0" "awk -F '[#]' '{ print NF }'" "" "" "" |
@@ -479,12 +480,6 @@ testing 'awk backslash+newline eaten with no trace' \ | |||
479 | "Hello world\n" \ | 480 | "Hello world\n" \ |
480 | '' '' | 481 | '' '' |
481 | 482 | ||
482 | testing 'awk assign while test' \ | ||
483 | "awk '\$1==\$1=\"foo\" {print \$1}'" \ | ||
484 | "foo\n" \ | ||
485 | "" \ | ||
486 | "foo" | ||
487 | |||
488 | optional PLATFORM_MINGW32 | 483 | optional PLATFORM_MINGW32 |
489 | testing 'awk match line ending' \ | 484 | testing 'awk match line ending' \ |
490 | "awk '/world$/'" \ | 485 | "awk '/world$/'" \ |
@@ -557,16 +552,30 @@ testing 'awk assign while assign' \ | |||
557 | # If field separator FS=' ' (default), fields are split only on | 552 | # If field separator FS=' ' (default), fields are split only on |
558 | # space or tab or linefeed, NOT other whitespace. | 553 | # space or tab or linefeed, NOT other whitespace. |
559 | testing 'awk does not split on CR (char 13)' \ | 554 | testing 'awk does not split on CR (char 13)' \ |
560 | "awk '{ \$1=\$0; print }'" \ | 555 | 'awk '$sq'{ $1=$0; print }'$sq \ |
561 | 'word1 word2 word3\r word2 word3\r\n' \ | 556 | 'word1 word2 word3\r word2 word3\r\n' \ |
562 | '' 'word1 word2 word3\r' | 557 | '' 'word1 word2 word3\r' |
563 | 558 | ||
564 | testing "awk = has higher precedence than == (despite what gawk manpage claims)" \ | 559 | # No, it seems a bug in gawk parser. |
565 | "awk 'BEGIN { v=1; print 2==v; print 2==v=2; print v; print v=3==3; print v}'" \ | 560 | #testing "awk = has higher precedence than == (despite what gawk manpage claims)" \ |
566 | '0\n1\n2\n1\n3\n' \ | 561 | # "awk 'BEGIN { v=1; print 2==v; print 2==v=2; print v; print v=3==3; print v}'" \ |
562 | # '0\n1\n2\n1\n3\n' \ | ||
563 | # '' '' | ||
564 | # | ||
565 | #testing 'awk assign while test' \ | ||
566 | # 'awk '$sq'$1==$1="foo" {print $1}'$sq \ | ||
567 | # "foo\n" \ | ||
568 | # "" \ | ||
569 | # "foo" | ||
570 | |||
571 | testing "awk = and ?: precedence" \ | ||
572 | 'awk '$sq'BEGIN { a=0?"bug":"ok"; print a}'$sq \ | ||
573 | 'ok\n' \ | ||
567 | '' '' | 574 | '' '' |
568 | 575 | ||
569 | sq="'" | 576 | # TODO: gawk can do this: awk 'BEGIN { u=v=w=1; print u=0?v=4:w=5; print u,v,w}' |
577 | # and even this: u=0?v=4?5:6:w=7?8:9 | ||
578 | |||
570 | testing 'awk gensub backslashes \' \ | 579 | testing 'awk gensub backslashes \' \ |
571 | 'awk '$sq'BEGIN { s="\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | 580 | 'awk '$sq'BEGIN { s="\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ |
572 | 's=\\ | 581 | 's=\\ |