Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: 3.1.6-bart-7: Self-loading auto-functions
- X-seq: zsh-workers 8404
- From: "Bart Schaefer" <schaefer@xxxxxxxxxxxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxx
- Subject: PATCH: 3.1.6-bart-7: Self-loading auto-functions
- Date: Mon, 25 Oct 1999 09:31:46 +0000
- Mailing-list: contact zsh-workers-help@xxxxxxxxxxxxxx; run by ezmlm
The first hunk of added text in the builtins.yo diff explains this pretty
completely. There may be a more elegant way to implement it than the way
I did, but it was pretty straightforward this way.
One change that may be controversial is the output of "functions". As was
mentioned in the exchange I had with Zefram, it no longer puts "undefined"
in front of an autoloaded function name. In the course of changing that,
I found that it might also output "traced" in that position, which for the
purposes of making `eval $(functions)' work was equally annoying. Further,
it might be useful to differentiate an actual autoloaded function from one
that merely calls "autoload -X".
So it now outputs comments like this:
foo() {
# undefined
# traced
builtin autoload -X
}
The comments use the user's $histchars[2], and you can tell a defined
function from an undefined one because of course defined functions always
have their comments stripped. If anyone has a better idea for this, I'd
be glad to see it changed.
Note that saving/restoring the value of the $functions special parameter
(from `zmodload parameter') has the side-effect of converting undefined
functions into functions defined to call autoload -X. Oh, well.
There's one partial bug fix in the paramter.c diff below: Unloading the
module would dump core when trying to unset the $dirstack parameter. The
remaining badness after the patch is that the dirstack gets erased as a
side-effect of unloading the module, but at 2:15 AM I didn't feel like
tackling that part.
Index: Doc/Zsh/builtins.yo
===================================================================
@@ -71,7 +71,24 @@
findex(autoload)
cindex(functions, autoloading)
cindex(autoloading functions)
-alias(autoload)(functions -u)
+item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(UXmt) ] [ var(name) ... ])(
+Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X).
+
+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.
+
+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
+function was not previously defined em(and) a definition for it was found.
+This does em(not) replace any existing definition of the function. The
+exit status is nonzero (failure) if the function was already defined or
+when no definition was found. In the latter case the function remains
+undefined and marked for autoloading.
+)
findex(bg)
cindex(jobs, backgrounding)
xitem(tt(bg) [ var(job) ... ])
@@ -353,7 +370,7 @@
point numbers are not permitted.
)
findex(functions)
-item(tt(functions) [ {tt(PLUS())|tt(-)}tt(tum) ] [ var(name) ... ])(
+item(tt(functions) [ {tt(PLUS())|tt(-)}tt(UXmtu) ] [ var(name) ... ])(
Equivalent to tt(typeset -f).
)
findex(getln)
@@ -1028,6 +1045,7 @@
For arrays (but not for associative arrays), keep only the first
occurrence of each duplicated value. This may also be set for
colon-separated special parameters like tt(PATH) or tt(FIGNORE), etc.
+This flag has a different meaning when used with tt(-f); see below.
)
item(tt(-Z))(
Right justify and fill with leading zeros if the first non-blank
@@ -1044,8 +1062,8 @@
)
item(tt(-f))(
The names refer to functions rather than parameters. No assignments
-can be made, and the only other valid flags are tt(-t), tt(-u) and
-tt(-U). The flag tt(-t) turns on execution tracing for this
+can be made, and the only other valid flags are tt(-t), tt(-u), tt(-U),
+tt(-X) and tt(+X). The flag tt(-t) turns on execution tracing for this
function. The tt(-u) and tt(-U) flags cause the function to be
marked for autoloading; tt(-U) also causes alias expansion to be
suppressed when the function is loaded. The tt(fpath) parameter
@@ -1096,10 +1114,12 @@
)
item(tt(-t))(
Tags the named parameters. Tags have no special meaning to the shell.
+This flag has a different meaning when used with tt(-f); see above.
)
item(tt(-u))(
Convert the result to upper case whenever the parameter is expanded.
The value is em(not) converted when assigned.
+This flag has a different meaning when used with tt(-f); see above.
)
item(tt(-x))(
Mark for automatic export to the environment of subsequently
Index: Doc/Zsh/func.yo
===================================================================
@@ -74,6 +74,29 @@
the initialization message on the first call, and the other message on the
second and subsequent calls.
+It is also possible to create a function that is not marked autoloaded,
+yet loads its own definition by searching tt(fpath): `tt(autoload -X)',
+when called from within a shell function tt(myfunc), is equivalent to:
+
+example(unfunction myfunc
+autoload myfunc
+myfunc "$@")
+
+In fact, the tt(functions) command outputs `tt(builtin autoload -X)' as
+the body of an autoloaded function. A true autoloaded function can be
+identifed by the presence of the comment `tt(# undefined)' in the body,
+because all comments are discarded from defined functions. This is done
+so that
+
+example(eval "$(functions)")
+
+produces a reasonable result.
+
+To load the definition of an autoloaded function tt(myfunc) without
+executing tt(myfunc), use:
+
+example(autoload +X myfunc)
+
sect(Special Functions)
The following functions, if defined, have special meaning to
the shell:
Index: Src/builtin.c
===================================================================
@@ -43,7 +43,7 @@
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, "Lgmr", NULL),
- BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tU", "u"),
+ BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tUX", "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),
@@ -1998,6 +1998,29 @@
return returnval;
}
+/* Helper for bin_functions() when run as "autoload -X" */
+
+static int
+eval_autoload(Shfunc shf, char *name, char *ops, int func)
+{
+ if (!(shf->flags & PM_UNDEFINED))
+ return 1;
+
+ if (shf->funcdef)
+ freestruct(shf->funcdef);
+
+ if (ops['X'] == 1) {
+ char *fargv[3];
+ fargv[0] = name;
+ fargv[1] = "\"$@\"";
+ fargv[2] = 0;
+ shf->funcdef = mkautofn(shf);
+ return bin_eval(name, fargv, ops, func);
+ }
+
+ return loadautofn(shf);
+}
+
/* Display or change the attributes of shell functions. *
* If called as autoload, it will define a new autoloaded *
* (undefined) shell function. */
@@ -2012,10 +2035,10 @@
int on = 0, off = 0, pflags = 0;
/* Do we have any flags defined? */
- if (ops['u'] == 1)
- on |= PM_UNDEFINED;
- else if (ops['u'] == 2)
+ if (ops['u'] == 2)
off |= PM_UNDEFINED;
+ else if (ops['u'] == 1 || ops['X'])
+ on |= PM_UNDEFINED;
if (ops['U'] == 1)
on |= PM_UNALIASED|PM_UNDEFINED;
else if (ops['U'] == 2)
@@ -2025,7 +2048,8 @@
else if (ops['t'] == 2)
off |= PM_TAGGED;
- if (off & PM_UNDEFINED) {
+ if ((off & PM_UNDEFINED) ||
+ (ops['X'] == 1 && (ops['m'] || *argv || !scriptname))) {
zwarnnam(name, "invalid option(s)", NULL, 0);
return 1;
}
@@ -2037,10 +2061,22 @@
* are given, we will print only functions containing these *
* flags, else we'll print them all. */
if (!*argv) {
- if (ops['U'] && !ops['u'])
- on &= ~PM_UNDEFINED;
- scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
- pflags);
+ if (ops['X'] == 1) {
+ if ((shf = (Shfunc) shfunctab->getnode(shfunctab, scriptname))) {
+ DPUTS(!shf->funcdef,
+ "BUG: Calling autoload from empty function");
+ } else {
+ shf = (Shfunc) zcalloc(sizeof *shf);
+ shfunctab->addnode(shfunctab, ztrdup(scriptname), shf);
+ }
+ shf->flags = on;
+ return eval_autoload(shf, scriptname, ops, func);
+ } else {
+ if (ops['U'] && !ops['u'])
+ on &= ~PM_UNDEFINED;
+ scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
+ pflags);
+ }
return 0;
}
@@ -2061,8 +2097,14 @@
for (shf = (Shfunc) shfunctab->nodes[i]; shf;
shf = (Shfunc) shf->next)
if (pattry(pprog, shf->nam) &&
- !(shf->flags & DISABLED))
- shf->flags = (shf->flags | on) & (~off);
+ !(shf->flags & DISABLED)) {
+ shf->flags = (shf->flags |
+ (on & ~PM_UNDEFINED)) & ~off;
+ if (ops['X'] &&
+ eval_autoload(shf, shf->nam, ops, func)) {
+ returnval = 1;
+ }
+ }
}
}
} else {
@@ -2078,10 +2120,12 @@
for (; *argv; argv++) {
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) {
/* if any flag was given */
- if (on|off)
+ if (on|off) {
/* turn on/off the given flags */
shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off;
- else
+ if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
+ returnval = 1;
+ } else
/* no flags, so just print */
shfunctab->printnode((HashNode) shf, pflags);
} else if (on & PM_UNDEFINED) {
@@ -2091,6 +2135,8 @@
shf->flags = on;
shf->funcdef = mkautofn(shf);
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
+ if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
+ returnval = 1;
} else
returnval = 1;
}
Index: Src/exec.c
===================================================================
@@ -2911,11 +2911,11 @@
l = getfpfunc(shf->nam);
noaliases = noalias;
- if(l == &dummy_list) {
+ if (l == &dummy_list) {
zerr("%s: function definition file not found", shf->nam, 0);
return 1;
}
- if(isset(KSHAUTOLOAD)) {
+ if (isset(KSHAUTOLOAD)) {
VARARR(char, n, strlen(shf->nam) + 1);
strcpy(n, shf->nam);
execlist(l, 1, 0);
@@ -2933,6 +2933,31 @@
}
execlist(shf->funcdef, 1, 0);
return lastval;
+}
+
+/**/
+int
+loadautofn(Shfunc shf)
+{
+ /* Copied from execautofn() -- should consolidate someday */
+
+ int noalias = noaliases;
+ List l;
+
+ noaliases = (shf->flags & PM_UNALIASED);
+ l = getfpfunc(shf->nam);
+ noaliases = noalias;
+
+ if (l == &dummy_list) {
+ zerr("%s: function definition file not found", shf->nam, 0);
+ return 1;
+ }
+ PERMALLOC {
+ shf->funcdef = dupstruct(stripkshdef(l, shf->nam));
+ } LASTALLOC;
+ shf->flags &= ~PM_UNDEFINED;
+
+ return 0;
}
/* execute a shell function */
Index: Src/hashtable.c
===================================================================
@@ -872,21 +872,29 @@
}
if (f->flags & PM_UNDEFINED)
- printf("undefined ");
- if (f->flags & PM_TAGGED)
- printf("traced ");
- if ((f->flags & PM_UNDEFINED) || !f->funcdef) {
- nicezputs(f->nam, stdout);
- printf(" () { }\n");
- return;
+ t = tricat("builtin autoload -X",
+ ((f->flags & PM_UNALIASED)? "U" : ""),
+ ((f->flags & PM_TAGGED)? "t" : ""));
+ else {
+ if (!f->funcdef)
+ t = 0;
+ else
+ t = getpermtext((void *) f->funcdef);
}
-
- t = getpermtext((void *) f->funcdef);
+
quotedzputs(f->nam, stdout);
- printf(" () {\n\t");
- zputs(t, stdout);
- printf("\n}\n");
- zsfree(t);
+ if (t) {
+ printf(" () {\n\t");
+ if (f->flags & PM_UNDEFINED)
+ printf("%c undefined\n\t", hashchar);
+ if (f->flags & PM_TAGGED)
+ printf("%c traced\n\t", hashchar);
+ zputs(t, stdout);
+ printf("\n}\n");
+ zsfree(t);
+ } else {
+ printf(" () { }\n");
+ }
}
/**************************************/
Index: Src/Modules/parameter.c
===================================================================
@@ -424,7 +424,9 @@
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, name))) {
if (shf->flags & PM_UNDEFINED)
- pm->u.str = "undefined";
+ pm->u.str = tricat("builtin autoload -X",
+ ((shf->flags & PM_UNALIASED)? "U" : ""),
+ ((shf->flags & PM_TAGGED)? "t" : ""));
else {
char *t = getpermtext((void *) dupstruct((void *)
shf->funcdef)), *h;
@@ -467,9 +469,12 @@
if (!(hn->flags & DISABLED)) {
pm.nam = hn->nam;
if (func != scancountparams) {
- if (((Shfunc) hn)->flags & PM_UNDEFINED)
- pm.u.str = "undefined";
- else {
+ if (((Shfunc) hn)->flags & PM_UNDEFINED) {
+ Shfunc shf = (Shfunc) hn;
+ pm.u.str = tricat("builtin autoload -X",
+ ((shf->flags & PM_UNALIASED)? "U" : ""),
+ ((shf->flags & PM_TAGGED)? "t" : ""));
+ } else {
char *t = getpermtext((void *)
dupstruct((void *) ((Shfunc) hn)->funcdef));
@@ -779,7 +784,7 @@
PERMALLOC {
freelinklist(dirstack, freestr);
dirstack = newlinklist();
- while (*x)
+ while (x && *x)
addlinknode(dirstack, ztrdup(*x++));
} LASTALLOC;
}
--
Bart Schaefer Brass Lantern Enterprises
http://www.well.com/user/barts http://www.brasslantern.com
Messages sorted by:
Reverse Date,
Date,
Thread,
Author