1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-27 16:50:58 +01:00

22981: Zvi Har'el: bad call from 22952

22980: add hook array for special functions
This commit is contained in:
Peter Stephenson 2006-11-08 10:38:05 +00:00
parent f367a90505
commit aba936b17c
9 changed files with 112 additions and 44 deletions

View file

@ -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,

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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 */

View file

@ -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;

View file

@ -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));
sfcontext = SFC_HOOK;
doshfunc("preexec", preprog, args, 0, 1);
sfcontext = osc;
callhookfunc("preexec", args, 1);
/* The only permanent storage is from getpermtext() */
zsfree(cmdstr);
freelinklist(args, (FreeFunc) NULL);
errflag = 0;
}
if (stopmsg) /* unset 'you have stopped jobs' flag */

View file

@ -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;
return 0;
stat = 0;
}
return 1;
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;
}
}
}
}
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;

View file

@ -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; }; }