int exectry(Estate state, int do_exec) { Wordcode end, always; int endval; int save_retflag, save_breaks, save_contflag; zlong save_try_errflag, save_try_tryflag; end = state->pc + WC_TRY_SKIP(state->pc[-1]); always = state->pc + 1 + WC_TRY_SKIP(*state->pc); state->pc++; pushheap(); cmdpush(CS_CURSH); /* The :try clause */ save_try_tryflag = try_tryflag; try_tryflag = 1; execlist(state, 1, do_exec); try_tryflag = save_try_tryflag; /* Don't record errflag here, may be reset. */ endval = lastval; freeheap(); cmdpop(); cmdpush(CS_ALWAYS); /* The always clause. */ save_try_errflag = try_errflag; try_errflag = (zlong)errflag; errflag = 0; save_retflag = retflag; retflag = 0; save_breaks = breaks; breaks = 0; save_contflag = contflag; contflag = 0; state->pc = always; execlist(state, 1, do_exec); errflag = try_errflag ? 1 : 0; try_errflag = save_try_errflag; if (!retflag) retflag = save_retflag; if (!breaks) breaks = save_breaks; if (!contflag) contflag = save_contflag; cmdpop(); popheap(); state->pc = end; return endval; }
int execif(Estate state, int do_exec) { Wordcode end, next; wordcode code = state->pc[-1]; int olderrexit, s = 0, run = 0; olderrexit = noerrexit; end = state->pc + WC_IF_SKIP(code); noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN; while (state->pc < end) { code = *state->pc++; if (wc_code(code) != WC_IF || (run = (WC_IF_TYPE(code) == WC_IF_ELSE))) { if (run) run = 2; break; } next = state->pc + WC_IF_SKIP(code); cmdpush(s ? CS_ELIF : CS_IF); execlist(state, 1, 0); cmdpop(); if (!lastval) { run = 1; break; } if (retflag) break; s = 1; state->pc = next; } if (run) { /* we need to ignore lastval until we reach execcmd() */ if (olderrexit) noerrexit = olderrexit; else if (lastval) noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_UNTIL_EXEC; else noerrexit &= ~ (NOERREXIT_EXIT | NOERREXIT_RETURN); cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN)); execlist(state, 1, do_exec); cmdpop(); } else { noerrexit = olderrexit; if (!retflag) lastval = 0; } state->pc = end; this_noerrexit = 1; return lastval; }
int execif(Estate state, int do_exec) { Wordcode end, next; wordcode code = state->pc[-1]; int olderrexit, s = 0, run = 0; olderrexit = noerrexit; end = state->pc + WC_IF_SKIP(code); if (!noerrexit) noerrexit = 1; while (state->pc < end) { code = *state->pc++; if (wc_code(code) != WC_IF || (run = (WC_IF_TYPE(code) == WC_IF_ELSE))) { if (run) run = 2; break; } next = state->pc + WC_IF_SKIP(code); cmdpush(s ? CS_ELIF : CS_IF); execlist(state, 1, 0); cmdpop(); if (!lastval) { run = 1; break; } if (retflag) break; s = 1; state->pc = next; } if (run) { /* we need to ignore lastval until we reach execcmd() */ noerrexit = olderrexit ? olderrexit : lastval ? 2 : 0; cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN)); execlist(state, 1, do_exec); cmdpop(); } else { noerrexit = olderrexit; lastval = 0; } state->pc = end; return lastval; }
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; }
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; char *name; hwbegin(0); cmdpush(hdocs->type == REDIR_HEREDOC ? CS_HEREDOC : CS_HEREDOCD); STOPHIST name = gethere(hdocs->str, hdocs->type); ALLOWHIST cmdpop(); hwend(); setheredoc(hdocs->pc, REDIR_HERESTR, name); zfree(hdocs, sizeof(struct heredocs)); hdocs = next; } } if (tok != NEWLIN) isnewlin = 0; else isnewlin = (inbufct) ? -1 : 1; if (tok == SEMI || tok == NEWLIN) tok = SEPER; }
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) { /* Successfully parsed, see if it was math */ c = hgetc(); if (c == ')') return 1; /* yes */ hungetc(c); lexstop = 0; c = ')'; } else if (lexstop) { /* we haven't got anything to unget */ return 2; } /* else unsuccessful: unget the whole thing */ hungetc(c); lexstop = 0; while (len > oldlen) { len--; hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr); } hungetc('('); return 0; }
int execrepeat(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; int count, htok = 0; char *tmp; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; tmp = ecgetstr(state, EC_DUPTOK, &htok); if (htok) singsub(&tmp); count = mathevali(tmp); if (errflag) return 1; pushheap(); cmdpush(CS_REPEAT); loops++; loop = state->pc; while (count-- > 0) { state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (errflag) { lastval = 1; break; } if (retflag) break; } cmdpop(); popheap(); loops--; simple_pline = old_simple_pline; state->pc = end; this_noerrexit = 1; return lastval; }
void zshlex(void) { if (tok == LEXERR) return; do { if (inrepeat_) ++inrepeat_; if (inrepeat_ == 3 && isset(SHORTLOOPS)) incmdpos = 1; tok = gettok(); } while (tok != ENDINPUT && exalias()); nocorrect &= 1; if (tok == NEWLIN || tok == ENDINPUT) { while (hdocs) { struct heredocs *next = hdocs->next; char *doc, *munged_term; hwbegin(0); cmdpush(hdocs->type == REDIR_HEREDOC ? CS_HEREDOC : CS_HEREDOCD); munged_term = dupstring(hdocs->str); STOPHIST doc = gethere(&munged_term, hdocs->type); ALLOWHIST cmdpop(); hwend(); if (!doc) { zerr("here document too large"); while (hdocs) { next = hdocs->next; zfree(hdocs, sizeof(struct heredocs)); hdocs = next; } tok = LEXERR; break; } setheredoc(hdocs->pc, REDIR_HERESTR, doc, hdocs->str, munged_term); zfree(hdocs, sizeof(struct heredocs)); hdocs = next; } } if (tok != NEWLIN) isnewlin = 0; else isnewlin = (inbufct) ? -1 : 1; if (tok == SEMI || (tok == NEWLIN && !(lexflags & LEXFLAGS_NEWLINE))) tok = SEPER; }
int execrepeat(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; int count, htok = 0; char *tmp; end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; tmp = ecgetstr(state, EC_DUPTOK, &htok); if (htok) singsub(&tmp); count = atoi(tmp); pushheap(); cmdpush(CS_REPEAT); loops++; loop = state->pc; while (count-- > 0) { state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (errflag) { lastval = 1; break; } if (retflag) break; } cmdpop(); popheap(); loops--; state->pc = end; return lastval; }
static int cmd_or_math(int cs_type) { 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(); *lexbuf.ptr = '\0'; if (!c) { /* Successfully parsed, see if it was math */ c = hgetc(); if (c == ')') return CMD_OR_MATH_MATH; /* yes */ hungetc(c); lexstop = 0; c = ')'; } else if (lexstop) { /* we haven't got anything to unget */ return CMD_OR_MATH_ERR; } /* else unsuccessful: unget the whole thing */ hungetc(c); lexstop = 0; 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 errflag ? CMD_OR_MATH_ERR : CMD_OR_MATH_CMD; }
int execwhile(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL); int old_simple_pline = simple_pline; end = state->pc + WC_WHILE_SKIP(code); olderrexit = noerrexit; oldval = 0; pushheap(); cmdpush(isuntil ? CS_UNTIL : CS_WHILE); loops++; loop = state->pc; if (loop[0] == WC_END && loop[1] == WC_END) { /* This is an empty loop. Make sure the signal handler sets the * flags and then just wait for someone hitting ^C. */ simple_pline = 1; while (!breaks) ; breaks--; simple_pline = old_simple_pline; } else for (;;) { state->pc = loop; noerrexit = 1; /* In case the test condition is a functional no-op, * make sure signal handlers recognize ^C to end the loop. */ simple_pline = 1; execlist(state, 1, 0); simple_pline = old_simple_pline; noerrexit = olderrexit; if (!((lastval == 0) ^ isuntil)) { if (breaks) breaks--; lastval = oldval; break; } if (retflag) { lastval = oldval; break; } /* In case the loop body is also a functional no-op, * make sure signal handlers recognize ^C as above. */ simple_pline = 1; execlist(state, 1, 0); simple_pline = old_simple_pline; if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (errflag) { lastval = 1; break; } if (retflag) break; freeheap(); oldval = lastval; } cmdpop(); popheap(); loops--; state->pc = end; return lastval; }
int execselect(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; char *str, *s, *name; LinkNode n; int i, usezle; FILE *inp; size_t more; LinkList args; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); name = ecgetstr(state, EC_NODUP, NULL); if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } else { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } if (!args || empty(args)) { state->pc = end; simple_pline = old_simple_pline; return 0; } loops++; pushheap(); cmdpush(CS_SELECT); usezle = interact && SHTTY != -1 && isset(USEZLE); inp = fdopen(dup(usezle ? SHTTY : 0), "r"); more = selectlist(args, 0); loop = state->pc; for (;;) { for (;;) { if (empty(bufstack)) { if (usezle) { int oef = errflag; isfirstln = 1; str = zleentry(ZLE_CMD_READ, &prompt3, NULL, 0, ZLCON_SELECT); if (errflag) str = NULL; /* Keep any user interrupt error status */ errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); free(str); fflush(stderr); str = fgets(zhalloc(256), 256, inp); } } else str = (char *)getlinknode(bufstack); if (!str && !errflag) setsparam("REPLY", ztrdup("")); /* EOF (user pressed Ctrl+D) */ if (!str || errflag) { if (breaks) breaks--; fprintf(stderr, "\n"); fflush(stderr); goto done; } if ((s = strchr(str, '\n'))) *s = '\0'; if (*str) break; more = selectlist(args, more); } setsparam("REPLY", ztrdup(str)); i = atoi(str); if (!i) str = ""; else { for (i--, n = firstnode(args); n && i; incnode(n), i--); if (n) str = (char *) getdata(n); else str = ""; } setsparam(name, ztrdup(str)); state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag || errflag) break; } done: cmdpop(); popheap(); fclose(inp); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
static enum lextok gettokstr(int c, int sub) { int bct = 0, pct = 0, brct = 0, seen_brct = 0, fdpar = 0; int intpos = 1, in_brace_param = 0; int inquote, unmatched = 0; enum lextok peek; #ifdef DEBUG int ocmdsp = cmdsp; #endif peek = STRING; if (!sub) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); } for (;;) { int act; int e; int inbl = inblank(c); if (fdpar && !inbl && c != ')') fdpar = 0; if (inbl && !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 (fdpar) { /* this is a single word `( )', treat as INOUTPAR */ add(c); *lexbuf.ptr = '\0'; return INOUTPAR; } 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); 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; } } else { if (e == '{') { add(c); c = Inbrace; ++bct; cmdpush(CS_BRACEPAR); if (!in_brace_param) { if ((in_brace_param = bct)) seen_brct = 0; } } else { hungetc(e); lexstop = 0; } } break; case LX2_INBRACK: if (!in_brace_param) { brct++; seen_brct = 1; } c = Inbrack; break; case LX2_OUTBRACK: if (!in_brace_param) brct--; if (brct < 0) brct = 0; c = Outbrack; break; case LX2_INPAR: if (isset(SHGLOB)) { if (sub || in_brace_param) break; if (incasepat && !lexbuf.len) return INPAR; if (!isset(KSHGLOB) && lexbuf.len) goto brk; } if (!in_brace_param) { if (!sub) { e = hgetc(); hungetc(e); lexstop = 0; /* For command words, parentheses are only * special at the start. But now we're tokenising * the remaining string. So I don't see what * the old incmdpos test here is for. * pws 1999/6/8 * * Oh, no. * func1( ) * is a valid function definition in [k]sh. The best * thing we can do, without really nasty lookahead tricks, * is break if we find a blank after a parenthesis. At * least this can't happen inside braces or brackets. We * only allow this with SHGLOB (set for both sh and ksh). * * Things like `print @( |foo)' should still * work, because [k]sh don't allow multiple words * in a function definition, so we only do this * in command position. * pws 1999/6/14 */ if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct && !brct && !intpos && incmdpos)) { /* * Either a () token, or a command word with * something suspiciously like a ksh function * definition. * The current word isn't spellcheckable. */ nocorrect |= 2; goto brk; } } /* * This also handles the [k]sh `foo( )' function definition. * Maintain a variable fdpar, set as long as a single set of * parentheses contains only space. Then if we get to the * closing parenthesis and it is still set, we can assume we * have a function definition. Only do this at the start of * the word, since the (...) must be a separate token. */ if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct) fdpar = 1; } c = Inpar; break; case LX2_INBRACE: if (isset(IGNOREBRACES) || sub) c = '{'; else { if (!lexbuf.len && incmdpos) { add('{'); *lexbuf.ptr = '\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 (in_brace_param || sub) break; e = hgetc(); if (e != '(') { hungetc(e); lexstop = 0; goto brk; } add(OutangProc); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; case LX2_INANG: if (isset(SHGLOB) && sub) break; e = hgetc(); if (!(in_brace_param || sub) && e == '(') { add(Inang); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; } hungetc(e); if(isnumglob()) { add(Inang); while ((c = hgetc()) != '>') add(c); c = Outang; break; } lexstop = 0; if (in_brace_param || sub) break; goto brk; case LX2_EQUALS: if (!sub) { 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 (peek != ENVSTRING && (incmdpos || intypeset) && !bct && !brct) { char *t = tokstr; if (idigit(*t)) while (++t < lexbuf.ptr && idigit(*t)); else { int sav = *lexbuf.ptr; *lexbuf.ptr = '\0'; t = itype_end(t, IIDENT, 0); if (t < lexbuf.ptr) { skipparens(Inbrack, Outbrack, &t); } else { *lexbuf.ptr = sav; } } if (*t == '+') t++; if (t == lexbuf.ptr) { e = hgetc(); if (e == '(') { *lexbuf.ptr = '\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 (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 = (lexbuf.len && lexbuf.ptr[-1] == String); add(Snull); cmdpush(CS_QUOTE); for (;;) { STOPHIST while ((c = hgetc()) != '\'' && !lexstop) { if (strquote && c == '\\') { c = hgetc(); if (lexstop) break; /* * Mostly we don't need to do anything special * with escape backslashes or closing quotes * inside $'...'; however in completion we * need to be able to strip multiple backslashes * neatly. */ if (c == '\\' || c == '\'') add(Bnull); else add('\\'); } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { if (lexbuf.ptr[-1] == '\\') lexbuf.ptr--, lexbuf.len--; else break; } add(c); } ALLOWHIST if (c != '\'') { unmatched = '\''; peek = LEXERR; cmdpop(); goto brk; } e = hgetc(); if (e != '\'' || unset(RCQUOTES) || strquote) 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) { unmatched = '"'; 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 != '`') { unmatched = '`'; peek = LEXERR; goto brk; } c = Tick; SETPAREND break; case LX2_DASH: /* * - shouldn't be treated as a special character unless * we're in a pattern. Howeve,simply counting "[" doesn't * work as []a-z] is a valid expression and we don't know * down here what this "[" is for as $foo[stuff] is valid * in zsh. So just detect an opening [, which is enough * to turn this into a pattern; the Dash will be harmlessly * untokenised if not wanted. */ if (seen_brct) c = Dash; else c = '-'; break; case LX2_BANG: /* * Same logic as Dash, for ! to perform negation in range. */ if (seen_brct) c = Bang; else c = '!'; } add(c); c = hgetc(); if (intpos) intpos--; if (lexstop) break; } brk: if (errflag) { if (in_brace_param) { while(bct-- >= in_brace_param) cmdpop(); } return LEXERR; } hungetc(c); if (unmatched) zerr("unmatched %c", unmatched); if (in_brace_param) { while(bct-- >= in_brace_param) cmdpop(); zerr("closing brace expected"); } else if (unset(IGNOREBRACES) && !sub && lexbuf.len > 1 && peek == STRING && lexbuf.ptr[-1] == '}' && lexbuf.ptr[-2] != Bnull) { /* hack to get {foo} command syntax work */ lexbuf.ptr--; lexbuf.len--; lexstop = 0; hungetc('}'); } *lexbuf.ptr = '\0'; DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed."); return peek; }
static enum lextok gettok(void) { int c, d; int peekfd = -1; enum lextok peek; beginning: tokstr = NULL; while (iblank(c = hgetc()) && !lexstop); toklineno = lineno; if (lexstop) return (errflag) ? LEXERR : ENDINPUT; isfirstln = 0; 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) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); hungetc(c); cmdpush(CS_MATH); c = dquote_parse(infor ? ';' : ')', 0); cmdpop(); *lexbuf.ptr = '\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 = hgetc(); if(d == '>') { peekfd = c - '0'; hungetc('>'); c = '&'; } else { hungetc(d); lexstop = 0; hungetc('&'); } } else if (d == '>' || d == '<') { peekfd = c - '0'; c = d; } else { hungetc(d); lexstop = 0; } } /* chars in initial position in word */ /* * Handle comments. There are some special cases when this * is not normal command input: lexflags implies we are examining * a line lexically without it being used for normal command input. */ if (c == hashchar && !nocomments && (isset(INTERACTIVECOMMENTS) || ((!lexflags || (lexflags & LEXFLAGS_COMMENTS)) && !expanding && (!interact || unset(SHINSTDIN) || strin)))) { /* History is handled here to prevent extra * * newlines being inserted into the history. */ if (lexflags & LEXFLAGS_COMMENTS_KEEP) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *)hcalloc(lexbuf.siz = LEX_HEAP_SIZE); add(c); } hwend(); while ((c = ingetc()) != '\n' && !lexstop) { hwaddc(c); addtoline(c); if (lexflags & LEXFLAGS_COMMENTS_KEEP) add(c); } if (errflag) peek = LEXERR; else { if (lexflags & LEXFLAGS_COMMENTS_KEEP) { *lexbuf.ptr = '\0'; if (!lexstop) hungetc(c); peek = STRING; } else { hwend(); hwbegin(0); hwaddc('\n'); addtoline('\n'); /* * If splitting a line and removing comments, * we don't want a newline token since it's * treated specially. */ if ((lexflags & LEXFLAGS_COMMENTS_STRIP) && lexstop) peek = ENDINPUT; else 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; else if (d == '|') return SEMIBAR; hungetc(d); lexstop = 0; return SEMI; case LX1_AMPER: d = hgetc(); if (d == '&') return DAMPER; else if (d == '!' || d == '|') return AMPERBANG; else if (d == '>') { tokfd = peekfd; 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 || (isset(SHGLOB) && !isset(KSHGLOB))) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); switch (cmd_or_math(CS_MATH)) { case CMD_OR_MATH_MATH: return DINPAR; case CMD_OR_MATH_CMD: /* * Not math, so we don't return the contents * as a string in this case. */ tokstr = NULL; return INPAR; case CMD_OR_MATH_ERR: /* * LEXFLAGS_ACTIVE means we came from bufferwords(), * so we treat as an incomplete math expression */ if (lexflags & LEXFLAGS_ACTIVE) tokstr = dyncat("((", tokstr ? tokstr : ""); /* fall through */ default: return LEXERR; } } } else if (d == ')') return INOUTPAR; hungetc(d); lexstop = 0; if (!(isset(SHGLOB) || incond == 1 || incmdpos)) break; return INPAR; case LX1_OUTPAR: return OUTPAR; case LX1_INANG: d = hgetc(); if (d == '(') { hungetc(d); lexstop = 0; unpeekfd: if(peekfd != -1) { hungetc(c); c = '0' + peekfd; } break; } if (d == '>') { peek = INOUTANG; } 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 { hungetc(d); if(isnumglob()) goto unpeekfd; peek = INANG; } tokfd = peekfd; return peek; case LX1_OUTANG: d = hgetc(); if (d == '(') { hungetc(d); goto unpeekfd; } 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); }
int execcase(Estate state, int do_exec) { Wordcode end, next; wordcode code = state->pc[-1]; char *word, *pat; int npat, save, nalts, ialt, patok; Patprog *spprog, pprog; end = state->pc + WC_CASE_SKIP(code); word = ecgetstr(state, EC_DUP, NULL); singsub(&word); untokenize(word); cmdpush(CS_CASE); while (state->pc < end) { code = *state->pc++; if (wc_code(code) != WC_CASE) break; save = 0; next = state->pc + WC_CASE_SKIP(code); nalts = *state->pc++; ialt = patok = 0; if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "case %s (", word); } while (!patok && nalts) { npat = state->pc[1]; spprog = state->prog->pats + npat; pprog = NULL; pat = NULL; if (isset(XTRACE)) { int htok = 0; pat = dupstring(ecrawstr(state->prog, state->pc, &htok)); if (htok) singsub(&pat); if (ialt++) fprintf(stderr, " | "); quote_tokenized_output(pat, xtrerr); } if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) pprog = *spprog; if (!pprog) { if (!pat) { char *opat; int htok = 0; pat = dupstring(opat = ecrawstr(state->prog, state->pc, &htok)); if (htok) singsub(&pat); save = (!(state->prog->flags & EF_HEAP) && !strcmp(pat, opat) && *spprog != dummy_patprog2); } if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), NULL))) zerr("bad pattern: %s", pat); else if (save) *spprog = pprog; } if (pprog && pattry(pprog, word)) patok = 1; state->pc += 2; nalts--; } state->pc += 2 * nalts; if (isset(XTRACE)) { fprintf(xtrerr, ")\n"); fflush(xtrerr); } if (patok) { execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); while (!retflag && wc_code(code) == WC_CASE && WC_CASE_TYPE(code) == WC_CASE_AND && state->pc < end) { state->pc = next; code = *state->pc++; next = state->pc + WC_CASE_SKIP(code); nalts = *state->pc++; state->pc += 2 * nalts; execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); } if (WC_CASE_TYPE(code) != WC_CASE_TESTAND) break; } state->pc = next; } cmdpop(); state->pc = end; return lastval; }
int gettok(void) { int c, d; int peekfd = -1, peek; 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 *) hcalloc(bsiz = 32); 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 = hgetc(); if(d == '>') { peekfd = c - '0'; hungetc('>'); c = '&'; } else { hungetc(d); lexstop = 0; hungetc('&'); } } else if (d == '>' || d == '<') { peekfd = c - '0'; c = d; } else { hungetc(d); lexstop = 0; } } /* chars in initial position in word */ if (c == hashchar && !nocomments && (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 == '>') { tokfd = peekfd; 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 *) hcalloc(bsiz = 32); 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; unpeekfd: if(peekfd != -1) { hungetc(c); c = '0' + peekfd; } break; } if (d == '>') { peek = INOUTANG; } 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 { hungetc(d); if(isnumglob()) goto unpeekfd; peek = INANG; } tokfd = peekfd; return peek; case LX1_OUTANG: d = hgetc(); if (d == '(') { hungetc(d); goto unpeekfd; } 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 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; }
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 == '`' || (endchar == ']' && (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || (c == '"' && sub)))) add(Bnull); else { /* lexstop is implicitly 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 '(': if (!math || !bct) pct++; break; case ')': if (!math || !bct) err = (!pct-- && math); break; case '[': if (!math || !bct) brct++; break; case ']': if (!math || !bct) err = (!brct-- && math); break; case '"': if (intick || ((endchar == ']' || !endchar) && !bct)) break; if (bct) { add(Dnull); cmdpush(CS_DQUOTE); err = dquote_parse('"', sub); cmdpop(); 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; }
int execfor(Estate state, int do_exec) { Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; LinkList vars = NULL, args = NULL; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); if (iscond) { str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); untokenize(str2); printprompt4(); fprintf(xtrerr, "%s\n", str2); fflush(xtrerr); } if (!errflag) { matheval(str); } if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); } else { vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } else { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } } if (!args || empty(args)) lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); singsub(&str); } else str = cond; if (!errflag) { while (iblank(*str)) str++; if (*str) { if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } val = mathevali(str); } else val = 1; } if (errflag) { if (breaks) breaks--; lastval = 1; break; } if (!val) break; } else { LinkNode node; int count = 0; for (node = firstnode(vars); node; incnode(node)) { name = (char *)getdata(node); if (!args || !(str = (char *) ugetnode(args))) { if (count) { str = ""; last = 1; } else break; } if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s=%s\n", name, str); fflush(xtrerr); } setsparam(name, ztrdup(str)); count++; } if (!count) break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag) break; if (iscond && !errflag) { if (atok) { str = dupstring(advance); singsub(&str); } else str = advance; if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } if (!errflag) matheval(str); } if (errflag) { if (breaks) breaks--; lastval = 1; break; } freeheap(); } popheap(); cmdpop(); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
static int gettokstr(int c, int sub) { int bct = 0, pct = 0, brct = 0, fdpar = 0; int intpos = 1, in_brace_param = 0; int peek, inquote, unmatched = 0; char endchar='"'; #ifdef DEBUG int ocmdsp = cmdsp; #endif peek = STRING; if (!sub) { len = 0; bptr = tokstr = (char *) hcalloc(bsiz = 32); } for (;;) { int act; int e; int inbl = inblank(c); if (fdpar && !inbl && c != ')') fdpar = 0; if (inbl && !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 (fdpar) { /* this is a single word `( )', treat as INOUTPAR */ add(c); *bptr = '\0'; return INOUTPAR; } 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 (isset(SHGLOB)) { if (sub || in_brace_param) break; if (incasepat && !len) return INPAR; } if (!in_brace_param) { if (!sub) { e = hgetc(); hungetc(e); lexstop = 0; /* For command words, parentheses are only * special at the start. But now we're tokenising * the remaining string. So I don't see what * the old incmdpos test here is for. * pws 1999/6/8 * * Oh, no. * func1( ) * is a valid function definition in [k]sh. The best * thing we can do, without really nasty lookahead tricks, * is break if we find a blank after a parenthesis. At * least this can't happen inside braces or brackets. We * only allow this with SHGLOB (set for both sh and ksh). * * Things like `print @( |foo)' should still * work, because [k]sh don't allow multiple words * in a function definition, so we only do this * in command position. * pws 1999/6/14 */ if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct && !brct && !intpos && incmdpos)) goto brk; } /* * This also handles the [k]sh `foo( )' function definition. * Maintain a variable fdpar, set as long as a single set of * parentheses contains only space. Then if we get to the * closing parenthesis and it is still set, we can assume we * have a function definition. Only do this at the start of * the word, since the (...) must be a separate token. */ if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct) fdpar = 1; } 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(e == '(' && intpos) { add(Inang); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; } hungetc(e); if(isnumglob()) { add(Inang); while ((c = hgetc()) != '>') add(c); c = Outang; break; } lexstop = 0; if (in_brace_param || sub) break; goto brk; 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 == '+') 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; #ifndef __SYMBIAN32__ case LX2_BKSLASH: c = hgetc(); if (c == '\n') { c = hgetc(); if (!lexstop) continue; } else add(Bnull); if (lexstop) goto brk; break; #endif 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 != '\'') { unmatched = '\''; peek = LEXERR; cmdpop(); goto brk; } e = hgetc(); if (e != '\'' || unset(RCQUOTES) || strquote) 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) { unmatched = '"'; 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 != '`') { unmatched = '`'; peek = LEXERR; goto brk; } c = Tick; SETPAREND break; } #ifdef __SYMBIAN32__ if(c=='\\') { c = hgetc(); if (c != '\n') { if (c == endchar) add(Bnull); else { /* lexstop is implicitly handled here */ add('\\'); } } } #endif add(c); c = hgetc(); if (intpos) intpos--; if (lexstop) break; } brk: hungetc(c); if (unmatched) zerr("unmatched %c", NULL, unmatched); 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 skipcomm(void) { #ifdef ZSH_OLD_SKIPCOMM int pct = 1, c, start = 1; cmdpush(CS_CMDSUBST); SETPARBEGIN c = Inpar; do { int iswhite; add(c); c = hgetc(); if (itok(c) || lexstop) break; iswhite = inblank(c); switch (c) { case '(': pct++; break; case ')': pct--; break; case '\\': add(c); c = hgetc(); break; case '\'': { int strquote = lexbuf.ptr[-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; case '#': if (start) { add(c); while ((c = hgetc()) != '\n' && !lexstop) add(c); iswhite = 1; } break; } start = iswhite; } while (pct); if (!lexstop) SETPAREND cmdpop(); return lexstop; #else char *new_tokstr; int new_lexstop, new_lex_add_raw; int save_infor = infor; struct lexbufstate new_lexbuf; int noalias = noaliases; noaliases = 1; infor = 0; 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; /* * If we're expanding an alias at this point, we need the whole * remaining text as part of the string for the command in * parentheses, so don't backtrack. This is different from the * usual case where the alias is fully within the command, where * we want the unexpanded text so that it will be expanded * again when the command in the parentheses is executed. * * I never wanted to be a software engineer, you know. */ if (inbufflags & INP_ALIAS) inbufflags |= INP_RAW_KEEP; 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; dbparens = 0; /* restored by zcontext_restore_partial() */ 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(); infor = save_infor; noaliases = noalias; return lexstop; #endif }
int exectry(Estate state, int do_exec) { Wordcode end, always; int endval; int save_retflag, save_breaks, save_contflag; zlong save_try_errflag, save_try_tryflag, save_try_interrupt; end = state->pc + WC_TRY_SKIP(state->pc[-1]); always = state->pc + 1 + WC_TRY_SKIP(*state->pc); state->pc++; pushheap(); cmdpush(CS_CURSH); /* The :try clause */ save_try_tryflag = try_tryflag; try_tryflag = 1; execlist(state, 1, do_exec); try_tryflag = save_try_tryflag; /* Don't record errflag here, may be reset. However, */ /* endval should show failure when there is an error. */ endval = lastval ? lastval : errflag; freeheap(); cmdpop(); cmdpush(CS_ALWAYS); /* The always clause. */ save_try_errflag = try_errflag; save_try_interrupt = try_interrupt; try_errflag = (zlong)(errflag & ERRFLAG_ERROR); try_interrupt = (zlong)((errflag & ERRFLAG_INT) ? 1 : 0); /* We need to reset all errors to allow the block to execute */ errflag = 0; save_retflag = retflag; retflag = 0; save_breaks = breaks; breaks = 0; save_contflag = contflag; contflag = 0; state->pc = always; execlist(state, 1, do_exec); if (try_errflag) errflag |= ERRFLAG_ERROR; else errflag &= ~ERRFLAG_ERROR; if (try_interrupt) errflag |= ERRFLAG_INT; else errflag &= ~ERRFLAG_INT; try_errflag = save_try_errflag; try_interrupt = save_try_interrupt; if (!retflag) retflag = save_retflag; if (!breaks) breaks = save_breaks; if (!contflag) contflag = save_contflag; cmdpop(); popheap(); state->pc = end; return endval; }
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 == ']' || infor; int zlemath = math && zlemetacs > zlemetall + 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 == '`' || (endchar == ']' && (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || (c == '"' && sub)))) add(Bnull); else { /* lexstop is implicitly 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); 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); 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 '(': if (!math || !bct) pct++; break; case ')': if (!math || !bct) err = (!pct-- && math); break; case '[': if (!math || !bct) brct++; break; case ']': if (!math || !bct) err = (!brct-- && math); break; case '"': if (intick || (endchar != '"' && !bct)) break; if (bct) { add(Dnull); cmdpush(CS_DQUOTE); err = dquote_parse('"', sub); cmdpop(); 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) { /* * TODO: as far as I can see, this hack is used in gettokstr() * to hungetc() a character on an error. However, I don't * understand what that actually gets us, and we can't guarantee * it's a character anyway, because of the previous test. * * We use the same feature in cmd_or_math where we actually do * need to unget if we decide it's really a command substitution. * We try to handle the other case by testing for lexstop. */ err = c; } if (zlemath && zlemetacs <= zlemetall + 1 - inbufct) inwhat = IN_MATH; return err; }