summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.awk1
-rw-r--r--Src/Builtins/rlimits.c72
-rw-r--r--Src/Modules/parameter.c8
-rw-r--r--Src/Zle/zle_keymap.c2
-rw-r--r--Src/Zle/zle_move.c33
-rw-r--r--Src/Zle/zle_tricky.c15
-rw-r--r--Src/Zle/zle_utils.c38
-rw-r--r--Src/builtin.c111
-rw-r--r--Src/compat.c4
-rw-r--r--Src/exec.c157
-rw-r--r--Src/hashtable.c16
-rw-r--r--Src/hist.c2
-rw-r--r--Src/init.c114
-rw-r--r--Src/jobs.c12
-rw-r--r--Src/lex.c107
-rw-r--r--Src/math.c68
-rw-r--r--Src/options.c81
-rw-r--r--Src/parse.c54
-rw-r--r--Src/prototypes.h9
-rw-r--r--Src/signals.c5
-rw-r--r--Src/subst.c16
-rw-r--r--Src/utils.c30
-rw-r--r--Src/zsh.h45
-rw-r--r--Src/zsh_system.h4
24 files changed, 730 insertions, 274 deletions
diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk
index 418206a66..bf914814d 100644
--- a/Src/Builtins/rlimits.awk
+++ b/Src/Builtins/rlimits.awk
@@ -42,6 +42,7 @@ BEGIN {limidx = 0}
if (limnam == "MEMLOCK") { msg[limnum] = "Mmemorylocked" }
if (limnam == "NOFILE") { msg[limnum] = "Ndescriptors" }
if (limnam == "NPROC") { msg[limnum] = "Nmaxproc" }
+ if (limnam == "NTHR") { msg[limnum] = "Nmaxthr" }
if (limnam == "OFILE") { msg[limnum] = "Ndescriptors" }
if (limnam == "PTHREAD") { msg[limnum] = "Nmaxpthreads" }
if (limnam == "RSS") { msg[limnum] = "Mresident" }
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 670516169..eedfa969c 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -238,32 +238,32 @@ printulimit(char *nam, int lim, int hard, int head)
switch (lim) {
case RLIMIT_CORE:
if (head)
- printf("-c: core file size (blocks) ");
+ printf("-c: core file size (blocks) ");
if (limit != RLIM_INFINITY)
limit /= 512;
break;
case RLIMIT_DATA:
if (head)
- printf("-d: data seg size (kbytes) ");
+ printf("-d: data seg size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
case RLIMIT_FSIZE:
if (head)
- printf("-f: file size (blocks) ");
+ printf("-f: file size (blocks) ");
if (limit != RLIM_INFINITY)
limit /= 512;
break;
# ifdef HAVE_RLIMIT_SIGPENDING
case RLIMIT_SIGPENDING:
if (head)
- printf("-i: pending signals ");
+ printf("-i: pending signals ");
break;
# endif
# ifdef HAVE_RLIMIT_MEMLOCK
case RLIMIT_MEMLOCK:
if (head)
- printf("-l: locked-in-memory size (kb) ");
+ printf("-l: locked-in-memory size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -273,7 +273,7 @@ printulimit(char *nam, int lim, int hard, int head)
# if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS) && !defined(RLIMIT_RSS_IS_AS)
case RLIMIT_RSS:
if (head)
- printf("-m: resident set size (kbytes) ");
+ printf("-m: resident set size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -281,7 +281,7 @@ printulimit(char *nam, int lim, int hard, int head)
# if defined(HAVE_RLIMIT_VMEM) && defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS)
case RLIMIT_VMEM:
if (head)
- printf("-m: memory size (kb) ");
+ printf("-m: memory size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -289,35 +289,41 @@ printulimit(char *nam, int lim, int hard, int head)
# ifdef HAVE_RLIMIT_NOFILE
case RLIMIT_NOFILE:
if (head)
- printf("-n: file descriptors ");
+ printf("-n: file descriptors ");
break;
# endif /* HAVE_RLIMIT_NOFILE */
# ifdef HAVE_RLIMIT_MSGQUEUE
case RLIMIT_MSGQUEUE:
if (head)
- printf("-q: bytes in POSIX msg queues ");
+ printf("-q: bytes in POSIX msg queues ");
break;
# endif
case RLIMIT_STACK:
if (head)
- printf("-s: stack size (kbytes) ");
+ printf("-s: stack size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
case RLIMIT_CPU:
if (head)
- printf("-t: cpu time (seconds) ");
+ printf("-t: cpu time (seconds) ");
break;
# ifdef HAVE_RLIMIT_NPROC
case RLIMIT_NPROC:
if (head)
- printf("-u: processes ");
+ printf("-u: processes ");
break;
# endif /* HAVE_RLIMIT_NPROC */
+# ifdef HAVE_RLIMIT_NTHR
+ case RLIMIT_NTHR:
+ if (head)
+ printf("-r: threads ");
+ break;
+#endif /* HAVE_RLIMIT_NTHR */
# if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS))
case RLIMIT_VMEM:
if (head)
- printf("-v: virtual memory size (kb) ");
+ printf("-v: virtual memory size (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -325,7 +331,7 @@ printulimit(char *nam, int lim, int hard, int head)
# if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS)
case RLIMIT_AS:
if (head)
- printf("-v: address space (kb) ");
+ printf("-v: address space (kbytes) ");
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -333,13 +339,13 @@ printulimit(char *nam, int lim, int hard, int head)
# ifdef HAVE_RLIMIT_LOCKS
case RLIMIT_LOCKS:
if (head)
- printf("-x: file locks ");
+ printf("-x: file locks ");
break;
# endif /* HAVE_RLIMIT_LOCKS */
# ifdef HAVE_RLIMIT_AIO_MEM
case RLIMIT_AIO_MEM:
if (head)
- printf("-N %2d: AIO locked-in-memory (kb) ", RLIMIT_AIO_MEM);
+ printf("-N %2d: AIO locked-in-memory (kbytes)", RLIMIT_AIO_MEM);
if (limit != RLIM_INFINITY)
limit /= 1024;
break;
@@ -347,44 +353,42 @@ printulimit(char *nam, int lim, int hard, int head)
# ifdef HAVE_RLIMIT_AIO_OPS
case RLIMIT_AIO_OPS:
if (head)
- printf("-N %2d: AIO operations ", RLIMIT_AIO_OPS);
+ printf("-N %2d: AIO operations ", RLIMIT_AIO_OPS);
break;
# endif /* HAVE_RLIMIT_AIO_OPS */
# ifdef HAVE_RLIMIT_TCACHE
case RLIMIT_TCACHE:
if (head)
- printf("-N %2d: cached threads ", RLIMIT_TCACHE);
+ printf("-N %2d: cached threads ", RLIMIT_TCACHE);
break;
# endif /* HAVE_RLIMIT_TCACHE */
# ifdef HAVE_RLIMIT_SBSIZE
case RLIMIT_SBSIZE:
if (head)
- printf("-N %2d: socket buffer size (kb) ", RLIMIT_SBSIZE);
- if (limit != RLIM_INFINITY)
- limit /= 1024;
+ printf("-b: socket buffer size (bytes) ", RLIMIT_SBSIZE);
break;
# endif /* HAVE_RLIMIT_SBSIZE */
# ifdef HAVE_RLIMIT_PTHREAD
case RLIMIT_PTHREAD:
if (head)
- printf("-N %2d: threads per process ", RLIMIT_PTHREAD);
+ printf("-N %2d: threads per process ", RLIMIT_PTHREAD);
break;
# endif /* HAVE_RLIMIT_PTHREAD */
# ifdef HAVE_RLIMIT_NICE
case RLIMIT_NICE:
if (head)
- printf("-e: max nice ");
+ printf("-e: max nice ");
break;
# endif /* HAVE_RLIMIT_NICE */
# ifdef HAVE_RLIMIT_RTPRIO
case RLIMIT_RTPRIO:
if (head)
- printf("-r: max rt priority ");
+ printf("-r: max rt priority ");
break;
# endif /* HAVE_RLIMIT_RTPRIO */
default:
if (head)
- printf("-N %2d: ", lim);
+ printf("-N %2d: ", lim);
break;
}
/* display the limit */
@@ -776,21 +780,31 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
case 'c':
res = RLIMIT_CORE;
break;
-# ifdef HAVE_RLIMIT_RSS
- case 'm':
- res = RLIMIT_RSS;
+# ifdef HAVE_RLIMIT_SBSIZE
+ case 'b':
+ res = RLIMIT_SBSIZE;
break;
-# endif /* HAVE_RLIMIT_RSS */
+# endif /* HAVE_RLIMIT_SBSIZE */
# ifdef HAVE_RLIMIT_MEMLOCK
case 'l':
res = RLIMIT_MEMLOCK;
break;
# endif /* HAVE_RLIMIT_MEMLOCK */
+# ifdef HAVE_RLIMIT_RSS
+ case 'm':
+ res = RLIMIT_RSS;
+ break;
+# endif /* HAVE_RLIMIT_RSS */
# ifdef HAVE_RLIMIT_NOFILE
case 'n':
res = RLIMIT_NOFILE;
break;
# endif /* HAVE_RLIMIT_NOFILE */
+# ifdef HAVE_RLIMIT_NTHR
+ case 'r':
+ res = RLIMIT_NTHR;
+ break;
+# endif /* HAVE_RLIMIT_NTHR */
# ifdef HAVE_RLIMIT_NPROC
case 'u':
res = RLIMIT_NPROC;
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 4d29ba635..a029c9cb4 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -289,7 +289,7 @@ setfunction(char *name, char *val, int dis)
shf = (Shfunc) zshcalloc(sizeof(*shf));
shf->funcdef = dupeprog(prog, 0);
shf->node.flags = dis;
- shf->emulation = sticky_emulation;
+ shfunc_set_sticky(shf);
if (!strncmp(name, "TRAP", 4) &&
(sn = getsignum(name + 4)) != -1) {
@@ -771,7 +771,7 @@ setpmoption(Param pm, char *value)
zwarn("invalid value: %s", value);
else if (!(n = optlookup(pm->node.nam)))
zwarn("no such option: %s", pm->node.nam);
- else if (dosetopt(n, (value && strcmp(value, "off")), 0))
+ else if (dosetopt(n, (value && strcmp(value, "off")), 0, opts))
zwarn("can't change option: %s", pm->node.nam);
zsfree(value);
}
@@ -784,7 +784,7 @@ unsetpmoption(Param pm, UNUSED(int exp))
if (!(n = optlookup(pm->node.nam)))
zwarn("no such option: %s", pm->node.nam);
- else if (dosetopt(n, 0, 0))
+ else if (dosetopt(n, 0, 0, opts))
zwarn("can't change option: %s", pm->node.nam);
}
@@ -812,7 +812,7 @@ setpmoptions(UNUSED(Param pm), HashTable ht)
if (!val || (strcmp(val, "on") && strcmp(val, "off")))
zwarn("invalid value: %s", val);
else if (dosetopt(optlookup(hn->nam),
- (val && strcmp(val, "off")), 0))
+ (val && strcmp(val, "off")), 0, opts))
zwarn("can't change option: %s", hn->nam);
}
deleteparamtable(ht);
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index c3731c47b..e21e769bd 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -912,7 +912,7 @@ bin_bindkey_new(char *name, UNUSED(char *kmname), Keymap km, char **argv, UNUSED
if(argv[1]) {
km = openkeymap(argv[1]);
if(!km) {
- zwarnnam(name, "no such keymap `%s'", argv[0]);
+ zwarnnam(name, "no such keymap `%s'", argv[1]);
return 1;
}
} else
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 0e940bc21..d5f464c2c 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -679,7 +679,7 @@ vifindnextchar(char **args)
if ((vfindchar = vigetkey()) != ZLEEOF) {
vfinddir = 1;
tailadd = 0;
- return virepeatfind(args);
+ return vifindchar(0, args);
}
return 1;
}
@@ -691,7 +691,7 @@ vifindprevchar(char **args)
if ((vfindchar = vigetkey()) != ZLEEOF) {
vfinddir = -1;
tailadd = 0;
- return virepeatfind(args);
+ return vifindchar(0, args);
}
return 1;
}
@@ -703,7 +703,7 @@ vifindnextcharskip(char **args)
if ((vfindchar = vigetkey()) != ZLEEOF) {
vfinddir = 1;
tailadd = -1;
- return virepeatfind(args);
+ return vifindchar(0, args);
}
return 1;
}
@@ -715,14 +715,14 @@ vifindprevcharskip(char **args)
if ((vfindchar = vigetkey()) != ZLEEOF) {
vfinddir = -1;
tailadd = 1;
- return virepeatfind(args);
+ return vifindchar(0, args);
}
return 1;
}
/**/
int
-virepeatfind(char **args)
+vifindchar(int repeat, char **args)
{
int ocs = zlecs, n = zmult;
@@ -735,6 +735,16 @@ virepeatfind(char **args)
zmult = n;
return ret;
}
+ if (repeat && tailadd != 0) {
+ if (vfinddir > 0) {
+ if(zlecs < zlell && (ZLE_INT_T)zleline[zlecs+1] == vfindchar)
+ INCCS();
+ }
+ else {
+ if(zlecs > 0 && (ZLE_INT_T)zleline[zlecs-1] == vfindchar)
+ DECCS();
+ }
+ }
while (n--) {
do {
if (vfinddir > 0)
@@ -760,19 +770,28 @@ virepeatfind(char **args)
/**/
int
+virepeatfind(char **args)
+{
+ return vifindchar(1, args);
+}
+
+/**/
+int
virevrepeatfind(char **args)
{
int ret;
if (zmult < 0) {
zmult = -zmult;
- ret = virepeatfind(args);
+ ret = vifindchar(1, args);
zmult = -zmult;
return ret;
}
+ tailadd = -tailadd;
vfinddir = -vfinddir;
- ret = virepeatfind(args);
+ ret = vifindchar(1, args);
vfinddir = -vfinddir;
+ tailadd = -tailadd;
return ret;
}
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 6fa887a1e..78a9fa490 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1071,7 +1071,8 @@ has_real_token(const char *s)
static char *
get_comp_string(void)
{
- int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct, varq = 0;
+ enum lextok t0, tt0;
+ int i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct, varq = 0;
int ona = noaliases;
/*
* Index of word being considered
@@ -1152,7 +1153,8 @@ get_comp_string(void)
lexflags = LEXFLAGS_ZLE;
inpush(dupstrspace(linptr), 0, NULL);
strinbeg(0);
- wordpos = tt0 = cp = rd = ins = oins = linarr = parct = ia = redirpos = 0;
+ wordpos = cp = rd = ins = oins = linarr = parct = ia = redirpos = 0;
+ tt0 = NULLTOK;
/* This loop is possibly the wrong way to do this. It goes through *
* the previously massaged command line using the lexer. It stores *
@@ -1238,7 +1240,8 @@ get_comp_string(void)
if (tt)
break;
/* Otherwise reset the variables we are collecting data in. */
- wordpos = tt0 = cp = rd = ins = redirpos = 0;
+ wordpos = cp = rd = ins = redirpos = 0;
+ tt0 = NULLTOK;
}
if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
tok == SELECT || tok == REPEAT || tok == CASE)) {
@@ -1251,7 +1254,7 @@ get_comp_string(void)
if (wordpos != redirpos)
wordpos = redirpos = 0;
}
- if (!lexflags && !tt0) {
+ if (!lexflags && tt0 == NULLTOK) {
/* This is done when the lexer reached the word the cursor is on. */
tt = tokstr ? dupstring(tokstr) : NULL;
@@ -1352,7 +1355,7 @@ get_comp_string(void)
(sl - 1) : (zlemetacs_qsub - wb)]);
}
} while (tok != LEXERR && tok != ENDINPUT &&
- (tok != SEPER || (lexflags && !tt0)));
+ (tok != SEPER || (lexflags && tt0 == NULLTOK)));
/* Calculate the number of words stored in the clwords array. */
clwnum = (tt || !wordpos) ? wordpos : wordpos - 1;
zsfree(clwords[clwnum]);
@@ -1388,7 +1391,7 @@ get_comp_string(void)
if (inwhat == IN_MATH)
s = NULL;
- else if (!t0 || t0 == ENDINPUT) {
+ else if (t0 == NULLTOK || t0 == ENDINPUT) {
/* There was no word (empty line). */
s = ztrdup("");
we = wb = zlemetacs;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index cf6787f3a..d0e7b5542 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1363,6 +1363,10 @@ static struct change *nextchanges, *endnextchanges;
static zlong undo_changeno;
+/* If non-zero, the last increment to undo_changeno was for the variable */
+
+static int undo_set_by_variable;
+
/**/
void
initundo(void)
@@ -1373,6 +1377,7 @@ initundo(void)
curchange->del = curchange->ins = NULL;
curchange->dell = curchange->insl = 0;
curchange->changeno = undo_changeno = 0;
+ undo_set_by_variable = 0;
lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE);
ZS_memcpy(lastline, zleline, (lastll = zlell));
lastcs = zlecs;
@@ -1498,6 +1503,7 @@ mkundoent(void)
ch->prev = NULL;
}
ch->changeno = ++undo_changeno;
+ undo_set_by_variable = 0;
endnextchanges = ch;
}
@@ -1520,23 +1526,25 @@ setlastline(void)
int
undo(char **args)
{
- zlong last_change = (zlong)0;
+ zlong last_change;
if (*args)
- {
last_change = zstrtol(*args, NULL, 0);
- }
+ else
+ last_change = (zlong)-1;
handleundo();
do {
- if(!curchange->prev)
+ struct change *prev = curchange->prev;
+ if(!prev)
return 1;
- if (unapplychange(curchange->prev))
- curchange = curchange->prev;
+ if (prev->changeno < last_change)
+ break;
+ if (unapplychange(prev))
+ curchange = prev;
else
break;
- } while (*args ? curchange->changeno != last_change :
- (curchange->flags & CH_PREV));
+ } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
setlastline();
return 0;
}
@@ -1660,6 +1668,16 @@ zlecallhook(char *name, char *arg)
zlong
get_undo_current_change(UNUSED(Param pm))
{
- return undo_changeno;
+ if (undo_set_by_variable) {
+ /* We were the last to increment this, doesn't need another one. */
+ return undo_changeno;
+ }
+ undo_set_by_variable = 1;
+ /*
+ * Increment the number in case a change is in progress;
+ * we don't want to back off what's already been done when
+ * we return to this change number. This eliminates any
+ * problem about the point where a change is numbered.
+ */
+ return ++undo_changeno;
}
-
diff --git a/Src/builtin.c b/Src/builtin.c
index b5a98cbd2..90fe1a6c5 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -46,7 +46,7 @@ static struct builtin builtins[] =
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL),
- BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "ktUwXz", "u"),
+ BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "mktTUwXz", "u"),
BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL),
BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
@@ -72,7 +72,7 @@ static struct builtin builtins[] =
BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlmnpPrRt:W", NULL),
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"),
- BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtuUz", NULL),
+ BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUz", NULL),
BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL),
@@ -548,8 +548,8 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
/* Obsolescent sh compatibility: set - is the same as set +xv *
* and set - args is the same as set +xv -- args */
if (!EMULATION(EMULATE_ZSH) && *args && **args == '-' && !args[0][1]) {
- dosetopt(VERBOSE, 0, 0);
- dosetopt(XTRACE, 0, 0);
+ dosetopt(VERBOSE, 0, 0, opts);
+ dosetopt(XTRACE, 0, 0, opts);
if (!args[1])
return 0;
}
@@ -580,7 +580,7 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
}
if(!(optno = optlookup(*args)))
zerrnam(nam, "no such option: %s", *args);
- else if(dosetopt(optno, action, 0))
+ else if(dosetopt(optno, action, 0, opts))
zerrnam(nam, "can't change option: %s", *args);
break;
} else if(**args == 'A') {
@@ -601,7 +601,7 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
else {
if (!(optno = optlookupc(**args)))
zerrnam(nam, "bad option: -%c", **args);
- else if(dosetopt(optno, action, 0))
+ else if(dosetopt(optno, action, 0, opts))
zerrnam(nam, "can't change option: -%c", **args);
}
}
@@ -1414,6 +1414,12 @@ bin_fc(char *nam, char **argv, Options ops, int func)
unqueue_signals();
return 0;
}
+
+ if (zleactive) {
+ zwarnnam(nam, "no interactive history within ZLE");
+ return 1;
+ }
+
/* put foo=bar type arguments into the substitution list */
while (*argv && equalsplit(*argv, &s)) {
Asgment a = (Asgment) zhalloc(sizeof *a);
@@ -1727,8 +1733,12 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
if (f == stdout) {
nicezputs(s, f);
putc('\n', f);
- } else
- fprintf(f, "%s\n", s);
+ } else {
+ int len;
+ unmetafy(s, &len);
+ fwrite(s, 1, len, f);
+ putc('\n', f);
+ }
}
/* move on to the next history line, or quit the loop */
if (first < last) {
@@ -2449,7 +2459,20 @@ bin_typeset(char *name, char **argv, Options ops, int func)
&& (locallevel == pm->level || !(on & PM_LOCAL))) {
if (pm->node.flags & PM_TIED) {
unqueue_signals();
- zerrnam(name, "can't tie already tied scalar: %s", asg0.name);
+ if (!strcmp(asg->name, pm->ename)) {
+ /*
+ * Already tied in the fashion requested.
+ */
+ struct tieddata *tdp = (struct tieddata*)pm->u.data;
+ /* Update join character */
+ tdp->joinchar = joinchar;
+ if (asg0.value)
+ setsparam(asg0.name, ztrdup(asg0.value));
+ return 0;
+ } else {
+ zerrnam(name, "can't tie already tied scalar: %s",
+ asg0.name);
+ }
return 1;
}
if (!asg0.value && !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
@@ -2672,6 +2695,10 @@ bin_functions(char *name, char **argv, Options ops, int func)
on |= PM_TAGGED;
else if (OPT_PLUS(ops,'t'))
off |= PM_TAGGED;
+ if (OPT_MINUS(ops,'T'))
+ on |= PM_TAGGED_LOCAL;
+ else if (OPT_PLUS(ops,'T'))
+ off |= PM_TAGGED_LOCAL;
if (OPT_MINUS(ops,'z')) {
on |= PM_ZSHSTORED;
off |= PM_KSHSTORED;
@@ -2861,7 +2888,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
/* with no options, just print all functions matching the glob pattern */
queue_signals();
- if (!(on|off)) {
+ if (!(on|off) && !OPT_ISSET(ops,'X')) {
scanmatchtable(shfunctab, pprog, 1, 0, DISABLED,
shfunctab->printnode, pflags);
} else {
@@ -2923,8 +2950,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
shf = (Shfunc) zshcalloc(sizeof *shf);
shf->node.flags = on;
shf->funcdef = mkautofn(shf);
- /* No sticky emulation for autoloaded functions */
- shf->emulation = 0;
+ shfunc_set_sticky(shf);
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
if (signum != -1) {
@@ -4987,11 +5013,15 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
{
int opt_L = OPT_ISSET(ops, 'L');
int opt_R = OPT_ISSET(ops, 'R');
- int saveemulation, savesticky_emulation, savehackchar;
- int ret = 1;
- char saveopts[OPT_SIZE];
+ int saveemulation, savehackchar;
+ int ret = 1, new_emulation;
+ char saveopts[OPT_SIZE], new_opts[OPT_SIZE];
char *cmd = 0;
const char *shname = *argv;
+ LinkList optlist;
+ LinkNode optnode;
+ Emulation_options save_sticky;
+ OptIndex *on_ptr, *off_ptr;
/* without arguments just print current emulation */
if (!shname) {
@@ -5024,7 +5054,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
/* with single argument set current emulation */
if (!argv[1]) {
- emulate(shname, OPT_ISSET(ops,'R'));
+ emulate(shname, OPT_ISSET(ops,'R'), &emulation, opts);
if (OPT_ISSET(ops,'L'))
opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
return 0;
@@ -5032,8 +5062,14 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
argv++;
memcpy(saveopts, opts, sizeof(opts));
+ memcpy(new_opts, opts, sizeof(opts));
savehackchar = keyboardhackchar;
- cmd = parseopts("emulate", &argv);
+ emulate(shname, OPT_ISSET(ops,'R'), &new_emulation, new_opts);
+ optlist = newlinklist();
+ if (parseopts("emulate", &argv, new_opts, &cmd, optlist)) {
+ ret = 1;
+ goto restore;
+ }
/* parseopts() has consumed anything that looks like an option */
if (*argv) {
@@ -5041,6 +5077,9 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
goto restore;
}
+ saveemulation = emulation;
+ emulation = new_emulation;
+ memcpy(opts, new_opts, sizeof(opts));
/* If "-c command" is given, evaluate command using specified
* emulation mode.
*/
@@ -5053,15 +5092,41 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
} else
return 0;
- saveemulation = emulation;
- savesticky_emulation = sticky_emulation;
- emulate(shname, OPT_ISSET(ops,'R'));
- sticky_emulation = emulation;
+ save_sticky = sticky;
+ sticky = hcalloc(sizeof(*sticky));
+ sticky->emulation = emulation;
+ for (optnode = firstnode(optlist); optnode; incnode(optnode)) {
+ /* Data is index into new_opts */
+ char *optptr = (char *)getdata(optnode);
+ if (*optptr)
+ sticky->n_on_opts++;
+ else
+ sticky->n_off_opts++;
+ }
+ if (sticky->n_on_opts)
+ on_ptr = sticky->on_opts =
+ zhalloc(sticky->n_on_opts * sizeof(*sticky->on_opts));
+ else
+ on_ptr = NULL;
+ if (sticky->n_off_opts)
+ off_ptr = sticky->off_opts = zhalloc(sticky->n_off_opts *
+ sizeof(*sticky->off_opts));
+ else
+ off_ptr = NULL;
+ for (optnode = firstnode(optlist); optnode; incnode(optnode)) {
+ /* Data is index into new_opts */
+ char *optptr = (char *)getdata(optnode);
+ int optno = optptr - new_opts;
+ if (*optptr)
+ *on_ptr++ = optno;
+ else
+ *off_ptr++ = optno;
+ }
ret = eval(argv);
- sticky_emulation = savesticky_emulation;
+ sticky = save_sticky;
emulation = saveemulation;
- restore:
memcpy(opts, saveopts, sizeof(opts));
+restore:
keyboardhackchar = savehackchar;
inittyptab(); /* restore banghist */
return ret;
diff --git a/Src/compat.c b/Src/compat.c
index e36de3219..cc4e876da 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -630,7 +630,7 @@ strtoul(nptr, endptr, base)
#endif /* HAVE_STRTOUL */
/**/
-#ifdef BROKEN_WCWIDTH
+#if defined(BROKEN_WCWIDTH) && (defined(__STDC_ISO_10646__) || defined(__APPLE__))
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
@@ -949,5 +949,5 @@ int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
#endif /* 0 */
/**/
-#endif /* BROKEN_WCWIDTH */
+#endif /* BROKEN_WCWIDTH && (__STDC_ISO_10646__ || __APPLE__) */
diff --git a/Src/exec.c b/Src/exec.c
index 6ebc9c014..1ecbc3967 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -404,7 +404,17 @@ execcursh(Estate state, int do_exec)
/* Skip word only used for try/always */
state->pc++;
- if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob))
+ /*
+ * The test thisjob != -1 was added because sometimes thisjob
+ * can be invalid at this point. The case in question was
+ * in a precmd function after operations involving background
+ * jobs.
+ *
+ * This is because sometimes we bypass job control to execute
+ * very simple functions via execssimple().
+ */
+ if (!list_pipe && thisjob != -1 && thisjob != list_pipe_job &&
+ !hasprocs(thisjob))
deletejob(jobtab + thisjob, 0);
cmdpush(CS_CURSH);
execlist(state, 1, do_exec);
@@ -1064,7 +1074,7 @@ static int
execsimple(Estate state)
{
wordcode code = *state->pc++;
- int lv;
+ int lv, otj;
if (errflag)
return (lastval = 1);
@@ -1075,6 +1085,13 @@ execsimple(Estate state)
code = wc_code(*state->pc++);
+ /*
+ * Because we're bypassing job control, ensure the called
+ * code doesn't see the current job.
+ */
+ otj = thisjob;
+ thisjob = -1;
+
if (code == WC_ASSIGN) {
cmdoutval = 0;
addvars(state, state->pc - 1, 0);
@@ -1086,6 +1103,8 @@ execsimple(Estate state)
} else
lv = (execfuncs[code - WC_CURSH])(state, 0);
+ thisjob = otj;
+
return lastval = lv;
}
@@ -1188,6 +1207,9 @@ execlist(Estate state, int dont_change_job, int exiting)
} else
donedebug = intrap ? 1 : 0;
+ /* Reset donetrap: this ensures that a trap is only *
+ * called once for each sublist that fails. */
+ donetrap = 0;
if (ltype & Z_SIMPLE) {
next = state->pc + WC_LIST_SKIP(code);
if (donedebug != 2)
@@ -1195,9 +1217,6 @@ execlist(Estate state, int dont_change_job, int exiting)
state->pc = next;
goto sublist_done;
}
- /* Reset donetrap: this ensures that a trap is only *
- * called once for each sublist that fails. */
- donetrap = 0;
/* Loop through code followed by &&, ||, or end of sublist. */
code = *state->pc++;
@@ -4248,7 +4267,7 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shf->node.flags = 0;
shf->filename = ztrdup(scriptfilename);
shf->lineno = lineno;
- shf->emulation = sticky_emulation;
+ shfunc_set_sticky(shf);
if (!names) {
/*
@@ -4300,6 +4319,46 @@ execfuncdef(Estate state, UNUSED(int do_exec))
return ret;
}
+/* Duplicate a sticky emulation */
+
+/**/
+
+mod_export Emulation_options
+sticky_emulation_dup(Emulation_options src, int useheap)
+{
+ Emulation_options newsticky = useheap ?
+ hcalloc(sizeof(*src)) : zshcalloc(sizeof(*src));
+ newsticky->emulation = src->emulation;
+ if (src->n_on_opts) {
+ size_t sz = src->n_on_opts * sizeof(*src->on_opts);
+ newsticky->n_on_opts = src->n_on_opts;
+ newsticky->on_opts = useheap ? zhalloc(sz) : zalloc(sz);
+ memcpy(newsticky->on_opts, src->on_opts, sz);
+ }
+ if (src->n_off_opts) {
+ size_t sz = src->n_off_opts * sizeof(*src->off_opts);
+ newsticky->n_off_opts = src->n_off_opts;
+ newsticky->off_opts = useheap ? zhalloc(sz) : zalloc(sz);
+ memcpy(newsticky->off_opts, src->off_opts, sz);
+ }
+
+ return newsticky;
+}
+
+/* Set the sticky emulation attributes for a shell function */
+
+/**/
+
+mod_export void
+shfunc_set_sticky(Shfunc shf)
+{
+ if (sticky)
+ shf->sticky = sticky_emulation_dup(sticky, 0);
+ else
+ shf->sticky = NULL;
+}
+
+
/* Main entry point to execute a shell function. */
/**/
@@ -4313,7 +4372,9 @@ execshfunc(Shfunc shf, LinkList args)
if (errflag)
return;
- if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) {
+ /* thisjob may be invalid if we're called via execsimple: see execcursh */
+ if (!list_pipe && thisjob != -1 && thisjob != list_pipe_job &&
+ !hasprocs(thisjob)) {
/* Without this deletejob the process table *
* would be filled by a recursive function. */
last_file_list = jobtab[thisjob].filelist;
@@ -4458,6 +4519,45 @@ loadautofn(Shfunc shf, int fksh, int autol)
}
/*
+ * Check if a sticky emulation differs from the current one.
+ */
+
+/**/
+
+int sticky_emulation_differs(Emulation_options sticky2)
+{
+ /* If no new sticky emulation, not a different emulation */
+ if (!sticky2)
+ return 0;
+ /* If no current sticky emulation, different */
+ if (!sticky)
+ return 1;
+ /* If basic emulation different, different */
+ if (sticky->emulation != sticky2->emulation)
+ return 1;
+ /* If differing numbers of options, different */
+ if (sticky->n_on_opts != sticky2->n_on_opts ||
+ sticky->n_off_opts != sticky2->n_off_opts)
+ return 1;
+ /*
+ * We need to compare option arrays, if non-null.
+ * We made parseopts() create the list of options in option
+ * order to make this easy.
+ */
+ /* If different options turned on, different */
+ if (sticky->n_on_opts &&
+ memcmp(sticky->on_opts, sticky2->on_opts,
+ sticky->n_on_opts * sizeof(*sticky->on_opts)) != 0)
+ return 1;
+ /* If different options turned on, different */
+ if (sticky->n_off_opts &&
+ memcmp(sticky->off_opts, sticky2->off_opts,
+ sticky->n_off_opts * sizeof(*sticky->off_opts)) != 0)
+ return 1;
+ return 0;
+}
+
+/*
* execute a shell function
*
* name is the name of the function
@@ -4484,11 +4584,13 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
int *oldpipestats = NULL;
char saveopts[OPT_SIZE], *oldscriptname = scriptname;
char *name = shfunc->node.nam;
- int flags = shfunc->node.flags;
+ int flags = shfunc->node.flags, ooflags;
char *fname = dupstring(name);
- int obreaks, saveemulation, savesticky_emulation, restore_sticky;
+ int obreaks, saveemulation, restore_sticky;
Eprog prog;
struct funcstack fstack;
+ static int oflags;
+ Emulation_options save_sticky = NULL;
#ifdef MAX_FUNCTION_DEPTH
static int funcdepth;
#endif
@@ -4526,9 +4628,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
* function we need to restore the original options on exit. */
memcpy(saveopts, opts, sizeof(opts));
saveemulation = emulation;
- savesticky_emulation = sticky_emulation;
+ save_sticky = sticky;
- if (shfunc->emulation && sticky_emulation != shfunc->emulation) {
+ if (sticky_emulation_differs(shfunc->sticky)) {
/*
* Function is marked for sticky emulation.
* Enable it now.
@@ -4541,14 +4643,38 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
*
* This propagates the sticky emulation to subfunctions.
*/
- emulation = sticky_emulation = shfunc->emulation;
+ sticky = sticky_emulation_dup(shfunc->sticky, 1);
+ emulation = sticky->emulation;
restore_sticky = 1;
- installemulation();
+ installemulation(emulation, opts);
+ if (sticky->n_on_opts) {
+ OptIndex *onptr;
+ for (onptr = sticky->on_opts;
+ onptr < sticky->on_opts + sticky->n_on_opts;
+ onptr++)
+ opts[*onptr] = 1;
+ }
+ if (sticky->n_off_opts) {
+ OptIndex *offptr;
+ for (offptr = sticky->off_opts;
+ offptr < sticky->off_opts + sticky->n_off_opts;
+ offptr++)
+ opts[*offptr] = 0;
+ }
} else
restore_sticky = 0;
- if (flags & PM_TAGGED)
+ if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
opts[XTRACE] = 1;
+ else if (oflags & PM_TAGGED_LOCAL)
+ opts[XTRACE] = 0;
+ ooflags = oflags;
+ /*
+ * oflags is static, because we compare it on the next recursive
+ * call. Hence also we maintain ooflags for restoring the previous
+ * value of oflags after the call.
+ */
+ oflags = flags;
opts[PRINTEXITVALUE] = 0;
if (doshargs) {
LinkNode node;
@@ -4633,6 +4759,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
optcind = oldoptcind;
zoptind = oldzoptind;
scriptname = oldscriptname;
+ oflags = ooflags;
if (restore_sticky) {
/*
@@ -4642,7 +4769,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
*/
memcpy(opts, saveopts, sizeof(opts));
emulation = saveemulation;
- sticky_emulation = savesticky_emulation;
+ sticky = save_sticky;
} else if (isset(LOCALOPTIONS)) {
/* restore all shell options except PRIVILEGED and RESTRICTED */
saveopts[PRIVILEGED] = opts[PRIVILEGED];
diff --git a/Src/hashtable.c b/Src/hashtable.c
index be71a1cc9..ef187927b 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -888,6 +888,15 @@ freeshfuncnode(HashNode hn)
if (shf->funcdef)
freeeprog(shf->funcdef);
zsfree(shf->filename);
+ if (shf->sticky) {
+ if (shf->sticky->n_on_opts)
+ zfree(shf->sticky->on_opts,
+ shf->sticky->n_on_opts * sizeof(*shf->sticky->on_opts));
+ if (shf->sticky->n_off_opts)
+ zfree(shf->sticky->off_opts,
+ shf->sticky->n_off_opts * sizeof(*shf->sticky->off_opts));
+ zfree(shf->sticky, sizeof(*shf->sticky));
+ }
zfree(shf, sizeof(struct shfunc));
}
@@ -923,12 +932,13 @@ printshfuncnode(HashNode hn, int printflags)
printf("%c undefined\n\t", hashchar);
else
t = getpermtext(f->funcdef, NULL, 1);
- if (f->node.flags & PM_TAGGED)
+ if (f->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))
printf("%c traced\n\t", hashchar);
if (!t) {
- char *fopt = "Utkz";
+ char *fopt = "UtTkz";
int flgs[] = {
- PM_UNALIASED, PM_TAGGED, PM_KSHSTORED, PM_ZSHSTORED, 0
+ PM_UNALIASED, PM_TAGGED, PM_TAGGED_LOCAL,
+ PM_KSHSTORED, PM_ZSHSTORED, 0
};
int fl;;
diff --git a/Src/hist.c b/Src/hist.c
index 0e63dca37..561e2acd5 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -573,7 +573,7 @@ histsubchar(int c)
} else {
herrflush();
unqueue_signals();
- zerr("Ambiguous history reference");
+ zerr("ambiguous history reference");
return -1;
}
diff --git a/Src/init.c b/Src/init.c
index 6f14943e1..8467a739c 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -149,7 +149,7 @@ loop(int toplevel, int justonce)
continue;
}
if (hend(prog)) {
- int toksav = tok;
+ enum lextok toksav = tok;
non_empty = 1;
if (toplevel &&
@@ -246,7 +246,8 @@ parseargs(char **argv, char **runscript)
opts[SHINSTDIN] = 0;
opts[SINGLECOMMAND] = 0;
- cmd = parseopts(NULL, &argv);
+ if (parseopts(NULL, &argv, opts, &cmd, NULL))
+ exit(1);
paramlist = znewlinklist();
if (*argv) {
@@ -276,18 +277,58 @@ parseargs(char **argv, char **runscript)
argzero = ztrdup(argzero);
}
+/* Insert into list in order of pointer value */
+
/**/
-mod_export char *
-parseopts(char *nam, char ***argvp)
+static void
+parseopts_insert(LinkList optlist, void *ptr)
+{
+ LinkNode node;
+
+ for (node = firstnode(optlist); node; incnode(node)) {
+ if (ptr < getdata(node)) {
+ insertlinknode(optlist, prevnode(node), ptr);
+ return;
+ }
+ }
+
+ addlinknode(optlist, ptr);
+}
+
+/*
+ * Parse shell options.
+ * If nam is not NULL, this is called from a command; don't
+ * exit on failure.
+ *
+ * If optlist is not NULL, it used to form a list of pointers
+ * into new_opts indicating which options have been changed.
+ */
+
+/**/
+mod_export int
+parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
+ LinkList optlist)
{
int optionbreak = 0;
int action, optno;
- char *cmd = 0; /* deliberately hides static */
char **argv = *argvp;
-#define WARN_OPTION(F, S) if (nam) zwarnnam(nam, F, S); else zerr(F, S)
-#define LAST_OPTION(N) \
- if (nam) { if (*argv) argv++; goto doneargv; } else exit(N)
+ *cmdp = 0;
+#define WARN_OPTION(F, S) \
+ do { \
+ if (nam) \
+ zwarnnam(nam, F, S); \
+ else \
+ zerr(F, S); \
+ } while (0)
+#define LAST_OPTION(N) \
+ do { \
+ if (nam) { \
+ if (*argv) \
+ argv++; \
+ goto doneargv; \
+ } else exit(N); \
+ } while(0)
/* loop through command line options (begins with "-" or "+") */
while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) {
@@ -327,26 +368,30 @@ parseopts(char *nam, char ***argvp)
optionbreak = 1;
} else if (**argv == 'c') {
/* -c command */
- cmd = *argv;
- opts[INTERACTIVE] &= 1;
+ *cmdp = *argv;
+ new_opts[INTERACTIVE] &= 1;
scriptname = scriptfilename = ztrdup("zsh");
} else if (**argv == 'o') {
if (!*++*argv)
argv++;
if (!*argv) {
WARN_OPTION("string expected after -o", NULL);
- LAST_OPTION(1);
+ return 1;
}
longoptions:
if (!(optno = optlookup(*argv))) {
WARN_OPTION("no such option: %s", *argv);
- LAST_OPTION(1);
+ return 1;
} else if (optno == RESTRICTED && !nam) {
restricted = action;
} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
WARN_OPTION("can't change option: %s", *argv);
- } else if (dosetopt(optno, action, !nam) && nam) {
- WARN_OPTION("can't change option: %s", *argv);
+ } else {
+ if (dosetopt(optno, action, !nam, new_opts) && nam) {
+ WARN_OPTION("can't change option: %s", *argv);
+ } else if (optlist) {
+ parseopts_insert(optlist, new_opts+optno);
+ }
}
break;
} else if (isspace(STOUC(**argv))) {
@@ -355,37 +400,41 @@ parseopts(char *nam, char ***argvp)
if (!isspace(STOUC(**argv))) {
badoptionstring:
WARN_OPTION("bad option string: '%s'", args);
- LAST_OPTION(1);
+ return 1;
}
break;
} else {
if (!(optno = optlookupc(**argv))) {
WARN_OPTION("bad option: -%c", **argv);
- LAST_OPTION(1);
+ return 1;
} else if (optno == RESTRICTED && !nam) {
restricted = action;
} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
WARN_OPTION("can't change option: %s", *argv);
- } else if (dosetopt(optno, action, !nam) && nam) {
- WARN_OPTION("can't change option: -%c", **argv);
+ } else {
+ if (dosetopt(optno, action, !nam, new_opts) && nam) {
+ WARN_OPTION("can't change option: -%c", **argv);
+ } else if (optlist) {
+ parseopts_insert(optlist, new_opts+optno);
+ }
}
}
}
argv++;
}
doneoptions:
- if (cmd) {
+ if (*cmdp) {
if (!*argv) {
- WARN_OPTION("string expected after -%s", cmd);
- LAST_OPTION(1);
+ WARN_OPTION("string expected after -%s", *cmdp);
+ return 1;
}
- cmd = *argv++;
+ *cmdp = *argv++;
}
doneargv:
*argvp = argv;
- return cmd;
+ return 0;
}
-
+
/**/
static void
printhelp(void)
@@ -1162,7 +1211,7 @@ init_misc(void)
#else
if (*zsh_name == 'r' || restricted)
#endif
- dosetopt(RESTRICTED, 1, 0);
+ dosetopt(RESTRICTED, 1, 0, opts);
if (cmd) {
if (SHIN >= 10)
fclose(bshin);
@@ -1225,7 +1274,7 @@ source(char *s)
subsh = 0;
lineno = 1;
loops = 0;
- dosetopt(SHINSTDIN, 0, 1);
+ dosetopt(SHINSTDIN, 0, 1, opts);
scriptname = s;
scriptfilename = s;
@@ -1297,7 +1346,7 @@ source(char *s)
thisjob = cj; /* current job number */
lineno = oldlineno; /* our current lineno */
loops = oloops; /* the # of nested loops we are in */
- dosetopt(SHINSTDIN, oldshst, 1); /* SHINSTDIN option */
+ dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option */
errflag = 0;
if (!exit_pending)
retflag = 0;
@@ -1535,7 +1584,7 @@ zsh_main(UNUSED(int argc), char **argv)
fdtable = zshcalloc(fdtable_size*sizeof(*fdtable));
createoptiontable();
- emulate(zsh_name, 1); /* initialises most options */
+ emulate(zsh_name, 1, &emulation, opts); /* initialises most options */
opts[LOGINSHELL] = (**argv == '-');
opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
opts[USEZLE] = 1; /* may be unset in init_io() */
@@ -1559,15 +1608,20 @@ zsh_main(UNUSED(int argc), char **argv)
* We only do this at top level, because if we are
* executing stuff we may refer to them by job pointer.
*/
+ int errexit = 0;
maybeshrinkjobtab();
do {
/* Reset return from top level which gets us back here */
retflag = 0;
loop(1,0);
+ if (errflag && !interact && !isset(CONTINUEONERROR)) {
+ errexit = 1;
+ break;
+ }
} while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN)));
- if (tok == LEXERR) {
- /* Make sure a parse error exits with non-zero status */
+ if (tok == LEXERR || errexit) {
+ /* Make sure a fatal error exits with non-zero status */
if (!lastval)
lastval = 1;
stopmsg = 1;
diff --git a/Src/jobs.c b/Src/jobs.c
index c9c549e1e..0dbb10b4f 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -209,7 +209,13 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux)
int
hasprocs(int job)
{
- Job jn = jobtab + job;
+ Job jn;
+
+ if (job < 0) {
+ DPUTS(1, "job number invalid in hasprocs");
+ return 0;
+ }
+ jn = jobtab + job;
return jn->procs || jn->auxprocs;
}
@@ -868,6 +874,8 @@ should_report_time(Job j)
/* can this ever happen? */
if (!j->procs)
return 0;
+ if (zleactive)
+ return 0;
#ifdef HAVE_GETRUSAGE
reporttime -= j->procs->ti.ru_utime.tv_sec + j->procs->ti.ru_stime.tv_sec;
@@ -1735,12 +1743,14 @@ init_jobs(char **argv, char **envp)
goto done;
p = strchr(q, 0);
}
+#if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
for(; *envp; envp++) {
q = *envp;
if(q != p+1)
goto done;
p = strchr(q, 0);
}
+#endif
done:
hackspace = p - hackzero;
#endif
diff --git a/Src/lex.c b/Src/lex.c
index 1cf3611c9..ac87e5ec8 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -42,7 +42,7 @@ char *zshlextext;
/**/
mod_export char *tokstr;
/**/
-mod_export int tok;
+mod_export enum lextok tok;
/**/
mod_export int tokfd;
@@ -207,7 +207,7 @@ struct lexstack {
int hlinesz;
char *hline;
char *hptr;
- int tok;
+ enum lextok tok;
int isnewlin;
char *tokstr;
char *zshlextext;
@@ -470,6 +470,10 @@ ctxtlex(void)
case DINBRACK:
incmdpos = 0;
break;
+
+ default:
+ /* nothing to do, keep compiler happy */
+ break;
}
if (tok != DINPAR)
infor = tok == FOR ? 2 : 0;
@@ -698,11 +702,12 @@ isnumglob(void)
}
/**/
-static int
+static enum lextok
gettok(void)
{
int c, d;
- int peekfd = -1, peek;
+ int peekfd = -1;
+ enum lextok peek;
beginning:
tokstr = NULL;
@@ -1007,12 +1012,13 @@ gettok(void)
*/
/**/
-static int
+static enum lextok
gettokstr(int c, int sub)
{
int bct = 0, pct = 0, brct = 0, fdpar = 0;
int intpos = 1, in_brace_param = 0;
- int peek, inquote, unmatched = 0;
+ int inquote, unmatched = 0;
+ enum lextok peek;
#ifdef DEBUG
int ocmdsp = cmdsp;
#endif
@@ -1259,51 +1265,53 @@ gettokstr(int c, int sub)
break;
goto brk;
case LX2_EQUALS:
- if (intpos) {
- e = hgetc();
- if (e != '(') {
- hungetc(e);
- lexstop = 0;
- c = Equals;
- } else {
- add(Equals);
- if (skipcomm()) {
- peek = LEXERR;
- goto brk;
- }
- c = Outpar;
- }
- } else if (!sub && peek != ENVSTRING &&
- incmdpos && !bct && !brct) {
- char *t = tokstr;
- if (idigit(*t))
- while (++t < bptr && idigit(*t));
- else {
- int sav = *bptr;
- *bptr = '\0';
- t = itype_end(t, IIDENT, 0);
- if (t < bptr) {
- skipparens(Inbrack, Outbrack, &t);
+ if (!sub) {
+ if (intpos) {
+ e = hgetc();
+ if (e != '(') {
+ hungetc(e);
+ lexstop = 0;
+ c = Equals;
} else {
- *bptr = sav;
+ add(Equals);
+ if (skipcomm()) {
+ peek = LEXERR;
+ goto brk;
+ }
+ c = Outpar;
}
- }
- if (*t == '+')
- t++;
- if (t == bptr) {
- e = hgetc();
- if (e == '(' && incmdpos) {
+ } else if (peek != ENVSTRING &&
+ incmdpos && !bct && !brct) {
+ char *t = tokstr;
+ if (idigit(*t))
+ while (++t < bptr && idigit(*t));
+ else {
+ int sav = *bptr;
*bptr = '\0';
- return ENVARRAY;
+ t = itype_end(t, IIDENT, 0);
+ if (t < bptr) {
+ skipparens(Inbrack, Outbrack, &t);
+ } else {
+ *bptr = sav;
+ }
}
- hungetc(e);
- lexstop = 0;
- peek = ENVSTRING;
- intpos = 2;
+ if (*t == '+')
+ t++;
+ if (t == bptr) {
+ e = hgetc();
+ if (e == '(' && incmdpos) {
+ *bptr = '\0';
+ return ENVARRAY;
+ }
+ hungetc(e);
+ lexstop = 0;
+ peek = ENVSTRING;
+ intpos = 2;
+ } else
+ c = Equals;
} else
c = Equals;
- } else
- c = Equals;
+ }
break;
case LX2_BKSLASH:
c = hgetc();
@@ -1692,6 +1700,7 @@ parse_subst_string(char *s)
{
int c, l = strlen(s), err;
char *ptr;
+ enum lextok ctok;
if (!*s || !strcmp(s, nulstring))
return 0;
@@ -1703,14 +1712,14 @@ parse_subst_string(char *s)
bptr = tokstr = s;
bsiz = l + 1;
c = hgetc();
- c = gettokstr(c, 1);
+ ctok = gettokstr(c, 1);
err = errflag;
strinend();
inpop();
DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
lexrestore();
errflag = err;
- if (c == LEXERR) {
+ if (ctok == LEXERR) {
untokenize(s);
return 1;
}
@@ -1720,9 +1729,9 @@ parse_subst_string(char *s)
* before lexrestore()) == l, but that's not necessarily the case if
* we stripped an RCQUOTE.
*/
- if (c != STRING || (errflag && !noerrs)) {
+ if (ctok != STRING || (errflag && !noerrs)) {
fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
- errflag ? "errflag" : "c != STRING");
+ errflag ? "errflag" : "ctok != STRING");
fflush(stderr);
untokenize(s);
return 1;
diff --git a/Src/math.c b/Src/math.c
index cca521098..e90d6a59a 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -447,12 +447,13 @@ lexconstant(void)
if (*nptr == '-')
nptr++;
- if (*nptr == '0')
+ if (*nptr == '0' &&
+ (memchr(nptr, '.', strlen(nptr)) == NULL))
{
nptr++;
if (*nptr == 'x' || *nptr == 'X') {
/* Let zstrtol parse number with base */
- yyval.u.l = zstrtol(ptr, &ptr, 0);
+ yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
/* Should we set lastbase here? */
lastbase = 16;
return NUM;
@@ -466,13 +467,13 @@ lexconstant(void)
* it can't be a base indication (always decimal)
* or a floating point number.
*/
- for (ptr2 = nptr; idigit(*ptr2); ptr2++)
+ for (ptr2 = nptr; idigit(*ptr2) || *ptr2 == '_'; ptr2++)
;
if (ptr2 > nptr && *ptr2 != '.' && *ptr2 != 'e' &&
*ptr2 != 'E' && *ptr2 != '#')
{
- yyval.u.l = zstrtol(ptr, &ptr, 0);
+ yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
lastbase = 8;
return NUM;
}
@@ -481,17 +482,43 @@ lexconstant(void)
}
else
{
- while (idigit(*nptr))
+ while (idigit(*nptr) || *nptr == '_')
nptr++;
}
if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
+ char *ptr2;
/* it's a float */
yyval.type = MN_FLOAT;
#ifdef USE_LOCALE
prev_locale = dupstring(setlocale(LC_NUMERIC, NULL));
setlocale(LC_NUMERIC, "POSIX");
#endif
+ if (*nptr == '.') {
+ nptr++;
+ while (idigit(*nptr) || *nptr == '_')
+ nptr++;
+ }
+ if (*nptr == 'e' || *nptr == 'E') {
+ nptr++;
+ if (*nptr == '+' || *nptr == '-')
+ nptr++;
+ while (idigit(*nptr) || *nptr == '_')
+ nptr++;
+ }
+ for (ptr2 = ptr; ptr2 < nptr; ptr2++) {
+ if (*ptr2 == '_') {
+ int len = nptr - ptr;
+ ptr = strdup(ptr);
+ for (ptr2 = ptr; len; len--) {
+ if (*ptr2 == '_')
+ chuck(ptr2);
+ else
+ ptr2++;
+ }
+ break;
+ }
+ }
yyval.u.d = strtod(ptr, &nptr);
#ifdef USE_LOCALE
if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
@@ -503,11 +530,12 @@ lexconstant(void)
ptr = nptr;
} else {
/* it's an integer */
- yyval.u.l = zstrtol(ptr, &ptr, 10);
+ yyval.u.l = zstrtol_underscore(ptr, &ptr, 10, 1);
if (*ptr == '#') {
ptr++;
- yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l);
+ lastbase = yyval.u.l;
+ yyval.u.l = zstrtol_underscore(ptr, &ptr, lastbase, 1);
}
}
return NUM;
@@ -1053,14 +1081,34 @@ op(int what)
return;
if (c.type == MN_FLOAT)
c.u.d = a.u.d / b.u.d;
- else
- c.u.l = a.u.l / b.u.l;
+ else {
+ /*
+ * Avoid exception when dividing the smallest
+ * negative integer by -1. Always treat it the
+ * same as multiplication. This still doesn't give
+ * numerically the right answer in two's complement,
+ * but treating both these in the same way seems
+ * reasonable.
+ */
+ if (b.u.l == -1)
+ c.u.l = - a.u.l;
+ else
+ c.u.l = a.u.l / b.u.l;
+ }
break;
case MOD:
case MODEQ:
if (!notzero(b))
return;
- c.u.l = a.u.l % b.u.l;
+ /*
+ * Avoid exception as above.
+ * Any integer mod -1 is the same as any integer mod 1
+ * i.e. zero.
+ */
+ if (b.u.l == -1)
+ c.u.l = 0;
+ else
+ c.u.l = a.u.l % b.u.l;
break;
case PLUS:
case PLUSEQ:
diff --git a/Src/options.c b/Src/options.c
index c6db75372..b36bd9944 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -35,21 +35,21 @@
/**/
mod_export int emulation;
-/* current sticky emulation: 0 means none */
+/* current sticky emulation: sticky = NULL means none */
/**/
-mod_export int sticky_emulation;
+mod_export Emulation_options sticky;
/* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */
-
+
/**/
mod_export char opts[OPT_SIZE];
-
+
/* Option name hash table */
/**/
mod_export HashTable optiontab;
-
+
/* The canonical option name table */
#define OPT_CSH EMULATE_CSH
@@ -70,7 +70,7 @@ mod_export HashTable optiontab;
/* option is an alias to an other option */
#define OPT_ALIAS (EMULATE_UNUSED<<2)
-#define defset(X) (!!((X)->node.flags & emulation))
+#define defset(X, my_emulation) (!!((X)->node.flags & my_emulation))
/*
* Note that option names should usually be fewer than 20 characters long
@@ -113,6 +113,7 @@ static struct optname optns[] = {
{{NULL, "combiningchars", 0}, COMBININGCHARS},
{{NULL, "completealiases", 0}, COMPLETEALIASES},
{{NULL, "completeinword", 0}, COMPLETEINWORD},
+{{NULL, "continueonerror", 0}, CONTINUEONERROR},
{{NULL, "correct", 0}, CORRECT},
{{NULL, "correctall", 0}, CORRECTALL},
{{NULL, "cshjunkiehistory", OPT_EMULATE|OPT_CSH}, CSHJUNKIEHISTORY},
@@ -160,7 +161,7 @@ static struct optname optns[] = {
{{NULL, "histverify", 0}, HISTVERIFY},
{{NULL, "hup", OPT_EMULATE|OPT_ZSH}, HUP},
{{NULL, "ignorebraces", OPT_EMULATE|OPT_SH}, IGNOREBRACES},
-{{NULL, "ignoreclosebraces", 0}, IGNORECLOSEBRACES},
+{{NULL, "ignoreclosebraces", OPT_EMULATE}, IGNORECLOSEBRACES},
{{NULL, "ignoreeof", 0}, IGNOREEOF},
{{NULL, "incappendhistory", 0}, INCAPPENDHISTORY},
{{NULL, "interactive", OPT_SPECIAL}, INTERACTIVE},
@@ -439,11 +440,11 @@ printoptionnode(HashNode hn, int set)
if (optno < 0)
optno = -optno;
if (isset(KSHOPTIONPRINT)) {
- if (defset(on))
+ if (defset(on, emulation))
printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
else
printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
- } else if (set == (isset(optno) ^ defset(on))) {
+ } else if (set == (isset(optno) ^ defset(on, emulation))) {
if (set ^ isset(optno))
fputs("no", stdout);
puts(on->node.nam);
@@ -475,6 +476,15 @@ createoptiontable(void)
optiontab->addnode(optiontab, on->node.nam, on);
}
+/* Emulation appropriate to the setemulate function */
+
+static int setemulate_emulation;
+
+/* Option array manipulated within the setemulate function */
+
+/**/
+static char *setemulate_opts;
+
/* Setting of default options */
/**/
@@ -490,20 +500,22 @@ setemulate(HashNode hn, int fully)
if (!(on->node.flags & OPT_ALIAS) &&
((fully && !(on->node.flags & OPT_SPECIAL)) ||
(on->node.flags & OPT_EMULATE)))
- opts[on->optno] = defset(on);
+ setemulate_opts[on->optno] = defset(on, setemulate_emulation);
}
/**/
void
-installemulation(void)
+installemulation(int new_emulation, char *new_opts)
{
+ setemulate_emulation = new_emulation;
+ setemulate_opts = new_opts;
scanhashtable(optiontab, 0, 0, 0, setemulate,
- !!(emulation & EMULATE_FULLY));
+ !!(new_emulation & EMULATE_FULLY));
}
/**/
void
-emulate(const char *zsh_name, int fully)
+emulate(const char *zsh_name, int fully, int *new_emulation, char *new_opts)
{
char ch = *zsh_name;
@@ -512,17 +524,17 @@ emulate(const char *zsh_name, int fully)
/* Work out the new emulation mode */
if (ch == 'c')
- emulation = EMULATE_CSH;
+ *new_emulation = EMULATE_CSH;
else if (ch == 'k')
- emulation = EMULATE_KSH;
+ *new_emulation = EMULATE_KSH;
else if (ch == 's' || ch == 'b')
- emulation = EMULATE_SH;
+ *new_emulation = EMULATE_SH;
else
- emulation = EMULATE_ZSH;
+ *new_emulation = EMULATE_ZSH;
if (fully)
- emulation |= EMULATE_FULLY;
- installemulation();
+ *new_emulation |= EMULATE_FULLY;
+ installemulation(*new_emulation, new_opts);
if (funcstack && funcstack->tp == FS_FUNC) {
/*
@@ -532,9 +544,9 @@ emulate(const char *zsh_name, int fully)
* close enough.
*/
Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name);
- if (shf && (shf->node.flags & PM_TAGGED)) {
+ if (shf && (shf->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))) {
/* Tracing is on, so set xtrace */
- opts[XTRACE] = 1;
+ new_opts[XTRACE] = 1;
}
}
}
@@ -545,7 +557,7 @@ emulate(const char *zsh_name, int fully)
static void
setoption(HashNode hn, int value)
{
- dosetopt(((Optname) hn)->optno, value, 0);
+ dosetopt(((Optname) hn)->optno, value, 0, opts);
}
/**/
@@ -582,7 +594,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
}
if(!(optno = optlookup(*args)))
zwarnnam(nam, "no such option: %s", *args);
- else if(dosetopt(optno, action, 0))
+ else if(dosetopt(optno, action, 0, opts))
zwarnnam(nam, "can't change option: %s", *args);
break;
} else if(**args == 'm') {
@@ -590,7 +602,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
} else {
if (!(optno = optlookupc(**args)))
zwarnnam(nam, "bad option: -%c", **args);
- else if(dosetopt(optno, action, 0))
+ else if(dosetopt(optno, action, 0, opts))
zwarnnam(nam, "can't change option: -%c", **args);
}
}
@@ -603,7 +615,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
while (*args) {
if(!(optno = optlookup(*args++)))
zwarnnam(nam, "no such option: %s", args[-1]);
- else if(dosetopt(optno, !isun, 0))
+ else if(dosetopt(optno, !isun, 0, opts))
zwarnnam(nam, "can't change option: %s", args[-1]);
}
} else {
@@ -713,7 +725,7 @@ static char *rparams[] = {
/**/
mod_export int
-dosetopt(int optno, int value, int force)
+dosetopt(int optno, int value, int force, char *new_opts)
{
if(!optno)
return -1;
@@ -735,7 +747,7 @@ dosetopt(int optno, int value, int force)
return -1;
} else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||
optno == SINGLECOMMAND)) {
- if (opts[optno] == value)
+ if (new_opts[optno] == value)
return 0;
/* it is not permitted to change the value of these options */
return -1;
@@ -751,7 +763,7 @@ dosetopt(int optno, int value, int force)
#endif /* HAVE_SETUID */
#ifdef JOB_CONTROL
} else if (!force && optno == MONITOR && value) {
- if (opts[optno] == value)
+ if (new_opts[optno] == value)
return 0;
if (SHTTY != -1) {
origpgrp = GETPGRP();
@@ -767,15 +779,15 @@ dosetopt(int optno, int value, int force)
return -1;
#endif /* GETPWNAM_FAKED */
} else if ((optno == EMACSMODE || optno == VIMODE) && value) {
- if (sticky_emulation)
+ if (sticky && sticky->emulation)
return -1;
zleentry(ZLE_CMD_SET_KEYMAP, optno);
- opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0;
+ new_opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0;
} else if (optno == SUNKEYBOARDHACK) {
/* for backward compatibility */
keyboardhackchar = (value ? '`' : '\0');
}
- opts[optno] = value;
+ new_opts[optno] = value;
if (optno == BANGHIST || optno == SHINSTDIN)
inittyptab();
return 0;
@@ -817,10 +829,11 @@ printoptionnodestate(HashNode hn, int hadplus)
int optno = on->optno;
if (hadplus) {
- if (defset(on) != isset(optno))
- printf("set -o %s%s\n", defset(on) ? "no" : "", on->node.nam);
+ if (defset(on, emulation) != isset(optno))
+ printf("set -o %s%s\n", defset(on, emulation) ?
+ "no" : "", on->node.nam);
} else {
- if (defset(on))
+ if (defset(on, emulation))
printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
else
printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
diff --git a/Src/parse.c b/Src/parse.c
index e4d038b6e..0f5d99cef 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -666,7 +666,8 @@ par_sublist(int *complex)
*complex |= c;
if (tok == DBAR || tok == DAMPER) {
- int qtok = tok, sl;
+ enum lextok qtok = tok;
+ int sl;
cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND);
zshlex();
@@ -1176,7 +1177,8 @@ par_case(int *complex)
static void
par_if(int *complex)
{
- int oecused = ecused, xtok, p, pp, type, usebrace = 0;
+ int oecused = ecused, p, pp, type, usebrace = 0;
+ enum lextok xtok;
unsigned char nc;
p = ecadd(0);
@@ -1367,7 +1369,8 @@ par_repeat(int *complex)
static void
par_subsh(int *complex)
{
- int oecused = ecused, otok = tok, p, pp;
+ enum lextok otok = tok;
+ int oecused = ecused, p, pp;
p = ecadd(0);
/* Extra word only needed for always block */
@@ -1607,6 +1610,11 @@ par_simple(int *complex, int nr)
} else if (tok == ENVARRAY) {
int oldcmdpos = incmdpos, n, type2;
+ /*
+ * We consider array setting complex because it can
+ * contain process substitutions, which need a valid job.
+ */
+ *complex = c = 1;
p = ecadd(0);
incmdpos = 0;
if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') {
@@ -2110,7 +2118,7 @@ par_cond_2(void)
&& !s1[2]);
condlex();
if (tok == INANG || tok == OUTANG) {
- int xtok = tok;
+ enum lextok xtok = tok;
condlex();
if (tok != STRING)
YYERROR(ecused);
@@ -2371,7 +2379,7 @@ freeeprog(Eprog p)
/**/
char *
-ecgetstr(Estate s, int dup, int *tok)
+ecgetstr(Estate s, int dup, int *tokflag)
{
static char buf[4];
wordcode c = *s->pc++;
@@ -2389,8 +2397,8 @@ ecgetstr(Estate s, int dup, int *tok)
} else {
r = s->strs + (c >> 2);
}
- if (tok)
- *tok = (c & 1);
+ if (tokflag)
+ *tokflag = (c & 1);
/*** Since function dump files are mapped read-only, avoiding to
* to duplicate strings when they don't contain tokens may fail
@@ -2407,33 +2415,33 @@ ecgetstr(Estate s, int dup, int *tok)
/**/
char *
-ecrawstr(Eprog p, Wordcode pc, int *tok)
+ecrawstr(Eprog p, Wordcode pc, int *tokflag)
{
static char buf[4];
wordcode c = *pc;
if (c == 6 || c == 7) {
- if (tok)
- *tok = (c & 1);
+ if (tokflag)
+ *tokflag = (c & 1);
return "";
} else if (c & 2) {
buf[0] = (char) ((c >> 3) & 0xff);
buf[1] = (char) ((c >> 11) & 0xff);
buf[2] = (char) ((c >> 19) & 0xff);
buf[3] = '\0';
- if (tok)
- *tok = (c & 1);
+ if (tokflag)
+ *tokflag = (c & 1);
return buf;
} else {
- if (tok)
- *tok = (c & 1);
+ if (tokflag)
+ *tokflag = (c & 1);
return p->strs + (c >> 2);
}
}
/**/
char **
-ecgetarr(Estate s, int num, int dup, int *tok)
+ecgetarr(Estate s, int num, int dup, int *tokflag)
{
char **ret, **rp;
int tf = 0, tmp = 0;
@@ -2445,15 +2453,15 @@ ecgetarr(Estate s, int num, int dup, int *tok)
tf |= tmp;
}
*rp = NULL;
- if (tok)
- *tok = tf;
+ if (tokflag)
+ *tokflag = tf;
return ret;
}
/**/
LinkList
-ecgetlist(Estate s, int num, int dup, int *tok)
+ecgetlist(Estate s, int num, int dup, int *tokflag)
{
if (num) {
LinkList ret;
@@ -2464,12 +2472,12 @@ ecgetlist(Estate s, int num, int dup, int *tok)
setsizednode(ret, i, ecgetstr(s, dup, &tmp));
tf |= tmp;
}
- if (tok)
- *tok = tf;
+ if (tokflag)
+ *tokflag = tf;
return ret;
}
- if (tok)
- *tok = 0;
+ if (tokflag)
+ *tokflag = 0;
return NULL;
}
@@ -3479,7 +3487,7 @@ dump_autoload(char *nam, char *file, int on, Options ops, int func)
shf = (Shfunc) zshcalloc(sizeof *shf);
shf->node.flags = on;
shf->funcdef = mkautofn(shf);
- shf->emulation = 0;
+ shf->sticky = NULL;
shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf);
if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->node.nam, ops, func))
ret = 1;
diff --git a/Src/prototypes.h b/Src/prototypes.h
index f059b6620..00988ac4c 100644
--- a/Src/prototypes.h
+++ b/Src/prototypes.h
@@ -49,11 +49,18 @@ extern int tgetent _((char *bp, TC_CONST char *name));
extern int tgetnum _((char *id));
extern int tgetflag _((char *id));
extern char *tgetstr _((char *id, char **area));
-extern char *tgoto _((TC_CONST char *cm, int destcol, int destline));
extern int tputs _((TC_CONST char *cp, int affcnt, int (*outc) (int)));
#undef TC_CONST
#endif
+/*
+ * Some systems that do have termcap headers nonetheless don't
+ * declare tgoto, so we detect if that is missing separately.
+ */
+#ifdef TGOTO_PROTO_MISSING
+char *tgoto(const char *cap, int col, int row);
+#endif
+
/* MISSING PROTOTYPES FOR VARIOUS OPERATING SYSTEMS */
#if defined(__hpux) && defined(_HPUX_SOURCE) && !defined(_XPG4_EXTENDED)
diff --git a/Src/signals.c b/Src/signals.c
index ad688094b..046ee6a4a 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -755,7 +755,10 @@ dosavetrap(int sig, int level)
newshf->node.flags = shf->node.flags;
newshf->funcdef = dupeprog(shf->funcdef, 0);
newshf->filename = ztrdup(shf->filename);
- newshf->emulation = shf->emulation;
+ if (shf->sticky) {
+ newshf->sticky = sticky_emulation_dup(shf->sticky, 0);
+ } else
+ newshf->sticky = 0;
if (shf->node.flags & PM_UNDEFINED)
newshf->funcdef->shf = newshf;
}
diff --git a/Src/subst.c b/Src/subst.c
index 932f41287..974a8456d 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1215,7 +1215,7 @@ get_strarg(char *s, int *lenp)
{
convchar_t del;
int len;
- char tok = 0;
+ char ctok = 0;
MB_METACHARINIT();
len = MB_METACHARLENCONV(s, &del);
@@ -1243,25 +1243,25 @@ get_strarg(char *s, int *lenp)
del = ZWC('>');
break;
case Inpar:
- tok = Outpar;
+ ctok = Outpar;
break;
case Inang:
- tok = Outang;
+ ctok = Outang;
break;
case Inbrace:
- tok = Outbrace;
+ ctok = Outbrace;
break;
case Inbrack:
- tok = Outbrack;
+ ctok = Outbrack;
break;
}
- if (tok) {
+ if (ctok) {
/*
* Looking for a matching token; we want the literal byte,
* not a decoded multibyte character, so search specially.
*/
- while (*s && *s != tok)
+ while (*s && *s != ctok)
s++;
} else {
convchar_t del2;
@@ -2314,6 +2314,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
val = dyncat(val, "-readonly");
if (f & PM_TAGGED)
val = dyncat(val, "-tag");
+ if (f & PM_TAGGED_LOCAL)
+ val = dyncat(val, "-tag_local");
if (f & PM_EXPORTED)
val = dyncat(val, "-export");
if (f & PM_UNIQUE)
diff --git a/Src/utils.c b/Src/utils.c
index d35ca1dfd..26e2a5c2c 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2030,13 +2030,20 @@ skipparens(char inpar, char outpar, char **s)
return level;
}
+/**/
+mod_export zlong
+zstrtol(const char *s, char **t, int base)
+{
+ return zstrtol_underscore(s, t, base, 0);
+}
+
/* Convert string to zlong (see zsh.h). This function (without the z) *
* is contained in the ANSI standard C library, but a lot of them seem *
* to be broken. */
/**/
mod_export zlong
-zstrtol(const char *s, char **t, int base)
+zstrtol_underscore(const char *s, char **t, int base, int underscore)
{
const char *inp, *trunc = NULL;
zulong calc = 0, newcalc = 0;
@@ -2062,22 +2069,24 @@ zstrtol(const char *s, char **t, int base)
if (base < 2 || base > 36) {
zerr("invalid base (must be 2 to 36 inclusive): %d", base);
return (zlong)0;
- } else if (base <= 10)
- for (; *s >= '0' && *s < ('0' + base); s++) {
- if (trunc)
+ } else if (base <= 10) {
+ for (; (*s >= '0' && *s < ('0' + base)) ||
+ (underscore && *s == '_'); s++) {
+ if (trunc || *s == '_')
continue;
newcalc = calc * base + *s - '0';
if (newcalc < calc)
{
- trunc = s;
- continue;
+ trunc = s;
+ continue;
}
calc = newcalc;
}
- else
+ } else {
for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
- || (*s >= 'A' && *s < ('A' + base - 10)); s++) {
- if (trunc)
+ || (*s >= 'A' && *s < ('A' + base - 10))
+ || (underscore && *s == '_'); s++) {
+ if (trunc || *s == '_')
continue;
newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
if (newcalc < calc)
@@ -2087,6 +2096,7 @@ zstrtol(const char *s, char **t, int base)
}
calc = newcalc;
}
+ }
/*
* Special case: check for a number that was just too long for
@@ -2877,7 +2887,7 @@ zjoin(char **arr, int delim, int heap)
* of items into an array of strings. */
/**/
-char **
+mod_export char **
colonsplit(char *s, int uniq)
{
int ct;
diff --git a/Src/zsh.h b/Src/zsh.h
index cc3a67008..207ef1836 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -232,7 +232,7 @@ enum {
* appear in strings and don't necessarily represent a single character.
*/
-enum {
+enum lextok {
NULLTOK, /* 0 */
SEPER,
NEWLIN,
@@ -407,6 +407,7 @@ typedef struct cmdnam *Cmdnam;
typedef struct complist *Complist;
typedef struct conddef *Conddef;
typedef struct dirsav *Dirsav;
+typedef struct emulation_options *Emulation_options;
typedef struct features *Features;
typedef struct feature_enables *Feature_enables;
typedef struct funcstack *Funcstack;
@@ -1099,7 +1100,7 @@ struct shfunc {
char *filename; /* Name of file located in */
zlong lineno; /* line number in above file */
Eprog funcdef; /* function definition */
- int emulation; /* sticky emulation for function */
+ Emulation_options sticky; /* sticky emulation definitions, if any */
};
/* Shell function context types. */
@@ -1554,6 +1555,7 @@ struct tieddata {
#define PM_HIDE (1<<14) /* Special behaviour hidden by local */
#define PM_HIDEVAL (1<<15) /* Value not shown in `typeset' commands */
#define PM_TIED (1<<16) /* array tied to colon-path or v.v. */
+#define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */
#define PM_KSHSTORED (1<<17) /* function stored in ksh form */
#define PM_ZSHSTORED (1<<18) /* function stored in zsh form */
@@ -1969,6 +1971,7 @@ enum {
COMPLETEINWORD,
CORRECT,
CORRECTALL,
+ CONTINUEONERROR,
CPRECEDENCES,
CSHJUNKIEHISTORY,
CSHJUNKIELOOPS,
@@ -2103,6 +2106,12 @@ enum {
OPT_SIZE
};
+/*
+ * Size required to fit an option number.
+ * If OPT_SIZE goes above 256 this will need to expand.
+ */
+typedef unsigned char OptIndex;
+
#undef isset
#define isset(X) (opts[X])
#define unset(X) (!opts[X])
@@ -2111,6 +2120,27 @@ enum {
#define jobbing (isset(MONITOR))
#define islogin (isset(LOGINSHELL))
+/*
+ * Record of emulation and options that need to be set
+ * for a full "emulate".
+ */
+struct emulation_options {
+ /* The emulation itself */
+ int emulation;
+ /* The number of options in on_opts. */
+ int n_on_opts;
+ /* The number of options in off_opts. */
+ int n_off_opts;
+ /*
+ * Array of options to be turned on.
+ * Only options specified explicitly in the emulate command
+ * are recorded. Null if n_on_opts is zero.
+ */
+ OptIndex *on_opts;
+ /* Array of options to be turned off, similar. */
+ OptIndex *off_opts;
+};
+
/***********************************************/
/* Definitions for terminal and display control */
/***********************************************/
@@ -2135,6 +2165,7 @@ struct ttyinfo {
#endif
};
+#ifndef __INTERIX
/* defines for whether tabs expand to spaces */
#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
#define SGTTYFLAG shttyinfo.tio.c_oflag
@@ -2152,6 +2183,7 @@ struct ttyinfo {
# endif
# endif
# endif
+#endif
/* flags for termflags */
@@ -2678,7 +2710,14 @@ typedef wint_t convchar_t;
#define MB_METASTRWIDTH(str) mb_metastrlen(str, 1)
#define MB_METASTRLEN2(str, widthp) mb_metastrlen(str, widthp)
-#ifdef BROKEN_WCWIDTH
+/*
+ * We replace broken implementations with one that uses Unicode
+ * characters directly as wide characters. In principle this is only
+ * likely to work if __STDC_ISO_10646__ is defined, since that's pretty
+ * much what the definition tells us. However, we happen to know this
+ * works on MacOS which doesn't define that.
+ */
+#if defined(BROKEN_WCWIDTH) && (defined(__STDC_ISO_10646__) || defined(__APPLE__))
#define WCWIDTH(wc) mk_wcwidth(wc)
#else
#define WCWIDTH(wc) wcwidth(wc)
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index f20a7bb90..f38533023 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -874,7 +874,3 @@ extern short ospeed;
# endif
# endif
#endif
-
-#ifdef TGOTO_PROTO_MISSING
-char *tgoto(const char *cap, int col, int row);
-#endif