mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-08 12:01:21 +02:00
zsh-workers/8404
This commit is contained in:
parent
f2217a0188
commit
1fe3b56224
6 changed files with 164 additions and 37 deletions
|
@ -71,7 +71,24 @@ which no alias has been defined.
|
|||
findex(autoload)
|
||||
cindex(functions, autoloading)
|
||||
cindex(autoloading functions)
|
||||
alias(autoload)(functions -u)
|
||||
item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(UXmt) ] [ var(name) ... ])(
|
||||
Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X).
|
||||
|
||||
The flag tt(-X) may be used only inside a shell function, and may not be
|
||||
followed by a var(name). It causes the calling function to be marked for
|
||||
autoloading and then immediately loaded and executed, with the current
|
||||
array of positional parameters as arguments. This replaces the previous
|
||||
definition of the function. If no function definition is found, an error
|
||||
is printed and the function remains undefined and marked for autoloading.
|
||||
|
||||
The flag tt(+X) attempts to load each var(name) as an autoloaded function,
|
||||
but does em(not) execute it. The exit status is zero (success) if the
|
||||
function was not previously defined em(and) a definition for it was found.
|
||||
This does em(not) replace any existing definition of the function. The
|
||||
exit status is nonzero (failure) if the function was already defined or
|
||||
when no definition was found. In the latter case the function remains
|
||||
undefined and marked for autoloading.
|
||||
)
|
||||
findex(bg)
|
||||
cindex(jobs, backgrounding)
|
||||
xitem(tt(bg) [ var(job) ... ])
|
||||
|
@ -353,7 +370,7 @@ Equivalent to tt(typeset -E), except that options irrelevant to floating
|
|||
point numbers are not permitted.
|
||||
)
|
||||
findex(functions)
|
||||
item(tt(functions) [ {tt(PLUS())|tt(-)}tt(tum) ] [ var(name) ... ])(
|
||||
item(tt(functions) [ {tt(PLUS())|tt(-)}tt(UXmtu) ] [ var(name) ... ])(
|
||||
Equivalent to tt(typeset -f).
|
||||
)
|
||||
findex(getln)
|
||||
|
@ -1028,6 +1045,7 @@ item(tt(-U))(
|
|||
For arrays (but not for associative arrays), keep only the first
|
||||
occurrence of each duplicated value. This may also be set for
|
||||
colon-separated special parameters like tt(PATH) or tt(FIGNORE), etc.
|
||||
This flag has a different meaning when used with tt(-f); see below.
|
||||
)
|
||||
item(tt(-Z))(
|
||||
Right justify and fill with leading zeros if the first non-blank
|
||||
|
@ -1044,8 +1062,8 @@ shown.
|
|||
)
|
||||
item(tt(-f))(
|
||||
The names refer to functions rather than parameters. No assignments
|
||||
can be made, and the only other valid flags are tt(-t), tt(-u) and
|
||||
tt(-U). The flag tt(-t) turns on execution tracing for this
|
||||
can be made, and the only other valid flags are tt(-t), tt(-u), tt(-U),
|
||||
tt(-X) and tt(+X). The flag tt(-t) turns on execution tracing for this
|
||||
function. The tt(-u) and tt(-U) flags cause the function to be
|
||||
marked for autoloading; tt(-U) also causes alias expansion to be
|
||||
suppressed when the function is loaded. The tt(fpath) parameter
|
||||
|
@ -1096,10 +1114,12 @@ The given var(name)s are marked readonly.
|
|||
)
|
||||
item(tt(-t))(
|
||||
Tags the named parameters. Tags have no special meaning to the shell.
|
||||
This flag has a different meaning when used with tt(-f); see above.
|
||||
)
|
||||
item(tt(-u))(
|
||||
Convert the result to upper case whenever the parameter is expanded.
|
||||
The value is em(not) converted when assigned.
|
||||
This flag has a different meaning when used with tt(-f); see above.
|
||||
)
|
||||
item(tt(-x))(
|
||||
Mark for automatic export to the environment of subsequently
|
||||
|
|
|
@ -74,6 +74,29 @@ and any subsequent calls. Without tt(KSH_AUTOLOAD) set, it will produce
|
|||
the initialization message on the first call, and the other message on the
|
||||
second and subsequent calls.
|
||||
|
||||
It is also possible to create a function that is not marked autoloaded,
|
||||
yet loads its own definition by searching tt(fpath): `tt(autoload -X)',
|
||||
when called from within a shell function tt(myfunc), is equivalent to:
|
||||
|
||||
example(unfunction myfunc
|
||||
autoload myfunc
|
||||
myfunc "$@")
|
||||
|
||||
In fact, the tt(functions) command outputs `tt(builtin autoload -X)' as
|
||||
the body of an autoloaded function. A true autoloaded function can be
|
||||
identifed by the presence of the comment `tt(# undefined)' in the body,
|
||||
because all comments are discarded from defined functions. This is done
|
||||
so that
|
||||
|
||||
example(eval "$(functions)")
|
||||
|
||||
produces a reasonable result.
|
||||
|
||||
To load the definition of an autoloaded function tt(myfunc) without
|
||||
executing tt(myfunc), use:
|
||||
|
||||
example(autoload +X myfunc)
|
||||
|
||||
sect(Special Functions)
|
||||
The following functions, if defined, have special meaning to
|
||||
the shell:
|
||||
|
|
|
@ -424,7 +424,9 @@ getpmfunction(HashTable ht, char *name)
|
|||
|
||||
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, name))) {
|
||||
if (shf->flags & PM_UNDEFINED)
|
||||
pm->u.str = "undefined";
|
||||
pm->u.str = tricat("builtin autoload -X",
|
||||
((shf->flags & PM_UNALIASED)? "U" : ""),
|
||||
((shf->flags & PM_TAGGED)? "t" : ""));
|
||||
else {
|
||||
char *t = getpermtext((void *) dupstruct((void *)
|
||||
shf->funcdef)), *h;
|
||||
|
@ -467,9 +469,12 @@ scanpmfunctions(HashTable ht, ScanFunc func, int flags)
|
|||
if (!(hn->flags & DISABLED)) {
|
||||
pm.nam = hn->nam;
|
||||
if (func != scancountparams) {
|
||||
if (((Shfunc) hn)->flags & PM_UNDEFINED)
|
||||
pm.u.str = "undefined";
|
||||
else {
|
||||
if (((Shfunc) hn)->flags & PM_UNDEFINED) {
|
||||
Shfunc shf = (Shfunc) hn;
|
||||
pm.u.str = tricat("builtin autoload -X",
|
||||
((shf->flags & PM_UNALIASED)? "U" : ""),
|
||||
((shf->flags & PM_TAGGED)? "t" : ""));
|
||||
} else {
|
||||
char *t = getpermtext((void *)
|
||||
dupstruct((void *) ((Shfunc) hn)->funcdef));
|
||||
|
||||
|
@ -779,7 +784,7 @@ dirssetfn(Param pm, char **x)
|
|||
PERMALLOC {
|
||||
freelinklist(dirstack, freestr);
|
||||
dirstack = newlinklist();
|
||||
while (*x)
|
||||
while (x && *x)
|
||||
addlinknode(dirstack, ztrdup(*x++));
|
||||
} LASTALLOC;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ static struct builtin builtins[] =
|
|||
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
|
||||
BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmr", NULL),
|
||||
BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tU", "u"),
|
||||
BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tUX", "u"),
|
||||
BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
|
||||
BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL),
|
||||
BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
|
||||
|
@ -1998,6 +1998,29 @@ bin_typeset(char *name, char **argv, char *ops, int func)
|
|||
return returnval;
|
||||
}
|
||||
|
||||
/* Helper for bin_functions() when run as "autoload -X" */
|
||||
|
||||
static int
|
||||
eval_autoload(Shfunc shf, char *name, char *ops, int func)
|
||||
{
|
||||
if (!(shf->flags & PM_UNDEFINED))
|
||||
return 1;
|
||||
|
||||
if (shf->funcdef)
|
||||
freestruct(shf->funcdef);
|
||||
|
||||
if (ops['X'] == 1) {
|
||||
char *fargv[3];
|
||||
fargv[0] = name;
|
||||
fargv[1] = "\"$@\"";
|
||||
fargv[2] = 0;
|
||||
shf->funcdef = mkautofn(shf);
|
||||
return bin_eval(name, fargv, ops, func);
|
||||
}
|
||||
|
||||
return loadautofn(shf);
|
||||
}
|
||||
|
||||
/* Display or change the attributes of shell functions. *
|
||||
* If called as autoload, it will define a new autoloaded *
|
||||
* (undefined) shell function. */
|
||||
|
@ -2012,10 +2035,10 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
int on = 0, off = 0, pflags = 0;
|
||||
|
||||
/* Do we have any flags defined? */
|
||||
if (ops['u'] == 1)
|
||||
on |= PM_UNDEFINED;
|
||||
else if (ops['u'] == 2)
|
||||
if (ops['u'] == 2)
|
||||
off |= PM_UNDEFINED;
|
||||
else if (ops['u'] == 1 || ops['X'])
|
||||
on |= PM_UNDEFINED;
|
||||
if (ops['U'] == 1)
|
||||
on |= PM_UNALIASED|PM_UNDEFINED;
|
||||
else if (ops['U'] == 2)
|
||||
|
@ -2025,7 +2048,8 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
else if (ops['t'] == 2)
|
||||
off |= PM_TAGGED;
|
||||
|
||||
if (off & PM_UNDEFINED) {
|
||||
if ((off & PM_UNDEFINED) ||
|
||||
(ops['X'] == 1 && (ops['m'] || *argv || !scriptname))) {
|
||||
zwarnnam(name, "invalid option(s)", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
@ -2037,10 +2061,22 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
* are given, we will print only functions containing these *
|
||||
* flags, else we'll print them all. */
|
||||
if (!*argv) {
|
||||
if (ops['U'] && !ops['u'])
|
||||
on &= ~PM_UNDEFINED;
|
||||
scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
|
||||
pflags);
|
||||
if (ops['X'] == 1) {
|
||||
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, scriptname))) {
|
||||
DPUTS(!shf->funcdef,
|
||||
"BUG: Calling autoload from empty function");
|
||||
} else {
|
||||
shf = (Shfunc) zcalloc(sizeof *shf);
|
||||
shfunctab->addnode(shfunctab, ztrdup(scriptname), shf);
|
||||
}
|
||||
shf->flags = on;
|
||||
return eval_autoload(shf, scriptname, ops, func);
|
||||
} else {
|
||||
if (ops['U'] && !ops['u'])
|
||||
on &= ~PM_UNDEFINED;
|
||||
scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
|
||||
pflags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2061,8 +2097,14 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
for (shf = (Shfunc) shfunctab->nodes[i]; shf;
|
||||
shf = (Shfunc) shf->next)
|
||||
if (pattry(pprog, shf->nam) &&
|
||||
!(shf->flags & DISABLED))
|
||||
shf->flags = (shf->flags | on) & (~off);
|
||||
!(shf->flags & DISABLED)) {
|
||||
shf->flags = (shf->flags |
|
||||
(on & ~PM_UNDEFINED)) & ~off;
|
||||
if (ops['X'] &&
|
||||
eval_autoload(shf, shf->nam, ops, func)) {
|
||||
returnval = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2078,10 +2120,12 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
for (; *argv; argv++) {
|
||||
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) {
|
||||
/* if any flag was given */
|
||||
if (on|off)
|
||||
if (on|off) {
|
||||
/* turn on/off the given flags */
|
||||
shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off;
|
||||
else
|
||||
if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
|
||||
returnval = 1;
|
||||
} else
|
||||
/* no flags, so just print */
|
||||
shfunctab->printnode((HashNode) shf, pflags);
|
||||
} else if (on & PM_UNDEFINED) {
|
||||
|
@ -2091,6 +2135,8 @@ bin_functions(char *name, char **argv, char *ops, int func)
|
|||
shf->flags = on;
|
||||
shf->funcdef = mkautofn(shf);
|
||||
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
|
||||
if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
|
||||
returnval = 1;
|
||||
} else
|
||||
returnval = 1;
|
||||
}
|
||||
|
|
29
Src/exec.c
29
Src/exec.c
|
@ -2911,11 +2911,11 @@ execautofn(Cmd cmd, LinkList args, int flags)
|
|||
l = getfpfunc(shf->nam);
|
||||
noaliases = noalias;
|
||||
|
||||
if(l == &dummy_list) {
|
||||
if (l == &dummy_list) {
|
||||
zerr("%s: function definition file not found", shf->nam, 0);
|
||||
return 1;
|
||||
}
|
||||
if(isset(KSHAUTOLOAD)) {
|
||||
if (isset(KSHAUTOLOAD)) {
|
||||
VARARR(char, n, strlen(shf->nam) + 1);
|
||||
strcpy(n, shf->nam);
|
||||
execlist(l, 1, 0);
|
||||
|
@ -2935,6 +2935,31 @@ execautofn(Cmd cmd, LinkList args, int flags)
|
|||
return lastval;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
loadautofn(Shfunc shf)
|
||||
{
|
||||
/* Copied from execautofn() -- should consolidate someday */
|
||||
|
||||
int noalias = noaliases;
|
||||
List l;
|
||||
|
||||
noaliases = (shf->flags & PM_UNALIASED);
|
||||
l = getfpfunc(shf->nam);
|
||||
noaliases = noalias;
|
||||
|
||||
if (l == &dummy_list) {
|
||||
zerr("%s: function definition file not found", shf->nam, 0);
|
||||
return 1;
|
||||
}
|
||||
PERMALLOC {
|
||||
shf->funcdef = dupstruct(stripkshdef(l, shf->nam));
|
||||
} LASTALLOC;
|
||||
shf->flags &= ~PM_UNDEFINED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* execute a shell function */
|
||||
|
||||
/**/
|
||||
|
|
|
@ -872,21 +872,29 @@ printshfuncnode(HashNode hn, int printflags)
|
|||
}
|
||||
|
||||
if (f->flags & PM_UNDEFINED)
|
||||
printf("undefined ");
|
||||
if (f->flags & PM_TAGGED)
|
||||
printf("traced ");
|
||||
if ((f->flags & PM_UNDEFINED) || !f->funcdef) {
|
||||
nicezputs(f->nam, stdout);
|
||||
printf(" () { }\n");
|
||||
return;
|
||||
t = tricat("builtin autoload -X",
|
||||
((f->flags & PM_UNALIASED)? "U" : ""),
|
||||
((f->flags & PM_TAGGED)? "t" : ""));
|
||||
else {
|
||||
if (!f->funcdef)
|
||||
t = 0;
|
||||
else
|
||||
t = getpermtext((void *) f->funcdef);
|
||||
}
|
||||
|
||||
t = getpermtext((void *) f->funcdef);
|
||||
|
||||
quotedzputs(f->nam, stdout);
|
||||
printf(" () {\n\t");
|
||||
zputs(t, stdout);
|
||||
printf("\n}\n");
|
||||
zsfree(t);
|
||||
if (t) {
|
||||
printf(" () {\n\t");
|
||||
if (f->flags & PM_UNDEFINED)
|
||||
printf("%c undefined\n\t", hashchar);
|
||||
if (f->flags & PM_TAGGED)
|
||||
printf("%c traced\n\t", hashchar);
|
||||
zputs(t, stdout);
|
||||
printf("\n}\n");
|
||||
zsfree(t);
|
||||
} else {
|
||||
printf(" () { }\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
|
Loading…
Reference in a new issue