diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Doc/Zsh/mod_parameter.yo | 29 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 96 | ||||
-rw-r--r-- | Src/hashtable.c | 9 | ||||
-rw-r--r-- | Test/C04funcdef.ztst | 4 | ||||
-rw-r--r-- | Test/V06parameter.ztst | 27 |
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 |