diff options
-rw-r--r-- | shell/ash.c | 43 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var_bash1b.right | 23 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var_bash1b.tests | 24 |
3 files changed, 73 insertions, 17 deletions
diff --git a/shell/ash.c b/shell/ash.c index eb5156bea..aaf0561b8 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -6612,7 +6612,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6612 | char *loc; | 6612 | char *loc; |
6613 | char *rmesc, *rmescend; | 6613 | char *rmesc, *rmescend; |
6614 | char *str; | 6614 | char *str; |
6615 | IF_BASH_SUBSTR(int pos, len, orig_len;) | ||
6616 | int amount, resetloc; | 6615 | int amount, resetloc; |
6617 | IF_BASH_PATTERN_SUBST(int workloc;) | 6616 | IF_BASH_PATTERN_SUBST(int workloc;) |
6618 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) | 6617 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) |
@@ -6641,14 +6640,23 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6641 | /* NOTREACHED */ | 6640 | /* NOTREACHED */ |
6642 | 6641 | ||
6643 | #if BASH_SUBSTR | 6642 | #if BASH_SUBSTR |
6644 | case VSSUBSTR: | 6643 | case VSSUBSTR: { |
6645 | //TODO: support more general format ${v:EXPR:EXPR}, | 6644 | int pos, len, orig_len; |
6646 | // where EXPR follows $(()) rules | 6645 | char *colon; |
6646 | |||
6647 | loc = str = stackblock() + strloc; | 6647 | loc = str = stackblock() + strloc; |
6648 | |||
6649 | # if !ENABLE_FEATURE_SH_MATH | ||
6650 | # define ash_arith number | ||
6651 | # endif | ||
6648 | /* Read POS in ${var:POS:LEN} */ | 6652 | /* Read POS in ${var:POS:LEN} */ |
6649 | pos = atoi(loc); /* number(loc) errors out on "1:4" */ | 6653 | colon = strchr(loc, ':'); |
6650 | len = str - startp - 1; | 6654 | if (colon) *colon = '\0'; |
6655 | pos = ash_arith(loc); | ||
6656 | if (colon) *colon = ':'; | ||
6651 | 6657 | ||
6658 | /* Read LEN in ${var:POS:LEN} */ | ||
6659 | len = str - startp - 1; | ||
6652 | /* *loc != '\0', guaranteed by parser */ | 6660 | /* *loc != '\0', guaranteed by parser */ |
6653 | if (quotes) { | 6661 | if (quotes) { |
6654 | char *ptr; | 6662 | char *ptr; |
@@ -6662,26 +6670,21 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6662 | } | 6670 | } |
6663 | } | 6671 | } |
6664 | orig_len = len; | 6672 | orig_len = len; |
6665 | |||
6666 | if (*loc++ == ':') { | 6673 | if (*loc++ == ':') { |
6667 | /* ${var::LEN} */ | 6674 | /* ${var::LEN} */ |
6668 | len = number(loc); | 6675 | len = ash_arith(loc); |
6669 | } else { | 6676 | } else { |
6670 | /* Skip POS in ${var:POS:LEN} */ | 6677 | /* Skip POS in ${var:POS:LEN} */ |
6671 | len = orig_len; | 6678 | len = orig_len; |
6672 | while (*loc && *loc != ':') { | 6679 | while (*loc && *loc != ':') { |
6673 | /* TODO? | ||
6674 | * bash complains on: var=qwe; echo ${var:1a:123} | ||
6675 | if (!isdigit(*loc)) | ||
6676 | ash_msg_and_raise_error(msg_illnum, str); | ||
6677 | */ | ||
6678 | loc++; | 6680 | loc++; |
6679 | } | 6681 | } |
6680 | if (*loc++ == ':') { | 6682 | if (*loc++ == ':') { |
6681 | len = number(loc); | 6683 | len = ash_arith(loc); |
6682 | } | 6684 | } |
6683 | //TODO: number() chokes on "-n". In bash, LEN=-n means strlen()-n | ||
6684 | } | 6685 | } |
6686 | # undef ash_arith | ||
6687 | |||
6685 | if (pos < 0) { | 6688 | if (pos < 0) { |
6686 | /* ${VAR:$((-n)):l} starts n chars from the end */ | 6689 | /* ${VAR:$((-n)):l} starts n chars from the end */ |
6687 | pos = orig_len + pos; | 6690 | pos = orig_len + pos; |
@@ -6689,12 +6692,16 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6689 | if ((unsigned)pos >= orig_len) { | 6692 | if ((unsigned)pos >= orig_len) { |
6690 | /* apart from obvious ${VAR:999999:l}, | 6693 | /* apart from obvious ${VAR:999999:l}, |
6691 | * covers ${VAR:$((-9999999)):l} - result is "" | 6694 | * covers ${VAR:$((-9999999)):l} - result is "" |
6692 | * (bash-compat) | 6695 | * (bash compat) |
6693 | */ | 6696 | */ |
6694 | pos = 0; | 6697 | pos = 0; |
6695 | len = 0; | 6698 | len = 0; |
6696 | } | 6699 | } |
6697 | if (len > (orig_len - pos)) | 6700 | if (len < 0) { |
6701 | /* ${VAR:N:-M} sets LEN to strlen()-M */ | ||
6702 | len = (orig_len - pos) + len; | ||
6703 | } | ||
6704 | if ((unsigned)len > (orig_len - pos)) | ||
6698 | len = orig_len - pos; | 6705 | len = orig_len - pos; |
6699 | 6706 | ||
6700 | for (str = startp; pos; str++, pos--) { | 6707 | for (str = startp; pos; str++, pos--) { |
@@ -6710,6 +6717,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6710 | amount = loc - expdest; | 6717 | amount = loc - expdest; |
6711 | STADJUST(amount, expdest); | 6718 | STADJUST(amount, expdest); |
6712 | return loc; | 6719 | return loc; |
6720 | } | ||
6713 | #endif /* BASH_SUBSTR */ | 6721 | #endif /* BASH_SUBSTR */ |
6714 | } | 6722 | } |
6715 | 6723 | ||
@@ -6754,6 +6762,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6754 | #if BASH_PATTERN_SUBST | 6762 | #if BASH_PATTERN_SUBST |
6755 | workloc = expdest - (char *)stackblock(); | 6763 | workloc = expdest - (char *)stackblock(); |
6756 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { | 6764 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { |
6765 | int len; | ||
6757 | char *idx, *end; | 6766 | char *idx, *end; |
6758 | 6767 | ||
6759 | if (!repl) { | 6768 | if (!repl) { |
diff --git a/shell/ash_test/ash-vars/var_bash1b.right b/shell/ash_test/ash-vars/var_bash1b.right new file mode 100644 index 000000000..fafc0f07c --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1b.right | |||
@@ -0,0 +1,23 @@ | |||
1 | all |0123456 | ||
2 | 4: |456 | ||
3 | 4:2 |45 | ||
4 | 4:-1 |45 | ||
5 | 4:-2 |4 | ||
6 | 4:-3 | | ||
7 | -4: |3456 | ||
8 | -4:2 |34 | ||
9 | -4:-1 |345 | ||
10 | -4:-2 |34 | ||
11 | -4:-3 |3 | ||
12 | -4:-4 | | ||
13 | -4:i=2 |34 | ||
14 | -4:i=-2|34 | ||
15 | -4:i=-3|3 | ||
16 | -4:i=-4| | ||
17 | -5: |23456 | ||
18 | -6: |123456 | ||
19 | -7: |0123456 | ||
20 | -8: | | ||
21 | -9: | | ||
22 | -9:-99 | | ||
23 | Ok:0 | ||
diff --git a/shell/ash_test/ash-vars/var_bash1b.tests b/shell/ash_test/ash-vars/var_bash1b.tests new file mode 100755 index 000000000..efbdef35c --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1b.tests | |||
@@ -0,0 +1,24 @@ | |||
1 | set -- 0123456 | ||
2 | echo "all |"$1 | ||
3 | echo "4: |"${1:4} | ||
4 | echo "4:2 |"${1:4:2} | ||
5 | echo "4:-1 |"${1:4:-1} | ||
6 | echo "4:-2 |"${1:4:-2} | ||
7 | echo "4:-3 |"${1:4:-3} | ||
8 | echo "-4: |"${1: -4} | ||
9 | echo "-4:2 |"${1: -4:2} | ||
10 | echo "-4:-1 |"${1: -4:-1} | ||
11 | echo "-4:-2 |"${1: -4:-2} | ||
12 | echo "-4:-3 |"${1: -4:-3} | ||
13 | echo "-4:-4 |"${1: -4:-4} | ||
14 | i=2; echo "-4:i=2 |"${1: -4:i} | ||
15 | i=-2; echo "-4:i=-2|"${1: -4:i} | ||
16 | i=-3; echo "-4:i=-3|"${1: -4:i} | ||
17 | i=-4; echo "-4:i=-4|"${1: -4:i} | ||
18 | echo "-5: |"${1: -5} | ||
19 | echo "-6: |"${1: -6} | ||
20 | echo "-7: |"${1: -7} | ||
21 | echo "-8: |"${1: -8} | ||
22 | echo "-9: |"${1: -9} | ||
23 | echo "-9:-99 |"${1: -9:-99} | ||
24 | echo Ok:$? | ||