Module Name: src Committed By: kre Date: Wed May 3 04:51:05 UTC 2017
Modified Files: src/bin/sh: input.c input.h parser.c Log Message: 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.) To generate a diff of this commit: cvs rdiff -u -r1.54 -r1.55 src/bin/sh/input.c cvs rdiff -u -r1.17 -r1.18 src/bin/sh/input.h cvs rdiff -u -r1.120 -r1.121 src/bin/sh/parser.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/bin/sh/input.c diff -u src/bin/sh/input.c:1.54 src/bin/sh/input.c:1.55 --- src/bin/sh/input.c:1.54 Wed May 3 04:13:53 2017 +++ src/bin/sh/input.c Wed May 3 04:51:04 2017 @@ -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 @@ __RCSID("$NetBSD: input.c,v 1.54 2017/05 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 @@ struct parsefile { 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 @@ struct parsefile { 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 @@ again: } } - 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 @@ pungetc(void) * 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; Index: src/bin/sh/input.h diff -u src/bin/sh/input.h:1.17 src/bin/sh/input.h:1.18 --- src/bin/sh/input.h:1.17 Wed May 3 04:13:53 2017 +++ src/bin/sh/input.h Wed May 3 04:51:04 2017 @@ -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 @@ char *pfgets(char *, int); 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); Index: src/bin/sh/parser.c diff -u src/bin/sh/parser.c:1.120 src/bin/sh/parser.c:1.121 --- src/bin/sh/parser.c:1.120 Wed Jun 1 02:47:05 2016 +++ src/bin/sh/parser.c Wed May 3 04:51:04 2017 @@ -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 int noexpand(char *); 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 @@ xxreadtoken(void) 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 @@ parsebackq(VSS *const stack, char * cons setprompt(2); needprompt = 0; } - switch (pc = pgetc()) { + switch (pc = pgetc_linecont()) { case '`': goto done; @@ -1405,7 +1406,7 @@ parseredir(const char *out, int c) if (c == '>') { if (fd < 0) fd = 1; - c = pgetc(); + c = pgetc_linecont(); if (c == '>') np->type = NAPPEND; else if (c == '|') @@ -1419,7 +1420,7 @@ parseredir(const char *out, int c) } 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 @@ parseredir(const char *out, int c) 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 @@ readtoken1(int firstc, char const *syn, USTPUTC(c, out); --parenlevel; } else { - if (pgetc() == ')') { + if (pgetc_linecont() == ')') { if (--arinest == 0) { TS_POP(); USTPUTC(CTLENDARI, out); @@ -1707,12 +1708,12 @@ parsesub: { 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 @@ parsesub: { subtype = VSNORMAL; flags = 0; if (c == OPENBRACE) { - c = pgetc(); + c = pgetc_linecont(); if (c == '#') { if ((c = pgetc()) == CLOSEBRACE) c = '#'; @@ -1739,7 +1740,7 @@ parsesub: { 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 @@ parsesub: { } 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 @@ badsub: switch (c) { case ':': flags |= VSNUL; - c = pgetc(); + c = pgetc_linecont(); /*FALLTHROUGH*/ default: p = strchr(types, c); @@ -1788,7 +1789,7 @@ badsub: int cc = c; subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; - c = pgetc(); + c = pgetc_linecont(); if (c == cc) subtype++; else @@ -1959,6 +1960,34 @@ setprompt(int which) } /* + * 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. */