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.c11
-rw-r--r--Src/Makefile.in1
-rw-r--r--Src/Modules/curses.c2
-rw-r--r--Src/Modules/db_gdbm.c2
-rw-r--r--Src/Modules/files.c48
-rw-r--r--Src/Modules/parameter.c2
-rw-r--r--Src/Modules/system.c6
-rw-r--r--Src/Modules/zftp.c15
-rw-r--r--Src/Modules/zpty.c2
-rw-r--r--Src/Modules/zutil.c33
-rw-r--r--Src/Zle/comp.h12
-rw-r--r--Src/Zle/compcore.c54
-rw-r--r--Src/Zle/compctl.c34
-rw-r--r--Src/Zle/complete.c63
-rw-r--r--Src/Zle/compmatch.c2
-rw-r--r--Src/Zle/compresult.c2
-rw-r--r--Src/Zle/computil.c2
-rw-r--r--Src/Zle/iwidgets.list2
-rw-r--r--Src/Zle/zle.h1
-rw-r--r--Src/Zle/zle_keymap.c2
-rw-r--r--Src/Zle/zle_main.c35
-rw-r--r--Src/Zle/zle_refresh.c70
-rw-r--r--Src/Zle/zle_thingy.c5
-rw-r--r--Src/Zle/zle_tricky.c4
-rw-r--r--Src/Zle/zle_utils.c14
-rw-r--r--Src/Zle/zle_vi.c2
-rw-r--r--Src/builtin.c120
-rw-r--r--Src/compat.c18
-rw-r--r--Src/exec.c90
-rw-r--r--Src/glob.c16
-rw-r--r--Src/hashtable.c2
-rw-r--r--Src/hist.c133
-rw-r--r--Src/init.c45
-rw-r--r--Src/jobs.c22
-rw-r--r--Src/lex.c2
-rw-r--r--Src/loop.c19
-rw-r--r--Src/main.c4
-rw-r--r--Src/makepro.awk2
-rw-r--r--Src/math.c15
-rw-r--r--Src/mem.c2
-rw-r--r--Src/module.c2
-rw-r--r--Src/options.c1
-rw-r--r--Src/params.c44
-rw-r--r--Src/parse.c17
-rw-r--r--Src/pattern.c42
-rw-r--r--Src/prompt.c42
-rw-r--r--Src/signals.c12
-rw-r--r--Src/sort.c27
-rw-r--r--Src/subst.c51
-rw-r--r--Src/text.c11
-rw-r--r--Src/utils.c33
-rw-r--r--Src/watch.c2
-rw-r--r--Src/zsh.h29
-rw-r--r--Src/zsh_system.h2
-rw-r--r--Src/ztype.h2
56 files changed, 887 insertions, 347 deletions
diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk
index fe2d0e931..e9c576c66 100644
--- a/Src/Builtins/rlimits.awk
+++ b/Src/Builtins/rlimits.awk
@@ -59,6 +59,7 @@ BEGIN {limidx = 0}
if (limnam == "NPTS") { msg[limnum] = "Npseudoterminals" }
if (limnam == "SWAP") { msg[limnum] = "Mswapsize" }
if (limnam == "KQUEUES") { msg[limnum] = "Nkqueues" }
+ if (limnam == "UMTXP") { msg[limnum] = "Numtxp" }
}
}
}
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 29f97b41d..6b552f3a9 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -413,6 +413,12 @@ printulimit(char *nam, int lim, int hard, int head)
printf("-k: kqueues ");
break;
# endif /* HAVE_RLIMIT_KQUEUES */
+# ifdef HAVE_RLIMIT_UMTXP
+ case RLIMIT_UMTXP:
+ if (head)
+ printf("-o: umtx shared locks ");
+ break;
+# endif /* HAVE_RLIMIT_UMTXP */
default:
if (head)
printf("-N %2d: ", lim);
@@ -895,6 +901,11 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
res = RLIMIT_PTHREAD;
break;
# endif
+# ifdef HAVE_RLIMIT_UMTXP
+ case 'o':
+ res = RLIMIT_UMTXP;
+ break;
+# endif
default:
/* unrecognised limit */
zwarnnam(name, "bad option: -%c", *options);
diff --git a/Src/Makefile.in b/Src/Makefile.in
index 0577554f8..0fdbb73d2 100644
--- a/Src/Makefile.in
+++ b/Src/Makefile.in
@@ -94,7 +94,6 @@ zsh.res.o: $(sdir)/zsh.rc $(sdir)/zsh.ico
stamp-modobjs: modobjs
@if cmp -s stamp-modobjs.tmp stamp-modobjs; then \
rm -f stamp-modobjs.tmp; \
- echo "\`stamp-modobjs' is up to date."; \
else \
mv -f stamp-modobjs.tmp stamp-modobjs; \
echo "Updated \`stamp-modobjs'."; \
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index a60dfcbf8..19f285e34 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -1519,7 +1519,7 @@ zccmd_resize(const char *nam, char **args)
// is not available.
return 0;
} else {
- // Without this call some window moves are innacurate. Tested on
+ // Without this call some window moves are inaccurate. Tested on
// OS X ncurses 5.4, Homebrew ncursesw 6.0-2, Arch Linux ncursesw
// 6.0, Ubuntu 14.04 ncurses 5.9, FreeBSD ncursesw.so.8
//
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index 12dd839cf..b8e7c76c6 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -766,7 +766,7 @@ static int remove_tied_name( const char *name ) {
/*
* Unmetafy that:
- * - duplicates bufer to work on it,
+ * - duplicates buffer to work on it,
* - does zalloc of exact size for the new string,
* - restores work buffer to original content, to restore strlen
*/
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index 6f816bac0..6d20e38a8 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -613,12 +613,52 @@ bin_rm(char *nam, char **args, Options ops, UNUSED(int func))
rmm.opt_interact = OPT_ISSET(ops,'i') && !OPT_ISSET(ops,'f');
rmm.opt_unlinkdir = OPT_ISSET(ops,'d');
err = recursivecmd(nam, OPT_ISSET(ops,'f'),
- OPT_ISSET(ops,'r') && !OPT_ISSET(ops,'d'),
+ !OPT_ISSET(ops,'d') && (OPT_ISSET(ops,'R') ||
+ OPT_ISSET(ops,'r')),
OPT_ISSET(ops,'s'),
args, recurse_donothing, rm_dirpost, rm_leaf, &rmm);
return OPT_ISSET(ops,'f') ? 0 : err;
}
+/* chmod builtin */
+
+struct chmodmagic {
+ char *nam;
+ mode_t mode;
+};
+
+/**/
+static int
+chmod_dochmod(char *arg, char *rp, UNUSED(struct stat const *sp), void *magic)
+{
+ struct chmodmagic *chm = magic;
+
+ if(chmod(rp, chm->mode)) {
+ zwarnnam(chm->nam, "%s: %e", arg, errno);
+ return 1;
+ }
+ return 0;
+}
+
+/**/
+static int
+bin_chmod(char *nam, char **args, Options ops, int func)
+{
+ struct chmodmagic chm;
+ char *str = args[0], *ptr;
+
+ chm.nam = nam;
+
+ chm.mode = zstrtol(str, &ptr, 8);
+ if(!*str || *ptr) {
+ zwarnnam(nam, "invalid mode `%s'", str);
+ return 1;
+ }
+
+ return recursivecmd(nam, 0, OPT_ISSET(ops,'R'), OPT_ISSET(ops,'s'),
+ args + 1, chmod_dochmod, recurse_donothing, chmod_dochmod, &chm);
+}
+
/* chown builtin */
struct chownmagic {
@@ -754,20 +794,22 @@ static struct builtin bintab[] = {
/* The names which overlap commands without necessarily being
* fully compatible. */
BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL),
+ BUILTIN("chmod", 0, bin_chmod, 2, -1, 0, "Rs", NULL),
BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL),
BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm:", NULL),
BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
- BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
+ BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfiRrs", NULL),
BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
/* The "safe" zsh-only names */
BUILTIN("zf_chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL),
+ BUILTIN("zf_chmod", 0, bin_chmod, 2, -1, 0, "Rs", NULL),
BUILTIN("zf_chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL),
BUILTIN("zf_ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
BUILTIN("zf_mkdir", 0, bin_mkdir, 1, -1, 0, "pm:", NULL),
BUILTIN("zf_mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
- BUILTIN("zf_rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
+ BUILTIN("zf_rm", 0, bin_rm, 1, -1, 0, "dfiRrs", NULL),
BUILTIN("zf_rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
BUILTIN("zf_sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 76824cf58..ef9148d7b 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -1552,7 +1552,7 @@ setpmnameddirs(Param pm, HashTable ht)
}
}
- /* The INTERACTIVE stuff ensures that the dirs are not immediatly removed
+ /* The INTERACTIVE stuff ensures that the dirs are not immediately removed
* when the sub-pms are deleted. */
i = opts[INTERACTIVE];
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index 7a4f4ee13..fb3d80773 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -174,7 +174,7 @@ bin_sysread(char *nam, char **args, Options ops, UNUSED(int func))
}
while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds,
- NULL, NULL,&select_tv)) < 1) {
+ NULL, NULL,&select_tv)) < 0) {
if (errno != EINTR || errflag || retflag || breaks || contflag)
break;
}
@@ -316,7 +316,7 @@ bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func))
int o, fd, moved_fd, explicit = -1;
mode_t perms = 0666;
#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
- int fdflags;
+ int fdflags = 0;
#endif
if (!OPT_ISSET(ops, 'u')) {
@@ -396,8 +396,8 @@ bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func))
#endif /* O_CLOEXEC */
fcntl(moved_fd, F_SETFD, FD_CLOEXEC);
#endif /* FD_CLOEXEC */
+ fdtable[moved_fd] = FDT_EXTERNAL;
if (explicit == -1) {
- fdtable[moved_fd] = FDT_EXTERNAL;
setiparam(fdvar, moved_fd);
/* if setting the variable failed, close moved_fd to avoid leak */
if (errflag)
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 4aaa1f072..e8e239e76 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -237,7 +237,7 @@ enum {
/*
* We keep an fd open for communication between the main shell
* and forked off bits and pieces. This allows us to know
- * if something happend in a subshell: mode changed, type changed,
+ * if something happened in a subshell: mode changed, type changed,
* connection was closed. If something too substantial happened
* in a subshell --- connection opened, ZFTP_USER and ZFTP_PWD changed
* --- we don't try to track it because it's too complicated.
@@ -1257,14 +1257,8 @@ zfstats(char *fnam, int remote, off_t *retsize, char **retmdtm, int fd)
if (retmdtm) {
/* use gmtime() rather than localtime() for consistency */
tm = gmtime(&statbuf.st_mtime);
- /*
- * FTP format for data is YYYYMMDDHHMMSS
- * Using tm directly is easier than worrying about
- * incompatible strftime()'s.
- */
- sprintf(tmbuf, "%04d%02d%02d%02d%02d%02d",
- tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
+ /* FTP format for date is YYYYMMDDHHMMSS */
+ ztrftime(tmbuf, sizeof(tmbuf), "%Y%m%d%H%M%S", tm, 0L);
mt = ztrdup(tmbuf);
}
}
@@ -2518,7 +2512,8 @@ zftp_local(UNUSED(char *name), char **args, int flags)
#ifdef OFF_T_IS_64_BIT
printf("%s %s\n", output64(sz), mt);
#else
- DPUTS(sizeof(sz) > 4, "Shell compiled with wrong off_t size");
+ DPUTS(sizeof(sz) > sizeof(long),
+ "Shell compiled with wrong off_t size");
printf("%ld %s\n", (long)sz, mt);
#endif
zsfree(mt);
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 2f83f7ce6..45fd15ee0 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -426,7 +426,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
execode(prog, 1, 0, "zpty");
stopmsg = 2;
mypid = 0; /* trick to ensure we _exit() */
- zexit(lastval, 0);
+ zexit(lastval, ZEXIT_NORMAL);
}
master = movefd(master);
if (master == -1) {
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 19a8306b5..24659cb16 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -88,7 +88,8 @@ typedef struct style *Style;
struct style {
struct hashnode node;
- Stypat pats; /* patterns */
+ Stypat pats; /* patterns, sorted by weight descending, then
+ by order of definition, newest first. */
};
struct stypat {
@@ -337,7 +338,19 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
p->eval = eprog;
p->next = NULL;
- /* Calculate the weight. */
+ /* Calculate the weight.
+ *
+ * The weight of a pattern is scored as follows:
+ *
+ * - The pattern is split to colon-separated components.
+ * - A component equal to '*' (with nothing else) scores 0 points.
+ * - A component that's a pattern, otherwise, scores 1 point.
+ * - A component that's a literal string scores 2 points.
+ * - The score of a pattern is the sum of the score of its components.
+ *
+ * This corresponds to the notion of 'more specific' in the zshmodules(1)
+ * documentation of zstyle.
+ */
for (weight = 0, tmp = 2, first = 1, str = pat; *str; str++) {
if (first && *str == '*' && (!str[1] || str[1] == ':')) {
@@ -362,9 +375,9 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
}
p->weight = (weight += tmp);
+ /* Insert 'q' to 's->pats', using 'qq' as a temporary. */
for (qq = NULL, q = s->pats; q && q->weight >= weight;
qq = q, q = q->next);
-
p->next = q;
if (qq)
qq->next = p;
@@ -1644,7 +1657,7 @@ static int
bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np;
- int del = 0, flags = 0, extract = 0, keep = 0;
+ int del = 0, flags = 0, extract = 0, fail = 0, keep = 0;
Zoptdesc sopts[256], d;
Zoptarr a, defarr = NULL;
Zoptval v;
@@ -1681,6 +1694,14 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
}
extract = 1;
break;
+ case 'F':
+ if (o[2]) {
+ args--;
+ o = NULL;
+ break;
+ }
+ fail = 1;
+ break;
case 'K':
if (o[2]) {
args--;
@@ -1843,6 +1864,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
if (!(d = lookup_opt(o + 1))) {
while (*++o) {
if (!(d = sopts[STOUC(*o)])) {
+ if (fail) {
+ zwarnnam(nam, "bad option: %c", *o);
+ return 1;
+ }
o = NULL;
break;
}
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 3e9834560..2e3249b52 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -35,7 +35,7 @@ typedef struct cexpl *Cexpl;
typedef struct cmgroup *Cmgroup;
typedef struct cmatch *Cmatch;
-/* This is for explantion strings. */
+/* This is for explanation strings. */
struct cexpl {
int always; /* display even without matches */
@@ -90,6 +90,9 @@ struct cmgroup {
#define CGF_PACKED 32 /* LIST_PACKED for this group */
#define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */
#define CGF_FILES 128 /* contains file names */
+#define CGF_MATSORT 256 /* sort by match rather than by display string */
+#define CGF_NUMSORT 512 /* sort numerically */
+#define CGF_REVSORT 1024 /* sort in reverse */
/* This is the struct used to hold matches. */
@@ -123,8 +126,8 @@ struct cmatch {
#define CMF_FILE (1<< 0) /* this is a file */
#define CMF_REMOVE (1<< 1) /* remove the suffix */
-#define CMF_ISPAR (1<< 2) /* is paramter expansion */
-#define CMF_PARBR (1<< 3) /* paramter expansion with a brace */
+#define CMF_ISPAR (1<< 2) /* is parameter expansion */
+#define CMF_PARBR (1<< 3) /* parameter expansion with a brace */
#define CMF_PARNEST (1<< 4) /* nested parameter expansion */
#define CMF_NOLIST (1<< 5) /* should not be listed */
#define CMF_DISPLINE (1<< 6) /* display strings one per line */
@@ -300,6 +303,9 @@ struct menuinfo {
#define CAF_ARRAYS 32 /* compadd -a or -k: array/assoc parameter names */
#define CAF_KEYS 64 /* compadd -k: assoc parameter names */
#define CAF_ALL 128 /* compadd -C: _all_matches */
+#define CAF_MATSORT 256 /* compadd -o match: sort by match rather than by display string */
+#define CAF_NUMSORT 512 /* compadd -o numeric: sort numerically */
+#define CAF_REVSORT 1024 /* compadd -o numeric: sort in reverse */
/* Data for compadd and addmatches() */
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 0a454ad5f..7e3badc57 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1492,7 +1492,7 @@ set_comp_sep(void)
* are specially handled (but currently only if RCQUOTES is not
* set, which isn't necessarily correct if the quotes were typed by
* the user).
- * osq: c.f. odq, taking account of Snull's and embeded "'"'s.
+ * osq: c.f. odq, taking account of Snull's and embedded "'"'s.
* qttype: type of quotes using standard QT_* definitions.
* lsq: when quoting is single quotes (QT_SINGLE), counts the offset
* adjustment needed in the word being examined in the lexer loop.
@@ -2080,6 +2080,9 @@ addmatches(Cadata dat, char **argv)
/* Select the group in which to store the matches. */
gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT : 0) |
+ ((dat->aflags & CAF_MATSORT) ? CGF_MATSORT : 0) |
+ ((dat->aflags & CAF_NUMSORT) ? CGF_NUMSORT : 0) |
+ ((dat->aflags & CAF_REVSORT) ? CGF_REVSORT : 0) |
((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
if (dat->group) {
@@ -3034,8 +3037,9 @@ begcmgroup(char *n, int flags)
HEAP_ERROR(p->heap_id);
}
#endif
- if (p->name &&
- flags == (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON)) &&
+ if (p->name && flags ==
+ (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON|
+ CGF_MATSORT|CGF_NUMSORT|CGF_REVSORT)) &&
!strcmp(n, p->name)) {
mgroup = p;
@@ -3118,32 +3122,35 @@ addexpl(int always)
/* The comparison function for matches (used for sorting). */
+static int matchorder;
+
/**/
static int
matchcmp(Cmatch *a, Cmatch *b)
{
- if ((*a)->disp && !((*a)->flags & CMF_MORDER)) {
- if ((*b)->disp) {
- if ((*a)->flags & CMF_DISPLINE) {
- if ((*b)->flags & CMF_DISPLINE)
- return strcmp((*a)->disp, (*b)->disp);
- else
- return -1;
- } else {
- if ((*b)->flags & CMF_DISPLINE)
- return 1;
- else
- return strcmp((*a)->disp, (*b)->disp);
- }
- }
- return -1;
+ const char *as, *bs;
+ int cmp = !!(*b)->disp - !!(*a)->disp;
+ int sortdir = (matchorder & CGF_REVSORT) ? -1 : 1;
+
+ /* if match sorting selected or we have no display strings */
+ if ((matchorder & CGF_MATSORT) || (!cmp && !(*a)->disp)) {
+ as = (*a)->str;
+ bs = (*b)->str;
+ } else {
+ if (cmp) /* matches with display strings come first */
+ return cmp;
+
+ cmp = ((*b)->flags & CMF_DISPLINE) - ((*a)->flags & CMF_DISPLINE);
+ if (cmp) /* sort one-per-line display strings first */
+ return cmp;
+
+ as = (*a)->disp;
+ bs = (*b)->disp;
}
- if ((*b)->disp && !((*b)->flags & CMF_MORDER))
- return 1;
- return zstrcmp((*a)->str, (*b)->str, (SORTIT_IGNORING_BACKSLASHES|
- (isset(NUMERICGLOBSORT) ?
- SORTIT_NUMERICALLY : 0)));
+ return sortdir * zstrcmp(as, bs, SORTIT_IGNORING_BACKSLASHES|
+ ((isset(NUMERICGLOBSORT) ||
+ matchorder & CGF_NUMSORT) ? SORTIT_NUMERICALLY : 0));
}
/* This tests whether two matches are equal (would produce the same
@@ -3205,6 +3212,7 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp)
} else {
if (!(flags & CGF_NOSORT)) {
/* Now sort the array (it contains matches). */
+ matchorder = flags;
qsort((void *) rp, n, sizeof(Cmatch),
(int (*) _((const void *, const void *)))matchcmp);
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index fe87409cb..08355d1b9 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1726,7 +1726,7 @@ static Patprog patcomp, filecomp;
* lppre/lpsuf -- the path prefix/suffix, unexpanded *
* fpre/fsuf -- prefix/suffix of the pathname component the cursor is in *
* prpre -- ppre in expanded form usable for opendir *
- * qipre, qisuf-- ingnored quoted string *
+ * qipre, qisuf-- ignored quoted string *
* *
* The integer variables hold the lengths of lpre, lsuf, rpre, rsuf, *
* fpre, fsuf, lppre, and lpsuf. noreal is non-zero if we have rpre/rsuf. */
@@ -2511,7 +2511,7 @@ makecomplistcmd(char *os, int incmd, int flags)
else if (!(cmdstr &&
(((ccp = (Compctlp) compctltab->getnode(compctltab, cmdstr)) &&
(cc = ccp->cc)) ||
- ((s = dupstring(cmdstr)) && remlpaths(&s) &&
+ ((s = dupstring(cmdstr)) && remlpaths(&s, 1) &&
(ccp = (Compctlp) compctltab->getnode(compctltab, s)) &&
(cc = ccp->cc))))) {
if (flags & CFN_DEFAULT)
@@ -3178,7 +3178,27 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* Compute line prefix/suffix. */
lpl = offs;
lpre = zhalloc(lpl + 1);
- memcpy(lpre, s, lpl);
+ if (comppatmatch)
+ {
+ int ccount;
+ char *psrc, *pdst;
+ for (ccount = 0, psrc = s, pdst = lpre;
+ ccount < lpl;
+ ++ccount, ++psrc, ++pdst)
+ {
+ if (*psrc == Meta)
+ {
+ ccount++;
+ *pdst++ = *psrc++;
+ *pdst = *psrc;
+ } else if (*psrc == Dash)
+ *pdst = '-';
+ else
+ *pdst = *psrc;
+ }
+ }
+ else
+ memcpy(lpre, s, lpl);
lpre[lpl] = '\0';
qlpre = quotename(lpre);
lsuf = dupstring(s + offs);
@@ -3331,13 +3351,11 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
zlemetaline[end] = save;
if (brend) {
Brinfo bp;
- char *p;
- int bl;
for (bp = brend; bp; bp = bp->next) {
- p = lpsuf + (we - zlemetacs) - bp->qpos -
- (bl = strlen(bp->str));
- strcpy(p, p + bl);
+ char *p2 = lpsuf + (we - zlemetacs) - bp->qpos;
+ char *p1 = p2 - strlen(bp->str);
+ memmove(p1, p2, strlen(p2) + 1);
}
}
if (!(lpsuf = strchr(lpsuf, '/')) && sf2)
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 1dc2b01c2..7beb6d847 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -84,7 +84,7 @@ char *compiprefix,
Param *comprpms;
/*
- * An array of Param structures for elemens of $compstate; see
+ * An array of Param structures for elements of $compstate; see
* 'compkparams' below.
*
* See CP_KEYPARAMS.
@@ -558,12 +558,53 @@ parse_class(Cpattern p, char *iptr)
return iptr;
}
+static struct { char *name; int abbrev; int oflag; } orderopts[] = {
+ { "nosort", 2, CAF_NOSORT },
+ { "match", 3, CAF_MATSORT },
+ { "numeric", 3, CAF_NUMSORT },
+ { "reverse", 3, CAF_REVSORT }
+};
+
+/* Parse the option to compadd -o, if flags is non-NULL set it
+ * returns -1 if the argument isn't a valid ordering, 0 otherwise */
+
+/**/
+static int
+parse_ordering(const char *arg, int *flags)
+{
+ int o, fl = 0;
+ const char *next, *opt = arg;
+ do {
+ int found = 0;
+ next = strchr(opt, ',');
+ if (!next)
+ next = opt + strlen(opt);
+
+ for (o = sizeof(orderopts)/sizeof(*orderopts) - 1; o >= 0 &&
+ !found; --o)
+ {
+ if ((found = next - opt >= orderopts[o].abbrev &&
+ !strncmp(orderopts[o].name, opt, next - opt)))
+ fl |= orderopts[o].oflag;
+ }
+ if (!found) {
+ if (flags) /* default to "match" */
+ *flags = CAF_MATSORT;
+ return -1;
+ }
+ } while (*next && ((opt = next + 1)));
+ if (flags)
+ *flags |= fl;
+ return 0;
+}
+
/**/
static int
bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
{
struct cadata dat;
char *mstr = NULL; /* argument of -M options, accumulated */
+ char *oarg = NULL; /* argument of -o option */
int added; /* return value */
Cmatcher match = NULL;
@@ -572,7 +613,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
return 1;
}
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg =
- dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
+ dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
dat.match = NULL;
dat.flags = 0;
@@ -587,6 +628,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
}
for (p = *argv + 1; *p; p++) {
char *m = NULL; /* argument of -M option (this one only) */
+ int order = 0; /* if -o found (argument to which is optional) */
char **sp = NULL; /* the argument to an option should be copied
to *sp. */
const char *e; /* error message */
@@ -710,7 +752,11 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
dat.flags |= CMF_DISPLINE;
break;
case 'o':
- dat.flags |= CMF_MORDER;
+ /* we honour just the first -o option but need to skip
+ * over a valid argument to subsequent -o options */
+ order = oarg ? -1 : 1;
+ sp = &oarg;
+ /* no error string because argument is optional */
break;
case 'E':
if (p[1]) {
@@ -741,15 +787,18 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
if (sp) {
if (p[1]) {
/* Pasted argument: -Xfoo. */
- if (!*sp)
+ if (!*sp) /* take first option only */
*sp = p + 1;
- p += strlen(p+1);
+ if (!order || !parse_ordering(oarg, order == 1 ? &dat.aflags : NULL))
+ p += strlen(p+1);
} else if (argv[1]) {
/* Argument in a separate word: -X foo. */
argv++;
if (!*sp)
*sp = *argv;
- } else {
+ if (order && parse_ordering(oarg, order == 1 ? &dat.aflags : NULL))
+ --argv;
+ } else if (!order) {
/* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */
zwarnnam(name, e, *p);
zsfree(mstr);
@@ -962,7 +1011,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
}
} else
#endif
- if ((int)strlen(test == CVT_PRENUM ? compprefix : compsuffix) >= na)
+ if ((int)strlen(test == CVT_PRENUM ? compprefix : compsuffix) < na)
return 0;
if (test == CVT_PRENUM)
ignore_prefix(na);
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 1cdbb8a48..cc4c3eca9 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -1399,7 +1399,7 @@ pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen,
if (prestrict->tp == CPAT_CHAR) {
/*
* Easy case: restricted to an exact character on
- * the line. Procede as normal.
+ * the line. Proceed as normal.
*/
c = prestrict->u.chr;
} else {
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index 05799399d..30fc60b78 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -827,7 +827,7 @@ do_ambiguous(void)
* if the completion is completely ambiguous') is set, and some *
* prefix was inserted, return now, bypassing the list-displaying *
* code. On the way, invalidate the list and note that we don't *
- * want to enter an AUTO_MENU imediately. */
+ * want to enter an AUTO_MENU immediately. */
if ((uselist == 3 ||
(!uselist && isset(BASHAUTOLIST) && isset(LISTAMBIGUOUS))) &&
la && iforcemenu != -1) {
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index cb1c01042..90db8b4b8 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -967,7 +967,7 @@ struct caarg {
#define CAA_RARGS 4
#define CAA_RREST 5
-/* The cache of parsed descriptons. */
+/* The cache of parsed descriptions. */
#define MAX_CACACHE 8
static Cadef cadef_cache[MAX_CACACHE];
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 58310cd74..c95c7a491 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -99,7 +99,7 @@
"recursive-edit", recursiveedit, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"redo", redo, ZLE_KEEPSUFFIX
-"reset-prompt", resetprompt, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"reset-prompt", resetprompt, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND | ZLE_NOLAST
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"select-a-word", selectword, ZLE_KEEPSUFFIX
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index f06c56483..609493f8c 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -217,6 +217,7 @@ struct widget {
#define ZLE_ISCOMP (1<<11) /* usable for new style completion */
#define WIDGET_INUSE (1<<12) /* widget is in use */
#define WIDGET_FREE (1<<13) /* request to free when no longer in use */
+#define ZLE_NOLAST (1<<14) /* widget should not alter lbindk */
/* thingies */
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index a5cf1011b..d13aed594 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -55,7 +55,7 @@ struct keymapname {
HashNode next; /* next in the hash chain */
char *nam; /* name of the keymap */
int flags; /* various flags (see below) */
- Keymap keymap; /* the keymap itsef */
+ Keymap keymap; /* the keymap itself */
};
/* Can't be deleted (.safe) */
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 3487b5d9f..be68f4722 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -632,7 +632,11 @@ raw_getbyte(long do_keytmout, char *cptr, int full)
* with all fds, then try unsetting the special ones.
*/
if (selret < 0 && !errtry) {
- errtry = 1;
+ /* Continue after irrelevant interrupt */
+ if (errno != EINTR) {
+ /* Don't trust special FDs */
+ errtry = 1;
+ }
continue;
}
if (selret == 0) {
@@ -704,7 +708,7 @@ raw_getbyte(long do_keytmout, char *cptr, int full)
*/
if (
# ifdef HAVE_POLL
- (fds[0].revents & POLLIN)
+ (fds[0].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL))
# else
FD_ISSET(SHTTY, &foofd)
# endif
@@ -889,7 +893,7 @@ getbyte(long do_keytmout, int *timeout, int full)
break;
if (r == 0) {
/* The test for IGNOREEOF was added to make zsh ignore ^Ds
- that were typed while commands are running. Unfortuantely
+ that were typed while commands are running. Unfortunately
this caused trouble under at least one system (SunOS 4.1).
Here shells that lost their xterm (e.g. if it was killed
with -9) didn't fail to read from the terminal but instead
@@ -901,7 +905,7 @@ getbyte(long do_keytmout, int *timeout, int full)
if ((zlereadflags & ZLRF_IGNOREEOF) && icnt++ < 20)
continue;
stopmsg = 1;
- zexit(1, 0);
+ zexit(1, ZEXIT_NORMAL);
}
icnt = 0;
if (errno == EINTR) {
@@ -924,7 +928,7 @@ getbyte(long do_keytmout, int *timeout, int full)
} else if (errno != 0) {
zerr("error on TTY read: %e", errno);
stopmsg = 1;
- zexit(1, 0);
+ zexit(1, ZEXIT_NORMAL);
}
}
if (cc == '\r') /* undo the exchange of \n and \r determined by */
@@ -1073,7 +1077,7 @@ redrawhook(void)
* temporarily reset state for special variable handling etc.
*/
incompfunc = 0;
- execzlefunc(initthingy, args, 1);
+ execzlefunc(initthingy, args, 1, 0);
incompfunc = old_incompfunc;
/* Restore errflag and retflag as zlecallhook() does */
@@ -1136,7 +1140,7 @@ zlecore(void)
eofsent = 1;
break;
}
- if (execzlefunc(bindk, zlenoargs, 0)) {
+ if (execzlefunc(bindk, zlenoargs, 0, 0)) {
handlefeep(zlenoargs);
if (eofsent)
break;
@@ -1256,7 +1260,6 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
resetneeded = 0;
fetchttyinfo = 0;
trashedzle = 0;
- clearflag = 0;
raw_lp = lp;
lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr);
raw_rp = rp;
@@ -1387,7 +1390,7 @@ execimmortal(Thingy func, char **args)
{
Thingy immortal = rthingy_nocreate(dyncat(".", func->nam));
if (immortal)
- return execzlefunc(immortal, args, 0);
+ return execzlefunc(immortal, args, 0, 0);
return 1;
}
@@ -1399,13 +1402,14 @@ execimmortal(Thingy func, char **args)
/**/
int
-execzlefunc(Thingy func, char **args, int set_bindk)
+execzlefunc(Thingy func, char **args, int set_bindk, int set_lbindk)
{
int r = 0, ret = 0, remetafy = 0;
int nestedvichg = vichgflag;
int isrepeat = (viinrepeat == 3);
Widget w;
Thingy save_bindk = bindk;
+ Thingy save_lbindk = lbindk;
if (set_bindk)
bindk = func;
@@ -1413,6 +1417,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
unmetafy_line();
remetafy = 1;
}
+ if (set_lbindk)
+ refthingy(save_lbindk);
if (isrepeat)
viinrepeat = 2;
@@ -1536,7 +1542,10 @@ execzlefunc(Thingy func, char **args, int set_bindk)
redup(osi, 0);
}
}
- if (r) {
+ if (set_lbindk) {
+ unrefthingy(lbindk);
+ lbindk = save_lbindk;
+ } else if (r) {
unrefthingy(lbindk);
refthingy(func);
lbindk = func;
@@ -1869,13 +1878,17 @@ describekeybriefly(UNUSED(char **args))
{
char *seq, *str, *msg, *is;
Thingy func;
+ Keymap km;
if (statusline)
return 1;
clearlist = 1;
statusline = "Describe key briefly: _";
zrefresh();
+ if (invicmdmode() && region_active && (km = openkeymap("visual")))
+ selectlocalmap(km);
seq = getkeymapcmd(curkeymap, &func, &str);
+ selectlocalmap(NULL);
statusline = NULL;
if(!*seq)
return 1;
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 1f293845f..7b8593dec 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -388,7 +388,7 @@ zle_free_highlight(void)
/*
* Interface to the region_highlight ZLE parameter.
- * Converts betwen a format like "P32 42 underline,bold" to
+ * Converts between a format like "P32 42 underline,bold" to
* the format in the region_highlights variable. Note that
* the region_highlights variable stores the internal (point/mark)
* region in element zero.
@@ -834,7 +834,7 @@ nextline(Rparams rpms, int wrapped)
if (rpms->nvln != -1 && rpms->nvln != winh - 1
&& (numscrolls != onumscrolls - 1
|| rpms->nvln <= winh / 2))
- return 1;
+ return 1;
numscrolls++;
rpms->canscroll = winh / 2;
}
@@ -1151,20 +1151,20 @@ zrefresh(void)
resetneeded = 0; /* unset */
oput_rpmpt = 0; /* no right-prompt currently on screen */
- if (!clearflag) {
- if (tccan(TCCLEAREOD))
- tcoutclear(TCCLEAREOD);
- else
- cleareol = 1; /* request: clear to end of line */
+ if (!clearflag) {
+ if (tccan(TCCLEAREOD))
+ tcoutclear(TCCLEAREOD);
+ else
+ cleareol = 1; /* request: clear to end of line */
if (listshown > 0)
listshown = 0;
}
- if (t0 > -1)
- olnct = (t0 < winh) ? t0 : winh;
- if (termflags & TERM_SHORT)
- vcs = 0;
+ if (t0 > -1)
+ olnct = (t0 < winh) ? t0 : winh;
+ if (termflags & TERM_SHORT)
+ vcs = 0;
else if (!clearflag && lpromptbuf[0]) {
- zputs(lpromptbuf, shout);
+ zputs(lpromptbuf, shout);
if (lpromptwof == winw)
zputs("\n", shout); /* works with both hasam and !hasam */
} else {
@@ -1678,7 +1678,12 @@ zrefresh(void)
moveto(0, winw - rprompt_off - rpromptw);
zputs(rpromptbuf, shout);
- vcs = winw - rprompt_off;
+ if (rprompt_off) {
+ vcs = winw - rprompt_off;
+ } else {
+ zputc(&zr_cr);
+ vcs = 0;
+ }
/* reset character attributes to that set by the main prompt */
txtchange = pmpt_attr;
/*
@@ -1885,7 +1890,7 @@ refreshline(int ln)
if (hasam && vcs == winw) {
if (nbuf[vln] && nbuf[vln][vcs + 1].chr == ZWC('\n')) {
vln++, vcs = 1;
- if (nbuf[vln] && nbuf[vln]->chr) {
+ if (nbuf[vln] && nbuf[vln]->chr) {
zputc(nbuf[vln]);
} else
zputc(&zr_sp); /* I don't think this should happen */
@@ -1954,11 +1959,11 @@ refreshline(int ln)
if (!nl->chr) {
if (ccs == winw && hasam && char_ins > 0 && ins_last
&& vcs != winw) {
- nl--; /* we can assume we can go back here */
+ nl--; /* we can assume we can go back here */
moveto(ln, winw - 1);
zputc(nl);
vcs++;
- return; /* write last character in line */
+ return; /* write last character in line */
}
if ((char_ins <= 0) || (ccs >= winw)) /* written everything */
return;
@@ -2159,24 +2164,19 @@ moveto(int ln, int cl)
const REFRESH_ELEMENT *rep;
if (vcs == winw) {
- if (rprompt_indent == 0 && tccan(TCLEFT)) {
- tc_leftcurs(1);
- vcs--;
+ vln++, vcs = 0;
+ if (!hasam) {
+ zputc(&zr_cr);
+ zputc(&zr_nl);
} else {
- vln++, vcs = 0;
- if (!hasam) {
- zputc(&zr_cr);
- zputc(&zr_nl);
- } else {
- if ((vln < nlnct) && nbuf[vln] && nbuf[vln]->chr)
- rep = nbuf[vln];
- else
- rep = &zr_sp;
- zputc(rep);
- zputc(&zr_cr);
- if ((vln < olnct) && obuf[vln] && obuf[vln]->chr)
- *obuf[vln] = *rep;
- }
+ if ((vln < nlnct) && nbuf[vln] && nbuf[vln]->chr)
+ rep = nbuf[vln];
+ else
+ rep = &zr_sp;
+ zputc(rep);
+ zputc(&zr_cr);
+ if ((vln < olnct) && obuf[vln] && obuf[vln]->chr)
+ *obuf[vln] = *rep;
}
}
@@ -2212,7 +2212,7 @@ moveto(int ln, int cl)
}
if (cl != vcs)
- singmoveto(cl);
+ singmoveto(cl);
}
/**/
@@ -2292,7 +2292,7 @@ tc_rightcurs(int ct)
/* it is cheaper to send TCRIGHT than reprint the whole prompt */
for (ct = lpromptw - i; ct--; )
tcout(TCRIGHT);
- else {
+ else {
if (i != 0)
zputc(&zr_cr);
tc_upcurs(lprompth - 1);
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 6b892b822..ce61db27b 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -703,7 +703,7 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
{
Thingy t;
struct modifier modsave = zmod;
- int ret, saveflag = 0, setbindk = 0, remetafy;
+ int ret, saveflag = 0, setbindk = 0, setlbindk, remetafy;
char *wname = *args++, *keymap_restore = NULL, *keymap_tmp;
if (!wname)
@@ -787,7 +787,8 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
* a vi range to detect a repeated key */
setbindk = setbindk ||
(t->widget && (t->widget->flags & (WIDGET_INT | ZLE_VIOPER)) == WIDGET_INT);
- ret = execzlefunc(t, args, setbindk);
+ setlbindk = t->widget && (t->widget->flags & ZLE_NOLAST) == ZLE_NOLAST;
+ ret = execzlefunc(t, args, setbindk, setlbindk);
unrefthingy(t);
if (saveflag)
zmod = modsave;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 2b25d6b2e..fdd168763 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1236,8 +1236,10 @@ get_comp_string(void)
else if (tok == OUTPAR) {
if (parct)
parct--;
- else
+ else if (linarr) {
linarr = 0;
+ incmdpos = 1;
+ }
}
if (inredir && IS_REDIROP(tok)) {
rdstr = rdstrbuf;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index c6df3d89c..2b306fdcd 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1607,7 +1607,11 @@ static int
unapplychange(struct change *ch)
{
if(ch->hist != histline) {
- zle_setline(quietgethist(ch->hist));
+ Histent he = quietgethist(ch->hist);
+ DPUTS(he == NULL, "quietgethist(ch->hist) returned NULL");
+ if(he == NULL)
+ return 1;
+ zle_setline(he);
zlecs = ch->new_cs;
return 0;
}
@@ -1647,7 +1651,11 @@ static int
applychange(struct change *ch)
{
if(ch->hist != histline) {
- zle_setline(quietgethist(ch->hist));
+ Histent he = quietgethist(ch->hist);
+ DPUTS(he == NULL, "quietgethist(ch->hist) returned NULL");
+ if(he == NULL)
+ return 1;
+ zle_setline(he);
zlecs = ch->old_cs;
return 0;
}
@@ -1733,7 +1741,7 @@ zlecallhook(char *name, char *arg)
args[0] = arg;
args[1] = NULL;
- execzlefunc(thingy, args, 1);
+ execzlefunc(thingy, args, 1, 0);
unrefthingy(thingy);
/* Retain any user interrupt error status */
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index a5ff9200c..0f198d0e8 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -216,7 +216,7 @@ getvirange(int wf)
* a number of lines is used. If the function used
* returns 1, we fail.
*/
- if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1))
+ if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1, 0))
ret = -1;
if (viinrepeat)
zmult = mult1;
diff --git a/Src/builtin.c b/Src/builtin.c
index 8dcdcc024..aa5767cf1 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -74,7 +74,7 @@ static struct builtin builtins[] =
BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlp:%rtux", "E"),
- BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMstTuUWx:z", NULL),
+ BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "ckmMstTuUWx:z", 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),
@@ -720,7 +720,7 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
/**** directory-handling builtins ****/
/**/
-int doprintdir = 0; /* set in exec.c (for autocd) */
+int doprintdir = 0; /* set in exec.c (for autocd, cdpath, etc.) */
/* pwd: display the name of the current directory */
@@ -912,7 +912,7 @@ cd_get_dest(char *nam, char **argv, int hard, int func)
char *end;
doprintdir++;
- if (argv[0][1] && (argv[0][0] == '+' || argv[0][0] == '-')
+ if (!isset(POSIXCD) && argv[0][1] && (argv[0][0] == '+' || argv[0][0] == '-')
&& strspn(argv[0]+1, "0123456789") == strlen(argv[0]+1)) {
dd = zstrtol(argv[0] + 1, &end, 10);
if (*end == '\0') {
@@ -1251,7 +1251,7 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
if (func != BIN_CD && isset(INTERACTIVE)) {
if (unset(PUSHDSILENT) && !quiet)
printdirstack();
- } else if (doprintdir) {
+ } else if (unset(CDSILENT) && doprintdir) {
fprintdir(pwd, stdout);
putchar('\n');
}
@@ -1718,7 +1718,7 @@ fcsubs(char **sp, struct asgment *sub)
newstr = sub->value.scalar;
sub = (Asgment)sub->node.next;
oldpos = s;
- /* loop over occurences of oldstr in s, replacing them with newstr */
+ /* loop over occurrences of oldstr in s, replacing them with newstr */
while ((newpos = (char *)strstr(oldpos, oldstr))) {
newmem = (char *) zhalloc(1 + (newpos - s)
+ strlen(newstr) + strlen(newpos + strlen(oldstr)));
@@ -2171,7 +2171,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
!ASG_VALUEP(asg))
on |= PM_UNSET;
else if (usepm && (pm->node.flags & PM_READONLY) &&
- !(on & PM_READONLY)) {
+ !(on & PM_READONLY) && func != BIN_EXPORT) {
zerr("read-only variable: %s", pm->node.nam);
return NULL;
}
@@ -2526,7 +2526,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
* Attempt to assign a scalar value to an array.
* This can happen if the array is special.
* We'll be lenient and guess what the user meant.
- * This is how normal assigment works.
+ * This is how normal assignment works.
*/
if (*asg->value.scalar) {
/* Array with one value */
@@ -2582,9 +2582,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
}
}
pm->node.flags |= (on & PM_READONLY);
-
- if (OPT_ISSET(ops,'p'))
- paramtab->printnode(&pm->node, PRINT_TYPESET);
+ DPUTS(OPT_ISSET(ops,'p'), "BUG: -p not handled");
return pm;
}
@@ -2714,7 +2712,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
(!isset(GLOBALEXPORT) && !OPT_ISSET(ops,'g')))
on |= PM_LOCAL;
- if (on & PM_TIED) {
+ if ((on & PM_TIED) && !OPT_ISSET(ops, 'p')) {
Param apm;
struct asgment asg0, asg2;
char *oldval = NULL, *joinstr;
@@ -3031,7 +3029,7 @@ eval_autoload(Shfunc shf, char *name, Options ops, int func)
}
if (OPT_MINUS(ops,'X')) {
char *fargv[3];
- fargv[0] = name;
+ fargv[0] = quotestring(name, QT_SINGLE_OPTIONAL);
fargv[1] = "\"$@\"";
fargv[2] = 0;
shf->funcdef = mkautofn(shf);
@@ -3250,11 +3248,50 @@ bin_functions(char *name, char **argv, Options ops, int func)
if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
(OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) ||
- (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || !scriptname))) {
+ (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || !scriptname)) ||
+ (OPT_ISSET(ops,'c') && (OPT_ISSET(ops,'x') || OPT_ISSET(ops,'X') ||
+ OPT_ISSET(ops,'m')))) {
zwarnnam(name, "invalid option(s)");
return 1;
}
+ if (OPT_ISSET(ops,'c')) {
+ Shfunc newsh;
+ if (!*argv || !argv[1] || argv[2]) {
+ zwarnnam(name, "-c: requires two arguments");
+ return 1;
+ }
+ shf = (Shfunc) shfunctab->getnode(shfunctab, *argv);
+ if (!shf) {
+ zwarnnam(name, "no such function: %s", *argv);
+ return 1;
+ }
+ if (shf->node.flags & PM_UNDEFINED) {
+ if (shf->funcdef) {
+ freeeprog(shf->funcdef);
+ shf->funcdef = &dummy_eprog;
+ }
+ shf = loadautofn(shf, 1, 0, 0);
+ if (!shf)
+ return 1;
+ }
+ newsh = zalloc(sizeof(*newsh));
+ memcpy(newsh, shf, sizeof(*newsh));
+ if (newsh->node.flags & PM_LOADDIR) {
+ /* Expand original location of autoloaded file */
+ newsh->node.flags &= ~PM_LOADDIR;
+ newsh->filename = tricat(shf->filename, "/", shf->node.nam);
+ } else
+ newsh->filename = ztrdup(shf->filename);
+ newsh->funcdef->nref++;
+ if (newsh->redir)
+ newsh->redir->nref++;
+ if (shf->sticky)
+ newsh->sticky = sticky_emulation_dup(sticky, 0);
+ shfunctab->addnode(shfunctab, ztrdup(argv[1]), &newsh->node);
+ return 0;
+ }
+
if (OPT_ISSET(ops,'x')) {
char *eptr;
expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10);
@@ -4993,8 +5030,7 @@ bin_print(char *name, char **args, Options ops, int func)
narg = strtoul(c, &endptr, 0);
if (*endptr == '$') {
c = endptr + 1;
- DPUTS(narg <= 0, "specified zero or negative arg");
- if (narg > argc) {
+ if (narg <= 0 || narg > argc) {
zwarnnam(name, "%d: argument specifier out of range",
narg);
if (fout != stdout)
@@ -5514,14 +5550,12 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
/* check for legality */
if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
p = "?";
- err:
zsfree(zoptarg);
setsparam(var, ztrdup(p));
if(quiet) {
zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
} else {
- zwarn(*p == '?' ? "bad option: %c%c" :
- "argument expected after %c%c option",
+ zwarn("bad option: %c%c",
"?-+"[lenoptbuf], opch);
zoptarg=ztrdup("");
}
@@ -5532,8 +5566,17 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
if(p[1] == ':') {
if(optcind == lenstr) {
if(!args[zoptind]) {
- p = ":";
- goto err;
+ zsfree(zoptarg);
+ if(quiet) {
+ setsparam(var, ztrdup(":"));
+ zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
+ } else {
+ setsparam(var, ztrdup("?"));
+ zoptarg = ztrdup("");
+ zwarn("argument expected after %c%c option",
+ "?-+"[lenoptbuf], opch);
+ }
+ return 0;
}
p = ztrdup(args[zoptind++]);
} else
@@ -5558,7 +5601,11 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
return 0;
}
-/* Flag that we should exit the shell as soon as all functions return. */
+/* Boolean flag that we should exit the shell as soon as all functions return.
+ *
+ * Set by the 'exit' builtin.
+ */
+
/**/
mod_export int
exit_pending;
@@ -5622,7 +5669,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
}
return lastval;
}
- zexit(num, 0); /* else treat return as logout/exit */
+ zexit(num, ZEXIT_NORMAL); /* else treat return as logout/exit */
break;
case BIN_LOGOUT:
if (unset(LOGINSHELL)) {
@@ -5644,7 +5691,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
* If we are already exiting... give this all up as
* a bad job.
*/
- if (stopmsg || (zexit(0,2), !stopmsg)) {
+ if (stopmsg || (zexit(0, ZEXIT_DEFERRED), !stopmsg)) {
retflag = 1;
breaks = loops;
exit_pending = 1;
@@ -5652,7 +5699,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
exit_val = num;
}
} else
- zexit(num, 0);
+ zexit(num, ZEXIT_NORMAL);
break;
}
return 0;
@@ -5737,14 +5784,15 @@ _realexit(void)
/* exit the shell. val is the return value of the shell. *
* from_where is
- * 1 if zexit is called because of a signal
- * 2 if we can't actually exit yet (e.g. functions need
- * terminating) but should perform the usual interactive tests.
+ * ZEXIT_SIGNAL if zexit is called because of a signal
+ * ZEXIT_DEFERRED if we can't actually exit yet (e.g., functions need
+ * terminating) but should perform the usual interactive
+ * tests.
*/
/**/
mod_export void
-zexit(int val, int from_where)
+zexit(int val, enum zexit_t from_where)
{
/*
* Don't do anything recursively: see below.
@@ -5755,7 +5803,7 @@ zexit(int val, int from_where)
if (shell_exiting == -1)
return;
- if (isset(MONITOR) && !stopmsg && from_where != 1) {
+ if (isset(MONITOR) && !stopmsg && from_where != ZEXIT_SIGNAL) {
scanjobs(); /* check if jobs need printing */
if (isset(CHECKJOBS))
checkjobs(); /* check if any jobs are running/stopped */
@@ -5764,8 +5812,9 @@ zexit(int val, int from_where)
return;
}
}
- /* Positive in_exit means we have been here before */
- if (from_where == 2 || (shell_exiting++ && from_where))
+ /* Positive shell_exiting means we have been here before */
+ if (from_where == ZEXIT_DEFERRED ||
+ (shell_exiting++ && from_where != ZEXIT_NORMAL))
return;
/*
@@ -5781,12 +5830,12 @@ zexit(int val, int from_where)
if (isset(MONITOR)) {
/* send SIGHUP to any jobs left running */
- killrunjobs(from_where == 1);
+ killrunjobs(from_where == ZEXIT_SIGNAL);
}
if (isset(RCS) && interact) {
if (!nohistsave) {
int writeflags = HFILE_USE_OPTIONS;
- if (from_where == 1)
+ if (from_where == ZEXIT_SIGNAL)
writeflags |= HFILE_NO_REWRITE;
saveandpophiststack(1, writeflags);
savehistfile(NULL, 1, writeflags);
@@ -7238,8 +7287,11 @@ bin_umask(char *nam, char **args, Options ops, UNUSED(int func))
char *s = *args;
/* Get the current umask. */
- um = umask(0);
+ queue_signals();
+ um = umask(0777);
umask(um);
+ unqueue_signals();
+
/* No arguments means to display the current setting. */
if (!s) {
if (OPT_ISSET(ops,'S')) {
diff --git a/Src/compat.c b/Src/compat.c
index 7b5c4411c..8ab335aa1 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -30,8 +30,8 @@
#include "zsh.mdh"
#include "compat.pro"
-/* Return pointer to first occurence of string t *
- * in string s. Return NULL if not present. */
+/* Return pointer to first occurrence of string t *
+ * in string s. Return NULL if not present. */
/**/
#ifndef HAVE_STRSTR
@@ -361,8 +361,18 @@ zgetdir(struct dirsav *d)
pino = sbuf.st_ino;
pdev = sbuf.st_dev;
- /* If they're the same, we've reached the root directory. */
+ /* If they're the same, we've reached the root directory... */
if (ino == pino && dev == pdev) {
+ /*
+ * ...well, probably. If this was an orphaned . after
+ * an unmount, or something such, we could be in trouble...
+ */
+ if (stat("/", &sbuf) < 0 ||
+ sbuf.st_ino != ino ||
+ sbuf.st_dev != dev) {
+ zerr("Failed to get current directory: path invalid");
+ return NULL;
+ }
if (!buf[pos])
buf[--pos] = '/';
if (d) {
@@ -509,7 +519,7 @@ zgetcwd(void)
#endif /* HAVE_GETCWD */
if (!ret)
ret = unmeta(pwd);
- if (!ret)
+ if (!ret || *ret == '\0')
ret = dupstring(".");
return ret;
}
diff --git a/Src/exec.c b/Src/exec.c
index 042ba065a..50027654a 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -940,6 +940,8 @@ hashcmd(char *arg0, char **pp)
char *s, buf[PATH_MAX+1];
char **pq;
+ if (*arg0 == '/')
+ return NULL;
for (; *pp; pp++)
if (**pp == '/') {
s = buf;
@@ -969,6 +971,10 @@ hashcmd(char *arg0, char **pp)
return cn;
}
+/* The value that 'locallevel' had when we forked. When we get back to this
+ * level, the current process (which is a subshell) will terminate.
+ */
+
/**/
int
forklevel;
@@ -1688,7 +1694,8 @@ execpline(Estate state, wordcode slcode, int how, int last1)
lastwj = thisjob = newjob;
- if (list_pipe || (pline_level && !(how & Z_TIMED)))
+ if (list_pipe || (pline_level && !(how & Z_TIMED) &&
+ !(jn->stat & STAT_NOSTTY)))
jn->stat |= STAT_NOPRINT;
if (nowait) {
@@ -2533,7 +2540,7 @@ setunderscore(char *str)
{
queue_signals();
if (str && *str) {
- int l = strlen(str) + 1, nl = (l + 31) & ~31;
+ size_t l = strlen(str) + 1, nl = (l + 31) & ~31;
if (nl > underscorelen || (underscorelen - nl) > 64) {
zfree(zunderscore, underscorelen);
@@ -2762,9 +2769,12 @@ execcmd_fork(Estate state, int how, int type, Wordcode varspc,
sigtrapped[SIGEXIT] = 0;
#ifdef HAVE_NICE
/* Check if we should run background jobs at a lower priority. */
- if ((how & Z_ASYNC) && isset(BGNICE))
- if (nice(5) < 0)
+ if ((how & Z_ASYNC) && isset(BGNICE)) {
+ errno = 0;
+ nice(5);
+ if (errno)
zwarn("nice(5) failed: %e", errno);
+ }
#endif /* HAVE_NICE */
return 0;
@@ -4293,7 +4303,7 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
(unset(RESTRICTED) || !(pm->node.flags & PM_RESTRICTED))) {
/*
* In this case we're just saving parts of
- * the parameter in a tempory, so use heap allocation
+ * the parameter in a temporary, so use heap allocation
* and don't bother copying every detail.
*/
tpm = (Param) hcalloc(sizeof *tpm);
@@ -4405,8 +4415,10 @@ closem(int how, int all)
/*
* Process substitution needs to be visible to user;
* fd's are explicitly cleaned up by filelist handling.
+ * External FDs are managed directly by the user.
*/
- (all || fdtable[i] != FDT_PROC_SUBST) &&
+ (all || (fdtable[i] != FDT_PROC_SUBST &&
+ fdtable[i] != FDT_EXTERNAL)) &&
(how == FDT_UNUSED || (fdtable[i] & FDT_TYPE_MASK) == how)) {
if (i == SHTTY)
SHTTY = -1;
@@ -4638,19 +4650,25 @@ getoutput(char *cmd, int qt)
return NULL;
}
-/* read output of command substitution */
+/* read output of command substitution
+ *
+ * The file descriptor "in" is closed by the function.
+ *
+ * "qt" indicates if the substitution was in double quotes.
+ *
+ * "readerror", if not NULL, is used to return any error that
+ * occurred during the read.
+ */
/**/
mod_export LinkList
readoutput(int in, int qt, int *readerror)
{
LinkList ret;
- char *buf, *ptr;
- int bsiz, c, cnt = 0;
- FILE *fin;
+ char *buf, *bufptr, *ptr, inbuf[64];
+ int bsiz, c, cnt = 0, readret;
int q = queue_signal_level();
- fin = fdopen(in, "r");
ret = newlinklist();
ptr = buf = (char *) hcalloc(bsiz = 64);
/*
@@ -4662,33 +4680,38 @@ readoutput(int in, int qt, int *readerror)
*/
dont_queue_signals();
child_unblock();
- while ((c = fgetc(fin)) != EOF || errno == EINTR) {
- if (c == EOF) {
- errno = 0;
- clearerr(fin);
- continue;
- }
- if (imeta(c)) {
- *ptr++ = Meta;
- c ^= 32;
- cnt++;
+ for (;;) {
+ readret = read(in, inbuf, 64);
+ if (readret <= 0) {
+ if (readret < 0 && errno == EINTR)
+ continue;
+ else
+ break;
}
- if (++cnt >= bsiz) {
- char *pp;
- queue_signals();
- pp = (char *) hcalloc(bsiz *= 2);
- dont_queue_signals();
+ for (bufptr = inbuf; bufptr < inbuf + readret; bufptr++) {
+ c = *bufptr;
+ if (imeta(c)) {
+ *ptr++ = Meta;
+ c ^= 32;
+ cnt++;
+ }
+ if (++cnt >= bsiz) {
+ char *pp;
+ queue_signals();
+ pp = (char *) hcalloc(bsiz *= 2);
+ dont_queue_signals();
- memcpy(pp, buf, cnt - 1);
- ptr = (buf = pp) + cnt - 1;
+ memcpy(pp, buf, cnt - 1);
+ ptr = (buf = pp) + cnt - 1;
+ }
+ *ptr++ = c;
}
- *ptr++ = c;
}
child_block();
restore_queue_signals(q);
if (readerror)
- *readerror = ferror(fin) ? errno : 0;
- fclose(fin);
+ *readerror = readret < 0 ? errno : 0;
+ close(in);
while (cnt && ptr[-1] == '\n')
ptr--, cnt--;
*ptr = '\0';
@@ -4821,6 +4844,7 @@ getoutputfile(char *cmd, char **eptr)
}
/* pid == 0 */
+ closem(FDT_UNUSED, 0);
redup(fd, 1);
entersubsh(ESUB_PGRP|ESUB_NOMONITOR, NULL);
cmdpush(CS_CMDSUBST);
@@ -4982,7 +5006,7 @@ getpipe(char *cmd, int nullexec)
procsubstpid = pid;
return pipes[!out];
}
- entersubsh(ESUB_PGRP, NULL);
+ entersubsh(ESUB_ASYNC|ESUB_PGRP, NULL);
redup(pipes[out], out);
closem(FDT_UNUSED, 0); /* this closes pipes[!out] as well */
cmdpush(CS_CMDSUBST);
@@ -5929,7 +5953,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
* exit command was handled.
*/
stopmsg = 1;
- zexit(exit_val, 0);
+ zexit(exit_val, ZEXIT_NORMAL);
}
}
diff --git a/Src/glob.c b/Src/glob.c
index ed2c90bd8..f67a376b9 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -274,7 +274,7 @@ addpath(char *s, int l)
}
/* stat the filename s appended to pathbuf. l should be true for lstat, *
- * false for stat. If st is NULL, the file is only checked for existance. *
+ * false for stat. If st is NULL, the file is only checked for existence. *
* s == "" is treated as s == ".". This is necessary since on most systems *
* foo/ can be used to reference a non-directory foo. Returns nonzero if *
* the file does not exists. */
@@ -400,7 +400,7 @@ insert(char *s, int checked)
if (colonmod) {
/* Handle the remainder of the qualifier: e.g. (:r:s/foo/bar/). */
char *mod = colonmod;
- modify(&news, &mod);
+ modify(&news, &mod, 1);
}
if (!statted && (gf_sorts & GS_NORMAL)) {
statfullpath(s, &buf, 1);
@@ -566,7 +566,7 @@ scanner(Complist q, int shortcircuit)
continue;
errsfound = errssofar;
if (pattry(p, fn)) {
- /* if this name matchs the pattern... */
+ /* if this name matches the pattern... */
if (pbcwdsav == pathbufcwd &&
strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) {
int err;
@@ -2909,6 +2909,12 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
mb_charinit();
tmatch = NULL;
+ set_pat_start(p, l);
+ if (pattrylen(p, send, 0, 0, &patstralloc, umltot) &&
+ !--n) {
+ *sp = get_match_ret(&imd, umltot, umltot);
+ return 1;
+ }
for (ioff = 0, t = s, umlen = umltot; t < send; ioff++) {
set_pat_start(p, t-s);
if (pattrylen(p, t, umlen, 0, &patstralloc, ioff))
@@ -3053,7 +3059,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
case (SUB_END|SUB_SUBSTR):
case (SUB_END|SUB_LONG|SUB_SUBSTR):
/* Longest/shortest at end, matching substrings. */
- if (!(fl & SUB_LONG)) {
+ {
set_pat_start(p, l);
if (pattrylen(p, send, 0, 0, &patstralloc, umltot) &&
!--n) {
@@ -3391,7 +3397,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
case (SUB_END|SUB_SUBSTR):
case (SUB_END|SUB_LONG|SUB_SUBSTR):
/* Longest/shortest at end, matching substrings. */
- if (!(fl & SUB_LONG)) {
+ {
set_pat_start(p, l);
if (pattrylen(p, send, 0, 0, &patstralloc, uml) && !--n) {
*sp = get_match_ret(&imd, uml, uml);
diff --git a/Src/hashtable.c b/Src/hashtable.c
index b7baa3142..e210ddeca 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -996,7 +996,7 @@ printshfuncnode(HashNode hn, int printflags)
* expansion of leading tabs.
* expand = 0 is standard: use hard tabs.
* expand > 0 uses that many spaces.
- * expand < 0 uses no identation.
+ * expand < 0 uses no indentation.
*
* Note this function and the following two are called with
* interrupts queued, so saving and restoring text_expand_tabs
diff --git a/Src/hist.c b/Src/hist.c
index dbdc1e4e5..5281e8718 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -181,7 +181,7 @@ mod_export char *chline;
* To avoid having to modify this every time we modify chline,
* we set it when we push the stack, and unset it when we pop
* the appropriate value off the stack. As it's never modified
- * on the stack this is the only maintainance we ever do on it.
+ * on the stack this is the only maintenance we ever do on it.
* In return, ZLE has to check both zle_chline and (if that's
* NULL) chline to get the current value.
*/
@@ -216,6 +216,7 @@ static struct histfile_stats {
char *text;
time_t stim, mtim;
off_t fpos, fsiz;
+ int interrupted;
zlong next_write_ev;
} lasthist;
@@ -475,7 +476,7 @@ herrflush(void)
*
* Note that this is a side effect --- this is not the usual reason
* for testing lex_add_raw which is to add the text to a different
- * buffer used when we are actually parsing the command substituion
+ * buffer used when we are actually parsing the command substitution
* (nothing to do with ZLE). Sorry.
*/
while (inbufct && (!strin || lex_add_raw)) {
@@ -554,6 +555,27 @@ substfailed(void)
return -1;
}
+/*
+ * Return a count given by decimal digits after a modifier.
+ */
+static int
+digitcount(void)
+{
+ int c = ingetc(), count;
+
+ if (idigit(c)) {
+ count = 0;
+ do {
+ count = 10 * count + (c - '0');
+ c = ingetc();
+ } while (idigit(c));
+ }
+ else
+ count = 0;
+ inungetc(c);
+ return count;
+}
+
/* Perform history substitution, returning the next character afterwards. */
/**/
@@ -834,7 +856,7 @@ histsubchar(int c)
}
break;
case 'h':
- if (!remtpath(&sline)) {
+ if (!remtpath(&sline, digitcount())) {
herrflush();
zerr("modifier failed: h");
return -1;
@@ -855,7 +877,7 @@ histsubchar(int c)
}
break;
case 't':
- if (!remlpaths(&sline)) {
+ if (!remlpaths(&sline, digitcount())) {
herrflush();
zerr("modifier failed: t");
return -1;
@@ -898,6 +920,16 @@ histsubchar(int c)
case 'u':
sline = casemodify(sline, CASMOD_UPPER);
break;
+ case 'P':
+ if (*sline != '/') {
+ char *here = zgetcwd();
+ if (here[strlen(here)-1] != '/')
+ sline = zhtricat(metafy(here, -1, META_HEAPDUP), "/", sline);
+ else
+ sline = dyncat(here, sline);
+ }
+ sline = xsymlink(sline, 1);
+ break;
default:
herrflush();
zerr("illegal modifier: %c", c);
@@ -1197,8 +1229,9 @@ histreduceblanks(void)
chline[pos] = '\0';
} else {
ptr = chline + pos;
- while ((*ptr++ = *lastptr++))
- ;
+ if (ptr < lastptr)
+ while ((*ptr++ = *lastptr++))
+ ;
}
}
@@ -1972,16 +2005,18 @@ chrealpath(char **junkptr)
/**/
int
-remtpath(char **junkptr)
+remtpath(char **junkptr, int count)
{
char *str = strend(*junkptr);
/* ignore trailing slashes */
while (str >= *junkptr && IS_DIRSEP(*str))
--str;
- /* skip filename */
- while (str >= *junkptr && !IS_DIRSEP(*str))
- --str;
+ if (!count) {
+ /* skip filename */
+ while (str >= *junkptr && !IS_DIRSEP(*str))
+ --str;
+ }
if (str < *junkptr) {
if (IS_DIRSEP(**junkptr))
*junkptr = dupstring ("/");
@@ -1990,6 +2025,34 @@ remtpath(char **junkptr)
return 0;
}
+
+ if (count)
+ {
+ /*
+ * Return this many components, so start from the front.
+ * Leading slash counts as one component, consistent with
+ * behaviour of repeated applications of :h.
+ */
+ char *strp = *junkptr;
+ while (strp < str) {
+ if (IS_DIRSEP(*strp)) {
+ if (--count <= 0) {
+ if (strp == *junkptr)
+ ++strp;
+ *strp = '\0';
+ return 1;
+ }
+ /* Count consecutive separators as one */
+ while (IS_DIRSEP(strp[1]))
+ ++strp;
+ }
+ ++strp;
+ }
+
+ /* Full string needed */
+ return 1;
+ }
+
/* repeated slashes are considered like a single slash */
while (str > *junkptr && IS_DIRSEP(str[-1]))
--str;
@@ -2038,7 +2101,7 @@ rembutext(char **junkptr)
/**/
mod_export int
-remlpaths(char **junkptr)
+remlpaths(char **junkptr, int count)
{
char *str = strend(*junkptr);
@@ -2048,12 +2111,29 @@ remlpaths(char **junkptr)
--str;
str[1] = '\0';
}
- for (; str >= *junkptr; --str)
- if (IS_DIRSEP(*str)) {
- *str = '\0';
- *junkptr = dupstring(str + 1);
- return 1;
+ for (;;) {
+ for (; str >= *junkptr; --str) {
+ if (IS_DIRSEP(*str)) {
+ if (--count > 0) {
+ if (str > *junkptr) {
+ --str;
+ break;
+ } else {
+ /* Whole string needed */
+ return 1;
+ }
+ }
+ *str = '\0';
+ *junkptr = dupstring(str + 1);
+ return 1;
+ }
}
+ /* Count consecutive separators as 1 */
+ while (str >= *junkptr && IS_DIRSEP(*str))
+ --str;
+ if (str <= *junkptr)
+ break;
+ }
return 0;
}
@@ -2544,11 +2624,13 @@ readhistfile(char *fn, int err, int readflags)
sb.st_size == 0)
return;
if (readflags & HFILE_FAST) {
- if ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
- || lockhistfile(fn, 0))
+ if (!lasthist.interrupted &&
+ ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
+ || lockhistfile(fn, 0)))
return;
lasthist.fsiz = sb.st_size;
lasthist.mtim = sb.st_mtime;
+ lasthist.interrupted = 0;
} else if ((ret = lockhistfile(fn, 1))) {
if (ret == 2) {
zwarn("locking failed for %s: %e: reading anyway", fn, errno);
@@ -2694,8 +2776,11 @@ readhistfile(char *fn, int err, int readflags)
*/
if (uselex || remeta)
freeheap();
- if (errflag & ERRFLAG_INT)
+ if (errflag & ERRFLAG_INT) {
+ /* Can't assume fast read next time if interrupted. */
+ lasthist.interrupted = 1;
break;
+ }
}
if (start && readflags & HFILE_USE_OPTIONS) {
zsfree(lasthist.text);
@@ -3236,6 +3321,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags)
int owb = wb, owe = we, oadx = addedx, onc = nocomments;
int ona = noaliases, ocs = zlemetacs, oll = zlemetall;
int forloop = 0, rcquotes = opts[RCQUOTES];
+ int envarray = 0;
char *p, *addedspaceptr;
if (!list)
@@ -3319,6 +3405,14 @@ bufferwords(LinkList list, char *buf, int *index, int flags)
ctxtlex();
if (tok == ENDINPUT || tok == LEXERR)
break;
+ /*
+ * After an array assignment, return to the initial
+ * start-of-command state. There could be a second ENVARRAY.
+ */
+ if (tok == OUTPAR && envarray) {
+ incmdpos = 1;
+ envarray = 0;
+ }
if (tok == FOR) {
/*
* The way for (( expr1 ; expr2; expr3 )) is parsed is:
@@ -3356,6 +3450,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags)
switch (tok) {
case ENVARRAY:
p = dyncat(tokstr, "=(");
+ envarray = 1;
break;
case DINPAR:
diff --git a/Src/init.c b/Src/init.c
index e7e62e2f7..04a5856ff 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -45,7 +45,10 @@ int noexitct = 0;
char *zunderscore;
/**/
-int underscorelen, underscoreused;
+size_t underscorelen;
+
+/**/
+int underscoreused;
/* what level of sourcing we are at */
@@ -134,7 +137,7 @@ loop(int toplevel, int justonce)
else
stophist = hstop;
/*
- * Reset all errors, including user interupts.
+ * Reset all errors, including user interrupts.
* This is what allows ^C in an interactive shell
* to return us to the command line.
*/
@@ -158,7 +161,7 @@ loop(int toplevel, int justonce)
* Handle that now.
*/
stopmsg = 1;
- zexit(exit_val, 0);
+ zexit(exit_val, ZEXIT_NORMAL);
}
if (tok == LEXERR && !lastval)
lastval = 1;
@@ -200,7 +203,7 @@ loop(int toplevel, int justonce)
* that would be inconsistent with the case where
* we didn't execute a preexec function. This is
* an implementation detail that an interrupting user
- * does't care about.
+ * doesn't care about.
*/
errflag &= ~ERRFLAG_ERROR;
}
@@ -359,7 +362,7 @@ static void parseopts_setemulate(char *nam, int flags)
* Parse shell options.
*
* If (flags & PARSEARGS_TOPLEVEL):
- * - we are doing shell initilisation
+ * - we are doing shell initialisation
* - nam is the name under which the shell was started
* - set up emulation and standard options based on that.
* Otherwise:
@@ -879,7 +882,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
char *ptr;
int i, j;
#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) || defined(FIXED_FPATH_DIR)
-#define FPATH_NEEDS_INIT 1
+# define FPATH_NEEDS_INIT 1
char **fpathptr;
# if defined(FPATH_DIR) && defined(FPATH_SUBDIRS)
char *fpath_subdirs[] = FPATH_SUBDIRS;
@@ -991,18 +994,29 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
# endif /* ADDITONAL_FPATH */
fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *));
# ifdef FIXED_FPATH_DIR
+ /* Zeroth: /usr/local/share/zsh/site-functions */
*fpathptr++ = ztrdup(FIXED_FPATH_DIR);
fpathlen--;
# endif
# ifdef SITEFPATH_DIR
+ /* First: the directory from --enable-site-fndir
+ *
+ * default: /usr/local/share/zsh/site-functions
+ * (but changeable by passing --prefix or --datadir to configure) */
*fpathptr++ = ztrdup(SITEFPATH_DIR);
fpathlen--;
# endif /* SITEFPATH_DIR */
# if defined(ADDITIONAL_FPATH)
+ /* Second: the directories from --enable-additional-fpath
+ *
+ * default: empty list */
for (j = 0; j < more_fndirs_len; j++)
*fpathptr++ = ztrdup(more_fndirs[j]);
# endif
# ifdef FPATH_DIR
+ /* Third: The directory from --enable-fndir
+ *
+ * default: /usr/local/share/zsh/${ZSH_VERSION}/functions */
# ifdef FPATH_SUBDIRS
# ifdef ADDITIONAL_FPATH
for (j = more_fndirs_len; j < fpathlen; j++)
@@ -1010,7 +1024,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
# else
for (j = 0; j < fpathlen; j++)
*fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j]);
-#endif
+# endif
# else
*fpathptr++ = ztrdup(FPATH_DIR);
# endif
@@ -1234,6 +1248,15 @@ init_signals(void)
intr();
+#ifdef POSIX_SIGNALS
+ {
+ struct sigaction act;
+ if (!sigaction(SIGQUIT, NULL, &act) &&
+ act.sa_handler == SIG_IGN)
+ sigtrapped[SIGQUIT] = ZSIG_IGNORED;
+ }
+#endif
+
#ifndef QDEBUG
signal_ignore(SIGQUIT);
#endif
@@ -1359,7 +1382,7 @@ init_misc(char *cmd, char *zsh_name)
bshin = fdopen(SHIN, "r");
execstring(cmd, 0, 1, "cmdarg");
stopmsg = 1;
- zexit((exit_pending || shell_exiting) ? exit_val : lastval, 0);
+ zexit((exit_pending || shell_exiting) ? exit_val : lastval, ZEXIT_NORMAL);
}
if (interact && isset(RCS))
@@ -1766,20 +1789,20 @@ zsh_main(UNUSED(int argc), char **argv)
if (!lastval)
lastval = 1;
stopmsg = 1;
- zexit(lastval, 0);
+ zexit(lastval, ZEXIT_NORMAL);
}
if (!(isset(IGNOREEOF) && interact)) {
#if 0
if (interact)
fputs(islogin ? "logout\n" : "exit\n", shout);
#endif
- zexit(lastval, 0);
+ zexit(lastval, ZEXIT_NORMAL);
continue;
}
noexitct++;
if (noexitct >= 10) {
stopmsg = 1;
- zexit(lastval, 0);
+ zexit(lastval, ZEXIT_NORMAL);
}
/*
* Don't print the message if it was already handled by
diff --git a/Src/jobs.c b/Src/jobs.c
index 73d7f26da..e7438251e 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1085,7 +1085,7 @@ printjob(Job jn, int lng, int synch)
{
/*
* A subjob still has process, which must finish before
- * further excution of the superjob, which the user wants to
+ * further execution of the superjob, which the user wants to
* know about. So report the status of the subjob as if it
* were the user-visible superjob.
*/
@@ -1932,7 +1932,7 @@ getjob(const char *s, const char *prog)
/* a digit here means we have a job number */
if (idigit(*s)) {
jobnum = atoi(s);
- if (jobnum && jobnum <= mymaxjob && myjobtab[jobnum].stat &&
+ if (jobnum > 0 && jobnum <= mymaxjob && myjobtab[jobnum].stat &&
!(myjobtab[jobnum].stat & STAT_SUBJOB) &&
/*
* If running jobs in a subshell, we are allowed to
@@ -2933,6 +2933,7 @@ acquire_pgrp(void)
sigaddset(&blockset, SIGTTOU);
sigaddset(&blockset, SIGTSTP);
oldset = signal_block(blockset);
+ int loop_count = 0;
while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
mypgrp = GETPGRP();
if (mypgrp == mypid) {
@@ -2948,8 +2949,21 @@ acquire_pgrp(void)
if (read(0, NULL, 0) != 0) {} /* Might generate SIGT* */
signal_block(blockset);
mypgrp = GETPGRP();
- if (mypgrp == lastpgrp && !interact)
- break; /* Unlikely that pgrp will ever change */
+ if (mypgrp == lastpgrp) {
+ if (!interact)
+ break; /* Unlikely that pgrp will ever change */
+ if (++loop_count == 100)
+ {
+ /*
+ * It's time to give up. The count is arbitrary;
+ * this is just to fix up unusual cases, so it's
+ * left large in an attempt not to break normal
+ * cases where there's some delay in the system
+ * setting up the terminal.
+ */
+ break;
+ }
+ }
lastpgrp = mypgrp;
}
if (mypgrp != mypid) {
diff --git a/Src/lex.c b/Src/lex.c
index f43bcc7db..1d86da94e 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -2109,7 +2109,7 @@ skipcomm(void)
hist_in_word(1);
} else {
/*
- * Set up for nested command subsitution, however
+ * Set up for nested command substitution, however
* we don't actually need the string until we get
* back to the top level and recover the lot.
* The $() body just appears empty.
diff --git a/Src/loop.c b/Src/loop.c
index 1013aeb50..01abc6cc9 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -425,7 +425,7 @@ execwhile(Estate state, UNUSED(int do_exec))
breaks--;
simple_pline = old_simple_pline;
- } else
+ } else {
for (;;) {
state->pc = loop;
noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN;
@@ -445,8 +445,11 @@ execwhile(Estate state, UNUSED(int do_exec))
lastval = oldval;
break;
}
- if (retflag)
+ if (retflag) {
+ if (breaks)
+ breaks--;
break;
+ }
/* In case the loop body is also a functional no-op,
* make sure signal handlers recognize ^C as above. */
@@ -470,6 +473,7 @@ execwhile(Estate state, UNUSED(int do_exec))
freeheap();
oldval = lastval;
}
+ }
cmdpop();
popheap();
loops--;
@@ -566,7 +570,7 @@ execif(Estate state, int do_exec)
if (run) {
/* we need to ignore lastval until we reach execcmd() */
- if (olderrexit)
+ if (olderrexit || run == 2)
noerrexit = olderrexit;
else if (lastval)
noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_UNTIL_EXEC;
@@ -728,7 +732,7 @@ exectry(Estate state, int do_exec)
Wordcode end, always;
int endval;
int save_retflag, save_breaks, save_contflag;
- zlong save_try_errflag, save_try_tryflag, save_try_interrupt;
+ zlong save_try_errflag, save_try_interrupt;
end = state->pc + WC_TRY_SKIP(state->pc[-1]);
always = state->pc + 1 + WC_TRY_SKIP(*state->pc);
@@ -737,12 +741,9 @@ exectry(Estate state, int do_exec)
cmdpush(CS_CURSH);
/* The :try clause */
- save_try_tryflag = try_tryflag;
- try_tryflag = 1;
-
+ ++try_tryflag;
execlist(state, 1, do_exec);
-
- try_tryflag = save_try_tryflag;
+ --try_tryflag;
/* Don't record errflag here, may be reset. However, */
/* endval should show failure when there is an error. */
diff --git a/Src/main.c b/Src/main.c
index 30eef5a25..bad698ee7 100644
--- a/Src/main.c
+++ b/Src/main.c
@@ -34,7 +34,7 @@
* Support for Cygwin binary/text mode filesystems.
* Peter A. Castro <doctor@fruitbat.org>
*
- * This deserves some explaination, because it uses Cygwin specific
+ * This deserves some explanation, because it uses Cygwin specific
* runtime functions.
*
* Cygwin supports the notion of binary or text mode access to files
@@ -43,7 +43,7 @@
* and all. If it's on a text mounted filesystem, Cygwin will strip out
* the CRs. This presents a problem because zsh code doesn't allow for
* CRLF's as line terminators. So, we must force all open files to be
- * in text mode reguardless of the underlying filesystem attributes.
+ * in text mode regardless of the underlying filesystem attributes.
* However, we only want to do this for reading, not writing as we still
* want to write files in the mode of the filesystem. To do this,
* we have two options: augment all {f}open() calls to have O_TEXT added to
diff --git a/Src/makepro.awk b/Src/makepro.awk
index 0498c1545..226d3f96b 100644
--- a/Src/makepro.awk
+++ b/Src/makepro.awk
@@ -121,7 +121,7 @@ BEGIN {
# initialiser.
dcltor = substr(line, 1, RLENGTH-1)
line = substr(line, RLENGTH+1)
- sub(/\=.*$/, "", dcltor)
+ sub(/=.*$/, "", dcltor)
match(dcltor, /^([^_0-9A-Za-z]| const )*/)
dcltor = substr(dcltor, 1, RLENGTH) "@+" substr(dcltor, RLENGTH+1)
match(dcltor, /^.*@\+[_0-9A-Za-z]+/)
diff --git a/Src/math.c b/Src/math.c
index a38770073..905b910ec 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -1133,8 +1133,7 @@ notzero(mnumber a)
/* macro to pop three values off the value stack */
-/**/
-void
+static void
op(int what)
{
mnumber a, b, c, *spval;
@@ -1569,14 +1568,19 @@ mathparse(int pc)
if (errflag)
return;
+ queue_signals();
mtok = zzlex();
/* Handle empty input */
- if (pc == TOPPREC && mtok == EOI)
+ if (pc == TOPPREC && mtok == EOI) {
+ unqueue_signals();
return;
+ }
checkunary(mtok, optr);
while (prec[mtok] <= pc) {
- if (errflag)
+ if (errflag) {
+ unqueue_signals();
return;
+ }
switch (mtok) {
case NUM:
push(yyval, NULL, 0);
@@ -1595,6 +1599,7 @@ mathparse(int pc)
if (mtok != M_OUTPAR) {
if (!errflag)
zerr("bad math expression: ')' expected");
+ unqueue_signals();
return;
}
break;
@@ -1613,6 +1618,7 @@ mathparse(int pc)
if (mtok != COLON) {
if (!errflag)
zerr("bad math expression: ':' expected");
+ unqueue_signals();
return;
}
if (q)
@@ -1636,4 +1642,5 @@ mathparse(int pc)
mtok = zzlex();
checkunary(mtok, optr);
}
+ unqueue_signals();
}
diff --git a/Src/mem.c b/Src/mem.c
index 77e4375f0..5951e57ed 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -1120,7 +1120,7 @@ struct m_hdr {
/* length of memory header, length of first field of memory header and
minimal size of a block left free (if we allocate memory and take a
block from the free list that is larger than needed, it must have at
- least M_MIN extra bytes to be splitted; if it has, the rest is put on
+ least M_MIN extra bytes to be split; if it has, the rest is put on
the free list) */
#define M_HSIZE (sizeof(struct m_hdr))
diff --git a/Src/module.c b/Src/module.c
index 33d75ebbd..f41b82f25 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -442,7 +442,7 @@ add_autobin(const char *module, const char *bnam, int flags)
}
/* Remove the builtin added previously by addbuiltin(). Returns *
- * zero on succes and -1 if there is no builtin with that name. */
+ * zero on success and -1 if there is no builtin with that name. */
/**/
int
diff --git a/Src/options.c b/Src/options.c
index 600b649e4..48c14c179 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -108,6 +108,7 @@ static struct optname optns[] = {
{{NULL, "cbases", 0}, CBASES},
{{NULL, "cprecedences", OPT_EMULATE|OPT_NONZSH}, CPRECEDENCES},
{{NULL, "cdablevars", OPT_EMULATE}, CDABLEVARS},
+{{NULL, "cdsilent", 0}, CDSILENT},
{{NULL, "chasedots", OPT_EMULATE}, CHASEDOTS},
{{NULL, "chaselinks", OPT_EMULATE}, CHASELINKS},
{{NULL, "checkjobs", OPT_EMULATE|OPT_ZSH}, CHECKJOBS},
diff --git a/Src/params.c b/Src/params.c
index 089a958ae..863b32600 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -44,7 +44,11 @@
#endif
#endif
-/* what level of localness we are at */
+/* What level of localness we are at.
+ *
+ * Hand-wavingly, this is incremented at every function call and decremented
+ * at every function return. See startparamscope().
+ */
/**/
mod_export int locallevel;
@@ -474,7 +478,13 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
static Param argvparam;
-/* hash table containing the parameters */
+/* "parameter table" - hash table containing the parameters
+ *
+ * realparamtab always points to the shell's global table. paramtab is sometimes
+ * temporarily changed to point at another table, while dealing with the keys
+ * of an associative array (for example, see makecompparams() which initializes
+ * the associative array ${compstate}).
+ */
/**/
mod_export HashTable paramtab, realparamtab;
@@ -1124,8 +1134,10 @@ copyparam(Param tpm, Param pm, int fakecopy)
tpm->base = pm->base;
tpm->width = pm->width;
tpm->level = pm->level;
- if (!fakecopy)
+ if (!fakecopy) {
+ tpm->old = pm->old;
tpm->node.flags &= ~PM_SPECIAL;
+ }
switch (PM_TYPE(pm->node.flags)) {
case PM_SCALAR:
tpm->u.str = ztrdup(pm->gsu.s->getfn(pm));
@@ -2201,10 +2213,10 @@ getstrvalue(Value v)
if (v->flags & VALFLAG_SUBST) {
if (v->pm->node.flags & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z)) {
- unsigned int fwidth = v->pm->width ? v->pm->width : MB_METASTRLEN(s);
+ size_t fwidth = v->pm->width ? (unsigned int)v->pm->width : MB_METASTRLEN(s);
switch (v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
char *t, *tend;
- unsigned int t0;
+ size_t t0;
case PM_LEFT:
case PM_LEFT | PM_RIGHT_Z:
@@ -2585,7 +2597,7 @@ assignstrvalue(Value v, char *val, int flags)
Param pm = v->pm;
/* Size doesn't change, can limit actions to only
* overwriting bytes in already allocated string */
- strncpy(z + v->start, val, vlen);
+ memcpy(z + v->start, val, vlen);
/* Implement remainder of strsetfn */
if (!(pm->node.flags & PM_HASHELEM) &&
((pm->node.flags & PM_NAMEDDIR) ||
@@ -3546,7 +3558,7 @@ setiparam(char *s, zlong val)
/*
* Set an integer parameter without forcing creation of an integer type.
- * This is useful if the integer is going to be set to a parmaeter which
+ * This is useful if the integer is going to be set to a parameter which
* would usually be scalar but may not exist.
*/
@@ -3617,10 +3629,18 @@ unsetparam_pm(Param pm, int altflag, int exp)
altpm = (Param) paramtab->getnode(paramtab, altremove);
/* tied parameters are at the same local level as each other */
oldpm = NULL;
- while (altpm && altpm->level > pm->level) {
- /* param under alternate name hidden by a local */
- oldpm = altpm;
- altpm = altpm->old;
+ /*
+ * Look for param under alternate name hidden by a local.
+ * If this parameter is special, however, the visible
+ * parameter is the special and the hidden one is keeping
+ * an old value --- we just mark the visible one as unset.
+ */
+ if (altpm && !(altpm->node.flags & PM_SPECIAL))
+ {
+ while (altpm && altpm->level > pm->level) {
+ oldpm = altpm;
+ altpm = altpm->old;
+ }
}
if (altpm) {
if (oldpm && !altpm->level) {
@@ -5858,7 +5878,7 @@ printparamnode(HashNode hn, int printflags)
doneminus = 0;
}
if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
- printf("%d ", p->width);
+ printf("%u ", p->width);
doneminus = 0;
}
}
diff --git a/Src/parse.c b/Src/parse.c
index 83383f10c..de1b27967 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -414,10 +414,10 @@ ecstrcode(char *s)
return c;
} else {
Eccstr p, *pp;
- int cmp;
+ long cmp;
for (pp = &ecstrs; (p = *pp); ) {
- if (!(cmp = p->nfunc - ecnfunc) && !(cmp = (((signed)p->hashval) - ((signed)val))) && !(cmp = strcmp(p->str, s))) {
+ if (!(cmp = p->nfunc - ecnfunc) && !(cmp = (((long)p->hashval) - ((long)val))) && !(cmp = strcmp(p->str, s))) {
return p->offs;
}
pp = (cmp < 0 ? &(p->left) : &(p->right));
@@ -1811,7 +1811,7 @@ par_simple(int *cmplx, int nr)
for (ptr = str; *ptr; ptr++) {
/*
* We can't treat this as "simple" if it contains
- * expansions that require process subsitution, since then
+ * expansions that require process substitution, since then
* we need process handling.
*/
if (ptr[1] == Inpar &&
@@ -1899,6 +1899,14 @@ par_simple(int *cmplx, int nr)
p += nrediradd;
sr += nrediradd;
}
+ else if (postassigns)
+ {
+ /* C.f. normal case below */
+ postassigns++;
+ ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0));
+ ecstr(toksave);
+ ecstr(""); /* TBD can possibly optimise out */
+ }
else
{
ecstr(toksave);
@@ -2271,7 +2279,8 @@ par_redir(int *rp, char *idstring)
void
setheredoc(int pc, int type, char *str, char *termstr, char *munged_termstr)
{
- ecbuf[pc] = WCB_REDIR(type | REDIR_FROM_HEREDOC_MASK);
+ int varid = WC_REDIR_VARID(ecbuf[pc]) ? REDIR_VARID_MASK : 0;
+ ecbuf[pc] = WCB_REDIR(type | REDIR_FROM_HEREDOC_MASK | varid);
ecbuf[pc + 2] = ecstrcode(str);
ecbuf[pc + 3] = ecstrcode(termstr);
ecbuf[pc + 4] = ecstrcode(munged_termstr);
diff --git a/Src/pattern.c b/Src/pattern.c
index 737f5cdcb..c7c2c8bea 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -156,7 +156,7 @@ typedef union upat *Upat;
* P_BRANCH, but applies to the immediately preceding branch. The code in
* the corresponding branch is followed by a P_EXCSYNC, which simply
* acts as a marker that a P_EXCLUDE comes next. The P_EXCLUDE
- * has a pointer to char embeded in it, which works
+ * has a pointer to char embedded in it, which works
* like P_WBRANCH: if we get to the P_EXCSYNC, and we already matched
* up to the same position, fail. Thus we are forced to backtrack
* on closures in the P_BRANCH if the first attempt was excluded.
@@ -502,7 +502,7 @@ patcompcharsset(void)
}
}
-/* Called before parsing a set of file matchs to initialize flags */
+/* Called before parsing a set of file matches to initialize flags */
/**/
void
@@ -2030,6 +2030,16 @@ int errsfound; /* Total error count so far */
/**/
int forceerrs; /* Forced maximum error count */
+/*
+ * exactpos is used to remember how far down an exact string we have
+ * matched, if we are doing approximation and can therefore redo from
+ * the same point; we never need to otherwise.
+ *
+ * exactend is a pointer to the end of the string, which isn't
+ * null-terminated.
+ */
+static char *exactpos, *exactend;
+
/**/
void
pattrystart(void)
@@ -2072,7 +2082,7 @@ patmungestring(char **string, int *stringlen, int *unmetalenin)
}
/*
- * Allocate memeory for pattern match. Note this is specific to use
+ * Allocate memory for pattern match. Note this is specific to use
* of pattern *and* trial string.
*
* Unmetafy a trial string for use in pattern matching, if needed.
@@ -2093,7 +2103,7 @@ patmungestring(char **string, int *stringlen, int *unmetalenin)
* In patstralloc (supplied by caller, must last until last pattry is done)
* unmetalen is the unmetafied length of the string; it will be
* calculated if the input value is negative.
- * unmetalenp is the umetafied length of a path segment preceeding
+ * unmetalenp is the umetafied length of a path segment preceding
* the trial string needed for file mananagement; it is calculated as
* needed so does not need to be initialised.
* alloced is the memory allocated on the heap --- same as return value from
@@ -2227,7 +2237,7 @@ pattrylen(Patprog prog, char *string, int len, int unmetalen,
* depends on both prog *and* the trial string). This should only be
* done if there is no path prefix (pathpos == 0) as otherwise the path
* buffer and unmetafied string may not match. To do this,
- * patallocstr() is callled (use force = 1 to ensure it is alway
+ * patallocstr() is called (use force = 1 to ensure it is always
* unmetafied); paststralloc points to existing storage. Memory is
* on the heap.
*
@@ -2321,7 +2331,7 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
if (patstralloc->alloced)
{
/*
- * Unmetafied; we need pattern sring that's also unmetafied.
+ * Unmetafied; we need pattern string that's also unmetafied.
* We'll cache it in the patstralloc structure.
* Note it's on the heap.
*/
@@ -2379,7 +2389,7 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
/*
* Remember the length in case used for ${..#..} etc.
* In this case, we didn't unmetafy the pattern string
- * In the orignal structure, but it might be unmetafied
+ * in the original structure, but it might be unmetafied
* for use with an unmetafied test string.
*/
patinlen = pstrlen;
@@ -2463,6 +2473,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
patinput = patinstart;
+ exactpos = exactend = NULL;
+ /* The only external call to patmatch --- all others are recursive */
if (patmatch((Upat)progstr)) {
/*
* we were lazy and didn't save the globflags if an exclusion
@@ -2480,7 +2492,7 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
* Optimization: if we didn't find any Meta characters
* to begin with, we don't need to look for them now.
*
- * For patstralloc pased in, we want the unmetafied length.
+ * For patstralloc passed in, we want the unmetafied length.
*/
if (patstralloc == &patstralloc_struct &&
patstralloc->unmetalen != origlen) {
@@ -2607,10 +2619,10 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
}
/*
- * Return length of previous succesful match. This is
+ * Return length of previous successful match. This is
* in metafied bytes, i.e. includes a count of Meta characters,
* unless the match was done on an unmetafied string using
- * a patstralloc stuct, in which case it, too is unmetafed.
+ * a patstralloc struct, in which case it too is unmetafied.
* Unusual and futile attempt at modular encapsulation.
*/
@@ -2653,16 +2665,6 @@ patmatchlen(void)
(charmatch_cache = (expr), CHARMATCH(charmatch_cache, chpa))
/*
- * exactpos is used to remember how far down an exact string we have
- * matched, if we are doing approximation and can therefore redo from
- * the same point; we never need to otherwise.
- *
- * exactend is a pointer to the end of the string, which isn't
- * null-terminated.
- */
-static char *exactpos, *exactend;
-
-/*
* Main matching routine.
*
* Testing the tail end of a match is usually done by recursion, but
diff --git a/Src/prompt.c b/Src/prompt.c
index f2b3f161e..b65bfb86b 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -163,7 +163,7 @@ promptpath(char *p, int npath, int tilde)
*
* txtchangep gives an integer controlling the attributes of
* the prompt. This is for use in zle to maintain the attributes
- * consistenly. Other parts of the shell should not need to use it.
+ * consistently. Other parts of the shell should not need to use it.
*/
/**/
@@ -1075,10 +1075,9 @@ putstr(int d)
mod_export void
countprompt(char *str, int *wp, int *hp, int overf)
{
- int w = 0, h = 1;
+ int w = 0, h = 1, multi = 0, wcw = 0;
int s = 1;
#ifdef MULTIBYTE_SUPPORT
- int wcw, multi = 0;
char inchar;
mbstate_t mbs;
wchar_t wc;
@@ -1087,10 +1086,28 @@ countprompt(char *str, int *wp, int *hp, int overf)
#endif
for (; *str; str++) {
- if (w > zterm_columns && overf >= 0) {
- w = 0;
+ /*
+ * Avoid double-incrementing the height when there's a newline in the
+ * prompt and the line it terminates takes up exactly the width of the
+ * terminal
+ */
+ while (w > zterm_columns && overf >= 0 && !multi) {
h++;
+ if (wcw) {
+ /*
+ * Wide characters don't get split off. They move to the
+ * next line if there is not enough space.
+ */
+ w = wcw;
+ break;
+ } else {
+ /*
+ * Tabs overflow to the next line as if they were made of spaces.
+ */
+ w -= zterm_columns;
+ }
}
+ wcw = 0;
/*
* Input string should be metafied, so tokens in it should
* be real tokens, even if there are multibyte characters.
@@ -1171,12 +1188,19 @@ countprompt(char *str, int *wp, int *hp, int overf)
* This isn't easy to handle generally; just assume there's no
* output.
*/
- if(w >= zterm_columns && overf >= 0) {
- if (!overf || w > zterm_columns) {
- w = 0;
- h++;
+ while (w > zterm_columns && overf >= 0) {
+ h++;
+ if (wcw) {
+ w = wcw;
+ break;
+ } else {
+ w -= zterm_columns;
}
}
+ if (w == zterm_columns && overf == 0) {
+ w = 0;
+ h++;
+ }
if(wp)
*wp = w;
if(hp)
diff --git a/Src/signals.c b/Src/signals.c
index f294049c2..96ff9e9b3 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -654,7 +654,7 @@ zhandler(int sig)
_exit(SIGPIPE);
else if (!isatty(SHTTY)) {
stopmsg = 1;
- zexit(SIGPIPE, 1);
+ zexit(SIGPIPE, ZEXIT_SIGNAL);
}
}
break;
@@ -662,7 +662,7 @@ zhandler(int sig)
case SIGHUP:
if (!handletrap(SIGHUP)) {
stopmsg = 1;
- zexit(SIGHUP, 1);
+ zexit(SIGHUP, ZEXIT_SIGNAL);
}
break;
@@ -670,7 +670,7 @@ zhandler(int sig)
if (!handletrap(SIGINT)) {
if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL))
- zexit(SIGINT, 1);
+ zexit(SIGINT, ZEXIT_SIGNAL);
if (list_pipe || chline || simple_pline) {
breaks = loops;
errflag |= ERRFLAG_INT;
@@ -703,7 +703,7 @@ zhandler(int sig)
errflag = noerrs = 0;
zwarn("timeout");
stopmsg = 1;
- zexit(SIGALRM, 1);
+ zexit(SIGALRM, ZEXIT_SIGNAL);
}
}
break;
@@ -1011,10 +1011,6 @@ removetrap(int sig)
(!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
dosavetrap(sig, locallevel);
- if (!trapped) {
- unqueue_signals();
- return NULL;
- }
if (sigtrapped[sig] & ZSIG_TRAPPED)
nsigtrapped--;
sigtrapped[sig] = 0;
diff --git a/Src/sort.c b/Src/sort.c
index 92ee1c0d4..8faf9349c 100644
--- a/Src/sort.c
+++ b/Src/sort.c
@@ -33,6 +33,9 @@
/* Flag for direction of sort: 1 forwards, -1 reverse */
static int sortdir;
+/* Flag that sort ignores backslashes */
+static int sortnobslash;
+
/* Flag that sort is numeric */
static int sortnumeric;
@@ -113,9 +116,24 @@ eltpcmp(const void *a, const void *b)
bs += (laststarta - as);
as += (laststarta - as);
}
+
+ if (sortnobslash) {
+ while (*as && *bs) {
+ if (*as == '\\')
+ as++;
+ if (*bs == '\\')
+ bs++;
+ if (*as != *bs || !*as)
+ break;
+ as++;
+ bs++;
+ }
+ }
+
#ifdef HAVE_STRCOLL
cmp = strcoll(as, bs);
#endif
+
if (sortnumeric) {
for (; *as == *bs && *as; as++, bs++);
#ifndef HAVE_STRCOLL
@@ -162,7 +180,10 @@ mod_export int
zstrcmp(const char *as, const char *bs, int sortflags)
{
struct sortelt ae, be, *aeptr, *beptr;
- int oldsortdir = sortdir, oldsortnumeric = sortnumeric, ret;
+ int oldsortdir = sortdir;
+ int oldsortnobslash = sortnobslash;
+ int oldsortnumeric = sortnumeric;
+ int ret;
ae.cmp = as;
be.cmp = bs;
@@ -173,11 +194,13 @@ zstrcmp(const char *as, const char *bs, int sortflags)
beptr = &be;
sortdir = 1;
+ sortnobslash = (sortflags & SORTIT_IGNORING_BACKSLASHES) ? 1 : 0;
sortnumeric = (sortflags & SORTIT_NUMERICALLY) ? 1 : 0;
ret = eltpcmp(&aeptr, &beptr);
/* Paranoia: I don't think we ever need to restore these. */
+ sortnobslash = oldsortnobslash;
sortnumeric = oldsortnumeric;
sortdir = oldsortdir;
@@ -227,7 +250,7 @@ strmetasort(char **array, int sortwhat, int *unmetalenp)
if (unmetalenp) {
/*
* Already unmetafied. We just need to check for
- * embededded nulls.
+ * embedded nulls.
*/
int count = unmetalenp[arrptr-array];
/* Remember this length for sorted array */
diff --git a/Src/subst.c b/Src/subst.c
index 60eb33390..79efc9ad2 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -91,7 +91,7 @@ keyvalpairelement(LinkList list, LinkNode node)
* "flag"s contains PREFORK_* flags, defined in zsh.h.
*
* "ret_flags" is used to return PREFORK_* values from nested parameter
- * substitions. It may be NULL in which case PREFORK_SUBEXP must not
+ * substitutions. It may be NULL in which case PREFORK_SUBEXP must not
* appear in flags; any return value from below will be discarded.
*/
@@ -1548,7 +1548,7 @@ untok_and_escape(char *s, int escapes, int tok_arg)
/*
* See if an argument str looks like a subscript or length following
* a colon and parse it. It must be followed by a ':' or nothing.
- * If this succeeds, expand and return the evaulated expression if
+ * If this succeeds, expand and return the evaluated expression if
* found, else return NULL.
*
* We assume this is what is meant if the first character is not
@@ -1682,7 +1682,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
*/
int wantt = 0;
/*
- * Indicates spliting a string into an array. There aren't
+ * Indicates splitting a string into an array. There aren't
* actually that many special cases for this --- which may
* be why it doesn't work properly; we split in some cases
* where we shouldn't, in particular on the multsubs for
@@ -1732,7 +1732,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
int mods = 0;
/*
* The (z) flag, nothing to do with SH_WORD_SPLIT which is tied
- * spbreak, see above; fairly straighforward in use but c.f.
+ * spbreak, see above; fairly straightforward in use but cf.
* the comment for mods.
*
* This gets set to one of the LEXFLAGS_* values.
@@ -2725,7 +2725,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* substitution is in quotes) always good enough? Potentially
* we may be OK by now --- all potential `@'s and subexpressions
* have been handled, including any [@] index which comes up
- * by virture of v->isarr being set to SCANPM_ISVAR_AT which
+ * by virtue of v->isarr being set to SCANPM_ISVAR_AT which
* is now in isarr.
*
* However, if we are replacing multsub() with something that
@@ -3044,7 +3044,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* shouldn't be any if not interactive.
*/
stopmsg = 1;
- zexit(1, 0);
+ zexit(1, ZEXIT_NORMAL);
} else
_exit(1);
}
@@ -3110,7 +3110,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
/*
* Either loop over an array doing replacements or
- * do the replacment on a string.
+ * do the replacement on a string.
*
* We need an untokenized value for matching.
*/
@@ -3438,7 +3438,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
s--;
if (unset(KSHARRAYS) || inbrace) {
if (!isarr)
- modify(&val, &s);
+ modify(&val, &s, inbrace);
else {
char *ss;
char **ap = aval;
@@ -3447,12 +3447,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
while ((*pp = *ap++)) {
ss = s;
- modify(pp++, &ss);
+ modify(pp++, &ss, inbrace);
}
if (pp == aval) {
char *t = "";
ss = s;
- modify(&t, &ss);
+ modify(&t, &ss, inbrace);
}
s = ss;
}
@@ -4182,6 +4182,12 @@ arithsubst(char *a, char **bptr, char *rest)
* PTR is an in/out parameter. On entry it contains the string of colon
* modifiers. On return it points past the last recognised modifier.
*
+ * INBRACE is non-zero if we are in some form of a bracketed or
+ * parenthesised expression; it is zero for modifiers ocurring
+ * in an an unbracketed variable substitution. This means that
+ * $foo:t222 is treated ias ${foo:t}222 rather than ${foo:t222}
+ * for backward compatibility.
+ *
* Example:
* ENTRY: *str is "." *ptr is ":AN"
* RETURN: *str is "/home/foobar" (equal to $PWD) *ptr points to the "N"
@@ -4189,7 +4195,7 @@ arithsubst(char *a, char **bptr, char *rest)
/**/
void
-modify(char **str, char **ptr)
+modify(char **str, char **ptr, int inbrace)
{
char *ptr1, *ptr2, *ptr3, *lptr, c, *test, *sep, *t, *tt, tc, *e;
char *copy, *all, *tmp, sav, sav1, *ptr1end;
@@ -4202,6 +4208,8 @@ modify(char **str, char **ptr)
*str = dupstring(*str);
while (**ptr == ':') {
+ int count = 0;
+
lptr = *ptr;
(*ptr)++;
wall = gbal = 0;
@@ -4214,10 +4222,8 @@ modify(char **str, char **ptr)
case 'a':
case 'A':
case 'c':
- case 'h':
case 'r':
case 'e':
- case 't':
case 'l':
case 'u':
case 'q':
@@ -4226,6 +4232,17 @@ modify(char **str, char **ptr)
c = **ptr;
break;
+ case 'h':
+ case 't':
+ c = **ptr;
+ if (inbrace && idigit((*ptr)[1])) {
+ do {
+ count = 10 * count + ((*ptr)[1] - '0');
+ ++(*ptr);
+ } while (idigit((*ptr)[1]));
+ }
+ break;
+
case 's':
c = **ptr;
(*ptr)++;
@@ -4392,7 +4409,7 @@ modify(char **str, char **ptr)
break;
}
case 'h':
- remtpath(&copy);
+ remtpath(&copy, count);
break;
case 'r':
remtext(&copy);
@@ -4401,7 +4418,7 @@ modify(char **str, char **ptr)
rembutext(&copy);
break;
case 't':
- remlpaths(&copy);
+ remlpaths(&copy, count);
break;
case 'l':
copy = casemodify(tt, CASMOD_LOWER);
@@ -4478,7 +4495,7 @@ modify(char **str, char **ptr)
break;
}
case 'h':
- remtpath(str);
+ remtpath(str, count);
break;
case 'r':
remtext(str);
@@ -4487,7 +4504,7 @@ modify(char **str, char **ptr)
rembutext(str);
break;
case 't':
- remlpaths(str);
+ remlpaths(str, count);
break;
case 'l':
*str = casemodify(*str, CASMOD_LOWER);
diff --git a/Src/text.c b/Src/text.c
index 3658b1bc6..69530ae79 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -470,8 +470,13 @@ gettext2(Estate state)
" || " : " && ");
s->code = *state->pc++;
s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END);
- if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT)
- taddstr("! ");
+ if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT) {
+ if (WC_SUBLIST_SKIP(s->code) == 0)
+ stack = 1;
+ taddstr((stack || (!(WC_SUBLIST_FLAGS(s->code) &
+ WC_SUBLIST_SIMPLE) && wc_code(*state->pc) !=
+ WC_PIPE)) ? "!" : "! ");
+ }
if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC)
taddstr("coproc ");
}
@@ -579,7 +584,7 @@ gettext2(Estate state)
state->pc = end;
if (!nargs) {
/*
- * Unnamed fucntion.
+ * Unnamed function.
* We're not going to pull any arguments off
* later, so skip them now...
*/
diff --git a/Src/utils.c b/Src/utils.c
index 32f600858..f5667f389 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -287,9 +287,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
{
const char *str;
int num;
-#ifdef DEBUG
long lnum;
-#endif
#ifdef HAVE_STRERROR_R
#define ERRBUFSIZE (80)
int olderrno;
@@ -325,12 +323,10 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
nicezputs(s, file);
break;
}
-#ifdef DEBUG
case 'L':
lnum = va_arg(ap, long);
fprintf(file, "%ld", lnum);
break;
-#endif
case 'd':
num = va_arg(ap, int);
fprintf(file, "%d", num);
@@ -2201,6 +2197,31 @@ gettempname(const char *prefix, int use_heap)
#ifdef HAVE__MKTEMP
/* Zsh uses mktemp() safely, so silence the warnings */
ret = (char *) _mktemp(ret);
+#elif HAVE_MKSTEMP && defined(DEBUG)
+ {
+ /* zsh uses mktemp() safely (all callers use O_EXCL, and one of them
+ * uses mkfifo()/mknod(), as opposed to open()), but some compilers
+ * warn about this anyway and give no way to disable the warning. To
+ * appease them, use mkstemp() and then close the fd and unlink the
+ * filename, to match callers' expectations.
+ *
+ * But do this in debug builds only, because we don't want to suffer
+ * x3 the disk access (touch, unlink, touch again) in production.
+ */
+ int fd;
+ errno = 0;
+ fd = mkstemp(ret);
+ if (fd < 0)
+ zwarn("can't get a temporary filename: %e", errno);
+ else {
+ close(fd);
+ ret = ztrdup(ret);
+
+ errno = 0;
+ if (unlink(ret) < 0)
+ zwarn("unlinking a temporary filename failed: %e", errno);
+ }
+ }
#else
ret = (char *) mktemp(ret);
#endif
@@ -3159,6 +3180,8 @@ spckword(char **s, int hist, int cmd, int ask)
scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0);
if (autocd) {
char **pp;
+ if (cd_able_vars(unmeta(guess)))
+ return;
for (pp = cdpath; *pp; pp++) {
char bestcd[PATH_MAX + 1];
int thisdist;
@@ -3336,7 +3359,7 @@ morefmt:
case '.':
{
long fnsec = nsec;
- if (digs > 9)
+ if (digs < 0 || digs > 9)
digs = 9;
if (ztrftimebuf(&bufsize, digs))
return -1;
diff --git a/Src/watch.c b/Src/watch.c
index cd7dc643d..93b3cb134 100644
--- a/Src/watch.c
+++ b/Src/watch.c
@@ -98,7 +98,7 @@
/*
* In utmpx, the ut_name field is replaced by ut_user.
- * Howver, on some systems ut_name may already be defined this
+ * However, on some systems ut_name may already be defined this
* way for the purposes of utmp.
*/
# ifndef ut_name
diff --git a/Src/zsh.h b/Src/zsh.h
index 10897372b..834142895 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -455,7 +455,7 @@ enum {
*/
#define FDT_FLOCK_EXEC 6
/*
- * Entry used by a process substition.
+ * Entry used by a process substitution.
* This marker is not tested internally as we associated the file
* descriptor with a job for closing.
*
@@ -1254,8 +1254,8 @@ enum {
/*
* Assignment has value?
- * If the assignment is an arrray, then it certainly has a value --- we
- * can only tell if there's an expicit assignment.
+ * If the assignment is an array, then it certainly has a value --- we
+ * can only tell if there's an explicit assignment.
*/
#define ASG_VALUEP(asg) (ASG_ARRAYP(asg) || \
@@ -1444,8 +1444,8 @@ struct builtin {
*/
#define BINF_HANDLES_OPTS (1<<18)
/*
- * Handles the assignement interface. The argv list actually contains
- * two nested litsts, the first of normal arguments, and the second of
+ * Handles the assignment interface. The argv list actually contains
+ * two nested lists, the first of normal arguments, and the second of
* assignment structures.
*/
#define BINF_ASSIGN (1<<19)
@@ -2006,7 +2006,7 @@ enum {
enum {
/*
* Set if the string had whitespace at the start
- * that should cause word splitting against any preceeding string.
+ * that should cause word splitting against any preceding string.
*/
MULTSUB_WS_AT_START = 1,
/*
@@ -2272,9 +2272,9 @@ struct histent {
*/
#define LEXFLAGS_NEWLINE 0x0010
-/******************************************/
-/* Definitions for programable completion */
-/******************************************/
+/*******************************************/
+/* Definitions for programmable completion */
+/*******************************************/
/* Nothing special. */
#define IN_NOTHING 0
@@ -2348,6 +2348,7 @@ enum {
CASEMATCH,
CBASES,
CDABLEVARS,
+ CDSILENT,
CHASEDOTS,
CHASELINKS,
CHECKJOBS,
@@ -2998,7 +2999,7 @@ struct sortelt {
int origlen;
/*
* The length of the string, if needed, else -1.
- * The length is only needed if there are embededded nulls.
+ * The length is only needed if there are embedded nulls.
*/
int len;
};
@@ -3221,6 +3222,14 @@ enum {
/* Hooks in core. */
/***************************************/
+/* The type of zexit()'s second parameter, which see. */
+enum zexit_t {
+ /* This isn't a bitfield. The values are here just for explicitness. */
+ ZEXIT_NORMAL = 0,
+ ZEXIT_SIGNAL = 1,
+ ZEXIT_DEFERRED = 2
+};
+
#define EXITHOOK (zshhooks + 0)
#define BEFORETRAPHOOK (zshhooks + 1)
#define AFTERTRAPHOOK (zshhooks + 2)
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index e7d529b6e..85e198f2e 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -522,7 +522,7 @@ struct timespec {
# define RLIMIT_VMEM RLIMIT_AS
#endif
-#ifdef HAVE_SYS_CAPABILITY_H
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_GET_PROC)
# include <sys/capability.h>
#endif
diff --git a/Src/ztype.h b/Src/ztype.h
index ae7236774..5c85b0cd7 100644
--- a/Src/ztype.h
+++ b/Src/ztype.h
@@ -66,7 +66,7 @@
* shell initialisation.
*/
#define ZTF_INIT (0x0001) /* One-off initialisation done */
-#define ZTF_INTERACT (0x0002) /* Shell interative and reading from stdin */
+#define ZTF_INTERACT (0x0002) /* Shell interactive and reading from stdin */
#define ZTF_SP_COMMA (0x0004) /* Treat comma as a special characters */
#define ZTF_BANGCHAR (0x0008) /* Treat bangchar as a special character */