line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Copyright (C) 2006-2010 Andrew Speer . |
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# This file is part of WebDyne::Chain. |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# WebDyne::Chain is free software; you can redistribute it and/or modify |
9
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
10
|
|
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or |
11
|
|
|
|
|
|
|
# (at your option) any later version. |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
14
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
|
|
|
|
# GNU General Public License for more details. |
17
|
|
|
|
|
|
|
# |
18
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
19
|
|
|
|
|
|
|
# along with this program; if not, write to the Free Software |
20
|
|
|
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21
|
|
|
|
|
|
|
# |
22
|
|
|
|
|
|
|
# |
23
|
|
|
|
|
|
|
package WebDyne::Chain; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Compiler Pragma |
27
|
|
|
|
|
|
|
# |
28
|
1
|
|
|
1
|
|
21919
|
sub BEGIN { $^W=0 }; |
29
|
1
|
|
|
1
|
|
7
|
use strict qw(vars); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
30
|
1
|
|
|
1
|
|
4
|
use vars qw($VERSION); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
46
|
|
31
|
1
|
|
|
1
|
|
9
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
32
|
1
|
|
|
1
|
|
4
|
no warnings qw(uninitialized); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
26
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Webmod, WebDyne Modules. |
36
|
|
|
|
|
|
|
# |
37
|
1
|
|
|
1
|
|
1336
|
use WebDyne; |
|
1
|
|
|
|
|
234229
|
|
|
1
|
|
|
|
|
45
|
|
38
|
1
|
|
|
1
|
|
10
|
use WebDyne::Constant; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
577
|
|
39
|
1
|
|
|
1
|
|
872
|
use WebDyne::Chain::Constant; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
49
|
|
40
|
1
|
|
|
1
|
|
8
|
use WebDyne::Base; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
72
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# Version information in a formate suitable for CPAN etc. Must be |
44
|
|
|
|
|
|
|
# all on one line |
45
|
|
|
|
|
|
|
# |
46
|
|
|
|
|
|
|
$VERSION='1.050'; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Debug using WebDyne debug handler |
50
|
|
|
|
|
|
|
# |
51
|
|
|
|
|
|
|
0 && debug("%s loaded, version $VERSION", __PACKAGE__); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Shortcut error handler, save using ISA; |
55
|
|
|
|
|
|
|
# |
56
|
|
|
|
|
|
|
require WebDyne::Err; |
57
|
|
|
|
|
|
|
*err_html=\&WebDyne::Err::err_html || *err_html; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Package wide hash ref for data storage |
61
|
|
|
|
|
|
|
# |
62
|
|
|
|
|
|
|
my %Package; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Make all errors non-fatal |
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
errnofatal(1); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# And done |
71
|
|
|
|
|
|
|
# |
72
|
|
|
|
|
|
|
1; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub handler : method { |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Get class, request object |
82
|
|
|
|
|
|
|
# |
83
|
0
|
|
|
0
|
0
|
|
my ($self, $r, $param_hr)=@_; |
84
|
0
|
|
0
|
|
|
|
my $class=ref($self) || do { |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Need new self ref |
88
|
|
|
|
|
|
|
# |
89
|
|
|
|
|
|
|
my %self=( |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
_time => time(), |
92
|
|
|
|
|
|
|
_r => $r, |
93
|
|
|
|
|
|
|
%{delete $self->{'_self'}}, |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
$self=bless \%self, $self; |
97
|
|
|
|
|
|
|
ref($self); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
}; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Setup error handlers |
104
|
|
|
|
|
|
|
# |
105
|
0
|
|
|
0
|
|
|
local $SIG{__DIE__} =sub { return $self->err_html(@_) }; |
|
0
|
|
|
|
|
|
|
106
|
0
|
0
|
|
0
|
|
|
local $SIG{__WARN__}=sub { return $self->err_html(@_) } if $WEBDYNE_WARNINGS_FATAL; |
|
0
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Debug |
110
|
|
|
|
|
|
|
# |
111
|
0
|
|
|
|
|
|
0 && debug("in WebDyne::Chain::handler, class $class, r $r, self $self, param_hr %s", |
112
|
|
|
|
|
|
|
Dumper($param_hr)); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Log URI |
116
|
|
|
|
|
|
|
# |
117
|
0
|
|
|
|
|
|
0 && debug("URI %s", $r->uri()); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Get string of modules to chain |
121
|
|
|
|
|
|
|
# |
122
|
0
|
|
|
|
|
|
my @module; |
123
|
0
|
0
|
|
|
|
|
if (my $module_ar=$param_hr->{'meta'}{'webdynechain'}) { |
|
|
0
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
0 && debug("using module_ar $module_ar %s from meta", Dumper($module_ar)); |
125
|
0
|
|
|
|
|
|
@module=@{$module_ar}; |
|
0
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
elsif (my $module=$r->dir_config('WebDyneChain')) { |
128
|
0
|
|
|
|
|
|
0 && debug("using module $module dir_config"); |
129
|
0
|
|
|
|
|
|
@module=split(/\s+/, $module); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
else { |
132
|
0
|
|
|
|
|
|
0 && debug('could not find any module chain info'); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# WebDyne::Chain must be the first handler in line, Webdyne the last |
137
|
|
|
|
|
|
|
# |
138
|
0
|
0
|
|
|
|
|
unshift @module, __PACKAGE__ unless ($module[0] eq +__PACKAGE__); |
139
|
0
|
0
|
|
|
|
|
push @module, 'WebDyne' unless ($module[$#module] eq 'WebDyne'); |
140
|
0
|
|
|
|
|
|
0 && debug('final module chain %s', join('*', @module)); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Store current chain |
144
|
|
|
|
|
|
|
# |
145
|
0
|
|
|
|
|
|
$Package{'_chain_ar'}=\@module; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# If only two modules (WebDyne::Chain, WebDyne) something is wrong |
149
|
|
|
|
|
|
|
# |
150
|
0
|
0
|
|
|
|
|
if (@module==2) { |
151
|
|
|
|
|
|
|
return |
152
|
0
|
|
|
|
|
|
$self->err_html('unable to determine module chain - have you set WebDyneChain var ?'); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Get location. Used to use r->location, now use module array to generate pseudo |
157
|
|
|
|
|
|
|
# location data; |
158
|
|
|
|
|
|
|
# |
159
|
0
|
|
|
|
|
|
my $location=join(undef, @module); |
160
|
0
|
|
|
|
|
|
0 && debug("location $location"); |
161
|
0
|
0
|
|
|
|
|
unless ($Package{'_chain_loaded_hr'}{$location}++) { |
162
|
0
|
|
|
|
|
|
0 && debug("modules not loaded, doing now"); |
163
|
0
|
|
|
|
|
|
local $SIG{'__DIE__'}; |
164
|
0
|
|
|
|
|
|
foreach my $package (@module) { |
165
|
0
|
0
|
|
|
|
|
eval("require $package") || |
166
|
|
|
|
|
|
|
return $self->err_html("unable to load package $package, ".lcfirst($@)); |
167
|
0
|
|
|
|
|
|
0 && debug("loaded $package"); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# If location not same as last time we were run, then unload chain |
173
|
|
|
|
|
|
|
# |
174
|
0
|
0
|
|
|
|
|
if ((my $location_current=$Package{'_location_current'}) ne $location) { |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# Need to unload cached code refs |
178
|
|
|
|
|
|
|
# |
179
|
0
|
|
|
|
|
|
0 && debug("location_current '$location_current' is ne this location ('$location'). restoring cr's"); |
180
|
0
|
|
|
|
|
|
&ISA_restore(); |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Update location |
184
|
|
|
|
|
|
|
# |
185
|
0
|
|
|
|
|
|
$Package{'_location_current'}=$location; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# If code ref's cached, load up now |
189
|
|
|
|
|
|
|
# |
190
|
0
|
0
|
|
|
|
|
if (my $chain_hr=$Package{'_chain_hr'}{$location}) { |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Debug |
194
|
|
|
|
|
|
|
# |
195
|
0
|
|
|
|
|
|
0 && debug("found cached code ref's for location $location loading"); |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Yes found, load up |
199
|
|
|
|
|
|
|
# |
200
|
0
|
|
|
|
|
|
while (my($method,$cr)=each %{$chain_hr}) { |
|
0
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Debug |
204
|
|
|
|
|
|
|
# |
205
|
0
|
|
|
|
|
|
0 && debug("loading cr $cr for method $method"); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Install code ref |
209
|
|
|
|
|
|
|
# |
210
|
0
|
|
|
|
|
|
*{$method}=$cr; |
|
0
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Update current pointer |
216
|
|
|
|
|
|
|
# |
217
|
0
|
|
|
|
|
|
$Package{'_chain_current_hr'}=$chain_hr; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
else { |
223
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
0 && debug('location chain same as last request, caching'); |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Debug |
230
|
|
|
|
|
|
|
# |
231
|
0
|
|
|
|
|
|
0 && debug('module array %s', Dumper(\@module)); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# All done, pass onto next handler in chain. NOTE no error handler (eg || $self->err_html). It is |
235
|
|
|
|
|
|
|
# not our job to check for errors here, we should just pass back whatever the next handler does. |
236
|
|
|
|
|
|
|
# |
237
|
0
|
|
|
|
|
|
return $self->SUPER::handler($r, @_[2..$#_]); |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Only get here if error handler invoked |
241
|
|
|
|
|
|
|
# |
242
|
0
|
|
|
|
|
|
RENDER_ERROR: |
243
|
|
|
|
|
|
|
return $self->err_html(); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# Only get here if subrequest invoked. |
247
|
0
|
|
|
|
|
|
HANDLER_COMPLETE: |
248
|
|
|
|
|
|
|
return &Apache::OK; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub ISA_restore { |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# Get cuurent chain hash |
258
|
|
|
|
|
|
|
# |
259
|
0
|
|
|
0
|
0
|
|
my $chain_hr=delete $Package{'_chain_current_hr'}; |
260
|
0
|
|
|
|
|
|
0 && debug('in ISA_restore, chain %s', Dumper($chain_hr)); |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Go through each module, restoring |
264
|
|
|
|
|
|
|
# |
265
|
0
|
|
|
|
|
|
foreach my $method (keys %{$chain_hr}) { |
|
0
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# Free up |
269
|
|
|
|
|
|
|
# |
270
|
0
|
|
|
|
|
|
0 && debug("free $method"); |
271
|
0
|
|
|
|
|
|
undef *{$method}; |
|
0
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub DESTROY { |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# Get chain array ref |
284
|
|
|
|
|
|
|
# |
285
|
0
|
|
|
0
|
|
|
my $self=shift(); |
286
|
0
|
|
|
|
|
|
my $chain_ar=$Package{'_chain_ar'}; |
287
|
0
|
|
|
|
|
|
0 && debug("self $self, going through DESTROY chain %s", Dumper($chain_ar)); |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Handle destroys specially, mini version of AUTOLOAD code below |
291
|
|
|
|
|
|
|
# |
292
|
0
|
|
|
|
|
|
foreach my $i (1 .. $#{$chain_ar}) { |
|
0
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
my $package_chain=$chain_ar->[$i]; |
294
|
0
|
|
|
|
|
|
0 && debug("looking for DESTROY $package_chain"); |
295
|
0
|
0
|
|
|
|
|
if (my $cr=UNIVERSAL::can($package_chain, 'DESTROY')) { |
296
|
0
|
|
|
|
|
|
0 && debug("DESTROY hit on $package_chain"); |
297
|
0
|
|
|
|
|
|
$cr->($self); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Destroy object |
303
|
|
|
|
|
|
|
# |
304
|
0
|
|
|
|
|
|
%{$self}=(); |
|
0
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
undef $self; |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub UNIVERSAL::AUTOLOAD { |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Get self ref, calling class, autoloaded method |
316
|
|
|
|
|
|
|
# |
317
|
0
|
|
|
0
|
|
|
my $self=$_[0]; |
318
|
0
|
|
0
|
|
|
|
my $autoload=$UNIVERSAL::AUTOLOAD || return; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# Do not handle DESTROY's |
322
|
|
|
|
|
|
|
# |
323
|
0
|
0
|
|
|
|
|
return if $autoload=~/::DESTROY$/; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# Debug |
327
|
|
|
|
|
|
|
# |
328
|
0
|
|
|
|
|
|
0 && debug("in UNIVERSAL::AUTOLOAD, self $self, autoload $autoload, caller %s", |
329
|
|
|
|
|
|
|
Dumper([(caller(1))[0..3]])); |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# Get apache request ref, location. If not present means called by non-WebDyne class, not supported |
333
|
|
|
|
|
|
|
# |
334
|
0
|
|
|
|
|
|
my $r; { |
335
|
0
|
|
|
|
|
|
local $SIG{'__DIE__'}=undef; |
|
0
|
|
|
|
|
|
|
336
|
0
|
0
|
|
|
|
|
unless (eval{ ref($self) && ($r=$self->{'_r'}) }) { |
|
0
|
0
|
|
|
|
|
|
337
|
0
|
|
|
|
|
|
err("call to run %s UNIVERSAL::AUTOLOAD for non chained method '$autoload', self ref '$self'.", +__PACKAGE__); |
338
|
0
|
|
|
|
|
|
goto RENDER_ERROR; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Get method user was looking for, keep full package name. |
345
|
|
|
|
|
|
|
# |
346
|
0
|
|
|
|
|
|
my ($package_autoload, $method_autoload)=($autoload=~/(.*)::(.*?)$/); |
347
|
0
|
|
|
|
|
|
0 && debug("package_autoload $package_autoload, method_autoload $method_autoload"); |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# And chain for this location |
351
|
|
|
|
|
|
|
# |
352
|
0
|
|
|
|
|
|
my $chain_ar=$Package{'_chain_ar'}; |
353
|
0
|
|
|
|
|
|
my $location=join(undef, @{$chain_ar}); |
|
0
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
0 && debug('going through chain %s', Dumper($chain_ar)); |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Caller information |
358
|
|
|
|
|
|
|
# |
359
|
0
|
|
|
|
|
|
my $subroutine_caller=(caller(1))[3]; |
360
|
0
|
|
|
|
|
|
my $subroutine_caller_cr=\&{"$subroutine_caller"}; |
|
0
|
|
|
|
|
|
|
361
|
0
|
|
|
|
|
|
my ($package_caller, $method_caller)=($subroutine_caller=~/(.*)::(.*?)$/); |
362
|
0
|
|
|
|
|
|
0 && debug("package_caller $package_caller, method_caller $method_caller"); |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# If SUPER method trawl through chain to find the package it was called from, make sure we start |
366
|
|
|
|
|
|
|
# from there in iteration code below |
367
|
|
|
|
|
|
|
# |
368
|
0
|
|
|
|
|
|
my $i=0; |
369
|
0
|
0
|
|
|
|
|
if ($autoload=~/\QSUPER::$method_autoload\E$/) { |
370
|
0
|
|
|
|
|
|
0 && debug("SUPER method"); |
371
|
0
|
|
|
|
|
|
for (1; $i < @{$chain_ar}; $i++) { |
|
0
|
|
|
|
|
|
|
372
|
0
|
0
|
|
|
|
|
if (UNIVERSAL::can($chain_ar->[$i], $method_caller) eq $subroutine_caller_cr) { |
373
|
0
|
|
|
|
|
|
$i++; |
374
|
0
|
|
|
|
|
|
last; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
else { |
377
|
0
|
|
|
|
|
|
0 && debug("miss on package $chain_ar->[$i], $_ ne $subroutine_caller_cr"); |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} |
380
|
0
|
|
|
|
|
|
0 && debug("loop finished, i $i, chain_ar %s", $#{$chain_ar}); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Iterate through the chain (in order) looking for the method |
385
|
|
|
|
|
|
|
# |
386
|
0
|
|
|
|
|
|
foreach $i ($i .. $#{$chain_ar}) { |
|
0
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# Can this package in the chain support the calling method ? |
390
|
|
|
|
|
|
|
# |
391
|
0
|
|
|
|
|
|
0 && debug("look for $method_autoload in package $chain_ar->[$i]"); |
392
|
0
|
0
|
|
|
|
|
if (my $cr=UNIVERSAL::can($chain_ar->[$i], $method_autoload)) { |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
# Yes. Check for loops |
396
|
|
|
|
|
|
|
# |
397
|
0
|
0
|
|
|
|
|
if ($cr eq $subroutine_caller_cr) { |
398
|
0
|
|
|
|
|
|
err("detected AUTOLOAD loop for method '$method_autoload' ". |
399
|
0
|
|
|
|
|
|
"package $package_caller. Current chain: %s", join(', ', @{$chain_ar})); |
400
|
0
|
|
|
|
|
|
goto RENDER_ERROR; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Update |
405
|
|
|
|
|
|
|
# |
406
|
0
|
|
|
|
|
|
0 && debug('hit'); |
407
|
0
|
|
|
|
|
|
*{$autoload}=$cr; |
|
0
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# And keep a record |
411
|
|
|
|
|
|
|
# |
412
|
0
|
|
|
|
|
|
$Package{'_chain_hr'}{$location}{$autoload}=$cr; |
413
|
0
|
|
0
|
|
|
|
$Package{'_chain_current_hr'} ||= $Package{'_chain_hr'}{$location}; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# And dispatch. The commented out code is good for debugging internal |
417
|
|
|
|
|
|
|
# server errors, esp if comment out *{$autoload} above and turn on |
418
|
|
|
|
|
|
|
# debugging |
419
|
|
|
|
|
|
|
# |
420
|
0
|
|
|
|
|
|
goto &{$cr}; |
|
0
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
else { |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Debug |
427
|
|
|
|
|
|
|
# |
428
|
0
|
|
|
|
|
|
0 && debug("unable to find method $method_autoload in package $chain_ar->[$i]"); |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# Last resort - look back through call chain |
436
|
|
|
|
|
|
|
# |
437
|
0
|
|
|
|
|
|
0 && debug("checking back through callstack for method $method_autoload"); |
438
|
0
|
|
|
|
|
|
my %chain=map { $_=> 1} @{$chain_ar}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
my @caller; |
440
|
0
|
|
|
|
|
|
for ($i=0; my $caller=(caller($i))[0]; $i++) { |
441
|
0
|
0
|
|
|
|
|
next if $chain{$caller}++; #already looked there |
442
|
0
|
|
|
|
|
|
push @caller, $caller; |
443
|
0
|
0
|
|
|
|
|
if (my $cr=UNIVERSAL::can($caller, $method_autoload)) { |
444
|
0
|
0
|
|
|
|
|
if ($cr eq $subroutine_caller_cr) { |
445
|
0
|
|
|
|
|
|
err("detected AUTOLOAD loop for method '$method_autoload' ". |
446
|
0
|
|
|
|
|
|
"package $package_caller. Current chain: %s", join(', ', @{$chain_ar})); |
447
|
0
|
|
|
|
|
|
goto RENDER_ERROR; |
448
|
|
|
|
|
|
|
} |
449
|
0
|
0
|
|
|
|
|
if ($WEBDYNE_AUTOLOAD_POLLUTE) { |
450
|
0
|
|
|
|
|
|
*{$autoload}=$cr; |
|
0
|
|
|
|
|
|
|
451
|
0
|
|
|
|
|
|
$Package{'_chain_hr'}{$location}{$autoload}=$cr; |
452
|
|
|
|
|
|
|
} |
453
|
0
|
|
|
|
|
|
goto &{$cr} |
|
0
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
# Return err |
459
|
|
|
|
|
|
|
# |
460
|
0
|
|
|
|
|
|
err("method '$method_autoload' not found in call chain: %s", join(',', @caller)); |
461
|
0
|
|
|
|
|
|
goto RENDER_ERROR; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
__END__ |