Filename | /var/www/foswiki11/lib/Foswiki/Attrs.pm |
Statements | Executed 15155 statements in 30.2ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
661 | 6 | 4 | 14.6ms | 14.6ms | new | Foswiki::Attrs::
1262 | 5 | 2 | 2.28ms | 2.28ms | remove | Foswiki::Attrs::
7 | 1 | 1 | 120µs | 120µs | stringify | Foswiki::Attrs::
1 | 1 | 1 | 24µs | 56µs | BEGIN@47 | Foswiki::Attrs::
1 | 1 | 1 | 16µs | 32µs | BEGIN@48 | Foswiki::Attrs::
1 | 1 | 1 | 15µs | 46µs | BEGIN@49 | 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 | *Since* _date_ indicates where functions or parameters have been added since | ||||
24 | the baseline of the API (TWiki release 4.2.3). The _date_ indicates the | ||||
25 | earliest date of a Foswiki release that will support that function or | ||||
26 | parameter. | ||||
27 | |||||
28 | *Deprecated* _date_ indicates where a function or parameters has been | ||||
29 | [[http://en.wikipedia.org/wiki/Deprecation][deprecated]]. Deprecated | ||||
30 | functions will still work, though they should | ||||
31 | _not_ be called in new plugins and should be replaced in older plugins | ||||
32 | as soon as possible. Deprecated parameters are simply ignored in Foswiki | ||||
33 | releases after _date_. | ||||
34 | |||||
35 | *Until* _date_ indicates where a function or parameter has been removed. | ||||
36 | The _date_ indicates the latest date at which Foswiki releases still supported | ||||
37 | the function or parameter. | ||||
38 | |||||
39 | =cut | ||||
40 | |||||
41 | # THIS PACKAGE IS PART OF THE PUBLISHED API USED BY EXTENSION AUTHORS. | ||||
42 | # DO NOT CHANGE THE EXISTING APIS (well thought out extensions are OK) | ||||
43 | # AND ENSURE ALL POD DOCUMENTATION IS COMPLETE AND ACCURATE. | ||||
44 | |||||
45 | package Foswiki::Attrs; | ||||
46 | |||||
47 | 2 | 42µs | 2 | 89µs | # spent 56µs (24+32) within Foswiki::Attrs::BEGIN@47 which was called:
# once (24µs+32µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 47 # spent 56µs making 1 call to Foswiki::Attrs::BEGIN@47
# spent 32µs making 1 call to strict::import |
48 | 2 | 31µs | 2 | 49µs | # spent 32µs (16+16) within Foswiki::Attrs::BEGIN@48 which was called:
# once (16µs+16µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 48 # spent 32µs making 1 call to Foswiki::Attrs::BEGIN@48
# spent 16µs making 1 call to warnings::import |
49 | 2 | 911µs | 2 | 77µs | # spent 46µs (15+31) within Foswiki::Attrs::BEGIN@49 which was called:
# once (15µs+31µs) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 49 # spent 46µs making 1 call to Foswiki::Attrs::BEGIN@49
# spent 31µs making 1 call to Assert::import |
50 | |||||
51 | 1 | 700ns | our $ERRORKEY = '_ERROR'; | ||
52 | 1 | 300ns | our $DEFAULTKEY = '_DEFAULT'; | ||
53 | 1 | 300ns | our $RAWKEY = '_RAW'; | ||
54 | 1 | 200ns | our $MARKER = "\0"; | ||
55 | |||||
56 | =begin TML | ||||
57 | |||||
58 | ---++ ClassMethod new ($string) => \%attrsObjectRef | ||||
59 | |||||
60 | * =$string= - String containing attribute specification | ||||
61 | |||||
62 | Parse a standard attribute string containing name=value pairs and create a new | ||||
63 | attributes object. The value may be a word or a quoted string. If there is an | ||||
64 | error during parsing, the parse will complete but $attrs->{_ERROR} will be | ||||
65 | set in the new object. $attrs->{_RAW} will always contain the full unprocessed | ||||
66 | $string. | ||||
67 | |||||
68 | =cut | ||||
69 | |||||
70 | # spent 14.6ms within Foswiki::Attrs::new which was called 661 times, avg 22µs/call:
# 343 times (7.77ms+0s) by Foswiki::_expandMacroOnTopicRendering at line 3159 of /var/www/foswiki11/lib/Foswiki.pm, avg 23µs/call
# 303 times (5.06ms+0s) by Foswiki::Templates::expandTemplate at line 127 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 17µs/call
# 11 times (1.53ms+0s) by Foswiki::Store::VC::Handler::_getTOPICINFO at line 270 of /var/www/foswiki11/lib/Foswiki/Store/VC/Handler.pm, avg 139µs/call
# 2 times (120µs+0s) by Foswiki::Func::extractParameters at line 3005 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 60µs/call
# once (65µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3163 of /var/www/foswiki11/lib/Foswiki.pm
# once (34µs+0s) by Foswiki::Templates::_expandTrivialTemplate at line 103 of /var/www/foswiki11/lib/Foswiki/Templates.pm | ||||
71 | 661 | 785µs | my ( $class, $string, $friendly ) = @_; | ||
72 | 661 | 825µs | my $this = bless( {}, $class ); | ||
73 | |||||
74 | 661 | 746µs | $this->{$RAWKEY} = $string; | ||
75 | |||||
76 | 661 | 497µs | return $this unless defined($string); | ||
77 | |||||
78 | 546 | 512µs | $string =~ s/\\(["'])/$MARKER.sprintf("%.2u", ord($1))/ge; # escapes | ||
79 | |||||
80 | 546 | 295µs | my $sep = ( $friendly ? "[\\s,]" : "\\s" ); | ||
81 | 546 | 161µs | my $first = 1; | ||
82 | |||||
83 | 546 | 1.91ms | if ( !$friendly && $string =~ s/^\s*\"(.*?)\"\s*(\w+\s*=\s*\"|$)/$2/s ) { | ||
84 | $this->{$DEFAULTKEY} = $1; | ||||
85 | } | ||||
86 | 546 | 678µs | while ( $string =~ m/\S/s ) { | ||
87 | |||||
88 | # name="value" pairs | ||||
89 | 678 | 3.26ms | if ( $string =~ s/^$sep*(\w+)\s*=\s*\"(.*?)\"//is ) { | ||
90 | 451 | 740µs | $this->{$1} = $2; | ||
91 | 451 | 126µs | $first = 0; | ||
92 | } | ||||
93 | |||||
94 | # simple double-quoted value with no name, sets the default | ||||
95 | elsif ( $string =~ s/^$sep*\"(.*?)\"//os ) { | ||||
96 | 41 | 93µs | $this->{$DEFAULTKEY} = $1 | ||
97 | unless defined( $this->{$DEFAULTKEY} ); | ||||
98 | 41 | 19µs | $first = 0; | ||
99 | } | ||||
100 | |||||
101 | elsif ($friendly) { | ||||
102 | |||||
103 | # name='value' pairs | ||||
104 | 8 | 94µs | if ( $string =~ s/^$sep*(\w+)\s*=\s*'(.*?)'//is ) { | ||
105 | $this->{$1} = $2; | ||||
106 | } | ||||
107 | |||||
108 | # name=value pairs | ||||
109 | elsif ( $string =~ s/^$sep*(\w+)\s*=\s*([^\s,\}\'\"]*)//is ) { | ||||
110 | $this->{$1} = $2; | ||||
111 | } | ||||
112 | |||||
113 | # simple single-quoted value with no name, sets the default | ||||
114 | elsif ( $string =~ s/^$sep*'(.*?)'//os ) { | ||||
115 | $this->{$DEFAULTKEY} = $1 | ||||
116 | unless defined( $this->{$DEFAULTKEY} ); | ||||
117 | } | ||||
118 | |||||
119 | # simple name with no value (boolean, or _DEFAULT) | ||||
120 | elsif ( $string =~ s/^$sep*([a-z]\w*)\b//is ) { | ||||
121 | my $key = $1; | ||||
122 | $this->{$key} = 1; | ||||
123 | } | ||||
124 | |||||
125 | # otherwise the whole string - sans padding - is the default | ||||
126 | else { | ||||
127 | |||||
128 | # SMELL: unchecked implicit untaint? | ||||
129 | if ( $string =~ m/^\s*(.*?)\s*$/s | ||||
130 | && !defined( $this->{$DEFAULTKEY} ) ) | ||||
131 | { | ||||
132 | $this->{$DEFAULTKEY} = $1; | ||||
133 | } | ||||
134 | last; | ||||
135 | } | ||||
136 | } | ||||
137 | |||||
138 | # SMELL: unchecked implicit untaint? | ||||
139 | elsif ( $string =~ m/^\s*(.*?)\s*$/s ) { | ||||
140 | 178 | 286µs | $this->{$DEFAULTKEY} = $1 if ($first); | ||
141 | 178 | 90µs | last; | ||
142 | } | ||||
143 | } | ||||
144 | 546 | 1.25ms | foreach my $k ( keys %$this ) { | ||
145 | 1517 | 1.37ms | $this->{$k} =~ s/$MARKER(\d\d)/chr($1)/geo; # escapes | ||
146 | } | ||||
147 | 546 | 1.87ms | return $this; | ||
148 | } | ||||
149 | |||||
150 | =begin TML | ||||
151 | |||||
152 | ---++ ObjectMethod isEmpty() -> boolean | ||||
153 | |||||
154 | Return false if attribute set is not empty. | ||||
155 | |||||
156 | =cut | ||||
157 | |||||
158 | sub isEmpty { | ||||
159 | my $this = shift; | ||||
160 | |||||
161 | foreach my $k ( keys %$this ) { | ||||
162 | return 0 if $k ne $RAWKEY; | ||||
163 | } | ||||
164 | return 1; | ||||
165 | } | ||||
166 | |||||
167 | =begin TML | ||||
168 | |||||
169 | ---++ ObjectMethod remove($key) -> $value | ||||
170 | |||||
171 | * =$key= - Attribute to remove | ||||
172 | Remove an attr value from the map, return old value. After a call to | ||||
173 | =remove= the attribute is no longer defined. | ||||
174 | |||||
175 | =cut | ||||
176 | |||||
177 | # spent 2.28ms within Foswiki::Attrs::remove which was called 1262 times, avg 2µs/call:
# 305 times (815µs+0s) by Foswiki::Templates::tmplP at line 154 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 3µs/call
# 305 times (488µs+0s) by Foswiki::Templates::tmplP at line 155 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 2µs/call
# 305 times (439µs+0s) by Foswiki::Templates::tmplP at line 156 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 1µs/call
# 305 times (422µs+0s) by Foswiki::Templates::tmplP at line 157 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 1µs/call
# 42 times (111µs+0s) by Foswiki::INCLUDE at line 127 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 3µs/call | ||||
178 | 1262 | 435µs | my ( $this, $attr ) = @_; | ||
179 | 1262 | 376µs | my $val = $this->{$attr}; | ||
180 | 1262 | 406µs | delete( $this->{$attr} ) if ( exists $this->{$attr} ); | ||
181 | 1262 | 12.3ms | return $val; | ||
182 | } | ||||
183 | |||||
184 | =begin TML | ||||
185 | |||||
186 | ---++ ObjectMethod stringify() -> $string | ||||
187 | |||||
188 | Generate a printed form for the map, using strict | ||||
189 | attribute syntax, with only the single-quote extension | ||||
190 | syntax observed (no {} brackets, though). | ||||
191 | |||||
192 | =cut | ||||
193 | |||||
194 | # spent 120µs within Foswiki::Attrs::stringify which was called 7 times, avg 17µs/call:
# 7 times (120µs+0s) by Foswiki::INCLUDE at line 122 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 17µs/call | ||||
195 | 7 | 3µs | my $this = shift; | ||
196 | 7 | 800ns | my $key; | ||
197 | 7 | 2µs | my @ss; | ||
198 | 7 | 33µs | foreach $key ( sort keys %$this ) { | ||
199 | 16 | 13µs | if ( $key ne $ERRORKEY && $key ne $RAWKEY ) { | ||
200 | 9 | 9µs | my $es = ( $key eq $DEFAULTKEY ) ? '' : $key . '='; | ||
201 | 9 | 7µs | my $val = $this->{$key}; | ||
202 | 9 | 8µs | $val =~ s/"/\\"/g; | ||
203 | 9 | 16µs | push( @ss, $es . '"' . $val . '"' ); | ||
204 | } | ||||
205 | } | ||||
206 | 7 | 41µs | return join( ' ', @ss ); | ||
207 | } | ||||
208 | |||||
209 | # ---++ StaticMethod extractValue() -> $string | ||||
210 | # | ||||
211 | # Legacy support, formerly known as extractNameValuePair. This | ||||
212 | # static method uses context information to determine how a value | ||||
213 | # string is to be parsed. For example, if you have an attribute string | ||||
214 | # like this: | ||||
215 | # | ||||
216 | # "abc def="ghi" jkl" def="qqq" | ||||
217 | # | ||||
218 | # then call extractValue( "def" ), it will return "ghi". | ||||
219 | |||||
220 | sub extractValue { | ||||
221 | my ( $str, $name ) = @_; | ||||
222 | |||||
223 | my $value = ''; | ||||
224 | return $value unless ($str); | ||||
225 | $str =~ s/\\\"/\\$MARKER/g; # escape \" | ||||
226 | |||||
227 | if ($name) { | ||||
228 | |||||
229 | # format is: %VAR{ ... name = "value" }% | ||||
230 | if ( $str =~ /(^|[^\S])$name\s*=\s*\"([^\"]*)\"/ ) { | ||||
231 | $value = $2 if defined $2; # distinguish between '' and "0" | ||||
232 | } | ||||
233 | |||||
234 | } | ||||
235 | else { | ||||
236 | |||||
237 | # test if format: { "value" ... } | ||||
238 | # SMELL: unchecked implicit untaint? | ||||
239 | if ( $str =~ /(^|\=\s*\"[^\"]*\")\s*\"(.*?)\"\s*(\w+\s*=\s*\"|$)/ ) { | ||||
240 | |||||
241 | # is: %VAR{ "value" }% | ||||
242 | # or: %VAR{ "value" param="etc" ... }% | ||||
243 | # or: %VAR{ ... = "..." "value" ... }% | ||||
244 | # Note: "value" may contain embedded double quotes | ||||
245 | $value = $2 if defined $2; # distinguish between '' and "0"; | ||||
246 | |||||
247 | } | ||||
248 | elsif ( ( $str =~ /^\s*\w+\s*=\s*\"([^\"]*)/ ) && ($1) ) { | ||||
249 | |||||
250 | # is: %VAR{ name = "value" }% | ||||
251 | # do nothing, is not a standalone var | ||||
252 | |||||
253 | } | ||||
254 | else { | ||||
255 | |||||
256 | # format is: %VAR{ value }% | ||||
257 | $value = $str; | ||||
258 | } | ||||
259 | } | ||||
260 | $value =~ s/\\$MARKER/\"/go; # resolve \" | ||||
261 | return $value; | ||||
262 | } | ||||
263 | |||||
264 | # ---++ ObjectMethod get($key) -> $value | ||||
265 | # | ||||
266 | # | $key | Attribute to get | | ||||
267 | # Get an attr value from the map. | ||||
268 | # | ||||
269 | # Synonymous with $attrs->{$key}. Retained mainly for compatibility with | ||||
270 | # the old AttrsContrib. | ||||
271 | sub get { | ||||
272 | my ( $this, $field ) = @_; | ||||
273 | return $this->{$field}; | ||||
274 | } | ||||
275 | |||||
276 | 1 | 4µs | 1; | ||
277 | __END__ |