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'
+---

Reply via email to