line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
######################################################################## |
2
|
|
|
|
|
|
|
# CVS : $Header: /home/cvs/software/cvsroot/configuration/lib/Config/Wrest.pm,v 1.36 2006/08/22 14:09:50 mattheww Exp $ |
3
|
|
|
|
|
|
|
######################################################################## |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Config::Wrest; |
6
|
12
|
|
|
12
|
|
96946
|
use strict; |
|
12
|
|
|
|
|
28
|
|
|
12
|
|
|
|
|
1585
|
|
7
|
12
|
|
|
12
|
|
62
|
use Carp; |
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
1122
|
|
8
|
12
|
|
|
12
|
|
65
|
use constant MAX_INCLUDES => 1000; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
1088
|
|
9
|
12
|
|
|
12
|
|
74
|
use constant MAX_SER_DEPTH => 500; |
|
12
|
|
|
|
|
18
|
|
|
12
|
|
|
|
|
557
|
|
10
|
12
|
|
|
12
|
|
58
|
use constant ERR_HASH => 'Data structure is not a hash reference'; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
550
|
|
11
|
12
|
|
|
12
|
|
96
|
use constant ERR_VARIABLES_HASH => 'The value of the Variables option must be a hash reference'; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
568
|
|
12
|
12
|
|
|
12
|
|
67
|
use constant ERR_BADREF => 'Data structure is not a hash or array reference'; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
799
|
|
13
|
12
|
|
|
12
|
|
59
|
use constant ERR_BADTOK => 'Found hash key with bad characters in it. Only \w, - and . are ok. Offending key was: "'; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
613
|
|
14
|
12
|
|
|
12
|
|
71
|
use constant ERR_BADLISTITEM => 'Found list value with bad characters in it. Try setting the UseQuotes option. Offending value was: "'; |
|
12
|
|
|
|
|
19
|
|
|
12
|
|
|
|
|
582
|
|
15
|
12
|
|
|
12
|
|
172
|
use constant ERR_BADLISTITEM_QUOTE => 'Found list value with bad characters in it, even though UseQuotes is set. Offending value was: "'; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
840
|
|
16
|
12
|
|
|
12
|
|
225
|
use constant ERR_MAX_SER_DEPTH_EXCEEDED => 'Recursed more than '.MAX_SER_DEPTH.' levels into the data structure, which exceeds recursion limit. Possible cyclic data structure - try setting the WriteWithReferences option to fix'; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
1164
|
|
17
|
12
|
|
|
12
|
|
57
|
use constant ERR_DESER_STRING_REF => 'The deserialize() method takes a string or a string reference, but was given a reference of type '; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
1118
|
|
18
|
12
|
|
|
12
|
|
64
|
use constant ERR_SER_STRING_REF => 'The serialize() method takes a string reference, but was given a reference of type '; |
|
12
|
|
|
|
|
153
|
|
|
12
|
|
|
|
|
772
|
|
19
|
12
|
|
|
12
|
|
64
|
use constant ERR_NO_FILENAME => 'You must supply a filename'; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
691
|
|
20
|
12
|
|
|
12
|
|
58
|
use constant VAR_CHECK_TOP_LEVEL => 1; |
|
12
|
|
|
|
|
35
|
|
|
12
|
|
|
|
|
541
|
|
21
|
|
|
|
|
|
|
|
22
|
12
|
|
|
12
|
|
55
|
use vars qw($VERSION $RE_DATASING $RE_DATASINGQUOTE); |
|
12
|
|
|
|
|
18
|
|
|
12
|
|
|
|
|
99652
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
$VERSION = sprintf('%d.%03d', q$Revision: 1.36 $ =~ /: (\d+)\.(\d+)/); |
25
|
|
|
|
|
|
|
$RE_DATASING = q/^([^\[\(\{\<\:\@\%\/][\S]*)$/; # unquoted list item values - no spaces... |
26
|
|
|
|
|
|
|
$RE_DATASINGQUOTE = q/^([\'\"].*[\'\"])$/; # quoted list item values _may_ have spaces |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
######################################################################## |
29
|
|
|
|
|
|
|
# Public Interface |
30
|
|
|
|
|
|
|
######################################################################## |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
33
|
42
|
|
|
42
|
1
|
63929
|
my ($class, %options) = @_; |
34
|
42
|
|
|
|
|
159
|
my $self = { |
35
|
|
|
|
|
|
|
UniqueIdCounter => 0, |
36
|
|
|
|
|
|
|
}; |
37
|
42
|
|
|
|
|
159
|
TRACE(__PACKAGE__."::new"); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# set defaults for various options |
40
|
|
|
|
|
|
|
# these default to false... |
41
|
42
|
|
|
|
|
107
|
for my $o (qw(IgnoreInvalidLines Subs TemplateBackend WriteWithEquals WriteWithReferences IgnoreUnclosedTags)) { |
42
|
252
|
|
100
|
|
|
1153
|
$self->{'options'}{$o} = $options{$o} || 0; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
# ...copy these as-is |
45
|
42
|
|
|
|
|
730
|
for my $o (qw(TemplateOptions)) { |
46
|
42
|
|
|
|
|
140
|
$self->{'options'}{$o} = $options{$o}; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
# ...and these default to true |
49
|
42
|
|
|
|
|
90
|
for my $o (qw(AllowEmptyValues Escapes UseQuotes WriteWithHeader Strict DieOnNonExistantVars)) { |
50
|
252
|
100
|
|
|
|
710
|
$self->{'options'}{$o} = ( exists $options{$o} ? $options{$o} : 1 ); |
51
|
|
|
|
|
|
|
} |
52
|
42
|
|
|
|
|
107
|
$self->{'options'}{'Variables'} = $options{'Variables'}; |
53
|
42
|
100
|
100
|
|
|
202
|
if ($self->{'options'}{'Variables'} && ref($self->{'options'}{'Variables'}) ne 'HASH') { |
54
|
2
|
|
|
|
|
277
|
croak(ERR_VARIABLES_HASH); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
40
|
|
|
|
|
85
|
$self->{'errorprefix'} = ''; |
58
|
40
|
|
|
|
|
104
|
bless($self, $class); |
59
|
40
|
|
|
|
|
123
|
$self->_restore_options; |
60
|
40
|
|
|
|
|
132
|
TRACE(__PACKAGE__."::new successful"); |
61
|
40
|
|
|
|
|
171
|
return $self; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub deserialize { |
65
|
26
|
|
|
26
|
1
|
33824
|
my ($self, $string) = @_; |
66
|
26
|
|
|
|
|
67
|
TRACE(__PACKAGE__."::deserialize"); |
67
|
|
|
|
|
|
|
|
68
|
26
|
|
|
|
|
80
|
$self->_restore_options; |
69
|
26
|
|
|
|
|
50
|
$self->{'errorprefix'} = (__PACKAGE__ . ":"); |
70
|
26
|
|
|
|
|
31
|
my $linearray; |
71
|
26
|
100
|
|
|
|
74
|
if (! ref($string)) { |
|
|
50
|
|
|
|
|
|
72
|
25
|
|
|
|
|
61
|
TRACE(__PACKAGE__."::deserialize - string literal"); |
73
|
25
|
|
|
|
|
96
|
$linearray = _str2array(\$string); |
74
|
|
|
|
|
|
|
} elsif (ref($string) eq 'SCALAR') { |
75
|
1
|
|
|
|
|
4
|
TRACE(__PACKAGE__."::deserialize - string reference"); |
76
|
1
|
|
|
|
|
4
|
$linearray = _str2array($string); |
77
|
|
|
|
|
|
|
} else { |
78
|
0
|
|
|
|
|
0
|
croak(ERR_DESER_STRING_REF.ref($string)); |
79
|
|
|
|
|
|
|
} |
80
|
26
|
|
|
|
|
82
|
return _parse($self, $linearray, $self->{'current_options'}); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
4
|
|
|
4
|
1
|
120
|
sub deserialise { return deserialize(@_); } |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub serialize { |
86
|
4
|
|
|
4
|
1
|
89
|
my ($self, $vars, $string) = @_; |
87
|
4
|
|
|
|
|
17
|
TRACE(__PACKAGE__."::serialize"); |
88
|
|
|
|
|
|
|
|
89
|
4
|
50
|
|
|
|
23
|
croak(ERR_HASH) unless (ref($vars) eq 'HASH'); |
90
|
4
|
50
|
33
|
|
|
27
|
croak(ERR_SER_STRING_REF.ref($string)) |
91
|
|
|
|
|
|
|
if defined $string && ref($string) ne 'SCALAR'; |
92
|
|
|
|
|
|
|
|
93
|
4
|
|
|
|
|
16
|
$self->_restore_options; |
94
|
4
|
|
|
|
|
7
|
$self->{'errorprefix'} = (__PACKAGE__ . ":"); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# copy current_options to pass to _serialise() |
97
|
4
|
|
50
|
|
|
20
|
my $c_options = $self->{'current_options'} || {}; |
98
|
4
|
|
|
|
|
63
|
my $options = { %$c_options }; |
99
|
4
|
|
|
|
|
27
|
my $rv = _serialise($self, $vars, $options); |
100
|
|
|
|
|
|
|
|
101
|
0
|
0
|
|
|
|
0
|
if ($options->{'WriteWithHeader'}) { |
102
|
|
|
|
|
|
|
# create header |
103
|
0
|
|
|
|
|
0
|
my $prep = '# Created by ' . __PACKAGE__ . " $VERSION at " . |
104
|
|
|
|
|
|
|
localtime() . "\n"; |
105
|
0
|
|
|
|
|
0
|
for my $i ([qw/set AllowEmptyValues IgnoreInvalidLines Strict DieOnNonExistantVars/], |
106
|
|
|
|
|
|
|
[qw/option Escapes UseQuotes/]) { |
107
|
0
|
|
|
|
|
0
|
my($type, @names) = @$i; |
108
|
|
|
|
|
|
|
$prep .= sprintf("\@%s %s %d\n", $type, $_, $options->{$_} ? 1 : 0) |
109
|
0
|
0
|
|
|
|
0
|
for @names; |
110
|
|
|
|
|
|
|
} |
111
|
0
|
|
|
|
|
0
|
$prep .= "# End of header\n"; |
112
|
0
|
|
|
|
|
0
|
$rv = $prep.$rv; |
113
|
|
|
|
|
|
|
} |
114
|
0
|
0
|
|
|
|
0
|
if ($string) { |
115
|
0
|
|
|
|
|
0
|
$$string = $rv; |
116
|
0
|
|
|
|
|
0
|
return undef; |
117
|
|
|
|
|
|
|
} else { |
118
|
0
|
|
|
|
|
0
|
return $rv; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
2
|
|
|
2
|
1
|
700
|
sub serialise { return serialize(@_); } |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub parse_file { |
125
|
16
|
|
|
16
|
1
|
91
|
my ($self, $filename) = @_; |
126
|
16
|
|
|
|
|
93
|
TRACE(__PACKAGE__."::parse_file '$filename'"); |
127
|
16
|
50
|
|
|
|
53
|
croak(ERR_NO_FILENAME) unless ( defined $filename ); |
128
|
|
|
|
|
|
|
|
129
|
16
|
|
|
|
|
113
|
$self->_restore_options; |
130
|
16
|
|
|
|
|
354
|
$self->{'errorprefix'} = (__PACKAGE__ . ": File '$filename':"); |
131
|
16
|
|
|
|
|
56
|
my $linearray = _file2array($filename); |
132
|
16
|
|
|
|
|
83
|
return _parse($self, $linearray, $self->{'current_options'}); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub write_file { |
136
|
1
|
|
|
1
|
1
|
30
|
my ($self, $filename, $vars) = @_; |
137
|
1
|
|
|
|
|
4
|
TRACE(__PACKAGE__."::write_file '$filename'"); |
138
|
1
|
50
|
|
|
|
3
|
croak(ERR_NO_FILENAME) unless ( defined $filename ); |
139
|
|
|
|
|
|
|
|
140
|
1
|
|
|
|
|
5
|
my $str = $self->serialize($vars); |
141
|
0
|
|
|
|
|
0
|
require File::Slurp::WithinPolicy; |
142
|
0
|
|
|
|
|
0
|
File::Slurp::WithinPolicy::write_file($filename, $str); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
######################################################################## |
146
|
|
|
|
|
|
|
# Private routines |
147
|
|
|
|
|
|
|
######################################################################## |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub _restore_options { |
150
|
86
|
|
|
86
|
|
115
|
my $self = shift; |
151
|
86
|
|
|
|
|
223
|
TRACE(__PACKAGE__."::_restore_options"); |
152
|
86
|
|
|
|
|
348
|
delete $self->{'current_options'}; |
153
|
86
|
|
|
|
|
101
|
for my $k (keys %{ $self->{'options'} }) { |
|
86
|
|
|
|
|
462
|
|
154
|
1204
|
|
|
|
|
4388
|
$self->{'current_options'}{$k} = $self->{'options'}{$k}; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
86
|
100
|
|
|
|
388
|
if ($self->{'options'}{'Variables'}) { |
158
|
11
|
|
|
|
|
24
|
TRACE(__PACKAGE__."::_restore_options cloning Variables"); |
159
|
11
|
|
|
|
|
1146
|
require Storable; |
160
|
11
|
|
|
|
|
4342
|
my $copy = Storable::dclone( $self->{'options'}{'Variables'} ); |
161
|
11
|
|
|
|
|
30
|
$self->{'current_options'}{'Variables'} = $copy; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _file2array { |
166
|
1021
|
|
|
1021
|
|
1366
|
my $filename = shift; |
167
|
1021
|
|
|
|
|
2581
|
TRACE(__PACKAGE__."::_file2array '$filename'"); |
168
|
|
|
|
|
|
|
|
169
|
1021
|
|
|
|
|
27460
|
require File::Slurp::WithinPolicy; |
170
|
1021
|
|
|
|
|
179154
|
my $contents = File::Slurp::WithinPolicy::read_file( $filename ); |
171
|
1020
|
|
|
|
|
84406
|
return _str2array(\$contents); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub _str2array { |
175
|
1232
|
|
|
1232
|
|
1526
|
my $contents = shift; |
176
|
1232
|
|
|
|
|
2628
|
TRACE(__PACKAGE__."::_str2array"); |
177
|
|
|
|
|
|
|
|
178
|
1232
|
|
|
|
|
1559
|
my @linearray; |
179
|
1232
|
100
|
|
|
|
3210
|
if ($$contents =~ m/\x0D\x0A/) { |
180
|
|
|
|
|
|
|
# handle 2-character line break sequences from DOS |
181
|
1
|
|
|
|
|
7
|
@linearray = split(/\x0D\x0A/, $$contents); |
182
|
|
|
|
|
|
|
} else { |
183
|
|
|
|
|
|
|
# handle single-character line breaks |
184
|
1231
|
|
|
|
|
9679
|
@linearray = split(/[\n\r]/, $$contents); |
185
|
|
|
|
|
|
|
} |
186
|
1232
|
|
|
|
|
4195
|
TRACE(__PACKAGE__."::_str2array returns ".@linearray." lines"); |
187
|
1232
|
|
|
|
|
3362
|
return \@linearray; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub _parse { |
191
|
42
|
|
|
42
|
|
60
|
my $self = shift; |
192
|
42
|
|
|
|
|
68
|
my ($linearray, $options) = @_; |
193
|
42
|
|
|
|
|
103
|
TRACE(__PACKAGE__."::_parse"); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
#ensure we have a hashref to prevent Any::Template errors |
196
|
42
|
|
100
|
|
|
295
|
$options->{'Variables'} ||= {}; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
#reset the hash which counts how many times we have used files |
199
|
42
|
|
|
|
|
96
|
$options->{'__includeguard'} = {}; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
#regular expressions that we'll use many times |
202
|
42
|
|
|
|
|
69
|
my $re_nuke = q/[\n\r]/; |
203
|
42
|
|
|
|
|
56
|
my $re_skipcomment = q/^\s*#/; |
204
|
42
|
|
|
|
|
55
|
my $re_skipblank = q/^\s*$/; |
205
|
42
|
|
|
|
|
63
|
my $re_trimcomment = q/#.*$/; |
206
|
42
|
|
|
|
|
59
|
my $re_trimtrailsp = q/\s*$/; |
207
|
42
|
|
|
|
|
50
|
my $re_trimleadsp = q/^\s*/; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# Also see the top of this module for other regular expressions |
210
|
42
|
|
|
|
|
298
|
my $re_datapair = q/^([\w\-\.]+)\s*[\s=]\s*(.*)/; |
211
|
|
|
|
|
|
|
|
212
|
42
|
|
|
|
|
55
|
my $re_openhash = q/^(\<)([\w\-\.]+)\>$/; |
213
|
42
|
|
|
|
|
53
|
my $re_openlist = q/^(\[)([\w\-\.]+)\]$/; |
214
|
42
|
|
|
|
|
49
|
my $re_closhash = q/^(\<)\/([\w\-\.]*)\>$/; |
215
|
42
|
|
|
|
|
80
|
my $re_closlist = q/^(\[)\/([\w\-\.]*)\]$/; |
216
|
|
|
|
|
|
|
|
217
|
42
|
|
|
|
|
48
|
my $re_command = q/^\s*\@\s*(\w+)\s*(.*?)\s*$/; |
218
|
|
|
|
|
|
|
|
219
|
42
|
|
|
|
|
56
|
my %vars; |
220
|
42
|
|
|
|
|
673
|
my @stack = (\%vars); # stack of references to each level of nesting |
221
|
42
|
|
|
|
|
71
|
my @level = (''); # stack holding the names of all enclosing blocks |
222
|
|
|
|
|
|
|
|
223
|
42
|
|
|
|
|
51
|
my $LINE = 0; |
224
|
42
|
|
|
|
|
113
|
while (@$linearray) { |
225
|
6063
|
|
|
|
|
5938
|
$LINE++; |
226
|
6063
|
|
|
|
|
8596
|
local $_ = shift @$linearray; |
227
|
6063
|
|
|
|
|
6691
|
chomp; |
228
|
6063
|
|
|
|
|
10296
|
s/$re_nuke//g; |
229
|
6063
|
100
|
|
|
|
18956
|
next if /$re_skipcomment/; # skip comments |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
#Interpolate values if required |
232
|
3906
|
100
|
100
|
|
|
10129
|
if ($options->{'Subs'} && length($_)) { |
233
|
186
|
|
|
|
|
245
|
my $linestring = $_; |
234
|
186
|
|
|
|
|
1945
|
require Any::Template; |
235
|
186
|
|
|
|
|
1507
|
my $backend = $options->{'TemplateBackend'}; |
236
|
186
|
|
|
|
|
261
|
my $backendoptions = $options->{'TemplateOptions'}; |
237
|
186
|
|
|
|
|
1160
|
my $t = new Any::Template({ Backend => $backend, Options => $backendoptions, String => $linestring }); |
238
|
186
|
|
|
|
|
141150
|
my $string = $t->process( { %ENV, %vars, %{$options->{'Variables'}} } ); |
|
186
|
|
|
|
|
4539
|
|
239
|
186
|
|
|
|
|
278028
|
my @lines; |
240
|
186
|
|
|
|
|
499
|
my $include_lines = _str2array(\$string); |
241
|
186
|
|
|
|
|
428
|
($_, @lines) = @$include_lines; |
242
|
186
|
|
|
|
|
1526
|
unshift @$linearray, @lines; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
3906
|
50
|
|
|
|
14063
|
next if /$re_skipcomment/; # skip comments again, in case the interpolation has created any |
246
|
3906
|
100
|
|
|
|
11978
|
next if /$re_skipblank/; # skip blank lines |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
#Remove comments, & surrounding space |
249
|
2802
|
|
|
|
|
4080
|
s/$re_trimcomment//; |
250
|
2802
|
|
|
|
|
15926
|
s/$re_trimtrailsp//; |
251
|
2802
|
|
|
|
|
8309
|
s/$re_trimleadsp//; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
#Block opening tags: and [BAR] |
254
|
2802
|
100
|
100
|
|
|
53878
|
if (/$re_openhash/ || /$re_openlist/) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
255
|
163
|
|
|
|
|
385
|
my ($type, $block) = ($1, $2); |
256
|
163
|
100
|
|
|
|
371
|
my $struct = (( $type eq '<' ) ? {} : [] ); |
257
|
163
|
100
|
|
|
|
415
|
if (ref($stack[$#stack]) eq 'HASH') { |
258
|
142
|
|
|
|
|
378
|
$stack[$#stack]->{$block} = $struct; |
259
|
|
|
|
|
|
|
} else { |
260
|
21
|
|
|
|
|
25
|
push(@{$stack[$#stack]}, $struct); |
|
21
|
|
|
|
|
41
|
|
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
163
|
|
|
|
|
287
|
push(@level, $block); |
264
|
163
|
|
|
|
|
450
|
push(@stack, $struct); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
#Block closing tags: , >, [/BAR] or [/] |
267
|
|
|
|
|
|
|
elsif ( /$re_closhash/ || /$re_closlist/) |
268
|
|
|
|
|
|
|
{ |
269
|
161
|
|
|
|
|
396
|
my ($type, $block) = ($1, $2); |
270
|
|
|
|
|
|
|
# ensure that the tag matches the item we popped off the stack |
271
|
161
|
|
|
|
|
211
|
my $popped = pop(@stack); |
272
|
161
|
100
|
|
|
|
404
|
if (ref $popped eq 'HASH') { |
|
|
50
|
|
|
|
|
|
273
|
118
|
100
|
|
|
|
275
|
die("$self->{'errorprefix'} Nesting Error - hash block closed with array-style tag - Line $LINE: $_\n") if ($type ne '<'); |
274
|
|
|
|
|
|
|
} elsif (ref $popped eq 'ARRAY') { |
275
|
43
|
100
|
|
|
|
277
|
die("$self->{'errorprefix'} Nesting Error - array block closed with hash-style tag - Line $LINE: $_\n") if ($type ne '['); |
276
|
|
|
|
|
|
|
} else { |
277
|
0
|
|
|
|
|
0
|
die("$self->{'errorprefix'} Internal Error - Stack contained '$popped' - Line $LINE: $_\n") |
278
|
|
|
|
|
|
|
} |
279
|
159
|
100
|
66
|
|
|
697
|
unless ($popped && ($#stack >= 0)) { die("$self->{'errorprefix'} Stack underflow error - Line $LINE: $_"); } |
|
1
|
|
|
|
|
16
|
|
280
|
158
|
100
|
100
|
|
|
873
|
if ((pop(@level) ne $block) && $block) { die("$self->{'errorprefix'} Nesting Error - Line $LINE: $_"); } |
|
1
|
|
|
|
|
14
|
|
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
#Lines for use in hashes, like: NAME = VALUE |
283
|
|
|
|
|
|
|
elsif (/$re_datapair/) |
284
|
|
|
|
|
|
|
{ |
285
|
1329
|
|
|
|
|
3286
|
my ($name, $value) = ($1, $2); |
286
|
1329
|
|
|
|
|
2263
|
$value = _strip_and_unquote ( $value, $options ); |
287
|
|
|
|
|
|
|
|
288
|
1329
|
100
|
|
|
|
3274
|
if (ref($stack[$#stack]) eq 'HASH') { |
289
|
1328
|
|
|
|
|
8775
|
$stack[$#stack]->{$name} = $value; |
290
|
|
|
|
|
|
|
} else { |
291
|
1
|
|
|
|
|
6
|
$self->_invalid_line ( "this line not valid in a list block: Line $LINE: $_\n" ); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
#Lines for use in lists, like: VALUE or 'VALUE WITH SPACES' |
295
|
|
|
|
|
|
|
elsif (/$RE_DATASING/ or /$RE_DATASINGQUOTE/) |
296
|
|
|
|
|
|
|
{ |
297
|
104
|
|
|
|
|
205
|
my $value = $1; |
298
|
104
|
|
|
|
|
198
|
$value = _strip_and_unquote ( $value, $options ); |
299
|
104
|
100
|
|
|
|
302
|
if (ref($stack[$#stack]) eq 'ARRAY') { |
300
|
99
|
|
|
|
|
102
|
push(@{$stack[$#stack]}, $value); |
|
99
|
|
|
|
|
413
|
|
301
|
|
|
|
|
|
|
} else { |
302
|
5
|
100
|
|
|
|
16
|
if (!$options->{AllowEmptyValues}) { |
303
|
1
|
|
|
|
|
10
|
$self->_invalid_line ( "this line only valid in a list block: Line $LINE: $_\n" ); |
304
|
|
|
|
|
|
|
} else { |
305
|
|
|
|
|
|
|
# it's a blank element |
306
|
4
|
|
|
|
|
19
|
$stack[$#stack]->{$value} = ""; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
# directives to the parser, like: @set suffix .jpg - or - @option Escapes 1 |
311
|
|
|
|
|
|
|
elsif (/$re_command/) |
312
|
|
|
|
|
|
|
{ |
313
|
1043
|
|
|
|
|
2174
|
my $cmd = lc($1); |
314
|
1043
|
|
|
|
|
1504
|
my $text = $2; |
315
|
1043
|
100
|
|
|
|
2740
|
if ($cmd eq 'option') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
316
|
8
|
|
|
|
|
44
|
my ($name, $value) = ($text =~ /^\s*(\w+)\s*(.*?)\s*$/); |
317
|
|
|
|
|
|
|
# check to make sure that name can be overridden with @option |
318
|
8
|
50
|
|
|
|
48
|
if ( $name !~ m/^(UseQuotes|Escapes|Subs|TemplateBackend)$/i ) { |
319
|
0
|
|
|
|
|
0
|
warn ( $self->{'errorprefix'} . |
320
|
|
|
|
|
|
|
"unable to set " . $name . " with \@option" ); |
321
|
|
|
|
|
|
|
} else { |
322
|
8
|
|
|
|
|
18
|
$value = _strip_and_unquote ( $value, $options ); |
323
|
8
|
|
|
|
|
34
|
$options->{$name} = $value; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
} elsif ($cmd eq 'set') { |
326
|
13
|
|
|
|
|
99
|
my ($name, $value) = ($text =~ /^\s*(\w+)\s*(.*?)\s*$/); |
327
|
13
|
|
|
|
|
39
|
$value = _strip_and_unquote ( $value, $options ); |
328
|
13
|
|
|
|
|
75
|
$options->{'Variables'}->{$name} = $value; |
329
|
|
|
|
|
|
|
} elsif ($cmd eq 'include') { |
330
|
1006
|
|
|
|
|
1871
|
$text = _strip_and_unquote ( $text, $options ); |
331
|
1006
|
100
|
|
|
|
3758
|
if ($options->{'__includeguard'}{$text}++ > MAX_INCLUDES) { |
332
|
1
|
|
|
|
|
38
|
die "$self->{'errorprefix'} the file $text has been included too many times - probably a recursive include. Line $LINE\n"; |
333
|
|
|
|
|
|
|
} |
334
|
1005
|
|
|
|
|
1571
|
my $lines = _file2array($text); |
335
|
1004
|
|
|
|
|
6653
|
unshift @$linearray, @$lines; |
336
|
|
|
|
|
|
|
} elsif ($cmd eq 'reference') { |
337
|
|
|
|
|
|
|
# the 'name' is optional in list blocks - this regex matches with and without the 'name' |
338
|
14
|
|
|
|
|
89
|
my ($name, $path) = ($text =~ /^\s*(?:([\w\-\.]+)?\s+)?(\S+)\s*$/); |
339
|
14
|
|
|
|
|
39
|
$path = _strip_and_unquote ( $path, $options ); |
340
|
14
|
100
|
|
|
|
50
|
if (ref($stack[$#stack]) eq 'HASH') { |
341
|
9
|
100
|
66
|
|
|
76
|
die "$self->{'errorprefix'} You must give the new value a name inside hash blocks: Line $LINE: $_\n" unless (defined($name) && length($name)); |
342
|
7
|
|
|
|
|
24
|
$stack[$#stack]->{$name} = _var($self, $path, \%vars); |
343
|
|
|
|
|
|
|
} else { # we're in an array block |
344
|
5
|
|
|
|
|
8
|
push(@{$stack[$#stack]}, _var($self, $path, \%vars)); |
|
5
|
|
|
|
|
20
|
|
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
} else { |
347
|
2
|
|
|
|
|
8
|
$self->_invalid_line ( "could not understand directive: Line $LINE: $_\n" ); |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
else |
351
|
|
|
|
|
|
|
{ |
352
|
2
|
|
|
|
|
13
|
$self->_invalid_line ( "skipping invalid line: Line $LINE: $_\n" ); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# did we needed to implicitly close some tags? |
357
|
32
|
100
|
|
|
|
111
|
unless ($#stack == 0) { |
358
|
1
|
|
|
|
|
6
|
my $error = "$self->{'errorprefix'} There were $#stack open tags implicitly closed"; |
359
|
1
|
50
|
|
|
|
8
|
if ($options->{IgnoreUnclosedTags}) { |
360
|
1
|
|
|
|
|
18
|
warn($error); |
361
|
|
|
|
|
|
|
} else { |
362
|
0
|
|
|
|
|
0
|
die($error); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
32
|
|
|
|
|
240
|
return \%vars |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub _strip_and_unquote { |
370
|
2474
|
|
|
2474
|
|
3615
|
my ($text, $options) = @_; |
371
|
2474
|
|
|
|
|
2619
|
my $re_quotes = q/^([\'\"])(.*)\1$/; |
372
|
2474
|
|
|
|
|
2494
|
my $re_escape = q/%((?:[0-9a-fA-F]{2})|(?:\{[0-9a-fA-F]+\}))/; |
373
|
2474
|
100
|
|
|
|
5070
|
if ($options->{UseQuotes}) { $text =~ s/$re_quotes/$2/; } |
|
2396
|
|
|
|
|
5197
|
|
374
|
2474
|
100
|
|
|
|
4563
|
if ($options->{Escapes}) { $text =~ s/$re_escape/_unescape($1)/ge; } |
|
2403
|
|
|
|
|
3931
|
|
|
62
|
|
|
|
|
132
|
|
375
|
2474
|
|
|
|
|
5410
|
return $text; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# fetch the value of $name from $vars (array or hashref) |
379
|
|
|
|
|
|
|
# $name may contain dereferences of the form zzz->yyy |
380
|
|
|
|
|
|
|
sub _var { |
381
|
41
|
|
|
41
|
|
25609
|
my ($self, $name, $vars) = @_; |
382
|
41
|
|
|
|
|
140
|
TRACE(__PACKAGE__."::_var '$name'"); |
383
|
41
|
|
|
|
|
58
|
my $ref = $vars; |
384
|
41
|
|
|
|
|
78
|
my $found = 0; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# split $name on arrow operator '->' |
387
|
41
|
|
|
|
|
79
|
my @levels = ($name); |
388
|
41
|
100
|
|
|
|
347
|
@levels = split /->/, $name if $name =~ /[\w\-\.]+->[\w\-\.]+/; |
389
|
|
|
|
|
|
|
|
390
|
41
|
|
|
|
|
106
|
for my $i (0..$#levels) { |
391
|
115
|
|
|
|
|
268
|
my $k = $levels[$i]; |
392
|
115
|
|
|
|
|
115
|
my($val, @allowed, $keystr); |
393
|
115
|
50
|
|
|
|
217
|
last unless defined $ref; |
394
|
115
|
100
|
|
|
|
351
|
if(ref $ref eq 'HASH') { |
395
|
93
|
|
|
|
|
276
|
$found = exists $ref->{$k}; |
396
|
93
|
|
|
|
|
205
|
$val = $ref->{$k}; |
397
|
93
|
|
|
|
|
708
|
@allowed = keys %$ref; |
398
|
93
|
|
|
|
|
233
|
$keystr = 'key'; |
399
|
|
|
|
|
|
|
} else { |
400
|
22
|
|
|
|
|
46
|
$found = defined($val = $ref->[$k]); |
401
|
22
|
|
|
|
|
30
|
$keystr = 'subscript'; |
402
|
|
|
|
|
|
|
} |
403
|
115
|
50
|
100
|
|
|
351
|
$found = 1 if @levels == 1 && !VAR_CHECK_TOP_LEVEL; |
404
|
115
|
100
|
|
|
|
223
|
unless($found) { |
405
|
1
|
|
|
|
|
3
|
my $error = "trying to use nonexistent $keystr $k"; |
406
|
1
|
50
|
|
|
|
3
|
$error .= "(We would have allowed: ". |
407
|
|
|
|
|
|
|
(join ",", @allowed).")" if @allowed; |
408
|
1
|
|
|
|
|
3
|
$self->_nonexistant_var($error); |
409
|
|
|
|
|
|
|
} |
410
|
114
|
50
|
|
|
|
378
|
$ref = $val if $found; |
411
|
|
|
|
|
|
|
} |
412
|
40
|
50
|
|
|
|
309
|
return $found ? $ref : undef; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub _unescape { |
416
|
62
|
|
|
62
|
|
165
|
my $str = shift; |
417
|
62
|
50
|
|
|
|
162
|
if ($str =~ m/[{}]/) { |
418
|
0
|
|
|
|
|
0
|
$str =~ s/[{}]//g; |
419
|
|
|
|
|
|
|
} |
420
|
62
|
|
|
|
|
461
|
return chr(hex($str)); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub _escape { |
424
|
4
|
|
|
4
|
|
8
|
my $str = shift; |
425
|
4
|
50
|
|
|
|
15
|
unless (defined $str) { |
426
|
0
|
|
|
|
|
0
|
return undef; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
4
|
|
|
|
|
12
|
my $packstr = "U*"; |
430
|
4
|
50
|
33
|
|
|
39
|
if ($] && $] < 5.006001) { |
431
|
0
|
|
|
|
|
0
|
$packstr = "C*"; # earlier version of perl didn't have the 'U' pack template |
432
|
|
|
|
|
|
|
} |
433
|
4
|
0
|
33
|
|
|
1025
|
if ($^V && $^V lt chr(5).chr(8)) { |
434
|
|
|
|
|
|
|
# perl 5.6 doesn't like us to unpack a string of single-byte characters |
435
|
|
|
|
|
|
|
# which contains a character in the 128-255 range with U*. So, we have to revert to |
436
|
|
|
|
|
|
|
# the C* template if all the characters are bytes. |
437
|
|
|
|
|
|
|
# Note that this code only executes on perl 5.6 |
438
|
0
|
|
|
|
|
0
|
my $strlen = length($str); # in 5.6, this is character oriented, so UTF8 characters are counted as 1 character. |
439
|
0
|
|
|
|
|
0
|
my @nbytes = split(//, $str); # in 5.6, this is byte-oriented, so UTF8 sequences get split into their component bytes. |
440
|
0
|
0
|
|
|
|
0
|
if ($strlen == @nbytes) { |
441
|
0
|
|
|
|
|
0
|
$packstr = "C*"; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
# otherwise the string has more bytes than characters, hence some characters are wide, hence we can use the U* template safely. |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
0
|
|
|
|
|
0
|
my @ords = unpack($packstr, $str); |
447
|
0
|
|
|
|
|
0
|
my $rv = ''; |
448
|
0
|
|
|
|
|
0
|
foreach my $ordn (@ords) { |
449
|
0
|
0
|
|
|
|
0
|
if ($ordn < 256) { |
450
|
0
|
0
|
0
|
|
|
0
|
if ( |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
451
|
|
|
|
|
|
|
($ordn >= 0x30 && $ordn <= 0x39) || # 0 to 9, Unicode code points. |
452
|
|
|
|
|
|
|
($ordn >= 0x41 && $ordn <= 0x5A) || # A to Z |
453
|
|
|
|
|
|
|
($ordn >= 0x61 && $ordn <= 0x7A) # a to z |
454
|
|
|
|
|
|
|
) { |
455
|
0
|
|
|
|
|
0
|
$rv .= chr($ordn); # the literal character |
456
|
|
|
|
|
|
|
} else { |
457
|
0
|
|
|
|
|
0
|
$rv .= sprintf("%%%02X", $ordn); # use the %ff escape |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
} else { |
460
|
0
|
|
|
|
|
0
|
$rv .= sprintf("%%{%X}", $ordn); # use the %{fff...} escape |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
} |
463
|
0
|
|
|
|
|
0
|
return $rv; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
sub _str_indent { |
467
|
0
|
|
|
0
|
|
0
|
my($depth, @items) = @_; |
468
|
0
|
|
|
|
|
0
|
return ("\t"x$depth).join('', grep defined $_, @items); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
sub _wraptag { |
471
|
0
|
|
|
0
|
|
0
|
my($name, $v, $depth, $content) = @_; |
472
|
0
|
0
|
|
|
|
0
|
my $wrapc = ref $v eq 'ARRAY' ? [qw/[ ]/] : [qw/< >/]; |
473
|
0
|
|
|
|
|
0
|
my $str = ''; |
474
|
0
|
|
0
|
|
|
0
|
$depth ||= 0; |
475
|
0
|
|
|
|
|
0
|
$str .= _str_indent($depth, $wrapc->[0], $name, $wrapc->[1], "\n"); |
476
|
0
|
0
|
|
|
|
0
|
$str .= defined $content ? $content : ''; |
477
|
0
|
|
|
|
|
0
|
$str .= _str_indent($depth, $wrapc->[0].'/', $name, $wrapc->[1], "\n"); |
478
|
0
|
|
|
|
|
0
|
return $str; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub _serialise_type { |
482
|
6
|
|
|
6
|
|
14
|
my($self, $data, $opt, $depth) = @_; |
483
|
6
|
|
|
|
|
12
|
my $type = ref($data); |
484
|
6
|
100
|
|
|
|
48
|
my @list = $type eq 'HASH' ? (sort keys %$data) : @$data; |
485
|
6
|
|
|
|
|
103
|
my($pathstack, $referencelut, $use_quotes, $use_equals, $useref) = |
486
|
|
|
|
|
|
|
map $opt->{$_}, qw/pathstack referencelut UseQuotes WriteWithEquals |
487
|
|
|
|
|
|
|
WriteWithReferences/; |
488
|
6
|
100
|
|
|
|
21
|
my $equals_string = $use_equals ? '= ' : ''; |
489
|
6
|
50
|
|
|
|
18
|
my $quote_mark = $use_quotes ? "'" : ''; |
490
|
6
|
|
|
|
|
11
|
my $string = ''; |
491
|
6
|
|
|
|
|
8
|
my $i = -1; |
492
|
|
|
|
|
|
|
|
493
|
6
|
|
|
|
|
12
|
foreach my $k (@list) { |
494
|
6
|
|
|
|
|
7
|
my($v, $el_str); |
495
|
|
|
|
|
|
|
|
496
|
6
|
100
|
|
|
|
19
|
if($type eq 'HASH') { # hash |
497
|
4
|
|
|
|
|
8
|
$v = $data->{$k}; |
498
|
4
|
|
|
|
|
14
|
_ok_token($k); |
499
|
4
|
|
|
|
|
15
|
push(@$pathstack, $k); |
500
|
4
|
|
|
|
|
14
|
$el_str = qq/key '$k'/; |
501
|
|
|
|
|
|
|
} else { # array |
502
|
2
|
|
|
|
|
4
|
$v = $k; |
503
|
2
|
|
|
|
|
8
|
$k = $self->_unique_id(); |
504
|
2
|
|
|
|
|
33
|
_ok_listitem($v, $use_quotes); |
505
|
2
|
|
|
|
|
5
|
push(@$pathstack, ++$i); |
506
|
2
|
|
|
|
|
4
|
$el_str = qq/element index $i/; |
507
|
|
|
|
|
|
|
} |
508
|
6
|
|
|
|
|
21
|
my $path = join('->', @$pathstack); |
509
|
6
|
50
|
|
|
|
38
|
TRACE(__PACKAGE__."::_serialise Path: $path is " . (defined($v) ? $v : 'undef')); |
510
|
|
|
|
|
|
|
|
511
|
6
|
100
|
66
|
|
|
41
|
if (defined $v and ref $v) { |
512
|
2
|
50
|
33
|
|
|
14
|
if ($useref && exists($referencelut->{$v}) && length($referencelut->{$v})) { |
|
|
|
33
|
|
|
|
|
513
|
0
|
0
|
|
|
|
0
|
$string .= _str_indent |
514
|
|
|
|
|
|
|
($depth, sprintf("\@reference %s%s\n", |
515
|
|
|
|
|
|
|
$type eq 'HASH' ? "$k " : "", |
516
|
|
|
|
|
|
|
$referencelut->{$v})); |
517
|
|
|
|
|
|
|
} else { |
518
|
2
|
|
|
|
|
6
|
my $tagname = $k; |
519
|
2
|
0
|
|
|
|
8
|
$tagname = (ref $v eq 'HASH' ? 'hash' : 'list').$tagname |
|
|
50
|
|
|
|
|
|
520
|
|
|
|
|
|
|
if $type eq 'ARRAY'; # prefix tagname |
521
|
2
|
|
|
|
|
8
|
$referencelut->{$v} = $path; |
522
|
2
|
|
|
|
|
13
|
$string .= join |
523
|
|
|
|
|
|
|
('', _wraptag($tagname, $v, $depth, |
524
|
|
|
|
|
|
|
_serialise($self, $v, $opt, $depth+1))); |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
} else { |
527
|
4
|
50
|
|
|
|
47
|
my $localv = $opt->{Escapes} ? _escape($v) : $v; |
528
|
0
|
|
|
|
|
0
|
my $flag = 1; |
529
|
|
|
|
|
|
|
|
530
|
0
|
0
|
0
|
|
|
0
|
if (!defined($localv) || !length($localv)) { |
531
|
0
|
0
|
|
|
|
0
|
if ($opt->{AllowEmptyValues}) { |
532
|
0
|
|
|
|
|
0
|
$localv = ''; |
533
|
|
|
|
|
|
|
} else { |
534
|
0
|
|
|
|
|
0
|
$self->_invalid_line ( "not writing an empty value for $el_str (full path '$path') because the AllowEmptyValues option is false\n" ); |
535
|
0
|
|
|
|
|
0
|
$flag = 0; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
} |
538
|
0
|
0
|
|
|
|
0
|
if ($flag) { |
539
|
0
|
|
|
|
|
0
|
my @el = ($quote_mark, $localv, $quote_mark, "\n"); |
540
|
0
|
0
|
|
|
|
0
|
unshift @el, ($k, " ", $equals_string) if $type eq 'HASH'; |
541
|
0
|
|
|
|
|
0
|
$string .= _str_indent($depth, @el); |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
} |
544
|
0
|
|
|
|
|
0
|
pop(@$pathstack); |
545
|
|
|
|
|
|
|
} #end foreach |
546
|
|
|
|
|
|
|
|
547
|
0
|
|
|
|
|
0
|
return $string; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub _serialise { |
551
|
6
|
|
|
6
|
|
12
|
my ($self, $data, $opt, $depth) = @_; |
552
|
|
|
|
|
|
|
|
553
|
6
|
|
100
|
|
|
39
|
$opt->{referencelut} ||= {}; |
554
|
6
|
|
100
|
|
|
41
|
$opt->{pathstack} ||= []; |
555
|
6
|
|
100
|
|
|
29
|
$depth ||= 0; |
556
|
|
|
|
|
|
|
|
557
|
6
|
|
|
|
|
26
|
TRACE(__PACKAGE__."::_serialise depth $depth"); |
558
|
6
|
50
|
|
|
|
19
|
croak(ERR_MAX_SER_DEPTH_EXCEEDED) if $depth > MAX_SER_DEPTH; |
559
|
|
|
|
|
|
|
|
560
|
6
|
|
|
|
|
41
|
return $self->_serialise_type($data, $opt, $depth); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub _nonexistant_var { |
564
|
1
|
|
|
1
|
|
2
|
my ($self, $error) = @_; |
565
|
|
|
|
|
|
|
|
566
|
1
|
50
|
|
|
|
4
|
return unless $self->{'current_options'}{'DieOnNonExistantVars'}; |
567
|
|
|
|
|
|
|
|
568
|
1
|
|
|
|
|
10
|
die ($self->{'errorprefix'} . $error); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub _invalid_line { |
572
|
6
|
|
|
6
|
|
11
|
my ($self, $error) = @_; |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# should we be ignoring invalid lines? |
575
|
6
|
50
|
|
|
|
25
|
return if $self->{'current_options'}{'IgnoreInvalidLines'}; |
576
|
|
|
|
|
|
|
|
577
|
6
|
|
|
|
|
23
|
TRACE("Strict = " . $self->{'current_options'}{'Strict'} ); |
578
|
6
|
100
|
|
|
|
17
|
if ($self->{'current_options'}{'Strict'}) |
579
|
|
|
|
|
|
|
{ |
580
|
2
|
|
|
|
|
24
|
die ($self->{'errorprefix'} . $error); |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
else |
583
|
|
|
|
|
|
|
{ |
584
|
4
|
|
|
|
|
68
|
warn ($self->{'errorprefix'} . $error . " [warning]"); |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# block elements inside lists have their names discarded, so we need to recreate a name |
589
|
|
|
|
|
|
|
sub _unique_id { |
590
|
2
|
|
|
2
|
|
5
|
my $self = shift; |
591
|
2
|
|
|
|
|
6
|
return ++$self->{'UniqueIdCounter'}; |
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# hash, list and item names must be \w\-\. only, so let's stop ConfigWriter creating bad file |
595
|
|
|
|
|
|
|
sub _ok_token { |
596
|
4
|
|
|
4
|
|
8
|
my $str = $_[0]; |
597
|
4
|
50
|
33
|
|
|
49
|
croak(ERR_BADTOK . $str . '"') if (!defined($str) || $str !~ m/^[\w\-\.]+$/); |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
sub _ok_listitem { |
601
|
2
|
|
|
2
|
|
5
|
my ($str, $quo) = @_; |
602
|
2
|
50
|
|
|
|
9
|
if ($quo) { |
603
|
2
|
50
|
|
|
|
51
|
croak(ERR_BADLISTITEM_QUOTE . $str . '"') if ("'$str'" !~ m/$RE_DATASINGQUOTE/); |
604
|
|
|
|
|
|
|
} else { |
605
|
0
|
0
|
|
|
|
0
|
croak(ERR_BADLISTITEM . $str . '"') if ($str !~ m/$RE_DATASING/); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# Debugging stubs |
610
|
3838
|
|
|
3838
|
0
|
4206
|
sub TRACE {} |
611
|
0
|
|
|
0
|
0
|
|
sub DUMP {} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
1; |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
######################################################################## |
616
|
|
|
|
|
|
|
# POD |
617
|
|
|
|
|
|
|
######################################################################## |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=head1 NAME |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
Config::Wrest - Read and write Configuration data With References, Environment variables, Sections, and Templating |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=head1 SYNOPSIS |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
use Config::Wrest; |
626
|
|
|
|
|
|
|
my $c = new Config::Wrest(); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# Read configuration data from a string, or from a reference to a string |
629
|
|
|
|
|
|
|
my $vars; |
630
|
|
|
|
|
|
|
$vars = $c->deserialize($string); |
631
|
|
|
|
|
|
|
$vars = $c->deserialize(\$string); |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# Write configuration data as a string |
634
|
|
|
|
|
|
|
my $string = $c->serialize(\%vars); |
635
|
|
|
|
|
|
|
# ...write the data into a specific scalar |
636
|
|
|
|
|
|
|
$c->serialize(\%vars, \$string); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# Convenience methods to interface with files |
639
|
|
|
|
|
|
|
$vars = $c->parse_file($filename); |
640
|
|
|
|
|
|
|
$c->write_file($filename, \%vars); |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=head1 DESCRIPTION |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
This module allows you to read configuration data written in a human-readable and easily-editable text format |
645
|
|
|
|
|
|
|
and access it as a perl data structure. It also allows you to write configuration data from perl back to this format. |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
The data format allows key/value pairs, comments, escaping of unprintable or problematic characters, |
648
|
|
|
|
|
|
|
sensible whitespace handling, support for Unicode data, |
649
|
|
|
|
|
|
|
nested sections, or blocks, of configuration data (analogous to hash- and array-references), and the optional |
650
|
|
|
|
|
|
|
preprocessing of each line through a templating engine. If you choose to use a templating engine then, depending |
651
|
|
|
|
|
|
|
on the engine you're using, you can interpolate other values into the data, interpolate environment variables, |
652
|
|
|
|
|
|
|
and perform other logic or transformations. The data format also allows you to use directives to alter the behaviour |
653
|
|
|
|
|
|
|
of the parser from inside the configuration file, to set variables, to include other files, and for other |
654
|
|
|
|
|
|
|
actions. |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Here's a brief example of some configuration data. Note the use of quotes, escape sequences, and nested blocks: |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
Language = perl |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
width = 100 # This is an end-of-line comment |
661
|
|
|
|
|
|
|
height 100 |
662
|
|
|
|
|
|
|
alt_text " square red image, copyright %A9 2001 " |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
colour red |
665
|
|
|
|
|
|
|
> |
666
|
|
|
|
|
|
|
[Suffixes] |
667
|
|
|
|
|
|
|
.jpg |
668
|
|
|
|
|
|
|
.jpeg |
669
|
|
|
|
|
|
|
[/] |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
@include path/to/file.cfg |
672
|
|
|
|
|
|
|
[Days] |
673
|
|
|
|
|
|
|
Sunday |
674
|
|
|
|
|
|
|
Can%{2019}t |
675
|
|
|
|
|
|
|
'Full Moon' |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
length 48h |
678
|
|
|
|
|
|
|
> |
679
|
|
|
|
|
|
|
# and so on... This is a full-line comment |
680
|
|
|
|
|
|
|
[/] |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
This parses to the perl data structure: |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
{ |
685
|
|
|
|
|
|
|
Language => 'perl', |
686
|
|
|
|
|
|
|
imageinfo => { |
687
|
|
|
|
|
|
|
width => '100', |
688
|
|
|
|
|
|
|
height => '100', |
689
|
|
|
|
|
|
|
alt_text => " square red image, copyright \xA9 2001 ", |
690
|
|
|
|
|
|
|
Nestedblock => { |
691
|
|
|
|
|
|
|
colour => 'red' |
692
|
|
|
|
|
|
|
}, |
693
|
|
|
|
|
|
|
Suffixes => [ |
694
|
|
|
|
|
|
|
'.jpg', |
695
|
|
|
|
|
|
|
'.jpeg' |
696
|
|
|
|
|
|
|
], |
697
|
|
|
|
|
|
|
}, |
698
|
|
|
|
|
|
|
Days => [ |
699
|
|
|
|
|
|
|
'Sunday', |
700
|
|
|
|
|
|
|
"Can\x{2019}t", # note the Unicode character in this string |
701
|
|
|
|
|
|
|
'Full Moon', |
702
|
|
|
|
|
|
|
{ |
703
|
|
|
|
|
|
|
'length' => '48h' |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
], |
706
|
|
|
|
|
|
|
# ...and of course, whatever data was read from the included file "path/to/file.cfg" |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
Of course, your configuration data may not need to use any of those special features, and might simply be key/value pairs: |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Basedir /usr/local/myprogram |
712
|
|
|
|
|
|
|
Debug 0 |
713
|
|
|
|
|
|
|
Database IFL1 |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
This parses to the perl data structure: |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
{ |
718
|
|
|
|
|
|
|
Basedir => '/usr/local/myprogram', |
719
|
|
|
|
|
|
|
Debug => '0', |
720
|
|
|
|
|
|
|
Database => 'IFL1', |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
These data structures can be serialized back to a textual form using this module. |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
For details of the data format see L and L. Also see L for options |
726
|
|
|
|
|
|
|
which affect the parsing of the data. All file input and output goes through L. |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
=head2 MODULE NAME |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
Although the "Wrest" in the module's name is an abbreviation for its main features, it also means |
731
|
|
|
|
|
|
|
"a key to tune a stringed instrument" or "active or moving power". (Collaborative International Dictionary of English) |
732
|
|
|
|
|
|
|
You can also think of it wresting your configuration data from human-readable form into perl. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=head1 METHODS |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=over 4 |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=item new( %OPTIONS ) |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
Return a new object, configured with the given options - see L. |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=item deserialize( $STRING ) or deserialize( \$STRING ) |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
Given either a string containing configuration data, or a reference to such a string, attempts to parse it |
745
|
|
|
|
|
|
|
and returns the configuration information as a hash reference. |
746
|
|
|
|
|
|
|
See L for details of warnings and errors. |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item serialize( \%VARS ) or serialize( \%VARS, \$STRING ) |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
Given a reference to a hash of configuration data, turns it back into its textual representation. |
751
|
|
|
|
|
|
|
If no string reference is supplied then this text string is returned, otherwise it is written into the |
752
|
|
|
|
|
|
|
given reference. See L for details of warnings and errors. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=item deserialise() |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
An alias for deserialize() |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=item serialise() |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
An alias for serialize() |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=item parse_file( $FILEPATH ) |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
Read the specified file, deserialize the contents and return the configuration data. |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=item write_file( $FILEPATH, \%VARS ) |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
Serializes the given configuration data and writes it to the specified file. |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=back |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=head1 CONSTRUCTOR OPTIONS |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
These are the options that can be supplied to the constructor, and some may meaningfully be modified by the |
775
|
|
|
|
|
|
|
@option directive - namely the UseQuotes, Escapes, Subs and TemplateBackend options. |
776
|
|
|
|
|
|
|
Some of these option are turned on by default. |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
=over 4 |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=item AllowEmptyValues |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
Default is 1. |
783
|
|
|
|
|
|
|
In this configuration data, one of the keys - "Wings" - has no value against it: |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
Species cod |
786
|
|
|
|
|
|
|
Category fish |
787
|
|
|
|
|
|
|
Wings |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
By default this will be interpreted as the empty string. If this option is set to false then |
790
|
|
|
|
|
|
|
the line will be skipped. A warning will also be emitted unless the IgnoreInvalidLines option is true. |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
This option also affects the serialization of data. When it's true it will also allow the serializer |
793
|
|
|
|
|
|
|
to create a configuration line like the "Wings" example, i.e. a key with an empty value, and |
794
|
|
|
|
|
|
|
allow serialization of empty values in arrays. |
795
|
|
|
|
|
|
|
However, if AllowEmptyValues was false then the serializer would see that the |
796
|
|
|
|
|
|
|
value for "Wings" was empty and would skip over it, emitting a warning by default. |
797
|
|
|
|
|
|
|
See the 'IgnoreInvalidLines' option for a way to suppress these warnings. |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
If you want to read an empty value in a list it needs to be quoted (see the UseQuotes option) otherwise it'll |
800
|
|
|
|
|
|
|
look like a completely blank line: |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
[valid] |
803
|
|
|
|
|
|
|
'green' |
804
|
|
|
|
|
|
|
'' |
805
|
|
|
|
|
|
|
[/] |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
Similarly, the UseQuotes option should be in effect if you wish to write out empty values in list blocks, so that they |
808
|
|
|
|
|
|
|
do not appear as blank lines. |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=item DieOnNonExistantVars |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
Default is 1. |
813
|
|
|
|
|
|
|
Usually the parser will die() if the configuration data references a variable |
814
|
|
|
|
|
|
|
that has not been previously declared. However, setting this option to 0 will |
815
|
|
|
|
|
|
|
disable this behaviour and silently continue parsing. |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=item Escapes |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
Default is 1. |
820
|
|
|
|
|
|
|
Translates escape sequences of the form '%[0-9a-fA-F][0-9a-fA-F]' or '%{[0-9a-fA-F]+}'into the character represented by the given hex number. |
821
|
|
|
|
|
|
|
E.g. this is useful for putting in newlines (%0A) or carriage-returns (%0D), or otherwise storing arbitrary data. |
822
|
|
|
|
|
|
|
The two-character form, %FF, is of course only useful for encoding characters in the range 0 to 255. The multi-character form |
823
|
|
|
|
|
|
|
can be used for a hex number of any length, e.g. %{A}, %{23}, %{A9}, %{153}, %{201C}. See L |
824
|
|
|
|
|
|
|
for more information. |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
This value is also used when serializing data. If true then the serialized data will have non-alphanumeric characters escaped. |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=item IgnoreInvalidLines |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
Default is 0. |
831
|
|
|
|
|
|
|
Disables warn()'ings that would normally occur when the parser encountered a line that couldn't be |
832
|
|
|
|
|
|
|
understood or was invalid. Also disables the warning when 'AllowEmptyValues' is false and you are |
833
|
|
|
|
|
|
|
attempting to serialize() an empty or undefined value. |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
=item IgnoreUnclosedTags |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
Default is 0. |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
By default, should the configuration data have an unbalanced number of opening |
840
|
|
|
|
|
|
|
and closing tags, an error will be generated to this effect. If |
841
|
|
|
|
|
|
|
IgnoreUnclosedTags is set to 1 then this error will be downgraded to a |
842
|
|
|
|
|
|
|
warning. |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
=item Strict |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
Default is 1. |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
By default any errors in the configuration will result in an error being |
849
|
|
|
|
|
|
|
thrown containing related details. To override this behaviour set the "Strict" |
850
|
|
|
|
|
|
|
option to 0, this will convert these errors into warnings and processing will |
851
|
|
|
|
|
|
|
continue. |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
=item Subs |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
Default is 0. By default the configuration lines are read verbatim. However, sometimes you want to be able to pick data from |
856
|
|
|
|
|
|
|
the environment, or you want to set a common string e.g. at the top of the file or in the Variables option (see below). |
857
|
|
|
|
|
|
|
This re-use or interpolation of values can save lots of repetition, and improve portability of configuration files. |
858
|
|
|
|
|
|
|
This module implements this kind of interpolation and re-use by giving you the ability to pass each line through |
859
|
|
|
|
|
|
|
a templating engine. |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
Simply set this option to 1 to make every line pass through Any::Template (which is loaded on demand) before being parsed. |
862
|
|
|
|
|
|
|
As each line is read it is turned into a new Any::Template object, and then the process() method is given all of the configuration |
863
|
|
|
|
|
|
|
data that has been read so far, and whatever data was provided in the Variables option (see below). |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
Here's an example of how you could use the feature, using a templating engine which looks in the data structure (mentioned above) and |
866
|
|
|
|
|
|
|
in the environment for its values. The template syntax is simply C<[INSERT I]> to insert a value, and let's assume that |
867
|
|
|
|
|
|
|
the environment variable DOCROOT is set to '/home/system'. So if Subs is true then the following lines: |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
Colour = 'red' |
870
|
|
|
|
|
|
|
@set FILE_SUFFIX cfg |
871
|
|
|
|
|
|
|
Filename [INSERT DOCROOT]/data/testsite/[INSERT Colour]/main.[INSERT FILE_SUFFIX] |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
will be parsed into: |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
{ |
876
|
|
|
|
|
|
|
'Colour' => 'red', |
877
|
|
|
|
|
|
|
'Filename' => '/home/system/data/testsite/red/main.cfg' |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
Obviously that's a simple example but shows how this feature can be used to factor out common values. |
881
|
|
|
|
|
|
|
Your Any::Template-compatible templating engine may provide far more advanced features which you're also free to use. |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
Note that keys in the Variables option override the keys derived from the configuration data so far. |
884
|
|
|
|
|
|
|
If the configuration data contains blocks then these will be available in the template's data structure as the appropriate |
885
|
|
|
|
|
|
|
hash- or array-references, just as would be returned by the deserialize() method. |
886
|
|
|
|
|
|
|
Also note that after the templating step, the "line" may now actually contain line breaks - and if it does the parser will |
887
|
|
|
|
|
|
|
continue to work through each line, parsing each line separately. The current line will of course not be passed |
888
|
|
|
|
|
|
|
through the templating engine again, but any subsequent lines will be. |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
You can always use the Escapes feature to include unusual characters in your data if your templating engine is able to |
891
|
|
|
|
|
|
|
escape data in the right way. |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
After the templating step, the line is then parsed as usual. See the @reference directive (L) for a related concept, |
894
|
|
|
|
|
|
|
where you can refer back to earlier values and blocks in their entirety. |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=item TemplateBackend |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
Only relevant if 'Subs' is true. Choose which 'Backend' to use with Any::Template. The default is empty, which means |
899
|
|
|
|
|
|
|
that Any::Template will use an environment variable to determine the default Backend - see L for details. |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=item TemplateOptions |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
Only relevant if 'Subs' is true. |
904
|
|
|
|
|
|
|
Some Any::Template backends take a hash-reference as an 'Options' constructor parameter. Set this option to the required |
905
|
|
|
|
|
|
|
hash-reference and it will be passed to the Any::Template constructor. Note that if the backend is changed |
906
|
|
|
|
|
|
|
by using a directive like '@set TemplateBackend Foo' this TemplateOptions will still be used. |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=item UseQuotes |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
Default is 1. |
911
|
|
|
|
|
|
|
If a value read from the config file is quoted (with matching C<'> or C<">), remove the quotes. Useful for including explicit whitespace. |
912
|
|
|
|
|
|
|
This option is also used when serializing data - if this option is true then values will always be written out with quotes. |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=item Variables |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
A reference to a hash which contains the names of some variables and their appropriate values. Only used when the Subs option |
917
|
|
|
|
|
|
|
is in effect. Note that this copied before use (using dclone() from L, loaded on demand) which means |
918
|
|
|
|
|
|
|
that the original data structure should be unaffected by @set directives, and that you can use the Config::Wrest |
919
|
|
|
|
|
|
|
object multiple times and the same data structure is used every time. |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
=item WriteWithEquals |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
Default is 0. When serializing data, keys and values will be separated by '='. |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=item WriteWithHeader |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
Default is 1. When serializing data, the default behaviour is to emit lines at the start indicating the |
928
|
|
|
|
|
|
|
software that serialized the data and the specific settings of the AllowEmptyValues, Escapes, and UseQuotes |
929
|
|
|
|
|
|
|
directives. This option suppresses those lines. |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=item WriteWithReferences |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
Default is 0. If true then an appropriate '@reference' directive will be emitted during serialization |
934
|
|
|
|
|
|
|
whenever a perl data structure is referred to for the second, or subsequent, times. |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
=back |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
=head1 DATA FORMAT |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
The data is read line-by-line. Comments are stripped and blank lines are ignored. |
941
|
|
|
|
|
|
|
You can't have multiple elements (key/value pairs, values in a list block, block opening tags, |
942
|
|
|
|
|
|
|
block closing tags, or directives) on a single line - you may only have one such element per line. |
943
|
|
|
|
|
|
|
Both the newline and carriage return characters (\n and \r) are considered as line breaks, and hence |
944
|
|
|
|
|
|
|
configuration files can be read and written across platforms (see L). |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
Data is stored in two ways: as key/value pairs, or as individual values when inside a "list block". |
947
|
|
|
|
|
|
|
Hash or list blocks may be nested inside other blocks to arbitrary depth. |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
=head2 KEY VALUE PAIRS |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
Lines such as these are used at the top level of the configuration file, or inside L. |
952
|
|
|
|
|
|
|
The line simply has a key and a value, separated by whitespace or an '=' sign: |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
colour=red |
955
|
|
|
|
|
|
|
name = "Scott Tiger" |
956
|
|
|
|
|
|
|
Age 23 |
957
|
|
|
|
|
|
|
Address foo%40example.com |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
The 'key' can consist of "\w" characters, "." and "-". |
960
|
|
|
|
|
|
|
VALUE can include anything but a '#' to the end of the line. |
961
|
|
|
|
|
|
|
See Escapes and UseQuotes in L. |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=head2 SINGLE VALUES |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
Lines such as these are used inside L. The value is simply given: |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
Thursday |
968
|
|
|
|
|
|
|
"Two Step" |
969
|
|
|
|
|
|
|
apple%{2019}s |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
These may not begin with these characters: '[', 'E', '(', '{', ':', '@', '%', '/' |
972
|
|
|
|
|
|
|
because they are the first thing in a line and such characters would be confused |
973
|
|
|
|
|
|
|
with actual tags and reserved characters. See Escapes and UseQuotes in L |
974
|
|
|
|
|
|
|
if your value begins with any of these, or if you want to include whitespace. |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
=head2 COMMENTS |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
Comments may be on a line by themselves: |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# Next line is for marketing... |
981
|
|
|
|
|
|
|
Whiteness = Whizzy Whiteness! |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
or at the end of a line: |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
Style=Loads of chrome # that's what marketing want |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
Note that everything following a '#' character (in Unicode that's called a "NUMBER SIGN") is taken to be a comment, so if you want |
988
|
|
|
|
|
|
|
to have an actual '#' in your data you must have the Escapes option turned on (see L) e.g.: |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
Colour %23FF9900 |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
even if the '#' is in the middle of a quoted string: |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
Foo "bar#baz" # a comment |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
is equivalent to: |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
Foo "bar |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
=head2 HASH BLOCKS |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
A block which contains L, or other blocks. They look like: |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
colour red |
1006
|
|
|
|
|
|
|
# contents go here |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
For convenience you can omit the block's name in the closing tag, like this: |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
Age 23 |
1013
|
|
|
|
|
|
|
# contents go here |
1014
|
|
|
|
|
|
|
> |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
The name of the block can consist of "\w" characters, "." and "-". |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
=head2 LIST BLOCKS |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
A block which contains a list of L, or other blocks. They look like: |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
[Instruments] |
1023
|
|
|
|
|
|
|
bass |
1024
|
|
|
|
|
|
|
guitar |
1025
|
|
|
|
|
|
|
[/Instruments] |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
and you can omit the name in the closing tag if you wish: |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
# ... |
1030
|
|
|
|
|
|
|
guitar |
1031
|
|
|
|
|
|
|
[/] |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
The name of the block can consist of "\w" characters, "." and "-". |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
=head2 WHITESPACE RULES |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
In L the '=' between the Name and Value is optional, but it can have whitespace before and/or after it. If |
1038
|
|
|
|
|
|
|
there's no '=' you need whitespace to separate the Name and Value. |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
Block opening and closing tags cannot have whitespace inside them. |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
Lines may be indented by arbitrary whitespace. Trailing whitespace is stripped from values (but |
1043
|
|
|
|
|
|
|
see the UseQuotes and Escapes entries in L). |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
=head2 ESCAPING |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
Sometimes you want to specify data with characters that are unprintable, hard-to type or have special meaning to Config::Wrest. |
1048
|
|
|
|
|
|
|
You can escape such characters using two forms. Firstly, the '%' symbol followed by two hex digits, e.g. C<%A9>, for |
1049
|
|
|
|
|
|
|
characters up to 255 decimal. Secondly you can write '%' followed by any hex number in braces, e.g. C<%{201c}> to specify |
1050
|
|
|
|
|
|
|
any character by its Unicode code point. |
1051
|
|
|
|
|
|
|
See 'Escapes' under L. |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=head2 DIRECTIVES |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
The configuration file itself can contain lines which tell the parser how to behave. |
1056
|
|
|
|
|
|
|
All directive lines begin with an '@'. For example you can turn on |
1057
|
|
|
|
|
|
|
the URL-style escaping, you can set variables, and so on. |
1058
|
|
|
|
|
|
|
These are recognized directives: |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
=over 4 |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
=item @include FILENAME |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
Insert a file into the current configuration in place of this directive, and continue reading configuration information. |
1065
|
|
|
|
|
|
|
This file is simply another file of Config::Wrest lines. If any options are set in the include, or in any nested includes, |
1066
|
|
|
|
|
|
|
the effect of them will persist after the end of that file - i.e. when a file is included it is effectively merged with |
1067
|
|
|
|
|
|
|
the parent file's contents. |
1068
|
|
|
|
|
|
|
The filename is treated according to the current setting of the UseQuotes and Escapes options. |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
=item @option NAME VALUE |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
Allows you to alter the VALUE of the parser option called NAME that is otherwise set in the perl interface. See L. |
1073
|
|
|
|
|
|
|
The value is treated according to the current setting of the UseQuotes and Escapes options. |
1074
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
=item @reference [ NAME ] PATH |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
Allows you to tell the parser to re-use a previous data value and put it in the current location against the given key 'NAME' |
1078
|
|
|
|
|
|
|
- inside hash blocks the 'NAME' is required, but inside list blocks the 'NAME' is optional and effectively ignored. This feature allows you to |
1079
|
|
|
|
|
|
|
have a block or value in your config file which is re-used many times further on in the file. The 'NAME' has the same restriction |
1080
|
|
|
|
|
|
|
as for all other key names. The 'PATH' is a string which specified the data item (which may be a plain value or a block) |
1081
|
|
|
|
|
|
|
that you wish to reference, and is built up by joining a sequence of hash keys and array indexes together with '->' arrows. |
1082
|
|
|
|
|
|
|
E.g. if you look at the example in L then the path 'imageinfo->Nestedblock' refers to that hash block, |
1083
|
|
|
|
|
|
|
'imageinfo->Nestedblock->colour' refers the value 'red', and 'Days->0' is the value 'Sunday'. |
1084
|
|
|
|
|
|
|
The 'PATH' is treated according to the current setting of the UseQuotes and Escapes options. |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
Note that this is a different |
1087
|
|
|
|
|
|
|
operation to using the 'Subs' feature because this directive uses actual perl data references, rather than inserting |
1088
|
|
|
|
|
|
|
some text which is then parsed into data structures, and hence can deal simply with complex structures. It is possible |
1089
|
|
|
|
|
|
|
to construct circular data structures using this directive. |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
=item @set NAME VALUE |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
Set a variable with the given NAME to any given VALUE, so that you may use that variable later on, if you've set the Subs option. |
1094
|
|
|
|
|
|
|
The variable name must consist of alphanumeric and underscore characters only. |
1095
|
|
|
|
|
|
|
The value is treated according to the current setting of the UseQuotes and Escapes options. |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
=back |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
=head2 UNICODE HANDLING |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
This section has been written from the point-of-view of perl 5.8, although the concepts translate to perl 5.6's |
1102
|
|
|
|
|
|
|
slightly different Unicode handling. |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
First it's important to differentiate between configuration data that is given to deserialize() as a string which contains |
1105
|
|
|
|
|
|
|
wide characters (i.e. code point >255), and data which contains escape sequences for wide characters. Escape sequences |
1106
|
|
|
|
|
|
|
can only occur in certain places, whereas actual wide characters can be used in key names, block names, directives and |
1107
|
|
|
|
|
|
|
in values. This is because the parser uses regular expressions which use metacharacters such as "\w", and these can |
1108
|
|
|
|
|
|
|
match against some wide characters. |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
Although you can use wide characters in directives, it may make no sense to try to "@include" a filename which contains |
1111
|
|
|
|
|
|
|
wide characters. |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
Configuration data will generally be read to or written from a file at some stage. You should be aware that |
1114
|
|
|
|
|
|
|
File::Slurp::WithinPolicy uses File::Slurp which reads files in byte-oriented fashion. |
1115
|
|
|
|
|
|
|
If this is not what you want, e.g. if your config files contain multi-byte characters such as UTF8, |
1116
|
|
|
|
|
|
|
then you should either read/write the file yourself using the appropriate layer |
1117
|
|
|
|
|
|
|
in the arguments to open(), or use the Encode module to go between perl's Unicode-based strings and the required |
1118
|
|
|
|
|
|
|
encoding (e.g. your configuration files may be stored on disk as ISO-8859-1, but you want it to be read into perl |
1119
|
|
|
|
|
|
|
as the Unicode characters, not as a stream of bytes). Similarly, you may wish to use Encode or similar to turn |
1120
|
|
|
|
|
|
|
a string into the correct encoding for your application to use. |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
Unicode specifies a number of different characters that should be considered as line endings: not just u000A and u000D, |
1123
|
|
|
|
|
|
|
but also u0085 and several others. However, to keep this module compatible with perl versions before 5.8 this |
1124
|
|
|
|
|
|
|
module splits data into lines on the sequence "\x0D\x0A" B on the regular expression C[\n\r]/>, and does B |
1125
|
|
|
|
|
|
|
split on any of the other characters given in the Unicode standard. If you want your configuration data to use any of the |
1126
|
|
|
|
|
|
|
other line endings you must read the file yourself, change the desired line ending to C<\n> and pass that string |
1127
|
|
|
|
|
|
|
to deserialize(). Reverse the process when using serialize() and writing files. E.g. on an OS/390 machine a |
1128
|
|
|
|
|
|
|
configuration file may be stored with C (i.e. "\x85") line endings which need to be changed when reading it |
1129
|
|
|
|
|
|
|
on a Unix machine. |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
This module has not been tested on EBCDIC platforms. |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
=head1 READING DATA |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
If you try to deserialize configuration data that has the wrong syntax (e.g. mis-nested blocks, or too many closing tags) |
1136
|
|
|
|
|
|
|
a fatal error will be raised. |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
Unrecognized directives cause a warning, as will key/value lines appearing in a list block, or list items appearing in a |
1139
|
|
|
|
|
|
|
hash block (see AllowEmptyValues in L). You also get a warning if there were too few closing tags |
1140
|
|
|
|
|
|
|
and the parse implicitly closed some for you. |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=head1 WRITING DATA |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
The data structure you want to serialize must be a hash reference. The values may be strings, arrayrefs or hashrefs, |
1145
|
|
|
|
|
|
|
and so on recursively. Any bad reference types cause a fatal croak(). |
1146
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
You are only allowed to use a restricted set of characters as hash keys, i.e. the names of block elements |
1148
|
|
|
|
|
|
|
and the key in key/value pairs of data. If your data structure has a hash key that could create bad |
1149
|
|
|
|
|
|
|
config data a fatal error is thrown with croak(). Values in list blocks are also checked, and a fatal error is raised |
1150
|
|
|
|
|
|
|
if the value would create bad config data. |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
In general you will want to use the 'Escapes' option described above. This makes it hard to produce bad configuration files. |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
If you want to dump out cyclic / self-referential data structures you'll need to set the 'WriteWithReferences' option, otherwise the deep recursion |
1155
|
|
|
|
|
|
|
will be detected and the serialization will throw a fatal error. |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
=head1 SEE ALSO |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
parse_file(), write_file() and the '@include' directive load L on demand to perform the file input/output operations. |
1160
|
|
|
|
|
|
|
See L for more details on perl's Unicode handling, and L for character recoding. |
1161
|
|
|
|
|
|
|
See L, and the relevant templating modules, if the 'Subs' option is true. |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
Although this module can read and write data structures it is not intended as an all-purpose serialization system. For that |
1164
|
|
|
|
|
|
|
see L. |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
Unicode Newline Guidelines from http://www.unicode.org/versions/Unicode4.0.0/ch05.pdf#G10213 |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
=head1 VERSION |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
$Revision: 1.36 $ on $Date: 2006/08/22 14:09:50 $ by $Author: mattheww $ |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
=head1 AUTHOR |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
IF&L Software Engineers |
1175
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
(c) BBC 2006. This program is free software; you can redistribute it and/or modify it under the GNU GPL. |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
See the file COPYING in this distribution, or http://www.gnu.org/licenses/gpl.txt |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
=cut |