aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-07-10 11:54:23 +0100
committerRon Yorston <rmy@pobox.com>2024-07-10 11:54:23 +0100
commit2dc17b7c80c803119dd2214bce4406b252ae2e9f (patch)
tree3eb11a8170e4164e2781a9be9925fc4bfa6f5053
parent29a24869e403e7364301e6fd7c745d327ed2d8c6 (diff)
parent0af28b84e58307422f807ddbdafc67a68f71eb64 (diff)
downloadbusybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.tar.gz
busybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.tar.bz2
busybox-w32-2dc17b7c80c803119dd2214bce4406b252ae2e9f.zip
Merge branch 'busybox' into merge
-rw-r--r--editors/awk.c188
-rw-r--r--libpwdgrp/uidgid_get.c6
-rw-r--r--networking/wget.c2
-rw-r--r--shell/ash.c33
-rwxr-xr-xtestsuite/awk.tests31
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
435static const uint32_t tokeninfo[] ALIGN4 = { 436static 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 */
516enum { 560enum {
@@ -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
925static void fmt_num(const char *format, double n) 970static 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
944static xhash *iamarray(var *a) 990static 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 */
1365static node *parse_expr(uint32_t term_tc) 1417static 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
1893static node *mk_splitter(const char *s, tsplitter *spl) 1953static 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
8sq="'"
8# testing "description" "command" "result" "infile" "stdin" 9# testing "description" "command" "result" "infile" "stdin"
9 10
10testing "awk -F case 0" "awk -F '[#]' '{ print NF }'" "" "" "" 11testing "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
482testing 'awk assign while test' \
483 "awk '\$1==\$1=\"foo\" {print \$1}'" \
484 "foo\n" \
485 "" \
486 "foo"
487
488optional PLATFORM_MINGW32 483optional PLATFORM_MINGW32
489testing 'awk match line ending' \ 484testing '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.
559testing 'awk does not split on CR (char 13)' \ 554testing '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
564testing "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
571testing "awk = and ?: precedence" \
572 'awk '$sq'BEGIN { a=0?"bug":"ok"; print a}'$sq \
573 'ok\n' \
567 '' '' 574 '' ''
568 575
569sq="'" 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
570testing 'awk gensub backslashes \' \ 579testing '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=\\