summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.awk6
-rw-r--r--Src/Builtins/rlimits.c56
-rw-r--r--Src/Modules/mathfunc.c9
-rw-r--r--Src/Modules/parameter.c40
-rw-r--r--Src/Modules/parameter.mdd2
-rw-r--r--Src/Modules/stat.c4
-rw-r--r--Src/Modules/zpty.c33
-rw-r--r--Src/Zle/compcore.c5
-rw-r--r--Src/Zle/compctl.c1
-rw-r--r--Src/Zle/computil.c63
-rw-r--r--Src/Zle/zle_main.c47
-rw-r--r--Src/Zle/zle_move.c16
-rw-r--r--Src/Zle/zle_tricky.c29
-rw-r--r--Src/Zle/zle_utils.c1
-rw-r--r--Src/builtin.c76
-rw-r--r--Src/exec.c158
-rw-r--r--Src/glob.c59
-rw-r--r--Src/hist.c118
-rw-r--r--Src/init.c9
-rw-r--r--Src/input.c4
-rw-r--r--Src/jobs.c137
-rw-r--r--Src/lex.c1
-rw-r--r--Src/math.c21
-rw-r--r--Src/options.c3
-rw-r--r--Src/params.c2
-rw-r--r--Src/parse.c45
-rw-r--r--Src/pattern.c480
-rw-r--r--Src/prompt.c43
-rw-r--r--Src/signals.c8
-rw-r--r--Src/signals.h8
-rw-r--r--Src/subst.c10
-rw-r--r--Src/utils.c22
-rw-r--r--Src/zsh.h82
-rw-r--r--Src/zsh.mdd12
-rw-r--r--Src/zsh_system.h2
35 files changed, 1235 insertions, 377 deletions
diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk
index bf914814d..fe2d0e931 100644
--- a/Src/Builtins/rlimits.awk
+++ b/Src/Builtins/rlimits.awk
@@ -42,7 +42,7 @@ BEGIN {limidx = 0}
if (limnam == "MEMLOCK") { msg[limnum] = "Mmemorylocked" }
if (limnam == "NOFILE") { msg[limnum] = "Ndescriptors" }
if (limnam == "NPROC") { msg[limnum] = "Nmaxproc" }
- if (limnam == "NTHR") { msg[limnum] = "Nmaxthr" }
+ if (limnam == "NTHR") { msg[limnum] = "Nmaxpthreads" }
if (limnam == "OFILE") { msg[limnum] = "Ndescriptors" }
if (limnam == "PTHREAD") { msg[limnum] = "Nmaxpthreads" }
if (limnam == "RSS") { msg[limnum] = "Mresident" }
@@ -55,6 +55,10 @@ BEGIN {limidx = 0}
if (limnam == "NICE") { msg[limnum] = "Nnice" }
if (limnam == "RTPRIO") { msg[limnum] = "Nrt_priority" }
if (limnam == "RTTIME") { msg[limnum] = "Urt_time" }
+ if (limnam == "POSIXLOCKS") { msg[limnum] = "Nposixlocks" }
+ if (limnam == "NPTS") { msg[limnum] = "Npseudoterminals" }
+ if (limnam == "SWAP") { msg[limnum] = "Mswapsize" }
+ if (limnam == "KQUEUES") { msg[limnum] = "Nkqueues" }
}
}
}
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index eedfa969c..fd4c94aaa 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -32,6 +32,14 @@
#if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY)
+#ifdef RLIMIT_POSIXLOCKS
+# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
+#endif
+
+#ifdef RLIMIT_NTHR
+# define RLIMIT_PTHREAD RLIMIT_NTHR
+#endif
+
enum {
ZLIMTYPE_MEMORY,
ZLIMTYPE_NUMBER,
@@ -314,12 +322,6 @@ printulimit(char *nam, int lim, int hard, int head)
printf("-u: processes ");
break;
# endif /* HAVE_RLIMIT_NPROC */
-# ifdef HAVE_RLIMIT_NTHR
- case RLIMIT_NTHR:
- if (head)
- printf("-r: threads ");
- break;
-#endif /* HAVE_RLIMIT_NTHR */
# if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS))
case RLIMIT_VMEM:
if (head)
@@ -371,7 +373,7 @@ printulimit(char *nam, int lim, int hard, int head)
# ifdef HAVE_RLIMIT_PTHREAD
case RLIMIT_PTHREAD:
if (head)
- printf("-N %2d: threads per process ", RLIMIT_PTHREAD);
+ printf("-T: threads per process ");
break;
# endif /* HAVE_RLIMIT_PTHREAD */
# ifdef HAVE_RLIMIT_NICE
@@ -386,6 +388,26 @@ printulimit(char *nam, int lim, int hard, int head)
printf("-r: max rt priority ");
break;
# endif /* HAVE_RLIMIT_RTPRIO */
+# ifdef HAVE_RLIMIT_NPTS
+ case RLIMIT_NPTS:
+ if (head)
+ printf("-p: pseudo-terminals ");
+ break;
+# endif /* HAVE_RLIMIT_NPTS */
+# ifdef HAVE_RLIMIT_SWAP
+ case RLIMIT_SWAP:
+ if (head)
+ printf("-w: swap size (kbytes) ");
+ if (limit != RLIM_INFINITY)
+ limit /= 1024;
+ break;
+# endif /* HAVE_RLIMIT_SWAP */
+# ifdef HAVE_RLIMIT_KQUEUES
+ case RLIMIT_KQUEUES:
+ if (head)
+ printf("-k: kqueues ");
+ break;
+# endif /* HAVE_RLIMIT_KQUEUES */
default:
if (head)
printf("-N %2d: ", lim);
@@ -800,11 +822,6 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
res = RLIMIT_NOFILE;
break;
# endif /* HAVE_RLIMIT_NOFILE */
-# ifdef HAVE_RLIMIT_NTHR
- case 'r':
- res = RLIMIT_NTHR;
- break;
-# endif /* HAVE_RLIMIT_NTHR */
# ifdef HAVE_RLIMIT_NPROC
case 'u':
res = RLIMIT_NPROC;
@@ -844,6 +861,21 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
res = RLIMIT_RTPRIO;
break;
# endif
+# ifdef HAVE_RLIMIT_NPTS
+ case 'p':
+ res = RLIMIT_NPTS;
+ break;
+# endif
+# ifdef HAVE_RLIMIT_SWAP
+ case 'w':
+ res = RLIMIT_SWAP;
+ break;
+# endif
+# ifdef HAVE_RLIMIT_KQUEUES
+ case 'k':
+ res = RLIMIT_KQUEUES;
+ break;
+# endif
default:
/* unrecognised limit */
zwarnnam(name, "bad option: -%c", *options);
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index 04483b555..efadd86ff 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -340,7 +340,16 @@ math_func(char *name, int argc, mnumber *argv, int id)
break;
case MF_GAMMA:
+#ifdef HAVE_TGAMMA
+ retd = tgamma(argd);
+#else
+#ifdef HAVE_SIGNGAM
+ retd = lgamma(argd);
+ retd = signgam*exp(retd);
+#else /*XXX assume gamma(x) returns Gamma(x), not log(|Gamma(x)|) */
retd = gamma(argd);
+#endif
+#endif
break;
case MF_HYPOT:
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index a029c9cb4..22148f991 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -759,6 +759,38 @@ disreswordsgetfn(UNUSED(Param pm))
return getreswords(DISABLED);
}
+/* Functions for the patchars special parameter. */
+
+/**/
+static char **
+getpatchars(int dis)
+{
+ int i;
+ char **ret, **p;
+
+ p = ret = (char **) zhalloc(ZPC_COUNT * sizeof(char *));
+
+ for (i = 0; i < ZPC_COUNT; i++)
+ if (zpc_strings[i] && !dis == !zpc_disables[i])
+ *p++ = dupstring(zpc_strings[i]);
+
+ *p = NULL;
+
+ return ret;
+}
+
+static char **
+patcharsgetfn(UNUSED(Param pm))
+{
+ return getpatchars(0);
+}
+
+static char **
+dispatcharsgetfn(UNUSED(Param pm))
+{
+ return getpatchars(1);
+}
+
/* Functions for the options special parameter. */
/**/
@@ -2018,6 +2050,10 @@ static const struct gsu_array reswords_gsu =
{ reswordsgetfn, arrsetfn, stdunsetfn };
static const struct gsu_array disreswords_gsu =
{ disreswordsgetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array patchars_gsu =
+{ patcharsgetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array dispatchars_gsu =
+{ dispatcharsgetfn, arrsetfn, stdunsetfn };
static const struct gsu_array dirs_gsu =
{ dirsgetfn, dirssetfn, stdunsetfn };
static const struct gsu_array historywords_gsu =
@@ -2038,6 +2074,8 @@ static struct paramdef partab[] = {
&pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
SPECIALPMDEF("dis_galiases", 0,
&pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
+ SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY,
+ &dispatchars_gsu, NULL, NULL),
SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY,
&disreswords_gsu, NULL, NULL),
SPECIALPMDEF("dis_saliases", 0,
@@ -2072,6 +2110,8 @@ static struct paramdef partab[] = {
&pmoptions_gsu, getpmoption, scanpmoptions),
SPECIALPMDEF("parameters", PM_READONLY,
NULL, getpmparameter, scanpmparameters),
+ SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY,
+ &patchars_gsu, NULL, NULL),
SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY,
&reswords_gsu, NULL, NULL),
SPECIALPMDEF("saliases", 0,
diff --git a/Src/Modules/parameter.mdd b/Src/Modules/parameter.mdd
index eb48d5f2a..a91a5dc09 100644
--- a/Src/Modules/parameter.mdd
+++ b/Src/Modules/parameter.mdd
@@ -2,6 +2,6 @@ name=zsh/parameter
link=either
load=yes
-autofeatures="p:parameters p:commands p:functions p:dis_functions p:funcfiletrace p:funcsourcetrace p:funcstack p:functrace p:builtins p:dis_builtins p:reswords p:dis_reswords p:options p:modules p:dirstack p:history p:historywords p:jobtexts p:jobdirs p:jobstates p:nameddirs p:userdirs p:aliases p:dis_aliases p:galiases p:dis_galiases p:saliases p:dis_saliases"
+autofeatures="p:parameters p:commands p:functions p:dis_functions p:funcfiletrace p:funcsourcetrace p:funcstack p:functrace p:builtins p:dis_builtins p:reswords p:dis_reswords p:patchars p:dis_patchars p:options p:modules p:dirstack p:history p:historywords p:jobtexts p:jobdirs p:jobstates p:nameddirs p:userdirs p:aliases p:dis_aliases p:galiases p:dis_galiases p:saliases p:dis_saliases"
objects="parameter.o"
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index a3e95bb59..edae0841e 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -339,7 +339,7 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
* -H hash: as for -A array, but returns a hash with the keys being those
* from stat -l
* -F fmt: specify a $TIME-like format for printing times; the default
- * is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies
+ * is the (CTIME-like) "%a %b %e %k:%M:%S %Z %Y". This option implies
* -s as it is not useful for numerical times.
*
* +type selects just element type of stat buffer (-l gives list):
@@ -361,7 +361,7 @@ bin_stat(char *name, char **args, Options ops, UNUSED(int func))
struct stat statbuf;
int found = 0, nargs;
- timefmt = "%a %b %e %k:%M:%S";
+ timefmt = "%a %b %e %k:%M:%S %Z %Y";
for (; *args && (**args == '+' || **args == '-'); args++) {
char *arg = *args+1;
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 25ec7dfea..fca0cc172 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -293,8 +293,8 @@ static int
newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
{
Ptycmd p;
- int master, slave, pid, oineval = ineval;
- char *oscriptname = scriptname;
+ int master, slave, pid, oineval = ineval, ret;
+ char *oscriptname = scriptname, syncch;
Eprog prog;
/* code borrowed from bin_eval() */
@@ -344,6 +344,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
if (get_pty(0, &slave))
exit(1);
+ SHTTY = slave;
+ attachtty(mypid);
#ifdef TIOCGWINSZ
/* Set the window size before associating with the terminal *
* so that we don't get hit with a SIGWINCH. I'm paranoid. */
@@ -396,8 +398,23 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
setsparam("TTY", ztrdup(ttystrname));
opts[INTERACTIVE] = 0;
+
+ syncch = 0;
+ do {
+ ret = write(1, &syncch, 1);
+ } while (ret != 1 && (
+#ifdef EWOULDBLOCK
+ errno == EWOULDBLOCK ||
+#else
+#ifdef EAGAIN
+ errno == EAGAIN ||
+#endif
+#endif
+ errno == EINTR));
+
execode(prog, 1, 0, "zpty");
stopmsg = 2;
+ mypid = 0; /* trick to ensure we _exit() */
zexit(lastval, 0);
}
master = movefd(master);
@@ -430,6 +447,18 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
scriptname = oscriptname;
ineval = oineval;
+ do {
+ ret = read(master, &syncch, 1);
+ } while (ret != 1 && (
+#ifdef EWOULDBLOCK
+ errno == EWOULDBLOCK ||
+#else
+#ifdef EAGAIN
+ errno == EAGAIN ||
+#endif
+#endif
+ errno == EINTR));
+
return 0;
}
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 39d41bdb5..5c5628a8d 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -826,7 +826,6 @@ callcompfunc(char *s, char *fn)
sfcontext = SFC_CWIDGET;
NEWHEAPS(compheap) {
LinkList largs = NULL;
- int olv = lastval;
if (*cfargs) {
char **p = cfargs;
@@ -836,9 +835,7 @@ callcompfunc(char *s, char *fn)
while (*p)
addlinknode(largs, dupstring(*p++));
}
- doshfunc(shfunc, largs, 0);
- cfret = lastval;
- lastval = olv;
+ cfret = doshfunc(shfunc, largs, 1);
} OLDHEAPS;
sfcontext = osc;
endparamscope();
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 0143370c7..ab1857c0a 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -398,7 +398,6 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl)
if (cl)
return 1;
else {
- freecompctl(cc);
cclist = COMP_REMOVE;
return 0;
}
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index cd508d0ac..f5e6ba195 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -465,6 +465,7 @@ cd_init(char *nam, char *hide, char *mlen, char *sep,
cd_state.showd = disp;
cd_state.maxg = cd_state.groups = cd_state.descs = 0;
cd_state.maxmlen = atoi(mlen);
+ cd_state.premaxw = 0;
itmp = zterm_columns - cd_state.swidth - 4;
if (cd_state.maxmlen > itmp)
cd_state.maxmlen = itmp;
@@ -643,35 +644,43 @@ cd_get(char **params)
p += str->len;
memset(p, ' ', (l = (cd_state.premaxw - str->width + CM_SPACE)));
p += l;
- strcpy(p, cd_state.sep);
- p += cd_state.slen;
- /*
- * copy a character at once until no more screen width
- * is available. Leave 1 character at the end of screen
- * as safety margin
- */
remw = zterm_columns - cd_state.premaxw -
cd_state.swidth - 3;
- d = str->desc;
- w = MB_METASTRWIDTH(d);
- if (w <= remw)
- strcpy(p, d);
- else {
- pp = p;
- while (remw > 0 && *d) {
- l = MB_METACHARLEN(d);
- memcpy(pp, d, l);
- pp[l] = '\0';
- w = MB_METASTRWIDTH(pp);
- if (w > remw) {
- *pp = '\0';
- break;
- }
+ while (remw < 0 && zterm_columns) {
+ /* line wrapped, use remainder of the extra line */
+ remw += zterm_columns;
+ }
+ if (cd_state.slen < remw) {
+ strcpy(p, cd_state.sep);
+ p += cd_state.slen;
+ remw -= cd_state.slen;
- pp += l;
- d += l;
- remw -= w;
+ /*
+ * copy a character at once until no more screen
+ * width is available. Leave 1 character at the
+ * end of screen as safety margin
+ */
+ d = str->desc;
+ w = MB_METASTRWIDTH(d);
+ if (w <= remw)
+ strcpy(p, d);
+ else {
+ pp = p;
+ while (remw > 0 && *d) {
+ l = MB_METACHARLEN(d);
+ memcpy(pp, d, l);
+ pp[l] = '\0';
+ w = MB_METASTRWIDTH(pp);
+ if (w > remw) {
+ *pp = '\0';
+ break;
+ }
+
+ pp += l;
+ d += l;
+ remw -= w;
+ }
}
}
@@ -1608,7 +1617,7 @@ get_cadef(char *nam, char **args)
return *p;
} else if (!min || !*p || (*p)->lastt < (*min)->lastt)
min = p;
- if (i)
+ if (i > 0)
min = p;
if ((new = parse_cadef(nam, args))) {
freecadef(*min);
@@ -2992,7 +3001,7 @@ get_cvdef(char *nam, char **args)
return *p;
} else if (!min || !*p || (*p)->lastt < (*min)->lastt)
min = p;
- if (i)
+ if (i > 0)
min = p;
if ((new = parse_cvdef(nam, args))) {
freecvdef(*min);
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index e1a575bdb..5798e74b4 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -567,7 +567,9 @@ raw_getbyte(long do_keytmout, char *cptr)
gettyinfo(&ti);
ti.tio.c_cc[VMIN] = 0;
settyinfo(&ti);
+ winch_unblock();
ret = read(SHTTY, cptr, 1);
+ winch_block();
ti.tio.c_cc[VMIN] = 1;
settyinfo(&ti);
if (ret > 0)
@@ -597,7 +599,9 @@ raw_getbyte(long do_keytmout, char *cptr)
else
poll_timeout = -1;
+ winch_unblock();
selret = poll(fds, errtry ? 1 : nfds, poll_timeout);
+ winch_block();
# else
int fdmax = SHTTY;
struct timeval *tvptr;
@@ -622,8 +626,10 @@ raw_getbyte(long do_keytmout, char *cptr)
else
tvptr = NULL;
+ winch_unblock();
selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd,
NULL, NULL, tvptr);
+ winch_block();
# endif
/*
* Make sure a user interrupt gets passed on straight away.
@@ -788,7 +794,9 @@ raw_getbyte(long do_keytmout, char *cptr)
# else
ioctl(SHTTY, TCSETA, &ti.tio);
# endif
+ winch_unblock();
ret = read(SHTTY, cptr, 1);
+ winch_block();
# ifdef HAVE_TERMIOS_H
tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio);
# else
@@ -799,7 +807,9 @@ raw_getbyte(long do_keytmout, char *cptr)
#endif
}
+ winch_unblock();
ret = read(SHTTY, cptr, 1);
+ winch_block();
return ret;
}
@@ -1105,7 +1115,7 @@ zlecore(void)
/**/
char *
-zleread(char **lp, char **rp, int flags, int context)
+zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
{
char *s;
int old_errno = errno;
@@ -1178,6 +1188,13 @@ zleread(char **lp, char **rp, int flags, int context)
viinsbegin = 0;
statusline = NULL;
selectkeymap("main", 1);
+ /*
+ * If main is linked to the viins keymap, we need to register
+ * explicitly that we're now in vi insert mode as there's
+ * no user operation to indicate this.
+ */
+ if (openkeymap("main") == openkeymap("viins"))
+ viinsert(NULL);
selectlocalmap(NULL);
fixsuffix();
if ((s = getlinknode(bufstack))) {
@@ -1223,7 +1240,9 @@ zleread(char **lp, char **rp, int flags, int context)
unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */
- zlecallhook("zle-line-init", NULL);
+ zlecallhook(init, NULL);
+
+ zrefresh();
zlecore();
@@ -1231,7 +1250,7 @@ zleread(char **lp, char **rp, int flags, int context)
setsparam("ZLE_LINE_ABORTED", zlegetline(NULL, NULL));
if (done && !exit_pending && !errflag)
- zlecallhook("zle-line-finish", NULL);
+ zlecallhook(finish, NULL);
statusline = NULL;
invalidatelist();
@@ -1471,7 +1490,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
Param pm = 0;
int ifl;
int type = PM_SCALAR, obreaks = breaks, haso = 0, oSHTTY = 0;
- char *p1, *p2, *main_keymapname, *vicmd_keymapname;
+ char *p1, *p2, *main_keymapname, *vicmd_keymapname, *init, *finish;
Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL;
FILE *oshout = NULL;
@@ -1499,6 +1518,8 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
p2 = OPT_ARG_SAFE(ops,'r');
main_keymapname = OPT_ARG_SAFE(ops,'M');
vicmd_keymapname = OPT_ARG_SAFE(ops,'m');
+ init = OPT_ARG_SAFE(ops,'i');
+ finish = OPT_ARG_SAFE(ops,'f');
if (type != PM_SCALAR && !OPT_ISSET(ops,'c')) {
zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A");
@@ -1600,6 +1621,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
haso = 1;
}
+
/* edit the parameter value */
zpushnode(bufstack, s);
@@ -1615,7 +1637,10 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
if (OPT_ISSET(ops,'h'))
hbegin(2);
isfirstln = OPT_ISSET(ops,'e');
- t = zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0, ZLCON_VARED);
+
+ t = zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0, ZLCON_VARED,
+ init ? init : "zle-line-init",
+ finish ? finish : "zle-line-finish");
if (OPT_ISSET(ops,'h'))
hend(NULL);
isfirstln = ifl;
@@ -1880,7 +1905,8 @@ zle_main_entry(int cmd, va_list ap)
flags = va_arg(ap, int);
context = va_arg(ap, int);
- return zleread(lp, rp, flags, context);
+ return zleread(lp, rp, flags, context,
+ "zle-line-init", "zle-line-finish");
}
case ZLE_CMD_ADD_TO_LINE:
@@ -1915,6 +1941,13 @@ zle_main_entry(int cmd, va_list ap)
break;
}
+ case ZLE_CMD_SET_HIST_LINE:
+ {
+ histline = va_arg(ap, zlong);
+
+ break;
+ }
+
default:
#ifdef DEBUG
dputs("Bad command %d in zle_main_entry", cmd);
@@ -1926,7 +1959,7 @@ zle_main_entry(int cmd, va_list ap)
static struct builtin bintab[] = {
BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL),
- BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcehM:m:p:r:t:", NULL),
+ BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcef:hi:M:m:p:r:t:", NULL),
BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNrRTU", NULL),
};
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index d5f464c2c..7312b3f20 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -30,7 +30,7 @@
#include "zle.mdh"
#include "zle_move.pro"
-static int vimarkcs[26], vimarkline[26];
+static int vimarkcs[27], vimarkline[27];
#ifdef MULTIBYTE_SUPPORT
/*
@@ -825,11 +825,17 @@ int
vigotomark(UNUSED(char **args))
{
ZLE_INT_T ch;
+ int oldcs = zlecs;
+ int oldline = histline;
ch = getfullchar(0);
- if (ch < ZWC('a') || ch > ZWC('z'))
- return 1;
- ch -= ZWC('a');
+ if (ch == ZWC('\'') || ch == ZWC('`'))
+ ch = 26;
+ else {
+ if (ch < ZWC('a') || ch > ZWC('z'))
+ return 1;
+ ch -= ZWC('a');
+ }
if (!vimarkline[ch])
return 1;
if (curhist != vimarkline[ch] && !zle_goto_hist(vimarkline[ch], 0, 0)) {
@@ -837,6 +843,8 @@ vigotomark(UNUSED(char **args))
return 1;
}
zlecs = vimarkcs[ch];
+ vimarkcs[26] = oldcs;
+ vimarkline[26] = oldline;
if (zlecs > zlell)
zlecs = zlell;
return 0;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 78a9fa490..e30e0b1aa 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1095,6 +1095,7 @@ get_comp_string(void)
* the command word is not at index zero in the array.
*/
int redirpos;
+ int noword;
char *s = NULL, *tmp, *p, *tt = NULL, rdop[20];
char *linptr, *u;
@@ -1165,7 +1166,7 @@ get_comp_string(void)
* and whatnot. */
do {
- qsub = 0;
+ qsub = noword = 0;
lincmd = ((incmdpos && !ins && !incond) ||
(oins == 2 && wordpos == 2) ||
@@ -1239,6 +1240,19 @@ get_comp_string(void)
* leave the loop. */
if (tt)
break;
+ if (ins < 2) {
+ /*
+ * Don't add this as a word, because we're about to start
+ * a new command line: pretend there's no string here.
+ * We don't dare do this if we're using one of the
+ * *really* gross hacks with ins to get later words
+ * to look like command words, because we don't
+ * understand how they work. Quite possibly we
+ * should be using a mechanism like the one here rather
+ * than the ins thing.
+ */
+ noword = 1;
+ }
/* Otherwise reset the variables we are collecting data in. */
wordpos = cp = rd = ins = redirpos = 0;
tt0 = NULLTOK;
@@ -1253,6 +1267,14 @@ get_comp_string(void)
/* If everything before is a redirection, don't reset the index */
if (wordpos != redirpos)
wordpos = redirpos = 0;
+ } else if (tok == SEPER) {
+ /*
+ * A following DOLOOP should cause us to reset to the start
+ * of the command line. For some reason we only recognise
+ * DOLOOP for this purpose (above) if ins is set. Why?
+ * Don't ask pointless questions.
+ */
+ ins = 1;
}
if (!lexflags && tt0 == NULLTOK) {
/* This is done when the lexer reached the word the cursor is on. */
@@ -1322,7 +1344,7 @@ get_comp_string(void)
else if (tok == DAMPER)
tokstr = "&&";
}
- if (!tokstr)
+ if (!tokstr || noword)
continue;
/* Hack to allow completion after `repeat n do'. */
if (oins == 2 && !wordpos && !strcmp(tokstr, "do"))
@@ -2114,8 +2136,8 @@ inststrlen(char *str, int move, int len)
return 0;
if (len == -1)
len = strlen(str);
- spaceinline(len);
if (zlemetaline != NULL) {
+ spaceinline(len);
strncpy(zlemetaline + zlemetacs, str, len);
if (move)
zlemetacs += len;
@@ -2126,6 +2148,7 @@ inststrlen(char *str, int move, int len)
instr = ztrduppfx(str, len);
zlestr = stringaszleline(instr, 0, &zlelen, NULL, NULL);
+ spaceinline(zlelen);
ZS_strncpy(zleline + zlecs, zlestr, zlelen);
free(zlestr);
zsfree(instr);
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index d0e7b5542..b84d253bb 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -145,6 +145,7 @@ zlecharasstring(ZLE_CHAR_T inchar, char *buf)
ptr2--;
}
*ptr = Meta;
+ ptr[1] ^= 32;
ret++;
}
diff --git a/Src/builtin.c b/Src/builtin.c
index 90fe1a6c5..c3f0169c7 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -55,11 +55,11 @@ static struct builtin builtins[] =
BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmprtuxz", NULL),
BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL),
- BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL),
+ BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmprs", NULL),
BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "LR", NULL),
- BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", NULL),
+ BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
@@ -467,7 +467,9 @@ bin_enable(char *name, char **argv, Options ops, int func)
int match = 0, returnval = 0;
/* Find out which hash table we are working with. */
- if (OPT_ISSET(ops,'f'))
+ if (OPT_ISSET(ops,'p')) {
+ return pat_enables(name, argv, func == BIN_ENABLE);
+ } else if (OPT_ISSET(ops,'f'))
ht = shfunctab;
else if (OPT_ISSET(ops,'r'))
ht = reswdtab;
@@ -937,11 +939,16 @@ cd_do_chdir(char *cnam, char *dest, int hard)
* DOS style names with drives in them
*/
static char buf[PATH_MAX];
+#ifdef HAVE_CYGWIN_CONV_PATH
+ cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, dest, buf,
+ PATH_MAX);
+#else
#ifndef _SYS_CYGWIN_H
void cygwin_conv_to_posix_path(const char *, char *);
#endif
cygwin_conv_to_posix_path(dest, buf);
+#endif
dest = buf;
#endif
nocdpath = dest[0] == '.' &&
@@ -1118,7 +1125,8 @@ cd_try_chdir(char *pfix, char *dest, int hard)
* argument to cd relatively. This is useful if the cwd
* or a parent directory is renamed in the interim.
*/
- if (lchdir(buf, NULL, hard) && lchdir(dest, NULL, hard)) {
+ if (lchdir(buf, NULL, hard) &&
+ (pfix || *dest == '/' || lchdir(dest, NULL, hard))) {
free(buf);
return NULL;
}
@@ -2470,7 +2478,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
setsparam(asg0.name, ztrdup(asg0.value));
return 0;
} else {
- zerrnam(name, "can't tie already tied scalar: %s",
+ zwarnnam(name, "can't tie already tied scalar: %s",
asg0.name);
}
return 1;
@@ -2680,7 +2688,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
Patprog pprog;
Shfunc shf;
int i, returnval = 0;
- int on = 0, off = 0, pflags = 0;
+ int on = 0, off = 0, pflags = 0, roff;
/* Do we have any flags defined? */
if (OPT_PLUS(ops,'u'))
@@ -2699,16 +2707,21 @@ bin_functions(char *name, char **argv, Options ops, int func)
on |= PM_TAGGED_LOCAL;
else if (OPT_PLUS(ops,'T'))
off |= PM_TAGGED_LOCAL;
+ roff = off;
if (OPT_MINUS(ops,'z')) {
on |= PM_ZSHSTORED;
off |= PM_KSHSTORED;
- } else if (OPT_PLUS(ops,'z'))
+ } else if (OPT_PLUS(ops,'z')) {
off |= PM_ZSHSTORED;
+ roff |= PM_ZSHSTORED;
+ }
if (OPT_MINUS(ops,'k')) {
on |= PM_KSHSTORED;
off |= PM_ZSHSTORED;
- } else if (OPT_PLUS(ops,'k'))
+ } else if (OPT_PLUS(ops,'k')) {
off |= PM_KSHSTORED;
+ roff |= PM_KSHSTORED;
+ }
if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
(OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) {
@@ -2716,7 +2729,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
return 1;
}
- if (OPT_PLUS(ops,'f') || OPT_ISSET(ops,'+'))
+ if (OPT_PLUS(ops,'f') || roff || OPT_ISSET(ops,'+'))
pflags |= PRINT_NAMEONLY;
if (OPT_MINUS(ops,'M') || OPT_PLUS(ops,'M')) {
@@ -3785,11 +3798,11 @@ bin_print(char *name, char **args, Options ops, int func)
/* -u and -p -- output to other than standard output */
if (OPT_HASARG(ops,'u') || OPT_ISSET(ops,'p')) {
- int fd;
+ int fdarg, fd;
if (OPT_ISSET(ops, 'p')) {
- fd = coprocout;
- if (fd < 0) {
+ fdarg = coprocout;
+ if (fdarg < 0) {
zwarnnam(name, "-p: no coprocess");
return 1;
}
@@ -3797,13 +3810,13 @@ bin_print(char *name, char **args, Options ops, int func)
char *argptr = OPT_ARG(ops,'u'), *eptr;
/* Handle undocumented feature that -up worked */
if (!strcmp(argptr, "p")) {
- fd = coprocout;
- if (fd < 0) {
+ fdarg= coprocout;
+ if (fdarg < 0) {
zwarnnam(name, "-p: no coprocess");
return 1;
}
} else {
- fd = (int)zstrtol(argptr, &eptr, 10);
+ fdarg = (int)zstrtol(argptr, &eptr, 10);
if (*eptr) {
zwarnnam(name, "number expected after -%c: %s", 'u',
argptr);
@@ -3812,8 +3825,8 @@ bin_print(char *name, char **args, Options ops, int func)
}
}
- if ((fd = dup(fd)) < 0) {
- zwarnnam(name, "bad file number: %d", fd);
+ if ((fd = dup(fdarg)) < 0) {
+ zwarnnam(name, "bad file number: %d", fdarg);
return 1;
}
if ((fout = fdopen(fd, "w")) == 0) {
@@ -5015,6 +5028,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
int opt_R = OPT_ISSET(ops, 'R');
int saveemulation, savehackchar;
int ret = 1, new_emulation;
+ unsigned int savepatterns;
char saveopts[OPT_SIZE], new_opts[OPT_SIZE];
char *cmd = 0;
const char *shname = *argv;
@@ -5056,7 +5070,8 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
if (!argv[1]) {
emulate(shname, OPT_ISSET(ops,'R'), &emulation, opts);
if (OPT_ISSET(ops,'L'))
- opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
+ opts[LOCALOPTIONS] = opts[LOCALTRAPS] = opts[LOCALPATTERNS] = 1;
+ clearpatterndisables();
return 0;
}
@@ -5077,6 +5092,13 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
goto restore;
}
+ savepatterns = savepatterndisables();
+ /*
+ * All emulations start with an empty set of pattern disables,
+ * hence no special "sticky" behaviour is required.
+ */
+ clearpatterndisables();
+
saveemulation = emulation;
emulation = new_emulation;
memcpy(opts, new_opts, sizeof(opts));
@@ -5126,6 +5148,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
sticky = save_sticky;
emulation = saveemulation;
memcpy(opts, saveopts, sizeof(opts));
+ restorepatterndisables(savepatterns);
restore:
keyboardhackchar = savehackchar;
inittyptab(); /* restore banghist */
@@ -5490,6 +5513,8 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
eof = 2;
else
eof = (bptr - buf != 1 || (buf[0] != 'y' && buf[0] != 'Y'));
+ buf[0] = eof ? 'n' : 'y';
+ bptr = buf + 1;
}
if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E'))
fwrite(buf, bptr - buf, 1, stdout);
@@ -5667,7 +5692,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
zputs(buf, stdout);
putchar('\n');
}
- if (!OPT_ISSET(ops,'e') && (*buf || first)) {
+ if (!OPT_ISSET(ops,'e') && (*buf || first || gotnl)) {
if (OPT_ISSET(ops,'A')) {
addlinknode(readll, buf);
al++;
@@ -5970,7 +5995,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
char **s;
Eprog prog;
struct estate state;
- int nargs;
+ int nargs, sense = 0, ret;
/* if "test" was invoked as "[", it needs a matching "]" *
* which is subsequently ignored */
@@ -5989,7 +6014,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
/*
* Implement some XSI extensions to POSIX here.
* See
- * http://www.opengroup.org/onlinepubs/009695399/utilities/test.html.
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
*/
nargs = arrlen(argv);
if (nargs == 3 || nargs == 4)
@@ -5998,6 +6023,10 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
argv[nargs-1] = NULL;
argv++;
}
+ if (nargs == 4 && !strcmp("!", argv[0])) {
+ sense = 1;
+ argv++;
+ }
}
lexsave();
@@ -6032,8 +6061,11 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
state.pc = prog->prog;
state.strs = prog->strs;
+ ret = evalcond(&state, name);
+ if (ret < 2 && sense)
+ ret = ! ret;
- return evalcond(&state, name);
+ return ret;
}
/* display a time, provided in units of 1/60s, as minutes and seconds */
diff --git a/Src/exec.c b/Src/exec.c
index 1ecbc3967..df915e152 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -448,10 +448,13 @@ zexecve(char *pth, char **argv, char **newenvp)
else
sprintf(buf + 2, "%s/%s", pwd, pth);
zputenv(buf);
+#ifndef FD_CLOEXEC
closedumps();
+#endif
if (newenvp == NULL)
newenvp = environ;
+ winch_unblock();
execve(pth, argv, newenvp);
/* If the execve returns (which in general shouldn't happen), *
@@ -486,6 +489,7 @@ zexecve(char *pth, char **argv, char **newenvp)
(pprog = pathprog(ptr2, NULL))) {
argv[-2] = ptr2;
argv[-1] = ptr + 1;
+ winch_unblock();
execve(pprog, argv - 2, newenvp);
}
zerr("%s: bad interpreter: %s: %e", pth, ptr2,
@@ -494,13 +498,16 @@ zexecve(char *pth, char **argv, char **newenvp)
*ptr = '\0';
argv[-2] = ptr2;
argv[-1] = ptr + 1;
+ winch_unblock();
execve(ptr2, argv - 2, newenvp);
} else {
argv[-1] = ptr2;
+ winch_unblock();
execve(ptr2, argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
argv[-1] = "sh";
+ winch_unblock();
execve("/bin/sh", argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
@@ -509,6 +516,7 @@ zexecve(char *pth, char **argv, char **newenvp)
break;
if (t0 == ct) {
argv[-1] = "sh";
+ winch_unblock();
execve("/bin/sh", argv - 1, newenvp);
}
}
@@ -1019,6 +1027,11 @@ execstring(char *s, int dont_change_job, int exiting, char *context)
Eprog prog;
pushheap();
+ if (isset(VERBOSE)) {
+ zputs(s, stderr);
+ fputc('\n', stderr);
+ fflush(stderr);
+ }
if ((prog = parse_string(s, 0)))
execode(prog, dont_change_job, exiting, context);
popheap();
@@ -1079,6 +1092,9 @@ execsimple(Estate state)
if (errflag)
return (lastval = 1);
+ if (!isset(EXECOPT))
+ return lastval = 0;
+
/* In evaluated traps, don't modify the line number. */
if (!IN_EVAL_TRAP() && !ineval && code)
lineno = code - 1;
@@ -1645,8 +1661,6 @@ execpline(Estate state, wordcode slcode, int how, int last1)
return lastval;
}
-static int subsh_close = -1;
-
/* execute pipeline. This function assumes the `pline' is not NULL. */
/**/
@@ -1723,7 +1737,7 @@ execpline2(Estate state, wordcode pcode,
}
} else {
/* otherwise just do the pipeline normally. */
- subsh_close = pipes[0];
+ addfilelist(NULL, pipes[0]);
execcmd(state, input, pipes[1], how, 0);
}
zclose(pipes[1]);
@@ -1736,8 +1750,6 @@ execpline2(Estate state, wordcode pcode,
execpline2(state, *state->pc++, how, pipes[0], output, last1);
list_pipe = old_list_pipe;
cmdpop();
- zclose(pipes[0]);
- subsh_close = -1;
}
}
@@ -1841,9 +1853,22 @@ quote_tokenized_output(char *str, FILE *file)
case '*':
case '?':
case '$':
+ case ' ':
putc('\\', file);
break;
+ case '\t':
+ fputs("$'\\t'", file);
+ continue;
+
+ case '\n':
+ fputs("$'\\n'", file);
+ continue;
+
+ case '\r':
+ fputs("$'\\r'", file);
+ continue;
+
case '=':
if (s == str)
putc('\\', file);
@@ -1885,7 +1910,14 @@ checkclobberparam(struct redir *f)
return 0;
}
- if (!isset(CLOBBER) && (fd = (int)getintvalue(v)) &&
+ /*
+ * We can't clobber the value in the parameter if it's
+ * already an opened file descriptor --- that means it's a decimal
+ * integer corresponding to an opened file descriptor,
+ * not merely an expression that evaluates to a file descriptor.
+ */
+ if (!isset(CLOBBER) && (s = getstrvalue(v)) &&
+ (fd = (int)zstrtol(s, &s, 10)) >= 0 && !*s &&
fd <= max_zsh_fd && fdtable[fd] == FDT_EXTERNAL) {
zwarn("can't clobber parameter %s containing file descriptor %d",
f->varid, fd);
@@ -1935,7 +1967,7 @@ clobber_open(struct redir *f)
/**/
static void
-closemn(struct multio **mfds, int fd)
+closemn(struct multio **mfds, int fd, int type)
{
if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) {
struct multio *mn = mfds[fd];
@@ -1994,7 +2026,7 @@ closemn(struct multio **mfds, int fd)
}
}
_exit(0);
- } else if (fd >= 0)
+ } else if (fd >= 0 && type == REDIR_CLOSE)
mfds[fd] = NULL;
}
@@ -2147,8 +2179,6 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag,
mfds[fd1]->fds[mfds[fd1]->ct++] = fdN;
}
}
- if (subsh_close >= 0 && fdtable[subsh_close] == FDT_UNUSED)
- subsh_close = -1;
}
/**/
@@ -2847,9 +2877,6 @@ execcmd(Estate state, int input, int output, int how, int last1)
close(synch[1]);
read_loop(synch[0], &dummy, 1);
close(synch[0]);
-#ifdef PATH_DEV_FD
- closem(FDT_PROC_SUBST);
-#endif
if (how & Z_ASYNC) {
lastpid = (zlong) pid;
/* indicate it's possible to set status for lastpid */
@@ -3066,7 +3093,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
}
if (fn->fd1 < 10)
- closemn(mfds, fn->fd1);
+ closemn(mfds, fn->fd1, REDIR_CLOSE);
if (!closed && zclose(fn->fd1) < 0) {
zwarn("failed to close file descriptor %d: %e",
fn->fd1, errno);
@@ -3075,7 +3102,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
case REDIR_MERGEIN:
case REDIR_MERGEOUT:
if (fn->fd2 < 10)
- closemn(mfds, fn->fd2);
+ closemn(mfds, fn->fd2, fn->type);
if (!checkclobberparam(fn))
fil = -1;
else if (fn->fd2 > 9 &&
@@ -3096,7 +3123,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
int fd = fn->fd2;
if(fd == -2)
fd = (fn->type == REDIR_MERGEOUT) ? coprocout : coprocin;
- fil = dup(fd);
+ fil = movefd(dup(fd));
}
if (fil == -1) {
char fdstr[4];
@@ -3124,7 +3151,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
else
fil = clobber_open(fn);
if(fil != -1 && IS_ERROR_REDIR(fn->type))
- dfil = dup(fil);
+ dfil = movefd(dup(fil));
else
dfil = 0;
if (fil == -1 || dfil == -1) {
@@ -3154,7 +3181,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
* spawning tee/cat processes as necessary. */
for (i = 0; i < 10; i++)
if (mfds[i] && mfds[i]->ct >= 2)
- closemn(mfds, i);
+ closemn(mfds, i, REDIR_CLOSE);
if (nullexec) {
if (nullexec == 1) {
@@ -3233,33 +3260,12 @@ execcmd(Estate state, int input, int output, int how, int last1)
if (is_shfunc) {
/* It's a shell function */
-
-#ifdef PATH_DEV_FD
- int i;
-
- for (i = 10; i <= max_zsh_fd; i++)
- if (fdtable[i] >= FDT_PROC_SUBST)
- fdtable[i]++;
-#endif
- if (subsh_close >= 0)
- zclose(subsh_close);
- subsh_close = -1;
-
execshfunc((Shfunc) hn, args);
-#ifdef PATH_DEV_FD
- for (i = 10; i <= max_zsh_fd; i++)
- if (fdtable[i] >= FDT_PROC_SUBST)
- if (--(fdtable[i]) <= FDT_PROC_SUBST)
- zclose(i);
-#endif
} else {
/* It's a builtin */
if (forked)
closem(FDT_INTERNAL);
lastval = execbuiltin(args, (Builtin) hn);
-#ifdef PATH_DEV_FD
- closem(FDT_PROC_SUBST);
-#endif
fflush(stdout);
if (save[1] == -2) {
if (ferror(stdout)) {
@@ -3329,9 +3335,6 @@ execcmd(Estate state, int input, int output, int how, int last1)
DPUTS(varspc,
"BUG: assignment before complex command");
list_pipe = 0;
- if (subsh_close >= 0)
- zclose(subsh_close);
- subsh_close = -1;
/* If we're forked (and we should be), no need to return */
DPUTS(last1 != 1 && !forked, "BUG: not exiting?");
DPUTS(type != WC_SUBSH, "Not sure what we're doing.");
@@ -3874,9 +3877,7 @@ getoutputfile(char *cmd, char **eptr)
untokenize(s);
}
- if (!jobtab[thisjob].filelist)
- jobtab[thisjob].filelist = znewlinklist();
- zaddlinknode(jobtab[thisjob].filelist, nam);
+ addfilelist(nam, 0);
if (!s)
child_block();
@@ -3962,9 +3963,7 @@ getproc(char *cmd, char **eptr)
return NULL;
if (!(prog = parsecmd(cmd, eptr)))
return NULL;
- if (!jobtab[thisjob].filelist)
- jobtab[thisjob].filelist = znewlinklist();
- zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
+ addfilelist(pnam, 0);
if ((pid = zfork(&bgtime))) {
if (pid == -1)
@@ -3982,7 +3981,7 @@ getproc(char *cmd, char **eptr)
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(fd, out);
#else /* PATH_DEV_FD */
- int pipes[2];
+ int pipes[2], fd;
if (thisjob == -1)
return NULL;
@@ -3999,7 +3998,9 @@ getproc(char *cmd, char **eptr)
zclose(pipes[!out]);
return NULL;
}
- fdtable[pipes[!out]] = FDT_PROC_SUBST;
+ fd = pipes[!out];
+ fdtable[fd] = FDT_PROC_SUBST;
+ addfilelist(NULL, fd);
if (!out)
{
addproc(pid, NULL, 1, &bgtime);
@@ -4614,6 +4615,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
}
starttrapscope();
+ startpatternscope();
pptab = pparams;
if (!(flags & PM_UNDEFINED))
@@ -4661,6 +4663,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
offptr++)
opts[*offptr] = 0;
}
+ /* All emulations start with pattern disables clear */
+ clearpatterndisables();
} else
restore_sticky = 0;
@@ -4761,6 +4765,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
scriptname = oldscriptname;
oflags = ooflags;
+ endpatternscope(); /* before restoring old LOCALPATTERNS */
+
if (restore_sticky) {
/*
* If we switched to an emulation environment just for
@@ -5070,7 +5076,6 @@ execsave(void)
es->trapisfunc = trapisfunc;
es->traplocallevel = traplocallevel;
es->noerrs = noerrs;
- es->subsh_close = subsh_close;
es->underscore = ztrdup(zunderscore);
es->next = exstack;
exstack = es;
@@ -5081,30 +5086,33 @@ execsave(void)
void
execrestore(void)
{
- struct execstack *en;
+ struct execstack *en = exstack;
DPUTS(!exstack, "BUG: execrestore() without execsave()");
- list_pipe_pid = exstack->list_pipe_pid;
- nowait = exstack->nowait;
- pline_level = exstack->pline_level;
- list_pipe_child = exstack->list_pipe_child;
- list_pipe_job = exstack->list_pipe_job;
- strcpy(list_pipe_text, exstack->list_pipe_text);
- lastval = exstack->lastval;
- noeval = exstack->noeval;
- badcshglob = exstack->badcshglob;
- cmdoutpid = exstack->cmdoutpid;
- cmdoutval = exstack->cmdoutval;
- use_cmdoutval = exstack->use_cmdoutval;
- trap_return = exstack->trap_return;
- trap_state = exstack->trap_state;
- trapisfunc = exstack->trapisfunc;
- traplocallevel = exstack->traplocallevel;
- noerrs = exstack->noerrs;
- subsh_close = exstack->subsh_close;
- setunderscore(exstack->underscore);
- zsfree(exstack->underscore);
- en = exstack->next;
- free(exstack);
- exstack = en;
+
+ queue_signals();
+ exstack = exstack->next;
+
+ list_pipe_pid = en->list_pipe_pid;
+ nowait = en->nowait;
+ pline_level = en->pline_level;
+ list_pipe_child = en->list_pipe_child;
+ list_pipe_job = en->list_pipe_job;
+ strcpy(list_pipe_text, en->list_pipe_text);
+ lastval = en->lastval;
+ noeval = en->noeval;
+ badcshglob = en->badcshglob;
+ cmdoutpid = en->cmdoutpid;
+ cmdoutval = en->cmdoutval;
+ use_cmdoutval = en->use_cmdoutval;
+ trap_return = en->trap_return;
+ trap_state = en->trap_state;
+ trapisfunc = en->trapisfunc;
+ traplocallevel = en->traplocallevel;
+ noerrs = en->noerrs;
+ setunderscore(en->underscore);
+ zsfree(en->underscore);
+ free(en);
+
+ unqueue_signals();
}
diff --git a/Src/glob.c b/Src/glob.c
index ca2ffaf51..e0d0cf68e 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -445,41 +445,6 @@ insert(char *s, int checked)
unqueue_signals();
}
-/* Check to see if str is eligible for filename generation. */
-
-/**/
-mod_export int
-haswilds(char *str)
-{
- /* `[' and `]' are legal even if bad patterns are usually not. */
- if ((*str == Inbrack || *str == Outbrack) && !str[1])
- return 0;
-
- /* If % is immediately followed by ?, then that ? is *
- * not treated as a wildcard. This is so you don't have *
- * to escape job references such as %?foo. */
- if (str[0] == '%' && str[1] == Quest)
- str[1] = '?';
-
- for (; *str; str++) {
- switch (*str) {
- case Inpar:
- case Bar:
- case Star:
- case Inbrack:
- case Inang:
- case Quest:
- return 1;
- case Pound:
- case Hat:
- if (isset(EXTENDEDGLOB))
- return 1;
- break;
- }
- }
- return 0;
-}
-
/* Do the globbing: scanner is called recursively *
* with successive bits of the path until we've *
* tried all of it. */
@@ -708,8 +673,9 @@ parsecomplist(char *instr)
}
/* Parse repeated directories such as (dir/)# and (dir/)## */
- if (*(str = instr) == Inpar && !skipparens(Inpar, Outpar, (char **)&str) &&
- *str == Pound && isset(EXTENDEDGLOB) && str[-2] == '/') {
+ if (*(str = instr) == zpc_special[ZPC_INPAR] &&
+ !skipparens(Inpar, Outpar, (char **)&str) &&
+ *str == zpc_special[ZPC_HASH] && str[-2] == '/') {
instr++;
if (!(p1 = patcompile(instr, compflags, &instr)))
return NULL;
@@ -761,9 +727,9 @@ parsepat(char *str)
* Check for initial globbing flags, so that they don't form
* a bogus path component.
*/
- if ((*str == Inpar && str[1] == Pound && isset(EXTENDEDGLOB)) ||
- (isset(KSHGLOB) && *str == '@' && str[1] == Inpar &&
- str[2] == Pound)) {
+ if ((*str == zpc_special[ZPC_INPAR] && str[1] == zpc_special[ZPC_HASH]) ||
+ (*str == zpc_special[ZPC_KSH_AT] && str[1] == Inpar &&
+ str[2] == zpc_special[ZPC_HASH])) {
str += (*str == Inpar) ? 2 : 3;
if (!patgetglobflags(&str, &assert, &ignore))
return NULL;
@@ -1146,7 +1112,8 @@ zglob(LinkList list, LinkNode np, int nountok)
gf_pre_words = NULL;
/* Check for qualifiers */
- while (!nobareglob || isset(EXTENDEDGLOB)) {
+ while (!nobareglob ||
+ (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH])) {
struct qual *newquals;
char *s;
int sense, paren;
@@ -1192,10 +1159,11 @@ zglob(LinkList list, LinkNode np, int nountok)
case Outpar:
paren++; /*FALLTHROUGH*/
case Bar:
- nobareglob = 1;
+ if (!zpc_disables[ZPC_BAR])
+ nobareglob = 1;
break;
case Tilde:
- if (isset(EXTENDEDGLOB))
+ if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_TILDE])
nobareglob = 1;
break;
case Inpar:
@@ -1205,7 +1173,7 @@ zglob(LinkList list, LinkNode np, int nountok)
}
if (*s != Inpar)
break;
- if (isset(EXTENDEDGLOB) && s[1] == Pound) {
+ if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH] && s[1] == Pound) {
if (s[2] == 'q') {
*s = 0;
s += 2;
@@ -1644,7 +1612,8 @@ zglob(LinkList list, LinkNode np, int nountok)
break;
}
default:
- zerr("unknown file attribute");
+ untokenize(--s);
+ zerr("unknown file attribute: %c", *s);
restore_globstate(saved);
return;
}
diff --git a/Src/hist.c b/Src/hist.c
index 561e2acd5..1845bd8ad 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -76,6 +76,9 @@ mod_export int excs, exlast;
* and a temporary history entry is inserted while the user is editing.
* If the resulting line was not added to the list, a flag is set so
* that curhist will be decremented in hbegin().
+ *
+ * Note curhist is passed to zle on variable length argument list:
+ * type must match that retrieved in zle_main_entry.
*/
/**/
@@ -518,6 +521,12 @@ histsubchar(int c)
}
c = ingetc();
}
+ if (ptr == buf &&
+ (c == '}' || c == ';' || c == '\'' || c == '"' || c == '`')) {
+ /* Neither event nor word designator, no expansion */
+ safeinungetc(c);
+ return bangchar;
+ }
*ptr = 0;
if (!*buf) {
if (c != '%') {
@@ -868,6 +877,8 @@ unlinkcurline(void)
mod_export void
hbegin(int dohist)
{
+ char *hf;
+
isfirstln = isfirstch = 1;
errflag = histdone = 0;
if (!dohist)
@@ -921,13 +932,35 @@ hbegin(int dohist)
defev = addhistnum(curhist, -1, HIST_FOREIGN);
} else
histactive = HA_ACTIVE | HA_NOINC;
+
+ hf = getsparam("HISTFILE");
+ /*
+ * For INCAPPENDHISTORY, when interactive, save the history here
+ * as it gives a better estimate of the times of commands.
+ *
+ * If SHAREHISTORY is also set continue to do so in the
+ * standard place, because that's safer about reading and
+ * rewriting history atomically.
+ *
+ * The histsave_stack_pos test won't usually fail here.
+ * We need to test the opposite for the hend() case because we
+ * need to save in the history file we've switched to, but then
+ * we pop immediately after that so the variable becomes zero.
+ * We will already have saved the line and restored the history
+ * so that (correctly) nothing happens here. But it shows
+ * I thought about it.
+ */
+ if (isset(INCAPPENDHISTORY) && !isset(SHAREHISTORY) &&
+ !(histactive & HA_NOINC) && !strin && histsave_stack_pos == 0)
+ savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
}
/**/
void
histreduceblanks(void)
{
- int i, len, pos, needblank, spacecount = 0;
+ int i, len, pos, needblank, spacecount = 0, trunc_ok;
+ char *lastptr, *ptr;
if (isset(HISTIGNORESPACE))
while (chline[spacecount] == ' ') spacecount++;
@@ -939,17 +972,41 @@ histreduceblanks(void)
if (chline[len] == '\0')
return;
+ /* Remember where the delimited words end */
+ if (chwordpos)
+ lastptr = chline + chwords[chwordpos-1];
+ else
+ lastptr = chline;
+
for (i = 0, pos = spacecount; i < chwordpos; i += 2) {
len = chwords[i+1] - chwords[i];
needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]);
if (pos != chwords[i]) {
- memcpy(chline + pos, chline + chwords[i], len + needblank);
+ memmove(chline + pos, chline + chwords[i], len + needblank);
chwords[i] = pos;
chwords[i+1] = chwords[i] + len;
}
pos += len + needblank;
}
- chline[pos] = '\0';
+
+ /*
+ * A terminating comment isn't recorded as a word.
+ * Only truncate the line if just whitespace remains.
+ */
+ trunc_ok = 1;
+ for (ptr = lastptr; *ptr; ptr++) {
+ if (!inblank(*ptr)) {
+ trunc_ok = 0;
+ break;
+ }
+ }
+ if (trunc_ok) {
+ chline[pos] = '\0';
+ } else {
+ ptr = chline + pos;
+ while ((*ptr++ = *lastptr++))
+ ;
+ }
}
/**/
@@ -1169,7 +1226,15 @@ mod_export int
hend(Eprog prog)
{
LinkList hookargs = newlinklist();
- int flag, save = 1, hookret, stack_pos = histsave_stack_pos;
+ int flag, hookret, stack_pos = histsave_stack_pos;
+ /*
+ * save:
+ * 0: don't save
+ * 1: save normally
+ * -1: save temporarily, delete after next line
+ * -2: save internally but mark for not writing
+ */
+ int save = 1;
char *hf;
DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline,
@@ -1222,7 +1287,11 @@ hend(Eprog prog)
}
if (chwordpos <= 2)
save = 0;
- else if (hookret || should_ignore_line(prog))
+ else if (should_ignore_line(prog))
+ save = -1;
+ else if (hookret == 2)
+ save = -2;
+ else if (hookret)
save = -1;
}
if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) {
@@ -1268,7 +1337,12 @@ hend(Eprog prog)
if (isset(HISTREDUCEBLANKS))
histreduceblanks();
}
- newflags = save > 0? 0 : HIST_TMPSTORE;
+ if (save == -1)
+ newflags = HIST_TMPSTORE;
+ else if (save == -2)
+ newflags = HIST_NOWRITE;
+ else
+ newflags = 0;
if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0
&& hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) {
/* This history entry compares the same as the previous.
@@ -1300,7 +1374,11 @@ hend(Eprog prog)
chline = hptr = NULL;
chwords = NULL;
histactive = 0;
- if (isset(SHAREHISTORY)? histfileIsLocked() : isset(INCAPPENDHISTORY))
+ /*
+ * For normal INCAPPENDHISTORY case and reasoning, see hbegin().
+ */
+ if (isset(SHAREHISTORY) ? histfileIsLocked() :
+ (isset(INCAPPENDHISTORY) && histsave_stack_pos != 0))
savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
/*
@@ -2389,6 +2467,9 @@ readhistfile(char *fn, int err, int readflags)
zerr("can't read history file %s", fn);
unlockhistfile(fn);
+
+ if (zleactive)
+ zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
}
#ifdef HAVE_FCNTL_H
@@ -2519,14 +2600,29 @@ savehistfile(char *fn, int err, int writeflags)
}
}
if (out) {
+ char *history_ignore;
+ Patprog histpat = NULL;
+
+ pushheap();
+
+ if ((history_ignore = getsparam("HISTORY_IGNORE")) != NULL) {
+ tokenize(history_ignore = dupstring(history_ignore));
+ remnulargs(history_ignore);
+ histpat = patcompile(history_ignore, 0, NULL);
+ }
+
ret = 0;
for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
|| (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
|| he->node.flags & HIST_TMPSTORE)
continue;
+ if (histpat &&
+ pattry(histpat, metafy(he->node.nam, -1, META_HEAPDUP))) {
+ continue;
+ }
if (writeflags & HFILE_SKIPOLD) {
- if (he->node.flags & HIST_OLD)
+ if (he->node.flags & (HIST_OLD|HIST_NOWRITE))
continue;
he->node.flags |= HIST_OLD;
if (writeflags & HFILE_USE_OPTIONS)
@@ -2604,6 +2700,8 @@ savehistfile(char *fn, int err, int writeflags)
histactive = remember_histactive;
}
}
+
+ popheap();
} else
ret = -1;
@@ -3314,6 +3412,8 @@ pushhiststack(char *hf, zlong hs, zlong shs, int level)
}
hist_ring = NULL;
curhist = histlinect = 0;
+ if (zleactive)
+ zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
histsiz = hs;
savehistsiz = shs;
inithist(); /* sets histtab */
@@ -3353,6 +3453,8 @@ pophiststack(void)
histtab = h->histtab;
hist_ring = h->hist_ring;
curhist = h->curhist;
+ if (zleactive)
+ zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
histlinect = h->histlinect;
histsiz = h->histsiz;
savehistsiz = h->savehistsiz;
diff --git a/Src/init.c b/Src/init.c
index 8467a739c..7032ff8ae 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -281,9 +281,10 @@ parseargs(char **argv, char **runscript)
/**/
static void
-parseopts_insert(LinkList optlist, void *ptr)
+parseopts_insert(LinkList optlist, void *base, int optno)
{
LinkNode node;
+ void *ptr = base + (optno < 0 ? -optno : optno);
for (node = firstnode(optlist); node; incnode(node)) {
if (ptr < getdata(node)) {
@@ -390,7 +391,7 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
if (dosetopt(optno, action, !nam, new_opts) && nam) {
WARN_OPTION("can't change option: %s", *argv);
} else if (optlist) {
- parseopts_insert(optlist, new_opts+optno);
+ parseopts_insert(optlist, new_opts, optno);
}
}
break;
@@ -415,7 +416,7 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
if (dosetopt(optno, action, !nam, new_opts) && nam) {
WARN_OPTION("can't change option: -%c", **argv);
} else if (optlist) {
- parseopts_insert(optlist, new_opts+optno);
+ parseopts_insert(optlist, new_opts, optno);
}
}
}
@@ -1113,6 +1114,7 @@ init_signals(void)
install_handler(SIGCHLD);
#ifdef SIGWINCH
install_handler(SIGWINCH);
+ winch_block(); /* See utils.c:preprompt() */
#endif
if (interact) {
install_handler(SIGALRM);
@@ -1582,6 +1584,7 @@ zsh_main(UNUSED(int argc), char **argv)
fdtable_size = zopenmax();
fdtable = zshcalloc(fdtable_size*sizeof(*fdtable));
+ fdtable[0] = fdtable[1] = fdtable[2] = FDT_EXTERNAL;
createoptiontable();
emulate(zsh_name, 1, &emulation, opts); /* initialises most options */
diff --git a/Src/input.c b/Src/input.c
index 5cff22da4..4ac7e6ec8 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -142,12 +142,14 @@ shingetline(void)
char *p;
p = buf;
+ winch_unblock();
for (;;) {
do {
errno = 0;
c = fgetc(bshin);
} while (c < 0 && errno == EINTR);
if (c < 0 || c == '\n') {
+ winch_block();
if (c == '\n')
*p++ = '\n';
if (p > buf) {
@@ -163,11 +165,13 @@ shingetline(void)
} else
*p++ = c;
if (p >= buf + BUFSIZ - 1) {
+ winch_block();
line = zrealloc(line, ll + (p - buf) + 1);
memcpy(line + ll, buf, p - buf);
ll += p - buf;
line[ll] = '\0';
p = buf;
+ winch_unblock();
}
}
}
diff --git a/Src/jobs.c b/Src/jobs.c
index 0dbb10b4f..371b8eb32 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -376,6 +376,36 @@ check_cursh_sig(int sig)
}
}
+/**/
+void
+storepipestats(Job jn, int inforeground, int fixlastval)
+{
+ int i, pipefail = 0, jpipestats[MAX_PIPESTATS];
+ Process p;
+
+ for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++) {
+ jpipestats[i] = ((WIFSIGNALED(p->status)) ?
+ 0200 | WTERMSIG(p->status) :
+ WEXITSTATUS(p->status));
+ if (jpipestats[i])
+ pipefail = jpipestats[i];
+ }
+ if (inforeground) {
+ memcpy(pipestats, jpipestats, sizeof(int)*i);
+ if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
+ pipestats[i++] = lastval;
+ numpipestats = i;
+ }
+
+ if (fixlastval) {
+ if (jn->stat & STAT_CURSH) {
+ if (!lastval && isset(PIPEFAIL))
+ lastval = pipefail;
+ } else if (isset(PIPEFAIL))
+ lastval = pipefail;
+ }
+}
+
/* Update status of job, possibly printing it */
/**/
@@ -507,17 +537,13 @@ update_job(Job jn)
return;
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
STAT_CHANGED | STAT_DONE;
- if (job == thisjob && (jn->stat & STAT_DONE)) {
- int i;
- Process p;
-
- for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++)
- pipestats[i] = ((WIFSIGNALED(p->status)) ?
- 0200 | WTERMSIG(p->status) :
- WEXITSTATUS(p->status));
- if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
- pipestats[i++] = lastval;
- numpipestats = i;
+ if (jn->stat & STAT_DONE) {
+ /* This may be redundant with printjob() but note that inforeground
+ * is true here for STAT_CURSH jobs even when job != thisjob, most
+ * likely because thisjob = -1 from exec.c:execsimple() trickery.
+ * However, if we reset lastval here we break it for printjob().
+ */
+ storepipestats(jn, inforeground, 0);
}
if (!inforeground &&
(jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) {
@@ -915,10 +941,13 @@ printjob(Job jn, int lng, int synch)
int doneprint = 0, skip_print = 0;
FILE *fout = (synch == 2 || !shout) ? stdout : shout;
- if (oldjobtab != NULL)
+ if (synch > 1 && oldjobtab != NULL)
job = jn - oldjobtab;
else
job = jn - jobtab;
+ DPUTS3(job < 0 || job > (oldjobtab && synch > 1 ? oldmaxjob : maxjob),
+ "bogus job number, jn = %L, jobtab = %L, oldjobtab = %L",
+ (long)jn, (long)jobtab, (long)oldjobtab);
if (jn->stat & STAT_NOPRINT) {
skip_print = 1;
@@ -968,6 +997,9 @@ printjob(Job jn, int lng, int synch)
if (skip_print) {
if (jn->stat & STAT_DONE) {
+ /* This looks silly, but see update_job() */
+ if (synch <= 1)
+ storepipestats(jn, job == thisjob, job == thisjob);
if (should_report_time(jn))
dumptime(jn);
deletejob(jn, 0);
@@ -1083,9 +1115,9 @@ printjob(Job jn, int lng, int synch)
fflush(fout);
}
-/* print "(pwd now: foo)" messages: with (lng & 4) we are printing
- * the directory where the job is running, otherwise the current directory
- */
+ /* print "(pwd now: foo)" messages: with (lng & 4) we are printing
+ * the directory where the job is running, otherwise the current directory
+ */
if ((lng & 4) || (interact && job == thisjob &&
jn->pwd && strcmp(jn->pwd, pwd))) {
@@ -1095,9 +1127,13 @@ printjob(Job jn, int lng, int synch)
fprintf(fout, ")\n");
fflush(fout);
}
-/* delete job if done */
+
+ /* delete job if done */
if (jn->stat & STAT_DONE) {
+ /* This looks silly, but see update_job() */
+ if (synch <= 1)
+ storepipestats(jn, job == thisjob, job == thisjob);
if (should_report_time(jn))
dumptime(jn);
deletejob(jn, 0);
@@ -1113,16 +1149,48 @@ printjob(Job jn, int lng, int synch)
return doneprint;
}
+/* Add a file to be deleted or fd to be closed to the current job */
+
+/**/
+void
+addfilelist(const char *name, int fd)
+{
+ Jobfile jf = (Jobfile)zalloc(sizeof(struct jobfile));
+ LinkList ll = jobtab[thisjob].filelist;
+
+ if (!ll)
+ ll = jobtab[thisjob].filelist = znewlinklist();
+ if (name)
+ {
+ jf->u.name = ztrdup(name);
+ jf->is_fd = 0;
+ }
+ else
+ {
+ jf->u.fd = fd;
+ jf->is_fd = 1;
+ }
+ zaddlinknode(ll, jf);
+}
+
+/* Finished with list of files for a job */
+
/**/
void
deletefilelist(LinkList file_list, int disowning)
{
- char *s;
+ Jobfile jf;
if (file_list) {
- while ((s = (char *)getlinknode(file_list))) {
- if (!disowning)
- unlink(s);
- zsfree(s);
+ while ((jf = (Jobfile)getlinknode(file_list))) {
+ if (jf->is_fd) {
+ if (!disowning)
+ zclose(jf->u.fd);
+ } else {
+ if (!disowning)
+ unlink(jf->u.name);
+ zsfree(jf->u.name);
+ }
+ zfree(jf, sizeof(*jf));
}
zfree(file_list, sizeof(struct linklist));
}
@@ -1336,6 +1404,31 @@ zwaitjob(int job, int wait_cmd)
jn->stat |= STAT_LOCKED;
if (jn->stat & STAT_CHANGED)
printjob(jn, !!isset(LONGLISTJOBS), 1);
+ if (jn->filelist) {
+ /*
+ * The main shell is finished with any file descriptors used
+ * for process substitution associated with this job: close
+ * them to indicate to listeners there's no more input.
+ *
+ * Note we can't safely delete temporary files yet as these
+ * are directly visible to other processes. However,
+ * we can't deadlock on the fact that those still exist, so
+ * that's not a problem.
+ */
+ LinkNode node = firstnode(jn->filelist);
+ while (node) {
+ Jobfile jf = (Jobfile)getdata(node);
+ if (jf->is_fd) {
+ LinkNode next = nextnode(node);
+ (void)remnode(jn->filelist, node);
+ zclose(jf->u.fd);
+ zfree(jf, sizeof(*jf));
+ node = next;
+ } else {
+ incnode(node);
+ }
+ }
+ }
while (!errflag && jn->stat &&
!(jn->stat & STAT_DONE) &&
!(interact && (jn->stat & STAT_STOPPED))) {
@@ -2522,6 +2615,8 @@ acquire_pgrp(void)
while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
mypgrp = GETPGRP();
if (mypgrp == mypid) {
+ if (!interact)
+ break; /* attachtty() will be a no-op, give up */
signal_setmask(oldset);
attachtty(mypgrp); /* Might generate SIGT* */
signal_block(blockset);
diff --git a/Src/lex.c b/Src/lex.c
index ac87e5ec8..d0f845020 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -778,6 +778,7 @@ gettok(void)
bptr = tokstr = (char *)hcalloc(bsiz = 32);
add(c);
}
+ hwend();
while ((c = ingetc()) != '\n' && !lexstop) {
hwaddc(c);
addtoline(c);
diff --git a/Src/math.c b/Src/math.c
index e90d6a59a..eae283d19 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -362,8 +362,9 @@ mathevall(char *s, enum prec_type prec_tp, char **ep)
if (mlevel >= MAX_MLEVEL) {
xyyval.type = MN_INTEGER;
xyyval.u.l = 0;
+ *ep = s;
- zerr("math recursion limit exceeded");
+ zerr("math recursion limit exceeded: %s", *ep);
return xyyval;
}
@@ -456,6 +457,11 @@ lexconstant(void)
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
/* Should we set lastbase here? */
lastbase = 16;
+ if (isset(FORCEFLOAT))
+ {
+ yyval.type = MN_FLOAT;
+ yyval.u.d = (double)yyval.u.l;
+ }
return NUM;
}
else if (isset(OCTALZEROES))
@@ -475,6 +481,11 @@ lexconstant(void)
{
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
lastbase = 8;
+ if (isset(FORCEFLOAT))
+ {
+ yyval.type = MN_FLOAT;
+ yyval.u.d = (double)yyval.u.l;
+ }
return NUM;
}
nptr = ptr2;
@@ -537,6 +548,11 @@ lexconstant(void)
lastbase = yyval.u.l;
yyval.u.l = zstrtol_underscore(ptr, &ptr, lastbase, 1);
}
+ if (isset(FORCEFLOAT))
+ {
+ yyval.type = MN_FLOAT;
+ yyval.u.d = (double)yyval.u.l;
+ }
}
return NUM;
}
@@ -1443,7 +1459,8 @@ mathparse(int pc)
case QUEST:
if (stack[sp].val.type == MN_UNSET)
stack[sp].val = getmathparam(stack + sp);
- q = (stack[sp].val.type == MN_FLOAT) ? (zlong)stack[sp].val.u.d :
+ q = (stack[sp].val.type == MN_FLOAT) ?
+ (stack[sp].val.u.d == 0 ? 0 : 1) :
stack[sp].val.u.l;
if (!q)
diff --git a/Src/options.c b/Src/options.c
index b36bd9944..ce73d9901 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -131,6 +131,7 @@ static struct optname optns[] = {
{{NULL, "extendedhistory", OPT_CSH}, EXTENDEDHISTORY},
{{NULL, "evallineno", OPT_EMULATE|OPT_ZSH}, EVALLINENO},
{{NULL, "flowcontrol", OPT_ALL}, FLOWCONTROL},
+{{NULL, "forcefloat", 0}, FORCEFLOAT},
{{NULL, "functionargzero", OPT_EMULATE|OPT_NONBOURNE},FUNCTIONARGZERO},
{{NULL, "glob", OPT_EMULATE|OPT_ALL}, GLOBOPT},
{{NULL, "globalexport", OPT_EMULATE|OPT_ZSH}, GLOBALEXPORT},
@@ -178,6 +179,7 @@ static struct optname optns[] = {
{{NULL, "listrowsfirst", 0}, LISTROWSFIRST},
{{NULL, "listtypes", OPT_ALL}, LISTTYPES},
{{NULL, "localoptions", OPT_EMULATE|OPT_KSH}, LOCALOPTIONS},
+{{NULL, "localpatterns", OPT_EMULATE}, LOCALPATTERNS},
{{NULL, "localtraps", OPT_EMULATE|OPT_KSH}, LOCALTRAPS},
{{NULL, "login", OPT_SPECIAL}, LOGINSHELL},
{{NULL, "longlistjobs", 0}, LONGLISTJOBS},
@@ -203,6 +205,7 @@ static struct optname optns[] = {
{{NULL, "overstrike", 0}, OVERSTRIKE},
{{NULL, "pathdirs", OPT_EMULATE}, PATHDIRS},
{{NULL, "pathscript", OPT_EMULATE|OPT_BOURNE}, PATHSCRIPT},
+{{NULL, "pipefail", OPT_EMULATE}, PIPEFAIL},
{{NULL, "posixaliases", OPT_EMULATE|OPT_BOURNE}, POSIXALIASES},
{{NULL, "posixbuiltins", OPT_EMULATE|OPT_BOURNE}, POSIXBUILTINS},
{{NULL, "posixcd", OPT_EMULATE|OPT_BOURNE}, POSIXCD},
diff --git a/Src/params.c b/Src/params.c
index 8649178ef..d6711e4fa 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -4667,10 +4667,12 @@ startparamscope(void)
mod_export void
endparamscope(void)
{
+ queue_signals();
locallevel--;
/* This pops anything from a higher locallevel */
saveandpophiststack(0, HFILE_USE_OPTIONS);
scanhashtable(paramtab, 0, 0, 0, scanendscope, 0);
+ unqueue_signals();
}
/**/
diff --git a/Src/parse.c b/Src/parse.c
index 753080d70..f0d0855d3 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2088,9 +2088,17 @@ par_cond_2(void)
}
}
if (tok == BANG) {
- condlex();
- ecadd(WCB_COND(COND_NOT, 0));
- return par_cond_2();
+ /*
+ * In "test" compatibility mode, "! -a ..." and "! -o ..."
+ * are treated as "[string] [and] ..." and "[string] [or] ...".
+ */
+ if (!(condlex == testlex && *testargs &&
+ (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o"))))
+ {
+ condlex();
+ ecadd(WCB_COND(COND_NOT, 0));
+ return par_cond_2();
+ }
}
if (tok == INPAR) {
int r;
@@ -3171,6 +3179,9 @@ load_dump_file(char *dump, struct stat *sbuf, int other, int len)
d->dev = sbuf->st_dev;
d->ino = sbuf->st_ino;
d->fd = fd;
+#ifdef FD_CLOEXEC
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0);
d->addr = addr;
d->len = len;
@@ -3415,6 +3426,16 @@ incrdumpcount(FuncDump f)
f->count++;
}
+/**/
+static void
+freedump(FuncDump f)
+{
+ munmap((void *) f->addr, f->len);
+ zclose(f->fd);
+ zsfree(f->filename);
+ zfree(f, sizeof(*f));
+}
+
/* Decrement the reference counter for a dump file. If zero, unmap the file. */
/**/
@@ -3431,23 +3452,23 @@ decrdumpcount(FuncDump f)
q->next = p->next;
else
dumps = p->next;
- munmap((void *) f->addr, f->len);
- zclose(f->fd);
- zsfree(f->filename);
- zfree(f, sizeof(*f));
+ freedump(f);
}
}
}
+#ifndef FD_CLOEXEC
/**/
mod_export void
closedumps(void)
{
- FuncDump p;
-
- for (p = dumps; p; p = p->next)
- zclose(p->fd);
+ while (dumps) {
+ FuncDump p = dumps->next;
+ freedump(dumps);
+ dumps = p;
+ }
}
+#endif
#else
@@ -3461,11 +3482,13 @@ decrdumpcount(FuncDump f)
{
}
+#ifndef FD_CLOEXEC
/**/
mod_export void
closedumps(void)
{
}
+#endif
#endif
diff --git a/Src/pattern.c b/Src/pattern.c
index 53ada0f8d..a7ef12573 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -225,34 +225,50 @@ typedef unsigned long zrange_t;
#endif
/*
- * Characters which terminate a pattern segment. We actually use
- * a pointer patendseg which skips the first character if we are not
- * parsing a file pattern.
- * Note that the size of this and the next array are hard-wired
- * via the definitions.
+ * Array of characters corresponding to zpc_chars enum, which it must match.
*/
+static const char zpc_chars[ZPC_COUNT] = {
+ '/', '\0', Bar, Outpar, Tilde, Inpar, Quest, Star, Inbrack, Inang,
+ Hat, Pound, Bnullkeep, Quest, Star, '+', '!', '@'
+};
-static char endseg[] = {
- '/', /* file only */
- '\0', Bar, Outpar, /* all patterns */
- Tilde /* extended glob only */
+/*
+ * Corresponding strings used in enable/disable -p.
+ * NULL means no way of turning this on or off.
+ */
+/**/
+mod_export const char *zpc_strings[ZPC_COUNT] = {
+ NULL, NULL, "|", NULL, "~", "(", "?", "*", "[", "<",
+ "^", "#", NULL, "?(", "*(", "+(", "!(", "@("
};
-#define PATENDSEGLEN_NORM 4
-#define PATENDSEGLEN_EXT 5
+/*
+ * Corresponding array of pattern disables as set by the user
+ * using "disable -p".
+ */
+/**/
+mod_export char zpc_disables[ZPC_COUNT];
-/* Characters which terminate a simple string */
+/*
+ * Stack of saved (compressed) zpc_disables for function scope.
+ */
-static char endstr[] = {
- '/', /* file only */
- '\0', Bar, Outpar, Quest, Star, Inbrack, Inpar, Inang, Bnullkeep,
- /* all patterns */
- Tilde, Hat, Pound /* extended glob only */
-};
+static struct zpc_disables_save *zpc_disables_stack;
-#define PATENDSTRLEN_NORM 10
-#define PATENDSTRLEN_EXT 13
+/*
+ * Characters which terminate a simple string (ZPC_COUNT) or
+ * an entire pattern segment (the first ZPC_SEG_COUNT).
+ * Each entry is either the corresponding character in zpc_chars
+ * or Marker which is guaranteed not to match a character in a
+ * pattern we are compiling.
+ *
+ * The complete list indicates characters that are special, so e.g.
+ * (testchar == special[ZPC_TILDE]) succeeds only if testchar is a Tilde
+ * *and* Tilde is currently special.
+ */
+/**/
+char zpc_special[ZPC_COUNT];
/* Default size for pattern buffer */
#define P_DEF_ALLOC 256
@@ -264,10 +280,6 @@ static char *patcode; /* point of code emission */
static long patsize; /* size of code */
static char *patout; /* start of code emission string */
static long patalloc; /* size allocated for same */
-static char *patendseg; /* characters ending segment */
-static int patendseglen; /* length of same */
-static char *patendstr; /* characters ending plain string */
-static int patendstrlen; /* length of sameo */
/* Flags used in both compilation and execution */
static int patflags; /* flags passed down to patcompile */
@@ -417,12 +429,68 @@ static long rn_offs;
(P_OP(p) == P_BACK) ? \
((p)-rn_offs) : ((p)+rn_offs) : NULL)
+/*
+ * Set up zpc_special with characters that end a string segment.
+ * "Marker" cannot occur in the pattern we are compiling so
+ * is used to mark "invalid".
+ */
+static void
+patcompcharsset(void)
+{
+ char *spp, *disp;
+ int i;
+
+ /* Initialise enabled special characters */
+ memcpy(zpc_special, zpc_chars, ZPC_COUNT);
+ /* Apply user disables from disable -p */
+ for (i = 0, spp = zpc_special, disp = zpc_disables;
+ i < ZPC_COUNT;
+ i++, spp++, disp++) {
+ if (*disp)
+ *spp = Marker;
+ }
+
+ if (!isset(EXTENDEDGLOB)) {
+ /* Extended glob characters are not active */
+ zpc_special[ZPC_TILDE] = zpc_special[ZPC_HAT] =
+ zpc_special[ZPC_HASH] = Marker;
+ }
+ if (!isset(KSHGLOB)) {
+ /*
+ * Ksh glob characters are not active.
+ * * and ? are shared with normal globbing, but for their
+ * use here we are looking for a following Inpar.
+ */
+ zpc_special[ZPC_KSH_QUEST] = zpc_special[ZPC_KSH_STAR] =
+ zpc_special[ZPC_KSH_PLUS] = zpc_special[ZPC_KSH_BANG] =
+ zpc_special[ZPC_KSH_AT] = Marker;
+ }
+ /*
+ * Note that if we are using KSHGLOB, then we test for a following
+ * Inpar, not zpc_special[ZPC_INPAR]: the latter makes an Inpar on
+ * its own active. The zpc_special[ZPC_KSH_*] followed by any old Inpar
+ * discriminate ksh globbing.
+ */
+ if (isset(SHGLOB)) {
+ /*
+ * Grouping and numeric ranges are not valid.
+ * We do allow alternation, however; it's needed for
+ * "case". This may not be entirely consistent.
+ *
+ * Don't disable Outpar: we may need to match the end of KSHGLOB
+ * parentheses and it would be difficult to tell them apart.
+ */
+ zpc_special[ZPC_INPAR] = zpc_special[ZPC_INANG] = Marker;
+ }
+}
+
/* Called before parsing a set of file matchs to initialize flags */
/**/
void
patcompstart(void)
{
+ patcompcharsset();
if (isset(CASEGLOB))
patglobflags = 0;
else
@@ -469,16 +537,9 @@ patcompile(char *exp, int inflags, char **endexp)
patnpar = 1;
patflags = inflags & ~(PAT_PURES|PAT_HAS_EXCLUDP);
- patendseg = endseg;
- patendseglen = isset(EXTENDEDGLOB) ? PATENDSEGLEN_EXT : PATENDSEGLEN_NORM;
- patendstr = endstr;
- patendstrlen = isset(EXTENDEDGLOB) ? PATENDSTRLEN_EXT : PATENDSTRLEN_NORM;
-
if (!(patflags & PAT_FILE)) {
- patendseg++;
- patendstr++;
- patendseglen--;
- patendstrlen--;
+ patcompcharsset();
+ zpc_special[ZPC_SLASH] = Marker;
remnulargs(patparse);
if (isset(MULTIBYTE))
patglobflags = GF_MULTIBYTE;
@@ -687,7 +748,7 @@ patcompswitch(int paren, int *flagp)
starter = 0;
br = patnode(P_BRANCH);
- if (!patcompbranch(&flags))
+ if (!patcompbranch(&flags, paren))
return 0;
if (patglobflags != (int)savglobflags)
gfchanged++;
@@ -698,11 +759,11 @@ patcompswitch(int paren, int *flagp)
*flagp |= flags & (P_HSTART|P_PURESTR);
- while (*patparse == Bar ||
- (isset(EXTENDEDGLOB) && *patparse == Tilde &&
+ while (*patparse == zpc_chars[ZPC_BAR] ||
+ (*patparse == zpc_special[ZPC_TILDE] &&
(patparse[1] == '/' ||
- !memchr(patendseg, patparse[1], patendseglen)))) {
- int tilde = *patparse++ == Tilde;
+ !memchr(zpc_special, patparse[1], ZPC_SEG_COUNT)))) {
+ int tilde = *patparse++ == zpc_special[ZPC_TILDE];
long gfnode = 0, newbr;
*flagp &= ~P_PURESTR;
@@ -739,12 +800,9 @@ patcompswitch(int paren, int *flagp)
up.p = NULL;
patadd((char *)&up, 0, sizeof(up), 0);
/* / is not treated as special if we are at top level */
- if (!paren && *patendseg == '/') {
+ if (!paren && zpc_special[ZPC_SLASH] == '/') {
tilde++;
- patendseg++;
- patendseglen--;
- patendstr++;
- patendstrlen--;
+ zpc_special[ZPC_SLASH] = Marker;
}
} else {
excsync = 0;
@@ -781,13 +839,10 @@ patcompswitch(int paren, int *flagp)
patglobflags = (int)savglobflags;
}
}
- newbr = patcompbranch(&flags);
+ newbr = patcompbranch(&flags, paren);
if (tilde == 2) {
/* restore special treatment of / */
- patendseg--;
- patendseglen++;
- patendstr--;
- patendstrlen++;
+ zpc_special[ZPC_SLASH] = '/';
}
if (!newbr)
return 0;
@@ -847,7 +902,7 @@ patcompswitch(int paren, int *flagp)
/**/
static long
-patcompbranch(int *flagp)
+patcompbranch(int *flagp, int paren)
{
long chain, latest = 0, starter;
int flags = 0;
@@ -855,14 +910,13 @@ patcompbranch(int *flagp)
*flagp = P_PURESTR;
starter = chain = 0;
- while (!memchr(patendseg, *patparse, patendseglen) ||
- (*patparse == Tilde && patparse[1] != '/' &&
- memchr(patendseg, patparse[1], patendseglen))) {
- if (isset(EXTENDEDGLOB) &&
- ((!isset(SHGLOB) &&
- (*patparse == Inpar && patparse[1] == Pound)) ||
- (isset(KSHGLOB) && *patparse == '@' && patparse[1] == Inpar &&
- patparse[2] == Pound))) {
+ while (!memchr(zpc_special, *patparse, ZPC_SEG_COUNT) ||
+ (*patparse == zpc_special[ZPC_TILDE] && patparse[1] != '/' &&
+ memchr(zpc_special, patparse[1], ZPC_SEG_COUNT))) {
+ if ((*patparse == zpc_special[ZPC_INPAR] &&
+ patparse[1] == zpc_special[ZPC_HASH]) ||
+ (*patparse == zpc_special[ZPC_KSH_AT] && patparse[1] == Inpar &&
+ patparse[2] == zpc_special[ZPC_HASH])) {
/* Globbing flags. */
char *pp1 = patparse;
int oldglobflags = patglobflags, ignore;
@@ -910,7 +964,7 @@ patcompbranch(int *flagp)
break;
else
continue;
- } else if (isset(EXTENDEDGLOB) && *patparse == Hat) {
+ } else if (*patparse == zpc_special[ZPC_HAT]) {
/*
* ^pat: anything but pat. For proper backtracking,
* etc., we turn this into (*~pat), except without the
@@ -919,7 +973,7 @@ patcompbranch(int *flagp)
patparse++;
latest = patcompnot(0, &flags);
} else
- latest = patcomppiece(&flags);
+ latest = patcomppiece(&flags, paren);
if (!latest)
return 0;
if (!starter)
@@ -1167,11 +1221,11 @@ pattern_range_to_string(char *rangestr, char *outstr)
/**/
static long
-patcomppiece(int *flagp)
+patcomppiece(int *flagp, int paren)
{
long starter = 0, next, op, opnd;
int flags, flags2, kshchar, len, ch, patch, nmeta;
- int pound, count;
+ int hash, count;
union upat up;
char *nptr, *str0, *ptr, *patprev;
zrange_t from, to;
@@ -1185,25 +1239,39 @@ patcomppiece(int *flagp)
* the string doesn't introduce a ksh-like parenthesized expression.
*/
kshchar = '\0';
- if (isset(KSHGLOB) && *patparse && patparse[1] == Inpar) {
- if (strchr("?*+!@", *patparse))
- kshchar = STOUC(*patparse);
- else if (*patparse == Star || *patparse == Quest)
- kshchar = STOUC(ztokens[*patparse - Pound]);
+ if (*patparse && patparse[1] == Inpar) {
+ if (*patparse == zpc_special[ZPC_KSH_PLUS])
+ kshchar = STOUC('+');
+ else if (*patparse == zpc_special[ZPC_KSH_BANG])
+ kshchar = STOUC('!');
+ else if (*patparse == zpc_special[ZPC_KSH_AT])
+ kshchar = STOUC('@');
+ else if (*patparse == zpc_special[ZPC_KSH_STAR])
+ kshchar = STOUC('*');
+ else if (*patparse == zpc_special[ZPC_KSH_QUEST])
+ kshchar = STOUC('?');
}
/*
- * End of string (or no string at all) if ksh-type parentheses,
- * or special character, unless that character is a tilde and
- * the character following is an end-of-segment character. Thus
- * tildes are not special if there is nothing following to
- * be excluded.
+ * If '(' is disabled as a pattern char, allow ')' as
+ * an ordinary string character if there are no parentheses to
+ * close. Don't allow it otherwise, it changes the syntax.
*/
- if (kshchar || (memchr(patendstr, *patparse, patendstrlen) &&
- (*patparse != Tilde ||
- patparse[1] == '/' ||
- !memchr(patendseg, patparse[1], patendseglen))))
- break;
+ if (zpc_special[ZPC_INPAR] != Marker || *patparse != Outpar ||
+ paren) {
+ /*
+ * End of string (or no string at all) if ksh-type parentheses,
+ * or special character, unless that character is a tilde and
+ * the character following is an end-of-segment character. Thus
+ * tildes are not special if there is nothing following to
+ * be excluded.
+ */
+ if (kshchar || (memchr(zpc_special, *patparse, ZPC_COUNT) &&
+ (*patparse != zpc_special[ZPC_TILDE] ||
+ patparse[1] == '/' ||
+ !memchr(zpc_special, patparse[1], ZPC_SEG_COUNT))))
+ break;
+ }
/* Remember the previous character for backtracking */
patprev = patparse;
@@ -1227,10 +1295,14 @@ patcomppiece(int *flagp)
* If we have more than one character, a following hash
* or (#c...) only applies to the last, so backtrack one character.
*/
- if (isset(EXTENDEDGLOB) &&
- (*patparse == Pound ||
- (*patparse == Inpar && patparse[1] == Pound &&
- patparse[2] == 'c')) && morelen)
+ if ((*patparse == zpc_special[ZPC_HASH] ||
+ (*patparse == zpc_special[ZPC_INPAR] &&
+ patparse[1] == zpc_special[ZPC_HASH] &&
+ patparse[2] == 'c') ||
+ (*patparse == zpc_special[ZPC_KSH_AT] &&
+ patparse[1] == Inpar &&
+ patparse[2] == zpc_special[ZPC_HASH] &&
+ patparse[3] == 'c')) && morelen)
patparse = patprev;
/*
* If len is 1, we can't have an active # following, so doesn't
@@ -1306,15 +1378,21 @@ patcomppiece(int *flagp)
METACHARINC(patparse);
switch(patch) {
case Quest:
+ DPUTS(zpc_special[ZPC_QUEST] == Marker,
+ "Treating '?' as pattern character although disabled");
flags |= P_SIMPLE;
starter = patnode(P_ANY);
break;
case Star:
+ DPUTS(zpc_special[ZPC_STAR] == Marker,
+ "Treating '*' as pattern character although disabled");
/* kshchar is used as a sign that we can't have #'s. */
kshchar = -1;
starter = patnode(P_STAR);
break;
case Inbrack:
+ DPUTS(zpc_special[ZPC_INBRACK] == Marker,
+ "Treating '[' as pattern character although disabled");
flags |= P_SIMPLE;
if (*patparse == Hat || *patparse == '^' || *patparse == '!') {
patparse++;
@@ -1368,9 +1446,10 @@ patcomppiece(int *flagp)
patadd(NULL, 0, 1, 0);
break;
case Inpar:
- /* is this how to treat parentheses in SHGLOB? */
- if (isset(SHGLOB) && !kshchar)
- return 0;
+ DPUTS(!kshchar && zpc_special[ZPC_INPAR] == Marker,
+ "Treating '(' as pattern character although disabled");
+ DPUTS(isset(SHGLOB) && !kshchar,
+ "Treating bare '(' as pattern character with SHGLOB");
if (kshchar == '!') {
/* This is nasty, we should really either handle all
* kshglobbing below or here. But most of the
@@ -1393,6 +1472,9 @@ patcomppiece(int *flagp)
break;
case Inang:
/* Numeric glob */
+ DPUTS(zpc_special[ZPC_INANG] == Marker,
+ "Treating '<' as pattern character although disabled");
+ DPUTS(isset(SHGLOB), "Treating <..> as numeric range with SHGLOB");
len = 0; /* beginning present 1, end present 2 */
if (idigit(*patparse)) {
from = (zrange_t) zstrtol((char *)patparse,
@@ -1435,6 +1517,8 @@ patcomppiece(int *flagp)
*/
break;
case Pound:
+ DPUTS(zpc_special[ZPC_HASH] == Marker,
+ "Treating '#' as pattern character although disabled");
DPUTS(!isset(EXTENDEDGLOB), "BUG: # not treated as string");
/*
* A hash here is an error; it should follow something
@@ -1447,7 +1531,7 @@ patcomppiece(int *flagp)
* Marker for restoring a backslash in output:
* does not match a character.
*/
- next = patcomppiece(flagp);
+ next = patcomppiece(flagp, paren);
/*
* Can't match a pure string since we need to do this
* as multiple chunks.
@@ -1465,16 +1549,21 @@ patcomppiece(int *flagp)
}
count = 0;
- if (!(pound = (*patparse == Pound && isset(EXTENDEDGLOB))) &&
- !(count = (isset(EXTENDEDGLOB) && *patparse == Inpar &&
- patparse[1] == Pound && patparse[2] == 'c')) &&
+ if (!(hash = (*patparse == zpc_special[ZPC_HASH])) &&
+ !(count = ((*patparse == zpc_special[ZPC_INPAR] &&
+ patparse[1] == zpc_special[ZPC_HASH] &&
+ patparse[2] == 'c') ||
+ (*patparse == zpc_special[ZPC_KSH_AT] &&
+ patparse[1] == Inpar &&
+ patparse[2] == zpc_special[ZPC_HASH] &&
+ patparse[3] == 'c'))) &&
(kshchar <= 0 || kshchar == '@' || kshchar == '!')) {
*flagp = flags;
return starter;
}
/* too much at once doesn't currently work */
- if (kshchar && pound)
+ if (kshchar && (hash || count))
return 0;
if (kshchar == '*') {
@@ -1490,7 +1579,7 @@ patcomppiece(int *flagp)
op = P_COUNT;
patparse += 3;
*flagp = P_HSTART;
- } else if (*++patparse == Pound) {
+ } else if (*++patparse == zpc_special[ZPC_HASH]) {
op = P_TWOHASH;
patparse++;
*flagp = P_HSTART;
@@ -1600,7 +1689,7 @@ patcomppiece(int *flagp)
pattail(starter, next);
patoptail(starter, next);
}
- if (*patparse == Pound)
+ if (*patparse == zpc_special[ZPC_HASH])
return 0;
return starter;
@@ -1629,7 +1718,7 @@ patcompnot(int paren, int *flagsp)
pattail(starter, excl = patnode(P_EXCLUDE));
up.p = NULL;
patadd((char *)&up, 0, sizeof(up), 0);
- if (!(br = (paren ? patcompswitch(1, &dummy) : patcompbranch(&dummy))))
+ if (!(br = (paren ? patcompswitch(1, &dummy) : patcompbranch(&dummy, 0))))
return 0;
pattail(br, patnode(P_EXCEND));
n = patnode(P_NOTHING); /* just so much easier */
@@ -3753,3 +3842,212 @@ freepatprog(Patprog prog)
if (prog && prog != dummy_patprog1 && prog != dummy_patprog2)
zfree(prog, prog->size);
}
+
+/* Disable or reenable a pattern character */
+
+/**/
+int
+pat_enables(const char *cmd, char **patp, int enable)
+{
+ int ret = 0;
+ const char **stringp;
+ char *disp;
+
+ if (!*patp) {
+ int done = 0;
+ for (stringp = zpc_strings, disp = zpc_disables;
+ stringp < zpc_strings + ZPC_COUNT;
+ stringp++, disp++) {
+ if (!*stringp)
+ continue;
+ if (enable ? *disp : !*disp)
+ continue;
+ if (done)
+ putc(' ', stdout);
+ printf("'%s'", *stringp);
+ done = 1;
+ }
+ if (done)
+ putc('\n', stdout);
+ return 0;
+ }
+
+ for (; *patp; patp++) {
+ for (stringp = zpc_strings, disp = zpc_disables;
+ stringp < zpc_strings + ZPC_COUNT;
+ stringp++, disp++) {
+ if (*stringp && !strcmp(*stringp, *patp)) {
+ *disp = (char)!enable;
+ break;
+ }
+ }
+ if (stringp == zpc_strings + ZPC_COUNT) {
+ zerrnam(cmd, "invalid pattern: %s", *patp);
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Save the current state of pattern disables, returning the saved value.
+ */
+
+/**/
+unsigned int
+savepatterndisables(void)
+{
+ unsigned int disables, bit;
+ char *disp;
+
+ disables = 0;
+ for (bit = 1, disp = zpc_disables;
+ disp < zpc_disables + ZPC_COUNT;
+ bit <<= 1, disp++) {
+ if (*disp)
+ disables |= bit;
+ }
+ return disables;
+}
+
+/*
+ * Function scope saving pattern enables.
+ */
+
+/**/
+void
+startpatternscope(void)
+{
+ Zpc_disables_save newdis;
+
+ newdis = (Zpc_disables_save)zalloc(sizeof(*newdis));
+ newdis->next = zpc_disables_stack;
+ newdis->disables = savepatterndisables();
+
+ zpc_disables_stack = newdis;
+}
+
+/*
+ * Restore completely the state of pattern disables.
+ */
+
+/**/
+void
+restorepatterndisables(unsigned int disables)
+{
+ char *disp;
+ unsigned int bit;
+
+ for (bit = 1, disp = zpc_disables;
+ disp < zpc_disables + ZPC_COUNT;
+ bit <<= 1, disp++) {
+ if (disables & bit)
+ *disp = 1;
+ else
+ *disp = 0;
+ }
+}
+
+/*
+ * Function scope to restore pattern enables if localpatterns is turned on.
+ */
+
+/**/
+void
+endpatternscope(void)
+{
+ Zpc_disables_save olddis;
+
+ olddis = zpc_disables_stack;
+ zpc_disables_stack = olddis->next;
+
+ if (isset(LOCALPATTERNS))
+ restorepatterndisables(olddis->disables);
+
+ zfree(olddis, sizeof(*olddis));
+}
+
+/* Reinitialise pattern disables */
+
+/**/
+void
+clearpatterndisables(void)
+{
+ memset(zpc_disables, 0, ZPC_COUNT);
+}
+
+
+/* Check to see if str is eligible for filename generation. */
+
+/**/
+mod_export int
+haswilds(char *str)
+{
+ char *start;
+
+ /* `[' and `]' are legal even if bad patterns are usually not. */
+ if ((*str == Inbrack || *str == Outbrack) && !str[1])
+ return 0;
+
+ /* If % is immediately followed by ?, then that ? is *
+ * not treated as a wildcard. This is so you don't have *
+ * to escape job references such as %?foo. */
+ if (str[0] == '%' && str[1] == Quest)
+ str[1] = '?';
+
+ /*
+ * Note that at this point zpc_special has not been set up.
+ */
+ start = str;
+ for (; *str; str++) {
+ switch (*str) {
+ case Inpar:
+ if ((!isset(SHGLOB) && !zpc_disables[ZPC_INPAR]) ||
+ (str > start && isset(KSHGLOB) &&
+ ((str[-1] == Quest && !zpc_disables[ZPC_KSH_QUEST]) ||
+ (str[-1] == Star && !zpc_disables[ZPC_KSH_STAR]) ||
+ (str[-1] == '+' && !zpc_disables[ZPC_KSH_PLUS]) ||
+ (str[-1] == '!' && !zpc_disables[ZPC_KSH_BANG]) ||
+ (str[-1] == '@' && !zpc_disables[ZPC_KSH_AT]))))
+ return 1;
+ break;
+
+ case Bar:
+ if (!zpc_disables[ZPC_BAR])
+ return 1;
+ break;
+
+ case Star:
+ if (!zpc_disables[ZPC_STAR])
+ return 1;
+ break;
+
+ case Inbrack:
+ if (!zpc_disables[ZPC_INBRACK])
+ return 1;
+ break;
+
+ case Inang:
+ if (!zpc_disables[ZPC_INANG])
+ return 1;
+ break;
+
+ case Quest:
+ if (!zpc_disables[ZPC_QUEST])
+ return 1;
+ break;
+
+ case Pound:
+ if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH])
+ return 1;
+ break;
+
+ case Hat:
+ if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HAT])
+ return 1;
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/Src/prompt.c b/Src/prompt.c
index e51ce2451..95a7d4969 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -232,6 +232,33 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
return new_vars.buf;
}
+/* Parse the argument for %F and %K */
+static int
+parsecolorchar(int arg, int is_fg)
+{
+ if (bv->fm[1] == '{') {
+ char *ep;
+ bv->fm += 2; /* skip over F{ */
+ if ((ep = strchr(bv->fm, '}'))) {
+ char oc = *ep, *col, *coll;
+ *ep = '\0';
+ /* expand the contents of the argument so you can use
+ * %v for example */
+ coll = col = promptexpand(bv->fm, 0, NULL, NULL, NULL);
+ *ep = oc;
+ arg = match_colour((const char **)&coll, is_fg, 0);
+ free(col);
+ bv->fm = ep;
+ } else {
+ arg = match_colour((const char **)&bv->fm, is_fg, 0);
+ if (*bv->fm != '}')
+ bv->fm--;
+ }
+ } else
+ arg = match_colour(NULL, 1, arg);
+ return arg;
+}
+
/* Perform %- and !-expansion as required on a section of the prompt. The *
* section is ended by an instance of endchar. If doprint is 0, the valid *
* % sequences are merely skipped over, and nothing is stored. */
@@ -494,13 +521,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY);
break;
case 'F':
- if (bv->fm[1] == '{') {
- bv->fm += 2;
- arg = match_colour((const char **)&bv->fm, 1, 0);
- if (*bv->fm != '}')
- bv->fm--;
- } else
- arg = match_colour(NULL, 1, arg);
+ arg = parsecolorchar(arg, 1);
if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) {
txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK,
TXTNOFGCOLOUR);
@@ -515,13 +536,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT);
break;
case 'K':
- if (bv->fm[1] == '{') {
- bv->fm += 2;
- arg = match_colour((const char **)&bv->fm, 0, 0);
- if (*bv->fm != '}')
- bv->fm--;
- } else
- arg = match_colour(NULL, 0, arg);
+ arg = parsecolorchar(arg, 0);
if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) {
txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK,
TXTNOBGCOLOUR);
diff --git a/Src/signals.c b/Src/signals.c
index 046ee6a4a..c8f5fbcca 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -185,7 +185,7 @@ noholdintr(void)
* only the given signal */
/**/
-sigset_t
+mod_export sigset_t
signal_mask(int sig)
{
sigset_t set;
@@ -202,7 +202,8 @@ signal_mask(int sig)
/**/
#ifndef BSD_SIGNALS
-sigset_t
+/**/
+mod_export sigset_t
signal_block(sigset_t set)
{
sigset_t oset;
@@ -245,7 +246,8 @@ signal_block(sigset_t set)
/* Unblock the signals in the given signal *
* set. Return the old signal set. */
-sigset_t
+/**/
+mod_export sigset_t
signal_unblock(sigset_t set)
{
sigset_t oset;
diff --git a/Src/signals.h b/Src/signals.h
index 9541a1a02..d68096891 100644
--- a/Src/signals.h
+++ b/Src/signals.h
@@ -59,6 +59,14 @@
#define child_block() signal_block(sigchld_mask)
#define child_unblock() signal_unblock(sigchld_mask)
+#ifdef SIGWINCH
+# define winch_block() signal_block(signal_mask(SIGWINCH))
+# define winch_unblock() signal_unblock(signal_mask(SIGWINCH))
+#else
+# define winch_block() 0
+# define winch_unblock() 0
+#endif
+
/* ignore a signal */
#define signal_ignore(S) signal(S, SIG_IGN)
diff --git a/Src/subst.c b/Src/subst.c
index 974a8456d..a4df2567f 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -3707,6 +3707,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
char *y;
x = val;
+ if (!x) {
+ /* Shouldn't have got here with a NULL string. */
+ DPUTS(1, "value is NULL in paramsubst");
+ return NULL;
+ }
if (prenum || postnum)
x = dopadding(x, prenum, postnum, preone, postone,
premul, postmul
@@ -4021,7 +4026,10 @@ modify(char **str, char **ptr)
all = tmp;
t = e;
}
- *str = all;
+ if (!all)
+ *str = dupstring("");
+ else
+ *str = all;
} else {
switch (c) {
diff --git a/Src/utils.c b/Src/utils.c
index 26e2a5c2c..d1d9406c2 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1287,9 +1287,17 @@ void
preprompt(void)
{
static time_t lastperiodic;
+ time_t currentmailcheck;
LinkNode ln;
- int period = getiparam("PERIOD");
- int mailcheck = getiparam("MAILCHECK");
+ zlong period = getiparam("PERIOD");
+ zlong mailcheck = getiparam("MAILCHECK");
+
+ /*
+ * Handle any pending window size changes before we compute prompts,
+ * then block them again to avoid interrupts during prompt display.
+ */
+ winch_unblock();
+ winch_block();
if (isset(PROMPTSP) && isset(PROMPTCR) && !use_exit_printed && shout) {
/* The PROMPT_SP heuristic will move the prompt down to a new line
@@ -1330,7 +1338,7 @@ preprompt(void)
/* If 1) the parameter PERIOD exists, 2) a hook function for *
* "periodic" exists, 3) it's been greater than PERIOD since we *
* executed any such hook, then execute it now. */
- if (period && (time(NULL) > lastperiodic + period) &&
+ if (period && ((zlong)time(NULL) > (zlong)lastperiodic + period) &&
!callhookfunc("periodic", NULL, 1, NULL))
lastperiodic = time(NULL);
if (errflag)
@@ -1348,7 +1356,9 @@ preprompt(void)
return;
/* Check mail */
- if (mailcheck && (int) difftime(time(NULL), lastmailcheck) > mailcheck) {
+ currentmailcheck = time(NULL);
+ if (mailcheck &&
+ (zlong) difftime(currentmailcheck, lastmailcheck) > mailcheck) {
char *mailfile;
if (mailpath && *mailpath && **mailpath)
@@ -1364,7 +1374,7 @@ preprompt(void)
}
unqueue_signals();
}
- lastmailcheck = time(NULL);
+ lastmailcheck = currentmailcheck;
}
if (prepromptfns) {
@@ -1424,7 +1434,7 @@ checkmailpath(char **s)
}
} else if (shout) {
if (st.st_size && st.st_atime <= st.st_mtime &&
- st.st_mtime > lastmailcheck) {
+ st.st_mtime >= lastmailcheck) {
if (!u) {
fprintf(shout, "You have new mail.\n");
fflush(shout);
diff --git a/Src/zsh.h b/Src/zsh.h
index 207ef1836..a935d23ad 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -179,7 +179,11 @@ struct mathfunc {
* Take care to update the use of IMETA appropriately when adding
* tokens here.
*/
-/* Marker used in paramsubst for rc_expand_param */
+/*
+ * Marker used in paramsubst for rc_expand_param.
+ * Also used in pattern character arrays as guaranteed not to
+ * mark a character in a string.
+ */
#define Marker ((char) 0xa0)
/* chars that need to be quoted if meant literally */
@@ -370,9 +374,8 @@ enum {
#ifdef PATH_DEV_FD
/*
* Entry used by a process substition.
- * The value will be incremented on entering a function and
- * decremented on exit; we don't close entries greater than
- * FDT_PROC_SUBST except when closing everything.
+ * This marker is not tested internally as we associated the file
+ * descriptor with a job for closing.
*/
#define FDT_PROC_SUBST 6
#endif
@@ -418,6 +421,7 @@ typedef struct heap *Heap;
typedef struct heapstack *Heapstack;
typedef struct histent *Histent;
typedef struct hookdef *Hookdef;
+typedef struct jobfile *Jobfile;
typedef struct job *Job;
typedef struct linkedmod *Linkedmod;
typedef struct linknode *LinkNode;
@@ -874,6 +878,18 @@ struct eccstr {
/* Definitions for job table and job control */
/********************************************/
+/* Entry in filelist linked list in job table */
+
+struct jobfile {
+ /* Record to be deleted or closed */
+ union {
+ char *name; /* Name of file to delete */
+ int fd; /* File descriptor to close */
+ } u;
+ /* Discriminant */
+ int is_fd;
+};
+
/* entry in the job table */
struct job {
@@ -885,6 +901,7 @@ struct job {
struct process *procs; /* list of processes */
struct process *auxprocs; /* auxiliary processes e.g multios */
LinkList filelist; /* list of files to delete when done */
+ /* elements are struct jobfile */
int stty_in_env; /* if STTY=... is present */
struct ttyinfo *ty; /* the modes specified by STTY */
};
@@ -960,7 +977,6 @@ struct execstack {
int trapisfunc;
int traplocallevel;
int noerrs;
- int subsh_close;
char *underscore;
};
@@ -1375,6 +1391,55 @@ struct patprog {
#define PAT_HAS_EXCLUDP 0x0800 /* (internal): top-level path1~path2. */
#define PAT_LCMATCHUC 0x1000 /* equivalent to setting (#l) */
+/**
+ * Indexes into the array of active pattern characters.
+ * This must match the array zpc_chars in pattern.c.
+ */
+enum zpc_chars {
+ /*
+ * These characters both terminate a pattern segment and
+ * a pure string segment.
+ */
+ ZPC_SLASH, /* / active as file separator */
+ ZPC_NULL, /* \0 as string terminator */
+ ZPC_BAR, /* | for "or" */
+ ZPC_OUTPAR, /* ) for grouping */
+ ZPC_TILDE, /* ~ for exclusion (extended glob) */
+ ZPC_SEG_COUNT, /* No. of the above characters */
+ /*
+ * These characters terminate a pure string segment.
+ */
+ ZPC_INPAR = ZPC_SEG_COUNT, /* ( for grouping */
+ ZPC_QUEST, /* ? as wildcard */
+ ZPC_STAR, /* * as wildcard */
+ ZPC_INBRACK, /* [ for character class */
+ ZPC_INANG, /* < for numeric glob */
+ ZPC_HAT, /* ^ for exclusion (extended glob) */
+ ZPC_HASH, /* # for repetition (extended glob) */
+ ZPC_BNULLKEEP, /* Special backslashed null not removed */
+ ZPC_KSH_QUEST, /* ? for ?(...) in KSH_GLOB */
+ ZPC_KSH_STAR, /* * for *(...) in KSH_GLOB */
+ ZPC_KSH_PLUS, /* + for +(...) in KSH_GLOB */
+ ZPC_KSH_BANG, /* ! for !(...) in KSH_GLOB */
+ ZPC_KSH_AT, /* @ for @(...) in KSH_GLOB */
+ ZPC_COUNT /* Number of special chararacters */
+};
+
+/*
+ * Structure to save disables special characters for function scope.
+ */
+struct zpc_disables_save {
+ struct zpc_disables_save *next;
+ /*
+ * Bit vector of ZPC_COUNT disabled characters.
+ * We'll live dangerously and assumed ZPC_COUNT is no greater
+ * than the number of bits an an unsigned int.
+ */
+ unsigned int disables;
+};
+
+typedef struct zpc_disables_save *Zpc_disables_save;
+
/*
* Special match types used in character classes. These
* are represented as tokens, with Meta added. The character
@@ -1829,6 +1894,7 @@ struct histent {
#define HIST_DUP 0x00000008 /* Command duplicates a later line */
#define HIST_FOREIGN 0x00000010 /* Command came from another shell */
#define HIST_TMPSTORE 0x00000020 /* Kill when user enters another cmd */
+#define HIST_NOWRITE 0x00000040 /* Keep internally but don't write */
#define GETHIST_UPWARD (-1)
#define GETHIST_DOWNWARD 1
@@ -1988,6 +2054,7 @@ enum {
EXTENDEDHISTORY,
EVALLINENO,
FLOWCONTROL,
+ FORCEFLOAT,
FUNCTIONARGZERO,
GLOBOPT,
GLOBALEXPORT,
@@ -2035,6 +2102,7 @@ enum {
LISTROWSFIRST,
LISTTYPES,
LOCALOPTIONS,
+ LOCALPATTERNS,
LOCALTRAPS,
LOGINSHELL,
LONGLISTJOBS,
@@ -2054,6 +2122,7 @@ enum {
OVERSTRIKE,
PATHDIRS,
PATHSCRIPT,
+ PIPEFAIL,
POSIXALIASES,
POSIXBUILTINS,
POSIXCD,
@@ -2689,7 +2758,8 @@ enum {
ZLE_CMD_RESET_PROMPT,
ZLE_CMD_REFRESH,
ZLE_CMD_SET_KEYMAP,
- ZLE_CMD_GET_KEY
+ ZLE_CMD_GET_KEY,
+ ZLE_CMD_SET_HIST_LINE
};
/***************************************/
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index 6e9077676..4bc884b3d 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -39,10 +39,14 @@ params.o: patchlevel.h
version.h: $(sdir_top)/Config/version.mk zshcurses.h zshterm.h
echo '#define ZSH_VERSION "'$(VERSION)'"' > $@
-patchlevel.h: $(sdir_top)/ChangeLog
- sed -ne \
- 's/^\* *\$$''Revision: \(.*\) ''\$$/#define ZSH_PATCHLEVEL "\1"/p' \
- $(sdir_top)/ChangeLog >patchlevel.h
+patchlevel.h: FORCE
+ @if [ -f $(sdir)/$@.release ]; then \
+ cp -f $(sdir)/$@.release $@; \
+ else \
+ echo '#define ZSH_PATCHLEVEL "'`cd $(sdir) && git describe --tags --long`'"' > $@.tmp; \
+ cmp $@ $@.tmp && rm -f $@.tmp || mv $@.tmp $@; \
+ fi
+FORCE:
zshcurses.h: ../config.h
@if test x$(ZSH_CURSES_H) != x; then \
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index f38533023..e68fd62f9 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -773,7 +773,7 @@ extern short ospeed;
# define IS_DIRSEP(c) ((c) == '/')
#endif
-#if defined(__GNUC__) && !defined(__APPLE__)
+#if defined(__GNUC__) && (!defined(__APPLE__) || defined(__clang__))
/* Does the OS X port of gcc still gag on __attribute__? */
#define UNUSED(x) x __attribute__((__unused__))
#else