ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Devel-FindRef/FindRef.pm
(Generate patch)

Comparing Devel-FindRef/FindRef.pm (file contents):
Revision 1.7 by root, Mon Apr 30 21:08:14 2007 UTC vs.
Revision 1.15 by root, Sat Jul 19 01:38:57 2008 UTC

1package Devel::FindRef; 1package Devel::FindRef;
2 2
3no warnings; # I hate warning nazis
3use strict; 4use strict;
4 5
5use XSLoader; 6use XSLoader;
6 7use Scalar::Util;
7 8
8BEGIN { 9BEGIN {
9 our $VERSION = '0.2'; 10 our $VERSION = '1.31';
10 XSLoader::load __PACKAGE__, $VERSION; 11 XSLoader::load __PACKAGE__, $VERSION;
11} 12}
12 13
13=head1 NAME 14=head1 NAME
14 15
15Devel::FindRef - where is that reference to my scalar hiding? 16Devel::FindRef - where is that reference to my variable hiding?
16 17
17=head1 SYNOPSIS 18=head1 SYNOPSIS
18 19
19 use Devel::FindRef; 20 use Devel::FindRef;
20 21
45 testsub; 46 testsub;
46 47
47The output is as follows (or similar to this, in case I forget to update 48The output is as follows (or similar to this, in case I forget to update
48the manpage after some changes): 49the manpage after some changes):
49 50
50 SCALAR(0x676fa0) is 51 SCALAR(0x814ece8) is
52 +- in the global $Test::var.
51 referenced by REF(0x676fb0), which is 53 +- referenced by REF(0x814f9e4), which is
52 in the lexical '$x' in CODE(0x676370), which is 54 | in the lexical '$x' in CODE(0x814ed78), which is
53 not found anywhere I looked :( 55 | the containing scope for CODE(0x820c4b0), which is
56 | in the global &Test::testsub.
54 referenced by REF(0x676360), which is 57 +- referenced by REF(0x814ed6c), which is
55 in the member 'ukukey' of HASH(0x756660), which is 58 | in the member 'ukukey' of HASH(0x81da20c), which is
56 in the global %Test::hash. 59 | in the global %Test::hash.
57 in the global $Test::var.
58 referenced by REF(0x6760e0), which is 60 +- referenced by REF(0x814ec28), which is
61 | not found anywhere I looked :(
62 +- referenced by REF(0x814eb44), which is
59 in the member 'ukukey2' of HASH(0x676f30), which is 63 in the member 'ukukey2' of HASH(0x814f99c), which is
60 referenced by REF(0x77bcf0), which is 64 +- referenced by REF(0x820c450), which is
61 in the lexical '$local' in CODE(0x77bcb0), which is 65 | in the lexical '$local' in CODE(0x820c4b0), which was seen before.
62 in the global &Test::testsub.
63 referenced by REF(0x77bc80), which is 66 +- referenced by REF(0x820c204), which is
64 in the global $Test::hash2. 67 in the global $Test::hash2.
65
66 68
67It is a bit convoluted to read, but basically it says that the value 69It is a bit convoluted to read, but basically it says that the value
68stored in C<$var> can be found: 70stored in C<$var> can be found:
69 71
70=over 4 72=over 4
101=cut 103=cut
102 104
103sub find($); 105sub find($);
104 106
105sub track { 107sub track {
108 my ($ref, $depth) = @_;
109 @_ = ();
110
106 my $buf = ""; 111 my $buf = "";
107 my %ignore; 112 my %seen;
113
114 Scalar::Util::weaken $ref;
108 115
109 my $track; $track = sub { 116 my $track; $track = sub {
110 my ($target, $depth, $indent) = @_; 117 my ($refref, $depth, $indent) = @_;
111 @_ = ();
112 local $ignore{$target+0} = undef;
113 118
114 if ($depth) { 119 if ($depth) {
115 my (@about) = grep !exists $ignore{$_->[1]}, find $target; 120 my (@about) = find $$refref;
116 if (@about) { 121 if (@about) {
117 local @ignore{map $_->[1]+0, @about} = ();
118 for my $about (@about) { 122 for my $about (@about) {
119 local $ignore{$about+0} = undef; 123 $buf .= "$indent" . (@about > 1 ? "+- " : " ") . $about->[0];
120 $buf .= (" ") x $indent;
121 $buf .= $about->[0];
122 if (@$about > 1) { 124 if (@$about > 1) {
125 if ($seen{ref2ptr $about->[1]}++) {
126 $buf .= " $about->[1], which was seen before.\n";
127 } else {
123 $buf .= " $about->[1], which is\n"; 128 $buf .= " $about->[1], which is\n";
124 $track->($about->[1], $depth - 1, $indent + 1); 129 $track->(\$about->[1], $depth - 1, $about == $about[-1] ? "$indent " : "$indent| ");
130 }
125 } else { 131 } else {
126 $buf .= ".\n"; 132 $buf .= ".\n";
127 } 133 }
128 } 134 }
129 } else { 135 } else {
130 $buf .= (" ") x $indent;
131 $buf .= "not found anywhere I looked :(\n"; 136 $buf .= "$indent not found anywhere I looked :(\n";
132 } 137 }
133 } else { 138 } else {
134 $buf .= (" ") x $indent;
135 $buf .= "not referenced within the search depth.\n"; 139 $buf .= "$indent not referenced within the search depth.\n";
136 } 140 }
137 }; 141 };
138 142
139 $buf .= "$_[0] is\n"; 143 $buf .= "$ref is\n";
140 $track->($_[0], $_[1] || 10, 1); 144 $track->(\$ref, $depth || $ENV{PERL_DEVEL_FINDREF_DEPTH} || 10, "");
141 $buf 145 $buf
142} 146}
143 147
144=item @references = Devel::FindRef::find $ref 148=item @references = Devel::FindRef::find $ref
145 149
146Return arrayrefs that contain [$message, $ref] pairs. The message 150Return arrayrefs that contain [$message, $ref] pairs. The message
147describes what kind of reference was found and the C<$ref> is the 151describes what kind of reference was found and the C<$ref> is the
148reference itself, which cna be omitted if C<find> decided to end the 152reference itself, which can be omitted if C<find> decided to end the
149search. 153search. The returned references are all weak references.
150 154
151The C<track> function uses this to find references to the value you are 155The C<track> function uses this to find references to the value you are
152interested in and recurses on the returned references. 156interested in and recurses on the returned references.
153 157
154=cut 158=cut
155 159
156sub find($) { 160sub find($) {
157 my ($about, $excl) = &find_; 161 my ($about, $excl) = &find_;
158 my %excl = map +($_ => undef), @$excl; 162 my %excl = map +($_ => undef), @$excl;
159 grep !exists $excl{$_->[1] + 0}, @$about 163 grep !exists $excl{ref2ptr $_->[1]}, @$about
160} 164}
161 165
162=item $ref = Devel::FindRef::ptr2ref $integer 166=item $ref = Devel::FindRef::ptr2ref $integer
163 167
164Sometimes you know (from debugging output) the address of a perl scalar 168Sometimes you know (from debugging output) the address of a perl scalar
167call on valid addresses, but extremely dangerous to call on invalid ones. 171call on valid addresses, but extremely dangerous to call on invalid ones.
168 172
169 # we know that HASH(0x176ff70) exists, so turn it into a hashref: 173 # we know that HASH(0x176ff70) exists, so turn it into a hashref:
170 my $ref_to_hash = Devel::FindRef::ptr2ref 0x176ff70; 174 my $ref_to_hash = Devel::FindRef::ptr2ref 0x176ff70;
171 175
176=item $ref = Devel::FindRef::ref2ptr $reference
177
178The opposite of C<ptr2ref>, above: returns the internal address of the
179value pointed to by the passed reference. I<No checks whatsoever will be
180done>, so don't use this.
181
172=back 182=back
183
184=head1 ENVIRONMENT VARIABLES
185
186You can set the environment variable C<PERL_DEVEL_FINDREF_DEPTH> to an
187integer to override the default depth in C<track>. If a call explicitly
188specified a depth it is not overridden.
173 189
174=head1 AUTHOR 190=head1 AUTHOR
175 191
176Marc Lehmann <pcg@goof.com>. 192Marc Lehmann <pcg@goof.com>.
177 193

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines