diff options
-rw-r--r-- | shell/ash.c | 332 |
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 | ||
6454 | static char * | 6455 | static char * |
6455 | exptilde(char *startp, char *p, int flag) | 6456 | exptilde(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 */ | ||
6649 | static 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 | */ |
6642 | static void | 6656 | static char * |
6643 | expari(int flag) | 6657 | expari(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 | */ |
6704 | static void | 6705 | static char * |
6705 | argstr(char *p, int flag) | 6706 | argstr(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 | ||
6832 | static char * | 6828 | static 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 | ||
6954 | static const char * | 6950 | static char * |
6955 | subevalvar(char *p, char *str, int strloc, int subtype, | 6951 | subevalvar(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); |