Author: jilles
Date: Sun Oct 19 11:59:15 2014
New Revision: 273276
URL: https://svnweb.freebsd.org/changeset/base/273276

Log:
  sh: Allow backslash-newline continuation in more places:
  
   * directly after a $
   * directly after ${
   * between the characters of a multi-character operator token
   * within a parameter name

Added:
  head/bin/sh/tests/parser/line-cont10.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont11.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont4.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont5.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont6.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont7.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont8.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont9.0   (contents, props changed)
Modified:
  head/bin/sh/parser.c
  head/bin/sh/tests/parser/Makefile

Modified: head/bin/sh/parser.c
==============================================================================
--- head/bin/sh/parser.c        Sun Oct 19 11:31:23 2014        (r273275)
+++ head/bin/sh/parser.c        Sun Oct 19 11:59:15 2014        (r273276)
@@ -125,6 +125,7 @@ static void consumetoken(int);
 static void synexpect(int) __dead2;
 static void synerror(const char *) __dead2;
 static void setprompt(int);
+static int pgetc_linecont(void);
 
 
 static void *
@@ -899,17 +900,17 @@ xxreadtoken(void)
                case PEOF:
                        RETURN(TEOF);
                case '&':
-                       if (pgetc() == '&')
+                       if (pgetc_linecont() == '&')
                                RETURN(TAND);
                        pungetc();
                        RETURN(TBACKGND);
                case '|':
-                       if (pgetc() == '|')
+                       if (pgetc_linecont() == '|')
                                RETURN(TOR);
                        pungetc();
                        RETURN(TPIPE);
                case ';':
-                       c = pgetc();
+                       c = pgetc_linecont();
                        if (c == ';')
                                RETURN(TENDCASE);
                        else if (c == '&')
@@ -991,7 +992,7 @@ parseredir(char *out, int c)
        np = (union node *)stalloc(sizeof (struct nfile));
        if (c == '>') {
                np->nfile.fd = 1;
-               c = pgetc();
+               c = pgetc_linecont();
                if (c == '>')
                        np->type = NAPPEND;
                else if (c == '&')
@@ -1004,7 +1005,7 @@ parseredir(char *out, int c)
                }
        } else {        /* c == '<' */
                np->nfile.fd = 0;
-               c = pgetc();
+               c = pgetc_linecont();
                if (c == '<') {
                        if (sizeof (struct nfile) != sizeof (struct nhere)) {
                                np = (union node *)stalloc(sizeof (struct 
nhere));
@@ -1013,7 +1014,7 @@ parseredir(char *out, int c)
                        np->type = NHERE;
                        heredoc = (struct heredoc *)stalloc(sizeof (struct 
heredoc));
                        heredoc->here = np;
-                       if ((c = pgetc()) == '-') {
+                       if ((c = pgetc_linecont()) == '-') {
                                heredoc->striptabs = 1;
                        } else {
                                heredoc->striptabs = 0;
@@ -1094,25 +1095,12 @@ parsebackq(char *out, struct nodelist **
                                needprompt = 0;
                        }
                        CHECKSTRSPACE(2, oout);
-                       c = pgetc();
+                       c = pgetc_linecont();
                        if (c == '`')
                                break;
                        switch (c) {
                        case '\\':
-                                if ((c = pgetc()) == '\n') {
-                                       plinno++;
-                                       if (doprompt)
-                                               setprompt(2);
-                                       else
-                                               setprompt(0);
-                                       /*
-                                        * If eating a newline, avoid putting
-                                        * the newline into the new character
-                                        * stream (via the USTPUTC after the
-                                        * switch).
-                                        */
-                                       continue;
-                               }
+                               c = pgetc();
                                 if (c != '\\' && c != '`' && c != '$'
                                     && (!dblquote || c != '"'))
                                         USTPUTC('\\', oout);
@@ -1507,7 +1495,7 @@ readtoken1(int firstc, char const *initi
                                        USTPUTC(c, out);
                                        --state[level].parenlevel;
                                } else {
-                                       if (pgetc() == ')') {
+                                       if (pgetc_linecont() == ')') {
                                                if (level > 0 &&
                                                    state[level].category == 
TSTATE_ARITH) {
                                                        level--;
@@ -1593,9 +1581,9 @@ parsesub: {
        int length;
        int c1;
 
-       c = pgetc();
+       c = pgetc_linecont();
        if (c == '(') { /* $(command) or $((arith)) */
-               if (pgetc() == '(') {
+               if (pgetc_linecont() == '(') {
                        PARSEARITH();
                } else {
                        pungetc();
@@ -1613,7 +1601,7 @@ parsesub: {
                flags = 0;
                if (c == '{') {
                        bracketed_name = 1;
-                       c = pgetc();
+                       c = pgetc_linecont();
                        subtype = 0;
                }
 varname:
@@ -1621,7 +1609,7 @@ varname:
                        length = 0;
                        do {
                                STPUTC(c, out);
-                               c = pgetc();
+                               c = pgetc_linecont();
                                length++;
                        } while (!is_eof(c) && is_in_name(c));
                        if (length == 6 &&
@@ -1640,22 +1628,22 @@ varname:
                        if (bracketed_name) {
                                do {
                                        STPUTC(c, out);
-                                       c = pgetc();
+                                       c = pgetc_linecont();
                                } while (is_digit(c));
                        } else {
                                STPUTC(c, out);
-                               c = pgetc();
+                               c = pgetc_linecont();
                        }
                } else if (is_special(c)) {
                        c1 = c;
-                       c = pgetc();
+                       c = pgetc_linecont();
                        if (subtype == 0 && c1 == '#') {
                                subtype = VSLENGTH;
                                if (strchr(types, c) == NULL && c != ':' &&
                                    c != '#' && c != '%')
                                        goto varname;
                                c1 = c;
-                               c = pgetc();
+                               c = pgetc_linecont();
                                if (c1 != '}' && c == '}') {
                                        pungetc();
                                        c = c1;
@@ -1680,7 +1668,7 @@ varname:
                        switch (c) {
                        case ':':
                                flags |= VSNUL;
-                               c = pgetc();
+                               c = pgetc_linecont();
                                /*FALLTHROUGH*/
                        default:
                                p = strchr(types, c);
@@ -1700,7 +1688,7 @@ varname:
                                        int cc = c;
                                        subtype = c == '#' ? VSTRIMLEFT :
                                                             VSTRIMRIGHT;
-                                       c = pgetc();
+                                       c = pgetc_linecont();
                                        if (c == cc)
                                                subtype++;
                                        else
@@ -1909,6 +1897,29 @@ setprompt(int which)
        }
 }
 
+static int
+pgetc_linecont(void)
+{
+       int c;
+
+       while ((c = pgetc_macro()) == '\\') {
+               c = pgetc();
+               if (c == '\n') {
+                       plinno++;
+                       if (doprompt)
+                               setprompt(2);
+                       else
+                               setprompt(0);
+               } else {
+                       pungetc();
+                       /* Allow the backslash to be pushed back. */
+                       pushstring("\\", 1, NULL);
+                       return (pgetc());
+               }
+       }
+       return (c);
+}
+
 /*
  * called by editline -- any expansions to the prompt
  *    should be added here.

Modified: head/bin/sh/tests/parser/Makefile
==============================================================================
--- head/bin/sh/tests/parser/Makefile   Sun Oct 19 11:31:23 2014        
(r273275)
+++ head/bin/sh/tests/parser/Makefile   Sun Oct 19 11:59:15 2014        
(r273276)
@@ -58,6 +58,14 @@ FILES+=              heredoc12.0
 FILES+=                line-cont1.0
 FILES+=                line-cont2.0
 FILES+=                line-cont3.0
+FILES+=                line-cont4.0
+FILES+=                line-cont5.0
+FILES+=                line-cont6.0
+FILES+=                line-cont7.0
+FILES+=                line-cont8.0
+FILES+=                line-cont9.0
+FILES+=                line-cont10.0
+FILES+=                line-cont11.0
 FILES+=                no-space1.0
 FILES+=                no-space2.0
 FILES+=                only-redir1.0

Added: head/bin/sh/tests/parser/line-cont10.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont10.0      Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]

Added: head/bin/sh/tests/parser/line-cont11.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont11.0      Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+T=$(mktemp "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -f -- "$T"' 0
+w='#A'
+# A naive pgetc_linecont() would push back two characters here, which
+# fails if a new buffer is read between the two characters.
+c='${w#\#}'
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+printf 'v=%s\n' "$c" >"$T"
+. "$T"
+if [ "${#v}" != 4096 ]; then
+       echo "Length is bad (${#v})"
+       exit 3
+fi
+case $v in
+*[!A]*) echo "Content is bad"; exit 3 ;;
+esac

Added: head/bin/sh/tests/parser/line-cont4.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont4.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]

Added: head/bin/sh/tests/parser/line-cont5.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont5.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]

Added: head/bin/sh/tests/parser/line-cont6.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont6.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+       efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]

Added: head/bin/sh/tests/parser/line-cont7.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont7.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]

Added: head/bin/sh/tests/parser/line-cont8.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont8.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]

Added: head/bin/sh/tests/parser/line-cont9.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont9.0       Sun Oct 19 11:59:15 2014        
(r273276)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to