summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-02-25 11:52:36 +0000
committerRon Yorston <rmy@pobox.com>2020-02-25 11:52:36 +0000
commit5e69872105e69980e5feb0b071a442cd423c59f5 (patch)
tree78fd5194d36e518e658f4f58635d6fc85515b778
parente2a5b8e5e936891142cb630d145e67882711fd13 (diff)
parent1555895b4af44ce47fe2365aec82e8e67c685f08 (diff)
downloadbusybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.tar.gz
busybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.tar.bz2
busybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.zip
Merge branch 'busybox' into merge
-rw-r--r--shell/ash.c390
1 files changed, 183 insertions, 207 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 690796740..47ad85440 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1925,7 +1925,7 @@ makestrspace(size_t newlen, char *p)
1925} 1925}
1926 1926
1927static char * 1927static char *
1928stack_nputstr(const char *s, size_t n, char *p) 1928stnputs(const char *s, size_t n, char *p)
1929{ 1929{
1930 p = makestrspace(n, p); 1930 p = makestrspace(n, p);
1931 p = (char *)mempcpy(p, s, n); 1931 p = (char *)mempcpy(p, s, n);
@@ -1935,7 +1935,7 @@ stack_nputstr(const char *s, size_t n, char *p)
1935static char * 1935static char *
1936stack_putstr(const char *s, char *p) 1936stack_putstr(const char *s, char *p)
1937{ 1937{
1938 return stack_nputstr(s, strlen(s), p); 1938 return stnputs(s, strlen(s), p);
1939} 1939}
1940 1940
1941static char * 1941static char *
@@ -3032,7 +3032,7 @@ updatepwd(const char *dir)
3032 else { 3032 else {
3033 if (absdrive) { 3033 if (absdrive) {
3034 if (!relpath) 3034 if (!relpath)
3035 new = stack_nputstr(dir, 2, new); 3035 new = stnputs(dir, 2, new);
3036 cdcomppath += 2; 3036 cdcomppath += 2;
3037 dir += 2; 3037 dir += 2;
3038 } 3038 }
@@ -6566,6 +6566,7 @@ static int substr_atoi(const char *s)
6566#define EXP_WORD 0x40 /* expand word in parameter expansion */ 6566#define EXP_WORD 0x40 /* expand word in parameter expansion */
6567#define EXP_QUOTED 0x100 /* expand word in double quotes */ 6567#define EXP_QUOTED 0x100 /* expand word in double quotes */
6568#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */ 6568#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
6569#define EXP_DISCARD 0x400 /* discard result of expansion */
6569 6570
6570/* 6571/*
6571 * rmescape() flags 6572 * rmescape() flags
@@ -6983,13 +6984,15 @@ removerecordregions(int endoff)
6983} 6984}
6984 6985
6985static char * 6986static char *
6986exptilde(char *startp, char *p, int flag) 6987exptilde(char *startp, int flag)
6987{ 6988{
6988 unsigned char c; 6989 unsigned char c;
6989 char *name; 6990 char *name;
6990 struct passwd *pw; 6991 struct passwd *pw;
6991 const char *home; 6992 const char *home;
6993 char *p;
6992 6994
6995 p = startp;
6993 name = p + 1; 6996 name = p + 1;
6994 6997
6995 while ((c = *++p) != '\0') { 6998 while ((c = *++p) != '\0') {
@@ -7008,6 +7011,8 @@ exptilde(char *startp, char *p, int flag)
7008 } 7011 }
7009 } 7012 }
7010 done: 7013 done:
7014 if (flag & EXP_DISCARD)
7015 goto out;
7011 *p = '\0'; 7016 *p = '\0';
7012 if (*name == '\0') { 7017 if (*name == '\0') {
7013 home = lookupvar("HOME"); 7018 home = lookupvar("HOME");
@@ -7017,13 +7022,13 @@ exptilde(char *startp, char *p, int flag)
7017 goto lose; 7022 goto lose;
7018 home = pw->pw_dir; 7023 home = pw->pw_dir;
7019 } 7024 }
7025 *p = c;
7020 if (!home) 7026 if (!home)
7021 goto lose; 7027 goto lose;
7022 *p = c;
7023 strtodest(home, flag | EXP_QUOTED); 7028 strtodest(home, flag | EXP_QUOTED);
7029 out:
7024 return p; 7030 return p;
7025 lose: 7031 lose:
7026 *p = c;
7027 return startp; 7032 return startp;
7028} 7033}
7029 7034
@@ -7132,6 +7137,9 @@ expbackq(union node *cmd, int flag)
7132 int startloc; 7137 int startloc;
7133 struct stackmark smark; 7138 struct stackmark smark;
7134 7139
7140 if (flag & EXP_DISCARD)
7141 goto out;
7142
7135 INT_OFF; 7143 INT_OFF;
7136 startloc = expdest - (char *)stackblock(); 7144 startloc = expdest - (char *)stackblock();
7137 pushstackmark(&smark, startloc); 7145 pushstackmark(&smark, startloc);
@@ -7174,64 +7182,57 @@ expbackq(union node *cmd, int flag)
7174 (int)((dest - (char *)stackblock()) - startloc), 7182 (int)((dest - (char *)stackblock()) - startloc),
7175 (int)((dest - (char *)stackblock()) - startloc), 7183 (int)((dest - (char *)stackblock()) - startloc),
7176 stackblock() + startloc)); 7184 stackblock() + startloc));
7185
7186 out:
7187 argbackq = argbackq->next;
7177} 7188}
7178 7189
7190/* expari needs it */
7191static char *argstr(char *p, int flag);
7192
7179#if ENABLE_FEATURE_SH_MATH 7193#if ENABLE_FEATURE_SH_MATH
7180/* 7194/*
7181 * Expand arithmetic expression. Backup to start of expression, 7195 * Expand arithmetic expression. Backup to start of expression,
7182 * evaluate, place result in (backed up) result, adjust string position. 7196 * evaluate, place result in (backed up) result, adjust string position.
7183 */ 7197 */
7184static void 7198static char *
7185expari(int flag) 7199expari(char *start, int flag)
7186{ 7200{
7187 char *p, *start; 7201 struct stackmark sm;
7188 int begoff; 7202 int begoff;
7203 int endoff;
7189 int len; 7204 int len;
7205 arith_t result;
7206 char *p;
7190 7207
7191 /* ifsfree(); */ 7208 p = stackblock();
7192 7209 begoff = expdest - p;
7193 /* 7210 p = argstr(start, flag & EXP_DISCARD);
7194 * This routine is slightly over-complicated for
7195 * efficiency. Next we scan backwards looking for the
7196 * start of arithmetic.
7197 */
7198 start = stackblock();
7199 p = expdest - 1;
7200 *p = '\0';
7201 p--;
7202 while (1) {
7203 int esc;
7204
7205 while ((unsigned char)*p != CTLARI) {
7206 p--;
7207#if DEBUG
7208 if (p < start) {
7209 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
7210 }
7211#endif
7212 }
7213
7214 esc = esclen(start, p);
7215 if (!(esc % 2)) {
7216 break;
7217 }
7218 7211
7219 p -= esc + 1; 7212 if (flag & EXP_DISCARD)
7220 } 7213 goto out;
7221 7214
7222 begoff = p - start; 7215 start = stackblock();
7216 endoff = expdest - start;
7217 start += begoff;
7218 STADJUST(start - expdest, expdest);
7223 7219
7224 removerecordregions(begoff); 7220 removerecordregions(begoff);
7225 7221
7226 expdest = p;
7227
7228 if (flag & QUOTES_ESC) 7222 if (flag & QUOTES_ESC)
7229 rmescapes(p + 1, 0, NULL); 7223 rmescapes(start, 0, NULL);
7230 7224
7231 len = cvtnum(ash_arith(p + 1), flag); 7225 pushstackmark(&sm, endoff);
7226 result = ash_arith(start);
7227 popstackmark(&sm);
7228
7229 len = cvtnum(result, flag);
7232 7230
7233 if (!(flag & EXP_QUOTED)) 7231 if (!(flag & EXP_QUOTED))
7234 recordregion(begoff, begoff + len, 0); 7232 recordregion(begoff, begoff + len, 0);
7233
7234 out:
7235 return p;
7235} 7236}
7236#endif 7237#endif
7237 7238
@@ -7243,8 +7244,8 @@ static char *evalvar(char *p, int flags);
7243 * characters to allow for further processing. Otherwise treat 7244 * characters to allow for further processing. Otherwise treat
7244 * $@ like $* since no splitting will be performed. 7245 * $@ like $* since no splitting will be performed.
7245 */ 7246 */
7246static void 7247static char *
7247argstr(char *p, int flags) 7248argstr(char *p, int flag)
7248{ 7249{
7249 static const char spclchars[] ALIGN1 = { 7250 static const char spclchars[] ALIGN1 = {
7250 '=', 7251 '=',
@@ -7255,51 +7256,56 @@ argstr(char *p, int flags)
7255 CTLVAR, 7256 CTLVAR,
7256 CTLBACKQ, 7257 CTLBACKQ,
7257#if ENABLE_FEATURE_SH_MATH 7258#if ENABLE_FEATURE_SH_MATH
7259 CTLARI,
7258 CTLENDARI, 7260 CTLENDARI,
7259#endif 7261#endif
7260 '\0' 7262 '\0'
7261 }; 7263 };
7262 const char *reject = spclchars; 7264 const char *reject = spclchars;
7263 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; 7265 int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
7264 int inquotes; 7266 int inquotes;
7265 size_t length; 7267 size_t length;
7266 int startloc; 7268 int startloc;
7267 7269
7268 if (!(flags & EXP_VARTILDE)) { 7270 reject += !!(flag & EXP_VARTILDE2);
7269 reject += 2; 7271 reject += flag & EXP_VARTILDE ? 0 : 2;
7270 } else if (flags & EXP_VARTILDE2) {
7271 reject++;
7272 }
7273 inquotes = 0; 7272 inquotes = 0;
7274 length = 0; 7273 length = 0;
7275 if (flags & EXP_TILDE) { 7274 if (flag & EXP_TILDE) {
7276 char *q; 7275 flag &= ~EXP_TILDE;
7277
7278 flags &= ~EXP_TILDE;
7279 tilde: 7276 tilde:
7280 q = p; 7277 if (*p == '~')
7281 if (*q == '~') 7278 p = exptilde(p, flag);
7282 p = exptilde(p, q, flags);
7283 } 7279 }
7284 start: 7280 start:
7285 startloc = expdest - (char *)stackblock(); 7281 startloc = expdest - (char *)stackblock();
7286 for (;;) { 7282 for (;;) {
7283 int end;
7287 unsigned char c; 7284 unsigned char c;
7288 7285
7289 length += strcspn(p + length, reject); 7286 length += strcspn(p + length, reject);
7287 end = 0;
7290 c = p[length]; 7288 c = p[length];
7291 if (c) { 7289 if (!(c & 0x80)
7292 if (!(c & 0x80) 7290 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
7293 IF_FEATURE_SH_MATH(|| c == CTLENDARI) 7291 || c == CTLENDVAR
7294 ) { 7292 ) {
7295 /* c == '=' || c == ':' || c == CTLENDARI */ 7293 /*
7296 length++; 7294 * c == '=' || c == ':' || c == '\0' ||
7297 } 7295 * c == CTLENDARI || c == CTLENDVAR
7296 */
7297 length++;
7298 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
7299 end = !!((c - 1) & 0x80);
7298 } 7300 }
7299 if (length > 0) { 7301 if (length > 0 && !(flag & EXP_DISCARD)) {
7300 int newloc; 7302 int newloc;
7301 expdest = stack_nputstr(p, length, expdest); 7303 char *q;
7302 newloc = expdest - (char *)stackblock(); 7304
7305 q = stnputs(p, length, expdest);
7306 q[-1] &= end - 1;
7307 expdest = q - (flag & EXP_WORD ? end : 0);
7308 newloc = q - (char *)stackblock() - end;
7303 if (breakall && !inquotes && newloc > startloc) { 7309 if (breakall && !inquotes && newloc > startloc) {
7304 recordregion(startloc, newloc, 0); 7310 recordregion(startloc, newloc, 0);
7305 } 7311 }
@@ -7308,15 +7314,12 @@ argstr(char *p, int flags)
7308 p += length + 1; 7314 p += length + 1;
7309 length = 0; 7315 length = 0;
7310 7316
7317 if (end)
7318 break;
7319
7311 switch (c) { 7320 switch (c) {
7312 case '\0':
7313 goto breakloop;
7314 case '=': 7321 case '=':
7315 if (flags & EXP_VARTILDE2) { 7322 flag |= EXP_VARTILDE2;
7316 p--;
7317 continue;
7318 }
7319 flags |= EXP_VARTILDE2;
7320 reject++; 7323 reject++;
7321 /* fall through */ 7324 /* fall through */
7322 case ':': 7325 case ':':
@@ -7328,20 +7331,15 @@ argstr(char *p, int flags)
7328 goto tilde; 7331 goto tilde;
7329 } 7332 }
7330 continue; 7333 continue;
7331 }
7332
7333 switch (c) {
7334 case CTLENDVAR: /* ??? */
7335 goto breakloop;
7336 case CTLQUOTEMARK: 7334 case CTLQUOTEMARK:
7337 /* "$@" syntax adherence hack */ 7335 /* "$@" syntax adherence hack */
7338 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { 7336 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
7339 p = evalvar(p + 1, flags | EXP_QUOTED) + 1; 7337 p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
7340 goto start; 7338 goto start;
7341 } 7339 }
7342 inquotes ^= EXP_QUOTED; 7340 inquotes ^= EXP_QUOTED;
7343 addquote: 7341 addquote:
7344 if (flags & QUOTES_ESC) { 7342 if (flag & QUOTES_ESC) {
7345 p--; 7343 p--;
7346 length++; 7344 length++;
7347 startloc++; 7345 startloc++;
@@ -7353,22 +7351,20 @@ argstr(char *p, int flags)
7353 goto addquote; 7351 goto addquote;
7354 case CTLVAR: 7352 case CTLVAR:
7355 TRACE(("argstr: evalvar('%s')\n", p)); 7353 TRACE(("argstr: evalvar('%s')\n", p));
7356 p = evalvar(p, flags | inquotes); 7354 p = evalvar(p, flag | inquotes);
7357 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 7355 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
7358 goto start; 7356 goto start;
7359 case CTLBACKQ: 7357 case CTLBACKQ:
7360 expbackq(argbackq->n, flags | inquotes); 7358 expbackq(argbackq->n, flag | inquotes);
7361 argbackq = argbackq->next;
7362 goto start; 7359 goto start;
7363#if ENABLE_FEATURE_SH_MATH 7360#if ENABLE_FEATURE_SH_MATH
7364 case CTLENDARI: 7361 case CTLARI:
7365 p--; 7362 p = expari(p, flag | inquotes);
7366 expari(flags | inquotes);
7367 goto start; 7363 goto start;
7368#endif 7364#endif
7369 } 7365 }
7370 } 7366 }
7371 breakloop: ; 7367 return p - 1;
7372} 7368}
7373 7369
7374static char * 7370static char *
@@ -7493,26 +7489,27 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
7493 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); 7489 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
7494} 7490}
7495 7491
7496static const char * 7492static char *
7497subevalvar(char *p, char *varname, int strloc, int subtype, 7493subevalvar(char *start, char *str, int strloc,
7498 int startloc, int varflags, int flag) 7494 int startloc, int varflags, int flag)
7499{ 7495{
7500 struct nodelist *saveargbackq = argbackq; 7496 int subtype = varflags & VSTYPE;
7501 int quotes = flag & QUOTES_ESC; 7497 int quotes = flag & QUOTES_ESC;
7502 char *startp; 7498 char *startp;
7503 char *loc; 7499 char *loc;
7504 char *rmesc, *rmescend; 7500 char *rmesc, *rmescend;
7505 char *str; 7501 long amount;
7506 int amount, resetloc; 7502 int resetloc;
7507 int argstr_flags; 7503 int argstr_flags;
7508 IF_BASH_PATTERN_SUBST(int workloc;) 7504 IF_BASH_PATTERN_SUBST(int workloc;)
7509 IF_BASH_PATTERN_SUBST(int slash_pos;) 7505 IF_BASH_PATTERN_SUBST(int slash_pos;)
7510 IF_BASH_PATTERN_SUBST(char *repl;) 7506 IF_BASH_PATTERN_SUBST(char *repl;)
7511 int zero; 7507 int zero;
7512 char *(*scan)(char*, char*, char*, char*, int, int); 7508 char *(*scan)(char*, char*, char*, char*, int, int);
7509 char *p;
7513 7510
7514 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 7511 //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
7515 // p, varname, strloc, subtype, startloc, varflags, quotes); 7512 // start, str, strloc, startloc, varflags, quotes);
7516 7513
7517#if BASH_PATTERN_SUBST 7514#if BASH_PATTERN_SUBST
7518 /* For "${v/pattern/repl}", we must find the delimiter _before_ 7515 /* For "${v/pattern/repl}", we must find the delimiter _before_
@@ -7522,7 +7519,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7522 repl = NULL; 7519 repl = NULL;
7523 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 7520 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7524 /* Find '/' and replace with NUL */ 7521 /* Find '/' and replace with NUL */
7525 repl = p; 7522 repl = start;
7526 /* The pattern can't be empty. 7523 /* The pattern can't be empty.
7527 * IOW: if the first char after "${v//" is a slash, 7524 * IOW: if the first char after "${v//" is a slash,
7528 * it does not terminate the pattern - it's the first char of the pattern: 7525 * it does not terminate the pattern - it's the first char of the pattern:
@@ -7547,17 +7544,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7547 } 7544 }
7548 } 7545 }
7549#endif 7546#endif
7550 argstr_flags = EXP_TILDE; 7547 argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7551 if (subtype != VSASSIGN 7548 if (!str
7552 && subtype != VSQUESTION
7553#if BASH_SUBSTR 7549#if BASH_SUBSTR
7554 && subtype != VSSUBSTR 7550 && subtype != VSSUBSTR
7555#endif 7551#endif
7556 ) { 7552 ) {
7557 /* EXP_CASE keeps CTLESC's */ 7553 /* EXP_CASE keeps CTLESC's */
7558 argstr_flags = EXP_TILDE | EXP_CASE; 7554 argstr_flags |= EXP_CASE;
7559 } 7555 }
7560 argstr(p, argstr_flags); 7556 p = argstr(start, argstr_flags);
7557
7561 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc); 7558 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7562#if BASH_PATTERN_SUBST 7559#if BASH_PATTERN_SUBST
7563 slash_pos = -1; 7560 slash_pos = -1;
@@ -7565,32 +7562,34 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7565 slash_pos = expdest - ((char *)stackblock() + strloc); 7562 slash_pos = expdest - ((char *)stackblock() + strloc);
7566 STPUTC('/', expdest); 7563 STPUTC('/', expdest);
7567 //bb_error_msg("repl+1:'%s'", repl + 1); 7564 //bb_error_msg("repl+1:'%s'", repl + 1);
7568 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ 7565 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7569 *repl = '/'; 7566 *repl = '/';
7570 } 7567 }
7571#endif 7568#endif
7572 STPUTC('\0', expdest); 7569 if (flag & EXP_DISCARD)
7573 argbackq = saveargbackq; 7570 return p;
7571
7574 startp = (char *)stackblock() + startloc; 7572 startp = (char *)stackblock() + startloc;
7575 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc); 7573 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7576 7574
7577 switch (subtype) { 7575 switch (subtype) {
7578 case VSASSIGN: 7576 case VSASSIGN:
7579 setvar0(varname, startp); 7577 setvar0(str, startp);
7580 amount = startp - expdest; 7578
7581 STADJUST(amount, expdest); 7579 loc = startp;
7582 return startp; 7580 goto out;
7583 7581
7584 case VSQUESTION: 7582 case VSQUESTION:
7585 varunset(p, varname, startp, varflags); 7583 varunset(start, str, startp, varflags);
7586 /* NOTREACHED */ 7584 /* NOTREACHED */
7587 7585
7588#if BASH_SUBSTR 7586#if BASH_SUBSTR
7589 case VSSUBSTR: { 7587 case VSSUBSTR: {
7590 int pos, len, orig_len; 7588 int pos, len, orig_len;
7591 char *colon; 7589 char *colon;
7590 char *vstr;
7592 7591
7593 loc = str = stackblock() + strloc; 7592 loc = vstr = stackblock() + strloc;
7594 7593
7595 /* Read POS in ${var:POS:LEN} */ 7594 /* Read POS in ${var:POS:LEN} */
7596 colon = strchr(loc, ':'); 7595 colon = strchr(loc, ':');
@@ -7599,12 +7598,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7599 if (colon) *colon = ':'; 7598 if (colon) *colon = ':';
7600 7599
7601 /* Read LEN in ${var:POS:LEN} */ 7600 /* Read LEN in ${var:POS:LEN} */
7602 len = str - startp - 1; 7601 len = vstr - startp - 1;
7603 /* *loc != '\0', guaranteed by parser */ 7602 /* *loc != '\0', guaranteed by parser */
7604 if (quotes) { 7603 if (quotes) {
7605 char *ptr; 7604 char *ptr;
7606 /* Adjust the length by the number of escapes */ 7605 /* Adjust the length by the number of escapes */
7607 for (ptr = startp; ptr < (str - 1); ptr++) { 7606 for (ptr = startp; ptr < (vstr - 1); ptr++) {
7608 if ((unsigned char)*ptr == CTLESC) { 7607 if ((unsigned char)*ptr == CTLESC) {
7609 len--; 7608 len--;
7610 ptr++; 7609 ptr++;
@@ -7642,19 +7641,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7642 if ((unsigned)len > (orig_len - pos)) 7641 if ((unsigned)len > (orig_len - pos))
7643 len = orig_len - pos; 7642 len = orig_len - pos;
7644 7643
7645 for (str = startp; pos; str++, pos--) { 7644 for (vstr = startp; pos; vstr++, pos--) {
7646 if (quotes && (unsigned char)*str == CTLESC) 7645 if (quotes && (unsigned char)*vstr == CTLESC)
7647 str++; 7646 vstr++;
7648 } 7647 }
7649 for (loc = startp; len; len--) { 7648 for (loc = startp; len; len--) {
7650 if (quotes && (unsigned char)*str == CTLESC) 7649 if (quotes && (unsigned char)*vstr == CTLESC)
7651 *loc++ = *str++; 7650 *loc++ = *vstr++;
7652 *loc++ = *str++; 7651 *loc++ = *vstr++;
7653 } 7652 }
7654 *loc = '\0'; 7653 *loc = '\0';
7655 amount = loc - expdest; 7654 goto out;
7656 STADJUST(amount, expdest);
7657 return loc;
7658 } 7655 }
7659#endif /* BASH_SUBSTR */ 7656#endif /* BASH_SUBSTR */
7660 } 7657 }
@@ -7720,7 +7717,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7720 7717
7721 /* If there's no pattern to match, return the expansion unmolested */ 7718 /* If there's no pattern to match, return the expansion unmolested */
7722 if (str[0] == '\0') 7719 if (str[0] == '\0')
7723 return NULL; 7720 goto out1;
7724 7721
7725 len = 0; 7722 len = 0;
7726 idx = startp; 7723 idx = startp;
@@ -7801,9 +7798,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7801 startp = (char *)stackblock() + startloc; 7798 startp = (char *)stackblock() + startloc;
7802 memmove(startp, (char *)stackblock() + workloc, len + 1); 7799 memmove(startp, (char *)stackblock() + workloc, len + 1);
7803 //bb_error_msg("startp:'%s'", startp); 7800 //bb_error_msg("startp:'%s'", startp);
7804 amount = expdest - (startp + len); 7801 loc = startp + len;
7805 STADJUST(-amount, expdest); 7802 goto out;
7806 return startp;
7807 } 7803 }
7808#endif /* BASH_PATTERN_SUBST */ 7804#endif /* BASH_PATTERN_SUBST */
7809 7805
@@ -7824,10 +7820,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7824 loc = startp + (str - loc) - 1; 7820 loc = startp + (str - loc) - 1;
7825 } 7821 }
7826 *loc = '\0'; 7822 *loc = '\0';
7827 amount = loc - expdest; 7823 } else
7828 STADJUST(amount, expdest); 7824 loc = str - 1;
7829 } 7825
7830 return loc; 7826 out:
7827 amount = loc - expdest;
7828 STADJUST(amount, expdest);
7829 out1:
7830 /* Remove any recorded regions beyond start of variable */
7831 removerecordregions(startloc);
7832
7833 return p;
7831} 7834}
7832 7835
7833/* 7836/*
@@ -7852,7 +7855,14 @@ varvalue(char *name, int varflags, int flags, int quoted)
7852 ssize_t len = 0; 7855 ssize_t len = 0;
7853 int sep; 7856 int sep;
7854 int subtype = varflags & VSTYPE; 7857 int subtype = varflags & VSTYPE;
7855 int discard = subtype == VSPLUS || subtype == VSLENGTH; 7858 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7859
7860 if (!subtype) {
7861 if (discard)
7862 return -1;
7863
7864 raise_error_syntax("bad substitution");
7865 }
7856 7866
7857 flags |= EXP_KEEPNUL; 7867 flags |= EXP_KEEPNUL;
7858 flags &= discard ? ~QUOTES_ESC : ~0; 7868 flags &= discard ? ~QUOTES_ESC : ~0;
@@ -7969,6 +7979,7 @@ varvalue(char *name, int varflags, int flags, int quoted)
7969 7979
7970 if (discard) 7980 if (discard)
7971 STADJUST(-len, expdest); 7981 STADJUST(-len, expdest);
7982
7972 return len; 7983 return len;
7973} 7984}
7974 7985
@@ -7981,18 +7992,16 @@ evalvar(char *p, int flag)
7981{ 7992{
7982 char varflags; 7993 char varflags;
7983 char subtype; 7994 char subtype;
7984 int quoted;
7985 char *var; 7995 char *var;
7986 int patloc; 7996 int patloc;
7987 int startloc; 7997 int startloc;
7988 ssize_t varlen; 7998 ssize_t varlen;
7999 int discard;
8000 int quoted;
7989 8001
7990 varflags = (unsigned char) *p++; 8002 varflags = (unsigned char) *p++;
7991 subtype = varflags & VSTYPE; 8003 subtype = varflags & VSTYPE;
7992 8004
7993 if (!subtype)
7994 raise_error_syntax("bad substitution");
7995
7996 quoted = flag & EXP_QUOTED; 8005 quoted = flag & EXP_QUOTED;
7997 var = p; 8006 var = p;
7998 startloc = expdest - (char *)stackblock(); 8007 startloc = expdest - (char *)stackblock();
@@ -8003,56 +8012,43 @@ evalvar(char *p, int flag)
8003 if (varflags & VSNUL) 8012 if (varflags & VSNUL)
8004 varlen--; 8013 varlen--;
8005 8014
8006 if (subtype == VSPLUS) { 8015 discard = varlen < 0 ? EXP_DISCARD : 0;
8007 varlen = -1 - varlen;
8008 goto vsplus;
8009 }
8010 8016
8011 if (subtype == VSMINUS) { 8017 switch (subtype) {
8012 vsplus: 8018 case VSPLUS:
8013 if (varlen < 0) { 8019 discard ^= EXP_DISCARD;
8014 argstr( 8020 /* fall through */
8015 p, 8021 case 0:
8016 flag | EXP_TILDE | EXP_WORD 8022 case VSMINUS:
8017 ); 8023 p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
8018 goto end;
8019 }
8020 goto record; 8024 goto record;
8021 }
8022 8025
8023 if (subtype == VSASSIGN || subtype == VSQUESTION) { 8026 case VSASSIGN:
8024 if (varlen >= 0) 8027 case VSQUESTION:
8028 p = subevalvar(p, var, 0, startloc, varflags,
8029 (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
8030
8031 if ((flag | ~discard) & EXP_DISCARD)
8025 goto record; 8032 goto record;
8026 8033
8027 subevalvar(p, var, 0, subtype, startloc, varflags,
8028 flag & ~QUOTES_ESC);
8029 varflags &= ~VSNUL; 8034 varflags &= ~VSNUL;
8030 /* 8035 subtype = VSNORMAL;
8031 * Remove any recorded regions beyond
8032 * start of variable
8033 */
8034 removerecordregions(startloc);
8035 goto again; 8036 goto again;
8036 } 8037 }
8037 8038
8038 if (varlen < 0 && uflag) 8039 if ((discard & ~flag) && uflag)
8039 varunset(p, var, 0, 0); 8040 varunset(p, var, 0, 0);
8040 8041
8041 if (subtype == VSLENGTH) { 8042 if (subtype == VSLENGTH) {
8043 p++;
8044 if (flag & EXP_DISCARD)
8045 return p;
8042 cvtnum(varlen > 0 ? varlen : 0, flag); 8046 cvtnum(varlen > 0 ? varlen : 0, flag);
8043 goto record; 8047 goto really_record;
8044 } 8048 }
8045 8049
8046 if (subtype == VSNORMAL) { 8050 if (subtype == VSNORMAL)
8047 record: 8051 goto record;
8048 if (quoted) {
8049 quoted = *var == '@' && shellparam.nparam;
8050 if (!quoted)
8051 goto end;
8052 }
8053 recordregion(startloc, expdest - (char *)stackblock(), quoted);
8054 goto end;
8055 }
8056 8052
8057#if DEBUG 8053#if DEBUG
8058 switch (subtype) { 8054 switch (subtype) {
@@ -8073,46 +8069,29 @@ evalvar(char *p, int flag)
8073 } 8069 }
8074#endif 8070#endif
8075 8071
8076 if (varlen >= 0) { 8072 flag |= discard;
8073 if (!(flag & EXP_DISCARD)) {
8077 /* 8074 /*
8078 * Terminate the string and start recording the pattern 8075 * Terminate the string and start recording the pattern
8079 * right after it 8076 * right after it
8080 */ 8077 */
8081 STPUTC('\0', expdest); 8078 STPUTC('\0', expdest);
8082 patloc = expdest - (char *)stackblock();
8083 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
8084 startloc, varflags, flag)) {
8085 int amount = expdest - (
8086 (char *)stackblock() + patloc - 1
8087 );
8088 STADJUST(-amount, expdest);
8089 }
8090 /* Remove any recorded regions beyond start of variable */
8091 removerecordregions(startloc);
8092 goto record;
8093 } 8079 }
8094 8080
8095 varlen = 0; 8081 patloc = expdest - (char *)stackblock();
8082 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
8096 8083
8097 end: 8084 record:
8098 if (subtype != VSNORMAL) { /* skip to end of alternative */ 8085 if ((flag | discard) & EXP_DISCARD)
8099 int nesting = 1; 8086 return p;
8100 for (;;) { 8087
8101 unsigned char c = *p++; 8088 really_record:
8102 if (c == CTLESC) 8089 if (quoted) {
8103 p++; 8090 quoted = *var == '@' && shellparam.nparam;
8104 else if (c == CTLBACKQ) { 8091 if (!quoted)
8105 if (varlen >= 0) 8092 return p;
8106 argbackq = argbackq->next;
8107 } else if (c == CTLVAR) {
8108 if ((*p++ & VSTYPE) != VSNORMAL)
8109 nesting++;
8110 } else if (c == CTLENDVAR) {
8111 if (--nesting == 0)
8112 break;
8113 }
8114 }
8115 } 8093 }
8094 recordregion(startloc, expdest - (char *)stackblock(), quoted);
8116 return p; 8095 return p;
8117} 8096}
8118 8097
@@ -8533,13 +8512,11 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
8533 STARTSTACKSTR(expdest); 8512 STARTSTACKSTR(expdest);
8534 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); 8513 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
8535 argstr(arg->narg.text, flag); 8514 argstr(arg->narg.text, flag);
8536 p = _STPUTC('\0', expdest);
8537 expdest = p - 1;
8538 if (arglist == NULL) { 8515 if (arglist == NULL) {
8539 /* here document expanded */ 8516 /* here document expanded */
8540 goto out; 8517 goto out;
8541 } 8518 }
8542 p = grabstackstr(p); 8519 p = grabstackstr(expdest);
8543 TRACE(("expandarg: p:'%s'\n", p)); 8520 TRACE(("expandarg: p:'%s'\n", p));
8544 exparg.lastp = &exparg.list; 8521 exparg.lastp = &exparg.list;
8545 /* 8522 /*
@@ -8600,7 +8577,6 @@ casematch(union node *pattern, char *val)
8600 argbackq = pattern->narg.backquote; 8577 argbackq = pattern->narg.backquote;
8601 STARTSTACKSTR(expdest); 8578 STARTSTACKSTR(expdest);
8602 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 8579 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8603 STACKSTRNUL(expdest);
8604 ifsfree(); 8580 ifsfree();
8605 result = patmatch(stackblock(), val); 8581 result = patmatch(stackblock(), val);
8606 popstackmark(&smark); 8582 popstackmark(&smark);
@@ -11076,7 +11052,6 @@ evalcommand(union node *cmd, int flags)
11076 fs.fd[0] = cmdentry.u.index; 11052 fs.fd[0] = cmdentry.u.index;
11077 jp = makejob(/*cmd,*/ 1); 11053 jp = makejob(/*cmd,*/ 1);
11078 spawn_forkshell(&fs, jp, cmd, FORK_FG); 11054 spawn_forkshell(&fs, jp, cmd, FORK_FG);
11079 TRACE(("forked child exited with %d\n", status));
11080 break; 11055 break;
11081 } 11056 }
11082#else 11057#else
@@ -11087,7 +11062,6 @@ evalcommand(union node *cmd, int flags)
11087 jp = makejob(/*cmd,*/ 1); 11062 jp = makejob(/*cmd,*/ 1);
11088 if (forkshell(jp, cmd, FORK_FG) != 0) { 11063 if (forkshell(jp, cmd, FORK_FG) != 0) {
11089 /* parent */ 11064 /* parent */
11090 TRACE(("forked child exited with %d\n", status));
11091 break; 11065 break;
11092 } 11066 }
11093 /* child */ 11067 /* child */
@@ -11114,6 +11088,8 @@ evalcommand(union node *cmd, int flags)
11114 } /* switch */ 11088 } /* switch */
11115 11089
11116 status = waitforjob(jp); 11090 status = waitforjob(jp);
11091 if (jp)
11092 TRACE(("forked child exited with %d\n", status));
11117 FORCE_INT_ON; 11093 FORCE_INT_ON;
11118 11094
11119 out: 11095 out: