From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22871 invoked by alias); 11 Dec 2016 22:18:53 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 40159 Received: (qmail 7277 invoked from network); 11 Dec 2016 22:18:53 -0000 X-Qmail-Scanner-Diagnostics: from know-smtprelay-omc-2.server.virginmedia.net by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.99.2/21882. spamassassin: 3.4.1. Clear:RC:0(80.0.253.66):SA:0(-0.0/5.0):. Processed in 1.371454 secs); 11 Dec 2016 22:18:53 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.1 X-Envelope-From: p.w.stephenson@ntlworld.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _smtprelay.virginmedia.com designates 80.0.253.66 as permitted sender) X-Originating-IP: [86.21.219.59] X-Spam: 0 X-Authority: v=2.1 cv=Ya9AnFlf c=1 sm=1 tr=0 a=utowdAHh8RITBM/6U1BPxA==:117 a=utowdAHh8RITBM/6U1BPxA==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=kj9zAlcOel0A:10 a=vo3ViOnWhzVPu3c56gcA:9 a=CjuIK1q_8ugA:10 Date: Sun, 11 Dec 2016 22:18:44 +0000 From: Peter Stephenson To: Zsh hackers list Subject: PATH: autoload with explicit path Message-ID: <20161211221844.5e51affe@ntlworld.com> X-Mailer: Claws Mail 3.11.1 (GTK+ 2.24.28; x86_64-redhat-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit 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 */