zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: 3.1.6-bart-7: Self-loading auto-functions
@ 1999-10-25  9:31 Bart Schaefer
  1999-10-25  9:46 ` Bart Schaefer
  1999-10-25 17:48 ` Oliver Kiddle
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Schaefer @ 1999-10-25  9:31 UTC (permalink / raw)
  To: zsh-workers

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


^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: PATCH: 3.1.6-bart-7: Self-loading auto-functions
@ 1999-10-25  9:53 Sven Wischnowsky
  1999-10-25 10:27 ` Zefram
  0 siblings, 1 reply; 7+ messages in thread
From: Sven Wischnowsky @ 1999-10-25  9:53 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> 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.

I've fiddled with `parameter.c' a lot over the weekend, adding
parameters for the `compgen'-replacement. There I made `functions'
prepend a `<disabled>' prefix to report disabled shell functions (and
the same string in other parameters). I was thinking about using
comments, too, and I still think they are ok for functions, but in my
case I needed something that also worked for aliases -- and I hope
`<disabled>' is uncommen enough to be usable there.

> ...
> 
> 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.

There were some other problems. E.g. the strings stored in the pparam
struct should all be dupstring()ed (because the new pattern matching
code may try to store the trailing '\0' again). Also, they shouldn't
be tricat()ed, because that uses zalloc()ed memory which isn't freed
anywhere.

Since my code is currently far too different from anyone else's, I
don't send a patch for it now, it'll come together with the completion 
code stuff.

While I'm at it: does anyone have an idea how we can make the
parameter module report stuff about zle widgets and keymaps? I don't
see a solution (other than making parameter depend on zle which I
don't want to do). So in the first implementation at least, parameters 
for them will be in the zle module. Sigh.

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: PATCH: 3.1.6-bart-7: Self-loading auto-functions
@ 1999-10-25 10:40 Sven Wischnowsky
  0 siblings, 0 replies; 7+ messages in thread
From: Sven Wischnowsky @ 1999-10-25 10:40 UTC (permalink / raw)
  To: zsh-workers


Zefram wrote:

> Sven Wischnowsky wrote:
> >While I'm at it: does anyone have an idea how we can make the
> >parameter module report stuff about zle widgets and keymaps? I don't
> >see a solution (other than making parameter depend on zle which I
> >don't want to do). So in the first implementation at least, parameters 
> >for them will be in the zle module. Sigh.
> 
> Logically, there should be a separate module for ZLE-related parameters,
> dependent on the ZLE module.

Yep, it's just that currently I'm planning only two of them (for
widgets and keymap-names). But then maybe someone would like to add a
real parameter-interface for setting keymaps. Hm, that may actually be 
useful...

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~1999-10-25 20:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-10-25  9:31 PATCH: 3.1.6-bart-7: Self-loading auto-functions Bart Schaefer
1999-10-25  9:46 ` Bart Schaefer
1999-10-25 17:48 ` Oliver Kiddle
1999-10-25 20:32   ` Bart Schaefer
1999-10-25  9:53 Sven Wischnowsky
1999-10-25 10:27 ` Zefram
1999-10-25 10:40 Sven Wischnowsky

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).