mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-29 19:00:57 +02:00
Add features associated with autoloading a function using an absolute
path. -d defaults to normal fpath -r remembers the path without actually loading. May be combined with -d. -R does the same but it's an error if not found -X can now take a directory path: this is used to output not yet loaded functions that have an associated path.
This commit is contained in:
parent
34656ec2f0
commit
f26d1ba6b0
9 changed files with 342 additions and 82 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2017-01-11 Peter Stephenson <p.stephenson@samsung.com>
|
||||||
|
|
||||||
|
* 40327 (with minor fixes): Doc/Zsh/builtins.yo,
|
||||||
|
README,Src/builtin.c, Src/exec.c, Src/hashtable.c, Src/parse.c,
|
||||||
|
Src/zsh.h, Test/C04funcdef.ztst: add ability to autoload
|
||||||
|
function from file using full path, with additional related
|
||||||
|
autoload options -r, -R, -d and extension to -X.
|
||||||
|
|
||||||
2017-01-10 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
2017-01-10 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||||
|
|
||||||
* 40305: Src/Zle/complist.c, Src/Zle/zle_main.c,
|
* 40305: Src/Zle/complist.c, Src/Zle/zle_main.c,
|
||||||
|
|
|
@ -147,20 +147,39 @@ ifnzman(noderef(Aliasing)).
|
||||||
findex(autoload)
|
findex(autoload)
|
||||||
cindex(functions, autoloading)
|
cindex(functions, autoloading)
|
||||||
cindex(autoloading functions)
|
cindex(autoloading functions)
|
||||||
item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(TUXkmtz) ] [ tt(-w) ] [ var(name) ... ])(
|
item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(RTUXdkmrtz) ] [ tt(-w) ] [ var(name) ... ])(
|
||||||
vindex(fpath, searching)
|
vindex(fpath, searching)
|
||||||
Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X) and
|
See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\
|
||||||
tt(-w). See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\
|
|
||||||
ifnzman(noderef(Functions)) for full details. The tt(fpath) parameter
|
ifnzman(noderef(Functions)) for full details. The tt(fpath) parameter
|
||||||
will be searched to find the function definition when the function is
|
will be searched to find the function definition when the function is
|
||||||
first referenced.
|
first referenced.
|
||||||
|
|
||||||
The flag tt(-X) may be used only inside a shell function, and may not be
|
If var(name) consists of an absolute path, the function is defined to
|
||||||
followed by a var(name). It causes the calling function to be marked for
|
load from the file given (searching as usual for dump files in the given
|
||||||
autoloading and then immediately loaded and executed, with the current
|
location). The name of the function is the basename (non-directory
|
||||||
array of positional parameters as arguments. This replaces the previous
|
part) of the file. It is normally an error if the function is not found
|
||||||
definition of the function. If no function definition is found, an error
|
in the given location; however, if the option tt(-d) is given, searching
|
||||||
is printed and the function remains undefined and marked for autoloading.
|
for the function defaults to tt($fpath).
|
||||||
|
|
||||||
|
If the option tt(-r) or tt(-R) is given, the function is searched for
|
||||||
|
immediately and the location is recorded internally for use when the
|
||||||
|
function is executed; a relative path is expanded using the value of
|
||||||
|
tt($PWD). This protects against a change to tt($fpath) after the call
|
||||||
|
to tt(autoload). With tt(-r), if the function is not found, it is
|
||||||
|
silently left unresolved until execution; with tt(-R), an error message
|
||||||
|
is printed and command processing aborted immediately the search fails,
|
||||||
|
i.e. at the tt(autoload) command rather than at function execution..
|
||||||
|
|
||||||
|
The flag tt(-X) may be used only inside a shell function. 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. If an argument is given,
|
||||||
|
it is used as a directory (i.e. it does not include the name of the
|
||||||
|
function) in which the function is to be found; this may be combined
|
||||||
|
with the tt(-d) option to allow the function search to default to tt($fpath)
|
||||||
|
if it is not in the given location.
|
||||||
|
|
||||||
The flag tt(+X) attempts to load each var(name) as an autoloaded function,
|
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
|
but does em(not) execute it. The exit status is zero (success) if the
|
||||||
|
@ -176,6 +195,13 @@ If the tt(-m) flag is also given each var(name) is treated as a
|
||||||
pattern and all functions already marked for autoload that match the
|
pattern and all functions already marked for autoload that match the
|
||||||
pattern are loaded.
|
pattern are loaded.
|
||||||
|
|
||||||
|
With the tt(-t) flag, turn on execution tracing; with tt(-T), turn on
|
||||||
|
execution tracing only for the current function, turning it off on entry
|
||||||
|
to any called functions that do not also have tracing enabled.
|
||||||
|
|
||||||
|
With the tt(-U) flag, alias expansion is suppressed when the function is
|
||||||
|
loaded.
|
||||||
|
|
||||||
With the tt(-w) flag, the var(name)s are taken as names of files compiled
|
With the tt(-w) flag, the var(name)s are taken as names of files compiled
|
||||||
with the tt(zcompile) builtin, and all functions defined in them are
|
with the tt(zcompile) builtin, and all functions defined in them are
|
||||||
marked for autoloading.
|
marked for autoloading.
|
||||||
|
@ -193,6 +219,10 @@ example(emulate zsh -c 'autoload -Uz var(func)')
|
||||||
|
|
||||||
arranges that when var(func) is loaded the shell is in native tt(zsh)
|
arranges that when var(func) is loaded the shell is in native tt(zsh)
|
||||||
emulation, and this emulation is also applied when var(func) is run.
|
emulation, and this emulation is also applied when var(func) is run.
|
||||||
|
|
||||||
|
Some of the functions of tt(autoload) are also provided by tt(functions
|
||||||
|
-u) or tt(functions -U), but tt(autoload) is a more comprehensive
|
||||||
|
interface.
|
||||||
)
|
)
|
||||||
findex(bg)
|
findex(bg)
|
||||||
cindex(jobs, backgrounding)
|
cindex(jobs, backgrounding)
|
||||||
|
@ -811,7 +841,8 @@ xitem(tt(functions -M) var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ])
|
||||||
xitem(tt(functions -M) [ tt(-m) var(pattern) ... ])
|
xitem(tt(functions -M) [ tt(-m) var(pattern) ... ])
|
||||||
item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )(
|
item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )(
|
||||||
Equivalent to tt(typeset -f), with the exception of the tt(-x) and
|
Equivalent to tt(typeset -f), with the exception of the tt(-x) and
|
||||||
tt(-M) options.
|
tt(-M) options. For tt(functions -u) and tt(functions -U), see
|
||||||
|
tt(autoload), which provides additional options.
|
||||||
|
|
||||||
The tt(-x) option indicates that any functions output will have
|
The tt(-x) option indicates that any functions output will have
|
||||||
each leading tab for indentation, added by the shell to show syntactic
|
each leading tab for indentation, added by the shell to show syntactic
|
||||||
|
@ -2034,7 +2065,9 @@ expansion to be suppressed when the function is loaded. See the
|
||||||
description of the `tt(autoload)' builtin for details.
|
description of the `tt(autoload)' builtin for details.
|
||||||
|
|
||||||
Note that the builtin tt(functions) provides the same basic capabilities
|
Note that the builtin tt(functions) provides the same basic capabilities
|
||||||
as tt(typeset -f) but gives access to a few extra options.
|
as tt(typeset -f) but gives access to a few extra options; tt(autoload)
|
||||||
|
gives further additional options for the case tt(typeset -fu) and
|
||||||
|
tt(typeset -fU).
|
||||||
)
|
)
|
||||||
item(tt(-h))(
|
item(tt(-h))(
|
||||||
Hide: only useful for special parameters (those marked `<S>' in the table in
|
Hide: only useful for special parameters (those marked `<S>' in the table in
|
||||||
|
|
16
README
16
README
|
@ -32,7 +32,7 @@ details, see the documentation.
|
||||||
Incompatibilities since 5.3.1
|
Incompatibilities since 5.3.1
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
The default behaviour of code like the following has changed:
|
1) The default behaviour of code like the following has changed:
|
||||||
|
|
||||||
alias foo='noglob foo'
|
alias foo='noglob foo'
|
||||||
foo() { print function body; }
|
foo() { print function body; }
|
||||||
|
@ -52,8 +52,18 @@ ALIAS_FUNC_DEF, has been added, which can be set to make the shell
|
||||||
behave as in previous versions. It is in any case recommended to use
|
behave as in previous versions. It is in any case recommended to use
|
||||||
the "function" keyword, as aliases are not expanded afterwards.
|
the "function" keyword, as aliases are not expanded afterwards.
|
||||||
|
|
||||||
Incompatibilities between 5.0.8 and 5.3.1
|
2) It was an undocumented, and largely useless, feature that a function
|
||||||
-----------------------------------------
|
autoloaded with an absolute path was searched for along the normal fpath
|
||||||
|
(as if the leading / was missing) and, if found, loaded under the full
|
||||||
|
name including the leading slash. This has been replaced with the more
|
||||||
|
useful feature that the function is searched for only at the given
|
||||||
|
absolute path; the name of the function is the base name of the file.
|
||||||
|
Note that functions including a non-leading / behave as before,
|
||||||
|
e.g. if `dir/name' is found anywhere under a directory in $fpath it is
|
||||||
|
loaded as a function named `dir/name'.
|
||||||
|
|
||||||
|
Incompatibilities between 5.0.8 and 5.3
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
1) In character classes delimited by "[" and "]" within patterns, whether
|
1) In character classes delimited by "[" and "]" within patterns, whether
|
||||||
used for filename generation (globbing) or other forms of pattern
|
used for filename generation (globbing) or other forms of pattern
|
||||||
|
|
123
Src/builtin.c
123
Src/builtin.c
|
@ -46,7 +46,7 @@ static struct builtin builtins[] =
|
||||||
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
|
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
|
||||||
BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -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, "Lgmrs", NULL),
|
BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL),
|
||||||
BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "mktTUwXz", "u"),
|
BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "dmktrRTUwXz", "u"),
|
||||||
BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
|
BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
|
||||||
BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, 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),
|
BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
|
||||||
|
@ -2922,9 +2922,59 @@ eval_autoload(Shfunc shf, char *name, Options ops, int func)
|
||||||
}
|
}
|
||||||
|
|
||||||
return !loadautofn(shf, (OPT_ISSET(ops,'k') ? 2 :
|
return !loadautofn(shf, (OPT_ISSET(ops,'k') ? 2 :
|
||||||
(OPT_ISSET(ops,'z') ? 0 : 1)), 1);
|
(OPT_ISSET(ops,'z') ? 0 : 1)), 1,
|
||||||
|
OPT_ISSET(ops,'d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Helper for bin_functions() for -X and -r options */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
check_autoload(Shfunc shf, char *name, Options ops, int func)
|
||||||
|
{
|
||||||
|
if (OPT_ISSET(ops,'X'))
|
||||||
|
{
|
||||||
|
return eval_autoload(shf, name, ops, func);
|
||||||
|
}
|
||||||
|
if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'R'))
|
||||||
|
{
|
||||||
|
char *dir_path;
|
||||||
|
if (shf->filename) {
|
||||||
|
char *spec_path[2];
|
||||||
|
spec_path[0] = shf->filename;
|
||||||
|
spec_path[1] = NULL;
|
||||||
|
if (getfpfunc(shf->node.nam, NULL, &dir_path, spec_path, 1)) {
|
||||||
|
/* shf->filename is already correct. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!OPT_ISSET(ops,'d')) {
|
||||||
|
if (OPT_ISSET(ops,'R')) {
|
||||||
|
zerr("%s: function definition file not found",
|
||||||
|
shf->node.nam);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getfpfunc(shf->node.nam, NULL, &dir_path, NULL, 1)) {
|
||||||
|
zsfree(shf->filename);
|
||||||
|
if (*dir_path != '/') {
|
||||||
|
dir_path = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP),
|
||||||
|
"/", dir_path);
|
||||||
|
dir_path = xsymlink(dir_path, 1);
|
||||||
|
}
|
||||||
|
shf->filename = ztrdup(dir_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (OPT_ISSET(ops,'R')) {
|
||||||
|
zerr("%s: function definition file not found",
|
||||||
|
shf->node.nam);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* with -r, we don't flag an error, just let it be found later. */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* List a user-defined math function. */
|
/* List a user-defined math function. */
|
||||||
static void
|
static void
|
||||||
|
@ -2962,6 +3012,28 @@ listusermathfunc(MathFunc p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_autoload_function(Shfunc shf, char *funcname)
|
||||||
|
{
|
||||||
|
char *nam;
|
||||||
|
if (*funcname == '/' && funcname[1] &&
|
||||||
|
(nam = strrchr(funcname, '/')) && nam[1]) {
|
||||||
|
char *dir;
|
||||||
|
nam = strrchr(funcname, '/');
|
||||||
|
if (nam == funcname) {
|
||||||
|
dir = "/";
|
||||||
|
} else {
|
||||||
|
*nam++ = '\0';
|
||||||
|
dir = funcname;
|
||||||
|
}
|
||||||
|
zsfree(shf->filename);
|
||||||
|
shf->filename = ztrdup(dir);
|
||||||
|
shfunctab->addnode(shfunctab, ztrdup(nam), shf);
|
||||||
|
} else {
|
||||||
|
shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Display or change the attributes of shell functions. *
|
/* Display or change the attributes of shell functions. *
|
||||||
* If called as autoload, it will define a new autoloaded *
|
* If called as autoload, it will define a new autoloaded *
|
||||||
* (undefined) shell function. */
|
* (undefined) shell function. */
|
||||||
|
@ -3007,10 +3079,17 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
off |= PM_KSHSTORED;
|
off |= PM_KSHSTORED;
|
||||||
roff |= PM_KSHSTORED;
|
roff |= PM_KSHSTORED;
|
||||||
}
|
}
|
||||||
|
if (OPT_MINUS(ops,'d')) {
|
||||||
|
on |= PM_CUR_FPATH;
|
||||||
|
off |= PM_CUR_FPATH;
|
||||||
|
} else if (OPT_PLUS(ops,'d')) {
|
||||||
|
off |= PM_CUR_FPATH;
|
||||||
|
roff |= PM_CUR_FPATH;
|
||||||
|
}
|
||||||
|
|
||||||
if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
|
if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
|
||||||
(OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) ||
|
(OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) ||
|
||||||
(OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) {
|
(OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || !scriptname))) {
|
||||||
zwarnnam(name, "invalid option(s)");
|
zwarnnam(name, "invalid option(s)");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -3165,16 +3244,15 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
return returnval;
|
return returnval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no arguments given, we will print functions. If flags *
|
|
||||||
* are given, we will print only functions containing these *
|
|
||||||
* flags, else we'll print them all. */
|
|
||||||
if (!*argv) {
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
queue_signals();
|
|
||||||
if (OPT_MINUS(ops,'X')) {
|
if (OPT_MINUS(ops,'X')) {
|
||||||
Funcstack fs;
|
Funcstack fs;
|
||||||
char *funcname = NULL;
|
char *funcname = NULL;
|
||||||
|
int ret;
|
||||||
|
if (*argv && argv[1]) {
|
||||||
|
zwarnnam(name, "-X: too many arguments");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
queue_signals();
|
||||||
for (fs = funcstack; fs; fs = fs->prev) {
|
for (fs = funcstack; fs; fs = fs->prev) {
|
||||||
if (fs->tp == FS_FUNC) {
|
if (fs->tp == FS_FUNC) {
|
||||||
/*
|
/*
|
||||||
|
@ -3197,15 +3275,24 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
shf = (Shfunc) zshcalloc(sizeof *shf);
|
shf = (Shfunc) zshcalloc(sizeof *shf);
|
||||||
shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
|
shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
|
||||||
}
|
}
|
||||||
|
if (*argv)
|
||||||
|
shf->filename = ztrdup(*argv);
|
||||||
shf->node.flags = on;
|
shf->node.flags = on;
|
||||||
ret = eval_autoload(shf, funcname, ops, func);
|
ret = eval_autoload(shf, funcname, ops, func);
|
||||||
}
|
}
|
||||||
} else {
|
unqueue_signals();
|
||||||
|
return ret;
|
||||||
|
} else if (!*argv) {
|
||||||
|
/* If no arguments given, we will print functions. If flags *
|
||||||
|
* are given, we will print only functions containing these *
|
||||||
|
* flags, else we'll print them all. */
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
queue_signals();
|
||||||
if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
|
if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
|
||||||
on &= ~PM_UNDEFINED;
|
on &= ~PM_UNDEFINED;
|
||||||
scanshfunc(1, on|off, DISABLED, shfunctab->printnode,
|
scanshfunc(1, on|off, DISABLED, shfunctab->printnode,
|
||||||
pflags, expand);
|
pflags, expand);
|
||||||
}
|
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3231,8 +3318,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
!(shf->node.flags & DISABLED)) {
|
!(shf->node.flags & DISABLED)) {
|
||||||
shf->node.flags = (shf->node.flags |
|
shf->node.flags = (shf->node.flags |
|
||||||
(on & ~PM_UNDEFINED)) & ~off;
|
(on & ~PM_UNDEFINED)) & ~off;
|
||||||
if (OPT_ISSET(ops,'X') &&
|
if (check_autoload(shf, shf->node.nam,
|
||||||
eval_autoload(shf, shf->node.nam, ops, func)) {
|
ops, func)) {
|
||||||
returnval = 1;
|
returnval = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3258,8 +3345,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
if (on|off) {
|
if (on|off) {
|
||||||
/* turn on/off the given flags */
|
/* turn on/off the given flags */
|
||||||
shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
|
shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
|
||||||
if (OPT_ISSET(ops,'X') &&
|
if (check_autoload(shf, shf->node.nam, ops, func))
|
||||||
eval_autoload(shf, shf->node.nam, ops, func))
|
|
||||||
returnval = 1;
|
returnval = 1;
|
||||||
} else
|
} else
|
||||||
/* no flags, so just print */
|
/* no flags, so just print */
|
||||||
|
@ -3282,7 +3368,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
shf->node.flags = on;
|
shf->node.flags = on;
|
||||||
shf->funcdef = mkautofn(shf);
|
shf->funcdef = mkautofn(shf);
|
||||||
shfunc_set_sticky(shf);
|
shfunc_set_sticky(shf);
|
||||||
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
|
add_autoload_function(shf, *argv);
|
||||||
|
|
||||||
if (signum != -1) {
|
if (signum != -1) {
|
||||||
if (settrap(signum, NULL, ZSIG_FUNC)) {
|
if (settrap(signum, NULL, ZSIG_FUNC)) {
|
||||||
|
@ -3293,8 +3379,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok && OPT_ISSET(ops,'X') &&
|
if (ok && check_autoload(shf, shf->node.nam, ops, func))
|
||||||
eval_autoload(shf, shf->node.nam, ops, func))
|
|
||||||
returnval = 1;
|
returnval = 1;
|
||||||
} else
|
} else
|
||||||
returnval = 1;
|
returnval = 1;
|
||||||
|
|
44
Src/exec.c
44
Src/exec.c
|
@ -3124,7 +3124,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
|
||||||
if (is_shfunc)
|
if (is_shfunc)
|
||||||
shf = (Shfunc)hn;
|
shf = (Shfunc)hn;
|
||||||
else {
|
else {
|
||||||
shf = loadautofn(state->prog->shf, 1, 0);
|
shf = loadautofn(state->prog->shf, 1, 0, 0);
|
||||||
if (shf)
|
if (shf)
|
||||||
state->prog->shf = shf;
|
state->prog->shf = shf;
|
||||||
else {
|
else {
|
||||||
|
@ -5142,7 +5142,7 @@ execautofn(Estate state, UNUSED(int do_exec))
|
||||||
{
|
{
|
||||||
Shfunc shf;
|
Shfunc shf;
|
||||||
|
|
||||||
if (!(shf = loadautofn(state->prog->shf, 1, 0)))
|
if (!(shf = loadautofn(state->prog->shf, 1, 0, 0)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
state->prog->shf = shf;
|
state->prog->shf = shf;
|
||||||
|
@ -5151,7 +5151,7 @@ execautofn(Estate state, UNUSED(int do_exec))
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Shfunc
|
Shfunc
|
||||||
loadautofn(Shfunc shf, int fksh, int autol)
|
loadautofn(Shfunc shf, int fksh, int autol, int current_fpath)
|
||||||
{
|
{
|
||||||
int noalias = noaliases, ksh = 1;
|
int noalias = noaliases, ksh = 1;
|
||||||
Eprog prog;
|
Eprog prog;
|
||||||
|
@ -5160,7 +5160,18 @@ loadautofn(Shfunc shf, int fksh, int autol)
|
||||||
pushheap();
|
pushheap();
|
||||||
|
|
||||||
noaliases = (shf->node.flags & PM_UNALIASED);
|
noaliases = (shf->node.flags & PM_UNALIASED);
|
||||||
prog = getfpfunc(shf->node.nam, &ksh, &fname);
|
if (shf->filename && shf->filename[0] == '/')
|
||||||
|
{
|
||||||
|
char *spec_path[2];
|
||||||
|
spec_path[0] = dupstring(shf->filename);
|
||||||
|
spec_path[1] = NULL;
|
||||||
|
prog = getfpfunc(shf->node.nam, &ksh, &fname, spec_path, 0);
|
||||||
|
if (prog == &dummy_eprog &&
|
||||||
|
(current_fpath || (shf->node.flags & PM_CUR_FPATH)))
|
||||||
|
prog = getfpfunc(shf->node.nam, &ksh, &fname, NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prog = getfpfunc(shf->node.nam, &ksh, &fname, NULL, 0);
|
||||||
noaliases = noalias;
|
noaliases = noalias;
|
||||||
|
|
||||||
if (ksh == 1) {
|
if (ksh == 1) {
|
||||||
|
@ -5602,12 +5613,18 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search fpath for an undefined function. Finds the file, and returns the *
|
/*
|
||||||
* list of its contents. */
|
* Search fpath for an undefined function. Finds the file, and returns the
|
||||||
|
* list of its contents.
|
||||||
|
*
|
||||||
|
* If test_only is 1, don't load function, just test for it:
|
||||||
|
* - Non-null return means function was found
|
||||||
|
* - *fname points to path at which found (not duplicated)
|
||||||
|
*/
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Eprog
|
Eprog
|
||||||
getfpfunc(char *s, int *ksh, char **fname)
|
getfpfunc(char *s, int *ksh, char **fname, char **alt_path, int test_only)
|
||||||
{
|
{
|
||||||
char **pp, buf[PATH_MAX+1];
|
char **pp, buf[PATH_MAX+1];
|
||||||
off_t len;
|
off_t len;
|
||||||
|
@ -5616,7 +5633,7 @@ getfpfunc(char *s, int *ksh, char **fname)
|
||||||
Eprog r;
|
Eprog r;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
pp = fpath;
|
pp = alt_path ? alt_path : fpath;
|
||||||
for (; *pp; pp++) {
|
for (; *pp; pp++) {
|
||||||
if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX)
|
if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5624,9 +5641,9 @@ getfpfunc(char *s, int *ksh, char **fname)
|
||||||
sprintf(buf, "%s/%s", *pp, s);
|
sprintf(buf, "%s/%s", *pp, s);
|
||||||
else
|
else
|
||||||
strcpy(buf, s);
|
strcpy(buf, s);
|
||||||
if ((r = try_dump_file(*pp, s, buf, ksh))) {
|
if ((r = try_dump_file(*pp, s, buf, ksh, test_only))) {
|
||||||
if (fname)
|
if (fname)
|
||||||
*fname = ztrdup(buf);
|
*fname = test_only ? *pp : ztrdup(buf);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
unmetafy(buf, NULL);
|
unmetafy(buf, NULL);
|
||||||
|
@ -5634,6 +5651,11 @@ getfpfunc(char *s, int *ksh, char **fname)
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (!fstat(fd, &st) && S_ISREG(st.st_mode) &&
|
if (!fstat(fd, &st) && S_ISREG(st.st_mode) &&
|
||||||
(len = lseek(fd, 0, 2)) != -1) {
|
(len = lseek(fd, 0, 2)) != -1) {
|
||||||
|
if (test_only) {
|
||||||
|
close(fd);
|
||||||
|
*fname = *pp;
|
||||||
|
return &dummy_eprog;
|
||||||
|
}
|
||||||
d = (char *) zalloc(len + 1);
|
d = (char *) zalloc(len + 1);
|
||||||
lseek(fd, 0, 0);
|
lseek(fd, 0, 0);
|
||||||
if ((rlen = read(fd, d, len)) >= 0) {
|
if ((rlen = read(fd, d, len)) >= 0) {
|
||||||
|
@ -5661,7 +5683,7 @@ getfpfunc(char *s, int *ksh, char **fname)
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &dummy_eprog;
|
return test_only ? NULL : &dummy_eprog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the most common type of ksh-style autoloading, when doing a *
|
/* Handle the most common type of ksh-style autoloading, when doing a *
|
||||||
|
|
|
@ -949,16 +949,20 @@ printshfuncnode(HashNode hn, int printflags)
|
||||||
zoutputtab(stdout);
|
zoutputtab(stdout);
|
||||||
}
|
}
|
||||||
if (!t) {
|
if (!t) {
|
||||||
char *fopt = "UtTkz";
|
char *fopt = "UtTkzc";
|
||||||
int flgs[] = {
|
int flgs[] = {
|
||||||
PM_UNALIASED, PM_TAGGED, PM_TAGGED_LOCAL,
|
PM_UNALIASED, PM_TAGGED, PM_TAGGED_LOCAL,
|
||||||
PM_KSHSTORED, PM_ZSHSTORED, 0
|
PM_KSHSTORED, PM_ZSHSTORED, PM_CUR_FPATH, 0
|
||||||
};
|
};
|
||||||
int fl;;
|
int fl;;
|
||||||
|
|
||||||
zputs("builtin autoload -X", stdout);
|
zputs("builtin autoload -X", stdout);
|
||||||
for (fl=0;fopt[fl];fl++)
|
for (fl=0;fopt[fl];fl++)
|
||||||
if (f->node.flags & flgs[fl]) putchar(fopt[fl]);
|
if (f->node.flags & flgs[fl]) putchar(fopt[fl]);
|
||||||
|
if (f->filename) {
|
||||||
|
putchar(' ');
|
||||||
|
zputs(f->filename, stdout);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
zputs(t, stdout);
|
zputs(t, stdout);
|
||||||
zsfree(t);
|
zsfree(t);
|
||||||
|
|
22
Src/parse.c
22
Src/parse.c
|
@ -3338,7 +3338,7 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
noaliases = (shf->node.flags & PM_UNALIASED);
|
noaliases = (shf->node.flags & PM_UNALIASED);
|
||||||
if (!(prog = getfpfunc(shf->node.nam, NULL, NULL)) ||
|
if (!(prog = getfpfunc(shf->node.nam, NULL, NULL, NULL, 0)) ||
|
||||||
prog == &dummy_eprog) {
|
prog == &dummy_eprog) {
|
||||||
noaliases = ona;
|
noaliases = ona;
|
||||||
zwarnnam(nam, "can't load function: %s", shf->node.nam);
|
zwarnnam(nam, "can't load function: %s", shf->node.nam);
|
||||||
|
@ -3580,7 +3580,7 @@ load_dump_file(char *dump, struct stat *sbuf, int other, int len)
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Eprog
|
Eprog
|
||||||
try_dump_file(char *path, char *name, char *file, int *ksh)
|
try_dump_file(char *path, char *name, char *file, int *ksh, int test_only)
|
||||||
{
|
{
|
||||||
Eprog prog;
|
Eprog prog;
|
||||||
struct stat std, stc, stn;
|
struct stat std, stc, stn;
|
||||||
|
@ -3589,7 +3589,7 @@ try_dump_file(char *path, char *name, char *file, int *ksh)
|
||||||
|
|
||||||
if (strsfx(FD_EXT, path)) {
|
if (strsfx(FD_EXT, path)) {
|
||||||
queue_signals();
|
queue_signals();
|
||||||
prog = check_dump_file(path, NULL, name, ksh);
|
prog = check_dump_file(path, NULL, name, ksh, test_only);
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
@ -3608,14 +3608,14 @@ try_dump_file(char *path, char *name, char *file, int *ksh)
|
||||||
if (!rd &&
|
if (!rd &&
|
||||||
(rc || std.st_mtime > stc.st_mtime) &&
|
(rc || std.st_mtime > stc.st_mtime) &&
|
||||||
(rn || std.st_mtime > stn.st_mtime) &&
|
(rn || std.st_mtime > stn.st_mtime) &&
|
||||||
(prog = check_dump_file(dig, &std, name, ksh))) {
|
(prog = check_dump_file(dig, &std, name, ksh, test_only))) {
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
/* No digest file. Now look for the per-function compiled file. */
|
/* No digest file. Now look for the per-function compiled file. */
|
||||||
if (!rc &&
|
if (!rc &&
|
||||||
(rn || stc.st_mtime > stn.st_mtime) &&
|
(rn || stc.st_mtime > stn.st_mtime) &&
|
||||||
(prog = check_dump_file(wc, &stc, name, ksh))) {
|
(prog = check_dump_file(wc, &stc, name, ksh, test_only))) {
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
@ -3643,7 +3643,7 @@ try_source_file(char *file)
|
||||||
|
|
||||||
if (strsfx(FD_EXT, file)) {
|
if (strsfx(FD_EXT, file)) {
|
||||||
queue_signals();
|
queue_signals();
|
||||||
prog = check_dump_file(file, NULL, tail, NULL);
|
prog = check_dump_file(file, NULL, tail, NULL, 0);
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
@ -3654,7 +3654,7 @@ try_source_file(char *file)
|
||||||
|
|
||||||
queue_signals();
|
queue_signals();
|
||||||
if (!rc && (rn || stc.st_mtime > stn.st_mtime) &&
|
if (!rc && (rn || stc.st_mtime > stn.st_mtime) &&
|
||||||
(prog = check_dump_file(wc, &stc, tail, NULL))) {
|
(prog = check_dump_file(wc, &stc, tail, NULL, 0))) {
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
@ -3667,7 +3667,8 @@ try_source_file(char *file)
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static Eprog
|
static Eprog
|
||||||
check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
|
check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh,
|
||||||
|
int test_only)
|
||||||
{
|
{
|
||||||
int isrec = 0;
|
int isrec = 0;
|
||||||
Wordcode d;
|
Wordcode d;
|
||||||
|
@ -3709,6 +3710,11 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
|
||||||
if ((h = dump_find_func(d, name))) {
|
if ((h = dump_find_func(d, name))) {
|
||||||
/* Found the name. If the file is already mapped, return the eprog,
|
/* Found the name. If the file is already mapped, return the eprog,
|
||||||
* otherwise map it and just go up. */
|
* otherwise map it and just go up. */
|
||||||
|
if (test_only)
|
||||||
|
{
|
||||||
|
/* This is all we need. Just return dummy. */
|
||||||
|
return &dummy_eprog;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
|
|
||||||
|
|
|
@ -1233,7 +1233,9 @@ struct cmdnam {
|
||||||
|
|
||||||
struct shfunc {
|
struct shfunc {
|
||||||
struct hashnode node;
|
struct hashnode node;
|
||||||
char *filename; /* Name of file located in */
|
char *filename; /* Name of file located in.
|
||||||
|
For not yet autoloaded file, name
|
||||||
|
of explicit directory, if not NULL. */
|
||||||
zlong lineno; /* line number in above file */
|
zlong lineno; /* line number in above file */
|
||||||
Eprog funcdef; /* function definition */
|
Eprog funcdef; /* function definition */
|
||||||
Eprog redir; /* redirections to apply */
|
Eprog redir; /* redirections to apply */
|
||||||
|
@ -1811,6 +1813,7 @@ struct tieddata {
|
||||||
#define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */
|
#define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */
|
||||||
|
|
||||||
#define PM_HIDE (1<<14) /* Special behaviour hidden by local */
|
#define PM_HIDE (1<<14) /* Special behaviour hidden by local */
|
||||||
|
#define PM_CUR_FPATH (1<<14) /* (function): can use $fpath with filename */
|
||||||
#define PM_HIDEVAL (1<<15) /* Value not shown in `typeset' commands */
|
#define PM_HIDEVAL (1<<15) /* Value not shown in `typeset' commands */
|
||||||
#define PM_TIED (1<<16) /* array tied to colon-path or v.v. */
|
#define PM_TIED (1<<16) /* array tied to colon-path or v.v. */
|
||||||
#define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */
|
#define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */
|
||||||
|
|
|
@ -330,6 +330,95 @@
|
||||||
0:whence -v of zsh-style autoload
|
0:whence -v of zsh-style autoload
|
||||||
>oops is a shell function from ./oops
|
>oops is a shell function from ./oops
|
||||||
|
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
mkdir extra
|
||||||
|
print 'print "I have been loaded by explicit path."' >extra/spec
|
||||||
|
autoload -Uz $PWD/extra/spec
|
||||||
|
spec
|
||||||
|
)
|
||||||
|
0:autoload with explicit path
|
||||||
|
>I have been loaded by explicit path.
|
||||||
|
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
print 'print "I have been loaded by default path."' >def
|
||||||
|
autoload -Uz $PWD/extra/def
|
||||||
|
def
|
||||||
|
)
|
||||||
|
1:autoload with explicit path with function in normal path, no -d
|
||||||
|
?(eval):5: def: function definition file not found
|
||||||
|
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
autoload -dUz $PWD/extra/def
|
||||||
|
def
|
||||||
|
)
|
||||||
|
0:autoload with explicit path with function in normal path, with -d
|
||||||
|
>I have been loaded by default path.
|
||||||
|
|
||||||
|
(
|
||||||
|
cd extra
|
||||||
|
fpath=(.)
|
||||||
|
autoload -r spec
|
||||||
|
cd ..
|
||||||
|
spec
|
||||||
|
)
|
||||||
|
0:autoload -r
|
||||||
|
>I have been loaded by explicit path.
|
||||||
|
|
||||||
|
(
|
||||||
|
cd extra
|
||||||
|
fpath=(.)
|
||||||
|
autoload -r def
|
||||||
|
cd ..
|
||||||
|
def
|
||||||
|
)
|
||||||
|
0:autoload -r is permissive
|
||||||
|
>I have been loaded by default path.
|
||||||
|
|
||||||
|
(
|
||||||
|
cd extra
|
||||||
|
fpath=(.)
|
||||||
|
autoload -R def
|
||||||
|
)
|
||||||
|
1:autoload -R is not permissive
|
||||||
|
?(eval):4: def: function definition file not found
|
||||||
|
|
||||||
|
(
|
||||||
|
spec() { autoload -XUz $PWD/extra; }
|
||||||
|
spec
|
||||||
|
)
|
||||||
|
0:autoload -X with path
|
||||||
|
>I have been loaded by explicit path.
|
||||||
|
|
||||||
|
# The line number 1 here and in the next test seems suspect,
|
||||||
|
# but this example proves it's not down to the new features
|
||||||
|
# being tested here.
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
cod() { autoload -XUz; }
|
||||||
|
cod
|
||||||
|
)
|
||||||
|
1:autoload -X with no path, failure
|
||||||
|
?(eval):1: cod: function definition file not found
|
||||||
|
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
def() { autoload -XUz $PWD/extra; }
|
||||||
|
def
|
||||||
|
)
|
||||||
|
1:autoload -X with wrong path and no -d
|
||||||
|
?(eval):1: def: function definition file not found
|
||||||
|
|
||||||
|
(
|
||||||
|
fpath=(.)
|
||||||
|
def() { autoload -dXUz $PWD/extra; }
|
||||||
|
def
|
||||||
|
)
|
||||||
|
0:autoload -dX with path
|
||||||
|
>I have been loaded by default path.
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
|
|
||||||
rm -f file.in file.out
|
rm -f file.in file.out
|
||||||
|
|
Loading…
Reference in a new issue