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.)
This commit is contained in:
kre 2017-05-03 04:51:04 +00:00
parent 9e4f9b37a1
commit eaa91315bd
3 changed files with 59 additions and 28 deletions

View File

@ -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/03 04:13:53 kre Exp $");
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;

View File

@ -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);

View File

@ -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 * const in,
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, int magicq)
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
@ -1958,6 +1959,34 @@ setprompt(int which)
out2str(getprompt(NULL));
}
/*
* 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.