aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-09-10 14:47:27 +0100
committerRon Yorston <rmy@pobox.com>2021-09-10 14:47:27 +0100
commit3eb1d088e09db204f456ad7b76eced21e429f001 (patch)
treea81b5bb422db5ee97475a8f1a4b5236442ed6f14 /shell
parent12bc40da28f85cbe97673671f315f847f1dbbabf (diff)
parent40f2dd7dd2e50c9d81dda4d72bf9c85c4c479a89 (diff)
downloadbusybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.tar.gz
busybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.tar.bz2
busybox-w32-3eb1d088e09db204f456ad7b76eced21e429f001.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c444
-rw-r--r--shell/ash_test/ash-alias/alias_brace.right1
-rwxr-xr-xshell/ash_test/ash-alias/alias_brace.tests16
-rw-r--r--shell/ash_test/ash-alias/alias_case.right1
-rwxr-xr-xshell/ash_test/ash-alias/alias_case.tests8
-rw-r--r--shell/ash_test/ash-misc/control_char3.right2
-rw-r--r--shell/ash_test/ash-misc/control_char4.right2
-rw-r--r--shell/ash_test/ash-misc/exitcode_trap7.right2
-rwxr-xr-xshell/ash_test/ash-misc/exitcode_trap7.tests7
-rw-r--r--shell/ash_test/ash-misc/set-n1.right3
-rwxr-xr-xshell/ash_test/ash-misc/set-n1.tests2
-rw-r--r--shell/ash_test/ash-misc/shift1.right2
-rw-r--r--shell/ash_test/ash-misc/tickquote1.right2
-rw-r--r--shell/ash_test/ash-parsing/groups_and_keywords2.right2
-rw-r--r--shell/ash_test/ash-psubst/emptytick.right4
-rw-r--r--shell/ash_test/ash-vars/param_expand_alt.right4
-rw-r--r--shell/ash_test/ash-vars/param_expand_assign.right14
-rw-r--r--shell/ash_test/ash-vars/param_expand_bash_substring.right10
-rw-r--r--shell/ash_test/ash-vars/param_expand_default.right2
-rw-r--r--shell/ash_test/ash-vars/param_expand_indicate_error.right32
-rw-r--r--shell/ash_test/ash-vars/var6.right4
-rw-r--r--shell/ash_test/ash-vars/var_LINENO2.right3
-rwxr-xr-xshell/ash_test/ash-vars/var_LINENO2.tests8
-rw-r--r--shell/ash_test/ash-vars/var_LINENO3.right2
-rwxr-xr-xshell/ash_test/ash-vars/var_LINENO3.tests2
-rwxr-xr-xshell/ash_test/run-all14
-rw-r--r--shell/hush.c18
-rw-r--r--shell/hush_test/hush-misc/exitcode_trap7.right2
-rwxr-xr-xshell/hush_test/hush-misc/exitcode_trap7.tests7
-rw-r--r--shell/hush_test/hush-misc/set-n1.right3
-rwxr-xr-xshell/hush_test/hush-misc/set-n1.tests2
-rw-r--r--shell/hush_test/hush-vars/var_LINENO2.right3
-rwxr-xr-xshell/hush_test/hush-vars/var_LINENO2.tests8
-rw-r--r--shell/hush_test/hush-vars/var_LINENO3.right2
-rwxr-xr-xshell/hush_test/hush-vars/var_LINENO3.tests2
35 files changed, 389 insertions, 251 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 508633689..7544204d1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -329,6 +329,10 @@ typedef long arith_t;
329# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 329# define PIPE_BUF 4096 /* amount of buffering in a pipe */
330#endif 330#endif
331 331
332#ifndef unlikely
333# define unlikely(cond) (cond)
334#endif
335
332#if !ENABLE_PLATFORM_MINGW32 336#if !ENABLE_PLATFORM_MINGW32
333# define is_absolute_path(path) ((path)[0] == '/') 337# define is_absolute_path(path) ((path)[0] == '/')
334#endif 338#endif
@@ -456,6 +460,7 @@ static const char *const optletters_optnames[] = {
456 "a" "allexport", 460 "a" "allexport",
457 "b" "notify", 461 "b" "notify",
458 "u" "nounset", 462 "u" "nounset",
463 "E" "errtrace",
459 "\0" "vi" 464 "\0" "vi"
460#if BASH_PIPEFAIL 465#if BASH_PIPEFAIL
461 ,"\0" "pipefail" 466 ,"\0" "pipefail"
@@ -518,6 +523,7 @@ struct globals_misc {
518#if !ENABLE_PLATFORM_MINGW32 523#if !ENABLE_PLATFORM_MINGW32
519 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 524 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
520#endif 525#endif
526 smallint inps4; /* Prevent PS4 nesting. */
521 int savestatus; /* exit status of last command outside traps */ 527 int savestatus; /* exit status of last command outside traps */
522 int rootpid; /* pid of main shell */ 528 int rootpid; /* pid of main shell */
523 /* shell level: 0 for the main shell, 1 for its children, and so on */ 529 /* shell level: 0 for the main shell, 1 for its children, and so on */
@@ -573,23 +579,24 @@ struct globals_misc {
573#define aflag optlist[11] 579#define aflag optlist[11]
574#define bflag optlist[12] 580#define bflag optlist[12]
575#define uflag optlist[13] 581#define uflag optlist[13]
576#define viflag optlist[14] 582#define Eflag optlist[14]
583#define viflag optlist[15]
577#if BASH_PIPEFAIL 584#if BASH_PIPEFAIL
578# define pipefail optlist[15] 585# define pipefail optlist[16]
579#else 586#else
580# define pipefail 0 587# define pipefail 0
581#endif 588#endif
582#if DEBUG 589#if DEBUG
583# define nolog optlist[15 + BASH_PIPEFAIL] 590# define nolog optlist[16 + BASH_PIPEFAIL]
584# define debug optlist[16 + BASH_PIPEFAIL] 591# define debug optlist[17 + BASH_PIPEFAIL]
585#endif 592#endif
586#if ENABLE_PLATFORM_MINGW32 593#if ENABLE_PLATFORM_MINGW32
587# define winxp optlist[15 + BASH_PIPEFAIL + 2*DEBUG] 594# define winxp optlist[16 + BASH_PIPEFAIL + 2*DEBUG]
588# if ENABLE_ASH_NOCONSOLE 595# if ENABLE_ASH_NOCONSOLE
589# define noconsole optlist[16 + BASH_PIPEFAIL + 2*DEBUG] 596# define noconsole optlist[17 + BASH_PIPEFAIL + 2*DEBUG]
590# endif 597# endif
591# if ENABLE_ASH_NOCASEGLOB 598# if ENABLE_ASH_NOCASEGLOB
592# define nocaseglob optlist[16 + BASH_PIPEFAIL + 2*DEBUG+ENABLE_ASH_NOCONSOLE] 599# define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*DEBUG+ENABLE_ASH_NOCONSOLE]
593# endif 600# endif
594#endif 601#endif
595 602
@@ -610,7 +617,11 @@ struct globals_misc {
610 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 617 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
611 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ 618 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
612#endif 619#endif
613 char *trap[NSIG]; 620 char *trap[NSIG + 1];
621/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
622#define NTRAP_ERR NSIG
623#define NTRAP_LAST NSIG
624
614#if !ENABLE_PLATFORM_MINGW32 625#if !ENABLE_PLATFORM_MINGW32
615 char **trap_ptr; /* used only by "trap hack" */ 626 char **trap_ptr; /* used only by "trap hack" */
616#endif 627#endif
@@ -626,6 +637,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
626#define exitstatus (G_misc.exitstatus ) 637#define exitstatus (G_misc.exitstatus )
627#define back_exitstatus (G_misc.back_exitstatus ) 638#define back_exitstatus (G_misc.back_exitstatus )
628#define job_warning (G_misc.job_warning) 639#define job_warning (G_misc.job_warning)
640#define inps4 (G_misc.inps4 )
629#define savestatus (G_misc.savestatus ) 641#define savestatus (G_misc.savestatus )
630#define rootpid (G_misc.rootpid ) 642#define rootpid (G_misc.rootpid )
631#define shlvl (G_misc.shlvl ) 643#define shlvl (G_misc.shlvl )
@@ -742,6 +754,9 @@ struct strpush {
742#endif 754#endif
743 char *string; /* remember the string since it may change */ 755 char *string; /* remember the string since it may change */
744 756
757 /* Delay freeing so we can stop nested aliases. */
758 struct strpush *spfree;
759
745 /* Remember last two characters for pungetc. */ 760 /* Remember last two characters for pungetc. */
746 int lastc[2]; 761 int lastc[2];
747 762
@@ -764,6 +779,9 @@ struct parsefile {
764 struct strpush *strpush; /* for pushing strings at this level */ 779 struct strpush *strpush; /* for pushing strings at this level */
765 struct strpush basestrpush; /* so pushing one is fast */ 780 struct strpush basestrpush; /* so pushing one is fast */
766 781
782 /* Delay freeing so we can stop nested aliases. */
783 struct strpush *spfree;
784
767 /* Remember last two characters for pungetc. */ 785 /* Remember last two characters for pungetc. */
768 int lastc[2]; 786 int lastc[2];
769 787
@@ -2366,6 +2384,8 @@ struct globals_var {
2366 struct var varinit[ARRAY_SIZE(varinit_data)]; 2384 struct var varinit[ARRAY_SIZE(varinit_data)];
2367 int lineno; 2385 int lineno;
2368 char linenovar[sizeof("LINENO=") + sizeof(int)*3]; 2386 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2387 unsigned trap_depth;
2388 bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
2369}; 2389};
2370extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; 2390extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2371#define G_var (*ash_ptr_to_globals_var) 2391#define G_var (*ash_ptr_to_globals_var)
@@ -2376,6 +2396,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2376#define varinit (G_var.varinit ) 2396#define varinit (G_var.varinit )
2377#define lineno (G_var.lineno ) 2397#define lineno (G_var.lineno )
2378#define linenovar (G_var.linenovar ) 2398#define linenovar (G_var.linenovar )
2399#define trap_depth (G_var.trap_depth )
2400#define in_trap_ERR (G_var.in_trap_ERR )
2379#define vifs varinit[0] 2401#define vifs varinit[0]
2380#if ENABLE_ASH_MAIL 2402#if ENABLE_ASH_MAIL
2381# define vmail varinit[1] 2403# define vmail varinit[1]
@@ -2547,7 +2569,7 @@ lookupvar(const char *name)
2547 v->var_func(NULL); 2569 v->var_func(NULL);
2548#endif 2570#endif
2549 if (!(v->flags & VUNSET)) { 2571 if (!(v->flags & VUNSET)) {
2550 if (v == &vlineno && v->var_text == linenovar) { 2572 if (v->var_text == linenovar) {
2551 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); 2573 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2552 } 2574 }
2553 return var_end(v->var_text); 2575 return var_end(v->var_text);
@@ -3439,12 +3461,8 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3439#define CENDFILE 11 /* end of file */ 3461#define CENDFILE 11 /* end of file */
3440#define CCTL 12 /* like CWORD, except it must be escaped */ 3462#define CCTL 12 /* like CWORD, except it must be escaped */
3441#define CSPCL 13 /* these terminate a word */ 3463#define CSPCL 13 /* these terminate a word */
3442#define CIGN 14 /* character should be ignored */
3443 3464
3444#define PEOF 256 3465#define PEOF 256
3445#if ENABLE_ASH_ALIAS
3446# define PEOA 257
3447#endif
3448 3466
3449#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE 3467#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3450 3468
@@ -3454,49 +3472,43 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3454# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) 3472# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3455#endif 3473#endif
3456static const uint16_t S_I_T[] ALIGN2 = { 3474static const uint16_t S_I_T[] ALIGN2 = {
3457#if ENABLE_ASH_ALIAS 3475 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 0, ' ' */
3458 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ 3476 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 1, \n */
3459#endif 3477 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 2, !*-/:=?[]~ */
3460 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */ 3478 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 3, '"' */
3461 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */ 3479 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 4, $ */
3462 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */ 3480 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 5, "'" */
3463 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */ 3481 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 6, ( */
3464 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */ 3482 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 7, ) */
3465 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */ 3483 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 8, \ */
3466 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */ 3484 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 9, ` */
3467 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */ 3485 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 10, } */
3468 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
3469 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
3470 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
3471#if !USE_SIT_FUNCTION 3486#if !USE_SIT_FUNCTION
3472 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */ 3487 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */
3473 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */ 3488 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 12, 0-9A-Za-z */
3474 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */ 3489 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 13, CTLESC ... */
3475#endif 3490#endif
3476#undef SIT_ITEM 3491#undef SIT_ITEM
3477}; 3492};
3478/* Constants below must match table above */ 3493/* Constants below must match table above */
3479enum { 3494enum {
3480#if ENABLE_ASH_ALIAS 3495 CSPCL_CWORD_CWORD_CWORD , /* 0 */
3481 CSPCL_CIGN_CIGN_CIGN , /* 0 */ 3496 CNL_CNL_CNL_CNL , /* 1 */
3482#endif 3497 CWORD_CCTL_CCTL_CWORD , /* 2 */
3483 CSPCL_CWORD_CWORD_CWORD , /* 1 */ 3498 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 3 */
3484 CNL_CNL_CNL_CNL , /* 2 */ 3499 CVAR_CVAR_CWORD_CVAR , /* 4 */
3485 CWORD_CCTL_CCTL_CWORD , /* 3 */ 3500 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 5 */
3486 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */ 3501 CSPCL_CWORD_CWORD_CLP , /* 6 */
3487 CVAR_CVAR_CWORD_CVAR , /* 5 */ 3502 CSPCL_CWORD_CWORD_CRP , /* 7 */
3488 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */ 3503 CBACK_CBACK_CCTL_CBACK , /* 8 */
3489 CSPCL_CWORD_CWORD_CLP , /* 7 */ 3504 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 9 */
3490 CSPCL_CWORD_CWORD_CRP , /* 8 */ 3505 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 10 */
3491 CBACK_CBACK_CCTL_CBACK , /* 9 */ 3506 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */
3492 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */ 3507 CWORD_CWORD_CWORD_CWORD , /* 12 */
3493 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */ 3508 CCTL_CCTL_CCTL_CCTL , /* 13 */
3494 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
3495 CWORD_CWORD_CWORD_CWORD , /* 13 */
3496 CCTL_CCTL_CCTL_CCTL , /* 14 */
3497}; 3509};
3498 3510
3499/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, 3511/* c in SIT(c, syntax) must be an *unsigned char* or PEOF,
3500 * caller must ensure proper cast on it if c is *char_ptr! 3512 * caller must ensure proper cast on it if c is *char_ptr!
3501 */ 3513 */
3502#if USE_SIT_FUNCTION 3514#if USE_SIT_FUNCTION
@@ -3514,44 +3526,28 @@ SIT(int c, int syntax)
3514 * but glibc one isn't. With '/' always treated as CWORD, 3526 * but glibc one isn't. With '/' always treated as CWORD,
3515 * both work fine. 3527 * both work fine.
3516 */ 3528 */
3517# if ENABLE_ASH_ALIAS
3518 static const uint8_t syntax_index_table[] ALIGN1 = {
3519 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
3520 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
3521 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
3522 11, 3 /* "}~" */
3523 };
3524# else
3525 static const uint8_t syntax_index_table[] ALIGN1 = { 3529 static const uint8_t syntax_index_table[] ALIGN1 = {
3526 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 3530 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
3527 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */ 3531 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
3528 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ 3532 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
3529 10, 2 /* "}~" */ 3533 10, 2 /* "}~" */
3530 }; 3534 };
3531# endif
3532 const char *s; 3535 const char *s;
3533 int indx; 3536 int indx;
3534 3537
3535 if (c == PEOF) 3538 if (c == PEOF)
3536 return CENDFILE; 3539 return CENDFILE;
3537# if ENABLE_ASH_ALIAS 3540 /* Cast is purely for paranoia here,
3538 if (c == PEOA) 3541 * just in case someone passed signed char to us */
3539 indx = 0; 3542 if ((unsigned char)c >= CTL_FIRST
3540 else 3543 && (unsigned char)c <= CTL_LAST
3541# endif 3544 ) {
3542 { 3545 return CCTL;
3543 /* Cast is purely for paranoia here,
3544 * just in case someone passed signed char to us */
3545 if ((unsigned char)c >= CTL_FIRST
3546 && (unsigned char)c <= CTL_LAST
3547 ) {
3548 return CCTL;
3549 }
3550 s = strchrnul(spec_symbls, c);
3551 if (*s == '\0')
3552 return CWORD;
3553 indx = syntax_index_table[s - spec_symbls];
3554 } 3546 }
3547 s = strchrnul(spec_symbls, c);
3548 if (*s == '\0')
3549 return CWORD;
3550 indx = syntax_index_table[s - spec_symbls];
3555 return (S_I_T[indx] >> (syntax*4)) & 0xf; 3551 return (S_I_T[indx] >> (syntax*4)) & 0xf;
3556} 3552}
3557 3553
@@ -3822,9 +3818,6 @@ static const uint8_t syntax_index_table[] ALIGN1 = {
3822 /* 254 */ CWORD_CWORD_CWORD_CWORD, 3818 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3823 /* 255 */ CWORD_CWORD_CWORD_CWORD, 3819 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3824 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 3820 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3825# if ENABLE_ASH_ALIAS
3826 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3827# endif
3828}; 3821};
3829 3822
3830#if 1 3823#if 1
@@ -5712,13 +5705,13 @@ clear_traps(void)
5712 char **tp; 5705 char **tp;
5713 5706
5714 INT_OFF; 5707 INT_OFF;
5715 for (tp = trap; tp < &trap[NSIG]; tp++) { 5708 for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5716 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ 5709 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
5717 if (trap_ptr == trap) 5710 if (trap_ptr == trap)
5718 free(*tp); 5711 free(*tp);
5719 /* else: it "belongs" to trap_ptr vector, don't free */ 5712 /* else: it "belongs" to trap_ptr vector, don't free */
5720 *tp = NULL; 5713 *tp = NULL;
5721 if ((tp - trap) != 0) 5714 if ((tp - trap) != 0 && (tp - trap) < NSIG)
5722 setsignal(tp - trap); 5715 setsignal(tp - trap);
5723 } 5716 }
5724 } 5717 }
@@ -10007,7 +10000,9 @@ dotrap(void)
10007 *g = 0; 10000 *g = 0;
10008 if (!p) 10001 if (!p)
10009 continue; 10002 continue;
10003 trap_depth++;
10010 evalstring(p, 0); 10004 evalstring(p, 0);
10005 trap_depth--;
10011 if (evalskip != SKIPFUNC) 10006 if (evalskip != SKIPFUNC)
10012 exitstatus = status; 10007 exitstatus = status;
10013 } 10008 }
@@ -10044,6 +10039,9 @@ evaltree(union node *n, int flags)
10044 10039
10045 setstackmark(&smark); 10040 setstackmark(&smark);
10046 10041
10042 if (nflag)
10043 goto out;
10044
10047 if (n == NULL) { 10045 if (n == NULL) {
10048 TRACE(("evaltree(NULL) called\n")); 10046 TRACE(("evaltree(NULL) called\n"));
10049 goto out; 10047 goto out;
@@ -10064,8 +10062,6 @@ evaltree(union node *n, int flags)
10064 goto setstatus; 10062 goto setstatus;
10065 case NREDIR: 10063 case NREDIR:
10066 errlinno = lineno = n->nredir.linno; 10064 errlinno = lineno = n->nredir.linno;
10067 if (funcline)
10068 lineno -= funcline - 1;
10069 expredir(n->nredir.redirect); 10065 expredir(n->nredir.redirect);
10070 pushredir(n->nredir.redirect); 10066 pushredir(n->nredir.redirect);
10071 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 10067 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
@@ -10078,8 +10074,7 @@ evaltree(union node *n, int flags)
10078 case NCMD: 10074 case NCMD:
10079 evalfn = evalcommand; 10075 evalfn = evalcommand;
10080 checkexit: 10076 checkexit:
10081 if (eflag && !(flags & EV_TESTED)) 10077 checkexit = ~flags & EV_TESTED;
10082 checkexit = ~0;
10083 goto calleval; 10078 goto calleval;
10084 case NFOR: 10079 case NFOR:
10085 evalfn = evalfor; 10080 evalfn = evalfor;
@@ -10101,7 +10096,6 @@ evaltree(union node *n, int flags)
10101 case NAND: 10096 case NAND:
10102 case NOR: 10097 case NOR:
10103 case NSEMI: { 10098 case NSEMI: {
10104
10105#if NAND + 1 != NOR 10099#if NAND + 1 != NOR
10106#error NAND + 1 != NOR 10100#error NAND + 1 != NOR
10107#endif 10101#endif
@@ -10129,8 +10123,7 @@ evaltree(union node *n, int flags)
10129 if (!status) { 10123 if (!status) {
10130 n = n->nif.ifpart; 10124 n = n->nif.ifpart;
10131 goto evaln; 10125 goto evaln;
10132 } 10126 } else if (n->nif.elsepart) {
10133 if (n->nif.elsepart) {
10134 n = n->nif.elsepart; 10127 n = n->nif.elsepart;
10135 goto evaln; 10128 goto evaln;
10136 } 10129 }
@@ -10152,10 +10145,36 @@ evaltree(union node *n, int flags)
10152 */ 10145 */
10153 dotrap(); 10146 dotrap();
10154 10147
10155 if (checkexit & status) 10148 if (checkexit && status) {
10156 raise_exception(EXEND); 10149 if (trap[NTRAP_ERR] && !in_trap_ERR) {
10157 if (flags & EV_EXIT) 10150 int err;
10151 struct jmploc *volatile savehandler = exception_handler;
10152 struct jmploc jmploc;
10153
10154 in_trap_ERR = 1;
10155 trap_depth++;
10156 err = setjmp(jmploc.loc);
10157 if (!err) {
10158 exception_handler = &jmploc;
10159 savestatus = exitstatus;
10160 evalstring(trap[NTRAP_ERR], 0);
10161 }
10162 trap_depth--;
10163 in_trap_ERR = 0;
10164
10165 exception_handler = savehandler;
10166 if (err && exception_type != EXERROR)
10167 longjmp(exception_handler->loc, 1);
10168
10169 exitstatus = savestatus;
10170 }
10171 if (eflag)
10172 goto exexit;
10173 }
10174 if (flags & EV_EXIT) {
10175 exexit:
10158 raise_exception(EXEND); 10176 raise_exception(EXEND);
10177 }
10159 10178
10160 popstackmark(&smark); 10179 popstackmark(&smark);
10161 TRACE(("leaving evaltree (no interrupts)\n")); 10180 TRACE(("leaving evaltree (no interrupts)\n"));
@@ -10221,8 +10240,6 @@ evalfor(union node *n, int flags)
10221 int status = 0; 10240 int status = 0;
10222 10241
10223 errlinno = lineno = n->ncase.linno; 10242 errlinno = lineno = n->ncase.linno;
10224 if (funcline)
10225 lineno -= funcline - 1;
10226 10243
10227 arglist.list = NULL; 10244 arglist.list = NULL;
10228 arglist.lastp = &arglist.list; 10245 arglist.lastp = &arglist.list;
@@ -10253,8 +10270,6 @@ evalcase(union node *n, int flags)
10253 int status = 0; 10270 int status = 0;
10254 10271
10255 errlinno = lineno = n->ncase.linno; 10272 errlinno = lineno = n->ncase.linno;
10256 if (funcline)
10257 lineno -= funcline - 1;
10258 10273
10259 arglist.list = NULL; 10274 arglist.list = NULL;
10260 arglist.lastp = &arglist.list; 10275 arglist.lastp = &arglist.list;
@@ -10289,8 +10304,6 @@ evalsubshell(union node *n, int flags)
10289 int status; 10304 int status;
10290 10305
10291 errlinno = lineno = n->nredir.linno; 10306 errlinno = lineno = n->nredir.linno;
10292 if (funcline)
10293 lineno -= funcline - 1;
10294 10307
10295 expredir(n->nredir.redirect); 10308 expredir(n->nredir.redirect);
10296 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 10309 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
@@ -10639,8 +10652,15 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
10639 struct jmploc *volatile savehandler; 10652 struct jmploc *volatile savehandler;
10640 struct jmploc jmploc; 10653 struct jmploc jmploc;
10641 int e; 10654 int e;
10655 int savelineno;
10642 int savefuncline; 10656 int savefuncline;
10657 char *savetrap = NULL;
10643 10658
10659 if (!Eflag) {
10660 savetrap = trap[NTRAP_ERR];
10661 trap[NTRAP_ERR] = NULL;
10662 }
10663 savelineno = lineno;
10644 saveparam = shellparam; 10664 saveparam = shellparam;
10645 savefuncline = funcline; 10665 savefuncline = funcline;
10646 savehandler = exception_handler; 10666 savehandler = exception_handler;
@@ -10663,7 +10683,14 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
10663 evaltree(func->n.ndefun.body, flags & EV_TESTED); 10683 evaltree(func->n.ndefun.body, flags & EV_TESTED);
10664 funcdone: 10684 funcdone:
10665 INT_OFF; 10685 INT_OFF;
10686 if (savetrap) {
10687 if (!trap[NTRAP_ERR])
10688 trap[NTRAP_ERR] = savetrap;
10689 else
10690 free(savetrap);
10691 }
10666 funcline = savefuncline; 10692 funcline = savefuncline;
10693 lineno = savelineno;
10667 freefunc(func); 10694 freefunc(func);
10668 freeparam(&shellparam); 10695 freeparam(&shellparam);
10669 shellparam = saveparam; 10696 shellparam = saveparam;
@@ -11076,11 +11103,12 @@ evalcommand(union node *cmd, int flags)
11076 int vlocal; 11103 int vlocal;
11077 11104
11078 errlinno = lineno = cmd->ncmd.linno; 11105 errlinno = lineno = cmd->ncmd.linno;
11079 if (funcline)
11080 lineno -= funcline - 1;
11081 11106
11082 /* First expand the arguments. */ 11107 /* First expand the arguments. */
11083 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 11108 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
11109#if BASH_PROCESS_SUBST
11110 redir_stop = redirlist;
11111#endif
11084 file_stop = g_parsefile; 11112 file_stop = g_parsefile;
11085 back_exitstatus = 0; 11113 back_exitstatus = 0;
11086 11114
@@ -11159,7 +11187,11 @@ evalcommand(union node *cmd, int flags)
11159 lastarg = nargv[-1]; 11187 lastarg = nargv[-1];
11160 11188
11161 expredir(cmd->ncmd.redirect); 11189 expredir(cmd->ncmd.redirect);
11190#if !BASH_PROCESS_SUBST
11162 redir_stop = pushredir(cmd->ncmd.redirect); 11191 redir_stop = pushredir(cmd->ncmd.redirect);
11192#else
11193 pushredir(cmd->ncmd.redirect);
11194#endif
11163 preverrout_fd = 2; 11195 preverrout_fd = 2;
11164 if (BASH_XTRACEFD && xflag) { 11196 if (BASH_XTRACEFD && xflag) {
11165 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. 11197 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
@@ -11196,10 +11228,12 @@ evalcommand(union node *cmd, int flags)
11196 } 11228 }
11197 11229
11198 /* Print the command if xflag is set. */ 11230 /* Print the command if xflag is set. */
11199 if (xflag) { 11231 if (xflag && !inps4) {
11200 const char *pfx = ""; 11232 const char *pfx = "";
11201 11233
11234 inps4 = 1;
11202 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX)); 11235 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
11236 inps4 = 0;
11203 11237
11204 sp = varlist.list; 11238 sp = varlist.list;
11205 while (sp) { 11239 while (sp) {
@@ -11483,7 +11517,7 @@ pushstring(char *s, struct alias *ap)
11483 11517
11484 len = strlen(s); 11518 len = strlen(s);
11485 INT_OFF; 11519 INT_OFF;
11486 if (g_parsefile->strpush) { 11520 if (g_parsefile->strpush || g_parsefile->spfree) {
11487 sp = ckzalloc(sizeof(*sp)); 11521 sp = ckzalloc(sizeof(*sp));
11488 sp->prev = g_parsefile->strpush; 11522 sp->prev = g_parsefile->strpush;
11489 } else { 11523 } else {
@@ -11493,6 +11527,7 @@ pushstring(char *s, struct alias *ap)
11493 sp->prev_string = g_parsefile->next_to_pgetc; 11527 sp->prev_string = g_parsefile->next_to_pgetc;
11494 sp->prev_left_in_line = g_parsefile->left_in_line; 11528 sp->prev_left_in_line = g_parsefile->left_in_line;
11495 sp->unget = g_parsefile->unget; 11529 sp->unget = g_parsefile->unget;
11530 sp->spfree = g_parsefile->spfree;
11496 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc)); 11531 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
11497#if ENABLE_ASH_ALIAS 11532#if ENABLE_ASH_ALIAS
11498 sp->ap = ap; 11533 sp->ap = ap;
@@ -11504,11 +11539,11 @@ pushstring(char *s, struct alias *ap)
11504 g_parsefile->next_to_pgetc = s; 11539 g_parsefile->next_to_pgetc = s;
11505 g_parsefile->left_in_line = len; 11540 g_parsefile->left_in_line = len;
11506 g_parsefile->unget = 0; 11541 g_parsefile->unget = 0;
11542 g_parsefile->spfree = NULL;
11507 INT_ON; 11543 INT_ON;
11508} 11544}
11509 11545
11510static void 11546static void popstring(void)
11511popstring(void)
11512{ 11547{
11513 struct strpush *sp = g_parsefile->strpush; 11548 struct strpush *sp = g_parsefile->strpush;
11514 11549
@@ -11523,10 +11558,6 @@ popstring(void)
11523 if (sp->string != sp->ap->val) { 11558 if (sp->string != sp->ap->val) {
11524 free(sp->string); 11559 free(sp->string);
11525 } 11560 }
11526 sp->ap->flag &= ~ALIASINUSE;
11527 if (sp->ap->flag & ALIASDEAD) {
11528 unalias(sp->ap->name);
11529 }
11530 } 11561 }
11531#endif 11562#endif
11532 g_parsefile->next_to_pgetc = sp->prev_string; 11563 g_parsefile->next_to_pgetc = sp->prev_string;
@@ -11534,8 +11565,7 @@ popstring(void)
11534 g_parsefile->unget = sp->unget; 11565 g_parsefile->unget = sp->unget;
11535 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc)); 11566 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
11536 g_parsefile->strpush = sp->prev; 11567 g_parsefile->strpush = sp->prev;
11537 if (sp != &(g_parsefile->basestrpush)) 11568 g_parsefile->spfree = sp;
11538 free(sp);
11539 INT_ON; 11569 INT_ON;
11540} 11570}
11541 11571
@@ -11628,26 +11658,16 @@ preadfd(void)
11628 */ 11658 */
11629//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) 11659//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
11630#define pgetc_debug(...) ((void)0) 11660#define pgetc_debug(...) ((void)0)
11631static int pgetc(void); 11661static int __pgetc(void);
11632static int 11662static int
11633preadbuffer(void) 11663preadbuffer(void)
11634{ 11664{
11635 char *q; 11665 char *q;
11636 int more; 11666 int more;
11637 11667
11638 if (g_parsefile->strpush) { 11668 if (unlikely(g_parsefile->strpush)) {
11639#if ENABLE_ASH_ALIAS
11640 if (g_parsefile->left_in_line == -1
11641 && g_parsefile->strpush->ap
11642 && g_parsefile->next_to_pgetc[-1] != ' '
11643 && g_parsefile->next_to_pgetc[-1] != '\t'
11644 ) {
11645 pgetc_debug("preadbuffer PEOA");
11646 return PEOA;
11647 }
11648#endif
11649 popstring(); 11669 popstring();
11650 return pgetc(); 11670 return __pgetc();
11651 } 11671 }
11652 /* on both branches above g_parsefile->left_in_line < 0. 11672 /* on both branches above g_parsefile->left_in_line < 0.
11653 * "pgetc" needs refilling. 11673 * "pgetc" needs refilling.
@@ -11729,18 +11749,43 @@ preadbuffer(void)
11729static void 11749static void
11730nlprompt(void) 11750nlprompt(void)
11731{ 11751{
11732 g_parsefile->linno++; 11752 if (trap_depth == 0)
11753 g_parsefile->linno++;
11733 setprompt_if(doprompt, 2); 11754 setprompt_if(doprompt, 2);
11734} 11755}
11735static void 11756static void
11736nlnoprompt(void) 11757nlnoprompt(void)
11737{ 11758{
11738 g_parsefile->linno++; 11759 if (trap_depth == 0)
11760 g_parsefile->linno++;
11739 needprompt = doprompt; 11761 needprompt = doprompt;
11740} 11762}
11741 11763
11742static int 11764static void freestrings(struct strpush *sp)
11743pgetc(void) 11765{
11766 INT_OFF;
11767 do {
11768 struct strpush *psp;
11769
11770 if (sp->ap) {
11771 sp->ap->flag &= ~ALIASINUSE;
11772 if (sp->ap->flag & ALIASDEAD) {
11773 unalias(sp->ap->name);
11774 }
11775 }
11776
11777 psp = sp;
11778 sp = sp->spfree;
11779
11780 if (psp != &(g_parsefile->basestrpush))
11781 free(psp);
11782 } while (sp);
11783
11784 g_parsefile->spfree = NULL;
11785 INT_ON;
11786}
11787
11788static int __pgetc(void)
11744{ 11789{
11745 int c; 11790 int c;
11746 11791
@@ -11762,23 +11807,19 @@ pgetc(void)
11762 return c; 11807 return c;
11763} 11808}
11764 11809
11765#if ENABLE_ASH_ALIAS 11810/*
11766static int 11811 * Read a character from the script, returning PEOF on end of file.
11767pgetc_without_PEOA(void) 11812 * Nul characters in the input are silently discarded.
11813 */
11814static int pgetc(void)
11768{ 11815{
11769 int c; 11816 struct strpush *sp = g_parsefile->spfree;
11770 do { 11817
11771 pgetc_debug("pgetc at %d:%p'%s'", 11818 if (unlikely(sp))
11772 g_parsefile->left_in_line, 11819 freestrings(sp);
11773 g_parsefile->next_to_pgetc, 11820
11774 g_parsefile->next_to_pgetc); 11821 return __pgetc();
11775 c = pgetc();
11776 } while (c == PEOA);
11777 return c;
11778} 11822}
11779#else
11780# define pgetc_without_PEOA() pgetc()
11781#endif
11782 11823
11783/* 11824/*
11784 * Undo a call to pgetc. Only two characters may be pushed back. 11825 * Undo a call to pgetc. Only two characters may be pushed back.
@@ -11855,6 +11896,7 @@ pushfile(void)
11855 pf->prev = g_parsefile; 11896 pf->prev = g_parsefile;
11856 pf->pf_fd = -1; 11897 pf->pf_fd = -1;
11857 /*pf->strpush = NULL; - ckzalloc did it */ 11898 /*pf->strpush = NULL; - ckzalloc did it */
11899 /*pf->spfree = NULL;*/
11858 /*pf->basestrpush.prev = NULL;*/ 11900 /*pf->basestrpush.prev = NULL;*/
11859 /*pf->unget = 0;*/ 11901 /*pf->unget = 0;*/
11860 g_parsefile = pf; 11902 g_parsefile = pf;
@@ -11872,8 +11914,12 @@ popfile(void)
11872 if (pf->pf_fd >= 0) 11914 if (pf->pf_fd >= 0)
11873 close(pf->pf_fd); 11915 close(pf->pf_fd);
11874 free(pf->buf); 11916 free(pf->buf);
11875 while (pf->strpush) 11917 if (g_parsefile->spfree)
11918 freestrings(g_parsefile->spfree);
11919 while (pf->strpush) {
11876 popstring(); 11920 popstring();
11921 freestrings(g_parsefile->spfree);
11922 }
11877 g_parsefile = pf->prev; 11923 g_parsefile = pf->prev;
11878 free(pf); 11924 free(pf);
11879 INT_ON; 11925 INT_ON;
@@ -11969,7 +12015,7 @@ setinputstring(char *string)
11969 g_parsefile->next_to_pgetc = string; 12015 g_parsefile->next_to_pgetc = string;
11970 g_parsefile->left_in_line = strlen(string); 12016 g_parsefile->left_in_line = strlen(string);
11971 g_parsefile->buf = NULL; 12017 g_parsefile->buf = NULL;
11972 g_parsefile->linno = 1; 12018 g_parsefile->linno = lineno;
11973 INT_ON; 12019 INT_ON;
11974} 12020}
11975 12021
@@ -12553,27 +12599,28 @@ static union node *andor(void);
12553static union node *pipeline(void); 12599static union node *pipeline(void);
12554static union node *parse_command(void); 12600static union node *parse_command(void);
12555static void parseheredoc(void); 12601static void parseheredoc(void);
12556static int peektoken(void);
12557static int readtoken(void); 12602static int readtoken(void);
12558 12603
12559static union node * 12604static union node *
12560list(int nlflag) 12605list(int nlflag)
12561{ 12606{
12607 int chknl = nlflag & 1 ? 0 : CHKNL;
12562 union node *n1, *n2, *n3; 12608 union node *n1, *n2, *n3;
12563 int tok; 12609 int tok;
12564 12610
12565 n1 = NULL; 12611 n1 = NULL;
12566 for (;;) { 12612 for (;;) {
12567 switch (readtoken()) { 12613 checkkwd = chknl | CHKKWD | CHKALIAS;
12614 tok = readtoken();
12615 switch (tok) {
12568 case TNL: 12616 case TNL:
12569 if (!(nlflag & 1))
12570 break;
12571 parseheredoc(); 12617 parseheredoc();
12572 return n1; 12618 return n1;
12573 12619
12574 case TEOF: 12620 case TEOF:
12575 if (!n1 && (nlflag & 1)) 12621 if (!n1 && !chknl)
12576 n1 = NODE_EOF; 12622 n1 = NODE_EOF;
12623 out_eof:
12577 parseheredoc(); 12624 parseheredoc();
12578 tokpushback++; 12625 tokpushback++;
12579 lasttoken = TEOF; 12626 lasttoken = TEOF;
@@ -12581,8 +12628,7 @@ list(int nlflag)
12581 } 12628 }
12582 12629
12583 tokpushback++; 12630 tokpushback++;
12584 checkkwd = CHKNL | CHKKWD | CHKALIAS; 12631 if (nlflag == 2 && ((1 << tok) & tokendlist))
12585 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
12586 return n1; 12632 return n1;
12587 nlflag |= 2; 12633 nlflag |= 2;
12588 12634
@@ -12611,15 +12657,16 @@ list(int nlflag)
12611 n1 = n3; 12657 n1 = n3;
12612 } 12658 }
12613 switch (tok) { 12659 switch (tok) {
12614 case TNL:
12615 case TEOF: 12660 case TEOF:
12661 goto out_eof;
12662 case TNL:
12616 tokpushback = 1; 12663 tokpushback = 1;
12617 /* fall through */ 12664 /* fall through */
12618 case TBACKGND: 12665 case TBACKGND:
12619 case TSEMI: 12666 case TSEMI:
12620 break; 12667 break;
12621 default: 12668 default:
12622 if ((nlflag & 1)) 12669 if (!chknl)
12623 raise_error_unexpected_syntax(-1); 12670 raise_error_unexpected_syntax(-1);
12624 tokpushback = 1; 12671 tokpushback = 1;
12625 return n1; 12672 return n1;
@@ -12793,8 +12840,9 @@ simplecmd(void)
12793 switch (t) { 12840 switch (t) {
12794#if BASH_FUNCTION 12841#if BASH_FUNCTION
12795 case TFUNCTION: 12842 case TFUNCTION:
12796 if (peektoken() != TWORD) 12843 if (readtoken() != TWORD)
12797 raise_error_unexpected_syntax(TWORD); 12844 raise_error_unexpected_syntax(TWORD);
12845 tokpushback = 1;
12798 function_flag = 1; 12846 function_flag = 1;
12799 break; 12847 break;
12800#endif 12848#endif
@@ -12831,7 +12879,9 @@ simplecmd(void)
12831#if BASH_FUNCTION 12879#if BASH_FUNCTION
12832 if (function_flag) { 12880 if (function_flag) {
12833 checkkwd = CHKNL | CHKKWD; 12881 checkkwd = CHKNL | CHKKWD;
12834 switch (peektoken()) { 12882 t = readtoken();
12883 tokpushback = 1;
12884 switch (t) {
12835 case TBEGIN: 12885 case TBEGIN:
12836 case TIF: 12886 case TIF:
12837 case TCASE: 12887 case TCASE:
@@ -13184,7 +13234,7 @@ static int
13184readtoken1(int c, int syntax, char *eofmark, int striptabs) 13234readtoken1(int c, int syntax, char *eofmark, int striptabs)
13185{ 13235{
13186 /* NB: syntax parameter fits into smallint */ 13236 /* NB: syntax parameter fits into smallint */
13187 /* c parameter is an unsigned char or PEOF or PEOA */ 13237 /* c parameter is an unsigned char or PEOF */
13188 char *out; 13238 char *out;
13189 size_t len; 13239 size_t len;
13190 struct nodelist *bqlist; 13240 struct nodelist *bqlist;
@@ -13254,7 +13304,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
13254 USTPUTC(c, out); 13304 USTPUTC(c, out);
13255 break; 13305 break;
13256 case CBACK: /* backslash */ 13306 case CBACK: /* backslash */
13257 c = pgetc_without_PEOA(); 13307 c = pgetc();
13258 if (c == PEOF) { 13308 if (c == PEOF) {
13259 USTPUTC(CTLESC, out); 13309 USTPUTC(CTLESC, out);
13260 USTPUTC('\\', out); 13310 USTPUTC('\\', out);
@@ -13361,8 +13411,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
13361 break; 13411 break;
13362 case CENDFILE: 13412 case CENDFILE:
13363 goto endword; /* exit outer loop */ 13413 goto endword; /* exit outer loop */
13364 case CIGN:
13365 break;
13366 default: 13414 default:
13367 if (synstack->varnest == 0) { 13415 if (synstack->varnest == 0) {
13368#if BASH_REDIR_OUTPUT 13416#if BASH_REDIR_OUTPUT
@@ -13384,8 +13432,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
13384#endif 13432#endif
13385 goto endword; /* exit outer loop */ 13433 goto endword; /* exit outer loop */
13386 } 13434 }
13387 IF_ASH_ALIAS(if (c != PEOA)) 13435 USTPUTC(c, out);
13388 USTPUTC(c, out);
13389 } 13436 }
13390 c = pgetc_top(synstack); 13437 c = pgetc_top(synstack);
13391 } /* for (;;) */ 13438 } /* for (;;) */
@@ -13436,14 +13483,9 @@ checkend: {
13436 int markloc; 13483 int markloc;
13437 char *p; 13484 char *p;
13438 13485
13439#if ENABLE_ASH_ALIAS
13440 if (c == PEOA)
13441 c = pgetc_without_PEOA();
13442#endif
13443 if (striptabs) { 13486 if (striptabs) {
13444 while (c == '\t') { 13487 while (c == '\t')
13445 c = pgetc_without_PEOA(); 13488 c = pgetc();
13446 }
13447 } 13489 }
13448 13490
13449 markloc = out - (char *)stackblock(); 13491 markloc = out - (char *)stackblock();
@@ -13457,12 +13499,13 @@ checkend: {
13457 * F 13499 * F
13458 * (see heredoc_bkslash_newline2.tests) 13500 * (see heredoc_bkslash_newline2.tests)
13459 */ 13501 */
13460 c = pgetc_without_PEOA(); 13502 c = pgetc();
13461 } 13503 }
13462 13504
13463 if (c == '\n' || c == PEOF) { 13505 if (c == '\n' || c == PEOF) {
13464 c = PEOF; 13506 c = PEOF;
13465 g_parsefile->linno++; 13507 if (trap_depth == 0)
13508 g_parsefile->linno++;
13466 needprompt = doprompt; 13509 needprompt = doprompt;
13467 } else { 13510 } else {
13468 int len_here; 13511 int len_here;
@@ -13581,7 +13624,6 @@ parsesub: {
13581 13624
13582 c = pgetc_eatbnl(); 13625 c = pgetc_eatbnl();
13583 if ((checkkwd & CHKEOFMARK) 13626 if ((checkkwd & CHKEOFMARK)
13584 || c > 255 /* PEOA or PEOF */
13585 || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 13627 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
13586 ) { 13628 ) {
13587#if BASH_DOLLAR_SQUOTE 13629#if BASH_DOLLAR_SQUOTE
@@ -13604,7 +13646,7 @@ parsesub: {
13604 PARSEBACKQNEW(); 13646 PARSEBACKQNEW();
13605 } 13647 }
13606 } else { 13648 } else {
13607 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ 13649 /* $VAR, $<specialchar>, ${...}, or PEOF */
13608 smalluint newsyn = synstack->syntax; 13650 smalluint newsyn = synstack->syntax;
13609 13651
13610 USTPUTC(CTLVAR, out); 13652 USTPUTC(CTLVAR, out);
@@ -13799,13 +13841,9 @@ parsebackq: {
13799 ) { 13841 ) {
13800 STPUTC('\\', pout); 13842 STPUTC('\\', pout);
13801 } 13843 }
13802 if (pc <= 255 /* not PEOA or PEOF */) { 13844 break;
13803 break;
13804 }
13805 /* fall through */
13806 13845
13807 case PEOF: 13846 case PEOF:
13808 IF_ASH_ALIAS(case PEOA:)
13809 raise_error_syntax("EOF in backquote substitution"); 13847 raise_error_syntax("EOF in backquote substitution");
13810 13848
13811 case '\n': 13849 case '\n':
@@ -13940,7 +13978,7 @@ xxreadtoken(void)
13940 setprompt_if(needprompt, 2); 13978 setprompt_if(needprompt, 2);
13941 for (;;) { /* until token or start of word found */ 13979 for (;;) { /* until token or start of word found */
13942 c = pgetc_eatbnl(); 13980 c = pgetc_eatbnl();
13943 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 13981 if (c == ' ' || c == '\t')
13944 continue; 13982 continue;
13945 13983
13946 if (c == '#') { 13984 if (c == '#') {
@@ -13998,7 +14036,6 @@ xxreadtoken(void)
13998 c = pgetc_eatbnl(); 14036 c = pgetc_eatbnl();
13999 switch (c) { 14037 switch (c) {
14000 case ' ': case '\t': 14038 case ' ': case '\t':
14001 IF_ASH_ALIAS(case PEOA:)
14002 continue; 14039 continue;
14003 case '#': 14040 case '#':
14004 while ((c = pgetc()) != '\n' && c != PEOF) 14041 while ((c = pgetc()) != '\n' && c != PEOF)
@@ -14058,10 +14095,14 @@ readtoken(void)
14058 if (kwd & CHKNL) { 14095 if (kwd & CHKNL) {
14059 while (t == TNL) { 14096 while (t == TNL) {
14060 parseheredoc(); 14097 parseheredoc();
14098 checkkwd = 0;
14061 t = xxreadtoken(); 14099 t = xxreadtoken();
14062 } 14100 }
14063 } 14101 }
14064 14102
14103 kwd |= checkkwd;
14104 checkkwd = 0;
14105
14065 if (t != TWORD || quoteflag) { 14106 if (t != TWORD || quoteflag) {
14066 goto out; 14107 goto out;
14067 } 14108 }
@@ -14080,7 +14121,7 @@ readtoken(void)
14080 } 14121 }
14081 } 14122 }
14082 14123
14083 if (checkkwd & CHKALIAS) { 14124 if (kwd & CHKALIAS) {
14084#if ENABLE_ASH_ALIAS 14125#if ENABLE_ASH_ALIAS
14085 struct alias *ap; 14126 struct alias *ap;
14086 ap = lookupalias(wordtext, 1); 14127 ap = lookupalias(wordtext, 1);
@@ -14093,7 +14134,6 @@ readtoken(void)
14093#endif 14134#endif
14094 } 14135 }
14095 out: 14136 out:
14096 checkkwd = 0;
14097#if DEBUG 14137#if DEBUG
14098 if (!alreadyseen) 14138 if (!alreadyseen)
14099 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : "")); 14139 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
@@ -14103,16 +14143,6 @@ readtoken(void)
14103 return t; 14143 return t;
14104} 14144}
14105 14145
14106static int
14107peektoken(void)
14108{
14109 int t;
14110
14111 t = readtoken();
14112 tokpushback = 1;
14113 return t;
14114}
14115
14116/* 14146/*
14117 * Read and parse a command. Returns NODE_EOF on end of file. 14147 * Read and parse a command. Returns NODE_EOF on end of file.
14118 * (NULL is a valid parse tree indicating a blank line.) 14148 * (NULL is a valid parse tree indicating a blank line.)
@@ -14162,23 +14192,26 @@ parseheredoc(void)
14162static const char * 14192static const char *
14163expandstr(const char *ps, int syntax_type) 14193expandstr(const char *ps, int syntax_type)
14164{ 14194{
14165 union node n; 14195 struct parsefile *file_stop;
14196 struct jmploc *volatile savehandler;
14197 struct heredoc *saveheredoclist;
14198 const char *result;
14166 int saveprompt; 14199 int saveprompt;
14167 struct parsefile *file_stop = g_parsefile;
14168 volatile int saveint;
14169 struct jmploc *volatile savehandler = exception_handler;
14170 struct jmploc jmploc; 14200 struct jmploc jmploc;
14171 const char *volatile result; 14201 union node n;
14172 int err; 14202 int err;
14173 14203
14204 file_stop = g_parsefile;
14205
14174 /* XXX Fix (char *) cast. */ 14206 /* XXX Fix (char *) cast. */
14175 setinputstring((char *)ps); 14207 setinputstring((char *)ps);
14176 14208
14209 saveheredoclist = heredoclist;
14210 heredoclist = NULL;
14177 saveprompt = doprompt; 14211 saveprompt = doprompt;
14178 doprompt = 0; 14212 doprompt = 0;
14179 result = ps; 14213 result = ps;
14180 14214 savehandler = exception_handler;
14181 SAVE_INT(saveint);
14182 err = setjmp(jmploc.loc); 14215 err = setjmp(jmploc.loc);
14183 if (err) 14216 if (err)
14184 goto out; 14217 goto out;
@@ -14188,7 +14221,7 @@ expandstr(const char *ps, int syntax_type)
14188 * PS1='$(date "+%H:%M:%S) > ' 14221 * PS1='$(date "+%H:%M:%S) > '
14189 */ 14222 */
14190 exception_handler = &jmploc; 14223 exception_handler = &jmploc;
14191 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); 14224 readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0);
14192 14225
14193 n.narg.type = NARG; 14226 n.narg.type = NARG;
14194 n.narg.next = NULL; 14227 n.narg.next = NULL;
@@ -14205,11 +14238,11 @@ out:
14205 exception_handler = savehandler; 14238 exception_handler = savehandler;
14206 if (err && exception_type != EXERROR) 14239 if (err && exception_type != EXERROR)
14207 longjmp(exception_handler->loc, 1); 14240 longjmp(exception_handler->loc, 1);
14208 RESTORE_INT(saveint);
14209 14241
14210 doprompt = saveprompt; 14242 doprompt = saveprompt;
14211 /* Try: PS1='`xxx(`' */ 14243 /* Try: PS1='`xxx(`' */
14212 unwindfiles(file_stop); 14244 unwindfiles(file_stop);
14245 heredoclist = saveheredoclist;
14213 14246
14214 return result; 14247 return result;
14215} 14248}
@@ -14329,9 +14362,6 @@ cmdloop(int top)
14329 if (doing_jobctl) 14362 if (doing_jobctl)
14330 showjobs(SHOW_CHANGED|SHOW_STDERR); 14363 showjobs(SHOW_CHANGED|SHOW_STDERR);
14331#endif 14364#endif
14332#if BASH_PROCESS_SUBST
14333 unwindredir(NULL);
14334#endif
14335 inter = 0; 14365 inter = 0;
14336 if (iflag && top) { 14366 if (iflag && top) {
14337 inter++; 14367 inter++;
@@ -14355,7 +14385,7 @@ cmdloop(int top)
14355 out2str("\nUse \"exit\" to leave shell.\n"); 14385 out2str("\nUse \"exit\" to leave shell.\n");
14356 } 14386 }
14357 numeof++; 14387 numeof++;
14358 } else if (nflag == 0) { 14388 } else {
14359 int i; 14389 int i;
14360 14390
14361#if !ENABLE_PLATFORM_MINGW32 14391#if !ENABLE_PLATFORM_MINGW32
@@ -14746,7 +14776,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14746 nextopt(nullstr); 14776 nextopt(nullstr);
14747 ap = argptr; 14777 ap = argptr;
14748 if (!*ap) { 14778 if (!*ap) {
14749 for (signo = 0; signo < NSIG; signo++) { 14779 for (signo = 0; signo <= NTRAP_LAST; signo++) {
14750 char *tr = trap_ptr[signo]; 14780 char *tr = trap_ptr[signo];
14751 if (tr) { 14781 if (tr) {
14752 /* note: bash adds "SIG", but only if invoked 14782 /* note: bash adds "SIG", but only if invoked
@@ -14755,7 +14785,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14755 * We are printing short names: */ 14785 * We are printing short names: */
14756 out1fmt("trap -- %s %s\n", 14786 out1fmt("trap -- %s %s\n",
14757 single_quote(tr), 14787 single_quote(tr),
14758 get_signame(signo)); 14788 (signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
14759 /* trap_ptr != trap only if we are in special-cased `trap` code. 14789 /* trap_ptr != trap only if we are in special-cased `trap` code.
14760 * In this case, we will exit very soon, no need to free(). */ 14790 * In this case, we will exit very soon, no need to free(). */
14761 /* if (trap_ptr != trap && tp[0]) */ 14791 /* if (trap_ptr != trap && tp[0]) */
@@ -14781,7 +14811,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14781 14811
14782 exitcode = 0; 14812 exitcode = 0;
14783 while (*ap) { 14813 while (*ap) {
14784 signo = get_signum(*ap); 14814 signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
14785 if (signo < 0) { 14815 if (signo < 0) {
14786 /* Mimic bash message exactly */ 14816 /* Mimic bash message exactly */
14787 ash_msg("%s: invalid signal specification", *ap); 14817 ash_msg("%s: invalid signal specification", *ap);
@@ -14802,7 +14832,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14802 } 14832 }
14803 free(trap[signo]); 14833 free(trap[signo]);
14804 trap[signo] = action; 14834 trap[signo] = action;
14805 if (signo != 0) 14835 if (signo != 0 && signo < NSIG)
14806 setsignal(signo); 14836 setsignal(signo);
14807 INT_ON; 14837 INT_ON;
14808 next: 14838 next:
@@ -15197,6 +15227,7 @@ exitreset(void)
15197 } 15227 }
15198 evalskip = 0; 15228 evalskip = 0;
15199 loopnest = 0; 15229 loopnest = 0;
15230 inps4 = 0;
15200 15231
15201 /* from expand.c: */ 15232 /* from expand.c: */
15202 ifsfree(); 15233 ifsfree();
@@ -15244,7 +15275,9 @@ exitshell(void)
15244 if (p) { 15275 if (p) {
15245 trap[0] = NULL; 15276 trap[0] = NULL;
15246 evalskip = 0; 15277 evalskip = 0;
15278 trap_depth++;
15247 evalstring(p, 0); 15279 evalstring(p, 0);
15280 trap_depth--;
15248 evalskip = SKIPFUNCDEF; 15281 evalskip = SKIPFUNCDEF;
15249 /*free(p); - we'll exit soon */ 15282 /*free(p); - we'll exit soon */
15250 } 15283 }
@@ -15704,6 +15737,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15704 // ^^ not necessary since now we special-case fd 0 15737 // ^^ not necessary since now we special-case fd 0
15705 // in save_fd_on_redirect() 15738 // in save_fd_on_redirect()
15706 15739
15740 lineno = 0; // bash compat
15707 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT); 15741 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
15708 // The above makes 15742 // The above makes
15709 // ash -sc 'echo $-' 15743 // ash -sc 'echo $-'
diff --git a/shell/ash_test/ash-alias/alias_brace.right b/shell/ash_test/ash-alias/alias_brace.right
new file mode 100644
index 000000000..7326d9603
--- /dev/null
+++ b/shell/ash_test/ash-alias/alias_brace.right
@@ -0,0 +1 @@
Ok
diff --git a/shell/ash_test/ash-alias/alias_brace.tests b/shell/ash_test/ash-alias/alias_brace.tests
new file mode 100755
index 000000000..7571b64ac
--- /dev/null
+++ b/shell/ash_test/ash-alias/alias_brace.tests
@@ -0,0 +1,16 @@
1# Note: bash would need:
2#shopt -s expand_aliases
3# to enable aliases in non-interactive mode
4alias BEGIN={ END=}
5BEGIN
6 cat <<- EOF > /dev/null
7 $(:)
8 EOF
9END
10
11: <<- EOF &&
12 $(:)
13EOF
14BEGIN
15 echo Ok
16END
diff --git a/shell/ash_test/ash-alias/alias_case.right b/shell/ash_test/ash-alias/alias_case.right
new file mode 100644
index 000000000..7326d9603
--- /dev/null
+++ b/shell/ash_test/ash-alias/alias_case.right
@@ -0,0 +1 @@
Ok
diff --git a/shell/ash_test/ash-alias/alias_case.tests b/shell/ash_test/ash-alias/alias_case.tests
new file mode 100755
index 000000000..ed8275875
--- /dev/null
+++ b/shell/ash_test/ash-alias/alias_case.tests
@@ -0,0 +1,8 @@
1# Note: bash would need:
2#shopt -s expand_aliases
3# to enable aliases in non-interactive mode
4alias a="case x in " b=x
5a
6b) echo BAD;;
7*) echo Ok;;
8esac
diff --git a/shell/ash_test/ash-misc/control_char3.right b/shell/ash_test/ash-misc/control_char3.right
index 283e02cbb..654005d24 100644
--- a/shell/ash_test/ash-misc/control_char3.right
+++ b/shell/ash_test/ash-misc/control_char3.right
@@ -1 +1 @@
SHELL: line 1: : not found SHELL: line 0: : not found
diff --git a/shell/ash_test/ash-misc/control_char4.right b/shell/ash_test/ash-misc/control_char4.right
index 2bf18e684..ec9d5fc98 100644
--- a/shell/ash_test/ash-misc/control_char4.right
+++ b/shell/ash_test/ash-misc/control_char4.right
@@ -1 +1 @@
SHELL: line 1: -: not found SHELL: line 0: -: not found
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.right b/shell/ash_test/ash-misc/exitcode_trap7.right
new file mode 100644
index 000000000..07d66e9d9
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap7.right
@@ -0,0 +1,2 @@
1Start
2Ok:0
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.tests b/shell/ash_test/ash-misc/exitcode_trap7.tests
new file mode 100755
index 000000000..f4b0eb544
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap7.tests
@@ -0,0 +1,7 @@
1$THIS_SH -c '
2cleanup() { set +e; false; }
3set -e
4trap cleanup EXIT
5echo Start
6'
7echo Ok:$?
diff --git a/shell/ash_test/ash-misc/set-n1.right b/shell/ash_test/ash-misc/set-n1.right
new file mode 100644
index 000000000..ac01831a7
--- /dev/null
+++ b/shell/ash_test/ash-misc/set-n1.right
@@ -0,0 +1,3 @@
1set -n stops in -c?
2YES
3Ok:0
diff --git a/shell/ash_test/ash-misc/set-n1.tests b/shell/ash_test/ash-misc/set-n1.tests
new file mode 100755
index 000000000..90d0f9146
--- /dev/null
+++ b/shell/ash_test/ash-misc/set-n1.tests
@@ -0,0 +1,2 @@
1$THIS_SH -c "echo 'set -n stops in -c?'; set -n; echo NO" && echo YES
2echo Ok:$?
diff --git a/shell/ash_test/ash-misc/shift1.right b/shell/ash_test/ash-misc/shift1.right
index b53453c3a..fdba79fd3 100644
--- a/shell/ash_test/ash-misc/shift1.right
+++ b/shell/ash_test/ash-misc/shift1.right
@@ -1,5 +1,5 @@
12 3 4 12 3 4
20: shift: line 1: Illegal number: -1 20: shift: line 0: Illegal number: -1
31 2 3 4 31 2 3 4
42 3 4 42 3 4
53 4 53 4
diff --git a/shell/ash_test/ash-misc/tickquote1.right b/shell/ash_test/ash-misc/tickquote1.right
index 2e661bfe3..e55a31c2d 100644
--- a/shell/ash_test/ash-misc/tickquote1.right
+++ b/shell/ash_test/ash-misc/tickquote1.right
@@ -1 +1 @@
./tickquote1.tests: line 1: syntax error: unterminated quoted string ./tickquote1.tests: line 0: syntax error: unterminated quoted string
diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.right b/shell/ash_test/ash-parsing/groups_and_keywords2.right
index 3fcbeb662..2ce38fe6e 100644
--- a/shell/ash_test/ash-parsing/groups_and_keywords2.right
+++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right
@@ -1,3 +1,3 @@
1./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")" 1./groups_and_keywords2.tests: eval: line 2: syntax error: unexpected ")"
2Fail:2 2Fail:2
3./groups_and_keywords2.tests: line 8: syntax error: unexpected ")" 3./groups_and_keywords2.tests: line 8: syntax error: unexpected ")"
diff --git a/shell/ash_test/ash-psubst/emptytick.right b/shell/ash_test/ash-psubst/emptytick.right
index 459c4f735..8fe9839ca 100644
--- a/shell/ash_test/ash-psubst/emptytick.right
+++ b/shell/ash_test/ash-psubst/emptytick.right
@@ -1,8 +1,8 @@
10 10
20 20
3./emptytick.tests: line 1: : Permission denied 3./emptytick.tests: line 2: : Permission denied
4127 4127
5./emptytick.tests: line 1: : Permission denied 5./emptytick.tests: line 3: : Permission denied
6127 6127
70 70
80 80
diff --git a/shell/ash_test/ash-vars/param_expand_alt.right b/shell/ash_test/ash-vars/param_expand_alt.right
index 1303f8064..d10f1206f 100644
--- a/shell/ash_test/ash-vars/param_expand_alt.right
+++ b/shell/ash_test/ash-vars/param_expand_alt.right
@@ -1,5 +1,5 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
2SHELL: line 1: syntax error: bad substitution 2SHELL: line 0: syntax error: bad substitution
3__ 3__
4_z_ _z_ 4_z_ _z_
5_ _ _ _ _ 5_ _ _ _ _
diff --git a/shell/ash_test/ash-vars/param_expand_assign.right b/shell/ash_test/ash-vars/param_expand_assign.right
index 6e9ea1379..52eaef9f8 100644
--- a/shell/ash_test/ash-vars/param_expand_assign.right
+++ b/shell/ash_test/ash-vars/param_expand_assign.right
@@ -1,11 +1,11 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
2SHELL: line 1: syntax error: bad substitution 2SHELL: line 0: syntax error: bad substitution
3SHELL: line 1: syntax error: bad substitution 3SHELL: line 0: syntax error: bad substitution
40 40
5SHELL: line 1: 1: bad variable name 5SHELL: line 0: 1: bad variable name
6SHELL: line 1: 1: bad variable name 6SHELL: line 0: 1: bad variable name
7SHELL: line 1: 1: bad variable name 7SHELL: line 0: 1: bad variable name
8SHELL: line 1: 1: bad variable name 8SHELL: line 0: 1: bad variable name
9_aa 9_aa
10_aa 10_aa
11_aa 11_aa
diff --git a/shell/ash_test/ash-vars/param_expand_bash_substring.right b/shell/ash_test/ash-vars/param_expand_bash_substring.right
index 687dd9002..22a0b2881 100644
--- a/shell/ash_test/ash-vars/param_expand_bash_substring.right
+++ b/shell/ash_test/ash-vars/param_expand_bash_substring.right
@@ -1,8 +1,8 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
2SHELL: line 1: syntax error: bad substitution 2SHELL: line 0: syntax error: bad substitution
3SHELL: line 1: syntax error: bad substitution 3SHELL: line 0: syntax error: bad substitution
4SHELL: line 1: syntax error: bad substitution 4SHELL: line 0: syntax error: bad substitution
5SHELL: line 1: syntax error: missing '}' 5SHELL: line 0: syntax error: missing '}'
60 60
71 =|| 71 =||
81:1 =|| 81:1 =||
diff --git a/shell/ash_test/ash-vars/param_expand_default.right b/shell/ash_test/ash-vars/param_expand_default.right
index 7a42f67e8..0852105ca 100644
--- a/shell/ash_test/ash-vars/param_expand_default.right
+++ b/shell/ash_test/ash-vars/param_expand_default.right
@@ -1,4 +1,4 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
2_0 _0 2_0 _0
3_ _ _ _word _word 3_ _ _ _word _word
4_aaaa _aaaa _aaaa _aaaa _aaaa 4_aaaa _aaaa _aaaa _aaaa _aaaa
diff --git a/shell/ash_test/ash-vars/param_expand_indicate_error.right b/shell/ash_test/ash-vars/param_expand_indicate_error.right
index 33afacee0..53ea07181 100644
--- a/shell/ash_test/ash-vars/param_expand_indicate_error.right
+++ b/shell/ash_test/ash-vars/param_expand_indicate_error.right
@@ -1,14 +1,14 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
21 21
30 30
4==== 4====
5_ 5_
6SHELL: line 1: 1: parameter not set 6SHELL: line 0: 1: parameter not set
7SHELL: line 1: 1: parameter not set or null 7SHELL: line 0: 1: parameter not set or null
8SHELL: line 1: 1: message1 8SHELL: line 0: 1: message1
9SHELL: line 1: 1: message1 9SHELL: line 0: 1: message1
10SHELL: line 1: 1: unset! 10SHELL: line 0: 1: unset!
11SHELL: line 1: 1: null or unset! 11SHELL: line 0: 1: null or unset!
12==== 12====
13_aaaa 13_aaaa
14_aaaa 14_aaaa
@@ -19,20 +19,20 @@ _aaaa
19_aaaa 19_aaaa
20==== 20====
21_ 21_
22SHELL: line 1: f: parameter not set 22SHELL: line 0: f: parameter not set
23SHELL: line 1: f: parameter not set or null 23SHELL: line 0: f: parameter not set or null
24SHELL: line 1: f: message3 24SHELL: line 0: f: message3
25SHELL: line 1: f: message3 25SHELL: line 0: f: message3
26SHELL: line 1: f: unset! 26SHELL: line 0: f: unset!
27SHELL: line 1: f: null or unset! 27SHELL: line 0: f: null or unset!
28==== 28====
29_ 29_
30_ 30_
31SHELL: line 1: f: parameter not set or null 31SHELL: line 0: f: parameter not set or null
32_ 32_
33SHELL: line 1: f: message4 33SHELL: line 0: f: message4
34_ 34_
35SHELL: line 1: f: null or unset! 35SHELL: line 0: f: null or unset!
36==== 36====
37_fff 37_fff
38_fff 38_fff
diff --git a/shell/ash_test/ash-vars/var6.right b/shell/ash_test/ash-vars/var6.right
index b37417fa1..e83f7b5eb 100644
--- a/shell/ash_test/ash-vars/var6.right
+++ b/shell/ash_test/ash-vars/var6.right
@@ -1,2 +1,2 @@
1SHELL: line 1: syntax error: bad substitution 1SHELL: line 0: syntax error: bad substitution
2SHELL: line 1: syntax error: bad substitution 2SHELL: line 0: syntax error: bad substitution
diff --git a/shell/ash_test/ash-vars/var_LINENO2.right b/shell/ash_test/ash-vars/var_LINENO2.right
new file mode 100644
index 000000000..73656647c
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO2.right
@@ -0,0 +1,3 @@
1Start LINENO=6, calling function
2In function: LINENO=4
3After function: LINENO=8
diff --git a/shell/ash_test/ash-vars/var_LINENO2.tests b/shell/ash_test/ash-vars/var_LINENO2.tests
new file mode 100755
index 000000000..7036dbdc8
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO2.tests
@@ -0,0 +1,8 @@
1#skip lines: make "line number within function" differ from overall line number
2#skip lines
3f() {
4 echo "In function: LINENO=$LINENO"
5}
6echo "Start LINENO=$LINENO, calling function"
7f
8echo "After function: LINENO=$LINENO"
diff --git a/shell/ash_test/ash-vars/var_LINENO3.right b/shell/ash_test/ash-vars/var_LINENO3.right
new file mode 100644
index 000000000..198c3cc99
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO3.right
@@ -0,0 +1,2 @@
1LINENO starts from 0 in -c
2and increments on next line: 1
diff --git a/shell/ash_test/ash-vars/var_LINENO3.tests b/shell/ash_test/ash-vars/var_LINENO3.tests
new file mode 100755
index 000000000..4502edfe0
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO3.tests
@@ -0,0 +1,2 @@
1$THIS_SH -c 'echo "LINENO starts from $LINENO in -c"
2echo "and increments on next line: $LINENO"'
diff --git a/shell/ash_test/run-all b/shell/ash_test/run-all
index caf033577..96703ef12 100755
--- a/shell/ash_test/run-all
+++ b/shell/ash_test/run-all
@@ -1,5 +1,14 @@
1#!/bin/sh 1#!/bin/sh
2 2
3unset LANG LANGUAGE
4unset LC_COLLATE
5unset LC_CTYPE
6unset LC_MONETARY
7unset LC_MESSAGES
8unset LC_NUMERIC
9unset LC_TIME
10unset LC_ALL
11
3TOPDIR=`pwd` 12TOPDIR=`pwd`
4 13
5if test ! -x ash; then 14if test ! -x ash; then
@@ -61,11 +70,12 @@ do_test()
61# echo Running test: "$x" 70# echo Running test: "$x"
62 echo -n "$1/$x:" 71 echo -n "$1/$x:"
63 { 72 {
64 "$THIS_SH" "./$x" >"$name.xx" 2>&1 73 "$THIS_SH" "./$x" 2>&1 | \
74 grep -va "^ash: using fallback suid method$" >"$name.xx"
65 diff -u "$name.xx" "$name.right" >"$TOPDIR/$noslash-$x.fail" \ 75 diff -u "$name.xx" "$name.right" >"$TOPDIR/$noslash-$x.fail" \
66 && rm -f "$name.xx" "$TOPDIR/$noslash-$x.fail" 76 && rm -f "$name.xx" "$TOPDIR/$noslash-$x.fail"
67 } && echo " ok" || echo " fail" 77 } && echo " ok" || echo " fail"
68 done 78 done
69 ) 79 )
70} 80}
71 81
diff --git a/shell/hush.c b/shell/hush.c
index 27092c12f..6d472337f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2753,6 +2753,12 @@ static int i_getch(struct in_str *i)
2753 if (ch != '\0') { 2753 if (ch != '\0') {
2754 i->p++; 2754 i->p++;
2755 i->last_char = ch; 2755 i->last_char = ch;
2756#if ENABLE_HUSH_LINENO_VAR
2757 if (ch == '\n') {
2758 G.parse_lineno++;
2759 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
2760 }
2761#endif
2756 return ch; 2762 return ch;
2757 } 2763 }
2758 return EOF; 2764 return EOF;
@@ -7540,11 +7546,11 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
7540static void parse_and_run_string(const char *s) 7546static void parse_and_run_string(const char *s)
7541{ 7547{
7542 struct in_str input; 7548 struct in_str input;
7543 //IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;) 7549 IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
7544 7550
7545 setup_string_in_str(&input, s); 7551 setup_string_in_str(&input, s);
7546 parse_and_run_stream(&input, '\0'); 7552 parse_and_run_stream(&input, '\0');
7547 //IF_HUSH_LINENO_VAR(G.parse_lineno = sv;) 7553 IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
7548} 7554}
7549 7555
7550static void parse_and_run_file(HFILE *fp) 7556static void parse_and_run_file(HFILE *fp)
@@ -9898,7 +9904,8 @@ static int run_list(struct pipe *pi)
9898#if ENABLE_HUSH_LOOPS 9904#if ENABLE_HUSH_LOOPS
9899 G.flag_break_continue = 0; 9905 G.flag_break_continue = 0;
9900#endif 9906#endif
9901 rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */ 9907 rcode = r = G.o_opt[OPT_O_NOEXEC] ? 0 : run_pipe(pi);
9908 /* NB: rcode is a smalluint, r is int */
9902 if (r != -1) { 9909 if (r != -1) {
9903 /* We ran a builtin, function, or group. 9910 /* We ran a builtin, function, or group.
9904 * rcode is already known 9911 * rcode is already known
@@ -10137,7 +10144,10 @@ static int set_mode(int state, char mode, const char *o_opt)
10137 int idx; 10144 int idx;
10138 switch (mode) { 10145 switch (mode) {
10139 case 'n': 10146 case 'n':
10140 G.o_opt[OPT_O_NOEXEC] = state; 10147 /* set -n has no effect in interactive shell */
10148 /* Try: while set -n; do echo $-; done */
10149 if (!G_interactive_fd)
10150 G.o_opt[OPT_O_NOEXEC] = state;
10141 break; 10151 break;
10142 case 'x': 10152 case 'x':
10143 IF_HUSH_MODE_X(G_x_mode = state;) 10153 IF_HUSH_MODE_X(G_x_mode = state;)
diff --git a/shell/hush_test/hush-misc/exitcode_trap7.right b/shell/hush_test/hush-misc/exitcode_trap7.right
new file mode 100644
index 000000000..07d66e9d9
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap7.right
@@ -0,0 +1,2 @@
1Start
2Ok:0
diff --git a/shell/hush_test/hush-misc/exitcode_trap7.tests b/shell/hush_test/hush-misc/exitcode_trap7.tests
new file mode 100755
index 000000000..f4b0eb544
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap7.tests
@@ -0,0 +1,7 @@
1$THIS_SH -c '
2cleanup() { set +e; false; }
3set -e
4trap cleanup EXIT
5echo Start
6'
7echo Ok:$?
diff --git a/shell/hush_test/hush-misc/set-n1.right b/shell/hush_test/hush-misc/set-n1.right
new file mode 100644
index 000000000..ac01831a7
--- /dev/null
+++ b/shell/hush_test/hush-misc/set-n1.right
@@ -0,0 +1,3 @@
1set -n stops in -c?
2YES
3Ok:0
diff --git a/shell/hush_test/hush-misc/set-n1.tests b/shell/hush_test/hush-misc/set-n1.tests
new file mode 100755
index 000000000..90d0f9146
--- /dev/null
+++ b/shell/hush_test/hush-misc/set-n1.tests
@@ -0,0 +1,2 @@
1$THIS_SH -c "echo 'set -n stops in -c?'; set -n; echo NO" && echo YES
2echo Ok:$?
diff --git a/shell/hush_test/hush-vars/var_LINENO2.right b/shell/hush_test/hush-vars/var_LINENO2.right
new file mode 100644
index 000000000..73656647c
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_LINENO2.right
@@ -0,0 +1,3 @@
1Start LINENO=6, calling function
2In function: LINENO=4
3After function: LINENO=8
diff --git a/shell/hush_test/hush-vars/var_LINENO2.tests b/shell/hush_test/hush-vars/var_LINENO2.tests
new file mode 100755
index 000000000..7036dbdc8
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_LINENO2.tests
@@ -0,0 +1,8 @@
1#skip lines: make "line number within function" differ from overall line number
2#skip lines
3f() {
4 echo "In function: LINENO=$LINENO"
5}
6echo "Start LINENO=$LINENO, calling function"
7f
8echo "After function: LINENO=$LINENO"
diff --git a/shell/hush_test/hush-vars/var_LINENO3.right b/shell/hush_test/hush-vars/var_LINENO3.right
new file mode 100644
index 000000000..198c3cc99
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_LINENO3.right
@@ -0,0 +1,2 @@
1LINENO starts from 0 in -c
2and increments on next line: 1
diff --git a/shell/hush_test/hush-vars/var_LINENO3.tests b/shell/hush_test/hush-vars/var_LINENO3.tests
new file mode 100755
index 000000000..4502edfe0
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_LINENO3.tests
@@ -0,0 +1,2 @@
1$THIS_SH -c 'echo "LINENO starts from $LINENO in -c"
2echo "and increments on next line: $LINENO"'