diff options
Diffstat (limited to 'Src/lex.c')
-rw-r--r-- | Src/lex.c | 770 |
1 files changed, 449 insertions, 321 deletions
@@ -35,7 +35,7 @@ /* tokens */ /**/ -mod_export char ztokens[] = "#$^*()$=|{}[]`<>>?~`,'\"\\\\"; +mod_export char ztokens[] = "#$^*(())$=|{}[]`<>>?~`,'\"\\\\"; /* parts of the current token */ @@ -90,6 +90,12 @@ int inalmore; int nocorrect; /* + * TBD: the following exported variables are part of the non-interface + * with ZLE for completion. They are poorly named and the whole + * scheme is incredibly brittle. One piece of robustness is applied: + * the variables are only set if LEXFLAGS_ZLE is set. Improvements + * should therefore concentrate on areas with this flag set. + * * Cursor position and line length in zle when the line is * metafied for access from the main shell. */ @@ -113,6 +119,16 @@ mod_export int addedx; /**/ mod_export int wb, we; +/**/ +mod_export int wordbeg; + +/**/ +mod_export int parbegin; + +/**/ +mod_export int parend; + + /* 1 if aliases should not be expanded */ /**/ @@ -134,19 +150,20 @@ mod_export int noaliases; /**/ mod_export int lexflags; -/**/ -mod_export int wordbeg; +/* don't recognize comments */ /**/ -mod_export int parbegin; +mod_export int nocomments; + +/* add raw input characters while parsing command substitution */ /**/ -mod_export int parend; +static int lex_add_raw; -/* don't recognize comments */ +/* variables associated with the above */ -/**/ -mod_export int nocomments; +static char *tokstr_raw; +static struct lexbufstate lexbuf_raw; /* text of punctuation tokens */ @@ -190,205 +207,58 @@ mod_export char *tokstrings[WHILE + 1] = { /* 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 lexflags; - int stophist; - int hlinesz; - char *hline; - char *hptr; - enum lextok tok; - int isnewlin; - char *tokstr; - char *zshlextext; - char *bptr; - int bsiz; - int len; - short *chwords; - int chwordlen; - int chwordpos; - int hwgetword; - int lexstop; - struct heredocs *hdocs; - int (*hgetc) _((void)); - void (*hungetc) _((int)); - void (*hwaddc) _((int)); - void (*hwbegin) _((int)); - void (*hwend) _((void)); - void (*addtoline) _((int)); - - int eclen, ecused, ecnpats; - Wordcode ecbuf; - Eccstr ecstrs; - int ecsoffs, ecssub, ecnfunc; - - unsigned char *cstack; - int csp; - zlong toklineno; -}; - -static struct lexstack *lstack = NULL; +static struct lexbufstate lexbuf = { NULL, 256, 0 }; -/* save the lexical state */ - -/* is this a hack or what? */ +/* save lexical context */ /**/ -mod_export void -lexsave(void) +void +lex_context_save(struct lex_stack *ls, int toplevel) { - struct lexstack *ls; + (void)toplevel; - 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->lexflags = lexflags; - ls->stophist = stophist; - stophist = 0; - if (!lstack) { - /* top level, make this version visible to ZLE */ - zle_chline = chline; - /* ensure line stored is NULL-terminated */ - if (hptr) - *hptr = '\0'; - } - ls->hline = chline; - chline = NULL; - ls->hptr = hptr; - hptr = NULL; - ls->hlinesz = hlinesz; - ls->cstack = cmdstack; - ls->csp = cmdsp; - cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); + ls->tok = tok; - ls->isnewlin = isnewlin; ls->tokstr = tokstr; ls->zshlextext = zshlextext; - ls->bptr = bptr; - tokstr = zshlextext = bptr = NULL; - ls->bsiz = bsiz; - bsiz = 256; - ls->len = len; - ls->chwords = chwords; - ls->chwordlen = chwordlen; - ls->chwordpos = chwordpos; - ls->hwgetword = hwgetword; + ls->lexbuf = lexbuf; + ls->lex_add_raw = lex_add_raw; + ls->tokstr_raw = tokstr_raw; + ls->lexbuf_raw = lexbuf_raw; ls->lexstop = lexstop; - ls->hdocs = hdocs; - ls->hgetc = hgetc; - ls->hungetc = hungetc; - ls->hwaddc = hwaddc; - ls->hwbegin = hwbegin; - ls->hwend = hwend; - ls->addtoline = addtoline; - ls->eclen = eclen; - ls->ecused = ecused; - ls->ecnpats = ecnpats; - ls->ecbuf = ecbuf; - ls->ecstrs = ecstrs; - ls->ecsoffs = ecsoffs; - ls->ecssub = ecssub; - ls->ecnfunc = ecnfunc; ls->toklineno = toklineno; - cmdsp = 0; - inredir = 0; - hdocs = NULL; - histactive = 0; - ecbuf = NULL; - - ls->next = lstack; - lstack = ls; + + tokstr = zshlextext = lexbuf.ptr = NULL; + lexbuf.siz = 256; + tokstr_raw = lexbuf_raw.ptr = NULL; + lexbuf_raw.siz = lexbuf_raw.len = lex_add_raw = 0; } -/* restore lexical state */ +/* restore lexical context */ /**/ mod_export void -lexrestore(void) +lex_context_restore(const struct lex_stack *ls, int toplevel) { - struct lexstack *ln = lstack; - - DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); - - queue_signals(); - lstack = lstack->next; - - if (!lstack) { - /* Back to top level: don't need special ZLE value */ - DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); - zle_chline = NULL; - } - - incmdpos = ln->incmdpos; - incond = ln->incond; - incasepat = ln->incasepat; - dbparens = ln->dbparens; - isfirstln = ln->isfirstln; - isfirstch = ln->isfirstch; - histactive = ln->histactive; - histdone = ln->histdone; - lexflags = ln->lexflags; - stophist = ln->stophist; - chline = ln->hline; - hptr = ln->hptr; - if (cmdstack) - zfree(cmdstack, CMDSTACKSZ); - cmdstack = ln->cstack; - cmdsp = ln->csp; - tok = ln->tok; - isnewlin = ln->isnewlin; - tokstr = ln->tokstr; - zshlextext = ln->zshlextext; - bptr = ln->bptr; - bsiz = ln->bsiz; - len = ln->len; - chwords = ln->chwords; - chwordlen = ln->chwordlen; - chwordpos = ln->chwordpos; - hwgetword = ln->hwgetword; - lexstop = ln->lexstop; - hdocs = ln->hdocs; - hgetc = ln->hgetc; - hungetc = ln->hungetc; - hwaddc = ln->hwaddc; - hwbegin = ln->hwbegin; - hwend = ln->hwend; - addtoline = ln->addtoline; - if (ecbuf) - zfree(ecbuf, eclen); - eclen = ln->eclen; - ecused = ln->ecused; - ecnpats = ln->ecnpats; - ecbuf = ln->ecbuf; - ecstrs = ln->ecstrs; - ecsoffs = ln->ecsoffs; - ecssub = ln->ecssub; - ecnfunc = ln->ecnfunc; - hlinesz = ln->hlinesz; - toklineno = ln->toklineno; - errflag = 0; - free(ln); - - unqueue_signals(); + (void)toplevel; + + dbparens = ls->dbparens; + isfirstln = ls->isfirstln; + isfirstch = ls->isfirstch; + lexflags = ls->lexflags; + tok = ls->tok; + tokstr = ls->tokstr; + zshlextext = ls->zshlextext; + lexbuf = ls->lexbuf; + lex_add_raw = ls->lex_add_raw; + tokstr_raw = ls->tokstr_raw; + lexbuf_raw = ls->lexbuf_raw; + lexstop = ls->lexstop; + toklineno = ls->toklineno; } /**/ @@ -563,9 +433,7 @@ initlextabs(void) void lexinit(void) { - incond = incasepat = nocorrect = - infor = dbparens = lexstop = 0; - incmdpos = 1; + nocorrect = dbparens = lexstop = 0; tok = ENDINPUT; } @@ -575,17 +443,18 @@ lexinit(void) void add(int c) { - *bptr++ = c; - if (bsiz == ++len) { - int newbsiz = bsiz * 2; + *lexbuf.ptr++ = c; + if (lexbuf.siz == ++lexbuf.len) { + int newbsiz = lexbuf.siz * 2; - if (newbsiz > inbufct && inbufct > bsiz) + if (newbsiz > inbufct && inbufct > lexbuf.siz) newbsiz = inbufct; - bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz)); + tokstr = (char *)hrealloc(tokstr, lexbuf.siz, newbsiz); + lexbuf.ptr = tokstr + lexbuf.len; /* len == bsiz, so bptr is at the start of newly allocated memory */ - memset(bptr, 0, newbsiz - bsiz); - bsiz = newbsiz; + memset(lexbuf.ptr, 0, newbsiz - lexbuf.siz); + lexbuf.siz = newbsiz; } } @@ -604,48 +473,61 @@ add(int c) } \ } +enum { + CMD_OR_MATH_CMD, + CMD_OR_MATH_MATH, + CMD_OR_MATH_ERR +}; + /* - * Return 1 for math, 0 for a command, 2 for an error. If it couldn't be + * Return one of the above. If it couldn't be * parsed as math, but there was no gross error, it's a command. */ static int cmd_or_math(int cs_type) { - int oldlen = len; + int oldlen = lexbuf.len; int c; + int oinflags = inbufflags; cmdpush(cs_type); + inbufflags |= INP_APPEND; c = dquote_parse(')', 0); + if (!(oinflags & INP_APPEND)) + inbufflags &= ~INP_APPEND; cmdpop(); - *bptr = '\0'; + *lexbuf.ptr = '\0'; if (!c) { /* Successfully parsed, see if it was math */ c = hgetc(); if (c == ')') - return 1; /* yes */ + return CMD_OR_MATH_MATH; /* yes */ hungetc(c); lexstop = 0; c = ')'; } else if (lexstop) { /* we haven't got anything to unget */ - return 2; + return CMD_OR_MATH_ERR; } /* else unsuccessful: unget the whole thing */ hungetc(c); lexstop = 0; - while (len > oldlen) { - len--; - hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr); + while (lexbuf.len > oldlen && !(errflag & ERRFLAG_ERROR)) { + lexbuf.len--; + hungetc(itok(*--lexbuf.ptr) ? + ztokens[*lexbuf.ptr - Pound] : *lexbuf.ptr); } + if (errflag) + return CMD_OR_MATH_ERR; hungetc('('); - return 0; + return errflag ? CMD_OR_MATH_ERR : CMD_OR_MATH_CMD; } /* * Parse either a $(( ... )) or a $(...) - * Return 0 on success, 1 on failure. + * Return the same as cmd_or_math(). */ static int cmd_or_math_sub(void) @@ -653,21 +535,23 @@ cmd_or_math_sub(void) int c = hgetc(), ret; if (c == '(') { + int lexpos = (int)(lexbuf.ptr - tokstr); add(Inpar); add('('); - if ((ret = cmd_or_math(CS_MATHSUBST)) == 1) { + if ((ret = cmd_or_math(CS_MATHSUBST)) == CMD_OR_MATH_MATH) { + tokstr[lexpos] = Inparmath; add(')'); - return 0; + return CMD_OR_MATH_MATH; } - if (ret == 2) - return 1; - bptr -= 2; - len -= 2; + if (ret == CMD_OR_MATH_ERR) + return CMD_OR_MATH_ERR; + lexbuf.ptr -= 2; + lexbuf.len -= 2; } else { hungetc(c); lexstop = 0; } - return skipcomm(); + return skipcomm() ? CMD_OR_MATH_ERR : CMD_OR_MATH_CMD; } /* Check whether we're looking at valid numeric globbing syntax * @@ -722,17 +606,18 @@ gettok(void) if (lexstop) return (errflag) ? LEXERR : ENDINPUT; isfirstln = 0; - wordbeg = inbufct - (qbang && c == bangchar); + if ((lexflags & LEXFLAGS_ZLE)) + 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 *) hcalloc(bsiz = LEX_HEAP_SIZE); + lexbuf.len = 0; + lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); hungetc(c); cmdpush(CS_MATH); c = dquote_parse(infor ? ';' : ')', 0); cmdpop(); - *bptr = '\0'; + *lexbuf.ptr = '\0'; if (!c && infor) { infor--; return DINPAR; @@ -780,8 +665,9 @@ gettok(void) * newlines being inserted into the history. */ if (lexflags & LEXFLAGS_COMMENTS_KEEP) { - len = 0; - bptr = tokstr = (char *)hcalloc(bsiz = LEX_HEAP_SIZE); + lexbuf.len = 0; + lexbuf.ptr = tokstr = + (char *)hcalloc(lexbuf.siz = LEX_HEAP_SIZE); add(c); } hwend(); @@ -796,7 +682,7 @@ gettok(void) peek = LEXERR; else { if (lexflags & LEXFLAGS_COMMENTS_KEEP) { - *bptr = '\0'; + *lexbuf.ptr = '\0'; if (!lexstop) hungetc(c); peek = STRING; @@ -882,13 +768,14 @@ gettok(void) return DINPAR; } if (incmdpos || (isset(SHGLOB) && !isset(KSHGLOB))) { - len = 0; - bptr = tokstr = (char *) hcalloc(bsiz = LEX_HEAP_SIZE); + lexbuf.len = 0; + lexbuf.ptr = tokstr = (char *) + hcalloc(lexbuf.siz = LEX_HEAP_SIZE); switch (cmd_or_math(CS_MATH)) { - case 1: + case CMD_OR_MATH_MATH: return DINPAR; - case 0: + case CMD_OR_MATH_CMD: /* * Not math, so we don't return the contents * as a string in this case. @@ -1032,8 +919,8 @@ gettokstr(int c, int sub) peek = STRING; if (!sub) { - len = 0; - bptr = tokstr = (char *) hcalloc(bsiz = LEX_HEAP_SIZE); + lexbuf.len = 0; + lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); } for (;;) { int act; @@ -1069,7 +956,7 @@ gettokstr(int c, int sub) if (fdpar) { /* this is a single word `( )', treat as INOUTPAR */ add(c); - *bptr = '\0'; + *lexbuf.ptr = '\0'; return INOUTPAR; } if ((sub || in_brace_param) && isset(SHGLOB)) @@ -1108,12 +995,19 @@ gettokstr(int c, int sub) c = Outbrack; } else if (e == '(') { add(String); - c = cmd_or_math_sub(); - if (c) { + switch (cmd_or_math_sub()) { + case CMD_OR_MATH_CMD: + c = Outpar; + break; + + case CMD_OR_MATH_MATH: + c = Outparmath; + break; + + default: peek = LEXERR; goto brk; } - c = Outpar; } else { if (e == '{') { add(c); @@ -1144,9 +1038,9 @@ gettokstr(int c, int sub) if (isset(SHGLOB)) { if (sub || in_brace_param) break; - if (incasepat && !len) + if (incasepat && !lexbuf.len) return INPAR; - if (!isset(KSHGLOB) && len) + if (!isset(KSHGLOB) && lexbuf.len) goto brk; } if (!in_brace_param) { @@ -1203,9 +1097,9 @@ gettokstr(int c, int sub) if (isset(IGNOREBRACES) || sub) c = '{'; else { - if (!len && incmdpos) { + if (!lexbuf.len && incmdpos) { add('{'); - *bptr = '\0'; + *lexbuf.ptr = '\0'; return STRING; } if (in_brace_param) { @@ -1291,23 +1185,23 @@ gettokstr(int c, int sub) incmdpos && !bct && !brct) { char *t = tokstr; if (idigit(*t)) - while (++t < bptr && idigit(*t)); + while (++t < lexbuf.ptr && idigit(*t)); else { - int sav = *bptr; - *bptr = '\0'; + int sav = *lexbuf.ptr; + *lexbuf.ptr = '\0'; t = itype_end(t, IIDENT, 0); - if (t < bptr) { + if (t < lexbuf.ptr) { skipparens(Inbrack, Outbrack, &t); } else { - *bptr = sav; + *lexbuf.ptr = sav; } } if (*t == '+') t++; - if (t == bptr) { + if (t == lexbuf.ptr) { e = hgetc(); if (e == '(' && incmdpos) { - *bptr = '\0'; + *lexbuf.ptr = '\0'; return ENVARRAY; } hungetc(e); @@ -1326,13 +1220,25 @@ gettokstr(int c, int sub) c = hgetc(); if (!lexstop) continue; - } else + } else { add(Bnull); + if (c == STOUC(Meta)) { + c = hgetc(); +#ifdef DEBUG + if (lexstop) { + fputs("BUG: input terminated by Meta\n", stderr); + fflush(stderr); + goto brk; + } +#endif + add(Meta); + } + } if (lexstop) goto brk; break; case LX2_QUOTE: { - int strquote = (len && bptr[-1] == String); + int strquote = (lexbuf.len && lexbuf.ptr[-1] == String); add(Snull); cmdpush(CS_QUOTE); @@ -1355,8 +1261,8 @@ gettokstr(int c, int sub) else add('\\'); } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { - if (bptr[-1] == '\\') - bptr--, len--; + if (lexbuf.ptr[-1] == '\\') + lexbuf.ptr--, lexbuf.len--; else break; } @@ -1439,6 +1345,8 @@ gettokstr(int c, int sub) break; } brk: + if (errflag) + return LEXERR; hungetc(c); if (unmatched) zerr("unmatched %c", unmatched); @@ -1446,15 +1354,16 @@ gettokstr(int c, int sub) while(bct-- >= in_brace_param) cmdpop(); zerr("closing brace expected"); - } else if (unset(IGNOREBRACES) && !sub && len > 1 && - peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) { + } else if (unset(IGNOREBRACES) && !sub && lexbuf.len > 1 && + peek == STRING && lexbuf.ptr[-1] == '}' && + lexbuf.ptr[-2] != Bnull) { /* hack to get {foo} command syntax work */ - bptr--; - len--; + lexbuf.ptr--; + lexbuf.len--; lexstop = 0; hungetc('}'); } - *bptr = '\0'; + *lexbuf.ptr = '\0'; DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed."); return peek; } @@ -1508,8 +1417,19 @@ dquote_parse(char endchar, int sub) c = hgetc(); if (c == '(') { add(Qstring); - err = cmd_or_math_sub(); - c = Outpar; + switch (cmd_or_math_sub()) { + case CMD_OR_MATH_CMD: + c = Outpar; + break; + + case CMD_OR_MATH_MATH: + c = Outparmath; + break; + + default: + err = 1; + break; + } } else if (c == '[') { add(String); add(Inbrack); @@ -1617,44 +1537,58 @@ dquote_parse(char endchar, int sub) return err; } -/* Tokenize a string given in s. Parsing is done as in double * - * quotes. This is usually called before singsub(). */ +/* + * Tokenize a string given in s. Parsing is done as in double + * quotes. This is usually called before singsub(). + * + * parsestr() is noisier, reporting an error if the parse failed. + * + * On entry, *s must point to a string allocated from the stack of + * exactly the right length, i.e. strlen(*s) + 1, as the string + * is used as the lexical token string whose memory management + * demands this. Usually the input string will therefore be + * the result of an immediately preceding dupstring(). + */ /**/ mod_export int -parsestr(char *s) +parsestr(char **s) { int err; if ((err = parsestrnoerr(s))) { - untokenize(s); - if (err > 32 && err < 127) - zerr("parse error near `%c'", err); - else - zerr("parse error"); + untokenize(*s); + if (!(errflag & ERRFLAG_INT)) { + if (err > 32 && err < 127) + zerr("parse error near `%c'", err); + else + zerr("parse error"); + } } return err; } /**/ mod_export int -parsestrnoerr(char *s) +parsestrnoerr(char **s) { - int l = strlen(s), err; + int l = strlen(*s), err; - lexsave(); - untokenize(s); - inpush(dupstring(s), 0, NULL); + zcontext_save(); + untokenize(*s); + inpush(dupstring(*s), 0, NULL); strinbeg(0); - len = 0; - bptr = tokstr = s; - bsiz = l + 1; + lexbuf.len = 0; + lexbuf.ptr = tokstr = *s; + lexbuf.siz = l + 1; err = dquote_parse('\0', 1); - *bptr = '\0'; + if (tokstr) + *s = tokstr; + *lexbuf.ptr = '\0'; strinend(); inpop(); DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return err; } @@ -1673,27 +1607,27 @@ parse_subscript(char *s, int sub, int endchar) if (!*s || *s == endchar) return 0; - lexsave(); + zcontext_save(); untokenize(t = dupstring(s)); inpush(t, 0, NULL); strinbeg(0); - len = 0; - bptr = tokstr = s; - bsiz = l + 1; + lexbuf.len = 0; + lexbuf.ptr = tokstr = s; + lexbuf.siz = l + 1; err = dquote_parse(endchar, sub); if (err) { - err = *bptr; - *bptr = '\0'; + err = *lexbuf.ptr; + *lexbuf.ptr = '\0'; untokenize(s); - *bptr = err; + *lexbuf.ptr = err; s = NULL; } else { - s = bptr; + s = lexbuf.ptr; } strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subscript: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return s; } @@ -1711,29 +1645,30 @@ parse_subst_string(char *s) if (!*s || !strcmp(s, nulstring)) return 0; - lexsave(); + zcontext_save(); untokenize(s); inpush(dupstring(s), 0, NULL); strinbeg(0); - len = 0; - bptr = tokstr = s; - bsiz = l + 1; + lexbuf.len = 0; + lexbuf.ptr = tokstr = s; + lexbuf.siz = l + 1; c = hgetc(); ctok = gettokstr(c, 1); err = errflag; strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); - lexrestore(); - errflag = err; + zcontext_restore(); + /* Keep any interrupt error status */ + errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { untokenize(s); return 1; } #ifdef DEBUG /* - * Historical note: we used to check here for olen (the value of len - * before lexrestore()) == l, but that's not necessarily the case if + * Historical note: we used to check here for olen (the value of lexbuf.len + * before zcontext_restore()) == l, but that's not necessarily the case if * we stripped an RCQUOTE. */ if (ctok != STRING || (errflag && !noerrs)) { @@ -1787,7 +1722,7 @@ parse_subst_string(char *s) /* Called below to report word positions. */ /**/ -mod_export void +static void gotword(void) { we = zlemetall + 1 - inbufct + (addedx == 2 ? 1 : 0); @@ -1797,13 +1732,62 @@ gotword(void) } } +/* Check if current lex text matches an alias: 1 if so, else 0 */ + +static int +checkalias(void) +{ + Alias an; + + if (!zshlextext) + return 0; + + if (!noaliases && isset(ALIASESOPT) && + (!isset(POSIXALIASES) || + (tok == STRING && !reswdtab->getnode(reswdtab, zshlextext)))) { + char *suf; + + an = (Alias) aliastab->getnode(aliastab, zshlextext); + if (an && !an->inuse && + ((an->node.flags & ALIAS_GLOBAL) || + (incmdpos && tok == STRING) || inalmore)) { + if (!lexstop) { + /* + * Tokens that don't require a space after, get one, + * because they are treated as if preceded by one. + */ + int c = hgetc(); + hungetc(c); + if (!iblank(c)) + inpush(" ", INP_ALIAS, 0); + } + inpush(an->text, INP_ALIAS, an); + if (an->text[0] == ' ' && !(an->node.flags & ALIAS_GLOBAL)) + aliasspaceflag = 1; + lexstop = 0; + return 1; + } + if ((suf = strrchr(zshlextext, '.')) && suf[1] && + suf > zshlextext && suf[-1] != Meta && + (an = (Alias)sufaliastab->getnode(sufaliastab, suf+1)) && + !an->inuse && incmdpos) { + inpush(dupstring(zshlextext), INP_ALIAS, NULL); + inpush(" ", INP_ALIAS, NULL); + inpush(an->text, INP_ALIAS, an); + lexstop = 0; + return 1; + } + } + + return 0; +} + /* expand aliases and reserved words */ /**/ int exalias(void) { - Alias an; Reswd rw; hwend(); @@ -1815,7 +1799,9 @@ exalias(void) if (!tokstr) { zshlextext = tokstrings[tok]; - return 0; + if (tok == NEWLIN) + return 0; + return checkalias(); } else { VARARR(char, copy, (strlen(tokstr) + 1)); @@ -1841,34 +1827,10 @@ exalias(void) if (tok == STRING) { /* Check for an alias */ - if (!noaliases && isset(ALIASESOPT) && - (!isset(POSIXALIASES) || - !reswdtab->getnode(reswdtab, zshlextext))) { - char *suf; - - an = (Alias) aliastab->getnode(aliastab, zshlextext); - if (an && !an->inuse && - ((an->node.flags & ALIAS_GLOBAL) || incmdpos || inalmore)) { - inpush(an->text, INP_ALIAS, an); - if (an->text[0] == ' ' && !(an->node.flags & ALIAS_GLOBAL)) - aliasspaceflag = 1; - lexstop = 0; - if (zshlextext == copy) - zshlextext = tokstr; - return 1; - } - if ((suf = strrchr(zshlextext, '.')) && suf[1] && - suf > zshlextext && suf[-1] != Meta && - (an = (Alias)sufaliastab->getnode(sufaliastab, suf+1)) && - !an->inuse && incmdpos) { - inpush(dupstring(zshlextext), INP_ALIAS, NULL); - inpush(" ", INP_ALIAS, NULL); - inpush(an->text, INP_ALIAS, an); - lexstop = 0; - if (zshlextext == copy) - zshlextext = tokstr; - return 1; - } + if ((zshlextext != copy || !isset(POSIXALIASES)) && checkalias()) { + if (zshlextext == copy) + zshlextext = tokstr; + return 1; } /* Then check for a reserved word */ @@ -1892,12 +1854,68 @@ exalias(void) return 0; } -/* skip (...) */ +/**/ +void +zshlex_raw_add(int c) +{ + if (!lex_add_raw) + return; + + *lexbuf_raw.ptr++ = c; + if (lexbuf_raw.siz == ++lexbuf_raw.len) { + int newbsiz = lexbuf_raw.siz * 2; + + tokstr_raw = (char *)hrealloc(tokstr_raw, lexbuf_raw.siz, newbsiz); + lexbuf_raw.ptr = tokstr_raw + lexbuf_raw.len; + memset(lexbuf_raw.ptr, 0, newbsiz - lexbuf_raw.siz); + lexbuf_raw.siz = newbsiz; + } +} + +/**/ +void +zshlex_raw_back(void) +{ + if (!lex_add_raw) + return; + lexbuf_raw.ptr--; + lexbuf_raw.len--; +} + +/**/ +int +zshlex_raw_mark(int offset) +{ + if (!lex_add_raw) + return 0; + return lexbuf_raw.len + offset; +} + +/**/ +void +zshlex_raw_back_to_mark(int mark) +{ + if (!lex_add_raw) + return; + lexbuf_raw.ptr = tokstr_raw + mark; + lexbuf_raw.len = mark; +} + +/* + * Skip (...) for command-style substitutions: $(...), <(...), >(...) + * + * In order to ensure we don't stop at closing parentheses with + * some other syntactic significance, we'll parse the input until + * we find an unmatched closing parenthesis. However, we'll throw + * away the result of the parsing and just keep the string we've built + * up on the way. + */ /**/ static int skipcomm(void) { +#ifdef ZSH_OLD_SKIPCOMM int pct = 1, c, start = 1; cmdpush(CS_CMDSUBST); @@ -1922,7 +1940,7 @@ skipcomm(void) c = hgetc(); break; case '\'': { - int strquote = bptr[-1] == '$'; + int strquote = lexbuf.ptr[-1] == '$'; add(c); STOPHIST while ((c = hgetc()) != '\'' && !lexstop) { @@ -1968,4 +1986,114 @@ skipcomm(void) SETPAREND cmdpop(); return lexstop; +#else + char *new_tokstr; + int new_lexstop, new_lex_add_raw; + struct lexbufstate new_lexbuf; + + cmdpush(CS_CMDSUBST); + SETPARBEGIN + add(Inpar); + + new_lex_add_raw = lex_add_raw + 1; + if (!lex_add_raw) { + /* + * We'll combine the string so far with the input + * read in for the command substitution. To do this + * we'll just propagate the current tokstr etc. as the + * variables used for adding raw input, and + * ensure we swap those for the real tokstr etc. at the end. + * + * However, we need to save and restore the rest of the + * lexical and parse state as we're effectively parsing + * an internal string. Because we're still parsing it from + * the original input source (we have to --- we don't know + * when to stop inputting it otherwise and can't rely on + * the input being recoverable until we've read it) we need + * to keep the same history context. + */ + new_tokstr = tokstr; + new_lexbuf = lexbuf; + + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + hist_in_word(1); + } else { + /* + * Set up for nested command subsitution, however + * we don't actually need the string until we get + * back to the top level and recover the lot. + * The $() body just appears empty. + * + * We do need to propagate the raw variables which would + * otherwise by cleared, though. + */ + new_tokstr = tokstr_raw; + new_lexbuf = lexbuf_raw; + + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + } + tokstr_raw = new_tokstr; + lexbuf_raw = new_lexbuf; + lex_add_raw = new_lex_add_raw; + /* + * Don't do any ZLE specials down here: they're only needed + * when we return the string from the recursive parse. + * (TBD: this probably means we should be initialising lexflags + * more consistently.) + * + * Note that in that case we're still using the ZLE line reading + * function at the history layer --- this is consistent with the + * intention of maintaining the history and input layers across + * the recursive parsing. + */ + lexflags &= ~LEXFLAGS_ZLE; + + if (!parse_event(OUTPAR) || tok != OUTPAR) + lexstop = 1; + /* Outpar lexical token gets added in caller if present */ + + /* + * We're going to keep the full raw input string + * as the current token string after popping the stack. + */ + new_tokstr = tokstr_raw; + new_lexbuf = lexbuf_raw; + /* + * We're also going to propagate the lexical state: + * if we couldn't parse the command substitution we + * can't continue. + */ + new_lexstop = lexstop; + + zcontext_restore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + + if (lex_add_raw) { + /* + * Keep going, so retain the raw variables. + */ + tokstr_raw = new_tokstr; + lexbuf_raw = new_lexbuf; + } else { + if (!new_lexstop) { + /* Ignore the ')' added on input */ + new_lexbuf.len--; + *--new_lexbuf.ptr = '\0'; + } + + /* + * Convince the rest of lex.c we were examining a string + * all along. + */ + tokstr = new_tokstr; + lexbuf = new_lexbuf; + lexstop = new_lexstop; + hist_in_word(0); + } + + if (!lexstop) + SETPAREND + cmdpop(); + + return lexstop; +#endif } |