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:
parent
9e4f9b37a1
commit
eaa91315bd
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user