summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/parameter.c55
-rw-r--r--Src/Modules/pcre.c2
-rw-r--r--Src/Zle/compcore.c2
-rw-r--r--Src/Zle/compctl.c2
-rw-r--r--Src/Zle/zle_refresh.c3
-rw-r--r--Src/builtin.c4
-rw-r--r--Src/exec.c187
-rw-r--r--Src/glob.c24
-rw-r--r--Src/hashtable.c15
-rw-r--r--Src/hist.c21
-rw-r--r--Src/init.c37
-rw-r--r--Src/jobs.c4
-rw-r--r--Src/lex.c110
-rw-r--r--Src/params.c39
-rw-r--r--Src/parse.c290
-rw-r--r--Src/pattern.c10
-rw-r--r--Src/prompt.c38
-rw-r--r--Src/signals.c15
-rw-r--r--Src/subst.c15
-rw-r--r--Src/utils.c44
-rw-r--r--Src/zsh.h4
-rw-r--r--Src/zsh.mdd3
-rw-r--r--Src/ztype.h9
23 files changed, 689 insertions, 244 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 0385a709e..55157a90c 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -392,20 +392,36 @@ getfunction(UNUSED(HashTable ht), const char *name, int dis)
((shf->node.flags & PM_TAGGED) ? "t" : "")));
} else {
char *t = getpermtext(shf->funcdef, NULL, 1), *n, *h;
+ char *start;
+
+ if (shf->redir)
+ start = "{\n\t";
+ else
+ start = "\t";
if (shf->funcdef->flags & EF_RUN) {
n = nicedupstring(name);
- h = (char *) zhalloc(strlen(t) + strlen(n) + 9);
- h[0] = '\t';
- strcpy(h + 1, t);
+ h = (char *) zhalloc(strlen(start) + strlen(t) + strlen(n) + 8);
+ strcpy(h, start);
+ strcat(h, t);
strcat(h, "\n\t");
strcat(h, n);
strcat(h, " \"$@\"");
} else
- h = dyncat("\t", t);
+ h = dyncat(start, t);
zsfree(t);
+ /*
+ * TBD: Is this unmetafy correct? Surely as this
+ * is a parameter value it stays metafied?
+ */
unmetafy(h, NULL);
+ if (shf->redir) {
+ t = getpermtext(shf->redir, NULL, 1);
+ h = zhtricat(h, "\n}", t);
+ zsfree(t);
+ }
+
pm->u.str = h;
}
} else {
@@ -456,21 +472,38 @@ scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
((shf->node.flags & PM_TAGGED) ? "Ut" : "U") :
((shf->node.flags & PM_TAGGED) ? "t" : "")));
} else {
- char *t = getpermtext(((Shfunc) hn)->funcdef, NULL, 1);
- char *n;
+ Shfunc shf = (Shfunc)hn;
+ char *t = getpermtext(shf->funcdef, NULL, 1);
+ char *n, *start;
- if (((Shfunc) hn)->funcdef->flags & EF_RUN) {
+ if (shf->redir)
+ start = "{\n\t";
+ else
+ start = "\t";
+
+ if (shf->funcdef->flags & EF_RUN) {
n = nicedupstring(hn->nam);
- pm.u.str = (char *) zhalloc(strlen(t) + strlen(n) + 9);
- pm.u.str[0] = '\t';
- strcpy(pm.u.str + 1, t);
+ pm.u.str = (char *) zhalloc(
+ strlen(start) + strlen(t) + strlen(n) + 8);
+ strcpy(pm.u.str, start);
+ strcat(pm.u.str, t);
strcat(pm.u.str, "\n\t");
strcat(pm.u.str, n);
strcat(pm.u.str, " \"$@\"");
} else
- pm.u.str = dyncat("\t", t);
+ pm.u.str = dyncat(start, t);
+ /*
+ * TBD: Is this unmetafy correct? Surely as this
+ * is a parameter value it stays metafied?
+ */
unmetafy(pm.u.str, NULL);
zsfree(t);
+
+ if (shf->redir) {
+ t = getpermtext(shf->redir, NULL, 1);
+ pm.u.str = zhtricat(pm.u.str, "\n}", t);
+ zsfree(t);
+ }
}
}
func(&pm.node, flags);
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index 040a33f8e..2393cd1e7 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -289,7 +289,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func))
matched_portion = OPT_ARG(ops,c);
}
if(OPT_HASARG(ops,c='n')) { /* The offset position to start the search, in bytes. */
- if ((offset_start = getposint(OPT_ARG(ops,c), nam) < 0))
+ if ((offset_start = getposint(OPT_ARG(ops,c), nam)) < 0)
return 1;
}
/* For the entire match, 'Return' the offset byte positions instead of the matched string */
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index ac7785ab7..35d410cc6 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -702,6 +702,7 @@ callcompfunc(char *s, char *fn)
}
zsfree(compprefix);
zsfree(compsuffix);
+ makebangspecial(0);
if (unset(COMPLETEINWORD)) {
tmp = (linwhat == IN_MATH ? dupstring(s) : multiquote(s, 0));
untokenize(tmp);
@@ -722,6 +723,7 @@ callcompfunc(char *s, char *fn)
untokenize(ss);
compsuffix = ztrdup(ss);
}
+ makebangspecial(1);
zsfree(complastprefix);
zsfree(complastsuffix);
complastprefix = ztrdup(compprefix);
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 52b9e9c82..0b7a32445 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -3416,7 +3416,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
*npp++ = tp;
pp++;
}
- *npp = '\0';
+ *npp = NULL;
}
}
if (!dirs) {
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 80be27f03..684ac13a2 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -258,7 +258,6 @@ static const REFRESH_ELEMENT zr_cr = { ZWC('\r'), 0 };
static const REFRESH_ELEMENT zr_dt = { ZWC('.'), 0 };
static const REFRESH_ELEMENT zr_nl = { ZWC('\n'), 0 };
static const REFRESH_ELEMENT zr_sp = { ZWC(' '), 0 };
-static const REFRESH_ELEMENT zr_ht = { ZWC('\t'), 0 };
static const REFRESH_ELEMENT zr_zr = { ZWC('\0'), 0 };
/*
@@ -429,7 +428,7 @@ get_region_highlight(UNUSED(Param pm))
digbuf1, digbuf2);
(void)output_highlight(rhp->atr, *arrp + strlen(*arrp));
}
- *arrp = '\0';
+ *arrp = NULL;
return retarr;
}
diff --git a/Src/builtin.c b/Src/builtin.c
index a2a3ad748..4a10c7dd1 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2759,7 +2759,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
tokenize(*argv);
if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
queue_signals();
- for (p = mathfuncs, q = NULL; p; q = p, p = p->next) {
+ for (p = mathfuncs, q = NULL; p; q = p) {
MathFunc next;
do {
next = NULL;
@@ -2774,6 +2774,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
}
/* if we deleted one, retry with the new p */
} while (next);
+ if (p)
+ p = p->next;
}
unqueue_signals();
} else {
diff --git a/Src/exec.c b/Src/exec.c
index 5ad957f98..d0fadd69a 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -198,7 +198,8 @@ static char *blank_env[] = { NULL };
/* Execution functions. */
static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = {
- execcursh, exectime, execfuncdef, execfor, execselect,
+ execcursh, exectime, NULL /* execfuncdef handled specially */,
+ execfor, execselect,
execwhile, execrepeat, execcase, execif, execcond,
execarith, execautofn, exectry
};
@@ -1005,6 +1006,8 @@ entersubsh(int flags)
signal_default(SIGTERM);
if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
signal_default(SIGINT);
+ if (!(sigtrapped[SIGPIPE]))
+ signal_default(SIGPIPE);
}
if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
signal_default(SIGQUIT);
@@ -1116,8 +1119,11 @@ execsimple(Estate state)
fflush(xtrerr);
}
lv = (errflag ? errflag : cmdoutval);
- } else
+ } else if (code == WC_FUNCDEF) {
+ lv = execfuncdef(state, NULL);
+ } else {
lv = (execfuncs[code - WC_CURSH])(state, 0);
+ }
thisjob = otj;
@@ -2783,6 +2789,58 @@ execcmd(Estate state, int input, int output, int how, int last1)
errflag = 1;
}
+ if (type == WC_FUNCDEF) {
+ /*
+ * The first word of a function definition is a list of
+ * names. If this is empty, we're doing an anonymous function:
+ * in that case redirections are handled normally.
+ * If not, it's a function definition: then we don't do
+ * redirections here but pass in the list of redirections to
+ * be stored for recall with the function.
+ */
+ if (*state->pc != 0) {
+ /* Nonymous, don't do redirections here */
+ redir = NULL;
+ }
+ } else if (is_shfunc || type == WC_AUTOFN) {
+ Shfunc shf;
+ if (is_shfunc)
+ shf = (Shfunc)hn;
+ else {
+ shf = loadautofn(state->prog->shf, 1, 0);
+ if (shf)
+ state->prog->shf = shf;
+ else {
+ /*
+ * This doesn't set errflag, so just return now.
+ */
+ lastval = 1;
+ if (oautocont >= 0)
+ opts[AUTOCONTINUE] = oautocont;
+ return;
+ }
+ }
+ /*
+ * A function definition may have a list of additional
+ * redirections to apply, so retrieve it.
+ */
+ if (shf->redir) {
+ struct estate s;
+ LinkList redir2;
+
+ s.prog = shf->redir;
+ s.pc = shf->redir->prog;
+ s.strs = shf->redir->strs;
+ redir2 = ecgetredirs(&s);
+ if (!redir)
+ redir = redir2;
+ else {
+ while (nonempty(redir2))
+ addlinknode(redir, ugetnode(redir2));
+ }
+ }
+ }
+
if (errflag) {
lastval = 1;
if (oautocont >= 0)
@@ -3050,7 +3108,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
break;
case REDIR_CLOSE:
if (fn->varid) {
- char *s = fn->varid;
+ char *s = fn->varid, *t;
struct value vbuf;
Value v;
int bad = 0;
@@ -3060,13 +3118,25 @@ execcmd(Estate state, int input, int output, int how, int last1)
} else if (v->pm->node.flags & PM_READONLY) {
bad = 2;
} else {
- fn->fd1 = (int)getintvalue(v);
+ s = getstrvalue(v);
if (errflag)
bad = 1;
- else if (fn->fd1 <= max_zsh_fd) {
- if (fn->fd1 >= 10 &&
- fdtable[fn->fd1] == FDT_INTERNAL)
- bad = 3;
+ else {
+ fn->fd1 = zstrtol(s, &t, 0);
+ if (s == t)
+ bad = 1;
+ else if (*t) {
+ /* Check for base#number format */
+ if (*t == '#' && *s != '0')
+ fn->fd1 = zstrtol(s = t+1, &t, fn->fd1);
+ if (s == t || *t)
+ bad = 1;
+ }
+ if (!bad && fn->fd1 <= max_zsh_fd) {
+ if (fn->fd1 >= 10 &&
+ fdtable[fn->fd1] == FDT_INTERNAL)
+ bad = 3;
+ }
}
}
if (bad) {
@@ -3131,7 +3201,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
fil = movefd(dup(fd));
}
if (fil == -1) {
- char fdstr[4];
+ char fdstr[DIGBUFSIZE];
closemnodes(mfds);
fixfds(save);
@@ -3226,10 +3296,44 @@ execcmd(Estate state, int input, int output, int how, int last1)
flags |= ESUB_REVERTPGRP;
entersubsh(flags);
}
- if (type >= WC_CURSH) {
+ if (type == WC_FUNCDEF) {
+ Eprog redir_prog;
+ if (!redir && wc_code(*beg) == WC_REDIR) {
+ /*
+ * We're not using a redirection from the currently
+ * parsed environment, which is what we'd do for an
+ * anonymous function, but there are redirections we
+ * should store with the new function.
+ */
+ struct estate s;
+
+ s.prog = state->prog;
+ s.pc = beg;
+ s.strs = state->prog->strs;
+
+ /*
+ * The copy uses the wordcode parsing area, so save and
+ * restore state.
+ */
+ lexsave();
+ redir_prog = eccopyredirs(&s);
+ lexrestore();
+ } else
+ redir_prog = NULL;
+
+ lastval = execfuncdef(state, redir_prog);
+ }
+ else if (type >= WC_CURSH) {
if (last1 == 1)
do_exec = 1;
- lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
+ if (type == WC_AUTOFN) {
+ /*
+ * We pre-loaded this to get any redirs.
+ * So we execuate a simplified function here.
+ */
+ lastval = execautofn_basic(state, do_exec);
+ } else
+ lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
} else if (is_builtin || is_shfunc) {
LinkList restorelist = 0, removelist = 0;
/* builtin or shell function */
@@ -3569,8 +3673,11 @@ closem(int how)
for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] != FDT_UNUSED &&
- (how == FDT_UNUSED || fdtable[i] == how))
+ (how == FDT_UNUSED || fdtable[i] == how)) {
+ if (i == SHTTY)
+ SHTTY = -1;
zclose(i);
+ }
}
/* convert here document into a here string */
@@ -4220,11 +4327,12 @@ exectime(Estate state, UNUSED(int do_exec))
/**/
static int
-execfuncdef(Estate state, UNUSED(int do_exec))
+execfuncdef(Estate state, Eprog redir_prog)
{
Shfunc shf;
char *s = NULL;
int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0, ret = 0;
+ int nfunc = 0;
Wordcode beg = state->pc, end;
Eprog prog;
Patprog *pp;
@@ -4249,6 +4357,8 @@ execfuncdef(Estate state, UNUSED(int do_exec))
}
}
+ DPUTS(!names && redir_prog,
+ "Passing redirection to anon function definition.");
while (!names || (s = (char *) ugetnode(names))) {
if (!names) {
prog = (Eprog) zhalloc(sizeof(*prog));
@@ -4290,6 +4400,15 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shf->node.flags = 0;
shf->filename = ztrdup(scriptfilename);
shf->lineno = lineno;
+ /*
+ * redir_prog is permanently allocated --- but if
+ * this function has multiple names we need an additional
+ * one.
+ */
+ if (nfunc++ && redir_prog)
+ shf->redir = dupeprog(redir_prog, 0);
+ else
+ shf->redir = redir_prog;
shfunc_set_sticky(shf);
if (!names) {
@@ -4320,6 +4439,8 @@ execfuncdef(Estate state, UNUSED(int do_exec))
ret = lastval;
freeeprog(shf->funcdef);
+ if (shf->redir) /* shouldn't be */
+ freeeprog(shf->redir);
zsfree(shf->filename);
zfree(shf, sizeof(*shf));
break;
@@ -4343,6 +4464,10 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shfunctab->addnode(shfunctab, ztrdup(s), shf);
}
}
+ if (!nfunc && redir_prog) {
+ /* For completeness, shouldn't happen */
+ freeeprog(redir_prog);
+ }
state->pc = end;
return ret;
}
@@ -4439,21 +4564,28 @@ execshfunc(Shfunc shf, LinkList args)
deletefilelist(last_file_list, 0);
}
-/* Function to execute the special type of command that represents an *
- * autoloaded shell function. The command structure tells us which *
- * function it is. This function is actually called as part of the *
- * execution of the autoloaded function itself, so when the function *
- * has been autoloaded, its list is just run with no frills. */
+/*
+ * Function to execute the special type of command that represents an
+ * autoloaded shell function. The command structure tells us which
+ * function it is. This function is actually called as part of the
+ * execution of the autoloaded function itself, so when the function
+ * has been autoloaded, its list is just run with no frills.
+ *
+ * There are two cases because if we are doing all-singing, all-dancing
+ * non-simple code we load the shell function early in execcmd() (the
+ * action also present in the non-basic version) to check if
+ * there are redirections that need to be handled at that point.
+ * Then we call execautofn_basic() to do the rest.
+ */
/**/
static int
-execautofn(Estate state, UNUSED(int do_exec))
+execautofn_basic(Estate state, UNUSED(int do_exec))
{
Shfunc shf;
char *oldscriptname, *oldscriptfilename;
- if (!(shf = loadautofn(state->prog->shf, 1, 0)))
- return 1;
+ shf = state->prog->shf;
/*
* Probably we didn't know the filename where this function was
@@ -4473,6 +4605,19 @@ execautofn(Estate state, UNUSED(int do_exec))
}
/**/
+static int
+execautofn(Estate state, UNUSED(int do_exec))
+{
+ Shfunc shf;
+
+ if (!(shf = loadautofn(state->prog->shf, 1, 0)))
+ return 1;
+
+ state->prog->shf = shf;
+ return execautofn_basic(state, 0);
+}
+
+/**/
Shfunc
loadautofn(Shfunc shf, int fksh, int autol)
{
diff --git a/Src/glob.c b/Src/glob.c
index cb853870a..ca7bc4410 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -178,7 +178,7 @@ struct globdata {
int gd_gf_numsort;
int gd_gf_follow, gd_gf_sorts, gd_gf_nsorts;
struct globsort gd_gf_sortlist[MAX_SORTS];
- LinkList gd_gf_pre_words;
+ LinkList gd_gf_pre_words, gd_gf_post_words;
char *gd_glob_pre, *gd_glob_suf;
};
@@ -210,6 +210,7 @@ static struct globdata curglobdata;
#define gf_nsorts (curglobdata.gd_gf_nsorts)
#define gf_sortlist (curglobdata.gd_gf_sortlist)
#define gf_pre_words (curglobdata.gd_gf_pre_words)
+#define gf_post_words (curglobdata.gd_gf_post_words)
/* and macros for save/restore */
@@ -899,6 +900,9 @@ gmatchcmp(Gmatch a, Gmatch b)
/* Count slashes. Trailing slashes don't count. */
while (*aptr && *aptr == *bptr)
aptr++, bptr++;
+ /* Like I just said... */
+ if ((!*aptr || !*bptr) && aptr > a->name && aptr[-1] == '/')
+ aptr--, bptr--;
if (*aptr)
for (; aptr[1]; aptr++)
if (*aptr == '/') {
@@ -1074,7 +1078,14 @@ insert_glob_match(LinkList list, LinkNode next, char *data)
}
}
- insertlinknode(list, next, data);
+ next = insertlinknode(list, next, data);
+
+ if (gf_post_words) {
+ LinkNode added;
+ for (added = firstnode(gf_post_words); added; incnode(added)) {
+ next = insertlinknode(list, next, dupstring(getdata(added)));
+ }
+ }
}
/*
@@ -1190,7 +1201,7 @@ zglob(LinkList list, LinkNode np, int nountok)
gf_noglobdots = unset(GLOBDOTS);
gf_numsort = isset(NUMERICGLOBSORT);
gf_sorts = gf_nsorts = 0;
- gf_pre_words = NULL;
+ gf_pre_words = gf_post_words = NULL;
/* Check for qualifiers */
while (!nobareglob ||
@@ -1679,9 +1690,10 @@ zglob(LinkList list, LinkNode np, int nountok)
if (tt != NULL)
{
- if (!gf_pre_words)
- gf_pre_words = newlinklist();
- addlinknode(gf_pre_words, tt);
+ LinkList *words = sense & 1 ? &gf_post_words : &gf_pre_words;
+ if (!*words)
+ *words = newlinklist();
+ addlinknode(*words, tt);
}
break;
}
diff --git a/Src/hashtable.c b/Src/hashtable.c
index ef187927b..7a430629d 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -887,6 +887,8 @@ freeshfuncnode(HashNode hn)
zsfree(shf->node.nam);
if (shf->funcdef)
freeeprog(shf->funcdef);
+ if (shf->redir)
+ freeeprog(shf->redir);
zsfree(shf->filename);
if (shf->sticky) {
if (shf->sticky->n_on_opts)
@@ -954,10 +956,19 @@ printshfuncnode(HashNode hn, int printflags)
printf(" \"$@\"");
}
}
- printf("\n}\n");
+ printf("\n}");
} else {
- printf(" () { }\n");
+ printf(" () { }");
}
+ if (f->redir) {
+ t = getpermtext(f->redir, NULL, 1);
+ if (t) {
+ zputs(t, stdout);
+ zsfree(t);
+ }
+ }
+
+ putchar('\n');
}
/**************************************/
diff --git a/Src/hist.c b/Src/hist.c
index 770d559b1..4660fd073 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -2490,6 +2490,9 @@ flockhistfile(char *fn, int keep_trying)
struct flock lck;
int ctr = keep_trying ? 9 : 0;
+ if (flock_fd >= 0)
+ return 0; /* already locked */
+
if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0)
return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */
@@ -2590,7 +2593,12 @@ savehistfile(char *fn, int err, int writeflags)
out = NULL;
} else {
int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600);
- out = fd >= 0 ? fdopen(fd, "w") : NULL;
+ if (fd >=0) {
+ out = fdopen(fd, "w");
+ if (!out)
+ close(fd);
+ } else
+ out = NULL;
}
#ifdef HAVE_FCHMOD
@@ -2768,12 +2776,6 @@ lockhistfile(char *fn, int keep_trying)
if (!fn && !(fn = getsparam("HISTFILE")))
return 1;
-#ifdef HAVE_FCNTL_H
- if (isset(HISTFCNTLLOCK) && flock_fd < 0) {
- return flockhistfile(fn, keep_trying);
- }
-#endif
-
if (!lockhistct++) {
struct stat sb;
int fd;
@@ -2786,6 +2788,11 @@ lockhistfile(char *fn, int keep_trying)
# endif
#endif
+#ifdef HAVE_FCNTL_H
+ if (isset(HISTFCNTLLOCK))
+ return flockhistfile(fn, keep_trying);
+#endif
+
lockfile = bicat(unmeta(fn), ".LOCK");
/* NOTE: only use symlink locking on a link()-having host in order to
* avoid a change from open()-based locking to symlink()-based. */
diff --git a/Src/init.c b/Src/init.c
index 5e92f59df..6d005dce7 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -252,8 +252,9 @@ parseargs(char **argv, char **runscript)
paramlist = znewlinklist();
if (*argv) {
if (unset(SHINSTDIN)) {
+ posixzero = *argv;
if (cmd)
- argzero = posixzero = *argv;
+ argzero = *argv;
else
*runscript = *argv;
opts[INTERACTIVE] &= 1;
@@ -769,7 +770,8 @@ setupvals(void)
struct timezone dummy_tz;
char *ptr;
int i, j;
-#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH)
+#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) || defined(FIXED_FPATH_DIR)
+#define FPATH_NEEDS_INIT 1
char **fpathptr;
# if defined(FPATH_DIR) && defined(FPATH_SUBDIRS)
char *fpath_subdirs[] = FPATH_SUBDIRS;
@@ -778,11 +780,17 @@ setupvals(void)
char *more_fndirs[] = ADDITIONAL_FPATH;
int more_fndirs_len;
# endif
+# ifdef FIXED_FPATH_DIR
+# define FIXED_FPATH_LEN 1
+# else
+# define FIXED_FPATH_LEN 0
+# endif
# ifdef SITEFPATH_DIR
- int fpathlen = 1;
+# define SITE_FPATH_LEN 1
# else
- int fpathlen = 0;
+# define SITE_FPATH_LEN 0
# endif
+ int fpathlen = FIXED_FPATH_LEN + SITE_FPATH_LEN;
#endif
int close_fds[10], tmppipe[2];
@@ -861,23 +869,27 @@ setupvals(void)
manpath = mkarray(NULL);
fignore = mkarray(NULL);
-#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined(ADDITIONAL_FPATH)
+#ifdef FPATH_NEEDS_INIT
# ifdef FPATH_DIR
# ifdef FPATH_SUBDIRS
fpathlen += sizeof(fpath_subdirs)/sizeof(char *);
-# else
+# else /* FPATH_SUBDIRS */
fpathlen++;
-# endif
-# endif
+# endif /* FPATH_SUBDIRS */
+# endif /* FPATH_DIR */
# if defined(ADDITIONAL_FPATH)
more_fndirs_len = sizeof(more_fndirs)/sizeof(char *);
fpathlen += more_fndirs_len;
-# endif
+# endif /* ADDITONAL_FPATH */
fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *));
+# ifdef FIXED_FPATH_DIR
+ *fpathptr++ = ztrdup(FIXED_FPATH_DIR);
+ fpathlen--;
+# endif
# ifdef SITEFPATH_DIR
*fpathptr++ = ztrdup(SITEFPATH_DIR);
fpathlen--;
-# endif
+# endif /* SITEFPATH_DIR */
# if defined(ADDITIONAL_FPATH)
for (j = 0; j < more_fndirs_len; j++)
*fpathptr++ = ztrdup(more_fndirs[j]);
@@ -896,9 +908,9 @@ setupvals(void)
# endif
# endif
*fpathptr = NULL;
-#else
+#else /* FPATH_NEEDS_INIT */
fpath = mkarray(NULL);
-#endif
+#endif /* FPATH_NEEDS_INIT */
mailpath = mkarray(NULL);
watch = mkarray(NULL);
@@ -1122,6 +1134,7 @@ init_signals(void)
winch_block(); /* See utils.c:preprompt() */
#endif
if (interact) {
+ install_handler(SIGPIPE);
install_handler(SIGALRM);
signal_ignore(SIGTERM);
}
diff --git a/Src/jobs.c b/Src/jobs.c
index 83a4d96a4..bd95afb7a 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1627,8 +1627,10 @@ spawnjob(void)
}
if (!hasprocs(thisjob))
deletejob(jobtab + thisjob, 0);
- else
+ else {
jobtab[thisjob].stat |= STAT_LOCKED;
+ pipecleanfilelist(jobtab[thisjob].filelist);
+ }
thisjob = -1;
}
diff --git a/Src/lex.c b/Src/lex.c
index 8e9a49f3b..1a854f52b 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -325,66 +325,70 @@ lexsave(void)
mod_export void
lexrestore(void)
{
- struct lexstack *ln;
+ struct lexstack *ln = lstack;
DPUTS(!lstack, "BUG: lexrestore() without lexsave()");
- incmdpos = lstack->incmdpos;
- incond = lstack->incond;
- incasepat = lstack->incasepat;
- dbparens = lstack->dbparens;
- isfirstln = lstack->isfirstln;
- isfirstch = lstack->isfirstch;
- histactive = lstack->histactive;
- histdone = lstack->histdone;
- lexflags = lstack->lexflags;
- stophist = lstack->stophist;
- chline = lstack->hline;
- hptr = lstack->hptr;
+
+ queue_signals();
+ lstack = lstack->next;
+
+ if (!lstack) {
+ /* Back to top level: don't need special ZLE value */
+ DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
+ zle_chline = NULL;
+ }
+
+ incmdpos = ln->incmdpos;
+ incond = ln->incond;
+ incasepat = ln->incasepat;
+ dbparens = ln->dbparens;
+ isfirstln = ln->isfirstln;
+ isfirstch = ln->isfirstch;
+ histactive = ln->histactive;
+ histdone = ln->histdone;
+ lexflags = ln->lexflags;
+ stophist = ln->stophist;
+ chline = ln->hline;
+ hptr = ln->hptr;
if (cmdstack)
- free(cmdstack);
- cmdstack = lstack->cstack;
- cmdsp = lstack->csp;
- tok = lstack->tok;
- isnewlin = lstack->isnewlin;
- tokstr = lstack->tokstr;
- zshlextext = lstack->zshlextext;
- bptr = lstack->bptr;
- bsiz = lstack->bsiz;
- len = lstack->len;
- chwords = lstack->chwords;
- chwordlen = lstack->chwordlen;
- chwordpos = lstack->chwordpos;
- hwgetword = lstack->hwgetword;
- lexstop = lstack->lexstop;
- hdocs = lstack->hdocs;
- hgetc = lstack->hgetc;
- hungetc = lstack->hungetc;
- hwaddc = lstack->hwaddc;
- hwbegin = lstack->hwbegin;
- hwend = lstack->hwend;
- addtoline = lstack->addtoline;
+ zfree(cmdstack, CMDSTACKSZ);
+ cmdstack = ln->cstack;
+ cmdsp = ln->csp;
+ tok = ln->tok;
+ isnewlin = ln->isnewlin;
+ tokstr = ln->tokstr;
+ zshlextext = ln->zshlextext;
+ bptr = ln->bptr;
+ bsiz = ln->bsiz;
+ len = ln->len;
+ chwords = ln->chwords;
+ chwordlen = ln->chwordlen;
+ chwordpos = ln->chwordpos;
+ hwgetword = ln->hwgetword;
+ lexstop = ln->lexstop;
+ hdocs = ln->hdocs;
+ hgetc = ln->hgetc;
+ hungetc = ln->hungetc;
+ hwaddc = ln->hwaddc;
+ hwbegin = ln->hwbegin;
+ hwend = ln->hwend;
+ addtoline = ln->addtoline;
if (ecbuf)
zfree(ecbuf, eclen);
- eclen = lstack->eclen;
- ecused = lstack->ecused;
- ecnpats = lstack->ecnpats;
- ecbuf = lstack->ecbuf;
- ecstrs = lstack->ecstrs;
- ecsoffs = lstack->ecsoffs;
- ecssub = lstack->ecssub;
- ecnfunc = lstack->ecnfunc;
- hlinesz = lstack->hlinesz;
- toklineno = lstack->toklineno;
+ eclen = ln->eclen;
+ ecused = ln->ecused;
+ ecnpats = ln->ecnpats;
+ ecbuf = ln->ecbuf;
+ ecstrs = ln->ecstrs;
+ ecsoffs = ln->ecsoffs;
+ ecssub = ln->ecssub;
+ ecnfunc = ln->ecnfunc;
+ hlinesz = ln->hlinesz;
+ toklineno = ln->toklineno;
errflag = 0;
+ free(ln);
- ln = lstack->next;
- if (!ln) {
- /* Back to top level: don't need special ZLE value */
- DPUTS(chline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
- zle_chline = NULL;
- }
- free(lstack);
- lstack = ln;
+ unqueue_signals();
}
/**/
diff --git a/Src/params.c b/Src/params.c
index 0699ead85..61edc5d08 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -46,7 +46,7 @@
/**/
mod_export int locallevel;
-
+
/* Variables holding values of special parameters */
/**/
@@ -325,9 +325,12 @@ IPDEF4("ZSH_SUBSHELL", &zsh_subshell),
IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu),
IPDEF5("LINES", &zterm_lines, zlevar_gsu),
IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, zlevar_gsu),
-IPDEF5("OPTIND", &zoptind, varinteger_gsu),
IPDEF5("SHLVL", &shlvl, varinteger_gsu),
-IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
+
+/* Don't import internal integer status variables. */
+#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
+IPDEF6("OPTIND", &zoptind, varinteger_gsu),
+IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
#define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
#define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
@@ -742,7 +745,8 @@ createparamtable(void)
if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) {
if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
!(pm->node.flags & PM_DONTIMPORT || pm->node.flags & PM_EXPORTED)) &&
- (pm = setsparam(iname, metafy(ivalue, -1, META_DUP)))) {
+ (pm = assignsparam(iname, metafy(ivalue, -1, META_DUP),
+ ASSPM_ENV_IMPORT))) {
pm->node.flags |= PM_EXPORTED;
if (pm->node.flags & PM_SPECIAL)
pm->env = mkenvstr (pm->node.nam,
@@ -2271,6 +2275,13 @@ export_param(Param pm)
mod_export void
setstrvalue(Value v, char *val)
{
+ assignstrvalue(v, val, 0);
+}
+
+/**/
+mod_export void
+assignstrvalue(Value v, char *val, int flags)
+{
if (unset(EXECOPT))
return;
if (v->pm->node.flags & PM_READONLY) {
@@ -2347,7 +2358,13 @@ setstrvalue(Value v, char *val)
break;
case PM_INTEGER:
if (val) {
- v->pm->gsu.i->setfn(v->pm, mathevali(val));
+ zlong ival;
+ if (flags & ASSPM_ENV_IMPORT) {
+ char *ptr;
+ ival = zstrtol_underscore(val, &ptr, 0, 1);
+ } else
+ ival = mathevali(val);
+ v->pm->gsu.i->setfn(v->pm, ival);
if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
!v->pm->width)
v->pm->width = strlen(val);
@@ -2359,7 +2376,13 @@ setstrvalue(Value v, char *val)
case PM_EFLOAT:
case PM_FFLOAT:
if (val) {
- mnumber mn = matheval(val);
+ mnumber mn;
+ if (flags & ASSPM_ENV_IMPORT) {
+ char *ptr;
+ mn.type = MN_FLOAT;
+ mn.u.d = strtod(val, &ptr);
+ } else
+ mn = matheval(val);
v->pm->gsu.f->setfn(v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
(double)mn.u.l);
if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
@@ -2742,8 +2765,8 @@ assignsparam(char *s, char *val, int flags)
}
}
}
-
- setstrvalue(v, val);
+
+ assignstrvalue(v, val, flags);
unqueue_signals();
return v->pm;
}
diff --git a/Src/parse.c b/Src/parse.c
index 5f1303f1c..433efb94e 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -202,7 +202,7 @@ struct heredocs *hdocs;
* sublists is that they can be executed faster, see exec.c. In the
* parser, the test if a list can be simplified is done quite simply
* by passing a int* around which gets set to non-zero if the thing
- * just parsed is `complex', i.e. may need to be run by forking or
+ * just parsed is `cmplx', i.e. may need to be run by forking or
* some such.
*
* In each of the above, strings are encoded as one word code. For empty
@@ -375,6 +375,8 @@ init_parse(void)
/* Build eprog. */
+/* careful: copy_ecstr is from arg1 to arg2, unlike memcpy */
+
static void
copy_ecstr(Eccstr s, char *p)
{
@@ -386,24 +388,25 @@ copy_ecstr(Eccstr s, char *p)
}
static Eprog
-bld_eprog(void)
+bld_eprog(int heap)
{
Eprog ret;
int l;
ecadd(WCB_END());
- ret = (Eprog) zhalloc(sizeof(*ret));
+ ret = heap ? (Eprog) zhalloc(sizeof(*ret)) : (Eprog) zalloc(sizeof(*ret));
ret->len = ((ecnpats * sizeof(Patprog)) +
(ecused * sizeof(wordcode)) +
ecsoffs);
ret->npats = ecnpats;
- ret->nref = -1; /* Eprog is on the heap */
- ret->pats = (Patprog *) zhalloc(ret->len);
+ ret->nref = heap ? -1 : 1;
+ ret->pats = heap ? (Patprog *) zhalloc(ret->len) :
+ (Patprog *) zshcalloc(ret->len);
ret->prog = (Wordcode) (ret->pats + ecnpats);
ret->strs = (char *) (ret->prog + ecused);
ret->shf = NULL;
- ret->flags = EF_HEAP;
+ ret->flags = heap ? EF_HEAP : EF_REAL;
ret->dump = NULL;
for (l = 0; l < ecnpats; l++)
ret->pats[l] = dummy_patprog1;
@@ -455,7 +458,7 @@ parse_event(void)
clear_hdocs();
return NULL;
}
- return bld_eprog();
+ return bld_eprog(1);
}
/**/
@@ -534,7 +537,7 @@ parse_list(void)
yyerror(0);
return NULL;
}
- return bld_eprog();
+ return bld_eprog(1);
}
/*
@@ -553,7 +556,7 @@ parse_cond(void)
clear_hdocs();
return NULL;
}
- return bld_eprog();
+ return bld_eprog(1);
}
/* This adds a list wordcode. The important bit about this is that it also
@@ -561,9 +564,9 @@ parse_cond(void)
/**/
static void
-set_list_code(int p, int type, int complex)
+set_list_code(int p, int type, int cmplx)
{
- if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) &&
+ if (!cmplx && (type == Z_SYNC || type == (Z_SYNC | Z_END)) &&
WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) {
int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE);
ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p);
@@ -578,9 +581,9 @@ set_list_code(int p, int type, int complex)
/**/
static void
-set_sublist_code(int p, int type, int flags, int skip, int complex)
+set_sublist_code(int p, int type, int flags, int skip, int cmplx)
{
- if (complex)
+ if (cmplx)
ecbuf[p] = WCB_SUBLIST(type, flags, skip);
else {
ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip);
@@ -594,7 +597,7 @@ set_sublist_code(int p, int type, int flags, int skip, int complex)
/**/
static int
-par_list(int *complex)
+par_list(int *cmplx)
{
int p, lp = -1, c;
@@ -607,10 +610,10 @@ par_list(int *complex)
c = 0;
if (par_sublist(&c)) {
- *complex |= c;
+ *cmplx |= c;
if (tok == SEPER || tok == AMPER || tok == AMPERBANG) {
if (tok != SEPER)
- *complex = 1;
+ *cmplx = 1;
set_list_code(p, ((tok == SEPER) ? Z_SYNC :
(tok == AMPER) ? Z_ASYNC :
(Z_ASYNC | Z_DISOWN)), c);
@@ -635,13 +638,13 @@ par_list(int *complex)
/**/
static int
-par_list1(int *complex)
+par_list1(int *cmplx)
{
int p = ecadd(0), c = 0;
if (par_sublist(&c)) {
set_list_code(p, (Z_SYNC | Z_END), c);
- *complex |= c;
+ *cmplx |= c;
return 1;
} else {
ecused--;
@@ -655,7 +658,7 @@ par_list1(int *complex)
/**/
static int
-par_sublist(int *complex)
+par_sublist(int *cmplx)
{
int f, p, c = 0;
@@ -664,7 +667,7 @@ par_sublist(int *complex)
if ((f = par_sublist2(&c)) != -1) {
int e = ecused;
- *complex |= c;
+ *cmplx |= c;
if (tok == DBAR || tok == DAMPER) {
enum lextok qtok = tok;
int sl;
@@ -673,7 +676,7 @@ par_sublist(int *complex)
zshlex();
while (tok == SEPER)
zshlex();
- sl = par_sublist(complex);
+ sl = par_sublist(cmplx);
set_sublist_code(p, (sl ? (qtok == DBAR ?
WC_SUBLIST_OR : WC_SUBLIST_AND) :
WC_SUBLIST_END),
@@ -694,20 +697,20 @@ par_sublist(int *complex)
/**/
static int
-par_sublist2(int *complex)
+par_sublist2(int *cmplx)
{
int f = 0;
if (tok == COPROC) {
- *complex = 1;
+ *cmplx = 1;
f |= WC_SUBLIST_COPROC;
zshlex();
} else if (tok == BANG) {
- *complex = 1;
+ *cmplx = 1;
f |= WC_SUBLIST_NOT;
zshlex();
}
- if (!par_pline(complex) && !f)
+ if (!par_pline(cmplx) && !f)
return -1;
return f;
@@ -719,19 +722,19 @@ par_sublist2(int *complex)
/**/
static int
-par_pline(int *complex)
+par_pline(int *cmplx)
{
int p;
zlong line = toklineno;
p = ecadd(0);
- if (!par_cmd(complex)) {
+ if (!par_cmd(cmplx, 0)) {
ecused--;
return 0;
}
if (tok == BAR) {
- *complex = 1;
+ *cmplx = 1;
cmdpush(CS_PIPE);
zshlex();
while (tok == SEPER)
@@ -739,7 +742,7 @@ par_pline(int *complex)
ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0));
ecispace(p + 1, 1);
ecbuf[p + 1] = ecused - 1 - p;
- if (!par_pline(complex)) {
+ if (!par_pline(cmplx)) {
tok = LEXERR;
}
cmdpop();
@@ -755,7 +758,7 @@ par_pline(int *complex)
ecbuf[r + 1] = 2;
ecbuf[r + 2] = ecstrcode("1");
- *complex = 1;
+ *cmplx = 1;
cmdpush(CS_ERRPIPE);
zshlex();
while (tok == SEPER)
@@ -763,7 +766,7 @@ par_pline(int *complex)
ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0));
ecispace(p + 1, 1);
ecbuf[p + 1] = ecused - 1 - p;
- if (!par_pline(complex)) {
+ if (!par_pline(cmplx)) {
tok = LEXERR;
}
cmdpop();
@@ -777,18 +780,20 @@ par_pline(int *complex)
/*
* cmd : { redir } ( for | case | if | while | repeat |
* subsh | funcdef | time | dinbrack | dinpar | simple ) { redir }
+ *
+ * zsh_construct is passed through to par_subsh(), q.v.
*/
/**/
static int
-par_cmd(int *complex)
+par_cmd(int *cmplx, int zsh_construct)
{
int r, nr = 0;
r = ecused;
if (IS_REDIROP(tok)) {
- *complex = 1;
+ *cmplx = 1;
while (IS_REDIROP(tok)) {
nr += par_redir(&r, NULL);
}
@@ -796,57 +801,57 @@ par_cmd(int *complex)
switch (tok) {
case FOR:
cmdpush(CS_FOR);
- par_for(complex);
+ par_for(cmplx);
cmdpop();
break;
case FOREACH:
cmdpush(CS_FOREACH);
- par_for(complex);
+ par_for(cmplx);
cmdpop();
break;
case SELECT:
- *complex = 1;
+ *cmplx = 1;
cmdpush(CS_SELECT);
- par_for(complex);
+ par_for(cmplx);
cmdpop();
break;
case CASE:
cmdpush(CS_CASE);
- par_case(complex);
+ par_case(cmplx);
cmdpop();
break;
case IF:
- par_if(complex);
+ par_if(cmplx);
break;
case WHILE:
cmdpush(CS_WHILE);
- par_while(complex);
+ par_while(cmplx);
cmdpop();
break;
case UNTIL:
cmdpush(CS_UNTIL);
- par_while(complex);
+ par_while(cmplx);
cmdpop();
break;
case REPEAT:
cmdpush(CS_REPEAT);
- par_repeat(complex);
+ par_repeat(cmplx);
cmdpop();
break;
case INPAR:
- *complex = 1;
+ *cmplx = 1;
cmdpush(CS_SUBSH);
- par_subsh(complex);
+ par_subsh(cmplx, zsh_construct);
cmdpop();
break;
case INBRACE:
cmdpush(CS_CURSH);
- par_subsh(complex);
+ par_subsh(cmplx, zsh_construct);
cmdpop();
break;
case FUNC:
cmdpush(CS_FUNCDEF);
- par_funcdef(complex);
+ par_funcdef(cmplx);
cmdpop();
break;
case DINBRACK:
@@ -864,7 +869,7 @@ par_cmd(int *complex)
static int inpartime = 0;
if (!inpartime) {
- *complex = 1;
+ *cmplx = 1;
inpartime = 1;
par_time();
inpartime = 0;
@@ -877,13 +882,13 @@ par_cmd(int *complex)
{
int sr;
- if (!(sr = par_simple(complex, nr))) {
+ if (!(sr = par_simple(cmplx, nr))) {
if (!nr)
return 0;
} else {
/* Take account of redirections */
if (sr > 1) {
- *complex = 1;
+ *cmplx = 1;
r += sr - 1;
}
}
@@ -891,7 +896,7 @@ par_cmd(int *complex)
break;
}
if (IS_REDIROP(tok)) {
- *complex = 1;
+ *cmplx = 1;
while (IS_REDIROP(tok))
(void)par_redir(&r, NULL);
}
@@ -909,7 +914,7 @@ par_cmd(int *complex)
/**/
static void
-par_for(int *complex)
+par_for(int *cmplx)
{
int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT);
int type;
@@ -994,25 +999,28 @@ par_for(int *complex)
zshlex();
if (tok == DOLOOP) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != DONE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (tok == INBRACE) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != OUTBRACE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (csh || isset(CSHJUNKIELOOPS)) {
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != ZEND)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (unset(SHORTLOOPS)) {
YYERRORV(oecused);
} else
- par_save_list1(complex);
+ par_save_list1(cmplx);
ecbuf[p] = (sel ?
WCB_SELECT(type, ecused - 1 - p) :
@@ -1028,7 +1036,7 @@ par_for(int *complex)
/**/
static void
-par_case(int *complex)
+par_case(int *cmplx)
{
int oecused = ecused, brflag, p, pp, n = 1, type;
int ona, onc;
@@ -1145,7 +1153,7 @@ par_case(int *complex)
pp = ecadd(0);
ecstr(str);
ecadd(ecnpats++);
- par_save_list(complex);
+ par_save_list(cmplx);
n++;
if (tok == SEMIAMP)
type = WC_CASE_AND;
@@ -1175,7 +1183,7 @@ par_case(int *complex)
/**/
static void
-par_if(int *complex)
+par_if(int *cmplx)
{
int oecused = ecused, p, pp, type, usebrace = 0;
enum lextok xtok;
@@ -1186,9 +1194,12 @@ par_if(int *complex)
for (;;) {
xtok = tok;
cmdpush(xtok == IF ? CS_IF : CS_ELIF);
- zshlex();
- if (xtok == FI)
+ if (xtok == FI) {
+ incmdpos = 0;
+ zshlex();
break;
+ }
+ zshlex();
if (xtok == ELSE)
break;
while (tok == SEPER)
@@ -1199,7 +1210,7 @@ par_if(int *complex)
}
pp = ecadd(0);
type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF);
- par_save_list(complex);
+ par_save_list(cmplx);
incmdpos = 1;
if (tok == ENDINPUT) {
cmdpop();
@@ -1214,7 +1225,7 @@ par_if(int *complex)
cmdpop();
cmdpush(nc);
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
incmdpos = 1;
cmdpop();
@@ -1223,12 +1234,13 @@ par_if(int *complex)
cmdpop();
cmdpush(nc);
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != OUTBRACE) {
cmdpop();
YYERRORV(oecused);
}
ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
+ /* command word (else) allowed to follow immediately */
zshlex();
incmdpos = 1;
if (tok == SEPER)
@@ -1240,7 +1252,7 @@ par_if(int *complex)
} else {
cmdpop();
cmdpush(nc);
- par_save_list1(complex);
+ par_save_list1(cmplx);
ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
incmdpos = 1;
break;
@@ -1254,18 +1266,19 @@ par_if(int *complex)
zshlex();
if (tok == INBRACE && usebrace) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != OUTBRACE) {
cmdpop();
YYERRORV(oecused);
}
} else {
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != FI) {
cmdpop();
YYERRORV(oecused);
}
}
+ incmdpos = 0;
ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp);
zshlex();
cmdpop();
@@ -1280,31 +1293,33 @@ par_if(int *complex)
/**/
static void
-par_while(int *complex)
+par_while(int *cmplx)
{
int oecused = ecused, p;
int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE);
p = ecadd(0);
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
incmdpos = 1;
while (tok == SEPER)
zshlex();
if (tok == DOLOOP) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != DONE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (tok == INBRACE) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != OUTBRACE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (isset(CSHJUNKIELOOPS)) {
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != ZEND)
YYERRORV(oecused);
zshlex();
@@ -1320,7 +1335,7 @@ par_while(int *complex)
/**/
static void
-par_repeat(int *complex)
+par_repeat(int *cmplx)
{
int oecused = ecused, p;
@@ -1337,25 +1352,27 @@ par_repeat(int *complex)
zshlex();
if (tok == DOLOOP) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != DONE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (tok == INBRACE) {
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != OUTBRACE)
YYERRORV(oecused);
+ incmdpos = 0;
zshlex();
} else if (isset(CSHJUNKIELOOPS)) {
- par_save_list(complex);
+ par_save_list(cmplx);
if (tok != ZEND)
YYERRORV(oecused);
zshlex();
} else if (unset(SHORTLOOPS)) {
YYERRORV(oecused);
} else
- par_save_list1(complex);
+ par_save_list1(cmplx);
ecbuf[p] = WCB_REPEAT(ecused - 1 - p);
}
@@ -1363,11 +1380,15 @@ par_repeat(int *complex)
/*
* subsh : INPAR list OUTPAR |
* INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ]
+ *
+ * With zsh_construct non-zero, we're doing a zsh special in which
+ * the following token is not considered in command position. This
+ * is used for arguments of anonymous functions.
*/
/**/
static void
-par_subsh(int *complex)
+par_subsh(int *cmplx, int zsh_construct)
{
enum lextok otok = tok;
int oecused = ecused, p, pp;
@@ -1376,11 +1397,11 @@ par_subsh(int *complex)
/* Extra word only needed for always block */
pp = ecadd(0);
zshlex();
- par_list(complex);
+ par_list(cmplx);
ecadd(WCB_END());
if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE))
YYERRORV(oecused);
- incmdpos = 1;
+ incmdpos = !zsh_construct;
zshlex();
/* Optional always block. No intervening SEPERs allowed. */
@@ -1397,7 +1418,7 @@ par_subsh(int *complex)
cmdpush(CS_ALWAYS);
zshlex();
- par_save_list(complex);
+ par_save_list(cmplx);
while (tok == SEPER)
zshlex();
@@ -1420,7 +1441,7 @@ par_subsh(int *complex)
/**/
static void
-par_funcdef(int *complex)
+par_funcdef(int *cmplx)
{
int oecused = ecused, num = 0, onp, p, c = 0;
int so, oecssub = ecssub;
@@ -1502,7 +1523,8 @@ par_funcdef(int *complex)
num++;
zshlex();
}
- *complex = (num > 0);
+ if (num > 0)
+ *cmplx = 1;
ecbuf[parg] = ecused - parg; /*?*/
ecbuf[parg+1] = num;
}
@@ -1564,15 +1586,15 @@ par_dinbrack(void)
/**/
static int
-par_simple(int *complex, int nr)
+par_simple(int *cmplx, int nr)
{
int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0;
- int c = *complex, nrediradd, assignments = 0;
+ int c = *cmplx, nrediradd, assignments = 0;
r = ecused;
for (;;) {
if (tok == NOCORRECT) {
- *complex = c = 1;
+ *cmplx = c = 1;
nocorrect = 1;
} else if (tok == ENVSTRING) {
char *p, *name, *str;
@@ -1600,7 +1622,7 @@ par_simple(int *complex, int nr)
*/
if (p[1] == Inpar &&
(*p == Equals || *p == Inang || *p == OutangProc)) {
- *complex = 1;
+ *cmplx = 1;
break;
}
}
@@ -1612,10 +1634,10 @@ par_simple(int *complex, int nr)
int oldcmdpos = incmdpos, n, type2;
/*
- * We consider array setting complex because it can
+ * We consider array setting cmplx because it can
* contain process substitutions, which need a valid job.
*/
- *complex = c = 1;
+ *cmplx = c = 1;
p = ecadd(0);
incmdpos = 0;
if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') {
@@ -1647,7 +1669,7 @@ par_simple(int *complex, int nr)
if (tok == STRING) {
int redir_var = 0;
- *complex = 1;
+ *cmplx = 1;
incmdpos = 0;
if (!isset(IGNOREBRACES) && *tokstr == Inbrace)
@@ -1666,7 +1688,7 @@ par_simple(int *complex, int nr)
if (IS_REDIROP(tok) && tokfd == -1)
{
- *complex = c = 1;
+ *cmplx = c = 1;
nrediradd = par_redir(&r, idstring);
p += nrediradd;
sr += nrediradd;
@@ -1687,7 +1709,7 @@ par_simple(int *complex, int nr)
zshlex();
}
} else if (IS_REDIROP(tok)) {
- *complex = c = 1;
+ *cmplx = c = 1;
nrediradd = par_redir(&r, NULL);
p += nrediradd;
sr += nrediradd;
@@ -1702,7 +1724,7 @@ par_simple(int *complex, int nr)
if (assignments)
YYERROR(oecused);
- *complex = c;
+ *cmplx = c;
lineno = 0;
incmdpos = 1;
cmdpush(CS_FUNCDEF);
@@ -1745,10 +1767,21 @@ par_simple(int *complex, int nr)
sl = ecadd(0);
(void)ecadd(WCB_PIPE(WC_PIPE_END, 0));
- if (!par_cmd(&c)) {
+ if (!par_cmd(&c, argc == 0)) {
cmdpop();
YYERROR(oecused);
}
+ if (argc == 0) {
+ /*
+ * Anonymous function, possibly with arguments.
+ * N.B. for cmplx structures in particular
+ * ( ... ) we rely on lower level code doing this
+ * to get the immediately following word (the
+ * first token after the ")" has already been
+ * read).
+ */
+ incmdpos = 0;
+ }
set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c);
set_list_code(ll, (Z_SYNC | Z_END), c);
@@ -1775,7 +1808,8 @@ par_simple(int *complex, int nr)
argc++;
zshlex();
}
- *complex = (argc > 0);
+ if (argc > 0)
+ *cmplx = 1;
ecbuf[parg] = ecused - parg; /*?*/
ecbuf[parg+1] = argc;
}
@@ -2542,6 +2576,73 @@ ecgetredirs(Estate s)
return ret;
}
+/*
+ * Copy the consecutive set of redirections in the state at s.
+ * Return NULL if none, else an Eprog consisting only of the
+ * redirections from permanently allocated memory.
+ *
+ * s is left in the state ready for whatever follows the redirections.
+ */
+
+/**/
+Eprog
+eccopyredirs(Estate s)
+{
+ Wordcode pc = s->pc;
+ wordcode code = *pc;
+ int ncode, ncodes = 0, r, type;
+
+ if (wc_code(code) != WC_REDIR)
+ return NULL;
+
+ init_parse();
+
+ while (wc_code(code) == WC_REDIR) {
+ type = WC_REDIR_TYPE(code);
+
+ DPUTS(type == REDIR_HEREDOC || type == REDIR_HEREDOCDASH,
+ "unexpanded here document");
+
+ if (WC_REDIR_FROM_HEREDOC(code))
+ ncode = 5;
+ else
+ ncode = 3;
+ if (WC_REDIR_VARID(code))
+ ncode++;
+ pc += ncode;
+ ncodes += ncode;
+ code = *pc;
+ }
+ r = ecused;
+ ecispace(r, ncodes);
+
+ code = *s->pc;
+ while (wc_code(code) == WC_REDIR) {
+ s->pc++;
+
+ ecbuf[r++] = code;
+ /* fd1 */
+ ecbuf[r++] = *s->pc++;
+ /* name or HERE string */
+ /* No DUP needed as we'll copy into Eprog immediately below */
+ ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL));
+ if (WC_REDIR_FROM_HEREDOC(code))
+ {
+ /* terminator, raw */
+ ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL));
+ /* terminator, munged */
+ ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL));
+ }
+ if (WC_REDIR_VARID(code))
+ ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL));
+
+ code = *s->pc;
+ }
+
+ /* bld_eprog() appends a useful WC_END marker */
+ return bld_eprog(0);
+}
+
/**/
mod_export struct eprog dummy_eprog;
@@ -3534,4 +3635,3 @@ dump_autoload(char *nam, char *file, int on, Options ops, int func)
}
return ret;
}
-
diff --git a/Src/pattern.c b/Src/pattern.c
index 94a299ebb..df5e602ca 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -3012,6 +3012,16 @@ patmatch(Upat prog)
break;
case P_STAR:
/* Handle specially for speed, although really P_ONEHASH+P_ANY */
+ while (P_OP(next) == P_STAR) {
+ /*
+ * If there's another * following we can optimise it
+ * out. Chains of *'s can give pathologically bad
+ * performance.
+ */
+ scan = next;
+ next = PATNEXT(scan);
+ }
+ /*FALLTHROUGH*/
case P_ONEHASH:
case P_TWOHASH:
/*
diff --git a/Src/prompt.c b/Src/prompt.c
index 328ae3c66..0cc9ef917 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -372,6 +372,17 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
if (t0 >= arg)
test = 1;
break;
+ case 'e':
+ {
+ Funcstack fsptr = funcstack;
+ test = arg;
+ while (fsptr && test > 0) {
+ test--;
+ fsptr = fsptr->prev;
+ }
+ test = !test;
+ }
+ break;
case 'L':
if (shlvl >= arg)
test = 1;
@@ -786,6 +797,19 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
if(bv->Rstring)
stradd(bv->Rstring);
break;
+ case 'e':
+ {
+ int depth = 0;
+ Funcstack fsptr = funcstack;
+ while (fsptr) {
+ depth++;
+ fsptr = fsptr->prev;
+ }
+ addbufspc(DIGBUFSIZE);
+ sprintf(bv->bp, "%d", depth);
+ bv->bp += strlen(bv->bp);
+ break;
+ }
case 'I':
if (funcstack && funcstack->tp != FS_SOURCE &&
!IN_EVAL_TRAP()) {
@@ -1292,12 +1316,11 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
*/
for (;;) {
*ptr++ = *fulltextptr;
- if (*fulltextptr == Outpar ||
- *fulltextptr == '\0')
+ if (*fulltextptr == '\0' ||
+ *fulltextptr++ == Outpar)
break;
- if (*fulltextptr == Nularg)
+ if (fulltextptr[-1] == Nularg)
remw--;
- fulltextptr++;
}
} else {
#ifdef MULTIBYTE_SUPPORT
@@ -1373,12 +1396,11 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
if (*skiptext == Inpar) {
/* see comment on left truncation above */
for (;;) {
- if (*skiptext == Outpar ||
- *skiptext == '\0')
+ if (*skiptext == '\0' ||
+ *skiptext++ == Outpar)
break;
- if (*skiptext == Nularg)
+ if (skiptext[-1] == Nularg)
maxwidth--;
- skiptext++;
}
} else {
#ifdef MULTIBYTE_SUPPORT
diff --git a/Src/signals.c b/Src/signals.c
index cb2b58161..2df69f96e 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -594,6 +594,17 @@ zhandler(int sig)
wait_for_processes();
break;
+ case SIGPIPE:
+ if (!handletrap(SIGPIPE)) {
+ if (!interact)
+ _exit(SIGPIPE);
+ else if (!isatty(SHTTY)) {
+ stopmsg = 1;
+ zexit(SIGPIPE, 1);
+ }
+ }
+ break;
+
case SIGHUP:
if (!handletrap(SIGHUP)) {
stopmsg = 1;
@@ -752,7 +763,7 @@ dosavetrap(int sig, int level)
Shfunc shf, newshf = NULL;
if ((shf = (Shfunc)gettrapnode(sig, 1))) {
/* Copy the node for saving */
- newshf = (Shfunc) zalloc(sizeof(*newshf));
+ newshf = (Shfunc) zshcalloc(sizeof(*newshf));
newshf->node.nam = ztrdup(shf->node.nam);
newshf->node.flags = shf->node.flags;
newshf->funcdef = dupeprog(shf->funcdef, 0);
@@ -897,6 +908,8 @@ removetrap(int sig)
noholdintr();
} else if (sig == SIGHUP)
install_handler(sig);
+ else if (sig == SIGPIPE && interact && !forklevel)
+ install_handler(sig);
else if (sig && sig <= SIGCOUNT &&
#ifdef SIGWINCH
sig != SIGWINCH &&
diff --git a/Src/subst.c b/Src/subst.c
index 4a5fe3a3c..1aa9b982e 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1522,6 +1522,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* unset. I don't quite understand why (v == NULL) isn't
* good enough, but there are places where we seem to need
* to second guess whether a value is a real value or not.
+ * See in particular the (colf && !vunset) test below.
*/
int vunset = 0;
/*
@@ -2638,8 +2639,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* - (array) contains no elements
* - (scalar) contains an empty string
*/
- if (colf && !vunset)
+ if (colf && !vunset) {
vunset = (isarr) ? !*aval : !*val || (*val == Nularg && !val[1]);
+ vunset *= -1; /* Record that vunset was originally false */
+ }
switch (s[-1]) {
case '+':
@@ -2862,7 +2865,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
getmatcharr(&aval, s, flags, flnum, replstr);
} else {
if (vunset) {
- if (unset(UNSET)) {
+ if (vunset > 0 && unset(UNSET)) {
*idend = '\0';
zerr("%s: parameter not set", idbeg);
return NULL;
@@ -2892,7 +2895,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
return NULL;
}
if (vunset) {
- if (unset(UNSET)) {
+ if (vunset > 0 && unset(UNSET)) {
*idend = '\0';
zerr("%s: parameter not set", idbeg);
return NULL;
@@ -2974,7 +2977,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
*ap = NULL;
} else {
if (vunset) {
- if (unset(UNSET)) {
+ if (vunset > 0 && unset(UNSET)) {
*idend = '\0';
zerr("%s: parameter not set", idbeg);
deletehashtable(ht);
@@ -3003,7 +3006,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
}
}
if (vunset) {
- if (unset(UNSET)) {
+ if (vunset > 0 && unset(UNSET)) {
*idend = '\0';
zerr("%s: parameter not set", idbeg);
return NULL;
@@ -3020,7 +3023,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
val = dupstring(vunset ? "0" : "1");
isarr = 0;
} else if (vunset) {
- if (unset(UNSET)) {
+ if (vunset > 0 && unset(UNSET)) {
*idend = '\0';
zerr("%s: parameter not set", idbeg);
return NULL;
diff --git a/Src/utils.c b/Src/utils.c
index 9109f66a7..e6eb8e6a7 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3424,12 +3424,12 @@ equalsplit(char *s, char **t)
return 0;
}
-static int specialcomma;
/* the ztypes table */
/**/
mod_export short int typtab[256];
+static int typtab_flags = 0;
/* initialize the ztypes table */
@@ -3440,8 +3440,15 @@ inittyptab(void)
int t0;
char *s;
- for (t0 = 0; t0 != 256; t0++)
- typtab[t0] = 0;
+ if (!(typtab_flags & ZTF_INIT)) {
+ typtab_flags = ZTF_INIT;
+ if (interact && isset(SHINSTDIN))
+ typtab_flags |= ZTF_INTERACT;
+ }
+
+ queue_signals();
+
+ memset(typtab, 0, sizeof(typtab));
for (t0 = 0; t0 != 32; t0++)
typtab[t0] = typtab[t0 + 128] = ICNTRL;
typtab[127] = ICNTRL;
@@ -3514,20 +3521,43 @@ inittyptab(void)
#endif
for (s = SPECCHARS; *s; s++)
typtab[STOUC(*s)] |= ISPECIAL;
- if (specialcomma)
+ if (typtab_flags & ZTF_SP_COMMA)
typtab[STOUC(',')] |= ISPECIAL;
- if (isset(BANGHIST) && bangchar && interact && isset(SHINSTDIN))
+ if (isset(BANGHIST) && bangchar && (typtab_flags & ZTF_INTERACT)) {
+ typtab_flags |= ZTF_BANGCHAR;
typtab[bangchar] |= ISPECIAL;
+ } else
+ typtab_flags &= ~ZTF_BANGCHAR;
+
+ unqueue_signals();
}
/**/
mod_export void
makecommaspecial(int yesno)
{
- if ((specialcomma = yesno) != 0)
+ if (yesno != 0) {
+ typtab_flags |= ZTF_SP_COMMA;
typtab[STOUC(',')] |= ISPECIAL;
- else
+ } else {
+ typtab_flags &= ~ZTF_SP_COMMA;
typtab[STOUC(',')] &= ~ISPECIAL;
+ }
+}
+
+/**/
+mod_export void
+makebangspecial(int yesno)
+{
+ /* Name and call signature for congruence with makecommaspecial(),
+ * but in this case when yesno is nonzero we defer to the state
+ * saved by inittyptab().
+ */
+ if (yesno == 0) {
+ typtab[bangchar] &= ~ISPECIAL;
+ } else if (typtab_flags & ZTF_BANGCHAR) {
+ typtab[bangchar] |= ISPECIAL;
+ }
}
diff --git a/Src/zsh.h b/Src/zsh.h
index fa7396112..d284c7aa7 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1139,6 +1139,7 @@ struct shfunc {
char *filename; /* Name of file located in */
zlong lineno; /* line number in above file */
Eprog funcdef; /* function definition */
+ Eprog redir; /* redirections to apply */
Emulation_options sticky; /* sticky emulation definitions, if any */
};
@@ -1820,7 +1821,8 @@ struct paramdef {
*/
enum {
ASSPM_AUGMENT = 1 << 0,
- ASSPM_WARN_CREATE = 1 << 1
+ ASSPM_WARN_CREATE = 1 << 1,
+ ASSPM_ENV_IMPORT = 1 << 2
};
/* node for named directory hash table (nameddirtab) */
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index cec3edab7..9a8c923f9 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -73,6 +73,9 @@ zshpaths.h: Makemod $(CONFIG_INCS)
@if test x$(sitefndir) != xno; then \
echo '#define SITEFPATH_DIR "'$(sitefndir)'"' >> zshpaths.h.tmp; \
fi
+ @if test x$(fixed_sitefndir) != x; then \
+ echo '#define FIXED_FPATH_DIR "'$(fixed_sitefndir)'"' >> zshpaths.h.tmp; \
+ fi
@if test x$(fndir) != xno; then \
echo '#define FPATH_DIR "'$(fndir)'"' >> zshpaths.h.tmp; \
if test x$(FUNCTIONS_SUBDIRS) != x && \
diff --git a/Src/ztype.h b/Src/ztype.h
index 14f66101c..eef0f23db 100644
--- a/Src/ztype.h
+++ b/Src/ztype.h
@@ -59,6 +59,15 @@
#define iwsep(X) zistype(X,IWSEP)
#define inull(X) zistype(X,INULL)
+/*
+ * Bit flags for typtab_flags --- preserved after
+ * shell initialisation.
+ */
+#define ZTF_INIT (0x0001) /* One-off initialisation done */
+#define ZTF_INTERACT (0x0002) /* Shell interative and reading from stdin */
+#define ZTF_SP_COMMA (0x0004) /* Treat comma as a special characters */
+#define ZTF_BANGCHAR (0x0008) /* Treat bangchar as a special character */
+
#ifdef MULTIBYTE_SUPPORT
#define WC_ZISTYPE(X,Y) wcsitype((X),(Y))
#define WC_ISPRINT(X) iswprint(X)