Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Attrs.pm |
Statements | Executed 11858 statements in 68.8ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
585 | 8 | 4 | 42.6ms | 57.1ms | new | Foswiki::Attrs::
2652 | 6 | 1 | 7.04ms | 7.04ms | CORE:subst (opcode) | Foswiki::Attrs::
744 | 5 | 2 | 6.45ms | 6.45ms | remove | Foswiki::Attrs::
1727 | 3 | 1 | 3.71ms | 3.71ms | CORE:regcomp (opcode) | Foswiki::Attrs::
764 | 3 | 1 | 1.92ms | 1.92ms | CORE:substcont (opcode) | Foswiki::Attrs::
871 | 2 | 1 | 1.87ms | 1.87ms | CORE:match (opcode) | Foswiki::Attrs::
20 | 1 | 1 | 1.49ms | 1.71ms | stringify | Foswiki::Attrs::
20 | 1 | 1 | 118µs | 118µs | CORE:sort (opcode) | Foswiki::Attrs::
1 | 1 | 1 | 53µs | 70µs | BEGIN@49 | Foswiki::Attrs::
1 | 1 | 1 | 37µs | 75µs | BEGIN@50 | Foswiki::Attrs::
1 | 1 | 1 | 30µs | 106µs | BEGIN@51 | Foswiki::Attrs::
0 | 0 | 0 | 0s | 0s | extractValue | Foswiki::Attrs::
0 | 0 | 0 | 0s | 0s | get | Foswiki::Attrs::
0 | 0 | 0 | 0s | 0s | isEmpty | Foswiki::Attrs::
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::Attrs | ||||
6 | |||||
7 | Class of attribute sets, designed for parsing and storing attribute values | ||||
8 | from a macro e.g. =%<nop>MACRO{"joe" fred="bad" joe="mad"}%= | ||||
9 | |||||
10 | An attribute set is a hash containing an entry for each parameter. The | ||||
11 | default parameter (unnamed quoted string) is named <code>_<nop>DEFAULT</code> in the hash. | ||||
12 | |||||
13 | Attributes declared later in the string will override those of the same | ||||
14 | name defined earlier. The one exception to this is the _DEFAULT key, where | ||||
15 | the _first_ instance is always taken. | ||||
16 | |||||
17 | As well as the default Foswiki syntax (parameter values double-quoted) | ||||
18 | this class also parses single-quoted values, unquoted spaceless | ||||
19 | values, spaces around the =, and commas as well as spaces separating values. | ||||
20 | The extended syntax has to be enabled by passing the =$friendly= parameter | ||||
21 | to =new=. | ||||
22 | |||||
23 | API version $Date$ (revision $Rev$) | ||||
24 | |||||
25 | *Since* _date_ indicates where functions or parameters have been added since | ||||
26 | the baseline of the API (TWiki release 4.2.3). The _date_ indicates the | ||||
27 | earliest date of a Foswiki release that will support that function or | ||||
28 | parameter. | ||||
29 | |||||
30 | *Deprecated* _date_ indicates where a function or parameters has been | ||||
31 | [[http://en.wikipedia.org/wiki/Deprecation][deprecated]]. Deprecated | ||||
32 | functions will still work, though they should | ||||
33 | _not_ be called in new plugins and should be replaced in older plugins | ||||
34 | as soon as possible. Deprecated parameters are simply ignored in Foswiki | ||||
35 | releases after _date_. | ||||
36 | |||||
37 | *Until* _date_ indicates where a function or parameter has been removed. | ||||
38 | The _date_ indicates the latest date at which Foswiki releases still supported | ||||
39 | the function or parameter. | ||||
40 | |||||
41 | =cut | ||||
42 | |||||
43 | # THIS PACKAGE IS PART OF THE PUBLISHED API USED BY EXTENSION AUTHORS. | ||||
44 | # DO NOT CHANGE THE EXISTING APIS (well thought out extensions are OK) | ||||
45 | # AND ENSURE ALL POD DOCUMENTATION IS COMPLETE AND ACCURATE. | ||||
46 | |||||
47 | package Foswiki::Attrs; | ||||
48 | |||||
49 | 2 | 72µs | 2 | 88µs | # spent 70µs (53+17) within Foswiki::Attrs::BEGIN@49 which was called:
# once (53µs+17µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 49 # spent 70µs making 1 call to Foswiki::Attrs::BEGIN@49
# spent 17µs making 1 call to strict::import |
50 | 2 | 62µs | 2 | 114µs | # spent 75µs (37+39) within Foswiki::Attrs::BEGIN@50 which was called:
# once (37µs+39µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 50 # spent 75µs making 1 call to Foswiki::Attrs::BEGIN@50
# spent 38µs making 1 call to warnings::import |
51 | 2 | 1.60ms | 2 | 182µs | # spent 106µs (30+76) within Foswiki::Attrs::BEGIN@51 which was called:
# once (30µs+76µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 51 # spent 106µs making 1 call to Foswiki::Attrs::BEGIN@51
# spent 76µs making 1 call to Assert::import |
52 | |||||
53 | 1 | 2µs | our $VERSION = '$Rev$'; | ||
54 | |||||
55 | 1 | 2µs | our $ERRORKEY = '_ERROR'; | ||
56 | 1 | 2µs | our $DEFAULTKEY = '_DEFAULT'; | ||
57 | 1 | 1µs | our $RAWKEY = '_RAW'; | ||
58 | 1 | 1µs | our $MARKER = "\0"; | ||
59 | |||||
60 | =begin TML | ||||
61 | |||||
62 | ---++ ClassMethod new ($string) => \%attrsObjectRef | ||||
63 | |||||
64 | * =$string= - String containing attribute specification | ||||
65 | |||||
66 | Parse a standard attribute string containing name=value pairs and create a new | ||||
67 | attributes object. The value may be a word or a quoted string. If there is an | ||||
68 | error during parsing, the parse will complete but $attrs->{_ERROR} will be | ||||
69 | set in the new object. $attrs->{_RAW} will always contain the full unprocessed | ||||
70 | $string. | ||||
71 | |||||
72 | =cut | ||||
73 | |||||
74 | # spent 57.1ms (42.6+14.4) within Foswiki::Attrs::new which was called 585 times, avg 98µs/call:
# 359 times (24.4ms+8.79ms) by Foswiki::_expandMacroOnTopicRendering at line 3065 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 92µs/call
# 142 times (10.00ms+3.10ms) by Foswiki::Templates::expandTemplate at line 127 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 92µs/call
# 30 times (2.18ms+601µs) by Foswiki::parseSections at line 2308 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 93µs/call
# 30 times (2.02ms+561µs) by Foswiki::parseSections at line 2340 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 86µs/call
# 13 times (2.84ms+983µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 270 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/VC/Handler.pm, avg 294µs/call
# 5 times (363µs+96µs) by Foswiki::Templates::_expandTrivialTemplate at line 103 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 92µs/call
# 3 times (615µs+224µs) by Foswiki::Func::extractParameters at line 2944 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 280µs/call
# 3 times (256µs+78µs) by Foswiki::_expandMacroOnTopicRendering at line 3069 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm, avg 111µs/call | ||||
75 | 8430 | 57.8ms | my ( $class, $string, $friendly ) = @_; | ||
76 | my $this = bless( {}, $class ); | ||||
77 | |||||
78 | $this->{$RAWKEY} = $string; | ||||
79 | |||||
80 | return $this unless defined($string); | ||||
81 | |||||
82 | 527 | 1.21ms | $string =~ s/\\(["'])/$MARKER.sprintf("%.2u", ord($1))/ge; # escapes # spent 1.02ms making 468 calls to Foswiki::Attrs::CORE:subst, avg 2µs/call
# spent 186µs making 59 calls to Foswiki::Attrs::CORE:substcont, avg 3µs/call | ||
83 | |||||
84 | my $sep = ( $friendly ? "[\\s,]" : "\\s" ); | ||||
85 | my $first = 1; | ||||
86 | |||||
87 | 1039 | 3.51ms | if ( !$friendly && $string =~ s/^\s*\"(.*?)\"\s*(\w+\s*=\s*\"|$)/$2/s ) { # spent 1.94ms making 393 calls to Foswiki::Attrs::CORE:subst, avg 5µs/call
# spent 1.57ms making 646 calls to Foswiki::Attrs::CORE:substcont, avg 2µs/call | ||
88 | $this->{$DEFAULTKEY} = $1; | ||||
89 | } | ||||
90 | 468 | 959µs | while ( $string =~ m/\S/s ) { # spent 959µs making 468 calls to Foswiki::Attrs::CORE:match, avg 2µs/call | ||
91 | |||||
92 | # name="value" pairs | ||||
93 | 1439 | 5.06ms | if ( $string =~ s/^$sep*(\w+)\s*=\s*\"(.*?)\"//is ) { # spent 2.09ms making 518 calls to Foswiki::Attrs::CORE:subst, avg 4µs/call
# spent 2.05ms making 518 calls to Foswiki::Attrs::CORE:regcomp, avg 4µs/call
# spent 914µs making 403 calls to Foswiki::Attrs::CORE:match, avg 2µs/call | ||
94 | $this->{$1} = $2; | ||||
95 | $first = 0; | ||||
96 | } | ||||
97 | |||||
98 | # simple double-quoted value with no name, sets the default | ||||
99 | elsif ( $string =~ s/^$sep*\"(.*?)\"//os ) { | ||||
100 | $this->{$DEFAULTKEY} = $1 | ||||
101 | unless defined( $this->{$DEFAULTKEY} ); | ||||
102 | $first = 0; | ||||
103 | } | ||||
104 | |||||
105 | elsif ($friendly) { | ||||
106 | |||||
107 | # name='value' pairs | ||||
108 | 30 | 151µs | if ( $string =~ s/^$sep*(\w+)\s*=\s*'(.*?)'//is ) { # spent 91µs making 15 calls to Foswiki::Attrs::CORE:regcomp, avg 6µs/call
# spent 60µs making 15 calls to Foswiki::Attrs::CORE:subst, avg 4µs/call | ||
109 | $this->{$1} = $2; | ||||
110 | } | ||||
111 | |||||
112 | # name=value pairs | ||||
113 | elsif ( $string =~ s/^$sep*(\w+)\s*=\s*([^\s,\}\'\"]*)//is ) { | ||||
114 | $this->{$1} = $2; | ||||
115 | } | ||||
116 | |||||
117 | # simple single-quoted value with no name, sets the default | ||||
118 | elsif ( $string =~ s/^$sep*'(.*?)'//os ) { | ||||
119 | $this->{$DEFAULTKEY} = $1 | ||||
120 | unless defined( $this->{$DEFAULTKEY} ); | ||||
121 | } | ||||
122 | |||||
123 | # simple name with no value (boolean, or _DEFAULT) | ||||
124 | elsif ( $string =~ s/^$sep*([a-z]\w*)\b//is ) { | ||||
125 | my $key = $1; | ||||
126 | $this->{$key} = 1; | ||||
127 | } | ||||
128 | |||||
129 | # otherwise the whole string - sans padding - is the default | ||||
130 | else { | ||||
131 | |||||
132 | # SMELL: unchecked implicit untaint? | ||||
133 | if ( $string =~ m/^\s*(.*?)\s*$/s | ||||
134 | && !defined( $this->{$DEFAULTKEY} ) ) | ||||
135 | { | ||||
136 | $this->{$DEFAULTKEY} = $1; | ||||
137 | } | ||||
138 | last; | ||||
139 | } | ||||
140 | } | ||||
141 | |||||
142 | # SMELL: unchecked implicit untaint? | ||||
143 | elsif ( $string =~ m/^\s*(.*?)\s*$/s ) { | ||||
144 | $this->{$DEFAULTKEY} = $1 if ($first); | ||||
145 | last; | ||||
146 | } | ||||
147 | } | ||||
148 | foreach my $k ( keys %$this ) { | ||||
149 | 2447 | 3.55ms | $this->{$k} =~ s/$MARKER(\d\d)/chr($1)/geo; # escapes # spent 1.82ms making 1194 calls to Foswiki::Attrs::CORE:subst, avg 2µs/call
# spent 1.56ms making 1194 calls to Foswiki::Attrs::CORE:regcomp, avg 1µs/call
# spent 163µs making 59 calls to Foswiki::Attrs::CORE:substcont, avg 3µs/call | ||
150 | } | ||||
151 | return $this; | ||||
152 | } | ||||
153 | |||||
154 | =begin TML | ||||
155 | |||||
156 | ---++ ObjectMethod isEmpty() -> boolean | ||||
157 | |||||
158 | Return false if attribute set is not empty. | ||||
159 | |||||
160 | =cut | ||||
161 | |||||
162 | sub isEmpty { | ||||
163 | my $this = shift; | ||||
164 | |||||
165 | foreach my $k ( keys %$this ) { | ||||
166 | return 0 if $k ne $RAWKEY; | ||||
167 | } | ||||
168 | return 1; | ||||
169 | } | ||||
170 | |||||
171 | =begin TML | ||||
172 | |||||
173 | ---++ ObjectMethod remove($key) -> $value | ||||
174 | |||||
175 | * =$key= - Attribute to remove | ||||
176 | Remove an attr value from the map, return old value. After a call to | ||||
177 | =remove= the attribute is no longer defined. | ||||
178 | |||||
179 | =cut | ||||
180 | |||||
181 | # spent 6.45ms within Foswiki::Attrs::remove which was called 744 times, avg 9µs/call:
# 156 times (1.47ms+0s) by Foswiki::Templates::tmplP at line 152 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 9µs/call
# 156 times (1.33ms+0s) by Foswiki::Templates::tmplP at line 153 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 9µs/call
# 156 times (1.28ms+0s) by Foswiki::Templates::tmplP at line 154 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 8µs/call
# 156 times (1.25ms+0s) by Foswiki::Templates::tmplP at line 155 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 8µs/call
# 120 times (1.13ms+0s) by Foswiki::INCLUDE at line 127 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 9µs/call | ||||
182 | 2976 | 7.47ms | my ( $this, $attr ) = @_; | ||
183 | my $val = $this->{$attr}; | ||||
184 | delete( $this->{$attr} ) if ( exists $this->{$attr} ); | ||||
185 | return $val; | ||||
186 | } | ||||
187 | |||||
188 | =begin TML | ||||
189 | |||||
190 | ---++ ObjectMethod stringify() -> $string | ||||
191 | |||||
192 | Generate a printed form for the map, using strict | ||||
193 | attribute syntax, with only the single-quote extension | ||||
194 | syntax observed (no {} brackets, though). | ||||
195 | |||||
196 | =cut | ||||
197 | |||||
198 | # spent 1.71ms (1.49+221µs) within Foswiki::Attrs::stringify which was called 20 times, avg 86µs/call:
# 20 times (1.49ms+221µs) by Foswiki::INCLUDE at line 122 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 86µs/call | ||||
199 | 440 | 1.73ms | my $this = shift; | ||
200 | my $key; | ||||
201 | my @ss; | ||||
202 | 20 | 118µs | foreach $key ( sort keys %$this ) { # spent 118µs making 20 calls to Foswiki::Attrs::CORE:sort, avg 6µs/call | ||
203 | if ( $key ne $ERRORKEY && $key ne $RAWKEY ) { | ||||
204 | my $es = ( $key eq $DEFAULTKEY ) ? '' : $key . '='; | ||||
205 | my $val = $this->{$key}; | ||||
206 | 64 | 103µs | $val =~ s/"/\\"/g; # spent 103µs making 64 calls to Foswiki::Attrs::CORE:subst, avg 2µs/call | ||
207 | push( @ss, $es . '"' . $val . '"' ); | ||||
208 | } | ||||
209 | } | ||||
210 | return join( ' ', @ss ); | ||||
211 | } | ||||
212 | |||||
213 | # ---++ StaticMethod extractValue() -> $string | ||||
214 | # | ||||
215 | # Legacy support, formerly known as extractNameValuePair. This | ||||
216 | # static method uses context information to determine how a value | ||||
217 | # string is to be parsed. For example, if you have an attribute string | ||||
218 | # like this: | ||||
219 | # | ||||
220 | # "abc def="ghi" jkl" def="qqq" | ||||
221 | # | ||||
222 | # then call extractValue( "def" ), it will return "ghi". | ||||
223 | |||||
224 | sub extractValue { | ||||
225 | my ( $str, $name ) = @_; | ||||
226 | |||||
227 | my $value = ''; | ||||
228 | return $value unless ($str); | ||||
229 | $str =~ s/\\\"/\\$MARKER/g; # escape \" | ||||
230 | |||||
231 | if ($name) { | ||||
232 | |||||
233 | # format is: %VAR{ ... name = "value" }% | ||||
234 | if ( $str =~ /(^|[^\S])$name\s*=\s*\"([^\"]*)\"/ ) { | ||||
235 | $value = $2 if defined $2; # distinguish between '' and "0" | ||||
236 | } | ||||
237 | |||||
238 | } | ||||
239 | else { | ||||
240 | |||||
241 | # test if format: { "value" ... } | ||||
242 | # SMELL: unchecked implicit untaint? | ||||
243 | if ( $str =~ /(^|\=\s*\"[^\"]*\")\s*\"(.*?)\"\s*(\w+\s*=\s*\"|$)/ ) { | ||||
244 | |||||
245 | # is: %VAR{ "value" }% | ||||
246 | # or: %VAR{ "value" param="etc" ... }% | ||||
247 | # or: %VAR{ ... = "..." "value" ... }% | ||||
248 | # Note: "value" may contain embedded double quotes | ||||
249 | $value = $2 if defined $2; # distinguish between '' and "0"; | ||||
250 | |||||
251 | } | ||||
252 | elsif ( ( $str =~ /^\s*\w+\s*=\s*\"([^\"]*)/ ) && ($1) ) { | ||||
253 | |||||
254 | # is: %VAR{ name = "value" }% | ||||
255 | # do nothing, is not a standalone var | ||||
256 | |||||
257 | } | ||||
258 | else { | ||||
259 | |||||
260 | # format is: %VAR{ value }% | ||||
261 | $value = $str; | ||||
262 | } | ||||
263 | } | ||||
264 | $value =~ s/\\$MARKER/\"/go; # resolve \" | ||||
265 | return $value; | ||||
266 | } | ||||
267 | |||||
268 | # ---++ ObjectMethod get($key) -> $value | ||||
269 | # | ||||
270 | # | $key | Attribute to get | | ||||
271 | # Get an attr value from the map. | ||||
272 | # | ||||
273 | # Synonymous with $attrs->{$key}. Retained mainly for compatibility with | ||||
274 | # the old AttrsContrib. | ||||
275 | sub get { | ||||
276 | my ( $this, $field ) = @_; | ||||
277 | return $this->{$field}; | ||||
278 | } | ||||
279 | |||||
280 | 1 | 8µs | 1; | ||
281 | __END__ | ||||
sub Foswiki::Attrs::CORE:match; # opcode | |||||
# spent 3.71ms within Foswiki::Attrs::CORE:regcomp which was called 1727 times, avg 2µs/call:
# 1194 times (1.56ms+0s) by Foswiki::Attrs::new at line 149, avg 1µs/call
# 518 times (2.05ms+0s) by Foswiki::Attrs::new at line 93, avg 4µs/call
# 15 times (91µs+0s) by Foswiki::Attrs::new at line 108, avg 6µs/call | |||||
# spent 118µs within Foswiki::Attrs::CORE:sort which was called 20 times, avg 6µs/call:
# 20 times (118µs+0s) by Foswiki::Attrs::stringify at line 202, avg 6µs/call | |||||
# spent 7.04ms within Foswiki::Attrs::CORE:subst which was called 2652 times, avg 3µs/call:
# 1194 times (1.82ms+0s) by Foswiki::Attrs::new at line 149, avg 2µs/call
# 518 times (2.09ms+0s) by Foswiki::Attrs::new at line 93, avg 4µs/call
# 468 times (1.02ms+0s) by Foswiki::Attrs::new at line 82, avg 2µs/call
# 393 times (1.94ms+0s) by Foswiki::Attrs::new at line 87, avg 5µs/call
# 64 times (103µs+0s) by Foswiki::Attrs::stringify at line 206, avg 2µs/call
# 15 times (60µs+0s) by Foswiki::Attrs::new at line 108, avg 4µs/call | |||||
# spent 1.92ms within Foswiki::Attrs::CORE:substcont which was called 764 times, avg 3µs/call:
# 646 times (1.57ms+0s) by Foswiki::Attrs::new at line 87, avg 2µs/call
# 59 times (186µs+0s) by Foswiki::Attrs::new at line 82, avg 3µs/call
# 59 times (163µs+0s) by Foswiki::Attrs::new at line 149, avg 3µs/call |