about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--Doc/Zsh/func.yo27
-rw-r--r--Doc/Zsh/options.yo7
-rw-r--r--Src/Zle/zle_main.c2
-rw-r--r--Src/builtin.c13
-rw-r--r--Src/glob.c2
-rw-r--r--Src/init.c30
-rw-r--r--Src/utils.c51
-rw-r--r--Test/A05execution.ztst12
9 files changed, 111 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index b62b4dcae..9ae3c901b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2006-11-08  Peter Stephenson  <pws@csr.com>
+
+	* 22978 (tweaked): Doc/Zsh/func.yo, Doc/Zsh/options.yo,
+	Src/builtin.c, Src/init.c, Src/utils.c, Src/Zle/zle_main.c,
+	Test/A05execution.ztst: use <hook>_functions array variables for
+	hook functions.
+
+	* 22981: Zvi Har'El: Src/glob.c: 22952 also got a
+	get_strarg() wrong in glob.c.
+
 2006-11-07  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* 22980: Doc/Zsh/expn.yo, Src/subst.c, Test/D04paramater.ztst,
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index 471954c25..5fac56aac 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -151,26 +151,47 @@ executing tt(myfunc), use:
 example(autoload +X myfunc)
 
 sect(Special Functions)
-The following functions, if defined, have special meaning to
-the shell:
+Certain functions, if defined, have special meaning to the shell.
+
+In the case of tt(chpwd), tt(periodic), tt(precmd) and tt(preexec) it is
+possible to define an array that has the same name with `tt(_functions)'
+appended.  Any element in such an array is taken as the name of a function
+to execute; it is executed in the same context and with the same arguments
+as the basic function.  For example, if tt($chpwd_functions) is an array
+containing the values `tt(mychpwd)', `tt(chpwd_save_dirstack)', then the
+shell attempts to execute the functions `tt(chpwd)', `tt(mychpwd)' and
+`tt(chpwd_save_dirstack)', in that order.  Any function that does not exist
+is silently ignored.  A function found by this mechanism is referred to
+elsewhere as a `hook function'.  An error in any function causes
+subsequent functions not to be run.  Note further that an error
+in a tt(precmd) hook causes an immediately following tt(periodic)
+function not to run (thought it may run at the next opportunity).
 
 startitem()
 findex(chpwd)
+vindex(chpwd_functions)
 item(tt(chpwd))(
 Executed whenever the current working directory is changed.
 )
 findex(periodic)
+vindex(periodic_functions)
 item(tt(periodic))(
 vindex(PERIOD)
 If the parameter tt(PERIOD)
 is set, this function is executed every tt($PERIOD)
-seconds, just before a prompt.
+seconds, just before a prompt.  Note that if multiple functions
+are defined using the array tt(periodic_functions) only one
+period is applied to the complete set of functions, and the
+scheduled time is not reset if the list of functions is altered.
+Hence the set of functions is always called together.
 )
 findex(precmd)
+vindex(precmd_functions)
 item(tt(precmd))(
 Executed before each prompt.
 )
 findex(preexec)
+vindex(preexec_functions)
 item(tt(preexec))(
 Executed just after a command has been read and is about to be
 executed.  If the history mechanism is active (and the line was not
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index d4e1deeef..3790beaed 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -912,8 +912,11 @@ such jobs will be killed automatically.
 
 The check is omitted if the commands run from the previous command line
 included a `tt(jobs)' command, since it is assumed the user is aware that
-there are background or suspended jobs.  A `tt(jobs)' command run from the
-tt(precmd) function is not counted for this purpose.
+there are background or suspended jobs.  A `tt(jobs)' command run from one
+of the hook functions defined in
+ifnzman(the section Special Functions in noderef(Functions))\
+ifzman(the section SPECIAL FUNCTIONS in zmanref(zshmisc))
+is not counted for this purpose.
 )
 pindex(HUP)
 cindex(jobs, HUP)
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index d8cbcb645..21ee8a4ed 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -716,7 +716,7 @@ raw_getbyte(int do_keytmout, char *cptr)
 # endif
 
 
-			callhookfunc(lwatch_funcs[i], funcargs);
+			callhookfunc(lwatch_funcs[i], funcargs, 0);
 			if (errflag) {
 			    /* No sensible way of handling errors here */
 			    errflag = 0;
diff --git a/Src/builtin.c b/Src/builtin.c
index e4ca9b3d9..adb0f6ee2 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1087,7 +1087,6 @@ cd_try_chdir(char *pfix, char *dest, int hard)
 static void
 cd_new_pwd(int func, LinkNode dir)
 {
-    Eprog prog;
     char *new_pwd, *s;
     int dirstacksize;
 
@@ -1134,15 +1133,9 @@ cd_new_pwd(int func, LinkNode dir)
     }
 
     /* execute the chpwd function */
-    if ((prog = getshfunc("chpwd")) != &dummy_eprog) {
-	int osc = sfcontext;
-
-	fflush(stdout);
-	fflush(stderr);
-	sfcontext = SFC_HOOK;
-	doshfunc("chpwd", prog, NULL, 0, 1);
-	sfcontext = osc;
-    }
+    fflush(stdout);
+    fflush(stderr);
+    callhookfunc("chpwd", NULL, 1);
 
     dirstacksize = getiparam("DIRSTACKSIZE");
     /* handle directory stack sizes out of range */
diff --git a/Src/glob.c b/Src/glob.c
index aa0ce1ac4..394e91d01 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1246,7 +1246,7 @@ zglob(LinkList list, LinkNode np, int nountok)
 			int arglen;
 
 			/* Find matching delimiters */
-			tt = get_strarg(s, &arglen, NULL);
+			tt = get_strarg(s, &arglen);
 			if (!*tt) {
 			    zerr("missing end of name");
 			    data = 0;
diff --git a/Src/init.c b/Src/init.c
index 7645af6b2..fad36bf0f 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -137,29 +137,33 @@ loop(int toplevel, int justonce)
 	}
 	if (hend(prog)) {
 	    int toksav = tok;
-	    Eprog preprog;
 
-	    if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) {
+	    if (toplevel &&
+		(getshfunc("preexec") != &dummy_eprog ||
+		 paramtab->getnode(paramtab, "preexec_functions"))) {
 		LinkList args;
-		int osc = sfcontext;
 		char *cmdstr;
 
-		args = znewlinklist();
-		zaddlinknode(args, "preexec");
+		/*
+		 * As we're about to freeheap() or popheap()
+		 * anyway, there's no gain in using permanent
+		 * storage here.
+		 */
+		args = newlinklist();
+		addlinknode(args, "preexec");
 		/* If curline got dumped from the history, we don't know
 		 * what the user typed. */
 		if (hist_ring && curline.histnum == curhist)
-		    zaddlinknode(args, hist_ring->node.nam);
+		    addlinknode(args, hist_ring->node.nam);
 		else
-		    zaddlinknode(args, "");
-		zaddlinknode(args, getjobtext(prog, NULL));
-		zaddlinknode(args, cmdstr = getpermtext(prog, NULL));
+		    addlinknode(args, "");
+		addlinknode(args, dupstring(getjobtext(prog, NULL)));
+		addlinknode(args, cmdstr = getpermtext(prog, NULL));
+
+		callhookfunc("preexec", args, 1);
 
-		sfcontext = SFC_HOOK;
-		doshfunc("preexec", preprog, args, 0, 1);
-		sfcontext = osc;
+		/* The only permanent storage is from getpermtext() */
 		zsfree(cmdstr);
-		freelinklist(args, (FreeFunc) NULL);
 		errflag = 0;
 	    }
 	    if (stopmsg)	/* unset 'you have stopped jobs' flag */
diff --git a/Src/utils.c b/Src/utils.c
index ed4abe3f1..5b6998950 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1079,28 +1079,53 @@ time_t lastmailcheck;
 /**/
 time_t lastwatch;
 
+/*
+ * Call a function given by "name" with optional arguments
+ * "lnklist".  If "arrayp" is not zero, we also look through
+ * the array "name"_functions and execute functions found there.
+ */
+
 /**/
 mod_export int
-callhookfunc(char *name, LinkList lnklst)
+callhookfunc(char *name, LinkList lnklst, int arrayp)
 {
     Eprog prog;
-
-    if ((prog = getshfunc(name)) != &dummy_eprog) {
 	/*
 	 * Save stopmsg, since user doesn't get a chance to respond
 	 * to a list of jobs generated in a hook.
 	 */
-	int osc = sfcontext, osm = stopmsg;
+    int osc = sfcontext, osm = stopmsg, stat = 1;
+
+    sfcontext = SFC_HOOK;
 
-	sfcontext = SFC_HOOK;
+    if ((prog = getshfunc(name)) != &dummy_eprog) {
 	doshfunc(name, prog, lnklst, 0, 1);
-	sfcontext = osc;
-	stopmsg = osm;
+	stat = 0;
+    }
 
-	return 0;
+    if (arrayp) {
+	char **arrptr;
+	int namlen = strlen(name);
+#define HOOK_SUFFIX	"_functions"
+#define HOOK_SUFFIX_LEN	11	/* including NUL byte */
+	VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN);
+	memcpy(arrnam, name, namlen);
+	memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN);
+
+	if ((arrptr = getaparam(arrnam))) {
+	    for (; *arrptr; arrptr++) {
+		if ((prog = getshfunc(*arrptr)) != &dummy_eprog) {
+		    doshfunc(arrnam, prog, lnklst, 0, 1);
+		    stat = 0;
+		}
+	    }
+	}
     }
 
-    return 1;
+    sfcontext = osc;
+    stopmsg = osm;
+
+    return stat;
 }
 
 /* do pre-prompt stuff */
@@ -1136,15 +1161,15 @@ preprompt(void)
 
     /* If a shell function named "precmd" exists, *
      * then execute it.                           */
-    callhookfunc("precmd", NULL);
+    callhookfunc("precmd", NULL, 1);
     if (errflag)
 	return;
 
-    /* If 1) the parameter PERIOD exists, 2) the shell function     *
+    /* If 1) the parameter PERIOD exists, 2) a hook function for    *
      * "periodic" exists, 3) it's been greater than PERIOD since we *
-     * executed "periodic", then execute it now.                    */
+     * executed any such hook, then execute it now.                 */
     if (period && (time(NULL) > lastperiodic + period) &&
-	!callhookfunc("periodic", NULL))
+	!callhookfunc("periodic", NULL, 1))
 	lastperiodic = time(NULL);
     if (errflag)
 	return;
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
index 202a4bb7a..e731d1109 100644
--- a/Test/A05execution.ztst
+++ b/Test/A05execution.ztst
@@ -105,6 +105,18 @@
 0q:chpwd
 >Changed to $ZTST_testdir/command.tmp
 
+  chpwd() { print chpwd: changed to $PWD; }
+  chpwdfn1()  { print chpwdfn1: changed to $PWD; }
+  chpwdfn2()  { print chpwdfn2: changed to $PWD; }
+  chpwd_functions=(chpwdfn1 '' chpwdnonexistentfn chpwdfn2)
+  cd .
+  unfunction chpwd
+  unset chpwd_functions
+0q:chpwd_functions
+>chpwd: changed to $ZTST_testdir/command.tmp
+>chpwdfn1: changed to $ZTST_testdir/command.tmp
+>chpwdfn2: changed to $ZTST_testdir/command.tmp
+
 # Hard to test periodic, precmd and preexec non-interactively.
 
   fn() { TRAPEXIT() { print Exit; }; }