summaryrefslogtreecommitdiffstats
path: root/bin/sh/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sh/parser.c')
-rw-r--r--bin/sh/parser.c291
1 files changed, 152 insertions, 139 deletions
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index e6e9f82..7fae29e 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -66,7 +66,6 @@ __FBSDID("$FreeBSD$");
* Shell command parser.
*/
-#define EOFMARKLEN 79
#define PROMPTLEN 128
/* values of checkkwd variable */
@@ -126,6 +125,7 @@ static void consumetoken(int);
static void synexpect(int) __dead2;
static void synerror(const char *) __dead2;
static void setprompt(int);
+static int pgetc_linecont(void);
static void *
@@ -718,7 +718,6 @@ parsefname(void)
if (n->type == NHERE) {
struct heredoc *here = heredoc;
struct heredoc *p;
- int i;
if (quoteflag == 0)
n->type = NXHERE;
@@ -727,7 +726,7 @@ parsefname(void)
while (*wordtext == '\t')
wordtext++;
}
- if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
+ if (! noexpand(wordtext))
synerror("Illegal eof marker for << redirection");
rmescapes(wordtext);
here->eofmark = wordtext;
@@ -891,7 +890,9 @@ xxreadtoken(void)
continue;
}
pungetc();
- goto breakloop;
+ /* FALLTHROUGH */
+ default:
+ return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
case '\n':
plinno++;
needprompt = doprompt;
@@ -899,17 +900,17 @@ xxreadtoken(void)
case PEOF:
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 ';':
- c = pgetc();
+ c = pgetc_linecont();
if (c == ';')
RETURN(TENDCASE);
else if (c == '&')
@@ -920,12 +921,8 @@ xxreadtoken(void)
RETURN(TLP);
case ')':
RETURN(TRP);
- default:
- goto breakloop;
}
}
-breakloop:
- return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
#undef RETURN
}
@@ -946,6 +943,98 @@ struct tokenstate
/*
+ * Check to see whether we are at the end of the here document. When this
+ * is called, c is set to the first character of the next input line. If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ * The new value of c is returned.
+ */
+
+static int
+checkend(int c, const char *eofmark, int striptabs)
+{
+ if (striptabs) {
+ while (c == '\t')
+ c = pgetc();
+ }
+ if (c == *eofmark) {
+ int c2;
+ const char *q;
+
+ for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
+ ;
+ if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
+ c = PEOF;
+ if (c2 == '\n') {
+ plinno++;
+ needprompt = doprompt;
+ }
+ } else {
+ pungetc();
+ pushstring(eofmark + 1, q - (eofmark + 1), NULL);
+ }
+ }
+ return (c);
+}
+
+
+/*
+ * Parse a redirection operator. The variable "out" points to a string
+ * specifying the fd to be redirected. The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+static void
+parseredir(char *out, int c)
+{
+ char fd = *out;
+ union node *np;
+
+ np = (union node *)stalloc(sizeof (struct nfile));
+ if (c == '>') {
+ np->nfile.fd = 1;
+ c = pgetc_linecont();
+ if (c == '>')
+ np->type = NAPPEND;
+ else if (c == '&')
+ np->type = NTOFD;
+ else if (c == '|')
+ np->type = NCLOBBER;
+ else {
+ np->type = NTO;
+ pungetc();
+ }
+ } else { /* c == '<' */
+ np->nfile.fd = 0;
+ c = pgetc_linecont();
+ if (c == '<') {
+ if (sizeof (struct nfile) != sizeof (struct nhere)) {
+ np = (union node *)stalloc(sizeof (struct nhere));
+ np->nfile.fd = 0;
+ }
+ np->type = NHERE;
+ heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+ heredoc->here = np;
+ if ((c = pgetc_linecont()) == '-') {
+ heredoc->striptabs = 1;
+ } else {
+ heredoc->striptabs = 0;
+ pungetc();
+ }
+ } else if (c == '&')
+ np->type = NFROMFD;
+ else if (c == '>')
+ np->type = NFROMTO;
+ else {
+ np->type = NFROM;
+ pungetc();
+ }
+ }
+ if (fd != '\0')
+ np->nfile.fd = digit_val(fd);
+ redirnode = np;
+}
+
+/*
* Called to parse command substitutions.
*/
@@ -1006,25 +1095,12 @@ parsebackq(char *out, struct nodelist **pbqlist,
needprompt = 0;
}
CHECKSTRSPACE(2, oout);
- switch (c = pgetc()) {
- case '`':
- goto done;
-
+ c = pgetc_linecont();
+ if (c == '`')
+ break;
+ switch (c) {
case '\\':
- if ((c = pgetc()) == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- /*
- * If eating a newline, avoid putting
- * the newline into the new character
- * stream (via the USTPUTC after the
- * switch).
- */
- continue;
- }
+ c = pgetc();
if (c != '\\' && c != '`' && c != '$'
&& (!dblquote || c != '"'))
USTPUTC('\\', oout);
@@ -1045,7 +1121,6 @@ parsebackq(char *out, struct nodelist **pbqlist,
}
USTPUTC(c, oout);
}
-done:
USTPUTC('\0', oout);
olen = oout - stackblock();
INTOFF;
@@ -1246,6 +1321,13 @@ readcstyleesc(char *out)
c = pgetc();
if (c == PEOF)
synerror("Unterminated quoted string");
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ }
}
pungetc();
return out;
@@ -1269,8 +1351,6 @@ readcstyleesc(char *out)
* will run code that appears at the end of readtoken1.
*/
-#define CHECKEND() {goto checkend; checkend_return:;}
-#define PARSEREDIR() {goto parseredir; parseredir_return:;}
#define PARSESUB() {goto parsesub; parsesub_return:;}
#define PARSEARITH() {goto parsearith; parsearith_return:;}
@@ -1281,7 +1361,6 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
int c = firstc;
char *out;
int len;
- char line[EOFMARKLEN + 1];
struct nodelist *bqlist;
int quotef;
int newvarnest;
@@ -1303,7 +1382,9 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
STARTSTACKSTR(out);
loop: { /* for each line, until end of word */
- CHECKEND(); /* set c to PEOF if at end of here document */
+ if (eofmark)
+ /* set c to PEOF if at end of here document */
+ c = checkend(c, eofmark, striptabs);
for (;;) { /* until end of line or end of word */
CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
@@ -1414,7 +1495,7 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
USTPUTC(c, out);
--state[level].parenlevel;
} else {
- if (pgetc() == ')') {
+ if (pgetc_linecont() == ')') {
if (level > 0 &&
state[level].category == TSTATE_ARITH) {
level--;
@@ -1469,7 +1550,7 @@ endword:
&& quotef == 0
&& len <= 2
&& (*out == '\0' || is_digit(*out))) {
- PARSEREDIR();
+ parseredir(out, c);
return lasttoken = TREDIR;
} else {
pungetc();
@@ -1484,97 +1565,6 @@ endword:
/*
- * Check to see whether we are at the end of the here document. When this
- * is called, c is set to the first character of the next input line. If
- * we are at the end of the here document, this routine sets the c to PEOF.
- */
-
-checkend: {
- if (eofmark) {
- if (striptabs) {
- while (c == '\t')
- c = pgetc();
- }
- if (c == *eofmark) {
- if (pfgets(line, sizeof line) != NULL) {
- const char *p, *q;
-
- p = line;
- for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
- if ((*p == '\0' || *p == '\n') && *q == '\0') {
- c = PEOF;
- if (*p == '\n') {
- plinno++;
- needprompt = doprompt;
- }
- } else {
- pushstring(line, strlen(line), NULL);
- }
- }
- }
- }
- goto checkend_return;
-}
-
-
-/*
- * Parse a redirection operator. The variable "out" points to a string
- * specifying the fd to be redirected. The variable "c" contains the
- * first character of the redirection operator.
- */
-
-parseredir: {
- char fd = *out;
- union node *np;
-
- np = (union node *)stalloc(sizeof (struct nfile));
- if (c == '>') {
- np->nfile.fd = 1;
- c = pgetc();
- if (c == '>')
- np->type = NAPPEND;
- else if (c == '&')
- np->type = NTOFD;
- else if (c == '|')
- np->type = NCLOBBER;
- else {
- np->type = NTO;
- pungetc();
- }
- } else { /* c == '<' */
- np->nfile.fd = 0;
- c = pgetc();
- if (c == '<') {
- if (sizeof (struct nfile) != sizeof (struct nhere)) {
- np = (union node *)stalloc(sizeof (struct nhere));
- np->nfile.fd = 0;
- }
- np->type = NHERE;
- heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
- heredoc->here = np;
- if ((c = pgetc()) == '-') {
- heredoc->striptabs = 1;
- } else {
- heredoc->striptabs = 0;
- pungetc();
- }
- } else if (c == '&')
- np->type = NFROMFD;
- else if (c == '>')
- np->type = NFROMTO;
- else {
- np->type = NFROM;
- pungetc();
- }
- }
- if (fd != '\0')
- np->nfile.fd = digit_val(fd);
- redirnode = np;
- goto parseredir_return;
-}
-
-
-/*
* Parse a substitution. At this point, we have read the dollar sign
* and nothing else.
*/
@@ -1591,9 +1581,9 @@ parsesub: {
int length;
int c1;
- c = pgetc();
+ c = pgetc_linecont();
if (c == '(') { /* $(command) or $((arith)) */
- if (pgetc() == '(') {
+ if (pgetc_linecont() == '(') {
PARSEARITH();
} else {
pungetc();
@@ -1611,7 +1601,7 @@ parsesub: {
flags = 0;
if (c == '{') {
bracketed_name = 1;
- c = pgetc();
+ c = pgetc_linecont();
subtype = 0;
}
varname:
@@ -1619,7 +1609,7 @@ varname:
length = 0;
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
length++;
} while (!is_eof(c) && is_in_name(c));
if (length == 6 &&
@@ -1638,22 +1628,22 @@ varname:
if (bracketed_name) {
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
} while (is_digit(c));
} else {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
}
} else if (is_special(c)) {
c1 = c;
- c = pgetc();
+ c = pgetc_linecont();
if (subtype == 0 && c1 == '#') {
subtype = VSLENGTH;
if (strchr(types, c) == NULL && c != ':' &&
c != '#' && c != '%')
goto varname;
c1 = c;
- c = pgetc();
+ c = pgetc_linecont();
if (c1 != '}' && c == '}') {
pungetc();
c = c1;
@@ -1678,7 +1668,7 @@ varname:
switch (c) {
case ':':
flags |= VSNUL;
- c = pgetc();
+ c = pgetc_linecont();
/*FALLTHROUGH*/
default:
p = strchr(types, c);
@@ -1698,7 +1688,7 @@ varname:
int cc = c;
subtype = c == '#' ? VSTRIMLEFT :
VSTRIMRIGHT;
- c = pgetc();
+ c = pgetc_linecont();
if (c == cc)
subtype++;
else
@@ -1907,6 +1897,29 @@ setprompt(int which)
}
}
+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.
@@ -1915,7 +1928,7 @@ char *
getprompt(void *unused __unused)
{
static char ps[PROMPTLEN];
- char *fmt;
+ const char *fmt;
const char *pwd;
int i, trim;
static char internal_error[] = "??";
@@ -2029,7 +2042,7 @@ expandstr(const char *ps)
parser_temp = NULL;
setinputstring(ps, 1);
doprompt = 0;
- readtoken1(pgetc(), DQSYNTAX, "\n\n", 0);
+ readtoken1(pgetc(), DQSYNTAX, "", 0);
if (backquotelist != NULL)
error("Command substitution not allowed here");
OpenPOWER on IntegriCloud