From e3c1b14cf9b685528efa50ca068a9f3fd9f9b05c Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Wed, 8 Jan 2020 03:42:56 -0600 Subject: Implement quote removal and fix unterminated bracket expansion. --- tests/sh.test | 4 ++-- toys/pending/sh.c | 41 +++++++++++++++++++++++++++++++---------- 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); } } -- cgit v1.2.3