From a6a1b28b9807c8c19d5fef424a86b86ddf33bc7f Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Mon, 24 Feb 2020 10:55:48 +0000
Subject: 45487: Missing mod_export declarations for AIX
---
Src/builtin.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'Src/builtin.c')
diff --git a/Src/builtin.c b/Src/builtin.c
index aa5767cf1..407cad159 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2597,7 +2597,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
*/
/**/
-int
+mod_export int
bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
{
Param pm;
--
cgit v1.2.3
From 66ee4918a1540ae3baf8077c216a2b36ccba76f4 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Thu, 9 Apr 2020 21:46:20 +0100
Subject: 45660: Fix crash setting vi or emacs mode on command line.
Delay setting the option until the module system is set up.
---
ChangeLog | 5 +++++
Src/builtin.c | 2 +-
Src/init.c | 30 +++++++++++++++++++++++-------
3 files changed, 29 insertions(+), 8 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 9ba79bf46..2d003e8a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-04-09 Peter Stephenson
+
+ * 45660: Src/builtin,c, Src/init.c: Delay initial setting of
+ keympa options until module system is active.
+
2020-04-05 dana
* 45655: Completion/Darwin/Type/_retrieve_mac_apps: Update
diff --git a/Src/builtin.c b/Src/builtin.c
index 407cad159..3dab3f9b4 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -6119,7 +6119,7 @@ bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func))
savehackchar = keyboardhackchar;
emulate(shname, opt_R, &new_emulation, new_opts);
optlist = newlinklist();
- if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0)) {
+ if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0, NULL)) {
ret = 1;
goto restore;
}
diff --git a/Src/init.c b/Src/init.c
index 04a5856ff..3d6c94d04 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -248,7 +248,8 @@ static int restricted;
/**/
static void
-parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr)
+parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
+ int *needkeymap)
{
char **x;
LinkList paramlist;
@@ -265,7 +266,7 @@ parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr)
* matched by code at the end of the present function.
*/
- if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags))
+ if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags, needkeymap))
exit(1);
/*
@@ -376,7 +377,7 @@ static void parseopts_setemulate(char *nam, int flags)
/**/
mod_export int
parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
- LinkList optlist, int flags)
+ LinkList optlist, int flags, int *needkeymap)
{
int optionbreak = 0;
int action, optno;
@@ -482,8 +483,14 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
return 1;
} else if (optno == RESTRICTED && toplevel) {
restricted = action;
- } else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) {
- WARN_OPTION("can't change option: %s", *argv);
+ } else if ((optno == EMACSMODE || optno == VIMODE)
+ && (!toplevel || needkeymap)){
+ if (!toplevel) {
+ WARN_OPTION("can't change option: %s", *argv);
+ } else {
+ /* Need to wait for modules to be loadable */
+ *needkeymap = optno;
+ }
} else {
if (dosetopt(optno, action, toplevel, new_opts) &&
!toplevel) {
@@ -1707,7 +1714,7 @@ zsh_main(UNUSED(int argc), char **argv)
{
char **t, *runscript = NULL, *zsh_name;
char *cmd; /* argument to -c */
- int t0;
+ int t0, needkeymap = 0;
#ifdef USE_LOCALE
setlocale(LC_ALL, "");
#endif
@@ -1753,7 +1760,7 @@ zsh_main(UNUSED(int argc), char **argv)
createoptiontable();
/* sets emulation, LOGINSHELL, PRIVILEGED, ZLE, INTERACTIVE,
* SHINSTDIN and SINGLECOMMAND */
- parseargs(zsh_name, argv, &runscript, &cmd);
+ parseargs(zsh_name, argv, &runscript, &cmd, &needkeymap);
SHTTY = -1;
init_io(cmd);
@@ -1762,6 +1769,15 @@ zsh_main(UNUSED(int argc), char **argv)
init_signals();
init_bltinmods();
init_builtins();
+
+ if (needkeymap)
+ {
+ /* Saved for after module system initialisation */
+ zleentry(ZLE_CMD_SET_KEYMAP, needkeymap);
+ opts[needkeymap] = 1;
+ opts[needkeymap == EMACSMODE ? VIMODE : EMACSMODE] = 0;
+ }
+
run_init_scripts();
setupshin(runscript);
init_misc(cmd, zsh_name);
--
cgit v1.2.3
From 4d2bcf2fe7637b641ccde31a8ca7c4875f0699c1 Mon Sep 17 00:00:00 2001
From: Daniel Shahaf
Date: Mon, 27 Apr 2020 19:30:39 +0000
Subject: 45729: internal: Add a second parameter to zlinklist2array(),
analogously to hlinklist2array().
Will be used in the next commit.
---
ChangeLog | 7 +++++++
Src/Modules/curses.c | 4 ++--
Src/Zle/compcore.c | 4 ++--
Src/Zle/computil.c | 4 ++--
Src/builtin.c | 10 +++++-----
Src/linklist.c | 13 +++++++++----
6 files changed, 27 insertions(+), 15 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index ad366f1c5..1942d9aab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2020-05-03 Daniel Shahaf
+
+ * 45729: Src/Modules/curses.c, Src/Zle/compcore.c,
+ Src/Zle/computil.c, Src/builtin.c, Src/linklist.c: internal:
+ Add a second parameter to zlinklist2array(), analogously to
+ hlinklist2array().
+
2020-05-02 Daniel Shahaf
* unposted: Util/zyodl.vim: Use 'conceal' for some macros that
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index 19f285e34..e46903916 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -1212,7 +1212,7 @@ zccmd_input(const char *nam, char **args)
addlinknode(margs, "CTRL");
if (mevent.bstate & BUTTON_ALT)
addlinknode(margs, "ALT");
- if (!setaparam(args[3], zlinklist2array(margs)))
+ if (!setaparam(args[3], zlinklist2array(margs, 1)))
return 1;
} else {
#endif
@@ -1464,7 +1464,7 @@ zccmd_querychar(const char *nam, char **args)
}
/* Turn this into an array and store it. */
- return !setaparam(args[1] ? args[1] : "reply", zlinklist2array(clist));
+ return !setaparam(args[1] ? args[1] : "reply", zlinklist2array(clist, 1));
}
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 7e3badc57..958fef8e7 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -648,7 +648,7 @@ callcompfunc(char *s, char *fn)
if (compredirs)
freearray(compredirs);
if (rdstrs)
- compredirs = zlinklist2array(rdstrs);
+ compredirs = zlinklist2array(rdstrs, 1);
else
compredirs = (char **) zshcalloc(sizeof(char *));
@@ -1922,7 +1922,7 @@ set_comp_sep(void)
mod_export void
set_list_array(char *name, LinkList l)
{
- setaparam(name, zlinklist2array(l));
+ setaparam(name, zlinklist2array(l, 1));
}
/* Get the words from a variable or a (list of words). */
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 90db8b4b8..ddfa70077 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3591,7 +3591,7 @@ bin_compvalues(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
if (cv_laststate.vals) {
char **ret;
- ret = zlinklist2array(cv_laststate.vals);
+ ret = zlinklist2array(cv_laststate.vals, 1);
sethparam(args[1], ret);
return 0;
@@ -4016,7 +4016,7 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
set = (Ctset) zalloc(sizeof(*set));
- set->tags = zlinklist2array(list);
+ set->tags = zlinklist2array(list, 1);
set->next = NULL;
set->ptr = NULL;
set->tag = NULL;
diff --git a/Src/builtin.c b/Src/builtin.c
index 3dab3f9b4..d5a874a95 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2280,7 +2280,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (asg->flags & ASG_ARRAY) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
if (!(pm = assignaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
+ zlinklist2array(asg->value.array, 1) :
mkarray(NULL), flags)))
return NULL;
}
@@ -2442,7 +2442,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (PM_TYPE(on) == PM_ARRAY && ASG_ARRAYP(asg)) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
if (!(pm = assignaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
+ zlinklist2array(asg->value.array, 1) :
mkarray(NULL), flags)))
return NULL;
dont_set = 1;
@@ -2536,7 +2536,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
arrayval = mkarray(NULL);
}
} else if (asg->value.array)
- arrayval = zlinklist2array(asg->value.array);
+ arrayval = zlinklist2array(asg->value.array, 1);
else
arrayval = mkarray(NULL);
if (!(pm=assignaparam(pname, arrayval, flags)))
@@ -2923,7 +2923,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
apm->ename = ztrdup(asg0.name);
if (asg->value.array) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
- assignaparam(asg->name, zlinklist2array(asg->value.array), flags);
+ assignaparam(asg->name, zlinklist2array(asg->value.array, 1), flags);
} else if (oldval)
assignsparam(asg0.name, oldval, 0);
unqueue_signals();
@@ -3901,7 +3901,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
}
unqueue_signals();
if (all) {
- allmatched = argv = zlinklist2array(matchednodes);
+ allmatched = argv = zlinklist2array(matchednodes, 1);
matchednodes = NULL;
popheap();
} else
diff --git a/Src/linklist.c b/Src/linklist.c
index 85d9bb367..f64685d9e 100644
--- a/Src/linklist.c
+++ b/Src/linklist.c
@@ -438,22 +438,27 @@ hlinklist2array(LinkList list, int copy)
/*
* Convert a linked list whose data elements are strings to
- * an array. The result is a permanently allocated, freearrayable
- * array.
+ * a permanently-allocated array. The elements of the array are the same
+ * elements as the linked list data if copy is 0, else they are duplicated
+ * into permanent memory so the result is a permanently allocated,
+ * freearrayable array that's a deep copy of the linked list.
*/
/**/
mod_export char **
-zlinklist2array(LinkList list)
+zlinklist2array(LinkList list, int copy)
{
int l = countlinknodes(list);
char **ret = (char **) zalloc((l + 1) * sizeof(char *)), **p;
LinkNode n;
for (n = firstnode(list), p = ret; n; incnode(n), p++) {
- *p = ztrdup((char *) getdata(n));
+ *p = (char *) getdata(n);
+ if (copy)
+ *p = ztrdup(*p);
}
*p = NULL;
return ret;
}
+
--
cgit v1.2.3
From ed23768f774eed04f1a9dd25b6e7fb76a2418dc4 Mon Sep 17 00:00:00 2001
From: Mikael Magnusson
Date: Fri, 5 Jun 2020 15:39:04 +0200
Subject: typeset: Fix leaving corrupted entries in paramtab
---
ChangeLog | 5 +++++
Src/builtin.c | 12 +++++++++---
2 files changed, 14 insertions(+), 3 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index e4a21a6e4..44bebc218 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-06-05 Mikael Magnusson
+
+ * 45985: Src/builtin.c: typeset: Fix leaving corrupted entries
+ in paramtab
+
2020-06-03 Yasuhiro KIMURA
* 45950: configure.ac: Fix 'make install' in out-of-tree
diff --git a/Src/builtin.c b/Src/builtin.c
index d5a874a95..770930579 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2480,12 +2480,16 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
return NULL;
}
if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
- if (typeset_setwidth(cname, pm, ops, on, 0))
+ if (typeset_setwidth(cname, pm, ops, on, 0)) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
}
if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
- if (typeset_setbase(cname, pm, ops, on, 0))
+ if (typeset_setbase(cname, pm, ops, on, 0)) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
}
} else {
if (idigit(*pname))
@@ -2503,8 +2507,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
*/
struct tieddata *tdp = (struct tieddata *)
zalloc(sizeof(struct tieddata));
- if (!tdp)
+ if (!tdp) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
tdp->joinchar = joinchar;
tdp->arrptr = &altpm->u.arr;
--
cgit v1.2.3
From 4e471c3f899b485e7a4122c75da1500c2d509236 Mon Sep 17 00:00:00 2001
From: Matthew Martin
Date: Fri, 3 Jul 2020 21:10:27 -0500
Subject: 46168: Update $PWD and call chpwd hook after normalizing path
---
ChangeLog | 5 +++++
Src/builtin.c | 35 +++++++++++++++++------------------
Test/B01cd.ztst | 19 ++++++++++++++++++-
3 files changed, 40 insertions(+), 19 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index b76d1988e..fa1c74563 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-07-03 Matthew Martin
+
+ * 46168: Src/builtin.c, Test/B01cd.ztst: Update $PWD and call
+ chpwd hook after normalizing path.
+
2020-07-03 Daniel Shahaf
* unposted (cf. users/24972, users/24978): Doc/Zsh/expn.yo:
diff --git a/Src/builtin.c b/Src/builtin.c
index 770930579..ff84ce936 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -841,7 +841,6 @@ int
bin_cd(char *nam, char **argv, Options ops, int func)
{
LinkNode dir;
- struct stat st1, st2;
if (isset(RESTRICTED)) {
zwarnnam(nam, "restricted");
@@ -860,23 +859,6 @@ bin_cd(char *nam, char **argv, Options ops, int func)
}
cd_new_pwd(func, dir, OPT_ISSET(ops, 'q'));
- if (stat(unmeta(pwd), &st1) < 0) {
- setjobpwd();
- zsfree(pwd);
- pwd = NULL;
- pwd = metafy(zgetcwd(), -1, META_DUP);
- } else if (stat(".", &st2) < 0) {
- if (chdir(unmeta(pwd)) < 0)
- zwarn("unable to chdir(%s): %e", pwd, errno);
- } else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
- if (chasinglinks) {
- setjobpwd();
- zsfree(pwd);
- pwd = NULL;
- pwd = metafy(zgetcwd(), -1, META_DUP);
- } else if (chdir(unmeta(pwd)) < 0)
- zwarn("unable to chdir(%s): %e", pwd, errno);
- }
unqueue_signals();
return 0;
}
@@ -1210,6 +1192,7 @@ static void
cd_new_pwd(int func, LinkNode dir, int quiet)
{
char *new_pwd, *s;
+ struct stat st1, st2;
int dirstacksize;
if (func == BIN_PUSHD)
@@ -1239,6 +1222,22 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
}
}
+ if (stat(unmeta(new_pwd), &st1) < 0) {
+ zsfree(new_pwd);
+ new_pwd = NULL;
+ new_pwd = metafy(zgetcwd(), -1, META_DUP);
+ } else if (stat(".", &st2) < 0) {
+ if (chdir(unmeta(new_pwd)) < 0)
+ zwarn("unable to chdir(%s): %e", new_pwd, errno);
+ } else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
+ if (chasinglinks) {
+ zsfree(new_pwd);
+ new_pwd = NULL;
+ new_pwd = metafy(zgetcwd(), -1, META_DUP);
+ } else if (chdir(unmeta(new_pwd)) < 0)
+ zwarn("unable to chdir(%s): %e", new_pwd, errno);
+ }
+
/* shift around the pwd variables, to make oldpwd and pwd relate to the
current (i.e. new) pwd */
zsfree(oldpwd);
diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst
index 21e751dcb..bc6757549 100644
--- a/Test/B01cd.ztst
+++ b/Test/B01cd.ztst
@@ -33,7 +33,7 @@
#
# Tests should use subdirectories ending in `.tmp'. These will be
# removed with all the contents even if the test is aborted.
- mkdir cdtst.tmp cdtst.tmp/real cdtst.tmp/sub
+ mkdir cdtst.tmp cdtst.tmp/foo cdtst.tmp/real cdtst.tmp/sub
ln -s ../real cdtst.tmp/sub/fake
@@ -149,6 +149,23 @@ F:something is broken. But you already knew that.
-f:(workers/45367) cd -P squashes multiple leading slashes
>/dev
+ chpwd_hook() { hook_pwd=$PWD; }
+ chpwd_functions=(chpwd_hook)
+ cd $mydir/cdtst.tmp/foo &&
+ (cd $mydir && mv $mydir/cdtst.tmp/{foo,bar}) &&
+ print $PWD &&
+ print $hook_pwd &&
+ cd . &&
+ print $PWD &&
+ print $hook_pwd
+ chpwd_functions=()
+ unfunction chpwd_hook
+0q:cd . with moved PWD
+>$mydir/cdtst.tmp/foo
+>$mydir/cdtst.tmp/foo
+>$mydir/cdtst.tmp/bar
+>$mydir/cdtst.tmp/bar
+
%clean
# This optional section cleans up after the test, if necessary,
# e.g. killing processes etc. This is in addition to the removal of *.tmp
--
cgit v1.2.3
From b6ba74cd4eaec2b6cb515748cf1b74a19133d4a4 Mon Sep 17 00:00:00 2001
From: Jun-ichi Takimoto
Date: Sun, 25 Oct 2020 23:02:36 +0100
Subject: 47301: Fix print -v metafication
---
ChangeLog | 5 +++++
Src/builtin.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 5650bdd68..abc051765 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-10-25 Mikael Magnusson
+
+ * Jun-ichi Takimoto: 47301: Src/builtin.c: Fix print -v
+ metafication
+
2020-10-18 Roman Perepelitsa
* 47476: Src/Modules/files.c: Fix a race condition in zf_mkdir -p
diff --git a/Src/builtin.c b/Src/builtin.c
index ff84ce936..09eb3728c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -4862,7 +4862,7 @@ bin_print(char *name, char **args, Options ops, int func)
/* normal output */
if (!fmt) {
- if (OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
+ if (OPT_ISSET(ops, 'z') ||
OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')) {
/*
* We don't want the arguments unmetafied after all.
--
cgit v1.2.3
From 465738fc2594ac4629de341738a106184858c678 Mon Sep 17 00:00:00 2001
From: Bart Schaefer
Date: Thu, 4 Feb 2021 17:52:22 -0800
Subject: 47895: Remove trailing spaces from "print -ac" output lines.
---
ChangeLog | 3 +++
Src/builtin.c | 2 +-
Test/D02glob.ztst | 6 +++---
3 files changed, 7 insertions(+), 4 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index cd24c23d3..6b4855d7b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2021-02-04 Bart Schaefer
+ * 47895: Src/builtin.c, Test/D02glob.ztst: Remove trailing spaces
+ from "print -ac" output lines.
+
* 47865: Test/D02glob.ztst: More tests for restricted directories
* 47889: Etc/FAQ.yo: Update csh alias equivalences (section 2.3)
diff --git a/Src/builtin.c b/Src/builtin.c
index 09eb3728c..35a0fb2db 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -4822,7 +4822,7 @@ bin_print(char *name, char **args, Options ops, int func)
{
fwrite(args[n], len[n], 1, fout);
l = widths[n];
- if (n < argc)
+ if (n < argc && ic < nc - 1)
for (; l < sc; l++)
fputc(' ', fout);
}
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index d3b2e9ec2..72891a2a7 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -750,9 +750,9 @@
done
print -raC 2 -- glob.tmp/secret-*/* glob.tmp/secret-*/file
0:names inside unreadable directories can be globbed if searchable
->glob.tmp/secret-d444/dir glob.tmp/secret-d444/file
->glob.tmp/secret-s444/dir glob.tmp/secret-s444/file
->glob.tmp/secret-d111/file glob.tmp/secret-s111/file
+>glob.tmp/secret-d444/dir glob.tmp/secret-d444/file
+>glob.tmp/secret-s444/dir glob.tmp/secret-s444/file
+>glob.tmp/secret-d111/file glob.tmp/secret-s111/file
print -rC 2 -- glob.tmp/secret-*/dir/*
0:glob files in readable directories inside unreadable directories
--
cgit v1.2.3
From 9c0533931c51b7d512d3e95850404f5aac2dbce1 Mon Sep 17 00:00:00 2001
From: Martijn Dekker
Date: Tue, 16 Feb 2021 18:34:41 +0000
Subject: 48073: Add fc -s as POSIX way of rerunning command without starting
editor
---
ChangeLog | 5 +++++
Doc/Zsh/builtins.yo | 3 ++-
Src/builtin.c | 4 ++--
3 files changed, 9 insertions(+), 3 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index c89fce748..cbc5eb23b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-02-17 Peter Stephenson
+
+ * 48073: Martijn Dekker: Doc/Zsh/builtins.yo, Src/builtin.c: fc
+ -s is POSIX version of fc -e -.
+
2021-02-16 Peter Stephenson
* 47876: Justtine Tunney: Src/exec.c: Add more cases where
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index ebb29f632..a7afe42cf 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -736,7 +736,7 @@ findex(fc)
cindex(history, editing)
cindex(editing history)
redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ ))ifnztexi( )))
-xitem(tt(fc) [ tt(-e) var(ename) ] [ tt(-LI) ] [ tt(-m) var(match) ] [ var(old)tt(=)var(new) ... ] [ var(first) [ var(last) ] ])
+xitem(tt(fc) [ tt(-e) var(ename) ] [ tt(-s) ] [ tt(-LI) ] [ tt(-m) var(match) ] [ var(old)tt(=)var(new) ... ] [ var(first) [ var(last) ] ])
xitem(tt(fc -l )[ tt(-LI) ] [ tt(-nrdfEiD) ] [ tt(-t) var(timefmt) ] [ tt(-m) var(match) ])
xitem(SPACES()[ var(old)tt(=)var(new) ... ] [ var(first) [ var(last) ] ])
xitem(tt(fc -p )[ tt(-a) ] [ var(filename) [ var(histsize) [ var(savehistsize) ] ] ])
@@ -783,6 +783,7 @@ the parameter tt(EDITOR) is used; if that is not set a builtin default,
usually `tt(vi)' is used. If var(ename) is `tt(-)', no editor is invoked.
When editing is complete, the edited command is executed.
+The flag `tt(-s)' is equivalent to `tt(-e -)'.
The flag tt(-r) reverses the order of the events and the
flag tt(-n) suppresses event numbers when listing.
diff --git a/Src/builtin.c b/Src/builtin.c
index 35a0fb2db..3093a3056 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -71,7 +71,7 @@ static struct builtin builtins[] =
* But that's actually not useful, so it's more consistent to
* cause an error.
*/
- BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
+ BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRst: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, "ckmMstTuUWx:z", NULL),
@@ -1643,7 +1643,7 @@ bin_fc(char *nam, char **argv, Options ops, int func)
if (!fclist(out, ops, first, last, asgf, pprog, 1)) {
char *editor;
- if (func == BIN_R)
+ if (func == BIN_R || OPT_ISSET(ops, 's'))
editor = "-";
else if (OPT_HASARG(ops, 'e'))
editor = OPT_ARG(ops, 'e');
--
cgit v1.2.3
From 6bef719302d6db33c63fb6f2636986dff1941ac2 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Thu, 18 Feb 2021 21:37:08 +0000
Subject: users/26509: fix for r -L
fc with the -L option should ignore remote entires, rather than
reading them and treating them as an error.
---
ChangeLog | 5 +++++
Src/builtin.c | 5 +++--
2 files changed, 8 insertions(+), 2 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index cbc5eb23b..8eaaee9d1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-02-18 Peter Stephenson
+
+ * users/26509: Src/builtin.c: fc -L should ignore remote entries
+ rather than treat them as an error.
+
2021-02-17 Peter Stephenson
* 48073: Martijn Dekker: Doc/Zsh/builtins.yo, Src/builtin.c: fc
diff --git a/Src/builtin.c b/Src/builtin.c
index 3093a3056..26335a2e8 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1599,8 +1599,9 @@ bin_fc(char *nam, char **argv, Options ops, int func)
* command line to avoid giving the user a nasty turn
* if some helpful soul ran "print -s 'rm -rf /'".
*/
- first = OPT_ISSET(ops,'l')? addhistnum(curhist,-16,0)
- : addhistnum(curline.histnum,-1,0);
+ int xflags = OPT_ISSET(ops,'L') ? HIST_FOREIGN : 0;
+ first = OPT_ISSET(ops,'l')? addhistnum(curhist,-16,xflags)
+ : addhistnum(curline.histnum,-1,xflags);
if (first < 1)
first = 1;
if (last < first)
--
cgit v1.2.3
From 82ff9f24f170eea7daa935fdaa09ab75a2f277ff Mon Sep 17 00:00:00 2001
From: Bart Schaefer
Date: Sun, 18 Apr 2021 13:58:09 -0700
Subject: 48560: add TYPESET_TO_UNSET option to remove initialization of
parameters
Changes typeset such that ${newparam-notset} yields "notset" and
"typeset -p newparam" does not show an assignment to the parameter. This
is similar to the default behavior of bash and ksh, with minor differences
in typeset output.
Also add tests for some POSIX incompatibilities plus minor changes for test
harness robustness.
---
ChangeLog | 19 +++++++++++++++++--
Completion/compinit | 1 +
Doc/Zsh/builtins.yo | 6 +++++-
Doc/Zsh/options.yo | 10 ++++++++++
Doc/Zsh/params.yo | 5 +++++
Src/builtin.c | 14 +++++++++++---
Src/options.c | 1 +
Src/params.c | 22 +++++++++++++++++++---
Src/subst.c | 3 ++-
Src/zsh.h | 3 +++
Test/D06subscript.ztst | 5 +++++
Test/E01options.ztst | 15 +++++++++++++++
Test/V10private.ztst | 12 ++++++------
Test/runtests.zsh | 2 +-
Test/ztst.zsh | 2 +-
15 files changed, 102 insertions(+), 18 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 722a2437c..7dcbbc533 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2021-04-18 Bart Schaefer
+
+ * 48560: Completion/compinit, Doc/Zsh/builtins.yo,
+ Doc/Zsh/options.yo, Doc/Zsh/params.yo, Src/builtin.c,
+ Src/options.c, Src/params.c, Src/subst.c, Src/zsh.h,
+ Test/D06subscript.ztst, Test/E01options.ztst, Test/E03posix.ztst,
+ Test/V10private.ztst, Test/runtests.zsh, Test/ztst.zsh: add
+ TYPESET_TO_UNSET option, which removes initialization of newly
+ declared parameters such that ${newparam-notset} yields "notset"
+ and "typeset -p newparam" does not show an assignment to the
+ parameter. This is similar to the default behavior of bash and
+ ksh, with minor differences in typeset output. Also add tests for
+ some POSIX incompatibilities plus minor changes for test harness
+ robustness.
+
2021-04-18 Jun-ichi Takimoto
* unposted: Etc/BUGS: remove a bug fixed by 47301
@@ -2909,7 +2924,7 @@ g
2019-02-14 Peter Stephenson
- * see 44062: back off change to ZLE per-line initiialisation,
+ * see 44062: back off change to ZLE per-line initialisation,
causing problems after failed reads and apparently not needed
for the intended fix of interrupt handling (40305 / 34656ec2).
@@ -15632,7 +15647,7 @@ g
* 32338: Doc/Makefile.in: create Doc/help.txt as an empty file
when Util/helpfiles fails, so that the rest of the build does not
- yeild a spurious error
+ yield a spurious error
* 32337: Src/params.c: initialize several special parameters to
unset for better compatibility in emulation modes; for the same
diff --git a/Completion/compinit b/Completion/compinit
index e81cd1604..1f2e7c634 100644
--- a/Completion/compinit
+++ b/Completion/compinit
@@ -165,6 +165,7 @@ _comp_options=(
NO_posixidentifiers
NO_shwordsplit
NO_shglob
+ NO_typesettounset
NO_warnnestedvar
NO_warncreateglobal
)
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index a7afe42cf..61dc6986f 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1872,7 +1872,11 @@ ifnzman(noderef(Local Parameters))\
retain their special attributes when made local.
For each var(name)tt(=)var(value) assignment, the parameter
-var(name) is set to var(value).
+var(name) is set to var(value). If the assignment is omitted and var(name)
+does em(not) refer to an existing parameter, a new parameter is intialized
+to empty string, zero, or empty array (as appropriate), em(unless) the
+shell option tt(TYPESET_TO_UNSET) is set. When that option is set,
+the parameter attributes are recorded but the parameter remains unset.
If the shell option tt(TYPESET_SILENT) is not set, for each remaining
var(name) that refers to a parameter that is already set, the name and
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 714e8a1a1..6e862fae8 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1942,6 +1942,16 @@ If the option is set, they will only be shown when parameters are selected
with the `tt(-m)' option. The option `tt(-p)' is available whether or not
the option is set.
)
+pindex(TYPESET_TO_UNSET)
+pindex(NO_TYPESET_TO_UNSET)
+pindex(TYPESETTOUNSET)
+pindex(NOTYPESETTOUNSET)
+item(tt(TYPESET_TO_UNSET) )(
+When declaring a new parameter with any of the `tt(typeset)' family of
+related commands, the parameter remains unset unless and until a
+value is explicity assigned to it, either in the `tt(typeset)' command
+itself or as a later assignment statement.
+)
pindex(VERBOSE)
pindex(NO_VERBOSE)
pindex(NOVERBOSE)
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 36c1ae4c2..a9044336f 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -393,6 +393,11 @@ is compared to the pattern, and the first matching key found is the
result. On failure substitutes the length of the array plus one, as
discussed under the description of `tt(r)', or the empty string for an
associative array.
+
+Note: Although `tt(i)' may be applied to a scalar substitution to find
+the offset of a substring, the results are likely to be misleading when
+searching within substitutions that yield an empty string, or when
+searching for the empty substring.
)
item(tt(I))(
Like `tt(i)', but gives the index of the last match, or all possible
diff --git a/Src/builtin.c b/Src/builtin.c
index 26335a2e8..6d119f7a5 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2491,6 +2491,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
return NULL;
}
}
+ if (isset(TYPESETTOUNSET))
+ pm->node.flags |= PM_DEFAULTED;
} else {
if (idigit(*pname))
zerrnam(cname, "not an identifier: %s", pname);
@@ -2836,7 +2838,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
unqueue_signals();
return 1;
} else if (pm) {
- if (!(pm->node.flags & PM_UNSET)
+ if ((!(pm->node.flags & PM_UNSET) || pm->node.flags & PM_DECLARED)
&& (locallevel == pm->level || !(on & PM_LOCAL))) {
if (pm->node.flags & PM_TIED) {
if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
@@ -2889,6 +2891,8 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
*
* Don't attempt to set it yet, it's too early
* to be exported properly.
+ *
+ * This may create the array with PM_DEFAULTED.
*/
asg2.name = asg->name;
asg2.flags = 0;
@@ -2930,8 +2934,12 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
if (asg->value.array) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
assignaparam(asg->name, zlinklist2array(asg->value.array, 1), flags);
- } else if (oldval)
- assignsparam(asg0.name, oldval, 0);
+ } else if (asg0.value.scalar || oldval) {
+ /* We have to undo what we did wrong with asg2 */
+ apm->node.flags &= ~PM_DEFAULTED;
+ if (oldval)
+ assignsparam(asg0.name, oldval, 0);
+ }
unqueue_signals();
return 0;
diff --git a/Src/options.c b/Src/options.c
index 6ea6290e5..783022591 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -259,6 +259,7 @@ static struct optname optns[] = {
{{NULL, "transientrprompt", 0}, TRANSIENTRPROMPT},
{{NULL, "trapsasync", 0}, TRAPSASYNC},
{{NULL, "typesetsilent", OPT_EMULATE|OPT_BOURNE}, TYPESETSILENT},
+{{NULL, "typesettounset", OPT_EMULATE|OPT_BOURNE}, TYPESETTOUNSET},
{{NULL, "unset", OPT_EMULATE|OPT_BSHELL}, UNSET},
{{NULL, "verbose", 0}, VERBOSE},
{{NULL, "vi", 0}, VIMODE},
diff --git a/Src/params.c b/Src/params.c
index 122f5da7d..33bbc54f6 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2093,7 +2093,8 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
if (sav)
*s = sav;
*pptr = s;
- if (!pm || (pm->node.flags & PM_UNSET))
+ if (!pm || ((pm->node.flags & PM_UNSET) &&
+ !(pm->node.flags & PM_DECLARED)))
return NULL;
if (v)
memset(v, 0, sizeof(*v));
@@ -3055,6 +3056,7 @@ assignsparam(char *s, char *val, int flags)
* Don't warn about anything.
*/
flags &= ~ASSPM_WARN;
+ v->pm->node.flags &= ~PM_DEFAULTED;
}
*ss = '[';
v = NULL;
@@ -3080,6 +3082,7 @@ assignsparam(char *s, char *val, int flags)
}
if (flags & ASSPM_WARN)
check_warn_pm(v->pm, "scalar", created, 1);
+ v->pm->node.flags &= ~PM_DEFAULTED;
if (flags & ASSPM_AUGMENT) {
if (v->start == 0 && v->end == -1) {
switch (PM_TYPE(v->pm->node.flags)) {
@@ -3232,6 +3235,7 @@ assignaparam(char *s, char **val, int flags)
if (flags & ASSPM_WARN)
check_warn_pm(v->pm, "array", created, may_warn_about_nested_vars);
+ v->pm->node.flags &= ~PM_DEFAULTED;
/*
* At this point, we may have array entries consisting of
@@ -3444,6 +3448,7 @@ sethparam(char *s, char **val)
return NULL;
}
check_warn_pm(v->pm, "associative array", checkcreate, 1);
+ v->pm->node.flags &= ~PM_DEFAULTED;
setarrvalue(v, val);
unqueue_signals();
return v->pm;
@@ -3515,6 +3520,7 @@ assignnparam(char *s, mnumber val, int flags)
if (flags & ASSPM_WARN)
check_warn_pm(v->pm, "numeric", 0, 1);
}
+ v->pm->node.flags &= ~PM_DEFAULTED;
setnumvalue(v, val);
unqueue_signals();
return v->pm;
@@ -3619,6 +3625,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
else
altremove = NULL;
+ pm->node.flags &= ~PM_DECLARED; /* like ksh, not like bash */
if (!(pm->node.flags & PM_UNSET))
pm->gsu.s->unsetfn(pm, exp);
if (pm->env)
@@ -3652,6 +3659,8 @@ unsetparam_pm(Param pm, int altflag, int exp)
}
zsfree(altremove);
+ if (!(pm->node.flags & PM_SPECIAL))
+ pm->gsu.s = &stdscalar_gsu;
}
/*
@@ -4116,6 +4125,11 @@ tiedarrsetfn(Param pm, char *x)
if (*dptr->arrptr)
freearray(*dptr->arrptr);
+ else if (pm->ename) {
+ Param altpm = (Param) paramtab->getnode(paramtab, pm->ename);
+ if (altpm)
+ altpm->node.flags &= ~PM_DEFAULTED;
+ }
if (x) {
char sepbuf[3];
if (imeta(dptr->joinchar))
@@ -5035,6 +5049,7 @@ arrfixenv(char *s, char **t)
if (isset(ALLEXPORT))
pm->node.flags |= PM_EXPORTED;
+ pm->node.flags &= ~PM_DEFAULTED;
/*
* Do not "fix" parameters that were not exported
@@ -5839,8 +5854,9 @@ printparamnode(HashNode hn, int printflags)
Param peer = NULL;
if (p->node.flags & PM_UNSET) {
- if (printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) &&
- p->node.flags & (PM_READONLY|PM_EXPORTED)) {
+ if ((printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) &&
+ p->node.flags & (PM_READONLY|PM_EXPORTED)) ||
+ (p->node.flags & PM_DEFAULTED) == PM_DEFAULTED) {
/*
* Special POSIX rules: show the parameter as readonly/exported
* even though it's unset, but with no value.
diff --git a/Src/subst.c b/Src/subst.c
index 96e0914eb..9928be0e9 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2563,7 +2563,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* Handle the (t) flag: value now becomes the type
* information for the parameter.
*/
- if (v && v->pm && !(v->pm->node.flags & PM_UNSET)) {
+ if (v && v->pm && ((v->pm->node.flags & PM_DECLARED) ||
+ !(v->pm->node.flags & PM_UNSET))) {
int f = v->pm->node.flags;
switch (PM_TYPE(f)) {
diff --git a/Src/zsh.h b/Src/zsh.h
index d70a4017c..af9b4fb67 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1929,8 +1929,10 @@ struct tieddata {
made read-only by the user */
#define PM_READONLY_SPECIAL (PM_SPECIAL|PM_READONLY|PM_RO_BY_DESIGN)
#define PM_DONTIMPORT (1<<22) /* do not import this variable */
+#define PM_DECLARED (1<<22) /* explicitly named with typeset */
#define PM_RESTRICTED (1<<23) /* cannot be changed in restricted mode */
#define PM_UNSET (1<<24) /* has null value */
+#define PM_DEFAULTED (PM_DECLARED|PM_UNSET)
#define PM_REMOVABLE (1<<25) /* special can be removed from paramtab */
#define PM_AUTOLOAD (1<<26) /* autoloaded from module */
#define PM_NORESTORE (1<<27) /* do not restore value of local special */
@@ -2536,6 +2538,7 @@ enum {
TRANSIENTRPROMPT,
TRAPSASYNC,
TYPESETSILENT,
+ TYPESETTOUNSET,
UNSET,
VERBOSE,
VIMODE,
diff --git a/Test/D06subscript.ztst b/Test/D06subscript.ztst
index c1a8d79cf..adbd398c4 100644
--- a/Test/D06subscript.ztst
+++ b/Test/D06subscript.ztst
@@ -289,3 +289,8 @@ F:Regression test for workers/42297
>14 24
>b b
>b?rbaz foob?r
+
+ i=1,3
+ [[ ${a[$i]} = ${a[i]} ]]
+0f:Math evaluation of commas in array subscripts
+F:In math, (($i)) should be the same as ((i)), see workers/47748.
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 415f46cd7..72749e6ab 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1451,3 +1451,18 @@ F:If this test fails at the first unsetopt, refer to P01privileged.ztst.
0q:RM_STAR_SILENT
*>zsh: sure you want to delete all 15 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
*>zsh: sure you want to delete (all <->|more than <->) files in / \[yn\]\? ${BEL}(|n)
+
+ () {
+ local var
+ print ${(t)var}
+ }
+0:(t) returns correct type
+>scalar-local
+
+ () {
+ readonly var
+ typeset -p var
+ }
+0:readonly with typeset -p
+F:compare E03posix.ztst
+>typeset -r var=''
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index a3a63867b..03e8259d5 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -19,14 +19,14 @@
() {
print $scalar_test
private scalar_test
- print $+scalar_test
+ typeset +m scalar_test
unset scalar_test
print $+scalar_test
}
print $scalar_test
0:basic scope hiding
>toplevel
->1
+>local scalar_test
>0
>toplevel
@@ -45,14 +45,14 @@
print $+unset_test
() {
private unset_test
- print $+unset_test
+ typeset +m unset_test
unset_test=setme
print $unset_test
}
print $+unset_test
0:variable defined only in scope
>0
->1
+>local unset_test
>setme
>0
@@ -62,13 +62,13 @@
local -Pa array_test=(in function)
() {
private array_test
- print $+array_test
+ typeset +m array_test
}
print $array_test
}
print $array_test
0:nested scope with different type, correctly restored
->1
+>local array_test
>in function
>top level
diff --git a/Test/runtests.zsh b/Test/runtests.zsh
index 562234d91..b66d579b6 100644
--- a/Test/runtests.zsh
+++ b/Test/runtests.zsh
@@ -7,7 +7,7 @@ emulate zsh
# protect from catastrophic failure of an individual test.
# We could probably do that with subshells instead.
-integer success failure skipped retval
+integer success=0 failure=0 skipped=0 retval
for file in "${(f)ZTST_testlist}"; do
$ZTST_exe +Z -f $ZTST_srcdir/ztst.zsh $file
retval=$?
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index e668ae942..a59c06dcf 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -60,7 +60,7 @@ ZTST_mainopts=(${(kv)options})
ZTST_testdir=$PWD
ZTST_testname=$1
-integer ZTST_testfailed
+integer ZTST_testfailed=0
# This is POSIX nonsense. Because of the vague feeling someone, somewhere
# may one day need to examine the arguments of "tail" using a standard
--
cgit v1.2.3
From 71b747567e350c5f849897c424ea76fd05b34ffe Mon Sep 17 00:00:00 2001
From: Bart Schaefer
Date: Sun, 18 Apr 2021 14:26:12 -0700
Subject: 47704: POSIX export and readonly ignore "-p" when parameter names
also appear
---
ChangeLog | 4 ++++
Src/builtin.c | 8 ++++++--
Src/params.c | 4 ++++
Test/B02typeset.ztst | 8 +++-----
4 files changed, 17 insertions(+), 7 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 7dcbbc533..c450afd05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2021-04-18 Bart Schaefer
+ * 47704: Src/builtin.c, Src/params.c, Test/B02typeset.ztst:
+ POSIX export and readonly ignore the "-p" option when parameter
+ names are also present.
+
* 48560: Completion/compinit, Doc/Zsh/builtins.yo,
Doc/Zsh/options.yo, Doc/Zsh/params.yo, Src/builtin.c,
Src/options.c, Src/params.c, Src/subst.c, Src/zsh.h,
diff --git a/Src/builtin.c b/Src/builtin.c
index 6d119f7a5..efa20607e 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2615,7 +2615,12 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
int on = 0, off = 0, roff, bit = PM_ARRAY;
int i;
int returnval = 0, printflags = 0;
- int hasargs;
+ int hasargs = *argv != NULL || (assigns && firstnode(assigns));
+
+ /* POSIXBUILTINS is set for bash/ksh and both ignore -p with args */
+ if ((func == BIN_READONLY || func == BIN_EXPORT) &&
+ isset(POSIXBUILTINS) && hasargs)
+ ops->ind['p'] = 0;
/* hash -f is really the builtin `functions' */
if (OPT_ISSET(ops,'f'))
@@ -2695,7 +2700,6 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* -p0 treated as -p for consistency */
}
}
- hasargs = *argv != NULL || (assigns && firstnode(assigns));
if (!hasargs) {
int exclude = 0;
if (!OPT_ISSET(ops,'p')) {
diff --git a/Src/params.c b/Src/params.c
index 33bbc54f6..20dfb5b5f 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5883,8 +5883,12 @@ printparamnode(HashNode hn, int printflags)
* don't.
*/
if (printflags & PRINT_POSIX_EXPORT) {
+ if (!(p->node.flags & PM_EXPORTED))
+ return;
printf("export ");
} else if (printflags & PRINT_POSIX_READONLY) {
+ if (!(p->node.flags & PM_READONLY))
+ return;
printf("readonly ");
} else if (locallevel && p->level >= locallevel) {
printf("typeset "); /* printf("local "); */
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index e7bf93794..8b3988151 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -620,7 +620,7 @@
print ${+pbro} >&2
(typeset -g pbro=3)
(pbro=4)
- readonly -p pbro >&2 # shows up as "readonly" although unset
+ readonly -p >&2 # shows up as "readonly" although unset
typeset -gr pbro # idempotent (no error)...
print ${+pbro} >&2 # ...so still readonly...
typeset -g +r pbro # ...can't turn it off
@@ -1050,23 +1050,21 @@
$ZTST_testdir/../Src/zsh --emulate sh -f -c '
PATH=/bin; export PATH; readonly PATH
- export -p PATH
+ export -p PATH # Should be a no-op, -p ignored
typeset -p PATH
readonly -p'
0: readonly/export output for exported+readonly+special when started as sh
->export PATH=/bin
>export -r PATH=/bin
>readonly PATH=/bin
function {
emulate -L sh
MANPATH=/bin; export MANPATH; readonly MANPATH
- export -p MANPATH
+ export -p MANPATH # Should be a no-op, -p ignored
typeset -p MANPATH
readonly -p
}
0: readonly/export output for exported+readonly+tied+special after switching to sh emulation
->export MANPATH=/bin
>export -rT MANPATH manpath=( /bin )
>readonly MANPATH=/bin
--
cgit v1.2.3
From c23a0d84b029676832ea0f2eeb0caa8c47d0500d Mon Sep 17 00:00:00 2001
From: dana
Date: Mon, 3 May 2021 18:08:11 -0500
Subject: 48614: getopts: Calculate OPTIND according to POSIX_BUILTINS
---
ChangeLog | 6 ++++++
Doc/Zsh/builtins.yo | 3 ++-
Doc/Zsh/options.yo | 3 ++-
README | 3 +++
Src/builtin.c | 10 ++++++++++
Test/B10getopts.ztst | 29 +++++++++++++++++++++++++++++
6 files changed, 52 insertions(+), 2 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index c522dfa80..882b15ce9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2021-05-03 dana
+
+ * 48614 (tweaked per 48630): Doc/Zsh/builtins.yo,
+ Doc/Zsh/options.yo, README, Src/builtin.c, Test/B10getopts.ztst:
+ Calculate OPTIND according to POSIX_BUILTINS
+
2021-05-03 Daniel Shahaf
* 48767: Doc/Zsh/params.yo: docs: $SECONDS: Clarify what types
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 61dc6986f..022921bfa 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -982,7 +982,8 @@ vindex(OPTARG, use of)
The first option to be examined may be changed by explicitly assigning
to tt(OPTIND). tt(OPTIND) has an initial value of tt(1), and is
normally set to tt(1) upon entry to a shell function and restored
-upon exit (this is disabled by the tt(POSIX_BUILTINS) option). tt(OPTARG)
+upon exit. (The tt(POSIX_BUILTINS) option disables this, and also changes
+the way the value is calculated to match other shells.) tt(OPTARG)
is not reset and retains its value from the most recent call to
tt(getopts). If either of tt(OPTIND) or tt(OPTARG) is explicitly
unset, it remains unset, and the index or option argument is not
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 6e862fae8..546b16b65 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2249,7 +2249,8 @@ command found in the path.
Furthermore, the tt(getopts) builtin behaves in a POSIX-compatible
fashion in that the associated variable tt(OPTIND) is not made
-local to functions.
+local to functions, and its value is calculated differently to match
+other shells.
Moreover, the warning and special exit code from
tt([[ -o )var(non_existent_option)tt( ]]) are suppressed.
diff --git a/README b/README
index 76bf4ec35..3ef8afcd1 100644
--- a/README
+++ b/README
@@ -99,6 +99,9 @@ emulate sh: When zsh emulates sh, the final command in a pipeline is now run in
a subshell. This differs from the behavior in the native (zsh) mode, but is
consistent with most other sh implementations.
+getopts now calculates OPTIND in a similar manner to other shells when the
+POSIX_BUILTINS option is enabled.
+
Incompatibilities between 5.7.1 and 5.8
---------------------------------------
diff --git a/Src/builtin.c b/Src/builtin.c
index efa20607e..b7ceefd55 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5568,6 +5568,11 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
/* check for legality */
if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
p = "?";
+ /* Keep OPTIND correct if the user doesn't return after the error */
+ if (isset(POSIXBUILTINS)) {
+ optcind = 0;
+ zoptind++;
+ }
zsfree(zoptarg);
setsparam(var, ztrdup(p));
if(quiet) {
@@ -5584,6 +5589,11 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
if(p[1] == ':') {
if(optcind == lenstr) {
if(!args[zoptind]) {
+ /* Fix OPTIND as above */
+ if (isset(POSIXBUILTINS)) {
+ optcind = 0;
+ zoptind++;
+ }
zsfree(zoptarg);
if(quiet) {
setsparam(var, ztrdup(":"));
diff --git a/Test/B10getopts.ztst b/Test/B10getopts.ztst
index 72c9e209e..e50d177c7 100644
--- a/Test/B10getopts.ztst
+++ b/Test/B10getopts.ztst
@@ -96,3 +96,32 @@
done
0:missing option-argument (quiet mode)
>:,x
+
+ # This function is written so it can be easily referenced against other shells
+ t() {
+ local o i=0 n=$1
+ shift
+ while [ $i -lt $n ]; do
+ i=$(( i + 1 ))
+ getopts a: o "$@" 2> /dev/null
+ done
+ printf '<%d>' "$OPTIND"
+ }
+ # Try all these the native way, then the POSIX_BUILTINS way
+ for 1 in no_posix_builtins posix_builtins; do (
+ setopt $1
+ print -rn - "$1: "
+ t 1
+ t 1 foo
+ t 1 -- foo
+ t 1 -a
+ t 1 -b
+ t 2 -a -b
+ t 4 -a -b -c -d -a
+ t 5 -a -b -c -a -b -c
+ t 5 -a -b -c -d -ax -a
+ print
+ ); done
+0:OPTIND calculation with and without POSIX_BUILTINS (workers/42248)
+>no_posix_builtins: <1><1><2><1><1><3><5><7><6>
+>posix_builtins: <1><1><2><2><2><3><6><7><7>
--
cgit v1.2.3
From db3614900602b51edd79ae8c1308b8665de9f913 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Sat, 15 May 2021 13:59:17 -0700
Subject: users/26742: break out of surrounding shell loops when exit is called
from an exit hook
---
ChangeLog | 3 +++
Src/builtin.c | 5 ++++-
2 files changed, 7 insertions(+), 1 deletion(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 38f18a4b9..8e241fa6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2021-05-15 Bart Schaefer
+ * Peter Stephenson: users/26742: Src/builtin.c: break out of
+ surrounding shell loops when "exit" is called from an exit hook
+
* users/26736: Src/Zle/zle_main.c: avoid infinite loop in getbyte
when read -q is called from exit hook
diff --git a/Src/builtin.c b/Src/builtin.c
index b7ceefd55..a29eb49e4 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5828,8 +5828,11 @@ zexit(int val, enum zexit_t from_where)
* a later value always overrides an earlier.
*/
exit_val = val;
- if (shell_exiting == -1)
+ if (shell_exiting == -1) {
+ retflag = 1;
+ breaks = loops;
return;
+ }
if (isset(MONITOR) && !stopmsg && from_where != ZEXIT_SIGNAL) {
scanjobs(); /* check if jobs need printing */
--
cgit v1.2.3
From cf5c4828d1cdfd79e369a6b3323466bc961851c4 Mon Sep 17 00:00:00 2001
From: Bart Schaefer
Date: Sun, 16 May 2021 19:51:11 -0700
Subject: 48857: declare "volatile" all globals that may be modified by signal
handlers
---
ChangeLog | 6 ++++++
Src/builtin.c | 16 +++++++---------
Src/exec.c | 8 +++++---
Src/loop.c | 2 +-
Src/makepro.awk | 2 +-
Src/params.c | 6 ++++--
Src/signals.c | 16 ++++++++--------
7 files changed, 32 insertions(+), 24 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 6f8520db7..89b469c0f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2021-05-16 Bart Schaefer
+
+ * 48857: Src/builtin.c, Src/exec.c, Src/loop.c, Src/makepro.awk,
+ Src/params.c, Src/signals.c: declare as "volatile" all globals
+ that may be modified by signal handlers; recognize in makepro.awk
+
2021-05-16 Oliver Kiddle
* Jörg Sommer: users/26649: Completion/Unix/Command/_rake:
diff --git a/Src/builtin.c b/Src/builtin.c
index a29eb49e4..a16fddcb7 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5635,13 +5635,16 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
*/
/**/
-mod_export int
-exit_pending;
+mod_export volatile int exit_pending;
/* Shell level at which we exit if exit_pending */
/**/
-mod_export int
-exit_level;
+mod_export volatile int exit_level;
+
+/* we have printed a 'you have stopped (running) jobs.' message */
+
+/**/
+mod_export volatile int stopmsg;
/* break, bye, continue, exit, logout, return -- most of these take *
* one numeric argument, and the other (logout) is related to return. *
@@ -5733,11 +5736,6 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
return 0;
}
-/* we have printed a 'you have stopped (running) jobs.' message */
-
-/**/
-mod_export int stopmsg;
-
/* check to see if user has jobs running/stopped */
/**/
diff --git a/Src/exec.c b/Src/exec.c
index 6f09e0d9f..49ff88b80 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -84,7 +84,7 @@ int nohistsave;
/* error flag: bits from enum errflag_bits */
/**/
-mod_export int errflag;
+mod_export volatile int errflag;
/*
* State of trap return value. Value is from enum trap_state.
@@ -122,7 +122,7 @@ int subsh;
/* != 0 if we have a return pending */
/**/
-mod_export int retflag;
+mod_export volatile int retflag;
/**/
long lastval2;
@@ -1268,7 +1268,9 @@ execsimple(Estate state)
} else {
int q = queue_signal_level();
dont_queue_signals();
- if (code == WC_FUNCDEF)
+ if (errflag)
+ lv = errflag;
+ else if (code == WC_FUNCDEF)
lv = execfuncdef(state, NULL);
else
lv = (execfuncs[code - WC_CURSH])(state, 0);
diff --git a/Src/loop.c b/Src/loop.c
index aa733a2cb..db5b3e097 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -43,7 +43,7 @@ mod_export int contflag;
/* # of break levels */
/**/
-mod_export int breaks;
+mod_export volatile int breaks;
/**/
int
diff --git a/Src/makepro.awk b/Src/makepro.awk
index 226d3f96b..f69660531 100644
--- a/Src/makepro.awk
+++ b/Src/makepro.awk
@@ -79,7 +79,7 @@ BEGIN {
break
}
sub(/^ */, "", line)
- match(line, /^((const|enum|mod_export|static|struct|union) +)*([_0-9A-Za-z]+ +|((char|double|float|int|long|short|unsigned|void) +)+)((const|static) +)*/)
+ match(line, /^((const|enum|mod_export|static|struct|union|volatile) +)*([_0-9A-Za-z]+ +|((char|double|float|int|long|short|unsigned|void) +)+)((const|static) +)*/)
dtype = substr(line, 1, RLENGTH)
sub(/ *$/, "", dtype)
if(" " dtype " " ~ / static /)
diff --git a/Src/params.c b/Src/params.c
index 20dfb5b5f..4f6b361f9 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -98,8 +98,10 @@ char *ifs, /* $IFS */
*pwd; /* $PWD */
/**/
-mod_export
-zlong lastval, /* $? */
+mod_export volatile zlong
+ lastval; /* $? */
+/**/
+mod_export zlong
mypid, /* $$ */
lastpid, /* $! */
zterm_columns, /* $COLUMNS */
diff --git a/Src/signals.c b/Src/signals.c
index 4adf03202..2c540f38f 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -53,7 +53,7 @@ mod_export Eprog siglists[VSIGCOUNT];
/* Total count of trapped signals */
/**/
-mod_export int nsigtrapped;
+mod_export volatile int nsigtrapped;
/* Running an exit trap? */
@@ -72,20 +72,20 @@ static int exit_trap_posix;
/* Variables used by signal queueing */
/**/
-mod_export int queueing_enabled, queue_front, queue_rear;
+mod_export volatile int queueing_enabled, queue_front, queue_rear;
/**/
mod_export int signal_queue[MAX_QUEUE_SIZE];
/**/
mod_export sigset_t signal_mask_queue[MAX_QUEUE_SIZE];
#ifdef DEBUG
/**/
-mod_export int queue_in;
+mod_export volatile int queue_in;
#endif
/* Variables used by trap queueing */
/**/
-mod_export int trap_queueing_enabled, trap_queue_front, trap_queue_rear;
+mod_export volatile int trap_queueing_enabled, trap_queue_front, trap_queue_rear;
/**/
mod_export int trap_queue[MAX_QUEUE_SIZE];
@@ -672,9 +672,9 @@ zhandler(int sig)
if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL))
zexit(SIGINT, ZEXIT_SIGNAL);
+ errflag |= ERRFLAG_INT;
if (list_pipe || chline || simple_pline) {
breaks = loops;
- errflag |= ERRFLAG_INT;
inerrflush();
check_cursh_sig(SIGINT);
}
@@ -1266,19 +1266,19 @@ unqueue_traps(void)
/* Are we already executing a trap? */
/**/
-int intrap;
+volatile int intrap;
/* Is the current trap a function? */
/**/
-int trapisfunc;
+volatile int trapisfunc;
/*
* If the current trap is not a function, at what function depth
* did the trap get called?
*/
/**/
-int traplocallevel;
+volatile int traplocallevel;
/*
* sig is the signal number.
--
cgit v1.2.3
From 5b4a1626c2efbbc4b46e8995e553ec2c14549904 Mon Sep 17 00:00:00 2001
From: Bart Schaefer
Date: Sun, 13 Jun 2021 16:30:06 -0700
Subject: 49069: literal interpretation of subscripts for unset of array/hash
elements
---
ChangeLog | 5 +++++
NEWS | 12 ++++++++++++
Src/builtin.c | 6 ++----
3 files changed, 19 insertions(+), 4 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 78271d448..83c2ac12d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-06-13 Bart Schaefer
+
+ * 49069: NEWS, Src/builtin.c: literal interpretation of subscripts
+ for unset of array/hash elements
+
2021-06-02 Oliver Kiddle
* Akinori MUSHA: 48942: Functions/Zle/edit-command-line:
diff --git a/NEWS b/NEWS
index ee97868f9..c12ec3b0e 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,18 @@ Note also the list of incompatibilities in the README file.
Changes since 5.8
-----------------
+When unsetting a hash element, the string enclosed in square brackets is
+interpreted literally after any normal command-line-argument expansions.
+Thus
+ unset "hash[$key]"
+first expands $key as usual for a double-quoted string, and then interprets
+that result as the exact hash element to unset. This differs from previous
+versions of the shell, which would also remove a leading backslash for an
+unusual subset of characters in the expansion of $key. Note this also
+means, for example, that
+ unset 'hash[ab]cd]'
+unsets the element with key "ab]cd" rather than silently doing nothing.
+
The function command learnt a -T option to declare a function and enable
tracing for it simultaneously.
diff --git a/Src/builtin.c b/Src/builtin.c
index a16fddcb7..d7d2ea297 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3724,14 +3724,12 @@ bin_unset(char *name, char **argv, Options ops, int func)
while ((s = *argv++)) {
char *ss = strchr(s, '['), *subscript = 0;
if (ss) {
- char *sse;
+ char *sse = ss + strlen(ss)-1;
*ss = 0;
- if ((sse = parse_subscript(ss+1, 1, ']'))) {
+ if (*sse == ']') {
*sse = 0;
subscript = dupstring(ss+1);
*sse = ']';
- remnulargs(subscript);
- untokenize(subscript);
}
}
if ((ss && !subscript) || !isident(s)) {
--
cgit v1.2.3
From 2b81d4be3232fced220be1cf9c80c087d91d88d6 Mon Sep 17 00:00:00 2001
From: Jun-ichi Takimoto
Date: Wed, 8 Sep 2021 11:58:29 +0900
Subject: unposted: add/remove UNUSED() for some function parameters
---
ChangeLog | 4 ++++
Src/Modules/db_gdbm.c | 2 +-
Src/Modules/files.c | 2 +-
Src/Modules/nearcolor.c | 2 +-
Src/Zle/complete.c | 2 +-
Src/builtin.c | 2 +-
6 files changed, 9 insertions(+), 5 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index fe9a3b4ee..6f4646287 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2021-09-08 Jun-ichi Takimoto
+ * unposted: Src/Modules/db_gdbm.c, Src/Modules/files.c,
+ Src/Modules/nearcolor.c, Src/Zle/complete.c, Src/builtin.c:
+ add/remove UNUSED() for some funtion parameters
+
* unposted: Src/input.c: add 'static' to shinsavestack
* 49377: Src/Zle/zle_keymap.c, Test/X03zlebindkey.ztst: fix
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index 84fdfa905..7e11ec939 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -233,7 +233,7 @@ bin_zuntie(char *nam, char **args, Options ops, UNUSED(int func))
/**/
static int
-bin_zgdbmpath(char *nam, char **args, Options ops, UNUSED(int func))
+bin_zgdbmpath(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
Param pm;
char *pmname;
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index d991f69d7..bf0e8f8a8 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -652,7 +652,7 @@ chmod_dochmod(char *arg, char *rp, UNUSED(struct stat const *sp), void *magic)
/**/
static int
-bin_chmod(char *nam, char **args, Options ops, int func)
+bin_chmod(char *nam, char **args, Options ops, UNUSED(int func))
{
struct chmodmagic chm;
char *str = args[0], *ptr;
diff --git a/Src/Modules/nearcolor.c b/Src/Modules/nearcolor.c
index b49ee9afb..d50a6bb44 100644
--- a/Src/Modules/nearcolor.c
+++ b/Src/Modules/nearcolor.c
@@ -188,7 +188,7 @@ enables_(Module m, int **enables)
/**/
int
-boot_(Module m)
+boot_(UNUSED(Module m))
{
addhookfunc("get_color_attr", (Hookfn) getnearestcolor);
return 0;
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 7beb6d847..71d114de9 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1343,7 +1343,7 @@ get_compstate(Param pm)
/**/
static void
-set_compstate(UNUSED(Param pm), HashTable ht)
+set_compstate(Param pm, HashTable ht)
{
struct compparam *cp;
Param *pp;
diff --git a/Src/builtin.c b/Src/builtin.c
index d7d2ea297..89bcd98db 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2024,7 +2024,7 @@ typeset_setwidth(const char * name, Param pm, Options ops, int on, int always)
/**/
static Param
-typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
+typeset_single(char *cname, char *pname, Param pm, int func,
int on, int off, int roff, Asgment asg, Param altpm,
Options ops, int joinchar)
{
--
cgit v1.2.3
From 271cfc685b17938e67a8212f2df78c32989411d7 Mon Sep 17 00:00:00 2001
From: Oliver Kiddle
Date: Tue, 2 Nov 2021 21:39:52 +0100
Subject: 49534, 49539: separate watch/log functionality out into a module
---
ChangeLog | 6 +
Doc/Makefile.in | 1 +
Doc/Zsh/builtins.yo | 8 -
Doc/Zsh/compat.yo | 3 +-
Doc/Zsh/mod_watch.yo | 140 ++++++++++
Doc/Zsh/params.yo | 118 ---------
Src/Modules/watch.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++++++
Src/Modules/watch.mdd | 7 +
Src/builtin.c | 1 -
Src/init.c | 1 -
Src/params.c | 16 +-
Src/utils.c | 16 --
Src/watch.c | 626 -------------------------------------------
Src/zsh.mdd | 2 +-
14 files changed, 878 insertions(+), 783 deletions(-)
create mode 100644 Doc/Zsh/mod_watch.yo
create mode 100644 Src/Modules/watch.c
create mode 100644 Src/Modules/watch.mdd
delete mode 100644 Src/watch.c
(limited to 'Src/builtin.c')
diff --git a/ChangeLog b/ChangeLog
index 5179555ca..00c0d5be6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2021-11-02 Oliver Kiddle
+ * 49534, 49539: Doc/Makefile.in, Doc/Zsh/builtins.yo,
+ Doc/Zsh/compat.yo, Doc/Zsh/mod_watch.yo, Doc/Zsh/params.yo,
+ Src/Modules/watch.mdd, Src/builtin.c, Src/init.c, Src/params.c,
+ Src/utils.c, Src/Modules/watch.c, Src/zsh.mdd: separate watch/log
+ functionality out into a module
+
* 49537: aczsh.m4, configure.ac: fix finding utmpx file on FreeBSD
2021-11-01 Jun-ichi Takimoto
diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 5a6a705ff..23e5fc7e2 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -69,6 +69,7 @@ Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
Zsh/mod_stat.yo Zsh/mod_system.yo Zsh/mod_tcp.yo \
Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
+Zsh/mod_watch.yo \
Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
Zsh/mod_zprof.yo Zsh/mod_zpty.yo Zsh/mod_zselect.yo \
Zsh/mod_zutil.yo
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index ddbcd4363..733d8f185 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1235,14 +1235,6 @@ Same as tt(typeset), except that the options tt(-g), and
tt(-f) are not permitted. In this case the tt(-x) option does not force
the use of tt(-g), i.e. exported variables will be local to functions.
)
-findex(log)
-vindex(watch, use of)
-cindex(watching users)
-cindex(users, watching)
-item(tt(log))(
-List all users currently logged in who are affected by
-the current setting of the tt(watch) parameter.
-)
findex(logout)
item(tt(logout) [ var(n) ])(
Same as tt(exit), except that it only works in a login shell.
diff --git a/Doc/Zsh/compat.yo b/Doc/Zsh/compat.yo
index 6e4dbcfa4..4d3567d45 100644
--- a/Doc/Zsh/compat.yo
+++ b/Doc/Zsh/compat.yo
@@ -30,8 +30,7 @@ tt(PROMPT2),
tt(PROMPT3),
tt(PROMPT4),
tt(psvar),
-tt(status),
-tt(watch).
+tt(status).
vindex(ENV, use of)
The usual zsh startup/shutdown scripts are not executed. Login shells
diff --git a/Doc/Zsh/mod_watch.yo b/Doc/Zsh/mod_watch.yo
new file mode 100644
index 000000000..4eea89e23
--- /dev/null
+++ b/Doc/Zsh/mod_watch.yo
@@ -0,0 +1,140 @@
+COMMENT(!MOD!zsh/watch
+Reporting of login and logout events.
+!MOD!)
+The tt(zsh/watch) module can be used to report when specific users log in or
+out. This is controlled via the following parameters.
+
+startitem()
+vindex(LOGCHECK)
+item(tt(LOGCHECK))(
+The interval in seconds between checks for login/logout activity
+using the tt(watch) parameter.
+)
+vindex(watch)
+vindex(WATCH)
+item(tt(watch) (tt(WATCH) ))(
+An array (colon-separated list) of login/logout events to report.
+
+If it contains the single word `tt(all)', then all login/logout events
+are reported. If it contains the single word `tt(notme)', then all
+events are reported as with `tt(all)' except tt($USERNAME).
+
+An entry in this list may consist of a username,
+an `tt(@)' followed by a remote hostname,
+and a `tt(%)' followed by a line (tty). Any of these may
+be a pattern (be sure to quote this during the assignment to
+tt(watch) so that it does not immediately perform file generation);
+the setting of the tt(EXTENDED_GLOB) option is respected.
+Any or all of these components may be present in an entry;
+if a login/logout event matches all of them,
+it is reported.
+
+For example, with the tt(EXTENDED_GLOB) option set, the following:
+
+example(watch=('^(pws|barts)'))
+
+causes reports for activity associated with any user other than tt(pws)
+or tt(barts).
+)
+vindex(WATCHFMT)
+item(tt(WATCHFMT))(
+The format of login/logout reports if the tt(watch) parameter is set.
+Default is `tt(%n has %a %l from %m)'.
+Recognizes the following escape sequences:
+
+startitem()
+item(tt(%n))(
+The name of the user that logged in/out.
+)
+item(tt(%a))(
+The observed action, i.e. "logged on" or "logged off".
+)
+item(tt(%l))(
+The line (tty) the user is logged in on.
+)
+item(tt(%M))(
+The full hostname of the remote host.
+)
+item(tt(%m))(
+The hostname up to the first `tt(.)'. If only the
+IP address is available or the utmp field contains
+the name of an X-windows display, the whole name is printed.
+
+em(NOTE:)
+The `tt(%m)' and `tt(%M)' escapes will work only if there is a host name
+field in the utmp on your machine. Otherwise they are
+treated as ordinary strings.
+)
+item(tt(%S) LPAR()tt(%s)RPAR())(
+Start (stop) standout mode.
+)
+item(tt(%U) LPAR()tt(%u)RPAR())(
+Start (stop) underline mode.
+)
+item(tt(%B) LPAR()tt(%b)RPAR())(
+Start (stop) boldface mode.
+)
+xitem(tt(%t))
+item(tt(%@))(
+The time, in 12-hour, am/pm format.
+)
+item(tt(%T))(
+The time, in 24-hour format.
+)
+item(tt(%w))(
+The date in `var(day)tt(-)var(dd)' format.
+)
+item(tt(%W))(
+The date in `var(mm)tt(/)var(dd)tt(/)var(yy)' format.
+)
+item(tt(%D))(
+The date in `var(yy)tt(-)var(mm)tt(-)var(dd)' format.
+)
+item(tt(%D{)var(string)tt(}))(
+The date formatted as var(string) using the tt(strftime) function, with
+zsh extensions as described by
+ifzman(EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
+ifnzman(noderef(Prompt Expansion)).
+)
+item(tt(%LPAR())var(x)tt(:)var(true-text)tt(:)var(false-text)tt(RPAR()))(
+Specifies a ternary expression.
+The character following the var(x) is
+arbitrary; the same character is used to separate the text
+for the "true" result from that for the "false" result.
+Both the separator and the right parenthesis may be escaped
+with a backslash.
+Ternary expressions may be nested.
+
+The test character var(x) may be any one of `tt(l)', `tt(n)', `tt(m)'
+or `tt(M)', which indicate a `true' result if the corresponding
+escape sequence would return a non-empty value; or it may be `tt(a)',
+which indicates a `true' result if the watched user has logged in,
+or `false' if he has logged out.
+Other characters evaluate to neither true nor false; the entire
+expression is omitted in this case.
+
+If the result is `true', then the var(true-text)
+is formatted according to the rules above and printed,
+and the var(false-text) is skipped.
+If `false', the var(true-text) is skipped and the var(false-text)
+is formatted and printed.
+Either or both of the branches may be empty, but
+both separators must be present in any case.
+)
+enditem()
+)
+enditem()
+
+Furthermore, the tt(zsh/watch) module makes available one builtin
+command:
+
+startitem()
+findex(log)
+vindex(watch, use of)
+cindex(watching users)
+cindex(users, watching)
+item(tt(log))(
+List all users currently logged in who are affected by
+the current setting of the tt(watch) parameter.
+)
+enditem()
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index a88e44d4f..1f2f01f55 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -1332,11 +1332,6 @@ most as many lines as given by the absolute value.
If set to zero, the shell asks only if the top of the listing would scroll
off the screen.
)
-vindex(LOGCHECK)
-item(tt(LOGCHECK))(
-The interval in seconds between checks for login/logout activity
-using the tt(watch) parameter.
-)
vindex(MAIL)
item(tt(MAIL))(
If this parameter is set and tt(mailpath) is not set,
@@ -1670,119 +1665,6 @@ to be interpreted as a file extension. The default is not to append
any suffix, thus this parameter should be assigned only when needed
and then unset again.
)
-vindex(watch)
-vindex(WATCH)
-item(tt(watch) (tt(WATCH) ))(
-An array (colon-separated list) of login/logout events to report.
-
-If it contains the single word `tt(all)', then all login/logout events
-are reported. If it contains the single word `tt(notme)', then all
-events are reported as with `tt(all)' except tt($USERNAME).
-
-An entry in this list may consist of a username,
-an `tt(@)' followed by a remote hostname,
-and a `tt(%)' followed by a line (tty). Any of these may
-be a pattern (be sure to quote this during the assignment to
-tt(watch) so that it does not immediately perform file generation);
-the setting of the tt(EXTENDED_GLOB) option is respected.
-Any or all of these components may be present in an entry;
-if a login/logout event matches all of them,
-it is reported.
-
-For example, with the tt(EXTENDED_GLOB) option set, the following:
-
-example(watch=('^(pws|barts)'))
-
-causes reports for activity associated with any user other than tt(pws)
-or tt(barts).
-)
-vindex(WATCHFMT)
-item(tt(WATCHFMT))(
-The format of login/logout reports if the tt(watch) parameter is set.
-Default is `tt(%n has %a %l from %m)'.
-Recognizes the following escape sequences:
-
-startitem()
-item(tt(%n))(
-The name of the user that logged in/out.
-)
-item(tt(%a))(
-The observed action, i.e. "logged on" or "logged off".
-)
-item(tt(%l))(
-The line (tty) the user is logged in on.
-)
-item(tt(%M))(
-The full hostname of the remote host.
-)
-item(tt(%m))(
-The hostname up to the first `tt(.)'. If only the
-IP address is available or the utmp field contains
-the name of an X-windows display, the whole name is printed.
-
-em(NOTE:)
-The `tt(%m)' and `tt(%M)' escapes will work only if there is a host name
-field in the utmp on your machine. Otherwise they are
-treated as ordinary strings.
-)
-item(tt(%S) LPAR()tt(%s)RPAR())(
-Start (stop) standout mode.
-)
-item(tt(%U) LPAR()tt(%u)RPAR())(
-Start (stop) underline mode.
-)
-item(tt(%B) LPAR()tt(%b)RPAR())(
-Start (stop) boldface mode.
-)
-xitem(tt(%t))
-item(tt(%@))(
-The time, in 12-hour, am/pm format.
-)
-item(tt(%T))(
-The time, in 24-hour format.
-)
-item(tt(%w))(
-The date in `var(day)tt(-)var(dd)' format.
-)
-item(tt(%W))(
-The date in `var(mm)tt(/)var(dd)tt(/)var(yy)' format.
-)
-item(tt(%D))(
-The date in `var(yy)tt(-)var(mm)tt(-)var(dd)' format.
-)
-item(tt(%D{)var(string)tt(}))(
-The date formatted as var(string) using the tt(strftime) function, with
-zsh extensions as described by
-ifzman(EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
-ifnzman(noderef(Prompt Expansion)).
-)
-item(tt(%LPAR())var(x)tt(:)var(true-text)tt(:)var(false-text)tt(RPAR()))(
-Specifies a ternary expression.
-The character following the var(x) is
-arbitrary; the same character is used to separate the text
-for the "true" result from that for the "false" result.
-Both the separator and the right parenthesis may be escaped
-with a backslash.
-Ternary expressions may be nested.
-
-The test character var(x) may be any one of `tt(l)', `tt(n)', `tt(m)'
-or `tt(M)', which indicate a `true' result if the corresponding
-escape sequence would return a non-empty value; or it may be `tt(a)',
-which indicates a `true' result if the watched user has logged in,
-or `false' if he has logged out.
-Other characters evaluate to neither true nor false; the entire
-expression is omitted in this case.
-
-If the result is `true', then the var(true-text)
-is formatted according to the rules above and printed,
-and the var(false-text) is skipped.
-If `false', the var(true-text) is skipped and the var(false-text)
-is formatted and printed.
-Either or both of the branches may be empty, but
-both separators must be present in any case.
-)
-enditem()
-)
vindex(WORDCHARS)
item(tt(WORDCHARS) )(
A list of non-alphanumeric characters considered part of a word
diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c
new file mode 100644
index 000000000..02f0562fc
--- /dev/null
+++ b/Src/Modules/watch.c
@@ -0,0 +1,716 @@
+/*
+ * watch.c - login/logout watching
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1992-1997 Paul Falstad
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Paul Falstad or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Paul Falstad and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Paul Falstad and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Paul Falstad and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "watch.mdh"
+
+/* Headers for utmp/utmpx structures */
+#ifdef HAVE_UTMP_H
+# include
+#endif
+#ifdef HAVE_UTMPX_H
+# include
+#endif
+
+/* Find utmp file */
+#if !defined(REAL_UTMP_FILE) && defined(UTMP_FILE)
+# define REAL_UTMP_FILE UTMP_FILE
+#endif
+#if !defined(REAL_UTMP_FILE) && defined(_PATH_UTMP)
+# define REAL_UTMP_FILE _PATH_UTMP
+#endif
+#if !defined(REAL_UTMP_FILE) && defined(PATH_UTMP_FILE)
+# define REAL_UTMP_FILE PATH_UTMP_FILE
+#endif
+
+/* Find wtmp file */
+#if !defined(REAL_WTMP_FILE) && defined(WTMP_FILE)
+# define REAL_WTMP_FILE WTMP_FILE
+#endif
+#if !defined(REAL_WTMP_FILE) && defined(_PATH_WTMP)
+# define REAL_WTMP_FILE _PATH_WTMP
+#endif
+#if !defined(REAL_WTMP_FILE) && defined(PATH_WTMP_FILE)
+# define REAL_WTMP_FILE PATH_WTMP_FILE
+#endif
+
+/* Find utmpx file */
+#if !defined(REAL_UTMPX_FILE) && defined(UTMPX_FILE)
+# define REAL_UTMPX_FILE UTMPX_FILE
+#endif
+#if !defined(REAL_UTMPX_FILE) && defined(_PATH_UTMPX)
+# define REAL_UTMPX_FILE _PATH_UTMPX
+#endif
+#if !defined(REAL_UTMPX_FILE) && defined(PATH_UTMPX_FILE)
+# define REAL_UTMPX_FILE PATH_UTMPX_FILE
+#endif
+
+/* Find wtmpx file */
+#if !defined(REAL_WTMPX_FILE) && defined(WTMPX_FILE)
+# define REAL_WTMPX_FILE WTMPX_FILE
+#endif
+#if !defined(REAL_WTMPX_FILE) && defined(_PATH_WTMPX)
+# define REAL_WTMPX_FILE _PATH_WTMPX
+#endif
+#if !defined(REAL_WTMPX_FILE) && defined(PATH_WTMPX_FILE)
+# define REAL_WTMPX_FILE PATH_WTMPX_FILE
+#endif
+
+/* Decide which structure to use. We use a structure that exists in *
+ * the headers, and require that its corresponding utmp file exist. *
+ * (wtmp is less important.) */
+
+#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMPX) && defined(REAL_UTMPX_FILE)
+# define WATCH_STRUCT_UTMP struct utmpx
+# if defined(HAVE_SETUTXENT) && defined(HAVE_GETUTXENT) && defined(HAVE_ENDUTXENT)
+# define setutent setutxent
+# define getutent getutxent
+# define endutent endutxent
+# ifndef HAVE_GETUTENT
+# define HAVE_GETUTENT 1
+# endif
+# endif
+
+/*
+ * In utmpx, the ut_name field is replaced by ut_user.
+ * However, on some systems ut_name may already be defined this
+ * way for the purposes of utmp.
+ */
+# ifndef ut_name
+# define ut_name ut_user
+# endif
+# ifdef HAVE_STRUCT_UTMPX_UT_XTIME
+# undef ut_time
+# define ut_time ut_xtime
+# else /* !HAVE_STRUCT_UTMPX_UT_XTIME */
+# ifdef HAVE_STRUCT_UTMPX_UT_TV
+# undef ut_time
+# define ut_time ut_tv.tv_sec
+# endif /* HAVE_STRUCT_UTMPX_UT_TV */
+# endif /* !HAVE_STRUCT_UTMPX_UT_XTIME */
+# define WATCH_UTMP_FILE REAL_UTMPX_FILE
+# ifdef REAL_WTMPX_FILE
+# define WATCH_WTMP_FILE REAL_WTMPX_FILE
+# endif
+# ifdef HAVE_STRUCT_UTMPX_UT_HOST
+# define WATCH_UTMP_UT_HOST 1
+# endif
+#endif
+
+#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMP) && defined(REAL_UTMP_FILE)
+# define WATCH_STRUCT_UTMP struct utmp
+# define WATCH_UTMP_FILE REAL_UTMP_FILE
+# ifdef REAL_WTMP_FILE
+# define WATCH_WTMP_FILE REAL_WTMP_FILE
+# endif
+# ifdef HAVE_STRUCT_UTMP_UT_HOST
+# define WATCH_UTMP_UT_HOST 1
+# endif
+#endif
+
+#ifdef WATCH_UTMP_UT_HOST
+# define DEFAULT_WATCHFMT "%n has %a %l from %m."
+#else /* !WATCH_UTMP_UT_HOST */
+# define DEFAULT_WATCHFMT "%n has %a %l."
+#endif /* !WATCH_UTMP_UT_HOST */
+
+#ifdef WATCH_STRUCT_UTMP
+
+# include "watch.pro"
+
+# ifndef WATCH_WTMP_FILE
+# define WATCH_WTMP_FILE "/dev/null"
+# endif
+
+static int wtabsz = 0;
+static WATCH_STRUCT_UTMP *wtab = NULL;
+
+/* the last time we checked the people in the WATCH variable */
+static time_t lastwatch;
+
+static time_t lastutmpcheck = 0;
+
+/* get the time of login/logout for WATCH */
+
+static time_t
+getlogtime(WATCH_STRUCT_UTMP *u, int inout)
+{
+ FILE *in;
+ WATCH_STRUCT_UTMP uu;
+ int first = 1;
+ int srchlimit = 50; /* max number of wtmp records to search */
+
+ if (inout)
+ return u->ut_time;
+ if (!(in = fopen(WATCH_WTMP_FILE, "r")))
+ return time(NULL);
+ fseek(in, 0, SEEK_END);
+ do {
+ if (fseek(in, ((first) ? -1 : -2) * sizeof(WATCH_STRUCT_UTMP), SEEK_CUR)) {
+ fclose(in);
+ return time(NULL);
+ }
+ first = 0;
+ if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
+ fclose(in);
+ return time(NULL);
+ }
+ if (uu.ut_time < lastwatch || !srchlimit--) {
+ fclose(in);
+ return time(NULL);
+ }
+ }
+ while (memcmp(&uu, u, sizeof(uu)));
+
+ do
+ if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
+ fclose(in);
+ return time(NULL);
+ }
+ while (strncmp(uu.ut_line, u->ut_line, sizeof(u->ut_line)));
+ fclose(in);
+ return uu.ut_time;
+}
+
+/* Mutually recursive call to handle ternaries in $WATCHFMT */
+
+# define BEGIN3 '('
+# define END3 ')'
+
+static char *
+watch3ary(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt)
+{
+ int truth = 1, sep;
+
+ switch (*fmt++) {
+ case 'n':
+ truth = (u->ut_name[0] != 0);
+ break;
+ case 'a':
+ truth = inout;
+ break;
+ case 'l':
+ if (!strncmp(u->ut_line, "tty", 3))
+ truth = (u->ut_line[3] != 0);
+ else
+ truth = (u->ut_line[0] != 0);
+ break;
+# ifdef WATCH_UTMP_UT_HOST
+ case 'm':
+ case 'M':
+ truth = (u->ut_host[0] != 0);
+ break;
+# endif /* WATCH_UTMP_UT_HOST */
+ default:
+ prnt = 0; /* Skip unknown conditionals entirely */
+ break;
+ }
+ sep = *fmt++;
+ fmt = watchlog2(inout, u, fmt, (truth && prnt), sep);
+ return watchlog2(inout, u, fmt, (!truth && prnt), END3);
+}
+
+/* print a login/logout event */
+
+/**/
+static char *
+watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
+{
+ char buf[40], buf2[80];
+ time_t timet;
+ struct tm *tm;
+ char *fm2;
+ int len;
+# ifdef WATCH_UTMP_UT_HOST
+ char *p;
+ int i;
+# endif /* WATCH_UTMP_UT_HOST */
+
+ while (*fmt)
+ if (*fmt == '\\') {
+ if (*++fmt) {
+ if (prnt)
+ putchar(*fmt);
+ ++fmt;
+ } else if (fini)
+ return fmt;
+ else
+ break;
+ }
+ else if (*fmt == fini)
+ return ++fmt;
+ else if (*fmt != '%') {
+ if (prnt)
+ putchar(*fmt);
+ ++fmt;
+ } else {
+ if (*++fmt == BEGIN3)
+ fmt = watch3ary(inout, u, ++fmt, prnt);
+ else if (!prnt)
+ ++fmt;
+ else
+ switch (*(fm2 = fmt++)) {
+ case 'n':
+ printf("%.*s", (int)sizeof(u->ut_name), u->ut_name);
+ break;
+ case 'a':
+ printf("%s", (!inout) ? "logged off" : "logged on");
+ break;
+ case 'l':
+ if (!strncmp(u->ut_line, "tty", 3))
+ printf("%.*s", (int)sizeof(u->ut_line) - 3, u->ut_line + 3);
+ else
+ printf("%.*s", (int)sizeof(u->ut_line), u->ut_line);
+ break;
+# ifdef WATCH_UTMP_UT_HOST
+ case 'm':
+ for (p = u->ut_host, i = sizeof(u->ut_host); i && *p; i--, p++) {
+ if (*p == '.' && !idigit(p[1]))
+ break;
+ putchar(*p);
+ }
+ break;
+ case 'M':
+ printf("%.*s", (int)sizeof(u->ut_host), u->ut_host);
+ break;
+# endif /* WATCH_UTMP_UT_HOST */
+ case 'T':
+ case 't':
+ case '@':
+ case 'W':
+ case 'w':
+ case 'D':
+ switch (*fm2) {
+ case '@':
+ case 't':
+ fm2 = "%l:%M%p";
+ break;
+ case 'T':
+ fm2 = "%K:%M";
+ break;
+ case 'w':
+ fm2 = "%a %f";
+ break;
+ case 'W':
+ fm2 = "%m/%d/%y";
+ break;
+ case 'D':
+ if (fm2[1] == '{') {
+ char *dd, *ss;
+ int n = 79;
+
+ for (ss = fm2 + 2, dd = buf2;
+ n-- && *ss && *ss != '}'; ++ss, ++dd)
+ *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
+ if (*ss == '}') {
+ *dd = '\0';
+ fmt = ss + 1;
+ fm2 = buf2;
+ }
+ else fm2 = "%y-%m-%d";
+ }
+ else fm2 = "%y-%m-%d";
+ break;
+ }
+ timet = getlogtime(u, inout);
+ tm = localtime(&timet);
+ len = ztrftime(buf, 40, fm2, tm, 0L);
+ if (len > 0)
+ metafy(buf, len, META_NOALLOC);
+ printf("%s", (*buf == ' ') ? buf + 1 : buf);
+ break;
+ case '%':
+ putchar('%');
+ break;
+ case 'S':
+ txtset(TXTSTANDOUT);
+ tsetcap(TCSTANDOUTBEG, TSC_RAW);
+ break;
+ case 's':
+ txtunset(TXTSTANDOUT);
+ tsetcap(TCSTANDOUTEND, TSC_RAW|TSC_DIRTY);
+ break;
+ case 'B':
+ txtset(TXTBOLDFACE);
+ tsetcap(TCBOLDFACEBEG, TSC_RAW|TSC_DIRTY);
+ break;
+ case 'b':
+ txtunset(TXTBOLDFACE);
+ tsetcap(TCALLATTRSOFF, TSC_RAW|TSC_DIRTY);
+ break;
+ case 'U':
+ txtset(TXTUNDERLINE);
+ tsetcap(TCUNDERLINEBEG, TSC_RAW);
+ break;
+ case 'u':
+ txtunset(TXTUNDERLINE);
+ tsetcap(TCUNDERLINEEND, TSC_RAW|TSC_DIRTY);
+ break;
+ default:
+ putchar('%');
+ putchar(*fm2);
+ break;
+ }
+ }
+ if (prnt)
+ putchar('\n');
+
+ return fmt;
+}
+
+/* See if the watch entry matches */
+
+static int
+watchlog_match(char *teststr, char *actual, int len)
+{
+ int ret = 0;
+ Patprog pprog;
+ char *str = dupstring(teststr);
+
+ tokenize(str);
+
+ if ((pprog = patcompile(str, PAT_STATIC, 0))) {
+ queue_signals();
+ if (pattry(pprog, actual))
+ ret = 1;
+ unqueue_signals();
+ } else if (!strncmp(actual, teststr, len))
+ ret = 1;
+ return ret;
+}
+
+/* check the List for login/logouts */
+
+static void
+watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
+{
+ char *v, *vv, sav;
+ int bad;
+
+ if (!*u->ut_name)
+ return;
+
+ if (*w && !strcmp(*w, "all")) {
+ (void)watchlog2(inout, u, fmt, 1, 0);
+ return;
+ }
+ if (*w && !strcmp(*w, "notme") &&
+ strncmp(u->ut_name, get_username(), sizeof(u->ut_name))) {
+ (void)watchlog2(inout, u, fmt, 1, 0);
+ return;
+ }
+ for (; *w; w++) {
+ bad = 0;
+ v = *w;
+ if (*v != '@' && *v != '%') {
+ for (vv = v; *vv && *vv != '@' && *vv != '%'; vv++);
+ sav = *vv;
+ *vv = '\0';
+ if (!watchlog_match(v, u->ut_name, sizeof(u->ut_name)))
+ bad = 1;
+ *vv = sav;
+ v = vv;
+ }
+ for (;;)
+ if (*v == '%') {
+ for (vv = ++v; *vv && *vv != '@'; vv++);
+ sav = *vv;
+ *vv = '\0';
+ if (!watchlog_match(v, u->ut_line, sizeof(u->ut_line)))
+ bad = 1;
+ *vv = sav;
+ v = vv;
+ }
+# ifdef WATCH_UTMP_UT_HOST
+ else if (*v == '@') {
+ for (vv = ++v; *vv && *vv != '%'; vv++);
+ sav = *vv;
+ *vv = '\0';
+ if (!watchlog_match(v, u->ut_host, strlen(v)))
+ bad = 1;
+ *vv = sav;
+ v = vv;
+ }
+# endif /* WATCH_UTMP_UT_HOST */
+ else
+ break;
+ if (!bad) {
+ (void)watchlog2(inout, u, fmt, 1, 0);
+ return;
+ }
+ }
+}
+
+/* compare 2 utmp entries */
+
+static int
+ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v)
+{
+ if (u->ut_time == v->ut_time)
+ return strncmp(u->ut_line, v->ut_line, sizeof(u->ut_line));
+ return u->ut_time - v->ut_time;
+}
+
+/* initialize the user List */
+
+static int
+readwtab(WATCH_STRUCT_UTMP **head, int initial_sz)
+{
+ WATCH_STRUCT_UTMP *uptr;
+ int wtabmax = initial_sz < 2 ? 32 : initial_sz;
+ int sz = 0;
+# ifdef HAVE_GETUTENT
+ WATCH_STRUCT_UTMP *tmp;
+# else
+ FILE *in;
+# endif
+
+ uptr = *head = (WATCH_STRUCT_UTMP *)
+ zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP));
+# ifdef HAVE_GETUTENT
+ setutent();
+ while ((tmp = getutent()) != NULL) {
+ memcpy(uptr, tmp, sizeof (WATCH_STRUCT_UTMP));
+# else
+ if (!(in = fopen(WATCH_UTMP_FILE, "r")))
+ return 0;
+ while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
+# endif
+# ifdef USER_PROCESS
+ if (uptr->ut_type == USER_PROCESS)
+# else /* !USER_PROCESS */
+ if (uptr->ut_name[0])
+# endif /* !USER_PROCESS */
+ {
+ uptr++;
+ if (++sz == wtabmax) {
+ uptr = (WATCH_STRUCT_UTMP *)
+ realloc(*head, (wtabmax *= 2) * sizeof(WATCH_STRUCT_UTMP));
+ if (uptr == NULL) {
+ /* memory pressure - so stop consuming and use, what we have
+ * Other option is to exit() here, as zmalloc does on error */
+ sz--;
+ break;
+ }
+ *head = uptr;
+ uptr += sz;
+ }
+ }
+ }
+# ifdef HAVE_GETUTENT
+ endutent();
+# else
+ fclose(in);
+# endif
+
+ if (sz)
+ qsort((void *) *head, sz, sizeof(WATCH_STRUCT_UTMP),
+ (int (*) _((const void *, const void *)))ucmp);
+ return sz;
+}
+
+/* Check for login/logout events; executed before *
+ * each prompt if WATCH is set */
+
+/**/
+void
+dowatch(void)
+{
+ WATCH_STRUCT_UTMP *utab, *uptr, *wptr;
+ struct stat st;
+ char **s;
+ char *fmt;
+ int utabsz, uct, wct;
+
+ s = watch;
+
+ holdintr();
+ if (!wtab)
+ wtabsz = readwtab(&wtab, 32);
+ if ((stat(WATCH_UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) {
+ noholdintr();
+ return;
+ }
+ lastutmpcheck = st.st_mtime;
+ utabsz = readwtab(&utab, wtabsz + 4);
+ noholdintr();
+ if (errflag) {
+ free(utab);
+ return;
+ }
+
+ wct = wtabsz;
+ uct = utabsz;
+ uptr = utab;
+ wptr = wtab;
+ if (errflag) {
+ free(utab);
+ return;
+ }
+ queue_signals();
+ if (!(fmt = getsparam_u("WATCHFMT")))
+ fmt = DEFAULT_WATCHFMT;
+ while ((uct || wct) && !errflag) {
+ if (!uct || (wct && ucmp(uptr, wptr) > 0))
+ wct--, watchlog(0, wptr++, s, fmt);
+ else if (!wct || (uct && ucmp(uptr, wptr) < 0))
+ uct--, watchlog(1, uptr++, s, fmt);
+ else
+ uptr++, wptr++, wct--, uct--;
+ }
+ unqueue_signals();
+ free(wtab);
+ wtab = utab;
+ wtabsz = utabsz;
+ fflush(stdout);
+ lastwatch = time(NULL);
+}
+
+static void
+checksched(void)
+{
+ /* Do nothing if WATCH is not set, or LOGCHECK has not elapsed */
+ if (watch && (int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK"))
+ dowatch();
+}
+
+/**/
+static int
+bin_log(UNUSED(char *nam), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
+{
+ if (!watch)
+ return 1;
+ if (wtab)
+ free(wtab);
+ wtab = (WATCH_STRUCT_UTMP *)zalloc(1);
+ wtabsz = 0;
+ lastutmpcheck = 0;
+ dowatch();
+ return 0;
+}
+
+#else /* !WATCH_STRUCT_UTMP */
+
+static void
+checksched(void)
+{
+}
+
+/**/
+static int
+bin_log(char *nam, char **argv, Options ops, int func)
+{
+ return bin_notavail(nam, argv, ops, func);
+}
+
+#endif /* !WATCH_STRUCT_UTMP */
+
+/**/
+static char **watch; /* $watch */
+
+/* module setup */
+
+static struct builtin bintab[] = {
+ BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
+};
+
+static struct paramdef partab[] = {
+ PARAMDEF("WATCH", PM_TIED|PM_SCALAR|PM_SPECIAL, &watch, &colonarr_gsu),
+ PARAMDEF("watch", PM_TIED|PM_ARRAY|PM_SPECIAL, &watch, &vararray_gsu),
+};
+
+static struct features module_features = {
+ bintab, sizeof(bintab)/sizeof(*bintab),
+ NULL, 0,
+ NULL, 0,
+ partab, sizeof(partab)/sizeof(*partab),
+ 0
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+ return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+ *features = featuresarray(m, &module_features);
+ return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+ return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+ static char const * const default_watchfmt = DEFAULT_WATCHFMT;
+ Param pm;
+
+ if ((pm = (Param) paramtab->getnode(paramtab, "watch")))
+ pm->ename = "WATCH";
+ if ((pm = (Param) paramtab->getnode(paramtab, "WATCH")))
+ pm->ename = "watch";
+ watch = mkarray(NULL);
+
+ /* These two parameters are only set to defaults if not set.
+ * So setting them in .zshrc will not be enough to load the
+ * module. It's useless until the watch array is set anyway. */
+ if (!paramtab->getnode(paramtab, "WATCHFMT"))
+ setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt));
+ if (!paramtab->getnode(paramtab, "LOGCHECK"))
+ setiparam("LOGCHECK", 60);
+
+ addprepromptfn(&checksched);
+
+ return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+ delprepromptfn(&checksched);
+ return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+ return 0;
+}
diff --git a/Src/Modules/watch.mdd b/Src/Modules/watch.mdd
new file mode 100644
index 000000000..7e8454ede
--- /dev/null
+++ b/Src/Modules/watch.mdd
@@ -0,0 +1,7 @@
+name=zsh/watch
+link=dynamic
+load=yes
+
+autofeatures="b:log p:WATCH p:watch"
+
+objects="watch.o"
diff --git a/Src/builtin.c b/Src/builtin.c
index 89bcd98db..8ef678b22 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -89,7 +89,6 @@ static struct builtin builtins[] =
BUILTIN("kill", BINF_HANDLES_OPTS, bin_kill, 0, -1, 0, NULL, NULL),
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
- BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
#if defined(ZSH_MEM) & defined(ZSH_MEM_DEBUG)
diff --git a/Src/init.c b/Src/init.c
index 878a53a37..871d46b12 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1042,7 +1042,6 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
#endif /* FPATH_NEEDS_INIT */
mailpath = mkarray(NULL);
- watch = mkarray(NULL);
psvar = mkarray(NULL);
module_path = mkarray(ztrdup(MODULE_DIR));
modulestab = newmoduletable(17, "modules");
diff --git a/Src/params.c b/Src/params.c
index b703a97ce..dadf83129 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -63,7 +63,6 @@ char **pparams, /* $argv */
**mailpath, /* $mailpath */
**manpath, /* $manpath */
**psvar, /* $psvar */
- **watch, /* $watch */
**zsh_eval_context; /* $zsh_eval_context */
/**/
mod_export
@@ -194,6 +193,10 @@ mod_export const struct gsu_hash stdhash_gsu =
mod_export const struct gsu_hash nullsethash_gsu =
{ hashgetfn, nullsethashfn, nullunsetfn };
+/**/
+mod_export const struct gsu_scalar colonarr_gsu =
+{ colonarrgetfn, colonarrsetfn, stdunsetfn };
+
/* Non standard methods (not exported) */
static const struct gsu_integer pound_gsu =
@@ -259,9 +262,6 @@ static const struct gsu_integer varint_readonly_gsu =
static const struct gsu_integer zlevar_gsu =
{ intvargetfn, zlevarsetfn, stdunsetfn };
-static const struct gsu_scalar colonarr_gsu =
-{ colonarrgetfn, colonarrsetfn, stdunsetfn };
-
static const struct gsu_integer argc_gsu =
{ poundgetfn, nullintsetfn, stdunsetfn };
static const struct gsu_array pipestatus_gsu =
@@ -398,7 +398,6 @@ IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED),
IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED),
IPDEF8("FPATH", &fpath, "fpath", PM_TIED),
IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED),
-IPDEF8("WATCH", &watch, "watch", PM_TIED),
IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED),
IPDEF8("PSVAR", &psvar, "psvar", PM_TIED),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED),
@@ -430,7 +429,6 @@ IPDEF9("fpath", &fpath, "FPATH", PM_TIED),
IPDEF9("mailpath", &mailpath, "MAILPATH", PM_TIED),
IPDEF9("manpath", &manpath, "MANPATH", PM_TIED),
IPDEF9("psvar", &psvar, "PSVAR", PM_TIED),
-IPDEF9("watch", &watch, "WATCH", PM_TIED),
IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL),
@@ -453,7 +451,6 @@ IPDEF8("CDPATH", &cdpath, NULL, 0),
IPDEF8("FIGNORE", &fignore, NULL, 0),
IPDEF8("FPATH", &fpath, NULL, 0),
IPDEF8("MAILPATH", &mailpath, NULL, 0),
-IPDEF8("WATCH", &watch, NULL, 0),
IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
IPDEF8("PSVAR", &psvar, NULL, 0),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL),
@@ -836,7 +833,6 @@ createparamtable(void)
*/
setsparam("TMPPREFIX", ztrdup_metafy(DEFAULT_TMPPREFIX));
setsparam("TIMEFMT", ztrdup_metafy(DEFAULT_TIMEFMT));
- setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt));
hostnam = (char *)zalloc(256);
gethostname(hostnam, 256);
@@ -4093,7 +4089,7 @@ arrvarsetfn(Param pm, char **x)
}
/**/
-char *
+mod_export char *
colonarrgetfn(Param pm)
{
char ***dptr = (char ***)pm->u.data;
@@ -4101,7 +4097,7 @@ colonarrgetfn(Param pm)
}
/**/
-void
+mod_export void
colonarrsetfn(Param pm, char *x)
{
char ***dptr = (char ***)pm->u.data;
diff --git a/Src/utils.c b/Src/utils.c
index ed3690172..8adab2bd7 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1494,11 +1494,6 @@ deltimedfn(voidvoidfnptr_t func)
/**/
time_t lastmailcheck;
-/* the last time we checked the people in the WATCH variable */
-
-/**/
-time_t lastwatch;
-
/*
* Call a function given by "name" with optional arguments
* "lnklst". If these are present the first argument is the function name.
@@ -1637,17 +1632,6 @@ preprompt(void)
if (errflag)
return;
- /* If WATCH is set, then check for the *
- * specified login/logout events. */
- if (watch) {
- if ((int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK")) {
- dowatch();
- lastwatch = time(NULL);
- }
- }
- if (errflag)
- return;
-
/* Check mail */
currentmailcheck = time(NULL);
if (mailcheck &&
diff --git a/Src/watch.c b/Src/watch.c
deleted file mode 100644
index c41704315..000000000
--- a/Src/watch.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * watch.c - login/logout watching
- *
- * This file is part of zsh, the Z shell.
- *
- * Copyright (c) 1992-1997 Paul Falstad
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and to distribute modified versions of this software for any
- * purpose, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * In no event shall Paul Falstad or the Zsh Development Group be liable
- * to any party for direct, indirect, special, incidental, or consequential
- * damages arising out of the use of this software and its documentation,
- * even if Paul Falstad and the Zsh Development Group have been advised of
- * the possibility of such damage.
- *
- * Paul Falstad and the Zsh Development Group specifically disclaim any
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose. The software
- * provided hereunder is on an "as is" basis, and Paul Falstad and the
- * Zsh Development Group have no obligation to provide maintenance,
- * support, updates, enhancements, or modifications.
- *
- */
-
-#include "zsh.mdh"
-
-/* Headers for utmp/utmpx structures */
-#ifdef HAVE_UTMP_H
-# include
-#endif
-#ifdef HAVE_UTMPX_H
-# include
-#endif
-
-/* Find utmp file */
-#if !defined(REAL_UTMP_FILE) && defined(UTMP_FILE)
-# define REAL_UTMP_FILE UTMP_FILE
-#endif
-#if !defined(REAL_UTMP_FILE) && defined(_PATH_UTMP)
-# define REAL_UTMP_FILE _PATH_UTMP
-#endif
-#if !defined(REAL_UTMP_FILE) && defined(PATH_UTMP_FILE)
-# define REAL_UTMP_FILE PATH_UTMP_FILE
-#endif
-
-/* Find wtmp file */
-#if !defined(REAL_WTMP_FILE) && defined(WTMP_FILE)
-# define REAL_WTMP_FILE WTMP_FILE
-#endif
-#if !defined(REAL_WTMP_FILE) && defined(_PATH_WTMP)
-# define REAL_WTMP_FILE _PATH_WTMP
-#endif
-#if !defined(REAL_WTMP_FILE) && defined(PATH_WTMP_FILE)
-# define REAL_WTMP_FILE PATH_WTMP_FILE
-#endif
-
-/* Find utmpx file */
-#if !defined(REAL_UTMPX_FILE) && defined(UTMPX_FILE)
-# define REAL_UTMPX_FILE UTMPX_FILE
-#endif
-#if !defined(REAL_UTMPX_FILE) && defined(_PATH_UTMPX)
-# define REAL_UTMPX_FILE _PATH_UTMPX
-#endif
-#if !defined(REAL_UTMPX_FILE) && defined(PATH_UTMPX_FILE)
-# define REAL_UTMPX_FILE PATH_UTMPX_FILE
-#endif
-
-/* Find wtmpx file */
-#if !defined(REAL_WTMPX_FILE) && defined(WTMPX_FILE)
-# define REAL_WTMPX_FILE WTMPX_FILE
-#endif
-#if !defined(REAL_WTMPX_FILE) && defined(_PATH_WTMPX)
-# define REAL_WTMPX_FILE _PATH_WTMPX
-#endif
-#if !defined(REAL_WTMPX_FILE) && defined(PATH_WTMPX_FILE)
-# define REAL_WTMPX_FILE PATH_WTMPX_FILE
-#endif
-
-/* Decide which structure to use. We use a structure that exists in *
- * the headers, and require that its corresponding utmp file exist. *
- * (wtmp is less important.) */
-
-#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMPX) && defined(REAL_UTMPX_FILE)
-# define WATCH_STRUCT_UTMP struct utmpx
-# if defined(HAVE_SETUTXENT) && defined(HAVE_GETUTXENT) && defined(HAVE_ENDUTXENT)
-# define setutent setutxent
-# define getutent getutxent
-# define endutent endutxent
-# ifndef HAVE_GETUTENT
-# define HAVE_GETUTENT 1
-# endif
-# endif
-
-/*
- * In utmpx, the ut_name field is replaced by ut_user.
- * However, on some systems ut_name may already be defined this
- * way for the purposes of utmp.
- */
-# ifndef ut_name
-# define ut_name ut_user
-# endif
-# ifdef HAVE_STRUCT_UTMPX_UT_XTIME
-# undef ut_time
-# define ut_time ut_xtime
-# else /* !HAVE_STRUCT_UTMPX_UT_XTIME */
-# ifdef HAVE_STRUCT_UTMPX_UT_TV
-# undef ut_time
-# define ut_time ut_tv.tv_sec
-# endif /* HAVE_STRUCT_UTMPX_UT_TV */
-# endif /* !HAVE_STRUCT_UTMPX_UT_XTIME */
-# define WATCH_UTMP_FILE REAL_UTMPX_FILE
-# ifdef REAL_WTMPX_FILE
-# define WATCH_WTMP_FILE REAL_WTMPX_FILE
-# endif
-# ifdef HAVE_STRUCT_UTMPX_UT_HOST
-# define WATCH_UTMP_UT_HOST 1
-# endif
-#endif
-
-#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMP) && defined(REAL_UTMP_FILE)
-# define WATCH_STRUCT_UTMP struct utmp
-# define WATCH_UTMP_FILE REAL_UTMP_FILE
-# ifdef REAL_WTMP_FILE
-# define WATCH_WTMP_FILE REAL_WTMP_FILE
-# endif
-# ifdef HAVE_STRUCT_UTMP_UT_HOST
-# define WATCH_UTMP_UT_HOST 1
-# endif
-#endif
-
-#ifdef WATCH_UTMP_UT_HOST
-# define DEFAULT_WATCHFMT "%n has %a %l from %m."
-#else /* !WATCH_UTMP_UT_HOST */
-# define DEFAULT_WATCHFMT "%n has %a %l."
-#endif /* !WATCH_UTMP_UT_HOST */
-
-/**/
-char const * const default_watchfmt = DEFAULT_WATCHFMT;
-
-#ifdef WATCH_STRUCT_UTMP
-
-# include "watch.pro"
-
-# ifndef WATCH_WTMP_FILE
-# define WATCH_WTMP_FILE "/dev/null"
-# endif
-
-static int wtabsz = 0;
-static WATCH_STRUCT_UTMP *wtab = NULL;
-static time_t lastutmpcheck = 0;
-
-/* get the time of login/logout for WATCH */
-
-/**/
-static time_t
-getlogtime(WATCH_STRUCT_UTMP *u, int inout)
-{
- FILE *in;
- WATCH_STRUCT_UTMP uu;
- int first = 1;
- int srchlimit = 50; /* max number of wtmp records to search */
-
- if (inout)
- return u->ut_time;
- if (!(in = fopen(WATCH_WTMP_FILE, "r")))
- return time(NULL);
- fseek(in, 0, SEEK_END);
- do {
- if (fseek(in, ((first) ? -1 : -2) * sizeof(WATCH_STRUCT_UTMP), SEEK_CUR)) {
- fclose(in);
- return time(NULL);
- }
- first = 0;
- if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
- fclose(in);
- return time(NULL);
- }
- if (uu.ut_time < lastwatch || !srchlimit--) {
- fclose(in);
- return time(NULL);
- }
- }
- while (memcmp(&uu, u, sizeof(uu)));
-
- do
- if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
- fclose(in);
- return time(NULL);
- }
- while (strncmp(uu.ut_line, u->ut_line, sizeof(u->ut_line)));
- fclose(in);
- return uu.ut_time;
-}
-
-/* Mutually recursive call to handle ternaries in $WATCHFMT */
-
-# define BEGIN3 '('
-# define END3 ')'
-
-/**/
-static char *
-watch3ary(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt)
-{
- int truth = 1, sep;
-
- switch (*fmt++) {
- case 'n':
- truth = (u->ut_name[0] != 0);
- break;
- case 'a':
- truth = inout;
- break;
- case 'l':
- if (!strncmp(u->ut_line, "tty", 3))
- truth = (u->ut_line[3] != 0);
- else
- truth = (u->ut_line[0] != 0);
- break;
-# ifdef WATCH_UTMP_UT_HOST
- case 'm':
- case 'M':
- truth = (u->ut_host[0] != 0);
- break;
-# endif /* WATCH_UTMP_UT_HOST */
- default:
- prnt = 0; /* Skip unknown conditionals entirely */
- break;
- }
- sep = *fmt++;
- fmt = watchlog2(inout, u, fmt, (truth && prnt), sep);
- return watchlog2(inout, u, fmt, (!truth && prnt), END3);
-}
-
-/* print a login/logout event */
-
-/**/
-static char *
-watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
-{
- char buf[40], buf2[80];
- time_t timet;
- struct tm *tm;
- char *fm2;
- int len;
-# ifdef WATCH_UTMP_UT_HOST
- char *p;
- int i;
-# endif /* WATCH_UTMP_UT_HOST */
-
- while (*fmt)
- if (*fmt == '\\') {
- if (*++fmt) {
- if (prnt)
- putchar(*fmt);
- ++fmt;
- } else if (fini)
- return fmt;
- else
- break;
- }
- else if (*fmt == fini)
- return ++fmt;
- else if (*fmt != '%') {
- if (prnt)
- putchar(*fmt);
- ++fmt;
- } else {
- if (*++fmt == BEGIN3)
- fmt = watch3ary(inout, u, ++fmt, prnt);
- else if (!prnt)
- ++fmt;
- else
- switch (*(fm2 = fmt++)) {
- case 'n':
- printf("%.*s", (int)sizeof(u->ut_name), u->ut_name);
- break;
- case 'a':
- printf("%s", (!inout) ? "logged off" : "logged on");
- break;
- case 'l':
- if (!strncmp(u->ut_line, "tty", 3))
- printf("%.*s", (int)sizeof(u->ut_line) - 3, u->ut_line + 3);
- else
- printf("%.*s", (int)sizeof(u->ut_line), u->ut_line);
- break;
-# ifdef WATCH_UTMP_UT_HOST
- case 'm':
- for (p = u->ut_host, i = sizeof(u->ut_host); i && *p; i--, p++) {
- if (*p == '.' && !idigit(p[1]))
- break;
- putchar(*p);
- }
- break;
- case 'M':
- printf("%.*s", (int)sizeof(u->ut_host), u->ut_host);
- break;
-# endif /* WATCH_UTMP_UT_HOST */
- case 'T':
- case 't':
- case '@':
- case 'W':
- case 'w':
- case 'D':
- switch (*fm2) {
- case '@':
- case 't':
- fm2 = "%l:%M%p";
- break;
- case 'T':
- fm2 = "%K:%M";
- break;
- case 'w':
- fm2 = "%a %f";
- break;
- case 'W':
- fm2 = "%m/%d/%y";
- break;
- case 'D':
- if (fm2[1] == '{') {
- char *dd, *ss;
- int n = 79;
-
- for (ss = fm2 + 2, dd = buf2;
- n-- && *ss && *ss != '}'; ++ss, ++dd)
- *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
- if (*ss == '}') {
- *dd = '\0';
- fmt = ss + 1;
- fm2 = buf2;
- }
- else fm2 = "%y-%m-%d";
- }
- else fm2 = "%y-%m-%d";
- break;
- }
- timet = getlogtime(u, inout);
- tm = localtime(&timet);
- len = ztrftime(buf, 40, fm2, tm, 0L);
- if (len > 0)
- metafy(buf, len, META_NOALLOC);
- printf("%s", (*buf == ' ') ? buf + 1 : buf);
- break;
- case '%':
- putchar('%');
- break;
- case 'S':
- txtset(TXTSTANDOUT);
- tsetcap(TCSTANDOUTBEG, TSC_RAW);
- break;
- case 's':
- txtunset(TXTSTANDOUT);
- tsetcap(TCSTANDOUTEND, TSC_RAW|TSC_DIRTY);
- break;
- case 'B':
- txtset(TXTBOLDFACE);
- tsetcap(TCBOLDFACEBEG, TSC_RAW|TSC_DIRTY);
- break;
- case 'b':
- txtunset(TXTBOLDFACE);
- tsetcap(TCALLATTRSOFF, TSC_RAW|TSC_DIRTY);
- break;
- case 'U':
- txtset(TXTUNDERLINE);
- tsetcap(TCUNDERLINEBEG, TSC_RAW);
- break;
- case 'u':
- txtunset(TXTUNDERLINE);
- tsetcap(TCUNDERLINEEND, TSC_RAW|TSC_DIRTY);
- break;
- default:
- putchar('%');
- putchar(*fm2);
- break;
- }
- }
- if (prnt)
- putchar('\n');
-
- return fmt;
-}
-
-/* See if the watch entry matches */
-
-static int
-watchlog_match(char *teststr, char *actual, int len)
-{
- int ret = 0;
- Patprog pprog;
- char *str = dupstring(teststr);
-
- tokenize(str);
-
- if ((pprog = patcompile(str, PAT_STATIC, 0))) {
- queue_signals();
- if (pattry(pprog, actual))
- ret = 1;
- unqueue_signals();
- } else if (!strncmp(actual, teststr, len))
- ret = 1;
- return ret;
-}
-
-/* check the List for login/logouts */
-
-/**/
-static void
-watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
-{
- char *v, *vv, sav;
- int bad;
-
- if (!*u->ut_name)
- return;
-
- if (*w && !strcmp(*w, "all")) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- if (*w && !strcmp(*w, "notme") &&
- strncmp(u->ut_name, get_username(), sizeof(u->ut_name))) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- for (; *w; w++) {
- bad = 0;
- v = *w;
- if (*v != '@' && *v != '%') {
- for (vv = v; *vv && *vv != '@' && *vv != '%'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_name, sizeof(u->ut_name)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
- for (;;)
- if (*v == '%') {
- for (vv = ++v; *vv && *vv != '@'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_line, sizeof(u->ut_line)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
-# ifdef WATCH_UTMP_UT_HOST
- else if (*v == '@') {
- for (vv = ++v; *vv && *vv != '%'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_host, strlen(v)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
-# endif /* WATCH_UTMP_UT_HOST */
- else
- break;
- if (!bad) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- }
-}
-
-/* compare 2 utmp entries */
-
-/**/
-static int
-ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v)
-{
- if (u->ut_time == v->ut_time)
- return strncmp(u->ut_line, v->ut_line, sizeof(u->ut_line));
- return u->ut_time - v->ut_time;
-}
-
-/* initialize the user List */
-
-/**/
-static int
-readwtab(WATCH_STRUCT_UTMP **head, int initial_sz)
-{
- WATCH_STRUCT_UTMP *uptr;
- int wtabmax = initial_sz < 2 ? 32 : initial_sz;
- int sz = 0;
-# ifdef HAVE_GETUTENT
- WATCH_STRUCT_UTMP *tmp;
-# else
- FILE *in;
-# endif
-
- uptr = *head = (WATCH_STRUCT_UTMP *)
- zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP));
-# ifdef HAVE_GETUTENT
- setutent();
- while ((tmp = getutent()) != NULL) {
- memcpy(uptr, tmp, sizeof (WATCH_STRUCT_UTMP));
-# else
- if (!(in = fopen(WATCH_UTMP_FILE, "r")))
- return 0;
- while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
-# endif
-# ifdef USER_PROCESS
- if (uptr->ut_type == USER_PROCESS)
-# else /* !USER_PROCESS */
- if (uptr->ut_name[0])
-# endif /* !USER_PROCESS */
- {
- uptr++;
- if (++sz == wtabmax) {
- uptr = (WATCH_STRUCT_UTMP *)
- realloc(*head, (wtabmax *= 2) * sizeof(WATCH_STRUCT_UTMP));
- if (uptr == NULL) {
- /* memory pressure - so stop consuming and use, what we have
- * Other option is to exit() here, as zmalloc does on error */
- sz--;
- break;
- }
- *head = uptr;
- uptr += sz;
- }
- }
- }
-# ifdef HAVE_GETUTENT
- endutent();
-# else
- fclose(in);
-# endif
-
- if (sz)
- qsort((void *) *head, sz, sizeof(WATCH_STRUCT_UTMP),
- (int (*) _((const void *, const void *)))ucmp);
- return sz;
-}
-
-/* Check for login/logout events; executed before *
- * each prompt if WATCH is set */
-
-/**/
-void
-dowatch(void)
-{
- WATCH_STRUCT_UTMP *utab, *uptr, *wptr;
- struct stat st;
- char **s;
- char *fmt;
- int utabsz, uct, wct;
-
- s = watch;
-
- holdintr();
- if (!wtab)
- wtabsz = readwtab(&wtab, 32);
- if ((stat(WATCH_UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) {
- noholdintr();
- return;
- }
- lastutmpcheck = st.st_mtime;
- utabsz = readwtab(&utab, wtabsz + 4);
- noholdintr();
- if (errflag) {
- free(utab);
- return;
- }
-
- wct = wtabsz;
- uct = utabsz;
- uptr = utab;
- wptr = wtab;
- if (errflag) {
- free(utab);
- return;
- }
- queue_signals();
- if (!(fmt = getsparam_u("WATCHFMT")))
- fmt = DEFAULT_WATCHFMT;
- while ((uct || wct) && !errflag) {
- if (!uct || (wct && ucmp(uptr, wptr) > 0))
- wct--, watchlog(0, wptr++, s, fmt);
- else if (!wct || (uct && ucmp(uptr, wptr) < 0))
- uct--, watchlog(1, uptr++, s, fmt);
- else
- uptr++, wptr++, wct--, uct--;
- }
- unqueue_signals();
- free(wtab);
- wtab = utab;
- wtabsz = utabsz;
- fflush(stdout);
-}
-
-/**/
-int
-bin_log(UNUSED(char *nam), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
-{
- if (!watch)
- return 1;
- if (wtab)
- free(wtab);
- wtab = (WATCH_STRUCT_UTMP *)zalloc(1);
- wtabsz = 0;
- lastutmpcheck = 0;
- dowatch();
- return 0;
-}
-
-#else /* !WATCH_STRUCT_UTMP */
-
-/**/
-void dowatch(void)
-{
-}
-
-/**/
-int
-bin_log(char *nam, char **argv, Options ops, int func)
-{
- return bin_notavail(nam, argv, ops, func);
-}
-
-#endif /* !WATCH_STRUCT_UTMP */
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index 9bcaccae5..da8d58322 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -13,7 +13,7 @@ objects="builtin.o compat.o cond.o context.o \
exec.o glob.o hashtable.o hashnameddir.o \
hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \
mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \
-signames.o sort.o string.o subst.o text.o utils.o watch.o \
+signames.o sort.o string.o subst.o text.o utils.o \
openssh_bsd_setres_id.o"
headers="../config.h zsh_system.h zsh.h sigcount.h signals.h \
--
cgit v1.2.3