On Sun, 12 Aug 2012, Alexander Polakov wrote: > Nobody cares, so here's my attempt. I haven't run it though a > world/ports build because of slow hardware on my hands right now. > > Index: lex.c > =================================================================== > RCS file: /cvs/src/bin/ksh/lex.c,v > retrieving revision 1.45 > diff -u -r1.45 lex.c > --- lex.c 9 Mar 2011 09:30:39 -0000 1.45 > +++ lex.c 11 Aug 2012 20:18:15 -0000 > @@ -271,6 +271,8 @@ > break; > case '\'': > *wp++ = OQUOTE; > + if (state == SBRACE) > + *wp++ = CHAR, *wp++ = c; > ignore_backslash_newline++; > PUSH_STATE(SSQUOTE); > break; > @@ -420,6 +422,8 @@ > if (c == '\'') { > POP_STATE(); > *wp++ = CQUOTE; > + if (state == SBRACE) > + *wp++ = CHAR, *wp++ = c; > ignore_backslash_newline--; > } else > *wp++ = QCHAR, *wp++ = c;
Unfortunately, that diff breaks the current, correct handling of single-quotes inside ${} that is *not* inside double-quotes. This: foo=1; echo ${foo:+'blah $foo'} should output blah $foo (Note the two spaces between 'blah' and '$foo' in both input and output) Below is an expansion of your diff for tests/unclass2.t to cover the cases discussed in this thread plus a couple others. As for how to get the fix to cover all those cases: the heredoc case can be handled by changing the added test to if ((cf & HEREDOC) || state == SBRACE) ...but it needs to be something like if ((cf & HEREDOC) || (state == SBRACE && is_in_double_quotes)) with "is_in_double_quotes" some magic to differentiate between the "${foo+'bar'}" and ${foo+'bar'} cases. That presumably involves walking up the statep list, but that has to stop when it hits a wrapping command-expansion. For example, the third new test in the diff below: echo "$( echo ${foo:+'blah $foo'})" that should output blah $foo Philip Index: tests/unclass2.t =================================================================== RCS file: /cvs/src/bin/ksh/tests/unclass2.t,v retrieving revision 1.2 diff -u -p -r1.2 unclass2.t --- tests/unclass2.t 25 Jun 1998 19:02:43 -0000 1.2 +++ tests/unclass2.t 12 Aug 2012 01:58:01 -0000 @@ -161,3 +161,55 @@ expected-stderr: ! XX --- +name: single-quotes-in-braces +description: + Check that single quotes inside unquoted {} are treated as quotes +stdin: + foo=1 + echo ${foo:+'blah $foo'} +expected-stdout: + blah $foo +--- + +name: single-quotes-in-quoted-braces +description: + Check that single quotes inside quoted {} are treated as normal char +stdin: + foo=1 + echo "${foo:+'blah $foo'}" +expected-stdout: + 'blah 1' +--- + +name: single-quotes-in-braces-nested +description: + Check that single quotes inside unquoted {} are treated as quotes, + even if that's inside a double-quoted command expansion +stdin: + foo=1 + echo "$( echo ${foo:+'blah $foo'})" +expected-stdout: + blah $foo +--- + +name: single-quotes-in-brace-pattern +description: + Check that single quotes inside {} pattern are treated as quotes +stdin: + foo=1234 + echo ${foo%'2'*} "${foo%'2'*}" ${foo%2'*'} "${foo%2'*'}" +expected-stdout: + 1 1 1234 1234 +--- + +name: single-quotes-in-heredoc-braces +description: + Check that single quotes inside {} in heredoc are treated as normal char +stdin: + foo=1 + cat <<EOM + ${foo:+'blah $foo'} + EOM +expected-stdout: + 'blah 1' +---