summaryrefslogtreecommitdiffhomepage
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 17:49:11 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 17:49:11 +0200
commit826360ff238eb23191950dd4c5051195eab9733a (patch)
treed9dbd7da77e985e181af0b8ad406d467379b498b /shell
parent4f8079de877cf2b7206e4cabaf465fb7d8cc4f62 (diff)
ash: more general format ${var:EXPR:EXPR}
function old new delta subevalvar 1171 1202 +31 localcmd 364 366 +2 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-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,
char *loc;
char *rmesc, *rmescend;
char *str;
- IF_BASH_SUBSTR(int pos, len, orig_len;)
int amount, resetloc;
IF_BASH_PATTERN_SUBST(int workloc;)
IF_BASH_PATTERN_SUBST(char *repl = NULL;)
@@ -6641,14 +6640,23 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
/* NOTREACHED */
#if BASH_SUBSTR
- case VSSUBSTR:
-//TODO: support more general format ${v:EXPR:EXPR},
-// where EXPR follows $(()) rules
+ case VSSUBSTR: {
+ int pos, len, orig_len;
+ char *colon;
+
loc = str = stackblock() + strloc;
+
+# if !ENABLE_FEATURE_SH_MATH
+# define ash_arith number
+# endif
/* Read POS in ${var:POS:LEN} */
- pos = atoi(loc); /* number(loc) errors out on "1:4" */
- len = str - startp - 1;
+ colon = strchr(loc, ':');
+ if (colon) *colon = '\0';
+ pos = ash_arith(loc);
+ if (colon) *colon = ':';
+ /* Read LEN in ${var:POS:LEN} */
+ len = str - startp - 1;
/* *loc != '\0', guaranteed by parser */
if (quotes) {
char *ptr;
@@ -6662,26 +6670,21 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
}
}
orig_len = len;
-
if (*loc++ == ':') {
/* ${var::LEN} */
- len = number(loc);
+ len = ash_arith(loc);
} else {
/* Skip POS in ${var:POS:LEN} */
len = orig_len;
while (*loc && *loc != ':') {
- /* TODO?
- * bash complains on: var=qwe; echo ${var:1a:123}
- if (!isdigit(*loc))
- ash_msg_and_raise_error(msg_illnum, str);
- */
loc++;
}
if (*loc++ == ':') {
- len = number(loc);
+ len = ash_arith(loc);
}
-//TODO: number() chokes on "-n". In bash, LEN=-n means strlen()-n
}
+# undef ash_arith
+
if (pos < 0) {
/* ${VAR:$((-n)):l} starts n chars from the end */
pos = orig_len + pos;
@@ -6689,12 +6692,16 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
if ((unsigned)pos >= orig_len) {
/* apart from obvious ${VAR:999999:l},
* covers ${VAR:$((-9999999)):l} - result is ""
- * (bash-compat)
+ * (bash compat)
*/
pos = 0;
len = 0;
}
- if (len > (orig_len - pos))
+ if (len < 0) {
+ /* ${VAR:N:-M} sets LEN to strlen()-M */
+ len = (orig_len - pos) + len;
+ }
+ if ((unsigned)len > (orig_len - pos))
len = orig_len - pos;
for (str = startp; pos; str++, pos--) {
@@ -6710,6 +6717,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
amount = loc - expdest;
STADJUST(amount, expdest);
return loc;
+ }
#endif /* BASH_SUBSTR */
}
@@ -6754,6 +6762,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
#if BASH_PATTERN_SUBST
workloc = expdest - (char *)stackblock();
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
+ int len;
char *idx, *end;
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 @@
+all |0123456
+4: |456
+4:2 |45
+4:-1 |45
+4:-2 |4
+4:-3 |
+-4: |3456
+-4:2 |34
+-4:-1 |345
+-4:-2 |34
+-4:-3 |3
+-4:-4 |
+-4:i=2 |34
+-4:i=-2|34
+-4:i=-3|3
+-4:i=-4|
+-5: |23456
+-6: |123456
+-7: |0123456
+-8: |
+-9: |
+-9:-99 |
+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 @@
+set -- 0123456
+ echo "all |"$1
+ echo "4: |"${1:4}
+ echo "4:2 |"${1:4:2}
+ echo "4:-1 |"${1:4:-1}
+ echo "4:-2 |"${1:4:-2}
+ echo "4:-3 |"${1:4:-3}
+ echo "-4: |"${1: -4}
+ echo "-4:2 |"${1: -4:2}
+ echo "-4:-1 |"${1: -4:-1}
+ echo "-4:-2 |"${1: -4:-2}
+ echo "-4:-3 |"${1: -4:-3}
+ echo "-4:-4 |"${1: -4:-4}
+i=2; echo "-4:i=2 |"${1: -4:i}
+i=-2; echo "-4:i=-2|"${1: -4:i}
+i=-3; echo "-4:i=-3|"${1: -4:i}
+i=-4; echo "-4:i=-4|"${1: -4:i}
+ echo "-5: |"${1: -5}
+ echo "-6: |"${1: -6}
+ echo "-7: |"${1: -7}
+ echo "-8: |"${1: -8}
+ echo "-9: |"${1: -9}
+ echo "-9:-99 |"${1: -9:-99}
+echo Ok:$?