aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c251
1 files changed, 147 insertions, 104 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 5ec035043..35438a887 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -204,7 +204,6 @@
204 204
205#define JOBS ENABLE_ASH_JOB_CONTROL 205#define JOBS ENABLE_ASH_JOB_CONTROL
206 206
207#include <setjmp.h>
208#include <fnmatch.h> 207#include <fnmatch.h>
209#include <sys/times.h> 208#include <sys/times.h>
210#include <sys/utsname.h> /* for setting $HOSTNAME */ 209#include <sys/utsname.h> /* for setting $HOSTNAME */
@@ -5755,7 +5754,7 @@ openredirect(union node *redir)
5755 f = open(fname, O_WRONLY, 0666); 5754 f = open(fname, O_WRONLY, 0666);
5756 if (f < 0) 5755 if (f < 0)
5757 goto ecreate; 5756 goto ecreate;
5758 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) { 5757 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5759 close(f); 5758 close(f);
5760 errno = EEXIST; 5759 errno = EEXIST;
5761 goto ecreate; 5760 goto ecreate;
@@ -6255,10 +6254,9 @@ static int substr_atoi(const char *s)
6255 * performs globbing, and thus diverges from what we do). 6254 * performs globbing, and thus diverges from what we do).
6256 */ 6255 */
6257#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 6256#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
6258#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ 6257#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6259#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 6258#define EXP_WORD 0x40 /* expand word in parameter expansion */
6260#define EXP_WORD 0x80 /* expand word in parameter expansion */ 6259#define EXP_QUOTED 0x80 /* expand word in double quotes */
6261#define EXP_QUOTED 0x100 /* expand word in double quotes */
6262/* 6260/*
6263 * rmescape() flags 6261 * rmescape() flags
6264 */ 6262 */
@@ -6268,7 +6266,7 @@ static int substr_atoi(const char *s)
6268#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 6266#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
6269 6267
6270/* Add CTLESC when necessary. */ 6268/* Add CTLESC when necessary. */
6271#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) 6269#define QUOTES_ESC (EXP_FULL | EXP_CASE)
6272/* Do not skip NUL characters. */ 6270/* Do not skip NUL characters. */
6273#define QUOTES_KEEPNUL EXP_TILDE 6271#define QUOTES_KEEPNUL EXP_TILDE
6274 6272
@@ -6343,7 +6341,10 @@ ifsbreakup(char *string, struct arglist *arglist)
6343 realifs = ifsset() ? ifsval() : defifs; 6341 realifs = ifsset() ? ifsval() : defifs;
6344 ifsp = &ifsfirst; 6342 ifsp = &ifsfirst;
6345 do { 6343 do {
6344 int afternul;
6345
6346 p = string + ifsp->begoff; 6346 p = string + ifsp->begoff;
6347 afternul = nulonly;
6347 nulonly = ifsp->nulonly; 6348 nulonly = ifsp->nulonly;
6348 ifs = nulonly ? nullstr : realifs; 6349 ifs = nulonly ? nullstr : realifs;
6349 ifsspc = 0; 6350 ifsspc = 0;
@@ -6355,7 +6356,7 @@ ifsbreakup(char *string, struct arglist *arglist)
6355 p++; 6356 p++;
6356 continue; 6357 continue;
6357 } 6358 }
6358 if (!nulonly) 6359 if (!(afternul || nulonly))
6359 ifsspc = (strchr(defifs, *p) != NULL); 6360 ifsspc = (strchr(defifs, *p) != NULL);
6360 /* Ignore IFS whitespace at start */ 6361 /* Ignore IFS whitespace at start */
6361 if (q == start && ifsspc) { 6362 if (q == start && ifsspc) {
@@ -6457,7 +6458,6 @@ rmescapes(char *str, int flag, int *slash_position)
6457 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; 6458 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6458 6459
6459 char *p, *q, *r; 6460 char *p, *q, *r;
6460 unsigned inquotes;
6461 unsigned protect_against_glob; 6461 unsigned protect_against_glob;
6462 unsigned globbing; 6462 unsigned globbing;
6463 6463
@@ -6488,18 +6488,21 @@ rmescapes(char *str, int flag, int *slash_position)
6488 } 6488 }
6489 } 6489 }
6490 6490
6491 inquotes = 0;
6492 globbing = flag & RMESCAPE_GLOB; 6491 globbing = flag & RMESCAPE_GLOB;
6493 protect_against_glob = globbing; 6492 protect_against_glob = globbing;
6494 while (*p) { 6493 while (*p) {
6495 if ((unsigned char)*p == CTLQUOTEMARK) { 6494 if ((unsigned char)*p == CTLQUOTEMARK) {
6496// Note: both inquotes and protect_against_glob only affect whether 6495// Note: protect_against_glob only affect whether
6497// CTLESC,<ch> gets converted to <ch> or to \<ch> 6496// CTLESC,<ch> gets converted to <ch> or to \<ch>
6498 inquotes = ~inquotes;
6499 p++; 6497 p++;
6500 protect_against_glob = globbing; 6498 protect_against_glob = globbing;
6501 continue; 6499 continue;
6502 } 6500 }
6501 if (*p == '\\') {
6502 /* naked back slash */
6503 protect_against_glob = 0;
6504 goto copy;
6505 }
6503 if ((unsigned char)*p == CTLESC) { 6506 if ((unsigned char)*p == CTLESC) {
6504 p++; 6507 p++;
6505#if DEBUG 6508#if DEBUG
@@ -6535,10 +6538,6 @@ rmescapes(char *str, int flag, int *slash_position)
6535 *q++ = '\\'; 6538 *q++ = '\\';
6536 } 6539 }
6537 } 6540 }
6538 } else if (*p == '\\' && !inquotes) {
6539 /* naked back slash */
6540 protect_against_glob = 0;
6541 goto copy;
6542 } 6541 }
6543#if BASH_PATTERN_SUBST 6542#if BASH_PATTERN_SUBST
6544 else if (slash_position && p == str + *slash_position) { 6543 else if (slash_position && p == str + *slash_position) {
@@ -7032,12 +7031,12 @@ argstr(char *p, int flags)
7032 case CTLENDVAR: /* ??? */ 7031 case CTLENDVAR: /* ??? */
7033 goto breakloop; 7032 goto breakloop;
7034 case CTLQUOTEMARK: 7033 case CTLQUOTEMARK:
7035 inquotes ^= EXP_QUOTED;
7036 /* "$@" syntax adherence hack */ 7034 /* "$@" syntax adherence hack */
7037 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { 7035 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
7038 p = evalvar(p + 1, flags | inquotes) + 1; 7036 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
7039 goto start; 7037 goto start;
7040 } 7038 }
7039 inquotes ^= EXP_QUOTED;
7041 addquote: 7040 addquote:
7042 if (flags & QUOTES_ESC) { 7041 if (flags & QUOTES_ESC) {
7043 p--; 7042 p--;
@@ -7048,16 +7047,6 @@ argstr(char *p, int flags)
7048 case CTLESC: 7047 case CTLESC:
7049 startloc++; 7048 startloc++;
7050 length++; 7049 length++;
7051
7052 /*
7053 * Quoted parameter expansion pattern: remove quote
7054 * unless inside inner quotes or we have a literal
7055 * backslash.
7056 */
7057 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
7058 EXP_QPAT && *p != '\\')
7059 break;
7060
7061 goto addquote; 7050 goto addquote;
7062 case CTLVAR: 7051 case CTLVAR:
7063 TRACE(("argstr: evalvar('%s')\n", p)); 7052 TRACE(("argstr: evalvar('%s')\n", p));
@@ -7248,15 +7237,24 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7248 } 7237 }
7249#endif 7238#endif
7250 argstr_flags = EXP_TILDE; 7239 argstr_flags = EXP_TILDE;
7251 if (subtype != VSASSIGN && subtype != VSQUESTION) 7240 if (subtype != VSASSIGN
7252 argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE); 7241 && subtype != VSQUESTION
7242#if BASH_SUBSTR
7243 && subtype != VSSUBSTR
7244#endif
7245 ) {
7246 /* EXP_CASE keeps CTLESC's */
7247 argstr_flags = EXP_TILDE | EXP_CASE;
7248 }
7253 argstr(p, argstr_flags); 7249 argstr(p, argstr_flags);
7250 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7254#if BASH_PATTERN_SUBST 7251#if BASH_PATTERN_SUBST
7255 slash_pos = -1; 7252 slash_pos = -1;
7256 if (repl) { 7253 if (repl) {
7257 slash_pos = expdest - ((char *)stackblock() + strloc); 7254 slash_pos = expdest - ((char *)stackblock() + strloc);
7258 STPUTC('/', expdest); 7255 STPUTC('/', expdest);
7259 argstr(repl + 1, argstr_flags); 7256 //bb_error_msg("repl+1:'%s'", repl + 1);
7257 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7260 *repl = '/'; 7258 *repl = '/';
7261 } 7259 }
7262#endif 7260#endif
@@ -11182,6 +11180,34 @@ pgetc_eatbnl(void)
11182 return c; 11180 return c;
11183} 11181}
11184 11182
11183struct synstack {
11184 smalluint syntax;
11185 uint8_t innerdq :1;
11186 uint8_t varpushed :1;
11187 uint8_t dblquote :1;
11188 int varnest; /* levels of variables expansion */
11189 int dqvarnest; /* levels of variables expansion within double quotes */
11190 int parenlevel; /* levels of parens in arithmetic */
11191 struct synstack *prev;
11192 struct synstack *next;
11193};
11194
11195static void
11196synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11197{
11198 memset(next, 0, sizeof(*next));
11199 next->syntax = syntax;
11200 next->next = *stack;
11201 (*stack)->prev = next;
11202 *stack = next;
11203}
11204
11205static ALWAYS_INLINE void
11206synstack_pop(struct synstack **stack)
11207{
11208 *stack = (*stack)->next;
11209}
11210
11185/* 11211/*
11186 * To handle the "." command, a stack of input files is used. Pushfile 11212 * To handle the "." command, a stack of input files is used. Pushfile
11187 * adds a new entry to the stack and popfile restores the previous level. 11213 * adds a new entry to the stack and popfile restores the previous level.
@@ -12443,19 +12469,13 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12443 size_t len; 12469 size_t len;
12444 struct nodelist *bqlist; 12470 struct nodelist *bqlist;
12445 smallint quotef; 12471 smallint quotef;
12446 smallint dblquote;
12447 smallint oldstyle; 12472 smallint oldstyle;
12448 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
12449 smallint pssyntax; /* we are expanding a prompt string */ 12473 smallint pssyntax; /* we are expanding a prompt string */
12450 int varnest; /* levels of variables expansion */
12451 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
12452 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
12453 int dqvarnest; /* levels of variables expansion within double quotes */
12454 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) 12474 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12475 /* syntax stack */
12476 struct synstack synbase = { };
12477 struct synstack *synstack = &synbase;
12455 12478
12456 bqlist = NULL;
12457 quotef = 0;
12458 IF_FEATURE_SH_MATH(prevsyntax = 0;)
12459#if ENABLE_ASH_EXPAND_PRMT 12479#if ENABLE_ASH_EXPAND_PRMT
12460 pssyntax = (syntax == PSSYNTAX); 12480 pssyntax = (syntax == PSSYNTAX);
12461 if (pssyntax) 12481 if (pssyntax)
@@ -12463,11 +12483,12 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12463#else 12483#else
12464 pssyntax = 0; /* constant */ 12484 pssyntax = 0; /* constant */
12465#endif 12485#endif
12466 dblquote = (syntax == DQSYNTAX); 12486 synstack->syntax = syntax;
12467 varnest = 0; 12487
12468 IF_FEATURE_SH_MATH(arinest = 0;) 12488 if (syntax == DQSYNTAX)
12469 IF_FEATURE_SH_MATH(parenlevel = 0;) 12489 synstack->dblquote = 1;
12470 dqvarnest = 0; 12490 quotef = 0;
12491 bqlist = NULL;
12471 12492
12472 STARTSTACKSTR(out); 12493 STARTSTACKSTR(out);
12473 loop: 12494 loop:
@@ -12475,9 +12496,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12475 CHECKEND(); /* set c to PEOF if at end of here document */ 12496 CHECKEND(); /* set c to PEOF if at end of here document */
12476 for (;;) { /* until end of line or end of word */ 12497 for (;;) { /* until end of line or end of word */
12477 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 12498 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
12478 switch (SIT(c, syntax)) { 12499 switch (SIT(c, synstack->syntax)) {
12479 case CNL: /* '\n' */ 12500 case CNL: /* '\n' */
12480 if (syntax == BASESYNTAX) 12501 if (synstack->syntax == BASESYNTAX)
12481 goto endword; /* exit outer loop */ 12502 goto endword; /* exit outer loop */
12482 USTPUTC(c, out); 12503 USTPUTC(c, out);
12483 nlprompt(); 12504 nlprompt();
@@ -12497,13 +12518,13 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12497 if (c & 0x100) { 12518 if (c & 0x100) {
12498 /* Unknown escape. Encode as '\z' */ 12519 /* Unknown escape. Encode as '\z' */
12499 c = (unsigned char)c; 12520 c = (unsigned char)c;
12500 if (eofmark == NULL || dblquote) 12521 if (eofmark == NULL || synstack->dblquote)
12501 USTPUTC(CTLESC, out); 12522 USTPUTC(CTLESC, out);
12502 USTPUTC('\\', out); 12523 USTPUTC('\\', out);
12503 } 12524 }
12504 } 12525 }
12505#endif 12526#endif
12506 if (eofmark == NULL || dblquote) 12527 if (!eofmark || synstack->dblquote || synstack->varnest)
12507 USTPUTC(CTLESC, out); 12528 USTPUTC(CTLESC, out);
12508 USTPUTC(c, out); 12529 USTPUTC(c, out);
12509 break; 12530 break;
@@ -12523,20 +12544,13 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12523 /* Backslash is retained if we are in "str" 12544 /* Backslash is retained if we are in "str"
12524 * and next char isn't dquote-special. 12545 * and next char isn't dquote-special.
12525 */ 12546 */
12526 if (dblquote 12547 if (synstack->dblquote
12527 && c != '\\' 12548 && c != '\\'
12528 && c != '`' 12549 && c != '`'
12529 && c != '$' 12550 && c != '$'
12530 && (c != '"' || eofmark != NULL) 12551 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12552 && (c != '}' || !synstack->varnest)
12531 ) { 12553 ) {
12532//dash survives not doing USTPUTC(CTLESC), but merely by chance:
12533//Example: "\z" gets encoded as "\<CTLESC>z".
12534//rmescapes() then emits "\", "\z", protecting z from globbing.
12535//But it's wrong, should protect _both_ from globbing:
12536//everything in double quotes is not globbed.
12537//Unlike dash, we have a fix in rmescapes() which emits bare "z"
12538//for "<CTLESC>z" since "z" is not glob-special (else unicode may break),
12539//and glob would see "\z" and eat "\". Thus:
12540 USTPUTC(CTLESC, out); /* protect '\' from glob */ 12554 USTPUTC(CTLESC, out); /* protect '\' from glob */
12541 USTPUTC('\\', out); 12555 USTPUTC('\\', out);
12542 } 12556 }
@@ -12546,56 +12560,62 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12546 } 12560 }
12547 break; 12561 break;
12548 case CSQUOTE: 12562 case CSQUOTE:
12549 syntax = SQSYNTAX; 12563 synstack->syntax = SQSYNTAX;
12550 quotemark: 12564 quotemark:
12551 if (eofmark == NULL) { 12565 if (eofmark == NULL) {
12552 USTPUTC(CTLQUOTEMARK, out); 12566 USTPUTC(CTLQUOTEMARK, out);
12553 } 12567 }
12554 break; 12568 break;
12555 case CDQUOTE: 12569 case CDQUOTE:
12556 syntax = DQSYNTAX; 12570 synstack->syntax = DQSYNTAX;
12557 dblquote = 1; 12571 synstack->dblquote = 1;
12572 toggledq:
12573 if (synstack->varnest)
12574 synstack->innerdq ^= 1;
12558 goto quotemark; 12575 goto quotemark;
12559 case CENDQUOTE: 12576 case CENDQUOTE:
12560 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;) 12577 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12561 if (eofmark != NULL && varnest == 0) { 12578 if (eofmark != NULL && synstack->varnest == 0) {
12562 USTPUTC(c, out); 12579 USTPUTC(c, out);
12563 } else { 12580 break;
12564 if (dqvarnest == 0) {
12565 syntax = BASESYNTAX;
12566 dblquote = 0;
12567 }
12568 quotef = 1;
12569 goto quotemark;
12570 } 12581 }
12571 break; 12582
12583 if (synstack->dqvarnest == 0) {
12584 synstack->syntax = BASESYNTAX;
12585 synstack->dblquote = 0;
12586 }
12587
12588 quotef = 1;
12589
12590 if (c == '"')
12591 goto toggledq;
12592
12593 goto quotemark;
12572 case CVAR: /* '$' */ 12594 case CVAR: /* '$' */
12573 PARSESUB(); /* parse substitution */ 12595 PARSESUB(); /* parse substitution */
12574 break; 12596 break;
12575 case CENDVAR: /* '}' */ 12597 case CENDVAR: /* '}' */
12576 if (varnest > 0) { 12598 if (!synstack->innerdq && synstack->varnest > 0) {
12577 varnest--; 12599 if (!--synstack->varnest && synstack->varpushed)
12578 if (dqvarnest > 0) { 12600 synstack_pop(&synstack);
12579 dqvarnest--; 12601 else if (synstack->dqvarnest > 0)
12580 } 12602 synstack->dqvarnest--;
12581 c = CTLENDVAR; 12603 c = CTLENDVAR;
12582 } 12604 }
12583 USTPUTC(c, out); 12605 USTPUTC(c, out);
12584 break; 12606 break;
12585#if ENABLE_FEATURE_SH_MATH 12607#if ENABLE_FEATURE_SH_MATH
12586 case CLP: /* '(' in arithmetic */ 12608 case CLP: /* '(' in arithmetic */
12587 parenlevel++; 12609 synstack->parenlevel++;
12588 USTPUTC(c, out); 12610 USTPUTC(c, out);
12589 break; 12611 break;
12590 case CRP: /* ')' in arithmetic */ 12612 case CRP: /* ')' in arithmetic */
12591 if (parenlevel > 0) { 12613 if (synstack->parenlevel > 0) {
12592 parenlevel--; 12614 synstack->parenlevel--;
12593 } else { 12615 } else {
12594 if (pgetc_eatbnl() == ')') { 12616 if (pgetc_eatbnl() == ')') {
12595 c = CTLENDARI; 12617 c = CTLENDARI;
12596 if (--arinest == 0) { 12618 synstack_pop(&synstack);
12597 syntax = prevsyntax;
12598 }
12599 } else { 12619 } else {
12600 /* 12620 /*
12601 * unbalanced parens 12621 * unbalanced parens
@@ -12621,7 +12641,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12621 case CIGN: 12641 case CIGN:
12622 break; 12642 break;
12623 default: 12643 default:
12624 if (varnest == 0) { 12644 if (synstack->varnest == 0) {
12625#if BASH_REDIR_OUTPUT 12645#if BASH_REDIR_OUTPUT
12626 if (c == '&') { 12646 if (c == '&') {
12627//Can't call pgetc_eatbnl() here, this requires three-deep pungetc() 12647//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
@@ -12640,12 +12660,12 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12640 endword: 12660 endword:
12641 12661
12642#if ENABLE_FEATURE_SH_MATH 12662#if ENABLE_FEATURE_SH_MATH
12643 if (syntax == ARISYNTAX) 12663 if (synstack->syntax == ARISYNTAX)
12644 raise_error_syntax("missing '))'"); 12664 raise_error_syntax("missing '))'");
12645#endif 12665#endif
12646 if (syntax != BASESYNTAX && eofmark == NULL) 12666 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12647 raise_error_syntax("unterminated quoted string"); 12667 raise_error_syntax("unterminated quoted string");
12648 if (varnest != 0) { 12668 if (synstack->varnest != 0) {
12649 /* { */ 12669 /* { */
12650 raise_error_syntax("missing '}'"); 12670 raise_error_syntax("missing '}'");
12651 } 12671 }
@@ -12827,7 +12847,7 @@ parsesub: {
12827 || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 12847 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12828 ) { 12848 ) {
12829#if BASH_DOLLAR_SQUOTE 12849#if BASH_DOLLAR_SQUOTE
12830 if (syntax != DQSYNTAX && c == '\'') 12850 if (synstack->syntax != DQSYNTAX && c == '\'')
12831 bash_dollar_squote = 1; 12851 bash_dollar_squote = 1;
12832 else 12852 else
12833#endif 12853#endif
@@ -12847,6 +12867,8 @@ parsesub: {
12847 } 12867 }
12848 } else { 12868 } else {
12849 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ 12869 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
12870 smalluint newsyn = synstack->syntax;
12871
12850 USTPUTC(CTLVAR, out); 12872 USTPUTC(CTLVAR, out);
12851 typeloc = out - (char *)stackblock(); 12873 typeloc = out - (char *)stackblock();
12852 STADJUST(1, out); 12874 STADJUST(1, out);
@@ -12905,6 +12927,8 @@ parsesub: {
12905 static const char types[] ALIGN1 = "}-+?="; 12927 static const char types[] ALIGN1 = "}-+?=";
12906 /* ${VAR...} but not $VAR or ${#VAR} */ 12928 /* ${VAR...} but not $VAR or ${#VAR} */
12907 /* c == first char after VAR */ 12929 /* c == first char after VAR */
12930 int cc = c;
12931
12908 switch (c) { 12932 switch (c) {
12909 case ':': 12933 case ':':
12910 c = pgetc_eatbnl(); 12934 c = pgetc_eatbnl();
@@ -12929,21 +12953,24 @@ parsesub: {
12929 break; 12953 break;
12930 } 12954 }
12931 case '%': 12955 case '%':
12932 case '#': { 12956 case '#':
12933 int cc = c;
12934 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); 12957 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12935 c = pgetc_eatbnl(); 12958 c = pgetc_eatbnl();
12936 if (c != cc) 12959 if (c == cc)
12937 goto badsub; 12960 subtype++;
12938 subtype++; 12961 else
12962 pungetc();
12963
12964 newsyn = BASESYNTAX;
12939 break; 12965 break;
12940 }
12941#if BASH_PATTERN_SUBST 12966#if BASH_PATTERN_SUBST
12942 case '/': 12967 case '/':
12943 /* ${v/[/]pattern/repl} */ 12968 /* ${v/[/]pattern/repl} */
12944//TODO: encode pattern and repl separately. 12969//TODO: encode pattern and repl separately.
12945// Currently ${v/$var_with_slash/repl} is horribly broken 12970// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12971// are broken (should print "ONE")
12946 subtype = VSREPLACE; 12972 subtype = VSREPLACE;
12973 newsyn = BASESYNTAX;
12947 c = pgetc_eatbnl(); 12974 c = pgetc_eatbnl();
12948 if (c != '/') 12975 if (c != '/')
12949 goto badsub; 12976 goto badsub;
@@ -12955,11 +12982,26 @@ parsesub: {
12955 badsub: 12982 badsub:
12956 pungetc(); 12983 pungetc();
12957 } 12984 }
12985
12986 if (newsyn == ARISYNTAX)
12987 newsyn = DQSYNTAX;
12988
12989 if ((newsyn != synstack->syntax || synstack->innerdq)
12990 && subtype != VSNORMAL
12991 ) {
12992 synstack_push(&synstack,
12993 synstack->prev ?: alloca(sizeof(*synstack)),
12994 newsyn);
12995
12996 synstack->varpushed = 1;
12997 synstack->dblquote = newsyn != BASESYNTAX;
12998 }
12999
12958 ((unsigned char *)stackblock())[typeloc] = subtype; 13000 ((unsigned char *)stackblock())[typeloc] = subtype;
12959 if (subtype != VSNORMAL) { 13001 if (subtype != VSNORMAL) {
12960 varnest++; 13002 synstack->varnest++;
12961 if (dblquote) 13003 if (synstack->dblquote)
12962 dqvarnest++; 13004 synstack->dqvarnest++;
12963 } 13005 }
12964 STPUTC('=', out); 13006 STPUTC('=', out);
12965 } 13007 }
@@ -13016,7 +13058,7 @@ parsebackq: {
13016 case '\\': 13058 case '\\':
13017 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */ 13059 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
13018 if (pc != '\\' && pc != '`' && pc != '$' 13060 if (pc != '\\' && pc != '`' && pc != '$'
13019 && (!dblquote || pc != '"') 13061 && (!synstack->dblquote || pc != '"')
13020 ) { 13062 ) {
13021 STPUTC('\\', pout); 13063 STPUTC('\\', pout);
13022 } 13064 }
@@ -13091,10 +13133,11 @@ parsebackq: {
13091 * Parse an arithmetic expansion (indicate start of one and set state) 13133 * Parse an arithmetic expansion (indicate start of one and set state)
13092 */ 13134 */
13093parsearith: { 13135parsearith: {
13094 if (++arinest == 1) { 13136
13095 prevsyntax = syntax; 13137 synstack_push(&synstack,
13096 syntax = ARISYNTAX; 13138 synstack->prev ?: alloca(sizeof(*synstack)),
13097 } 13139 ARISYNTAX);
13140 synstack->dblquote = 1;
13098 USTPUTC(CTLARI, out); 13141 USTPUTC(CTLARI, out);
13099 goto parsearith_return; 13142 goto parsearith_return;
13100} 13143}
@@ -14542,7 +14585,7 @@ init(void)
14542 14585
14543 14586
14544//usage:#define ash_trivial_usage 14587//usage:#define ash_trivial_usage
14545//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 14588//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
14546//usage:#define ash_full_usage "\n\n" 14589//usage:#define ash_full_usage "\n\n"
14547//usage: "Unix shell interpreter" 14590//usage: "Unix shell interpreter"
14548 14591