aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c332
1 files changed, 154 insertions, 178 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 03864c667..425da6bb6 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6035,6 +6035,7 @@ static int substr_atoi(const char *s)
6035#define EXP_WORD 0x40 /* expand word in parameter expansion */ 6035#define EXP_WORD 0x40 /* expand word in parameter expansion */
6036#define EXP_QUOTED 0x100 /* expand word in double quotes */ 6036#define EXP_QUOTED 0x100 /* expand word in double quotes */
6037#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */ 6037#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
6038#define EXP_DISCARD 0x400 /* discard result of expansion */
6038 6039
6039/* 6040/*
6040 * rmescape() flags 6041 * rmescape() flags
@@ -6452,13 +6453,15 @@ removerecordregions(int endoff)
6452} 6453}
6453 6454
6454static char * 6455static char *
6455exptilde(char *startp, char *p, int flag) 6456exptilde(char *startp, int flag)
6456{ 6457{
6457 unsigned char c; 6458 unsigned char c;
6458 char *name; 6459 char *name;
6459 struct passwd *pw; 6460 struct passwd *pw;
6460 const char *home; 6461 const char *home;
6462 char *p;
6461 6463
6464 p = startp;
6462 name = p + 1; 6465 name = p + 1;
6463 6466
6464 while ((c = *++p) != '\0') { 6467 while ((c = *++p) != '\0') {
@@ -6477,6 +6480,8 @@ exptilde(char *startp, char *p, int flag)
6477 } 6480 }
6478 } 6481 }
6479 done: 6482 done:
6483 if (flag & EXP_DISCARD)
6484 goto out;
6480 *p = '\0'; 6485 *p = '\0';
6481 if (*name == '\0') { 6486 if (*name == '\0') {
6482 home = lookupvar("HOME"); 6487 home = lookupvar("HOME");
@@ -6486,13 +6491,13 @@ exptilde(char *startp, char *p, int flag)
6486 goto lose; 6491 goto lose;
6487 home = pw->pw_dir; 6492 home = pw->pw_dir;
6488 } 6493 }
6494 *p = c;
6489 if (!home) 6495 if (!home)
6490 goto lose; 6496 goto lose;
6491 *p = c;
6492 strtodest(home, flag | EXP_QUOTED); 6497 strtodest(home, flag | EXP_QUOTED);
6498 out:
6493 return p; 6499 return p;
6494 lose: 6500 lose:
6495 *p = c;
6496 return startp; 6501 return startp;
6497} 6502}
6498 6503
@@ -6591,6 +6596,9 @@ expbackq(union node *cmd, int flag)
6591 int startloc; 6596 int startloc;
6592 struct stackmark smark; 6597 struct stackmark smark;
6593 6598
6599 if (flag & EXP_DISCARD)
6600 goto out;
6601
6594 INT_OFF; 6602 INT_OFF;
6595 startloc = expdest - (char *)stackblock(); 6603 startloc = expdest - (char *)stackblock();
6596 pushstackmark(&smark, startloc); 6604 pushstackmark(&smark, startloc);
@@ -6632,64 +6640,57 @@ expbackq(union node *cmd, int flag)
6632 (int)((dest - (char *)stackblock()) - startloc), 6640 (int)((dest - (char *)stackblock()) - startloc),
6633 (int)((dest - (char *)stackblock()) - startloc), 6641 (int)((dest - (char *)stackblock()) - startloc),
6634 stackblock() + startloc)); 6642 stackblock() + startloc));
6643
6644 out:
6645 argbackq = argbackq->next;
6635} 6646}
6636 6647
6648/* expari needs it */
6649static char *argstr(char *p, int flag);
6650
6637#if ENABLE_FEATURE_SH_MATH 6651#if ENABLE_FEATURE_SH_MATH
6638/* 6652/*
6639 * Expand arithmetic expression. Backup to start of expression, 6653 * Expand arithmetic expression. Backup to start of expression,
6640 * evaluate, place result in (backed up) result, adjust string position. 6654 * evaluate, place result in (backed up) result, adjust string position.
6641 */ 6655 */
6642static void 6656static char *
6643expari(int flag) 6657expari(char *start, int flag)
6644{ 6658{
6645 char *p, *start; 6659 struct stackmark sm;
6646 int begoff; 6660 int begoff;
6661 int endoff;
6647 int len; 6662 int len;
6663 arith_t result;
6664 char *p;
6648 6665
6649 /* ifsfree(); */ 6666 p = stackblock();
6650 6667 begoff = expdest - p;
6651 /* 6668 p = argstr(start, flag & EXP_DISCARD);
6652 * This routine is slightly over-complicated for
6653 * efficiency. Next we scan backwards looking for the
6654 * start of arithmetic.
6655 */
6656 start = stackblock();
6657 p = expdest - 1;
6658 *p = '\0';
6659 p--;
6660 while (1) {
6661 int esc;
6662
6663 while ((unsigned char)*p != CTLARI) {
6664 p--;
6665#if DEBUG
6666 if (p < start) {
6667 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6668 }
6669#endif
6670 }
6671
6672 esc = esclen(start, p);
6673 if (!(esc % 2)) {
6674 break;
6675 }
6676 6669
6677 p -= esc + 1; 6670 if (flag & EXP_DISCARD)
6678 } 6671 goto out;
6679 6672
6680 begoff = p - start; 6673 start = stackblock();
6674 endoff = expdest - start;
6675 start += begoff;
6676 STADJUST(start - expdest, expdest);
6681 6677
6682 removerecordregions(begoff); 6678 removerecordregions(begoff);
6683 6679
6684 expdest = p;
6685
6686 if (flag & QUOTES_ESC) 6680 if (flag & QUOTES_ESC)
6687 rmescapes(p + 1, 0, NULL); 6681 rmescapes(start, 0, NULL);
6682
6683 pushstackmark(&sm, endoff);
6684 result = ash_arith(start);
6685 popstackmark(&sm);
6688 6686
6689 len = cvtnum(ash_arith(p + 1), flag); 6687 len = cvtnum(result, flag);
6690 6688
6691 if (!(flag & EXP_QUOTED)) 6689 if (!(flag & EXP_QUOTED))
6692 recordregion(begoff, begoff + len, 0); 6690 recordregion(begoff, begoff + len, 0);
6691
6692 out:
6693 return p;
6693} 6694}
6694#endif 6695#endif
6695 6696
@@ -6701,7 +6702,7 @@ static char *evalvar(char *p, int flags);
6701 * characters to allow for further processing. Otherwise treat 6702 * characters to allow for further processing. Otherwise treat
6702 * $@ like $* since no splitting will be performed. 6703 * $@ like $* since no splitting will be performed.
6703 */ 6704 */
6704static void 6705static char *
6705argstr(char *p, int flag) 6706argstr(char *p, int flag)
6706{ 6707{
6707 static const char spclchars[] ALIGN1 = { 6708 static const char spclchars[] ALIGN1 = {
@@ -6713,6 +6714,7 @@ argstr(char *p, int flag)
6713 CTLVAR, 6714 CTLVAR,
6714 CTLBACKQ, 6715 CTLBACKQ,
6715#if ENABLE_FEATURE_SH_MATH 6716#if ENABLE_FEATURE_SH_MATH
6717 CTLARI,
6716 CTLENDARI, 6718 CTLENDARI,
6717#endif 6719#endif
6718 '\0' 6720 '\0'
@@ -6723,41 +6725,45 @@ argstr(char *p, int flag)
6723 size_t length; 6725 size_t length;
6724 int startloc; 6726 int startloc;
6725 6727
6726 if (!(flag & EXP_VARTILDE)) { 6728 reject += !!(flag & EXP_VARTILDE2);
6727 reject += 2; 6729 reject += flag & EXP_VARTILDE ? 0 : 2;
6728 } else if (flag & EXP_VARTILDE2) {
6729 reject++;
6730 }
6731 inquotes = 0; 6730 inquotes = 0;
6732 length = 0; 6731 length = 0;
6733 if (flag & EXP_TILDE) { 6732 if (flag & EXP_TILDE) {
6734 char *q;
6735
6736 flag &= ~EXP_TILDE; 6733 flag &= ~EXP_TILDE;
6737 tilde: 6734 tilde:
6738 q = p; 6735 if (*p == '~')
6739 if (*q == '~') 6736 p = exptilde(p, flag);
6740 p = exptilde(p, q, flag);
6741 } 6737 }
6742 start: 6738 start:
6743 startloc = expdest - (char *)stackblock(); 6739 startloc = expdest - (char *)stackblock();
6744 for (;;) { 6740 for (;;) {
6741 int end;
6745 unsigned char c; 6742 unsigned char c;
6746 6743
6747 length += strcspn(p + length, reject); 6744 length += strcspn(p + length, reject);
6745 end = 0;
6748 c = p[length]; 6746 c = p[length];
6749 if (c) { 6747 if (!(c & 0x80)
6750 if (!(c & 0x80) 6748 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6751 IF_FEATURE_SH_MATH(|| c == CTLENDARI) 6749 || c == CTLENDVAR
6752 ) { 6750 ) {
6753 /* c == '=' || c == ':' || c == CTLENDARI */ 6751 /*
6754 length++; 6752 * c == '=' || c == ':' || c == '\0' ||
6755 } 6753 * c == CTLENDARI || c == CTLENDVAR
6754 */
6755 length++;
6756 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6757 end = !!((c - 1) & 0x80);
6756 } 6758 }
6757 if (length > 0) { 6759 if (length > 0 && !(flag & EXP_DISCARD)) {
6758 int newloc; 6760 int newloc;
6759 expdest = stnputs(p, length, expdest); 6761 char *q;
6760 newloc = expdest - (char *)stackblock(); 6762
6763 q = stnputs(p, length, expdest);
6764 q[-1] &= end - 1;
6765 expdest = q - (flag & EXP_WORD ? end : 0);
6766 newloc = q - (char *)stackblock() - end;
6761 if (breakall && !inquotes && newloc > startloc) { 6767 if (breakall && !inquotes && newloc > startloc) {
6762 recordregion(startloc, newloc, 0); 6768 recordregion(startloc, newloc, 0);
6763 } 6769 }
@@ -6766,14 +6772,11 @@ argstr(char *p, int flag)
6766 p += length + 1; 6772 p += length + 1;
6767 length = 0; 6773 length = 0;
6768 6774
6775 if (end)
6776 break;
6777
6769 switch (c) { 6778 switch (c) {
6770 case '\0':
6771 goto breakloop;
6772 case '=': 6779 case '=':
6773 if (flag & EXP_VARTILDE2) {
6774 p--;
6775 continue;
6776 }
6777 flag |= EXP_VARTILDE2; 6780 flag |= EXP_VARTILDE2;
6778 reject++; 6781 reject++;
6779 /* fall through */ 6782 /* fall through */
@@ -6786,11 +6789,6 @@ argstr(char *p, int flag)
6786 goto tilde; 6789 goto tilde;
6787 } 6790 }
6788 continue; 6791 continue;
6789 }
6790
6791 switch (c) {
6792 case CTLENDVAR: /* ??? */
6793 goto breakloop;
6794 case CTLQUOTEMARK: 6792 case CTLQUOTEMARK:
6795 /* "$@" syntax adherence hack */ 6793 /* "$@" syntax adherence hack */
6796 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { 6794 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
@@ -6816,17 +6814,15 @@ argstr(char *p, int flag)
6816 goto start; 6814 goto start;
6817 case CTLBACKQ: 6815 case CTLBACKQ:
6818 expbackq(argbackq->n, flag | inquotes); 6816 expbackq(argbackq->n, flag | inquotes);
6819 argbackq = argbackq->next;
6820 goto start; 6817 goto start;
6821#if ENABLE_FEATURE_SH_MATH 6818#if ENABLE_FEATURE_SH_MATH
6822 case CTLENDARI: 6819 case CTLARI:
6823 p--; 6820 p = expari(p, flag | inquotes);
6824 expari(flag | inquotes);
6825 goto start; 6821 goto start;
6826#endif 6822#endif
6827 } 6823 }
6828 } 6824 }
6829 breakloop: ; 6825 return p - 1;
6830} 6826}
6831 6827
6832static char * 6828static char *
@@ -6951,25 +6947,27 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
6951 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); 6947 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6952} 6948}
6953 6949
6954static const char * 6950static char *
6955subevalvar(char *p, char *str, int strloc, int subtype, 6951subevalvar(char *start, char *str, int strloc,
6956 int startloc, int varflags, int flag) 6952 int startloc, int varflags, int flag)
6957{ 6953{
6958 struct nodelist *saveargbackq = argbackq; 6954 int subtype = varflags & VSTYPE;
6959 int quotes = flag & QUOTES_ESC; 6955 int quotes = flag & QUOTES_ESC;
6960 char *startp; 6956 char *startp;
6961 char *loc; 6957 char *loc;
6962 char *rmesc, *rmescend; 6958 char *rmesc, *rmescend;
6963 int amount, resetloc; 6959 long amount;
6960 int resetloc;
6964 int argstr_flags; 6961 int argstr_flags;
6965 IF_BASH_PATTERN_SUBST(int workloc;) 6962 IF_BASH_PATTERN_SUBST(int workloc;)
6966 IF_BASH_PATTERN_SUBST(int slash_pos;) 6963 IF_BASH_PATTERN_SUBST(int slash_pos;)
6967 IF_BASH_PATTERN_SUBST(char *repl;) 6964 IF_BASH_PATTERN_SUBST(char *repl;)
6968 int zero; 6965 int zero;
6969 char *(*scan)(char*, char*, char*, char*, int, int); 6966 char *(*scan)(char*, char*, char*, char*, int, int);
6967 char *p;
6970 6968
6971 //bb_error_msg("subevalvar(p:'%s',str:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 6969 //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
6972 // p, str, strloc, subtype, startloc, varflags, quotes); 6970 // start, str, strloc, startloc, varflags, quotes);
6973 6971
6974#if BASH_PATTERN_SUBST 6972#if BASH_PATTERN_SUBST
6975 /* For "${v/pattern/repl}", we must find the delimiter _before_ 6973 /* For "${v/pattern/repl}", we must find the delimiter _before_
@@ -6979,7 +6977,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6979 repl = NULL; 6977 repl = NULL;
6980 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 6978 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6981 /* Find '/' and replace with NUL */ 6979 /* Find '/' and replace with NUL */
6982 repl = p; 6980 repl = start;
6983 /* The pattern can't be empty. 6981 /* The pattern can't be empty.
6984 * IOW: if the first char after "${v//" is a slash, 6982 * IOW: if the first char after "${v//" is a slash,
6985 * it does not terminate the pattern - it's the first char of the pattern: 6983 * it does not terminate the pattern - it's the first char of the pattern:
@@ -7004,17 +7002,17 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7004 } 7002 }
7005 } 7003 }
7006#endif 7004#endif
7007 argstr_flags = EXP_TILDE; 7005 argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7008 if (subtype != VSASSIGN 7006 if (!str
7009 && subtype != VSQUESTION
7010#if BASH_SUBSTR 7007#if BASH_SUBSTR
7011 && subtype != VSSUBSTR 7008 && subtype != VSSUBSTR
7012#endif 7009#endif
7013 ) { 7010 ) {
7014 /* EXP_CASE keeps CTLESC's */ 7011 /* EXP_CASE keeps CTLESC's */
7015 argstr_flags = EXP_TILDE | EXP_CASE; 7012 argstr_flags |= EXP_CASE;
7016 } 7013 }
7017 argstr(p, argstr_flags); 7014 p = argstr(start, argstr_flags);
7015
7018 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc); 7016 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7019#if BASH_PATTERN_SUBST 7017#if BASH_PATTERN_SUBST
7020 slash_pos = -1; 7018 slash_pos = -1;
@@ -7022,24 +7020,25 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7022 slash_pos = expdest - ((char *)stackblock() + strloc); 7020 slash_pos = expdest - ((char *)stackblock() + strloc);
7023 STPUTC('/', expdest); 7021 STPUTC('/', expdest);
7024 //bb_error_msg("repl+1:'%s'", repl + 1); 7022 //bb_error_msg("repl+1:'%s'", repl + 1);
7025 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ 7023 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7026 *repl = '/'; 7024 *repl = '/';
7027 } 7025 }
7028#endif 7026#endif
7029 STPUTC('\0', expdest); 7027 if (flag & EXP_DISCARD)
7030 argbackq = saveargbackq; 7028 return p;
7029
7031 startp = (char *)stackblock() + startloc; 7030 startp = (char *)stackblock() + startloc;
7032 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc); 7031 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7033 7032
7034 switch (subtype) { 7033 switch (subtype) {
7035 case VSASSIGN: 7034 case VSASSIGN:
7036 setvar0(str, startp); 7035 setvar0(str, startp);
7037 amount = startp - expdest; 7036
7038 STADJUST(amount, expdest); 7037 loc = startp;
7039 return startp; 7038 goto out;
7040 7039
7041 case VSQUESTION: 7040 case VSQUESTION:
7042 varunset(p, str, startp, varflags); 7041 varunset(start, str, startp, varflags);
7043 /* NOTREACHED */ 7042 /* NOTREACHED */
7044 7043
7045#if BASH_SUBSTR 7044#if BASH_SUBSTR
@@ -7110,9 +7109,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7110 *loc++ = *vstr++; 7109 *loc++ = *vstr++;
7111 } 7110 }
7112 *loc = '\0'; 7111 *loc = '\0';
7113 amount = loc - expdest; 7112 goto out;
7114 STADJUST(amount, expdest);
7115 return loc;
7116 } 7113 }
7117#endif /* BASH_SUBSTR */ 7114#endif /* BASH_SUBSTR */
7118 } 7115 }
@@ -7178,7 +7175,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7178 7175
7179 /* If there's no pattern to match, return the expansion unmolested */ 7176 /* If there's no pattern to match, return the expansion unmolested */
7180 if (str[0] == '\0') 7177 if (str[0] == '\0')
7181 return NULL; 7178 goto out1;
7182 7179
7183 len = 0; 7180 len = 0;
7184 idx = startp; 7181 idx = startp;
@@ -7259,9 +7256,8 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7259 startp = (char *)stackblock() + startloc; 7256 startp = (char *)stackblock() + startloc;
7260 memmove(startp, (char *)stackblock() + workloc, len + 1); 7257 memmove(startp, (char *)stackblock() + workloc, len + 1);
7261 //bb_error_msg("startp:'%s'", startp); 7258 //bb_error_msg("startp:'%s'", startp);
7262 amount = expdest - (startp + len); 7259 loc = startp + len;
7263 STADJUST(-amount, expdest); 7260 goto out;
7264 return startp;
7265 } 7261 }
7266#endif /* BASH_PATTERN_SUBST */ 7262#endif /* BASH_PATTERN_SUBST */
7267 7263
@@ -7282,10 +7278,17 @@ subevalvar(char *p, char *str, int strloc, int subtype,
7282 loc = startp + (str - loc) - 1; 7278 loc = startp + (str - loc) - 1;
7283 } 7279 }
7284 *loc = '\0'; 7280 *loc = '\0';
7285 amount = loc - expdest; 7281 } else
7286 STADJUST(amount, expdest); 7282 loc = str - 1;
7287 } 7283
7288 return loc; 7284 out:
7285 amount = loc - expdest;
7286 STADJUST(amount, expdest);
7287 out1:
7288 /* Remove any recorded regions beyond start of variable */
7289 removerecordregions(startloc);
7290
7291 return p;
7289} 7292}
7290 7293
7291/* 7294/*
@@ -7310,7 +7313,14 @@ varvalue(char *name, int varflags, int flags, int quoted)
7310 ssize_t len = 0; 7313 ssize_t len = 0;
7311 int sep; 7314 int sep;
7312 int subtype = varflags & VSTYPE; 7315 int subtype = varflags & VSTYPE;
7313 int discard = subtype == VSPLUS || subtype == VSLENGTH; 7316 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7317
7318 if (!subtype) {
7319 if (discard)
7320 return -1;
7321
7322 raise_error_syntax("bad substitution");
7323 }
7314 7324
7315 flags |= EXP_KEEPNUL; 7325 flags |= EXP_KEEPNUL;
7316 flags &= discard ? ~QUOTES_ESC : ~0; 7326 flags &= discard ? ~QUOTES_ESC : ~0;
@@ -7427,6 +7437,7 @@ varvalue(char *name, int varflags, int flags, int quoted)
7427 7437
7428 if (discard) 7438 if (discard)
7429 STADJUST(-len, expdest); 7439 STADJUST(-len, expdest);
7440
7430 return len; 7441 return len;
7431} 7442}
7432 7443
@@ -7439,18 +7450,15 @@ evalvar(char *p, int flag)
7439{ 7450{
7440 char varflags; 7451 char varflags;
7441 char subtype; 7452 char subtype;
7442 int quoted;
7443 char *var; 7453 char *var;
7444 int patloc; 7454 int patloc;
7445 int startloc; 7455 int startloc;
7446 ssize_t varlen; 7456 ssize_t varlen;
7457 int quoted;
7447 7458
7448 varflags = (unsigned char) *p++; 7459 varflags = (unsigned char) *p++;
7449 subtype = varflags & VSTYPE; 7460 subtype = varflags & VSTYPE;
7450 7461
7451 if (!subtype)
7452 raise_error_syntax("bad substitution");
7453
7454 quoted = flag & EXP_QUOTED; 7462 quoted = flag & EXP_QUOTED;
7455 var = p; 7463 var = p;
7456 startloc = expdest - (char *)stackblock(); 7464 startloc = expdest - (char *)stackblock();
@@ -7461,35 +7469,29 @@ evalvar(char *p, int flag)
7461 if (varflags & VSNUL) 7469 if (varflags & VSNUL)
7462 varlen--; 7470 varlen--;
7463 7471
7464 if (subtype == VSPLUS) { 7472 switch (subtype) {
7473 case VSPLUS:
7465 varlen = -1 - varlen; 7474 varlen = -1 - varlen;
7466 goto vsplus; 7475 /* fall through */
7467 } 7476 case 0:
7468 7477 case VSMINUS:
7469 if (subtype == VSMINUS) { 7478 p = argstr(p, flag | EXP_TILDE | EXP_WORD);
7470 vsplus: 7479 if (varlen < 0)
7471 if (varlen < 0) { 7480 return p;
7472 argstr(
7473 p,
7474 flag | EXP_TILDE | EXP_WORD
7475 );
7476 goto end;
7477 }
7478 goto record; 7481 goto record;
7479 }
7480 7482
7481 if (subtype == VSASSIGN || subtype == VSQUESTION) { 7483 case VSASSIGN:
7484 case VSQUESTION:
7482 if (varlen >= 0) 7485 if (varlen >= 0)
7483 goto record; 7486 goto record;
7484 7487
7485 subevalvar(p, var, 0, subtype, startloc, varflags, 7488 p = subevalvar(p, var, 0, startloc, varflags,
7486 flag & ~QUOTES_ESC); 7489 flag & ~QUOTES_ESC);
7490
7491 if (flag & EXP_DISCARD)
7492 return p;
7493
7487 varflags &= ~VSNUL; 7494 varflags &= ~VSNUL;
7488 /*
7489 * Remove any recorded regions beyond
7490 * start of variable
7491 */
7492 removerecordregions(startloc);
7493 goto again; 7495 goto again;
7494 } 7496 }
7495 7497
@@ -7497,20 +7499,15 @@ evalvar(char *p, int flag)
7497 varunset(p, var, 0, 0); 7499 varunset(p, var, 0, 0);
7498 7500
7499 if (subtype == VSLENGTH) { 7501 if (subtype == VSLENGTH) {
7502 p++;
7503 if (flag & EXP_DISCARD)
7504 return p;
7500 cvtnum(varlen > 0 ? varlen : 0, flag); 7505 cvtnum(varlen > 0 ? varlen : 0, flag);
7501 goto record; 7506 goto record;
7502 } 7507 }
7503 7508
7504 if (subtype == VSNORMAL) { 7509 if (subtype == VSNORMAL)
7505 record: 7510 goto record;
7506 if (quoted) {
7507 quoted = *var == '@' && shellparam.nparam;
7508 if (!quoted)
7509 goto end;
7510 }
7511 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7512 goto end;
7513 }
7514 7511
7515#if DEBUG 7512#if DEBUG
7516 switch (subtype) { 7513 switch (subtype) {
@@ -7531,46 +7528,28 @@ evalvar(char *p, int flag)
7531 } 7528 }
7532#endif 7529#endif
7533 7530
7534 if (varlen >= 0) { 7531 flag |= varlen < 0 ? EXP_DISCARD : 0;
7532 if (!(flag & EXP_DISCARD)) {
7535 /* 7533 /*
7536 * Terminate the string and start recording the pattern 7534 * Terminate the string and start recording the pattern
7537 * right after it 7535 * right after it
7538 */ 7536 */
7539 STPUTC('\0', expdest); 7537 STPUTC('\0', expdest);
7540 patloc = expdest - (char *)stackblock();
7541 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7542 startloc, varflags, flag)) {
7543 int amount = expdest - (
7544 (char *)stackblock() + patloc - 1
7545 );
7546 STADJUST(-amount, expdest);
7547 }
7548 /* Remove any recorded regions beyond start of variable */
7549 removerecordregions(startloc);
7550 goto record;
7551 } 7538 }
7552 7539
7553 varlen = 0; 7540 patloc = expdest - (char *)stackblock();
7541 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
7554 7542
7555 end: 7543 record:
7556 if (subtype != VSNORMAL) { /* skip to end of alternative */ 7544 if (flag & EXP_DISCARD)
7557 int nesting = 1; 7545 return p;
7558 for (;;) { 7546
7559 unsigned char c = *p++; 7547 if (quoted) {
7560 if (c == CTLESC) 7548 quoted = *var == '@' && shellparam.nparam;
7561 p++; 7549 if (!quoted)
7562 else if (c == CTLBACKQ) { 7550 return p;
7563 if (varlen >= 0)
7564 argbackq = argbackq->next;
7565 } else if (c == CTLVAR) {
7566 if ((*p++ & VSTYPE) != VSNORMAL)
7567 nesting++;
7568 } else if (c == CTLENDVAR) {
7569 if (--nesting == 0)
7570 break;
7571 }
7572 }
7573 } 7551 }
7552 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7574 return p; 7553 return p;
7575} 7554}
7576 7555
@@ -7983,13 +7962,11 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7983 STARTSTACKSTR(expdest); 7962 STARTSTACKSTR(expdest);
7984 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); 7963 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7985 argstr(arg->narg.text, flag); 7964 argstr(arg->narg.text, flag);
7986 p = _STPUTC('\0', expdest);
7987 expdest = p - 1;
7988 if (arglist == NULL) { 7965 if (arglist == NULL) {
7989 /* here document expanded */ 7966 /* here document expanded */
7990 goto out; 7967 goto out;
7991 } 7968 }
7992 p = grabstackstr(p); 7969 p = grabstackstr(expdest);
7993 TRACE(("expandarg: p:'%s'\n", p)); 7970 TRACE(("expandarg: p:'%s'\n", p));
7994 exparg.lastp = &exparg.list; 7971 exparg.lastp = &exparg.list;
7995 /* 7972 /*
@@ -8050,7 +8027,6 @@ casematch(union node *pattern, char *val)
8050 argbackq = pattern->narg.backquote; 8027 argbackq = pattern->narg.backquote;
8051 STARTSTACKSTR(expdest); 8028 STARTSTACKSTR(expdest);
8052 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 8029 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8053 STACKSTRNUL(expdest);
8054 ifsfree(); 8030 ifsfree();
8055 result = patmatch(stackblock(), val); 8031 result = patmatch(stackblock(), val);
8056 popstackmark(&smark); 8032 popstackmark(&smark);