Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATH: autoload with explicit path
- X-seq: zsh-workers 40159
- From: Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: PATH: autoload with explicit path
- Date: Sun, 11 Dec 2016 22:18:44 +0000
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
Not to be committed until 5.3 is safely done and dusted, but you might
as well see it now.
I wanted to autoload a function from an explicit path. (Not so auto, in
fact, but there isn't a trivial way of manually loading an autoload -z
format file without using autoload.) I could rig something up in a
function, saving and restoring fpath or wrapping the contents of the
file, but it strikes me it's a bit mean of the shell not simply to do
something sensible with
autoload +X /path/to/myfunc
That doesn't do anything sensible at the moment --- relative paths to
functions do, with the full relative path as the name, which is entirely
consistent, but absolute paths don't and in fact it tries the name as a
relative path anyway which seems Just Plain Wrong.
Then I found it was pretty much as easy (easier, actually, since fewer
special cases) to implement this generally:
autoload -Uz /path/to/myfunc
defines myfunc to be found in the directory /path/to by reusing the
filename element of the shfunc structure that's currently unused at this
stage.
This seemed quite a useful feature. No doc or tests at this stage.
Also TBD: output from "autoload" with no name. Just needs to update the
output of the autoload -X line appropriately, so this is a minor detail,
I think.
Also TBD: I should clearly document that autoload has its normal
semantics i.e. if the function already exists that definition is kept.
Explicit path != forced reload.
Also TBD: should output a special error message if not found so
user knows where it was looking.
pws
diff --git a/Src/builtin.c b/Src/builtin.c
index 65e0cb1..96571df 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2962,6 +2962,27 @@ 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;
+ }
+ 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. */
@@ -3195,7 +3216,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
"BUG: Calling autoload from empty function");
} else {
shf = (Shfunc) zshcalloc(sizeof *shf);
- shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
+ add_autoload_function(shf, funcname);
}
shf->node.flags = on;
ret = eval_autoload(shf, funcname, ops, func);
@@ -3266,6 +3287,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
printshfuncexpand(&shf->node, pflags, expand);
} else if (on & PM_UNDEFINED) {
int signum = -1, ok = 1;
+ char *nam;
if (!strncmp(*argv, "TRAP", 4) &&
(signum = getsignum(*argv + 4)) != -1) {
@@ -3282,7 +3304,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)) {
diff --git a/Src/exec.c b/Src/exec.c
index a439aec..6e4e99c 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5155,12 +5155,23 @@ loadautofn(Shfunc shf, int fksh, int autol)
{
int noalias = noaliases, ksh = 1;
Eprog prog;
- char *fname;
+ char *fname, **alt_path, *spec_path[2];
pushheap();
+ if (shf->filename && shf->filename[0] == '/')
+ {
+ spec_path[0] = dupstring(shf->filename);
+ spec_path[1] = NULL;
+ alt_path = spec_path;
+ }
+ else
+ {
+ alt_path = NULL;
+ }
+
noaliases = (shf->node.flags & PM_UNALIASED);
- prog = getfpfunc(shf->node.nam, &ksh, &fname);
+ prog = getfpfunc(shf->node.nam, &ksh, &fname, alt_path);
noaliases = noalias;
if (ksh == 1) {
@@ -5607,7 +5618,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
/**/
Eprog
-getfpfunc(char *s, int *ksh, char **fname)
+getfpfunc(char *s, int *ksh, char **fname, char **alt_path)
{
char **pp, buf[PATH_MAX+1];
off_t len;
@@ -5616,7 +5627,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;
diff --git a/Src/parse.c b/Src/parse.c
index 50a0d5f..38c6da2 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -3324,7 +3324,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)) ||
prog == &dummy_eprog) {
noaliases = ona;
zwarnnam(nam, "can't load function: %s", shf->node.nam);
diff --git a/Src/zsh.h b/Src/zsh.h
index f22d8b1..4fdd09a 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -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 */
Messages sorted by:
Reverse Date,
Date,
Thread,
Author