Skip to content

Commit 34f70c5

Browse files
40440: Add $functions_source hash to zsh/parameter.
This allows you to find out where a function was loaded from.
1 parent ea7b4d4 commit 34f70c5

File tree

6 files changed

+162
-10
lines changed

6 files changed

+162
-10
lines changed

ChangeLog

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2017-01-28 Peter Stephenson <[email protected]>
2+
3+
* 40440: ../Doc/Zsh/mod_parameter.yo, Modules/parameter.c,
4+
hashtable.c, ../Test/C04funcdef.ztst, ../Test/V06parameter.ztst:
5+
Add $functions_source to zsh/parameter to help find where
6+
functions where loaded from.
7+
18
2017-01-27 Peter Stephenson <[email protected]>
29

310
* Zach Whaley: 40200: Completion/Unix/Command/_perforce: update

Doc/Zsh/mod_parameter.yo

+28-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,30 @@ vindex(dis_functions)
3737
item(tt(dis_functions))(
3838
Like tt(functions) but for disabled functions.
3939
)
40+
vindex(functions_source)
41+
item(tt(functions_source))(
42+
This readonly associative array maps names of enabled functions to the
43+
name of the file containing the source of the function.
44+
45+
For an autoloaded function that has already been loaded, or marked for
46+
autoload with an absolute path, or that has had its path resolved with
47+
`tt(functions -r)', this is the file found for autoloading, resolved
48+
to an absolute path.
49+
50+
For a function defined within the body of a script or sourced file,
51+
this is the name of that file. In this case, this is the exact path
52+
originally used to that file, which may be a relative path.
53+
54+
For any other function, including any defined at an interactive prompt or
55+
an autoload function whose path has not yet been resolved, this is
56+
the empty string. However, the hash element is reported as defined
57+
just so long as the function is present: the keys to this hash are
58+
the same as those to tt($funcions).
59+
)
60+
vindex(dis_functions_source)
61+
item(tt(dis_functions_source))(
62+
Like tt(functions_source) but for disabled functions.
63+
)
4064
vindex(builtins)
4165
item(tt(builtins))(
4266
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)'
202226
or `var(name) tt(LPAR()RPAR())' started. In the case of an autoloaded
203227
function the line number is reported as zero.
204228
The format of each element is var(filename)tt(:)var(lineno).
229+
205230
For functions autoloaded from a file in native zsh format, where only the
206231
body of the function occurs in the file, or for files that have been
207232
executed by the tt(source) or `tt(.)' builtins, the trace information is
208-
shown as var(filename)tt(:)var(0), since the entire file is the definition.
233+
shown as var(filename)tt(:)var(0), since the entire file is the
234+
definition. The source file name is resolved to an absolute path when
235+
the function is loaded or the path to it otherwise resolved.
209236

210237
Most users will be interested in the information in the
211238
tt(funcfiletrace) array instead.

Src/Modules/parameter.c

+96
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,98 @@ scanpmdisfunctions(HashTable ht, ScanFunc func, int flags)
515515
scanfunctions(ht, func, flags, DISABLED);
516516
}
517517

518+
/* Functions for the functions_source special parameter. */
519+
520+
/* Retrieve the source file for a function by explicit name */
521+
522+
/**/
523+
static HashNode
524+
getfunction_source(UNUSED(HashTable ht), const char *name, int dis)
525+
{
526+
Shfunc shf;
527+
Param pm = NULL;
528+
529+
pm = (Param) hcalloc(sizeof(struct param));
530+
pm->node.nam = dupstring(name);
531+
pm->node.flags = PM_SCALAR|PM_READONLY;
532+
pm->gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
533+
534+
if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
535+
(dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) {
536+
pm->u.str = getshfuncfile(shf);
537+
if (!pm->u.str)
538+
pm->u.str = dupstring("");
539+
}
540+
return &pm->node;
541+
}
542+
543+
/* Retrieve the source file for functions by scanning the table */
544+
545+
/**/
546+
static void
547+
scanfunctions_source(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
548+
{
549+
struct param pm;
550+
int i;
551+
HashNode hn;
552+
553+
memset((void *)&pm, 0, sizeof(struct param));
554+
pm.node.flags = PM_SCALAR|PM_READONLY;
555+
pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
556+
557+
for (i = 0; i < shfunctab->hsize; i++) {
558+
for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
559+
if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
560+
pm.node.nam = hn->nam;
561+
if (func != scancountparams &&
562+
((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
563+
!(flags & SCANPM_WANTKEYS))) {
564+
pm.u.str = getshfuncfile((Shfunc)hn);
565+
if (!pm.u.str)
566+
pm.u.str = dupstring("");
567+
}
568+
func(&pm.node, flags);
569+
}
570+
}
571+
}
572+
}
573+
574+
/* Param table entry for retrieving functions_source element */
575+
576+
/**/
577+
static HashNode
578+
getpmfunction_source(HashTable ht, const char *name)
579+
{
580+
return getfunction_source(ht, name, 0);
581+
}
582+
583+
/* Param table entry for retrieving ds_functions_source element */
584+
585+
/**/
586+
static HashNode
587+
getpmdisfunction_source(HashTable ht, const char *name)
588+
{
589+
return getfunction_source(ht, name, 1);
590+
}
591+
592+
/* Param table entry for scanning functions_source table */
593+
594+
/**/
595+
static void
596+
scanpmfunction_source(HashTable ht, ScanFunc func, int flags)
597+
{
598+
scanfunctions_source(ht, func, flags, 0);
599+
}
600+
601+
/* Param table entry for scanning dis_functions_source table */
602+
603+
/**/
604+
static void
605+
scanpmdisfunction_source(HashTable ht, ScanFunc func, int flags)
606+
{
607+
scanfunctions_source(ht, func, flags, 1);
608+
}
609+
518610
/* Functions for the funcstack special parameter. */
519611

520612
/**/
@@ -2095,6 +2187,8 @@ static struct paramdef partab[] = {
20952187
NULL, getpmdisbuiltin, scanpmdisbuiltins),
20962188
SPECIALPMDEF("dis_functions", 0,
20972189
&pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
2190+
SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL,
2191+
getpmdisfunction_source, scanpmdisfunction_source),
20982192
SPECIALPMDEF("dis_galiases", 0,
20992193
&pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
21002194
SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY,
@@ -2111,6 +2205,8 @@ static struct paramdef partab[] = {
21112205
&funcstack_gsu, NULL, NULL),
21122206
SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
21132207
scanpmfunctions),
2208+
SPECIALPMDEF("functions_source", PM_READONLY, NULL,
2209+
getpmfunction_source, scanpmfunction_source),
21142210
SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
21152211
&functrace_gsu, NULL, NULL),
21162212
SPECIALPMDEF("galiases", 0,

Src/hashtable.c

+9
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,15 @@ dircache_set(char **name, char *value)
15651565
zsfree(*name);
15661566
*name = NULL;
15671567
} else {
1568+
/*
1569+
* As the function path has been resolved to a particular
1570+
* location, we'll store it as an absolute path.
1571+
*/
1572+
if (*value != '/') {
1573+
value = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP),
1574+
"/", value);
1575+
value = xsymlink(value, 1);
1576+
}
15681577
/*
15691578
* We'll maintain the cache at exactly the right size rather
15701579
* than overallocating. The rationale here is that typically

Test/C04funcdef.ztst

+2-2
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,10 @@
325325
printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops
326326
autoload oops
327327
oops
328-
whence -v oops
328+
whence -v oops | sed -e "s%$PWD%CURDIR%"
329329
)
330330
0:whence -v of zsh-style autoload
331-
>oops is a shell function from ./oops
331+
>oops is a shell function from CURDIR/oops
332332

333333
(
334334
fpath=(.)

Test/V06parameter.ztst

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
%test
22

33
print 'print In sourced file
4-
print $LINENO + $functrace + $funcsourcetrace
4+
print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
55
' >sourcedfile
66
print -r -- 'print Started functrace.zsh
77
module_path=(./Modules)
8-
print $LINENO + $functrace + $funcsourcetrace
8+
print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
99
:
1010
fn() {
1111
print Inside function $0
12-
print $LINENO + $functrace + $funcsourcetrace
12+
print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
1313
}
1414
:
1515
fn
1616
:
1717
fpath=(. $fpath)
1818
:
1919
echo '\''print Inside $0
20-
print $LINENO + $functrace + $funcsourcetrace
20+
print $LINENO + $functrace + ${funcsourcetrace/#$PWD/CURDIR}
2121
'\'' >autofn
2222
:
2323
autoload autofn
@@ -32,9 +32,9 @@
3232
>Inside function fn
3333
>2 + ./functrace.zsh:10 + ./functrace.zsh:5
3434
>Inside autofn
35-
>2 + ./functrace.zsh:20 + ./autofn:0
35+
>2 + ./functrace.zsh:20 + CURDIR/autofn:0
3636
>Inside autofn
37-
>2 + ./functrace.zsh:21 + ./autofn:0
37+
>2 + ./functrace.zsh:21 + CURDIR/autofn:0
3838
>In sourced file
3939
>2 + ./functrace.zsh:22 + ./sourcedfile:0
4040

@@ -66,6 +66,19 @@
6666
>./rocky3.zsh:13 (eval):2
6767
>./rocky3.zsh:14 ./rocky3.zsh:14
6868

69+
(
70+
fpath=($PWD)
71+
print "print I have been autoloaded" >myfunc
72+
autoload $PWD/myfunc
73+
print ${functions_source[myfunc]/#$PWD/CURDIR}
74+
myfunc
75+
print ${functions_source[myfunc]/#$PWD/CURDIR}
76+
)
77+
0: $functions_source
78+
>CURDIR/myfunc
79+
>I have been autoloaded
80+
>CURDIR/myfunc
81+
6982
%clean
7083

71-
rm -f autofn functrace.zsh rocky3.zsh sourcedfile
84+
rm -f autofn functrace.zsh rocky3.zsh sourcedfile myfunc

0 commit comments

Comments
 (0)