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