← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/local/src/github.com/foswiki/core/bin/view
  Run on Sun Dec 4 17:17:59 2011
Reported on Sun Dec 4 17:26:51 2011

Filename/usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm
StatementsExecuted 15095 statements in 84.2ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
44425.5ms554msFoswiki::Templates::::readTemplateFoswiki::Templates::readTemplate
202120.4ms487msFoswiki::Templates::::_readTemplateFileFoswiki::Templates::_readTemplateFile
1563213.5ms36.0msFoswiki::Templates::::tmplPFoswiki::Templates::tmplP (recurses: max depth 8, inclusive time 105ms)
3611918.20ms8.20msFoswiki::Templates::::CORE:matchFoswiki::Templates::CORE:match (opcode)
14741115.50ms5.50msFoswiki::Templates::::CORE:substFoswiki::Templates::CORE:subst (opcode)
1115.47ms5.99msFoswiki::Templates::::BEGIN@483Foswiki::Templates::BEGIN@483
142953.21ms35.3msFoswiki::Templates::::expandTemplateFoswiki::Templates::expandTemplate (recurses: max depth 7, inclusive time 88.4ms)
257511.48ms1.48msFoswiki::Templates::::CORE:substcontFoswiki::Templates::CORE:substcont (opcode)
1511625µs1.28msFoswiki::Templates::::_readFileFoswiki::Templates::_readFile
10211600µs600µsFoswiki::Templates::::CORE:ftisFoswiki::Templates::CORE:ftis (opcode)
15811410µs410µsFoswiki::Templates::::CORE:regcompFoswiki::Templates::CORE:regcomp (opcode)
1821389µs1.48msFoswiki::Templates::::_decommentFoswiki::Templates::_decomment
1511310µs310µsFoswiki::Templates::::CORE:openFoswiki::Templates::CORE:open (opcode)
1511269µs269µsFoswiki::Templates::::CORE:readlineFoswiki::Templates::CORE:readline (opcode)
111195µs195µsFoswiki::Templates::::finishFoswiki::Templates::finish
511157µs32.5msFoswiki::Templates::::_expandTrivialTemplateFoswiki::Templates::_expandTrivialTemplate
151175µs75µsFoswiki::Templates::::CORE:closeFoswiki::Templates::CORE:close (opcode)
11128µs35µsFoswiki::Templates::::BEGIN@33Foswiki::Templates::BEGIN@33
11128µs28µsFoswiki::Templates::::newFoswiki::Templates::new
11127µs70µsFoswiki::Templates::::BEGIN@35Foswiki::Templates::BEGIN@35
11124µs44µsFoswiki::Templates::::BEGIN@34Foswiki::Templates::BEGIN@34
11117µs120µsFoswiki::Templates::::BEGIN@42Foswiki::Templates::BEGIN@42
1119µs9µsFoswiki::Templates::::BEGIN@37Foswiki::Templates::BEGIN@37
0000s0sFoswiki::Templates::::getTemplateFromCacheFoswiki::Templates::getTemplateFromCache
0000s0sFoswiki::Templates::::haveTemplateFoswiki::Templates::haveTemplate
0000s0sFoswiki::Templates::::saveTemplateToCacheFoswiki::Templates::saveTemplateToCache
Call graph for these subroutines as a Graphviz dot language file.
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
7Support for Skin Template directives
8
9=cut
10
11=begin TML
12
13The 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
20Note; the template cache does not get reset during initialisation, so
21the haveTemplate test will return true if a template was loaded during
22a previous run when used with mod_perl or speedycgi. Frustrating for
23the template author, but they just have to switch off
24the accelerators during development.
25
26This is to all intents and purposes a singleton object. It could
27easily be coverted into a true singleton (template manager).
28
29=cut
30
31package Foswiki::Templates;
32
33253µs243µs
# spent 35µs (28+7) within Foswiki::Templates::BEGIN@33 which was called: # once (28µs+7µs) by Foswiki::templates at line 33
use strict;
# spent 35µs making 1 call to Foswiki::Templates::BEGIN@33 # spent 7µs making 1 call to strict::import
34248µs264µs
# spent 44µs (24+20) within Foswiki::Templates::BEGIN@34 which was called: # once (24µs+20µs) by Foswiki::templates at line 34
use warnings;
# spent 44µs making 1 call to Foswiki::Templates::BEGIN@34 # spent 20µs making 1 call to warnings::import
35249µs2112µs
# spent 70µs (27+42) within Foswiki::Templates::BEGIN@35 which was called: # once (27µs+42µs) by Foswiki::templates at line 35
use Assert;
# spent 70µs making 1 call to Foswiki::Templates::BEGIN@35 # spent 42µs making 1 call to Assert::import
36
37247µs19µs
# spent 9µs within Foswiki::Templates::BEGIN@37 which was called: # once (9µs+0s) by Foswiki::templates at line 37
use Foswiki::Attrs ();
# spent 9µ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.
4223.03ms2222µs
# spent 120µs (17+102) within Foswiki::Templates::BEGIN@42 which was called: # once (17µs+102µs) by Foswiki::templates at line 42
use constant TRACE => 0;
# spent 120µs making 1 call to Foswiki::Templates::BEGIN@42 # spent 102µs making 1 call to constant::import
43
4412µsmy $MAX_EXPANSION_RECURSIONS = 999;
45
46=begin TML
47
48---++ ClassMethod new ( $session )
49
50Constructor. Creates a new template database object.
51 * $session - session (Foswiki) object
52
53=cut
54
55
# spent 28µs within Foswiki::Templates::new which was called: # once (28µs+0s) by Foswiki::templates at line 1952 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
sub new {
56533µs my ( $class, $session ) = @_;
57 my $this = bless( { session => $session }, $class );
58
59 $this->{VARS} = { sep => ' | ' };
60 $this->{expansionRecursions} = {};
61 return $this;
62}
63
64=begin TML
65
66---++ ObjectMethod finish()
67Break 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 195µs within Foswiki::Templates::finish which was called: # once (195µs+0s) by Foswiki::finish at line 2100 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
sub finish {
754194µs my $this = shift;
76 undef $this->{VARS};
77 undef $this->{session};
78 undef $this->{expansionRecursions};
79}
80
81=begin TML
82
83---++ ObjectMethod haveTemplate( $name ) -> $boolean
84
85Return true if the template exists and is loaded into the cache
86
87=cut
88
89sub 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 32.5ms (157µs+32.4) within Foswiki::Templates::_expandTrivialTemplate which was called 5 times, avg 6.51ms/call: # 5 times (157µs+32.4ms) by Foswiki::Templates::readTemplate at line 335, avg 6.51ms/call
sub _expandTrivialTemplate {
9925173µs my ( $this, $text ) = @_;
100
101 # SMELL: unchecked implicit untaint?
102521µs $text =~ /%TMPL\:P{(.*)}%/;
# spent 21µs making 5 calls to Foswiki::Templates::CORE:match, avg 4µs/call
1035459µs my $attrs = new Foswiki::Attrs($1);
# spent 459µs making 5 calls to Foswiki::Attrs::new, avg 92µs/call
104
105 # Can't expand context-dependant templates
106 return $text if ( $attrs->{context} );
107531.9ms return $this->tmplP($attrs);
# spent 31.9ms making 5 calls to Foswiki::Templates::tmplP, avg 6.38ms/call
108}
109
110=begin TML
111
112---++ ObjectMethod expandTemplate( $params ) -> $string
113
114Expand the template specified in the parameter string using =tmplP=.
115
116Examples:
117<verbatim>
118$tmpls->expandTemplate("blah");
119$tmpls->expandTemplate(context="view" then="sigh" else="humph");
120</verbatim>
121
122=cut
123
124
# spent 35.3ms (3.21+32.1) within Foswiki::Templates::expandTemplate which was called 142 times, avg 249µs/call: # 131 times (2.91ms+28.1ms) by Foswiki::Templates::tmplP at line 192, avg 237µs/call # 3 times (80µs+878µs) by Foswiki::Func::expandTemplate at line 2441 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 319µs/call # 2 times (63µs+544µs) by Foswiki::LoginManager::_LOGOUT at line 1086 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 304µs/call # once (38µs+1.26ms) by Foswiki::Form::renderForDisplay at line 598 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm # once (21µs+460µs) by Foswiki::Search::loadTemplates at line 496 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (37µs+291µs) by Foswiki::Search::loadTemplates at line 495 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (21µs+210µs) by Foswiki::Form::renderForDisplay at line 618 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm # once (20µs+206µs) by Foswiki::Search::loadTemplates at line 507 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (20µs+200µs) by Foswiki::Form::renderForDisplay at line 600 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm
sub expandTemplate {
1255683.07ms my ( $this, $params ) = @_;
126
12714213.1ms my $attrs = new Foswiki::Attrs($params);
# spent 13.1ms making 142 calls to Foswiki::Attrs::new, avg 92µs/call
1281422.84ms my $value = $this->tmplP($attrs);
# spent 107ms making 142 calls to Foswiki::Templates::tmplP, avg 757µs/call, recursion: max depth 8, sum of overlapping time 105ms
129 return $value;
130}
131
132=begin TML
133
134---+ ObjectMethod tmplP( $attrs ) -> $string
135
136Return value expanded text of the template, as found from looking
137in the register of template definitions. The attrs can contain a template
138name in _DEFAULT, and / or =context=, =then= and =else= values.
139
140Recursively expands any contained TMPL:P tags.
141
142Note that it would be trivial to add template parameters to this,
143simply by iterating over the other parameters (other than _DEFAULT, context,
144then and else) and doing a s/// in the template for that parameter value. This
145would add considerably to the power of templates.
146
147=cut
148
149
# spent 36.0ms (13.5+22.5) within Foswiki::Templates::tmplP which was called 156 times, avg 230µs/call: # 142 times (12.1ms+-9.27ms) by Foswiki::Templates::expandTemplate at line 128, avg 20µs/call # 9 times (800µs+404µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:281] at line 281 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 134µs/call # 5 times (586µs+31.3ms) by Foswiki::Templates::_expandTrivialTemplate at line 107, avg 6.38ms/call
sub tmplP {
15018676.31ms my ( $this, $params ) = @_;
151
1521561.47ms my $template = $params->remove('_DEFAULT') || '';
# spent 1.47ms making 156 calls to Foswiki::Attrs::remove, avg 9µs/call
1531561.33ms my $context = $params->remove('context');
# spent 1.33ms making 156 calls to Foswiki::Attrs::remove, avg 9µs/call
1541561.28ms my $then = $params->remove('then');
# spent 1.28ms making 156 calls to Foswiki::Attrs::remove, avg 8µs/call
1551561.25ms my $else = $params->remove('else');
# spent 1.25ms making 156 calls to Foswiki::Attrs::remove, avg 8µs/call
1563486µs if ($context) {
157 $template = $then if defined($then);
158 foreach my $id ( split( /\,\s*/, $context ) ) {
1593589µs unless ( $this->{session}->{context}->{$id} ) {
160 $template = ( $else || '' );
161 last;
162 }
163 }
164 }
165
166 return '' unless $template;
167
168 $this->{expansionRecursions}->{$template} += 1;
169
170 if ( $this->{expansionRecursions}->{$template} > $MAX_EXPANSION_RECURSIONS )
171 {
172 throw Foswiki::OopsException(
173 'attention',
174 def => 'template_recursion',
175 params => [$template]
176 );
177 }
178
179 my $val = '';
1806004.66ms if ( exists( $this->{VARS}->{$template} ) ) {
181 $val = $this->{VARS}->{$template};
182 $val = "<!--$template-->\n$val<!--/$template-->\n" if (TRACE);
183 foreach my $p ( keys %$params ) {
1843162.97ms if ( $p eq 'then' || $p eq 'else' ) {
185 $val =~ s/%$p%/$this->expandTemplate($1)/ge;
186 }
187 elsif ( defined( $params->{$p} ) ) {
1881227µs336787µs $val =~ s/%$p%/$params->{$p}/ge;
# spent 410µs making 158 calls to Foswiki::Templates::CORE:regcomp, avg 3µs/call # spent 324µs making 158 calls to Foswiki::Templates::CORE:subst, avg 2µs/call # spent 52µs making 20 calls to Foswiki::Templates::CORE:substcont, avg 3µs/call
189 }
190 }
191150263µs $val =~ s/%TMPL:PREV%/%TMPL:P{"$template:_PREV"}%/g;
# spent 263µs making 150 calls to Foswiki::Templates::CORE:subst, avg 2µs/call
192131729µs47932.3ms $val =~ s/%TMPL:P{(.*?)}%/$this->expandTemplate($1)/ge;
# spent 119ms making 131 calls to Foswiki::Templates::expandTemplate, avg 911µs/call, recursion: max depth 7, sum of overlapping time 88.4ms # spent 822µs making 198 calls to Foswiki::Templates::CORE:substcont, avg 4µs/call # spent 466µs making 150 calls to Foswiki::Templates::CORE:subst, avg 3µs/call
193 }
194
195 return $val;
196}
197
198=begin TML
199
200---++ ObjectMethod readTemplate ( $name, %options ) -> $text
201
202Reads a template, loading the definitions therein.
203
204Return value: expanded template text
205
206By default throws an OopsException if the template was not found or the
207access controls denied access.
208
209%options include:
210 * =skin= - skin name,
211 * =web= - web to search
212 * =no_oops= - if true, will not throw an exception. Instead, returns undef.
213
214If template text is found, extracts include statements and fully expands them.
215Also extracts template definitions and adds them to the
216list of loaded templates, overwriting any previous definition.
217
218=cut
219
220
# spent 554ms (25.5+529) within Foswiki::Templates::readTemplate which was called 4 times, avg 139ms/call: # once (3.10ms+426ms) by Foswiki::Func::loadTemplate at line 2409 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm # once (20.5ms+90.6ms) by Foswiki::UI::View::view at line 229 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (1.12ms+7.80ms) by Foswiki::Search::loadTemplates at line 480 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (777µs+4.08ms) by Foswiki::Form::renderForDisplay at line 596 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm
sub readTemplate {
221682.02ms my ( $this, $name, %opts ) = @_;
222416µs ASSERT($name) if DEBUG;
# spent 16µs making 4 calls to Assert::ASSERTS_OFF, avg 4µs/call
22341.68ms my $skins = $opts{skins} || $this->{session}->getSkin();
# spent 1.68ms making 4 calls to Foswiki::getSkin, avg 419µs/call
224 my $web = $opts{web} || $this->{session}->{webName};
225
226 $this->{files} = ();
227
228 # recursively read template file(s)
229418.5ms my $text = _readTemplateFile( $this, $name, $skins, $web );
# spent 18.5ms making 4 calls to Foswiki::Templates::_readTemplateFile, avg 4.62ms/call
230
231 # Check file was found
232 unless ( defined $text ) {
233
234 # if no_oops is given, return undef silently
235 if ( $opts{no_oops} ) {
236 return undef;
237 }
238 else {
239 throw Foswiki::OopsException(
240 'attention',
241 def => 'no_such_template',
242 params => [
243 $name,
244
245 # More info for overridable templates
246 ( $name =~ /^(view|edit)$/ ) ? $name . '_TEMPLATE' : ''
247 ]
248 );
249 }
250 }
251
252 # SMELL: unchecked implicit untaint?
253434µs while ( $text =~ /%TMPL\:INCLUDE{[\s\"]*(.*?)[\"\s]*}%/s ) {
# spent 34µs making 4 calls to Foswiki::Templates::CORE:match, avg 8µs/call
254261.17ms46789µs $text =~ s/%TMPL\:INCLUDE{[\s\"]*(.*?)[\"\s]*}%/
# spent 485µs making 26 calls to Foswiki::Templates::CORE:substcont, avg 19µs/call # spent 157µs making 10 calls to Foswiki::Templates::CORE:match, avg 16µs/call # spent 147µs making 10 calls to Foswiki::Templates::CORE:subst, avg 15µs/call
25516468ms _readTemplateFile( $this, $1, $skins, $web ) || ''/ge;
# spent 468ms making 16 calls to Foswiki::Templates::_readTemplateFile, avg 29.3ms/call
256 }
257
258416µs if ( $text !~ /%TMPL\:/ ) {
# spent 16µs making 4 calls to Foswiki::Templates::CORE:match, avg 4µs/call
259
260 # no %TMPL's to process
261
262 # SMELL: legacy - leading spaces to tabs, should not be required
263 $text =~ s|^(( {3})+)|"\t" x (length($1)/3)|geom;
264
265 return $text;
266 }
267
268 my $result = '';
269 my $key = '';
270 my $val = '';
271 my $delim = '';
272 foreach ( split( /(%TMPL\:)/, $text ) ) {
273571129.6ms29086.68ms if (/^(%TMPL\:)$/) {
# spent 6.68ms making 2908 calls to Foswiki::Templates::CORE:match, avg 2µs/call
274 $delim = $1;
275 }
276 elsif ( (/^DEF{[\s\"]*(.*?)[\"\s]*}%(.*)/s) && ($1) ) {
277
278 # handle %TMPL:DEF{key}%
279 if ($key) {
280
281 # if the key is already defined, rename the existing
282 # template to key:_PREV
283 my $new_value = $val;
284 my $prev_key = $key;
285 my $prev_value = $this->{VARS}->{$prev_key};
286 $this->{VARS}->{$prev_key} = $new_value;
287 while ($prev_value) {
288 $new_value = $prev_value;
289 $prev_key = "$prev_key:_PREV";
290 $prev_value = $this->{VARS}->{$prev_key};
291 $this->{VARS}->{$prev_key} = $new_value;
292 }
293
294 }
295 $key = $1;
296
297 # SMELL: unchecked implicit untaint?
298 $val = $2;
299
300 }
301 elsif (/^END%[\s\n\r]*(.*)/s) {
302
303 # handle %TMPL:END%
304
305 # if the key is already defined, rename the existing template to
306 # key:_PREV
307 my $new_value = $val;
308 my $prev_key = $key;
309 my $prev_value = $this->{VARS}->{$prev_key};
310 $this->{VARS}->{$prev_key} = $new_value;
311 while ($prev_value) {
312192426µs $new_value = $prev_value;
313 $prev_key = "$prev_key:_PREV";
314 $prev_value = $this->{VARS}->{$prev_key};
315 $this->{VARS}->{$prev_key} = $new_value;
316 }
317
318 $key = '';
319 $val = '';
320
321 # SMELL: unchecked implicit untaint?
322 $result .= $1;
323
324 }
325 elsif ($key) {
326 $val .= "$delim$_";
327
328 }
329 else {
330 $result .= "$delim$_";
331 }
332 }
333
334 # handle %TMPL:P{"..."}% recursively
335530µs1532.6ms $result =~ s/(%TMPL\:P{.*?}%)/_expandTrivialTemplate( $this, $1)/geo;
# spent 32.5ms making 5 calls to Foswiki::Templates::_expandTrivialTemplate, avg 6.51ms/call # spent 55µs making 6 calls to Foswiki::Templates::CORE:substcont, avg 9µs/call # spent 18µs making 4 calls to Foswiki::Templates::CORE:subst, avg 5µs/call
336
337 # SMELL: legacy - leading spaces to tabs, should not be required
338520µs11151µs $result =~ s|^(( {3})+)|"\t" x (length($1)/3)|geom;
# spent 83µs making 4 calls to Foswiki::Templates::CORE:subst, avg 21µs/call # spent 68µs making 7 calls to Foswiki::Templates::CORE:substcont, avg 10µs/call
339
340 $this->saveTemplateToCache( '_complete', $name, $skins, $web, $result )
341 if (TRACE);
342 return $result;
343}
344
345# STATIC: Return value: raw template text, or undef if read fails
346
# spent 487ms (20.4+467) within Foswiki::Templates::_readTemplateFile which was called 20 times, avg 24.3ms/call: # 16 times (16.2ms+452ms) by Foswiki::Templates::readTemplate at line 255, avg 29.3ms/call # 4 times (4.25ms+14.2ms) by Foswiki::Templates::readTemplate at line 229, avg 4.62ms/call
sub _readTemplateFile {
3473622.40ms my ( $this, $name, $skins, $web ) = @_;
348 my $session = $this->{session};
349
350 # SMELL: not i18n-friendly (can't have accented characters in template name)
351 # zap anything suspicious
3522058µs $name =~ s/[^A-Za-z0-9_,.\/]//go;
# spent 58µs making 20 calls to Foswiki::Templates::CORE:subst, avg 3µs/call
353
354 # if the name ends in .tmpl, then this is an explicit include from
355 # the templates directory. No further searching required.
3562044µs if ( $name =~ /\.tmpl$/ ) {
# spent 44µs making 20 calls to Foswiki::Templates::CORE:match, avg 2µs/call
357 my $text =
358 _decomment(
359 _readFile( $session, "$Foswiki::cfg{TemplateDir}/$name" ) );
360 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
361 if (TRACE);
362 return $text;
363 }
364
365 my $userdirweb = $web;
366 my $userdirname = $name;
36740289µs2033µs if ( $name =~ /^(.+)\.(.+?)$/ ) {
# spent 33µs making 20 calls to Foswiki::Templates::CORE:match, avg 2µs/call
368
369 # ucfirst taints if use locale is in force
370 $userdirweb = Foswiki::Sandbox::untaintUnchecked( ucfirst($1) );
371 $userdirname = Foswiki::Sandbox::untaintUnchecked( ucfirst($2) );
372
373 # if the name can be parsed into $web.$name, then this is an attempt
374 # to explicit include that topic. No further searching required.
375 if ( $session->topicExists( $userdirweb, $userdirname ) ) {
376 my $meta =
377 Foswiki::Meta->load( $session, $userdirweb, $userdirname );
378
379 # Check we are allowed access
380 unless ( $meta->haveAccess( 'VIEW', $session->{user} ) ) {
381 return $this->{session}->inlineAlert( 'alerts', 'access_denied',
382 "$userdirweb.$userdirname" );
383 }
384 my $text = $meta->text();
385 $text = '' unless defined $text;
386
387 $text =
388 "<!--$userdirweb/$userdirname-->\n"
389 . $text
390 . "<!--/$userdirweb/$userdirname-->\n"
391 if (TRACE);
392
393 $text = _decomment($text);
394 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
395 if (TRACE);
396 return $text;
397 }
398 }
399 else {
400
401 # ucfirst taints if use locale is in force
40220403µs $userdirweb =
# spent 403µs making 20 calls to Foswiki::Sandbox::untaintUnchecked, avg 20µs/call
403 Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirweb) );
40420293µs $userdirname =
# spent 293µs making 20 calls to Foswiki::Sandbox::untaintUnchecked, avg 15µs/call
405 Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirname) );
406 }
407
408 my @skinList = split( /\,\s*/, $skins );
409 my $nrskins = $#skinList;
410
411 my @templatePath = split( /\s*,\s*/, $Foswiki::cfg{TemplatePath} );
412 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 my @candidates = ();
428
429 $nrskins = 0 if $nrskins < 0;
430
431 my $nrtemplates = $#templatePath;
432
4331601.55ms for ( my $templateixd = 0 ; $templateixd <= $nrtemplates ; $templateixd++ )
434 {
435352015.1ms for ( my $idx = 0 ; $idx <= $nrskins ; $idx++ ) {
436 my $file = $templatePath[$templateixd];
437 my $userdir = 0;
438
439 # also need to do %PUBURL% etc.?
440 # push the first time even if not modified
441 my $skin = $skinList[$idx] || '';
442
443 # consider skin templates first
444 # this is done by giving the template path with 'skin' in it
445 # a higher sort priority (so a lower number: 0)
446320580µs my $isSkinned = ( $file =~ m/\$skin/ ? 0 : 1 );
# spent 580µs making 320 calls to Foswiki::Templates::CORE:match, avg 2µs/call
447
448 my $webName = $web || '';
449 my $tmplName = $name || '';
4506401.60ms320632µs unless ( $file =~ m/.tmpl$/ ) {
# spent 632µs making 320 calls to Foswiki::Templates::CORE:match, avg 2µs/call
451
452 # Could also use $Skin, $Web, $Name to indicate uppercase
453 $userdir = 1;
454
455 # Again untainting when using ucfirst
4561602.47ms $skin = Foswiki::Sandbox::untaintUnchecked( ucfirst($skin) );
# spent 2.47ms making 160 calls to Foswiki::Sandbox::untaintUnchecked, avg 15µs/call
457 $webName = $userdirweb;
458 $tmplName = $userdirname;
459 }
460320958µs $file =~ s/\$skin/$skin/go;
# spent 958µs making 320 calls to Foswiki::Templates::CORE:subst, avg 3µs/call
461320940µs $file =~ s/\$web/$webName/go;
# spent 940µs making 320 calls to Foswiki::Templates::CORE:subst, avg 3µs/call
4623201.15ms $file =~ s/\$name/$tmplName/go;
# spent 1.15ms making 320 calls to Foswiki::Templates::CORE:subst, avg 4µs/call
463
464# sort priority is:
465# primary: if template path has 'skin' in it; so that skin templates are considered first
466# secondary: the skin order number
467# tertiary: the template path order number
468
469 push(
470 @candidates,
471 {
472 primary => $isSkinned,
473 secondary => $idx,
474 tertiary => $templateixd,
475 file => $file,
476 userdir => $userdir,
477 skin => $skin
478 }
479 );
480 }
481 }
482
48321.47ms26.06ms
# spent 5.99ms (5.47+518µs) within Foswiki::Templates::BEGIN@483 which was called: # once (5.47ms+518µs) by Foswiki::templates at line 483
use Sort::Maker;
# spent 5.99ms making 1 call to Foswiki::Templates::BEGIN@483 # spent 73µs making 1 call to Exporter::import
4842017.6ms my $sorter = make_sorter(
# spent 17.6ms making 20 calls to Sort::Maker::make_sorter, avg 878µs/call
485 qw( ST ),
486 number => '$_->{primary}',
487 number => '$_->{secondary}',
488 number => '$_->{tertiary}'
489 );
490
491 # sort
492205.95ms @candidates = $sorter->(@candidates);
493
494 foreach my $candidate (@candidates) {
4953441.84ms my $file = $candidate->{file};
496
4972101.89ms102600µs if ( $candidate->{userdir} ) {
# spent 600µs making 102 calls to Foswiki::Templates::CORE:ftis, avg 6µs/call
498
499704.25ms my ( $web1, $name1 ) =
# spent 4.25ms making 70 calls to Foswiki::normalizeWebTopicName, avg 61µs/call
500 $session->normalizeWebTopicName( $web, $file );
501
50224551µs7011.0ms if ( $session->topicExists( $web1, $name1 ) ) {
# spent 11.0ms making 70 calls to Foswiki::topicExists, avg 157µs/call
503
504 # recursion prevention.
505 next
506 if (
507 defined(
508 $this->{files}
509 ->{ 'topic' . $session->{user}, $name1, $web1 }
510 )
511 );
512 $this->{files}->{ 'topic' . $session->{user}, $name1, $web1 } =
513 1;
514
515 # access control
5163409ms my $meta = Foswiki::Meta->load( $session, $web1, $name1 );
# spent 409ms making 3 calls to Foswiki::Meta::load, avg 136ms/call
51737.78ms next unless $meta->haveAccess( 'VIEW', $session->{user} );
# spent 7.78ms making 3 calls to Foswiki::Meta::haveAccess, avg 2.59ms/call
518
5193104µs my $text = $meta->text();
# spent 104µs making 3 calls to Foswiki::Meta::text, avg 35µs/call
520 $text = '' unless defined $text;
521
522 $text = "<!--$web1.$name1-->\n$text<!--/$web1.$name1-->\n"
523 if (TRACE);
524
5253130µs $text = _decomment($text);
# spent 130µs making 3 calls to Foswiki::Templates::_decomment, avg 43µs/call
526 $this->saveTemplateToCache( '_cache', $name, $skins, $web,
527 $text )
528 if (TRACE);
529 return $text;
530 }
531 }
532 elsif ( -e $file ) {
533 next if ( defined( $this->{files}->{$file} ) );
534
535 # recursion prevention.
536 $this->{files}->{$file} = 1;
537
538302.63ms my $text = _decomment( _readFile( $session, $file ) );
# spent 1.35ms making 15 calls to Foswiki::Templates::_decomment, avg 90µs/call # spent 1.28ms making 15 calls to Foswiki::Templates::_readFile, avg 85µs/call
539 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
540 if (TRACE);
541 return $text;
542 }
543 }
544
545 # File was not found
546 return undef;
547}
548
549
# spent 1.28ms (625µs+653µs) within Foswiki::Templates::_readFile which was called 15 times, avg 85µs/call: # 15 times (625µs+653µs) by Foswiki::Templates::_readTemplateFile at line 538, avg 85µs/call
sub _readFile {
55045522µs my ( $session, $fn ) = @_;
551 my $F;
552
55360760µs15310µs if ( open( $F, '<', $fn ) ) {
# spent 310µs making 15 calls to Foswiki::Templates::CORE:open, avg 21µs/call
554 local $/;
55515269µs my $text = <$F>;
# spent 269µs making 15 calls to Foswiki::Templates::CORE:readline, avg 18µs/call
5561575µs close($F);
# spent 75µs making 15 calls to Foswiki::Templates::CORE:close, avg 5µs/call
557
558 $text = "<!--$fn-->\n$text<!--/$fn-->\n" if (TRACE);
559
560 return $text;
561 }
562 else {
563 $session->logger->log( 'warning', "$fn: $!" );
564 return undef;
565 }
566}
567
568
# spent 1.48ms (389µs+1.09) within Foswiki::Templates::_decomment which was called 18 times, avg 82µs/call: # 15 times (303µs+1.05ms) by Foswiki::Templates::_readTemplateFile at line 538, avg 90µs/call # 3 times (86µs+44µs) by Foswiki::Templates::_readTemplateFile at line 525, avg 43µs/call
sub _decomment {
569721.49ms my $text = shift;
570
571 return $text unless $text;
572
573 # Kill comments, marked by %{ ... }%
574 # (and remove whitespace either side of the comment)
575181.09ms $text =~ s/\s*%{.*?}%\s*//sg;
# spent 1.09ms making 18 calls to Foswiki::Templates::CORE:subst, avg 61µs/call
576 return $text;
577}
578
579#See http://wikiring.com/Blog/BlogEntry8?cat=WikiRing
580#used for debugging templates, and later maybe for speed.
581sub saveTemplateToCache {
582 my ( $this, $cacheName, $name, $skins, $web, $tmplText ) = @_;
583 $skins = '' unless ( defined($skins) );
584 $web = '' unless ( defined($web) );
585
586 my $tmpl_cachedir = $Foswiki::cfg{TemplateDir} . $cacheName;
587 mkdir($tmpl_cachedir) unless ( -e $tmpl_cachedir );
588 my $filename = Foswiki::Sandbox::untaintUnchecked(
589 $tmpl_cachedir . '/' . $name . '__' . $skins . '__' . $web . '.tmpl' );
590
591 unless ( open( FILE, ">$filename" ) ) {
592 die "Can't create file $filename - $!\n" if DEBUG;
593 print STDERR "Can't create file $filename - $!\n";
594
595 return;
596 }
597 print FILE $tmplText;
598 close(FILE);
599}
600
601#unused, but can be used for a speedup by caching the expanded Template
602sub getTemplateFromCache {
603 my ( $this, $name, $skins, $web ) = @_;
604 $skins = '' unless ( defined($skins) );
605 $web = '' unless ( defined($web) );
606
607 my $tmpl_cachedir = $Foswiki::cfg{TemplateDir} . '_cache';
608 mkdir($tmpl_cachedir) unless ( -e $tmpl_cachedir );
609 my $filename = Foswiki::Sandbox::untaintUnchecked(
610 $tmpl_cachedir . '/' . $name . '__' . $skins . '__' . $web . '.tmpl' );
611
612 if ( -e $filename ) {
613 open( IN_FILE, "<$filename" ) || return;
614 local $/ = undef; # set to read to EOF
615 my $data = <IN_FILE>;
616 close(IN_FILE);
617 return $data;
618 }
619}
620
62115µs1;
622__END__
 
# spent 75µs within Foswiki::Templates::CORE:close which was called 15 times, avg 5µs/call: # 15 times (75µs+0s) by Foswiki::Templates::_readFile at line 556, avg 5µs/call
sub Foswiki::Templates::CORE:close; # opcode
# spent 600µs within Foswiki::Templates::CORE:ftis which was called 102 times, avg 6µs/call: # 102 times (600µs+0s) by Foswiki::Templates::_readTemplateFile at line 497, avg 6µs/call
sub Foswiki::Templates::CORE:ftis; # opcode
# spent 8.20ms within Foswiki::Templates::CORE:match which was called 3611 times, avg 2µs/call: # 2908 times (6.68ms+0s) by Foswiki::Templates::readTemplate at line 273, avg 2µs/call # 320 times (632µs+0s) by Foswiki::Templates::_readTemplateFile at line 450, avg 2µs/call # 320 times (580µs+0s) by Foswiki::Templates::_readTemplateFile at line 446, avg 2µs/call # 20 times (44µs+0s) by Foswiki::Templates::_readTemplateFile at line 356, avg 2µs/call # 20 times (33µs+0s) by Foswiki::Templates::_readTemplateFile at line 367, avg 2µs/call # 10 times (157µs+0s) by Foswiki::Templates::readTemplate at line 254, avg 16µs/call # 5 times (21µs+0s) by Foswiki::Templates::_expandTrivialTemplate at line 102, avg 4µs/call # 4 times (34µs+0s) by Foswiki::Templates::readTemplate at line 253, avg 8µs/call # 4 times (16µs+0s) by Foswiki::Templates::readTemplate at line 258, avg 4µs/call
sub Foswiki::Templates::CORE:match; # opcode
# spent 310µs within Foswiki::Templates::CORE:open which was called 15 times, avg 21µs/call: # 15 times (310µs+0s) by Foswiki::Templates::_readFile at line 553, avg 21µs/call
sub Foswiki::Templates::CORE:open; # opcode
# spent 269µs within Foswiki::Templates::CORE:readline which was called 15 times, avg 18µs/call: # 15 times (269µs+0s) by Foswiki::Templates::_readFile at line 555, avg 18µs/call
sub Foswiki::Templates::CORE:readline; # opcode
# spent 410µs within Foswiki::Templates::CORE:regcomp which was called 158 times, avg 3µs/call: # 158 times (410µs+0s) by Foswiki::Templates::tmplP at line 188, avg 3µs/call
sub Foswiki::Templates::CORE:regcomp; # opcode
# spent 5.50ms within Foswiki::Templates::CORE:subst which was called 1474 times, avg 4µs/call: # 320 times (1.15ms+0s) by Foswiki::Templates::_readTemplateFile at line 462, avg 4µs/call # 320 times (958µs+0s) by Foswiki::Templates::_readTemplateFile at line 460, avg 3µs/call # 320 times (940µs+0s) by Foswiki::Templates::_readTemplateFile at line 461, avg 3µs/call # 158 times (324µs+0s) by Foswiki::Templates::tmplP at line 188, avg 2µs/call # 150 times (466µs+0s) by Foswiki::Templates::tmplP at line 192, avg 3µs/call # 150 times (263µs+0s) by Foswiki::Templates::tmplP at line 191, avg 2µs/call # 20 times (58µs+0s) by Foswiki::Templates::_readTemplateFile at line 352, avg 3µs/call # 18 times (1.09ms+0s) by Foswiki::Templates::_decomment at line 575, avg 61µs/call # 10 times (147µs+0s) by Foswiki::Templates::readTemplate at line 254, avg 15µs/call # 4 times (83µs+0s) by Foswiki::Templates::readTemplate at line 338, avg 21µs/call # 4 times (18µs+0s) by Foswiki::Templates::readTemplate at line 335, avg 5µs/call
sub Foswiki::Templates::CORE:subst; # opcode
# spent 1.48ms within Foswiki::Templates::CORE:substcont which was called 257 times, avg 6µs/call: # 198 times (822µs+0s) by Foswiki::Templates::tmplP at line 192, avg 4µs/call # 26 times (485µs+0s) by Foswiki::Templates::readTemplate at line 254, avg 19µs/call # 20 times (52µs+0s) by Foswiki::Templates::tmplP at line 188, avg 3µs/call # 7 times (68µs+0s) by Foswiki::Templates::readTemplate at line 338, avg 10µs/call # 6 times (55µs+0s) by Foswiki::Templates::readTemplate at line 335, avg 9µs/call
sub Foswiki::Templates::CORE:substcont; # opcode