From 0a0acb55db8d7c4dec445573f1b0528d126b9e1f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Apr 2015 19:36:38 +0200 Subject: ash: fix handling of duplicate "local" Signed-off-by: Denys Vlasenko --- shell/ash.c | 51 +++++++++++++++++++++---------- shell/ash_test/ash-heredoc/heredoc1.right | 2 +- shell/ash_test/ash-vars/var3.right | 5 +++ shell/ash_test/ash-vars/var3.tests | 1 + 4 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 shell/ash_test/ash-vars/var3.right create mode 100755 shell/ash_test/ash-vars/var3.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index b568013b4..697a64fea 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2030,7 +2030,7 @@ varcmp(const char *p, const char *q) int c, d; while ((c = *p) == (d = *q)) { - if (!c || c == '=') + if (c == '\0' || c == '=') goto out; p++; q++; @@ -2247,7 +2247,7 @@ setvar(const char *name, const char *val, int flags) } static void FAST_FUNC -setvar2(const char *name, const char *val) +setvar0(const char *name, const char *val) { setvar(name, val, 0); } @@ -2310,7 +2310,7 @@ unsetvar(const char *s) free(vp); INT_ON; } else { - setvar2(s, 0); + setvar0(s, NULL); vp->flags &= ~VEXPORT; } ok: @@ -5505,7 +5505,7 @@ ash_arith(const char *s) arith_t result; math_state.lookupvar = lookupvar; - math_state.setvar = setvar2; + math_state.setvar = setvar0; //math_state.endofname = endofname; INT_OFF; @@ -6360,7 +6360,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, switch (subtype) { case VSASSIGN: - setvar2(varname, startp); + setvar0(varname, startp); amount = startp - expdest; STADJUST(amount, expdest); return startp; @@ -8591,7 +8591,7 @@ evalfor(union node *n, int flags) loopnest++; flags &= EV_TESTED; for (sp = arglist.list; sp; sp = sp->next) { - setvar2(n->nfor.var, sp->text); + setvar0(n->nfor.var, sp->text); evaltree(n->nfor.body, flags); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { @@ -8970,21 +8970,37 @@ mklocal(char *name) struct localvar *lvp; struct var **vpp; struct var *vp; + char *eq = strchr(name, '='); INT_OFF; - lvp = ckzalloc(sizeof(struct localvar)); + /* Cater for duplicate "local". Examples: + * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x + * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x + */ + lvp = localvars; + while (lvp) { + if (varcmp(lvp->vp->var_text, name) == 0) { + if (eq) + setvareq(name, 0); + /* else: + * it's a duplicate "local VAR" declaration, do nothing + */ + return; + } + lvp = lvp->next; + } + + lvp = ckzalloc(sizeof(*lvp)); if (LONE_DASH(name)) { char *p; p = ckmalloc(sizeof(optlist)); lvp->text = memcpy(p, optlist, sizeof(optlist)); vp = NULL; } else { - char *eq; - vpp = hashvar(name); vp = *findvar(vpp, name); - eq = strchr(name, '='); if (vp == NULL) { + /* variable did not exist yet */ if (eq) setvareq(name, VSTRFIXED); else @@ -8994,12 +9010,15 @@ mklocal(char *name) } else { lvp->text = vp->var_text; lvp->flags = vp->flags; + /* make sure neither "struct var" nor string gets freed + * during (un)setting: + */ vp->flags |= VSTRFIXED|VTEXTFIXED; if (eq) setvareq(name, 0); else /* "local VAR" unsets VAR: */ - setvar(name, NULL, 0); + setvar0(name, NULL); } } lvp->vp = vp; @@ -9491,7 +9510,7 @@ evalcommand(union node *cmd, int flags) * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ - setvar2("_", lastarg); + setvar0("_", lastarg); } popstackmark(&smark); } @@ -12885,7 +12904,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) * to jump out of it. */ INT_OFF; - r = shell_builtin_read(setvar2, + r = shell_builtin_read(setvar0, argptr, bltinlookup("IFS"), /* can be NULL */ read_flags, @@ -13046,14 +13065,14 @@ init(void) } } - setvar2("PPID", utoa(getppid())); + setvar0("PPID", utoa(getppid())); #if ENABLE_ASH_BASH_COMPAT p = lookupvar("SHLVL"); setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); if (!lookupvar("HOSTNAME")) { struct utsname uts; uname(&uts); - setvar2("HOSTNAME", uts.nodename); + setvar0("HOSTNAME", uts.nodename); } #endif p = lookupvar("PWD"); @@ -13309,7 +13328,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) hp = lookupvar("HOME"); if (hp) { hp = concat_path_file(hp, ".ash_history"); - setvar2("HISTFILE", hp); + setvar0("HISTFILE", hp); free((char*)hp); hp = lookupvar("HISTFILE"); } diff --git a/shell/ash_test/ash-heredoc/heredoc1.right b/shell/ash_test/ash-heredoc/heredoc1.right index 895f5ee80..40aa5a5fe 100644 --- a/shell/ash_test/ash-heredoc/heredoc1.right +++ b/shell/ash_test/ash-heredoc/heredoc1.right @@ -1 +1 @@ -heredoc1.tests: line 3: syntax error: unexpected "then" +./heredoc1.tests: line 3: syntax error: unexpected "then" diff --git a/shell/ash_test/ash-vars/var3.right b/shell/ash_test/ash-vars/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/ash_test/ash-vars/var3.right @@ -0,0 +1,5 @@ +1 +1 + + +0 diff --git a/shell/ash_test/ash-vars/var3.tests b/shell/ash_test/ash-vars/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/ash_test/ash-vars/var3.tests @@ -0,0 +1 @@ +x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x -- cgit v1.2.3-55-g6feb From 73327a048b112ba2b742b758bb5a3caf95c7bf1a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Apr 2015 19:38:13 +0200 Subject: hush: document buggy handling of duplicate "local" Signed-off-by: Denys Vlasenko --- shell/hush_test/hush-bugs/var3.right | 5 +++++ shell/hush_test/hush-bugs/var3.tests | 1 + 2 files changed, 6 insertions(+) create mode 100644 shell/hush_test/hush-bugs/var3.right create mode 100755 shell/hush_test/hush-bugs/var3.tests (limited to 'shell') diff --git a/shell/hush_test/hush-bugs/var3.right b/shell/hush_test/hush-bugs/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.right @@ -0,0 +1,5 @@ +1 +1 + + +0 diff --git a/shell/hush_test/hush-bugs/var3.tests b/shell/hush_test/hush-bugs/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.tests @@ -0,0 +1 @@ +x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x -- cgit v1.2.3-55-g6feb From 61d6ae244af424b2a05468307723f21c8810ab9e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 19 Apr 2015 10:50:25 +0100 Subject: libbb: remove unnecessary argument to nonblock_immune_read The loop_on_EINTR argument to nonblock_immune_read is always set to 1. function old new delta xmalloc_reads 200 195 -5 pgetc 488 483 -5 argstr 1313 1308 -5 nonblock_immune_read 123 86 -37 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-52) Total: -52 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/read_printf.c | 8 ++++---- shell/ash.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'shell') diff --git a/include/libbb.h b/include/libbb.h index 0f8363b78..21da5f100 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -713,7 +713,7 @@ void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) F extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC; -extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) FAST_FUNC; +extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count) FAST_FUNC; // NB: will return short read on error, not -1, // if some data was read before error occurred extern ssize_t full_read(int fd, void *buf, size_t count) FAST_FUNC; diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 5ed6e3632..b6a17cc36 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -45,20 +45,20 @@ * which detects EAGAIN and uses poll() to wait on the fd. * Thankfully, poll() doesn't care about O_NONBLOCK flag. */ -ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) +ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count) { struct pollfd pfd[1]; ssize_t n; while (1) { - n = loop_on_EINTR ? safe_read(fd, buf, count) : read(fd, buf, count); + n = safe_read(fd, buf, count); if (n >= 0 || errno != EAGAIN) return n; /* fd is in O_NONBLOCK mode. Wait using poll and repeat */ pfd[0].fd = fd; pfd[0].events = POLLIN; /* note: safe_poll pulls in printf */ - loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1); + safe_poll(pfd, 1, -1); } } @@ -81,7 +81,7 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p) p = buf + sz; sz += 128; } - if (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 1) != 1) { + if (nonblock_immune_read(fd, p, 1) != 1) { /* EOF/error */ if (p == buf) { /* we read nothing */ free(buf); diff --git a/shell/ash.c b/shell/ash.c index 697a64fea..c51fb804d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5923,7 +5923,7 @@ expbackq(union node *cmd, int quoted, int quotes) read: if (in.fd < 0) break; - i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); + i = nonblock_immune_read(in.fd, buf, sizeof(buf)); TRACE(("expbackq: read returns %d\n", i)); if (i <= 0) break; @@ -9696,7 +9696,7 @@ preadfd(void) #if ENABLE_FEATURE_EDITING retry: if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) - nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { int timeout = -1; # if ENABLE_ASH_IDLE_TIMEOUT @@ -9738,7 +9738,7 @@ preadfd(void) } } #else - nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); #endif #if 0 /* disabled: nonblock_immune_read() handles this problem */ -- cgit v1.2.3-55-g6feb From 1285aa62f914ba894b82880e57bd81cfbc41f180 Mon Sep 17 00:00:00 2001 From: Eugene Rudoy Date: Sun, 26 Apr 2015 23:32:00 +0200 Subject: ash: consider "local -" case while iterating over local variables in mklocal. fixes segfault introduced in 0a0acb55db8d7c4dec445573f1b0528d126b9e1f with functions using "local -". test-case: f() { local -; local x; }; f note: with this change applied multiple 'local -'s still cause multiple entries to be added to the localvars list. this problem will be addressed in a separate commit. Signed-off-by: Eugene Rudoy Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index c51fb804d..3e9997b53 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8979,7 +8979,7 @@ mklocal(char *name) */ lvp = localvars; while (lvp) { - if (varcmp(lvp->vp->var_text, name) == 0) { + if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) { if (eq) setvareq(name, 0); /* else: -- cgit v1.2.3-55-g6feb From e0a4e107aa9d1e03546c090b07874dff1865705e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 May 2015 02:20:14 +0200 Subject: ash: explain what "local -" does Signed-off-by: Denys Vlasenko --- shell/ash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 3e9997b53..7af8842bb 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8962,7 +8962,8 @@ parse_command_args(char **argv, const char **path) * Make a variable a local variable. When a variable is made local, it's * value and flags are saved in a localvar structure. The saved values * will be restored when the shell function returns. We handle the name - * "-" as a special case. + * "-" as a special case: it makes changes to "set +-options" local + * (options will be restored on return from the function). */ static void mklocal(char *name) -- cgit v1.2.3-55-g6feb From d68d1fbd6cb31a61975112acb1c792735a063847 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:49:28 +0200 Subject: ash: code shrink around varvalue Based on commit c989d72 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta strtodest - 40 +40 memtodest 123 147 +24 parse_command 1443 1440 -3 readtoken1 3205 3199 -6 argstr 1203 1180 -23 varvalue 788 660 -128 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/4 up/down: 64/-160) Total: -96 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 84 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 38 insertions(+), 46 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 7af8842bb..a81922add 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5539,6 +5539,11 @@ ash_arith(const char *s) #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ +/* Add CTLESC when necessary. */ +#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) +/* Do not skip NUL characters. */ +#define QUOTES_KEEPNUL EXP_TILDE + /* * Structure specifying which parts of the string should be searched * for IFS characters. @@ -5695,29 +5700,34 @@ preglob(const char *pattern, int quoted, int flag) static void memtodest(const char *p, size_t len, int syntax, int quotes) { - char *q = expdest; + char *q; + + if (!len) + return; - q = makestrspace(quotes ? len * 2 : len, q); + q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest); - while (len--) { + do { unsigned char c = *p++; - if (c == '\0') - continue; - if (quotes) { + if (c) { int n = SIT(c, syntax); - if (n == CCTL || n == CBACK) + if ((quotes & QUOTES_ESC) && + (n == CCTL || n == CBACK)) USTPUTC(CTLESC, q); - } + } else if (!(quotes & QUOTES_KEEPNUL)) + continue; USTPUTC(c, q); - } + } while (--len); expdest = q; } -static void +static size_t strtodest(const char *p, int syntax, int quotes) { - memtodest(p, strlen(p), syntax, quotes); + size_t len = strlen(p); + memtodest(p, len, syntax, quotes); + return len; } /* @@ -5790,7 +5800,7 @@ exptilde(char *startp, char *p, int flags) char *name; struct passwd *pw; const char *home; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); + int quotes = flags & QUOTES_ESC; name = p + 1; @@ -6043,7 +6053,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) '\0' }; const char *reject = spclchars; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ + int quotes = flags & QUOTES_ESC; int breakall = flags & EXP_WORD; int inquotes; size_t length; @@ -6608,13 +6618,16 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) const char *p; int num; int i; - int sepq = 0; ssize_t len = 0; - int subtype = varflags & VSTYPE; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); + int sep; int quoted = varflags & VSQUOTE; + int subtype = varflags & VSTYPE; + int discard = subtype == VSPLUS || subtype == VSLENGTH; + int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; int syntax = quoted ? DQSYNTAX : BASESYNTAX; + sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0; + switch (*name) { case '$': num = rootpid; @@ -6649,7 +6662,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) break; case '@': { char **ap; - int sep; + char sepc; if (quoted && (flags & EXP_FULL)) { /* note: this is not meant as PEOF value */ @@ -6659,39 +6672,20 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) /* fall through */ case '*': sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; - i = SIT(sep, syntax); - if (quotes && (i == CCTL || i == CBACK)) - sepq = 1; param: ap = shellparam.p; + sepc = sep; if (!ap) return -1; while ((p = *ap++) != NULL) { - size_t partlen; - - partlen = strlen(p); - len += partlen; - - if (!(subtype == VSPLUS || subtype == VSLENGTH)) - memtodest(p, partlen, syntax, quotes); + len += strtodest(p, syntax, quotes); if (*ap && sep) { - char *q; - len++; - if (subtype == VSPLUS || subtype == VSLENGTH) { - continue; - } - q = expdest; - if (sepq) - STPUTC(CTLESC, q); - /* note: may put NUL despite sep != 0 - * (see sep = 1 << CHAR_BIT above) */ - STPUTC(sep, q); - expdest = q; + memtodest(&sepc, 1, syntax, quotes); } } - return len; + break; } /* case '@' and '*' */ case '0': case '1': @@ -6740,9 +6734,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) if (!p) return -1; - len = strlen(p); - if (!(subtype == VSPLUS || subtype == VSLENGTH)) - memtodest(p, len, syntax, quotes); + len = strtodest(p, syntax, quotes); #if ENABLE_UNICODE_SUPPORT if (subtype == VSLENGTH && len > 0) { reinit_unicode_for_ash(); @@ -6751,10 +6743,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) } } #endif - return len; + break; } - if (subtype == VSPLUS || subtype == VSLENGTH) + if (discard) STADJUST(-len, expdest); return len; } @@ -6870,7 +6862,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) patloc = expdest - (char *)stackblock(); if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, startloc, varflags, - /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), + /* quotes: */ flags & QUOTES_ESC, var_str_list) ) { int amount = expdest - ( -- cgit v1.2.3-55-g6feb From eb6b48ba743d510ad9e6f9c3a8b3899d1eb9b5f3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:51:35 +0200 Subject: ash: perform tilde expansion in all parameter expansion words Previously tilde expansion was not carried out for =?#% expansion words. Test case: a=~root:~root echo ${a#~root} Old result: /root:/root New result: :/root Based on commit dd721f71 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta subevalvar 1152 1153 +1 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 4 ++-- shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right | 1 + shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right create mode 100755 shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index a81922add..4c43f1f30 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6361,8 +6361,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, // p, varname, strloc, subtype, startloc, varflags, quotes); herefd = -1; - argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, - var_str_list); + argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? + EXP_CASE : 0), var_str_list); STPUTC('\0', expdest); herefd = saveherefd; argbackq = saveargbackq; diff --git a/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right new file mode 100644 index 000000000..2357750c5 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right @@ -0,0 +1 @@ +:/root diff --git a/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests new file mode 100755 index 000000000..6605315d0 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests @@ -0,0 +1,2 @@ +a=~root:~root +echo ${a#~root} -- cgit v1.2.3-55-g6feb From 3df47f9cbbb7f16608cbc642026625cdf7f06aa9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:53:26 +0200 Subject: ash: do not expand tilde in parameter expansion within quotes Test case: unset a echo "${a:-~root}" Old result: /root New result: ~root Based on commit 170f44d from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta evalvar 598 604 +6 parse_command 1440 1443 +3 localcmd 325 327 +2 readtoken1 3199 3200 +1 argstr 1180 1164 -16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 12/-16) Total: -4 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 8 +++----- ...var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | 1 + ...var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right create mode 100755 shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 4c43f1f30..d87166c4f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5529,7 +5529,7 @@ ash_arith(const char *s) #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ -#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ +#define EXP_QUOTED 0x100 /* expand word in double quotes */ /* * rmescape() flags */ @@ -6054,7 +6054,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) }; const char *reject = spclchars; int quotes = flags & QUOTES_ESC; - int breakall = flags & EXP_WORD; + int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; int inquotes; size_t length; int startloc; @@ -6072,8 +6072,6 @@ argstr(char *p, int flags, struct strlist *var_str_list) flags &= ~EXP_TILDE; tilde: q = p; - if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) - q++; if (*q == '~') p = exptilde(p, q, flags); } @@ -6790,7 +6788,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { argstr( p, - flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), + flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), var_str_list ); goto end; diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right @@ -0,0 +1 @@ +~root diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests @@ -0,0 +1,2 @@ +unset a +echo "${a:-~root}" -- cgit v1.2.3-55-g6feb From 7e4ed267b645090fb576e1c876a88a9c73faabe9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:54:43 +0200 Subject: ash: remove superfluous code in arithmetic mode Based on commits 1a74845, cfc3d6a and ff13779 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta evalcommand 1197 1204 +7 localcmd 327 325 -2 readtoken1 3200 3180 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 7/-22) Total: -15 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index d87166c4f..ee7642a64 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11282,9 +11282,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) goto quotemark; case CENDQUOTE: IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) - if (eofmark != NULL && arinest == 0 - && varnest == 0 - ) { + if (eofmark != NULL && varnest == 0) { USTPUTC(c, out); } else { if (dqvarnest == 0) { @@ -11320,7 +11318,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) if (pgetc() == ')') { if (--arinest == 0) { syntax = prevsyntax; - dblquote = (syntax == DQSYNTAX); c = CTLENDARI; } } else { @@ -11645,7 +11642,7 @@ parsesub: { ((unsigned char *)stackblock())[typeloc] = subtype | flags; if (subtype != VSNORMAL) { varnest++; - if (dblquote || arinest) { + if (dblquote) { dqvarnest++; } } -- cgit v1.2.3-55-g6feb From ad88bdee0c382b9f1cbbb2d76cc739afb2790a60 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:56:16 +0200 Subject: ash: remove arithmetic expansion collapsing at parse time Collapsing arithmetic expansion is incorrect when the inner arithmetic expansion is a part of a parameter expansion. Test case: unset a echo $((3 + ${a:=$((4 + 5))})) echo $a Old result: 12 (4 + 5) New result: 12 9 Based on commit bb777a6 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta readtoken1 3180 3163 -17 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 18 ++++++------------ ...t-collapse-arithmetic-expansion-at-parse-time.right | 2 ++ ...t-collapse-arithmetic-expansion-at-parse-time.tests | 3 +++ 3 files changed, 11 insertions(+), 12 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right create mode 100755 shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index ee7642a64..33a477d80 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11316,9 +11316,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) parenlevel--; } else { if (pgetc() == ')') { + c = CTLENDARI; if (--arinest == 0) { syntax = prevsyntax; - c = CTLENDARI; } } else { /* @@ -11809,18 +11809,12 @@ parsearith: { if (++arinest == 1) { prevsyntax = syntax; syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"', out); - else - USTPUTC(' ', out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); } + USTPUTC(CTLARI, out); + if (dblquote) + USTPUTC('"', out); + else + USTPUTC(' ', out); goto parsearith_return; } #endif diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right @@ -0,0 +1,2 @@ +12 +9 diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests @@ -0,0 +1,3 @@ +unset a +echo $((3 + ${a:=$((4 + 5))})) +echo $a -- cgit v1.2.3-55-g6feb From 549deab5abd59c1ab752754170f69aa2248e72c9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:57:51 +0200 Subject: ash: move parse-time quote flag detection to run-time Because the parser does not recursively parse parameter expansion with respect to quotes, we can't accurately determine quote status at parse time. This patch works around this by moving the quote detection to run-time where we do interpret it recursively. Test case: foo=\\ echo "<${foo#[\\]}>" Old result: <\> New result: <> Do not quote back slashes in parameter expansions outside quotes. Test case: a=/b/c/* b=\\ echo ${a%$b*} Old result: /b/c/* New result: /b/c/ Based on commits 880d952, 7cfd8be, 0d7d660 and a7c21a6 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta argstr 1164 1193 +29 memtodest 147 174 +27 subevalvar 1153 1177 +24 redirect 1279 1282 +3 dolatstr 5 7 +2 static.spclchars 10 9 -1 expandarg 962 960 -2 evalcase 273 271 -2 evalcommand 1204 1197 -7 rmescapes 236 227 -9 preglob 27 8 -19 evalvar 604 582 -22 cmdputs 389 334 -55 readtoken1 3163 3061 -102 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/9 up/down: 85/-219) Total: -134 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 164 +++++++++------------ ...es-in-parameter-expansions-outside-quotes.right | 1 + ...es-in-parameter-expansions-outside-quotes.tests | 3 + .../ash-vars/var-runtime-quote-detection.right | 1 + .../ash-vars/var-runtime-quote-detection.tests | 1 + 5 files changed, 72 insertions(+), 98 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right create mode 100755 shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests create mode 100644 shell/ash_test/ash-vars/var-runtime-quote-detection.right create mode 100755 shell/ash_test/ash-vars/var-runtime-quote-detection.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 33a477d80..e7e70817f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -598,8 +598,6 @@ out2str(const char *p) #define CTLVAR ((unsigned char)'\202') /* variable defn */ #define CTLENDVAR ((unsigned char)'\203') #define CTLBACKQ ((unsigned char)'\204') -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == '\205' */ #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ #define CTLENDARI ((unsigned char)'\207') #define CTLQUOTEMARK ((unsigned char)'\210') @@ -608,7 +606,6 @@ out2str(const char *p) /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ #define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ @@ -628,8 +625,9 @@ out2str(const char *p) #endif static const char dolatstr[] ALIGN1 = { - CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' + CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0' }; +#define DOLATSTRLEN 6 #define NCMD 0 #define NPIPE 1 @@ -865,9 +863,7 @@ trace_puts_quoted(char *s) case '\\': c = '\\'; goto backslash; case CTLESC: c = 'e'; goto backslash; case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; backslash: putc('\\', tracefile); putc(c, tracefile); @@ -1030,7 +1026,6 @@ sharg(union node *arg, FILE *fp) putc('}', fp); break; case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: putc('$', fp); putc('(', fp); shtree(bqlist->n, -1, NULL, fp); @@ -4413,11 +4408,7 @@ cmdputs(const char *s) str = "${#"; else str = "${"; - if (!(subtype & VSQUOTE) == !(quoted & 1)) - goto dostr; - quoted ^= 1; - c = '"'; - break; + goto dostr; case CTLENDVAR: str = "\"}" + !(quoted & 1); quoted >>= 1; @@ -4426,9 +4417,6 @@ cmdputs(const char *s) case CTLBACKQ: str = "$(...)"; goto dostr; - case CTLBACKQ+CTLQUOTE: - str = "\"$(...)\""; - goto dostr; #if ENABLE_SH_MATH_SUPPORT case CTLARI: str = "$(("; @@ -5526,7 +5514,7 @@ ash_arith(const char *s) #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ +#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ #define EXP_QUOTED 0x100 /* expand word in double quotes */ @@ -5535,12 +5523,11 @@ ash_arith(const char *s) */ #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ -#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ /* Add CTLESC when necessary. */ -#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) +#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) /* Do not skip NUL characters. */ #define QUOTES_KEEPNUL EXP_TILDE @@ -5641,13 +5628,11 @@ rmescapes(char *str, int flag) } } - inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; + inquotes = 0; globbing = flag & RMESCAPE_GLOB; protect_against_glob = globbing; while (*p) { if ((unsigned char)*p == CTLQUOTEMARK) { -// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 -// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? // Note: both inquotes and protect_against_glob only affect whether // CTLESC, gets converted to or to \ inquotes = ~inquotes; @@ -5655,16 +5640,15 @@ rmescapes(char *str, int flag) protect_against_glob = globbing; continue; } - if (*p == '\\') { - /* naked back slash */ - protect_against_glob = 0; - goto copy; - } if ((unsigned char)*p == CTLESC) { p++; - if (protect_against_glob && inquotes && *p != '/') { + if (protect_against_glob) { *q++ = '\\'; } + } else if (*p == '\\' && !inquotes) { + /* naked back slash */ + protect_against_glob = 0; + goto copy; } protect_against_glob = globbing; copy: @@ -5685,13 +5669,9 @@ rmescapes(char *str, int flag) * Returns an stalloced string. */ static char * -preglob(const char *pattern, int quoted, int flag) +preglob(const char *pattern, int flag) { - flag |= RMESCAPE_GLOB; - if (quoted) { - flag |= RMESCAPE_QUOTED; - } - return rmescapes((char *)pattern, flag); + return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); } /* @@ -5712,7 +5692,9 @@ memtodest(const char *p, size_t len, int syntax, int quotes) if (c) { int n = SIT(c, syntax); if ((quotes & QUOTES_ESC) && - (n == CCTL || n == CBACK)) + ((n == CCTL) || + (((quotes & EXP_FULL) || syntax != BASESYNTAX) && + n == CBACK))) USTPUTC(CTLESC, q); } else if (!(quotes & QUOTES_KEEPNUL)) continue; @@ -5905,7 +5887,7 @@ evalbackcmd(union node *n, struct backcmd *result) * Expand stuff in backwards quotes. */ static void -expbackq(union node *cmd, int quoted, int quotes) +expbackq(union node *cmd, int flag) { struct backcmd in; int i; @@ -5913,7 +5895,7 @@ expbackq(union node *cmd, int quoted, int quotes) char *p; char *dest; int startloc; - int syntax = quoted ? DQSYNTAX : BASESYNTAX; + int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; struct stackmark smark; INT_OFF; @@ -5929,7 +5911,7 @@ expbackq(union node *cmd, int quoted, int quotes) if (i == 0) goto read; for (;;) { - memtodest(p, i, syntax, quotes); + memtodest(p, i, syntax, flag & QUOTES_ESC); read: if (in.fd < 0) break; @@ -5953,7 +5935,7 @@ expbackq(union node *cmd, int quoted, int quotes) STUNPUTC(dest); expdest = dest; - if (quoted == 0) + if (!(flag & EXP_QUOTED)) recordregion(startloc, dest - (char *)stackblock(), 0); TRACE(("evalbackq: size:%d:'%.*s'\n", (int)((dest - (char *)stackblock()) - startloc), @@ -5967,11 +5949,10 @@ expbackq(union node *cmd, int quoted, int quotes) * evaluate, place result in (backed up) result, adjust string position. */ static void -expari(int quotes) +expari(int flag) { char *p, *start; int begoff; - int flag; int len; /* ifsfree(); */ @@ -6009,16 +5990,14 @@ expari(int quotes) removerecordregions(begoff); - flag = p[1]; - expdest = p; - if (quotes) - rmescapes(p + 2, 0); + if (flag & QUOTES_ESC) + rmescapes(p + 1, 0); - len = cvtnum(ash_arith(p + 2)); + len = cvtnum(ash_arith(p + 1)); - if (flag != '"') + if (!(flag & EXP_QUOTED)) recordregion(begoff, begoff + len, 0); } #endif @@ -6046,14 +6025,12 @@ argstr(char *p, int flags, struct strlist *var_str_list) CTLESC, CTLVAR, CTLBACKQ, - CTLBACKQ | CTLQUOTE, #if ENABLE_SH_MATH_SUPPORT CTLENDARI, #endif '\0' }; const char *reject = spclchars; - int quotes = flags & QUOTES_ESC; int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; int inquotes; size_t length; @@ -6128,19 +6105,14 @@ argstr(char *p, int flags, struct strlist *var_str_list) case CTLENDVAR: /* ??? */ goto breakloop; case CTLQUOTEMARK: + inquotes ^= EXP_QUOTED; /* "$@" syntax adherence hack */ - if (!inquotes - && memcmp(p, dolatstr, 4) == 0 - && ( p[4] == (char)CTLQUOTEMARK - || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) - ) - ) { - p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; + if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { + p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1; goto start; } - inquotes = !inquotes; addquote: - if (quotes) { + if (flags & QUOTES_ESC) { p--; length++; startloc++; @@ -6149,22 +6121,30 @@ argstr(char *p, int flags, struct strlist *var_str_list) case CTLESC: startloc++; length++; + + /* + * Quoted parameter expansion pattern: remove quote + * unless inside inner quotes or we have a literal + * backslash. + */ + if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) == + EXP_QPAT && *p != '\\') + break; + goto addquote; case CTLVAR: TRACE(("argstr: evalvar('%s')\n", p)); - p = evalvar(p, flags, var_str_list); + p = evalvar(p, flags | inquotes, var_str_list); TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); goto start; case CTLBACKQ: - c = '\0'; - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c, quotes); + expbackq(argbackq->n, flags | inquotes); argbackq = argbackq->next; goto start; #if ENABLE_SH_MATH_SUPPORT case CTLENDARI: p--; - expari(quotes); + expari(flags | inquotes); goto start; #endif } @@ -6296,13 +6276,13 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) #if ENABLE_ASH_BASH_COMPAT static char * -parse_sub_pattern(char *arg, int varflags) +parse_sub_pattern(char *arg, int quoted) { char *idx, *repl = NULL; unsigned char c; //char *org_arg = arg; - //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); + //bb_error_msg("arg:'%s' quoted:%x", arg, quoted); idx = arg; while (1) { c = *arg; @@ -6318,7 +6298,7 @@ parse_sub_pattern(char *arg, int varflags) *idx++ = c; arg++; /* - * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} + * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} * The result is a_\_z_c (not a\_\_z_c)! * * Enable debug prints in this function and you'll see: @@ -6328,7 +6308,7 @@ parse_sub_pattern(char *arg, int varflags) * IOW: search pattern and replace string treat backslashes * differently! That is the reason why we check repl below: */ - if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) + if (c == '\\' && *arg == '\\' && repl && !quoted) arg++; /* skip both '\', not just first one */ } *idx = c; /* NUL */ @@ -6340,9 +6320,10 @@ parse_sub_pattern(char *arg, int varflags) static const char * subevalvar(char *p, char *varname, int strloc, int subtype, - int startloc, int varflags, int quotes, struct strlist *var_str_list) + int startloc, int varflags, int flag, struct strlist *var_str_list) { struct nodelist *saveargbackq = argbackq; + int quotes = flag & QUOTES_ESC; char *startp; char *loc; char *rmesc, *rmescend; @@ -6360,7 +6341,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, herefd = -1; argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? - EXP_CASE : 0), var_str_list); + (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), + var_str_list); STPUTC('\0', expdest); herefd = saveherefd; argbackq = saveargbackq; @@ -6471,7 +6453,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, } rmescend--; str = (char *)stackblock() + strloc; - preglob(str, varflags & VSQUOTE, 0); + preglob(str, 0); #if ENABLE_ASH_BASH_COMPAT workloc = expdest - (char *)stackblock(); @@ -6479,7 +6461,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, varflags); + repl = parse_sub_pattern(str, flag & EXP_QUOTED); //bb_error_msg("repl:'%s'", repl); if (!repl) repl = nullstr; @@ -6618,7 +6600,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) int i; ssize_t len = 0; int sep; - int quoted = varflags & VSQUOTE; + int quoted = flags & EXP_QUOTED; int subtype = varflags & VSTYPE; int discard = subtype == VSPLUS || subtype == VSLENGTH; int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; @@ -6758,7 +6740,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) { char varflags; char subtype; - char quoted; + int quoted; char easy; char *var; int patloc; @@ -6767,7 +6749,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) varflags = (unsigned char) *p++; subtype = varflags & VSTYPE; - quoted = varflags & VSQUOTE; + quoted = flags & EXP_QUOTED; var = p; easy = (!quoted || (*var == '@' && shellparam.nparam)); startloc = expdest - (char *)stackblock(); @@ -6788,7 +6770,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { argstr( p, - flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), + flags | EXP_TILDE | EXP_WORD, var_str_list ); goto end; @@ -6802,7 +6784,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { if (subevalvar(p, var, /* strloc: */ 0, subtype, startloc, varflags, - /* quotes: */ 0, + /* quotes: */ flags & ~QUOTES_ESC, var_str_list) ) { varflags &= ~VSNUL; @@ -6859,10 +6841,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, - startloc, varflags, - /* quotes: */ flags & QUOTES_ESC, - var_str_list) - ) { + startloc, varflags, flags, var_str_list)) { int amount = expdest - ( (char *)stackblock() + patloc - 1 ); @@ -6881,7 +6860,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) unsigned char c = *p++; if (c == CTLESC) p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { + else if (c == CTLBACKQ) { if (varlen >= 0) argbackq = argbackq->next; } else if (c == CTLVAR) { @@ -7217,7 +7196,7 @@ expandmeta(struct strlist *str /*, int flag*/) savelastp = exparg.lastp; INT_OFF; - p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ @@ -7307,7 +7286,7 @@ static void expandhere(union node *arg, int fd) { herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); + expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); full_write(fd, stackblock(), expdest - (char *)stackblock()); } @@ -7317,7 +7296,7 @@ expandhere(union node *arg, int fd) static int patmatch(char *pattern, const char *string) { - return pmatch(preglob(pattern, 0, 0), string); + return pmatch(preglob(pattern, 0), string); } /* @@ -8570,7 +8549,7 @@ evalfor(union node *n, int flags) arglist.list = NULL; arglist.lastp = &arglist.list; for (argp = n->nfor.args; argp; argp = argp->narg.next) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); /* XXX */ if (evalskip) goto out; @@ -11260,11 +11239,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) && c != '$' && (c != '"' || eofmark != NULL) ) { - USTPUTC(CTLESC, out); USTPUTC('\\', out); } - if (SIT(c, SQSYNTAX) == CCTL) - USTPUTC(CTLESC, out); + USTPUTC(CTLESC, out); USTPUTC(c, out); quotef = 1; } @@ -11637,8 +11614,6 @@ parsesub: { do_pungetc: pungetc(); } - if (dblquote || arinest) - flags |= VSQUOTE; ((unsigned char *)stackblock())[typeloc] = subtype | flags; if (subtype != VSNORMAL) { varnest++; @@ -11792,10 +11767,7 @@ parsebackq: { } parsebackquote = savepbq; exception_handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); + USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; goto parsebackq_newreturn; @@ -11811,10 +11783,6 @@ parsearith: { syntax = ARISYNTAX; } USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"', out); - else - USTPUTC(' ', out); goto parsearith_return; } #endif @@ -12129,7 +12097,7 @@ expandstr(const char *ps) n.narg.text = wordtext; n.narg.backquote = backquotelist; - expandarg(&n, NULL, 0); + expandarg(&n, NULL, EXP_QUOTED); return stackblock(); } #endif diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right new file mode 100644 index 000000000..030ebdeb6 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right @@ -0,0 +1 @@ +/b/c/ diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests new file mode 100755 index 000000000..fb9371467 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests @@ -0,0 +1,3 @@ +a=/b/c/* +b=\\ +echo ${a%$b*} diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.right b/shell/ash_test/ash-vars/var-runtime-quote-detection.right new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.right @@ -0,0 +1 @@ +<> diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.tests b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests new file mode 100755 index 000000000..e570631fd --- /dev/null +++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests @@ -0,0 +1 @@ +foo=\\ echo "<${foo#[\\]}>" -- cgit v1.2.3-55-g6feb From 417622cc2e1ce0f3bc797b3997f5728433c8ccee Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:59:14 +0200 Subject: ash: fix breakage of ${v/pat/str} The commit ash: move parse-time quote flag detection to run-time breaks pattern substitution in parameter expansion. Fix this and revise the code so that the different handling of the pattern and the replacement string takes place in rmescapes rather than the separate function parse_sub_pattern. function old new delta rmescapes 227 273 +46 static.qchars 3 4 +1 subevalvar 1177 1157 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 47/-20) Total: 27 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 79 ++++++++++++++++++++++--------------------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index e7e70817f..282f761fc 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5525,6 +5525,7 @@ ash_arith(const char *s) #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ +#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */ /* Add CTLESC when necessary. */ #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) @@ -5594,14 +5595,16 @@ esclen(const char *start, const char *p) static char * rmescapes(char *str, int flag) { - static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; + static const char qchars[] ALIGN1 = { + IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; char *p, *q, *r; unsigned inquotes; unsigned protect_against_glob; unsigned globbing; + IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) - p = strpbrk(str, qchars); + p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); if (!p) return str; @@ -5650,6 +5653,13 @@ rmescapes(char *str, int flag) protect_against_glob = 0; goto copy; } +#if ENABLE_ASH_BASH_COMPAT + else if (*p == '/' && slash) { + /* stop handling globbing and mark location of slash */ + globbing = slash = 0; + *p = CTLESC; + } +#endif protect_against_glob = globbing; copy: *q++ = *p++; @@ -6274,50 +6284,6 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } -#if ENABLE_ASH_BASH_COMPAT -static char * -parse_sub_pattern(char *arg, int quoted) -{ - char *idx, *repl = NULL; - unsigned char c; - - //char *org_arg = arg; - //bb_error_msg("arg:'%s' quoted:%x", arg, quoted); - idx = arg; - while (1) { - c = *arg; - if (!c) - break; - if (c == '/') { - /* Only the first '/' seen is our separator */ - if (!repl) { - repl = idx + 1; - c = '\0'; - } - } - *idx++ = c; - arg++; - /* - * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} - * The result is a_\_z_c (not a\_\_z_c)! - * - * Enable debug prints in this function and you'll see: - * ash: arg:'\\b/_\\_z_' varflags:d - * ash: pattern:'\\b' repl:'_\_z_' - * That is, \\b is interpreted as \\b, but \\_ as \_! - * IOW: search pattern and replace string treat backslashes - * differently! That is the reason why we check repl below: - */ - if (c == '\\' && *arg == '\\' && repl && !quoted) - arg++; /* skip both '\', not just first one */ - } - *idx = c; /* NUL */ - //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); - - return repl; -} -#endif /* ENABLE_ASH_BASH_COMPAT */ - static const char * subevalvar(char *p, char *varname, int strloc, int subtype, int startloc, int varflags, int flag, struct strlist *var_str_list) @@ -6328,7 +6294,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *loc; char *rmesc, *rmescend; char *str; - IF_ASH_BASH_COMPAT(const char *repl = NULL;) + IF_ASH_BASH_COMPAT(char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; int amount, resetloc; @@ -6453,7 +6419,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, } rmescend--; str = (char *)stackblock() + strloc; - preglob(str, 0); + /* + * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} + * The result is a_\_z_c (not a\_\_z_c)! + * + * The search pattern and replace string treat backslashes differently! + * RMESCAPE_SLASH causes preglob to work differently on the pattern + * and string. It's only used on the first call. + */ + preglob(str, IF_ASH_BASH_COMPAT( + (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? + RMESCAPE_SLASH :) 0); #if ENABLE_ASH_BASH_COMPAT workloc = expdest - (char *)stackblock(); @@ -6461,11 +6437,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, flag & EXP_QUOTED); - //bb_error_msg("repl:'%s'", repl); - if (!repl) + if ((repl=strchr(str, CTLESC))) + *repl++ = '\0'; + else repl = nullstr; } + //bb_error_msg("str:'%s' repl:'%s'", str, repl); /* If there's no pattern to match, return the expansion unmolested */ if (str[0] == '\0') -- cgit v1.2.3-55-g6feb From 523006798c45307830eaae9d29ca9fdc1a1b50af Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 10:13:21 +0200 Subject: testsuite: add some tests for ash Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- .../ash-vars/var-pattern-replacement-in-parameter-expansion-1.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-2.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-3.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-4.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-5.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests | 2 ++ 10 files changed, 15 insertions(+) create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests (limited to 'shell') diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right @@ -0,0 +1 @@ +a_\_z_c diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests @@ -0,0 +1,2 @@ +v="a\bc" +echo ${v/\\b/_\\_\z_} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right @@ -0,0 +1 @@ +ax/yc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests @@ -0,0 +1,2 @@ +v="abc" +echo ${v/b/x/y} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right @@ -0,0 +1 @@ +axcabc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v/b/x} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right @@ -0,0 +1 @@ +axcaxc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v//b/x} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right @@ -0,0 +1 @@ +axc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests @@ -0,0 +1,2 @@ +v="ab/c" +echo ${v/b\//x} -- cgit v1.2.3-55-g6feb From 9a595bb36ded308e6d4336aef2c1cd3ac738a398 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 18 May 2015 10:23:16 +0200 Subject: hush: add recent ash tests to hush testsuite too (they all pass for hush) Signed-off-by: Denys Vlasenko --- .../var-do-not-collapse-arithmetic-expansion-at-parse-time.right | 2 ++ .../var-do-not-collapse-arithmetic-expansion-at-parse-time.tests | 3 +++ .../var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | 1 + .../var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | 2 ++ ...-not-quote-backslashes-in-parameter-expansions-outside-quotes.right | 1 + ...-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests | 3 +++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-1.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-2.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-3.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-4.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-5.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests | 2 ++ shell/hush_test/hush-vars/var-runtime-quote-detection.right | 1 + shell/hush_test/hush-vars/var-runtime-quote-detection.tests | 1 + 18 files changed, 29 insertions(+) create mode 100644 shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right create mode 100755 shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests create mode 100644 shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right create mode 100755 shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests create mode 100644 shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right create mode 100755 shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests create mode 100644 shell/hush_test/hush-vars/var-runtime-quote-detection.right create mode 100755 shell/hush_test/hush-vars/var-runtime-quote-detection.tests (limited to 'shell') diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right @@ -0,0 +1,2 @@ +12 +9 diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests @@ -0,0 +1,3 @@ +unset a +echo $((3 + ${a:=$((4 + 5))})) +echo $a diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right @@ -0,0 +1 @@ +~root diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests @@ -0,0 +1,2 @@ +unset a +echo "${a:-~root}" diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right new file mode 100644 index 000000000..030ebdeb6 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right @@ -0,0 +1 @@ +/b/c/ diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests new file mode 100755 index 000000000..fb9371467 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests @@ -0,0 +1,3 @@ +a=/b/c/* +b=\\ +echo ${a%$b*} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right @@ -0,0 +1 @@ +a_\_z_c diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests @@ -0,0 +1,2 @@ +v="a\bc" +echo ${v/\\b/_\\_\z_} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right @@ -0,0 +1 @@ +ax/yc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests @@ -0,0 +1,2 @@ +v="abc" +echo ${v/b/x/y} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right @@ -0,0 +1 @@ +axcabc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v/b/x} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right @@ -0,0 +1 @@ +axcaxc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v//b/x} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right @@ -0,0 +1 @@ +axc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests @@ -0,0 +1,2 @@ +v="ab/c" +echo ${v/b\//x} diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.right b/shell/hush_test/hush-vars/var-runtime-quote-detection.right new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.right @@ -0,0 +1 @@ +<> diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.tests b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests new file mode 100755 index 000000000..e570631fd --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests @@ -0,0 +1 @@ +foo=\\ echo "<${foo#[\\]}>" -- cgit v1.2.3-55-g6feb