summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <p.w.stephenson@ntlworld.com>2017-01-28 19:33:27 +0000
committerPeter Stephenson <p.w.stephenson@ntlworld.com>2017-01-28 19:33:27 +0000
commit34f70c5dc08bbecd20fbb8a1797851103fbad45e (patch)
tree5170a04f299804c871a9c6ba913d5d07bfa576b2
parentea7b4d4b2da60fe44019b1c0e298a202a3b211b7 (diff)
downloadzsh-34f70c5dc08bbecd20fbb8a1797851103fbad45e.tar.gz
zsh-34f70c5dc08bbecd20fbb8a1797851103fbad45e.tar.xz
zsh-34f70c5dc08bbecd20fbb8a1797851103fbad45e.zip
40440: Add $functions_source hash to zsh/parameter.
This allows you to find out where a function was loaded from.
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/mod_parameter.yo29
-rw-r--r--Src/Modules/parameter.c96
-rw-r--r--Src/hashtable.c9
-rw-r--r--Test/C04funcdef.ztst4
-rw-r--r--Test/V06parameter.ztst27
6 files changed, 162 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 126287cdc..021be2f94 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2017-01-28  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 40440: ../Doc/Zsh/mod_parameter.yo, Modules/parameter.c,
+	hashtable.c, ../Test/C04funcdef.ztst, ../Test/V06parameter.ztst:
+	Add $functions_source to zsh/parameter to help find where
+	functions where loaded from.
+
 2017-01-27  Peter Stephenson  <p.stephenson@samsung.com>
 
 	* Zach Whaley: 40200: Completion/Unix/Command/_perforce: update
diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index 3d260f8e9..942e4c5b6 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -37,6 +37,30 @@ vindex(dis_functions)
 item(tt(dis_functions))(
 Like tt(functions) but for disabled functions.
 )
+vindex(functions_source)
+item(tt(functions_source))(
+This readonly associative array maps names of enabled functions to the
+name of the file containing the source of the function.
+
+For an autoloaded function that has already been loaded, or marked for
+autoload with an absolute path, or that has had its path resolved with
+`tt(functions -r)', this is the file found for autoloading, resolved
+to an absolute path.
+
+For a function defined within the body of a script or sourced file,
+this is the name of that file.  In this case, this is the exact path
+originally used to that file, which may be a relative path.
+
+For any other function, including any defined at an interactive prompt or
+an autoload function whose path has not yet been resolved, this is
+the empty string.  However, the hash element is reported as defined
+just so long as the function is present:  the keys to this hash are
+the same as those to tt($funcions).
+)
+vindex(dis_functions_source)
+item(tt(dis_functions_source))(
+Like tt(functions_source) but for disabled functions.
+)
 vindex(builtins)
 item(tt(builtins))(
 This associative array gives information about the builtin commands
@@ -202,10 +226,13 @@ defined.  The line number is the line where the `tt(function) var(name)'
 or `var(name) tt(LPAR()RPAR())' started.  In the case of an autoloaded
 function  the line number is reported as zero.
 The format of each element is var(filename)tt(:)var(lineno).
+
 For functions autoloaded from a file in native zsh format, where only the
 body of the function occurs in the file, or for files that have been
 executed by the tt(source) or `tt(.)' builtins, the trace information is
-shown as var(filename)tt(:)var(0), since the entire file is the definition.
+shown as var(filename)tt(:)var(0), since the entire file is the
+definition.  The source file name is resolved to an absolute path when
+the function is loaded or the path to it otherwise resolved.
 
 Most users will be interested in the information in the
 tt(funcfiletrace) array instead.
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 98bcaba6e..6e6228732 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -515,6 +515,98 @@ scanpmdisfunctions(HashTable ht, ScanFunc func, int flags)
     scanfunctions(ht, func, flags, DISABLED);
 }
 
+/* Functions for the functions_source special parameter. */
+
+/* Retrieve the source file for a function by explicit name */
+
+/**/
+static HashNode
+getfunction_source(UNUSED(HashTable ht), const char *name, int dis)
+{
+    Shfunc shf;
+    Param pm = NULL;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR|PM_READONLY;
+    pm->gsu.s = dis ? &pmdisfunction_gsu :  &pmfunction_gsu;
+
+    if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
+	(dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) {
+	pm->u.str = getshfuncfile(shf);
+	if (!pm->u.str)
+	    pm->u.str = dupstring("");
+    }
+    return &pm->node;
+}
+
+/* Retrieve the source file for functions by scanning the table */
+
+/**/
+static void
+scanfunctions_source(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.node.flags = PM_SCALAR|PM_READONLY;
+    pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
+
+    for (i = 0; i < shfunctab->hsize; i++) {
+	for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
+	    if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
+		pm.node.nam = hn->nam;
+		if (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS))) {
+		    pm.u.str = getshfuncfile((Shfunc)hn);
+		    if (!pm.u.str)
+			pm.u.str = dupstring("");
+		}
+		func(&pm.node, flags);
+	    }
+	}
+    }
+}
+
+/* Param table entry for retrieving functions_source element */
+
+/**/
+static HashNode
+getpmfunction_source(HashTable ht, const char *name)
+{
+    return getfunction_source(ht, name, 0);
+}
+
+/* Param table entry for retrieving ds_functions_source element */
+
+/**/
+static HashNode
+getpmdisfunction_source(HashTable ht, const char *name)
+{
+    return getfunction_source(ht, name, 1);
+}
+
+/* Param table entry for scanning functions_source table */
+
+/**/
+static void
+scanpmfunction_source(HashTable ht, ScanFunc func, int flags)
+{
+    scanfunctions_source(ht, func, flags, 0);
+}
+
+/* Param table entry for scanning dis_functions_source table */
+
+/**/
+static void
+scanpmdisfunction_source(HashTable ht, ScanFunc func, int flags)
+{
+    scanfunctions_source(ht, func, flags, 1);
+}
+
 /* Functions for the funcstack special parameter. */
 
 /**/
@@ -2095,6 +2187,8 @@ static struct paramdef partab[] = {
 	    NULL, getpmdisbuiltin, scanpmdisbuiltins),
     SPECIALPMDEF("dis_functions", 0, 
 	    &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
+    SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL,
+		 getpmdisfunction_source, scanpmdisfunction_source),
     SPECIALPMDEF("dis_galiases", 0,
 	    &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
     SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY,
@@ -2111,6 +2205,8 @@ static struct paramdef partab[] = {
 	    &funcstack_gsu, NULL, NULL),
     SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
 		 scanpmfunctions),
+    SPECIALPMDEF("functions_source", PM_READONLY, NULL,
+		 getpmfunction_source, scanpmfunction_source),
     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
 	    &functrace_gsu, NULL, NULL),
     SPECIALPMDEF("galiases", 0,
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 1f2789d07..8987c8597 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -1566,6 +1566,15 @@ dircache_set(char **name, char *value)
 	*name = NULL;
     } else {
 	/*
+	 * As the function path has been resolved to a particular
+	 * location, we'll store it as an absolute path.
+	 */
+	if (*value != '/') {
+	    value = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP),
+			     "/", value);
+	    value = xsymlink(value, 1);
+	}
+	/*
 	 * We'll maintain the cache at exactly the right size rather
 	 * than overallocating.  The rationale here is that typically
 	 * we'll get a lot of functions in a small number of directories
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
index 5edbe26bb..176841dd2 100644
--- a/Test/C04funcdef.ztst
+++ b/Test/C04funcdef.ztst
@@ -325,10 +325,10 @@
     printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops
     autoload oops
     oops
-    whence -v oops
+    whence -v oops | sed -e "s%$PWD%CURDIR%"
   )
 0:whence -v of zsh-style autoload
->oops is a shell function from ./oops
+>oops is a shell function from CURDIR/oops
 
   (
     fpath=(.)
diff --git a/Test/V06parameter.ztst b/Test/V06parameter.ztst
index c7df35dce..c2a2a4da5 100644
--- a/Test/V06parameter.ztst
+++ b/Test/V06parameter.ztst
@@ -1,15 +1,15 @@
 %test
 
   print 'print In sourced file
-  print $LINENO + $functrace + $funcsourcetrace
+  print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
   ' >sourcedfile
   print -r -- 'print Started functrace.zsh
   module_path=(./Modules)
-  print $LINENO + $functrace + $funcsourcetrace
+  print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
   :
   fn() {
     print Inside function $0
-    print $LINENO + $functrace + $funcsourcetrace
+    print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
   }
   :
   fn
@@ -17,7 +17,7 @@
   fpath=(. $fpath)
   :
   echo '\''print Inside $0
-    print $LINENO + $functrace + $funcsourcetrace
+    print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
   '\'' >autofn
   :
   autoload autofn
@@ -32,9 +32,9 @@
 >Inside function fn
 >2 + ./functrace.zsh:10 + ./functrace.zsh:5
 >Inside autofn
->2 + ./functrace.zsh:20 + ./autofn:0
+>2 + ./functrace.zsh:20 + CURDIR/autofn:0
 >Inside autofn
->2 + ./functrace.zsh:21 + ./autofn:0
+>2 + ./functrace.zsh:21 + CURDIR/autofn:0
 >In sourced file
 >2 + ./functrace.zsh:22 + ./sourcedfile:0
 
@@ -66,6 +66,19 @@
 >./rocky3.zsh:13 (eval):2
 >./rocky3.zsh:14 ./rocky3.zsh:14
 
+  (
+    fpath=($PWD)
+    print "print I have been autoloaded" >myfunc
+    autoload $PWD/myfunc
+    print ${functions_source[myfunc]/#$PWD/CURDIR}
+    myfunc
+    print ${functions_source[myfunc]/#$PWD/CURDIR}
+  )
+0: $functions_source
+>CURDIR/myfunc
+>I have been autoloaded
+>CURDIR/myfunc
+
 %clean
 
- rm -f autofn functrace.zsh rocky3.zsh sourcedfile
+ rm -f autofn functrace.zsh rocky3.zsh sourcedfile myfunc