From c01a178ece6740f719fef81ecdf9283b5c8b71d5 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 13 Nov 2014 19:44:01 +0000 Subject: Marc Finet: problems with working directory rationalisation. Ensure the length of the directory is kept up to date. Abort following symlinks as soon as there's an error. --- Src/utils.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/Src/utils.c b/Src/utils.c index e6eb8e6a7..c6e7aed35 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -727,7 +727,7 @@ xsymlinks(char *s) zulong xbuflen = strlen(xbuf); opp = pp = slashsplit(s); - for (; xbuflen < sizeof(xbuf) && *pp; pp++) { + for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) { if (!strcmp(*pp, ".")) continue; if (!strcmp(*pp, "..")) { @@ -762,9 +762,13 @@ xsymlinks(char *s) strcpy(xbuf, ""); if (xsymlinks(xbuf3 + 1) < 0) ret = -1; + else + xbuflen = strlen(xbuf); } else if (xsymlinks(xbuf3) < 0) ret = -1; + else + xbuflen = strlen(xbuf); } } freearray(opp); -- cgit v1.2.3 From a8927bf27b57a1f49d525f628a97de9c1fce710b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 26 Nov 2014 17:26:58 +0000 Subject: 33793: add 0b binary interpretation to integer constants --- ChangeLog | 5 +++++ Doc/Zsh/arith.yo | 3 ++- Src/math.c | 6 ++++-- Src/utils.c | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 834537d64..7b56eca4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-11-26 Peter Stephenson + + * 33793: Src/math.c, Src/utils.c, Doc/Zsh/arith.yo: Arithmetic + constants beginning 0b specify binary. + 2014-11-25 Oliver Kiddle * Jun T: 33769: Test/comptest: workaround for KEYTIMEOUT to diff --git a/Doc/Zsh/arith.yo b/Doc/Zsh/arith.yo index 96dc2dc68..a620b73d1 100644 --- a/Doc/Zsh/arith.yo +++ b/Doc/Zsh/arith.yo @@ -39,7 +39,8 @@ zero status. cindex(arithmetic base) cindex(bases, in arithmetic) Integers can be in bases other than 10. -A leading `tt(0x)' or `tt(0X)' denotes hexadecimal. +A leading `tt(0x)' or `tt(0X)' denotes hexadecimal and a leading +`tt(0b)' or `tt(0B) binary. Integers may also be of the form `var(base)tt(#)var(n)', where var(base) is a decimal number between two and thirty-six representing the arithmetic base and var(n) diff --git a/Src/math.c b/Src/math.c index 266569827..438a17089 100644 --- a/Src/math.c +++ b/Src/math.c @@ -449,12 +449,14 @@ lexconstant(void) nptr++; if (*nptr == '0') { + int lowchar; nptr++; - if (*nptr == 'x' || *nptr == 'X') { + lowchar = tolower(*nptr); + if (lowchar == 'x' || lowchar == 'b') { /* Let zstrtol parse number with base */ yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1); /* Should we set lastbase here? */ - lastbase = 16; + lastbase = (lowchar == 'b') ? 2 : 16; if (isset(FORCEFLOAT)) { yyval.type = MN_FLOAT; diff --git a/Src/utils.c b/Src/utils.c index c6e7aed35..5f0c1062b 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2082,6 +2082,8 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore) base = 10; else if (*++s == 'x' || *s == 'X') base = 16, s++; + else if (*s == 'b' || *s == 'B') + base = 2, s++; else base = 8; } -- cgit v1.2.3 From 0d4b548d1e4a08105597791fd6308d7fd70d3ddf Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sun, 30 Nov 2014 23:19:55 +0100 Subject: 33818: fix types passed to sizeof detected by coverity as being wrong --- ChangeLog | 6 ++++++ Src/Builtins/sched.c | 2 +- Src/Zle/complist.c | 4 ++-- Src/exec.c | 4 ++-- Src/sort.c | 2 +- Src/utils.c | 6 +++--- 6 files changed, 15 insertions(+), 9 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 2a308a37e..fed76e508 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2014-11-30 Oliver Kiddle + + * 33818: Src/Builtins/sched.c, Src/Zle/complist.c, + Src/exec.c, Src/sort.c, Src/utils.c: fix types passed to sizeof + detected by coverity as being wrong + 2014-11-28 Barton E. Schaefer * 33819: Test/A06assign.ztst: regression tests for 33816 diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index c1cc98354..bcf7661f4 100644 --- a/Src/Builtins/sched.c +++ b/Src/Builtins/sched.c @@ -346,7 +346,7 @@ schedgetfn(UNUSED(Param pm)) for (i = 0, sch = schedcmds; sch; sch = sch->next, i++) ; - aptr = ret = zhalloc(sizeof(char **) * (i+1)); + aptr = ret = zhalloc(sizeof(char *) * (i+1)); for (sch = schedcmds; sch; sch = sch->next, aptr++) { char tbuf[40], *flagstr; time_t t; diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 2e1a5273c..c129940f7 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -2059,8 +2059,8 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) i = zterm_columns * listdat.nlines; free(mtab); - mtab = (Cmatch **) zalloc(i * sizeof(Cmatch **)); - memset(mtab, 0, i * sizeof(Cmatch **)); + mtab = (Cmatch **) zalloc(i * sizeof(Cmatch *)); + memset(mtab, 0, i * sizeof(Cmatch *)); free(mgtab); mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup)); #ifdef DEBUG diff --git a/Src/exec.c b/Src/exec.c index 2b7c55f8f..a5f877191 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2299,13 +2299,13 @@ addvars(Estate state, Wordcode pc, int addflags) continue; } if (vl) { - ptr = arr = (char **) zalloc(sizeof(char **) * + ptr = arr = (char **) zalloc(sizeof(char *) * (countlinknodes(vl) + 1)); while (nonempty(vl)) *ptr++ = ztrdup((char *) ugetnode(vl)); } else - ptr = arr = (char **) zalloc(sizeof(char **)); + ptr = arr = (char **) zalloc(sizeof(char *)); *ptr = NULL; if (xtr) { diff --git a/Src/sort.c b/Src/sort.c index 3d00bb576..92ee1c0d4 100644 --- a/Src/sort.c +++ b/Src/sort.c @@ -368,7 +368,7 @@ strmetasort(char **array, int sortwhat, int *unmetalenp) sortdir = (sortwhat & SORTIT_BACKWARDS) ? -1 : 1; sortnumeric = (sortwhat & SORTIT_NUMERICALLY) ? 1 : 0; - qsort(sortptrarr, nsort, sizeof(SortElt *), eltpcmp); + qsort(sortptrarr, nsort, sizeof(SortElt), eltpcmp); sortnumeric = oldsortnumeric; sortdir = oldsortdir; diff --git a/Src/utils.c b/Src/utils.c index 5f0c1062b..926814759 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -693,12 +693,12 @@ slashsplit(char *s) int t0; if (!*s) - return (char **) zshcalloc(sizeof(char **)); + return (char **) zshcalloc(sizeof(char *)); for (t = s, t0 = 0; *t; t++) if (*t == '/') t0++; - q = r = (char **) zalloc(sizeof(char **) * (t0 + 2)); + q = r = (char **) zalloc(sizeof(char *) * (t0 + 2)); while ((t = strchr(s, '/'))) { *q++ = ztrduppfx(s, t - s); @@ -2955,7 +2955,7 @@ colonsplit(char *s, int uniq) for (t = s, ct = 0; *t; t++) /* count number of colons */ if (*t == ':') ct++; - ptr = ret = (char **) zalloc(sizeof(char **) * (ct + 2)); + ptr = ret = (char **) zalloc(sizeof(char *) * (ct + 2)); t = s; do { -- cgit v1.2.3 From 48cd1b6c3b51a7bc6d45d4aeb7ff8c55d97a6f2a Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 7 Dec 2014 11:06:07 -0800 Subject: 33894: boundary conditions in unmeta(), unmetafy() Check that we aren't running off the end of the string when converting the next byte after a Meta byte. This is just defensive programming in case of bad metafied strings coming through from gettokstr(), some repairs there are likely still needed. --- ChangeLog | 4 ++++ Src/utils.c | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index eec56154d..25a7ce278 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2014-12-07 Barton E. Schaefer + + * 33894: Src/utils.c: boundary conditions in unmeta(), unmetafy() + 2014-12-07 Peter Stephenson * Daniel Shahaf: 33883: Doc/Zsh/expn.yo, diff --git a/Src/utils.c b/Src/utils.c index 926814759..5c90638a2 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4164,7 +4164,7 @@ unmetafy(char *s, int *len) for (p = s; *p && *p != Meta; p++); for (t = p; (*t = *p++);) - if (*t++ == Meta) + if (*t++ == Meta && *p) t[-1] = *p++ ^ 32; if (len) *len = t - s; @@ -4208,8 +4208,10 @@ unmeta(const char *file_name) meta = 0; for (t = file_name; *t; t++) { - if (*t == Meta) - meta = 1; + if (*t == Meta) { + meta = t[1]; + break; + } } if (!meta) { /* -- cgit v1.2.3 From 0a07ffd47cb5000ff32d5fc5905e7d3e87603d16 Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Tue, 9 Dec 2014 02:41:01 +0900 Subject: 33932: revise boundary check in unmeta() --- ChangeLog | 4 ++++ Src/utils.c | 8 +++----- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index b8af2130c..5ce58d8e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2014-12-09 Jun-ichi Takimoto + + * 33932: Src/utils.c: revise boundary check in unmeta() + 2014-12-08 Oliver Kiddle * 33924: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list, Src/Zle/zle.h, diff --git a/Src/utils.c b/Src/utils.c index 5c90638a2..ab3d3da93 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4208,10 +4208,8 @@ unmeta(const char *file_name) meta = 0; for (t = file_name; *t; t++) { - if (*t == Meta) { - meta = t[1]; - break; - } + if (*t == Meta) + meta = 1; } if (!meta) { /* @@ -4250,7 +4248,7 @@ unmeta(const char *file_name) } for (t = file_name, p = fn; *t; p++) - if ((*p = *t++) == Meta) + if ((*p = *t++) == Meta && *t) *p = *t++ ^ 32; *p = '\0'; return fn; -- 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/utils.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 33d1439fdbf56ec100dbddfa9f7472a0da59d183 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 2 Jan 2015 21:32:51 +0000 Subject: users/19667: whence -S shows intermediate steps in symlink expansion --- ChangeLog | 3 +++ Doc/Zsh/builtins.yo | 9 +++++-- Src/builtin.c | 12 +++++----- Src/utils.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 15 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 4e125d1de..ac957d1df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-02 Peter Stephenson + * users/19667: Doc/Zsh/builtins.yo, Src/builtin.c, Src/utils.c: + whence -S shows intermediate steps in symlink expansion. + * 34077: Test/A07control.ztst: add some further tests for return status from "for" loops. diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 38788d3c4..b4f4b6742 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1667,7 +1667,7 @@ See also the shell variable tt(STTY) for a means of initialising the tty before running external commands. ) findex(type) -item(tt(type) [ tt(-wfpams) ] var(name) ...)( +item(tt(type) [ tt(-wfpamsS) ] var(name) ...)( Equivalent to tt(whence -v). ) findex(typeset) @@ -2083,7 +2083,7 @@ the user is potentially interested in both, so this problem is intrinsic to process IDs. ) findex(whence) -item(tt(whence) [ tt(-vcwfpams) ] var(name) ...)( +item(tt(whence) [ tt(-vcwfpamsS) ] var(name) ...)( For each name, indicate how it would be interpreted if used as a command name. @@ -2126,6 +2126,11 @@ of these patterns. item(tt(-s))( If a pathname contains symlinks, print the symlink-free pathname as well. ) +item(tt(-S))( +As tt(-s), but if the pathname had to be resolved by following +multiple symlinks, the intermediate steps are printed, too. The +symlink resolved at each step might be anywhere in the path. +) enditem() ) findex(where) diff --git a/Src/builtin.c b/Src/builtin.c index 264169cb4..47d1aa06d 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -119,7 +119,7 @@ static struct builtin builtins[] = BUILTIN("times", BINF_PSPECIAL, bin_times, 0, 0, 0, NULL, NULL), BUILTIN("trap", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_trap, 0, -1, 0, NULL, NULL), BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), - BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), + BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsSw", "v"), BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klprtuxmz", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "ms", "a"), @@ -128,7 +128,7 @@ static struct builtin builtins[] = BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL), BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL), BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL), - BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL), + BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSw", NULL), BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"), BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL), @@ -3331,8 +3331,8 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (v && !csh) zputs(*argv, stdout), fputs(" is ", stdout); zputs(buf, stdout); - if (OPT_ISSET(ops,'s')) - print_if_link(buf); + if (OPT_ISSET(ops,'s') || OPT_ISSET(ops, 'S')) + print_if_link(buf, OPT_ISSET(ops, 'S')); fputc('\n', stdout); } informed = 1; @@ -3352,8 +3352,8 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (v && !csh) zputs(*argv, stdout), fputs(" is ", stdout); zputs(cnam, stdout); - if (OPT_ISSET(ops,'s')) - print_if_link(cnam); + if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S')) + print_if_link(cnam, OPT_ISSET(ops,'S')); fputc('\n', stdout); } } else { diff --git a/Src/utils.c b/Src/utils.c index 893a8ca02..2b2a815a8 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -719,7 +719,7 @@ slashsplit(char *s) /**/ static int -xsymlinks(char *s) +xsymlinks(char *s, int full) { char **pp, **opp; char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; @@ -758,14 +758,49 @@ xsymlinks(char *s) } else { ret = 1; metafy(xbuf3, t0, META_NOALLOC); + if (!full) { + /* + * If only one expansion requested, ensure the + * full path is in xbuf. + */ + zulong len = xbuflen; + if (*xbuf3 == '/') + strcpy(xbuf, xbuf3); + else if ((len += strlen(xbuf3) + 1) < sizeof(xbuf)) { + strcpy(xbuf + xbuflen, "/"); + strcpy(xbuf + xbuflen + 1, xbuf3); + } else { + *xbuf = 0; + ret = -1; + break; + } + + while (*++pp) { + zulong newlen = len + strlen(*pp) + 1; + if (newlen < sizeof(xbuf)) { + strcpy(xbuf + len, "/"); + strcpy(xbuf + len + 1, *pp); + len = newlen; + } else { + *xbuf = 01; + ret = -1; + break; + } + } + /* + * No need to update xbuflen, we're finished + * the expansion (for now). + */ + break; + } if (*xbuf3 == '/') { strcpy(xbuf, ""); - if (xsymlinks(xbuf3 + 1) < 0) + if (xsymlinks(xbuf3 + 1, 0) < 0) ret = -1; else xbuflen = strlen(xbuf); } else - if (xsymlinks(xbuf3) < 0) + if (xsymlinks(xbuf3, 0) < 0) ret = -1; else xbuflen = strlen(xbuf); @@ -787,7 +822,7 @@ xsymlink(char *s) if (*s != '/') return NULL; *xbuf = '\0'; - if (xsymlinks(s + 1) < 0) + if (xsymlinks(s + 1, 1) < 0) zwarn("path expansion failed, using root directory"); if (!*xbuf) return ztrdup("/"); @@ -796,12 +831,30 @@ xsymlink(char *s) /**/ void -print_if_link(char *s) +print_if_link(char *s, int all) { if (*s == '/') { *xbuf = '\0'; - if (xsymlinks(s + 1) > 0) - printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); + if (all) { + char *start = s + 1; + char xbuflink[PATH_MAX]; + for (;;) { + if (xsymlinks(start, 0) > 0) { + printf(" -> "); + zputs(*xbuf ? xbuf : "/", stdout); + if (!*xbuf) + break; + strcpy(xbuflink, xbuf); + start = xbuflink + 1; + *xbuf = '\0'; + } else { + break; + } + } + } else { + if (xsymlinks(s + 1, 1) > 0) + printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); + } } } -- cgit v1.2.3 From f9cba834cdcd5f35d21768b6412577236adc5ed2 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 4 Jan 2015 19:05:39 +0000 Subject: 34091: typo with "whence -s" expansions --- ChangeLog | 2 ++ Src/utils.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index d8918acb3..ca5d401ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-04 Peter Stephenson + * 34091: Src/utils.c: typo with "whence -s" expansions. + * users/19682: Doc/Zsh/builtins.yo: document recommended use of whence. diff --git a/Src/utils.c b/Src/utils.c index 2b2a815a8..959df9ab7 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -795,12 +795,12 @@ xsymlinks(char *s, int full) } if (*xbuf3 == '/') { strcpy(xbuf, ""); - if (xsymlinks(xbuf3 + 1, 0) < 0) + if (xsymlinks(xbuf3 + 1, 1) < 0) ret = -1; else xbuflen = strlen(xbuf); } else - if (xsymlinks(xbuf3, 0) < 0) + if (xsymlinks(xbuf3, 1) < 0) ret = -1; else xbuflen = strlen(xbuf); -- cgit v1.2.3 From 98f465c09f6edc56e8332de42fddee9b689b2ed6 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 4 Jan 2015 19:42:45 +0000 Subject: 34092: fix miscount of symlink resolution for "..". This caused problems with expanding a path with ".." in "whence -S". --- ChangeLog | 3 +++ Src/utils.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index ca5d401ab..d1b385f86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-04 Peter Stephenson + * 34092: Src/utils.c: miscount of buffer length in symlink + resolution after ".." caused error with whence -S. + * 34091: Src/utils.c: typo with "whence -s" expansions. * users/19682: Doc/Zsh/builtins.yo: document recommended use of diff --git a/Src/utils.c b/Src/utils.c index 959df9ab7..390f513ba 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -741,6 +741,8 @@ xsymlinks(char *s, int full) while (*--p != '/') xbuflen--; *p = '\0'; + /* The \0 isn't included in the length */ + xbuflen--; continue; } sprintf(xbuf2, "%s/%s", xbuf, *pp); -- cgit v1.2.3 From c425cc9632fc475e3117cf96e69e2510be5d80c0 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 6 Jan 2015 04:32:07 +0100 Subject: 34108: Don't leak ifs stuff Found by Coverity (Issue 1255785). --- ChangeLog | 2 ++ Src/utils.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 1b3076632..6698da345 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-06 Mikael Magnusson + * 34108: Src/utils.c: Don't leak ifs stuff + * 34107: Src/hist.c: getsubsargs: free ptr1 before returning * 34134: Src/exec.c: anon funcs: don't leak shf and related data diff --git a/Src/utils.c b/Src/utils.c index 390f513ba..72a0c9c1f 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3543,7 +3543,7 @@ inittyptab(void) for (t0 = (int)STOUC(Snull); t0 <= (int)STOUC(Nularg); t0++) typtab[t0] |= ITOK | IMETA | INULL; for (s = ifs ? ifs : EMULATION(EMULATE_KSH|EMULATE_SH) ? - ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS); *s; s++) { + DEFAULT_IFS_SH : DEFAULT_IFS; *s; s++) { int c = STOUC(*s == Meta ? *++s ^ 32 : *s); #ifdef MULTIBYTE_SUPPORT if (!isascii(c)) { @@ -3578,7 +3578,7 @@ inittyptab(void) #ifdef MULTIBYTE_SUPPORT set_widearray(wordchars, &wordchars_wide); set_widearray(ifs ? ifs : EMULATION(EMULATE_KSH|EMULATE_SH) ? - ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS), &ifs_wide); + DEFAULT_IFS_SH : DEFAULT_IFS, &ifs_wide); #endif for (s = SPECCHARS; *s; s++) typtab[STOUC(*s)] |= ISPECIAL; -- cgit v1.2.3 From 4701b05cf760fddeee4b203f04130540f2d903a8 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 6 Jan 2015 02:09:35 +0100 Subject: 34138: wcs_nicechar: only deref widthp if it was given --- ChangeLog | 3 +++ Src/utils.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 688ad8d44..c3957f049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-06 Mikael Magnusson + * 34138: Src/utils.c: wcs_nicechar: only deref widthp if it + was given + * 34120: Src/Zle/compctl.c, Src/jobs.c: Check contents instead of array diff --git a/Src/utils.c b/Src/utils.c index 72a0c9c1f..f8d239458 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -566,7 +566,7 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep) return buf; } if (swidep) - *swidep = buf + *widthp; + *swidep = widthp ? buf + *widthp : buf; return buf; } -- cgit v1.2.3 From c6c9f5daf2e196e6ab7346dfbf5f5166a1d87f0c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 18 Jan 2015 22:38:57 +0000 Subject: 34322: bug with interface to parsestr() etc. Was showing up in places like ${(e)...} where command substitution could reallocate the token string, but actually there was never any guarantee that the lexer wouldn't do that, so this was always a bit iffy. --- ChangeLog | 6 ++++++ Src/Zle/compctl.c | 4 ++-- Src/Zle/compresult.c | 3 ++- Src/exec.c | 9 +++++---- Src/init.c | 11 +++++++---- Src/lex.c | 30 +++++++++++++++++++++--------- Src/params.c | 3 ++- Src/prompt.c | 2 +- Src/subst.c | 8 +++++--- Src/utils.c | 2 +- Test/D04parameter.ztst | 7 +++++++ 11 files changed, 59 insertions(+), 26 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 30068eb8b..5d52f6693 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2015-01-18 Peter Stephenson + * 34322: Src/Zle/compctl.c, Src/Zle/compresult.c, Src/exec.c, + Src/init.c, Src/lex.c, Src/params.c, Src/prompt.c, Src/subst.c, + Src/utils.c, Test/D04parameter.ztst: update interface to + parsestr()/parsestrnoerr() to ensure correct token string + is passed back. + * 34320: Src/hist.c, Src/lex.c: alias expansion in history of command substitution. diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 43dd4e2a9..189582d22 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -3853,7 +3853,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) yaptr = get_user_var(uv); if ((tt = cc->explain)) { tt = dupstring(tt); - if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { + if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) { singsub(&tt); untokenize(tt); } @@ -3873,7 +3873,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } } else if ((tt = cc->explain)) { tt = dupstring(tt); - if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { + if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) { singsub(&tt); untokenize(tt); } diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index dbef7f841..9f383f4b8 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1090,7 +1090,8 @@ do_single(Cmatch m) } if (tryit) { noerrs = 1; - parsestr(p); + p = dupstring(p); + parsestr(&p); singsub(&p); errflag &= ~ERRFLAG_ERROR; noerrs = ne; diff --git a/Src/exec.c b/Src/exec.c index 7b6495113..f42fb2b9b 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3772,19 +3772,20 @@ gethere(char **strp, int typ) *bptr++ = '\n'; } *t = '\0'; + s = buf; + buf = dupstring(buf); + zfree(s, bsiz); if (!qt) { int ef = errflag; - parsestr(buf); + parsestr(&buf); if (!errflag) { /* Retain any user interrupt error */ errflag = ef | (errflag & ERRFLAG_INT); } } - s = dupstring(buf); - zfree(buf, bsiz); - return s; + return buf; } /* open here string fd */ diff --git a/Src/init.c b/Src/init.c index e7d86feac..3e41fb9dd 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1197,10 +1197,13 @@ run_init_scripts(void) if (islogin) sourcehome(".profile"); noerrs = 2; - if (s && !parsestr(s)) { - singsub(&s); - noerrs = 0; - source(s); + if (s) { + s = dupstring(s); + if (!parsestr(&s)) { + singsub(&s); + noerrs = 0; + source(s); + } } noerrs = 0; } else diff --git a/Src/lex.c b/Src/lex.c index e4dfdfaca..433c27fbb 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -1503,17 +1503,27 @@ dquote_parse(char endchar, int sub) return err; } -/* Tokenize a string given in s. Parsing is done as in double * - * quotes. This is usually called before singsub(). */ +/* + * Tokenize a string given in s. Parsing is done as in double + * quotes. This is usually called before singsub(). + * + * parsestr() is noisier, reporting an error if the parse failed. + * + * On entry, *s must point to a string allocated from the stack of + * exactly the right length, i.e. strlen(*s) + 1, as the string + * is used as the lexical token string whose memory management + * demands this. Usually the input string will therefore be + * the result of an immediately preceding dupstring(). + */ /**/ mod_export int -parsestr(char *s) +parsestr(char **s) { int err; if ((err = parsestrnoerr(s))) { - untokenize(s); + untokenize(*s); if (err > 32 && err < 127) zerr("parse error near `%c'", err); else @@ -1524,18 +1534,20 @@ parsestr(char *s) /**/ mod_export int -parsestrnoerr(char *s) +parsestrnoerr(char **s) { - int l = strlen(s), err; + int l = strlen(*s), err; zcontext_save(); - untokenize(s); - inpush(dupstring(s), 0, NULL); + untokenize(*s); + inpush(dupstring(*s), 0, NULL); strinbeg(0); lexbuf.len = 0; - lexbuf.ptr = tokstr = s; + lexbuf.ptr = tokstr = *s; lexbuf.siz = l + 1; err = dquote_parse('\0', 1); + if (tokstr) + *s = tokstr; *lexbuf.ptr = '\0'; strinend(); inpop(); diff --git a/Src/params.c b/Src/params.c index b8e0c429b..64c78bd63 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1260,7 +1260,8 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, if (ishash && (keymatch || !rev)) remnulargs(s); if (needtok) { - if (parsestr(s)) + s = dupstring(s); + if (parsestr(&s)) return 0; singsub(&s); } else if (rev) diff --git a/Src/prompt.c b/Src/prompt.c index 3552575f3..ffc1d0df2 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -183,7 +183,7 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) int oldval = lastval; s = dupstring(s); - if (!parsestr(s)) + if (!parsestr(&s)) singsub(&s); /* * We don't need the special Nularg hack here and we're diff --git a/Src/subst.c b/Src/subst.c index 5f993d6fd..a2bb6483a 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1306,7 +1306,7 @@ get_intarg(char **s, int *delmatchp) p = dupstring(*s + arglen); *s = t + arglen; *t = sav; - if (parsestr(p)) + if (parsestr(&p)) return -1; singsub(&p); if (errflag) @@ -1329,7 +1329,8 @@ subst_parse_str(char **sp, int single, int err) *sp = s = dupstring(*sp); - if (!(err ? parsestr(s) : parsestrnoerr(s))) { + if (!(err ? parsestr(&s) : parsestrnoerr(&s))) { + *sp = s; if (!single) { int qt = 0; @@ -1439,7 +1440,8 @@ check_colon_subscript(char *str, char **endp) } sav = **endp; **endp = '\0'; - if (parsestr(str = dupstring(str))) + str = dupstring(str); + if (parsestr(&str)) return NULL; singsub(&str); remnulargs(str); diff --git a/Src/utils.c b/Src/utils.c index f8d239458..4561b5e9a 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1515,7 +1515,7 @@ checkmailpath(char **s) setunderscore(*s); u = dupstring(u); - if (! parsestr(u)) { + if (!parsestr(&u)) { singsub(&u); zputs(u, shout); fputc('\n', shout); diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 94d15f205..cf639fa8c 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -1663,3 +1663,10 @@ 0:SHLVL appears sensible when about to exit shell >2 >2 + +# The following tests the return behaviour of parsestr/parsestrnoerr + alias param-test-alias='print $'\''\x45xpanded in substitution'\' + param='$(param-test-alias)' + print ${(e)param} +0:Alias expansion in command substitution in parameter evaluation +>Expanded in substitution -- cgit v1.2.3 From 12b813b5895cae579e403dafe43878868f27fe0f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 22 Jan 2015 20:20:15 +0000 Subject: 34331: better handling of NULL in cd. Problem was return from symbolic link expander in weird cases where there file system isn't behaving itself properly. --- ChangeLog | 5 +++++ Src/builtin.c | 8 +++++--- Src/utils.c | 11 +++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 4b01b2ac3..9636f5c67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-01-22 Peter Stephenson + + * 34331: Src/builtin.c, Src/utils.c: don't trip over + NULL pointer in cd in rare cases where file system goes AWOL. + 2015-01-22 Barton E. Schaefer * 34344: Test/V07pcre.ztst: fix 34338, builtins need loading too diff --git a/Src/builtin.c b/Src/builtin.c index 1818941b2..08be1acdd 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1156,9 +1156,11 @@ cd_new_pwd(int func, LinkNode dir, int quiet) zsfree(getlinknode(dirstack)); if (chasinglinks) { - s = new_pwd; - new_pwd = findpwd(s); - zsfree(s); + s = findpwd(new_pwd); + if (s) { + zsfree(new_pwd); + new_pwd = s; + } } if (isset(PUSHDIGNOREDUPS)) { LinkNode n; diff --git a/Src/utils.c b/Src/utils.c index 4561b5e9a..cf18f1240 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1108,10 +1108,13 @@ getnameddir(char *name) if ((pw = getpwnam(name))) { char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir) : ztrdup(pw->pw_dir); - adduserdir(name, dir, ND_USERNAME, 1); - str = dupstring(dir); - zsfree(dir); - return str; + if (dir) { + adduserdir(name, dir, ND_USERNAME, 1); + str = dupstring(dir); + zsfree(dir); + return str; + } else + return ztrdup(pw->pw_dir); } } #endif /* HAVE_GETPWNAM */ -- cgit v1.2.3 From ccd3663d4e9a1749450b35cc689359f78a310c04 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 25 Jan 2015 18:03:20 +0000 Subject: 34383: ztrdup() should be dupstring() in new cd code --- ChangeLog | 4 ++++ Src/utils.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index f11eebe4e..427725564 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-01-25 Peter Stephenson + + * 34383: Src/utils.c: new ztrdup() shoud be dupstring(). + 2015-01-25 Oliver Kiddle * 34373, 34374: Completion/Unix/Command/_chown, diff --git a/Src/utils.c b/Src/utils.c index cf18f1240..0490df516 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1114,7 +1114,7 @@ getnameddir(char *name) zsfree(dir); return str; } else - return ztrdup(pw->pw_dir); + return dupstring(pw->pw_dir); } } #endif /* HAVE_GETPWNAM */ -- cgit v1.2.3 From f7a2fba5342a3cf8c2590111a0a296acd8c8a211 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sat, 24 Jan 2015 15:36:16 +0000 Subject: 34369: document error and warning codes --- ChangeLog | 2 ++ Src/utils.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 427725564..5b3cbdf9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-25 Peter Stephenson + * 34369: Daniel Shahaf: document error / warning codes. + * 34383: Src/utils.c: new ztrdup() shoud be dupstring(). 2015-01-25 Oliver Kiddle diff --git a/Src/utils.c b/Src/utils.c index 0490df516..383042dec 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -112,7 +112,20 @@ set_widearray(char *mb_array, Widechar_array wca) #endif -/* Print an error */ +/* Print an error + + The following functions use the following printf-like format codes + (implemented by zerrmsg()): + + Code Argument types Prints + %s const char * C string (null terminated) + %l const char *, int C string of given length (null not required) + %L long decimal value + %d int decimal value + %% (none) literal '%' + %c int character at that codepoint + %e int strerror() message (argument is typically 'errno') + */ static void zwarning(const char *cmd, const char *fmt, va_list ap) @@ -343,6 +356,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) fputs(errmsg + 1, file); } break; + /* When adding format codes, update the comment above zwarning(). */ } } else { putc(*fmt == Meta ? *++fmt ^ 32 : *fmt, file); -- cgit v1.2.3 From 4688de16772beffc315bbf765475a2932cbd8628 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 23 Jan 2015 20:00:01 +0000 Subject: 34365: History lockfile backoff: randomised time. Time doubles on each lock failure. zsleep() provides microsecond resolution for sleep; uses nanosleep() if available, else select via means of existing tty poll function. --- Src/hist.c | 41 +++++++++++++++++++------- Src/utils.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- configure.ac | 3 +- 3 files changed, 125 insertions(+), 15 deletions(-) (limited to 'Src/utils.c') diff --git a/Src/hist.c b/Src/hist.c index 11d9722d5..303c1dd4a 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2610,7 +2610,8 @@ static int flockhistfile(char *fn, int keep_trying) { struct flock lck; - int ctr = keep_trying ? 9 : 0; + long sleep_us = 0x10000; /* about 67 ms */ + time_t end_time; if (flock_fd >= 0) return 0; /* already locked */ @@ -2623,13 +2624,22 @@ flockhistfile(char *fn, int keep_trying) lck.l_start = 0; lck.l_len = 0; /* lock the whole file */ + /* + * Timeout is ten seconds. + */ + end_time = time(NULL) + (time_t)10; while (fcntl(flock_fd, F_SETLKW, &lck) == -1) { - if (--ctr < 0) { + if (!keep_trying || time(NULL) >= end_time || + /* + * Randomise wait to minimise clashes with shells exiting at + * the same time. + */ + !zsleep_random(sleep_us, end_time)) { close(flock_fd); flock_fd = -1; return 1; } - sleep(1); + sleep_us <<= 1; } return 0; @@ -2865,7 +2875,7 @@ savehistfile(char *fn, int err, int writeflags) static int lockhistct; static int -checklocktime(char *lockfile, time_t then) +checklocktime(char *lockfile, long *sleep_usp, time_t then) { time_t now = time(NULL); @@ -2875,9 +2885,19 @@ checklocktime(char *lockfile, time_t then) return -1; } - if (now - then < 10) - sleep(1); - else + if (now - then < 10) { + /* + * To give the effect of a gradually increasing backoff, + * we'll sleep a period based on the time we've spent so far. + */ + DPUTS(now < then, "time flowing backwards through history"); + /* + * Randomise to minimise clashes with shells exiting at the same + * time. + */ + (void)zsleep_random(*sleep_usp, then + 10); + *sleep_usp <<= 1; + } else unlink(lockfile); return 0; @@ -2894,6 +2914,7 @@ lockhistfile(char *fn, int keep_trying) { int ct = lockhistct; int ret = 0; + long sleep_us = 0x10000; /* about 67 ms */ if (!fn && !(fn = getsparam("HISTFILE"))) return 1; @@ -2937,7 +2958,7 @@ lockhistfile(char *fn, int keep_trying) continue; break; } - if (checklocktime(lockfile, sb.st_mtime) < 0) { + if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) { ret = 1; break; } @@ -2965,7 +2986,7 @@ lockhistfile(char *fn, int keep_trying) continue; ret = 2; } else { - if (checklocktime(lockfile, sb.st_mtime) < 0) { + if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) { ret = 1; break; } @@ -2993,7 +3014,7 @@ lockhistfile(char *fn, int keep_trying) ret = 2; break; } - if (checklocktime(lockfile, sb.st_mtime) < 0) { + if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) { ret = 1; break; } diff --git a/Src/utils.c b/Src/utils.c index 383042dec..45f596a42 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2275,6 +2275,10 @@ setblock_stdin(void) * Note that apart from setting (and restoring) non-blocking input, * this function does not change the input mode. The calling function * should have set cbreak mode if necessary. + * + * fd may be -1 to sleep until the timeout in microseconds. This is a + * fallback for old systems that don't have nanosleep(). Some very old + * systems might not have select: get with it, daddy-o. */ /**/ @@ -2296,6 +2300,8 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) struct ttyinfo ti; #endif + if (fd < 0) + polltty = 0; /* no tty to poll */ #if defined(HAS_TIO) && !defined(__CYGWIN__) /* @@ -2317,7 +2323,7 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) * as plausible as it sounds, but it seems the right way to guess. * pws 2000/06/26 */ - if (polltty) { + if (fd >= 0) { gettyinfo(&ti); if ((polltty = ti.tio.c_cc[VMIN])) { ti.tio.c_cc[VMIN] = 0; @@ -2333,16 +2339,24 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) expire_tv.tv_sec = (int) (microseconds / (zlong)1000000); expire_tv.tv_usec = microseconds % (zlong)1000000; FD_ZERO(&foofd); - FD_SET(fd, &foofd); - ret = select(fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); + if (fd > -1) { + FD_SET(fd, &foofd); + ret = select(fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); + } else + ret = select(0, NULL, NULL, NULL, &expire_tv); #else + if (fd < 0) { + /* OK, can't do that. Just quietly sleep for a second. */ + sleep(1); + return 1; + } #ifdef FIONREAD if (ioctl(fd, FIONREAD, (char *) &val) == 0) ret = (val > 0); #endif #endif - if (ret < 0) { + if (fd >= 0 && ret < 0) { /* * Final attempt: set non-blocking read and try to read a character. * Praise Bill, this works under Cygwin (nothing else seems to). @@ -2364,6 +2378,80 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) return (ret > 0); } +/* + * Sleep for the given number of microseconds --- must be within + * range of a long at the moment, but this is only used for + * limited internal purposes. + */ + +/**/ +int +zsleep(long us) +{ +#ifdef HAVE_NANOSLEEP + struct timespec sleeptime; + + sleeptime.tv_sec = (time_t)us / (time_t)1000000; + sleeptime.tv_nsec = (us % 1000000L) * 1000L; + for (;;) { + struct timespec rem; + int ret = nanosleep(&sleeptime, &rem); + + if (ret == 0) + return 1; + else if (errno != EINTR) + return 0; + sleeptime = rem; + } +#else + int dummy; + return read_poll(-1, &dummy, 0, us); +#endif +} + +/** + * Sleep for time (fairly) randomly up to max_us microseconds. + * Don't let the wallclock time extend beyond end_time. + * Return 1 if that seemed to work, else 0. + * + * For best results max_us should be a multiple of 2**16 or large + * enough that it doesn't matter. + */ + +/**/ +int +zsleep_random(long max_us, time_t end_time) +{ + long r; + time_t now = time(NULL); + + /* + * Randomish backoff. Doesn't need to be fundamentally + * unpredictable, just probably unlike the value another + * exiting shell is using. On some systems the bottom 16 + * bits aren't that random but the use here doesn't + * really care. + */ + r = (long)(rand() & 0xFFFF); + /* + * Turn this into a fraction of sleep_us. Again, this + * doesn't need to be particularly accurate and the base time + * is sufficient that we can do the division first and not + * worry about the range. + */ + r = (max_us >> 16) * r; + /* + * Don't sleep beyond timeout. + * Not that important as timeout is ridiculously long, but + * if there's an interface, interface to it... + */ + while (r && now + (time_t)(r / 1000000) > end_time) + r >>= 1; + if (r) /* pedantry */ + return zsleep(r); + return 0; +} + /**/ int checkrmall(char *s) diff --git a/configure.ac b/configure.ac index 8ea9737c5..bfc02b2d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1299,7 +1299,8 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ gdbm_open getxattr \ realpath canonicalize_file_name \ symlink getcwd \ - cygwin_conv_path) + cygwin_conv_path \ + nanosleep) AC_FUNC_STRCOLL AH_TEMPLATE([REALPATH_ACCEPTS_NULL], -- cgit v1.2.3 From 494c251cb0b0af70ac940b42df1d6c9940e469c8 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 25 Jan 2015 16:07:49 -0800 Subject: 34399: fix polltty thinko from 34365 Also add missing ChangeLog entry for 34365. --- ChangeLog | 6 ++++++ Src/utils.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index abc381f91..191d6a9e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-25 Barton E. Schaefer + * 34399: Src/utils.c: fix polltty thinko from 34365 + * 34389: Src/hist.c: fix parsing of ">!" when read from histfile with HIST_LEX_WORDS in effect @@ -7,6 +9,10 @@ * 34369: Daniel Shahaf: document error / warning codes. + * 34365: configure.ac, Src/hist.c, Src/utils.c: History lockfile + backoff: randomised time. zsleep() provides microsecond + resolution for sleep. + * 34383: Src/utils.c: new ztrdup() shoud be dupstring(). 2015-01-25 Oliver Kiddle diff --git a/Src/utils.c b/Src/utils.c index 45f596a42..d38babbe4 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2323,7 +2323,7 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) * as plausible as it sounds, but it seems the right way to guess. * pws 2000/06/26 */ - if (fd >= 0) { + if (polltty && fd >= 0) { gettyinfo(&ti); if ((polltty = ti.tio.c_cc[VMIN])) { ti.tio.c_cc[VMIN] = 0; -- cgit v1.2.3 From 5751de7975d559dbdf641126589683bd92fad9bc Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 26 Jan 2015 18:47:29 -0800 Subject: 34403: refine 34399 to avoid settyinfo() when the input descriptor is not a TTY --- ChangeLog | 5 +++++ Src/utils.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 5939ea141..a183c5086 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,11 @@ * 34387: Src/module.c: Avoid loading the main zsh binary as a module +2015-01-26 Barton E. Schaefer + + * 34403: Src/utils.c: refine 34399 to avoid settyinfo() when the + input descriptor is not a TTY + 2015-01-26 Peter Stephenson * 34402: Src/Modules/db_gdbm.c: make unsetting a tied gdbm diff --git a/Src/utils.c b/Src/utils.c index d38babbe4..47d99442d 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2300,8 +2300,8 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) struct ttyinfo ti; #endif - if (fd < 0) - polltty = 0; /* no tty to poll */ + if (fd < 0 || (polltty && !isatty(fd))) + polltty = 0; /* no tty to poll */ #if defined(HAS_TIO) && !defined(__CYGWIN__) /* -- cgit v1.2.3 From dfbb5e4853d8cc55fb7c3ffe53887130cbc2dc3f Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sun, 8 Feb 2015 06:44:02 +0100 Subject: 34466: Fix double unmeta in rm verification --- ChangeLog | 4 ++++ Src/utils.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index fdb02a943..1af298bf4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-02-09 Mikael Magnusson + + * 34466: Src/utils.c: Fix double unmeta in rm verification + 2015-02-08 Daniel Hahler * 34469: Completion/Unix/Command/_git: git completion: add "stash" diff --git a/Src/utils.c b/Src/utils.c index 47d99442d..702829c0c 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2460,7 +2460,7 @@ checkrmall(char *s) return 1; fprintf(shout, "zsh: sure you want to delete all the files in "); if (*s != '/') { - nicezputs(pwd[1] ? unmeta(pwd) : "", shout); + nicezputs(pwd[1] ? pwd : "", shout); fputc('/', shout); } nicezputs(s, shout); -- cgit v1.2.3 From b237ba0a8eaa5001283ac8448872021723b90aff Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 20 Feb 2015 16:25:47 +0000 Subject: 34587: ensure multibyte characters don't overflow. They could start incorporating tokens, with bad karma. Add test. --- ChangeLog | 5 +++++ Src/utils.c | 8 ++++++++ Test/D07multibyte.ztst | 20 +++++++++++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index c4ff0223e..fbf11386b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-02-20 Peter Stephenson + + * 34587: Src/utils.c, Test/D07multibyte.ztst: ensure multibyte + characters don't overflow into tokens and add test. + 2015-02-19 Barton E. Schaefer * 34568: Src/Module.c: use META_HEAPDUP when passing dlerror() diff --git a/Src/utils.c b/Src/utils.c index 702829c0c..1bcceb091 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4797,6 +4797,14 @@ mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp) inchar = *++ptr ^ 32; DPUTS(!*ptr, "BUG: unexpected end of string in mb_metacharlen()\n"); + } else if (imeta(*ptr)) { + /* + * As this is metafied input, this is a token --- this + * can't be a part of the string. It might be + * something on the end of an unbracketed parameter + * reference, for example. + */ + break; } else inchar = *ptr; ptr++; diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst index 2cb995346..33e76bee7 100644 --- a/Test/D07multibyte.ztst +++ b/Test/D07multibyte.ztst @@ -448,20 +448,30 @@ 0:read passes through invalid multibyte characters >0xC5 - word=abcま + word=abcま word[-1]= print $word - word=abcま + word=abcま word[-2]= print $word - word=abcま + word=abcま word[4]=d print $word - word=abcま + word=abcま word[3]=not_c - print $word + print $word 0:assignment with negative indices >abc >abま >abcd >abnot_cま + + # The following doesn't necessarily need UTF-8, but this gives + # us the full effect --- if we parse this wrongly the \xe9 + # in combination with the tokenized input afterwards looks like a + # valid UTF-8 character. But it isn't. + print $'$\xe9#``' >test_bad_param + (setopt nonomatch + . ./test_bad_param) +127:Invalid parameter name with following tokenized input +?./test_bad_param:1: command not found: $\M-i# -- cgit v1.2.3 From 4bc554bb8b46d9b47bb847a72bb5c0226d54b8e5 Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Thu, 5 Mar 2015 01:48:34 +0900 Subject: 34636: replace broken isprint() on Mac OS X --- ChangeLog | 5 +++++ Src/compat.c | 15 +++++++++++++++ Src/pattern.c | 2 +- Src/utils.c | 4 ++-- Src/ztype.h | 6 ++++++ configure.ac | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 3 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index d4c6c4d4d..0816dc501 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-03-05 Jun-ichi Takimoto + + * 34636: Src/compat.c, Src/pattern.c, Src/utils.c, Src/ztype.c, + configure.ac: replace broken isprint() on Mac OS X. + 2015-03-04 Peter Stephenson * 34641: Src/lex.c, Test/A02alias.ztst: make it possible to diff --git a/Src/compat.c b/Src/compat.c index b0bcb6265..09b3d6a5f 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -951,3 +951,18 @@ int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) /**/ #endif /* BROKEN_WCWIDTH && (__STDC_ISO_10646__ || __APPLE__) */ +/**/ +#if defined(__APPLE__) && defined(BROKEN_ISPRINT) + +/**/ +int +isprint_ascii(int c) +{ + if (!strcmp(nl_langinfo(CODESET), "UTF-8")) + return (c >= 0x20 && c <= 0x7e); + else + return isprint(c); +} + +/**/ +#endif /* __APPLE__ && BROKEN_ISPRINT */ diff --git a/Src/pattern.c b/Src/pattern.c index df5e602ca..17cd40c23 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -3622,7 +3622,7 @@ patmatchrange(char *range, int ch, int *indptr, int *mtp) return 1; break; case PP_PRINT: - if (isprint(ch)) + if (ISPRINT(ch)) return 1; break; case PP_PUNCT: diff --git a/Src/utils.c b/Src/utils.c index 1bcceb091..3d12807e2 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -414,7 +414,7 @@ nicechar(int c) static char buf[6]; char *s = buf; c &= 0xff; - if (isprint(c)) + if (ISPRINT(c)) goto done; if (c & 0x80) { if (isset(PRINTEIGHTBIT)) @@ -423,7 +423,7 @@ nicechar(int c) *s++ = 'M'; *s++ = '-'; c &= 0x7f; - if(isprint(c)) + if(ISPRINT(c)) goto done; } if (c == 0x7f) { diff --git a/Src/ztype.h b/Src/ztype.h index eef0f23db..d1bef0a5a 100644 --- a/Src/ztype.h +++ b/Src/ztype.h @@ -75,3 +75,9 @@ #define WC_ZISTYPE(X,Y) zistype((X),(Y)) #define WC_ISPRINT(X) isprint(X) #endif + +#if defined(__APPLE__) && defined(BROKEN_ISPRINT) +#define ISPRINT(c) isprint_ascii(c) +#else +#define ISPRINT(c) isprint(c) +#endif diff --git a/configure.ac b/configure.ac index bfc02b2d4..7e770cd81 100644 --- a/configure.ac +++ b/configure.ac @@ -2567,6 +2567,8 @@ AH_TEMPLATE([MULTIBYTE_SUPPORT], [Define to 1 if you want support for multibyte character sets.]) AH_TEMPLATE([BROKEN_WCWIDTH], [Define to 1 if the wcwidth() function is present but broken.]) +AH_TEMPLATE([BROKEN_ISPRINT], +[Define to 1 if the isprint() function is broken under UTF-8 locale.]) if test x$zsh_cv_c_unicode_support = xyes; then AC_DEFINE(MULTIBYTE_SUPPORT) @@ -2622,6 +2624,38 @@ if test x$zsh_cv_c_unicode_support = xyes; then if test x$zsh_cv_c_broken_wcwidth = xyes; then AC_DEFINE(BROKEN_WCWIDTH) fi + + dnl Check if isprint() behaves correctly under UTF-8 locale. + dnl On some platform (maybe only on Mac OS X), isprint() returns + dnl true for all characters in the range from 0xa0 to 0xff if + dnl called under UTF-8 locale. + [locale_prog='char *my_locales[] = { + "en_US.UTF-8", "en_GB.UTF-8", "en.UTF-8", ' + locale_prog="$locale_prog"`locale -a 2>/dev/null | \ + sed -e 's/utf8/UTF-8/' | grep UTF-8 | \ + while read line; do echo " \"$line\","; done;` + locale_prog="$locale_prog 0 }; + #include + #include + + int main() { + char **localep; + for (localep = my_locales; *localep; localep++) + if (setlocale(LC_ALL, *localep) && isprint(0xa0)) + return 0; + return 1; + } + "] + + AC_CACHE_CHECK(if the isprint() function is broken, + zsh_cv_c_broken_isprint, + [AC_TRY_RUN([$locale_prog], + zsh_cv_c_broken_isprint=yes, + zsh_cv_c_broken_isprint=no, + zsh_cv_c_broken_isprint=no)]) + if test x$zsh_cv_c_broken_isprint = xyes; then + AC_DEFINE(BROKEN_ISPRINT) + fi fi dnl -- cgit v1.2.3