aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c43
-rw-r--r--shell/ash_test/ash-vars/var_bash1b.right23
-rwxr-xr-xshell/ash_test/ash-vars/var_bash1b.tests24
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 @@
1all |0123456
24: |456
34:2 |45
44:-1 |45
54:-2 |4
64:-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 |
23Ok: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 @@
1set -- 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}
14i=2; echo "-4:i=2 |"${1: -4:i}
15i=-2; echo "-4:i=-2|"${1: -4:i}
16i=-3; echo "-4:i=-3|"${1: -4:i}
17i=-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}
24echo Ok:$?