summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.awk2
-rw-r--r--Src/Builtins/rlimits.c52
-rw-r--r--Src/Builtins/rlimits.mdd2
-rw-r--r--Src/Modules/datetime.c73
-rw-r--r--Src/Modules/datetime.mdd2
-rw-r--r--Src/Modules/db_gdbm.c10
-rw-r--r--Src/Modules/pcre.c60
-rw-r--r--Src/Modules/pcre.mdd2
-rw-r--r--Src/Modules/zftp.c2
-rw-r--r--Src/Zle/compcore.c29
-rw-r--r--Src/Zle/complete.c2
-rw-r--r--Src/Zle/complist.c18
-rw-r--r--Src/Zle/zle_main.c7
-rw-r--r--Src/Zle/zle_refresh.c16
-rw-r--r--Src/Zle/zle_thingy.c12
-rw-r--r--Src/Zle/zle_tricky.c64
-rw-r--r--Src/builtin.c55
-rw-r--r--Src/exec.c142
-rw-r--r--Src/glob.c3
-rw-r--r--Src/hist.c330
-rw-r--r--Src/jobs.c63
-rw-r--r--Src/lex.c11
-rw-r--r--Src/math.c2
-rw-r--r--Src/module.c8
-rw-r--r--Src/params.c32
-rw-r--r--Src/parse.c42
-rw-r--r--Src/signals.c24
-rw-r--r--Src/subst.c48
-rw-r--r--Src/text.c30
-rw-r--r--Src/utils.c72
-rw-r--r--Src/zsh.h2
31 files changed, 866 insertions, 351 deletions
diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk
index b96941125..418206a66 100644
--- a/Src/Builtins/rlimits.awk
+++ b/Src/Builtins/rlimits.awk
@@ -53,6 +53,7 @@ BEGIN {limidx = 0}
if (limnam == "MSGQUEUE") { msg[limnum] = "Nmsgqueue" }
if (limnam == "NICE") { msg[limnum] = "Nnice" }
if (limnam == "RTPRIO") { msg[limnum] = "Nrt_priority" }
+ if (limnam == "RTTIME") { msg[limnum] = "Urt_time" }
}
}
}
@@ -99,6 +100,7 @@ END {
if(limtype == "M") { limtype = "MEMORY" }
if(limtype == "N") { limtype = "NUMBER" }
if(limtype == "T") { limtype = "TIME" }
+ if(limtype == "U") { limtype = "MICROSECONDS" }
}
printf("\tZLIMTYPE_%s,\n", limtype)
}
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index ffcb92052..670516169 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -36,6 +36,7 @@ enum {
ZLIMTYPE_MEMORY,
ZLIMTYPE_NUMBER,
ZLIMTYPE_TIME,
+ ZLIMTYPE_MICROSECONDS,
ZLIMTYPE_UNKNOWN
};
@@ -101,9 +102,9 @@ showlimitvalue(int lim, rlim_t val)
printf("%lld\n", val);
# else
# ifdef RLIM_T_IS_UNSIGNED
- printf("%lu\n", val);
+ printf("%lu\n", (unsigned long)val);
# else
- printf("%ld\n", val);
+ printf("%ld\n", (long)val);
# endif /* RLIM_T_IS_UNSIGNED */
# endif /* RLIM_T_IS_LONG_LONG */
# endif /* RLIM_T_IS_QUAD_T */
@@ -113,10 +114,37 @@ showlimitvalue(int lim, rlim_t val)
seconds. */
printf("%d:%02d:%02d\n", (int)(val / 3600),
(int)(val / 60) % 60, (int)(val % 60));
+ } else if (limtype[lim] == ZLIMTYPE_MICROSECONDS) {
+ /* microseconds */
+# ifdef RLIM_T_IS_QUAD_T
+ printf("%qdus\n", val);
+# else
+# ifdef RLIM_T_IS_LONG_LONG
+ printf("%lldus\n", val);
+# else
+# ifdef RLIM_T_IS_UNSIGNED
+ printf("%luus\n", (unsigned long)val);
+# else
+ printf("%ldus\n", (long)val);
+# endif /* RLIM_T_IS_UNSIGNED */
+# endif /* RLIM_T_IS_LONG_LONG */
+# endif /* RLIM_T_IS_QUAD_T */
} else if (limtype[lim] == ZLIMTYPE_NUMBER ||
limtype[lim] == ZLIMTYPE_UNKNOWN) {
/* pure numeric resource */
- printf("%d\n", (int)val);
+# ifdef RLIM_T_IS_QUAD_T
+ printf("%qd\n", val);
+# else
+# ifdef RLIM_T_IS_LONG_LONG
+ printf("%lld\n", val);
+# else
+# ifdef RLIM_T_IS_UNSIGNED
+ printf("%lu\n", (unsigned long)val);
+# else
+ printf("%ld\n", (long)val);
+# endif /* RLIM_T_IS_UNSIGNED */
+# endif /* RLIM_T_IS_LONG_LONG */
+# endif /* RLIM_T_IS_QUAD_T */
} else if (val >= 1024L * 1024L)
/* memory resource -- display with `K' or `M' modifier */
# ifdef RLIM_T_IS_QUAD_T
@@ -125,18 +153,18 @@ showlimitvalue(int lim, rlim_t val)
printf("%qdkB\n", val / 1024L);
# else
# ifdef RLIM_T_IS_LONG_LONG
- printf("%lldMB\n", val / (1024L * 1024L));
+ printf("%lldMB\n", val / (1024L * 1024L));
else
printf("%lldkB\n", val / 1024L);
# else
# ifdef RLIM_T_IS_UNSIGNED
- printf("%luMB\n", val / (1024L * 1024L));
+ printf("%luMB\n", (unsigned long)(val / (1024L * 1024L)));
else
- printf("%lukB\n", val / 1024L);
+ printf("%lukB\n", (unsigned long)(val / 1024L));
# else
- printf("%ldMB\n", val / (1024L * 1024L));
+ printf("%ldMB\n", (long)val / (1024L * 1024L));
else
- printf("%ldkB\n", val / 1024L);
+ printf("%ldkB\n", (long)val / 1024L);
# endif /* RLIM_T_IS_UNSIGNED */
# endif /* RLIM_T_IS_LONG_LONG */
# endif /* RLIM_T_IS_QUAD_T */
@@ -370,9 +398,9 @@ printulimit(char *nam, int lim, int hard, int head)
printf("%lld\n", limit);
# else
# ifdef RLIM_T_IS_UNSIGNED
- printf("%lu\n", limit);
+ printf("%lu\n", (unsigned long)limit);
# else
- printf("%ld\n", limit);
+ printf("%ld\n", (long)limit);
# endif /* RLIM_T_IS_UNSIGNED */
# endif /* RLIM_T_IS_LONG_LONG */
# endif /* RLIM_T_IS_QUAD_T */
@@ -539,7 +567,9 @@ bin_limit(char *nam, char **argv, Options ops, UNUSED(int func))
return 1;
}
}
- } else if (limtype[lim] == ZLIMTYPE_NUMBER || limtype[lim] == ZLIMTYPE_UNKNOWN) {
+ } else if (limtype[lim] == ZLIMTYPE_NUMBER ||
+ limtype[lim] == ZLIMTYPE_UNKNOWN ||
+ limtype[lim] == ZLIMTYPE_MICROSECONDS) {
/* pure numeric resource -- only a straight decimal number is
permitted. */
char *t = s;
diff --git a/Src/Builtins/rlimits.mdd b/Src/Builtins/rlimits.mdd
index ca9fa8b84..9e6e9e598 100644
--- a/Src/Builtins/rlimits.mdd
+++ b/Src/Builtins/rlimits.mdd
@@ -14,7 +14,7 @@ rlimits.o rlimits..o: rlimits.h
rlimits.h: rlimits.awk @RLIMITS_INC_H@
$(AWK) -f $(sdir)/rlimits.awk @RLIMITS_INC_H@ /dev/null > rlimits.h
@if grep ZLIMTYPE_UNKNOWN rlimits.h >/dev/null; then \
- echo >&2 WARNING: unknown limits: mail rlimits.h to developers; \
+ echo >&2 WARNING: unknown limits: mail Src/Builtins/rlimits.h to developers; \
else :; fi
clean-here: clean.rlimits
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 45818b968..a4e7eca86 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -151,6 +151,69 @@ getcurrentsecs(UNUSED(Param pm))
return (zlong) time(NULL);
}
+static double
+getcurrentrealtime(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;
+ }
+
+ 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)
+{
+ 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);
+
+ 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);
+ arr[1] = dupstring(buf);
+ arr[2] = NULL;
+
+ return arr;
+#endif
+}
+
static struct builtin bintab[] = {
BUILTIN("strftime", 0, bin_strftime, 2, 2, 0, "qrs:", NULL),
};
@@ -158,9 +221,19 @@ static struct builtin bintab[] = {
static const struct gsu_integer epochseconds_gsu =
{ getcurrentsecs, NULL, stdunsetfn };
+static const struct gsu_float epochrealtime_gsu =
+{ getcurrentrealtime, NULL, stdunsetfn };
+
+static const struct gsu_array epochtime_gsu =
+{ getcurrenttime, NULL, stdunsetfn };
+
static struct paramdef patab[] = {
SPECIALPMDEF("EPOCHSECONDS", PM_INTEGER|PM_READONLY,
&epochseconds_gsu, NULL, NULL),
+ SPECIALPMDEF("EPOCHREALTIME", PM_FFLOAT|PM_READONLY,
+ &epochrealtime_gsu, NULL, NULL),
+ SPECIALPMDEF("epochtime", PM_ARRAY|PM_READONLY,
+ &epochtime_gsu, NULL, NULL)
};
static struct features module_features = {
diff --git a/Src/Modules/datetime.mdd b/Src/Modules/datetime.mdd
index 0e5ffffb2..b7c1a4a95 100644
--- a/Src/Modules/datetime.mdd
+++ b/Src/Modules/datetime.mdd
@@ -4,6 +4,6 @@ link=either
load=no
functions='Functions/Calendar/*'
-autofeatures="b:strftime p:EPOCHSECONDS"
+autofeatures="b:strftime p:EPOCHSECONDS p:EPOCHREALTIME p:epochtime"
objects="datetime.o"
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index bdbbe19d8..9a2a7a5b9 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -39,7 +39,9 @@
#include <gdbm.h>
+#if 0 /* what is this for? */
static char *backtype = "db/gdbm";
+#endif
static const struct gsu_scalar gdbm_gsu =
{ gdbmgetfn, gdbmsetfn, gdbmunsetfn };
@@ -138,7 +140,6 @@ static void
gdbmsetfn(Param pm, char *val)
{
datum key, content;
- int ret;
GDBM_FILE dbf;
key.dptr = pm->node.nam;
@@ -147,7 +148,7 @@ gdbmsetfn(Param pm, char *val)
content.dsize = strlen(content.dptr) + 1;
dbf = (GDBM_FILE)(pm->u.hash->tmpdata);
- ret = gdbm_store(dbf, key, content, GDBM_REPLACE);
+ (void)gdbm_store(dbf, key, content, GDBM_REPLACE);
}
/**/
@@ -155,14 +156,13 @@ static void
gdbmunsetfn(Param pm, int um)
{
datum key;
- int ret;
GDBM_FILE dbf;
key.dptr = pm->node.nam;
key.dsize = strlen(key.dptr) + 1;
dbf = (GDBM_FILE)(pm->u.hash->tmpdata);
- ret = gdbm_delete(dbf, key);
+ (void)gdbm_delete(dbf, key);
}
/**/
@@ -171,12 +171,10 @@ getgdbmnode(HashTable ht, const char *name)
{
int len;
char *nameu;
- datum key;
Param pm = NULL;
nameu = dupstring(name);
unmetafy(nameu, &len);
- key.dptr = nameu;
pm = (Param) hcalloc(sizeof(struct param));
pm->node.nam = nameu;
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index e1a897944..2e3556a8d 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -77,6 +77,7 @@ bin_pcre_compile(char *nam, char **args, Options ops, UNUSED(int func))
{
int pcre_opts = 0, pcre_errptr;
const char *pcre_error;
+ char *target;
if(OPT_ISSET(ops,'a')) pcre_opts |= PCRE_ANCHORED;
if(OPT_ISSET(ops,'i')) pcre_opts |= PCRE_CASELESS;
@@ -92,8 +93,13 @@ bin_pcre_compile(char *nam, char **args, Options ops, UNUSED(int func))
if (pcre_pattern)
pcre_free(pcre_pattern);
- pcre_pattern = pcre_compile(*args, pcre_opts, &pcre_error, &pcre_errptr, NULL);
+ target = ztrdup(*args);
+ unmetafy(target, NULL);
+
+ pcre_pattern = pcre_compile(target, pcre_opts, &pcre_error, &pcre_errptr, NULL);
+ free(target);
+
if (pcre_pattern == NULL)
{
zwarnnam(nam, "error in regex: %s", pcre_error);
@@ -161,7 +167,7 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar,
sprintf(offset_all, "%d %d", ovec[0], ovec[1]);
setsparam("ZPCRE_OP", ztrdup(offset_all));
}
- match_all = ztrdup(captures[0]);
+ match_all = metafy(captures[0], -1, META_DUP);
setsparam(matchvar, match_all);
/*
* If we're setting match, mbegin, mend we only do
@@ -169,7 +175,15 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar,
* (c.f. regex.c).
*/
if (!want_begin_end || nelem) {
- matches = zarrdup(&captures[capture_start]);
+ char **x, **y;
+ y = &captures[capture_start];
+ matches = x = (char **) zalloc(sizeof(char *) * (arrlen(y) + 1));
+ do {
+ if (*y)
+ *x++ = metafy(*y, -1, META_DUP);
+ else
+ *x++ = NULL;
+ } while (*y++);
setaparam(substravar, matches);
}
@@ -255,6 +269,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func))
{
int ret, capcount, *ovec, ovecsize, c;
char *matched_portion = NULL;
+ char *plaintext = NULL;
char *receptacle = NULL;
int return_value = 1;
/* The subject length and offset start are both int values in pcre_exec */
@@ -278,7 +293,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func))
}
/* For the entire match, 'Return' the offset byte positions instead of the matched string */
if(OPT_ISSET(ops,'b')) want_offset_pair = 1;
-
+
if(!*args) {
zwarnnam(nam, "not enough arguments");
}
@@ -288,26 +303,28 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func))
zwarnnam(nam, "error %d in fullinfo", ret);
return 1;
}
-
+
ovecsize = (capcount+1)*3;
ovec = zalloc(ovecsize*sizeof(int));
-
- subject_len = (int)strlen(*args);
+
+ plaintext = ztrdup(*args);
+ unmetafy(plaintext, NULL);
+ subject_len = (int)strlen(plaintext);
if (offset_start < 0 || offset_start >= subject_len)
ret = PCRE_ERROR_NOMATCH;
else
- ret = pcre_exec(pcre_pattern, pcre_hints, *args, subject_len, offset_start, 0, ovec, ovecsize);
+ ret = pcre_exec(pcre_pattern, pcre_hints, plaintext, subject_len, offset_start, 0, ovec, ovecsize);
if (ret==0) return_value = 0;
else if (ret==PCRE_ERROR_NOMATCH) /* no match */;
else if (ret>0) {
- zpcre_get_substrings(*args, ovec, ret, matched_portion, receptacle,
+ zpcre_get_substrings(plaintext, ovec, ret, matched_portion, receptacle,
want_offset_pair, 0, 0);
return_value = 0;
}
else {
- zwarnnam(nam, "error in pcre_exec");
+ zwarnnam(nam, "error in pcre_exec [%d]", ret);
}
if (ovec)
@@ -322,7 +339,7 @@ cond_pcre_match(char **a, int id)
{
pcre *pcre_pat;
const char *pcre_err;
- char *lhstr, *rhre, *avar=NULL;
+ char *lhstr, *rhre, *lhstr_plain, *rhre_plain, *avar=NULL;
int r = 0, pcre_opts = 0, pcre_errptr, capcnt, *ov, ovsize;
int return_value = 0;
@@ -331,6 +348,10 @@ cond_pcre_match(char **a, int id)
lhstr = cond_str(a,0,0);
rhre = cond_str(a,1,0);
+ lhstr_plain = ztrdup(lhstr);
+ rhre_plain = ztrdup(rhre);
+ unmetafy(lhstr_plain, NULL);
+ unmetafy(rhre_plain, NULL);
pcre_pat = NULL;
ov = NULL;
@@ -339,7 +360,7 @@ cond_pcre_match(char **a, int id)
switch(id) {
case CPCRE_PLAIN:
- pcre_pat = pcre_compile(rhre, pcre_opts, &pcre_err, &pcre_errptr, NULL);
+ pcre_pat = pcre_compile(rhre_plain, pcre_opts, &pcre_err, &pcre_errptr, NULL);
if (pcre_pat == NULL) {
zwarn("failed to compile regexp /%s/: %s", rhre, pcre_err);
break;
@@ -347,7 +368,7 @@ cond_pcre_match(char **a, int id)
pcre_fullinfo(pcre_pat, NULL, PCRE_INFO_CAPTURECOUNT, &capcnt);
ovsize = (capcnt+1)*3;
ov = zalloc(ovsize*sizeof(int));
- r = pcre_exec(pcre_pat, NULL, lhstr, strlen(lhstr), 0, 0, ov, ovsize);
+ r = pcre_exec(pcre_pat, NULL, lhstr_plain, strlen(lhstr_plain), 0, 0, ov, ovsize);
/* r < 0 => error; r==0 match but not enough size in ov
* r > 0 => (r-1) substrings found; r==1 => no substrings
*/
@@ -356,13 +377,16 @@ cond_pcre_match(char **a, int id)
return_value = 1;
break;
}
- else if (r==PCRE_ERROR_NOMATCH) return 0; /* no match */
+ else if (r==PCRE_ERROR_NOMATCH) {
+ return_value = 0; /* no match */
+ break;
+ }
else if (r<0) {
- zwarn("pcre_exec() error: %d", r);
+ zwarn("pcre_exec() error [%d]", r);
break;
}
else if (r>0) {
- zpcre_get_substrings(lhstr, ov, r, NULL, avar, 0,
+ zpcre_get_substrings(lhstr_plain, ov, r, NULL, avar, 0,
isset(BASHREMATCH),
!isset(BASHREMATCH));
return_value = 1;
@@ -371,6 +395,10 @@ cond_pcre_match(char **a, int id)
break;
}
+ if (lhstr_plain)
+ free(lhstr_plain);
+ if(rhre_plain)
+ free(rhre_plain);
if (pcre_pat)
pcre_free(pcre_pat);
if (ov)
diff --git a/Src/Modules/pcre.mdd b/Src/Modules/pcre.mdd
index 3e1579117..6eb3c691b 100644
--- a/Src/Modules/pcre.mdd
+++ b/Src/Modules/pcre.mdd
@@ -1,5 +1,5 @@
name=zsh/pcre
-link=`if test x$enable_pcre = xyes; then echo dynamic; else echo no; fi`
+link=`if test x$enable_pcre = xyes && (pcre-config --version >/dev/null 2>/dev/null); then echo dynamic; else echo no; fi`
load=no
autofeatures="b:pcre_compile b:pcre_study b:pcre_match"
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 8d688abd4..d16e2f618 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -2520,7 +2520,7 @@ zftp_local(UNUSED(char *name), char **args, int flags)
printf("%s %s\n", output64(sz), mt);
#else
DPUTS(sizeof(sz) > 4, "Shell compiled with wrong off_t size");
- printf("%ld %s\n", sz, mt);
+ printf("%ld %s\n", (long)sz, mt);
#endif
zsfree(mt);
if (dofd)
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 5514e2e1d..b1de6c6cc 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -607,7 +607,7 @@ callcompfunc(char *s, char *fn)
if (rdstr)
compredirect = rdstr;
kset |= CP_REDIRECT;
- } else
+ } else {
switch (linwhat) {
case IN_ENV:
compcontext = (linarr ? "array_value" : "value");
@@ -637,6 +637,7 @@ callcompfunc(char *s, char *fn)
aadd = 1;
}
}
+ }
compcontext = ztrdup(compcontext);
if (compwords)
freearray(compwords);
@@ -1099,7 +1100,7 @@ mod_export char *
check_param(char *s, int set, int test)
{
char *p;
- int found = 0;
+ int found = 0, qstring = 0;
zsfree(parpre);
parpre = NULL;
@@ -1126,6 +1127,7 @@ check_param(char *s, int set, int test)
!(*p == String && p[1] == Snull) &&
!(*p == Qstring && p[1] == '\'')) {
found = 1;
+ qstring = (*p == Qstring);
break;
}
}
@@ -1150,7 +1152,7 @@ check_param(char *s, int set, int test)
p[1] != Inpar && p[1] != Inbrack && p[1] != Snull) {
/* This is a parameter expression, not $(...), $[...], $'...'. */
char *b = p + 1, *e = b, *ie;
- int n = 0, br = 1, nest = 0;
+ int br = 1, nest = 0;
if (*b == Inbrace) {
char *tb = b;
@@ -1161,7 +1163,18 @@ check_param(char *s, int set, int test)
/* Ignore the possible (...) flags. */
b++, br++;
- n = skipparens(Inpar, Outpar, &b);
+ if ((qstring ? skipparens('(', ')', &b) :
+ skipparens(Inpar, Outpar, &b)) > 0) {
+ /*
+ * We are still within the parameter flags. There's no
+ * point trying to do anything clever here with
+ * parameter names. Instead, just report that we are in
+ * a brace parameter but let the completion function
+ * decide what to do about it.
+ */
+ ispar = 2;
+ return NULL;
+ }
for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--);
if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring))
@@ -1204,7 +1217,7 @@ check_param(char *s, int set, int test)
}
/* Now make sure that the cursor is inside the name. */
- if (offs <= e - s && offs >= b - s && n <= 0) {
+ if (offs <= e - s && offs >= b - s) {
char sav;
if (br) {
@@ -1465,7 +1478,7 @@ set_comp_sep(void)
* when stripping single quotes: 1 for RCQUOTES, 3 otherwise
* (because we leave a "'" in the final string).
*/
- int dq = 0, odq, sq = 0, osq, qttype, sqq = 0, lsq = 0, qa = 0;
+ int dq = 0, odq, sq = 0, qttype, sqq = 0, lsq = 0, qa = 0;
/* dolq: like sq and dq but for dollars quoting. */
int dolq = 0;
/* remember some global variable values (except lp is local) */
@@ -1570,7 +1583,6 @@ set_comp_sep(void)
}
odq = dq;
- osq = sq;
inpush(dupstrspace(tmp), 0, NULL);
zlemetaline = tmp;
/*
@@ -3294,7 +3306,7 @@ dupmatch(Cmatch m, int nbeg, int nend)
mod_export int
permmatches(int last)
{
- Cmgroup g = amatches, n, opm;
+ Cmgroup g = amatches, n;
Cmatch *p, *q;
Cexpl *ep, *eq, e, o;
LinkList mlist;
@@ -3308,7 +3320,6 @@ permmatches(int last)
}
newmatches = fi = 0;
- opm = pmatches;
pmatches = lmatches = NULL;
nmatches = smatches = diffmatches = 0;
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 6398fd3e7..ea5e41f5f 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1544,7 +1544,7 @@ cond_range(char **a, int id)
}
static struct builtin bintab[] = {
- BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
+ BUILTIN("compadd", BINF_HANDLES_OPTS, bin_compadd, 0, -1, 0, NULL, NULL),
BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL),
};
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index fdca7a99f..bcf356179 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -849,9 +849,9 @@ putmatchcol(char *group, char *n)
{
Patcol pc;
- nrefs = MAX_POS - 1;
+ for (pc = mcolors.pats; pc; pc = pc->next) {
+ nrefs = MAX_POS - 1;
- for (pc = mcolors.pats; pc; pc = pc->next)
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
pattryrefs(pc->pat, n, -1, -1, 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
@@ -863,6 +863,7 @@ putmatchcol(char *group, char *n)
return 0;
}
+ }
zcputs(group, COL_NO);
@@ -880,9 +881,9 @@ putfilecol(char *group, char *filename, mode_t m, int special)
Patcol pc;
int len;
- nrefs = MAX_POS - 1;
+ for (pc = mcolors.pats; pc; pc = pc->next) {
+ nrefs = MAX_POS - 1;
- for (pc = mcolors.pats; pc; pc = pc->next)
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
pattryrefs(pc->pat, filename, -1, -1, 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
@@ -894,6 +895,7 @@ putfilecol(char *group, char *filename, mode_t m, int special)
return 0;
}
+ }
if (special != -1) {
colour = special;
@@ -1369,8 +1371,6 @@ compprintlist(int showall)
}
#endif
if ((e = g->expls)) {
- int l;
-
if (!lastused && lasttype == 1) {
e = lastexpl;
ml = lastml;
@@ -1393,9 +1393,9 @@ compprintlist(int showall)
}
if (mlbeg < 0 && mfirstl < 0)
mfirstl = ml;
- l = compprintfmt((*e)->str,
- ((*e)->always ? -1 : (*e)->count),
- dolist(ml), 1, ml, &stop);
+ (void)compprintfmt((*e)->str,
+ ((*e)->always ? -1 : (*e)->count),
+ dolist(ml), 1, ml, &stop);
if (mselect >= 0) {
int mm = (mcols * ml), i;
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 6acedee70..3cdc3b2ed 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -53,11 +53,6 @@ mod_export int zlecs, zlell;
/**/
mod_export int incompctlfunc;
-/* != 0 if we are in a new style completion function */
-
-/**/
-mod_export int incompfunc;
-
/* != 0 if completion module is loaded */
/**/
@@ -1233,7 +1228,7 @@ zleread(char **lp, char **rp, int flags, int context)
alarm(0);
freeundo();
- if (eofsent) {
+ if (eofsent || errflag) {
s = NULL;
} else {
zleline[zlell++] = ZWC('\n');
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 797f86251..260df8bf6 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -341,7 +341,7 @@ zle_set_highlight(void)
match_highlight(*atrs + 8, &special_atr_on);
special_atr_on_set = 1;
} else if (strpfx("region:", *atrs)) {
- match_highlight(*atrs + 7, &region_highlights->atr);
+ match_highlight(*atrs + 7, &region_highlights[0].atr);
region_atr_on_set = 1;
} else if (strpfx("isearch:", *atrs)) {
match_highlight(*atrs + 8, &(region_highlights[1].atr));
@@ -357,7 +357,7 @@ zle_set_highlight(void)
if (!special_atr_on_set)
special_atr_on = TXTSTANDOUT;
if (!region_atr_on_set)
- region_highlights->atr = TXTSTANDOUT;
+ region_highlights[0].atr = TXTSTANDOUT;
if (!isearch_atr_on_set)
region_highlights[1].atr = TXTUNDERLINE;
if (!suffix_atr_on_set)
@@ -1022,14 +1022,14 @@ zrefresh(void)
/* check for region between point ($CURSOR) and mark ($MARK) */
if (region_active) {
if (zlecs <= mark) {
- region_highlights->start = zlecs;
- region_highlights->end = mark;
+ region_highlights[0].start = zlecs;
+ region_highlights[0].end = mark;
} else {
- region_highlights->start = mark;
- region_highlights->end = zlecs;
+ region_highlights[0].start = mark;
+ region_highlights[0].end = zlecs;
}
} else {
- region_highlights->start = region_highlights->end = -1;
+ region_highlights[0].start = region_highlights[0].end = -1;
}
/* check for isearch string to highlight */
if (isearch_active) {
@@ -2418,8 +2418,6 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on);
if (tmpline[t0] == ZWC('\t')) {
- REFRESH_ELEMENT sp = zr_sp;
- sp.atr = base_atr_on;
for (*vp++ = zr_sp; (vp - vbuf) & 7; )
*vp++ = zr_sp;
vp[-1].atr |= base_atr_off;
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index f712e1750..03e73b4ca 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -394,9 +394,13 @@ bin_zle_list(UNUSED(char *name), char **args, Options ops, UNUSED(char func))
Thingy t;
for (; *args && !ret; args++) {
- if (!(t = (Thingy) thingytab->getnode2(thingytab, *args)) ||
+ HashNode hn = thingytab->getnode2(thingytab, *args);
+ if (!(t = (Thingy) hn) ||
(!OPT_ISSET(ops,'a') && (t->widget->flags & WIDGET_INT)))
ret = 1;
+ else if (OPT_ISSET(ops,'L')) {
+ scanlistwidgets(hn, 1);
+ }
}
return ret;
}
@@ -483,6 +487,12 @@ bin_zle_keymap(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
return selectkeymap(*args, 0);
}
+/*
+ * List a widget.
+ * If list is negative, just print the name.
+ * If list is 0, use abbreviated format.
+ * If list is positive, output as a command.
+ */
/**/
static void
scanlistwidgets(HashNode hn, int list)
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 8f7c2aac1..6fa887a1e 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -398,7 +398,18 @@ mod_export char *cmdstr;
/**/
mod_export char *varname;
-/* != 0 if we are in a subscript */
+/*
+ * != 0 if we are in a subscript.
+ * Of course, this being the completion code, you're expected to guess
+ * what the different numbers actually mean, but here's a cheat:
+ * 1: Key of an ordinary array
+ * 2: Key of a hash
+ * 3: Ummm.... this appears to be a special case of 2. After a lot
+ * of uncommented code looking for groups of brackets, we suddenly
+ * decide to set it to 2. The only upshot seems to be that compctl
+ * then doesn't add a matching ']' at the end, so I think it means
+ * there's one there already.
+ */
/**/
mod_export int insubscr;
@@ -529,7 +540,7 @@ parambeg(char *s)
* or $'...').
*/
char *b = p + 1, *e = b;
- int n = 0, br = 1, nest = 0;
+ int n = 0, br = 1;
if (*b == Inbrace) {
char *tb = b;
@@ -541,10 +552,6 @@ parambeg(char *s)
/* Ignore the possible (...) flags. */
b++, br++;
n = skipparens(Inpar, Outpar, &b);
-
- for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--);
- if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring))
- nest = 1;
}
/* Ignore the stuff before the parameter name. */
@@ -1862,6 +1869,10 @@ get_comp_string(void)
}
} else if (p < curs) {
if (*p == Outbrace) {
+ /*
+ * HERE: strip and remember code from last
+ * comma to here.
+ */
cant = 1;
break;
}
@@ -1869,6 +1880,16 @@ get_comp_string(void)
char *tp = p;
if (!skipparens(Inbrace, Outbrace, &tp)) {
+ /*
+ * Balanced brace: skip.
+ * We only deal with unfinished braces, so
+ * something{foo<x>bar,morestuff}else
+ * doesn't work
+ *
+ * HERE: instead, continue, look for a comma.
+ * Stack tp and brace for popping when we
+ * find a comma at each level.
+ */
i += tp - p - 1;
dp += tp - p - 1;
p = tp - 1;
@@ -1911,10 +1932,16 @@ get_comp_string(void)
hascom = 1;
}
} else {
+ /* On or after the cursor position */
if (*p == Inbrace) {
char *tp = p;
if (!skipparens(Inbrace, Outbrace, &tp)) {
+ /*
+ * Balanced braces after the cursor.
+ * Could do the same with these as
+ * those before the cursor.
+ */
i += tp - p - 1;
dp += tp - p - 1;
p = tp - 1;
@@ -1925,6 +1952,14 @@ get_comp_string(void)
break;
}
if (p == curs) {
+ /*
+ * We've reached the cursor position.
+ * If there's a pending open brace at this
+ * point we need to stack the text.
+ * We've marked the bit we don't want from
+ * bbeg to bend, which might be a comma
+ * between the opening brace and us.
+ */
if (bbeg) {
Brinfo new;
int len = bend - bbeg;
@@ -1954,10 +1989,23 @@ get_comp_string(void)
bbeg = NULL;
}
if (*p == Comma) {
+ /*
+ * Comma on or after cursor.
+ * We set bbeg to NULL at the cursor; here
+ * it's being used to find the first comma
+ * afterwards.
+ */
if (!bbeg)
bbeg = p;
hascom = 2;
} else if (*p == Outbrace) {
+ /*
+ * Closing brace on or after the cursor.
+ * Not sure how this can be after the cursor;
+ * if it was matched, wouldn't we have skipped
+ * over the group, and if it wasn't, surely we're
+ * not interested in it?
+ */
Brinfo new;
int len;
@@ -2150,10 +2198,6 @@ doexpansion(char *s, int lst, int olst, int explincmd)
ss = quotename(ss, NULL);
untokenize(ss);
inststr(ss);
-#if 0
- if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
- (zlemetacs && zlemetaline[zlemetacs-1] != '/')) {
-#endif
if (nonempty(vl) || !first) {
spaceinline(1);
zlemetaline[zlemetacs++] = ' ';
diff --git a/Src/builtin.c b/Src/builtin.c
index fc98eb1b1..71fc04ce1 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -99,7 +99,7 @@ static struct builtin builtins[] =
#endif
BUILTIN("popd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 1, BIN_POPD, "q", NULL),
- BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsu:z-", NULL),
+ BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsSu:z-", NULL),
BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, NULL, NULL),
BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "qsPL", NULL),
BUILTIN("pushln", 0, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"),
@@ -3965,25 +3965,45 @@ bin_print(char *name, char **args, Options ops, int func)
return 0;
}
/* -s option -- add the arguments to the history list */
- if (OPT_ISSET(ops,'s')) {
+ if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S')) {
int nwords = 0, nlen, iwords;
char **pargs = args;
queue_signals();
- ent = prepnexthistent();
while (*pargs++)
nwords++;
- if ((ent->nwords = nwords)) {
- ent->words = (short *)zalloc(nwords*2*sizeof(short));
- nlen = iwords = 0;
- for (pargs = args; *pargs; pargs++) {
- ent->words[iwords++] = nlen;
- nlen += strlen(*pargs);
- ent->words[iwords++] = nlen;
- nlen++;
+ if (nwords) {
+ if (OPT_ISSET(ops,'S')) {
+ int wordsize;
+ short *words;
+ if (nwords > 1) {
+ zwarnnam(name, "option -S takes a single argument");
+ return 1;
+ }
+ words = NULL;
+ wordsize = 0;
+ histsplitwords(*args, &words, &wordsize, &nwords, 1);
+ ent = prepnexthistent();
+ ent->words = (short *)zalloc(nwords*sizeof(short));
+ memcpy(ent->words, words, nwords*sizeof(short));
+ free(words);
+ ent->nwords = nwords/2;
+ } else {
+ ent = prepnexthistent();
+ ent->words = (short *)zalloc(nwords*2*sizeof(short));
+ ent->nwords = nwords;
+ nlen = iwords = 0;
+ for (pargs = args; *pargs; pargs++) {
+ ent->words[iwords++] = nlen;
+ nlen += strlen(*pargs);
+ ent->words[iwords++] = nlen;
+ nlen++;
+ }
}
- } else
+ } else {
+ ent = prepnexthistent();
ent->words = (short *)NULL;
+ }
ent->node.nam = zjoin(args, ' ', 0);
ent->stim = ent->ftim = time(NULL);
ent->node.flags = 0;
@@ -5529,7 +5549,14 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
*bptr = '\0';
#endif
/* dispose of word appropriately */
- if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) {
+ if (OPT_ISSET(ops,'e') ||
+ /*
+ * When we're doing an array assignment, we'll
+ * handle echoing at that point. In all other
+ * cases (including -A with no assignment)
+ * we'll do it here.
+ */
+ (OPT_ISSET(ops,'E') && !OPT_ISSET(ops,'A'))) {
zputs(buf, stdout);
putchar('\n');
}
@@ -5561,7 +5588,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
: (char **)zalloc((al + 1) * sizeof(char *)));
for (pp = p, n = firstnode(readll); n; incnode(n)) {
- if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) {
+ if (OPT_ISSET(ops,'E')) {
zputs((char *) getdata(n), stdout);
putchar('\n');
}
diff --git a/Src/exec.c b/Src/exec.c
index 2558185c8..2c644e6b7 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -50,20 +50,20 @@ int noerrexit;
* noerrs = 1: suppress error messages
* noerrs = 2: don't set errflag on parse error, either
*/
-
+
/**/
mod_export int noerrs;
-
+
/* do not save history on exec and exit */
/**/
int nohistsave;
-
+
/* error/break flag */
-
+
/**/
mod_export int errflag;
-
+
/*
* State of trap return value. Value is from enum trap_state.
*/
@@ -88,23 +88,23 @@ int trap_state;
* - non-negative in a trap once it was triggered. It should remain
* non-negative until restored after execution of the trap.
*/
-
+
/**/
int trap_return;
-
+
/* != 0 if this is a subshell */
-
+
/**/
int subsh;
-
+
/* != 0 if we have a return pending */
-
+
/**/
mod_export int retflag;
/**/
long lastval2;
-
+
/* The table of file descriptors. A table element is zero if the *
* corresponding fd is not used by the shell. It is greater than *
* 1 if the fd is used by a <(...) or >(...) substitution and 1 if *
@@ -148,12 +148,12 @@ int fdtable_flocks;
mod_export int zleactive;
/* pid of process undergoing 'process substitution' */
-
+
/**/
pid_t cmdoutpid;
-
+
/* exit status of process undergoing 'process substitution' */
-
+
/**/
int cmdoutval;
@@ -166,7 +166,7 @@ int cmdoutval;
/**/
int use_cmdoutval;
-/* The context in which a shell function is called, see SFC_* in zsh.h. */
+/* The context in which a shell function is called, see SFC_* in zsh.h. */
/**/
mod_export int sfcontext;
@@ -239,7 +239,7 @@ parse_string(char *s, int reset_lineno)
/**/
mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
-
+
/**/
mod_export int
zsetlimit(int limnum, char *nam)
@@ -340,7 +340,7 @@ zfork(struct timeval *tv)
*
* (when waiting for the grep, ignoring execpline2 for now). At this time,
* zsh has built two job-table entries for it: one for the cat and one for
- * the grep. If the user hits ^Z at this point (and jobbing is used), the
+ * the grep. If the user hits ^Z at this point (and jobbing is used), the
* shell is notified that the grep was suspended. The list_pipe flag is
* used to tell the execpline where it was waiting that it was in a pipeline
* with a shell construct at the end (which may also be a shell function or
@@ -351,7 +351,7 @@ zfork(struct timeval *tv)
* shell (its pid and the text for it) in the job entry of the cat. The pid
* is passed down in the list_pipe_pid variable.
* But there is a problem: the suspended grep is a child of the parent shell
- * and can't be adopted by the sub-shell. So the parent shell also has to
+ * and can't be adopted by the sub-shell. So the parent shell also has to
* keep the information about this process (more precisely: this pipeline)
* by keeping the job table entry it created for it. The fact that there
* are two jobs which have to be treated together is remembered by setting
@@ -405,7 +405,7 @@ execcursh(Estate state, int do_exec)
state->pc++;
if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob))
- deletejob(jobtab + thisjob);
+ deletejob(jobtab + thisjob, 0);
cmdpush(CS_CURSH);
execlist(state, 1, do_exec);
cmdpop();
@@ -528,10 +528,10 @@ isgooderr(int e, char *dir)
{
/*
* Maybe the directory was unreadable, or maybe it wasn't
- * even a directory.
+ * even a directory.
*/
return ((e != EACCES || !access(dir, X_OK)) &&
- e != ENOENT && e != ENOTDIR);
+ e != ENOENT && e != ENOTDIR);
}
/*
@@ -639,7 +639,7 @@ execute(LinkList args, int flags, int defpath)
break;
}
- /* for command -p, search the default path */
+ /* for command -p, search the default path */
if (defpath) {
char *s, pbuf[PATH_MAX];
char *dptr, *pe, *ps = DEFAULT_PATH;
@@ -676,7 +676,7 @@ execute(LinkList args, int flags, int defpath)
eno = ee;
} else {
-
+
if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
char nn[PATH_MAX], *dptr;
@@ -1312,9 +1312,9 @@ sublist_done:
donetrap = 1;
}
if (lastval) {
- int errreturn = isset(ERRRETURN) &&
+ int errreturn = isset(ERRRETURN) &&
(isset(INTERACTIVE) || locallevel || sourcelevel);
- int errexit = isset(ERREXIT) ||
+ int errexit = isset(ERREXIT) ||
(isset(ERRRETURN) && !errreturn);
if (errexit) {
if (sigtrapped[SIGEXIT])
@@ -1434,7 +1434,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
zclose(opipe[0]);
}
if (how & Z_DISOWN) {
- deletejob(jobtab + thisjob);
+ deletejob(jobtab + thisjob, 1);
thisjob = -1;
}
else
@@ -1484,7 +1484,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
printjob(jn, !!isset(LONGLISTJOBS), 1);
}
else if (newjob != list_pipe_job)
- deletejob(jn);
+ deletejob(jn, 0);
else
lastwj = -1;
}
@@ -1536,7 +1536,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
else if (pid) {
char dummy;
- lpforked =
+ lpforked =
(killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
list_pipe_pid = pid;
list_pipe_start = bgtime;
@@ -1588,7 +1588,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
if (list_pipe && (lastval & 0200) && pj >= 0 &&
(!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
- deletejob(jn);
+ deletejob(jn, 0);
jn = jobtab + pj;
if (jn->gleader)
killjb(jn, lastval & ~0200);
@@ -1596,7 +1596,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
if (list_pipe_child ||
((jn->stat & STAT_DONE) &&
(list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB)))))
- deletejob(jn);
+ deletejob(jn, 0);
thisjob = pj;
}
@@ -2845,7 +2845,11 @@ execcmd(Estate state, int input, int output, int how, int last1)
/* 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|STAT_NOPRINT;
+ 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 *
@@ -2908,6 +2912,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
addfd(forked, save, mfds, fn->fd1, fn->fd2, 1, fn->varid);
} else {
+ int closed;
if (fn->type != REDIR_HERESTR && xpandredir(fn, redir))
continue;
if (errflag) {
@@ -2975,17 +2980,16 @@ execcmd(Estate state, int input, int output, int how, int last1)
fn->fd1 = (int)getintvalue(v);
if (errflag)
bad = 1;
- else if (fn->fd1 > max_zsh_fd)
- bad = 3;
- else if (fn->fd1 >= 10 &&
+ else if (fn->fd1 <= max_zsh_fd) {
+ if (fn->fd1 >= 10 &&
fdtable[fn->fd1] == FDT_INTERNAL)
- bad = 4;
+ bad = 3;
+ }
}
if (bad) {
const char *bad_msg[] = {
"parameter %s does not contain a file descriptor",
"can't close file descriptor from readonly parameter %s",
- "file descriptor %d out of range, not closed",
"file descriptor %d used by shell, not closed"
};
if (bad > 2)
@@ -2995,11 +2999,27 @@ execcmd(Estate state, int input, int output, int how, int last1)
execerr();
}
}
- if (!forked && fn->fd1 < 10 && save[fn->fd1] == -2)
+ /*
+ * Note we may attempt to close an fd beyond max_zsh_fd:
+ * OK as long as we never look in fdtable for it.
+ */
+ closed = 0;
+ if (!forked && fn->fd1 < 10 && save[fn->fd1] == -2) {
save[fn->fd1] = movefd(fn->fd1);
+ if (save[fn->fd1] >= 0) {
+ /*
+ * The original fd is now closed, we don't need
+ * to do it below.
+ */
+ closed = 1;
+ }
+ }
if (fn->fd1 < 10)
closemn(mfds, fn->fd1);
- zclose(fn->fd1);
+ if (!closed && zclose(fn->fd1) < 0) {
+ zwarn("failed to close file descriptor %d: %e",
+ fn->fd1, errno);
+ }
break;
case REDIR_MERGEIN:
case REDIR_MERGEOUT:
@@ -3008,11 +3028,17 @@ execcmd(Estate state, int input, int output, int how, int last1)
if (!checkclobberparam(fn))
fil = -1;
else if (fn->fd2 > 9 &&
- (fn->fd2 > max_zsh_fd ||
- (fdtable[fn->fd2] != FDT_UNUSED &&
- fdtable[fn->fd2] != FDT_EXTERNAL) ||
- fn->fd2 == coprocin ||
- fn->fd2 == coprocout)) {
+ /*
+ * If the requested fd is > max_zsh_fd,
+ * the shell doesn't know about it.
+ * Just assume the user knows what they're
+ * doing.
+ */
+ (fn->fd2 <= max_zsh_fd &&
+ ((fdtable[fn->fd2] != FDT_UNUSED &&
+ fdtable[fn->fd2] != FDT_EXTERNAL) ||
+ fn->fd2 == coprocin ||
+ fn->fd2 == coprocout))) {
fil = -1;
errno = EBADF;
} else {
@@ -3112,7 +3138,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
ESUB_PGRP | ESUB_FAKE;
if (type != WC_SUBSH)
flags |= ESUB_KEEPTRAP;
- if ((do_exec || (type >= WC_CURSH && last1 == 1))
+ if ((do_exec || (type >= WC_CURSH && last1 == 1))
&& !forked)
flags |= ESUB_REVERTPGRP;
entersubsh(flags);
@@ -3739,7 +3765,15 @@ parsecmd(char *cmd, char **eptr)
for (str = cmd + 2; *str && *str != Outpar; str++);
if (!*str || cmd[1] != Inpar) {
- zerr("oops.");
+ /*
+ * This can happen if the expression is being parsed
+ * inside another construct, e.g. as a value within ${..:..} etc.
+ * So print a proper error message instead of the not very
+ * useful but traditional "oops".
+ */
+ char *errstr = dupstrpfx(cmd, 2);
+ untokenize(errstr);
+ zerr("unterminated `%s...)'", errstr);
return NULL;
}
*str = '\0';
@@ -4184,10 +4218,19 @@ execfuncdef(Estate state, UNUSED(int do_exec))
* Anonymous function, execute immediately.
* Function name is "(anon)", parameter list is empty.
*/
- LinkList args = newlinklist();
+ LinkList args;
+ state->pc = end;
+ end += *state->pc++;
+ args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
+
+ if (htok && args)
+ execsubst(args);
+
+ if (!args)
+ args = newlinklist();
shf->node.nam = "(anon)";
- addlinknode(args, shf->node.nam);
+ pushnode(args, shf->node.nam);
execshfunc(shf, args);
ret = lastval;
@@ -4238,7 +4281,7 @@ execshfunc(Shfunc shf, LinkList args)
* would be filled by a recursive function. */
last_file_list = jobtab[thisjob].filelist;
jobtab[thisjob].filelist = NULL;
- deletejob(jobtab + thisjob);
+ deletejob(jobtab + thisjob, 0);
}
if (isset(XTRACE)) {
@@ -4267,7 +4310,7 @@ execshfunc(Shfunc shf, LinkList args)
cmdsp = ocsp;
if (!list_pipe)
- deletefilelist(last_file_list);
+ deletefilelist(last_file_list, 0);
}
/* Function to execute the special type of command that represents an *
@@ -4334,6 +4377,7 @@ loadautofn(Shfunc shf, int fksh, int autol)
}
if (!prog) {
zsfree(fname);
+ popheap();
return NULL;
}
if (ksh == 2 || (ksh == 1 && isset(KSHAUTOLOAD))) {
diff --git a/Src/glob.c b/Src/glob.c
index bfc7f0416..cf4a5a537 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1801,7 +1801,7 @@ zglob(LinkList list, LinkNode np, int nountok)
Eprog prog;
if ((prog = parse_string(sortp->exec, 0))) {
- int ef = errflag, lv = lastval, ret;
+ int ef = errflag, lv = lastval;
/* Parsed OK, execute for each name */
for (tmpptr = matchbuf; tmpptr < matchptr; tmpptr++) {
@@ -1814,7 +1814,6 @@ zglob(LinkList list, LinkNode np, int nountok)
tmpptr->sortstrs[iexec] = tmpptr->name;
}
- ret = lastval;
errflag = ef;
lastval = lv;
} else {
diff --git a/Src/hist.c b/Src/hist.c
index 01a97da2b..aeb6edda5 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -229,7 +229,7 @@ ihwaddc(int c)
/* Quote un-expanded bangs in the history line. */
if (c == bangchar && stophist < 2 && qbang)
/* If qbang is not set, we do not escape this bangchar as it's *
- * not mecessary (e.g. it's a bang in !=, or it is followed *
+ * not necessary (e.g. it's a bang in !=, or it is followed *
* by a space). Roughly speaking, qbang is zero only if the *
* history interpreter has already digested this bang and *
* found that it is not necessary to escape it. */
@@ -876,7 +876,18 @@ hbegin(int dohist)
stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0;
else
stophist = 0;
- if (stophist == 2 || (inbufflags & INP_ALIAS)) {
+ /*
+ * pws: We used to test for "|| (inbufflags & INP_ALIAS)"
+ * in this test, but at this point we don't have input
+ * set up up so this can trigger unnecessarily.
+ * I don't see how the test at this point could ever be
+ * useful, since we only get here when we're initialising
+ * the history mechanism, before we've done any input.
+ *
+ * (I also don't see any point where this function is called with
+ * dohist=0.)
+ */
+ if (stophist == 2) {
chline = hptr = NULL;
hlinesz = 0;
chwords = NULL;
@@ -1344,7 +1355,8 @@ ihwend(void)
(chwordlen += 32) *
sizeof(short));
}
- if (hwgetword > -1) {
+ if (hwgetword > -1 &&
+ (inbufflags & INP_ALIAS) && !(inbufflags & INP_HIST)) {
/* We want to reuse the current word position */
chwordpos = hwgetword;
/* Start from where previous word ended, if possible */
@@ -2235,10 +2247,12 @@ readhistfile(char *fn, int err, int readflags)
if (!fn && !(fn = getsparam("HISTFILE")))
return;
+ if (stat(unmeta(fn), &sb) < 0 ||
+ sb.st_size == 0)
+ return;
if (readflags & HFILE_FAST) {
- if (stat(unmeta(fn), &sb) < 0
- || (lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
- || lockhistfile(fn, 0))
+ if ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
+ || lockhistfile(fn, 0))
return;
lasthist.fsiz = sb.st_size;
lasthist.mtim = sb.st_mtime;
@@ -2338,110 +2352,11 @@ readhistfile(char *fn, int err, int readflags)
/*
* Divide up the words.
*/
- nwordpos = 0;
start = pt;
uselex = isset(HISTLEXWORDS) && !(readflags & HFILE_FAST);
- if (uselex) {
- /*
- * Attempt to do this using the lexer.
- */
- LinkList wordlist = bufferwords(NULL, pt, NULL,
- LEXFLAGS_COMMENTS_KEEP);
- LinkNode wordnode;
- int nwords_max;
- nwords_max = 2 * countlinknodes(wordlist);
- if (nwords_max > nwords) {
- nwords = nwords_max;
- words = (short *)realloc(words, nwords*sizeof(short));
- }
- for (wordnode = firstnode(wordlist);
- wordnode;
- incnode(wordnode)) {
- char *word = getdata(wordnode);
-
- for (;;) {
- /*
- * Not really an oddity: "\\\n" is
- * removed from input as if whitespace.
- */
- if (inblank(*pt))
- pt++;
- else if (pt[0] == '\\' && pt[1] == '\n')
- pt += 2;
- else
- break;
- }
- if (!strpfx(word, pt)) {
- int bad = 0;
- /*
- * Oddity 1: newlines turn into semicolons.
- */
- if (!strcmp(word, ";"))
- continue;
- while (*pt) {
- if (!*word) {
- bad = 1;
- break;
- }
- /*
- * Oddity 2: !'s turn into |'s.
- */
- if (*pt == *word ||
- (*pt == '!' && *word == '|')) {
- pt++;
- word++;
- } else {
- bad = 1;
- break;
- }
- }
- if (bad) {
-#ifdef DEBUG
- dputs(ERRMSG("bad wordsplit reading history: "
- "%s\nat: %s\nword: %s"),
- start, pt, word);
-#endif
- pt = start;
- nwordpos = 0;
- uselex = 0;
- break;
- }
- } else if (!strcmp(word, ";") && strpfx(";;", pt)) {
- /*
- * Don't get confused between a semicolon that's
- * probably really a newline and a double
- * semicolon that's terminating a case.
- */
- continue;
- }
- words[nwordpos++] = pt - start;
- pt += strlen(word);
- words[nwordpos++] = pt - start;
- }
+ histsplitwords(pt, &words, &nwords, &nwordpos, uselex);
+ if (uselex)
freeheap();
- }
- if (!uselex) {
- do {
- for (;;) {
- if (inblank(*pt))
- pt++;
- else if (pt[0] == '\\' && pt[1] == '\n')
- pt += 2;
- else
- break;
- }
- if (*pt) {
- if (nwordpos >= nwords)
- words = (short *)
- realloc(words, (nwords += 64)*sizeof(short));
- words[nwordpos++] = pt - start;
- while (*pt && !inblank(*pt))
- pt++;
- words[nwordpos++] = pt - start;
- }
- } while (*pt);
-
- }
he->nwords = nwordpos/2;
if (he->nwords) {
@@ -3141,6 +3056,207 @@ bufferwords(LinkList list, char *buf, int *index, int flags)
return list;
}
+/*
+ * Split up a line into words for use in a history file.
+ *
+ * lineptr is the line to be split.
+ *
+ * *wordsp and *nwordsp are an array already allocated to hold words
+ * and its length. The array holds both start and end positions,
+ * so *nwordsp actually counts twice the number of words in the
+ * original string. *nwordsp may be zero in which case the array
+ * will be allocated.
+ *
+ * *nwordposp returns the used length of *wordsp in the same units as
+ * *nwordsp, i.e. twice the number of words in the input line.
+ *
+ * If uselex is 1, attempt to do this using the lexical analyser.
+ * This is more accurate, but slower; for reading history files it's
+ * controlled by the option HISTLEXWORDS. If this failed (which
+ * indicates a bug in the shell) it falls back to whitespace-separated
+ * strings, printing a message if in debug mode.
+ *
+ * If uselex is 0, just look for whitespace-separated words; the only
+ * special handling is for a backslash-newline combination as used
+ * by the history file format to save multiline buffers.
+ */
+/**/
+mod_export void
+histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp,
+ int uselex)
+{
+ int nwords = *nwordsp, nwordpos = 0;
+ short *words = *wordsp;
+ char *start = lineptr;
+
+ if (uselex) {
+ LinkList wordlist = bufferwords(NULL, lineptr, NULL,
+ LEXFLAGS_COMMENTS_KEEP);
+ LinkNode wordnode;
+ int nwords_max;
+
+ nwords_max = 2 * countlinknodes(wordlist);
+ if (nwords_max > nwords) {
+ *nwordsp = nwords = nwords_max;
+ *wordsp = words = (short *)zrealloc(words, nwords*sizeof(short));
+ }
+ for (wordnode = firstnode(wordlist);
+ wordnode;
+ incnode(wordnode)) {
+ char *word = getdata(wordnode);
+ char *lptr, *wptr = word;
+ int loop_next = 0, skipping;
+
+ /* Skip stuff at the start of the word */
+ for (;;) {
+ /*
+ * Not really an oddity: "\\\n" is
+ * removed from input as if whitespace.
+ */
+ if (inblank(*lineptr))
+ lineptr++;
+ else if (lineptr[0] == '\\' && lineptr[1] == '\n') {
+ /*
+ * Optimisation: we handle this in the loop below,
+ * too.
+ */
+ lineptr += 2;
+ } else
+ break;
+ }
+ lptr = lineptr;
+ /*
+ * Skip chunks of word with possible intervening
+ * backslash-newline.
+ *
+ * To get round C's annoying lack of ability to
+ * reference the outer loop, we'll break from this
+ * one with
+ * loop_next = 0: carry on as normal
+ * loop_next = 1: break from outer loop
+ * loop_next = 2: continue round outer loop.
+ */
+ do {
+ skipping = 0;
+ if (strpfx(wptr, lptr)) {
+ /*
+ * Normal case: word from lexer matches start of
+ * string from line. Just advance over it.
+ */
+ int len;
+ if (!strcmp(wptr, ";") && strpfx(";;", lptr)) {
+ /*
+ * Don't get confused between a semicolon that's
+ * probably really a newline and a double
+ * semicolon that's terminating a case.
+ */
+ loop_next = 2;
+ break;
+ }
+ len = strlen(wptr);
+ lptr += len;
+ wptr += len;
+ } else {
+ /*
+ * Didn't get to the end of the word.
+ * See what's amiss.
+ */
+ int bad = 0;
+ /*
+ * Oddity 1: newlines turn into semicolons.
+ */
+ if (!strcmp(wptr, ";"))
+ {
+ loop_next = 2;
+ break;
+ }
+ while (*lptr) {
+ if (!*wptr) {
+ /*
+ * End of the word before the end of the
+ * line: not good.
+ */
+ bad = 1;
+ loop_next = 1;
+ break;
+ }
+ /*
+ * Oddity 2: !'s turn into |'s.
+ */
+ if (*lptr == *wptr ||
+ (*lptr == '!' && *wptr == '|')) {
+ lptr++;
+ wptr++;
+ } else if (lptr[0] == '\\' &&
+ lptr[1] == '\n') {
+ /*
+ * \\\n can occur in the middle of a word;
+ * wptr is already pointing at this, we
+ * just need to skip over the break
+ * in lptr and look at the next chunk.
+ */
+ lptr += 2;
+ skipping = 1;
+ break;
+ } else {
+ bad = 1;
+ loop_next = 1;
+ break;
+ }
+ }
+ if (bad) {
+#ifdef DEBUG
+ dputs(ERRMSG("bad wordsplit reading history: "
+ "%s\nat: %s\nword: %s"),
+ start, lineptr, word);
+#endif
+ lineptr = start;
+ nwordpos = 0;
+ uselex = 0;
+ loop_next = 1;
+ }
+ }
+ } while (skipping);
+ if (loop_next) {
+ if (loop_next == 1)
+ break;
+ continue;
+ }
+ /* Record position of current word... */
+ words[nwordpos++] = lineptr - start;
+ words[nwordpos++] = lptr - start;
+
+ /* ready for start of next word. */
+ lineptr = lptr;
+ }
+ }
+ if (!uselex) {
+ do {
+ for (;;) {
+ if (inblank(*lineptr))
+ lineptr++;
+ else if (lineptr[0] == '\\' && lineptr[1] == '\n')
+ lineptr += 2;
+ else
+ break;
+ }
+ if (*lineptr) {
+ if (nwordpos >= nwords) {
+ *nwordsp = nwords = nwords + 64;
+ *wordsp = words = (short *)
+ zrealloc(words, nwords*sizeof(*words));
+ }
+ words[nwordpos++] = lineptr - start;
+ while (*lineptr && !inblank(*lineptr))
+ lineptr++;
+ words[nwordpos++] = lineptr - start;
+ }
+ } while (*lineptr);
+ }
+
+ *nwordposp = nwordpos;
+}
+
/* Move the current history list out of the way and prepare a fresh history
* list using hf for HISTFILE, hs for HISTSIZE, and shs for SAVEHIST. If
* the hf value is an empty string, HISTFILE will be unset from the new
diff --git a/Src/jobs.c b/Src/jobs.c
index b3ec0008c..94d25bb85 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -160,6 +160,8 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux)
Process pn;
int i;
+ *jptr = NULL;
+ *pptr = NULL;
for (i = 1; i <= maxjob; i++)
{
/*
@@ -189,15 +191,16 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux)
* the termination of the process which pid we were supposed
* to return in a different job.
*/
- if (pn->pid == pid && pn->status == SP_RUNNING) {
+ if (pn->pid == pid) {
*pptr = pn;
*jptr = jobtab + i;
- return 1;
+ if (pn->status == SP_RUNNING)
+ return 1;
}
}
}
- return 0;
+ return (*pptr && *jptr);
}
/* Does the given job number have any processes? */
@@ -266,7 +269,7 @@ handle_sub(int job, int fg)
sleep, the rest will be executed by a sub-shell,
but the parent shell gets notified for the
sleep.
- deletejob(sj); */
+ deletejob(sj, 0); */
/* If this super-job contains only the sub-shell,
we have to attach the tty to its process group
now. */
@@ -950,7 +953,9 @@ printjob(Job jn, int lng, int synch)
if (skip_print) {
if (jn->stat & STAT_DONE) {
- deletejob(jn);
+ if (should_report_time(jn))
+ dumptime(jn);
+ deletejob(jn, 0);
if (job == curjob) {
curjob = prevjob;
prevjob = job;
@@ -1080,7 +1085,7 @@ printjob(Job jn, int lng, int synch)
if (jn->stat & STAT_DONE) {
if (should_report_time(jn))
dumptime(jn);
- deletejob(jn);
+ deletejob(jn, 0);
if (job == curjob) {
curjob = prevjob;
prevjob = job;
@@ -1095,12 +1100,13 @@ printjob(Job jn, int lng, int synch)
/**/
void
-deletefilelist(LinkList file_list)
+deletefilelist(LinkList file_list, int disowning)
{
char *s;
if (file_list) {
while ((s = (char *)getlinknode(file_list))) {
- unlink(s);
+ if (!disowning)
+ unlink(s);
zsfree(s);
}
zfree(file_list, sizeof(struct linklist));
@@ -1136,7 +1142,7 @@ freejob(Job jn, int deleting)
/* careful in case we shrink and move the job table */
int job = jn - jobtab;
if (deleting)
- deletejob(jobtab + jn->other);
+ deletejob(jobtab + jn->other, 0);
else
freejob(jobtab + jn->other, 0);
jn = jobtab + job;
@@ -1156,13 +1162,17 @@ freejob(Job jn, int deleting)
/*
* We are actually finished with this job, rather
* than freeing it to make space.
+ *
+ * If "disowning" is set, files associated with the job are not
+ * actually deleted --- and won't be as there is nothing left
+ * to clear up.
*/
/**/
void
-deletejob(Job jn)
+deletejob(Job jn, int disowning)
{
- deletefilelist(jn->filelist);
+ deletefilelist(jn->filelist, disowning);
if (jn->stat & STAT_ATTACH) {
attachtty(mypgrp);
adjustwinsize(0);
@@ -1338,7 +1348,7 @@ zwaitjob(int job, int wait_cmd)
child_block();
}
} else {
- deletejob(jn);
+ deletejob(jn, 0);
pipestats[0] = lastval;
numpipestats = 1;
}
@@ -1361,7 +1371,7 @@ waitjobs(void)
if (jn->procs || jn->auxprocs)
zwaitjob(thisjob, 0);
else {
- deletejob(jn);
+ deletejob(jn, 0);
pipestats[0] = lastval;
numpipestats = 1;
}
@@ -1489,7 +1499,7 @@ spawnjob(void)
}
}
if (!hasprocs(thisjob))
- deletejob(jobtab + thisjob);
+ deletejob(jobtab + thisjob, 0);
else
jobtab[thisjob].stat |= STAT_LOCKED;
thisjob = -1;
@@ -1930,12 +1940,19 @@ bin_fg(char *name, char **argv, Options ops, int func)
Process p;
if (findproc(pid, &j, &p, 0)) {
- /*
- * returns 0 for normal exit, else signal+128
- * in which case we should return that status.
- */
- retval = waitforpid(pid, 1);
- if (!retval)
+ if (j->stat & STAT_STOPPED) {
+ retval = (killjb(j, SIGCONT) != 0);
+ if (retval == 0)
+ makerunning(j);
+ }
+ if (retval == 0) {
+ /*
+ * returns 0 for normal exit, else signal+128
+ * in which case we should return that status.
+ */
+ retval = waitforpid(pid, 1);
+ }
+ if (retval == 0)
retval = lastval2;
} else if (isset(POSIXJOBS) &&
pid == lastpid && lastpid_status >= 0L) {
@@ -2058,7 +2075,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
waitjobs();
retval = lastval2;
} else if (ofunc == BIN_DISOWN)
- deletejob(jobtab + job);
+ deletejob(jobtab + job, 1);
break;
case BIN_JOBS:
printjob(job + (oldjobtab ? oldjobtab : jobtab), lng, 2);
@@ -2094,7 +2111,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
#endif
pids);
}
- deletejob(jobtab + job);
+ deletejob(jobtab + job, 1);
break;
}
thisjob = ocj;
@@ -2245,7 +2262,7 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
}
if (sig > SIGCOUNT) {
zwarnnam(nam, "unknown signal: SIG%s", signame);
- zwarnnam(nam, "type kill -l for a List of signals");
+ zwarnnam(nam, "type kill -l for a list of signals");
return 1;
}
}
diff --git a/Src/lex.c b/Src/lex.c
index fdd05efff..90c4effd9 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1567,7 +1567,7 @@ dquote_parse(char endchar, int sub)
err = (!brct-- && math);
break;
case '"':
- if (intick || ((endchar == ']' || !endchar) && !bct))
+ if (intick || (endchar != '"' && !bct))
break;
if (bct) {
add(Dnull);
@@ -1698,7 +1698,7 @@ parse_subscript(char *s, int sub, int endchar)
mod_export int
parse_subst_string(char *s)
{
- int c, l = strlen(s), err, olen, lexstop_ret;
+ int c, l = strlen(s), err;
char *ptr;
if (!*s || !strcmp(s, nulstring))
@@ -1711,13 +1711,11 @@ parse_subst_string(char *s)
bptr = tokstr = s;
bsiz = l + 1;
c = hgetc();
- lexstop_ret = lexstop;
c = gettokstr(c, 1);
err = errflag;
strinend();
inpop();
DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
- olen = len;
lexrestore();
errflag = err;
if (c == LEXERR) {
@@ -1726,8 +1724,9 @@ parse_subst_string(char *s)
}
#ifdef DEBUG
/*
- * Historical note: we used to check here for olen == l, but
- * that's not necessarily the case if we stripped an RCQUOTE.
+ * Historical note: we used to check here for olen (the value of len
+ * before lexrestore()) == l, but that's not necessarily the case if
+ * we stripped an RCQUOTE.
*/
if (c != STRING || (errflag && !noerrs)) {
fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
diff --git a/Src/math.c b/Src/math.c
index beef74525..cca521098 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -969,7 +969,6 @@ void
op(int what)
{
mnumber a, b, c, *spval;
- char *lv;
int tp = type[what];
if (errflag)
@@ -1155,7 +1154,6 @@ op(int what)
}
if (tp & (OP_E2|OP_E2IO)) {
struct mathvalue *mvp = stack + sp + 1;
- lv = stack[sp+1].lval;
c = setmathvar(mvp, c);
push(c, mvp->lval, 0);
} else
diff --git a/Src/module.c b/Src/module.c
index 219bdfa8e..5cc595c47 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1081,6 +1081,11 @@ addparamdef(Paramdef d)
pm->gsu.i = d->gsu ? (GsuInteger)d->gsu : &varinteger_gsu;
break;
+ case PM_FFLOAT:
+ case PM_EFLOAT:
+ pm->gsu.f = d->gsu;
+ break;
+
case PM_ARRAY:
pm->gsu.a = d->gsu ? (GsuArray)d->gsu : &vararray_gsu;
break;
@@ -1592,7 +1597,8 @@ do_load_module(char const *name, int silent)
ret = try_load_module(name);
if (!ret && !silent) {
#ifdef HAVE_DLERROR
- zwarn("failed to load module `%s': %s", name, dlerror());
+ zwarn("failed to load module `%s': %s", name,
+ metafy(dlerror(), -1, META_USEHEAP));
#else
zwarn("failed to load module: %s", name);
#endif
diff --git a/Src/params.c b/Src/params.c
index a59c51767..446cccc7e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -655,7 +655,10 @@ createparamtable(void)
char **new_environ;
int envsize;
#endif
- char **envp, **envp2, **sigptr, **t;
+#ifndef USE_SET_UNSET_ENV
+ char **envp;
+#endif
+ char **envp2, **sigptr, **t;
char buf[50], *str, *iname, *ivalue, *hostnam;
int oae = opts[ALLEXPORT];
#ifdef HAVE_UNAME
@@ -721,7 +724,11 @@ createparamtable(void)
/* Now incorporate environment variables we are inheriting *
* into the parameter hash table. Copy them into dynamic *
* memory so that we can free them if needed */
- for (envp = envp2 = environ; *envp2; envp2++) {
+ for (
+#ifndef USE_SET_UNSET_ENV
+ envp =
+#endif
+ envp2 = environ; *envp2; envp2++) {
if (split_env_string(*envp2, &iname, &ivalue)) {
if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) {
if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
@@ -993,9 +1000,7 @@ mod_export int
isident(char *s)
{
char *ss;
- int ne;
- ne = noeval; /* save the current value of noeval */
if (!*s) /* empty string is definitely not valid */
return 0;
@@ -3041,9 +3046,21 @@ mod_export void
stdunsetfn(Param pm, UNUSED(int exp))
{
switch (PM_TYPE(pm->node.flags)) {
- case PM_SCALAR: pm->gsu.s->setfn(pm, NULL); break;
- case PM_ARRAY: pm->gsu.a->setfn(pm, NULL); break;
- case PM_HASHED: pm->gsu.h->setfn(pm, NULL); break;
+ case PM_SCALAR:
+ if (pm->gsu.s->setfn)
+ pm->gsu.s->setfn(pm, NULL);
+ break;
+
+ case PM_ARRAY:
+ if (pm->gsu.a->setfn)
+ pm->gsu.a->setfn(pm, NULL);
+ break;
+
+ case PM_HASHED:
+ if (pm->gsu.h->setfn)
+ pm->gsu.h->setfn(pm, NULL);
+ break;
+
default:
if (!(pm->node.flags & PM_SPECIAL))
pm->u.str = NULL;
@@ -4188,6 +4205,7 @@ arrfixenv(char *s, char **t)
int
zputenv(char *str)
{
+ DPUTS(!str, "Attempt to put null string into environment.");
#ifdef USE_SET_UNSET_ENV
/*
* If we are using unsetenv() to remove values from the
diff --git a/Src/parse.c b/Src/parse.c
index e59a882ca..e4d038b6e 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1465,6 +1465,10 @@ par_funcdef(void)
ecssub = oecssub;
YYERRORV(oecused);
}
+ if (num == 0) {
+ /* Anonymous function, possibly with arguments */
+ incmdpos = 0;
+ }
zshlex();
} else if (unset(SHORTLOOPS)) {
lineno += oldlineno;
@@ -1480,12 +1484,25 @@ par_funcdef(void)
ecbuf[p + num + 4] = ecnpats;
ecbuf[p + 1] = num;
- lineno += oldlineno;
ecnpats = onp;
ecssub = oecssub;
ecnfunc++;
ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
+
+ if (num == 0) {
+ /* Unnamed function */
+ int parg = ecadd(0);
+ ecadd(0);
+ while (tok == STRING) {
+ ecstr(tokstr);
+ num++;
+ zshlex();
+ }
+ ecbuf[parg] = ecused - parg; /*?*/
+ ecbuf[parg+1] = num;
+ }
+ lineno += oldlineno;
}
/*
@@ -1707,13 +1724,17 @@ par_simple(int *complex, int nr)
ecssub = oecssub;
YYERROR(oecused);
}
+ if (argc == 0) {
+ /* Anonymous function, possibly with arguments */
+ incmdpos = 0;
+ }
zshlex();
} else {
- int ll, sl, pl, c = 0;
+ int ll, sl, c = 0;
ll = ecadd(0);
sl = ecadd(0);
- pl = ecadd(WCB_PIPE(WC_PIPE_END, 0));
+ (void)ecadd(WCB_PIPE(WC_PIPE_END, 0));
if (!par_cmd(&c)) {
cmdpop();
@@ -1730,13 +1751,26 @@ par_simple(int *complex, int nr)
ecbuf[p + argc + 3] = ecsoffs - so;
ecbuf[p + argc + 4] = ecnpats;
- lineno += oldlineno;
ecnpats = onp;
ecssub = oecssub;
ecnfunc++;
ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
+ if (argc == 0) {
+ /* Unnamed function */
+ int parg = ecadd(0);
+ ecadd(0);
+ while (tok == STRING) {
+ ecstr(tokstr);
+ argc++;
+ zshlex();
+ }
+ ecbuf[parg] = ecused - parg; /*?*/
+ ecbuf[parg+1] = argc;
+ }
+ lineno += oldlineno;
+
isfunc = 1;
isnull = 0;
break;
diff --git a/Src/signals.c b/Src/signals.c
index 456a85300..ad688094b 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -489,16 +489,24 @@ wait_for_processes(void)
* Find the process and job containing this pid and
* update it.
*/
- pn = NULL;
if (findproc(pid, &jn, &pn, 0)) {
+ if (((jn->stat & STAT_BUILTIN) ||
+ (list_pipe &&
+ (thisjob == -1 ||
+ (jobtab[thisjob].stat & STAT_BUILTIN)))) &&
+ WIFSTOPPED(status) && WSTOPSIG(status) == SIGTSTP) {
+ killjb(jn, SIGCONT);
+ zwarn("job can't be suspended");
+ } else {
#if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE)
- struct timezone dummy_tz;
- gettimeofday(&pn->endtime, &dummy_tz);
- pn->status = status;
- pn->ti = ru;
+ struct timezone dummy_tz;
+ gettimeofday(&pn->endtime, &dummy_tz);
+ pn->status = status;
+ pn->ti = ru;
#else
- update_process(pn, status);
+ update_process(pn, status);
#endif
+ }
update_job(jn);
} else if (findproc(pid, &jn, &pn, 1)) {
pn->status = status;
@@ -1185,7 +1193,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
traplocallevel = locallevel;
runhookdef(BEFORETRAPHOOK, NULL);
if (*sigtr & ZSIG_FUNC) {
- int osc = sfcontext;
+ int osc = sfcontext, old_incompfunc = incompfunc;
HashNode hn = gettrapnode(sig, 0);
args = znewlinklist();
@@ -1211,8 +1219,10 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
trapisfunc = isfunc = 1;
sfcontext = SFC_SIGNAL;
+ incompfunc = 0;
doshfunc((Shfunc)sigfn, args, 1);
sfcontext = osc;
+ incompfunc= old_incompfunc;
freelinklist(args, (FreeFunc) NULL);
zsfree(name);
} else {
diff --git a/Src/subst.c b/Src/subst.c
index f9c48404b..4e8ed721d 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -162,6 +162,8 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
subst = getproc(str, &rest); /* <(...) or >(...) */
else
subst = getoutputfile(str, &rest); /* =(...) */
+ if (errflag)
+ return NULL;
if (!subst)
subst = "";
@@ -245,7 +247,10 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
if (endchar == Outpar && str2[1] == '(' && str[-2] == ')') {
/* Math substitution of the form $((...)) */
str[-2] = '\0';
- str = arithsubst(str2 + 2, &str3, str);
+ if (isset(EXECOPT))
+ str = arithsubst(str2 + 2, &str3, str);
+ else
+ strncpy(str3, str2, 1);
setdata(node, (void *) str3);
continue;
}
@@ -2080,7 +2085,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
|| (cc = s[1]) == '*' || cc == Star || cc == '@'
|| cc == '?' || cc == Quest
|| cc == '$' || cc == String || cc == Qstring
- || cc == '#' || cc == Pound
+ /*
+ * Me And My Squiggle:
+ * ${##} is the length of $#, but ${##foo}
+ * is $# with a "foo" removed from the start.
+ * If someone had defined the *@!@! language
+ * properly in the first place we wouldn't
+ * have this nonsense.
+ */
+ || ((cc == '#' || cc == Pound) &&
+ s[2] == Outbrace)
|| cc == '-' || (cc == ':' && s[2] == '-')
|| (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) {
getlen = 1 + whichlen, s++;
@@ -2706,19 +2720,21 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
case '?':
case Quest:
if (vunset) {
- *idend = '\0';
- zerr("%s: %s", idbeg, *s ? s : "parameter not set");
- if (!interact) {
- if (mypid == getpid()) {
- /*
- * paranoia: don't check for jobs, but there shouldn't
- * be any if not interactive.
- */
- stopmsg = 1;
- zexit(1, 0);
- } else
- _exit(1);
- }
+ if (isset(EXECOPT)) {
+ *idend = '\0';
+ zerr("%s: %s", idbeg, *s ? s : "parameter not set");
+ if (!interact) {
+ if (mypid == getpid()) {
+ /*
+ * paranoia: don't check for jobs, but there
+ * shouldn't be any if not interactive.
+ */
+ stopmsg = 1;
+ zexit(1, 0);
+ } else
+ _exit(1);
+ }
+ }
return NULL;
}
break;
@@ -2839,7 +2855,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
char *check_offset = check_colon_subscript(s, &check_offset2);
if (check_offset) {
zlong offset = mathevali(check_offset);
- zlong length;
+ zlong length = 0;
int length_set = 0;
int offset_hack_argzero = 0;
if (errflag)
diff --git a/Src/text.c b/Src/text.c
index 669037a2d..f55553ed0 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -253,6 +253,7 @@ struct tstack {
struct {
char *strs;
Wordcode end;
+ int nargs;
} _funcdef;
struct {
Wordcode end;
@@ -456,19 +457,31 @@ gettext2(Estate state)
if (!s) {
Wordcode p = state->pc;
Wordcode end = p + WC_FUNCDEF_SKIP(code);
+ int nargs = *state->pc++;
- taddlist(state, *state->pc++);
+ taddlist(state, nargs);
+ if (nargs)
+ taddstr(" ");
if (tjob) {
- taddstr(" () { ... }");
+ taddstr("() { ... }");
state->pc = end;
+ if (!nargs) {
+ /*
+ * Unnamed fucntion.
+ * We're not going to pull any arguments off
+ * later, so skip them now...
+ */
+ state->pc += *end;
+ }
stack = 1;
} else {
- taddstr(" () {");
+ taddstr("() {");
tindent++;
taddnl(1);
n = tpush(code, 1);
n->u._funcdef.strs = state->strs;
n->u._funcdef.end = end;
+ n->u._funcdef.nargs = nargs;
state->strs += *state->pc;
state->pc += 3;
}
@@ -478,6 +491,17 @@ gettext2(Estate state)
dec_tindent();
taddnl(0);
taddstr("}");
+ if (s->u._funcdef.nargs == 0) {
+ /* Unnamed function with post-arguments */
+ int nargs;
+ s->u._funcdef.end += *state->pc++;
+ nargs = *state->pc++;
+ if (nargs) {
+ taddstr(" ");
+ taddlist(state, nargs);
+ }
+ state->pc = s->u._funcdef.end;
+ }
stack = 1;
}
break;
diff --git a/Src/utils.c b/Src/utils.c
index 066710e1e..6c2ea98d5 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -40,6 +40,11 @@ mod_export char *scriptname; /* is sometimes a function name */
/**/
mod_export char *scriptfilename;
+/* != 0 if we are in a new style completion function */
+
+/**/
+mod_export int incompfunc;
+
#ifdef MULTIBYTE_SUPPORT
struct widechar_array {
wchar_t *chars;
@@ -1232,8 +1237,10 @@ callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval)
* to a list of jobs generated in a hook.
*/
int osc = sfcontext, osm = stopmsg, stat = 1, ret = 0;
+ int old_incompfunc = incompfunc;
sfcontext = SFC_HOOK;
+ incompfunc = 0;
if ((shfunc = getshfunc(name))) {
ret = doshfunc(shfunc, lnklst, 1);
@@ -1262,6 +1269,7 @@ callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval)
sfcontext = osc;
stopmsg = osm;
+ incompfunc = old_incompfunc;
if (retval)
*retval = ret;
@@ -1683,8 +1691,8 @@ adjustwinsize(int from)
winchanged =
#endif /* TIOCGWINSZ */
resetneeded = 1;
- zleentry(ZLE_CMD_REFRESH);
zleentry(ZLE_CMD_RESET_PROMPT);
+ zleentry(ZLE_CMD_REFRESH);
}
}
@@ -1802,22 +1810,20 @@ zclose(int fd)
{
if (fd >= 0) {
/*
- * We sometimes zclose() an fd twice where the second
- * time is a catch-all in case there was a failure using
- * the fd. This is harmless but we need to trap it
- * for the error check here.
+ * Careful: we allow closing of arbitrary fd's, beyond
+ * max_zsh_fd. In that case we don't try anything clever.
*/
- DPUTS2(fd > max_zsh_fd && fdtable[fd] != FDT_UNUSED,
- "BUG: fd is %d, max_zsh_fd is %d", fd, max_zsh_fd);
- if (fdtable[fd] == FDT_FLOCK)
- fdtable_flocks--;
- fdtable[fd] = FDT_UNUSED;
- while (max_zsh_fd > 0 && fdtable[max_zsh_fd] == FDT_UNUSED)
- max_zsh_fd--;
- if (fd == coprocin)
- coprocin = -1;
- if (fd == coprocout)
- coprocout = -1;
+ if (fd <= max_zsh_fd) {
+ if (fdtable[fd] == FDT_FLOCK)
+ fdtable_flocks--;
+ fdtable[fd] = FDT_UNUSED;
+ while (max_zsh_fd > 0 && fdtable[max_zsh_fd] == FDT_UNUSED)
+ max_zsh_fd--;
+ if (fd == coprocin)
+ coprocin = -1;
+ if (fd == coprocout)
+ coprocout = -1;
+ }
return close(fd);
}
return -1;
@@ -2492,16 +2498,18 @@ spckword(char **s, int hist, int cmd, int ask)
return;
if (!(*s)[0] || !(*s)[1])
return;
- if (shfunctab->getnode(shfunctab, *s) ||
- builtintab->getnode(builtintab, *s) ||
- cmdnamtab->getnode(cmdnamtab, *s) ||
- aliastab->getnode(aliastab, *s) ||
- reswdtab->getnode(reswdtab, *s))
- return;
- else if (isset(HASHLISTALL)) {
- cmdnamtab->filltable(cmdnamtab);
- if (cmdnamtab->getnode(cmdnamtab, *s))
+ if (cmd) {
+ if (shfunctab->getnode(shfunctab, *s) ||
+ builtintab->getnode(builtintab, *s) ||
+ cmdnamtab->getnode(cmdnamtab, *s) ||
+ aliastab->getnode(aliastab, *s) ||
+ reswdtab->getnode(reswdtab, *s))
return;
+ else if (isset(HASHLISTALL)) {
+ cmdnamtab->filltable(cmdnamtab);
+ if (cmdnamtab->getnode(cmdnamtab, *s))
+ return;
+ }
}
t = *s;
if (*t == Tilde || *t == Equals || *t == String)
@@ -2615,6 +2623,8 @@ spckword(char **s, int hist, int cmd, int ask)
fflush(shout);
zbeep();
x = getquery("nyae \t", 0);
+ if (cmd && x == 'n')
+ pathchecked = path;
} else
x = 'n';
} else
@@ -3170,6 +3180,10 @@ sepsplit(char *s, char *sep, int allownull, int heap)
int n, sl;
char *t, *tt, **r, **p;
+ /* Null string? Treat as empty string. */
+ if (s[0] == Nularg && !s[1])
+ s++;
+
if (!sep)
return spacesplit(s, allownull, heap, 0);
@@ -3218,7 +3232,7 @@ getshfunc(char *nam)
char **
subst_string_by_func(Shfunc func, char *arg1, char *orig)
{
- int osc = sfcontext, osm = stopmsg;
+ int osc = sfcontext, osm = stopmsg, old_incompfunc = incompfunc;
LinkList l = newlinklist();
char **ret;
@@ -3227,6 +3241,7 @@ subst_string_by_func(Shfunc func, char *arg1, char *orig)
addlinknode(l, arg1);
addlinknode(l, orig);
sfcontext = SFC_SUBST;
+ incompfunc = 0;
if (doshfunc(func, l, 1))
ret = NULL;
@@ -3235,6 +3250,7 @@ subst_string_by_func(Shfunc func, char *arg1, char *orig)
sfcontext = osc;
stopmsg = osm;
+ incompfunc = old_incompfunc;
return ret;
}
@@ -4689,7 +4705,7 @@ addunprintable(char *v, const char *u, const char *uend)
mod_export char *
quotestring(const char *s, char **e, int instring)
{
- const char *u, *tt;
+ const char *u;
char *v;
int alloclen;
char *buf;
@@ -4740,7 +4756,7 @@ quotestring(const char *s, char **e, int instring)
break;
}
- tt = quotestart = v = buf = zshcalloc(alloclen);
+ quotestart = v = buf = zshcalloc(alloclen);
DPUTS(instring < QT_BACKSLASH || instring == QT_BACKTICK ||
instring > QT_SINGLE_OPTIONAL,
diff --git a/Src/zsh.h b/Src/zsh.h
index 62ab5ade3..e3141120f 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -907,6 +907,8 @@ struct job {
#define STAT_ATTACH (0x1000) /* delay reattaching shell to tty */
#define STAT_SUBLEADER (0x2000) /* is super-job, but leader is sub-shell */
+#define STAT_BUILTIN (0x4000) /* job at tail of pipeline is a builtin */
+
#define SP_RUNNING -1 /* fake status for jobs currently running */
struct timeinfo {