~kosova/+junk/tuxfamily-twiki

« back to all changes in this revision

Viewing changes to foswiki/lib/Foswiki/Attrs.pm

  • Committer: James Michael DuPont
  • Date: 2009-07-18 19:58:49 UTC
  • Revision ID: jamesmikedupont@gmail.com-20090718195849-vgbmaht2ys791uo2
added foswiki

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: 2009-01-06 19:25:41 +0100 (Tue, 06 Jan 2009) $ (revision $Rev: 4272 (2009-06-21) $)
 
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
use strict;
 
50
use Assert;
 
51
 
 
52
our $VERSION = '$Rev: 4272 (2009-06-21) $';
 
53
 
 
54
our $ERRORKEY   = '_ERROR';
 
55
our $DEFAULTKEY = '_DEFAULT';
 
56
our $RAWKEY     = '_RAW';
 
57
 
 
58
=begin TML
 
59
 
 
60
---++ ClassMethod new ($string) => \%attrsObjectRef
 
61
 
 
62
   * =$string= - String containing attribute specification
 
63
 
 
64
Parse a standard attribute string containing name=value pairs and create a new
 
65
attributes object. The value may be a word or a quoted string. If there is an
 
66
error during parsing, the parse will complete but $attrs->{_ERROR} will be
 
67
set in the new object. $attrs->{_RAW} will always contain the full unprocessed
 
68
$string.
 
69
 
 
70
=cut
 
71
 
 
72
sub new {
 
73
    my ( $class, $string, $friendly ) = @_;
 
74
    my $this = bless( {}, $class );
 
75
 
 
76
    $this->{$RAWKEY} = $string;
 
77
 
 
78
    return $this unless defined($string);
 
79
 
 
80
    $string =~
 
81
      s/\\(["'])/$Foswiki::TranslationToken.sprintf("%.2u", ord($1))/ge; # escapes
 
82
 
 
83
    my $sep = ( $friendly ? "[\\s,]" : "\\s" );
 
84
    my $first = 1;
 
85
 
 
86
    if ( !$friendly && $string =~ s/^\s*\"(.*?)\"\s*(\w+\s*=\s*\"|$)/$2/s ) {
 
87
        $this->{$DEFAULTKEY} = $1;
 
88
    }
 
89
    while ( $string =~ m/\S/s ) {
 
90
 
 
91
        # name="value" pairs
 
92
        if ( $string =~ s/^$sep*(\w+)\s*=\s*\"(.*?)\"//is ) {
 
93
            $this->{$1} = $2;
 
94
            $first = 0;
 
95
        }
 
96
 
 
97
        # simple double-quoted value with no name, sets the default
 
98
        elsif ( $string =~ s/^$sep*\"(.*?)\"//os ) {
 
99
            $this->{$DEFAULTKEY} = $1
 
100
              unless defined( $this->{$DEFAULTKEY} );
 
101
            $first = 0;
 
102
        }
 
103
        elsif ($friendly) {
 
104
 
 
105
            # name='value' pairs
 
106
            if ( $string =~ s/^$sep*(\w+)\s*=\s*'(.*?)'//is ) {
 
107
                $this->{$1} = $2;
 
108
            }
 
109
 
 
110
            # name=value pairs
 
111
            elsif ( $string =~ s/^$sep*(\w+)\s*=\s*([^\s,\}\'\"]*)//is ) {
 
112
                $this->{$1} = $2;
 
113
            }
 
114
 
 
115
            # simple single-quoted value with no name, sets the default
 
116
            elsif ( $string =~ s/^$sep*'(.*?)'//os ) {
 
117
                $this->{$DEFAULTKEY} = $1
 
118
                  unless defined( $this->{$DEFAULTKEY} );
 
119
            }
 
120
 
 
121
            # simple name with no value (boolean, or _DEFAULT)
 
122
            elsif ( $string =~ s/^$sep*([a-z]\w*)\b//is ) {
 
123
                my $key = $1;
 
124
                $this->{$key} = 1;
 
125
            }
 
126
 
 
127
            # otherwise the whole string - sans padding - is the default
 
128
            else {
 
129
                # SMELL: unchecked implicit untaint?
 
130
                if ( $string =~ m/^\s*(.*?)\s*$/s
 
131
                    && !defined( $this->{$DEFAULTKEY} ) )
 
132
                {
 
133
                    $this->{$DEFAULTKEY} = $1;
 
134
                }
 
135
                last;
 
136
            }
 
137
        }
 
138
        # SMELL: unchecked implicit untaint?
 
139
        elsif ( $string =~ m/^\s*(.*?)\s*$/s ) {
 
140
            $this->{$DEFAULTKEY} = $1 if ($first);
 
141
            last;
 
142
        }
 
143
    }
 
144
    foreach my $k ( keys %$this ) {
 
145
        $this->{$k} =~ s/$Foswiki::TranslationToken(\d\d)/chr($1)/geo;   # escapes
 
146
    }
 
147
    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
sub remove {
 
178
    my ( $this, $attr ) = @_;
 
179
    my $val = $this->{$attr};
 
180
    delete( $this->{$attr} ) if ( exists $this->{$attr} );
 
181
    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
sub stringify {
 
195
    my $this = shift;
 
196
    my $key;
 
197
    my @ss;
 
198
    foreach $key ( sort keys %$this ) {
 
199
        if ( $key ne $ERRORKEY && $key ne $RAWKEY ) {
 
200
            my $es = ( $key eq $DEFAULTKEY ) ? '' : $key . '=';
 
201
            my $val = $this->{$key};
 
202
            $val =~ s/"/\\"/g;
 
203
            push( @ss, $es . '"' . $val . '"' );
 
204
        }
 
205
    }
 
206
    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/\\\"/\\$Foswiki::TranslationToken/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/\\$Foswiki::TranslationToken/\"/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;
 
277
__DATA__
 
278
# Module of Foswiki - The Free and Open Source Wiki, http://foswiki.org/
 
279
#
 
280
# Copyright (C) 2008-2009 Foswiki Contributors. Foswiki Contributors
 
281
# are listed in the AUTHORS file in the root of this distribution.
 
282
# NOTE: Please extend that file, not this notice.
 
283
#
 
284
# Additional copyrights apply to some or all of the code in this
 
285
# file as follows:
 
286
# Derived from Contrib::Attrs, which is
 
287
# Copyright (C) 2001 Motorola - All rights reserved
 
288
# Copyright (C) 1999-2007 TWiki Contributors. All Rights Reserved.
 
289
# TWiki Contributors are listed in the AUTHORS file in the root of
 
290
# this distribution. NOTE: Please extend that file, not this notice.
 
291
#
 
292
# This program is free software; you can redistribute it and/or
 
293
# modify it under the terms of the GNU General Public License
 
294
# as published by the Free Software Foundation; either version 2
 
295
# of the License, or (at your option) any later version. For
 
296
# more details read LICENSE in the root of this distribution.
 
297
#
 
298
# This program is distributed in the hope that it will be useful,
 
299
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
300
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
301
#
 
302
# As per the GPL, removal of this notice is prohibited.