Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sh Deal with \newline line continuations more correctly.



details:   https://anonhg.NetBSD.org/src/rev/e63eabe7c21d
branches:  trunk
changeset: 823691:e63eabe7c21d
user:      kre <kre%NetBSD.org@localhost>
date:      Wed May 03 04:51:04 2017 +0000

description:
Deal with \newline line continuations more correctly.
They can occur anywhere (*anywhere*) not only where it
happens to be convenient to the parser...

This fix from FreeBSD (thanks again folks).

To make this work, pushstring()'s signature needed to change to allow a
const char * as its string arg, which meant sprinkling some const other
places for a brighter appearance (and handling fallout).

All this because I wanted to see what number would come from

echo $\
{\
L\
I\
N\
E\
N\
O\
}

and was surprised at the result!    That works now...

The bug would also affect stuff like

true &\
& false

and all kinds of other uses where the \newline occurred in the
"wrong" place.

An ATF test for sh syntax is coming... (sometime.)

diffstat:

 bin/sh/input.c  |  16 +++++++------
 bin/sh/input.h  |   6 ++--
 bin/sh/parser.c |  65 +++++++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 59 insertions(+), 28 deletions(-)

diffs (285 lines):

diff -r 30d5bb3d548a -r e63eabe7c21d bin/sh/input.c
--- a/bin/sh/input.c    Wed May 03 04:13:53 2017 +0000
+++ b/bin/sh/input.c    Wed May 03 04:51:04 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: input.c,v 1.54 2017/05/03 04:13:53 kre Exp $   */
+/*     $NetBSD: input.c,v 1.55 2017/05/03 04:51:04 kre Exp $   */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)input.c    8.3 (Berkeley) 6/9/95";
 #else
-__RCSID("$NetBSD: input.c,v 1.54 2017/05/03 04:13:53 kre Exp $");
+__RCSID("$NetBSD: input.c,v 1.55 2017/05/03 04:51:04 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -71,7 +71,7 @@
 MKINIT
 struct strpush {
        struct strpush *prev;   /* preceding string on stack */
-       char *prevstring;
+       const char *prevstring;
        int prevnleft;
        int prevlleft;
        struct alias *ap;       /* if push was associated with an alias */
@@ -89,7 +89,7 @@
        int fd;                 /* file descriptor (or -1 if string) */
        int nleft;              /* number of chars left in this line */
        int lleft;              /* number of chars left in this buffer */
-       char *nextc;            /* next char in buffer */
+       const char *nextc;      /* next char in buffer */
        char *buf;              /* input buffer */
        struct strpush *strpush; /* for pushing strings at this level */
        struct strpush basestrpush; /* so pushing one is fast */
@@ -99,7 +99,7 @@
 int plinno = 1;                        /* input line number */
 int parsenleft;                        /* copy of parsefile->nleft */
 MKINIT int parselleft;         /* copy of parsefile->lleft */
-char *parsenextc;              /* copy of parsefile->nextc */
+const char *parsenextc;                /* copy of parsefile->nextc */
 MKINIT struct parsefile basepf;        /* top level input file */
 MKINIT char basebuf[BUFSIZ];   /* buffer for top level input file */
 struct parsefile *parsefile = &basepf; /* current input file */
@@ -262,7 +262,9 @@
                }
        }
 
-       q = p = parsenextc;
+               /* p = (not const char *)parsenextc; */
+       p = parsefile->buf + (parsenextc - parsefile->buf);
+       q = p;
 
        /* delete nul characters */
 #ifndef SMALL
@@ -341,7 +343,7 @@
  * We handle aliases this way.
  */
 void
-pushstring(char *s, int len, struct alias *ap)
+pushstring(const char *s, int len, struct alias *ap)
 {
        struct strpush *sp;
 
diff -r 30d5bb3d548a -r e63eabe7c21d bin/sh/input.h
--- a/bin/sh/input.h    Wed May 03 04:13:53 2017 +0000
+++ b/bin/sh/input.h    Wed May 03 04:51:04 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: input.h,v 1.17 2017/05/03 04:13:53 kre Exp $   */
+/*     $NetBSD: input.h,v 1.18 2017/05/03 04:51:04 kre Exp $   */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -43,7 +43,7 @@
  */
 extern int plinno;
 extern int parsenleft;         /* number of characters left in input buffer */
-extern char *parsenextc;       /* next character in input buffer */
+extern const char *parsenextc; /* next character in input buffer */
 extern int init_editline;      /* 0 == not setup, 1 == OK, -1 == failed */
 
 struct alias;
@@ -52,7 +52,7 @@
 int pgetc(void);
 int preadbuffer(void);
 void pungetc(void);
-void pushstring(char *, int, struct alias *);
+void pushstring(const char *, int, struct alias *);
 void popstring(void);
 void setinputfile(const char *, int);
 void setinputfd(int, int);
diff -r 30d5bb3d548a -r e63eabe7c21d bin/sh/parser.c
--- a/bin/sh/parser.c   Wed May 03 04:13:53 2017 +0000
+++ b/bin/sh/parser.c   Wed May 03 04:51:04 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: parser.c,v 1.120 2016/06/01 02:47:05 kre Exp $ */
+/*     $NetBSD: parser.c,v 1.121 2017/05/03 04:51:04 kre Exp $ */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)parser.c   8.7 (Berkeley) 5/16/95";
 #else
-__RCSID("$NetBSD: parser.c,v 1.120 2016/06/01 02:47:05 kre Exp $");
+__RCSID("$NetBSD: parser.c,v 1.121 2017/05/03 04:51:04 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -119,6 +119,7 @@
 STATIC void synexpect(int, const char *) __dead;
 STATIC void synerror(const char *) __dead;
 STATIC void setprompt(int);
+STATIC int pgetc_linecont(void);
 
 
 static const char EOFhere[] = "EOF reading here (<<) document";
@@ -1005,17 +1006,17 @@
                        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 ';':
-                       if (pgetc() == ';')
+                       if (pgetc_linecont() == ';')
                                RETURN(TENDCASE);
                        pungetc();
                        RETURN(TSEMI);
@@ -1281,7 +1282,7 @@
                                setprompt(2);
                                needprompt = 0;
                        }
-                       switch (pc = pgetc()) {
+                       switch (pc = pgetc_linecont()) {
                        case '`':
                                goto done;
 
@@ -1405,7 +1406,7 @@
        if (c == '>') {
                if (fd < 0)
                        fd = 1;
-               c = pgetc();
+               c = pgetc_linecont();
                if (c == '>')
                        np->type = NAPPEND;
                else if (c == '|')
@@ -1419,7 +1420,7 @@
        } else {        /* c == '<' */
                if (fd < 0)
                        fd = 0;
-               switch (c = pgetc()) {
+               switch (c = pgetc_linecont()) {
                case '<':
                        if (sizeof (struct nfile) != sizeof (struct nhere)) {
                                np = stalloc(sizeof(struct nhere));
@@ -1429,7 +1430,7 @@
                        heredoc = stalloc(sizeof(struct heredoc));
                        heredoc->here = np;
                        heredoc->startline = plinno;
-                       if ((c = pgetc()) == '-') {
+                       if ((c = pgetc_linecont()) == '-') {
                                heredoc->striptabs = 1;
                        } else {
                                heredoc->striptabs = 0;
@@ -1623,7 +1624,7 @@
                                USTPUTC(c, out);
                                --parenlevel;
                        } else {
-                               if (pgetc() == ')') {
+                               if (pgetc_linecont() == ')') {
                                        if (--arinest == 0) {
                                                TS_POP();
                                                USTPUTC(CTLENDARI, out);
@@ -1707,12 +1708,12 @@
        int i;
        int linno;
 
-       c = pgetc();
+       c = pgetc_linecont();
        if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
                USTPUTC('$', out);
                pungetc();
        } else if (c == '(') {  /* $(command) or $((arith)) */
-               if (pgetc() == '(') {
+               if (pgetc_linecont() == '(') {
                        PARSEARITH();
                } else {
                        pungetc();
@@ -1725,7 +1726,7 @@
                subtype = VSNORMAL;
                flags = 0;
                if (c == OPENBRACE) {
-                       c = pgetc();
+                       c = pgetc_linecont();
                        if (c == '#') {
                                if ((c = pgetc()) == CLOSEBRACE)
                                        c = '#';
@@ -1739,7 +1740,7 @@
                        p = out;
                        do {
                                STPUTC(c, out);
-                               c = pgetc();
+                               c = pgetc_linecont();
                        } while (is_in_name(c));
                        if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
                                /* Replace the variable name with the
@@ -1756,12 +1757,12 @@
                } else if (is_digit(c)) {
                        do {
                                USTPUTC(c, out);
-                               c = pgetc();
+                               c = pgetc_linecont();
                        } while (subtype != VSNORMAL && is_digit(c));
                }
                else if (is_special(c)) {
                        USTPUTC(c, out);
-                       c = pgetc();
+                       c = pgetc_linecont();
                }
                else {
 badsub:
@@ -1774,7 +1775,7 @@
                        switch (c) {
                        case ':':
                                flags |= VSNUL;
-                               c = pgetc();
+                               c = pgetc_linecont();
                                /*FALLTHROUGH*/
                        default:
                                p = strchr(types, c);
@@ -1788,7 +1789,7 @@
                                        int cc = c;
                                        subtype = c == '#' ? VSTRIMLEFT :
                                                             VSTRIMRIGHT;
-                                       c = pgetc();
+                                       c = pgetc_linecont();
                                        if (c == cc)
                                                subtype++;
                                        else
@@ -1959,6 +1960,34 @@
 }
 
 /*
+ * handle getting the next character, while ignoring \ \n
+ * (which is a little tricky as we only have one char of pushback
+ * and we need that one elsewhere).
+ */
+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.
  */



Home | Main Index | Thread Index | Old Index