summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/builtin.c173
-rw-r--r--Src/exec.c44
-rw-r--r--Src/hashtable.c8
-rw-r--r--Src/parse.c24
-rw-r--r--Src/zsh.h5
5 files changed, 187 insertions, 67 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 0f04d149f..78d67ca8e 100644
--- a/Src/builtin.c
+++ b/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) {
- int ret = 0;
-
+ 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();
- 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;
- }
+ 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;
+ }
+ 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 {
- 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);
+ shf = (Shfunc) zshcalloc(sizeof *shf);
+ shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
}
- } else {
- if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
+ 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_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;
diff --git a/Src/exec.c b/Src/exec.c
index a439aec7f..a41d05b41 100644
--- a/Src/exec.c
+++ b/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 *
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 7c3367568..2a8b58535 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -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);
diff --git a/Src/parse.c b/Src/parse.c
index ed6c4a8dd..314cc09d3 100644
--- a/Src/parse.c
+++ b/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);
diff --git a/Src/zsh.h b/Src/zsh.h
index 2a41638db..67c5a3587 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 */
@@ -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 */