diff options
Diffstat (limited to 'Src/lex.c')
-rw-r--r-- | Src/lex.c | 1489 |
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; +} |