summaryrefslogtreecommitdiff
path: root/Src/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/lex.c')
-rw-r--r--Src/lex.c1489
1 files changed, 1489 insertions, 0 deletions
diff --git a/Src/lex.c b/Src/lex.c
new file mode 100644
index 000000000..6f4f2dd20
--- /dev/null
+++ b/Src/lex.c
@@ -0,0 +1,1489 @@
+/*
+ * lex.c - lexical analysis
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1992-1997 Paul Falstad
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Paul Falstad or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Paul Falstad and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Paul Falstad and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Paul Falstad and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "zsh.mdh"
+#include "lex.pro"
+
+/* tokens */
+
+/**/
+char ztokens[] = "#$^*()$=|{}[]`<>?~`,'\"\\";
+
+/* parts of the current token */
+
+/**/
+char *yytext, *tokstr;
+/**/
+int tok, tokfd;
+
+/* lexical analyzer error flag */
+
+/**/
+int lexstop;
+
+/* if != 0, this is the first line of the command */
+
+/**/
+int isfirstln;
+
+/* if != 0, this is the first char of the command (not including white space) */
+
+/**/
+int isfirstch;
+
+/* flag that an alias should be expanded after expansion ending in space */
+
+/**/
+int inalmore;
+
+/* don't do spelling correction */
+
+/**/
+int nocorrect;
+
+/* the line buffer */
+
+/**/
+unsigned char *line;
+
+/* cursor position and line length */
+
+/**/
+int cs, ll;
+
+/* inwhat says what exactly we are in *
+ * (its value is one of the IN_* things). */
+
+/**/
+int inwhat;
+
+/* 1 if x added to complete in a blank between words */
+
+/**/
+int addedx;
+
+/* 1 if aliases should not be expanded */
+
+/**/
+int noaliases;
+
+/* we are parsing a line sent to use by the editor */
+
+/**/
+int zleparse;
+
+/**/
+int wordbeg;
+
+/**/
+int parbegin;
+
+/**/
+int parend;
+
+/* text of puctuation tokens */
+
+static char *tokstrings[WHILE + 1] = {
+ NULL, /* NULLTOK 0 */
+ ";", /* SEPER */
+ "\\n", /* NEWLIN */
+ ";", /* SEMI */
+ ";;", /* DSEMI */
+ "&", /* AMPER 5 */
+ "(", /* INPAR */
+ ")", /* OUTPAR */
+ "||", /* DBAR */
+ "&&", /* DAMPER */
+ ")", /* OUTANG 10 */
+ ">|", /* OUTANGBANG */
+ ">>", /* DOUTANG */
+ ">>|", /* DOUTANGBANG */
+ "<", /* INANG */
+ "<>", /* INOUTANG 15 */
+ "<<", /* DINANG */
+ "<<-", /* DINANGDASH */
+ "<&", /* INANGAMP */
+ ">&", /* OUTANGAMP */
+ "&>", /* AMPOUTANG 20 */
+ "&>|", /* OUTANGAMPBANG */
+ ">>&", /* DOUTANGAMP */
+ ">>&|", /* DOUTANGAMPBANG */
+ "<<<", /* TRINANG */
+ "|", /* BAR 25 */
+ "|&", /* BARAMP */
+ "()", /* INOUTPAR */
+ "((", /* DINPAR */
+ "))", /* DOUTPAR */
+ "&|", /* AMPERBANG 30 */
+ ";&", /* SEMIAMP */
+};
+
+/* lexical state */
+
+static int dbparens;
+static int len = 0, bsiz = 256;
+static char *bptr;
+
+struct lexstack {
+ struct lexstack *next;
+
+ int incmdpos;
+ int incond;
+ int incasepat;
+ int dbparens;
+ int isfirstln;
+ int isfirstch;
+ int histactive;
+ int histdone;
+ int spaceflag;
+ int stophist;
+ int hlinesz;
+ char *hline;
+ char *hptr;
+ int tok;
+ int isnewlin;
+ char *tokstr;
+ char *yytext;
+ char *bptr;
+ int bsiz;
+ short *chwords;
+ int chwordlen;
+ int chwordpos;
+ int hwgetword;
+ int lexstop;
+ struct heredocs *hdocs;
+
+ unsigned char *cstack;
+ int csp;
+};
+
+static struct lexstack *lstack = NULL;
+
+/* save the lexical state */
+
+/* is this a hack or what? */
+
+/**/
+void
+lexsave(void)
+{
+ struct lexstack *ls;
+
+ ls = (struct lexstack *)malloc(sizeof(struct lexstack));
+
+ ls->incmdpos = incmdpos;
+ ls->incond = incond;
+ ls->incasepat = incasepat;
+ ls->dbparens = dbparens;
+ ls->isfirstln = isfirstln;
+ ls->isfirstch = isfirstch;
+ ls->histactive = histactive;
+ ls->histdone = histdone;
+ ls->spaceflag = spaceflag;
+ ls->stophist = stophist;
+ ls->hline = chline;
+ ls->hptr = hptr;
+ ls->hlinesz = hlinesz;
+ ls->cstack = cmdstack;
+ ls->csp = cmdsp;
+ cmdstack = (unsigned char *)zalloc(256);
+ ls->tok = tok;
+ ls->isnewlin = isnewlin;
+ ls->tokstr = tokstr;
+ ls->yytext = yytext;
+ ls->bptr = bptr;
+ ls->bsiz = bsiz;
+ ls->chwords = chwords;
+ ls->chwordlen = chwordlen;
+ ls->chwordpos = chwordpos;
+ ls->hwgetword = hwgetword;
+ ls->lexstop = lexstop;
+ ls->hdocs = hdocs;
+ cmdsp = 0;
+ inredir = 0;
+ hdocs = NULL;
+
+ ls->next = lstack;
+ lstack = ls;
+}
+
+/* restore lexical state */
+
+/**/
+void
+lexrestore(void)
+{
+ struct lexstack *ln;
+
+ DPUTS(!lstack, "BUG: lexrestore() without lexsave()");
+ incmdpos = lstack->incmdpos;
+ incond = lstack->incond;
+ incasepat = lstack->incasepat;
+ dbparens = lstack->dbparens;
+ isfirstln = lstack->isfirstln;
+ isfirstch = lstack->isfirstch;
+ histactive = lstack->histactive;
+ histdone = lstack->histdone;
+ spaceflag = lstack->spaceflag;
+ stophist = lstack->stophist;
+ chline = lstack->hline;
+ hptr = lstack->hptr;
+ if (cmdstack)
+ free(cmdstack);
+ cmdstack = lstack->cstack;
+ cmdsp = lstack->csp;
+ tok = lstack->tok;
+ isnewlin = lstack->isnewlin;
+ tokstr = lstack->tokstr;
+ yytext = lstack->yytext;
+ bptr = lstack->bptr;
+ bsiz = lstack->bsiz;
+ chwords = lstack->chwords;
+ chwordlen = lstack->chwordlen;
+ chwordpos = lstack->chwordpos;
+ hwgetword = lstack->hwgetword;
+ lexstop = lstack->lexstop;
+ hdocs = lstack->hdocs;
+ hlinesz = lstack->hlinesz;
+ errflag = 0;
+
+ ln = lstack->next;
+ free(lstack);
+ lstack = ln;
+}
+
+/**/
+void
+yylex(void)
+{
+ if (tok == LEXERR)
+ return;
+ do
+ tok = gettok();
+ while (tok != ENDINPUT && exalias());
+ if (tok == NEWLIN || tok == ENDINPUT) {
+ while (hdocs) {
+ struct heredocs *next = hdocs->next;
+
+ hwbegin(0);
+ cmdpush(hdocs->rd->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
+ STOPHIST
+ hdocs->rd->name = gethere(hdocs->rd->name, hdocs->rd->type);
+ ALLOWHIST
+ cmdpop();
+ hwend();
+ hdocs->rd->type = HERESTR;
+ zfree(hdocs, sizeof(struct heredocs));
+ hdocs = next;
+ }
+ }
+ if (tok != NEWLIN)
+ isnewlin = 0;
+ else
+ isnewlin = (inbufct) ? -1 : 1;
+ if (tok == SEMI || tok == NEWLIN)
+ tok = SEPER;
+}
+
+/**/
+void
+ctxtlex(void)
+{
+ static int oldpos;
+
+ yylex();
+ switch (tok) {
+ case SEPER:
+ case NEWLIN:
+ case SEMI:
+ case DSEMI:
+ case SEMIAMP:
+ case AMPER:
+ case AMPERBANG:
+ case INPAR:
+ case INBRACE:
+ case DBAR:
+ case DAMPER:
+ case BAR:
+ case BARAMP:
+ case INOUTPAR:
+ case DO:
+ case THEN:
+ case ELIF:
+ case ELSE:
+ case DOUTBRACK:
+ incmdpos = 1;
+ break;
+ case STRING:
+ /* case ENVSTRING: */
+ case ENVARRAY:
+ case OUTPAR:
+ case CASE:
+ case DINBRACK:
+ incmdpos = 0;
+ break;
+ }
+ if (tok != DINPAR)
+ infor = tok == FOR ? 2 : 0;
+ if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
+ inredir = 1;
+ oldpos = incmdpos;
+ incmdpos = 0;
+ } else if (inredir) {
+ incmdpos = oldpos;
+ inredir = 0;
+ }
+}
+
+#define LX1_BKSLASH 0
+#define LX1_COMMENT 1
+#define LX1_NEWLIN 2
+#define LX1_SEMI 3
+#define LX1_AMPER 5
+#define LX1_BAR 6
+#define LX1_INPAR 7
+#define LX1_OUTPAR 8
+#define LX1_INANG 13
+#define LX1_OUTANG 14
+#define LX1_OTHER 15
+
+#define LX2_BREAK 0
+#define LX2_OUTPAR 1
+#define LX2_BAR 2
+#define LX2_STRING 3
+#define LX2_INBRACK 4
+#define LX2_OUTBRACK 5
+#define LX2_TILDE 6
+#define LX2_INPAR 7
+#define LX2_INBRACE 8
+#define LX2_OUTBRACE 9
+#define LX2_OUTANG 10
+#define LX2_INANG 11
+#define LX2_EQUALS 12
+#define LX2_BKSLASH 13
+#define LX2_QUOTE 14
+#define LX2_DQUOTE 15
+#define LX2_BQUOTE 16
+#define LX2_COMMA 17
+#define LX2_OTHER 18
+#define LX2_META 19
+
+static unsigned char lexact1[256], lexact2[256], lextok2[256];
+
+/**/
+void
+initlextabs(void)
+{
+ int t0;
+ static char *lx1 = "\\q\n;!&|(){}[]<>";
+ static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
+
+ for (t0 = 0; t0 != 256; t0++) {
+ lexact1[t0] = LX1_OTHER;
+ lexact2[t0] = LX2_OTHER;
+ lextok2[t0] = t0;
+ }
+ for (t0 = 0; lx1[t0]; t0++)
+ lexact1[(int)lx1[t0]] = t0;
+ for (t0 = 0; lx2[t0]; t0++)
+ lexact2[(int)lx2[t0]] = t0;
+ lexact2['&'] = LX2_BREAK;
+ lexact2[STOUC(Meta)] = LX2_META;
+ lextok2['*'] = Star;
+ lextok2['?'] = Quest;
+ lextok2['{'] = Inbrace;
+ lextok2['['] = Inbrack;
+ lextok2['$'] = String;
+ lextok2['~'] = Tilde;
+ lextok2['#'] = Pound;
+ lextok2['^'] = Hat;
+}
+
+/* initialize lexical state */
+
+/**/
+void
+lexinit(void)
+{
+ incond = incasepat = nocorrect =
+ infor = dbparens = lexstop = 0;
+ incmdpos = 1;
+ tok = ENDINPUT;
+}
+
+/* add a char to the string buffer */
+
+/**/
+void
+add(int c)
+{
+ *bptr++ = c;
+ if (bsiz == ++len) {
+ int newbsiz;
+
+ newbsiz = bsiz * 8;
+ while (newbsiz < inbufct)
+ newbsiz *= 2;
+ bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
+ bsiz = newbsiz;
+ }
+}
+
+#define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && cs >= ll+1-inbufct) parbegin = inbufct;}
+#define SETPAREND {\
+ if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1)\
+ if (cs >= ll + 1 - inbufct)\
+ parbegin = -1;\
+ else\
+ parend = inbufct;}
+
+static int
+cmd_or_math(int cs_type)
+{
+ int oldlen = len;
+ int c;
+
+ cmdpush(cs_type);
+ c = dquote_parse(')', 0);
+ cmdpop();
+ *bptr = '\0';
+ if (!c) {
+ c = hgetc();
+ if (c == ')')
+ return 1;
+ hungetc(c);
+ lexstop = 0;
+ c = ')';
+ }
+ hungetc(c);
+ lexstop = 0;
+ while (len > oldlen) {
+ len--;
+ hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr);
+ }
+ hungetc('(');
+ return 0;
+}
+
+static int
+cmd_or_math_sub(void)
+{
+ int c = hgetc();
+
+ if (c == '(') {
+ add(Inpar);
+ add('(');
+ if (cmd_or_math(CS_MATHSUBST)) {
+ add(')');
+ return 0;
+ }
+ bptr -= 2;
+ len -= 2;
+ } else {
+ hungetc(c);
+ lexstop = 0;
+ }
+ return skipcomm();
+}
+
+/**/
+int
+gettok(void)
+{
+ int c, d;
+ int peekfd = -1, peek;
+
+ MUSTUSEHEAP("gettok");
+ beginning:
+ tokstr = NULL;
+ while (iblank(c = hgetc()) && !lexstop);
+ if (lexstop)
+ return (errflag) ? LEXERR : ENDINPUT;
+ isfirstln = 0;
+ wordbeg = inbufct - (qbang && c == bangchar);
+ hwbegin(-1-(qbang && c == bangchar));
+ /* word includes the last character read and possibly \ before ! */
+ if (dbparens) {
+ len = 0;
+ bptr = tokstr = (char *)ncalloc(bsiz = 256);
+ hungetc(c);
+ cmdpush(CS_MATH);
+ c = dquote_parse(infor ? ';' : ')', 0);
+ cmdpop();
+ *bptr = '\0';
+ if (!c && infor) {
+ infor--;
+ return DINPAR;
+ }
+ if (c || (c = hgetc()) != ')') {
+ hungetc(c);
+ return LEXERR;
+ }
+ dbparens = 0;
+ return DOUTPAR;
+ } else if (idigit(c)) { /* handle 1< foo */
+ d = hgetc();
+ if (d == '>' || d == '<') {
+ peekfd = c - '0';
+ c = d;
+ } else {
+ hungetc(d);
+ lexstop = 0;
+ }
+ }
+
+ /* chars in initial position in word */
+
+ if (c == hashchar &&
+ (isset(INTERACTIVECOMMENTS) ||
+ (!zleparse && !expanding &&
+ (!interact || unset(SHINSTDIN) || strin)))) {
+ /* History is handled here to prevent extra *
+ * newlines being inserted into the history. */
+
+ while ((c = ingetc()) != '\n' && !lexstop) {
+ hwaddc(c);
+ addtoline(c);
+ }
+
+ if (errflag)
+ peek = LEXERR;
+ else {
+ hwend();
+ hwbegin(0);
+ hwaddc('\n');
+ addtoline('\n');
+ peek = NEWLIN;
+ }
+ return peek;
+ }
+ switch (lexact1[STOUC(c)]) {
+ case LX1_BKSLASH:
+ d = hgetc();
+ if (d == '\n')
+ goto beginning;
+ hungetc(d);
+ lexstop = 0;
+ break;
+ case LX1_NEWLIN:
+ return NEWLIN;
+ case LX1_SEMI:
+ d = hgetc();
+ if(d == ';')
+ return DSEMI;
+ else if(d == '&')
+ return SEMIAMP;
+ hungetc(d);
+ lexstop = 0;
+ return SEMI;
+ case LX1_AMPER:
+ d = hgetc();
+ if (d == '&')
+ return DAMPER;
+ else if (d == '!' || d == '|')
+ return AMPERBANG;
+ else if (d == '>') {
+ d = hgetc();
+ if (d == '!' || d == '|')
+ return OUTANGAMPBANG;
+ else if (d == '>') {
+ d = hgetc();
+ if (d == '!' || d == '|')
+ return DOUTANGAMPBANG;
+ hungetc(d);
+ lexstop = 0;
+ return DOUTANGAMP;
+ }
+ hungetc(d);
+ lexstop = 0;
+ return AMPOUTANG;
+ }
+ hungetc(d);
+ lexstop = 0;
+ return AMPER;
+ case LX1_BAR:
+ d = hgetc();
+ if (d == '|')
+ return DBAR;
+ else if (d == '&')
+ return BARAMP;
+ hungetc(d);
+ lexstop = 0;
+ return BAR;
+ case LX1_INPAR:
+ d = hgetc();
+ if (d == '(') {
+ if (infor) {
+ dbparens = 1;
+ return DINPAR;
+ }
+ if (incmdpos) {
+ len = 0;
+ bptr = tokstr = (char *)ncalloc(bsiz = 256);
+ return cmd_or_math(CS_MATH) ? DINPAR : INPAR;
+ }
+ } else if (d == ')')
+ return INOUTPAR;
+ hungetc(d);
+ lexstop = 0;
+ if (!(incond == 1 || incmdpos))
+ break;
+ return INPAR;
+ case LX1_OUTPAR:
+ return OUTPAR;
+ case LX1_INANG:
+ d = hgetc();
+ if (!incmdpos && d == '(') {
+ hungetc(d);
+ lexstop = 0;
+ break;
+ }
+ if (d == '>')
+ peek = INOUTANG;
+ else if (idigit(d) || d == '-') {
+ int tbs = 256, n = 0, nc;
+ char *tbuf, *tbp, *ntb;
+
+ tbuf = tbp = (char *)zalloc(tbs);
+ hungetc(d);
+
+ while ((nc = hgetc()) && !lexstop) {
+ if (!idigit(nc) && nc != '-')
+ break;
+ *tbp++ = (char)nc;
+ if (++n == tbs) {
+ ntb = (char *)realloc(tbuf, tbs *= 2);
+ tbp += ntb - tbuf;
+ tbuf = ntb;
+ }
+ }
+ if (nc == '>' && !lexstop) {
+ hungetc(nc);
+ while (n--)
+ hungetc(*--tbp);
+ zfree(tbuf, tbs);
+ break;
+ }
+ if (nc && !lexstop)
+ hungetc(nc);
+ lexstop = 0;
+ while (n--)
+ hungetc(*--tbp);
+ zfree(tbuf, tbs);
+ peek = INANG;
+ } else if (d == '<') {
+ int e = hgetc();
+
+ if (e == '(') {
+ hungetc(e);
+ hungetc(d);
+ peek = INANG;
+ } else if (e == '<')
+ peek = TRINANG;
+ else if (e == '-')
+ peek = DINANGDASH;
+ else {
+ hungetc(e);
+ lexstop = 0;
+ peek = DINANG;
+ }
+ } else if (d == '&')
+ peek = INANGAMP;
+ else {
+ peek = INANG;
+ hungetc(d);
+ lexstop = 0;
+ }
+ tokfd = peekfd;
+ return peek;
+ case LX1_OUTANG:
+ d = hgetc();
+ if (d == '(') {
+ hungetc(d);
+ break;
+ } else if (d == '&') {
+ d = hgetc();
+ if (d == '!' || d == '|')
+ peek = OUTANGAMPBANG;
+ else {
+ hungetc(d);
+ lexstop = 0;
+ peek = OUTANGAMP;
+ }
+ } else if (d == '!' || d == '|')
+ peek = OUTANGBANG;
+ else if (d == '>') {
+ d = hgetc();
+ if (d == '&') {
+ d = hgetc();
+ if (d == '!' || d == '|')
+ peek = DOUTANGAMPBANG;
+ else {
+ hungetc(d);
+ lexstop = 0;
+ peek = DOUTANGAMP;
+ }
+ } else if (d == '!' || d == '|')
+ peek = DOUTANGBANG;
+ else if (d == '(') {
+ hungetc(d);
+ hungetc('>');
+ peek = OUTANG;
+ } else {
+ hungetc(d);
+ lexstop = 0;
+ peek = DOUTANG;
+ if (isset(HISTALLOWCLOBBER))
+ hwaddc('|');
+ }
+ } else {
+ hungetc(d);
+ lexstop = 0;
+ peek = OUTANG;
+ if (!incond && isset(HISTALLOWCLOBBER))
+ hwaddc('|');
+ }
+ tokfd = peekfd;
+ return peek;
+ }
+
+ /* we've started a string, now get the *
+ * rest of it, performing tokenization */
+ return gettokstr(c, 0);
+}
+
+/**/
+static int
+gettokstr(int c, int sub)
+{
+ int bct = 0, pct = 0, brct = 0;
+ int intpos = 1, in_brace_param = 0;
+ int peek, inquote;
+#ifdef DEBUG
+ int ocmdsp = cmdsp;
+#endif
+
+ peek = STRING;
+ if (!sub) {
+ len = 0;
+ bptr = tokstr = (char *)ncalloc(bsiz = 256);
+ }
+ for (;;) {
+ int act;
+ int e;
+
+ if (inblank(c) && !in_brace_param && !pct)
+ act = LX2_BREAK;
+ else {
+ act = lexact2[STOUC(c)];
+ c = lextok2[STOUC(c)];
+ }
+ switch (act) {
+ case LX2_BREAK:
+ if (!in_brace_param && !sub)
+ goto brk;
+ break;
+ case LX2_META:
+ c = hgetc();
+#ifdef DEBUG
+ if (lexstop) {
+ fputs("BUG: input terminated by Meta\n", stderr);
+ fflush(stderr);
+ goto brk;
+ }
+#endif
+ add(Meta);
+ break;
+ case LX2_OUTPAR:
+ if ((sub || in_brace_param) && isset(SHGLOB))
+ break;
+ if (!in_brace_param && !pct--)
+ if (sub) {
+ pct = 0;
+ break;
+ } else
+ goto brk;
+ c = Outpar;
+ break;
+ case LX2_BAR:
+ if (!pct && !in_brace_param)
+ if (sub)
+ break;
+ else
+ goto brk;
+ if (unset(SHGLOB) || (!sub && !in_brace_param))
+ c = Bar;
+ break;
+ case LX2_STRING:
+ e = hgetc();
+ if (e == '[') {
+ cmdpush(CS_MATHSUBST);
+ add(String);
+ add(Inbrack);
+ c = dquote_parse(']', sub);
+ cmdpop();
+ if (c) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outbrack;
+ } else if (e == '(') {
+ add(String);
+ c = cmd_or_math_sub();
+ if (c) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outpar;
+ } else {
+ if (e == '{') {
+ add(c);
+ c = Inbrace;
+ ++bct;
+ cmdpush(CS_BRACEPAR);
+ if (!in_brace_param)
+ in_brace_param = bct;
+ } else {
+ hungetc(e);
+ lexstop = 0;
+ }
+ }
+ break;
+ case LX2_INBRACK:
+ if (!in_brace_param)
+ brct++;
+ c = Inbrack;
+ break;
+ case LX2_OUTBRACK:
+ if (!in_brace_param)
+ brct--;
+ if (brct < 0)
+ brct = 0;
+ c = Outbrack;
+ break;
+ case LX2_INPAR:
+ if ((sub || in_brace_param) && isset(SHGLOB))
+ break;
+ if (!in_brace_param) {
+ if (!sub) {
+ e = hgetc();
+ hungetc(e);
+ lexstop = 0;
+ if (e == ')' ||
+ (incmdpos && !brct && peek != ENVSTRING))
+ goto brk;
+ }
+ pct++;
+ }
+ c = Inpar;
+ break;
+ case LX2_INBRACE:
+ if (isset(IGNOREBRACES) || sub)
+ c = '{';
+ else {
+ if (!len && incmdpos) {
+ add('{');
+ *bptr = '\0';
+ return STRING;
+ }
+ if (in_brace_param)
+ cmdpush(CS_BRACE);
+ bct++;
+ }
+ break;
+ case LX2_OUTBRACE:
+ if ((isset(IGNOREBRACES) || sub) && !in_brace_param)
+ break;
+ if (!bct)
+ break;
+ if (in_brace_param)
+ cmdpop();
+ if (bct-- == in_brace_param)
+ in_brace_param = 0;
+ c = Outbrace;
+ break;
+ case LX2_COMMA:
+ if (unset(IGNOREBRACES) && !sub && bct > in_brace_param)
+ c = Comma;
+ break;
+ case LX2_OUTANG:
+ if (!intpos)
+ if (in_brace_param || sub)
+ break;
+ else
+ goto brk;
+ e = hgetc();
+ if (e != '(') {
+ hungetc(e);
+ lexstop = 0;
+ goto brk;
+ }
+ add(Outang);
+ if (skipcomm()) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outpar;
+ break;
+ case LX2_INANG:
+ if (isset(SHGLOB) && sub)
+ break;
+ e = hgetc();
+ if (!(idigit(e) || e == '-' || (e == '(' && intpos))) {
+ hungetc(e);
+ lexstop = 0;
+ if (in_brace_param || sub)
+ break;
+ goto brk;
+ }
+ c = Inang;
+ if (e == '(') {
+ add(c);
+ if (skipcomm()) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outpar;
+ } else {
+ add(c);
+ c = e;
+ while (c != '>' && !lexstop)
+ add(c), c = hgetc();
+ c = Outang;
+ }
+ break;
+ case LX2_EQUALS:
+ if (intpos) {
+ e = hgetc();
+ if (e != '(') {
+ hungetc(e);
+ lexstop = 0;
+ c = Equals;
+ } else {
+ add(Equals);
+ if (skipcomm()) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outpar;
+ }
+ } else if (!sub && peek != ENVSTRING &&
+ incmdpos && !bct && !brct) {
+ char *t = tokstr;
+ if (idigit(*t))
+ while (++t < bptr && idigit(*t));
+ else {
+ while (iident(*t) && ++t < bptr);
+ if (t < bptr) {
+ *bptr = '\0';
+ skipparens(Inbrack, Outbrack, &t);
+ }
+ }
+ if (t == bptr) {
+ e = hgetc();
+ if (e == '(' && incmdpos) {
+ *bptr = '\0';
+ return ENVARRAY;
+ }
+ hungetc(e);
+ lexstop = 0;
+ peek = ENVSTRING;
+ intpos = 2;
+ } else
+ c = Equals;
+ } else
+ c = Equals;
+ break;
+ case LX2_BKSLASH:
+ c = hgetc();
+ if (c == '\n') {
+ c = hgetc();
+ if (!lexstop)
+ continue;
+ } else
+ add(Bnull);
+ if (lexstop)
+ goto brk;
+ break;
+ case LX2_QUOTE: {
+ int strquote = (len && bptr[-1] == String);
+
+ add(Snull);
+ cmdpush(CS_QUOTE);
+ for (;;) {
+ STOPHIST
+ while ((c = hgetc()) != '\'' && !lexstop) {
+ if (strquote && c == '\\') {
+ add(c);
+ c = hgetc();
+ if (lexstop)
+ break;
+ } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
+ if (bptr[-1] == '\\')
+ bptr--, len--;
+ else
+ break;
+ }
+ add(c);
+ }
+ ALLOWHIST
+ if (c != '\'') {
+ zerr("unmatched \'", NULL, 0);
+ peek = LEXERR;
+ cmdpop();
+ goto brk;
+ }
+ e = hgetc();
+ if (e != '\'' || unset(RCQUOTES))
+ break;
+ add(c);
+ }
+ cmdpop();
+ hungetc(e);
+ lexstop = 0;
+ c = Snull;
+ break;
+ }
+ case LX2_DQUOTE:
+ add(Dnull);
+ cmdpush(CS_DQUOTE);
+ c = dquote_parse('"', sub);
+ cmdpop();
+ if (c) {
+ zerr("unmatched \"", NULL, 0);
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Dnull;
+ break;
+ case LX2_BQUOTE:
+ add(Tick);
+ cmdpush(CS_BQUOTE);
+ SETPARBEGIN
+ inquote = 0;
+ while ((c = hgetc()) != '`' && !lexstop)
+ if (c == '\\') {
+ c = hgetc();
+ if (c != '\n') {
+ add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\');
+ add(c);
+ }
+ else if (!sub && isset(CSHJUNKIEQUOTES))
+ add(c);
+ } else {
+ if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
+ break;
+ }
+ add(c);
+ if (c == '\'')
+ if ((inquote = !inquote))
+ STOPHIST
+ else
+ ALLOWHIST
+ }
+ if (inquote)
+ ALLOWHIST
+ cmdpop();
+ if (c != '`') {
+ zerr("unmatched `", NULL, 0);
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Tick;
+ SETPAREND
+ break;
+ }
+ add(c);
+ c = hgetc();
+ if (intpos)
+ intpos--;
+ if (lexstop)
+ break;
+ }
+ brk:
+ hungetc(c);
+ if (in_brace_param) {
+ while(bct-- >= in_brace_param)
+ cmdpop();
+ zerr("closing brace expected", NULL, 0);
+ } else if (unset(IGNOREBRACES) && !sub && len > 1 &&
+ peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) {
+ /* hack to get {foo} command syntax work */
+ bptr--;
+ len--;
+ lexstop = 0;
+ hungetc('}');
+ }
+ *bptr = '\0';
+ DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed.");
+ return peek;
+}
+
+/**/
+static int
+dquote_parse(char endchar, int sub)
+{
+ int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
+ int c;
+ int math = endchar == ')' || endchar == ']';
+ int zlemath = math && cs > ll + addedx - inbufct;
+
+ while (((c = hgetc()) != endchar || bct ||
+ (math && ((pct > 0) || (brct > 0))) ||
+ intick) && !lexstop) {
+ cont:
+ switch (c) {
+ case '\\':
+ c = hgetc();
+ if (c != '\n') {
+ if (c == '$' || c == '\\' || (c == '}' && !intick && bct) ||
+ c == endchar || c == '`')
+ add(Bnull);
+ else {
+ /* lexstop is implicitely handled here */
+ add('\\');
+ goto cont;
+ }
+ } else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"')
+ continue;
+ break;
+ case '\n':
+ err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"';
+ break;
+ case '$':
+ if (intick)
+ break;
+ c = hgetc();
+ if (c == '(') {
+ add(Qstring);
+ err = cmd_or_math_sub();
+ c = Outpar;
+ } else if (c == '[') {
+ add(String);
+ add(Inbrack);
+ cmdpush(CS_MATHSUBST);
+ err = dquote_parse(']', sub);
+ cmdpop();
+ c = Outbrack;
+ } else if (c == '{') {
+ add(Qstring);
+ c = Inbrace;
+ cmdpush(CS_BRACEPAR);
+ bct++;
+ } else if (c == '$')
+ add(Qstring);
+ else {
+ hungetc(c);
+ lexstop = 0;
+ c = Qstring;
+ }
+ break;
+ case '}':
+ if (intick || !bct)
+ break;
+ c = Outbrace;
+ bct--;
+ cmdpop();
+ break;
+ case '`':
+ c = Qtick;
+ if (intick == 2)
+ ALLOWHIST
+ if ((intick = !intick)) {
+ SETPARBEGIN
+ cmdpush(CS_BQUOTE);
+ } else {
+ SETPAREND
+ cmdpop();
+ }
+ break;
+ case '\'':
+ if (!intick)
+ break;
+ if (intick == 1)
+ intick = 2, STOPHIST
+ else
+ intick = 1, ALLOWHIST
+ break;
+ case '(':
+ pct++;
+ break;
+ case ')':
+ err = (!pct-- && math);
+ break;
+ case '[':
+ brct++;
+ break;
+ case ']':
+ err = (!brct-- && math);
+ break;
+ case '"':
+ if (intick || (!endchar && !bct))
+ break;
+ if (bct) {
+ add(Dnull);
+ err = dquote_parse('"', sub);
+ c = Dnull;
+ } else
+ err = 1;
+ break;
+ }
+ if (err || lexstop)
+ break;
+ add(c);
+ }
+ if (intick == 2)
+ ALLOWHIST
+ if (intick)
+ cmdpop();
+ while (bct--)
+ cmdpop();
+ if (lexstop)
+ err = intick || endchar || err;
+ else if (err == 1)
+ err = c;
+ if (zlemath && cs <= ll + 1 - inbufct)
+ inwhat = IN_MATH;
+ return err;
+}
+
+/* Tokenize a string given in s. Parsing is done as in double *
+ * quotes. This is usually called before singsub(). */
+
+/**/
+int
+parsestr(char *s)
+{
+ int l = strlen(s), err;
+
+ HEAPALLOC {
+ lexsave();
+ untokenize(s);
+ inpush(dupstring(s), 0, NULL);
+ strinbeg();
+ stophist = 2;
+ len = 0;
+ bptr = tokstr = s;
+ bsiz = l + 1;
+ err = dquote_parse('\0', 1);
+ *bptr = '\0';
+ strinend();
+ inpop();
+ DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
+ lexrestore();
+ if (err) {
+ untokenize(s);
+ if (err > 32 && err < 127)
+ zerr("parse error near `%c'", NULL, err);
+ else
+ zerr("parse error", NULL, 0);
+ }
+ } LASTALLOC;
+ return err;
+}
+
+/* Tokenize a string given in s. Parsing is done as if s were a normal *
+ * command-line argument but it may contain separators. This is used *
+ * to parse the right-hand side of ${...%...} substitutions. */
+
+/**/
+int
+parse_subst_string(char *s)
+{
+ int c, l = strlen(s), err;
+
+ if (! *s)
+ return 0;
+ lexsave();
+ untokenize(s);
+ inpush(dupstring(s), 0, NULL);
+ strinbeg();
+ stophist = 2;
+ len = 0;
+ bptr = tokstr = s;
+ bsiz = l + 1;
+ c = hgetc();
+ c = gettokstr(c, 1);
+ err = errflag;
+ strinend();
+ inpop();
+ DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
+ lexrestore();
+ errflag = err;
+ if (c == LEXERR) {
+ untokenize(s);
+ return 1;
+ }
+#ifdef DEBUG
+ if (c != STRING || len != l || errflag) {
+ fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
+ len < l ? "len < l" : errflag ? "errflag" : "c != STRING");
+ fflush(stderr);
+ untokenize(s);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* expand aliases and reserved words */
+
+/**/
+int
+exalias(void)
+{
+ Alias an;
+ Reswd rw;
+
+ hwend();
+ if (interact && isset(SHINSTDIN) && !strin && !incasepat &&
+ tok == STRING && !nocorrect && !(inbufflags & INP_ALIAS) &&
+ (isset(CORRECTALL) || (isset(CORRECT) && incmdpos)))
+ spckword(&tokstr, 1, incmdpos, 1);
+
+ if (!tokstr) {
+ yytext = tokstrings[tok];
+ if (yytext)
+ yytext = dupstring(yytext);
+ return 0;
+ }
+
+ if (has_token(tokstr)) {
+ char *p, *t;
+
+ yytext = p = ncalloc(strlen(tokstr) + 1);
+ for (t = tokstr; (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
+ } else
+ yytext = tokstr;
+
+ if (zleparse && !(inbufflags & INP_ALIAS)) {
+ int zp = zleparse;
+
+ gotword();
+ if (zp == 1 && !zleparse) {
+ return 0;
+ }
+ }
+
+ if (tok == STRING) {
+ /* Check for an alias */
+ an = noaliases ? NULL : (Alias) aliastab->getnode(aliastab, yytext);
+ if (an && !an->inuse && ((an->flags & ALIAS_GLOBAL) || incmdpos ||
+ inalmore)) {
+ inpush(an->text, INP_ALIAS, an);
+ /* remove from history if it begins with space */
+ if (isset(HISTIGNORESPACE) && an->text[0] == ' ')
+ remhist();
+ lexstop = 0;
+ return 1;
+ }
+
+ /* Then check for a reserved word */
+ if ((incmdpos ||
+ (unset(IGNOREBRACES) && yytext[0] == '}' && !yytext[1])) &&
+ (rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) {
+ tok = rw->token;
+ if (tok == DINBRACK)
+ incond = 1;
+ } else if (incond && !strcmp(yytext, "]]")) {
+ tok = DOUTBRACK;
+ incond = 0;
+ } else if (incond && yytext[0] == '!' && !yytext[1])
+ tok = BANG;
+ }
+ inalmore = 0;
+ return 0;
+}
+
+/* skip (...) */
+
+/**/
+static int
+skipcomm(void)
+{
+ int pct = 1, c;
+
+ cmdpush(CS_CMDSUBST);
+ SETPARBEGIN
+ c = Inpar;
+ do {
+ add(c);
+ c = hgetc();
+ if (itok(c) || lexstop)
+ break;
+ switch (c) {
+ case '(':
+ pct++;
+ break;
+ case ')':
+ pct--;
+ break;
+ case '\\':
+ add(c);
+ c = hgetc();
+ break;
+ case '\'': {
+ int strquote = bptr[-1] == '$';
+ add(c);
+ STOPHIST
+ while ((c = hgetc()) != '\'' && !lexstop) {
+ if (c == '\\' && strquote) {
+ add(c);
+ c = hgetc();
+ }
+ add(c);
+ }
+ ALLOWHIST
+ break;
+ }
+ case '\"':
+ add(c);
+ while ((c = hgetc()) != '\"' && !lexstop)
+ if (c == '\\') {
+ add(c);
+ add(hgetc());
+ } else
+ add(c);
+ break;
+ case '`':
+ add(c);
+ while ((c = hgetc()) != '`' && !lexstop)
+ if (c == '\\')
+ add(c), add(hgetc());
+ else
+ add(c);
+ break;
+ }
+ }
+ while (pct);
+ if (!lexstop)
+ SETPAREND
+ cmdpop();
+ return lexstop;
+}