From 60afef10dee17524f83dbf1feee59e21fbd9520a Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 28 Apr 2023 23:20:18 -0500 Subject: [PATCH] Fix line continuation debris, add test, minor in-passing cleanups. --- tests/sh.test | 4 +++- toys/pending/sh.c | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/sh.test b/tests/sh.test index 0cc16b9b..7ffc993c 100644 --- a/tests/sh.test +++ b/tests/sh.test @@ -123,6 +123,7 @@ export EVAL="timeout 10 $SH -c" testing 'trailing $ is literal' 'echo $' '$\n' '' '' # TODO testing 'empty +() is literal' 'echo +()' '+()\n' '' '' + shxpect 'queued work after HERE' I$'<<0;echo hello\n' E"> " I$'0\n' O$'hello\n' shxpect '$_ preserved on assignment error' I$'true hello; a=1 b=2 c=${}\n' \ E E"$P" I$'echo $_\n' O$'hello\n' @@ -151,7 +152,6 @@ testing 'cd in renamed dir' \ rm -rf one testing "smoketest" "echo hello" "hello\n" "" "" -testing "line break" $'ec\\\nho hello' 'hello\n' '' '' testing "assignment" 'x=y; echo $x' 'y\n' '' '' testing "+= assignment" 'x+=abc; y=def; y+=$x; echo $y' 'defabc\n' '' '' testing "eval" "eval echo hello" "hello\n" "" "" @@ -541,6 +541,8 @@ shxpect '${/newline/}' I$'x=$\'\na\';echo ${x/\n' E'> ' I$'/b}\n' O$'ba\n' E'> ' shxpect 'line continuation' I$'echo "hello" \\\n' E'> ' I$'> blah\n' E"$P" \ I$'wc blah\n' O$'1 1 6 blah\n' shxpect 'line continuation2' I$'echo ABC\\\n' E'> ' I$'DEF\n' O$'ABCDEF\n' +testing "line continuation3" $'ec\\\nho hello' 'hello\n' '' '' +testing "line continuation4" $'if true | \\\n(true);then echo true;fi' 'true\n' '' '' # Race condition (in bash, but not in toysh) can say 43. testing 'SECONDS' 'readonly SECONDS=41; sleep 1; echo $SECONDS' '42\n' '' '' diff --git a/toys/pending/sh.c b/toys/pending/sh.c index 2bdf64a3..b1a5d1a0 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -1121,7 +1121,7 @@ static char *parse_word(char *start, int early, int quote) // \? $() ${} $[] ?() *() +() @() !() else { - if (ii=='\\') { // TODO why end[1] here? sh -c $'abc\\\ndef' Add test. + if (ii=='\\') { if (!*end || (*end=='\n' && !end[1])) return early ? end : 0; } else if (ii=='$' && -1!=(qq = stridx("({[", *end))) { if (strstart(&end, "((")) { @@ -2138,12 +2138,11 @@ barf: } else if (*slice=='/') { struct sh_arg wild = {0}; - s = slashcopy(ss = slice+(xx = !!strchr("/#%", slice[1]))+1, "/}", - &wild); + xx = !!strchr("/#%", slice[1]); + s = slashcopy(ss = slice+xx+1, "/}", &wild); ss += (long)wild.v[wild.c]; ss = (*ss == '/') ? slashcopy(ss+1, "}", 0) : 0; jj = ss ? strlen(ss) : 0; - ll = 0; for (ll = 0; ifs[ll];) { // TODO nocasematch option if (0<(dd = wildcard_match(ifs+ll, s, &wild, 0))) { @@ -3042,6 +3041,7 @@ static int parse_line(char *line, struct sh_pipeline **ppl, // Do we need to request another line to finish word (find ending quote)? if (!end) { // Save unparsed bit of this line, we'll need to re-parse it. + if (*start=='\\' && (!start[1] || start[1]=='\n')) start++; arg_add(arg, xstrndup(start, strlen(start))); arg->c = -arg->c; free(delete); -- 2.39.2