mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-23 17:01:05 +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>
|
||||
|
||||
* 40305: Src/Zle/complist.c, Src/Zle/zle_main.c,
|
||||
|
|
|
@ -147,20 +147,39 @@ ifnzman(noderef(Aliasing)).
|
|||
findex(autoload)
|
||||
cindex(functions, autoloading)
|
||||
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)
|
||||
Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X) and
|
||||
tt(-w). See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\
|
||||
See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\
|
||||
ifnzman(noderef(Functions)) for full details. The tt(fpath) parameter
|
||||
will be searched to find the function definition when the function is
|
||||
first referenced.
|
||||
|
||||
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.
|
||||
If var(name) consists of an absolute path, the function is defined to
|
||||
load from the file given (searching as usual for dump files in the given
|
||||
location). The name of the function is the basename (non-directory
|
||||
part) of the file. It is normally an error if the function is not found
|
||||
in the given location; however, if the option tt(-d) is given, searching
|
||||
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,
|
||||
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 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(zcompile) builtin, and all functions defined in them are
|
||||
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)
|
||||
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)
|
||||
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) ... ])
|
||||
item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )(
|
||||
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
|
||||
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.
|
||||
|
||||
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))(
|
||||
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
|
||||
-----------------------------
|
||||
|
||||
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'
|
||||
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
|
||||
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
|
||||
used for filename generation (globbing) or other forms of pattern
|
||||
|
|
175
Src/builtin.c
175
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_true, 0, -1, 0, NULL, 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("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, 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 :
|
||||
(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. */
|
||||
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. *
|
||||
* If called as autoload, it will define a new autoloaded *
|
||||
* (undefined) shell function. */
|
||||
|
@ -3007,10 +3079,17 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
off |= 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')) ||
|
||||
(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)");
|
||||
return 1;
|
||||
}
|
||||
|
@ -3165,47 +3244,55 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
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) {
|
||||
if (OPT_MINUS(ops,'X')) {
|
||||
Funcstack fs;
|
||||
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) {
|
||||
if (fs->tp == FS_FUNC) {
|
||||
/*
|
||||
* dupstring here is paranoia but unlikely to be
|
||||
* problematic
|
||||
*/
|
||||
funcname = dupstring(fs->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!funcname)
|
||||
{
|
||||
zerrnam(name, "bad autoload");
|
||||
ret = 1;
|
||||
} else {
|
||||
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, funcname))) {
|
||||
DPUTS(!shf->funcdef,
|
||||
"BUG: Calling autoload from empty function");
|
||||
} else {
|
||||
shf = (Shfunc) zshcalloc(sizeof *shf);
|
||||
shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
|
||||
}
|
||||
if (*argv)
|
||||
shf->filename = ztrdup(*argv);
|
||||
shf->node.flags = on;
|
||||
ret = eval_autoload(shf, funcname, ops, func);
|
||||
}
|
||||
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_MINUS(ops,'X')) {
|
||||
Funcstack fs;
|
||||
char *funcname = NULL;
|
||||
for (fs = funcstack; fs; fs = fs->prev) {
|
||||
if (fs->tp == FS_FUNC) {
|
||||
/*
|
||||
* dupstring here is paranoia but unlikely to be
|
||||
* problematic
|
||||
*/
|
||||
funcname = dupstring(fs->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!funcname)
|
||||
{
|
||||
zerrnam(name, "bad autoload");
|
||||
ret = 1;
|
||||
} else {
|
||||
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, funcname))) {
|
||||
DPUTS(!shf->funcdef,
|
||||
"BUG: Calling autoload from empty function");
|
||||
} else {
|
||||
shf = (Shfunc) zshcalloc(sizeof *shf);
|
||||
shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
|
||||
}
|
||||
shf->node.flags = on;
|
||||
ret = eval_autoload(shf, funcname, ops, func);
|
||||
}
|
||||
} else {
|
||||
if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
|
||||
if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
|
||||
on &= ~PM_UNDEFINED;
|
||||
scanshfunc(1, on|off, DISABLED, shfunctab->printnode,
|
||||
pflags, expand);
|
||||
}
|
||||
unqueue_signals();
|
||||
return ret;
|
||||
}
|
||||
|
@ -3231,8 +3318,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
!(shf->node.flags & DISABLED)) {
|
||||
shf->node.flags = (shf->node.flags |
|
||||
(on & ~PM_UNDEFINED)) & ~off;
|
||||
if (OPT_ISSET(ops,'X') &&
|
||||
eval_autoload(shf, shf->node.nam, ops, func)) {
|
||||
if (check_autoload(shf, shf->node.nam,
|
||||
ops, func)) {
|
||||
returnval = 1;
|
||||
}
|
||||
}
|
||||
|
@ -3258,8 +3345,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
if (on|off) {
|
||||
/* turn on/off the given flags */
|
||||
shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
|
||||
if (OPT_ISSET(ops,'X') &&
|
||||
eval_autoload(shf, shf->node.nam, ops, func))
|
||||
if (check_autoload(shf, shf->node.nam, ops, func))
|
||||
returnval = 1;
|
||||
} else
|
||||
/* no flags, so just print */
|
||||
|
@ -3282,7 +3368,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
shf->node.flags = on;
|
||||
shf->funcdef = mkautofn(shf);
|
||||
shfunc_set_sticky(shf);
|
||||
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
|
||||
add_autoload_function(shf, *argv);
|
||||
|
||||
if (signum != -1) {
|
||||
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') &&
|
||||
eval_autoload(shf, shf->node.nam, ops, func))
|
||||
if (ok && check_autoload(shf, shf->node.nam, ops, func))
|
||||
returnval = 1;
|
||||
} else
|
||||
returnval = 1;
|
||||
|
|
44
Src/exec.c
44
Src/exec.c
|
@ -3124,7 +3124,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
|
|||
if (is_shfunc)
|
||||
shf = (Shfunc)hn;
|
||||
else {
|
||||
shf = loadautofn(state->prog->shf, 1, 0);
|
||||
shf = loadautofn(state->prog->shf, 1, 0, 0);
|
||||
if (shf)
|
||||
state->prog->shf = shf;
|
||||
else {
|
||||
|
@ -5142,7 +5142,7 @@ execautofn(Estate state, UNUSED(int do_exec))
|
|||
{
|
||||
Shfunc shf;
|
||||
|
||||
if (!(shf = loadautofn(state->prog->shf, 1, 0)))
|
||||
if (!(shf = loadautofn(state->prog->shf, 1, 0, 0)))
|
||||
return 1;
|
||||
|
||||
state->prog->shf = shf;
|
||||
|
@ -5151,7 +5151,7 @@ execautofn(Estate state, UNUSED(int do_exec))
|
|||
|
||||
/**/
|
||||
Shfunc
|
||||
loadautofn(Shfunc shf, int fksh, int autol)
|
||||
loadautofn(Shfunc shf, int fksh, int autol, int current_fpath)
|
||||
{
|
||||
int noalias = noaliases, ksh = 1;
|
||||
Eprog prog;
|
||||
|
@ -5160,7 +5160,18 @@ loadautofn(Shfunc shf, int fksh, int autol)
|
|||
pushheap();
|
||||
|
||||
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;
|
||||
|
||||
if (ksh == 1) {
|
||||
|
@ -5602,12 +5613,18 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
|
|||
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
|
||||
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];
|
||||
off_t len;
|
||||
|
@ -5616,7 +5633,7 @@ getfpfunc(char *s, int *ksh, char **fname)
|
|||
Eprog r;
|
||||
int fd;
|
||||
|
||||
pp = fpath;
|
||||
pp = alt_path ? alt_path : fpath;
|
||||
for (; *pp; pp++) {
|
||||
if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX)
|
||||
continue;
|
||||
|
@ -5624,9 +5641,9 @@ getfpfunc(char *s, int *ksh, char **fname)
|
|||
sprintf(buf, "%s/%s", *pp, s);
|
||||
else
|
||||
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)
|
||||
*fname = ztrdup(buf);
|
||||
*fname = test_only ? *pp : ztrdup(buf);
|
||||
return r;
|
||||
}
|
||||
unmetafy(buf, NULL);
|
||||
|
@ -5634,6 +5651,11 @@ getfpfunc(char *s, int *ksh, char **fname)
|
|||
struct stat st;
|
||||
if (!fstat(fd, &st) && S_ISREG(st.st_mode) &&
|
||||
(len = lseek(fd, 0, 2)) != -1) {
|
||||
if (test_only) {
|
||||
close(fd);
|
||||
*fname = *pp;
|
||||
return &dummy_eprog;
|
||||
}
|
||||
d = (char *) zalloc(len + 1);
|
||||
lseek(fd, 0, 0);
|
||||
if ((rlen = read(fd, d, len)) >= 0) {
|
||||
|
@ -5661,7 +5683,7 @@ getfpfunc(char *s, int *ksh, char **fname)
|
|||
close(fd);
|
||||
}
|
||||
}
|
||||
return &dummy_eprog;
|
||||
return test_only ? NULL : &dummy_eprog;
|
||||
}
|
||||
|
||||
/* Handle the most common type of ksh-style autoloading, when doing a *
|
||||
|
|
|
@ -949,16 +949,20 @@ printshfuncnode(HashNode hn, int printflags)
|
|||
zoutputtab(stdout);
|
||||
}
|
||||
if (!t) {
|
||||
char *fopt = "UtTkz";
|
||||
char *fopt = "UtTkzc";
|
||||
int flgs[] = {
|
||||
PM_UNALIASED, PM_TAGGED, PM_TAGGED_LOCAL,
|
||||
PM_KSHSTORED, PM_ZSHSTORED, 0
|
||||
PM_KSHSTORED, PM_ZSHSTORED, PM_CUR_FPATH, 0
|
||||
};
|
||||
int fl;;
|
||||
|
||||
zputs("builtin autoload -X", stdout);
|
||||
for (fl=0;fopt[fl];fl++)
|
||||
if (f->node.flags & flgs[fl]) putchar(fopt[fl]);
|
||||
if (f->filename) {
|
||||
putchar(' ');
|
||||
zputs(f->filename, stdout);
|
||||
}
|
||||
} else {
|
||||
zputs(t, stdout);
|
||||
zsfree(t);
|
||||
|
|
24
Src/parse.c
24
Src/parse.c
|
@ -3338,7 +3338,7 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
|
|||
return 1;
|
||||
}
|
||||
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) {
|
||||
noaliases = ona;
|
||||
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
|
||||
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;
|
||||
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)) {
|
||||
queue_signals();
|
||||
prog = check_dump_file(path, NULL, name, ksh);
|
||||
prog = check_dump_file(path, NULL, name, ksh, test_only);
|
||||
unqueue_signals();
|
||||
return prog;
|
||||
}
|
||||
|
@ -3608,14 +3608,14 @@ try_dump_file(char *path, char *name, char *file, int *ksh)
|
|||
if (!rd &&
|
||||
(rc || std.st_mtime > stc.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();
|
||||
return prog;
|
||||
}
|
||||
/* No digest file. Now look for the per-function compiled file. */
|
||||
if (!rc &&
|
||||
(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();
|
||||
return prog;
|
||||
}
|
||||
|
@ -3643,7 +3643,7 @@ try_source_file(char *file)
|
|||
|
||||
if (strsfx(FD_EXT, file)) {
|
||||
queue_signals();
|
||||
prog = check_dump_file(file, NULL, tail, NULL);
|
||||
prog = check_dump_file(file, NULL, tail, NULL, 0);
|
||||
unqueue_signals();
|
||||
return prog;
|
||||
}
|
||||
|
@ -3654,7 +3654,7 @@ try_source_file(char *file)
|
|||
|
||||
queue_signals();
|
||||
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();
|
||||
return prog;
|
||||
}
|
||||
|
@ -3667,7 +3667,8 @@ try_source_file(char *file)
|
|||
|
||||
/**/
|
||||
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;
|
||||
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))) {
|
||||
/* Found the name. If the file is already mapped, return the eprog,
|
||||
* otherwise map it and just go up. */
|
||||
if (test_only)
|
||||
{
|
||||
/* This is all we need. Just return dummy. */
|
||||
return &dummy_eprog;
|
||||
}
|
||||
|
||||
#ifdef USE_MMAP
|
||||
|
||||
|
@ -3745,7 +3751,7 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
|
|||
|
||||
#endif
|
||||
|
||||
{
|
||||
{
|
||||
Eprog prog;
|
||||
Patprog *pp;
|
||||
int np, fd, po = h->npats * sizeof(Patprog);
|
||||
|
|
|
@ -1233,7 +1233,9 @@ struct cmdnam {
|
|||
|
||||
struct shfunc {
|
||||
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 */
|
||||
Eprog funcdef; /* function definition */
|
||||
Eprog redir; /* redirections to apply */
|
||||
|
@ -1811,6 +1813,7 @@ struct tieddata {
|
|||
#define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */
|
||||
|
||||
#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_TIED (1<<16) /* array tied to colon-path or v.v. */
|
||||
#define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */
|
||||
|
|
|
@ -330,6 +330,95 @@
|
|||
0:whence -v of zsh-style autoload
|
||||
>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
|
||||
|
||||
rm -f file.in file.out
|
||||
|
|
Loading…
Reference in a new issue