From 58da0f495cdf2bbef6a7043f5f06c77991c79a9e Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 21 Nov 2014 01:08:25 +0100 Subject: 33730: vim style text objects for selecting words --- Src/Zle/textobjects.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 Src/Zle/textobjects.c (limited to 'Src/Zle/textobjects.c') diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c new file mode 100644 index 000000000..7f049c5dd --- /dev/null +++ b/Src/Zle/textobjects.c @@ -0,0 +1,321 @@ +/* + * textobjects.c - ZLE module implementing Vim style text objects + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 2014 Oliver Kiddle + * 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 Oliver Kiddle 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 Oliver Kiddle and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Oliver Kiddle 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 Oliver Kiddle and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "zle.mdh" +#include "textobjects.pro" + +/* class of character: 0 is whitespace, 1 is word character, 2 is other */ +static int +wordclass(ZLE_CHAR_T x) +{ + return (ZC_iblank(x) ? 0 : ((ZC_ialnum(x) || (ZWC('_') == x)) ? 1 : 2)); +} + +static int +blankwordclass(ZLE_CHAR_T x) +{ + return (ZC_iblank(x) ? 0 : 1); +} + +/**/ +int +selectword(UNUSED(char **args)) +{ + int n = zmult; + int all = (bindk == t_selectaword || bindk == t_selectablankword); + int (*viclass)(ZLE_CHAR_T) = (bindk == t_selectaword || + bindk == t_selectinword) ? wordclass : blankwordclass; + int sclass = viclass(zleline[zlecs]); + int doblanks = all && sclass; + + if (!invicmdmode()) { + region_active = 1; + mark = zlecs; + } + if (!region_active || zlecs == mark) { + /* search back to first character of same class as the start position + * also stop at the beginning of the line */ + mark = zlecs; + while (mark) { + int pos = mark; + DECPOS(pos); + if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass) + break; + mark = pos; + } + /* similarly scan forward over characters of the same class */ + while (zlecs < zlell) { + INCCS(); + int pos = zlecs; + /* single newlines within blanks are included */ + if (all && !sclass && pos < zlell && zleline[pos] == ZWC('\n')) + INCPOS(pos); + + if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass) + break; + } + + if (all) { + int nclass = viclass(zleline[zlecs]); + /* if either start or new position is blank advance over + * a new block of characters of a common type */ + if (!nclass || !sclass) { + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != nclass) + break; + } + if (n < 2) + doblanks = 0; + } + } + } else { + /* For visual mode, advance one char so repeated + * invocations select subsequent words */ + if (zlecs > mark) { + if (zlecs < zlell) + INCCS(); + } else if (zlecs) + DECCS(); + if (zlecs < mark) { + /* visual mode with the cursor before the mark: move cursor back */ + while (n-- > 0) { + int pos = zlecs; + /* first over blanks */ + if (all && (!viclass(zleline[pos]) || + zleline[pos] == ZWC('\n'))) { + all = 0; + while (pos) { + DECPOS(pos); + if (zleline[pos] == ZWC('\n')) + break; + zlecs = pos; + if (viclass(zleline[pos])) + break; + } + } else if (zlecs && zleline[zlecs] == ZWC('\n')) { + /* for in widgets pass over one newline */ + DECPOS(pos); + if (zleline[pos] != ZWC('\n')) + zlecs = pos; + } + pos = zlecs; + sclass = viclass(zleline[zlecs]); + /* now retreat over non-blanks */ + while (zleline[pos] != ZWC('\n') && + viclass(zleline[pos]) == sclass) { + zlecs = pos; + if (!pos) { + zlecs = 0; + break; + } + DECPOS(pos); + } + /* blanks again but only if there were none first time */ + if (all && zlecs) { + pos = zlecs; + DECPOS(pos); + if (!viclass(zleline[pos])) { + while (pos) { + DECPOS(pos); + if (zleline[pos] == ZWC('\n') || + viclass(zleline[pos])) + break; + zlecs = pos; + } + } + } + } + return 0; + } + n++; + doblanks = 0; + } + region_active = !!region_active; /* force to character wise */ + + /* for each digit argument, advance over further block of one class */ + while (--n > 0) { + if (zlecs < zlell && zleline[zlecs] == ZWC('\n')) + INCCS(); + sclass = viclass(zleline[zlecs]); + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != sclass) + break; + } + /* for 'a' widgets, advance extra block if either consists of blanks */ + if (all) { + if (zlecs < zlell && zleline[zlecs] == ZWC('\n')) + INCCS(); + if (!sclass || !viclass(zleline[zlecs]) ) { + sclass = viclass(zleline[zlecs]); + if (n == 1 && !sclass) + doblanks = 0; + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != sclass) + break; + } + } + } + } + + /* if we didn't remove blanks at either end we remove some at the start */ + if (doblanks) { + int pos = mark; + while (pos) { + DECPOS(pos); + /* don't remove blanks at the start of the line, i.e indentation */ + if (zleline[pos] == ZWC('\n')) + break; + if (!ZC_iblank(zleline[pos])) { + INCPOS(pos); + mark = pos; + break; + } + } + } + /* Adjustment: vi operators don't include the cursor position, in insert + * or emacs mode the region also doesn't but for vi visual mode it is + * included. */ + if (zlecs && zlecs > mark && !virangeflag) + DECCS(); + + return 0; +} + +/**/ +int +selectargument(UNUSED(char **args)) +{ + int ne = noerrs, ocs = zlemetacs; + int owb = wb, owe= we, oadx = addedx, ona = noaliases; + char *p; + int ll, cs; + char *linein; + int wend = 0, wcur = 0; + int n = zmult; + int *wstarts; + int tmpsz; + + if (n < 1 || 2*n > zlell + 1) + return 1; + + /* if used from emacs mode enable the region */ + if (!invicmdmode()) { + region_active = 1; + mark = zlecs; + } + + wstarts = (int *) zhalloc(n * sizeof(int)); + memset(wstarts, 0, n * sizeof(int)); + + addedx = 0; + noerrs = 1; + lexsave(); + lexflags = LEXFLAGS_ACTIVE; + linein = zlegetline(&ll, &cs); + zlemetall = ll; + zlemetacs = cs; + + if (!isfirstln && chline) { + p = (char *) zhalloc(hptr - chline + zlemetall + 2); + memcpy(p, chline, hptr - chline); + memcpy(p + (hptr - chline), linein, ll); + p[(hptr - chline) + ll] = '\0'; + inpush(p, 0, NULL); + zlemetacs += hptr - chline; + } else { + p = (char *) zhalloc(ll + 1); + memcpy(p, linein, ll); + p[ll] = '\0'; + inpush(p, 0, NULL); + } + if (zlemetacs) + zlemetacs--; + strinbeg(0); + noaliases = 1; + do { + wstarts[wcur++] = wend; + wcur %= n; + ctxtlex(); + if (tok == ENDINPUT || tok == LEXERR) + break; + wend = zlemetall - inbufct; + } while (tok != ENDINPUT && tok != LEXERR && wend <= zlemetacs); + noaliases = ona; + strinend(); + inpop(); + errflag = 0; + noerrs = ne; + lexrestore(); + zlemetacs = ocs; + wb = owb; + we = owe; + addedx = oadx; + + /* convert offsets for mark and zlecs back to ZLE internal format */ + linein[wend] = '\0'; /* a bit of a hack to get two offsets */ + free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark)); + + if (bindk == t_selectinshellword) { + ZLE_CHAR_T *match = ZWS("`\'\""); + ZLE_CHAR_T *lmatch = ZWS("\'({"), *rmatch = ZWS("\')}"); + ZLE_CHAR_T *ematch = match, *found; + int start, end = zlecs; + /* for 'in' widget, don't include initial blanks ... */ + while (mark < zlecs && ZC_iblank(zleline[mark])) + INCPOS(mark); + /* ... or a matching pair of quotes */ + start = mark; + if (zleline[start] == ZWC('$')) { + match = lmatch; + ematch = rmatch; + INCPOS(start); + } + found = ZS_strchr(match, zleline[start]); + if (found) { + DECPOS(end); + if (zleline[end] == ematch[found-match]) { + zlecs = end; + INCPOS(start); + mark = start; + } + } + } + + /* Adjustment: vi operators don't include the cursor position */ + if (!virangeflag) + DECCS(); + + return 0; +} -- cgit v1.2.3 From 7a4a309973a2cfad2aefbfd6dfa8cc137005b227 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 5 Dec 2014 20:12:02 +0100 Subject: 33860: minor fixes to vi mode changes --- ChangeLog | 4 ++++ Src/Zle/textobjects.c | 1 + Src/Zle/zle_misc.c | 27 +++++++++++++++++-------- Src/Zle/zle_move.c | 12 ++++++----- Src/Zle/zle_vi.c | 56 +++++++++++++++++++++++---------------------------- Test/X02zlevi.ztst | 10 +++++++++ 6 files changed, 66 insertions(+), 44 deletions(-) (limited to 'Src/Zle/textobjects.c') diff --git a/ChangeLog b/ChangeLog index 7c15d969b..ca2a6021c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2014-12-05 Oliver Kiddle + * 33860: Src/Zle/textobjects.c, Src/Zle/zle_misc.c, + Src/Zle/zle_move.c, Src/Zle/zle_vi.c, Test/X02zlevi.ztst: + minor fixes to vi mode changes + * 33845: Src/Zle/zle_hist.c: save correct cursor position with push-line from vi command mode diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 7f049c5dd..85d014b27 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -286,6 +286,7 @@ selectargument(UNUSED(char **args)) /* convert offsets for mark and zlecs back to ZLE internal format */ linein[wend] = '\0'; /* a bit of a hack to get two offsets */ free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark)); + free(linein); if (bindk == t_selectinshellword) { ZLE_CHAR_T *match = ZWS("`\'\""); diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index a1dc3fa5c..d432acf7b 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -476,9 +476,11 @@ killregion(UNUSED(char **args)) foredel(1, 0); vifirstnonblank(zlenoargs); } - } else if (mark > zlecs) - forekill(mark - zlecs + invicmdmode(), CUT_RAW); - else { + } else if (mark > zlecs) { + if (invicmdmode()) + INCPOS(mark); + forekill(mark - zlecs, CUT_RAW); + } else { if (invicmdmode()) INCCS(); backkill(zlecs - mark, CUT_FRONT|CUT_RAW); @@ -490,6 +492,7 @@ killregion(UNUSED(char **args)) int copyregionaskill(char **args) { + int start, end; if (*args) { int len; ZLE_STRING_T line = stringaszleline(*args, 0, &len, NULL, NULL); @@ -498,10 +501,16 @@ copyregionaskill(char **args) } else { if (mark > zlell) mark = zlell; - if (mark > zlecs) - cut(zlecs, mark - zlecs + invicmdmode(), 0); - else - cut(mark, zlecs - mark + invicmdmode(), CUT_FRONT); + if (mark > zlecs) { + start = zlecs; + end = mark; + } else { + start = mark; + end = zlecs; + } + if (invicmdmode()) + INCPOS(end); + cut(start, end - start, mark > zlecs ? 0 : CUT_FRONT); } return 0; } @@ -1057,7 +1066,9 @@ quoteregion(UNUSED(char **args)) mark = zlecs; zlecs = tmp; } - str = (ZLE_STRING_T)hcalloc((len = mark - zlecs + extra) * + if (extra) + INCPOS(mark); + str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) * ZLE_CHAR_SIZE); ZS_memcpy(str, zleline + zlecs, len); foredel(len, CUT_RAW); diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c index fad6b0a5f..939cfb1d0 100644 --- a/Src/Zle/zle_move.c +++ b/Src/Zle/zle_move.c @@ -575,7 +575,8 @@ vimatchbracket(UNUSED(char **args)) if ((zlecs == zlell || zleline[zlecs] == '\n') && zlecs > 0) DECCS(); - + if (virangeflag) + mark = zlecs; otog: if (zlecs == zlell || zleline[zlecs] == '\n') { zlecs = ocs; @@ -587,7 +588,6 @@ vimatchbracket(UNUSED(char **args)) oth = '}'; break; case /*{*/ '}': - virangeflag = -virangeflag; dir = -1; oth = '{'; /*}*/ break; @@ -596,7 +596,6 @@ vimatchbracket(UNUSED(char **args)) oth = ')'; break; case ')': - virangeflag = -virangeflag; dir = -1; oth = '('; break; @@ -605,7 +604,6 @@ vimatchbracket(UNUSED(char **args)) oth = ']'; break; case ']': - virangeflag = -virangeflag; dir = -1; oth = '['; break; @@ -613,6 +611,8 @@ vimatchbracket(UNUSED(char **args)) INCCS(); goto otog; } + if (virangeflag && dir < 0) + INCPOS(mark); /* include starting position when going backwards */ ct = 1; while (zlecs >= 0 && zlecs < zlell && ct) { if (dir < 0) @@ -636,7 +636,7 @@ vimatchbracket(UNUSED(char **args)) int viforwardchar(char **args) { - int lim = findeol() - invicmdmode() + virangeflag; + int lim = findeol(); int n = zmult; if (n < 0) { @@ -646,6 +646,8 @@ viforwardchar(char **args) zmult = n; return ret; } + if (invicmdmode() && !virangeflag) + DECPOS(lim); if (zlecs >= lim) return 1; while (n-- && zlecs < lim) diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index e9a367668..249e38f15 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -167,6 +167,8 @@ getvirange(int wf) Thingy k2; if (visual) { + if (!zlell) + return -1; pos = mark; vilinerange = (visual == 2); region_active = 0; @@ -179,17 +181,15 @@ getvirange(int wf) if (km) selectlocalmap(km); /* Now we need to execute the movement command, to see where it * - * actually goes. virangeflag here indicates to the movement * - * function that it should place the cursor at the end of the * - * range, rather than where the cursor would actually go if it * - * were executed normally. This makes a difference to some * - * commands, but not all. For example, if searching forward * - * for a character, under normal circumstances the cursor lands * - * on the character. For a range, the range must include the * - * character, so the cursor gets placed after the character if * - * virangeflag is set. vi-match-bracket needs to change the * - * value of virangeflag under some circumstances, meaning that * - * we need to change the *starting* position. */ + * actually goes. virangeflag here indicates to the movement * + * function that it should place the cursor at the end of the * + * range, rather than where the cursor would actually go if it * + * were executed normally. This makes a difference to some * + * commands, but not all. For example, if searching forward * + * for a character, under normal circumstances the cursor lands * + * on the character. For a range, the range must include the * + * character, so the cursor gets placed after the character if * + * virangeflag is set. */ zmod.flags &= ~MOD_TMULT; do { vilinerange = 0; @@ -202,10 +202,10 @@ getvirange(int wf) return -1; } /* - * With k2 == bindk, the command key is repeated: - * a number of lines is used. If the function used - * returns 1, we fail. - */ + * With k2 == bindk, the command key is repeated: + * a number of lines is used. If the function used + * returns 1, we fail. + */ if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1)) ret = -1; if(vichgrepeat) @@ -217,8 +217,8 @@ getvirange(int wf) selectlocalmap(NULL); /* It is an error to use a non-movement command to delimit the * - * range. We here reject the case where the command modified * - * the line, or selected a different history line. */ + * range. We here reject the case where the command modified * + * the line, or selected a different history line. */ if (histline != hist1 || zlell != lastll || memcmp(zleline, lastline, zlell)) { histline = hist1; ZS_memcpy(zleline, lastline, zlell = lastll); @@ -228,21 +228,16 @@ getvirange(int wf) } /* Can't handle an empty file. Also, if the movement command * - * failed, or didn't move, it is an error. */ - if (!zlell || (zlecs == pos && mark == -1 && virangeflag != 2) || ret == -1) { + * failed, or didn't move, it is an error. */ + if (!zlell || (zlecs == pos && (mark == -1 || mark == zlecs) && + virangeflag != 2) || ret == -1) { mark = mpos; return -1; } - - /* vi-match-bracket changes the value of virangeflag when * - * moving to the opening bracket, meaning that we need to * - * change the *starting* position. */ - if (virangeflag == -1) - INCPOS(pos); virangeflag = 0; /* if the mark has moved, ignore the original cursor position * - * and use the mark. */ + * and use the mark. */ if (mark != -1) pos = mark; } @@ -883,7 +878,7 @@ vijoin(UNUSED(char **args)) } else if ((x = findeol()) == zlell || (visual && x >= mark)) return 1; - while (n) { + do { zlecs = x + 1; pos = zlecs; for (; zlecs != zlell && ZC_iblank(zleline[zlecs]); INCPOS(zlecs)) @@ -895,14 +890,13 @@ vijoin(UNUSED(char **args)) DECPOS(pos); if (ZC_iblank(zleline[pos])) { zlecs = pos; - return 0; + continue; } } spaceinline(1); zleline[zlecs] = ZWC(' '); - if ((!visual && --n < 2) || (x = findeol()) == zlell || (visual && x >= mark)) - return 0; - } + } while (!((!visual && --n < 2) || (x = findeol()) == zlell || (visual && x >= mark))); + return 0; } diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst index 8f9390250..520431193 100644 --- a/Test/X02zlevi.ztst +++ b/Test/X02zlevi.ztst @@ -317,6 +317,16 @@ >BUFFER: bhello >CURSOR: 5 + zletest $'old\C-w\evyvP' +0:yank empty selection +>BUFFER: old +>CURSOR: 2 + + zletest $'old\C-w\evdvP' +0:delete empty selection +>BUFFER: old +>CURSOR: 2 + zletest $'one\eotwo\eyykVp' 0:yank linewise and put over linewise selection at start of buffer >BUFFER: two -- cgit v1.2.3 From d067ebcacd55472f720b2765ec686a69b25c9a90 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 7 Dec 2014 16:24:19 +0000 Subject: 33876: etc.: Separate errors and keyboards interrupts Combination of 12 commits from interrupt_abort branch. Basic strategy is to introduce bits to errflag and to set and reset them separately. Remove interrupt status on return to main keymap. Turn off ERRFLAG_INT for always block. Restore bit thereafter: we probably need a new variable in order to allow user interrupts to be reset in the always block. Add TRY_BLOCK_INTERRUPT This works the same as TRY_BLOCK_ERROR, but for a SIGINT, too. Ensure propagation of SIGINT from exited job. If received by foreground job, shell uses ERRFLAG_INT, not ERRFLAG_ERROR, to set the new state. Reset errflag before precmd() Add always block in _main_completion to fix ZLS_COLORS Ensures we get the right state of $ZLS_COLORS at the end of _main_complete even if there's an interrupt. However, the "right state" is a bit messy as it depends on styles. --- ChangeLog | 20 +++++++++++-- Completion/Base/Core/_main_complete | 21 ++++++++------ Doc/Zsh/params.yo | 11 ++++++++ Src/Modules/zpty.c | 2 +- Src/Modules/zutil.c | 8 ++++-- Src/Zle/compcore.c | 2 +- Src/Zle/compctl.c | 10 +++---- Src/Zle/compresult.c | 2 +- Src/Zle/textobjects.c | 2 +- Src/Zle/zle_hist.c | 6 ++-- Src/Zle/zle_keymap.c | 10 +++++++ Src/Zle/zle_main.c | 14 ++++++---- Src/Zle/zle_misc.c | 2 +- Src/Zle/zle_tricky.c | 20 +++++++++++-- Src/Zle/zle_utils.c | 3 +- Src/builtin.c | 22 +++++++-------- Src/exec.c | 56 +++++++++++++++++++++++-------------- Src/glob.c | 12 ++++---- Src/hist.c | 10 ++++--- Src/init.c | 29 ++++++++++++++++--- Src/input.c | 3 +- Src/jobs.c | 23 +++++++++------ Src/lex.c | 5 ++-- Src/loop.c | 28 ++++++++++++++++--- Src/params.c | 13 +++++---- Src/parse.c | 31 ++++++++++---------- Src/prompt.c | 7 +++-- Src/signals.c | 28 ++++++++++++++++--- Src/subst.c | 27 ++++++++++++------ Src/utils.c | 8 +++--- Src/zsh.h | 14 ++++++++++ 31 files changed, 315 insertions(+), 134 deletions(-) (limited to 'Src/Zle/textobjects.c') diff --git a/ChangeLog b/ChangeLog index 94e28ccb2..e30324894 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2014-12-11 Peter Stephenson + + * 33876: etc.: Completion/Base/Core/_main_complete, + Doc/Zsh/params.yo, Src/Modules/zpty.c, Src/Modules/zutil.c, + Src/Zle/compcore.c, Src/Zle/compctl.c, Src/Zle/compresult.c, + Src/Zle/textobjects.c, Src/Zle/zle_hist.c, Src/Zle/zle_keymap.c, + Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c, Src/builtin.c, Src/exec.c, Src/glob.c, + Src/hist.c, Src/init.c, Src/input.c, Src/jobs.c, Src/lex.c, + Src/loop.c, Src/params.c, Src/parse.c, Src/prompt.c, + Src/signals.c, Src/subst.c, Src/utils.c, Src/zsh.h: Separate + shell errors and user interrupt flags into different bits of + errflag: ERRFLAG_ERROR and ERRFLAG_INT. Various + rationalisations to make keyboard interrupts work smoothly. + Work done on interrupt_abort branch. + 2014-12-10 Mikael Magnusson * 33948: Completion/Unix/Command/_getent, @@ -612,7 +628,7 @@ * 33354: Src/jobs.c, Test/A05execution.ztst: when backgrounding a pipeline, close all pipe descriptors in the parent; add test for both this and 33345+33346 - + 2014-10-03 Bart Schaefer * 33346: Src/parse.c: another bit of the 33345 repair @@ -2083,7 +2099,7 @@ 2013-12-20 Barton E. Schaefer * 32172; Test/A05execution.ztst: regression test for 32171 - + * 32171: Src/exec.c: fix leaked pipe descriptor that could deadlock a pipeline from a complex shell construct or function into an external command diff --git a/Completion/Base/Core/_main_complete b/Completion/Base/Core/_main_complete index bc63e83fb..d6a100777 100644 --- a/Completion/Base/Core/_main_complete +++ b/Completion/Base/Core/_main_complete @@ -43,6 +43,8 @@ local -a precommands typeset -U _lastdescr _comp_ignore _comp_colors +{ + [[ -z "$curcontext" ]] && curcontext=::: zstyle -s ":completion:${curcontext}:" insert-tab tmp || tmp=yes @@ -349,17 +351,20 @@ fi ( "$_comp_force_list" = ?* && nm -ge _comp_force_list ) ]] && compstate[list]="${compstate[list]//messages} force" -if [[ "$compstate[old_list]" = keep ]]; then - if [[ $_saved_colors_set = 1 ]]; then - ZLS_COLORS="$_saved_colors" +} always { + # Stuff we always do to clean up. + if [[ "$compstate[old_list]" = keep ]]; then + if [[ $_saved_colors_set = 1 ]]; then + ZLS_COLORS="$_saved_colors" + else + unset ZLS_COLORS + fi + elif (( $#_comp_colors )); then + ZLS_COLORS="${(j.:.)_comp_colors}" else unset ZLS_COLORS fi -elif (( $#_comp_colors )); then - ZLS_COLORS="${(j.:.)_comp_colors}" -else - unset ZLS_COLORS -fi +} # Now call the post-functions. diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 5833d6be9..391a5fb0a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -754,6 +754,17 @@ It may be reset, clearing the error condition. See ifzman(em(Complex Commands) in zmanref(zshmisc))\ ifnzman(noderef(Complex Commands)) ) +vindex(TRY_BLOCK_INTERRUPT) +item(tt(TRY_BLOCK_INTERRUPT) )( +This variable works in a similar way to tt(TRY_BLOCK_ERROR), but +represents the status of an interrupt from the signal SIGINT, which +typically comes from the keyboard when the user types tt(^C). If set to +0, any such interrupt will be reset; otherwise, the interrupt is +propagated after the tt(always) block. + +Note that it is possible that an interrupt arrives during the execution +of the tt(always) block; this interrupt is also propagated. +) vindex(TTY) item(tt(TTY))( The name of the tty associated with the shell, if any. diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 63c79a731..7b6130c6f 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -308,7 +308,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 1cca0c4b8..c89495070 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -301,7 +301,8 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval) int ef = errflag; eprog = parse_string(zjoin(vals, ' ', 1), 0); - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); if (!eprog) { @@ -394,10 +395,11 @@ evalstyle(Stypat p) unsetparam("reply"); execode(p->eval, 1, 0, "style"); if (errflag) { - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); return NULL; } - errflag = ef; + errflag = ef | (errflag & ERRFLAG_INT); queue_signals(); if ((ret = getaparam("reply"))) diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 35d410cc6..b0c6e06f8 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1671,7 +1671,7 @@ set_comp_sep(void) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 0b7a32445..d15c2d1b0 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1879,7 +1879,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) if (!m || !(m = m->next)) break; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } redup(osi, 0); dat->lst = 1; @@ -2121,7 +2121,7 @@ getreal(char *str) if (!errflag && nonempty(l) && ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) return dupstring(peekfirst(l)); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return dupstring(str); } @@ -2599,7 +2599,7 @@ makecomplistlist(Compctl cc, char *s, int incmd, int compadd) makecomplistflags(cc, s, incmd, compadd); /* Reset some information variables for the next try. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; offs = oloffs; wb = owb; we = owe; @@ -2847,7 +2847,7 @@ sep_comp_string(char *ss, char *s, int noffs) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; @@ -3725,7 +3725,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); /* Fine, now do full expansion. */ prefork(foo, 0); diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index fcceb670c..93438a053 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1092,7 +1092,7 @@ do_single(Cmatch m) noerrs = 1; parsestr(p); singsub(&p); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; } } else { diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 85d014b27..37d2c0ad9 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -275,7 +275,7 @@ selectargument(UNUSED(char **args)) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); zlemetacs = ocs; diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 9f65994dc..88623bb3c 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -853,8 +853,10 @@ pushlineoredit(char **args) free(zhline); } ret = pushline(args); - if (!isfirstln) - errflag = done = 1; + if (!isfirstln) { + errflag |= ERRFLAG_ERROR; + done = 1; + } clearlist = 1; return ret; } diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 30d25ebaa..48f210c7e 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -504,6 +504,16 @@ mod_export void selectlocalmap(Keymap m) { localkeymap = m; + if (!m) + { + /* + * No local keymap; so we are returning to the global map. If + * the user ^Ced in the local map, they probably just want to go + * back to normal editing. So remove the interrupt error + * status. + */ + errflag &= ~ERRFLAG_INT; + } } /* Reopen the currently selected keymap, in case it got deleted. This * diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index caa052b13..a2f48e13a 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -744,7 +744,7 @@ raw_getbyte(long do_keytmout, char *cptr) } if (errflag) { /* No sensible way of handling errors here */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* * Paranoia: don't run the hooks again this * time. @@ -882,7 +882,7 @@ getbyte(long do_keytmout, int *timeout) die = 0; if (!errflag && !retflag && !breaks && !exit_pending) continue; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; errno = old_errno; return lastchar = EOF; @@ -1075,7 +1075,7 @@ zlecore(void) DECCS(); handleundo(); } else { - errflag = 1; + errflag |= ERRFLAG_ERROR; break; } #ifdef HAVE_POLL @@ -1233,6 +1233,10 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zleactive = 1; resetneeded = 1; + /* + * Start of the main zle read. + * Fully reset error conditions, including user interrupt. + */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); @@ -1658,7 +1662,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func)) } if (!t || errflag) { /* error in editing */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); @@ -1778,7 +1782,7 @@ recursiveedit(UNUSED(char **args)) zrefresh(); zlecore(); - locerror = errflag; + locerror = errflag ? 1 : 0; errflag = done = eofsent = 0; return locerror; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index d432acf7b..23286fc20 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -1041,7 +1041,7 @@ copyprevshellword(UNUSED(char **args)) int sendbreak(UNUSED(char **args)) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return 1; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index b15d91c8e..864f804b7 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -829,7 +829,7 @@ docomplete(int lst) if (olst == COMP_EXPAND_COMPLETE && !strcmp(ol, zlemetaline)) { zlemetacs = ocs; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!compfunc) { char *p; @@ -877,6 +877,19 @@ docomplete(int lst) active = 0; makecommaspecial(0); + + /* + * As a special case, we reset user interrupts here. + * That's because completion is an intensive piece of + * computation that the user might want to interrupt separately + * from anything else going on. If they do, they probably + * want to keep the line edit buffer intact. + * + * There's a race here that the user might hit ^C just + * after completion exited anyway, but that's inevitable. + */ + errflag &= ~ERRFLAG_INT; + return dat[1]; } @@ -1394,7 +1407,8 @@ get_comp_string(void) } strinend(); inpop(); - errflag = lexflags = 0; + lexflags = 0; + errflag &= ~ERRFLAG_ERROR; if (parbegin != -1) { /* We are in command or process substitution if we are not in * a $((...)). */ @@ -2917,7 +2931,7 @@ getcurcmd(void) popheap(); strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; unmetafy_line(); lexrestore(); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 08a32c30e..de91182b5 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1715,7 +1715,8 @@ zlecallhook(char *name, char *arg) execzlefunc(thingy, args, 1); unrefthingy(thingy); - errflag = saverrflag; + /* Retain any user interrupt error status */ + errflag = saverrflag | (errflag & ERRFLAG_INT); retflag = savretflag; } diff --git a/Src/builtin.c b/Src/builtin.c index c2af51f2e..ad3a1925f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -422,7 +422,7 @@ execbuiltin(LinkList args, Builtin bn) argc -= argv - argarr; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 1; } @@ -3136,7 +3136,7 @@ bin_unset(char *name, char **argv, Options ops, int func) } } returnval = errflag; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } else { zerrnam(name, "%s: invalid element for unset", s); returnval = 1; @@ -4242,7 +4242,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { width = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4272,7 +4272,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { prec = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4452,7 +4452,7 @@ bin_print(char *name, char **args, Options ops, int func) zlongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zlongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zlongval) @@ -4481,7 +4481,7 @@ bin_print(char *name, char **args, Options ops, int func) } else doubleval = 0; if (errflag) { doubleval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(doubleval) @@ -4494,7 +4494,7 @@ bin_print(char *name, char **args, Options ops, int func) zulongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zulongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zulongval) @@ -4871,7 +4871,7 @@ zexit(int val, int from_where) in_exit = -1; /* * We want to do all remaining processing regardless of preceding - * errors. + * errors, even user interrupts. */ errflag = 0; @@ -5074,7 +5074,7 @@ eval(char **argv) if (fpushed) funcstack = funcstack->prev; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; @@ -6101,7 +6101,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) condlex = zshlex; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); return 1; } @@ -6278,7 +6278,7 @@ bin_let(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func)) while (*argv) val = matheval(*argv++); /* Errors in math evaluation in let are non-fatal. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* should test for fabs(val.u.d) < epsilon? */ return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0; } diff --git a/Src/exec.c b/Src/exec.c index a5f877191..6a7dbb1e1 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -59,7 +59,7 @@ mod_export int noerrs; /**/ int nohistsave; -/* error/break flag */ +/* error flag: bits from enum errflag_bits */ /**/ mod_export int errflag; @@ -1601,7 +1601,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1); list_pipe_pid = pid; list_pipe_start = bgtime; - nowait = errflag = 1; + nowait = 1; + errflag |= ERRFLAG_ERROR; breaks = loops; close(synch[1]); read_loop(synch[0], &dummy, 1); @@ -1634,7 +1635,10 @@ execpline(Estate state, wordcode slcode, int how, int last1) list_pipe_child = 1; opts[INTERACTIVE] = 0; if (errbrk_saved) { - errflag = prev_errflag; + /* + * Keep any user interrupt bit in errflag. + */ + errflag = prev_errflag | (errflag & ERRFLAG_INT); breaks = prev_breaks; } break; @@ -1719,12 +1723,14 @@ execpline2(Estate state, wordcode pcode, if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (pid) { char dummy, *text; @@ -2560,7 +2566,8 @@ execcmd(Estate state, int input, int output, int how, int last1) while (next && *next == '-' && strlen(next) >= 2) { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } uremnode(args, firstnode(args)); @@ -2577,12 +2584,14 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } if (!nextnode(firstnode(args))) { zerr("exec flag -a requires a parameter"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } exec_argv0 = (char *) @@ -2598,7 +2607,8 @@ execcmd(Estate state, int input, int output, int how, int last1) break; default: zerr("unknown exec flag -%c", *cmdopt); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } } @@ -2661,7 +2671,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] || (cflags & BINF_PREFIX)) { zerr("redirection with no command"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) { if (!args) @@ -2691,7 +2702,7 @@ execcmd(Estate state, int input, int output, int how, int last1) if (varspc) addvars(state, varspc, 0); if (errflag) - lastval = errflag; + lastval = 1; else lastval = cmdoutval; if (isset(XTRACE)) { @@ -2795,7 +2806,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } } if (!nextnode(firstnode(args))) - errflag = 1; + errflag |= ERRFLAG_ERROR; } if (type == WC_FUNCDEF) { @@ -2940,7 +2951,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto fatal; } if (pid) { @@ -3529,7 +3541,7 @@ execcmd(Estate state, int input, int output, int how, int last1) else exit(1); } - errflag = 1; + errflag |= ERRFLAG_ERROR; } } if (newxtrerr) { @@ -3759,8 +3771,10 @@ gethere(char **strp, int typ) parsestr(buf); - if (!errflag) - errflag = ef; + if (!errflag) { + /* Retain any user interrupt error */ + errflag = ef | (errflag & ERRFLAG_INT); + } } s = dupstring(buf); zfree(buf, bsiz); @@ -3854,7 +3868,7 @@ getoutput(char *cmd, int qt) return readoutput(stream, qt); } if (mpipe(pipes) < 0) { - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; return NULL; } @@ -3864,7 +3878,7 @@ getoutput(char *cmd, int qt) /* fork error */ zclose(pipes[0]); zclose(pipes[1]); - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; child_unblock(); return NULL; @@ -4274,7 +4288,7 @@ execcond(Estate state, UNUSED(int do_exec)) * into a shell error. */ if (stat == 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdpop(); if (isset(XTRACE)) { fprintf(xtrerr, " ]]\n"); @@ -4314,7 +4328,7 @@ execarith(Estate state, UNUSED(int do_exec)) fflush(xtrerr); } if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 2; } /* should test for fabs(val.u.d) < epsilon? */ @@ -4932,7 +4946,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) (name = fname)))) { zwarn("%s: function not defined by file", name); if (noreturnval) - errflag = 1; + errflag |= ERRFLAG_ERROR; else lastval = 1; goto doneshfunc; diff --git a/Src/glob.c b/Src/glob.c index b3903f2ff..82f8d626c 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -682,7 +682,7 @@ parsecomplist(char *instr) /* Now get the next path component if there is one. */ l1 = (Complist) zhalloc(sizeof *l1); if ((l1->next = parsecomplist(instr)) == NULL) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL); @@ -728,7 +728,7 @@ parsecomplist(char *instr) return (ef && !l1->next) ? NULL : l1; } } - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } @@ -1790,7 +1790,7 @@ zglob(LinkList list, LinkNode np, int nountok) insertlinknode(list, node, ostr); return; } - errflag = 0; + errflag &= ~ERRFLAG_ERROR; zerr("bad pattern: %s", ostr); return; } @@ -1873,7 +1873,8 @@ zglob(LinkList list, LinkNode np, int nountok) tmpptr->sortstrs[iexec] = tmpptr->name; } - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; } else { /* Failed, let's be safe */ @@ -3733,7 +3734,8 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str) execode(prog, 1, 0, "globqual"); ret = lastval; - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; if (!(inserts = getaparam("reply")) && diff --git a/Src/hist.c b/Src/hist.c index 7fe843a4a..a0061707c 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -287,7 +287,8 @@ ihgetc(void) c = histsubchar(c); if (c < 0) { /* bad expansion */ - errflag = lexstop = 1; + lexstop = 1; + errflag |= ERRFLAG_ERROR; return ' '; } } @@ -721,7 +722,7 @@ histsubchar(int c) noerrs = 1; parse_subst_string(sline); noerrs = one; - errflag = oef; + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(sline); untokenize(sline); } @@ -880,7 +881,8 @@ hbegin(int dohist) char *hf; isfirstln = isfirstch = 1; - errflag = histdone = 0; + errflag &= ~ERRFLAG_ERROR; + histdone = 0; if (!dohist) stophist = 2; else if (dohist != 2) @@ -3182,7 +3184,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; nocomments = onc; noerrs = ne; lexrestore(); diff --git a/Src/init.c b/Src/init.c index 655166135..305908724 100644 --- a/Src/init.c +++ b/Src/init.c @@ -118,11 +118,24 @@ loop(int toplevel, int justonce) if (interact && toplevel) { int hstop = stophist; stophist = 3; + /* + * Reset all errors including the interrupt error status + * immediately, so preprompt runs regardless of what + * just happened. We'll reset again below as a + * precaution to ensure we get back to the command line + * no matter what. + */ + errflag = 0; preprompt(); if (stophist != 3) hbegin(1); else stophist = hstop; + /* + * Reset all errors, including user interupts. + * This is what allows ^C in an interactive shell + * to return us to the command line. + */ errflag = 0; } } @@ -178,7 +191,15 @@ loop(int toplevel, int justonce) /* The only permanent storage is from getpermtext() */ zsfree(cmdstr); - errflag = 0; + /* + * Note this does *not* remove a user interrupt error + * condition, even though we're at the top level loop: + * that would be inconsistent with the case where + * we didn't execute a preexec function. This is + * an implementation detail that an interrupting user + * does't care about. + */ + errflag &= ~ERRFLAG_ERROR; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; @@ -689,7 +710,7 @@ init_term(void) { if (isset(INTERACTIVE)) zerr("can't find terminal definition for %s", term); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; termflags |= TERM_BAD; return 0; } else { @@ -1336,7 +1357,7 @@ source(char *s) if (prog) { pushheap(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; execode(prog, 1, 0, "filecode"); popheap(); if (errflag) @@ -1379,7 +1400,7 @@ source(char *s) lineno = oldlineno; /* our current lineno */ loops = oloops; /* the # of nested loops we are in */ dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!exit_pending) retflag = 0; scriptname = old_scriptname; diff --git a/Src/input.c b/Src/input.c index 4ac7e6ec8..9552331a9 100644 --- a/Src/input.c +++ b/Src/input.c @@ -291,7 +291,8 @@ inputline(void) } if (errflag) { free(ingetcline); - return lexstop = errflag = 1; + errflag |= ERRFLAG_ERROR; + return lexstop = 1; } if (isset(VERBOSE)) { /* Output the whole line read so far. */ diff --git a/Src/jobs.c b/Src/jobs.c index 6663a40a6..a668b07e6 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -509,7 +509,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } } else { @@ -526,7 +526,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } if (somestopped && jn->stat & STAT_SUPERJOB) @@ -581,7 +581,7 @@ update_job(Job jn) breaks = loops; } else { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; } check_cursh_sig(sig); } @@ -1444,12 +1444,19 @@ zwaitjob(int job, int wait_cmd) restore_queue_signals(q); return 128 + last_signal; } - /* Commenting this out makes ^C-ing a job started by a function - stop the whole function again. But I guess it will stop - something else from working properly, we have to find out - what this might be. --oberon + /* Commenting this out makes ^C-ing a job started by a function + stop the whole function again. But I guess it will stop + something else from working properly, we have to find out + what this might be. --oberon + + When attempting to separate errors and interrupts, we + assumed because of the previous comment it would be OK + to remove ERRFLAG_ERROR and leave ERRFLAG_INT set, since + that's the one related to ^C. But that doesn't work. + There's something more here we don't understand. --pws + + errflag = 0; */ - errflag = 0; */ if (subsh) { killjb(jn, SIGCONT); jn->stat &= ~STAT_STOPPED; diff --git a/Src/lex.c b/Src/lex.c index b2a05448c..4addf8033 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -385,7 +385,7 @@ lexrestore(void) ecnfunc = ln->ecnfunc; hlinesz = ln->hlinesz; toklineno = ln->toklineno; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; free(ln); unqueue_signals(); @@ -1737,7 +1737,8 @@ parse_subst_string(char *s) inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); lexrestore(); - errflag = err; + /* Keep any interrupt error status */ + errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { untokenize(s); return 1; diff --git a/Src/loop.c b/Src/loop.c index 82d2fe31a..8bb1ec9dd 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -259,7 +259,8 @@ execselect(Estate state, UNUSED(int do_exec)) 0, ZLCON_SELECT); if (errflag) str = NULL; - errflag = oef; + /* Keep any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); @@ -632,6 +633,14 @@ execcase(Estate state, int do_exec) zlong try_errflag = -1; +/** + * Corresponding interrupt error status form `try' block. + */ + +/**/ +zlong +try_interrupt = -1; + /**/ zlong try_tryflag = 0; @@ -643,7 +652,7 @@ 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; + 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); @@ -670,7 +679,10 @@ exectry(Estate state, int do_exec) /* The always clause. */ save_try_errflag = try_errflag; - try_errflag = (zlong)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; @@ -682,8 +694,16 @@ exectry(Estate state, int do_exec) state->pc = always; execlist(state, 1, do_exec); - errflag = try_errflag ? 1 : 0; + 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) diff --git a/Src/params.c b/Src/params.c index 61edc5d08..79088d162 100644 --- a/Src/params.c +++ b/Src/params.c @@ -331,6 +331,7 @@ IPDEF5("SHLVL", &shlvl, varinteger_gsu), #define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} IPDEF6("OPTIND", &zoptind, varinteger_gsu), IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), +IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt, varinteger_gsu), #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} #define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} @@ -2654,7 +2655,7 @@ assignsparam(char *s, char *val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); zsfree(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2783,7 +2784,7 @@ assignaparam(char *s, char **val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2799,7 +2800,7 @@ assignaparam(char *s, char **val, int flags) zerr("%s: attempt to set slice of associative array", v->pm->node.nam); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } v = NULL; @@ -2870,13 +2871,13 @@ sethparam(char *s, char **val) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (strchr(s, '[')) { freearray(val); zerr("nested associative arrays not yet supported"); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) @@ -2916,7 +2917,7 @@ setnparam(char *s, mnumber val) if (!isident(s)) { zerr("not an identifier: %s", s); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) diff --git a/Src/parse.c b/Src/parse.c index 4ceeb4eaf..c1709e03a 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -71,13 +71,14 @@ struct heredocs *hdocs; #define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } #define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } -#define COND_ERROR(X,Y) do { \ - zwarn(X,Y); \ - herrflush(); \ - if (noerrs != 2) \ - errflag = 1; \ - YYERROR(ecused) \ -} while(0) +#define COND_ERROR(X,Y) \ + do { \ + zwarn(X,Y); \ + herrflush(); \ + if (noerrs != 2) \ + errflag |= ERRFLAG_ERROR; \ + YYERROR(ecused) \ + } while(0) /* @@ -506,7 +507,7 @@ par_event(void) yyerror(1); herrflush(); if (noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; ecused--; return 0; } else { @@ -2339,7 +2340,7 @@ yyerror(int noerr) zwarn("parse error"); } if (!noerr && noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; } /* @@ -3031,7 +3032,7 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) file = metafy(file, flen, META_REALLOC); if (!(prog = parse_string(file, 1)) || errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); zfree(file, flen); zwarnnam(nam, "can't read file: %s", *files); @@ -3141,7 +3142,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, for (hn = shfunctab->nodes[i]; hn; hn = hn->next) if (cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3166,7 +3167,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, pattry(pprog, hn->nam) && cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3177,13 +3178,13 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, if (errflag || !(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) { zwarnnam(nam, "unknown function: %s", *names); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; } if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3192,7 +3193,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, } if (empty(progs)) { zwarnnam(nam, "no functions"); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; diff --git a/Src/prompt.c b/Src/prompt.c index 0cc9ef917..3552575f3 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -192,8 +192,11 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) if (*s == Nularg && s[1] == '\0') *s = '\0'; - /* Ignore errors and status change in prompt substitution */ - errflag = olderr; + /* + * Ignore errors and status change in prompt substitution. + * However, keep any user interrupt error that occurred. + */ + errflag = olderr | (errflag & ERRFLAG_INT); lastval = oldval; } diff --git a/Src/signals.c b/Src/signals.c index e72850516..899f1217b 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -619,7 +619,7 @@ zhandler(int sig) zexit(SIGINT, 1); if (list_pipe || chline || simple_pline) { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); check_cursh_sig(SIGINT); } @@ -640,6 +640,11 @@ zhandler(int sig) if (idle >= 0 && idle < tmout) alarm(tmout - idle); else { + /* + * We want to exit now. + * Cancel all errors, including a user interrupt + * which is now redundant. + */ errflag = noerrs = 0; zwarn("timeout"); stopmsg = 1; @@ -1267,7 +1272,18 @@ dotrapargs(int sig, int *sigtr, void *sigfn) !(isfunc && new_trap_return == 0)) { if (isfunc) { breaks = loops; - errflag = 1; + /* + * For SIGINT we behave the same as the default behaviour + * i.e. we set the error bit indicating an interrupt. + * We do this with SIGQUIT, too, even though we don't + * handle SIGQUIT by default. That's to try to make + * it behave a bit more like its normal behaviour when + * the trap handler has told us that's what it wants. + */ + if (sig == SIGINT || sig == SIGQUIT) + errflag |= ERRFLAG_INT; + else + errflag |= ERRFLAG_ERROR; } lastval = new_trap_return; /* return triggered */ @@ -1282,8 +1298,12 @@ dotrapargs(int sig, int *sigtr, void *sigfn) */ lastval = olastval; } - if (try_tryflag) - errflag = traperr; + if (try_tryflag) { + if (traperr) + errflag |= ERRFLAG_ERROR; + else + errflag &= ~ERRFLAG_ERROR; + } breaks += obreaks; /* return not triggered: restore old flag */ retflag = oretflag; diff --git a/Src/subst.c b/Src/subst.c index 61aa1c136..43932c256 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2822,7 +2822,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = parse_subst_string(s); noerrs = one; if (!quoteerr) { - errflag = oef; + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); if (haserr) shtokenize(s); } else if (haserr || errflag) { @@ -3249,8 +3250,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = 1; } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } if (haserr || errflag) return NULL; } @@ -3483,8 +3486,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) untokenize(*ap); } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -3516,8 +3521,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) noerrs = 1; haserr = parse_subst_string(val); noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -4086,7 +4093,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(copy); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(copy); untokenize(copy); } @@ -4161,7 +4169,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(*str); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(*str); untokenize(*str); } diff --git a/Src/utils.c b/Src/utils.c index ab3d3da93..893a8ca02 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -153,7 +153,7 @@ VA_DCL if (errflag || noerrs) { if (noerrs < 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } @@ -161,7 +161,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(NULL, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -181,7 +181,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(cmd, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -330,7 +330,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) num = va_arg(ap, int); if (num == EINTR) { fputs("interrupt\n", file); - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } errmsg = strerror(num); diff --git a/Src/zsh.h b/Src/zsh.h index 031deaf3f..b366e0ff4 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2623,6 +2623,20 @@ enum trap_state { #define IN_EVAL_TRAP() \ (intrap && !trapisfunc && traplocallevel == locallevel) +/* + * Bits in the errflag variable. + */ +enum errflag_bits { + /* + * Standard internal error bit. + */ + ERRFLAG_ERROR = 1, + /* + * User interrupt. + */ + ERRFLAG_INT = 2 +}; + /***********/ /* Sorting */ /***********/ -- cgit v1.2.3 From cfd91eac0732da8ece012ca4ab051d928a85c9dd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 8 Jan 2015 21:39:26 +0000 Subject: Rearrange context saving. Variables are now associated with the module that declares them, being initialised and saved/restored there. However, as many variables are used for communication between modules, many of them are set in multiple places, so the assignment is ambiguous. --- ChangeLog | 9 ++ Src/Zle/compcore.c | 4 +- Src/Zle/compctl.c | 8 +- Src/Zle/textobjects.c | 4 +- Src/Zle/zle_tricky.c | 24 ++-- Src/builtin.c | 8 +- Src/context.c | 116 ++++++++++++++++++ Src/exec.c | 8 +- Src/hist.c | 88 +++++++++++++- Src/init.c | 4 +- Src/lex.c | 321 ++++++++++---------------------------------------- Src/parse.c | 83 ++++++++++++- Src/signals.c | 4 +- Src/zsh.h | 65 ++++++++++ Src/zsh.mdd | 3 +- 15 files changed, 450 insertions(+), 299 deletions(-) create mode 100644 Src/context.c (limited to 'Src/Zle/textobjects.c') diff --git a/ChangeLog b/ChangeLog index c4ea61b41..a78425bda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2015-01-09 Peter Stephenson + + * 34189: Src/Zle/compcore.c, Src/Zle/compctl.c, + Src/Zle/textobjects.c, Src/Zle/zle_tricky.c, Src/builtin.c, + Src/context.c, Src/exec.c, Src/hist.c, Src/init.c, Src/lex.c, + Src/parse.c, Src/signals.c, Src/zsh.h, Src/zsh.mdd: + vain attempt to make context save and restore neater and + control the status variables thereby managed. + 2015-01-09 Peter Stephenson * 34182: Doc/Zsh/mod_files.yo: to add zf_* builtins you can diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index f5056058a..000f9da2a 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1524,7 +1524,7 @@ set_comp_sep(void) ol = zlemetaline; addedx = 1; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; /* * tl is the length of the temporary string including @@ -1673,7 +1673,7 @@ set_comp_sep(void) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); wb = owb; we = owe; zlemetaline = ol; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 2a80e6c84..43dd4e2a9 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2795,7 +2795,7 @@ sep_comp_string(char *ss, char *s, int noffs) * get the words we have to expand. */ addedx = 1; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; tmp = (char *) zhalloc(tl = sl + 3 + strlen(s)); strcpy(tmp, ss); @@ -2849,7 +2849,7 @@ sep_comp_string(char *ss, char *s, int noffs) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); wb = owb; we = owe; zlemetacs = ocs; @@ -3707,7 +3707,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; tmpbuf = (char *)zhalloc(strlen(cc->str) + 5); sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */ @@ -3726,7 +3726,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) strinend(); inpop(); errflag &= ~ERRFLAG_ERROR; - lexrestore(); + zcontext_restore(); /* Fine, now do full expansion. */ prefork(foo, 0); if (!errflag) { diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 37d2c0ad9..9b3277a97 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -241,7 +241,7 @@ selectargument(UNUSED(char **args)) addedx = 0; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ACTIVE; linein = zlegetline(&ll, &cs); zlemetall = ll; @@ -277,7 +277,7 @@ selectargument(UNUSED(char **args)) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); zlemetacs = ocs; wb = owb; we = owe; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 950c22f38..f18ad170e 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -698,7 +698,7 @@ docomplete(int lst) freeheap(); /* Save the lexer state, in case the completion code uses the lexer * * somewhere (e.g. when processing a compctl -s flag). */ - lexsave(); + zcontext_save(); if (inwhat == IN_ENV) lincmd = 0; if (s) { @@ -868,7 +868,7 @@ docomplete(int lst) } else ret = 1; /* Reset the lexer state, pop the heap. */ - lexrestore(); + zcontext_restore(); popheap(); dat[0] = lst; @@ -1164,7 +1164,7 @@ get_comp_string(void) varname = NULL; insubscr = 0; clwpos = -1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; inpush(dupstrspace(linptr), 0, NULL); strinbeg(0); @@ -1422,7 +1422,7 @@ get_comp_string(void) zlemetall -= parend; zlemetaline[zlemetall + addedx] = '\0'; } - lexrestore(); + zcontext_restore(); tt = NULL; goto start; } @@ -1496,12 +1496,12 @@ get_comp_string(void) if (tmp) { tmp = NULL; linptr = zlemetaline; - lexrestore(); + zcontext_restore(); addedx = 0; goto start; } noaliases = ona; - lexrestore(); + zcontext_restore(); return NULL; } @@ -2151,7 +2151,7 @@ get_comp_string(void) offs = boffs; } } - lexrestore(); + zcontext_restore(); return (char *)s; } @@ -2791,7 +2791,7 @@ doexpandhist(void) expanding = 1; excs = zlemetacs; zlemetall = zlemetacs = 0; - lexsave(); + zcontext_save(); /* We push ol as it will remain unchanged */ inpush(ol, 0, NULL); strinbeg(1); @@ -2803,7 +2803,7 @@ doexpandhist(void) } while (tok != ENDINPUT && tok != LEXERR); while (!lexstop) hgetc(); - /* We have to save errflags because it's reset in lexrestore. Since * + /* We have to save errflags because it's reset in zcontext_restore. Since * * noerrs was set to 1 errflag is true if there was a habort() which * * means that the expanded string is unusable. */ err = errflag; @@ -2811,7 +2811,7 @@ doexpandhist(void) noaliases = ona; strinend(); inpop(); - lexrestore(); + zcontext_restore(); expanding = 0; if (!err) { @@ -2910,7 +2910,7 @@ getcurcmd(void) int curlincmd; char *s = NULL; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; metafy_line(); inpush(dupstrspace(zlemetaline), 0, NULL); @@ -2934,7 +2934,7 @@ getcurcmd(void) inpop(); errflag &= ~ERRFLAG_ERROR; unmetafy_line(); - lexrestore(); + zcontext_restore(); return s; } diff --git a/Src/builtin.c b/Src/builtin.c index d2108264f..8abe728db 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -6102,7 +6102,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) } } - lexsave(); + zcontext_save(); testargs = argv; tok = NULLTOK; condlex = testlex; @@ -6112,16 +6112,16 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) if (errflag) { errflag &= ~ERRFLAG_ERROR; - lexrestore(); + zcontext_restore(); return 1; } if (!prog || tok == LEXERR) { zwarnnam(name, tokstr ? "parse error" : "argument expected"); - lexrestore(); + zcontext_restore(); return 1; } - lexrestore(); + zcontext_restore(); if (*curtestarg) { zwarnnam(name, "too many arguments"); diff --git a/Src/context.c b/Src/context.c new file mode 100644 index 000000000..bd8d191bf --- /dev/null +++ b/Src/context.c @@ -0,0 +1,116 @@ +/* + * context.c - context save and restore + * + * 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. + * + */ +/* + * This short file provides a home for the stack of saved contexts. + * The actions for saving and restoring are encapsulated within + * individual modules. + */ + +#include "zsh.mdh" +#include "context.pro" + +struct context_stack { + struct context_stack *next; + + struct hist_stack hist_stack; + struct lex_stack lex_stack; + struct parse_stack parse_stack; +}; + +static struct context_stack *cstack; + +/* save some or all of current context */ + +/**/ +mod_export void +zcontext_save_partial(int parts) +{ + struct context_stack *cs; + + cs = (struct context_stack *)malloc(sizeof(struct context_stack)); + + if (parts & ZCONTEXT_HIST) { + hist_context_save(&cs->hist_stack, !cstack); + } + if (parts & ZCONTEXT_LEX) { + lex_context_save(&cs->lex_stack, !cstack); + } + if (parts & ZCONTEXT_PARSE) { + parse_context_save(&cs->parse_stack, !cstack); + } + + cs->next = cstack; + cstack = cs; +} + +/* save context in full */ + +/**/ +mod_export void +zcontext_save(void) +{ + zcontext_save_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); +} + +/* restore context or part thereof */ + +/**/ +mod_export void +zcontext_restore_partial(int parts) +{ + struct context_stack *cs = cstack; + + DPUTS(!cstack, "BUG: zcontext_restore() without zcontext_save()"); + + queue_signals(); + cstack = cstack->next; + + if (parts & ZCONTEXT_HIST) { + hist_context_restore(&cs->hist_stack, !cstack); + } + if (parts & ZCONTEXT_LEX) { + lex_context_restore(&cs->lex_stack, !cstack); + } + if (parts & ZCONTEXT_PARSE) { + parse_context_restore(&cs->parse_stack, !cstack); + } + + free(cs); + + unqueue_signals(); +} + +/* restore full context */ + +/**/ +mod_export void +zcontext_restore(void) +{ + zcontext_restore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); +} diff --git a/Src/exec.c b/Src/exec.c index ab9291024..7b6495113 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -217,7 +217,7 @@ parse_string(char *s, int reset_lineno) Eprog p; zlong oldlineno; - lexsave(); + zcontext_save(); inpush(s, INP_LINENO, NULL); strinbeg(0); oldlineno = lineno; @@ -229,7 +229,7 @@ parse_string(char *s, int reset_lineno) lastval = 1; strinend(); inpop(); - lexrestore(); + zcontext_restore(); return p; } @@ -3349,9 +3349,9 @@ execcmd(Estate state, int input, int output, int how, int last1) * The copy uses the wordcode parsing area, so save and * restore state. */ - lexsave(); + zcontext_save(); redir_prog = eccopyredirs(&s); - lexrestore(); + zcontext_restore(); } else redir_prog = NULL; diff --git a/Src/hist.c b/Src/hist.c index e65d78bfd..447f00e84 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -222,6 +222,85 @@ static int histsave_stack_pos = 0; static zlong histfile_linect; +/* save history context */ + +/**/ +void +hist_context_save(struct hist_stack *hs, int toplevel) +{ + if (toplevel) { + /* top level, make this version visible to ZLE */ + zle_chline = chline; + /* ensure line stored is NULL-terminated */ + if (hptr) + *hptr = '\0'; + } + hs->histactive = histactive; + hs->histdone = histdone; + hs->stophist = stophist; + hs->hline = chline; + hs->hptr = hptr; + hs->chwords = chwords; + hs->chwordlen = chwordlen; + hs->chwordpos = chwordpos; + hs->hwgetword = hwgetword; + hs->hgetc = hgetc; + hs->hungetc = hungetc; + hs->hwaddc = hwaddc; + hs->hwbegin = hwbegin; + hs->hwend = hwend; + hs->addtoline = addtoline; + hs->hlinesz = hlinesz; + /* + * We save and restore the command stack with history + * as it's visible to the user interactively, so if + * we're preserving history state we'll continue to + * show the current set of commands from input. + */ + hs->cstack = cmdstack; + hs->csp = cmdsp; + + stophist = 0; + chline = NULL; + hptr = NULL; + histactive = 0; + cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); + cmdsp = 0; +} + +/**/ +void +hist_context_restore(const struct hist_stack *hs, int toplevel) +{ + if (toplevel) { + /* Back to top level: don't need special ZLE value */ + DPUTS(hs->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); + zle_chline = NULL; + } + histactive = hs->histactive; + histdone = hs->histdone; + stophist = hs->stophist; + chline = hs->hline; + hptr = hs->hptr; + chwords = hs->chwords; + chwordlen = hs->chwordlen; + chwordpos = hs->chwordpos; + hwgetword = hs->hwgetword; + hgetc = hs->hgetc; + hungetc = hs->hungetc; + hwaddc = hs->hwaddc; + hwbegin = hs->hwbegin; + hwend = hs->hwend; + addtoline = hs->addtoline; + hlinesz = hs->hlinesz; + if (cmdstack) + zfree(cmdstack, CMDSTACKSZ); + cmdstack = hs->cstack; + cmdsp = hs->csp; +} + +/* restore history context */ + /* add a character to the current history word */ static void @@ -815,6 +894,11 @@ strinbeg(int dohist) strin++; hbegin(dohist); lexinit(); + /* + * Also initialise some variables owned by the parser but + * used for communication between the parser and lexer. + */ + init_parse_status(); } /* done reading a string */ @@ -2992,7 +3076,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) opts[RCQUOTES] = 0; addedx = 0; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = flags | LEXFLAGS_ACTIVE; /* * Are we handling comments? @@ -3189,7 +3273,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) errflag &= ~ERRFLAG_ERROR; nocomments = onc; noerrs = ne; - lexrestore(); + zcontext_restore(); zlemetacs = ocs; zlemetall = oll; wb = owb; diff --git a/Src/init.c b/Src/init.c index 080fc8561..e7d86feac 100644 --- a/Src/init.c +++ b/Src/init.c @@ -107,7 +107,7 @@ loop(int toplevel, int justonce) pushheap(); if (!toplevel) - lexsave(); + zcontext_save(); for (;;) { freeheap(); if (stophist == 3) /* re-entry via preprompt() */ @@ -227,7 +227,7 @@ loop(int toplevel, int justonce) } err = errflag; if (!toplevel) - lexrestore(); + zcontext_restore(); popheap(); if (err) diff --git a/Src/lex.c b/Src/lex.c index d440f3d70..69441b28d 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -203,263 +203,64 @@ 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; - int lex_add_raw; - char *tokstr_raw; - char *bptr_raw; - int bsiz_raw; - int len_raw; - 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; - -/* save the context or parts thereof */ - -/* is this a hack or what? */ +/* save lexical context */ /**/ -mod_export void -lexsave_partial(int parts) -{ - struct lexstack *ls; - - ls = (struct lexstack *)malloc(sizeof(struct lexstack)); - - if (parts & ZCONTEXT_LEX) { - ls->incmdpos = incmdpos; - ls->incond = incond; - ls->incasepat = incasepat; - ls->dbparens = dbparens; - ls->isfirstln = isfirstln; - ls->isfirstch = isfirstch; - ls->lexflags = lexflags; - - ls->tok = tok; - ls->isnewlin = isnewlin; - ls->tokstr = tokstr; - ls->zshlextext = zshlextext; - ls->bptr = bptr; - ls->bsiz = bsiz; - ls->len = len; - ls->lex_add_raw = lex_add_raw; - ls->tokstr_raw = tokstr_raw; - ls->bptr_raw = bptr_raw; - ls->bsiz_raw = bsiz_raw; - ls->len_raw = len_raw; - ls->lexstop = lexstop; - ls->toklineno = toklineno; - - tokstr = zshlextext = bptr = NULL; - bsiz = 256; - tokstr_raw = bptr_raw = NULL; - bsiz_raw = len_raw = lex_add_raw = 0; - - inredir = 0; - } - if (parts & ZCONTEXT_HIST) { - if (!lstack) { - /* top level, make this version visible to ZLE */ - zle_chline = chline; - /* ensure line stored is NULL-terminated */ - if (hptr) - *hptr = '\0'; - } - ls->histactive = histactive; - ls->histdone = histdone; - ls->stophist = stophist; - ls->hline = chline; - ls->hptr = hptr; - ls->chwords = chwords; - ls->chwordlen = chwordlen; - ls->chwordpos = chwordpos; - ls->hwgetword = hwgetword; - ls->hgetc = hgetc; - ls->hungetc = hungetc; - ls->hwaddc = hwaddc; - ls->hwbegin = hwbegin; - ls->hwend = hwend; - ls->addtoline = addtoline; - ls->hlinesz = hlinesz; - /* - * We save and restore the command stack with history - * as it's visible to the user interactively, so if - * we're preserving history state we'll continue to - * show the current set of commands from input. - */ - ls->cstack = cmdstack; - ls->csp = cmdsp; - - stophist = 0; - chline = NULL; - hptr = NULL; - histactive = 0; - cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); - cmdsp = 0; - } - if (parts & ZCONTEXT_PARSE) { - ls->hdocs = hdocs; - ls->eclen = eclen; - ls->ecused = ecused; - ls->ecnpats = ecnpats; - ls->ecbuf = ecbuf; - ls->ecstrs = ecstrs; - ls->ecsoffs = ecsoffs; - ls->ecssub = ecssub; - ls->ecnfunc = ecnfunc; - ecbuf = NULL; - hdocs = NULL; - } - - ls->next = lstack; - lstack = ls; -} - -/* save context in full */ - -/**/ -mod_export void -lexsave(void) -{ - lexsave_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); -} - -/* restore context or part therefore */ - -/**/ -mod_export void -lexrestore_partial(int parts) +void +lex_context_save(struct lex_stack *ls, int toplevel) { - struct lexstack *ln = lstack; - - DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); - - queue_signals(); - lstack = lstack->next; - - if (parts & ZCONTEXT_LEX) { - incmdpos = ln->incmdpos; - incond = ln->incond; - incasepat = ln->incasepat; - dbparens = ln->dbparens; - isfirstln = ln->isfirstln; - isfirstch = ln->isfirstch; - lexflags = ln->lexflags; - tok = ln->tok; - isnewlin = ln->isnewlin; - tokstr = ln->tokstr; - zshlextext = ln->zshlextext; - bptr = ln->bptr; - bsiz = ln->bsiz; - len = ln->len; - lex_add_raw = ln->lex_add_raw; - tokstr_raw = ln->tokstr_raw; - bptr_raw = ln->bptr_raw; - bsiz_raw = ln->bsiz_raw; - len_raw = ln->len_raw; - lexstop = ln->lexstop; - toklineno = ln->toklineno; - } - - if (parts & ZCONTEXT_HIST) { - 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; - } - histactive = ln->histactive; - histdone = ln->histdone; - stophist = ln->stophist; - chline = ln->hline; - hptr = ln->hptr; - chwords = ln->chwords; - chwordlen = ln->chwordlen; - chwordpos = ln->chwordpos; - hwgetword = ln->hwgetword; - hgetc = ln->hgetc; - hungetc = ln->hungetc; - hwaddc = ln->hwaddc; - hwbegin = ln->hwbegin; - hwend = ln->hwend; - addtoline = ln->addtoline; - hlinesz = ln->hlinesz; - if (cmdstack) - zfree(cmdstack, CMDSTACKSZ); - cmdstack = ln->cstack; - cmdsp = ln->csp; - } - - if (parts & ZCONTEXT_PARSE) { - if (ecbuf) - zfree(ecbuf, eclen); - - hdocs = ln->hdocs; - eclen = ln->eclen; - ecused = ln->ecused; - ecnpats = ln->ecnpats; - ecbuf = ln->ecbuf; - ecstrs = ln->ecstrs; - ecsoffs = ln->ecsoffs; - ecssub = ln->ecssub; - ecnfunc = ln->ecnfunc; - - errflag &= ~ERRFLAG_ERROR; - } - - free(ln); - - unqueue_signals(); + (void)toplevel; + + ls->dbparens = dbparens; + ls->isfirstln = isfirstln; + ls->isfirstch = isfirstch; + ls->lexflags = lexflags; + + ls->tok = tok; + ls->tokstr = tokstr; + ls->zshlextext = zshlextext; + ls->bptr = bptr; + ls->bsiz = bsiz; + ls->len = len; + ls->lex_add_raw = lex_add_raw; + ls->tokstr_raw = tokstr_raw; + ls->bptr_raw = bptr_raw; + ls->bsiz_raw = bsiz_raw; + ls->len_raw = len_raw; + ls->lexstop = lexstop; + ls->toklineno = toklineno; + + tokstr = zshlextext = bptr = NULL; + bsiz = 256; + tokstr_raw = bptr_raw = NULL; + bsiz_raw = len_raw = lex_add_raw = 0; } -/* complete restore context */ +/* restore lexical context */ /**/ mod_export void -lexrestore(void) +lex_context_restore(const struct lex_stack *ls, int toplevel) { - lexrestore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); + (void)toplevel; + + dbparens = ls->dbparens; + isfirstln = ls->isfirstln; + isfirstch = ls->isfirstch; + lexflags = ls->lexflags; + tok = ls->tok; + tokstr = ls->tokstr; + zshlextext = ls->zshlextext; + bptr = ls->bptr; + bsiz = ls->bsiz; + len = ls->len; + lex_add_raw = ls->lex_add_raw; + tokstr_raw = ls->tokstr_raw; + bptr_raw = ls->bptr_raw; + bsiz_raw = ls->bsiz_raw; + len_raw = ls->len_raw; + lexstop = ls->lexstop; + toklineno = ls->toklineno; } /**/ @@ -634,9 +435,7 @@ initlextabs(void) void lexinit(void) { - incond = incasepat = nocorrect = - infor = dbparens = lexstop = 0; - incmdpos = 1; + nocorrect = dbparens = lexstop = 0; tok = ENDINPUT; } @@ -1725,7 +1524,7 @@ parsestrnoerr(char *s) { int l = strlen(s), err; - lexsave(); + zcontext_save(); untokenize(s); inpush(dupstring(s), 0, NULL); strinbeg(0); @@ -1737,7 +1536,7 @@ parsestrnoerr(char *s) strinend(); inpop(); DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return err; } @@ -1756,7 +1555,7 @@ 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); @@ -1776,7 +1575,7 @@ parse_subscript(char *s, int sub, int endchar) strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subscript: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return s; } @@ -1794,7 +1593,7 @@ parse_subst_string(char *s) if (!*s || !strcmp(s, nulstring)) return 0; - lexsave(); + zcontext_save(); untokenize(s); inpush(dupstring(s), 0, NULL); strinbeg(0); @@ -1807,7 +1606,7 @@ parse_subst_string(char *s) strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); - lexrestore(); + zcontext_restore(); /* Keep any interrupt error status */ errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { @@ -1817,7 +1616,7 @@ parse_subst_string(char *s) #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 + * before zcontext_restore()) == l, but that's not necessarily the case if * we stripped an RCQUOTE. */ if (ctok != STRING || (errflag && !noerrs)) { @@ -2047,7 +1846,7 @@ skipcomm(void) new_len = len; new_bsiz = bsiz; - lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); } else { /* * Set up for nested command subsitution, however @@ -2063,7 +1862,7 @@ skipcomm(void) new_len = len_raw; new_bsiz = bsiz_raw; - lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); } tokstr_raw = new_tokstr; bsiz_raw = new_bsiz; @@ -2090,7 +1889,7 @@ skipcomm(void) */ new_lexstop = lexstop; - lexrestore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_restore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); if (lex_add_raw) { /* diff --git a/Src/parse.c b/Src/parse.c index fa37ca3d9..0b54a904d 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -31,7 +31,7 @@ #include "parse.pro" /* != 0 if we are about to read a command word */ - + /**/ mod_export int incmdpos; @@ -242,6 +242,67 @@ int ecsoffs, ecssub, ecnfunc; #define EC_DOUBLE_THRESHOLD 32768 #define EC_INCREMENT 1024 +/* save parse context */ + +/**/ +void +parse_context_save(struct parse_stack *ps, int toplevel) +{ + (void)toplevel; + + ps->incmdpos = incmdpos; + ps->aliasspaceflag = aliasspaceflag; + ps->incond = incond; + ps->inredir = inredir; + ps->incasepat = incasepat; + ps->isnewlin = isnewlin; + ps->infor = infor; + + ps->hdocs = hdocs; + ps->eclen = eclen; + ps->ecused = ecused; + ps->ecnpats = ecnpats; + ps->ecbuf = ecbuf; + ps->ecstrs = ecstrs; + ps->ecsoffs = ecsoffs; + ps->ecssub = ecssub; + ps->ecnfunc = ecnfunc; + ecbuf = NULL; + hdocs = NULL; +} + +/* restore parse context */ + +/**/ +void +parse_context_restore(const struct parse_stack *ps, int toplevel) +{ + (void)toplevel; + + if (ecbuf) + zfree(ecbuf, eclen); + + incmdpos = ps->incmdpos; + aliasspaceflag = ps->aliasspaceflag; + incond = ps->incond; + inredir = ps->inredir; + incasepat = ps->incasepat; + incasepat = ps->incasepat; + isnewlin = ps->isnewlin; + infor = ps->infor; + + hdocs = ps->hdocs; + eclen = ps->eclen; + ecused = ps->ecused; + ecnpats = ps->ecnpats; + ecbuf = ps->ecbuf; + ecstrs = ps->ecstrs; + ecsoffs = ps->ecsoffs; + ecssub = ps->ecssub; + ecnfunc = ps->ecnfunc; + + errflag &= ~ERRFLAG_ERROR; +} /* Adjust pointers in here-doc structs. */ @@ -359,6 +420,21 @@ ecstrcode(char *s) } while (0) +/**/ +mod_export void +init_parse_status(void) +{ + /* + * These variables are currently declared by the parser, so we + * initialise them here. Possibly they are more naturally declared + * by the lexical anaylser; however, as they are used for signalling + * between the two it's a bit ambiguous. We clear them when + * using the lexical analyser for strings as well as here. + */ + incasepat = incond = inredir = infor = 0; + incmdpos = 1; +} + /* Initialise wordcode buffer. */ /**/ @@ -373,6 +449,8 @@ init_parse(void) ecsoffs = ecnpats = 0; ecssub = 0; ecnfunc = 0; + + init_parse_status(); } /* Build eprog. */ @@ -539,9 +617,8 @@ parse_list(void) int c = 0; tok = ENDINPUT; - incmdpos = 1; - zshlex(); init_parse(); + zshlex(); par_list(&c); if (tok != ENDINPUT) { clear_hdocs(); diff --git a/Src/signals.c b/Src/signals.c index 899f1217b..3950ad1a2 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1210,7 +1210,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) intrap++; *sigtr |= ZSIG_IGNORED; - lexsave(); + zcontext_save(); /* execsave will save the old trap_return and trap_state */ execsave(); breaks = retflag = 0; @@ -1265,7 +1265,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) new_trap_return = trap_return; execrestore(); - lexrestore(); + zcontext_restore(); if (new_trap_state == TRAP_STATE_FORCE_RETURN && /* zero return from function isn't special */ diff --git a/Src/zsh.h b/Src/zsh.h index 475b7824f..8fb4f977a 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2691,6 +2691,71 @@ struct sortelt { typedef struct sortelt *SortElt; +/*********************************************************/ +/* Structures to save and restore for individual modules */ +/*********************************************************/ + +/* History */ +struct hist_stack { + int histactive; + int histdone; + int stophist; + int hlinesz; + char *hline; + char *hptr; + short *chwords; + int chwordlen; + int chwordpos; + int hwgetword; + int (*hgetc) _((void)); + void (*hungetc) _((int)); + void (*hwaddc) _((int)); + void (*hwbegin) _((int)); + void (*hwend) _((void)); + void (*addtoline) _((int)); + unsigned char *cstack; + int csp; +}; + +/* Lexical analyser */ +struct lex_stack { + int dbparens; + int isfirstln; + int isfirstch; + int lexflags; + enum lextok tok; + char *tokstr; + char *zshlextext; + char *bptr; + int bsiz; + int len; + int lex_add_raw; + char *tokstr_raw; + char *bptr_raw; + int bsiz_raw; + int len_raw; + int lexstop; + zlong toklineno; +}; + +/* Parser */ +struct parse_stack { + struct heredocs *hdocs; + + int incmdpos; + int aliasspaceflag; + int incond; + int inredir; + int incasepat; + int isnewlin; + int infor; + + int eclen, ecused, ecnpats; + Wordcode ecbuf; + Eccstr ecstrs; + int ecsoffs, ecssub, ecnfunc; +}; + /************************/ /* Flags to casemodifiy */ /************************/ diff --git a/Src/zsh.mdd b/Src/zsh.mdd index 9a8c923f9..f0379d2d1 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -9,7 +9,8 @@ alwayslink=1 # autobins not specified because of alwayslink -objects="builtin.o compat.o cond.o exec.o glob.o hashtable.o hashnameddir.o \ +objects="builtin.o compat.o cond.o context.o \ +exec.o glob.o hashtable.o hashnameddir.o \ hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \ mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \ signames.o sort.o string.o subst.o text.o utils.o watch.o" -- cgit v1.2.3