[git commit] ash: more general format ${var:EXPR:EXPR}

Denys Vlasenko vda.linux at googlemail.com
Mon Jul 17 15:49:11 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=826360ff238eb23191950dd4c5051195eab9733a
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
subevalvar                                          1171    1202     +31
localcmd                                             364     366      +2

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                              | 43 +++++++++++++++++++-------------
 shell/ash_test/ash-vars/var_bash1b.right | 23 +++++++++++++++++
 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 eb5156b..aaf0561 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 0000000..fafc0f0
--- /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 0000000..efbdef3
--- /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:$?


More information about the busybox-cvs mailing list