ash: simplify EOF/newline handling in list parser
authorRon Yorston <rmy@pobox.com>
Thu, 29 Oct 2015 11:30:55 +0000 (11:30 +0000)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 29 Oct 2015 20:44:11 +0000 (21:44 +0100)
Processing of here documents in ash has had a couple of breakages
which are now the subject of tests.  This commit should fix both.

It is based on the following commit in dash git by Herbert Xu:

   <7c245aa> [PARSER] Simplify EOF/newline handling in list parser

(See git://git.kernel.org/pub/scm/utils/dash/dash.git)

Reported-by: Natanael Copa <ncopa@alpinelinux.org>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index 72fc7d52463221ef9b686d5e02d6e88ef6f1df6d..9a8bab5abaa0a8e9c34cfe094c6eef083f0d604c 100644 (file)
@@ -10524,7 +10524,7 @@ static union node *andor(void);
 static union node *pipeline(void);
 static union node *parse_command(void);
 static void parseheredoc(void);
-static char peektoken(void);
+static int peektoken(void);
 static int readtoken(void);
 
 static union node *
@@ -10533,11 +10533,27 @@ list(int nlflag)
        union node *n1, *n2, *n3;
        int tok;
 
-       checkkwd = CHKNL | CHKKWD | CHKALIAS;
-       if (nlflag == 2 && peektoken())
-               return NULL;
        n1 = NULL;
        for (;;) {
+               switch (peektoken()) {
+               case TNL:
+                       if (!(nlflag & 1))
+                               break;
+                       parseheredoc();
+                       return n1;
+
+               case TEOF:
+                       if (!n1 && (nlflag & 1))
+                               n1 = NODE_EOF;
+                       parseheredoc();
+                       return n1;
+               }
+
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               if (nlflag == 2 && tokname_array[peektoken()][0])
+                       return n1;
+               nlflag |= 2;
+
                n2 = andor();
                tok = readtoken();
                if (tok == TBACKGND) {
@@ -10563,30 +10579,15 @@ list(int nlflag)
                        n1 = n3;
                }
                switch (tok) {
+               case TNL:
+               case TEOF:
+                       tokpushback = 1;
+                       /* fall through */
                case TBACKGND:
                case TSEMI:
-                       tok = readtoken();
-                       /* fall through */
-               case TNL:
-                       if (tok == TNL) {
-                               parseheredoc();
-                               if (nlflag == 1)
-                                       return n1;
-                       } else {
-                               tokpushback = 1;
-                       }
-                       checkkwd = CHKNL | CHKKWD | CHKALIAS;
-                       if (peektoken())
-                               return n1;
                        break;
-               case TEOF:
-                       if (heredoclist)
-                               parseheredoc();
-                       else
-                               pungetc();              /* push back EOF on input */
-                       return n1;
                default:
-                       if (nlflag == 1)
+                       if ((nlflag & 1))
                                raise_error_unexpected_syntax(-1);
                        tokpushback = 1;
                        return n1;
@@ -11954,14 +11955,14 @@ readtoken(void)
        return t;
 }
 
-static char
+static int
 peektoken(void)
 {
        int t;
 
        t = readtoken();
        tokpushback = 1;
-       return tokname_array[t][0];
+       return t;
 }
 
 /*
@@ -11971,18 +11972,12 @@ peektoken(void)
 static union node *
 parsecmd(int interact)
 {
-       int t;
-
        tokpushback = 0;
+       checkkwd = 0;
+       heredoclist = 0;
        doprompt = interact;
        setprompt_if(doprompt, doprompt);
        needprompt = 0;
-       t = readtoken();
-       if (t == TEOF)
-               return NODE_EOF;
-       if (t == TNL)
-               return NULL;
-       tokpushback = 1;
        return list(1);
 }