Filename | /var/www/foswiki11/lib/Foswiki/Templates.pm |
Statements | Executed 57779 statements in 55.4ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
42 | 2 | 2 | 28.7ms | 71.8ms | readTemplate | Foswiki::Templates::
305 | 3 | 2 | 17.1ms | 23.0ms | tmplP (recurses: max depth 9, inclusive time 45.8ms) | Foswiki::Templates::
94 | 2 | 1 | 9.39ms | 24.2ms | _readTemplateFile | Foswiki::Templates::
92 | 1 | 1 | 3.97ms | 3.97ms | _readFile | Foswiki::Templates::
303 | 5 | 3 | 2.95ms | 27.1ms | expandTemplate (recurses: max depth 8, inclusive time 37.0ms) | Foswiki::Templates::
92 | 1 | 1 | 2.09ms | 2.09ms | _decomment | Foswiki::Templates::
1 | 1 | 1 | 659µs | 659µs | finish | Foswiki::Templates::
1 | 1 | 1 | 22µs | 48µs | BEGIN@33 | Foswiki::Templates::
1 | 1 | 1 | 20µs | 12.6ms | _expandTrivialTemplate | Foswiki::Templates::
1 | 1 | 1 | 14µs | 33µs | BEGIN@128 | Foswiki::Templates::
1 | 1 | 1 | 14µs | 40µs | BEGIN@35 | Foswiki::Templates::
1 | 1 | 1 | 14µs | 29µs | BEGIN@34 | Foswiki::Templates::
1 | 1 | 1 | 13µs | 69µs | BEGIN@42 | Foswiki::Templates::
1 | 1 | 1 | 13µs | 13µs | new | Foswiki::Templates::
1 | 1 | 1 | 12µs | 21µs | BEGIN@196 | Foswiki::Templates::
1 | 1 | 1 | 11µs | 30µs | BEGIN@130 | Foswiki::Templates::
1 | 1 | 1 | 10µs | 21µs | BEGIN@198 | Foswiki::Templates::
1 | 1 | 1 | 5µs | 5µs | BEGIN@37 | Foswiki::Templates::
0 | 0 | 0 | 0s | 0s | haveTemplate | Foswiki::Templates::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Templates | ||||
6 | |||||
7 | Support for Skin Template directives | ||||
8 | |||||
9 | =cut | ||||
10 | |||||
11 | =begin TML | ||||
12 | |||||
13 | The following tokens are supported by this language: | ||||
14 | |||||
15 | | %<nop>TMPL:P% | Instantiates a previously defined template | | ||||
16 | | %<nop>TMPL:DEF% | Opens a template definition | | ||||
17 | | %<nop>TMPL:END% | Closes a template definition | | ||||
18 | | %<nop>TMPL:INCLUDE% | Includes another file of templates | | ||||
19 | |||||
20 | Note; the template cache does not get reset during initialisation, so | ||||
21 | the haveTemplate test will return true if a template was loaded during | ||||
22 | a previous run when used with mod_perl or speedycgi. Frustrating for | ||||
23 | the template author, but they just have to switch off | ||||
24 | the accelerators during development. | ||||
25 | |||||
26 | This is to all intents and purposes a singleton object. It could | ||||
27 | easily be coverted into a true singleton (template manager). | ||||
28 | |||||
29 | =cut | ||||
30 | |||||
31 | package Foswiki::Templates; | ||||
32 | |||||
33 | 2 | 40µs | 2 | 75µs | # spent 48µs (22+26) within Foswiki::Templates::BEGIN@33 which was called:
# once (22µs+26µs) by Foswiki::templates at line 33 # spent 48µs making 1 call to Foswiki::Templates::BEGIN@33
# spent 26µs making 1 call to strict::import |
34 | 2 | 31µs | 2 | 45µs | # spent 29µs (14+16) within Foswiki::Templates::BEGIN@34 which was called:
# once (14µs+16µs) by Foswiki::templates at line 34 # spent 29µs making 1 call to Foswiki::Templates::BEGIN@34
# spent 16µs making 1 call to warnings::import |
35 | 2 | 30µs | 2 | 66µs | # spent 40µs (14+26) within Foswiki::Templates::BEGIN@35 which was called:
# once (14µs+26µs) by Foswiki::templates at line 35 # spent 40µs making 1 call to Foswiki::Templates::BEGIN@35
# spent 26µs making 1 call to Assert::import |
36 | |||||
37 | 2 | 35µs | 1 | 5µs | # spent 5µs within Foswiki::Templates::BEGIN@37 which was called:
# once (5µs+0s) by Foswiki::templates at line 37 # spent 5µs making 1 call to Foswiki::Templates::BEGIN@37 |
38 | |||||
39 | # Enable TRACE to get HTML comments in the output showing where templates | ||||
40 | # (both DEFs and files) open and close. Will probably bork the output, so | ||||
41 | # normally you should use it with a bin/view command-line. | ||||
42 | 2 | 302µs | 2 | 124µs | # spent 69µs (13+56) within Foswiki::Templates::BEGIN@42 which was called:
# once (13µs+56µs) by Foswiki::templates at line 42 # spent 69µs making 1 call to Foswiki::Templates::BEGIN@42
# spent 56µs making 1 call to constant::import |
43 | |||||
44 | 1 | 400ns | my $MAX_EXPANSION_RECURSIONS = 999; | ||
45 | |||||
46 | =begin TML | ||||
47 | |||||
48 | ---++ ClassMethod new ( $session ) | ||||
49 | |||||
50 | Constructor. Creates a new template database object. | ||||
51 | * $session - session (Foswiki) object | ||||
52 | |||||
53 | =cut | ||||
54 | |||||
55 | # spent 13µs within Foswiki::Templates::new which was called:
# once (13µs+0s) by Foswiki::templates at line 2032 of /var/www/foswiki11/lib/Foswiki.pm | ||||
56 | 1 | 1µs | my ( $class, $session ) = @_; | ||
57 | 1 | 8µs | my $this = bless( { session => $session }, $class ); | ||
58 | |||||
59 | 1 | 2µs | $this->{VARS} = { sep => ' | ' }; | ||
60 | 1 | 400ns | $this->{expansionRecursions} = {}; | ||
61 | 1 | 7µs | return $this; | ||
62 | } | ||||
63 | |||||
64 | =begin TML | ||||
65 | |||||
66 | ---++ ObjectMethod finish() | ||||
67 | Break circular references. | ||||
68 | |||||
69 | =cut | ||||
70 | |||||
71 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
72 | # whether they are references or not. That way this method is "golden | ||||
73 | # documentation" of the live fields in the object. | ||||
74 | # spent 659µs within Foswiki::Templates::finish which was called:
# once (659µs+0s) by Foswiki::finish at line 2163 of /var/www/foswiki11/lib/Foswiki.pm | ||||
75 | 1 | 1µs | my $this = shift; | ||
76 | 1 | 651µs | undef $this->{VARS}; | ||
77 | 1 | 1µs | undef $this->{session}; | ||
78 | 1 | 8µs | undef $this->{expansionRecursions}; | ||
79 | } | ||||
80 | |||||
81 | =begin TML | ||||
82 | |||||
83 | ---++ ObjectMethod haveTemplate( $name ) -> $boolean | ||||
84 | |||||
85 | Return true if the template exists and is loaded into the cache | ||||
86 | |||||
87 | =cut | ||||
88 | |||||
89 | sub haveTemplate { | ||||
90 | my ( $this, $template ) = @_; | ||||
91 | |||||
92 | return exists( $this->{VARS}->{$template} ); | ||||
93 | } | ||||
94 | |||||
95 | # Expand only simple templates that can be expanded statically. | ||||
96 | # Templates with conditions can only be expanded after the | ||||
97 | # context is fully known. | ||||
98 | # spent 12.6ms (20µs+12.6) within Foswiki::Templates::_expandTrivialTemplate which was called:
# once (20µs+12.6ms) by Foswiki::Templates::readTemplate at line 342 | ||||
99 | 1 | 1µs | my ( $this, $text ) = @_; | ||
100 | |||||
101 | # SMELL: unchecked implicit untaint? | ||||
102 | 1 | 1µs | $text =~ /%TMPL\:P{(.*)}%/; | ||
103 | 1 | 9µs | 1 | 34µs | my $attrs = new Foswiki::Attrs($1); # spent 34µs making 1 call to Foswiki::Attrs::new |
104 | |||||
105 | # Can't expand context-dependant templates | ||||
106 | 1 | 300ns | return $text if ( $attrs->{context} ); | ||
107 | 1 | 6µs | 1 | 12.6ms | return $this->tmplP($attrs); # spent 12.6ms making 1 call to Foswiki::Templates::tmplP |
108 | } | ||||
109 | |||||
110 | =begin TML | ||||
111 | |||||
112 | ---++ ObjectMethod expandTemplate( $params ) -> $string | ||||
113 | |||||
114 | Expand the template specified in the parameter string using =tmplP=. | ||||
115 | |||||
116 | Examples: | ||||
117 | <verbatim> | ||||
118 | $tmpls->expandTemplate("blah"); | ||||
119 | $tmpls->expandTemplate(context="view" then="sigh" else="humph"); | ||||
120 | </verbatim> | ||||
121 | |||||
122 | =cut | ||||
123 | |||||
124 | # spent 27.1ms (2.95+24.2) within Foswiki::Templates::expandTemplate which was called 303 times, avg 90µs/call:
# 178 times (1.54ms+11.0ms) by Foswiki::Templates::tmplP at line 197, avg 70µs/call
# 41 times (317µs+8.05ms) by Foswiki::Search::loadTemplates at line 524 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 204µs/call
# 41 times (748µs+3.56ms) by Foswiki::Search::loadTemplates at line 523 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 105µs/call
# 41 times (309µs+1.44ms) by Foswiki::Search::loadTemplates at line 535 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 43µs/call
# 2 times (37µs+175µs) by Foswiki::LoginManager::_LOGIN at line 1156 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm, avg 106µs/call | ||||
125 | 303 | 257µs | my ( $this, $params ) = @_; | ||
126 | |||||
127 | 303 | 905µs | 303 | 5.06ms | my $attrs = new Foswiki::Attrs($params); # spent 5.06ms making 303 calls to Foswiki::Attrs::new, avg 17µs/call |
128 | 2 | 41µs | 2 | 51µs | # spent 33µs (14+18) within Foswiki::Templates::BEGIN@128 which was called:
# once (14µs+18µs) by Foswiki::templates at line 128 # spent 33µs making 1 call to Foswiki::Templates::BEGIN@128
# spent 18µs making 1 call to warnings::unimport |
129 | 303 | 605µs | 303 | 10.3ms | my $value = $this->tmplP($attrs); # spent 56.2ms making 303 calls to Foswiki::Templates::tmplP, avg 185µs/call, recursion: max depth 9, sum of overlapping time 45.8ms |
130 | 2 | 301µs | 2 | 49µs | # spent 30µs (11+19) within Foswiki::Templates::BEGIN@130 which was called:
# once (11µs+19µs) by Foswiki::templates at line 130 # spent 30µs making 1 call to Foswiki::Templates::BEGIN@130
# spent 19µs making 1 call to warnings::import |
131 | 303 | 993µs | return $value; | ||
132 | } | ||||
133 | |||||
134 | =begin TML | ||||
135 | |||||
136 | ---+ ObjectMethod tmplP( $attrs ) -> $string | ||||
137 | |||||
138 | Return value expanded text of the template, as found from looking | ||||
139 | in the register of template definitions. The attrs can contain a template | ||||
140 | name in _DEFAULT, and / or =context=, =then= and =else= values. | ||||
141 | |||||
142 | Recursively expands any contained TMPL:P tags. | ||||
143 | |||||
144 | Note that it would be trivial to add template parameters to this, | ||||
145 | simply by iterating over the other parameters (other than _DEFAULT, context, | ||||
146 | then and else) and doing a s/// in the template for that parameter value. This | ||||
147 | would add considerably to the power of templates. | ||||
148 | |||||
149 | =cut | ||||
150 | |||||
151 | # spent 23.0ms (17.1+5.87) within Foswiki::Templates::tmplP which was called 305 times, avg 75µs/call:
# 303 times (17.0ms+-6.66ms) by Foswiki::Templates::expandTemplate at line 129, avg 34µs/call
# once (74µs+12.5ms) by Foswiki::Templates::_expandTrivialTemplate at line 107
# once (43µs+12µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:283] at line 283 of /var/www/foswiki11/lib/Foswiki.pm | ||||
152 | 305 | 154µs | my ( $this, $params ) = @_; | ||
153 | |||||
154 | 305 | 454µs | 305 | 815µs | my $template = $params->remove('_DEFAULT') || ''; # spent 815µs making 305 calls to Foswiki::Attrs::remove, avg 3µs/call |
155 | 305 | 353µs | 305 | 488µs | my $context = $params->remove('context'); # spent 488µs making 305 calls to Foswiki::Attrs::remove, avg 2µs/call |
156 | 305 | 320µs | 305 | 439µs | my $then = $params->remove('then'); # spent 439µs making 305 calls to Foswiki::Attrs::remove, avg 1µs/call |
157 | 305 | 312µs | 305 | 422µs | my $else = $params->remove('else'); # spent 422µs making 305 calls to Foswiki::Attrs::remove, avg 1µs/call |
158 | 305 | 50µs | if ($context) { | ||
159 | 16 | 5µs | $template = $then if defined($then); | ||
160 | 16 | 16µs | foreach my $id ( split( /\,\s*/, $context ) ) { | ||
161 | 16 | 17µs | unless ( $this->{session}->{context}->{$id} ) { | ||
162 | 13 | 3µs | $template = ( $else || '' ); | ||
163 | 13 | 6µs | last; | ||
164 | } | ||||
165 | } | ||||
166 | } | ||||
167 | |||||
168 | 305 | 45µs | return '' unless $template; | ||
169 | |||||
170 | 302 | 245µs | $this->{expansionRecursions}->{$template} += 1; | ||
171 | |||||
172 | #print STDERR "template=$template; recursion = " . $this->{expansionRecursions}->{$template} . "\n"; | ||||
173 | |||||
174 | 302 | 137µs | if ( $this->{expansionRecursions}->{$template} > $MAX_EXPANSION_RECURSIONS ) | ||
175 | { | ||||
176 | throw Foswiki::OopsException( | ||||
177 | 'attention', | ||||
178 | def => 'template_recursion', | ||||
179 | params => [$template] | ||||
180 | ); | ||||
181 | } | ||||
182 | |||||
183 | 302 | 106µs | my $val = ''; | ||
184 | 302 | 194µs | if ( exists( $this->{VARS}->{$template} ) ) { | ||
185 | 296 | 166µs | $val = $this->{VARS}->{$template}; | ||
186 | $val = "<!--$template-->$val<!--/$template-->" if (TRACE); | ||||
187 | 296 | 351µs | foreach my $p ( keys %$params ) { | ||
188 | 304 | 380µs | if ( $p eq 'then' || $p eq 'else' ) { | ||
189 | $val =~ s/%$p%/$this->expandTemplate($1)/ge; | ||||
190 | } | ||||
191 | elsif ( defined( $params->{$p} ) ) { | ||||
192 | 304 | 405µs | $val =~ s/%$p%/$params->{$p}/ge; | ||
193 | } | ||||
194 | } | ||||
195 | 296 | 254µs | $val =~ s/%TMPL:PREV%/%TMPL:P{"$template:_PREV"}%/g; | ||
196 | 2 | 56µs | 2 | 31µs | # spent 21µs (12+9) within Foswiki::Templates::BEGIN@196 which was called:
# once (12µs+9µs) by Foswiki::templates at line 196 # spent 21µs making 1 call to Foswiki::Templates::BEGIN@196
# spent 9µs making 1 call to warnings::unimport |
197 | 474 | 1.03ms | 178 | 12.5ms | $val =~ s/%TMPL:P{(.*?)}%/$this->expandTemplate($1)/ge; # spent 49.5ms making 178 calls to Foswiki::Templates::expandTemplate, avg 278µs/call, recursion: max depth 8, sum of overlapping time 37.0ms |
198 | 2 | 1.44ms | 2 | 33µs | # spent 21µs (10+12) within Foswiki::Templates::BEGIN@198 which was called:
# once (10µs+12µs) by Foswiki::templates at line 198 # spent 21µs making 1 call to Foswiki::Templates::BEGIN@198
# spent 12µs making 1 call to warnings::import |
199 | } | ||||
200 | |||||
201 | 302 | 190µs | $this->{expansionRecursions}->{$template} -= 1; | ||
202 | 302 | 788µs | return $val; | ||
203 | } | ||||
204 | |||||
205 | =begin TML | ||||
206 | |||||
207 | ---++ ObjectMethod readTemplate ( $name, %options ) -> $text | ||||
208 | |||||
209 | Reads a template, loading the definitions therein. | ||||
210 | |||||
211 | Return value: expanded template text | ||||
212 | |||||
213 | By default throws an OopsException if the template was not found or the | ||||
214 | access controls denied access. | ||||
215 | |||||
216 | %options include: | ||||
217 | * =skin= - skin name, | ||||
218 | * =web= - web to search | ||||
219 | * =no_oops= - if true, will not throw an exception. Instead, returns undef. | ||||
220 | |||||
221 | If template text is found, extracts include statements and fully expands them. | ||||
222 | Also extracts template definitions and adds them to the | ||||
223 | list of loaded templates, overwriting any previous definition. | ||||
224 | |||||
225 | =cut | ||||
226 | |||||
227 | # spent 71.8ms (28.7+43.1) within Foswiki::Templates::readTemplate which was called 42 times, avg 1.71ms/call:
# 41 times (26.0ms+27.2ms) by Foswiki::Search::loadTemplates at line 508 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1.30ms/call
# once (2.67ms+15.9ms) by Foswiki::UI::View::view at line 239 of /var/www/foswiki11/lib/Foswiki/UI/View.pm | ||||
228 | 42 | 66µs | my ( $this, $name, %opts ) = @_; | ||
229 | 42 | 52µs | 42 | 38µs | ASSERT($name) if DEBUG; # spent 38µs making 42 calls to Assert::ASSERTS_OFF, avg 917ns/call |
230 | 42 | 278µs | 42 | 6.18ms | my $skins = $opts{skins} || $this->{session}->getSkin(); # spent 6.18ms making 42 calls to Foswiki::getSkin, avg 147µs/call |
231 | 42 | 120µs | my $web = $opts{web} || $this->{session}->{webName}; | ||
232 | |||||
233 | 42 | 166µs | $this->{files} = (); | ||
234 | |||||
235 | # recursively read template file(s) | ||||
236 | 42 | 213µs | 42 | 7.24ms | my $text = _readTemplateFile( $this, $name, $skins, $web ); # spent 7.24ms making 42 calls to Foswiki::Templates::_readTemplateFile, avg 172µs/call |
237 | |||||
238 | # Check file was found | ||||
239 | 42 | 18µs | unless ( defined $text ) { | ||
240 | |||||
241 | # if no_oops is given, return undef silently | ||||
242 | if ( $opts{no_oops} ) { | ||||
243 | return undef; | ||||
244 | } | ||||
245 | else { | ||||
246 | throw Foswiki::OopsException( | ||||
247 | 'attention', | ||||
248 | def => 'no_such_template', | ||||
249 | params => [ | ||||
250 | $name, | ||||
251 | |||||
252 | # More info for overridable templates | ||||
253 | ( $name =~ /^(view|edit)$/ ) ? $name . '_TEMPLATE' : '' | ||||
254 | ] | ||||
255 | ); | ||||
256 | } | ||||
257 | } | ||||
258 | |||||
259 | # SMELL: unchecked implicit untaint? | ||||
260 | 42 | 292µs | while ( $text =~ /%TMPL\:INCLUDE{[\s\"]*(.*?)[\"\s]*}%/s ) { | ||
261 | 46 | 606µs | $text =~ s/%TMPL\:INCLUDE{[\s\"]*(.*?)[\"\s]*}%/ | ||
262 | 52 | 88µs | 52 | 17.0ms | _readTemplateFile( $this, $1, $skins, $web ) || ''/ge; # spent 17.0ms making 52 calls to Foswiki::Templates::_readTemplateFile, avg 326µs/call |
263 | } | ||||
264 | |||||
265 | 42 | 90µs | if ( $text !~ /%TMPL\:/ ) { | ||
266 | |||||
267 | # no %TMPL's to process | ||||
268 | |||||
269 | # SMELL: legacy - leading spaces to tabs, should not be required | ||||
270 | $text =~ s|^(( {3})+)|"\t" x (length($1)/3)|geom; | ||||
271 | |||||
272 | return $text; | ||||
273 | } | ||||
274 | |||||
275 | 42 | 63µs | my $result = ''; | ||
276 | 42 | 66µs | my $key = ''; | ||
277 | 42 | 31µs | my $val = ''; | ||
278 | 42 | 18µs | my $delim = ''; | ||
279 | 42 | 1.18ms | foreach ( split( /(%TMPL\:)/, $text ) ) { | ||
280 | 3662 | 4.59ms | if (/^(%TMPL\:)$/) { | ||
281 | $delim = $1; | ||||
282 | } | ||||
283 | elsif ( (/^DEF{[\s\"]*(.*?)[\"\s]*}%(.*)/s) && ($1) ) { | ||||
284 | |||||
285 | # handle %TMPL:DEF{key}% | ||||
286 | 744 | 83µs | if ($key) { | ||
287 | |||||
288 | # if the key is already defined, rename the existing | ||||
289 | # template to key:_PREV | ||||
290 | my $new_value = $val; | ||||
291 | my $prev_key = $key; | ||||
292 | my $prev_value = $this->{VARS}->{$prev_key}; | ||||
293 | $this->{VARS}->{$prev_key} = $new_value; | ||||
294 | while ($prev_value) { | ||||
295 | $new_value = $prev_value; | ||||
296 | $prev_key = "$prev_key:_PREV"; | ||||
297 | $prev_value = $this->{VARS}->{$prev_key}; | ||||
298 | $this->{VARS}->{$prev_key} = $new_value; | ||||
299 | } | ||||
300 | |||||
301 | } | ||||
302 | 744 | 193µs | $key = $1; | ||
303 | |||||
304 | # SMELL: unchecked implicit untaint? | ||||
305 | 744 | 241µs | $val = $2; | ||
306 | |||||
307 | } | ||||
308 | elsif (/^END%[\s\n\r]*(.*)/s) { | ||||
309 | |||||
310 | # handle %TMPL:END% | ||||
311 | |||||
312 | # if the key is already defined, rename the existing template to | ||||
313 | # key:_PREV | ||||
314 | 745 | 186µs | my $new_value = $val; | ||
315 | 745 | 124µs | my $prev_key = $key; | ||
316 | 745 | 655µs | my $prev_value = $this->{VARS}->{$prev_key}; | ||
317 | 745 | 537µs | $this->{VARS}->{$prev_key} = $new_value; | ||
318 | 745 | 209µs | while ($prev_value) { | ||
319 | 7461 | 689µs | $new_value = $prev_value; | ||
320 | 7461 | 839µs | $prev_key = "$prev_key:_PREV"; | ||
321 | 7461 | 7.82ms | $prev_value = $this->{VARS}->{$prev_key}; | ||
322 | 7461 | 8.10ms | $this->{VARS}->{$prev_key} = $new_value; | ||
323 | } | ||||
324 | |||||
325 | 745 | 105µs | $key = ''; | ||
326 | 745 | 76µs | $val = ''; | ||
327 | |||||
328 | # SMELL: unchecked implicit untaint? | ||||
329 | 745 | 377µs | $result .= $1; | ||
330 | |||||
331 | } | ||||
332 | elsif ($key) { | ||||
333 | $val .= "$delim$_"; | ||||
334 | |||||
335 | } | ||||
336 | else { | ||||
337 | 43 | 64µs | $result .= "$delim$_"; | ||
338 | } | ||||
339 | } | ||||
340 | |||||
341 | # handle %TMPL:P{"..."}% recursively | ||||
342 | 43 | 44µs | 1 | 12.6ms | $result =~ s/(%TMPL\:P{.*?}%)/_expandTrivialTemplate( $this, $1)/geo; # spent 12.6ms making 1 call to Foswiki::Templates::_expandTrivialTemplate |
343 | |||||
344 | # SMELL: legacy - leading spaces to tabs, should not be required | ||||
345 | 42 | 49µs | $result =~ s|^(( {3})+)|"\t" x (length($1)/3)|geom; | ||
346 | |||||
347 | 42 | 267µs | return $result; | ||
348 | } | ||||
349 | |||||
350 | # STATIC: Return value: raw template text, or undef if read fails | ||||
351 | sub _readTemplateFile { | ||||
352 | 94 | 176µs | my ( $this, $name, $skins, $web ) = @_; | ||
353 | 94 | 60µs | my $session = $this->{session}; | ||
354 | |||||
355 | #print STDERR "SKIN path is $skins\n"; | ||||
356 | |||||
357 | # SMELL: not i18n-friendly (can't have accented characters in template name) | ||||
358 | # zap anything suspicious | ||||
359 | 94 | 94µs | $name =~ s/[^A-Za-z0-9_,.\/]//go; | ||
360 | |||||
361 | # if the name ends in .tmpl, then this is an explicit include from | ||||
362 | # the templates directory. No further searching required. | ||||
363 | 94 | 98µs | if ( $name =~ /\.tmpl$/ ) { | ||
364 | return _decomment( | ||||
365 | _readFile( $session, "$Foswiki::cfg{TemplateDir}/$name" ) ); | ||||
366 | } | ||||
367 | |||||
368 | 94 | 54µs | my $userdirweb = $web; | ||
369 | 94 | 27µs | my $userdirname = $name; | ||
370 | 94 | 70µs | if ( $name =~ /^(.+)\.(.+?)$/ ) { | ||
371 | |||||
372 | # ucfirst taints if use locale is in force | ||||
373 | $userdirweb = Foswiki::Sandbox::untaintUnchecked( ucfirst($1) ); | ||||
374 | $userdirname = Foswiki::Sandbox::untaintUnchecked( ucfirst($2) ); | ||||
375 | |||||
376 | # if the name can be parsed into $web.$name, then this is an attempt | ||||
377 | # to explicit include that topic. No further searching required. | ||||
378 | if ( $session->topicExists( $userdirweb, $userdirname ) ) { | ||||
379 | my $meta = | ||||
380 | Foswiki::Meta->load( $session, $userdirweb, $userdirname ); | ||||
381 | |||||
382 | # Check we are allowed access | ||||
383 | unless ( $meta->haveAccess( 'VIEW', $session->{user} ) ) { | ||||
384 | return $this->{session}->inlineAlert( 'alerts', 'access_denied', | ||||
385 | "$userdirweb.$userdirname" ); | ||||
386 | } | ||||
387 | my $text = $meta->text(); | ||||
388 | $text = '' unless defined $text; | ||||
389 | |||||
390 | $text = | ||||
391 | "<!--$userdirweb/$userdirname-->" | ||||
392 | . $text | ||||
393 | . "<!--/$userdirweb/$userdirname-->" | ||||
394 | if (TRACE); | ||||
395 | |||||
396 | return _decomment($text); | ||||
397 | } | ||||
398 | } | ||||
399 | else { | ||||
400 | |||||
401 | # ucfirst taints if use locale is in force | ||||
402 | 94 | 338µs | 94 | 626µs | $userdirweb = # spent 626µs making 94 calls to Foswiki::Sandbox::untaintUnchecked, avg 7µs/call |
403 | Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirweb) ); | ||||
404 | 94 | 138µs | 94 | 213µs | $userdirname = # spent 213µs making 94 calls to Foswiki::Sandbox::untaintUnchecked, avg 2µs/call |
405 | Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirname) ); | ||||
406 | } | ||||
407 | |||||
408 | 94 | 187µs | my @skinList = split( /\,\s*/, $skins ); | ||
409 | 94 | 55µs | my $nrskins = $#skinList; | ||
410 | |||||
411 | 94 | 884µs | my @templatePath = split( /\s*,\s*/, $Foswiki::cfg{TemplatePath} ); | ||
412 | 94 | 130µs | if ( | ||
413 | ( $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled} ) | ||||
414 | && ( lc($name) eq 'foswiki' ) | ||||
415 | && defined( | ||||
416 | $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{TemplatePath} | ||||
417 | ) | ||||
418 | ) | ||||
419 | { | ||||
420 | |||||
421 | # TWikiCompatibility, need to test to see if there is a twiki.skin tmpl | ||||
422 | @templatePath = | ||||
423 | @{ $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{TemplatePath} }; | ||||
424 | } | ||||
425 | |||||
426 | # Search the $Foswiki::cfg{TemplatePath} for the skinned versions | ||||
427 | 94 | 19µs | my @candidates; | ||
428 | |||||
429 | 94 | 35µs | $nrskins = 0 if $nrskins < 0; | ||
430 | 94 | 97µs | foreach my $template (@templatePath) { | ||
431 | 380 | 423µs | for ( my $idx = 0 ; $idx <= $nrskins ; $idx++ ) { | ||
432 | 380 | 111µs | my $file = $template; | ||
433 | 380 | 55µs | my $userdir = 0; | ||
434 | |||||
435 | # also need to do %PUBURL% etc.? | ||||
436 | # push the first time even if not modified | ||||
437 | 380 | 155µs | my $skin = $skinList[$idx] || ''; | ||
438 | 380 | 78µs | my $webName = $web || ''; | ||
439 | 380 | 70µs | my $tmplName = $name || ''; | ||
440 | 380 | 421µs | unless ( $file =~ m/.tmpl$/ ) { | ||
441 | |||||
442 | # Could also use $Skin, $Web, $Name to indicate uppercase | ||||
443 | 98 | 32µs | $userdir = 1; | ||
444 | |||||
445 | # Again untainting when using ucfirst | ||||
446 | 98 | 161µs | 98 | 350µs | $skin = Foswiki::Sandbox::untaintUnchecked( ucfirst($skin) ); # spent 350µs making 98 calls to Foswiki::Sandbox::untaintUnchecked, avg 4µs/call |
447 | 98 | 17µs | $webName = $userdirweb; | ||
448 | 98 | 25µs | $tmplName = $userdirname; | ||
449 | } | ||||
450 | 380 | 724µs | $file =~ s/\$skin/$skin/geo; | ||
451 | 380 | 456µs | $file =~ s/\$web/$webName/geo; | ||
452 | 380 | 562µs | $file =~ s/\$name/$tmplName/geo; | ||
453 | |||||
454 | 380 | 93µs | my ( $candidatename, $candidatevalidate, $candidateretrieve ); | ||
455 | |||||
456 | 380 | 1.26ms | if ($userdir) { | ||
457 | |||||
458 | # candidate in user directory | ||||
459 | 98 | 264µs | 98 | 1.35ms | my ( $web1, $name1 ) = # spent 1.35ms making 98 calls to Foswiki::normalizeWebTopicName, avg 14µs/call |
460 | $session->normalizeWebTopicName( $web, $file ); | ||||
461 | |||||
462 | 98 | 287µs | 98 | 6.24ms | if ( $session->topicExists( $web1, $name1 ) ) { # spent 6.24ms making 98 calls to Foswiki::topicExists, avg 64µs/call |
463 | |||||
464 | # recursion prevention. | ||||
465 | next | ||||
466 | if ( | ||||
467 | defined( | ||||
468 | $this->{files} | ||||
469 | ->{ 'topic' . $session->{user}, $name1, $web1 } | ||||
470 | ) | ||||
471 | ); | ||||
472 | $this->{files} | ||||
473 | ->{ 'topic' . $session->{user}, $name1, $web1 } = 1; | ||||
474 | |||||
475 | # access control | ||||
476 | my $meta = Foswiki::Meta->load( $session, $web1, $name1 ); | ||||
477 | next unless $meta->haveAccess( 'VIEW', $session->{user} ); | ||||
478 | |||||
479 | my $text = $meta->text(); | ||||
480 | $text = '' unless defined $text; | ||||
481 | |||||
482 | $text = "<!--$web1.$name1-->$text<!--/$web1.$name1-->" | ||||
483 | if (TRACE); | ||||
484 | |||||
485 | return _decomment($text); | ||||
486 | } | ||||
487 | } | ||||
488 | elsif ( -e $file ) { | ||||
489 | 138 | 202µs | next if ( defined( $this->{files}->{$file} ) ); | ||
490 | |||||
491 | # recursion prevention. | ||||
492 | 92 | 126µs | $this->{files}->{$file} = 1; | ||
493 | |||||
494 | 92 | 739µs | 184 | 6.05ms | return _decomment( _readFile( $session, $file ) ); # spent 3.97ms making 92 calls to Foswiki::Templates::_readFile, avg 43µs/call
# spent 2.09ms making 92 calls to Foswiki::Templates::_decomment, avg 23µs/call |
495 | } | ||||
496 | } | ||||
497 | } | ||||
498 | |||||
499 | # File was not found | ||||
500 | 2 | 5µs | return undef; | ||
501 | } | ||||
502 | |||||
503 | # spent 3.97ms within Foswiki::Templates::_readFile which was called 92 times, avg 43µs/call:
# 92 times (3.97ms+0s) by Foswiki::Templates::_readTemplateFile at line 494, avg 43µs/call | ||||
504 | 92 | 72µs | my ( $session, $fn ) = @_; | ||
505 | 92 | 15µs | my $F; | ||
506 | |||||
507 | 92 | 1.37ms | if ( open( $F, '<', $fn ) ) { | ||
508 | 92 | 149µs | local $/; | ||
509 | 92 | 1.36ms | my $text = <$F>; | ||
510 | 92 | 501µs | close($F); | ||
511 | |||||
512 | $text = "<!--$fn-->$text<!--/$fn-->" if (TRACE); | ||||
513 | |||||
514 | 92 | 752µs | return $text; | ||
515 | } | ||||
516 | else { | ||||
517 | $session->logger->log( 'warning', "$fn: $!" ); | ||||
518 | return undef; | ||||
519 | } | ||||
520 | } | ||||
521 | |||||
522 | # spent 2.09ms within Foswiki::Templates::_decomment which was called 92 times, avg 23µs/call:
# 92 times (2.09ms+0s) by Foswiki::Templates::_readTemplateFile at line 494, avg 23µs/call | ||||
523 | 92 | 98µs | my $text = shift; | ||
524 | |||||
525 | 92 | 24µs | return $text unless $text; | ||
526 | |||||
527 | # Kill comments, marked by %{ ... }% | ||||
528 | # (and remove whitespace either side of the comment) | ||||
529 | 92 | 1.72ms | $text =~ s/\s*%{.*?}%\s*//sg; | ||
530 | 92 | 279µs | return $text; | ||
531 | } | ||||
532 | |||||
533 | 1 | 4µs | 1; | ||
534 | __END__ |