From 826360ff238eb23191950dd4c5051195eab9733a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 Jul 2017 17:49:11 +0200 Subject: [PATCH] ash: more general format ${var:EXPR:EXPR} function old new delta subevalvar 1171 1202 +31 localcmd 364 366 +2 Signed-off-by: Denys Vlasenko --- shell/ash.c | 47 ++++++++++++++---------- shell/ash_test/ash-vars/var_bash1b.right | 23 ++++++++++++ shell/ash_test/ash-vars/var_bash1b.tests | 24 ++++++++++++ 3 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 shell/ash_test/ash-vars/var_bash1b.right create mode 100755 shell/ash_test/ash-vars/var_bash1b.tests 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 - loc = str = stackblock() + strloc; - /* Read POS in ${var:POS:LEN} */ - pos = atoi(loc); /* number(loc) errors out on "1:4" */ - len = str - startp - 1; + 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} */ + 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:$?