From aba936b17cca86ee0742341f23f0f96795a23275 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 8 Nov 2006 10:38:05 +0000 Subject: 22981: Zvi Har'el: bad call from 22952 22980: add hook array for special functions --- ChangeLog | 10 ++++++++++ Doc/Zsh/func.yo | 27 +++++++++++++++++++++++--- Doc/Zsh/options.yo | 7 +++++-- Src/Zle/zle_main.c | 2 +- Src/builtin.c | 13 +++---------- Src/glob.c | 2 +- Src/init.c | 30 ++++++++++++++++------------- Src/utils.c | 51 +++++++++++++++++++++++++++++++++++++------------- Test/A05execution.ztst | 12 ++++++++++++ 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 + + * 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 _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 * 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; }; } -- cgit 1.4.1