aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2020-01-08 03:42:56 -0600
committerRob Landley <rob@landley.net>2020-01-08 03:42:56 -0600
commite3c1b14cf9b685528efa50ca068a9f3fd9f9b05c (patch)
treeef33f155d7f3ab6165161a32e9f0c924fa58ced2
parente50071809764cc581a3447fc965e26a10a179953 (diff)
downloadtoybox-e3c1b14cf9b685528efa50ca068a9f3fd9f9b05c.tar.gz
Implement quote removal and fix unterminated bracket expansion.
-rwxr-xr-xtests/sh.test4
-rw-r--r--toys/pending/sh.c41
2 files changed, 33 insertions, 12 deletions
diff --git a/tests/sh.test b/tests/sh.test
index 95d7d196..97356b85 100755
--- a/tests/sh.test
+++ b/tests/sh.test
@@ -14,8 +14,8 @@ testing "simple pipe" "echo hello | cat" "hello\n" "" ""
testing "brackets" "echo {A{a,b}B{c,d}C}" "{AaBcC} {AaBdC} {AbBcC} {AbBdC}\n" \
"" ""
testing "brackets2" "echo {A{a,b}B{c,d}C,D}" "AaBcC AaBdC AbBcC AbBdC D\n" "" ""
-#testing "brackets3" 'echo {A"b,c"D}' "{Ab,cD}\n" "" ""
-#testing "brackets4" 'echo {A"bc",D}' "Abc D\n" "" ""
+testing "brackets3" 'echo {A"b,c"D}' "{Ab,cD}\n" "" ""
+testing "brackets4" 'echo {A"bc",D}' "Abc D\n" "" ""
testing "brackets5" 'echo {A,B,C' "{A,B,C\n" "" ""
testing "brackets6" 'echo {{{{A,B},C}D},E}' "{AD} {BD} {CD} E\n" "" ""
testing "brackets7" 'echo {{{a,b},c,{d,e}},f}' "a b c d e f\n" "" ""
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index 4697f081..01ba9be1 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -220,6 +220,7 @@ static char *getvar(char *s)
// returns pointer to next unquoted (or double quoted if dquot) char.
+// handle \ '' "" `` $()
int skip_quote(char *s, int dquot, int *depth)
{
int i, q = dquot ? *depth : 0;
@@ -263,6 +264,8 @@ static void expand_arg_nobrace(struct sh_arg *arg, char *old, unsigned flags,
{
char *new = old;
+ if (flags&FORCE_KEEP) old = 0;
+
// TODO ls -l /proc/$$/fd
// Tilde expansion
@@ -282,7 +285,9 @@ static void expand_arg_nobrace(struct sh_arg *arg, char *old, unsigned flags,
}
if (pw && pw->pw_dir) ss = pw->pw_dir;
if (!ss || !*ss) ss = "/";
- new = xmprintf("%s%s", ss, s);
+ s = xmprintf("%s%s", ss, s);
+ if (old != new) free(new);
+ new = s;
}
// ${ $(( $( $[ $' ` " '
@@ -316,9 +321,23 @@ TODO this recurses
}
*/
+ // quote removal
+ if (!(flags&NO_QUOTE)) {
+ int to = 0, from = 0;
+
+ for (;;) {
+ char c = new[from++];
+
+ if (c == '"' || c=='\'') continue;
+ if (c == '\\' && new[from]) c = new[from++];
+ if (from != to && old == new) new = xstrdup(new);
+ if (!(new[to++] = c)) break;
+ }
+ }
+
// Record result.
if (old==new && (flags&FORCE_COPY)) new = xstrdup(new);
- if ((old!=new || (flags&FORCE_KEEP)) && delete) {
+ if (old!=new && delete) {
struct arg_list *al = xmalloc(sizeof(struct arg_list));
al->next = *delete;
@@ -342,8 +361,16 @@ int debug;
// collect brace spans
if (!(flags&NO_BRACE)) for (i = 0; ; i++) {
- if (!old[i += skip_quote(old+i, 0, 0)]) break;
- if (old[i] == '{') {
+ i += skip_quote(old+i, 0, 0);
+ if (!bb && !old[i]) break;
+ if (bb && (!old[i] || old[i] == '}')) {
+ bb->active = bb->commas[bb->cnt+1] = i;
+ for (bnext = bb; bb && bb->active; bb = (bb==blist)?0:bb->prev);
+dprintf(2, "}[%d]%p@%d\n", bnext->cnt, bb, i);
+ // discard commaless brace
+ if (!old[i] || !bnext->cnt)
+ free((blist == bnext) ? dlist_pop(&blist) : bnext);
+ } else if (old[i] == '{') {
dlist_add_nomalloc((void *)&blist,
(void *)(bb = xzalloc(sizeof(struct brace)+34*4)));
dprintf(2, "{%p@%d %c\n", bb, i, bb->debug = old[i+1]);
@@ -358,12 +385,6 @@ dprintf(2, ",%p@%d\t%c\n", bb, i, old[i+1]);
}
bb->commas[++bb->cnt] = i;
dprintf(2, "cnt %c %d\n", bb->debug, bb->cnt);
- } else if (bb && old[i] == '}') {
- bb->active = bb->commas[bb->cnt+1] = i;
- for (bnext = bb; bb && bb->active; bb = (bb==blist)?0:bb->prev);
-dprintf(2, "}[%d]%p@%d\n", bnext->cnt, bb, i);
- // discard commaless brace
- if (!bnext->cnt) free((blist == bnext) ? dlist_pop(&blist) : bnext);
}
}