mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-27 04:40:59 +01:00
22981: Zvi Har'el: bad call from 22952
22980: add hook array for special functions
This commit is contained in:
parent
f367a90505
commit
aba936b17c
9 changed files with 112 additions and 44 deletions
10
ChangeLog
10
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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
callhookfunc("chpwd", NULL, 1);
|
||||
|
||||
dirstacksize = getiparam("DIRSTACKSIZE");
|
||||
/* handle directory stack sizes out of range */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
30
Src/init.c
30
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));
|
||||
|
||||
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 */
|
||||
|
|
|
|||
49
Src/utils.c
49
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;
|
||||
|
||||
if ((prog = getshfunc(name)) != &dummy_eprog) {
|
||||
doshfunc(name, prog, lnklst, 0, 1);
|
||||
stat = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sfcontext = osc;
|
||||
stopmsg = osm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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; }; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue