summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 16:46:57 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 16:46:57 +0200
commite32b6503e75d5bcbf8ffff69cafb09523ff2b482 (patch)
treed0d68a95f68d55215b86f792e11e89b1e75b1ed1
parent203fd7bc66b869e5022ad33d26065e69eaaaf66b (diff)
hush: support ${VAR:N:-M}
function old new delta expand_one_var 1602 1615 +13 builtin_type 114 116 +2 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c48
-rw-r--r--shell/hush_test/hush-vars/var_bash1b.right23
-rwxr-xr-xshell/hush_test/hush-vars/var_bash1b.tests24
3 files changed, 72 insertions, 23 deletions
diff --git a/shell/hush.c b/shell/hush.c
index fd2a3d0f5..836f3b83c 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -5723,32 +5723,34 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
if (errmsg)
goto arith_err;
debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
- if (len >= 0) {
- if (beg < 0) {
- /* negative beg counts from the end */
- beg = (arith_t)strlen(val) + beg;
- if (beg < 0) /* ${v: -999999} is "" */
- beg = len = 0;
- }
- debug_printf_varexp("from val:'%s'\n", val);
- if (len == 0 || !val || beg >= strlen(val)) {
+ if (beg < 0) {
+ /* negative beg counts from the end */
+ beg = (arith_t)strlen(val) + beg;
+ if (beg < 0) /* ${v: -999999} is "" */
+ beg = len = 0;
+ }
+ debug_printf_varexp("from val:'%s'\n", val);
+ if (len < 0) {
+ /* in bash, len=-n means strlen()-n */
+ len = (arith_t)strlen(val) - beg + len;
+ if (len < 0) /* bash compat */
+ die_if_script("%s: substring expression < 0", var);
+ }
+ if (len == 0 || !val || beg >= strlen(val)) {
arith_err:
- val = NULL;
- } else {
- /* Paranoia. What if user entered 9999999999999
- * which fits in arith_t but not int? */
- if (len >= INT_MAX)
- len = INT_MAX;
- val = to_be_freed = xstrndup(val + beg, len);
- }
- debug_printf_varexp("val:'%s'\n", val);
- } else
-//TODO: in bash, len=-n means strlen()-n
-#endif /* HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH */
- {
- die_if_script("malformed ${%s:...}", var);
val = NULL;
+ } else {
+ /* Paranoia. What if user entered 9999999999999
+ * which fits in arith_t but not int? */
+ if (len >= INT_MAX)
+ len = INT_MAX;
+ val = to_be_freed = xstrndup(val + beg, len);
}
+ debug_printf_varexp("val:'%s'\n", val);
+#else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */
+ die_if_script("malformed ${%s:...}", var);
+ val = NULL;
+#endif
} else { /* one of "-=+?" */
/* Standard-mandated substitution ops:
* ${var?word} - indicate error if unset
diff --git a/shell/hush_test/hush-vars/var_bash1b.right b/shell/hush_test/hush-vars/var_bash1b.right
new file mode 100644
index 000000000..fafc0f07c
--- /dev/null
+++ b/shell/hush_test/hush-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/hush_test/hush-vars/var_bash1b.tests b/shell/hush_test/hush-vars/var_bash1b.tests
new file mode 100755
index 000000000..efbdef35c
--- /dev/null
+++ b/shell/hush_test/hush-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:$?