aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-02-12 08:43:06 +0000
committerRon Yorston <rmy@pobox.com>2019-02-12 08:43:06 +0000
commit7a8bd5ae33d8c390763f0787afe6b8c495e2d978 (patch)
tree29b0abb320d73b37f4fa4d9b355b3b32db42e836
parent0eda390d68c456975289471e68b615ae096ab33b (diff)
parentf81e0120f4478c58e126bcadb19b9954ed184e8f (diff)
downloadbusybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.gz
busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.bz2
busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.zip
Merge branch 'busybox' into merge
-rw-r--r--debianutils/start_stop_daemon.c69
-rw-r--r--editors/awk.c41
-rw-r--r--editors/sed.c30
-rw-r--r--editors/vi.c78
-rw-r--r--examples/udhcp/udhcpd.conf78
-rwxr-xr-xexamples/var_service/dhcp_if/convert2ipconf24
-rwxr-xr-xexamples/var_service/ifplugd_if/run3
-rwxr-xr-xexamples/var_service/supplicant_if/run3
-rw-r--r--findutils/grep.c21
-rw-r--r--include/libbb.h10
-rw-r--r--libbb/capability.c2
-rw-r--r--libbb/lineedit.c9
-rw-r--r--libbb/vfork_daemon_rexec.c16
-rw-r--r--loginutils/adduser.c2
-rw-r--r--loginutils/login.c8
-rw-r--r--miscutils/bc.c271
-rw-r--r--miscutils/i2c_tools.c176
-rw-r--r--networking/libiproute/iplink.c18
-rw-r--r--networking/tls_fe.c18
-rw-r--r--networking/udhcp/common.h4
-rw-r--r--networking/wget.c43
-rw-r--r--procps/sysctl.c57
-rwxr-xr-xscripts/checkstack.pl108
-rw-r--r--selinux/chcon.c2
-rwxr-xr-xtestsuite/awk.tests20
-rw-r--r--testsuite/bc_references.bc106
-rw-r--r--testsuite/bc_references_results.txt212
-rwxr-xr-xtestsuite/grep.tests7
-rwxr-xr-xtestsuite/start-stop-daemon.tests12
29 files changed, 1117 insertions, 331 deletions
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index 43b6fca26..3a4c1044a 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -409,7 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
409{ 409{
410 unsigned opt; 410 unsigned opt;
411 char *signame; 411 char *signame;
412 char *startas; 412 char *startas = NULL;
413 char *chuid; 413 char *chuid;
414#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY 414#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
415// char *retry_arg = NULL; 415// char *retry_arg = NULL;
@@ -425,10 +425,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
425 /* -K or -S is required; they are mutually exclusive */ 425 /* -K or -S is required; they are mutually exclusive */
426 /* -p is required if -m is given */ 426 /* -p is required if -m is given */
427 /* -xpun (at least one) is required if -K is given */ 427 /* -xpun (at least one) is required if -K is given */
428 /* -xa (at least one) is required if -S is given */ 428// /* -xa (at least one) is required if -S is given */
429//WRONG: "start-stop-daemon -S -- sleep 5" is a valid invocation
429 /* -q turns off -v */ 430 /* -q turns off -v */
430 "\0" 431 "\0"
431 "K:S:K--S:S--K:m?p:K?xpun:S?xa" 432 "K:S:K--S:S--K:m?p:K?xpun"
432 IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), 433 IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"),
433 LONGOPTS 434 LONGOPTS
434 &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile 435 &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
@@ -442,21 +443,34 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
442 if (signal_nr < 0) bb_show_usage(); 443 if (signal_nr < 0) bb_show_usage();
443 } 444 }
444 445
445 if (!(opt & OPT_a)) 446 //argc -= optind;
446 startas = execname; 447 argv += optind;
447 if (!execname) /* in case -a is given and -x is not */ 448// ARGS contains zeroth arg if -x/-a is not given, else it starts with 1st arg.
449// These will try to execute "[/bin/]sleep 5":
450// "start-stop-daemon -S -- sleep 5"
451// "start-stop-daemon -S -x /bin/sleep -- 5"
452// "start-stop-daemon -S -a sleep -- 5"
453// NB: -n option does _not_ behave in this way: this will try to execute "5":
454// "start-stop-daemon -S -n sleep -- 5"
455 if (!execname) { /* -x is not given */
448 execname = startas; 456 execname = startas;
449 if (execname) { 457 if (!execname) { /* neither -x nor -a is given */
450 G.execname_sizeof = strlen(execname) + 1; 458 execname = argv[0];
451 G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); 459 if (!execname)
460 bb_show_usage();
461 argv++;
462 }
452 } 463 }
464 if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */
465 startas = execname;
466 *--argv = startas;
467 G.execname_sizeof = strlen(execname) + 1;
468 G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
453 469
454// IF_FEATURE_START_STOP_DAEMON_FANCY( 470// IF_FEATURE_START_STOP_DAEMON_FANCY(
455// if (retry_arg) 471// if (retry_arg)
456// retries = xatoi_positive(retry_arg); 472// retries = xatoi_positive(retry_arg);
457// ) 473// )
458 //argc -= optind;
459 argv += optind;
460 474
461 if (userspec) { 475 if (userspec) {
462 user_id = bb_strtou(userspec, NULL, 10); 476 user_id = bb_strtou(userspec, NULL, 10);
@@ -473,7 +487,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
473 487
474 if (G.found_procs) { 488 if (G.found_procs) {
475 if (!QUIET) 489 if (!QUIET)
476 printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); 490 printf("%s is already running\n", execname);
477 return !(opt & OPT_OKNODO); 491 return !(opt & OPT_OKNODO);
478 } 492 }
479 493
@@ -482,30 +496,37 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
482 xstat(execname, &G.execstat); 496 xstat(execname, &G.execstat);
483#endif 497#endif
484 498
485 *--argv = startas;
486 if (opt & OPT_BACKGROUND) { 499 if (opt & OPT_BACKGROUND) {
487#if BB_MMU
488 bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK);
489 /* DAEMON_DEVNULL_STDIO is superfluous -
490 * it's always done by bb_daemonize() */
491#else
492 /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do 500 /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do
493 * without: SSD is not itself a daemon, it _execs_ a daemon. 501 * without: SSD is not itself a daemon, it _execs_ a daemon.
494 * The usual NOMMU problem of "child can't run indefinitely, 502 * The usual NOMMU problem of "child can't run indefinitely,
495 * it must exec" does not bite us: we exec anyway. 503 * it must exec" does not bite us: we exec anyway.
504 *
505 * bb_daemonize(DAEMON_DEVNULL_STDIO | DAEMON_CLOSE_EXTRA_FDS | DAEMON_DOUBLE_FORK)
506 * can be used on MMU systems, but use of vfork()
507 * is preferable since we want to create pidfile
508 * _before_ parent returns, and vfork() on Linux
509 * ensures that (by blocking parent until exec in the child).
496 */ 510 */
497 pid_t pid = xvfork(); 511 pid_t pid = xvfork();
498 if (pid != 0) { 512 if (pid != 0) {
499 /* parent */ 513 /* Parent */
500 /* why _exit? the child may have changed the stack, 514 /* why _exit? the child may have changed the stack,
501 * so "return 0" may do bad things */ 515 * so "return 0" may do bad things
516 */
502 _exit(EXIT_SUCCESS); 517 _exit(EXIT_SUCCESS);
503 } 518 }
504 /* Child */ 519 /* Child */
505 setsid(); /* detach from controlling tty */ 520 setsid(); /* detach from controlling tty */
506 /* Redirect stdio to /dev/null, close extra FDs */ 521 /* Redirect stdio to /dev/null, close extra FDs */
507 bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); 522 bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
508#endif 523 /* On Linux, session leader can acquire ctty
524 * unknowingly, by opening a tty.
525 * Prevent this: stop being a session leader.
526 */
527 pid = xvfork();
528 if (pid != 0)
529 _exit(EXIT_SUCCESS); /* Parent */
509 } 530 }
510 if (opt & OPT_MAKEPID) { 531 if (opt & OPT_MAKEPID) {
511 /* User wants _us_ to make the pidfile */ 532 /* User wants _us_ to make the pidfile */
@@ -534,6 +555,10 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
534 } 555 }
535 } 556 }
536#endif 557#endif
537 execvp(startas, argv); 558 /* Try:
559 * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000
560 * should exec "/bin/usleep", but argv[0] should be "qwerty":
561 */
562 execvp(execname, argv);
538 bb_perror_msg_and_die("can't execute '%s'", startas); 563 bb_perror_msg_and_die("can't execute '%s'", startas);
539} 564}
diff --git a/editors/awk.c b/editors/awk.c
index 86cd9a289..dbb26068d 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -275,18 +275,21 @@ typedef struct tsplitter_s {
275 | TC_STRING | TC_NUMBER | TC_UOPPOST) 275 | TC_STRING | TC_NUMBER | TC_UOPPOST)
276#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) 276#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
277 277
278#define OF_RES1 0x010000 278#define OF_RES1 0x010000
279#define OF_RES2 0x020000 279#define OF_RES2 0x020000
280#define OF_STR1 0x040000 280#define OF_STR1 0x040000
281#define OF_STR2 0x080000 281#define OF_STR2 0x080000
282#define OF_NUM1 0x100000 282#define OF_NUM1 0x100000
283#define OF_CHECKED 0x200000 283#define OF_CHECKED 0x200000
284#define OF_REQUIRED 0x400000
285
284 286
285/* combined operator flags */ 287/* combined operator flags */
286#define xx 0 288#define xx 0
287#define xV OF_RES2 289#define xV OF_RES2
288#define xS (OF_RES2 | OF_STR2) 290#define xS (OF_RES2 | OF_STR2)
289#define Vx OF_RES1 291#define Vx OF_RES1
292#define Rx (OF_RES1 | OF_NUM1 | OF_REQUIRED)
290#define VV (OF_RES1 | OF_RES2) 293#define VV (OF_RES1 | OF_RES2)
291#define Nx (OF_RES1 | OF_NUM1) 294#define Nx (OF_RES1 | OF_NUM1)
292#define NV (OF_RES1 | OF_NUM1 | OF_RES2) 295#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
@@ -425,7 +428,7 @@ static const uint32_t tokeninfo[] = {
425 0, 428 0,
426 0, /* \n */ 429 0, /* \n */
427 ST_IF, ST_DO, ST_FOR, OC_BREAK, 430 ST_IF, ST_DO, ST_FOR, OC_BREAK,
428 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, 431 OC_CONTINUE, OC_DELETE|Rx, OC_PRINT,
429 OC_PRINTF, OC_NEXT, OC_NEXTFILE, 432 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
430 OC_RETURN|Vx, OC_EXIT|Nx, 433 OC_RETURN|Vx, OC_EXIT|Nx,
431 ST_WHILE, 434 ST_WHILE,
@@ -593,7 +596,7 @@ static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
593static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; 596static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
594static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; 597static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
595static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; 598static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
596static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; 599static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments";
597static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 600static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
598static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 601static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
599static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 602static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
@@ -1269,7 +1272,7 @@ static node *parse_expr(uint32_t iexp)
1269 debug_printf_parse("%s(%x)\n", __func__, iexp); 1272 debug_printf_parse("%s(%x)\n", __func__, iexp);
1270 1273
1271 sn.info = PRIMASK; 1274 sn.info = PRIMASK;
1272 sn.r.n = glptr = NULL; 1275 sn.r.n = sn.a.n = glptr = NULL;
1273 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1276 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1274 1277
1275 while (!((tc = next_token(xtc)) & iexp)) { 1278 while (!((tc = next_token(xtc)) & iexp)) {
@@ -1291,6 +1294,7 @@ static node *parse_expr(uint32_t iexp)
1291 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) 1294 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1292 ) { 1295 ) {
1293 vn = vn->a.n; 1296 vn = vn->a.n;
1297 if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN);
1294 } 1298 }
1295 if ((t_info & OPCLSMASK) == OC_TERNARY) 1299 if ((t_info & OPCLSMASK) == OC_TERNARY)
1296 t_info += P(6); 1300 t_info += P(6);
@@ -1429,7 +1433,11 @@ static void chain_expr(uint32_t info)
1429 node *n; 1433 node *n;
1430 1434
1431 n = chain_node(info); 1435 n = chain_node(info);
1436
1432 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1437 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1438 if ((info & OF_REQUIRED) && !n->l.n)
1439 syntax_error(EMSG_TOO_FEW_ARGS);
1440
1433 if (t_tclass & TC_GRPTERM) 1441 if (t_tclass & TC_GRPTERM)
1434 rollback_token(); 1442 rollback_token();
1435} 1443}
@@ -1609,12 +1617,25 @@ static void parse_program(char *p)
1609 f = newfunc(t_string); 1617 f = newfunc(t_string);
1610 f->body.first = NULL; 1618 f->body.first = NULL;
1611 f->nargs = 0; 1619 f->nargs = 0;
1612 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 1620 /* Match func arg list: a comma sep list of >= 0 args, and a close paren */
1621 while (next_token(TC_VARIABLE | TC_SEQTERM | TC_COMMA)) {
1622 /* Either an empty arg list, or trailing comma from prev iter
1623 * must be followed by an arg */
1624 if (f->nargs == 0 && t_tclass == TC_SEQTERM)
1625 break;
1626
1627 /* TC_SEQSTART/TC_COMMA must be followed by TC_VARIABLE */
1628 if (t_tclass != TC_VARIABLE)
1629 syntax_error(EMSG_UNEXP_TOKEN);
1630
1613 v = findvar(ahash, t_string); 1631 v = findvar(ahash, t_string);
1614 v->x.aidx = f->nargs++; 1632 v->x.aidx = f->nargs++;
1615 1633
1634 /* Arg followed either by end of arg list or 1 comma */
1616 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) 1635 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1617 break; 1636 break;
1637 if (t_tclass != TC_COMMA)
1638 syntax_error(EMSG_UNEXP_TOKEN);
1618 } 1639 }
1619 seq = &f->body; 1640 seq = &f->body;
1620 chain_group(); 1641 chain_group();
diff --git a/editors/sed.c b/editors/sed.c
index fd56e0e7f..a5cedbd8d 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -377,25 +377,25 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex)
377/* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ 377/* Grab a filename. Whitespace at start is skipped, then goes to EOL. */
378static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval) 378static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval)
379{ 379{
380 int start = 0, idx, hack = 0; 380 const char *start;
381 const char *eol;
381 382
382 /* Skip whitespace, then grab filename to end of line */ 383 /* Skip whitespace, then grab filename to end of line */
383 while (isspace(filecmdstr[start])) 384 start = skip_whitespace(filecmdstr);
384 start++; 385 eol = strchrnul(start, '\n');
385 idx = start; 386 if (eol == start)
386 while (filecmdstr[idx] && filecmdstr[idx] != '\n')
387 idx++;
388
389 /* If lines glued together, put backslash back. */
390 if (filecmdstr[idx] == '\n')
391 hack = 1;
392 if (idx == start)
393 bb_error_msg_and_die("empty filename"); 387 bb_error_msg_and_die("empty filename");
394 *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
395 if (hack)
396 (*retval)[idx] = '\\';
397 388
398 return idx; 389 if (*eol) {
390 /* If lines glued together, put backslash back. */
391 *retval = xstrndup(start, eol-start + 1);
392 (*retval)[eol-start] = '\\';
393 } else {
394 /* eol is NUL */
395 *retval = xstrdup(start);
396 }
397
398 return eol - filecmdstr;
399} 399}
400 400
401static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) 401static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
diff --git a/editors/vi.c b/editors/vi.c
index 3c758cca0..a46339813 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -600,6 +600,7 @@ static void check_context(char); // remember context for '' command
600#if ENABLE_FEATURE_VI_UNDO 600#if ENABLE_FEATURE_VI_UNDO
601static void flush_undo_data(void); 601static void flush_undo_data(void);
602static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack 602static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack
603static void undo_push_insert(char *, int, int); // convenience function
603static void undo_pop(void); // Undo the last operation 604static void undo_pop(void); // Undo the last operation
604# if ENABLE_FEATURE_VI_UNDO_QUEUE 605# if ENABLE_FEATURE_VI_UNDO_QUEUE
605static void undo_queue_commit(void); // Flush any queued objects to the undo stack 606static void undo_queue_commit(void); // Flush any queued objects to the undo stack
@@ -2013,19 +2014,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2013 c = get_one_char(); 2014 c = get_one_char();
2014 *p = c; 2015 *p = c;
2015#if ENABLE_FEATURE_VI_UNDO 2016#if ENABLE_FEATURE_VI_UNDO
2016 switch (undo) { 2017 undo_push_insert(p, 1, undo);
2017 case ALLOW_UNDO:
2018 undo_push(p, 1, UNDO_INS);
2019 break;
2020 case ALLOW_UNDO_CHAIN:
2021 undo_push(p, 1, UNDO_INS_CHAIN);
2022 break;
2023# if ENABLE_FEATURE_VI_UNDO_QUEUE
2024 case ALLOW_UNDO_QUEUED:
2025 undo_push(p, 1, UNDO_INS_QUEUED);
2026 break;
2027# endif
2028 }
2029#else 2018#else
2030 modified_count++; 2019 modified_count++;
2031#endif /* ENABLE_FEATURE_VI_UNDO */ 2020#endif /* ENABLE_FEATURE_VI_UNDO */
@@ -2053,19 +2042,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2053 if (c == '\n') 2042 if (c == '\n')
2054 undo_queue_commit(); 2043 undo_queue_commit();
2055# endif 2044# endif
2056 switch (undo) { 2045 undo_push_insert(p, 1, undo);
2057 case ALLOW_UNDO:
2058 undo_push(p, 1, UNDO_INS);
2059 break;
2060 case ALLOW_UNDO_CHAIN:
2061 undo_push(p, 1, UNDO_INS_CHAIN);
2062 break;
2063# if ENABLE_FEATURE_VI_UNDO_QUEUE
2064 case ALLOW_UNDO_QUEUED:
2065 undo_push(p, 1, UNDO_INS_QUEUED);
2066 break;
2067# endif
2068 }
2069#else 2046#else
2070 modified_count++; 2047 modified_count++;
2071#endif /* ENABLE_FEATURE_VI_UNDO */ 2048#endif /* ENABLE_FEATURE_VI_UNDO */
@@ -2085,7 +2062,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2085 p += bias; 2062 p += bias;
2086 q += bias; 2063 q += bias;
2087#if ENABLE_FEATURE_VI_UNDO 2064#if ENABLE_FEATURE_VI_UNDO
2088 undo_push(p, len, UNDO_INS); 2065 undo_push_insert(p, len, undo);
2089#endif 2066#endif
2090 memcpy(p, q, len); 2067 memcpy(p, q, len);
2091 p += len; 2068 p += len;
@@ -2339,16 +2316,18 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to
2339 } 2316 }
2340 break; 2317 break;
2341 case UNDO_INS_QUEUED: 2318 case UNDO_INS_QUEUED:
2342 if (length != 1) 2319 if (length < 1)
2343 return; 2320 return;
2344 switch (undo_queue_state) { 2321 switch (undo_queue_state) {
2345 case UNDO_EMPTY: 2322 case UNDO_EMPTY:
2346 undo_queue_state = UNDO_INS; 2323 undo_queue_state = UNDO_INS;
2347 undo_queue_spos = src; 2324 undo_queue_spos = src;
2348 case UNDO_INS: 2325 case UNDO_INS:
2349 undo_q++; // Don't need to save any data for insertions 2326 while (length--) {
2350 if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) 2327 undo_q++; // Don't need to save any data for insertions
2351 undo_queue_commit(); 2328 if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX)
2329 undo_queue_commit();
2330 }
2352 return; 2331 return;
2353 case UNDO_DEL: 2332 case UNDO_DEL:
2354 // Switch from storing deleted text to inserted text 2333 // Switch from storing deleted text to inserted text
@@ -2394,6 +2373,23 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to
2394 modified_count++; 2373 modified_count++;
2395} 2374}
2396 2375
2376static void undo_push_insert(char *p, int len, int undo)
2377{
2378 switch (undo) {
2379 case ALLOW_UNDO:
2380 undo_push(p, len, UNDO_INS);
2381 break;
2382 case ALLOW_UNDO_CHAIN:
2383 undo_push(p, len, UNDO_INS_CHAIN);
2384 break;
2385# if ENABLE_FEATURE_VI_UNDO_QUEUE
2386 case ALLOW_UNDO_QUEUED:
2387 undo_push(p, len, UNDO_INS_QUEUED);
2388 break;
2389# endif
2390 }
2391}
2392
2397static void undo_pop(void) // Undo the last operation 2393static void undo_pop(void) // Undo the last operation
2398{ 2394{
2399 int repeat; 2395 int repeat;
@@ -2667,14 +2663,7 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s
2667 2663
2668 i = strlen(s); 2664 i = strlen(s);
2669#if ENABLE_FEATURE_VI_UNDO 2665#if ENABLE_FEATURE_VI_UNDO
2670 switch (undo) { 2666 undo_push_insert(p, i, undo);
2671 case ALLOW_UNDO:
2672 undo_push(p, i, UNDO_INS);
2673 break;
2674 case ALLOW_UNDO_CHAIN:
2675 undo_push(p, i, UNDO_INS_CHAIN);
2676 break;
2677 }
2678#endif 2667#endif
2679 bias = text_hole_make(p, i); 2668 bias = text_hole_make(p, i);
2680 p += bias; 2669 p += bias;
@@ -4263,14 +4252,9 @@ static void do_cmd(int c)
4263 case 'r': // r- replace the current char with user input 4252 case 'r': // r- replace the current char with user input
4264 c1 = get_one_char(); // get the replacement char 4253 c1 = get_one_char(); // get the replacement char
4265 if (*dot != '\n') { 4254 if (*dot != '\n') {
4266#if ENABLE_FEATURE_VI_UNDO 4255 dot = text_hole_delete(dot, dot, ALLOW_UNDO);
4267 undo_push(dot, 1, UNDO_DEL); 4256 dot = char_insert(dot, c1, ALLOW_UNDO_CHAIN);
4268 *dot = c1; 4257 dot_left();
4269 undo_push(dot, 1, UNDO_INS_CHAIN);
4270#else
4271 *dot = c1;
4272 modified_count++;
4273#endif
4274 } 4258 }
4275 end_cmd_q(); // stop adding to q 4259 end_cmd_q(); // stop adding to q
4276 break; 4260 break;
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf
index 90714bcdf..bb8774e08 100644
--- a/examples/udhcp/udhcpd.conf
+++ b/examples/udhcp/udhcpd.conf
@@ -74,43 +74,49 @@ option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
74option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" 74option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4"
75option 14 "dumpfile" 75option 14 "dumpfile"
76 76
77# Currently supported options (for more info, see options.c): 77# Currently supported options [hex option value] (for more info, see options.c):
78#opt lease NUM 78#opt lease NUM # [0x33]
79#opt subnet IP 79#opt subnet IP # [0x01]
80#opt broadcast IP 80#opt broadcast IP # [0x1c]
81#opt router IP_LIST 81#opt router IP_LIST # [0x03]
82#opt ipttl NUM 82#opt ipttl NUM # [0x17]
83#opt mtu NUM 83#opt mtu NUM # [0x1a]
84#opt hostname STRING # client's hostname 84#opt hostname STRING # [0x0c] client's hostname
85#opt domain STRING # client's domain suffix 85#opt domain STRING # [0x0f] client's domain suffix
86#opt search STRING_LIST # search domains 86#opt search STRING_LIST # [0x77] search domains
87#opt nisdomain STRING 87#opt nisdomain STRING # [0x28]
88#opt timezone NUM # (localtime - UTC_time) in seconds. signed 88#opt timezone NUM # [0x02] (localtime - UTC_time) in seconds. signed
89#opt tftp STRING # tftp server name 89#opt tftp STRING # [0x42] tftp server name
90#opt bootfile STRING # tftp file to download (e.g. kernel image) 90#opt bootfile STRING # [0x43] tftp file to download (e.g. kernel image)
91#opt bootsize NUM # size of that file 91#opt bootsize NUM # [0x0d] size of that file
92#opt rootpath STRING # (NFS) path to mount as root fs 92#opt rootpath STRING # [0x11] (NFS) path to mount as root fs
93#opt wpad STRING 93#opt wpad STRING # [0xfc] Web Proxy Auto Discovery Protocol
94#opt serverid IP # default: server's IP 94#opt serverid IP # [0x36] default: server's IP
95#opt message STRING # error message (udhcpd sends it on success too) 95#opt message STRING # [0x38] error message (udhcpd sends it on success too)
96#opt vlanid NUM # 802.1P VLAN ID 96#opt vlanid NUM # [0x84] 802.1P VLAN ID
97#opt vlanpriority NUM # 802.1Q VLAN priority 97#opt vlanpriority NUM # [0x85] 802.1Q VLAN priority
98# RFC 5071: PXELINUX Options
99#opt 0xd0 F100747E # [0xd0] magic
100#opt pxeconffile STRING # [0xd1]
101#opt pxepathprefix STRING # [0xd2]
102#opt reboottime NUM # [0xd3] bootstrap timeout
98# Options specifying server(s) 103# Options specifying server(s)
99#opt dns IP_LIST 104#opt dns IP_LIST # [0x06]
100#opt wins IP_LIST 105#opt wins IP_LIST # [0x2c]
101#opt nissrv IP_LIST 106#opt nissrv IP_LIST # [0x29]
102#opt ntpsrv IP_LIST 107#opt ntpsrv IP_LIST # [0x2a]
103#opt lprsrv IP_LIST 108#opt lprsrv IP_LIST # [0x09]
104#opt swapsrv IP 109#opt swapsrv IP # [0x10]
105# Options specifying routes 110# Options specifying routes
106#opt routes IP_PAIR_LIST 111#opt routes IP_PAIR_LIST # [0x21]
107#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option 112#opt staticroutes STATIC_ROUTES # [0x79] RFC 3442 classless static route option
108#opt msstaticroutes STATIC_ROUTES # same, using MS option number 113#opt msstaticroutes STATIC_ROUTES # [0xf9] same, using MS option number
109# Obsolete options, no longer supported 114# Obsolete options, no longer supported
110#opt logsrv IP_LIST # 704/UDP log server (not syslog!) 115#opt logsrv IP_LIST # [0x07] 704/UDP log server (not syslog!)
111#opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) 116#opt namesrv IP_LIST # [0x05] IEN 116 name server, obsolete (August 1979!!!)
112#opt cookiesrv IP_LIST # RFC 865 "quote of the day" server, rarely (never?) used 117#opt cookiesrv IP_LIST # [0x08] RFC 865 "quote of the day" server, rarely (never?) used
113#opt timesrv IP_LIST # RFC 868 time server, rarely (never?) used 118#opt timesrv IP_LIST # [0x04] RFC 868 time server, rarely (never?) used
114# TODO: in development 119# TODO: in development
115#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc 120#opt userclass STRING # [0x4d] RFC 3004. set of LASCII strings. "I am a printer" etc
116#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs 121#opt sipsrv STRING LIST # [0x78] RFC 3361. flag byte, then: 0: domain names, 1: IP addrs
122#opt ip6rd .... # [0xd4] IPv6 rapid deployment
diff --git a/examples/var_service/dhcp_if/convert2ipconf b/examples/var_service/dhcp_if/convert2ipconf
index 62a288ebf..31e3c7fde 100755
--- a/examples/var_service/dhcp_if/convert2ipconf
+++ b/examples/var_service/dhcp_if/convert2ipconf
@@ -26,6 +26,30 @@ exec 2>&1
26test "$interface" || exit 1 26test "$interface" || exit 1
27test "$ip" || exit 1 27test "$ip" || exit 1
28 28
29# some servers do not return subnet option.
30# guess it for standard private networks.
31if ! test "$mask"; then
32 case "$ip" in
33 10.*)
34 mask=8;;
35 192.168.*)
36 mask=16;;
37 #172.16-31.x.x
38 172.1[6789].*)
39 mask=12;;
40 172.2[0123456789].*)
41 mask=12;;
42 172.3[01].*)
43 mask=12;;
44 esac
45fi
46
47# some servers do not return router option.
48# assume DHCP server is the router.
49if ! test "$router"; then
50 test "$serverid" && router="$serverid"
51fi
52
29{ 53{
30echo "let cfg=cfg+1" 54echo "let cfg=cfg+1"
31test "$interface" && echo "if[\$cfg]='$interface'" 55test "$interface" && echo "if[\$cfg]='$interface'"
diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run
index 5d1d4e355..5c662f298 100755
--- a/examples/var_service/ifplugd_if/run
+++ b/examples/var_service/ifplugd_if/run
@@ -16,7 +16,7 @@ exec \
16env - PATH="$PATH" \ 16env - PATH="$PATH" \
17softlimit \ 17softlimit \
18setuidgid root \ 18setuidgid root \
19ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" 19ifplugd -aqlMns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler"
20 20
21# We use -t3 to wake ifplugd up less often. 21# We use -t3 to wake ifplugd up less often.
22# If after three tests (3*3=9 > 8) link state seen to be different, 22# If after three tests (3*3=9 > 8) link state seen to be different,
@@ -29,6 +29,7 @@ ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler"
29# from pointlessly trying to get a lease. 29# from pointlessly trying to get a lease.
30# -q means that stopping monitoring does not stop dhcp/zcip/etc: 30# -q means that stopping monitoring does not stop dhcp/zcip/etc:
31# presumably, admin decided to control them manually. 31# presumably, admin decided to control them manually.
32# -M prevents frequent respawning if device does not exist (yet?)
32 33
33#-a Don't up interface automatically 34#-a Don't up interface automatically
34#-p Don't run "up" script on startup 35#-p Don't run "up" script on startup
diff --git a/examples/var_service/supplicant_if/run b/examples/var_service/supplicant_if/run
index 45211e001..279d18af5 100755
--- a/examples/var_service/supplicant_if/run
+++ b/examples/var_service/supplicant_if/run
@@ -8,7 +8,8 @@ pwd="$PWD"
8if="${PWD##*/dhcp_}" 8if="${PWD##*/dhcp_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev "$if" up 11# "or sleep" idiom prevents rapid respawning if iface does not exist
12ip link set dev "$if" up || { sleep 5; exit; }
12 13
13##echo "* Powersave disable on $if" 14##echo "* Powersave disable on $if"
14##iw dev "$if" set power_save off 15##iw dev "$if" set power_save off
diff --git a/findutils/grep.c b/findutils/grep.c
index a4033a40b..2cbe7ea91 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -404,7 +404,7 @@ static int grep_file(FILE *file)
404#endif 404#endif
405 ) { 405 ) {
406 if (option_mask32 & OPT_x) { 406 if (option_mask32 & OPT_x) {
407 found = (gl->matched_range.rm_so == 0 407 found |= (gl->matched_range.rm_so == 0
408 && match_at[gl->matched_range.rm_eo] == '\0'); 408 && match_at[gl->matched_range.rm_eo] == '\0');
409 } else 409 } else
410 if (!(option_mask32 & OPT_w)) { 410 if (!(option_mask32 & OPT_w)) {
@@ -443,15 +443,23 @@ static int grep_file(FILE *file)
443 } 443 }
444 } 444 }
445 } 445 }
446 /* If it's non-inverted search, we can stop 446 /* If it's a non-inverted search, we can stop
447 * at first match */ 447 * at first match and report it.
448 if (found && !invert_search) 448 * If it's an inverted search, we can move on
449 goto do_found; 449 * to the next line of input, ignoring the
450 * rest of the patterns.
451 */
452 if (found) {
453 //if (invert_search)
454 // goto do_not_found;
455 //goto do_found;
456 break; // this accomplishes both
457 }
450 pattern_ptr = pattern_ptr->link; 458 pattern_ptr = pattern_ptr->link;
451 } /* while (pattern_ptr) */ 459 } /* while (pattern_ptr) */
452 460
453 if (found ^ invert_search) { 461 if (found ^ invert_search) {
454 do_found: 462 //do_found:
455 /* keep track of matches */ 463 /* keep track of matches */
456 nmatches++; 464 nmatches++;
457 465
@@ -552,6 +560,7 @@ static int grep_file(FILE *file)
552 } 560 }
553#if ENABLE_FEATURE_GREP_CONTEXT 561#if ENABLE_FEATURE_GREP_CONTEXT
554 else { /* no match */ 562 else { /* no match */
563 //do_not_found:
555 /* if we need to print some context lines after the last match, do so */ 564 /* if we need to print some context lines after the last match, do so */
556 if (print_n_lines_after) { 565 if (print_n_lines_after) {
557 print_line(line, strlen(line), linenum, '-'); 566 print_line(line, strlen(line), linenum, '-');
diff --git a/include/libbb.h b/include/libbb.h
index 1b5994357..0c7e03ee8 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1244,11 +1244,11 @@ void set_task_comm(const char *comm) FAST_FUNC;
1244 * to /dev/null if they are not. 1244 * to /dev/null if they are not.
1245 */ 1245 */
1246enum { 1246enum {
1247 DAEMON_CHDIR_ROOT = 1, 1247 DAEMON_CHDIR_ROOT = 1 << 0,
1248 DAEMON_DEVNULL_STDIO = 2, 1248 DAEMON_DEVNULL_STDIO = 1 << 1,
1249 DAEMON_CLOSE_EXTRA_FDS = 4, 1249 DAEMON_CLOSE_EXTRA_FDS = 1 << 2,
1250 DAEMON_ONLY_SANITIZE = 8, /* internal use */ 1250 DAEMON_ONLY_SANITIZE = 1 << 3, /* internal use */
1251 DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ 1251 //DAEMON_DOUBLE_FORK = 1 << 4, /* double fork to avoid controlling tty */
1252}; 1252};
1253#if BB_MMU 1253#if BB_MMU
1254 enum { re_execed = 0 }; 1254 enum { re_execed = 0 };
diff --git a/libbb/capability.c b/libbb/capability.c
index 6587dcbf7..d0ae78b91 100644
--- a/libbb/capability.c
+++ b/libbb/capability.c
@@ -67,7 +67,7 @@ unsigned FAST_FUNC cap_name_to_number(const char *cap)
67 goto found; 67 goto found;
68 } 68 }
69 for (i = 0; i < ARRAY_SIZE(capabilities); i++) { 69 for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
70 if (strcasecmp(capabilities[i], cap) != 0) 70 if (strcasecmp(capabilities[i], cap) == 0)
71 goto found; 71 goto found;
72 } 72 }
73 bb_error_msg_and_die("unknown capability '%s'", cap); 73 bb_error_msg_and_die("unknown capability '%s'", cap);
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 0b4e326d8..0ec9baa5f 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2462,13 +2462,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2462 timeout = st->timeout; 2462 timeout = st->timeout;
2463 } 2463 }
2464#if MAX_HISTORY > 0 2464#if MAX_HISTORY > 0
2465 if (state->flags & DO_HISTORY) {
2465# if ENABLE_FEATURE_EDITING_SAVEHISTORY 2466# if ENABLE_FEATURE_EDITING_SAVEHISTORY
2466 if (state->hist_file) 2467 if (state->hist_file)
2467 if (state->cnt_history == 0) 2468 if (state->cnt_history == 0)
2468 load_history(state); 2469 load_history(state);
2469# endif 2470# endif
2470 if (state->flags & DO_HISTORY)
2471 state->cur_history = state->cnt_history; 2471 state->cur_history = state->cnt_history;
2472 }
2472#endif 2473#endif
2473 2474
2474 /* prepare before init handlers */ 2475 /* prepare before init handlers */
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 569a6fc34..2d497d754 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -297,14 +297,14 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
297 dup2(fd, 0); 297 dup2(fd, 0);
298 dup2(fd, 1); 298 dup2(fd, 1);
299 dup2(fd, 2); 299 dup2(fd, 2);
300 if (flags & DAEMON_DOUBLE_FORK) { 300// if (flags & DAEMON_DOUBLE_FORK) {
301 /* On Linux, session leader can acquire ctty 301// /* On Linux, session leader can acquire ctty
302 * unknowingly, by opening a tty. 302// * unknowingly, by opening a tty.
303 * Prevent this: stop being a session leader. 303// * Prevent this: stop being a session leader.
304 */ 304// */
305 if (fork_or_rexec(argv)) 305// if (fork_or_rexec(argv))
306 _exit(EXIT_SUCCESS); /* parent */ 306// _exit(EXIT_SUCCESS); /* parent */
307 } 307// }
308 } 308 }
309 while (fd > 2) { 309 while (fd > 2) {
310 close(fd--); 310 close(fd--);
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
index b2b5be5b3..850c810c4 100644
--- a/loginutils/adduser.c
+++ b/loginutils/adduser.c
@@ -198,7 +198,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
198 198
199 pw.pw_gecos = (char *)"Linux User,,,"; 199 pw.pw_gecos = (char *)"Linux User,,,";
200 /* We assume that newly created users "inherit" root's shell setting */ 200 /* We assume that newly created users "inherit" root's shell setting */
201 pw.pw_shell = (char *)get_shell_name(); 201 pw.pw_shell = xstrdup(get_shell_name()); /* might come from getpwnam(), need to make a copy */
202 pw.pw_dir = NULL; 202 pw.pw_dir = NULL;
203 203
204 opts = getopt32long(argv, "^" 204 opts = getopt32long(argv, "^"
diff --git a/loginutils/login.c b/loginutils/login.c
index 25bb5203b..4df651cc6 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -245,7 +245,9 @@ static void login_pam_end(pam_handle_t *pamh)
245 pam_strerror(pamh, pamret), pamret); 245 pam_strerror(pamh, pamret), pamret);
246 } 246 }
247} 247}
248#endif /* ENABLE_PAM */ 248#else
249# define login_pam_end(pamh) ((void)0)
250#endif
249 251
250static void get_username_or_die(char *buf, int size_buf) 252static void get_username_or_die(char *buf, int size_buf)
251{ 253{
@@ -471,6 +473,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
471 * to know _why_ login failed */ 473 * to know _why_ login failed */
472 syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg, 474 syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg,
473 pam_strerror(pamh, pamret), pamret); 475 pam_strerror(pamh, pamret), pamret);
476 login_pam_end(pamh);
474 safe_strncpy(username, "UNKNOWN", sizeof(username)); 477 safe_strncpy(username, "UNKNOWN", sizeof(username));
475#else /* not PAM */ 478#else /* not PAM */
476 pw = getpwnam(username); 479 pw = getpwnam(username);
@@ -528,8 +531,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
528 if (child_pid < 0) 531 if (child_pid < 0)
529 bb_perror_msg("vfork"); 532 bb_perror_msg("vfork");
530 else { 533 else {
531 if (safe_waitpid(child_pid, NULL, 0) == -1) 534 wait_for_exitstatus(child_pid);
532 bb_perror_msg("waitpid");
533 update_utmp_DEAD_PROCESS(child_pid); 535 update_utmp_DEAD_PROCESS(child_pid);
534 } 536 }
535 IF_PAM(login_pam_end(pamh);) 537 IF_PAM(login_pam_end(pamh);)
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 7fecb264d..36e978ed8 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -4,8 +4,8 @@
4 * Adapted from https://github.com/gavinhoward/bc 4 * Adapted from https://github.com/gavinhoward/bc
5 * Original code copyright (c) 2018 Gavin D. Howard and contributors. 5 * Original code copyright (c) 2018 Gavin D. Howard and contributors.
6 */ 6 */
7//TODO: GNU extensions: 7//TODO:
8// support "define f(*param[])" - "pass array by reference" syntax 8// maybe implement a^b for non-integer b?
9 9
10#define DEBUG_LEXER 0 10#define DEBUG_LEXER 0
11#define DEBUG_COMPILE 0 11#define DEBUG_COMPILE 0
@@ -380,6 +380,12 @@ typedef struct BcInstPtr {
380 size_t inst_idx; 380 size_t inst_idx;
381} BcInstPtr; 381} BcInstPtr;
382 382
383typedef enum BcType {
384 BC_TYPE_VAR,
385 BC_TYPE_ARRAY,
386 BC_TYPE_REF,
387} BcType;
388
383typedef enum BcLexType { 389typedef enum BcLexType {
384 XC_LEX_EOF, 390 XC_LEX_EOF,
385 XC_LEX_INVALID, 391 XC_LEX_INVALID,
@@ -1092,15 +1098,25 @@ static void bc_vec_pop_all(BcVec *v)
1092 bc_vec_npop(v, v->len); 1098 bc_vec_npop(v, v->len);
1093} 1099}
1094 1100
1095static size_t bc_vec_push(BcVec *v, const void *data) 1101static size_t bc_vec_npush(BcVec *v, size_t n, const void *data)
1096{ 1102{
1097 size_t len = v->len; 1103 size_t len = v->len;
1098 if (len >= v->cap) bc_vec_grow(v, 1); 1104 if (len + n > v->cap) bc_vec_grow(v, n);
1099 memmove(v->v + (v->size * len), data, v->size); 1105 memmove(v->v + (v->size * len), data, v->size * n);
1100 v->len++; 1106 v->len = len + n;
1101 return len; 1107 return len;
1102} 1108}
1103 1109
1110static size_t bc_vec_push(BcVec *v, const void *data)
1111{
1112 return bc_vec_npush(v, 1, data);
1113 //size_t len = v->len;
1114 //if (len >= v->cap) bc_vec_grow(v, 1);
1115 //memmove(v->v + (v->size * len), data, v->size);
1116 //v->len = len + 1;
1117 //return len;
1118}
1119
1104// G.prog.results often needs "pop old operand, push result" idiom. 1120// G.prog.results often needs "pop old operand, push result" idiom.
1105// Can do this without a few extra ops 1121// Can do this without a few extra ops
1106static size_t bc_result_pop_and_push(const void *data) 1122static size_t bc_result_pop_and_push(const void *data)
@@ -3528,14 +3544,14 @@ static void xc_parse_pushName(char *name)
3528// (The above describes 32-bit case). 3544// (The above describes 32-bit case).
3529#define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) 3545#define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t))
3530 3546
3531static void xc_parse_pushIndex(size_t idx) 3547static void bc_vec_pushIndex(BcVec *v, size_t idx)
3532{ 3548{
3533 size_t mask; 3549 size_t mask;
3534 unsigned amt; 3550 unsigned amt;
3535 3551
3536 dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); 3552 dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx);
3537 if (idx < SMALL_INDEX_LIMIT) { 3553 if (idx < SMALL_INDEX_LIMIT) {
3538 xc_parse_push(idx); 3554 bc_vec_pushByte(v, idx);
3539 return; 3555 return;
3540 } 3556 }
3541 3557
@@ -3548,14 +3564,19 @@ static void xc_parse_pushIndex(size_t idx)
3548 } 3564 }
3549 // amt is at least 1 here - "one byte of length data follows" 3565 // amt is at least 1 here - "one byte of length data follows"
3550 3566
3551 xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt); 3567 bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt);
3552 3568
3553 do { 3569 do {
3554 xc_parse_push((unsigned char)idx); 3570 bc_vec_pushByte(v, (unsigned char)idx);
3555 idx >>= 8; 3571 idx >>= 8;
3556 } while (idx != 0); 3572 } while (idx != 0);
3557} 3573}
3558 3574
3575static void xc_parse_pushIndex(size_t idx)
3576{
3577 bc_vec_pushIndex(&G.prs.func->code, idx);
3578}
3579
3559static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) 3580static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx)
3560{ 3581{
3561 xc_parse_push(inst); 3582 xc_parse_push(inst);
@@ -4340,7 +4361,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcLexType type)
4340} 4361}
4341#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) 4362#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS)
4342 4363
4343static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) 4364static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type)
4344{ 4365{
4345 BcId *autoid; 4366 BcId *autoid;
4346 BcId a; 4367 BcId a;
@@ -4349,13 +4370,13 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var)
4349 autoid = (void*)f->autos.v; 4370 autoid = (void*)f->autos.v;
4350 for (i = 0; i < f->autos.len; i++, autoid++) { 4371 for (i = 0; i < f->autos.len; i++, autoid++) {
4351 if (strcmp(name, autoid->name) == 0 4372 if (strcmp(name, autoid->name) == 0
4352 && var == autoid->idx 4373 && type == (BcType) autoid->idx
4353 ) { 4374 ) {
4354 RETURN_STATUS(bc_error("duplicate function parameter or auto name")); 4375 RETURN_STATUS(bc_error("duplicate function parameter or auto name"));
4355 } 4376 }
4356 } 4377 }
4357 4378
4358 a.idx = var; 4379 a.idx = type;
4359 a.name = name; 4380 a.name = name;
4360 4381
4361 bc_vec_push(&f->autos, &a); 4382 bc_vec_push(&f->autos, &a);
@@ -4368,7 +4389,7 @@ static BC_STATUS zbc_parse_funcdef(void)
4368{ 4389{
4369 BcParse *p = &G.prs; 4390 BcParse *p = &G.prs;
4370 BcStatus s; 4391 BcStatus s;
4371 bool var, comma, voidfunc; 4392 bool comma, voidfunc;
4372 char *name; 4393 char *name;
4373 4394
4374 dbg_lex_enter("%s:%d entered", __func__, __LINE__); 4395 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
@@ -4406,6 +4427,16 @@ static BC_STATUS zbc_parse_funcdef(void)
4406 4427
4407 comma = false; 4428 comma = false;
4408 while (p->lex != BC_LEX_RPAREN) { 4429 while (p->lex != BC_LEX_RPAREN) {
4430 BcType t = BC_TYPE_VAR;
4431
4432 if (p->lex == XC_LEX_OP_MULTIPLY) {
4433 t = BC_TYPE_REF;
4434 s = zxc_lex_next();
4435 if (s) RETURN_STATUS(s);
4436 s = zbc_POSIX_does_not_allow("references");
4437 if (s) RETURN_STATUS(s);
4438 }
4439
4409 if (p->lex != XC_LEX_NAME) 4440 if (p->lex != XC_LEX_NAME)
4410 RETURN_STATUS(bc_error_bad_function_definition()); 4441 RETURN_STATUS(bc_error_bad_function_definition());
4411 4442
@@ -4415,9 +4446,8 @@ static BC_STATUS zbc_parse_funcdef(void)
4415 s = zxc_lex_next(); 4446 s = zxc_lex_next();
4416 if (s) goto err; 4447 if (s) goto err;
4417 4448
4418 var = p->lex != BC_LEX_LBRACKET; 4449 if (p->lex == BC_LEX_LBRACKET) {
4419 4450 if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
4420 if (!var) {
4421 s = zxc_lex_next(); 4451 s = zxc_lex_next();
4422 if (s) goto err; 4452 if (s) goto err;
4423 4453
@@ -4429,6 +4459,10 @@ static BC_STATUS zbc_parse_funcdef(void)
4429 s = zxc_lex_next(); 4459 s = zxc_lex_next();
4430 if (s) goto err; 4460 if (s) goto err;
4431 } 4461 }
4462 else if (t == BC_TYPE_REF) {
4463 s = bc_error_at("vars can't be references");
4464 goto err;
4465 }
4432 4466
4433 comma = p->lex == BC_LEX_COMMA; 4467 comma = p->lex == BC_LEX_COMMA;
4434 if (comma) { 4468 if (comma) {
@@ -4436,7 +4470,7 @@ static BC_STATUS zbc_parse_funcdef(void)
4436 if (s) goto err; 4470 if (s) goto err;
4437 } 4471 }
4438 4472
4439 s = zbc_func_insert(p->func, name, var); 4473 s = zbc_func_insert(p->func, name, t);
4440 if (s) goto err; 4474 if (s) goto err;
4441 } 4475 }
4442 4476
@@ -4488,7 +4522,7 @@ static BC_STATUS zbc_parse_auto(void)
4488 if (s) RETURN_STATUS(s); 4522 if (s) RETURN_STATUS(s);
4489 4523
4490 for (;;) { 4524 for (;;) {
4491 bool var; 4525 BcType t;
4492 4526
4493 if (p->lex != XC_LEX_NAME) 4527 if (p->lex != XC_LEX_NAME)
4494 RETURN_STATUS(bc_error_at("bad 'auto' syntax")); 4528 RETURN_STATUS(bc_error_at("bad 'auto' syntax"));
@@ -4497,8 +4531,9 @@ static BC_STATUS zbc_parse_auto(void)
4497 s = zxc_lex_next(); 4531 s = zxc_lex_next();
4498 if (s) goto err; 4532 if (s) goto err;
4499 4533
4500 var = (p->lex != BC_LEX_LBRACKET); 4534 t = BC_TYPE_VAR;
4501 if (!var) { 4535 if (p->lex == BC_LEX_LBRACKET) {
4536 t = BC_TYPE_ARRAY;
4502 s = zxc_lex_next(); 4537 s = zxc_lex_next();
4503 if (s) goto err; 4538 if (s) goto err;
4504 4539
@@ -4510,7 +4545,7 @@ static BC_STATUS zbc_parse_auto(void)
4510 if (s) goto err; 4545 if (s) goto err;
4511 } 4546 }
4512 4547
4513 s = zbc_func_insert(p->func, name, var); 4548 s = zbc_func_insert(p->func, name, t);
4514 if (s) goto err; 4549 if (s) goto err;
4515 4550
4516 if (p->lex == XC_LEX_NLINE 4551 if (p->lex == XC_LEX_NLINE
@@ -5119,12 +5154,64 @@ static BC_STATUS zdc_parse_exprs_until_eof(void)
5119#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) 5154#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n)))
5120#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) 5155#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n)))
5121 5156
5122static BcVec* xc_program_search(char *id, bool var) 5157static size_t xc_program_index(char *code, size_t *bgn)
5158{
5159 unsigned char *bytes = (void*)(code + *bgn);
5160 unsigned amt;
5161 unsigned i;
5162 size_t res;
5163
5164 amt = *bytes++;
5165 if (amt < SMALL_INDEX_LIMIT) {
5166 *bgn += 1;
5167 return amt;
5168 }
5169 amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here
5170 *bgn += amt + 1;
5171
5172 res = 0;
5173 i = 0;
5174 do {
5175 res |= (size_t)(*bytes++) << i;
5176 i += 8;
5177 } while (--amt != 0);
5178
5179 return res;
5180}
5181
5182static char *xc_program_name(char *code, size_t *bgn)
5183{
5184 code += *bgn;
5185 *bgn += strlen(code) + 1;
5186
5187 return xstrdup(code);
5188}
5189
5190static BcVec* xc_program_dereference(BcVec *vec)
5191{
5192 BcVec *v;
5193 size_t vidx, nidx, i = 0;
5194
5195 //assert(vec->size == sizeof(uint8_t));
5196
5197 vidx = xc_program_index(vec->v, &i);
5198 nidx = xc_program_index(vec->v, &i);
5199
5200 v = bc_vec_item(&G.prog.arrs, vidx);
5201 v = bc_vec_item(v, nidx);
5202
5203 //assert(v->size != sizeof(uint8_t));
5204
5205 return v;
5206}
5207
5208static BcVec* xc_program_search(char *id, BcType type)
5123{ 5209{
5124 BcId e, *ptr; 5210 BcId e, *ptr;
5125 BcVec *v, *map; 5211 BcVec *v, *map;
5126 size_t i; 5212 size_t i;
5127 int new; 5213 int new;
5214 bool var = (type == BC_TYPE_VAR);
5128 5215
5129 v = var ? &G.prog.vars : &G.prog.arrs; 5216 v = var ? &G.prog.vars : &G.prog.arrs;
5130 map = var ? &G.prog.var_map : &G.prog.arr_map; 5217 map = var ? &G.prog.var_map : &G.prog.arr_map;
@@ -5178,17 +5265,20 @@ static BC_STATUS zxc_program_num(BcResult *r, BcNum **num)
5178 case XC_RESULT_VAR: 5265 case XC_RESULT_VAR:
5179 case XC_RESULT_ARRAY: 5266 case XC_RESULT_ARRAY:
5180 case XC_RESULT_ARRAY_ELEM: { 5267 case XC_RESULT_ARRAY_ELEM: {
5181 BcVec *v; 5268 BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
5182 void *p; 5269 BcVec *v = xc_program_search(r->d.id.name, type);
5183 v = xc_program_search(r->d.id.name, r->t == XC_RESULT_VAR); 5270 void *p = bc_vec_top(v);
5184// dc variables are all stacks, so here we have this: 5271
5185 p = bc_vec_top(v);
5186// TODO: eliminate these stacks for bc-only config?
5187 if (r->t == XC_RESULT_ARRAY_ELEM) { 5272 if (r->t == XC_RESULT_ARRAY_ELEM) {
5273 size_t idx = r->d.id.idx;
5274
5188 v = p; 5275 v = p;
5189 if (v->len <= r->d.id.idx) 5276 if (v->size == sizeof(uint8_t))
5190 bc_array_expand(v, r->d.id.idx + 1); 5277 v = xc_program_dereference(v);
5191 *num = bc_vec_item(v, r->d.id.idx); 5278 //assert(v->size == sizeof(BcNum));
5279 if (v->len <= idx)
5280 bc_array_expand(v, idx + 1);
5281 *num = bc_vec_item(v, idx);
5192 } else { 5282 } else {
5193 *num = p; 5283 *num = p;
5194 } 5284 }
@@ -5347,39 +5437,6 @@ static BC_STATUS zxc_program_read(void)
5347} 5437}
5348#define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) 5438#define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS)
5349 5439
5350static size_t xc_program_index(char *code, size_t *bgn)
5351{
5352 unsigned char *bytes = (void*)(code + *bgn);
5353 unsigned amt;
5354 unsigned i;
5355 size_t res;
5356
5357 amt = *bytes++;
5358 if (amt < SMALL_INDEX_LIMIT) {
5359 *bgn += 1;
5360 return amt;
5361 }
5362 amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here
5363 *bgn += amt + 1;
5364
5365 res = 0;
5366 i = 0;
5367 do {
5368 res |= (size_t)(*bytes++) << i;
5369 i += 8;
5370 } while (--amt != 0);
5371
5372 return res;
5373}
5374
5375static char *xc_program_name(char *code, size_t *bgn)
5376{
5377 code += *bgn;
5378 *bgn += strlen(code) + 1;
5379
5380 return xstrdup(code);
5381}
5382
5383static void xc_program_printString(const char *str) 5440static void xc_program_printString(const char *str)
5384{ 5441{
5385#if ENABLE_DC 5442#if ENABLE_DC
@@ -5755,43 +5812,81 @@ static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push)
5755#define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) 5812#define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS)
5756#endif // ENABLE_DC 5813#endif // ENABLE_DC
5757 5814
5758static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, bool var) 5815static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t)
5759{ 5816{
5760 BcStatus s; 5817 BcStatus s;
5761 BcResult *ptr, r; 5818 BcResult *ptr, r;
5762 BcVec *v; 5819 BcVec *vec;
5763 BcNum *n; 5820 BcNum *n;
5821 bool var = (t == BC_TYPE_VAR);
5764 5822
5765 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) 5823 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
5766 RETURN_STATUS(bc_error_stack_has_too_few_elements()); 5824 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5767 5825
5768 ptr = bc_vec_top(&G.prog.results); 5826 ptr = bc_vec_top(&G.prog.results);
5769 if ((ptr->t == XC_RESULT_ARRAY) != !var) 5827 if ((ptr->t == XC_RESULT_ARRAY) == var)
5770 RETURN_STATUS(bc_error_variable_is_wrong_type()); 5828 RETURN_STATUS(bc_error_variable_is_wrong_type());
5771 v = xc_program_search(name, var); 5829 vec = xc_program_search(name, t);
5772 5830
5773#if ENABLE_DC 5831#if ENABLE_DC
5774 if (ptr->t == XC_RESULT_STR && !var) 5832 if (ptr->t == XC_RESULT_STR) {
5775 RETURN_STATUS(bc_error_variable_is_wrong_type()); 5833 if (!var)
5776 if (ptr->t == XC_RESULT_STR) 5834 RETURN_STATUS(bc_error_variable_is_wrong_type());
5777 RETURN_STATUS(zdc_program_assignStr(ptr, v, true)); 5835 RETURN_STATUS(zdc_program_assignStr(ptr, vec, true));
5836 }
5778#endif 5837#endif
5779 5838
5780 s = zxc_program_num(ptr, &n); 5839 s = zxc_program_num(ptr, &n);
5781 if (s) RETURN_STATUS(s); 5840 if (s) RETURN_STATUS(s);
5782 5841
5783 // Do this once more to make sure that pointers were not invalidated. 5842 // Do this once more to make sure that pointers were not invalidated.
5784 v = xc_program_search(name, var); 5843 vec = xc_program_search(name, t);
5785 5844
5786 if (var) { 5845 if (var) {
5787 bc_num_init_DEF_SIZE(&r.d.n); 5846 bc_num_init_DEF_SIZE(&r.d.n);
5788 bc_num_copy(&r.d.n, n); 5847 bc_num_copy(&r.d.n, n);
5789 } else { 5848 } else {
5849 BcVec *v = (BcVec*) n;
5850 bool ref, ref_size;
5851
5852 ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY);
5853 ref_size = (v->size == sizeof(uint8_t));
5854
5855 if (ref || (ref_size && t == BC_TYPE_REF)) {
5856 bc_vec_init(&r.d.v, sizeof(uint8_t), NULL);
5857 if (ref) {
5858 size_t vidx, idx;
5859 BcId id;
5860
5861 id.name = ptr->d.id.name;
5862 v = xc_program_search(ptr->d.id.name, BC_TYPE_REF);
5863
5864 // Make sure the pointer was not invalidated.
5865 vec = xc_program_search(name, t);
5866
5867 vidx = bc_map_find_exact(&G.prog.arr_map, &id);
5868 //assert(vidx != BC_VEC_INVALID_IDX);
5869 vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx;
5870 idx = v->len - 1;
5871
5872 bc_vec_pushIndex(&r.d.v, vidx);
5873 bc_vec_pushIndex(&r.d.v, idx);
5874 }
5875 // If we get here, we are copying a ref to a ref.
5876 else bc_vec_npush(&r.d.v, v->len, v->v);
5877
5878 // We need to return early.
5879 goto ret;
5880 }
5881
5882 if (ref_size && t != BC_TYPE_REF)
5883 v = xc_program_dereference(v);
5884
5790 bc_array_init(&r.d.v, true); 5885 bc_array_init(&r.d.v, true);
5791 bc_array_copy(&r.d.v, (BcVec *) n); 5886 bc_array_copy(&r.d.v, v);
5792 } 5887 }
5793 5888 ret:
5794 bc_vec_push(v, &r.d); 5889 bc_vec_push(vec, &r.d);
5795 bc_vec_pop(&G.prog.results); 5890 bc_vec_pop(&G.prog.results);
5796 5891
5797 RETURN_STATUS(s); 5892 RETURN_STATUS(s);
@@ -5818,7 +5913,7 @@ static BC_STATUS zxc_program_assign(char inst)
5818 5913
5819 if (left->t != XC_RESULT_VAR) 5914 if (left->t != XC_RESULT_VAR)
5820 RETURN_STATUS(bc_error_variable_is_wrong_type()); 5915 RETURN_STATUS(bc_error_variable_is_wrong_type());
5821 v = xc_program_search(left->d.id.name, true); 5916 v = xc_program_search(left->d.id.name, BC_TYPE_VAR);
5822 5917
5823 RETURN_STATUS(zdc_program_assignStr(right, v, false)); 5918 RETURN_STATUS(zdc_program_assignStr(right, v, false));
5824 } 5919 }
@@ -5897,7 +5992,7 @@ static BC_STATUS xc_program_pushVar(char *code, size_t *bgn,
5897 5992
5898#if ENABLE_DC 5993#if ENABLE_DC
5899 if (pop || copy) { 5994 if (pop || copy) {
5900 BcVec *v = xc_program_search(name, true); 5995 BcVec *v = xc_program_search(name, BC_TYPE_VAR);
5901 BcNum *num = bc_vec_top(v); 5996 BcNum *num = bc_vec_top(v);
5902 5997
5903 free(name); 5998 free(name);
@@ -6014,16 +6109,19 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx)
6014 for (i = 0; i < nparams; ++i) { 6109 for (i = 0; i < nparams; ++i) {
6015 BcResult *arg; 6110 BcResult *arg;
6016 BcStatus s; 6111 BcStatus s;
6112 bool arr;
6017 6113
6018 a = bc_vec_item(&func->autos, nparams - 1 - i); 6114 a = bc_vec_item(&func->autos, nparams - 1 - i);
6019 arg = bc_vec_top(&G.prog.results); 6115 arg = bc_vec_top(&G.prog.results);
6020 6116
6021 if ((!a->idx) != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch 6117 arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF);
6118
6119 if (arr != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch
6022 // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) 6120 // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions)
6023 ) { 6121 ) {
6024 RETURN_STATUS(bc_error_variable_is_wrong_type()); 6122 RETURN_STATUS(bc_error_variable_is_wrong_type());
6025 } 6123 }
6026 s = zxc_program_popResultAndCopyToVar(a->name, a->idx); 6124 s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx);
6027 if (s) RETURN_STATUS(s); 6125 if (s) RETURN_STATUS(s);
6028 } 6126 }
6029 6127
@@ -6031,12 +6129,13 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx)
6031 for (; i < func->autos.len; i++, a++) { 6129 for (; i < func->autos.len; i++, a++) {
6032 BcVec *v; 6130 BcVec *v;
6033 6131
6034 v = xc_program_search(a->name, a->idx); 6132 v = xc_program_search(a->name, (BcType) a->idx);
6035 if (a->idx) { 6133 if (a->idx == BC_TYPE_VAR) {
6036 BcNum n2; 6134 BcNum n2;
6037 bc_num_init_DEF_SIZE(&n2); 6135 bc_num_init_DEF_SIZE(&n2);
6038 bc_vec_push(v, &n2); 6136 bc_vec_push(v, &n2);
6039 } else { 6137 } else {
6138 //assert(a->idx == BC_TYPE_ARRAY);
6040 BcVec v2; 6139 BcVec v2;
6041 bc_array_init(&v2, true); 6140 bc_array_init(&v2, true);
6042 bc_vec_push(v, &v2); 6141 bc_vec_push(v, &v2);
@@ -6087,7 +6186,7 @@ static BC_STATUS zbc_program_return(char inst)
6087 a = (void*)f->autos.v; 6186 a = (void*)f->autos.v;
6088 for (i = 0; i < f->autos.len; i++, a++) { 6187 for (i = 0; i < f->autos.len; i++, a++) {
6089 BcVec *v; 6188 BcVec *v;
6090 v = xc_program_search(a->name, a->idx); 6189 v = xc_program_search(a->name, (BcType) a->idx);
6091 bc_vec_pop(v); 6190 bc_vec_pop(v);
6092 } 6191 }
6093 6192
@@ -6399,7 +6498,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
6399 6498
6400 if (exec) { 6499 if (exec) {
6401 BcVec *v; 6500 BcVec *v;
6402 v = xc_program_search(name, true); 6501 v = xc_program_search(name, BC_TYPE_VAR);
6403 n = bc_vec_top(v); 6502 n = bc_vec_top(v);
6404 } 6503 }
6405 6504
@@ -6724,7 +6823,7 @@ static BC_STATUS zxc_program_exec(void)
6724 } 6823 }
6725 case DC_INST_PUSH_TO_VAR: { 6824 case DC_INST_PUSH_TO_VAR: {
6726 char *name = xc_program_name(code, &ip->inst_idx); 6825 char *name = xc_program_name(code, &ip->inst_idx);
6727 s = zxc_program_popResultAndCopyToVar(name, true); 6826 s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR);
6728 free(name); 6827 free(name);
6729 break; 6828 break;
6730 } 6829 }
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c
index 610fed5d6..7a2e8534a 100644
--- a/miscutils/i2c_tools.c
+++ b/miscutils/i2c_tools.c
@@ -36,17 +36,26 @@
36//config: help 36//config: help
37//config: Detect I2C chips. 37//config: Detect I2C chips.
38//config: 38//config:
39//config:config I2CTRANSFER
40//config: bool "i2ctransfer (4.0 kb)"
41//config: default y
42//config: select PLATFORM_LINUX
43//config: help
44//config: Send user-defined I2C messages in one transfer.
45//config:
39 46
40//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) 47//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
41//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) 48//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
42//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) 49//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
43//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) 50//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
51//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP))
44/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ 52/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
45 53
46//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o 54//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
47//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o 55//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
48//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o 56//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
49//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o 57//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
58//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o
50 59
51/* 60/*
52 * Unsupported stuff: 61 * Unsupported stuff:
@@ -80,12 +89,19 @@
80#define I2C_FUNCS 0x0705 89#define I2C_FUNCS 0x0705
81#define I2C_PEC 0x0708 90#define I2C_PEC 0x0708
82#define I2C_SMBUS 0x0720 91#define I2C_SMBUS 0x0720
92#define I2C_RDWR 0x0707
93#define I2C_RDWR_IOCTL_MAX_MSGS 42
94#define I2C_RDWR_IOCTL_MAX_MSGS_STR "42"
83struct i2c_smbus_ioctl_data { 95struct i2c_smbus_ioctl_data {
84 __u8 read_write; 96 __u8 read_write;
85 __u8 command; 97 __u8 command;
86 __u32 size; 98 __u32 size;
87 union i2c_smbus_data *data; 99 union i2c_smbus_data *data;
88}; 100};
101struct i2c_rdwr_ioctl_data {
102 struct i2c_msg *msgs; /* pointers to i2c_msgs */
103 __u32 nmsgs; /* number of i2c_msgs */
104};
89/* end linux/i2c-dev.h */ 105/* end linux/i2c-dev.h */
90 106
91/* 107/*
@@ -262,7 +278,7 @@ static int i2c_bus_lookup(const char *bus_str)
262 return xstrtou_range(bus_str, 10, 0, 0xfffff); 278 return xstrtou_range(bus_str, 10, 0, 0xfffff);
263} 279}
264 280
265#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP 281#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
266static int i2c_parse_bus_addr(const char *addr_str) 282static int i2c_parse_bus_addr(const char *addr_str)
267{ 283{
268 /* Slave address must be in range 0x03 - 0x77. */ 284 /* Slave address must be in range 0x03 - 0x77. */
@@ -1373,3 +1389,161 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1373 return 0; 1389 return 0;
1374} 1390}
1375#endif /* ENABLE_I2CDETECT */ 1391#endif /* ENABLE_I2CDETECT */
1392
1393#if ENABLE_I2CTRANSFER
1394static void check_i2c_func(int fd)
1395{
1396 unsigned long funcs;
1397
1398 get_funcs_matrix(fd, &funcs);
1399
1400 if (!(funcs & I2C_FUNC_I2C))
1401 bb_error_msg_and_die("adapter does not support I2C transfers");
1402}
1403
1404//usage:#define i2ctransfer_trivial_usage
1405//usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..."
1406//usage:#define i2ctransfer_full_usage "\n\n"
1407//usage: "Read/write I2C data in one transfer"
1408//usage: "\n"
1409//usage: "\n -f Force access to busy addresses"
1410//usage: "\n -a Force access to non-regular addresses"
1411//usage: "\n -y Disable interactive mode"
1412int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1413int i2ctransfer_main(int argc UNUSED_PARAM, char **argv)
1414{
1415 enum {
1416 opt_f = (1 << 0),
1417 opt_y = (1 << 1),
1418 opt_a = (1 << 2),
1419 };
1420 int bus_num, bus_addr;
1421 int fd;
1422 unsigned opts, first, last;
1423 int nmsgs, nmsgs_sent, i;
1424 struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS];
1425 struct i2c_rdwr_ioctl_data rdwr;
1426
1427 memset(msgs, 0, sizeof(msgs));
1428
1429 opts = getopt32(argv, "^"
1430 "fya"
1431 "\0" "-2" /* minimum 2 args */
1432 );
1433 first = 0x03;
1434 last = 0x77;
1435 if (opts & opt_a) {
1436 first = 0x00;
1437 last = 0x7f;
1438 }
1439
1440 argv += optind;
1441 bus_num = i2c_bus_lookup(argv[0]);
1442 fd = i2c_dev_open(bus_num);
1443 check_i2c_func(fd);
1444
1445 bus_addr = -1;
1446 nmsgs = 0;
1447 while (*++argv) {
1448 char *arg_ptr;
1449 unsigned len;
1450 uint16_t flags;
1451 char *end;
1452
1453 if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS)
1454 bb_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR);
1455
1456 flags = 0;
1457 arg_ptr = *argv;
1458 switch (*arg_ptr++) {
1459 case 'r': flags |= I2C_M_RD; break;
1460 case 'w': break;
1461 default:
1462 bb_show_usage();
1463 }
1464
1465 end = strchr(arg_ptr, '@');
1466 if (end) *end = '\0';
1467 len = xstrtou_range(arg_ptr, 0, 0, 0xffff);
1468 if (end) {
1469 bus_addr = xstrtou_range(end + 1, 0, first, last);
1470 i2c_set_slave_addr(fd, bus_addr, (opts & opt_f));
1471 } else {
1472 /* Reuse last address if possible */
1473 if (bus_addr < 0)
1474 bb_error_msg_and_die("no address given in '%s'", *argv);
1475 }
1476
1477 msgs[nmsgs].addr = bus_addr;
1478 msgs[nmsgs].flags = flags;
1479 msgs[nmsgs].len = len;
1480 if (len)
1481 msgs[nmsgs].buf = xzalloc(len);
1482
1483 if (!(flags & I2C_M_RD)) {
1484 /* Consume DATA arg(s) */
1485 unsigned buf_idx = 0;
1486
1487 while (buf_idx < len) {
1488 uint8_t data8;
1489 unsigned long data;
1490
1491 arg_ptr = *++argv;
1492 if (!arg_ptr)
1493 bb_show_usage();
1494 data = strtoul(arg_ptr, &end, 0);
1495 if (data > 0xff || arg_ptr == end)
1496 bb_error_msg_and_die("invalid data byte '%s'", *argv);
1497
1498 data8 = data;
1499 while (buf_idx < len) {
1500 msgs[nmsgs].buf[buf_idx++] = data8;
1501 if (!*end)
1502 break;
1503 switch (*end) {
1504 /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
1505 case 'p':
1506 data8 = (data8 ^ 27) + 13;
1507 data8 = (data8 << 1) | (data8 >> 7);
1508 break;
1509 case '+': data8++; break;
1510 case '-': data8--; break;
1511 case '=': break;
1512 default:
1513 bb_error_msg_and_die("invalid data byte suffix: '%s'",
1514 *argv);
1515 }
1516 }
1517 }
1518 }
1519 nmsgs++;
1520 }
1521
1522 if (!(opts & opt_y))
1523 confirm_action(bus_addr, 0, 0, 0);
1524
1525 rdwr.msgs = msgs;
1526 rdwr.nmsgs = nmsgs;
1527 nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR");
1528 if (nmsgs_sent < nmsgs)
1529 bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs);
1530
1531 for (i = 0; i < nmsgs_sent; i++) {
1532 if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) {
1533 int j;
1534 for (j = 0; j < msgs[i].len - 1; j++)
1535 printf("0x%02x ", msgs[i].buf[j]);
1536 /* Print final byte with newline */
1537 printf("0x%02x\n", msgs[i].buf[j]);
1538 }
1539 }
1540
1541# if ENABLE_FEATURE_CLEAN_UP
1542 close(fd);
1543 for (i = 0; i < nmsgs; i++)
1544 free(msgs[i].buf);
1545# endif
1546
1547 return 0;
1548}
1549#endif /* ENABLE_I2CTRANSFER */
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index 9c164a71d..1a1064bdc 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -490,11 +490,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
490 ; 490 ;
491 enum { 491 enum {
492 ARG_id = 0, 492 ARG_id = 0,
493 ARG_protocol,
493 ARG_reorder_hdr, 494 ARG_reorder_hdr,
494 ARG_gvrp, 495 ARG_gvrp,
495 ARG_mvrp, 496 ARG_mvrp,
496 ARG_loose_binding, 497 ARG_loose_binding,
497 ARG_protocol,
498 }; 498 };
499 enum { 499 enum {
500 PROTO_8021Q = 0, 500 PROTO_8021Q = 0,
@@ -518,11 +518,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
518 id = get_u16(*argv, "id"); 518 id = get_u16(*argv, "id");
519 addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); 519 addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id));
520 } else if (arg == ARG_protocol) { 520 } else if (arg == ARG_protocol) {
521 arg = index_in_substrings(protocols, *argv); 521 arg = index_in_substrings(protocols, str_tolower(*argv));
522 if (arg == PROTO_8021Q) 522 if (arg == PROTO_8021Q)
523 proto = ETH_P_8021Q; 523 proto = htons(ETH_P_8021Q);
524 else if (arg == PROTO_8021AD) 524 else if (arg == PROTO_8021AD)
525 proto = ETH_P_8021AD; 525 proto = htons(ETH_P_8021AD);
526 else 526 else
527 bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", 527 bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'",
528 *argv); 528 *argv);
@@ -673,13 +673,19 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
673 673
674 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 674 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
675 } 675 }
676 /* Allow "ip link add dev" and "ip link add name" */
677 if (!name_str)
678 name_str = dev_str;
679 else if (!dev_str)
680 dev_str = name_str;
681 /* else if (!strcmp(name_str, dev_str))
682 name_str = dev_str; */
683
676 if (rtm != RTM_NEWLINK) { 684 if (rtm != RTM_NEWLINK) {
677 if (!dev_str) 685 if (!dev_str)
678 return 1; /* Need a device to delete */ 686 return 1; /* Need a device to delete */
679 req.i.ifi_index = xll_name_to_index(dev_str); 687 req.i.ifi_index = xll_name_to_index(dev_str);
680 } else { 688 } else {
681 if (!name_str)
682 name_str = dev_str;
683 if (link_str) { 689 if (link_str) {
684 int idx = xll_name_to_index(link_str); 690 int idx = xll_name_to_index(link_str);
685 addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); 691 addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
diff --git a/networking/tls_fe.c b/networking/tls_fe.c
index f235082f5..10971bbff 100644
--- a/networking/tls_fe.c
+++ b/networking/tls_fe.c
@@ -43,17 +43,13 @@ typedef uint32_t word32;
43#if 0 //UNUSED 43#if 0 //UNUSED
44static void fprime_copy(byte *x, const byte *a) 44static void fprime_copy(byte *x, const byte *a)
45{ 45{
46 int i; 46 memcpy(x, a, F25519_SIZE);
47 for (i = 0; i < F25519_SIZE; i++)
48 x[i] = a[i];
49} 47}
50#endif 48#endif
51 49
52static void lm_copy(byte* x, const byte* a) 50static void lm_copy(byte* x, const byte* a)
53{ 51{
54 int i; 52 memcpy(x, a, F25519_SIZE);
55 for (i = 0; i < F25519_SIZE; i++)
56 x[i] = a[i];
57} 53}
58 54
59#if 0 //UNUSED 55#if 0 //UNUSED
@@ -200,7 +196,7 @@ static void fe_load(byte *x, word32 c)
200static void fe_normalize(byte *x) 196static void fe_normalize(byte *x)
201{ 197{
202 byte minusp[F25519_SIZE]; 198 byte minusp[F25519_SIZE];
203 word16 c; 199 unsigned c;
204 int i; 200 int i;
205 201
206 /* Reduce using 2^255 = 19 mod p */ 202 /* Reduce using 2^255 = 19 mod p */
@@ -219,13 +215,13 @@ static void fe_normalize(byte *x)
219 */ 215 */
220 c = 19; 216 c = 19;
221 217
222 for (i = 0; i + 1 < F25519_SIZE; i++) { 218 for (i = 0; i < F25519_SIZE - 1; i++) {
223 c += x[i]; 219 c += x[i];
224 minusp[i] = (byte)c; 220 minusp[i] = (byte)c;
225 c >>= 8; 221 c >>= 8;
226 } 222 }
227 223
228 c += ((word16)x[i]) - 128; 224 c += ((unsigned)x[i]) - 128;
229 minusp[31] = (byte)c; 225 minusp[31] = (byte)c;
230 226
231 /* Load x-p if no underflow */ 227 /* Load x-p if no underflow */
@@ -234,13 +230,13 @@ static void fe_normalize(byte *x)
234 230
235static void lm_add(byte* r, const byte* a, const byte* b) 231static void lm_add(byte* r, const byte* a, const byte* b)
236{ 232{
237 word16 c = 0; 233 unsigned c = 0;
238 int i; 234 int i;
239 235
240 /* Add */ 236 /* Add */
241 for (i = 0; i < F25519_SIZE; i++) { 237 for (i = 0; i < F25519_SIZE; i++) {
242 c >>= 8; 238 c >>= 8;
243 c += ((word16)a[i]) + ((word16)b[i]); 239 c += ((unsigned)a[i]) + ((unsigned)b[i]);
244 r[i] = (byte)c; 240 r[i] = (byte)c;
245 } 241 }
246 242
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 62f9a2a4a..b68f9394e 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -154,8 +154,8 @@ enum {
154//#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */ 154//#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */
155//#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */ 155//#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */
156//#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */ 156//#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */
157//#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration File */ 157//#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration file */
158//#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Configuration File */ 158//#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Path prefix */
159//#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */ 159//#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */
160//#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */ 160//#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */
161//#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */ 161//#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */
diff --git a/networking/wget.c b/networking/wget.c
index 3cae1192c..bb70039f9 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -248,7 +248,7 @@ struct globals {
248 * With 512 byte buffer, it was measured to be 248 * With 512 byte buffer, it was measured to be
249 * an order of magnitude slower than with big one. 249 * an order of magnitude slower than with big one.
250 */ 250 */
251 char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(sizeof(long)); 251 char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(16);
252} FIX_ALIASING; 252} FIX_ALIASING;
253#define G (*ptr_to_globals) 253#define G (*ptr_to_globals)
254#define INIT_G() do { \ 254#define INIT_G() do { \
@@ -388,9 +388,6 @@ static void set_alarm(void)
388 * is_ip_address() attempts to verify whether or not a string 388 * is_ip_address() attempts to verify whether or not a string
389 * contains an IPv4 or IPv6 address (vs. an FQDN). The result 389 * contains an IPv4 or IPv6 address (vs. an FQDN). The result
390 * of inet_pton() can be used to determine this. 390 * of inet_pton() can be used to determine this.
391 *
392 * TODO add proper error checking when inet_pton() returns -1
393 * (some form of system error has occurred, and errno is set)
394 */ 391 */
395static int is_ip_address(const char *string) 392static int is_ip_address(const char *string)
396{ 393{
@@ -908,10 +905,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
908 polldata.fd = fileno(dfp); 905 polldata.fd = fileno(dfp);
909 polldata.events = POLLIN | POLLPRI; 906 polldata.events = POLLIN | POLLPRI;
910#endif 907#endif
911 if (G.output_fd == 1) 908 if (!(option_mask32 & WGET_OPT_QUIET)) {
912 fprintf(stderr, "writing to stdout\n"); 909 if (G.output_fd == 1)
913 else 910 fprintf(stderr, "writing to stdout\n");
914 fprintf(stderr, "saving to '%s'\n", G.fname_out); 911 else
912 fprintf(stderr, "saving to '%s'\n", G.fname_out);
913 }
915 progress_meter(PROGRESS_START); 914 progress_meter(PROGRESS_START);
916 915
917 if (G.chunked) 916 if (G.chunked)
@@ -1042,6 +1041,15 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
1042 */ 1041 */
1043 } 1042 }
1044 1043
1044 /* Draw full bar and free its resources */
1045 G.chunked = 0; /* makes it show 100% even for chunked download */
1046 G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */
1047 progress_meter(PROGRESS_END);
1048 if (G.content_len != 0) {
1049 bb_perror_msg_and_die("connection closed prematurely");
1050 /* GNU wget says "DATE TIME (NN MB/s) - Connection closed at byte NNN. Retrying." */
1051 }
1052
1045 /* If -c failed, we restart from the beginning, 1053 /* If -c failed, we restart from the beginning,
1046 * but we do not truncate file then, we do it only now, at the end. 1054 * but we do not truncate file then, we do it only now, at the end.
1047 * This lets user to ^C if his 99% complete 10 GB file download 1055 * This lets user to ^C if his 99% complete 10 GB file download
@@ -1053,14 +1061,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
1053 ftruncate(G.output_fd, pos); 1061 ftruncate(G.output_fd, pos);
1054 } 1062 }
1055 1063
1056 /* Draw full bar and free its resources */ 1064 if (!(option_mask32 & WGET_OPT_QUIET)) {
1057 G.chunked = 0; /* makes it show 100% even for chunked download */ 1065 if (G.output_fd == 1)
1058 G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ 1066 fprintf(stderr, "written to stdout\n");
1059 progress_meter(PROGRESS_END); 1067 else
1060 if (G.output_fd == 1) 1068 fprintf(stderr, "'%s' saved\n", G.fname_out);
1061 fprintf(stderr, "written to stdout\n"); 1069 }
1062 else
1063 fprintf(stderr, "'%s' saved\n", G.fname_out);
1064} 1070}
1065 1071
1066static void download_one_url(const char *url) 1072static void download_one_url(const char *url)
@@ -1421,7 +1427,8 @@ However, in real world it was observed that some web servers
1421 G.output_fd = -1; 1427 G.output_fd = -1;
1422 } 1428 }
1423 } else { 1429 } else {
1424 fprintf(stderr, "remote file exists\n"); 1430 if (!(option_mask32 & WGET_OPT_QUIET))
1431 fprintf(stderr, "remote file exists\n");
1425 } 1432 }
1426 1433
1427 if (dfp != sfp) { 1434 if (dfp != sfp) {
@@ -1492,8 +1499,6 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0")
1492 G.proxy_flag = "on"; /* use proxies if env vars are set */ 1499 G.proxy_flag = "on"; /* use proxies if env vars are set */
1493 G.user_agent = "Wget"; /* "User-Agent" header field */ 1500 G.user_agent = "Wget"; /* "User-Agent" header field */
1494 1501
1495#if ENABLE_FEATURE_WGET_LONG_OPTIONS
1496#endif
1497 GETOPT32(argv, "^" 1502 GETOPT32(argv, "^"
1498 "cqSO:o:P:Y:U:T:+" 1503 "cqSO:o:P:Y:U:T:+"
1499 /*ignored:*/ "t:" 1504 /*ignored:*/ "t:"
diff --git a/procps/sysctl.c b/procps/sysctl.c
index 5fa7646d1..6d77185ca 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -56,7 +56,31 @@ enum {
56 56
57static void sysctl_dots_to_slashes(char *name) 57static void sysctl_dots_to_slashes(char *name)
58{ 58{
59 char *cptr, *last_good, *end; 59 char *cptr, *last_good, *end, *slash;
60 char end_ch;
61
62 end = strchrnul(name, '=');
63
64 slash = strchrnul(name, '/');
65 if (slash < end
66 && strchrnul(name, '.') < slash
67 ) {
68 /* There are both dots and slashes, and 1st dot is
69 * before 1st slash.
70 * (IOW: not raw, unmangled a/b/c.d format)
71 *
72 * procps supports this syntax for names with dots:
73 * net.ipv4.conf.eth0/100.mc_forwarding
74 * (dots and slashes are simply swapped)
75 */
76 while (end != name) {
77 end--;
78 if (*end == '.') *end = '/';
79 else if (*end == '/') *end = '.';
80 }
81 return;
82 }
83 /* else: use our old behavior: */
60 84
61 /* Convert minimum number of '.' to '/' so that 85 /* Convert minimum number of '.' to '/' so that
62 * we end up with existing file's name. 86 * we end up with existing file's name.
@@ -76,10 +100,10 @@ static void sysctl_dots_to_slashes(char *name)
76 * 100 *
77 * To set up testing: modprobe 8021q; vconfig add eth0 100 101 * To set up testing: modprobe 8021q; vconfig add eth0 100
78 */ 102 */
79 end = name + strlen(name); 103 end_ch = *end;
80 last_good = name - 1;
81 *end = '.'; /* trick the loop into trying full name too */ 104 *end = '.'; /* trick the loop into trying full name too */
82 105
106 last_good = name - 1;
83 again: 107 again:
84 cptr = end; 108 cptr = end;
85 while (cptr > last_good) { 109 while (cptr > last_good) {
@@ -96,7 +120,7 @@ static void sysctl_dots_to_slashes(char *name)
96 } 120 }
97 cptr--; 121 cptr--;
98 } 122 }
99 *end = '\0'; 123 *end = end_ch;
100} 124}
101 125
102static int sysctl_act_on_setting(char *setting) 126static int sysctl_act_on_setting(char *setting)
@@ -112,6 +136,8 @@ static int sysctl_act_on_setting(char *setting)
112 while (*cptr) { 136 while (*cptr) {
113 if (*cptr == '/') 137 if (*cptr == '/')
114 *cptr = '.'; 138 *cptr = '.';
139 else if (*cptr == '.')
140 *cptr = '/';
115 cptr++; 141 cptr++;
116 } 142 }
117 143
@@ -119,14 +145,16 @@ static int sysctl_act_on_setting(char *setting)
119 if (cptr) 145 if (cptr)
120 writing = 1; 146 writing = 1;
121 if (writing) { 147 if (writing) {
122 if (cptr == NULL) { 148 if (!cptr) {
123 bb_error_msg("error: '%s' must be of the form name=value", 149 bb_error_msg("error: '%s' must be of the form name=value",
124 outname); 150 outname);
125 retval = EXIT_FAILURE; 151 retval = EXIT_FAILURE;
126 goto end; 152 goto end;
127 } 153 }
128 value = cptr + 1; /* point to the value in name=value */ 154 value = cptr + 1; /* point to the value in name=value */
129 if (setting == cptr || !*value) { 155 if (setting == cptr /* "name" can't be empty */
156 /* || !*value - WRONG: "sysctl net.ipv4.ip_local_reserved_ports=" is a valid syntax (clears the value) */
157 ) {
130 bb_error_msg("error: malformed setting '%s'", outname); 158 bb_error_msg("error: malformed setting '%s'", outname);
131 retval = EXIT_FAILURE; 159 retval = EXIT_FAILURE;
132 goto end; 160 goto end;
@@ -175,6 +203,7 @@ static int sysctl_act_on_setting(char *setting)
175 close(fd); 203 close(fd);
176 if (value == NULL) { 204 if (value == NULL) {
177 bb_perror_msg("error reading key '%s'", outname); 205 bb_perror_msg("error reading key '%s'", outname);
206 retval = EXIT_FAILURE;
178 goto end; 207 goto end;
179 } 208 }
180 209
@@ -203,19 +232,21 @@ static int sysctl_act_on_setting(char *setting)
203 232
204static int sysctl_act_recursive(const char *path) 233static int sysctl_act_recursive(const char *path)
205{ 234{
206 DIR *dirp;
207 struct stat buf; 235 struct stat buf;
208 struct dirent *entry;
209 char *next;
210 int retval = 0; 236 int retval = 0;
211 237
212 stat(path, &buf); 238 if (!(option_mask32 & FLAG_WRITE)
213 if (S_ISDIR(buf.st_mode) && !(option_mask32 & FLAG_WRITE)) { 239 && stat(path, &buf) == 0
240 && S_ISDIR(buf.st_mode)
241 ) {
242 struct dirent *entry;
243 DIR *dirp;
244
214 dirp = opendir(path); 245 dirp = opendir(path);
215 if (dirp == NULL) 246 if (dirp == NULL)
216 return -1; 247 return -1;
217 while ((entry = readdir(dirp)) != NULL) { 248 while ((entry = readdir(dirp)) != NULL) {
218 next = concat_subpath_file(path, entry->d_name); 249 char *next = concat_subpath_file(path, entry->d_name);
219 if (next == NULL) 250 if (next == NULL)
220 continue; /* d_name is "." or ".." */ 251 continue; /* d_name is "." or ".." */
221 /* if path was ".", drop "./" prefix: */ 252 /* if path was ".", drop "./" prefix: */
@@ -303,6 +334,8 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv)
303 return sysctl_act_recursive("."); 334 return sysctl_act_recursive(".");
304 } 335 }
305 336
337//TODO: if(!argv[0]) bb_show_usage() ?
338
306 retval = 0; 339 retval = 0;
307 while (*argv) { 340 while (*argv) {
308 sysctl_dots_to_slashes(*argv); 341 sysctl_dots_to_slashes(*argv);
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index 55cdd78c1..cf912e0fb 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -1,10 +1,11 @@
1#!/usr/bin/perl 1#!/usr/bin/env perl
2# SPDX-License-Identifier: GPL-2.0
2 3
3# Stolen from Linux kernel :) 4# Stolen from Linux kernel :)
4 5
5# Check the stack usage of functions 6# Check the stack usage of functions
6# 7#
7# Copyright Joern Engel <joern@wh.fh-wedel.de> 8# Copyright Joern Engel <joern@lazybastard.org>
8# Inspired by Linus Torvalds 9# Inspired by Linus Torvalds
9# Original idea maybe from Keith Owens 10# Original idea maybe from Keith Owens
10# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de> 11# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
@@ -14,40 +15,57 @@
14# sh64 port by Paul Mundt 15# sh64 port by Paul Mundt
15# Random bits by Matt Mackall <mpm@selenic.com> 16# Random bits by Matt Mackall <mpm@selenic.com>
16# M68k port by Geert Uytterhoeven and Andreas Schwab 17# M68k port by Geert Uytterhoeven and Andreas Schwab
18# blackfin port by Alex Landau
19# AArch64, PARISC ports by Kyle McMartin
20# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
21# ppc64le port by Breno Leitao <leitao@debian.org>
17# 22#
18# Usage: 23# Usage:
19# objdump -d vmlinux | checkstack.pl [arch] 24# objdump -d vmlinux | scripts/checkstack.pl [arch]
20# 25#
21# TODO : Port to all architectures (one regex per arch) 26# TODO : Port to all architectures (one regex per arch)
22 27
28use strict;
29
23# check for arch 30# check for arch
24# 31#
25# $re is used for two matches: 32# $re is used for two matches:
26# $& (whole re) matches the complete objdump line with the stack growth 33# $& (whole re) matches the complete objdump line with the stack growth
27# $1 (first bracket) matches the size of the stack growth 34# $1 (first bracket) matches the size of the stack growth
28# 35#
36# $dre is similar, but for dynamic stack reductions:
37# $& (whole re) matches the complete objdump line with the stack growth
38# $1 (first bracket) matches the dynamic amount of the stack growth
39#
29# use anything else and feel the pain ;) 40# use anything else and feel the pain ;)
30my (@stack, $re, $x, $xs); 41my (@stack, $re, $dre, $x, $xs, $funcre);
31{ 42{
32 my $arch = shift; 43 my $arch = shift;
33 if ($arch eq "") { 44 if ($arch eq "") {
34 $arch = `uname -m`; 45 $arch = `uname -m`;
46 chomp($arch);
35 } 47 }
36 48
37 $x = "[0-9a-f]"; # hex character 49 $x = "[0-9a-f]"; # hex character
38 $xs = "[0-9a-f ]"; # hex character or space 50 $xs = "[0-9a-f ]"; # hex character or space
39 if ($arch eq 'arm') { 51 $funcre = qr/^$x* <(.*)>:$/;
52 if ($arch eq 'aarch64') {
53 #ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp, #-80]!
54 #a110: d11643ff sub sp, sp, #0x590
55 $re = qr/^.*stp.*sp, \#-([0-9]{1,8})\]\!/o;
56 $dre = qr/^.*sub.*sp, sp, #(0x$x{1,8})/o;
57 } elsif ($arch eq 'arm') {
40 #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 58 #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64
41 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; 59 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
60 } elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) {
61 #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
62 # or
63 # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
64 $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o;
65 $dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o;
42 } elsif ($arch eq 'blackfin') { 66 } elsif ($arch eq 'blackfin') {
43 # 52: 00 e8 03 00 LINK 0xc; 67 # 52: 00 e8 03 00 LINK 0xc;
44 $re = qr/.*LINK (0x$x{1,5});$/o; 68 $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
45 } elsif ($arch =~ /^i[3456]86$/) {
46 #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
47 $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o;
48 } elsif ($arch eq 'x86_64') {
49 # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
50 $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o;
51 } elsif ($arch eq 'ia64') { 69 } elsif ($arch eq 'ia64') {
52 #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 70 #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12
53 $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; 71 $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
@@ -61,42 +79,43 @@ my (@stack, $re, $x, $xs);
61 } elsif ($arch eq 'mips') { 79 } elsif ($arch eq 'mips') {
62 #88003254: 27bdffe0 addiu sp,sp,-32 80 #88003254: 27bdffe0 addiu sp,sp,-32
63 $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; 81 $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
64 } elsif ($arch eq 'ppc') { 82 } elsif ($arch eq 'nios2') {
65 #c00029f4: 94 21 ff 30 stwu r1,-208(r1) 83 #25a8: defffb04 addi sp,sp,-20
66 $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; 84 $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
67 } elsif ($arch eq 'ppc64') { 85 } elsif ($arch eq 'openrisc') {
68 #XXX 86 # c000043c: 9c 21 fe f0 l.addi r1,r1,-272
69 $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; 87 $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o;
70 } elsif ($arch eq 'powerpc') { 88 } elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
89 $re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
90 } elsif ($arch eq 'powerpc' || $arch =~ /^ppc(64)?(le)?$/ ) {
91 # powerpc : 94 21 ff 30 stwu r1,-208(r1)
92 # ppc64(le) : 81 ff 21 f8 stdu r1,-128(r1)
71 $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; 93 $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
72 } elsif ($arch =~ /^s390x?$/) { 94 } elsif ($arch =~ /^s390x?$/) {
73 # 11160: a7 fb ff 60 aghi %r15,-160 95 # 11160: a7 fb ff 60 aghi %r15,-160
74 $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o; 96 # or
97 # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
98 $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
99 (?:\(\%r15\))?$/ox;
75 } elsif ($arch =~ /^sh64$/) { 100 } elsif ($arch =~ /^sh64$/) {
76 #XXX: we only check for the immediate case presently, 101 #XXX: we only check for the immediate case presently,
77 # though we will want to check for the movi/sub 102 # though we will want to check for the movi/sub
78 # pair for larger users. -- PFM. 103 # pair for larger users. -- PFM.
79 #a00048e0: d4fc40f0 addi.l r15,-240,r15 104 #a00048e0: d4fc40f0 addi.l r15,-240,r15
80 $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; 105 $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
106 } elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
107 # f0019d10: 9d e3 bf 90 save %sp, -112, %sp
108 $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
81 } else { 109 } else {
82 print("wrong or unknown architecture\n"); 110 print("wrong or unknown architecture \"$arch\"\n");
83 exit 111 exit
84 } 112 }
85} 113}
86 114
87sub bysize($) {
88 my ($asize, $bsize);
89 ($asize = $a) =~ s/.*: *(.*)$/$1/;
90 ($bsize = $b) =~ s/.*: *(.*)$/$1/;
91 $bsize <=> $asize
92}
93
94# 115#
95# main() 116# main()
96# 117#
97my $funcre = qr/^$x* <(.*)>:$/; 118my ($func, $file, $lastslash);
98my $func;
99my $file, $lastslash;
100 119
101while (my $line = <STDIN>) { 120while (my $line = <STDIN>) {
102 if ($line =~ m/$funcre/) { 121 if ($line =~ m/$funcre/) {
@@ -136,6 +155,31 @@ while (my $line = <STDIN>) {
136 next if ($size < 100); 155 next if ($size < 100);
137 push @stack, "$intro$size\n"; 156 push @stack, "$intro$size\n";
138 } 157 }
158 elsif (defined $dre && $line =~ m/$dre/) {
159 my $size = "Dynamic ($1)";
160
161 next if $line !~ m/^($xs*)/;
162 my $addr = $1;
163 $addr =~ s/ /0/g;
164 $addr = "0x$addr";
165
166 #bbox: was: my $intro = "$addr $func [$file]:";
167 my $intro = "$func [$file]:";
168 my $padlen = 56 - length($intro);
169 while ($padlen > 0) {
170 $intro .= ' ';
171 $padlen -= 8;
172 }
173 push @stack, "$intro$size\n";
174 }
175}
176
177sub bysize($) {
178 my ($asize, $bsize);
179 ($asize = $a) =~ s/.*: *(.*)$/$1/;
180 ($bsize = $b) =~ s/.*: *(.*)$/$1/;
181 $bsize <=> $asize
139} 182}
140 183
141print sort bysize @stack; 184# Sort output by size (last field)
185print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;
diff --git a/selinux/chcon.c b/selinux/chcon.c
index 92eb76737..5bf91710c 100644
--- a/selinux/chcon.c
+++ b/selinux/chcon.c
@@ -204,7 +204,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv)
204 fname[fname_len] = '\0'; 204 fname[fname_len] = '\0';
205 205
206 if (recursive_action(fname, 206 if (recursive_action(fname,
207 ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSIVE : 0), 207 ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0),
208 change_filedir_context, 208 change_filedir_context,
209 change_filedir_context, 209 change_filedir_context,
210 NULL, 0) != TRUE) 210 NULL, 0) != TRUE)
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 3933fefc9..0db6a26e4 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -280,6 +280,18 @@ testing "awk 'delete a[v--]' evaluates v-- once" \
280" \ 280" \
281 "" "" 281 "" ""
282 282
283testing "awk func arg parsing 1" \
284 "awk 'func f(,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
285
286testing "awk func arg parsing 2" \
287 "awk 'func f(a,,b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
288
289testing "awk func arg parsing 3" \
290 "awk 'func f(a,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
291
292testing "awk func arg parsing 4" \
293 "awk 'func f(a b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
294
283testing "awk handles empty ()" \ 295testing "awk handles empty ()" \
284 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" 296 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
285 297
@@ -336,7 +348,13 @@ testing "awk continue" \
336 'BEGIN { if (1) continue; else a = 1 }' 348 'BEGIN { if (1) continue; else a = 1 }'
337 349
338testing "awk handles invalid for loop" \ 350testing "awk handles invalid for loop" \
339 "awk '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" 351 "awk -e '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
352
353testing "awk handles colon not preceded by ternary" \
354 "awk -e foo:bar: 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
355
356testing "awk errors on missing delete arg" \
357 "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" ""
340 358
341# testing "description" "command" "result" "infile" "stdin" 359# testing "description" "command" "result" "infile" "stdin"
342testing 'awk negative field access' \ 360testing 'awk negative field access' \
diff --git a/testsuite/bc_references.bc b/testsuite/bc_references.bc
new file mode 100644
index 000000000..fc48c1a56
--- /dev/null
+++ b/testsuite/bc_references.bc
@@ -0,0 +1,106 @@
1define printarray(a[], len) {
2
3 auto i
4
5 for (i = 0; i < len; ++i) {
6 a[i]
7 }
8}
9
10define a2(a[], len) {
11
12 auto i
13
14 for (i = 0; i < len; ++i) {
15 a[i] = a[i] * a[i]
16 }
17
18 printarray(a[], len)
19}
20
21define a4(a__[], len) {
22
23 auto i
24
25 for (i = 0; i < len; ++i) {
26 a__[i] = a__[i] * a__[i]
27 }
28
29 printarray(a__[], len)
30}
31
32define a6(*a__[], len) {
33
34 auto i
35
36 for (i = 0; i < len; ++i) {
37 a__[i] = a__[i] * a__[i]
38 }
39
40 printarray(a__[], len)
41}
42
43define a1(*a[], len) {
44
45 auto i
46
47 for (i = 0; i < len; ++i) {
48 a[i] = i
49 }
50
51 a2(a[], len)
52
53 printarray(a[], len)
54}
55
56define a3(*a__[], len) {
57
58 auto i
59
60 for (i = 0; i < len; ++i) {
61 a__[i] = i
62 }
63
64 a4(a__[], len)
65
66 printarray(a__[], len)
67}
68
69define a5(*a__[], len) {
70
71 auto i
72
73 for (i = 0; i < len; ++i) {
74 a__[i] = i
75 }
76
77 a2(a__[], len)
78
79 printarray(a__[], len)
80}
81
82define a7(*a__[], len) {
83
84 auto i
85
86 for (i = 0; i < len; ++i) {
87 a__[i] = i
88 }
89
90 a6(a__[], len)
91
92 printarray(a__[], len)
93}
94
95len = 16
96
97a1(a[], len)
98printarray(a[], len)
99a3(a[], len)
100printarray(a[], len)
101a5(a[], len)
102printarray(a[], len)
103a7(a[], len)
104printarray(a[], len)
105
106halt
diff --git a/testsuite/bc_references_results.txt b/testsuite/bc_references_results.txt
new file mode 100644
index 000000000..564b54a3a
--- /dev/null
+++ b/testsuite/bc_references_results.txt
@@ -0,0 +1,212 @@
10
21
34
49
516
625
736
849
964
1081
11100
12121
13144
14169
15196
16225
170
180
190
201
212
223
234
245
256
267
278
289
2910
3011
3112
3213
3314
3415
350
360
370
381
392
403
414
425
436
447
458
469
4710
4811
4912
5013
5114
5215
530
540
551
564
579
5816
5925
6036
6149
6264
6381
64100
65121
66144
67169
68196
69225
700
710
720
731
742
753
764
775
786
797
808
819
8210
8311
8412
8513
8614
8715
880
890
900
911
922
933
944
955
966
977
988
999
10010
10111
10212
10313
10414
10515
1060
1070
1081
1094
1109
11116
11225
11336
11449
11564
11681
117100
118121
119144
120169
121196
122225
1230
1240
1250
1261
1272
1283
1294
1305
1316
1327
1338
1349
13510
13611
13712
13813
13914
14015
1410
1420
1430
1441
1452
1463
1474
1485
1496
1507
1518
1529
15310
15411
15512
15613
15714
15815
1590
1600
1611
1624
1639
16416
16525
16636
16749
16864
16981
170100
171121
172144
173169
174196
175225
1760
1770
1780
1791
1804
1819
18216
18325
18436
18549
18664
18781
188100
189121
190144
191169
192196
193225
1940
1950
1960
1971
1984
1999
20016
20125
20236
20349
20464
20581
206100
207121
208144
209169
210196
211225
2120
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index e57889790..26f8e69cf 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -177,6 +177,13 @@ testing "grep -w word match second word" \
177 "bword,word\n""wordb,word\n""bwordb,word\n" \ 177 "bword,word\n""wordb,word\n""bwordb,word\n" \
178 "" 178 ""
179 179
180
181testing "grep -x -v -e EXP1 -e EXP2 finds nothing if either EXP matches" \
182 "grep -x -v -e '.*aa.*' -e 'bb.*'; echo \$?" \
183 "1\n" \
184 "" \
185 " aa bb cc\n"
186
180# -r on symlink to dir should recurse into dir 187# -r on symlink to dir should recurse into dir
181mkdir -p grep.testdir/foo 188mkdir -p grep.testdir/foo
182echo bar > grep.testdir/foo/file 189echo bar > grep.testdir/foo/file
diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests
index d07aeef0e..2ddb7fefb 100755
--- a/testsuite/start-stop-daemon.tests
+++ b/testsuite/start-stop-daemon.tests
@@ -16,4 +16,16 @@ testing "start-stop-daemon -a without -x" \
16 "1\n" \ 16 "1\n" \
17 "" "" 17 "" ""
18 18
19testing "start-stop-daemon without -x and -a" \
20 'start-stop-daemon -S false 2>&1; echo $?' \
21 "1\n" \
22 "" ""
23
24# Unfortunately, this does not actually check argv[0] correctness,
25# but at least it checks that pathname to exec() is correct
26testing "start-stop-daemon with both -x and -a" \
27 'start-stop-daemon -S -x /bin/false -a qwerty false 2>&1; echo $?' \
28 "1\n" \
29 "" ""
30
19exit $FAILCOUNT 31exit $FAILCOUNT