summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/clone.c2
-rw-r--r--Src/Modules/datetime.c46
-rw-r--r--Src/Modules/db_gdbm.c5
-rw-r--r--Src/Modules/mathfunc.c106
-rw-r--r--Src/Modules/parameter.c1
-rw-r--r--Src/Modules/parameter.mdd2
-rw-r--r--Src/Modules/pcre.c1
-rw-r--r--Src/Modules/stat.c22
-rw-r--r--Src/Modules/system.c4
-rw-r--r--Src/Modules/termcap.c14
-rw-r--r--Src/Modules/terminfo.c14
-rw-r--r--Src/Modules/zftp.c2
-rw-r--r--Src/Modules/zpty.c2
-rw-r--r--Src/Zle/compcore.c22
-rw-r--r--Src/Zle/zle_main.c23
-rw-r--r--Src/Zle/zle_params.c12
-rw-r--r--Src/Zle/zle_thingy.c2
-rw-r--r--Src/builtin.c30
-rw-r--r--Src/compat.c33
-rw-r--r--Src/exec.c425
-rw-r--r--Src/glob.c6
-rw-r--r--Src/init.c3
-rw-r--r--Src/jobs.c6
-rw-r--r--Src/math.c70
-rw-r--r--Src/options.c31
-rw-r--r--Src/params.c38
-rw-r--r--Src/parse.c4
-rw-r--r--Src/pattern.c19
-rw-r--r--Src/prompt.c9
-rw-r--r--Src/signals.c35
-rw-r--r--Src/signals.h2
-rw-r--r--Src/subst.c2
-rw-r--r--Src/utils.c59
-rw-r--r--Src/zsh.h6
-rw-r--r--Src/zsh_system.h8
35 files changed, 663 insertions, 403 deletions
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index 930429248..ef6275dcf 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -69,7 +69,7 @@ bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
dup2(ttyfd,2);
if (ttyfd > 2)
close(ttyfd);
- closem(0);
+ closem(FDT_UNUSED, 0);
close(coprocin);
close(coprocout);
/* Acquire a controlling terminal */
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 6e9047bc5..be378b347 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -180,66 +180,30 @@ getcurrentsecs(UNUSED(Param pm))
}
static double
-getcurrentrealtime(Param pm)
+getcurrentrealtime(UNUSED(Param pm))
{
-#ifdef HAVE_CLOCK_GETTIME
struct timespec now;
-
- if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
- zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
- return (double)0.0;
- }
-
+ zgettime(&now);
return (double)now.tv_sec + (double)now.tv_nsec * 1e-9;
-#else
- struct timeval now;
- struct timezone dummy_tz;
-
- (void)pm;
- gettimeofday(&now, &dummy_tz);
-
- return (double)now.tv_sec + (double)now.tv_usec * 1e-6;
-#endif
}
static char **
-getcurrenttime(Param pm)
+getcurrenttime(UNUSED(Param pm))
{
char **arr;
char buf[DIGBUFSIZE];
-
-#ifdef HAVE_CLOCK_GETTIME
struct timespec now;
- if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
- zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
- return NULL;
- }
-
- arr = (char **)zhalloc(3 * sizeof(*arr));
- sprintf(buf, "%ld", (long)now.tv_sec);
- arr[0] = dupstring(buf);
- sprintf(buf, "%ld", now.tv_nsec);
- arr[1] = dupstring(buf);
- arr[2] = NULL;
-
- return arr;
-#else
- struct timeval now;
- struct timezone dummy_tz;
-
- (void)pm;
- gettimeofday(&now, &dummy_tz);
+ zgettime(&now);
arr = (char **)zhalloc(3 * sizeof(*arr));
sprintf(buf, "%ld", (long)now.tv_sec);
arr[0] = dupstring(buf);
- sprintf(buf, "%ld", (long)now.tv_usec * 1000);
+ sprintf(buf, "%ld", (long)now.tv_nsec);
arr[1] = dupstring(buf);
arr[2] = NULL;
return arr;
-#endif
}
static struct builtin bintab[] = {
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index 5f776f407..ed702b912 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -359,7 +359,7 @@ gdbmsetfn(Param pm, char *val)
}
if (val) {
- pm->u.str = ztrdup(val);
+ pm->u.str = val;
pm->node.flags |= PM_UPTODATE;
}
@@ -732,6 +732,9 @@ static int remove_tied_name( const char *name ) {
p++;
}
+ if (*p)
+ zsfree(*p);
+
/* Copy x+1 to x */
while (*p) {
*p=*(p+1);
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index a7e8b294c..fc2593dca 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -65,6 +65,7 @@ MF_LGAMMA,
MF_LOG,
MF_LOG10,
MF_LOG1P,
+MF_LOG2,
MF_LOGB,
MF_NEXTAFTER,
MF_RINT,
@@ -93,22 +94,6 @@ MS_RAND48
* conversion), atan2.
*/
-/* Flags for bounds. Note these must start at 1, not 0. */
-
-enum {
- BF_POS = 1, /* must be positive */
- BF_NONNEG = 2, /* must be non-negative */
- BF_FRAC = 3, /* must be -1 <= x <= 1 */
- BF_GE1 = 4, /* must be >= 1 */
- BF_FRACO = 5, /* must be in open range -1 < x < 1 */
- BF_INTPOS = 6, /* must be non-integer or positive */
- BF_GTRM1 = 7, /* must be > -1 */
- BF_NONZ = 8, /* must be nonzero */
- BF_POS2 = 9 /* second argument must be positive */
-};
-
-#define BFLAG(x) ((x) << 8)
-
/*
* Flags for type of function: unlike the above, these must
* be individually bit-testable.
@@ -121,18 +106,18 @@ enum {
TF_NOASS = 8 /* don't assign result as double */
};
-#define TFLAG(x) ((x) << 16)
+#define TFLAG(x) ((x) << 8)
static struct mathfunc mftab[] = {
- NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) |
+ NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS |
TFLAG(TF_NOCONV|TF_NOASS)),
- NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)),
- NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH | BFLAG(BF_GE1)),
- NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN | BFLAG(BF_FRAC)),
+ NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS),
+ NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH),
+ NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN),
NUMMATHFUNC("asinh", math_func, 1, 1, MF_ASINH),
NUMMATHFUNC("atan", math_func, 1, 2, MF_ATAN),
- NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH | BFLAG(BF_FRACO)),
+ NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH),
NUMMATHFUNC("cbrt", math_func, 1, 1, MF_CBRT),
NUMMATHFUNC("ceil", math_func, 1, 1, MF_CEIL),
NUMMATHFUNC("copysign", math_func, 2, 2, MF_COPYSIGN),
@@ -146,20 +131,20 @@ static struct mathfunc mftab[] = {
NUMMATHFUNC("float", math_func, 1, 1, MF_FLOAT),
NUMMATHFUNC("floor", math_func, 1, 1, MF_FLOOR),
NUMMATHFUNC("fmod", math_func, 2, 2, MF_FMOD),
- NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA | BFLAG(BF_INTPOS)),
+ NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA),
NUMMATHFUNC("hypot", math_func, 2, 2, MF_HYPOT),
- NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | BFLAG(BF_NONZ) |
- TFLAG(TF_NOASS)),
+ NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | TFLAG(TF_NOASS)),
NUMMATHFUNC("int", math_func, 1, 1, MF_INT | TFLAG(TF_NOASS)),
NUMMATHFUNC("j0", math_func, 1, 1, MF_J0),
NUMMATHFUNC("j1", math_func, 1, 1, MF_J1),
NUMMATHFUNC("jn", math_func, 2, 2, MF_JN | TFLAG(TF_INT1)),
NUMMATHFUNC("ldexp", math_func, 2, 2, MF_LDEXP | TFLAG(TF_INT2)),
- NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA | BFLAG(BF_INTPOS)),
- NUMMATHFUNC("log", math_func, 1, 1, MF_LOG | BFLAG(BF_POS)),
- NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10 | BFLAG(BF_POS)),
- NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)),
- NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)),
+ NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA),
+ NUMMATHFUNC("log", math_func, 1, 1, MF_LOG),
+ NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10),
+ NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P),
+ NUMMATHFUNC("log2", math_func, 1, 1, MF_LOG2),
+ NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB),
NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER),
#ifdef HAVE_ERAND48
STRMATHFUNC("rand48", math_string, MS_RAND48),
@@ -171,17 +156,17 @@ static struct mathfunc mftab[] = {
#endif
NUMMATHFUNC("sin", math_func, 1, 1, MF_SIN),
NUMMATHFUNC("sinh", math_func, 1, 1, MF_SINH),
- NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT | BFLAG(BF_NONNEG)),
+ NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT),
NUMMATHFUNC("tan", math_func, 1, 1, MF_TAN),
NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH),
- NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)),
- NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)),
- NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1))
+ NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0),
+ NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1),
+ NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | TFLAG(TF_INT1))
};
/**/
static mnumber
-math_func(char *name, int argc, mnumber *argv, int id)
+math_func(UNUSED(char *name), int argc, mnumber *argv, int id)
{
mnumber ret;
double argd = 0, argd2 = 0, retd = 0;
@@ -208,49 +193,6 @@ math_func(char *name, int argc, mnumber *argv, int id)
if (errflag)
return ret;
- if (id & 0xff00) {
- int rtst = 0;
-
- switch ((id >> 8) & 0xff) {
- case BF_POS:
- rtst = (argd <= 0.0);
- break;
-
- case BF_NONNEG:
- rtst = (argd < 0.0);
- break;
-
- case BF_FRAC:
- rtst = (fabs(argd) > 1.0);
- break;
-
- case BF_GE1:
- rtst = (argd < 1.0);
- break;
-
- case BF_FRACO:
- rtst = (fabs(argd) >= 1.0);
- break;
-
- case BF_INTPOS:
- rtst = (argd <= 0 && (double)(zlong)argd == argd);
- break;
-
- case BF_GTRM1:
- rtst = (argd <= -1);
- break;
-
- case BF_POS2:
- rtst = (argd2 <= 0.0);
- break;
- }
-
- if (rtst) {
- zerr("math: argument to %s out of range", name);
- return ret;
- }
- }
-
switch (id & 0xff) {
case MF_ABS:
ret.type = argv->type;
@@ -398,6 +340,14 @@ math_func(char *name, int argc, mnumber *argv, int id)
retd = log1p(argd);
break;
+ case MF_LOG2:
+#ifdef HAVE_LOG2
+ retd = log2(argd);
+#else
+ retd = log(argd) / log(2);
+#endif
+ break;
+
case MF_LOGB:
retd = logb(argd);
break;
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 10c47d214..783c36df3 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -2190,6 +2190,7 @@ static const struct gsu_array dirs_gsu =
static const struct gsu_array historywords_gsu =
{ histwgetfn, arrsetfn, stdunsetfn };
+/* Make sure to update autofeatures in parameter.mdd if necessary */
static struct paramdef partab[] = {
SPECIALPMDEF("aliases", 0,
&pmraliases_gsu, getpmralias, scanpmraliases),
diff --git a/Src/Modules/parameter.mdd b/Src/Modules/parameter.mdd
index a91a5dc09..f71c17a72 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: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"
+autofeatures="p:parameters p:commands p:functions p:dis_functions p:functions_source p:dis_functions_source 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:usergroups p:aliases p:dis_aliases p:galiases p:dis_galiases p:saliases p:dis_saliases"
objects="parameter.o"
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index 15ee34bc8..6289e003e 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -380,6 +380,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func))
if (ovec)
zfree(ovec, ovecsize*sizeof(int));
+ zsfree(plaintext);
return return_value;
}
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 66baa1292..50a6a9bb2 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -188,7 +188,7 @@ static char *timefmt;
/**/
static void
-stattimeprint(time_t tim, char *outbuf, int flags)
+stattimeprint(time_t tim, long nsecs, char *outbuf, int flags)
{
if (flags & STF_RAW) {
sprintf(outbuf, "%ld", (unsigned long)tim);
@@ -199,7 +199,7 @@ stattimeprint(time_t tim, char *outbuf, int flags)
char *oend = outbuf + strlen(outbuf);
/* Where the heck does "40" come from? */
int len = ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
- localtime(&tim), 0L);
+ localtime(&tim), nsecs);
if (len > 0)
metafy(oend, len, META_NOALLOC);
if (flags & STF_RAW)
@@ -291,15 +291,27 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
break;
case ST_ATIM:
- stattimeprint(sbuf->st_atime, optr, flags);
+#ifdef GET_ST_ATIME_NSEC
+ stattimeprint(sbuf->st_atime, GET_ST_ATIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_atime, 0L, optr, flags);
+#endif
break;
case ST_MTIM:
- stattimeprint(sbuf->st_mtime, optr, flags);
+#ifdef GET_ST_MTIME_NSEC
+ stattimeprint(sbuf->st_mtime, GET_ST_MTIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_mtime, 0L, optr, flags);
+#endif
break;
case ST_CTIM:
- stattimeprint(sbuf->st_ctime, optr, flags);
+#ifdef GET_ST_CTIME_NSEC
+ stattimeprint(sbuf->st_ctime, GET_ST_CTIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_ctime, 0L, optr, flags);
+#endif
break;
case ST_BLKSIZE:
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index 9fd4d2583..7a4f4ee13 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -772,6 +772,8 @@ fillpmsysparams(Param pm, const char *name)
num = (int)getpid();
} else if (!strcmp(name, "ppid")) {
num = (int)getppid();
+ } else if (!strcmp(name, "procsubstpid")) {
+ num = (int)procsubstpid;
} else {
pm->u.str = dupstring("");
pm->node.flags |= PM_UNSET;
@@ -805,6 +807,8 @@ scanpmsysparams(UNUSED(HashTable ht), ScanFunc func, int flags)
func(&spm.node, flags);
fillpmsysparams(&spm, "ppid");
func(&spm.node, flags);
+ fillpmsysparams(&spm, "procsubstpid");
+ func(&spm.node, flags);
}
static struct mathfunc mftab[] = {
diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c
index 60a6e138a..af4009a3a 100644
--- a/Src/Modules/termcap.c
+++ b/Src/Modules/termcap.c
@@ -345,16 +345,7 @@ int
boot_(UNUSED(Module m))
{
#ifdef HAVE_TGETENT
-# ifdef HAVE_SETUPTERM
- int errret;
-
- /*
- * Just because we can't set up the terminal doesn't
- * mean the modules hasn't booted---TERM may change,
- * and it should be handled dynamically---so ignore errors here.
- */
- (void)setupterm((char *)0, 1, &errret);
-# endif
+ zsetupterm();
#endif
return 0;
}
@@ -363,6 +354,9 @@ boot_(UNUSED(Module m))
int
cleanup_(Module m)
{
+#ifdef HAVE_TGETENT
+ zdeleteterm();
+#endif
return setfeatureenables(m, &module_features, NULL);
}
diff --git a/Src/Modules/terminfo.c b/Src/Modules/terminfo.c
index bbd325899..4596b41d2 100644
--- a/Src/Modules/terminfo.c
+++ b/Src/Modules/terminfo.c
@@ -338,16 +338,7 @@ int
boot_(UNUSED(Module m))
{
#ifdef USE_TERMINFO_MODULE
-# ifdef HAVE_SETUPTERM
- int errret;
-
- /*
- * Just because we can't set up the terminal doesn't
- * mean the modules hasn't booted---TERM may change,
- * and it should be handled dynamically---so ignore errors here.
- */
- (void)setupterm((char *)0, 1, &errret);
-# endif
+ zsetupterm();
#endif
return 0;
@@ -357,6 +348,9 @@ boot_(UNUSED(Module m))
int
cleanup_(Module m)
{
+#ifdef USE_TERMINFO_MODULE
+ zdeleteterm();
+#endif
return setfeatureenables(m, &module_features, NULL);
}
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 24f4b4200..4aaa1f072 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -362,7 +362,7 @@ static jmp_buf zfalrmbuf;
/* The signal handler itself */
/**/
-static RETSIGTYPE
+static void
zfhandler(int sig)
{
if (sig == SIGALRM) {
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 1c93a1d02..2f83f7ce6 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -400,7 +400,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
dup2(slave, 1);
dup2(slave, 2);
- closem(0);
+ closem(FDT_UNUSED, 0);
close(slave);
close(master);
close(coprocin);
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 52b0c173f..8eca39447 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1610,9 +1610,11 @@ set_comp_sep(void)
inpush(dupstrspace(tmp), 0, NULL);
zlemetaline = tmp;
/*
- * Length of temporary string, calculated above.
+ * tl is the length of temporary string, calculated above.
+ * It seems zlemetall need not include the 'x' added at the cursor.
+ * addedx is taken care of in function gotword() (lex.c).
*/
- zlemetall = tl;
+ zlemetall = tl - addedx;
strinbeg(0);
noaliases = 1;
do {
@@ -1638,7 +1640,7 @@ set_comp_sep(void)
p[-1] = '\0';
}
}
- if (tok == ENDINPUT || tok == LEXERR)
+ if (tok == ENDINPUT)
break;
if (tokstr && *tokstr) {
for (p = tokstr; dq && *p; p++) {
@@ -1667,9 +1669,9 @@ set_comp_sep(void)
if (!got && !lexflags) {
DPUTS(!p, "no current word in substr");
got = 1;
- cur = i;
- swb = wb - 1 - dq - sq - dolq;
- swe = we - 1 - dq - sq - dolq;
+ cur = countlinknodes(foo) - 1; /* cur is 0 offset */
+ swb = wb - dq - sq - dolq;
+ swe = we - dq - sq - dolq;
sqq = lsq;
soffs = zlemetacs - swb - css;
DPUTS2(p[soffs] != 'x', "expecting 'x' at offset %d of \"%s\"",
@@ -1901,7 +1903,11 @@ set_comp_sep(void)
p = compwords[i] = (char *) getdata(n);
untokenize(p);
}
- compcurrent = cur + 1;
+ /* The current position shouldn't exceed the new word count */
+ if ((compcurrent = cur + 1) > i) {
+ DPUTS2(1, "compcurrent=%d > number_of_words=%d", compcurrent, i);
+ compcurrent = i;
+ }
compwords[i] = NULL;
}
instring = ois;
@@ -3550,6 +3556,8 @@ freematches(Cmgroup g, int cm)
}
free(g->expls);
}
+ if (g->widths)
+ free(g->widths);
zsfree(g->name);
free(g);
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index be2b062b0..db70e7d7e 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -58,6 +58,11 @@ mod_export int incompctlfunc;
/**/
mod_export int hascompmod;
+/* Increment for each nested recursive-edit */
+
+/**/
+mod_export int zle_recursive;
+
/* ZLRF_* flags passed to zleread() */
/**/
@@ -631,6 +636,8 @@ raw_getbyte(long do_keytmout, char *cptr)
continue;
}
if (selret == 0) {
+ zlong save_lastval;
+
/*
* Nothing ready and no error, so we timed out.
*/
@@ -648,6 +655,7 @@ raw_getbyte(long do_keytmout, char *cptr)
break;
case ZTM_FUNC:
+ save_lastval = lastval;
while (firstnode(timedfns)) {
Timedfn tfdat = (Timedfn)getdata(firstnode(timedfns));
/*
@@ -661,6 +669,7 @@ raw_getbyte(long do_keytmout, char *cptr)
break;
tfdat->func();
}
+ lastval = save_lastval;
/* Function may have messed up the display */
if (resetneeded)
zrefresh();
@@ -800,6 +809,8 @@ raw_getbyte(long do_keytmout, char *cptr)
}
# endif
}
+ /* If looping, need to recalculate timeout */
+ calc_timeout(&tmout, do_keytmout);
}
# ifdef HAVE_POLL
zfree(fds, sizeof(struct pollfd) * nfds);
@@ -1648,6 +1659,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;
+ int warn_flags;
char *p1, *p2, *main_keymapname, *vicmd_keymapname, *init, *finish;
Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL;
FILE *oshout = NULL;
@@ -1661,6 +1673,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
return 1;
}
+ warn_flags = OPT_ISSET(ops, 'g') ? 0 : ASSPM_WARN;
if (OPT_ISSET(ops,'A'))
{
if (OPT_ISSET(ops, 'a'))
@@ -1841,11 +1854,11 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
a = spacesplit(t, 1, 0, 1);
zsfree(t);
if (PM_TYPE(pm->node.flags) == PM_ARRAY)
- setaparam(args[0], a);
+ assignaparam(args[0], a, warn_flags);
else
sethparam(args[0], a);
} else
- setsparam(args[0], t);
+ assignsparam(args[0], t, warn_flags);
unqueue_signals();
return 0;
}
@@ -1933,6 +1946,8 @@ recursiveedit(UNUSED(char **args))
int locerror;
int q = queue_signal_level();
+ ++zle_recursive;
+
/* zlecore() expects to be entered with signal queue disabled */
dont_queue_signals();
@@ -1942,6 +1957,8 @@ recursiveedit(UNUSED(char **args))
restore_queue_signals(q);
+ --zle_recursive;
+
locerror = errflag ? 1 : 0;
errflag = done = eofsent = 0;
@@ -2144,7 +2161,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, "aAcef:hi:M:m:p:r:t:", NULL),
+ BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcef:ghi:M:m:p:r:t:", NULL),
BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDfFgGIKlLmMNrRTUw", NULL),
};
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index f3112165a..9f4fb5ac2 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -93,6 +93,8 @@ static const struct gsu_integer numeric_gsu =
{ get_numeric, set_numeric, unset_numeric };
static const struct gsu_integer pending_gsu =
{ get_pending, NULL, zleunsetfn };
+static const struct gsu_integer recursive_gsu =
+{ get_recursive, NULL, zleunsetfn };
static const struct gsu_integer region_active_gsu =
{ get_region_active, set_region_active, zleunsetfn };
static const struct gsu_integer undo_change_no_gsu =
@@ -180,6 +182,7 @@ static struct zleparam {
{ "SUFFIX_START", PM_INTEGER, GSU(suffixstart_gsu), NULL },
{ "SUFFIX_END", PM_INTEGER, GSU(suffixend_gsu), NULL },
{ "SUFFIX_ACTIVE", PM_INTEGER | PM_READONLY, GSU(suffixactive_gsu), NULL },
+ { "ZLE_RECURSIVE", PM_INTEGER | PM_READONLY, GSU(recursive_gsu), NULL },
{ "ZLE_STATE", PM_SCALAR | PM_READONLY, GSU(zle_state_gsu), NULL },
{ NULL, 0, NULL, NULL }
};
@@ -528,6 +531,13 @@ get_pending(UNUSED(Param pm))
/**/
static zlong
+get_recursive(UNUSED(Param pm))
+{
+ return zle_recursive;
+}
+
+/**/
+static zlong
get_yankstart(UNUSED(Param pm))
{
return yankb;
@@ -819,7 +829,7 @@ get_registers(UNUSED(HashTable ht), const char *name)
/**/
static void
-set_registers(UNUSED(Param pm), HashTable ht)
+set_registers(Param pm, HashTable ht)
{
int i;
HashNode hn;
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 5601c1178..6b892b822 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -725,13 +725,13 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
remetafy = 0;
while (*args && **args == '-') {
+ char skip_this_arg[2] = "x";
char *num;
if (!args[0][1] || args[0][1] == '-') {
args++;
break;
}
while (*++(*args)) {
- char skip_this_arg[2] = "x";
switch (**args) {
case 'n':
num = args[0][1] ? args[0]+1 : args[1];
diff --git a/Src/builtin.c b/Src/builtin.c
index 73cfe7ad1..93fa9112c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3199,7 +3199,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
pflags |= PRINT_NAMEONLY;
if (OPT_MINUS(ops,'M') || OPT_PLUS(ops,'M')) {
- MathFunc p, q;
+ MathFunc p, q, prev;
/*
* Add/remove/list function as mathematical.
*/
@@ -3331,15 +3331,10 @@ bin_functions(char *name, char **argv, Options ops, int func)
p->maxargs = maxargs;
queue_signals();
- for (q = mathfuncs; q; q = q->next) {
+ for (q = mathfuncs, prev = NULL; q; prev = q, q = q->next) {
if (!strcmp(q->name, funcname)) {
- unqueue_signals();
- zwarnnam(name, "-M %s: function already exists",
- funcname);
- zsfree(p->name);
- zsfree(p->module);
- zfree(p, sizeof(struct mathfunc));
- return 1;
+ removemathfunc(prev, q);
+ break;
}
}
@@ -5234,8 +5229,14 @@ bin_print(char *name, char **args, Options ops, int func)
errflag &= ~ERRFLAG_ERROR;
ret = 1;
}
- print_val(doubleval)
- break;
+ /* force consistent form for Inf/NaN output */
+ if (isnan(doubleval))
+ count += fputs("nan", fout);
+ else if (isinf(doubleval))
+ count += fputs((doubleval < 0.0) ? "-inf" : "inf", fout);
+ else
+ print_val(doubleval)
+ break;
case 3:
#ifdef ZSH_64_BIT_UTYPE
*d++ = 'l';
@@ -5317,8 +5318,13 @@ bin_shift(char *name, char **argv, Options ops, UNUSED(int func))
/* optional argument can be either numeric or an array */
queue_signals();
- if (*argv && !getaparam(*argv))
+ if (*argv && !getaparam(*argv)) {
num = mathevali(*argv++);
+ if (errflag) {
+ unqueue_signals();
+ return 1;
+ }
+ }
if (num < 0) {
unqueue_signals();
diff --git a/Src/compat.c b/Src/compat.c
index a130d9264..7b5c4411c 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -94,6 +94,39 @@ gettimeofday(struct timeval *tv, struct timezone *tz)
#endif
+/* Provide clock time with nanoseconds */
+
+/**/
+mod_export int
+zgettime(struct timespec *ts)
+{
+ int ret = -1;
+
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec dts;
+ if (clock_gettime(CLOCK_REALTIME, &dts) < 0) {
+ zwarn("unable to retrieve time: %e", errno);
+ ret--;
+ } else {
+ ret++;
+ ts->tv_sec = (time_t) dts.tv_sec;
+ ts->tv_nsec = (long) dts.tv_nsec;
+ }
+#endif
+
+ if (ret) {
+ struct timeval dtv;
+ struct timezone dtz;
+ gettimeofday(&dtv, &dtz);
+ ret++;
+ ts->tv_sec = (time_t) dtv.tv_sec;
+ ts->tv_nsec = (long) dtv.tv_usec * 1000;
+ }
+
+ return ret;
+}
+
+
/* compute the difference between two calendar times */
/**/
diff --git a/Src/exec.c b/Src/exec.c
index 216057aa7..615a5086f 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -174,6 +174,11 @@ mod_export int zleactive;
/**/
pid_t cmdoutpid;
+/* pid of last process started by <(...), >(...) */
+
+/**/
+mod_export pid_t procsubstpid;
+
/* exit status of process undergoing 'process substitution' */
/**/
@@ -698,7 +703,7 @@ execute(LinkList args, int flags, int defpath)
* Note that we don't close fd's attached to process substitution
* here, which should be visible to external processes.
*/
- closem(FDT_XTRACE);
+ closem(FDT_XTRACE, 0);
#ifndef FD_CLOEXEC
if (SHTTY != -1) {
close(SHTTY);
@@ -1878,8 +1883,6 @@ static void
execpline2(Estate state, wordcode pcode,
int how, int input, int output, int last1)
{
- pid_t pid;
- int pipes[2];
struct execcmd_params eparams;
if (breaks || retflag)
@@ -1900,65 +1903,21 @@ execpline2(Estate state, wordcode pcode,
}
if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) {
execcmd_analyse(state, &eparams);
- execcmd_exec(state, &eparams, input, output, how, last1 ? 1 : 2);
+ execcmd_exec(state, &eparams, input, output, how, last1 ? 1 : 2, -1);
} else {
+ int pipes[2];
int old_list_pipe = list_pipe;
- int subsh_close = -1;
- Wordcode next = state->pc + (*state->pc), start_pc;
+ Wordcode next = state->pc + (*state->pc);
- start_pc = ++state->pc;
+ ++state->pc;
execcmd_analyse(state, &eparams);
if (mpipe(pipes) < 0) {
/* FIXME */
}
- /* if we are doing "foo | bar" where foo is a current *
- * shell command, do foo in a subshell and do the *
- * rest of the pipeline in the current shell. */
- if ((eparams.type >= WC_CURSH || !eparams.args)
- && (how & Z_SYNC)) {
- int synch[2];
- struct timeval bgtime;
-
- if (pipe(synch) < 0) {
- zerr("pipe failed: %e", errno);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- return;
- } else if ((pid = zfork(&bgtime)) == -1) {
- close(synch[0]);
- close(synch[1]);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- return;
- } else if (pid) {
- char dummy, *text;
-
- text = getjobtext(state->prog, start_pc);
- addproc(pid, text, 0, &bgtime);
- close(synch[1]);
- read_loop(synch[0], &dummy, 1);
- close(synch[0]);
- } else {
- zclose(pipes[0]);
- close(synch[0]);
- entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0)
- | ESUB_PGRP | ESUB_KEEPTRAP);
- close(synch[1]);
- if (sigtrapped[SIGEXIT])
- {
- unsettrap(SIGEXIT);
- }
- execcmd_exec(state, &eparams, input, pipes[1], how, 1);
- _exit(lastval);
- }
- } else {
- /* otherwise just do the pipeline normally. */
- addfilelist(NULL, pipes[0]);
- subsh_close = pipes[0];
- execcmd_exec(state, &eparams, input, pipes[1], how, 0);
- }
+ addfilelist(NULL, pipes[0]);
+ execcmd_exec(state, &eparams, input, pipes[1], how, 0, pipes[0]);
zclose(pipes[1]);
state->pc = next;
@@ -1969,8 +1928,6 @@ execpline2(Estate state, wordcode pcode,
execpline2(state, *state->pc++, how, pipes[0], output, last1);
list_pipe = old_list_pipe;
cmdpop();
- if (subsh_close != pipes[0])
- zclose(pipes[0]);
}
}
@@ -2707,6 +2664,85 @@ static void execcmd_getargs(LinkList preargs, LinkList args, int expand)
}
}
+/**/
+static int
+execcmd_fork(Estate state, int how, int type, Wordcode varspc,
+ LinkList *filelistp, char *text, int oautocont,
+ int close_if_forked)
+{
+ pid_t pid;
+ int synch[2], flags;
+ char dummy;
+ struct timeval bgtime;
+
+ child_block();
+
+ if (pipe(synch) < 0) {
+ zerr("pipe failed: %e", errno);
+ return -1;
+ } else if ((pid = zfork(&bgtime)) == -1) {
+ close(synch[0]);
+ close(synch[1]);
+ lastval = 1;
+ errflag |= ERRFLAG_ERROR;
+ return -1;
+ }
+ if (pid) {
+ close(synch[1]);
+ read_loop(synch[0], &dummy, 1);
+ close(synch[0]);
+ if (how & Z_ASYNC) {
+ lastpid = (zlong) pid;
+ } else if (!jobtab[thisjob].stty_in_env && varspc) {
+ /* search for STTY=... */
+ Wordcode p = varspc;
+ wordcode ac;
+
+ while (wc_code(ac = *p) == WC_ASSIGN) {
+ if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
+ jobtab[thisjob].stty_in_env = 1;
+ break;
+ }
+ p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
+ 3 : WC_ASSIGN_NUM(ac) + 2);
+ }
+ }
+ addproc(pid, text, 0, &bgtime);
+ if (oautocont >= 0)
+ opts[AUTOCONTINUE] = oautocont;
+ pipecleanfilelist(jobtab[thisjob].filelist, 1);
+ return pid;
+ }
+
+ /* pid == 0 */
+ close(synch[0]);
+ flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP;
+ if ((type != WC_SUBSH) && !(how & Z_ASYNC))
+ flags |= ESUB_KEEPTRAP;
+ if (type == WC_SUBSH && !(how & Z_ASYNC))
+ flags |= ESUB_JOB_CONTROL;
+ *filelistp = jobtab[thisjob].filelist;
+ entersubsh(flags);
+ close(synch[1]);
+ zclose(close_if_forked);
+
+ if (sigtrapped[SIGINT] & ZSIG_IGNORED)
+ holdintr();
+ /*
+ * EXIT traps shouldn't be called even if we forked to run
+ * shell code as this isn't the main shell.
+ */
+ sigtrapped[SIGEXIT] = 0;
+#ifdef HAVE_NICE
+ /* Check if we should run background jobs at a lower priority. */
+ if ((how & Z_ASYNC) && isset(BGNICE))
+ if (nice(5) < 0)
+ zwarn("nice(5) failed: %e", errno);
+#endif /* HAVE_NICE */
+
+ return 0;
+}
+
/*
* Execute a command at the lowest level of the hierarchy.
*/
@@ -2714,7 +2750,7 @@ static void execcmd_getargs(LinkList preargs, LinkList args, int expand)
/**/
static void
execcmd_exec(Estate state, Execcmd_params eparams,
- int input, int output, int how, int last1)
+ int input, int output, int how, int last1, int close_if_forked)
{
HashNode hn = NULL;
LinkList filelist = NULL;
@@ -2724,7 +2760,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
char *text;
int save[10];
int fil, dfil, is_cursh, do_exec = 0, redir_err = 0, i;
- int nullexec = 0, magic_assign = 0, forked = 0;
+ int nullexec = 0, magic_assign = 0, forked = 0, old_lastval;
int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0;
/* Various flags to the command. */
int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1;
@@ -2749,6 +2785,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* If assignment but no command get the status from variable
* assignment.
*/
+ old_lastval = lastval;
if (!args && varspc)
lastval = errflag ? errflag : cmdoutval;
/*
@@ -2791,6 +2828,29 @@ execcmd_exec(Estate state, Execcmd_params eparams,
pushnode(args, dupstring("fg"));
}
+ if ((how & Z_ASYNC) || output) {
+ /*
+ * If running in the background, or not the last command in a
+ * pipeline, we don't need any of the rest of this function to
+ * affect the state in the main shell, so fork immediately.
+ *
+ * In other cases we may need to process the command line
+ * a bit further before we make the decision.
+ */
+ text = getjobtext(state->prog, eparams->beg);
+ switch (execcmd_fork(state, how, type, varspc, &filelist,
+ text, oautocont, close_if_forked)) {
+ case -1:
+ goto fatal;
+ case 0:
+ break;
+ default:
+ return;
+ }
+ last1 = forked = 1;
+ } else
+ text = NULL;
+
/* Check if it's a builtin needing automatic MAGIC_EQUALS_SUBST *
* handling. Things like typeset need this. We can't detect the *
* command if it contains some tokens (e.g. x=ex; ${x}port), so this *
@@ -2799,7 +2859,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if ((type == WC_SIMPLE || type == WC_TYPESET) && args) {
/*
* preargs contains args that have been expanded by prefork.
- * Running execcmd_getargs() causes the any argument available
+ * Running execcmd_getargs() causes any argument available
* in args to be exanded where necessary and transferred to
* preargs. We call execcmd_getargs() every time we need to
* analyse an argument not available in preargs, though there is
@@ -2846,8 +2906,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
is_builtin = 1;
/* autoload the builtin if necessary */
- if (!(hn = resolvebuiltin(cmdarg, hn)))
+ if (!(hn = resolvebuiltin(cmdarg, hn))) {
+ if (forked)
+ _exit(lastval);
return;
+ }
if (type != WC_TYPESET)
magic_assign = (hn->flags & BINF_MAGICEQUALS);
break;
@@ -3025,6 +3088,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("unknown exec flag -%c", *cmdopt);
lastval = 1;
errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3074,6 +3139,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
esprefork = (magic_assign ||
(isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ?
PREFORK_TYPESET : 0;
+
if (args) {
if (eparams->htok)
prefork(args, esprefork, NULL);
@@ -3117,6 +3183,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("redirection with no command");
lastval = 1;
errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _exit(lastval);
return;
} else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
if (!args)
@@ -3135,6 +3203,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
}
} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
lastval = 0;
+ if (forked)
+ _exit(lastval);
return;
} else {
/*
@@ -3145,11 +3215,16 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (badcshglob == 1) {
zerr("no match");
lastval = 1;
+ if (forked)
+ _exit(lastval);
return;
}
cmdoutval = use_cmdoutval ? lastval : 0;
- if (varspc)
+ if (varspc) {
+ /* Make sure $? is still correct for assignment */
+ lastval = old_lastval;
addvars(state, varspc, 0);
+ }
if (errflag)
lastval = 1;
else
@@ -3158,12 +3233,16 @@ execcmd_exec(Estate state, Execcmd_params eparams,
fputc('\n', xtrerr);
fflush(xtrerr);
}
+ if (forked)
+ _exit(lastval);
return;
}
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
zerrnam("exec", "%s: restricted",
(char *) getdata(firstnode(args)));
lastval = 1;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3198,6 +3277,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
break;
@@ -3206,8 +3287,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
is_builtin = 1;
/* autoload the builtin if necessary */
- if (!(hn = resolvebuiltin(cmdarg, hn)))
+ if (!(hn = resolvebuiltin(cmdarg, hn))) {
+ if (forked)
+ _exit(lastval);
return;
+ }
break;
}
cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -3222,15 +3306,15 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
/* Get the text associated with this command. */
- if ((how & Z_ASYNC) ||
+ if (!text &&
(!sfcontext && (jobbing || (how & Z_TIMED))))
text = getjobtext(state->prog, eparams->beg);
- else
- text = NULL;
/*
* Set up special parameter $_
@@ -3301,6 +3385,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3329,6 +3415,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3378,7 +3466,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/**************************************************************************
* Do we need to fork? We need to fork if: *
- * 1) The command is supposed to run in the background. (or) *
+ * 1) The command is supposed to run in the background. This *
+ * case is now handled above (forked = 1 here). (or) *
* 2) There is no `exec' flag, and either: *
* a) This is a builtin or shell function with output piped somewhere. *
* b) This is an external command and we can't do a `fake exec'. *
@@ -3397,99 +3486,45 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* current shell. *
**************************************************************************/
- if ((how & Z_ASYNC) ||
- (!do_exec &&
- (((is_builtin || is_shfunc) && output) ||
- (!is_cursh && (last1 != 1 || nsigtrapped || havefiles() ||
- fdtable_flocks))))) {
-
- pid_t pid;
- int synch[2], flags;
- char dummy;
- struct timeval bgtime;
-
- child_block();
-
- if (pipe(synch) < 0) {
- zerr("pipe failed: %e", errno);
- goto fatal;
- } else if ((pid = zfork(&bgtime)) == -1) {
- close(synch[0]);
- close(synch[1]);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- goto fatal;
- }
- if (pid) {
-
- close(synch[1]);
- read_loop(synch[0], &dummy, 1);
- close(synch[0]);
- if (how & Z_ASYNC) {
- lastpid = (zlong) pid;
- } else if (!jobtab[thisjob].stty_in_env && varspc) {
- /* search for STTY=... */
- Wordcode p = varspc;
- wordcode ac;
-
- while (wc_code(ac = *p) == WC_ASSIGN) {
- if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
- jobtab[thisjob].stty_in_env = 1;
- break;
- }
- p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
- 3 : WC_ASSIGN_NUM(ac) + 2);
- }
+ if (!forked) {
+ if (!do_exec &&
+ (((is_builtin || is_shfunc) && output) ||
+ (!is_cursh && (last1 != 1 || nsigtrapped || havefiles() ||
+ fdtable_flocks)))) {
+ switch (execcmd_fork(state, how, type, varspc, &filelist,
+ text, oautocont, close_if_forked)) {
+ case -1:
+ goto fatal;
+ case 0:
+ break;
+ default:
+ return;
}
- addproc(pid, text, 0, &bgtime);
- if (oautocont >= 0)
- opts[AUTOCONTINUE] = oautocont;
- pipecleanfilelist(jobtab[thisjob].filelist, 1);
- return;
- }
- /* pid == 0 */
- close(synch[0]);
- flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP;
- if ((type != WC_SUBSH) && !(how & Z_ASYNC))
- flags |= ESUB_KEEPTRAP;
- if (type == WC_SUBSH && !(how & Z_ASYNC))
- flags |= ESUB_JOB_CONTROL;
- filelist = jobtab[thisjob].filelist;
- entersubsh(flags);
- close(synch[1]);
- forked = 1;
- if (sigtrapped[SIGINT] & ZSIG_IGNORED)
- holdintr();
-#ifdef HAVE_NICE
- /* Check if we should run background jobs at a lower priority. */
- if ((how & Z_ASYNC) && isset(BGNICE))
- if (nice(5) < 0)
- zwarn("nice(5) failed: %e", errno);
-#endif /* HAVE_NICE */
-
- } else if (is_cursh) {
- /* This is a current shell procedure that didn't need to fork. *
- * This includes current shell procedures that are being exec'ed, *
- * as well as null execs. */
- jobtab[thisjob].stat |= STAT_CURSH;
- if (!jobtab[thisjob].procs)
- jobtab[thisjob].stat |= STAT_NOPRINT;
- if (is_builtin)
- jobtab[thisjob].stat |= STAT_BUILTIN;
- } else {
- /* This is an exec (real or fake) for an external command. *
- * Note that any form of exec means that the subshell is fake *
- * (but we may be in a subshell already). */
- is_exec = 1;
- /*
- * If we are in a subshell environment anyway, say we're forked,
- * even if we're actually not forked because we know the
- * subshell is exiting. This ensures SHLVL reflects the current
- * shell, and also optimises out any save/restore we'd need to
- * do if we were returning to the main shell.
- */
- if (type == WC_SUBSH)
forked = 1;
+ } else if (is_cursh) {
+ /* This is a current shell procedure that didn't need to fork. *
+ * This includes current shell procedures that are being exec'ed, *
+ * as well as null execs. */
+ jobtab[thisjob].stat |= STAT_CURSH;
+ if (!jobtab[thisjob].procs)
+ jobtab[thisjob].stat |= STAT_NOPRINT;
+ if (is_builtin)
+ jobtab[thisjob].stat |= STAT_BUILTIN;
+ } else {
+ /* This is an exec (real or fake) for an external command. *
+ * Note that any form of exec means that the subshell is fake *
+ * (but we may be in a subshell already). */
+ is_exec = 1;
+ /*
+ * If we are in a subshell environment anyway, say we're forked,
+ * even if we're actually not forked because we know the
+ * subshell is exiting. This ensures SHLVL reflects the current
+ * shell, and also optimises out any save/restore we'd need to
+ * do if we were returning to the main shell.
+ */
+ if (type == WC_SUBSH)
+ forked = 1;
+ }
}
if ((esglob = !(cflags & BINF_NOGLOB)) && args && eparams->htok) {
@@ -3903,7 +3938,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
LinkList assigns = (LinkList)0;
int postassigns = eparams->postassigns;
if (forked)
- closem(FDT_INTERNAL);
+ closem(FDT_INTERNAL, 0);
if (postassigns) {
Wordcode opc = state->pc;
state->pc = eparams->assignspc;
@@ -4089,7 +4124,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (errflag)
_exit(1);
}
- closem(FDT_INTERNAL);
+ closem(FDT_INTERNAL, 0);
if (coprocin != -1) {
zclose(coprocin);
coprocin = -1;
@@ -4151,7 +4186,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
for (i = 0; i < 10; i++)
if (fdtable[i] != FDT_UNUSED)
close(i);
- closem(FDT_UNUSED);
+ closem(FDT_UNUSED, 1);
if (thisjob != -1)
waitjobs();
_exit(lastval);
@@ -4327,16 +4362,24 @@ fixfds(int *save)
*
* Close any that are marked as used if "how" is FDT_UNUSED, else
* close any with the value "how".
+ *
+ * If "all" is zero, we'll skip cases where we need the file
+ * descriptor to be visible externally.
*/
/**/
mod_export void
-closem(int how)
+closem(int how, int all)
{
int i;
for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] != FDT_UNUSED &&
+ /*
+ * Process substitution needs to be visible to user;
+ * fd's are explicitly cleaned up by filelist handling.
+ */
+ (all || fdtable[i] != FDT_PROC_SUBST) &&
(how == FDT_UNUSED || (fdtable[i] & FDT_TYPE_MASK) == how)) {
if (i == SHTTY)
SHTTY = -1;
@@ -4375,7 +4418,9 @@ gethere(char **strp, int typ)
while ((c = hgetc()) == '\t' && strip)
;
for (;;) {
- if (bptr == buf + bsiz) {
+ if (bptr >= buf + bsiz - 2) {
+ ptrdiff_t toff = t - buf;
+ ptrdiff_t bptroff = bptr - buf;
char *newbuf = realloc(buf, 2 * bsiz);
if (!newbuf) {
/* out of memory */
@@ -4383,20 +4428,20 @@ gethere(char **strp, int typ)
return NULL;
}
buf = newbuf;
- t = buf + bsiz - (bptr - t);
- bptr = buf + bsiz;
+ t = buf + toff;
+ bptr = buf + bptroff;
bsiz *= 2;
}
- if (lexstop)
+ if (lexstop || c == '\n')
break;
- if (c == '\n') {
- if (!qt && bptr > t && *(bptr - 1) == '\\') {
- /* line continuation */
+ if (!qt && c == '\\') {
+ *bptr++ = c;
+ c = hgetc();
+ if (c == '\n') {
bptr--;
c = hgetc();
continue;
- } else
- break;
+ }
}
*bptr++ = c;
c = hgetc();
@@ -4576,10 +4621,20 @@ readoutput(int in, int qt, int *readerror)
char *buf, *ptr;
int bsiz, c, cnt = 0;
FILE *fin;
+ int q = queue_signal_level();
fin = fdopen(in, "r");
ret = newlinklist();
ptr = buf = (char *) hcalloc(bsiz = 64);
+ /*
+ * We need to be sensitive to SIGCHLD else we can be
+ * stuck forever with important processes unreaped.
+ * The case that triggered this was where the exiting
+ * process is group leader of the foreground process and we need
+ * to reclaim the terminal else ^C doesn't work.
+ */
+ dont_queue_signals();
+ child_unblock();
while ((c = fgetc(fin)) != EOF || errno == EINTR) {
if (c == EOF) {
errno = 0;
@@ -4592,13 +4647,18 @@ readoutput(int in, int qt, int *readerror)
cnt++;
}
if (++cnt >= bsiz) {
- char *pp = (char *) hcalloc(bsiz *= 2);
+ char *pp;
+ queue_signals();
+ pp = (char *) hcalloc(bsiz *= 2);
+ dont_queue_signals();
memcpy(pp, buf, cnt - 1);
ptr = (buf = pp) + cnt - 1;
}
*ptr++ = c;
}
+ child_block();
+ restore_queue_signals(q);
if (readerror)
*readerror = ferror(fin) ? errno : 0;
fclose(fin);
@@ -4802,9 +4862,10 @@ getproc(char *cmd, char **eptr)
return NULL;
if (!out)
addproc(pid, NULL, 1, &bgtime);
+ procsubstpid = pid;
return pnam;
}
- closem(FDT_UNUSED);
+ closem(FDT_UNUSED, 0);
fd = open(pnam, out ? O_WRONLY | O_NOCTTY : O_RDONLY | O_NOCTTY);
if (fd == -1) {
zerr("can't open %s: %e", pnam, errno);
@@ -4819,7 +4880,7 @@ getproc(char *cmd, char **eptr)
zerr("process substitution %s cannot be used here", cmd);
return NULL;
}
- pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
+ pnam = zhalloc(strlen(PATH_DEV_FD) + 1 + DIGBUFSIZE);
if (!(prog = parsecmd(cmd, eptr)))
return NULL;
if (mpipe(pipes) < 0)
@@ -4839,11 +4900,12 @@ getproc(char *cmd, char **eptr)
{
addproc(pid, NULL, 1, &bgtime);
}
+ procsubstpid = pid;
return pnam;
}
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(pipes[out], out);
- closem(FDT_UNUSED); /* this closes pipes[!out] as well */
+ closem(FDT_UNUSED, 0); /* this closes pipes[!out] as well */
#endif /* PATH_DEV_FD */
cmdpush(CS_CMDSUBST);
@@ -4889,11 +4951,12 @@ getpipe(char *cmd, int nullexec)
}
if (!nullexec)
addproc(pid, NULL, 1, &bgtime);
+ procsubstpid = pid;
return pipes[!out];
}
entersubsh(ESUB_PGRP);
redup(pipes[out], out);
- closem(FDT_UNUSED); /* this closes pipes[!out] as well */
+ closem(FDT_UNUSED, 0); /* this closes pipes[!out] as well */
cmdpush(CS_CMDSUBST);
execode(prog, 0, 1, out ? "outsubst" : "insubst");
cmdpop();
@@ -5736,7 +5799,19 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
undoshfunc:
--funcdepth;
if (retflag) {
+ /*
+ * This function is forced to return.
+ */
retflag = 0;
+ /*
+ * The calling function isn't necessarily forced to return,
+ * but it should be made sensitive to ERR_EXIT and
+ * ERR_RETURN as the assumptions we made at the end of
+ * constructs within this function no longer apply. If
+ * there are cases where this is not true, they need adding
+ * to C03traps.ztst.
+ */
+ this_noerrexit = 0;
breaks = funcsave->breaks;
}
freearray(pparams);
@@ -6124,6 +6199,7 @@ execsave(void)
es->cmdoutpid = cmdoutpid;
es->cmdoutval = cmdoutval;
es->use_cmdoutval = use_cmdoutval;
+ es->procsubstpid = procsubstpid;
es->trap_return = trap_return;
es->trap_state = trap_state;
es->trapisfunc = trapisfunc;
@@ -6159,6 +6235,7 @@ execrestore(void)
cmdoutpid = en->cmdoutpid;
cmdoutval = en->cmdoutval;
use_cmdoutval = en->use_cmdoutval;
+ procsubstpid = en->procsubstpid;
trap_return = en->trap_return;
trap_state = en->trap_state;
trapisfunc = en->trapisfunc;
diff --git a/Src/glob.c b/Src/glob.c
index 66a95329f..ed2c90bd8 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1455,13 +1455,15 @@ zglob(LinkList list, LinkNode np, int nountok)
if ((pw = getpwnam(s + arglen)))
data = pw->pw_uid;
else {
- zerr("unknown user");
+ zerr("unknown username '%s'", s + arglen);
data = 0;
}
*tt = sav;
#else /* !USE_GETPWNAM */
sav = *tt;
- zerr("unknown user");
+ *tt = '\0';
+ zerr("unable to resolve non-numeric username '%s'", s + arglen);
+ *tt = sav;
data = 0;
#endif /* !USE_GETPWNAM */
if (sav)
diff --git a/Src/init.c b/Src/init.c
index c5372665a..e9e6be9b4 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -459,7 +459,8 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
/* -c command */
*cmdp = *argv;
new_opts[INTERACTIVE] &= 1;
- scriptname = scriptfilename = ztrdup("zsh");
+ if (toplevel)
+ scriptname = scriptfilename = ztrdup("zsh");
} else if (**argv == 'o') {
if (!*++*argv)
argv++;
diff --git a/Src/jobs.c b/Src/jobs.c
index 330ee6b37..38b3d896b 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1258,11 +1258,7 @@ pipecleanfilelist(LinkList filelist, int proc_subst_only)
while (node) {
Jobfile jf = (Jobfile)getdata(node);
if (jf->is_fd &&
- (!proc_subst_only
-#ifdef FDT_PROC_SUBST
- || fdtable[jf->u.fd] == FDT_PROC_SUBST
-#endif
- )) {
+ (!proc_subst_only || fdtable[jf->u.fd] == FDT_PROC_SUBST)) {
LinkNode next = nextnode(node);
zclose(jf->u.fd);
(void)remnode(filelist, node);
diff --git a/Src/math.c b/Src/math.c
index c3831602b..b08e05cb4 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -535,7 +535,7 @@ lexconstant(void)
for (ptr2 = ptr; ptr2 < nptr; ptr2++) {
if (*ptr2 == '_') {
int len = nptr - ptr;
- ptr = ztrdup(ptr);
+ ptr = dupstring(ptr);
for (ptr2 = ptr; len; len--) {
if (*ptr2 == '_')
chuck(ptr2);
@@ -578,6 +578,36 @@ int outputradix;
/**/
int outputunderscore;
+#ifndef HAVE_ISINF
+/**/
+int
+isinf(double x)
+{
+ if ((-1.0 < x) && (x < 1.0)) /* x is small, and thus finite */
+ return (0);
+ else if ((x + x) == x) /* only true if x == Infinity */
+ return (1);
+ else /* must be finite (normal or subnormal), or NaN */
+ return (0);
+}
+#endif
+
+#if !defined(HAVE_ISNAN)
+static double
+store(double *x)
+{
+ return (*x);
+}
+
+/**/
+int
+isnan(double x)
+{
+ /* (x != x) should be sufficient, but some compilers incorrectly optimize it away */
+ return (store(&x) != store(&x));
+}
+#endif
+
/**/
static int
zzlex(void)
@@ -610,8 +640,19 @@ zzlex(void)
}
if (unary) {
if (idigit(*ptr) || *ptr == '.') {
- ptr--;
- return lexconstant();
+ int ctype = lexconstant();
+ if (ctype == NUM)
+ {
+ if (yyval.type == MN_FLOAT)
+ {
+ yyval.u.d = -yyval.u.d;
+ }
+ else
+ {
+ yyval.u.l = -yyval.u.l;
+ }
+ }
+ return ctype;
} else
return UMINUS;
} else
@@ -785,11 +826,10 @@ zzlex(void)
ptr++;
break;
}
- case ' ':
+ case ' ': /* Fall through! */
case '\t':
case '\n':
break;
- /* Fall through! */
default:
if (idigit(*--ptr) || *ptr == '.')
return lexconstant();
@@ -814,6 +854,20 @@ zzlex(void)
p = ptr;
ptr = ie;
+ if (ie - p == 3) {
+ if (strncasecmp(p, "NaN", 3) == 0) {
+ yyval.type = MN_FLOAT;
+ yyval.u.d = 0.0;
+ yyval.u.d /= yyval.u.d;
+ return NUM;
+ }
+ else if (strncasecmp(p, "Inf", 3) == 0) {
+ yyval.type = MN_FLOAT;
+ yyval.u.d = 0.0;
+ yyval.u.d = 1.0 / yyval.u.d;
+ return NUM;
+ }
+ }
if (*ptr == '[' || (!cct && *ptr == '(')) {
char op = *ptr, cp = ((*ptr == '[') ? ']' : ')');
int l;
@@ -1068,9 +1122,9 @@ callmathfunc(char *o)
static int
notzero(mnumber a)
{
- if ((a.type & MN_INTEGER) ? a.u.l == 0 : a.u.d == 0.0) {
- zerr("division by zero");
- return 0;
+ if ((a.type & MN_INTEGER) && a.u.l == 0) {
+ zerr("division by zero");
+ return 0;
}
return 1;
}
diff --git a/Src/options.c b/Src/options.c
index 590652ea9..600b649e4 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -769,15 +769,32 @@ dosetopt(int optno, int value, int force, char *new_opts)
} else if(optno == PRIVILEGED && !value) {
/* unsetting PRIVILEGED causes the shell to make itself unprivileged */
#ifdef HAVE_SETUID
- setuid(getuid());
- setgid(getgid());
- if (setuid(getuid())) {
- zwarn("failed to change user ID: %e", errno);
- return -1;
- } else if (setgid(getgid())) {
+ int ignore_err;
+ errno = 0;
+ /*
+ * Set the GID first as if we set the UID to non-privileged it
+ * might be impossible to restore the GID.
+ *
+ * Some OSes (possibly no longer around) have been known to
+ * fail silently the first time, so we attempt the change twice.
+ * If it fails we are guaranteed to pick this up the second
+ * time, so ignore the first time.
+ *
+ * Some versions of gcc make it hard to ignore the results the
+ * first time, hence the following. (These are probably not
+ * systems that require the doubled calls.)
+ */
+ ignore_err = setgid(getgid());
+ (void)ignore_err;
+ ignore_err = setuid(getuid());
+ (void)ignore_err;
+ if (setgid(getgid())) {
zwarn("failed to change group ID: %e", errno);
return -1;
- }
+ } else if (setuid(getuid())) {
+ zwarn("failed to change user ID: %e", errno);
+ return -1;
+ }
#else
zwarn("setuid not available");
return -1;
diff --git a/Src/params.c b/Src/params.c
index 36f5f0676..a1c299f60 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -36,6 +36,8 @@
#else
#include "patchlevel.h"
+#include <math.h>
+
/* If removed from the ChangeLog for some reason */
#ifndef ZSH_PATCHLEVEL
#define ZSH_PATCHLEVEL "unknown"
@@ -1425,7 +1427,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
HashTable ht = v->pm->gsu.h->getfn(v->pm);
if (!ht) {
if (flags & SCANPM_CHECKING)
- return isset(KSHARRAYS) ? 1 : 0;
+ return 0;
ht = newparamtable(17, v->pm->node.nam);
v->pm->gsu.h->setfn(v->pm, ht);
}
@@ -1513,7 +1515,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
}
}
} else {
- if (!v->isarr && !word) {
+ if (!v->isarr && !word && !quote_arg) {
l = strlen(s);
if (a2) {
if (!l || *s != '*') {
@@ -1532,9 +1534,23 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
}
}
if (!keymatch) {
- if (quote_arg)
+ if (quote_arg) {
untokenize(s);
- else
+ /* Scalar (e) needs implicit asterisk tokens */
+ if (!v->isarr && !word) {
+ l = strlen(s);
+ d = (char *) hcalloc(l + 2);
+ if (a2) {
+ *d = Star;
+ strcpy(d + 1, s);
+ } else {
+ strcpy(d, s);
+ d[l] = Star;
+ d[l + 1] = '\0';
+ }
+ s = d;
+ }
+ } else
tokenize(s);
remnulargs(s);
pprog = patcompile(s, 0, NULL);
@@ -5431,10 +5447,16 @@ convfloat(double dval, int digits, int flags, FILE *fout)
ret = NULL;
} else {
VARARR(char, buf, 512 + digits);
- sprintf(buf, fmt, digits, dval);
- if (!strchr(buf, 'e') && !strchr(buf, '.'))
- strcat(buf, ".");
- ret = dupstring(buf);
+ if (isinf(dval))
+ ret = dupstring((dval < 0.0) ? "-Inf" : "Inf");
+ else if (isnan(dval))
+ ret = dupstring("NaN");
+ else {
+ sprintf(buf, fmt, digits, dval);
+ if (!strchr(buf, 'e') && !strchr(buf, '.'))
+ strcat(buf, ".");
+ ret = dupstring(buf);
+ }
}
#ifdef USE_LOCALE
if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
diff --git a/Src/parse.c b/Src/parse.c
index 47e5a246a..83383f10c 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1510,8 +1510,10 @@ par_while(int *cmplx)
if (tok != ZEND)
YYERRORV(oecused);
zshlex();
- } else
+ } else if (unset(SHORTLOOPS)) {
YYERRORV(oecused);
+ } else
+ par_save_list1(cmplx);
ecbuf[p] = WCB_WHILE(type, ecused - 1 - p);
}
diff --git a/Src/pattern.c b/Src/pattern.c
index fc7c73739..737f5cdcb 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -3605,7 +3605,15 @@ mb_patmatchrange(char *range, wchar_t ch, int zmb_ind, wint_t *indptr, int *mtp)
return 1;
break;
case PP_BLANK:
- if (ch == L' ' || ch == L'\t')
+#if !defined(HAVE_ISWBLANK) && !defined(iswblank)
+/*
+ * iswblank() is GNU and C99. There's a remote chance that some
+ * systems still don't support it (but would support the other ones
+ * if MULTIBYTE_SUPPORT is enabled).
+ */
+#define iswblank(c) (c == L' ' || c == L'\t')
+#endif
+ if (iswblank(ch))
return 1;
break;
case PP_CNTRL:
@@ -3840,7 +3848,14 @@ patmatchrange(char *range, int ch, int *indptr, int *mtp)
return 1;
break;
case PP_BLANK:
- if (ch == ' ' || ch == '\t')
+#if !defined(HAVE_ISBLANK) && !defined(isblank)
+/*
+ * isblank() is GNU and C99. There's a remote chance that some
+ * systems still don't support it.
+ */
+#define isblank(c) (c == ' ' || c == '\t')
+#endif
+ if (isblank(ch))
return 1;
break;
case PP_CNTRL:
diff --git a/Src/prompt.c b/Src/prompt.c
index 95da52559..959ed8e3d 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -273,8 +273,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
char *ss, *hostnam;
int t0, arg, test, sep, j, numjobs, len;
struct tm *tm;
- struct timezone dummy_tz;
- struct timeval tv;
+ struct timespec ts;
time_t timet;
Nameddir nd;
@@ -664,8 +663,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
tmfmt = "%l:%M%p";
break;
}
- gettimeofday(&tv, &dummy_tz);
- tm = localtime(&tv.tv_sec);
+ zgettime(&ts);
+ tm = localtime(&ts.tv_sec);
/*
* Hack because strftime won't say how
* much space it actually needs. Try to add it
@@ -675,7 +674,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
*/
for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) {
addbufspc(t0);
- if ((len = ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec))
+ if ((len = ztrftime(bv->bp, t0, tmfmt, tm, ts.tv_nsec))
>= 0)
break;
}
diff --git a/Src/signals.c b/Src/signals.c
index 94f379e72..20c6fdf4a 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -537,6 +537,21 @@ wait_for_processes(void)
#else
update_process(pn, status);
#endif
+ if (WIFEXITED(status) &&
+ pn->pid == jn->gleader &&
+ killpg(pn->pid, 0) == -1) {
+ jn->gleader = 0;
+ if (!(jn->stat & STAT_NOSTTY)) {
+ /*
+ * This PID was in control of the terminal;
+ * reclaim terminal now it has exited.
+ * It's still possible some future forked
+ * process of this job will become group
+ * leader, however.
+ */
+ attachtty(mypgrp);
+ }
+ }
}
update_job(jn);
} else if (findproc(pid, &jn, &pn, 1)) {
@@ -573,7 +588,7 @@ wait_for_processes(void)
/* the signal handler */
/**/
-mod_export RETSIGTYPE
+mod_export void
zhandler(int sig)
{
sigset_t newmask, oldmask;
@@ -778,9 +793,21 @@ killjb(Job jn, int sig)
else
return killpg(jn->gleader, sig);
}
- for (pn = jn->procs; pn; pn = pn->next)
- if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH && sig != 0)
- return -1;
+ for (pn = jn->procs; pn; pn = pn->next) {
+ /*
+ * Do not kill this job's process if it's already dead as its
+ * pid could have been reused by the system.
+ * As the PID doesn't exist don't return an error.
+ */
+ if (pn->status == SP_RUNNING || WIFSTOPPED(pn->status)) {
+ /*
+ * kill -0 on a job is pointless. We still call kill() for each process
+ * in case the user cares about it but we ignore its outcome.
+ */
+ if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH && sig != 0)
+ return -1;
+ }
+ }
return err;
}
diff --git a/Src/signals.h b/Src/signals.h
index 1904f4326..41ac88cce 100644
--- a/Src/signals.h
+++ b/Src/signals.h
@@ -27,7 +27,7 @@
*
*/
-#define SIGNAL_HANDTYPE RETSIGTYPE (*)_((int))
+#define SIGNAL_HANDTYPE void (*)_((int))
#ifndef HAVE_KILLPG
# define killpg(pgrp,sig) kill(-(pgrp),sig)
diff --git a/Src/subst.c b/Src/subst.c
index a265a187e..c1021fbf3 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -3169,7 +3169,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
zip = hmkarray(sval);
}
if (!isarr) {
- aval = mkarray(val);
+ aval = hmkarray(val);
isarr = 1;
}
if (zip) {
diff --git a/Src/utils.c b/Src/utils.c
index b41851700..075d27241 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -375,6 +375,43 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
fflush(file);
}
+/*
+ * Wrapper for setupterm() and del_curterm().
+ * These are called from terminfo.c and termcap.c.
+ */
+static int term_count; /* reference count of cur_term */
+
+/**/
+mod_export void
+zsetupterm(void)
+{
+#ifdef HAVE_SETUPTERM
+ int errret;
+
+ DPUTS(term_count < 0 || (term_count > 0 && !cur_term),
+ "inconsistent term_count and/or cur_term");
+ /*
+ * Just because we can't set up the terminal doesn't
+ * mean the modules hasn't booted---TERM may change,
+ * and it should be handled dynamically---so ignore errors here.
+ */
+ if (term_count++ == 0)
+ (void)setupterm((char *)0, 1, &errret);
+#endif
+}
+
+/**/
+mod_export void
+zdeleteterm(void)
+{
+#ifdef HAVE_SETUPTERM
+ DPUTS(term_count < 1 || !cur_term,
+ "inconsistent term_count and/or cur_term");
+ if (--term_count == 0)
+ del_curterm(cur_term);
+#endif
+}
+
/* Output a single character, for the termcap routines. *
* This is used instead of putchar since it can be a macro. */
@@ -3224,7 +3261,7 @@ ztrftimebuf(int *bufsizeptr, int decr)
/**/
mod_export int
-ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec)
+ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long nsec)
{
int hr12;
#ifdef HAVE_STRFTIME
@@ -3299,15 +3336,15 @@ morefmt:
case '.':
if (ztrftimebuf(&bufsize, digs))
return -1;
- if (digs > 6)
- digs = 6;
- if (digs < 6) {
+ if (digs > 9)
+ digs = 9;
+ if (digs < 9) {
int trunc;
- for (trunc = 5 - digs; trunc; trunc--)
- usec /= 10;
- usec = (usec + 5) / 10;
+ for (trunc = 8 - digs; trunc; trunc--)
+ nsec /= 10;
+ nsec = (nsec + 8) / 10;
}
- sprintf(buf, "%0*ld", digs, usec);
+ sprintf(buf, "%0*ld", digs, nsec);
buf += digs;
break;
case '\0':
@@ -3369,6 +3406,12 @@ morefmt:
*buf++ = '0' + tm->tm_min / 10;
*buf++ = '0' + tm->tm_min % 10;
break;
+ case 'N':
+ if (ztrftimebuf(&bufsize, 9))
+ return -1;
+ sprintf(buf, "%09ld", nsec);
+ buf += 9;
+ break;
case 'S':
if (tm->tm_sec > 9 || !strip)
*buf++ = '0' + tm->tm_sec / 10;
diff --git a/Src/zsh.h b/Src/zsh.h
index 8b4898477..8e7f20b2c 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -454,15 +454,14 @@ enum {
* so the shell can still exec the last process.
*/
#define FDT_FLOCK_EXEC 6
-#ifdef PATH_DEV_FD
/*
* Entry used by a process substition.
* This marker is not tested internally as we associated the file
* descriptor with a job for closing.
+ *
+ * This is not used unless PATH_DEV_FD is defined.
*/
#define FDT_PROC_SUBST 7
-#endif
-
/*
* Mask to get the basic FDT type.
*/
@@ -1096,6 +1095,7 @@ struct execstack {
pid_t cmdoutpid;
int cmdoutval;
int use_cmdoutval;
+ pid_t procsubstpid;
int trap_return;
int trap_state;
int trapisfunc;
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index 5339b496f..8289ee97c 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -250,6 +250,14 @@ struct timezone {
};
#endif
+/* Used to provide compatibility with clock_gettime() */
+#if !defined(HAVE_STRUCT_TIMESPEC) && !defined(ZSH_OOT_MODULE)
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+#endif
+
/* There's more than one non-standard way to get at this data */
#if !defined(HAVE_STRUCT_DIRENT_D_INO) && defined(HAVE_STRUCT_DIRENT_D_STAT)
# define d_ino d_stat.st_ino