line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::Nested; |
2
|
|
|
|
|
|
|
# Copyright (c) 2008-2010 Sullivan Beck. All rights reserved. |
3
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify it |
4
|
|
|
|
|
|
|
# under the same terms as Perl itself. |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
######################################################################## |
7
|
|
|
|
|
|
|
# TODO |
8
|
|
|
|
|
|
|
######################################################################## |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# If no structural information is kept, merge methods can only |
11
|
|
|
|
|
|
|
# keep/replace/append for lists but unordered non-uniform lists |
12
|
|
|
|
|
|
|
# are allowed. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# When specifying structure, /foo/* forces uniform if it is not |
15
|
|
|
|
|
|
|
# already specified as non-uniform. If a structure is uniform, |
16
|
|
|
|
|
|
|
# then applying structure to /foo/1 is equivalent to /foo/* (but |
17
|
|
|
|
|
|
|
# a warning may be issued). |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Add validity tests for data |
20
|
|
|
|
|
|
|
# see Data::Domain, Data::Validator |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Add subtract (to remove items in one NDS from another) |
23
|
|
|
|
|
|
|
# see Data::Validate::XSD |
24
|
|
|
|
|
|
|
# treats all lists as ordered... it's simply too complicated |
25
|
|
|
|
|
|
|
# otherwise |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Add clean (to remove empty paths) |
28
|
|
|
|
|
|
|
# a hash key with a value of undef should be deleted |
29
|
|
|
|
|
|
|
# a list element with a value of undef should be deleted if unordered |
30
|
|
|
|
|
|
|
# a list consisting of only undefs should be deleted (and fix parent) |
31
|
|
|
|
|
|
|
# a hash with no keys should be deleted (and fix parent) |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
######################################################################## |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
require 5.000; |
36
|
93
|
|
|
93
|
|
37773
|
use strict; |
|
93
|
|
|
|
|
185
|
|
|
93
|
|
|
|
|
4636
|
|
37
|
93
|
|
|
93
|
|
119661
|
use Storable qw(dclone); |
|
93
|
|
|
|
|
508184
|
|
|
93
|
|
|
|
|
8446
|
|
38
|
93
|
|
|
93
|
|
114720
|
use Algorithm::Permute; |
|
93
|
|
|
|
|
390314
|
|
|
93
|
|
|
|
|
13876
|
|
39
|
93
|
|
|
93
|
|
112655
|
use IO::File; |
|
93
|
|
|
|
|
1344649
|
|
|
93
|
|
|
|
|
14112
|
|
40
|
93
|
|
|
93
|
|
880
|
use warnings; |
|
93
|
|
|
|
|
217
|
|
|
93
|
|
|
|
|
3773
|
|
41
|
|
|
|
|
|
|
|
42
|
93
|
|
|
93
|
|
640
|
use vars qw($VERSION); |
|
93
|
|
|
|
|
221
|
|
|
93
|
|
|
|
|
10229
|
|
43
|
|
|
|
|
|
|
$VERSION = "3.12"; |
44
|
|
|
|
|
|
|
|
45
|
93
|
|
|
93
|
|
558
|
use vars qw($_DBG $_DBG_INDENT $_DBG_OUTPUT $_DBG_FH $_DBG_POINT); |
|
93
|
|
|
|
|
195
|
|
|
93
|
|
|
|
|
1883889
|
|
46
|
|
|
|
|
|
|
$_DBG = 0; |
47
|
|
|
|
|
|
|
$_DBG_INDENT = 0; |
48
|
|
|
|
|
|
|
$_DBG_OUTPUT = "dbg.out"; |
49
|
|
|
|
|
|
|
$_DBG_FH = (); |
50
|
|
|
|
|
|
|
$_DBG_POINT = 0; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
############################################################################### |
53
|
|
|
|
|
|
|
# BASE METHODS |
54
|
|
|
|
|
|
|
############################################################################### |
55
|
|
|
|
|
|
|
# |
56
|
|
|
|
|
|
|
# The Data::Nested object is a hash of the form: |
57
|
|
|
|
|
|
|
# |
58
|
|
|
|
|
|
|
# { warn => FLAG whether to warn |
59
|
|
|
|
|
|
|
# delim => DELIMITER the path delimiter |
60
|
|
|
|
|
|
|
# nds => { NAME => NDS } named NDSes |
61
|
|
|
|
|
|
|
# structure => FLAG whether to do structure |
62
|
|
|
|
|
|
|
# blank => FLAG whether the empty |
63
|
|
|
|
|
|
|
# string is treated as |
64
|
|
|
|
|
|
|
# a keepable value when |
65
|
|
|
|
|
|
|
# merging |
66
|
|
|
|
|
|
|
# struct => { PATH => { ITEM => VAL } } structural information |
67
|
|
|
|
|
|
|
# defstruct => { ITEM => VAL } default structure |
68
|
|
|
|
|
|
|
# ruleset => { RULESET => { def => { ITEM => VAL }, |
69
|
|
|
|
|
|
|
# path => { PATH => VAL } } } |
70
|
|
|
|
|
|
|
# default and path |
71
|
|
|
|
|
|
|
# specific ruleset |
72
|
|
|
|
|
|
|
# merge methods |
73
|
|
|
|
|
|
|
# cache => {...} cached information |
74
|
|
|
|
|
|
|
# } |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub new { |
77
|
93
|
|
|
93
|
1
|
124792
|
my($class) = @_; |
78
|
|
|
|
|
|
|
|
79
|
93
|
|
|
|
|
1506
|
my $self = { |
80
|
|
|
|
|
|
|
"warn" => 0, |
81
|
|
|
|
|
|
|
"delim" => "/", |
82
|
|
|
|
|
|
|
"nds" => {}, |
83
|
|
|
|
|
|
|
"structure" => 1, |
84
|
|
|
|
|
|
|
"blank" => 0, |
85
|
|
|
|
|
|
|
"struct" => {}, |
86
|
|
|
|
|
|
|
"defstruct" => {}, |
87
|
|
|
|
|
|
|
"ruleset" => {}, |
88
|
|
|
|
|
|
|
"err" => "", |
89
|
|
|
|
|
|
|
"errmsg" => "", |
90
|
|
|
|
|
|
|
}; |
91
|
93
|
|
|
|
|
336
|
bless $self, $class; |
92
|
93
|
|
|
|
|
513
|
_structure_defaults($self); |
93
|
93
|
|
|
|
|
609
|
_merge_defaults($self); |
94
|
|
|
|
|
|
|
|
95
|
93
|
|
|
|
|
998
|
return $self; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub version { |
99
|
0
|
|
|
0
|
1
|
0
|
my($self) = @_; |
100
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
0
|
return $VERSION; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub no_structure { |
105
|
0
|
|
|
0
|
1
|
0
|
my($self) = @_; |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
0
|
$$self{"structure"} = 0; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub blank { |
111
|
3
|
|
|
3
|
1
|
22
|
my($self,$val) = @_; |
112
|
|
|
|
|
|
|
|
113
|
3
|
|
|
|
|
9
|
$$self{"blank"} = $val; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub err { |
117
|
36763
|
|
|
36763
|
1
|
44343
|
my($self) = @_; |
118
|
|
|
|
|
|
|
|
119
|
36763
|
|
|
|
|
134355
|
return $$self{"err"}; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub errmsg { |
123
|
0
|
|
|
0
|
1
|
0
|
my($self) = @_; |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
0
|
return $$self{"errmsg"}; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
############################################################################### |
129
|
|
|
|
|
|
|
# PATH METHODS |
130
|
|
|
|
|
|
|
############################################################################### |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub delim { |
133
|
37716
|
|
|
37716
|
1
|
46053
|
my($self,$delim) = @_; |
134
|
37716
|
100
|
|
|
|
74160
|
if (! defined $delim) { |
135
|
37715
|
|
|
|
|
88107
|
return $$self{"delim"}; |
136
|
|
|
|
|
|
|
} |
137
|
1
|
|
|
|
|
3
|
$$self{"delim"} = $delim; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
{ |
141
|
|
|
|
|
|
|
my %path = (); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub path { |
144
|
41333
|
|
|
41333
|
1
|
56470
|
my($self,$path) = @_; |
145
|
41333
|
|
|
|
|
51917
|
my $array = wantarray; |
146
|
|
|
|
|
|
|
|
147
|
41333
|
100
|
|
|
|
65891
|
if ($array) { |
148
|
6386
|
100
|
|
|
|
13120
|
return @$path if (ref($path)); |
149
|
6100
|
100
|
|
|
|
10669
|
return () if (! $path); |
150
|
6092
|
100
|
|
|
|
13459
|
return @{ $path{$path} } if (exists $path{$path}); |
|
5121
|
|
|
|
|
18543
|
|
151
|
|
|
|
|
|
|
|
152
|
971
|
|
|
|
|
2122
|
my($delim) = $self->delim(); |
153
|
971
|
|
|
|
|
6115
|
my @tmp = split(/\Q$delim\E/,$path); |
154
|
971
|
100
|
100
|
|
|
5439
|
shift(@tmp) if (! defined($tmp[0]) || $tmp[0] eq ""); |
155
|
971
|
|
|
|
|
3652
|
$path{$path} = [ @tmp ]; |
156
|
971
|
|
|
|
|
3665
|
return @tmp; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
} else { |
159
|
34947
|
|
|
|
|
62531
|
my($delim) = $self->delim(); |
160
|
34947
|
100
|
|
|
|
73481
|
if (! ref($path)) { |
161
|
20
|
50
|
|
|
|
52
|
return $delim if (! $path); |
162
|
20
|
|
|
|
|
46
|
return $path; |
163
|
|
|
|
|
|
|
} |
164
|
34927
|
|
|
|
|
105957
|
return $delim . join($delim,@$path); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
############################################################################### |
170
|
|
|
|
|
|
|
# RULESET METHODS |
171
|
|
|
|
|
|
|
############################################################################### |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub ruleset { |
174
|
6
|
|
|
6
|
1
|
638
|
my($self,$name) = @_; |
175
|
6
|
|
|
|
|
13
|
$$self{"err"} = ""; |
176
|
|
|
|
|
|
|
|
177
|
6
|
50
|
66
|
|
|
80
|
if ($name eq "keep" || |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
178
|
|
|
|
|
|
|
$name eq "replace" || |
179
|
|
|
|
|
|
|
$name eq "default" || |
180
|
|
|
|
|
|
|
$name eq "override") { |
181
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsrul03"; |
182
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Unable to create a ruleset using a reserved name " . |
183
|
|
|
|
|
|
|
"[$name]"; |
184
|
1
|
|
|
|
|
3
|
return; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
5
|
100
|
|
|
|
38
|
if ($name !~ /^[a-zA-Z0-9]+$/) { |
188
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsrul01"; |
189
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "A non-alphanumeric character used in a ruleset name" . |
190
|
|
|
|
|
|
|
"[$name]"; |
191
|
1
|
|
|
|
|
2
|
return; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
4
|
100
|
|
|
|
14
|
if (exists $$self{"ruleset"}{$name}) { |
195
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsrul02"; |
196
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to create ruleset for a name already in use" . |
197
|
|
|
|
|
|
|
" [$name]."; |
198
|
1
|
|
|
|
|
3
|
return; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
3
|
|
|
|
|
15
|
$$self{"ruleset"}{$name} = { "def" => {}, |
202
|
|
|
|
|
|
|
"path" => {} }; |
203
|
3
|
|
|
|
|
7
|
return; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub ruleset_valid { |
207
|
86
|
|
|
86
|
1
|
759
|
my($self,$name) = @_; |
208
|
86
|
100
|
|
|
|
544
|
return 1 if (exists $$self{"ruleset"}{$name}); |
209
|
5
|
|
|
|
|
26
|
return 0; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
############################################################################### |
213
|
|
|
|
|
|
|
# NDS METHODS |
214
|
|
|
|
|
|
|
############################################################################### |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# This takes $nds (which may be an NDS, or the name of a stored NDS) |
217
|
|
|
|
|
|
|
# and it returns the actual NDS referred to, or undef if there is a |
218
|
|
|
|
|
|
|
# problem. |
219
|
|
|
|
|
|
|
# |
220
|
|
|
|
|
|
|
# If $new is passed in, new structure is allowed. |
221
|
|
|
|
|
|
|
# If $copy is passed in, a copy of the NDS is returned. |
222
|
|
|
|
|
|
|
# If $nocheck is passed in, no structural check is done. |
223
|
|
|
|
|
|
|
# |
224
|
|
|
|
|
|
|
sub _nds { |
225
|
5386
|
|
|
5386
|
|
8077
|
my($self,$nds,$new,$copy,$nocheck) = @_; |
226
|
|
|
|
|
|
|
|
227
|
5386
|
100
|
|
|
|
14512
|
if (! defined($nds)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
228
|
140
|
|
|
|
|
267
|
return undef; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
} elsif (ref($nds)) { |
231
|
4174
|
100
|
66
|
|
|
18579
|
if ($$self{"structure"} && ! $nocheck) { |
232
|
728
|
|
|
|
|
1357
|
_check_structure($self,$nds,$new,()); |
233
|
728
|
50
|
|
|
|
1445
|
return undef if ($self->err()); |
234
|
|
|
|
|
|
|
} |
235
|
4174
|
50
|
|
|
|
7012
|
if ($copy) { |
236
|
0
|
|
|
|
|
0
|
return dclone($nds); |
237
|
|
|
|
|
|
|
} else { |
238
|
4174
|
|
|
|
|
8409
|
return $nds; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
} elsif (exists $$self{"nds"}{$nds}) { |
242
|
424
|
50
|
|
|
|
725
|
if ($copy) { |
243
|
0
|
|
|
|
|
0
|
return dclone($$self{"nds"}{$nds}); |
244
|
|
|
|
|
|
|
} else { |
245
|
424
|
|
|
|
|
1174
|
return $$self{"nds"}{$nds}; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} else { |
248
|
648
|
|
|
|
|
946
|
$$self{"err"} = "ndsnam01"; |
249
|
648
|
|
|
|
|
1481
|
$$self{"errmsg"} = "No NDS stored under the name [$nds]"; |
250
|
648
|
|
|
|
|
1263
|
return undef; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub nds { |
255
|
32
|
|
|
32
|
1
|
2493
|
my($self,$name,$nds,$new) = @_; |
256
|
32
|
|
|
|
|
74
|
$$self{"err"} = ""; |
257
|
32
|
|
|
|
|
57
|
$$self{"errmsg"} = ""; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# |
260
|
|
|
|
|
|
|
# $obj->nds($name); |
261
|
|
|
|
|
|
|
# $obj->nds($name,"_copy"); |
262
|
|
|
|
|
|
|
# |
263
|
|
|
|
|
|
|
|
264
|
32
|
100
|
100
|
|
|
247
|
if (! defined $nds || $nds eq "_copy") { |
265
|
4
|
50
|
|
|
|
10
|
if (exists $$self{"nds"}{$name}) { |
266
|
4
|
100
|
66
|
|
|
15
|
if (defined $nds && $nds eq "_copy") { |
267
|
1
|
|
|
|
|
28
|
return dclone($$self{"nds"}{$name}); |
268
|
|
|
|
|
|
|
} else { |
269
|
3
|
|
|
|
|
18
|
return $$self{"nds"}{$name}; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} else { |
272
|
0
|
|
|
|
|
0
|
return undef; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# |
277
|
|
|
|
|
|
|
# $obj->nds($name,"_delete"); |
278
|
|
|
|
|
|
|
# |
279
|
|
|
|
|
|
|
|
280
|
28
|
100
|
|
|
|
100
|
if ($nds eq "_delete") { |
281
|
2
|
100
|
|
|
|
12
|
delete $$self{"nds"}{$name}, return 1 |
282
|
|
|
|
|
|
|
if (exists $$self{"nds"}{$name}); |
283
|
1
|
|
|
|
|
3
|
return 0; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# |
287
|
|
|
|
|
|
|
# $obj->nds($name,"_exists"); |
288
|
|
|
|
|
|
|
# |
289
|
|
|
|
|
|
|
|
290
|
26
|
100
|
|
|
|
109
|
if ($nds eq "_exists") { |
291
|
2
|
100
|
|
|
|
8
|
return 1 if (exists $$self{"nds"}{$name}); |
292
|
1
|
|
|
|
|
3
|
return 0; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# |
296
|
|
|
|
|
|
|
# $obj->nds($name,$nds); |
297
|
|
|
|
|
|
|
# $obj->nds($name,$nds,$new); |
298
|
|
|
|
|
|
|
# |
299
|
|
|
|
|
|
|
|
300
|
24
|
100
|
|
|
|
96
|
if (exists $$self{"nds"}{$name}) { |
301
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsnam02"; |
302
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Attempt to copy NDS to a name already in use [$name]"; |
303
|
1
|
|
|
|
|
3
|
return undef; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
23
|
100
|
|
|
|
92
|
if (ref($nds)) { |
|
|
100
|
|
|
|
|
|
307
|
19
|
|
|
|
|
85
|
$self->check_structure($nds,$new); |
308
|
19
|
50
|
|
|
|
59
|
return undef if ($self->err()); |
309
|
19
|
|
|
|
|
70
|
$$self{"nds"}{$name} = $nds; |
310
|
19
|
|
|
|
|
90
|
return undef; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
} elsif (exists $$self{"nds"}{$nds}) { |
313
|
3
|
|
|
|
|
187
|
$$self{"nds"}{$name} = dclone($$self{"nds"}{$nds}); |
314
|
3
|
|
|
|
|
10
|
return undef; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
} else { |
317
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsnam01"; |
318
|
1
|
|
|
|
|
5
|
$$self{"errmsg"} = "No NDS stored under the name [$nds]"; |
319
|
1
|
|
|
|
|
4
|
return undef; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub empty { |
324
|
3314
|
|
|
3314
|
1
|
6013
|
my($self,$nds) = @_; |
325
|
3314
|
|
|
|
|
4973
|
$$self{"err"} = ""; |
326
|
3314
|
|
|
|
|
4350
|
$$self{"errmsg"} = ""; |
327
|
3314
|
100
|
|
|
|
6710
|
return 1 if (! defined $nds); |
328
|
|
|
|
|
|
|
|
329
|
3155
|
|
|
|
|
5843
|
$nds = _nds($self,$nds,0,0,1); |
330
|
3155
|
100
|
|
|
|
6559
|
return undef if ($self->err()); |
331
|
|
|
|
|
|
|
|
332
|
2508
|
|
|
|
|
4662
|
return _empty($self,$nds); |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub _empty { |
336
|
7526
|
|
|
7526
|
|
10004
|
my($self,$nds) = @_; |
337
|
|
|
|
|
|
|
|
338
|
7526
|
100
|
|
|
|
22137
|
if (! defined $nds) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
339
|
1110
|
|
|
|
|
3588
|
return 1; |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
342
|
1649
|
|
|
|
|
2496
|
foreach my $ele (@$nds) { |
343
|
1800
|
100
|
|
|
|
2891
|
return 0 if (! _empty($self,$ele)); |
344
|
|
|
|
|
|
|
} |
345
|
410
|
|
|
|
|
1696
|
return 1; |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
} elsif (ref($nds) eq "HASH") { |
348
|
1838
|
|
|
|
|
4372
|
foreach my $key (keys %$nds) { |
349
|
2684
|
100
|
|
|
|
5271
|
return 0 if (! _empty($self,$$nds{$key})); |
350
|
|
|
|
|
|
|
} |
351
|
440
|
|
|
|
|
1479
|
return 1; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
} elsif ($nds eq "") { |
354
|
399
|
100
|
|
|
|
1088
|
return 0 if ($$self{"blank"}); |
355
|
372
|
|
|
|
|
1250
|
return 1; |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
} else { |
358
|
2530
|
|
|
|
|
13362
|
return 0; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
############################################################################### |
363
|
|
|
|
|
|
|
# GET_STRUCTURE |
364
|
|
|
|
|
|
|
############################################################################### |
365
|
|
|
|
|
|
|
# Retrieve structural information for a path. Makes use of the default |
366
|
|
|
|
|
|
|
# structural information. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub get_structure { |
369
|
34566
|
|
|
34566
|
1
|
58667
|
my($self,$path,$info) = @_; |
370
|
34566
|
|
|
|
|
50119
|
$$self{"err"} = ""; |
371
|
34566
|
|
|
|
|
45322
|
$$self{"errmsg"} = ""; |
372
|
34566
|
100
|
66
|
|
|
104579
|
$info = "type" if (! defined $info || ! $info); |
373
|
|
|
|
|
|
|
|
374
|
34566
|
100
|
100
|
|
|
175081
|
if (exists $$self{"cache"}{"get_structure"}{$path} && |
375
|
|
|
|
|
|
|
exists $$self{"cache"}{"get_structure"}{$path}{$info}) { |
376
|
32205
|
|
|
|
|
90084
|
return $$self{"cache"}{"get_structure"}{$path}{$info}; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Split the path so that we can convert all elements into "*" when |
380
|
|
|
|
|
|
|
# appropriate. |
381
|
|
|
|
|
|
|
|
382
|
2361
|
|
|
|
|
5248
|
my @path = $self->path($path); |
383
|
2361
|
|
|
|
|
3917
|
my @p = (); |
384
|
2361
|
|
|
|
|
4034
|
my $p = "/"; |
385
|
2361
|
100
|
|
|
|
6236
|
if (! exists $$self{"struct"}{$p}) { |
386
|
74
|
|
|
|
|
192
|
$$self{"err"} = "ndschk03"; |
387
|
74
|
|
|
|
|
162
|
$$self{"errmsg"} = "No structural information available at all."; |
388
|
74
|
|
|
|
|
228
|
return ""; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
2287
|
|
|
|
|
4865
|
while (@path) { |
392
|
3209
|
|
|
|
|
4868
|
my $ele = shift(@path); |
393
|
3209
|
|
|
|
|
9354
|
my $p1 = $self->path([@p,"*"]); |
394
|
3209
|
|
|
|
|
11560
|
my $p2 = $self->path([@p,$ele]); |
395
|
3209
|
100
|
|
|
|
12479
|
if (exists $$self{"struct"}{$p1}) { |
|
|
100
|
|
|
|
|
|
396
|
280
|
|
|
|
|
431
|
push(@p,"*"); |
397
|
280
|
|
|
|
|
816
|
$p = $p1; |
398
|
|
|
|
|
|
|
} elsif (exists $$self{"struct"}{$p2}) { |
399
|
2309
|
|
|
|
|
3782
|
push(@p,$ele); |
400
|
2309
|
|
|
|
|
6570
|
$p = $p2; |
401
|
|
|
|
|
|
|
} else { |
402
|
620
|
100
|
|
|
|
1599
|
return 0 if ($info eq "valid"); |
403
|
617
|
|
|
|
|
962
|
$$self{"err"} = "ndschk04"; |
404
|
617
|
|
|
|
|
1149
|
$$self{"errmsg"} = "Invalid path: $p2"; |
405
|
617
|
|
|
|
|
1750
|
return ""; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# Return the information about the path. |
410
|
|
|
|
|
|
|
|
411
|
1667
|
100
|
|
|
|
3955
|
if ($info eq "valid") { |
412
|
95
|
|
|
|
|
361
|
$$self{"cache"}{"get_structure"}{$path}{$info} = 1; |
413
|
95
|
|
|
|
|
539
|
return 1; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
1572
|
100
|
|
|
|
4574
|
if (exists $$self{"struct"}{$p}{$info}) { |
417
|
1116
|
|
|
|
|
2258
|
my $val = $$self{"struct"}{$p}{$info}; |
418
|
1116
|
50
|
66
|
|
|
11527
|
$$self{"cache"}{"get_structure"}{$path}{$info} = $val |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
419
|
|
|
|
|
|
|
if ( ($info eq "type" && $val =~ /^(hash|list|scalar|other)$/) || |
420
|
|
|
|
|
|
|
$info eq "uniform" || |
421
|
|
|
|
|
|
|
$info eq "ordered"); |
422
|
1116
|
|
|
|
|
3172
|
return $val; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
456
|
100
|
|
|
|
1433
|
if (! exists $$self{"struct"}{$p}{"type"}) { |
426
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndschk05"; |
427
|
1
|
|
|
|
|
5
|
$$self{"errmsg"} = "It is not known what type of data is stored at " . |
428
|
|
|
|
|
|
|
"path: $p"; |
429
|
1
|
|
|
|
|
5
|
return "" |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
455
|
|
|
|
|
1009
|
my $type = $$self{"struct"}{$p}{"type"}; |
433
|
|
|
|
|
|
|
|
434
|
455
|
100
|
|
|
|
1471
|
if ($info eq "ordered") { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
435
|
137
|
100
|
|
|
|
481
|
if ($type ne "list") { |
436
|
45
|
|
|
|
|
100
|
$$self{"err"} = "ndschk06"; |
437
|
45
|
|
|
|
|
121
|
$$self{"errmsg"} = "Ordered information requested for a non-list " . |
438
|
|
|
|
|
|
|
"structure: $p"; |
439
|
45
|
|
|
|
|
142
|
return ""; |
440
|
|
|
|
|
|
|
} |
441
|
92
|
|
|
|
|
366
|
return $$self{"defstruct"}{"ordered"}; |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
} elsif ($info eq "uniform") { |
444
|
314
|
100
|
|
|
|
938
|
if ($type eq "hash") { |
|
|
100
|
|
|
|
|
|
445
|
203
|
|
|
|
|
788
|
return $$self{"defstruct"}{"uniform_hash"}; |
446
|
|
|
|
|
|
|
} elsif ($type eq "list") { |
447
|
110
|
|
|
|
|
614
|
my $ordered = $self->get_structure($p,"ordered"); |
448
|
110
|
100
|
|
|
|
1748
|
if ($ordered) { |
449
|
31
|
|
|
|
|
257
|
return $$self{"defstruct"}{"uniform_ol"}; |
450
|
|
|
|
|
|
|
} else { |
451
|
79
|
|
|
|
|
410
|
return 1; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
} else { |
455
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndschk07"; |
456
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Uniform information requested for a scalar " . |
457
|
|
|
|
|
|
|
"structure: $p"; |
458
|
1
|
|
|
|
|
5
|
return ""; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
} elsif ($info eq "merge") { |
462
|
0
|
0
|
|
|
|
0
|
if ($type eq "list") { |
|
|
0
|
|
|
|
|
|
463
|
0
|
|
|
|
|
0
|
my $ordered = $self->get_structure($p,"ordered"); |
464
|
0
|
0
|
|
|
|
0
|
if ($ordered) { |
465
|
0
|
|
|
|
|
0
|
return $$self{"defstruct"}{"merge_ol"}; |
466
|
|
|
|
|
|
|
} else { |
467
|
0
|
|
|
|
|
0
|
return $$self{"defstruct"}{"merge_ul"}; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
} elsif ($type eq "hash") { |
471
|
0
|
|
|
|
|
0
|
return $$self{"defstruct"}{"merge_hash"}; |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
} else { |
474
|
0
|
|
|
|
|
0
|
return $$self{"defstruct"}{"merge_scalar"}; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
} elsif ($info eq "keys") { |
478
|
3
|
100
|
|
|
|
8
|
if ($type ne "hash") { |
479
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndschk08"; |
480
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Keys requested for a non-hash structure: $p"; |
481
|
1
|
|
|
|
|
5
|
return ""; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
2
|
100
|
66
|
|
|
15
|
if (exists $$self{"struct"}{$p}{"uniform"} && |
485
|
|
|
|
|
|
|
$$self{"struct"}{$p}{"uniform"}) { |
486
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndschk09"; |
487
|
1
|
|
|
|
|
5
|
$$self{"errmsg"} = "Keys requested for a uniform hash structure: $p"; |
488
|
1
|
|
|
|
|
5
|
return ""; |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
1
|
|
|
|
|
2
|
my @keys = (); |
492
|
1
|
|
|
|
|
2
|
PP: foreach my $pp (CORE::keys %{ $$self{"struct"} }) { |
|
1
|
|
|
|
|
7
|
|
493
|
|
|
|
|
|
|
# Look for paths of the form: $p/KEY |
494
|
20
|
|
|
|
|
38
|
my @pp = $self->path($pp); |
495
|
20
|
100
|
|
|
|
61
|
next if ($#pp != $#p + 1); |
496
|
8
|
|
|
|
|
10
|
my $key = pop(@pp); |
497
|
8
|
|
|
|
|
16
|
my $tmp = $self->path(\@pp); |
498
|
8
|
100
|
|
|
|
24
|
next if ($tmp ne $p); |
499
|
2
|
|
|
|
|
5
|
push(@keys,$key); |
500
|
|
|
|
|
|
|
} |
501
|
1
|
|
|
|
|
14
|
return sort @keys; |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
} else { |
504
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndschk99"; |
505
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Unknown structural information requested: $info"; |
506
|
1
|
|
|
|
|
5
|
return ""; |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
############################################################################### |
511
|
|
|
|
|
|
|
# SET_STRUCTURE |
512
|
|
|
|
|
|
|
############################################################################### |
513
|
|
|
|
|
|
|
# This sets a piece of structural information (and does all error checking |
514
|
|
|
|
|
|
|
# on it). |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub set_structure { |
517
|
227
|
|
|
227
|
1
|
7653
|
my($self,$item,$val,$path) = @_; |
518
|
227
|
|
|
|
|
352
|
$$self{"err"} = ""; |
519
|
227
|
|
|
|
|
410
|
$$self{"errmsg"} = ""; |
520
|
|
|
|
|
|
|
|
521
|
227
|
100
|
|
|
|
412
|
if ($path) { |
522
|
223
|
|
|
|
|
400
|
_set_structure_path($self,$item,$val,$path); |
523
|
|
|
|
|
|
|
} else { |
524
|
4
|
|
|
|
|
7
|
_set_structure_default($self,$item,$val); |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# Set a structural item for a path. |
529
|
|
|
|
|
|
|
# |
530
|
|
|
|
|
|
|
sub _set_structure_path { |
531
|
906
|
|
|
906
|
|
2064
|
my($self,$item,$val,$path) = @_; |
532
|
|
|
|
|
|
|
|
533
|
906
|
|
|
|
|
1982
|
my @path = $self->path($path); |
534
|
906
|
|
|
|
|
2216
|
$path = $self->path(\@path); |
535
|
906
|
|
|
|
|
2659
|
_structure_valid($self,$item,$val,$path,@path); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# Rules for a valid structure: |
539
|
|
|
|
|
|
|
# |
540
|
|
|
|
|
|
|
# If parent is not valid |
541
|
|
|
|
|
|
|
# INVALID |
542
|
|
|
|
|
|
|
# End |
543
|
|
|
|
|
|
|
# |
544
|
|
|
|
|
|
|
# If we're not setting an item |
545
|
|
|
|
|
|
|
# VALID |
546
|
|
|
|
|
|
|
# End |
547
|
|
|
|
|
|
|
# |
548
|
|
|
|
|
|
|
# If type is not set |
549
|
|
|
|
|
|
|
# set it to unknown |
550
|
|
|
|
|
|
|
# End |
551
|
|
|
|
|
|
|
# |
552
|
|
|
|
|
|
|
# INVALID if incompatible with any other options already set |
553
|
|
|
|
|
|
|
# INVALID if path incompatible with type |
554
|
|
|
|
|
|
|
# INVALID if path incompatible with parent |
555
|
|
|
|
|
|
|
# INVALID if any direct childres incompatible |
556
|
|
|
|
|
|
|
# |
557
|
|
|
|
|
|
|
# Set item |
558
|
|
|
|
|
|
|
# |
559
|
|
|
|
|
|
|
sub _structure_valid { |
560
|
2856
|
|
|
2856
|
|
6454
|
my($self,$item,$val,$path,@path) = @_; |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# |
563
|
|
|
|
|
|
|
# Check for an invalid parent |
564
|
|
|
|
|
|
|
# |
565
|
|
|
|
|
|
|
|
566
|
2856
|
|
|
|
|
2869
|
my (@parent,$parent); |
567
|
2856
|
100
|
|
|
|
5808
|
if (@path) { |
568
|
1618
|
|
|
|
|
3120
|
@parent = @path; |
569
|
1618
|
|
|
|
|
1929
|
pop(@parent); |
570
|
1618
|
|
|
|
|
26352
|
$parent = $self->path([@parent]); |
571
|
1618
|
|
|
|
|
5484
|
_structure_valid($self,"","",$parent,@parent); |
572
|
1618
|
50
|
|
|
|
3161
|
return if ($self->err()); |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
# |
576
|
|
|
|
|
|
|
# If we're not setting a value, then the most we've done is |
577
|
|
|
|
|
|
|
# set defaults (which we know we've done correct), so it's valid |
578
|
|
|
|
|
|
|
# to the extent that we're able to check. |
579
|
|
|
|
|
|
|
# |
580
|
|
|
|
|
|
|
|
581
|
2856
|
100
|
|
|
|
6745
|
return unless ($item); |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# |
584
|
|
|
|
|
|
|
# Make sure type is set. If it's not, set it to "unknown". |
585
|
|
|
|
|
|
|
# |
586
|
|
|
|
|
|
|
|
587
|
1238
|
100
|
|
|
|
5357
|
$$self{"struct"}{$path}{"type"} = "unknown" |
588
|
|
|
|
|
|
|
if (! exists $$self{"struct"}{$path}{"type"}); |
589
|
1238
|
|
|
|
|
2355
|
my $type = $$self{"struct"}{$path}{"type"}; |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# |
592
|
|
|
|
|
|
|
# Check to make sure that $item and $val are valid and that |
593
|
|
|
|
|
|
|
# they don't conflict with other structural settings for |
594
|
|
|
|
|
|
|
# this path. |
595
|
|
|
|
|
|
|
# |
596
|
|
|
|
|
|
|
|
597
|
1238
|
|
|
|
|
1412
|
my $set_ordered = 0; |
598
|
1238
|
|
|
|
|
1346
|
my $set_uniform = 0; |
599
|
1238
|
|
|
|
|
1361
|
my $valid = 0; |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# Type checks |
602
|
1238
|
100
|
|
|
|
2666
|
if ($item eq "type") { |
603
|
822
|
|
|
|
|
1146
|
$valid = 1; |
604
|
822
|
100
|
100
|
|
|
3921
|
if ($val ne "scalar" && |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
605
|
|
|
|
|
|
|
$val ne "list" && |
606
|
|
|
|
|
|
|
$val ne "hash" && |
607
|
|
|
|
|
|
|
$val ne "other") { |
608
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr01"; |
609
|
1
|
|
|
|
|
2
|
$$self{"errmsg"} = "Attempt to set type to an invalid value: $val"; |
610
|
1
|
|
|
|
|
4
|
return; |
611
|
|
|
|
|
|
|
} |
612
|
821
|
100
|
100
|
|
|
2057
|
if ($type ne "unknown" && |
613
|
|
|
|
|
|
|
$type ne "list/hash") { |
614
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr02"; |
615
|
1
|
|
|
|
|
2
|
$$self{"errmsg"} = "Once type is set, it may not be reset: $path"; |
616
|
1
|
|
|
|
|
3
|
return; |
617
|
|
|
|
|
|
|
} |
618
|
820
|
100
|
100
|
|
|
2436
|
if ($type eq "list/hash" && |
|
|
|
66
|
|
|
|
|
619
|
|
|
|
|
|
|
$val ne "list" && |
620
|
|
|
|
|
|
|
$val ne "hash") { |
621
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr03"; |
622
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Attempt to set type to scalar when a list/hash " . |
623
|
|
|
|
|
|
|
"type is required: $path"; |
624
|
1
|
|
|
|
|
5
|
return; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# Ordered checks |
629
|
1235
|
100
|
|
|
|
2731
|
if ($item eq "ordered") { |
630
|
77
|
|
|
|
|
94
|
$valid = 1; |
631
|
77
|
100
|
|
|
|
253
|
if (exists $$self{"struct"}{$path}{"ordered"}) { |
632
|
2
|
|
|
|
|
3
|
$$self{"err"} = "ndsstr04"; |
633
|
2
|
|
|
|
|
5
|
$$self{"errmsg"} = "Attempt to reset ordered: $path"; |
634
|
2
|
|
|
|
|
8
|
return; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# only allowed for lists |
638
|
75
|
50
|
33
|
|
|
438
|
if ($type eq "unknown" || |
639
|
|
|
|
|
|
|
$type eq "list/hash") { |
640
|
0
|
|
|
|
|
0
|
_structure_valid($self,"type","list",$path,@path); |
641
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
642
|
0
|
|
|
|
|
0
|
$type = "list"; |
643
|
|
|
|
|
|
|
} |
644
|
75
|
100
|
|
|
|
173
|
if ($type ne "list") { |
645
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsstr05"; |
646
|
1
|
|
|
|
|
2
|
$$self{"errmsg"} = "Attempt to set ordered on a non-list structure: " . |
647
|
|
|
|
|
|
|
"$path"; |
648
|
1
|
|
|
|
|
4
|
return; |
649
|
|
|
|
|
|
|
} |
650
|
74
|
100
|
100
|
|
|
415
|
if ($val ne "0" && |
651
|
|
|
|
|
|
|
$val ne "1") { |
652
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr06"; |
653
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Ordered value must be 0 or 1: $path"; |
654
|
1
|
|
|
|
|
5
|
return; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
# check conflicts with "uniform" |
658
|
73
|
100
|
|
|
|
223
|
if (! exists $$self{"struct"}{$path}{"uniform"}) { |
|
|
50
|
|
|
|
|
|
659
|
71
|
100
|
|
|
|
461
|
if ($val) { |
660
|
|
|
|
|
|
|
# We're making an unknown list ordered. This can |
661
|
|
|
|
|
|
|
# apply to uniform or non-uniform lists, so nothing |
662
|
|
|
|
|
|
|
# is required. |
663
|
|
|
|
|
|
|
} else { |
664
|
|
|
|
|
|
|
# We're making an unknown list unordered. The |
665
|
|
|
|
|
|
|
# list must be uniform. |
666
|
36
|
|
|
|
|
61
|
$set_uniform = 1; |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
} elsif ($$self{"struct"}{$path}{"uniform"}) { |
669
|
|
|
|
|
|
|
# We're making an uniform list ordered or non-ordered. |
670
|
|
|
|
|
|
|
# Both are allowed. |
671
|
|
|
|
|
|
|
} else { |
672
|
2
|
50
|
|
|
|
6
|
if ($val) { |
673
|
|
|
|
|
|
|
# We're making an non-uniform list ordered. This is |
674
|
|
|
|
|
|
|
# allowed. |
675
|
|
|
|
|
|
|
} else { |
676
|
|
|
|
|
|
|
# We're trying to make an non-uniform list unordered. |
677
|
|
|
|
|
|
|
# This is NOT allowed. |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
# NOTE: This will never occur. Any time we set a list to |
680
|
|
|
|
|
|
|
# non-uniform, it will automatically set the ordered flag |
681
|
|
|
|
|
|
|
# appropriately, so trying to set it here will result in an |
682
|
|
|
|
|
|
|
# ndsstr04 error. |
683
|
0
|
|
|
|
|
0
|
return; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
# Uniform checks |
689
|
1231
|
100
|
|
|
|
2546
|
if ($item eq "uniform") { |
690
|
338
|
|
|
|
|
447
|
$valid = 1; |
691
|
338
|
100
|
|
|
|
1196
|
if (exists $$self{"struct"}{$path}{"uniform"}) { |
692
|
2
|
|
|
|
|
4
|
$$self{"err"} = "ndsstr07"; |
693
|
2
|
|
|
|
|
5
|
$$self{"errmsg"} = "Attempt to reset uniform: $path"; |
694
|
2
|
|
|
|
|
7
|
return; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
# only applies to lists and hashes |
698
|
336
|
50
|
|
|
|
950
|
if ($type eq "unknown") { |
699
|
0
|
|
|
|
|
0
|
_structure_valid($self,"type","list/hash",$path,@path); |
700
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
701
|
|
|
|
|
|
|
} |
702
|
336
|
100
|
100
|
|
|
1714
|
if ($type ne "list" && |
|
|
|
66
|
|
|
|
|
703
|
|
|
|
|
|
|
$type ne "hash" && |
704
|
|
|
|
|
|
|
$type ne "list/hash") { |
705
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsstr08"; |
706
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to set uniform on a scalar structure: " . |
707
|
|
|
|
|
|
|
"$path"; |
708
|
1
|
|
|
|
|
4
|
return; |
709
|
|
|
|
|
|
|
} |
710
|
335
|
100
|
100
|
|
|
1535
|
if ($val ne "0" && |
711
|
|
|
|
|
|
|
$val ne "1") { |
712
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsstr09"; |
713
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Uniform value must be 0 or 1: $path"; |
714
|
1
|
|
|
|
|
3
|
return; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
# check conflicts with "ordered" |
718
|
334
|
100
|
66
|
|
|
2302
|
if (exists $$self{"struct"}{$path}{"type"} && |
719
|
|
|
|
|
|
|
$$self{"struct"}{$path}{"type"} eq "list") { |
720
|
128
|
100
|
|
|
|
537
|
if (! exists $$self{"struct"}{$path}{"ordered"}) { |
|
|
100
|
|
|
|
|
|
721
|
59
|
100
|
|
|
|
206
|
if ($val) { |
722
|
|
|
|
|
|
|
# We're making an unknown list uniform. This can |
723
|
|
|
|
|
|
|
# apply to ordered or unorderd lists, so nothing |
724
|
|
|
|
|
|
|
# is required. |
725
|
|
|
|
|
|
|
} else { |
726
|
|
|
|
|
|
|
# We're making an unknown list non-uniform. The |
727
|
|
|
|
|
|
|
# list must be ordered. |
728
|
2
|
|
|
|
|
3
|
$set_ordered = 1; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
} elsif ($$self{"struct"}{$path}{"ordered"}) { |
731
|
|
|
|
|
|
|
# We're making an ordered list uniform or non-uniform. |
732
|
|
|
|
|
|
|
# Both are allowed. |
733
|
|
|
|
|
|
|
} else { |
734
|
36
|
50
|
|
|
|
106
|
if ($val) { |
735
|
|
|
|
|
|
|
# We're making an unordered list uniform. This is |
736
|
|
|
|
|
|
|
# allowed. |
737
|
|
|
|
|
|
|
} else { |
738
|
|
|
|
|
|
|
# We're trying to make an unordered list non-uniform. |
739
|
|
|
|
|
|
|
# This is NOT allowed. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
# NOTE: This error will never occur. Any time we set a |
742
|
|
|
|
|
|
|
# list to unordered, it will automatically set the |
743
|
|
|
|
|
|
|
# uniform flag appropriately, so trying to set it here |
744
|
|
|
|
|
|
|
# will result in a ndsstr07 error. |
745
|
0
|
|
|
|
|
0
|
return; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# $item is invalid |
752
|
1227
|
100
|
|
|
|
3215
|
if (! $valid) { |
753
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr98"; |
754
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Invalid default structural item: $item"; |
755
|
1
|
|
|
|
|
3
|
return; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
# |
759
|
|
|
|
|
|
|
# Check to make sure that the current path is valid with |
760
|
|
|
|
|
|
|
# respect to the type of structure we're currently in (this |
761
|
|
|
|
|
|
|
# is defined in the parent element). |
762
|
|
|
|
|
|
|
# |
763
|
|
|
|
|
|
|
|
764
|
1226
|
100
|
|
|
|
2595
|
if (@path) { |
765
|
1056
|
|
|
|
|
1735
|
my $curr_ele = $path[$#path]; |
766
|
1056
|
100
|
|
|
|
2893
|
if (exists $$self{"struct"}{$parent}{"type"}) { |
767
|
1046
|
|
|
|
|
1977
|
my $parent_type = $$self{"struct"}{$parent}{"type"}; |
768
|
|
|
|
|
|
|
|
769
|
1046
|
50
|
|
|
|
2414
|
if ($parent_type eq "unknown") { |
770
|
0
|
|
|
|
|
0
|
_structure_valid($self,"type","list/hash",$parent,@parent); |
771
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
1046
|
100
|
66
|
|
|
15069
|
if ($parent_type eq "scalar" || |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
775
|
|
|
|
|
|
|
$parent_type eq "other") { |
776
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr10"; |
777
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Trying to set structural information for a " . |
778
|
|
|
|
|
|
|
"child with a scalar parent: $path"; |
779
|
1
|
|
|
|
|
23
|
return; |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
} elsif ($parent_type eq "list" && |
782
|
|
|
|
|
|
|
$curr_ele =~ /^\d+$/) { |
783
|
4
|
50
|
|
|
|
18
|
if (exists $$self{"struct"}{$parent}{"uniform"}) { |
784
|
4
|
100
|
|
|
|
14
|
if ($$self{"struct"}{$parent}{"uniform"}) { |
785
|
|
|
|
|
|
|
# Parent = list,uniform Curr = 2 |
786
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr11"; |
787
|
1
|
|
|
|
|
5
|
$$self{"errmsg"} = "Attempt to set structural information " . |
788
|
|
|
|
|
|
|
"for a specific element in a uniform list: $path"; |
789
|
1
|
|
|
|
|
5
|
return; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
} else { |
792
|
|
|
|
|
|
|
# Parent = list, unknown Curr = 2 |
793
|
|
|
|
|
|
|
# => force parent to be non-uniform |
794
|
0
|
|
|
|
|
0
|
_structure_valid($self,"uniform","0",$parent,@parent); |
795
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
} elsif ($parent_type eq "list" && |
799
|
|
|
|
|
|
|
$curr_ele eq "*") { |
800
|
131
|
100
|
|
|
|
475
|
if (exists $$self{"struct"}{$parent}{"uniform"}) { |
801
|
45
|
100
|
|
|
|
171
|
if (! $$self{"struct"}{$parent}{"uniform"}) { |
802
|
|
|
|
|
|
|
# Parent = list,nonuniform Curr = * |
803
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr12"; |
804
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Attempt to set structural information " . |
805
|
|
|
|
|
|
|
"for all elements in a non-uniform list: $path"; |
806
|
1
|
|
|
|
|
5
|
return; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
} else { |
809
|
|
|
|
|
|
|
# Parent = list,unknown Curr = * |
810
|
|
|
|
|
|
|
# => force parent to be uniform |
811
|
86
|
|
|
|
|
251
|
_structure_valid($self,"uniform","1",$parent,@parent); |
812
|
86
|
50
|
|
|
|
296
|
return if ($self->err()); |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
} elsif ($parent_type eq "list") { |
816
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr13"; |
817
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Attempt to access a list with a non-integer " . |
818
|
|
|
|
|
|
|
"index.: $path"; |
819
|
1
|
|
|
|
|
4
|
return; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
} elsif (($parent_type eq "hash" || $parent_type eq "list/hash") && |
822
|
|
|
|
|
|
|
$curr_ele eq "*") { |
823
|
5
|
50
|
|
|
|
17
|
if (exists $$self{"struct"}{$parent}{"uniform"}) { |
824
|
5
|
100
|
|
|
|
19
|
if (! $$self{"struct"}{$parent}{"uniform"}) { |
825
|
|
|
|
|
|
|
# Parent = list/hash,non-uniform Curr = * |
826
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr15"; |
827
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to set structural information " . |
828
|
|
|
|
|
|
|
"for all elements in a non-uniform structure: $path"; |
829
|
1
|
|
|
|
|
6
|
return; |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
} else { |
832
|
|
|
|
|
|
|
# Parent = hash,unknown Curr = * |
833
|
|
|
|
|
|
|
# => force parent to be uniform |
834
|
0
|
|
|
|
|
0
|
_structure_valid($self,"uniform","1",$parent,@parent); |
835
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
} elsif ($parent_type eq "hash" || $parent_type eq "list/hash") { |
839
|
904
|
100
|
|
|
|
2678
|
if (exists $$self{"struct"}{$parent}{"uniform"}) { |
840
|
706
|
100
|
|
|
|
2514
|
if ($$self{"struct"}{$parent}{"uniform"}) { |
841
|
|
|
|
|
|
|
# Parent = list/hash,uniform Curr = foo |
842
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr14"; |
843
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to set structural information " . |
844
|
|
|
|
|
|
|
"for a specific element in a uniform structure: $path"; |
845
|
1
|
|
|
|
|
4
|
return; |
846
|
|
|
|
|
|
|
} |
847
|
|
|
|
|
|
|
} else { |
848
|
|
|
|
|
|
|
# Parent = hash,unknown Curr = foo |
849
|
|
|
|
|
|
|
# => force parent to be non-uniform |
850
|
198
|
|
|
|
|
592
|
_structure_valid($self,"uniform","0",$parent,@parent); |
851
|
198
|
50
|
|
|
|
661
|
return if ($self->err()); |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
} |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
} else { |
856
|
|
|
|
|
|
|
# Parent is not type'd yet. |
857
|
|
|
|
|
|
|
|
858
|
10
|
50
|
33
|
|
|
115
|
if ($curr_ele eq "*" || |
859
|
|
|
|
|
|
|
$curr_ele =~ /^\d+$/) { |
860
|
0
|
|
|
|
|
0
|
_structure_valid($self,"type","list/hash",$parent,@parent); |
861
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
862
|
|
|
|
|
|
|
} else { |
863
|
10
|
|
|
|
|
32
|
_structure_valid($self,"type","hash",$parent,@parent); |
864
|
10
|
100
|
|
|
|
25
|
return if ($self->err()); |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
} |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
# |
870
|
|
|
|
|
|
|
# Set the item |
871
|
|
|
|
|
|
|
# |
872
|
|
|
|
|
|
|
|
873
|
1219
|
|
|
|
|
3894
|
$$self{"struct"}{$path}{$item} = $val; |
874
|
1219
|
100
|
|
|
|
2664
|
if ($set_ordered) { |
875
|
2
|
|
|
|
|
5
|
_structure_valid($self,"ordered","1",$path,@path); |
876
|
2
|
50
|
|
|
|
3
|
return if ($self->err()); |
877
|
|
|
|
|
|
|
} |
878
|
1219
|
100
|
|
|
|
4715
|
if ($set_uniform) { |
879
|
36
|
|
|
|
|
85
|
_structure_valid($self,"uniform","1",$path,@path); |
880
|
36
|
50
|
|
|
|
82
|
return if ($self->err()); |
881
|
|
|
|
|
|
|
} |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
{ |
885
|
|
|
|
|
|
|
# Values for the default structural information. First value in the |
886
|
|
|
|
|
|
|
# list is the error code for this item. Second value is the default |
887
|
|
|
|
|
|
|
# for this item. |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
my %def = ( "ordered" => [ "ndsstr16", |
890
|
|
|
|
|
|
|
"Attempt to set the default ordered " . |
891
|
|
|
|
|
|
|
"value to something other than 0/1", |
892
|
|
|
|
|
|
|
qw(0 1) ], |
893
|
|
|
|
|
|
|
"uniform_hash" => [ "ndsstr17", |
894
|
|
|
|
|
|
|
"Attempt to set the default uniform_hash" . |
895
|
|
|
|
|
|
|
" value to something other than 0/1", |
896
|
|
|
|
|
|
|
qw(0 1) ], |
897
|
|
|
|
|
|
|
"uniform_ol" => [ "ndsstr18", |
898
|
|
|
|
|
|
|
"Attempt to set the default uniform_ol " . |
899
|
|
|
|
|
|
|
"value to something other than 0/1", |
900
|
|
|
|
|
|
|
qw(1 0) ], |
901
|
|
|
|
|
|
|
); |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
sub _set_structure_default { |
904
|
4
|
|
|
4
|
|
7
|
my($self,$item,$val) = @_; |
905
|
|
|
|
|
|
|
|
906
|
4
|
100
|
|
|
|
9
|
if (! exists $def{$item}) { |
907
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsstr99"; |
908
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Invalid structural item for a path: $item"; |
909
|
1
|
|
|
|
|
2
|
return; |
910
|
|
|
|
|
|
|
} |
911
|
3
|
|
|
|
|
4
|
my @tmp = @{ $def{$item} }; |
|
3
|
|
|
|
|
13
|
|
912
|
3
|
|
|
|
|
5
|
my $err = shift(@tmp); |
913
|
3
|
|
|
|
|
3
|
my $msg = shift(@tmp); |
914
|
3
|
|
|
|
|
5
|
my %tmp = map { $_,1 } @tmp; |
|
6
|
|
|
|
|
17
|
|
915
|
3
|
50
|
|
|
|
10
|
if (! exists $tmp{$val}) { |
916
|
3
|
|
|
|
|
6
|
$$self{"err"} = $err; |
917
|
3
|
|
|
|
|
7
|
$$self{"errmsg"} = "$msg: $item = $val"; |
918
|
3
|
|
|
|
|
12
|
return; |
919
|
|
|
|
|
|
|
} |
920
|
0
|
|
|
|
|
0
|
$$self{"defstruct"}{$item} = $val; |
921
|
0
|
|
|
|
|
0
|
return; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# Set up the default structure: |
925
|
|
|
|
|
|
|
sub _structure_defaults { |
926
|
93
|
|
|
93
|
|
246
|
my($self) = @_; |
927
|
93
|
|
|
|
|
326
|
my($d) = "defstruct"; |
928
|
|
|
|
|
|
|
|
929
|
93
|
50
|
|
|
|
1080
|
$$self{$d} = {} if (! exists $$self{$d}); |
930
|
93
|
|
|
|
|
584
|
foreach my $key (CORE::keys %def) { |
931
|
279
|
|
|
|
|
1332
|
$$self{$d}{$key} = $def{$key}[2]; |
932
|
|
|
|
|
|
|
} |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
############################################################################### |
937
|
|
|
|
|
|
|
# CHECK_STRUCTURE/CHECK_VALUE |
938
|
|
|
|
|
|
|
############################################################################### |
939
|
|
|
|
|
|
|
# This checks the structure of an NDS (and may update the structural |
940
|
|
|
|
|
|
|
# information if appropriate). |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
sub check_structure { |
943
|
596
|
|
|
596
|
1
|
1113
|
my($self,$nds,$new) = @_; |
944
|
596
|
|
|
|
|
1000
|
$$self{"err"} = ""; |
945
|
596
|
|
|
|
|
900
|
$$self{"errmsg"} = ""; |
946
|
|
|
|
|
|
|
|
947
|
596
|
100
|
|
|
|
1408
|
return if (! ref($nds)); |
948
|
588
|
50
|
|
|
|
1355
|
return if (! $$self{"structure"}); |
949
|
|
|
|
|
|
|
|
950
|
588
|
100
|
|
|
|
1189
|
$new = 0 if (! $new); |
951
|
|
|
|
|
|
|
|
952
|
588
|
|
|
|
|
1247
|
_check_structure($self,$nds,$new,()); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
sub check_value { |
956
|
5
|
|
|
5
|
1
|
576
|
my($self,$path,$val,$new) = @_; |
957
|
5
|
|
|
|
|
8
|
$$self{"err"} = ""; |
958
|
5
|
|
|
|
|
6
|
$$self{"errmsg"} = ""; |
959
|
5
|
|
|
|
|
10
|
my(@path) = $self->path($path); |
960
|
5
|
|
|
|
|
10
|
_check_structure($self,$val,$new,@path); |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
sub _check_structure { |
964
|
26314
|
|
|
26314
|
|
53122
|
my($self,$nds,$new,@path) = @_; |
965
|
26314
|
100
|
|
|
|
52617
|
return if (! defined $nds); |
966
|
|
|
|
|
|
|
|
967
|
24780
|
|
|
|
|
68271
|
my $path = $self->path([@path]); |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
# Check to make sure that it's the correct type of data. |
970
|
|
|
|
|
|
|
|
971
|
24780
|
|
|
|
|
62137
|
my $type = $self->get_structure($path,"type"); |
972
|
|
|
|
|
|
|
|
973
|
24780
|
100
|
|
|
|
49964
|
if ($type) { |
974
|
24096
|
|
|
|
|
33076
|
my $ref = lc(ref($nds)); |
975
|
24096
|
100
|
|
|
|
44546
|
$ref = "scalar" if (! $ref); |
976
|
24096
|
100
|
|
|
|
45726
|
$ref = "list" if ($ref eq "array"); |
977
|
|
|
|
|
|
|
|
978
|
24096
|
100
|
100
|
|
|
112094
|
if ($type eq "hash" || $type eq "list" || $type eq "scalar") { |
|
|
50
|
100
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
979
|
24084
|
100
|
|
|
|
52548
|
if ($ref ne $type) { |
980
|
8
|
|
|
|
|
15
|
$$self{"err"} = "ndschk01"; |
981
|
8
|
|
|
|
|
29
|
$$self{"errmsg"} = "Invalid type: $path (expected $type, got $ref)"; |
982
|
8
|
|
|
|
|
23
|
return; |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
} elsif ($type eq "list/hash") { |
986
|
0
|
0
|
0
|
|
|
0
|
if ($ref ne "list" && $ref ne "hash") { |
987
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndschk01"; |
988
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Invalid type: $path (expected $type, got $ref)"; |
989
|
0
|
|
|
|
|
0
|
return; |
990
|
|
|
|
|
|
|
} |
991
|
0
|
|
|
|
|
0
|
$type = ""; |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
} elsif ($type eq "other") { |
994
|
12
|
50
|
33
|
|
|
80
|
if ($ref eq "scalar" || |
|
|
|
33
|
|
|
|
|
995
|
|
|
|
|
|
|
$ref eq "hash" || |
996
|
|
|
|
|
|
|
$ref eq "list") { |
997
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndschk01"; |
998
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Invalid type: $path (expected $type, got $ref)"; |
999
|
0
|
|
|
|
|
0
|
return; |
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
} elsif ($type eq "unknown") { |
1003
|
0
|
|
|
|
|
0
|
$type = ""; |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
} else { |
1006
|
0
|
|
|
|
|
0
|
die "[check_structure] Impossible error: $type"; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
|
1010
|
24772
|
100
|
|
|
|
42207
|
if (! $type) { |
1011
|
|
|
|
|
|
|
# If the structure is not previously defined, it will set an |
1012
|
|
|
|
|
|
|
# error code. Erase that one (it's not interesting) and then |
1013
|
|
|
|
|
|
|
# set the structure based on the new value (if allowed). |
1014
|
684
|
|
|
|
|
1160
|
$$self{"err"} = ""; |
1015
|
684
|
|
|
|
|
948
|
$$self{"errmsg"} = ""; |
1016
|
684
|
100
|
|
|
|
1188
|
if ($new) { |
1017
|
683
|
|
|
|
|
1271
|
$type = lc(ref($nds)); |
1018
|
683
|
100
|
|
|
|
1431
|
$type = "list" if ($type eq "array"); |
1019
|
683
|
100
|
100
|
|
|
2467
|
if (! $type) { |
|
|
100
|
|
|
|
|
|
1020
|
451
|
|
|
|
|
968
|
_set_structure_path($self,"type","scalar",$path); |
1021
|
|
|
|
|
|
|
} elsif ($type eq "hash" || |
1022
|
|
|
|
|
|
|
$type eq "list") { |
1023
|
231
|
|
|
|
|
888
|
_set_structure_path($self,"type",$type,$path); |
1024
|
|
|
|
|
|
|
} else { |
1025
|
1
|
|
|
|
|
4
|
_set_structure_path($self,"type","other",$path); |
1026
|
|
|
|
|
|
|
} |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
} else { |
1029
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndschk02"; |
1030
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "New structure not allowed"; |
1031
|
1
|
|
|
|
|
2
|
return; |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
24771
|
100
|
100
|
|
|
105598
|
return unless ($type eq "list" || $type eq "hash"); |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
# Recurse into hashes. |
1038
|
|
|
|
|
|
|
|
1039
|
8327
|
|
|
|
|
16813
|
my $uniform = $self->get_structure($path,"uniform"); |
1040
|
8327
|
100
|
|
|
|
20962
|
if ($type eq "hash") { |
1041
|
4730
|
|
|
|
|
11251
|
foreach my $key (CORE::keys %$nds) { |
1042
|
13653
|
|
|
|
|
22907
|
my $val = $$nds{$key}; |
1043
|
13653
|
50
|
|
|
|
20267
|
if ($uniform) { |
1044
|
0
|
|
|
|
|
0
|
_check_structure($self,$val,$new,@path,"*"); |
1045
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
1046
|
|
|
|
|
|
|
} else { |
1047
|
13653
|
|
|
|
|
26366
|
_check_structure($self,$val,$new,@path,$key); |
1048
|
13653
|
100
|
|
|
|
24984
|
return if ($self->err()); |
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
} |
1051
|
4722
|
|
|
|
|
11591
|
return; |
1052
|
|
|
|
|
|
|
} |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
# Recurse into lists |
1055
|
|
|
|
|
|
|
|
1056
|
3597
|
|
|
|
|
8677
|
for (my $i=0; $i<=$#$nds; $i++) { |
1057
|
11321
|
|
|
|
|
15423
|
my $val = $$nds[$i]; |
1058
|
11321
|
50
|
|
|
|
16980
|
if ($uniform) { |
1059
|
11321
|
|
|
|
|
30185
|
_check_structure($self,$val,$new,@path,"*"); |
1060
|
11321
|
100
|
|
|
|
21270
|
return if ($self->err()); |
1061
|
|
|
|
|
|
|
} else { |
1062
|
0
|
|
|
|
|
0
|
_check_structure($self,$val,$new,@path,$i); |
1063
|
0
|
0
|
|
|
|
0
|
return if ($self->err()); |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
3596
|
|
|
|
|
10036
|
return; |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
############################################################################### |
1071
|
|
|
|
|
|
|
# VALID/VALUE |
1072
|
|
|
|
|
|
|
############################################################################### |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
sub value { |
1075
|
1738
|
|
|
1738
|
1
|
6070
|
my($self,$nds,$path,$copy,$nocheck) = @_; |
1076
|
1738
|
100
|
|
|
|
3732
|
$nocheck=0 if (! $nocheck); |
1077
|
1738
|
|
|
|
|
2571
|
$$self{"err"} = ""; |
1078
|
1738
|
|
|
|
|
2480
|
$$self{"errmsg"} = ""; |
1079
|
1738
|
|
|
|
|
3362
|
$nds = _nds($self,$nds,1,0,$nocheck); |
1080
|
1738
|
100
|
|
|
|
3717
|
return undef if ($self->err()); |
1081
|
|
|
|
|
|
|
|
1082
|
1737
|
|
|
|
|
3483
|
my($delim) = $self->delim(); |
1083
|
1737
|
|
|
|
|
3637
|
my @path = $self->path($path); |
1084
|
|
|
|
|
|
|
|
1085
|
1737
|
|
|
|
|
4083
|
my $val = _value($self,$nds,$delim,"",@path); |
1086
|
1737
|
100
|
|
|
|
3613
|
return undef if ($self->err()); |
1087
|
|
|
|
|
|
|
|
1088
|
1434
|
50
|
33
|
|
|
9513
|
if ($copy && ref($val)) { |
1089
|
0
|
|
|
|
|
0
|
return dclone($val); |
1090
|
|
|
|
|
|
|
} else { |
1091
|
1434
|
|
|
|
|
4188
|
return $val; |
1092
|
|
|
|
|
|
|
} |
1093
|
|
|
|
|
|
|
} |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
sub _value { |
1096
|
3272
|
|
|
3272
|
|
6764
|
my($self,$nds,$delim,$path,@path) = @_; |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
# |
1099
|
|
|
|
|
|
|
# We've traversed as far as @path goes |
1100
|
|
|
|
|
|
|
# |
1101
|
|
|
|
|
|
|
|
1102
|
3272
|
100
|
|
|
|
6778
|
if (! @path) { |
1103
|
1434
|
|
|
|
|
4171
|
return $nds; |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
# |
1107
|
|
|
|
|
|
|
# Get the next path element. |
1108
|
|
|
|
|
|
|
# |
1109
|
|
|
|
|
|
|
|
1110
|
1838
|
|
|
|
|
2809
|
my $p = shift(@path); |
1111
|
1838
|
100
|
|
|
|
4232
|
$path = ($path ? join($delim,$path,$p) : "$delim$p"); |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
# |
1114
|
|
|
|
|
|
|
# Handle the case where $nds is a scalar, or not |
1115
|
|
|
|
|
|
|
# a known data type. |
1116
|
|
|
|
|
|
|
# |
1117
|
|
|
|
|
|
|
|
1118
|
1838
|
100
|
100
|
|
|
8406
|
if (! defined($nds)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
# $nds doesn't contain the path |
1120
|
149
|
|
|
|
|
276
|
$$self{"err"} = "ndsdat01"; |
1121
|
149
|
|
|
|
|
316
|
$$self{"errmsg"} = "A path does not exist in the NDS: $path"; |
1122
|
149
|
|
|
|
|
315
|
return undef; |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
} elsif (! ref($nds)) { |
1125
|
|
|
|
|
|
|
# $nds is a scalar |
1126
|
1
|
|
|
|
|
4
|
$$self{"err"} = "ndsdat04"; |
1127
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "The NDS has a scalar at a point where a hash or " . |
1128
|
|
|
|
|
|
|
"list should be: $path"; |
1129
|
1
|
|
|
|
|
5
|
return undef; |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
} elsif (ref($nds) ne "HASH" && ref($nds) ne "ARRAY") { |
1132
|
|
|
|
|
|
|
# $nds is an unsupported data type |
1133
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsdat05"; |
1134
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "The NDS has a reference to an unsupported data " . |
1135
|
|
|
|
|
|
|
"type where a hash or list should be: $path"; |
1136
|
1
|
|
|
|
|
3
|
return undef; |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
# |
1140
|
|
|
|
|
|
|
# Handle hash references. |
1141
|
|
|
|
|
|
|
# |
1142
|
|
|
|
|
|
|
|
1143
|
1687
|
100
|
|
|
|
3554
|
if (ref($nds) eq "HASH") { |
1144
|
1670
|
100
|
|
|
|
3270
|
if (exists $$nds{$p}) { |
1145
|
1526
|
|
|
|
|
4773
|
return _value($self,$$nds{$p},$delim,$path,@path); |
1146
|
|
|
|
|
|
|
} else { |
1147
|
144
|
|
|
|
|
344
|
$$self{"err"} = "ndsdat02"; |
1148
|
144
|
|
|
|
|
320
|
$$self{"errmsg"} = "A hash key does not exist in the NDS: $path"; |
1149
|
144
|
|
|
|
|
435
|
return undef; |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# |
1154
|
|
|
|
|
|
|
# Handle lists. |
1155
|
|
|
|
|
|
|
# |
1156
|
|
|
|
|
|
|
|
1157
|
17
|
100
|
|
|
|
127
|
if ($p !~ /^\d+$/) { |
|
|
100
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
# A non-integer list reference |
1159
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsdat06"; |
1160
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "A non-integer index used to access a list: $path"; |
1161
|
1
|
|
|
|
|
4
|
return undef; |
1162
|
|
|
|
|
|
|
} elsif ($#$nds < $p) { |
1163
|
7
|
|
|
|
|
15
|
$$self{"err"} = "ndsdat03"; |
1164
|
7
|
|
|
|
|
15
|
$$self{"errmsg"} = "A list element does not exist in the NDS: $path"; |
1165
|
7
|
|
|
|
|
24
|
return undef; |
1166
|
|
|
|
|
|
|
} else { |
1167
|
9
|
|
|
|
|
35
|
return _value($self,$$nds[$p],$delim,$path,@path); |
1168
|
|
|
|
|
|
|
} |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
############################################################################### |
1172
|
|
|
|
|
|
|
# KEYS, VALUES |
1173
|
|
|
|
|
|
|
############################################################################### |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
sub keys { |
1176
|
118
|
|
|
118
|
1
|
19987
|
my($self,$nds,$path) = @_; |
1177
|
118
|
|
|
|
|
246
|
$$self{"err"} = ""; |
1178
|
118
|
|
|
|
|
191
|
$$self{"errmsg"} = ""; |
1179
|
118
|
|
|
|
|
298
|
$nds = _nds($self,$nds,1,0,0); |
1180
|
118
|
|
|
|
|
339
|
my $val = $self->value($nds,$path); |
1181
|
118
|
100
|
|
|
|
250
|
return undef if ($self->err()); |
1182
|
|
|
|
|
|
|
|
1183
|
108
|
100
|
|
|
|
597
|
if (! ref($val)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1184
|
1
|
|
|
|
|
7
|
return (); |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
} elsif (ref($val) eq "ARRAY") { |
1187
|
57
|
|
|
|
|
90
|
my(@ret); |
1188
|
57
|
|
|
|
|
172
|
foreach my $i (0..$#$val) { |
1189
|
189
|
100
|
|
|
|
377
|
push(@ret,$i) if (! _empty($self,$$val[$i])); |
1190
|
|
|
|
|
|
|
} |
1191
|
57
|
|
|
|
|
360
|
return @ret; |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
} elsif (ref($val) eq "HASH") { |
1194
|
50
|
|
|
|
|
65
|
my(@ret); |
1195
|
50
|
|
|
|
|
401
|
foreach my $key (sort(CORE::keys %$val)) { |
1196
|
95
|
50
|
|
|
|
228
|
push(@ret,$key) if (! _empty($self,$$val{$key})); |
1197
|
|
|
|
|
|
|
} |
1198
|
50
|
|
|
|
|
257
|
return @ret; |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
} else { |
1201
|
0
|
|
|
|
|
0
|
return undef; |
1202
|
|
|
|
|
|
|
} |
1203
|
|
|
|
|
|
|
} |
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
sub values { |
1206
|
99
|
|
|
99
|
1
|
1068
|
my($self,$nds,$path) = @_; |
1207
|
99
|
|
|
|
|
180
|
$$self{"err"} = ""; |
1208
|
99
|
|
|
|
|
327
|
$$self{"errmsg"} = ""; |
1209
|
99
|
|
|
|
|
394
|
$nds = _nds($self,$nds,1,0,0); |
1210
|
99
|
|
|
|
|
424
|
my $val = $self->value($nds,$path); |
1211
|
99
|
100
|
|
|
|
240
|
return undef if ($self->err()); |
1212
|
|
|
|
|
|
|
|
1213
|
89
|
100
|
|
|
|
370
|
if (! ref($val)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1214
|
1
|
|
|
|
|
5
|
return ($val); |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
} elsif (ref($val) eq "ARRAY") { |
1217
|
51
|
|
|
|
|
79
|
my(@ret); |
1218
|
51
|
|
|
|
|
144
|
foreach my $i (0..$#$val) { |
1219
|
177
|
100
|
|
|
|
402
|
push(@ret,$$val[$i]) if (! _empty($self,$$val[$i])); |
1220
|
|
|
|
|
|
|
} |
1221
|
51
|
|
|
|
|
360
|
return @ret; |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
} elsif (ref($val) eq "HASH") { |
1224
|
37
|
|
|
|
|
50
|
my(@ret); |
1225
|
37
|
|
|
|
|
168
|
foreach my $key (sort(CORE::keys %$val)) { |
1226
|
73
|
50
|
|
|
|
165
|
push(@ret,$$val{$key}) if (! _empty($self,$$val{$key})); |
1227
|
|
|
|
|
|
|
} |
1228
|
37
|
|
|
|
|
242
|
return @ret; |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
} else { |
1231
|
0
|
|
|
|
|
0
|
return undef; |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
} |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
############################################################################### |
1236
|
|
|
|
|
|
|
# SET_MERGE |
1237
|
|
|
|
|
|
|
############################################################################### |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
sub set_merge { |
1240
|
98
|
|
|
98
|
1
|
3818
|
my($self,$item,$val,@args) = @_; |
1241
|
98
|
|
|
|
|
159
|
$$self{"err"} = ""; |
1242
|
98
|
|
|
|
|
145
|
$$self{"errmsg"} = ""; |
1243
|
|
|
|
|
|
|
|
1244
|
98
|
100
|
|
|
|
187
|
if (_merge_default($self,$item)) { |
|
|
50
|
|
|
|
|
|
1245
|
9
|
|
|
|
|
19
|
_set_merge_default($self,$item,$val,@args); |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
} elsif ($item eq "merge") { |
1248
|
89
|
|
|
|
|
277
|
_set_merge_path($self,$val,@args); |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
} else { |
1251
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer01"; |
1252
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Attempt to set a merge setting to an unknown " . |
1253
|
|
|
|
|
|
|
"value: $item"; |
1254
|
0
|
|
|
|
|
0
|
return; |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
} |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
# Set a merge item for a path. |
1259
|
|
|
|
|
|
|
# |
1260
|
|
|
|
|
|
|
sub _set_merge_path { |
1261
|
89
|
|
|
89
|
|
151
|
my($self,$path,$method,$ruleset) = @_; |
1262
|
89
|
100
|
|
|
|
288
|
$ruleset = "*" if (! $ruleset); |
1263
|
|
|
|
|
|
|
|
1264
|
89
|
|
|
|
|
201
|
my @path = $self->path($path); |
1265
|
89
|
|
|
|
|
205
|
$path = $self->path(\@path); |
1266
|
|
|
|
|
|
|
|
1267
|
89
|
100
|
|
|
|
351
|
if (exists $$self{"ruleset"}{$ruleset}{"path"}{$path}) { |
1268
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsmer06"; |
1269
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to reset merge value for a path: $path"; |
1270
|
1
|
|
|
|
|
4
|
return; |
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
# Check type vs. method |
1274
|
|
|
|
|
|
|
|
1275
|
88
|
|
|
|
|
204
|
my $type = $self->get_structure($path,"type"); |
1276
|
|
|
|
|
|
|
|
1277
|
88
|
100
|
66
|
|
|
205
|
if ($type eq "list") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1278
|
66
|
|
|
|
|
141
|
my $ordered = $self->get_structure($path,"ordered"); |
1279
|
|
|
|
|
|
|
|
1280
|
66
|
100
|
|
|
|
148
|
if (! _merge_allowed($type,$ordered,$method)) { |
1281
|
4
|
100
|
|
|
|
10
|
if ($ordered) { |
1282
|
2
|
|
|
|
|
4
|
$$self{"err"} = "ndsmer08"; |
1283
|
2
|
|
|
|
|
7
|
$$self{"errmsg"} = "Invalid merge method for ordered list " . |
1284
|
|
|
|
|
|
|
"merging: $path"; |
1285
|
2
|
|
|
|
|
9
|
return; |
1286
|
|
|
|
|
|
|
} else { |
1287
|
2
|
|
|
|
|
3
|
$$self{"err"} = "ndsmer09"; |
1288
|
2
|
|
|
|
|
7
|
$$self{"errmsg"} = "Invalid merge method for unordered list " . |
1289
|
|
|
|
|
|
|
"merging: $path"; |
1290
|
2
|
|
|
|
|
9
|
return; |
1291
|
|
|
|
|
|
|
} |
1292
|
|
|
|
|
|
|
} |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
} elsif ($type eq "hash") { |
1295
|
19
|
100
|
|
|
|
57
|
if (! _merge_allowed($type,0,$method)) { |
1296
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsmer10"; |
1297
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Invalid merge method for hash merging: $path"; |
1298
|
1
|
|
|
|
|
5
|
return; |
1299
|
|
|
|
|
|
|
} |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
} elsif ($type eq "scalar" || $type eq "other") { |
1302
|
2
|
100
|
|
|
|
6
|
if (! _merge_allowed($type,0,$method)) { |
1303
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsmer11"; |
1304
|
1
|
|
|
|
|
53
|
$$self{"errmsg"} = "Invalid merge method for scalar merging: $path"; |
1305
|
1
|
|
|
|
|
6
|
return; |
1306
|
|
|
|
|
|
|
} |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
} else { |
1309
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsmer07"; |
1310
|
1
|
|
|
|
|
3
|
$$self{"errmsg"} = "Attempt to set merge for a path with no " . |
1311
|
|
|
|
|
|
|
"known type: $path"; |
1312
|
1
|
|
|
|
|
4
|
return; |
1313
|
|
|
|
|
|
|
} |
1314
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
# Set the method |
1316
|
|
|
|
|
|
|
|
1317
|
81
|
|
|
|
|
237
|
$$self{"ruleset"}{$ruleset}{"path"}{$path} = $method; |
1318
|
81
|
|
|
|
|
311
|
return; |
1319
|
|
|
|
|
|
|
} |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
{ |
1322
|
|
|
|
|
|
|
# Values for the default structural information. First value in the |
1323
|
|
|
|
|
|
|
# list is the error code for this item. Second value is the default |
1324
|
|
|
|
|
|
|
# for this item. |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
my %def = ( "merge_hash" => [ "ndsmer02", |
1327
|
|
|
|
|
|
|
"Attempt to set merge_hash to an " . |
1328
|
|
|
|
|
|
|
"invalid value", |
1329
|
|
|
|
|
|
|
qw(merge |
1330
|
|
|
|
|
|
|
keep keep_warn |
1331
|
|
|
|
|
|
|
replace replace_warn |
1332
|
|
|
|
|
|
|
error) ], |
1333
|
|
|
|
|
|
|
"merge_ol" => [ "ndsmer03", |
1334
|
|
|
|
|
|
|
"Attempt to set merge_ol to an invalid " . |
1335
|
|
|
|
|
|
|
"value", |
1336
|
|
|
|
|
|
|
qw(merge |
1337
|
|
|
|
|
|
|
keep keep_warn |
1338
|
|
|
|
|
|
|
replace replace_warn |
1339
|
|
|
|
|
|
|
error) ], |
1340
|
|
|
|
|
|
|
"merge_ul" => [ "ndsmer04", |
1341
|
|
|
|
|
|
|
"Attempt to set merge_ul to an invalid " . |
1342
|
|
|
|
|
|
|
"value", |
1343
|
|
|
|
|
|
|
qw(append |
1344
|
|
|
|
|
|
|
keep keep_warn |
1345
|
|
|
|
|
|
|
replace replace_warn |
1346
|
|
|
|
|
|
|
error) ], |
1347
|
|
|
|
|
|
|
"merge_scalar" => [ "ndsmer05", |
1348
|
|
|
|
|
|
|
"Attempt to set merge_scalar to an " . |
1349
|
|
|
|
|
|
|
"invalid value", |
1350
|
|
|
|
|
|
|
qw(keep keep_warn |
1351
|
|
|
|
|
|
|
replace replace_warn |
1352
|
|
|
|
|
|
|
error) ], |
1353
|
|
|
|
|
|
|
); |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
sub _merge_default { |
1356
|
98
|
|
|
98
|
|
216
|
my($self,$item) = @_; |
1357
|
98
|
100
|
|
|
|
379
|
return 1 if (exists $def{$item}); |
1358
|
89
|
|
|
|
|
302
|
return 0; |
1359
|
|
|
|
|
|
|
} |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
sub _set_merge_default { |
1362
|
9
|
|
|
9
|
|
15
|
my($self,$item,$val,$ruleset) = @_; |
1363
|
9
|
50
|
|
|
|
19
|
$ruleset = "*" if (! $ruleset); |
1364
|
|
|
|
|
|
|
|
1365
|
9
|
|
|
|
|
9
|
my @tmp = @{ $def{$item} }; |
|
9
|
|
|
|
|
32
|
|
1366
|
9
|
|
|
|
|
13
|
my $err = shift(@tmp); |
1367
|
9
|
|
|
|
|
12
|
my $msg = shift(@tmp); |
1368
|
9
|
|
|
|
|
11
|
my %tmp = map { $_,1 } @tmp; |
|
52
|
|
|
|
|
100
|
|
1369
|
9
|
100
|
|
|
|
25
|
if (! exists $tmp{$val}) { |
1370
|
4
|
|
|
|
|
8
|
$$self{"err"} = $err; |
1371
|
4
|
|
|
|
|
10
|
$$self{"errmsg"} = "$msg: $item = $val"; |
1372
|
4
|
|
|
|
|
17
|
return; |
1373
|
|
|
|
|
|
|
} |
1374
|
5
|
|
|
|
|
13
|
$$self{"ruleset"}{$ruleset}{"def"}{$item} = $val; |
1375
|
5
|
|
|
|
|
22
|
return; |
1376
|
|
|
|
|
|
|
} |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
# Set up the default merge: |
1379
|
|
|
|
|
|
|
sub _merge_defaults { |
1380
|
93
|
|
|
93
|
|
235
|
my($self) = @_; |
1381
|
|
|
|
|
|
|
|
1382
|
93
|
|
|
|
|
492
|
foreach my $key (CORE::keys %def) { |
1383
|
372
|
|
|
|
|
1637
|
$$self{"ruleset"}{"*"}{"def"}{$key} = $def{$key}[2]; |
1384
|
|
|
|
|
|
|
} |
1385
|
|
|
|
|
|
|
|
1386
|
93
|
|
|
|
|
756
|
$$self{"ruleset"}{"keep"}{"def"} = |
1387
|
|
|
|
|
|
|
{ "merge_hash" => "keep", |
1388
|
|
|
|
|
|
|
"merge_ol" => "keep", |
1389
|
|
|
|
|
|
|
"merge_ul" => "keep", |
1390
|
|
|
|
|
|
|
"merge_scalar" => "keep" }; |
1391
|
|
|
|
|
|
|
|
1392
|
93
|
|
|
|
|
587
|
$$self{"ruleset"}{"replace"}{"def"} = |
1393
|
|
|
|
|
|
|
{ "merge_hash" => "replace", |
1394
|
|
|
|
|
|
|
"merge_ol" => "replace", |
1395
|
|
|
|
|
|
|
"merge_ul" => "replace", |
1396
|
|
|
|
|
|
|
"merge_scalar" => "replace" }; |
1397
|
|
|
|
|
|
|
|
1398
|
93
|
|
|
|
|
585
|
$$self{"ruleset"}{"default"}{"def"} = |
1399
|
|
|
|
|
|
|
{ "merge_hash" => "merge", |
1400
|
|
|
|
|
|
|
"merge_ol" => "merge", |
1401
|
|
|
|
|
|
|
"merge_ul" => "keep", |
1402
|
|
|
|
|
|
|
"merge_scalar" => "keep" }; |
1403
|
|
|
|
|
|
|
|
1404
|
93
|
|
|
|
|
562
|
$$self{"ruleset"}{"override"}{"def"} = |
1405
|
|
|
|
|
|
|
{ "merge_hash" => "merge", |
1406
|
|
|
|
|
|
|
"merge_ol" => "merge", |
1407
|
|
|
|
|
|
|
"merge_ul" => "replace", |
1408
|
|
|
|
|
|
|
"merge_scalar" => "replace" }; |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
} |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
sub _merge_allowed { |
1413
|
87
|
|
|
87
|
|
135
|
my($type,$ordered,$val) = @_; |
1414
|
|
|
|
|
|
|
|
1415
|
87
|
|
|
|
|
91
|
my @tmp; |
1416
|
87
|
100
|
|
|
|
276
|
if ($type eq "hash") { |
|
|
100
|
|
|
|
|
|
1417
|
19
|
|
|
|
|
26
|
@tmp = @{ $def{"merge_hash"} }; |
|
19
|
|
|
|
|
260
|
|
1418
|
|
|
|
|
|
|
} elsif ($type eq "list") { |
1419
|
66
|
100
|
|
|
|
215
|
if ($ordered) { |
1420
|
33
|
|
|
|
|
39
|
@tmp = @{ $def{"merge_ol"} }; |
|
33
|
|
|
|
|
135
|
|
1421
|
|
|
|
|
|
|
} else { |
1422
|
33
|
|
|
|
|
36
|
@tmp = @{ $def{"merge_ul"} }; |
|
33
|
|
|
|
|
122
|
|
1423
|
|
|
|
|
|
|
} |
1424
|
|
|
|
|
|
|
} else { |
1425
|
2
|
|
|
|
|
2
|
@tmp = @{ $def{"merge_scalar"} }; |
|
2
|
|
|
|
|
8
|
|
1426
|
|
|
|
|
|
|
} |
1427
|
|
|
|
|
|
|
|
1428
|
87
|
|
|
|
|
142
|
my $err = shift(@tmp); |
1429
|
87
|
|
|
|
|
112
|
my $msg = shift(@tmp); |
1430
|
87
|
|
|
|
|
178
|
my %tmp = map { $_,1 } @tmp; |
|
520
|
|
|
|
|
1263
|
|
1431
|
87
|
100
|
|
|
|
299
|
return 0 if (! exists $tmp{$val}); |
1432
|
81
|
|
|
|
|
367
|
return 1; |
1433
|
|
|
|
|
|
|
} |
1434
|
|
|
|
|
|
|
} |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
############################################################################### |
1437
|
|
|
|
|
|
|
# GET_MERGE |
1438
|
|
|
|
|
|
|
############################################################################### |
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
sub get_merge { |
1441
|
319
|
|
|
319
|
1
|
1123
|
my($self,$path,$ruleset) = @_; |
1442
|
319
|
|
|
|
|
488
|
$$self{"err"} = ""; |
1443
|
319
|
|
|
|
|
435
|
$$self{"errmsg"} = ""; |
1444
|
319
|
100
|
|
|
|
699
|
$ruleset = "*" if (! $ruleset); |
1445
|
319
|
|
|
|
|
622
|
my @path = $self->path($path); |
1446
|
319
|
|
|
|
|
781
|
$path = $self->path(\@path); |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
# Check ruleset |
1449
|
|
|
|
|
|
|
|
1450
|
319
|
100
|
|
|
|
1293
|
return $$self{"ruleset"}{$ruleset}{"path"}{$path} |
1451
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"path"}{$path}); |
1452
|
|
|
|
|
|
|
|
1453
|
242
|
|
|
|
|
543
|
my $type = $self->get_structure($path,"type"); |
1454
|
242
|
|
|
|
|
308
|
my $ordered; |
1455
|
242
|
50
|
|
|
|
531
|
if ($type eq "list") { |
1456
|
0
|
|
|
|
|
0
|
$ordered = $self->get_structure($path,"ordered"); |
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
|
1459
|
242
|
100
|
33
|
|
|
929
|
if ($type eq "hash") { |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1460
|
151
|
50
|
|
|
|
918
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_hash"} |
1461
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"def"}{"merge_hash"}); |
1462
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
} elsif ($type eq "list" && $ordered) { |
1464
|
0
|
0
|
|
|
|
0
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_ol"} |
1465
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"def"}{"merge_ol"}); |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
} elsif ($type eq "list") { |
1468
|
0
|
0
|
|
|
|
0
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_ul"} |
1469
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"def"}{"merge_ul"}); |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
} elsif ($type eq "scalar" || $type eq "other") { |
1472
|
91
|
100
|
|
|
|
556
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_scalar"} |
1473
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"def"}{"merge_scalar"}); |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
} else { |
1476
|
0
|
|
|
|
|
0
|
return ""; |
1477
|
|
|
|
|
|
|
} |
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
# Check "*" (this should always find something) |
1480
|
|
|
|
|
|
|
|
1481
|
1
|
|
|
|
|
2
|
$ruleset = "*"; |
1482
|
|
|
|
|
|
|
|
1483
|
1
|
50
|
|
|
|
4
|
return $$self{"ruleset"}{$ruleset}{"path"}{$path} |
1484
|
|
|
|
|
|
|
if (exists $$self{"ruleset"}{$ruleset}{"path"}{$path}); |
1485
|
|
|
|
|
|
|
|
1486
|
1
|
50
|
33
|
|
|
11
|
if ($type eq "hash") { |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1487
|
0
|
|
|
|
|
0
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_hash"}; |
1488
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
} elsif ($type eq "list" && $ordered) { |
1490
|
0
|
|
|
|
|
0
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_ol"}; |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
} elsif ($type eq "list") { |
1493
|
0
|
|
|
|
|
0
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_ul"}; |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
} elsif ($type eq "scalar" || $type eq "other") { |
1496
|
1
|
|
|
|
|
5
|
return $$self{"ruleset"}{$ruleset}{"def"}{"merge_scalar"}; |
1497
|
|
|
|
|
|
|
} |
1498
|
|
|
|
|
|
|
} |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
############################################################################### |
1501
|
|
|
|
|
|
|
# MERGE |
1502
|
|
|
|
|
|
|
############################################################################### |
1503
|
|
|
|
|
|
|
# This merges two NDSes into a single one. |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
sub merge { |
1506
|
102
|
|
|
102
|
1
|
389
|
my($self,$nds1,$nds2,@args) = @_; |
1507
|
102
|
|
|
|
|
216
|
$$self{"err"} = ""; |
1508
|
102
|
|
|
|
|
166
|
$$self{"errmsg"} = ""; |
1509
|
102
|
50
|
|
|
|
305
|
return if (! defined $nds2); |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
# |
1512
|
|
|
|
|
|
|
# Parse ruleset and new arguments |
1513
|
|
|
|
|
|
|
# |
1514
|
|
|
|
|
|
|
|
1515
|
102
|
|
|
|
|
166
|
my ($ruleset,$new); |
1516
|
102
|
50
|
|
|
|
324
|
if (! @args) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1517
|
0
|
|
|
|
|
0
|
$ruleset = "*"; |
1518
|
0
|
|
|
|
|
0
|
$new = 0; |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
} elsif ($#args == 0) { |
1521
|
102
|
100
|
66
|
|
|
530
|
if ($args[0] eq "0" || $args[0] eq "1") { |
1522
|
4
|
|
|
|
|
15
|
$ruleset = "*"; |
1523
|
4
|
|
|
|
|
19
|
$new = $args[0]; |
1524
|
|
|
|
|
|
|
} else { |
1525
|
98
|
|
|
|
|
131
|
$ruleset = $args[0]; |
1526
|
98
|
|
|
|
|
140
|
$new = 0; |
1527
|
|
|
|
|
|
|
} |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
} elsif ($#args == 1) { |
1530
|
0
|
|
|
|
|
0
|
$ruleset = $args[0]; |
1531
|
0
|
|
|
|
|
0
|
$new = $args[1]; |
1532
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
} else { |
1534
|
0
|
|
|
|
|
0
|
die "[merge] Unknown argument list"; |
1535
|
|
|
|
|
|
|
} |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
# |
1538
|
|
|
|
|
|
|
# Get nds1 and nds2 by reference or name |
1539
|
|
|
|
|
|
|
# |
1540
|
|
|
|
|
|
|
|
1541
|
102
|
|
|
|
|
227
|
$nds1 = _nds($self,$nds1,$new); |
1542
|
102
|
50
|
|
|
|
276
|
if (! defined($nds1)) { |
1543
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer12"; |
1544
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "While merging, the first NDS is not defined: $nds1"; |
1545
|
0
|
|
|
|
|
0
|
return; |
1546
|
|
|
|
|
|
|
} |
1547
|
|
|
|
|
|
|
|
1548
|
102
|
|
|
|
|
200
|
$nds2 = _nds($self,$nds2,$new); |
1549
|
102
|
50
|
|
|
|
266
|
if (! defined($nds2)) { |
1550
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer13"; |
1551
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "While merging, the second NDS is not defined: $nds2"; |
1552
|
0
|
|
|
|
|
0
|
return; |
1553
|
|
|
|
|
|
|
} |
1554
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
# |
1556
|
|
|
|
|
|
|
# Check structure |
1557
|
|
|
|
|
|
|
# |
1558
|
|
|
|
|
|
|
|
1559
|
102
|
|
|
|
|
310
|
$self->check_structure($nds1,$new); |
1560
|
102
|
50
|
|
|
|
288
|
if ($$self{"err"}) { |
1561
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer14"; |
1562
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The first NDS has an invalid structure."; |
1563
|
0
|
|
|
|
|
0
|
return; |
1564
|
|
|
|
|
|
|
} |
1565
|
102
|
|
|
|
|
317
|
$self->check_structure($nds2,$new); |
1566
|
102
|
50
|
|
|
|
285
|
if ($$self{"err"}) { |
1567
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer15"; |
1568
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The second NDS has an invalid structure."; |
1569
|
0
|
|
|
|
|
0
|
return; |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
# |
1573
|
|
|
|
|
|
|
# Merge |
1574
|
|
|
|
|
|
|
# |
1575
|
|
|
|
|
|
|
|
1576
|
102
|
|
|
|
|
314
|
my $tmp = _merge($self,$nds1,$nds2,[],$ruleset); |
1577
|
102
|
50
|
|
|
|
285
|
if (ref($nds1) eq "HASH") { |
|
|
0
|
|
|
|
|
|
1578
|
102
|
|
|
|
|
746
|
%$nds1 = %$tmp; |
1579
|
|
|
|
|
|
|
} elsif (ref($nds1) eq "ARRAY") { |
1580
|
0
|
|
|
|
|
0
|
@$nds1 = @$tmp; |
1581
|
|
|
|
|
|
|
} else { |
1582
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer16"; |
1583
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The NDS must be a list or hash."; |
1584
|
0
|
|
|
|
|
0
|
return; |
1585
|
|
|
|
|
|
|
} |
1586
|
102
|
|
|
|
|
484
|
return; |
1587
|
|
|
|
|
|
|
} |
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
sub _merge { |
1590
|
315
|
|
|
315
|
|
564
|
my($self,$nds1,$nds2,$pathref,$ruleset) = @_; |
1591
|
315
|
|
|
|
|
614
|
my $path = $self->path($pathref); |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# |
1594
|
|
|
|
|
|
|
# If $nds2 is empty, we'll always return whatever $nds1 is. |
1595
|
|
|
|
|
|
|
# If $nds1 is empty or "", we'll always return whatever $nds2 is. |
1596
|
|
|
|
|
|
|
# |
1597
|
|
|
|
|
|
|
|
1598
|
315
|
50
|
|
|
|
717
|
return $nds1 if ($self->empty($nds2)); |
1599
|
315
|
50
|
66
|
|
|
693
|
if ($self->empty($nds1) || |
|
|
|
33
|
|
|
|
|
1600
|
|
|
|
|
|
|
(! ref($nds1) && $nds1 eq "")) { |
1601
|
0
|
|
|
|
|
0
|
return $nds2; |
1602
|
|
|
|
|
|
|
} |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
# |
1605
|
|
|
|
|
|
|
# $method can be merge, keep, keep_warn, replace, replace_warn, |
1606
|
|
|
|
|
|
|
# error, append |
1607
|
|
|
|
|
|
|
# |
1608
|
|
|
|
|
|
|
# handle keep*, replace*, and error |
1609
|
|
|
|
|
|
|
# |
1610
|
|
|
|
|
|
|
|
1611
|
315
|
|
|
|
|
735
|
my $type = $self->get_structure($path); |
1612
|
315
|
|
|
|
|
809
|
my $method = $self->get_merge($path,$ruleset); |
1613
|
|
|
|
|
|
|
|
1614
|
315
|
100
|
66
|
|
|
2057
|
if ($method eq "keep" || $method eq "keep_warn") { |
|
|
100
|
66
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1615
|
114
|
50
|
|
|
|
250
|
warn($self,"[merge] keeping initial value\n" . |
1616
|
|
|
|
|
|
|
" path: $path",1) if ($method eq "keep_warn"); |
1617
|
114
|
|
|
|
|
501
|
return $nds1; |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
} elsif ($method eq "replace" || $method eq "replace_warn") { |
1620
|
29
|
50
|
|
|
|
70
|
warn($self,"[merge] replacing initial value\n" . |
1621
|
|
|
|
|
|
|
" path: $path",1) if ($method eq "replace_warn"); |
1622
|
29
|
50
|
|
|
|
78
|
if (ref($nds2)) { |
1623
|
29
|
|
|
|
|
115
|
return $nds2; |
1624
|
|
|
|
|
|
|
} |
1625
|
0
|
|
|
|
|
0
|
return $nds2; |
1626
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
} elsif ($method eq "error") { |
1628
|
0
|
0
|
|
|
|
0
|
if (ref($nds1)) { |
|
|
0
|
|
|
|
|
|
1629
|
0
|
|
|
|
|
0
|
warn($self,"[merge] multiply defined value\n" . |
1630
|
|
|
|
|
|
|
" path: $path",1); |
1631
|
0
|
|
|
|
|
0
|
exit; |
1632
|
|
|
|
|
|
|
} elsif ($nds1 eq $nds2) { |
1633
|
0
|
|
|
|
|
0
|
return $nds1; |
1634
|
|
|
|
|
|
|
} else { |
1635
|
0
|
|
|
|
|
0
|
warn($self,"[merge] nonidentical values\n" . |
1636
|
|
|
|
|
|
|
" path: $path",1); |
1637
|
0
|
|
|
|
|
0
|
exit; |
1638
|
|
|
|
|
|
|
} |
1639
|
|
|
|
|
|
|
} |
1640
|
|
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
# |
1642
|
|
|
|
|
|
|
# Merge two lists |
1643
|
|
|
|
|
|
|
# |
1644
|
|
|
|
|
|
|
|
1645
|
172
|
100
|
|
|
|
420
|
if (ref($nds1) eq "ARRAY") { |
1646
|
20
|
|
|
|
|
57
|
return _merge_lists($self,$method,$nds1,$nds2,$pathref,$ruleset); |
1647
|
|
|
|
|
|
|
} |
1648
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
# |
1650
|
|
|
|
|
|
|
# Merge two hashes |
1651
|
|
|
|
|
|
|
# |
1652
|
|
|
|
|
|
|
|
1653
|
152
|
50
|
|
|
|
429
|
if (ref($nds1) eq "HASH") { |
1654
|
152
|
|
|
|
|
420
|
return _merge_hashes($self,$method,$nds1,$nds2,$pathref,$ruleset); |
1655
|
|
|
|
|
|
|
} |
1656
|
|
|
|
|
|
|
} |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
# Method is: merge |
1659
|
|
|
|
|
|
|
# |
1660
|
|
|
|
|
|
|
sub _merge_hashes { |
1661
|
152
|
|
|
152
|
|
294
|
my($self,$method,$val1,$val2,$pathref,$ruleset) = @_; |
1662
|
|
|
|
|
|
|
|
1663
|
152
|
|
|
|
|
352
|
foreach my $key (CORE::keys %$val2) { |
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
# |
1666
|
|
|
|
|
|
|
# If $val2 is empty, we'll keep $val1 |
1667
|
|
|
|
|
|
|
# If $val1 is empty or "", we'll always set it to $val2 |
1668
|
|
|
|
|
|
|
# |
1669
|
|
|
|
|
|
|
|
1670
|
282
|
50
|
|
|
|
631
|
next if ($self->empty($$val2{$key})); |
1671
|
|
|
|
|
|
|
|
1672
|
282
|
100
|
66
|
|
|
1056
|
if (! exists $$val1{$key} || |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
1673
|
|
|
|
|
|
|
$self->empty($$val1{$key}) || |
1674
|
|
|
|
|
|
|
(! ref($$val1{$key}) && $$val1{$key} eq "")) { |
1675
|
103
|
|
|
|
|
324
|
$$val1{$key} = $$val2{$key}; |
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
} else { |
1678
|
179
|
|
|
|
|
812
|
$$val1{$key} = |
1679
|
|
|
|
|
|
|
_merge($self,$$val1{$key},$$val2{$key},[@$pathref,$key],$ruleset); |
1680
|
|
|
|
|
|
|
} |
1681
|
|
|
|
|
|
|
} |
1682
|
|
|
|
|
|
|
|
1683
|
152
|
|
|
|
|
627
|
return $val1; |
1684
|
|
|
|
|
|
|
} |
1685
|
|
|
|
|
|
|
|
1686
|
|
|
|
|
|
|
# Method is: append, merge |
1687
|
|
|
|
|
|
|
# |
1688
|
|
|
|
|
|
|
sub _merge_lists { |
1689
|
20
|
|
|
20
|
|
34
|
my($self,$method,$val1,$val2,$pathref,$ruleset) = @_; |
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
# Handle append unordered |
1692
|
|
|
|
|
|
|
|
1693
|
20
|
100
|
|
|
|
58
|
if ($method eq "append") { |
1694
|
10
|
|
|
|
|
30
|
push(@$val1,@$val2); |
1695
|
10
|
|
|
|
|
41
|
return $val1; |
1696
|
|
|
|
|
|
|
} |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
# Handle merge ordered (merge each i'th element) |
1699
|
|
|
|
|
|
|
|
1700
|
10
|
|
|
|
|
16
|
my($i); |
1701
|
10
|
|
|
|
|
45
|
for ($i=0; $i<=$#$val2; $i++) { |
1702
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
# val1[i] val2[i] |
1704
|
|
|
|
|
|
|
# ------- ------- |
1705
|
|
|
|
|
|
|
# * empty do nothing |
1706
|
|
|
|
|
|
|
# empty/'' * val1[i] = val2[i] |
1707
|
|
|
|
|
|
|
# * * recurse into (including scalars) |
1708
|
|
|
|
|
|
|
|
1709
|
30
|
100
|
66
|
|
|
106
|
if ($self->empty($$val2[$i])) { |
|
|
100
|
66
|
|
|
|
|
1710
|
5
|
|
|
|
|
21
|
next; |
1711
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
} elsif ($self->empty($$val1[$i]) || |
1713
|
|
|
|
|
|
|
(! ref($$val1[$i]) && $$val1[$i] eq "")) { |
1714
|
10
|
|
|
|
|
36
|
$$val1[$i] = $$val2[$i]; |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
} else { |
1717
|
15
|
|
|
|
|
93
|
$$val1[$i] = |
1718
|
|
|
|
|
|
|
_merge($self,$$val1[$i],$$val2[$i],[@$pathref,$i],$ruleset); |
1719
|
|
|
|
|
|
|
} |
1720
|
|
|
|
|
|
|
} |
1721
|
|
|
|
|
|
|
|
1722
|
10
|
|
|
|
|
43
|
return $val1; |
1723
|
|
|
|
|
|
|
} |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
############################################################################### |
1726
|
|
|
|
|
|
|
# MERGE_PATH |
1727
|
|
|
|
|
|
|
############################################################################### |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
sub merge_path { |
1730
|
21
|
|
|
21
|
1
|
298
|
my($self,$nds,$val,$path,@args) = @_; |
1731
|
21
|
|
|
|
|
49
|
$$self{"err"} = ""; |
1732
|
21
|
|
|
|
|
37
|
$$self{"errmsg"} = ""; |
1733
|
|
|
|
|
|
|
|
1734
|
21
|
|
|
|
|
55
|
my @path = $self->path($path); |
1735
|
21
|
|
|
|
|
65
|
$path = $self->path(\@path); |
1736
|
|
|
|
|
|
|
|
1737
|
21
|
100
|
|
|
|
88
|
return merge($self,$nds,$val,@args) if (! @path); |
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
# |
1740
|
|
|
|
|
|
|
# Parse ruleset and new arguments |
1741
|
|
|
|
|
|
|
# |
1742
|
|
|
|
|
|
|
|
1743
|
19
|
|
|
|
|
33
|
my ($ruleset,$new); |
1744
|
19
|
50
|
|
|
|
90
|
if (! @args) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1745
|
0
|
|
|
|
|
0
|
$ruleset = "*"; |
1746
|
0
|
|
|
|
|
0
|
$new = 0; |
1747
|
|
|
|
|
|
|
|
1748
|
|
|
|
|
|
|
} elsif ($#args == 0) { |
1749
|
15
|
50
|
33
|
|
|
77
|
if ($args[0] eq "0" || $args[0] eq "1") { |
1750
|
15
|
|
|
|
|
19
|
$ruleset = "*"; |
1751
|
15
|
|
|
|
|
28
|
$new = $args[0]; |
1752
|
|
|
|
|
|
|
} else { |
1753
|
0
|
|
|
|
|
0
|
$ruleset = $args[0]; |
1754
|
0
|
|
|
|
|
0
|
$new = 0; |
1755
|
|
|
|
|
|
|
} |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
} elsif ($#args == 1) { |
1758
|
4
|
|
|
|
|
6
|
$ruleset = $args[0]; |
1759
|
4
|
|
|
|
|
14
|
$new = $args[1]; |
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
} else { |
1762
|
0
|
|
|
|
|
0
|
die "[merge_path] Unknown argument list"; |
1763
|
|
|
|
|
|
|
} |
1764
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
# |
1766
|
|
|
|
|
|
|
# Get nds by reference or name |
1767
|
|
|
|
|
|
|
# |
1768
|
|
|
|
|
|
|
|
1769
|
19
|
|
|
|
|
51
|
$nds = _nds($self,$nds,0,0,1); |
1770
|
19
|
50
|
|
|
|
48
|
if (! defined($nds)) { |
1771
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer17"; |
1772
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Attempt to merge a value into an undefined NDS: $nds"; |
1773
|
0
|
|
|
|
|
0
|
return; |
1774
|
|
|
|
|
|
|
} |
1775
|
|
|
|
|
|
|
|
1776
|
|
|
|
|
|
|
# |
1777
|
|
|
|
|
|
|
# Check structure |
1778
|
|
|
|
|
|
|
# |
1779
|
|
|
|
|
|
|
|
1780
|
19
|
|
|
|
|
52
|
$self->check_structure($nds,$new); |
1781
|
19
|
50
|
|
|
|
52
|
if ($self->err()) { |
1782
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer18"; |
1783
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The NDS has an invalid structure: $path"; |
1784
|
0
|
|
|
|
|
0
|
return; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
|
1787
|
19
|
|
|
|
|
63
|
_check_structure($self,$val,$new,@path); |
1788
|
19
|
50
|
|
|
|
61
|
if ($self->err()) { |
1789
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsmer19"; |
1790
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The value has an invalid structure: $path"; |
1791
|
0
|
|
|
|
|
0
|
return; |
1792
|
|
|
|
|
|
|
} |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
# |
1795
|
|
|
|
|
|
|
# Get the NDS stored at the path. |
1796
|
|
|
|
|
|
|
# |
1797
|
|
|
|
|
|
|
|
1798
|
19
|
|
|
|
|
31
|
my $ele = pop(@path); |
1799
|
19
|
|
|
|
|
78
|
$nds = _merge_path_nds($self,$nds,[],@path); |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
# |
1802
|
|
|
|
|
|
|
# Merge in the value |
1803
|
|
|
|
|
|
|
# |
1804
|
|
|
|
|
|
|
|
1805
|
19
|
50
|
|
|
|
64
|
if (ref($nds) eq "HASH") { |
|
|
0
|
|
|
|
|
|
1806
|
19
|
|
|
|
|
87
|
$$nds{$ele} = _merge($self,$$nds{$ele},$val,[@path,$ele],$ruleset); |
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
1809
|
0
|
|
|
|
|
0
|
$$nds[$ele] = _merge($self,$$nds[$ele],$val,[@path,$ele],$ruleset); |
1810
|
|
|
|
|
|
|
} |
1811
|
19
|
|
|
|
|
106
|
return; |
1812
|
|
|
|
|
|
|
} |
1813
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
# This returns the NDS stored at @path in $nds. $pathref is the path |
1815
|
|
|
|
|
|
|
# of $nds with respect to the main NDS structure. |
1816
|
|
|
|
|
|
|
# |
1817
|
|
|
|
|
|
|
# Since we removed the last element of the path in the merge_path |
1818
|
|
|
|
|
|
|
# method, this can ONLY be called with hash/list structures. |
1819
|
|
|
|
|
|
|
# |
1820
|
|
|
|
|
|
|
sub _merge_path_nds { |
1821
|
19
|
|
|
19
|
|
39
|
my($self,$nds,$pathref,@path) = @_; |
1822
|
19
|
50
|
|
|
|
65
|
return $nds if (! @path); |
1823
|
0
|
|
|
|
|
0
|
my($ele) = shift(@path); |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
# Easy case: return an existing element |
1826
|
|
|
|
|
|
|
|
1827
|
0
|
0
|
|
|
|
0
|
if (ref($nds) eq "HASH") { |
1828
|
0
|
0
|
|
|
|
0
|
if (exists $$nds{$ele}) { |
1829
|
0
|
|
|
|
|
0
|
return _merge_path_nds($self,$$nds{$ele},[@$pathref,$ele],@path); |
1830
|
|
|
|
|
|
|
} |
1831
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
} else { |
1833
|
0
|
0
|
|
|
|
0
|
if (defined $$nds[$ele]) { |
1834
|
0
|
|
|
|
|
0
|
return _merge_path_nds($self,$$nds[$ele],[@$pathref,$ele],@path); |
1835
|
|
|
|
|
|
|
} |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
# Hard case: create new structure |
1839
|
|
|
|
|
|
|
|
1840
|
0
|
|
|
|
|
0
|
my $type = $self->get_structure([@$pathref,$ele]); |
1841
|
0
|
|
|
|
|
0
|
my $new; |
1842
|
0
|
0
|
|
|
|
0
|
if ($type eq "hash") { |
1843
|
0
|
|
|
|
|
0
|
$new = {}; |
1844
|
|
|
|
|
|
|
} else { |
1845
|
0
|
|
|
|
|
0
|
$new = []; |
1846
|
|
|
|
|
|
|
} |
1847
|
|
|
|
|
|
|
|
1848
|
0
|
0
|
|
|
|
0
|
if (ref($nds) eq "HASH") { |
1849
|
0
|
|
|
|
|
0
|
$$nds{$ele} = $new; |
1850
|
0
|
|
|
|
|
0
|
return _merge_path_nds($self,$$nds{$ele},[@$pathref,$ele],@path); |
1851
|
|
|
|
|
|
|
|
1852
|
|
|
|
|
|
|
} else { |
1853
|
0
|
|
|
|
|
0
|
$$nds[$ele] = $new; |
1854
|
0
|
|
|
|
|
0
|
return _merge_path_nds($self,$$nds[$ele],[@$pathref,$ele],@path); |
1855
|
|
|
|
|
|
|
} |
1856
|
|
|
|
|
|
|
} |
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
############################################################################### |
1859
|
|
|
|
|
|
|
# ERASE |
1860
|
|
|
|
|
|
|
############################################################################### |
1861
|
|
|
|
|
|
|
# This removes a path from an NDS based on the structural information. |
1862
|
|
|
|
|
|
|
# Hash elements are deleted, ordered elements are cleared, unordered |
1863
|
|
|
|
|
|
|
# elements are deleted. |
1864
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
sub erase { |
1866
|
10
|
|
|
10
|
1
|
63
|
my($self,$nds,$path) = @_; |
1867
|
10
|
|
|
|
|
22
|
$$self{"err"} = ""; |
1868
|
10
|
|
|
|
|
17
|
$$self{"errmsg"} = ""; |
1869
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
# |
1871
|
|
|
|
|
|
|
# Get the NDS |
1872
|
|
|
|
|
|
|
# |
1873
|
|
|
|
|
|
|
|
1874
|
10
|
|
|
|
|
23
|
$nds = _nds($self,$nds,1,0,0); |
1875
|
10
|
50
|
|
|
|
23
|
return undef if ($self->err()); |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
# |
1878
|
|
|
|
|
|
|
# If $path not passed in, clear the entire NDS |
1879
|
|
|
|
|
|
|
# |
1880
|
|
|
|
|
|
|
|
1881
|
10
|
|
|
|
|
26
|
my(@path) = $self->path($path); |
1882
|
10
|
100
|
|
|
|
29
|
if (! @path) { |
1883
|
4
|
100
|
|
|
|
16
|
if (ref($nds) eq "HASH") { |
|
|
50
|
|
|
|
|
|
1884
|
2
|
|
|
|
|
6
|
%$nds = (); |
1885
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
1886
|
2
|
|
|
|
|
5
|
@$nds = (); |
1887
|
|
|
|
|
|
|
} |
1888
|
4
|
|
|
|
|
9
|
return 1; |
1889
|
|
|
|
|
|
|
} |
1890
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
# |
1892
|
|
|
|
|
|
|
# Get the parent of $path |
1893
|
|
|
|
|
|
|
# |
1894
|
|
|
|
|
|
|
|
1895
|
6
|
|
|
|
|
9
|
my $ele = pop(@path); |
1896
|
6
|
|
|
|
|
20
|
$nds = $self->value($nds,[@path]); |
1897
|
6
|
50
|
|
|
|
16
|
return undef if ($self->err()); |
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
# |
1900
|
|
|
|
|
|
|
# Delete the element |
1901
|
|
|
|
|
|
|
# |
1902
|
|
|
|
|
|
|
|
1903
|
6
|
100
|
|
|
|
17
|
if (ref($nds) eq "HASH") { |
1904
|
4
|
50
|
|
|
|
12
|
if (exists $$nds{$ele}) { |
1905
|
4
|
|
|
|
|
13
|
delete $$nds{$ele}; |
1906
|
|
|
|
|
|
|
} else { |
1907
|
0
|
|
|
|
|
0
|
return 0; |
1908
|
|
|
|
|
|
|
} |
1909
|
|
|
|
|
|
|
|
1910
|
|
|
|
|
|
|
} else { |
1911
|
2
|
|
|
|
|
7
|
my $ordered = $self->get_structure([@path],"ordered"); |
1912
|
2
|
100
|
|
|
|
6
|
if ($ordered) { |
1913
|
1
|
50
|
|
|
|
5
|
if (defined $$nds[$ele]) { |
1914
|
1
|
|
|
|
|
3
|
$$nds[$ele] = undef; |
1915
|
|
|
|
|
|
|
} else { |
1916
|
0
|
|
|
|
|
0
|
return 0; |
1917
|
|
|
|
|
|
|
} |
1918
|
|
|
|
|
|
|
} else { |
1919
|
1
|
50
|
|
|
|
7
|
if (defined $$nds[$ele]) { |
1920
|
1
|
|
|
|
|
3
|
splice(@$nds,$ele,1); |
1921
|
|
|
|
|
|
|
} else { |
1922
|
0
|
|
|
|
|
0
|
return 0; |
1923
|
|
|
|
|
|
|
} |
1924
|
|
|
|
|
|
|
} |
1925
|
|
|
|
|
|
|
} |
1926
|
|
|
|
|
|
|
|
1927
|
6
|
|
|
|
|
16
|
return 1; |
1928
|
|
|
|
|
|
|
} |
1929
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
############################################################################### |
1931
|
|
|
|
|
|
|
# WHICH |
1932
|
|
|
|
|
|
|
############################################################################### |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
sub which { |
1935
|
3
|
|
|
3
|
1
|
1017
|
my($self,$nds,@crit) = @_; |
1936
|
3
|
|
|
|
|
9
|
$$self{"err"} = ""; |
1937
|
3
|
|
|
|
|
8
|
$$self{"errmsg"} = ""; |
1938
|
|
|
|
|
|
|
|
1939
|
3
|
|
|
|
|
11
|
$nds = _nds($self,$nds,1,0,0); |
1940
|
|
|
|
|
|
|
|
1941
|
3
|
100
|
|
|
|
11
|
if (! @crit) { |
1942
|
1
|
|
|
|
|
2
|
my %ret; |
1943
|
1
|
|
|
|
|
6
|
_which_scalar($self,$nds,\%ret,{},[]); |
1944
|
1
|
|
|
|
|
11
|
return %ret; |
1945
|
|
|
|
|
|
|
} else { |
1946
|
2
|
|
|
|
|
4
|
my(@re,%vals,%ret); |
1947
|
2
|
|
|
|
|
6
|
foreach my $crit (@crit) { |
1948
|
3
|
100
|
|
|
|
12
|
if (ref($crit) eq "Regexp") { |
1949
|
1
|
|
|
|
|
3
|
push(@re,$crit); |
1950
|
|
|
|
|
|
|
} else { |
1951
|
2
|
|
|
|
|
6
|
$vals{$crit} = 1; |
1952
|
|
|
|
|
|
|
} |
1953
|
|
|
|
|
|
|
} |
1954
|
2
|
|
|
|
|
11
|
_which_scalar($self,$nds,\%ret,\%vals,\@re); |
1955
|
2
|
|
|
|
|
19
|
return %ret; |
1956
|
|
|
|
|
|
|
} |
1957
|
|
|
|
|
|
|
} |
1958
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
# Sets %ret to be a hash of PATH => VAL for every path which |
1960
|
|
|
|
|
|
|
# passes one of the criteria. |
1961
|
|
|
|
|
|
|
# |
1962
|
|
|
|
|
|
|
# If %vals is not empty, a path passes if it's value is any of |
1963
|
|
|
|
|
|
|
# the keys in %vals. |
1964
|
|
|
|
|
|
|
# |
1965
|
|
|
|
|
|
|
# If @re is not empty, a path passes if it matches any of the |
1966
|
|
|
|
|
|
|
# regular expressions in @re. |
1967
|
|
|
|
|
|
|
# |
1968
|
|
|
|
|
|
|
sub _which_scalar { |
1969
|
24
|
|
|
24
|
|
52
|
my($self,$nds,$ret,$vals,$re,@path) = @_; |
1970
|
|
|
|
|
|
|
|
1971
|
24
|
100
|
|
|
|
79
|
if (ref($nds) eq "HASH") { |
|
|
100
|
|
|
|
|
|
1972
|
6
|
|
|
|
|
16
|
foreach my $key (CORE::keys %$nds) { |
1973
|
15
|
|
|
|
|
59
|
_which_scalar($self,$$nds{$key},$ret,$vals,$re,@path,$key); |
1974
|
|
|
|
|
|
|
} |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
1977
|
3
|
|
|
|
|
13
|
foreach (my $i = 0; $i <= $#$nds; $i++) { |
1978
|
6
|
|
|
|
|
17
|
_which_scalar($self,$$nds[$i],$ret,$vals,$re,@path,$i); |
1979
|
|
|
|
|
|
|
} |
1980
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
} else { |
1982
|
15
|
|
|
|
|
52
|
my $path = $self->path([@path]); |
1983
|
15
|
|
|
|
|
27
|
my $crit = 0; |
1984
|
|
|
|
|
|
|
|
1985
|
15
|
100
|
|
|
|
37
|
if (CORE::keys %$vals) { |
1986
|
5
|
|
|
|
|
6
|
$crit = 1; |
1987
|
5
|
100
|
|
|
|
12
|
if (exists $$vals{$nds}) { |
1988
|
2
|
|
|
|
|
4
|
$$ret{$path} = $nds; |
1989
|
2
|
|
|
|
|
9
|
return; |
1990
|
|
|
|
|
|
|
} |
1991
|
|
|
|
|
|
|
} |
1992
|
|
|
|
|
|
|
|
1993
|
13
|
100
|
|
|
|
26
|
if (@$re) { |
1994
|
5
|
|
|
|
|
6
|
$crit = 1; |
1995
|
5
|
|
|
|
|
6
|
foreach my $re (@$re) { |
1996
|
5
|
100
|
|
|
|
28
|
if ($nds =~ $re) { |
1997
|
2
|
|
|
|
|
6
|
$$ret{$path} = $nds; |
1998
|
2
|
|
|
|
|
10
|
return; |
1999
|
|
|
|
|
|
|
} |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
} |
2002
|
|
|
|
|
|
|
|
2003
|
11
|
100
|
|
|
|
35
|
return if ($crit); |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
# No criteria passed in |
2006
|
5
|
50
|
|
|
|
15
|
$$ret{$path} = $nds if (defined $nds); |
2007
|
5
|
|
|
|
|
18
|
return; |
2008
|
|
|
|
|
|
|
} |
2009
|
|
|
|
|
|
|
} |
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
############################################################################### |
2012
|
|
|
|
|
|
|
# PATHS |
2013
|
|
|
|
|
|
|
############################################################################### |
2014
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
sub paths { |
2016
|
16
|
|
|
16
|
1
|
3752
|
my($self,@args) = @_; |
2017
|
16
|
|
|
|
|
30
|
$$self{"err"} = ""; |
2018
|
16
|
|
|
|
|
21
|
$$self{"errmsg"} = ""; |
2019
|
16
|
50
|
|
|
|
35
|
@args = ("scalar") if (! @args); |
2020
|
|
|
|
|
|
|
|
2021
|
|
|
|
|
|
|
# Parse parameters |
2022
|
|
|
|
|
|
|
|
2023
|
16
|
|
|
|
|
18
|
my %tmp; |
2024
|
16
|
|
|
|
|
24
|
foreach my $arg (@args) { |
2025
|
31
|
100
|
100
|
|
|
224
|
if ($arg eq "scalar" || |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
2026
|
|
|
|
|
|
|
$arg eq "list" || |
2027
|
|
|
|
|
|
|
$arg eq "hash") { |
2028
|
16
|
100
|
33
|
|
|
99
|
if (exists $tmp{"scalar"} || |
|
|
|
66
|
|
|
|
|
2029
|
|
|
|
|
|
|
exists $tmp{"list"} || |
2030
|
|
|
|
|
|
|
exists $tmp{"hash"}) { |
2031
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndsdat07"; |
2032
|
1
|
|
|
|
|
5
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2033
|
|
|
|
|
|
|
"method: @args"; |
2034
|
1
|
|
|
|
|
51
|
return undef; |
2035
|
|
|
|
|
|
|
} |
2036
|
|
|
|
|
|
|
} elsif ($arg eq "uniform" || |
2037
|
|
|
|
|
|
|
$arg eq "nonuniform") { |
2038
|
7
|
50
|
33
|
|
|
34
|
if (exists $tmp{"uniform"} || |
2039
|
|
|
|
|
|
|
exists $tmp{"nonuniform"}) { |
2040
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsdat07"; |
2041
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2042
|
|
|
|
|
|
|
"method: @args"; |
2043
|
0
|
|
|
|
|
0
|
return undef; |
2044
|
|
|
|
|
|
|
} |
2045
|
|
|
|
|
|
|
} elsif ($arg eq "ordered" || |
2046
|
|
|
|
|
|
|
$arg eq "unordered") { |
2047
|
7
|
50
|
33
|
|
|
38
|
if (exists $tmp{"ordered"} || |
2048
|
|
|
|
|
|
|
exists $tmp{"unordered"}) { |
2049
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsdat07"; |
2050
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2051
|
|
|
|
|
|
|
"method: @args"; |
2052
|
0
|
|
|
|
|
0
|
return undef; |
2053
|
|
|
|
|
|
|
} |
2054
|
|
|
|
|
|
|
} else { |
2055
|
1
|
|
|
|
|
4
|
$$self{"err"} = "ndsdat08"; |
2056
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Invalid parameter in paths method: $arg"; |
2057
|
1
|
|
|
|
|
5
|
return undef; |
2058
|
|
|
|
|
|
|
} |
2059
|
29
|
|
|
|
|
66
|
$tmp{$arg} = 1; |
2060
|
|
|
|
|
|
|
} |
2061
|
|
|
|
|
|
|
|
2062
|
14
|
100
|
66
|
|
|
57
|
if (exists $tmp{"scalar"} && |
|
|
|
66
|
|
|
|
|
2063
|
|
|
|
|
|
|
(exists $tmp{"uniform"} || |
2064
|
|
|
|
|
|
|
exists $tmp{"nonuniform"} || |
2065
|
|
|
|
|
|
|
exists $tmp{"ordered"} || |
2066
|
|
|
|
|
|
|
exists $tmp{"unordered"})) { |
2067
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsdat07"; |
2068
|
1
|
|
|
|
|
6
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2069
|
|
|
|
|
|
|
"method: @args"; |
2070
|
1
|
|
|
|
|
4
|
return undef; |
2071
|
|
|
|
|
|
|
} |
2072
|
|
|
|
|
|
|
|
2073
|
13
|
100
|
66
|
|
|
42
|
if (exists $tmp{"hash"} && |
|
|
|
66
|
|
|
|
|
2074
|
|
|
|
|
|
|
(exists $tmp{"ordered"} || |
2075
|
|
|
|
|
|
|
exists $tmp{"unordered"})) { |
2076
|
1
|
|
|
|
|
2
|
$$self{"err"} = "ndsdat07"; |
2077
|
1
|
|
|
|
|
6
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2078
|
|
|
|
|
|
|
"method: @args"; |
2079
|
1
|
|
|
|
|
4
|
return undef; |
2080
|
|
|
|
|
|
|
} |
2081
|
|
|
|
|
|
|
|
2082
|
12
|
50
|
100
|
|
|
55
|
if (exists $tmp{"list"} && |
|
|
|
66
|
|
|
|
|
2083
|
|
|
|
|
|
|
exists $tmp{"unordered"} && |
2084
|
|
|
|
|
|
|
exists $tmp{"nonuniform"}) { |
2085
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndsdat07"; |
2086
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "Invalid parameter combination in paths " . |
2087
|
|
|
|
|
|
|
"method: @args"; |
2088
|
0
|
|
|
|
|
0
|
return undef; |
2089
|
|
|
|
|
|
|
} |
2090
|
|
|
|
|
|
|
|
2091
|
|
|
|
|
|
|
# Check which paths fit |
2092
|
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
|
2094
|
12
|
|
|
|
|
14
|
my @ret = sort(CORE::keys %{ $$self{"struct"} }); |
|
12
|
|
|
|
|
143
|
|
2095
|
|
|
|
|
|
|
|
2096
|
12
|
|
|
|
|
29
|
my $type = ""; |
2097
|
12
|
100
|
|
|
|
39
|
if (exists $tmp{"scalar"}) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2098
|
1
|
|
|
|
|
4
|
$type = "scalar"; |
2099
|
|
|
|
|
|
|
} elsif (exists $tmp{"list"}) { |
2100
|
8
|
|
|
|
|
10
|
$type = "list"; |
2101
|
|
|
|
|
|
|
} elsif (exists $tmp{"hash"}) { |
2102
|
3
|
|
|
|
|
5
|
$type = "hash"; |
2103
|
|
|
|
|
|
|
} |
2104
|
12
|
50
|
|
|
|
23
|
if ($type) { |
2105
|
12
|
|
|
|
|
13
|
my @tmp; |
2106
|
12
|
|
|
|
|
17
|
foreach my $path (@ret) { |
2107
|
216
|
100
|
|
|
|
495
|
push(@tmp,$path) if ($$self{"struct"}{$path}{"type"} eq $type); |
2108
|
|
|
|
|
|
|
} |
2109
|
12
|
|
|
|
|
44
|
@ret = @tmp; |
2110
|
|
|
|
|
|
|
} |
2111
|
|
|
|
|
|
|
|
2112
|
12
|
|
|
|
|
16
|
my $ordered = ""; |
2113
|
12
|
100
|
|
|
|
34
|
if (exists $tmp{"ordered"}) { |
|
|
100
|
|
|
|
|
|
2114
|
3
|
|
|
|
|
4
|
$ordered = 1; |
2115
|
|
|
|
|
|
|
} elsif (exists $tmp{"unordered"}) { |
2116
|
2
|
|
|
|
|
3
|
$ordered = 0; |
2117
|
|
|
|
|
|
|
} |
2118
|
12
|
100
|
|
|
|
25
|
if ($ordered ne "") { |
2119
|
5
|
|
|
|
|
5
|
my @tmp; |
2120
|
5
|
|
|
|
|
8
|
foreach my $path (@ret) { |
2121
|
15
|
100
|
66
|
|
|
77
|
push(@tmp,$path) if (exists $$self{"struct"}{$path}{"ordered"} && |
2122
|
|
|
|
|
|
|
$$self{"struct"}{$path}{"ordered"} == $ordered); |
2123
|
|
|
|
|
|
|
} |
2124
|
5
|
|
|
|
|
12
|
@ret = @tmp; |
2125
|
|
|
|
|
|
|
} |
2126
|
|
|
|
|
|
|
|
2127
|
12
|
|
|
|
|
15
|
my $uniform = ""; |
2128
|
12
|
100
|
|
|
|
29
|
if (exists $tmp{"uniform"}) { |
|
|
100
|
|
|
|
|
|
2129
|
4
|
|
|
|
|
6
|
$uniform = 1; |
2130
|
|
|
|
|
|
|
} elsif (exists $tmp{"nonuniform"}) { |
2131
|
3
|
|
|
|
|
5
|
$uniform = 0; |
2132
|
|
|
|
|
|
|
} |
2133
|
12
|
100
|
|
|
|
25
|
if ($uniform ne "") { |
2134
|
7
|
|
|
|
|
8
|
my @tmp; |
2135
|
7
|
|
|
|
|
9
|
foreach my $path (@ret) { |
2136
|
23
|
100
|
66
|
|
|
121
|
push(@tmp,$path) if (exists $$self{"struct"}{$path}{"uniform"} && |
2137
|
|
|
|
|
|
|
$$self{"struct"}{$path}{"uniform"} == $uniform); |
2138
|
|
|
|
|
|
|
} |
2139
|
7
|
|
|
|
|
20
|
@ret = @tmp; |
2140
|
|
|
|
|
|
|
} |
2141
|
|
|
|
|
|
|
|
2142
|
12
|
|
|
|
|
59
|
return @ret; |
2143
|
|
|
|
|
|
|
} |
2144
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
############################################################################### |
2146
|
|
|
|
|
|
|
# TEST_CONDITIONS |
2147
|
|
|
|
|
|
|
############################################################################### |
2148
|
|
|
|
|
|
|
|
2149
|
|
|
|
|
|
|
sub test_conditions { |
2150
|
1181
|
|
|
1181
|
1
|
28101
|
my($self,$nds,@cond) = @_; |
2151
|
1181
|
|
|
|
|
1957
|
$$self{"err"} = ""; |
2152
|
1181
|
|
|
|
|
1820
|
$$self{"errmsg"} = ""; |
2153
|
1181
|
100
|
|
|
|
2600
|
return 1 if (! @cond); |
2154
|
|
|
|
|
|
|
|
2155
|
1165
|
|
|
|
|
2384
|
COND: while (@cond) { |
2156
|
1165
|
|
|
|
|
1848
|
my $path = shift(@cond); |
2157
|
1165
|
|
|
|
|
1531
|
my $cond = shift(@cond); |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
# Get the value at the path. An error code means that the path |
2160
|
|
|
|
|
|
|
# is not defined (but the path is valid in the sense that it COULD |
2161
|
|
|
|
|
|
|
# be there... it just doesn't exist in this NDS). |
2162
|
|
|
|
|
|
|
|
2163
|
1165
|
|
|
|
|
2722
|
my $v = $self->value($nds,$path,0,1); |
2164
|
1165
|
100
|
|
|
|
2303
|
if ($self->err()) { |
2165
|
208
|
|
|
|
|
368
|
$$self{"err"} = ""; |
2166
|
208
|
|
|
|
|
381
|
$$self{"errmsg"} = ""; |
2167
|
208
|
|
|
|
|
268
|
$v = undef; |
2168
|
|
|
|
|
|
|
} |
2169
|
|
|
|
|
|
|
|
2170
|
1165
|
100
|
|
|
|
3475
|
if (! defined $v) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2171
|
|
|
|
|
|
|
# no path does NOT automatically mean failure... worse, we |
2172
|
|
|
|
|
|
|
# can't tell whether it should be tested as a hash, list, or |
2173
|
|
|
|
|
|
|
# scalar |
2174
|
356
|
|
|
|
|
758
|
my($valid,$pass) = _test_hash_condition($self,$v,$cond); |
2175
|
356
|
100
|
|
|
|
689
|
if ($valid) { |
2176
|
152
|
100
|
|
|
|
602
|
return 0 if (! $pass); |
2177
|
|
|
|
|
|
|
} else { |
2178
|
204
|
100
|
66
|
|
|
466
|
return 0 if (! _test_list_condition($self,$v,$cond) && |
2179
|
|
|
|
|
|
|
! _test_scalar_condition($self,$v,$cond)); |
2180
|
|
|
|
|
|
|
} |
2181
|
|
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
} elsif (ref($v) eq "HASH") { |
2183
|
79
|
|
|
|
|
163
|
my($valid,$pass) = _test_hash_condition($self,$v,$cond); |
2184
|
79
|
100
|
|
|
|
166
|
if ($valid) { |
2185
|
78
|
100
|
|
|
|
317
|
return 0 if (! $pass); |
2186
|
|
|
|
|
|
|
} else { |
2187
|
|
|
|
|
|
|
# Set error (invalid condition) |
2188
|
1
|
|
|
|
|
3
|
$$self{"err"} = "ndscon01"; |
2189
|
1
|
|
|
|
|
4
|
$$self{"errmsg"} = "Invalid test condition used: $path: $cond"; |
2190
|
1
|
|
|
|
|
4
|
return undef; |
2191
|
|
|
|
|
|
|
} |
2192
|
|
|
|
|
|
|
|
2193
|
|
|
|
|
|
|
} elsif (ref($v) eq "ARRAY") { |
2194
|
348
|
100
|
|
|
|
1079
|
return 0 if (! _test_list_condition($self,$v,$cond)); |
2195
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
} else { |
2197
|
382
|
100
|
|
|
|
887
|
return 0 if (! _test_scalar_condition($self,$v,$cond)); |
2198
|
|
|
|
|
|
|
} |
2199
|
|
|
|
|
|
|
} |
2200
|
|
|
|
|
|
|
|
2201
|
564
|
|
|
|
|
1702
|
return 1; |
2202
|
|
|
|
|
|
|
} |
2203
|
|
|
|
|
|
|
|
2204
|
|
|
|
|
|
|
# If $nds contains a hash, condition can be any of the following: |
2205
|
|
|
|
|
|
|
# |
2206
|
|
|
|
|
|
|
# exists:VAL : true if a key named VAL exists in the hash |
2207
|
|
|
|
|
|
|
# empty:VAL : true if a key named VAL is empty in the hash (it |
2208
|
|
|
|
|
|
|
# doesn't exist, or has an empty value) |
2209
|
|
|
|
|
|
|
# empty : true if the hash is empty |
2210
|
|
|
|
|
|
|
# |
2211
|
|
|
|
|
|
|
sub _test_hash_condition { |
2212
|
435
|
|
|
435
|
|
659
|
my($self,$nds,$cond) = @_; |
2213
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
# Make sure it's a valid condition for this data type. |
2215
|
|
|
|
|
|
|
|
2216
|
435
|
100
|
66
|
|
|
2543
|
if ($cond !~ /^\!?empty(:.+)?$/i && |
2217
|
|
|
|
|
|
|
$cond !~ /^\!?exists:.+$/i) { |
2218
|
205
|
|
|
|
|
525
|
return (0,0); |
2219
|
|
|
|
|
|
|
} |
2220
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
# An undefined value: |
2222
|
|
|
|
|
|
|
# passes empty |
2223
|
|
|
|
|
|
|
# passes empty:VAL |
2224
|
|
|
|
|
|
|
# passes !exists:VAL |
2225
|
|
|
|
|
|
|
# fails all others |
2226
|
|
|
|
|
|
|
|
2227
|
230
|
100
|
|
|
|
523
|
if (! defined $nds) { |
2228
|
152
|
100
|
100
|
|
|
812
|
return (1,1) if ($cond =~ /^empty/i || |
2229
|
|
|
|
|
|
|
$cond =~ /^\!exists/i); |
2230
|
76
|
|
|
|
|
175
|
return (1,0); |
2231
|
|
|
|
|
|
|
} |
2232
|
|
|
|
|
|
|
|
2233
|
|
|
|
|
|
|
# A non-hash element should not even be passed in. |
2234
|
|
|
|
|
|
|
|
2235
|
78
|
50
|
|
|
|
196
|
if (ref($nds) ne "HASH") { |
2236
|
0
|
|
|
|
|
0
|
die "ERROR: [_test_hash_condition] impossible: non-hash passed in\n"; |
2237
|
|
|
|
|
|
|
} |
2238
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
# Test for existance of a key or an empty key |
2240
|
|
|
|
|
|
|
|
2241
|
78
|
100
|
|
|
|
300
|
if ($cond =~ /^(\!?)(exists|empty):(.+)$/) { |
2242
|
56
|
|
|
|
|
204
|
my ($not,$op,$key) = ($1,$2,$3); |
2243
|
56
|
|
|
|
|
104
|
my $exists = (exists $$nds{$key}); |
2244
|
|
|
|
|
|
|
|
2245
|
56
|
100
|
|
|
|
142
|
if (lc($op) eq "exists") { |
2246
|
28
|
100
|
100
|
|
|
224
|
return (1,1) if ( ($exists && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2247
|
|
|
|
|
|
|
(! $exists && $not) ); |
2248
|
14
|
|
|
|
|
41
|
return (1,0); |
2249
|
|
|
|
|
|
|
} |
2250
|
|
|
|
|
|
|
|
2251
|
28
|
|
|
|
|
38
|
my $empty = 1; |
2252
|
28
|
100
|
|
|
|
127
|
$empty = $self->empty([ $$nds{$key} ]) if ($exists); |
2253
|
|
|
|
|
|
|
|
2254
|
28
|
100
|
100
|
|
|
232
|
return (1,1) if ( ($empty && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2255
|
|
|
|
|
|
|
(! $empty && $not) ); |
2256
|
14
|
|
|
|
|
37
|
return (1,0); |
2257
|
|
|
|
|
|
|
} |
2258
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
# An empty value: |
2260
|
|
|
|
|
|
|
# passes empty |
2261
|
|
|
|
|
|
|
# fails !empty |
2262
|
|
|
|
|
|
|
# A non-empty value: |
2263
|
|
|
|
|
|
|
# fails empty |
2264
|
|
|
|
|
|
|
# passes !empty |
2265
|
|
|
|
|
|
|
|
2266
|
22
|
|
|
|
|
45
|
$cond = lc($cond); |
2267
|
22
|
100
|
|
|
|
53
|
if ($self->empty($nds)) { |
2268
|
10
|
100
|
|
|
|
39
|
return (1,1) if ($cond eq "empty"); |
2269
|
5
|
50
|
|
|
|
39
|
return (1,0) if ($cond eq "!empty"); |
2270
|
|
|
|
|
|
|
} else { |
2271
|
12
|
100
|
|
|
|
45
|
return (1,0) if ($cond eq "empty"); |
2272
|
6
|
50
|
|
|
|
31
|
return (1,1) if ($cond eq "!empty"); |
2273
|
|
|
|
|
|
|
} |
2274
|
|
|
|
|
|
|
} |
2275
|
|
|
|
|
|
|
|
2276
|
|
|
|
|
|
|
# If $path refers to a list, conditions may be any of the following: |
2277
|
|
|
|
|
|
|
# |
2278
|
|
|
|
|
|
|
# empty : true if the list is empty |
2279
|
|
|
|
|
|
|
# defined:VAL : true if the VAL'th (VAL is an integer) element |
2280
|
|
|
|
|
|
|
# is defined |
2281
|
|
|
|
|
|
|
# empty:VAL : true if the VAL'th (VAL is an integer) element |
2282
|
|
|
|
|
|
|
# is empty (or not defined) |
2283
|
|
|
|
|
|
|
# contains:VAL : true if the list contains the element VAL |
2284
|
|
|
|
|
|
|
# <:VAL : true if the list has fewer than VAL (an integer) |
2285
|
|
|
|
|
|
|
# non-empty elements |
2286
|
|
|
|
|
|
|
# <=:VAL |
2287
|
|
|
|
|
|
|
# =:VAL |
2288
|
|
|
|
|
|
|
# >:VAL |
2289
|
|
|
|
|
|
|
# >=:VAL |
2290
|
|
|
|
|
|
|
# VAL : equivalent to contains:VAL |
2291
|
|
|
|
|
|
|
# |
2292
|
|
|
|
|
|
|
sub _test_list_condition { |
2293
|
552
|
|
|
552
|
|
910
|
my($self,$nds,$cond) = @_; |
2294
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
# An undefined value: |
2296
|
|
|
|
|
|
|
# passes empty |
2297
|
|
|
|
|
|
|
# passes empty:VAL |
2298
|
|
|
|
|
|
|
# passes !defined:VAL |
2299
|
|
|
|
|
|
|
# passes !contains:VAL |
2300
|
|
|
|
|
|
|
# passes =:0 |
2301
|
|
|
|
|
|
|
# passes !=:* (not zero) |
2302
|
|
|
|
|
|
|
# passes <:* |
2303
|
|
|
|
|
|
|
# passes <=:* |
2304
|
|
|
|
|
|
|
# passes >=:0 |
2305
|
|
|
|
|
|
|
# fails all others |
2306
|
|
|
|
|
|
|
|
2307
|
552
|
100
|
|
|
|
1095
|
if (! defined($nds)) { |
2308
|
204
|
100
|
66
|
|
|
3827
|
return 1 if ($cond =~ /^empty(:.+)?$/i || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2309
|
|
|
|
|
|
|
$cond =~ /^\!defined:(.+)$/i || |
2310
|
|
|
|
|
|
|
$cond =~ /^\!contains:(.+)$/i || |
2311
|
|
|
|
|
|
|
$cond eq "=:0" || |
2312
|
|
|
|
|
|
|
$cond =~ /^\!=:(\d*[1-9]\d*)$/ || |
2313
|
|
|
|
|
|
|
$cond =~ /^<:(\d+)$/ || |
2314
|
|
|
|
|
|
|
$cond =~ /^<=:(\d+)$/ || |
2315
|
|
|
|
|
|
|
$cond eq ">=:0"); |
2316
|
148
|
|
|
|
|
699
|
return 0; |
2317
|
|
|
|
|
|
|
} |
2318
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
# A non-list element should not even be passed in. |
2320
|
|
|
|
|
|
|
|
2321
|
348
|
50
|
|
|
|
745
|
if (ref($nds) ne "ARRAY") { |
2322
|
0
|
|
|
|
|
0
|
die "ERROR: [_test_list_condition] impossible: non-list passed in\n"; |
2323
|
|
|
|
|
|
|
} |
2324
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
# Test for defined/empty keys |
2326
|
|
|
|
|
|
|
|
2327
|
348
|
100
|
|
|
|
1144
|
if ($cond =~ /^(\!?)(defined|empty):(\d+)$/i) { |
2328
|
112
|
|
|
|
|
325
|
my ($not,$op,$i) = ($1,$2,$3); |
2329
|
112
|
|
|
|
|
285
|
my $def = (defined $$nds[$i]); |
2330
|
|
|
|
|
|
|
|
2331
|
112
|
100
|
|
|
|
256
|
if (lc($op) eq "defined") { |
2332
|
72
|
100
|
100
|
|
|
564
|
return 1 if ( ($def && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2333
|
|
|
|
|
|
|
(! $def && $not) ); |
2334
|
36
|
|
|
|
|
198
|
return 0; |
2335
|
|
|
|
|
|
|
} |
2336
|
|
|
|
|
|
|
|
2337
|
40
|
|
|
|
|
60
|
my $empty = 1; |
2338
|
40
|
100
|
|
|
|
143
|
$empty = $self->empty([ $$nds[$i] ]) if ($def); |
2339
|
|
|
|
|
|
|
|
2340
|
40
|
100
|
100
|
|
|
354
|
return 1 if ( ($empty && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2341
|
|
|
|
|
|
|
(! $empty && $not) ); |
2342
|
20
|
|
|
|
|
103
|
return 0; |
2343
|
|
|
|
|
|
|
} |
2344
|
|
|
|
|
|
|
|
2345
|
|
|
|
|
|
|
# < <= = > >= tests |
2346
|
|
|
|
|
|
|
|
2347
|
236
|
100
|
|
|
|
844
|
if ($cond =~ /^(\!?)(<=|<|=|>=|>):(\d+)$/) { |
2348
|
126
|
|
|
|
|
362
|
my($not,$op,$val) = ($1,$2,$3); |
2349
|
126
|
|
|
|
|
156
|
my $n = 0; |
2350
|
126
|
|
|
|
|
204
|
foreach my $v (@$nds) { |
2351
|
224
|
100
|
|
|
|
793
|
$n++ if (! $self->empty([ $v ])); |
2352
|
|
|
|
|
|
|
} |
2353
|
|
|
|
|
|
|
|
2354
|
126
|
100
|
|
|
|
370
|
if ($op eq "<") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2355
|
38
|
100
|
100
|
|
|
337
|
return 1 if ( ($n < $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2356
|
|
|
|
|
|
|
($n >= $val && $not) ); |
2357
|
19
|
|
|
|
|
100
|
return 0; |
2358
|
|
|
|
|
|
|
|
2359
|
|
|
|
|
|
|
} elsif ($op eq "<=") { |
2360
|
38
|
100
|
100
|
|
|
344
|
return 1 if ( ($n <= $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2361
|
|
|
|
|
|
|
($n > $val && $not) ); |
2362
|
19
|
|
|
|
|
106
|
return 0; |
2363
|
|
|
|
|
|
|
|
2364
|
|
|
|
|
|
|
} elsif ($op eq "=") { |
2365
|
36
|
100
|
100
|
|
|
375
|
return 1 if ( ($n == $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2366
|
|
|
|
|
|
|
($n != $val && $not) ); |
2367
|
18
|
|
|
|
|
94
|
return 0; |
2368
|
|
|
|
|
|
|
|
2369
|
|
|
|
|
|
|
} elsif ($op eq ">=") { |
2370
|
8
|
100
|
100
|
|
|
65
|
return 1 if ( ($n >= $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2371
|
|
|
|
|
|
|
($n < $val && $not) ); |
2372
|
4
|
|
|
|
|
15
|
return 0; |
2373
|
|
|
|
|
|
|
|
2374
|
|
|
|
|
|
|
} else { |
2375
|
6
|
100
|
100
|
|
|
48
|
return 1 if ( ($n > $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2376
|
|
|
|
|
|
|
($n <= $val && $not) ); |
2377
|
3
|
|
|
|
|
13
|
return 0; |
2378
|
|
|
|
|
|
|
} |
2379
|
|
|
|
|
|
|
} |
2380
|
|
|
|
|
|
|
|
2381
|
|
|
|
|
|
|
# contains condition |
2382
|
|
|
|
|
|
|
|
2383
|
110
|
100
|
|
|
|
394
|
if ($cond =~ /^(\!?)contains:(.*)$/i) { |
2384
|
68
|
|
|
|
|
191
|
my($not,$val) = ($1,$2); |
2385
|
68
|
50
|
|
|
|
148
|
$val = "" if (! defined $val); |
2386
|
68
|
|
|
|
|
122
|
foreach my $v (@$nds) { |
2387
|
142
|
100
|
|
|
|
277
|
next if (! defined $v); |
2388
|
118
|
100
|
|
|
|
279
|
if ($v eq $val) { |
2389
|
26
|
100
|
|
|
|
113
|
return 1 if (! $not); |
2390
|
13
|
50
|
|
|
|
95
|
return 0 if ($not); |
2391
|
|
|
|
|
|
|
} |
2392
|
|
|
|
|
|
|
} |
2393
|
42
|
100
|
|
|
|
188
|
return 0 if (! $not); |
2394
|
21
|
|
|
|
|
103
|
return 1; |
2395
|
|
|
|
|
|
|
} |
2396
|
|
|
|
|
|
|
|
2397
|
|
|
|
|
|
|
# An empty list: |
2398
|
|
|
|
|
|
|
# passes empty |
2399
|
|
|
|
|
|
|
# fails !empty |
2400
|
|
|
|
|
|
|
# A non-empty list: |
2401
|
|
|
|
|
|
|
# fails empty |
2402
|
|
|
|
|
|
|
# passes !empty |
2403
|
|
|
|
|
|
|
|
2404
|
42
|
|
|
|
|
70
|
my $c = lc($cond); |
2405
|
42
|
100
|
|
|
|
122
|
if ($self->empty([ $nds ])) { |
2406
|
12
|
100
|
|
|
|
66
|
return 1 if ($c eq "empty"); |
2407
|
6
|
50
|
|
|
|
47
|
return 0 if ($c eq "!empty"); |
2408
|
|
|
|
|
|
|
} else { |
2409
|
30
|
100
|
|
|
|
134
|
return 0 if ($c eq "empty"); |
2410
|
17
|
100
|
|
|
|
99
|
return 1 if ($c eq "!empty"); |
2411
|
|
|
|
|
|
|
} |
2412
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
# VAL test |
2414
|
|
|
|
|
|
|
|
2415
|
4
|
|
|
|
|
6
|
my $not = 0; |
2416
|
4
|
100
|
|
|
|
16
|
$not = 1 if ($cond =~ s/^\!//); |
2417
|
|
|
|
|
|
|
|
2418
|
4
|
|
|
|
|
7
|
foreach my $v (@$nds) { |
2419
|
6
|
50
|
|
|
|
10
|
next if (! defined $v); |
2420
|
6
|
100
|
|
|
|
13
|
if ($v eq $cond) { |
2421
|
2
|
100
|
|
|
|
65
|
return 1 if (! $not); |
2422
|
1
|
50
|
|
|
|
7
|
return 0 if ($not); |
2423
|
|
|
|
|
|
|
} |
2424
|
|
|
|
|
|
|
} |
2425
|
2
|
100
|
|
|
|
11
|
return 0 if (! $not); |
2426
|
1
|
|
|
|
|
5
|
return 1; |
2427
|
|
|
|
|
|
|
} |
2428
|
|
|
|
|
|
|
|
2429
|
|
|
|
|
|
|
# If $path refers to a scalar, conditions may be any of the following: |
2430
|
|
|
|
|
|
|
# |
2431
|
|
|
|
|
|
|
# defined : true if the value is not defined |
2432
|
|
|
|
|
|
|
# empty : true if the value is empty |
2433
|
|
|
|
|
|
|
# zero : true if the value defined and evaluates to 0 |
2434
|
|
|
|
|
|
|
# true : true if the value defined and evaluates to true |
2435
|
|
|
|
|
|
|
# =:VAL : true if the the value is VAL |
2436
|
|
|
|
|
|
|
# member:VAL:VAL:... |
2437
|
|
|
|
|
|
|
# : true if the value is any of the values given (in |
2438
|
|
|
|
|
|
|
# this case, ALL of the colons (including the first |
2439
|
|
|
|
|
|
|
# one) can be replace by any other single character |
2440
|
|
|
|
|
|
|
# separator |
2441
|
|
|
|
|
|
|
# VAL : true if the value is equal to VAL |
2442
|
|
|
|
|
|
|
# |
2443
|
|
|
|
|
|
|
sub _test_scalar_condition { |
2444
|
530
|
|
|
530
|
|
838
|
my($self,$nds,$cond) = @_; |
2445
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
# An undefined value |
2447
|
|
|
|
|
|
|
# passes !defined |
2448
|
|
|
|
|
|
|
# passes !zero |
2449
|
|
|
|
|
|
|
# passes !true |
2450
|
|
|
|
|
|
|
# passes empty |
2451
|
|
|
|
|
|
|
# passes !=:* |
2452
|
|
|
|
|
|
|
# passes !member:* |
2453
|
|
|
|
|
|
|
# fails all others |
2454
|
|
|
|
|
|
|
|
2455
|
530
|
100
|
|
|
|
1055
|
if (! defined $nds) { |
2456
|
148
|
100
|
66
|
|
|
2360
|
return 1 if ($cond =~ /^!defined$/i || |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
2457
|
|
|
|
|
|
|
$cond =~ /^empty$/i || |
2458
|
|
|
|
|
|
|
$cond =~ /^\!zero$/i || |
2459
|
|
|
|
|
|
|
$cond =~ /^\!true$/i || |
2460
|
|
|
|
|
|
|
$cond =~ /^\!=:/ || |
2461
|
|
|
|
|
|
|
$cond =~ /^\!member/i); |
2462
|
113
|
|
|
|
|
657
|
return 0; |
2463
|
|
|
|
|
|
|
} |
2464
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
# A non-scalar element should not even be passed in. |
2466
|
|
|
|
|
|
|
|
2467
|
382
|
50
|
|
|
|
702
|
if (ref($nds)) { |
2468
|
0
|
|
|
|
|
0
|
die "ERROR: [_test_scalar_condition] impossible: non-scalar passed in\n"; |
2469
|
|
|
|
|
|
|
} |
2470
|
|
|
|
|
|
|
|
2471
|
|
|
|
|
|
|
# A defined value |
2472
|
|
|
|
|
|
|
# passes defined |
2473
|
|
|
|
|
|
|
# fails ! defined |
2474
|
|
|
|
|
|
|
|
2475
|
382
|
|
|
|
|
617
|
my($c) = lc($cond); |
2476
|
382
|
100
|
|
|
|
789
|
return 1 if ($c eq "defined"); |
2477
|
363
|
100
|
|
|
|
896
|
return 0 if ($c eq "!defined"); |
2478
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
# An empty value (must pass it as a structure, NOT a scalar) |
2480
|
|
|
|
|
|
|
# passes empty |
2481
|
|
|
|
|
|
|
# fails !empty |
2482
|
|
|
|
|
|
|
# A non-empty value |
2483
|
|
|
|
|
|
|
# passes !empty |
2484
|
|
|
|
|
|
|
# fails empty |
2485
|
|
|
|
|
|
|
|
2486
|
344
|
100
|
|
|
|
1004
|
if ($self->empty([$nds])) { |
2487
|
38
|
100
|
|
|
|
115
|
return 1 if ($c eq "empty"); |
2488
|
33
|
100
|
|
|
|
110
|
return 0 if ($c eq "!empty"); |
2489
|
|
|
|
|
|
|
} else { |
2490
|
306
|
100
|
|
|
|
666
|
return 0 if ($c eq "empty"); |
2491
|
292
|
100
|
|
|
|
647
|
return 1 if ($c eq "!empty"); |
2492
|
|
|
|
|
|
|
} |
2493
|
|
|
|
|
|
|
|
2494
|
306
|
50
|
|
|
|
808
|
$nds = "" if (! defined $nds); |
2495
|
|
|
|
|
|
|
|
2496
|
|
|
|
|
|
|
# zero and true tests |
2497
|
|
|
|
|
|
|
|
2498
|
306
|
100
|
|
|
|
1219
|
if ($c eq "zero") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2499
|
3
|
100
|
100
|
|
|
22
|
return 1 if ($nds eq "" || $nds == 0); |
2500
|
1
|
|
|
|
|
6
|
return 0; |
2501
|
|
|
|
|
|
|
} elsif ($c eq "!zero") { |
2502
|
3
|
100
|
100
|
|
|
21
|
return 0 if ($nds eq "" || $nds == 0); |
2503
|
1
|
|
|
|
|
6
|
return 1; |
2504
|
|
|
|
|
|
|
} elsif ($c eq "true") { |
2505
|
3
|
100
|
|
|
|
9
|
return 1 if ($nds); |
2506
|
2
|
|
|
|
|
11
|
return 0; |
2507
|
|
|
|
|
|
|
} elsif ($c eq "!true") { |
2508
|
3
|
100
|
|
|
|
11
|
return 0 if ($nds); |
2509
|
2
|
|
|
|
|
11
|
return 1; |
2510
|
|
|
|
|
|
|
} |
2511
|
|
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
# = test |
2513
|
|
|
|
|
|
|
|
2514
|
294
|
100
|
|
|
|
748
|
if ($cond =~ /^(\!?)=:(.*)/) { |
2515
|
38
|
|
|
|
|
116
|
my($not,$val) = ($1,$2); |
2516
|
38
|
50
|
|
|
|
77
|
$val = "" if (! defined $val); |
2517
|
38
|
100
|
100
|
|
|
352
|
return 1 if ( ($nds eq $val && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2518
|
|
|
|
|
|
|
($nds ne $val && $not) ); |
2519
|
19
|
|
|
|
|
100
|
return 0; |
2520
|
|
|
|
|
|
|
} |
2521
|
|
|
|
|
|
|
|
2522
|
|
|
|
|
|
|
# member test |
2523
|
|
|
|
|
|
|
|
2524
|
256
|
100
|
|
|
|
701
|
if ($cond =~ /^(\!?)member(.)(.+)$/) { |
2525
|
72
|
|
|
|
|
222
|
my($not,$sep,$vals) = ($1,$2,$3); |
2526
|
72
|
50
|
|
|
|
488
|
my %tmp = map { (defined $_ ? $_ : ""),1 } split(/\Q$sep\E/,$vals); |
|
116
|
|
|
|
|
507
|
|
2527
|
72
|
100
|
100
|
|
|
932
|
return 1 if ( (exists $tmp{$nds} && ! $not) || |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2528
|
|
|
|
|
|
|
(! exists $tmp{$nds} && $not) ); |
2529
|
36
|
|
|
|
|
217
|
return 0; |
2530
|
|
|
|
|
|
|
} |
2531
|
|
|
|
|
|
|
|
2532
|
|
|
|
|
|
|
# VAL test |
2533
|
|
|
|
|
|
|
|
2534
|
184
|
100
|
|
|
|
462
|
if ($cond =~ s/^\!//) { |
2535
|
3
|
100
|
|
|
|
14
|
return 0 if ($nds eq $cond); |
2536
|
1
|
|
|
|
|
6
|
return 1; |
2537
|
|
|
|
|
|
|
} |
2538
|
|
|
|
|
|
|
|
2539
|
181
|
100
|
|
|
|
648
|
return 1 if ($nds eq $cond); |
2540
|
97
|
|
|
|
|
695
|
return 0; |
2541
|
|
|
|
|
|
|
} |
2542
|
|
|
|
|
|
|
|
2543
|
|
|
|
|
|
|
############################################################################### |
2544
|
|
|
|
|
|
|
# IDENTICAL, CONTAINS |
2545
|
|
|
|
|
|
|
############################################################################### |
2546
|
|
|
|
|
|
|
|
2547
|
|
|
|
|
|
|
sub identical { |
2548
|
10
|
|
|
10
|
1
|
2647
|
my($self,@args) = @_; |
2549
|
10
|
|
|
|
|
32
|
$$self{"err"} = ""; |
2550
|
10
|
|
|
|
|
28
|
$$self{"errmsg"} = ""; |
2551
|
|
|
|
|
|
|
|
2552
|
10
|
|
|
|
|
35
|
my($nds1,$nds2,$path) = _ic_args($self,@args); |
2553
|
10
|
50
|
|
|
|
24
|
return if ($self->err()); |
2554
|
|
|
|
|
|
|
|
2555
|
10
|
|
|
|
|
41
|
_DBG_begin("Identical"); |
2556
|
|
|
|
|
|
|
|
2557
|
10
|
|
|
|
|
37
|
my $flag = _identical_contains($self,$nds1,$nds2,1,$path); |
2558
|
|
|
|
|
|
|
|
2559
|
10
|
|
|
|
|
32
|
_DBG_end($flag); |
2560
|
10
|
|
|
|
|
103
|
return $flag; |
2561
|
|
|
|
|
|
|
} |
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
sub contains { |
2564
|
10
|
|
|
10
|
1
|
91
|
my($self,@args) = @_; |
2565
|
10
|
|
|
|
|
28
|
$$self{"err"} = ""; |
2566
|
10
|
|
|
|
|
25
|
$$self{"errmsg"} = ""; |
2567
|
|
|
|
|
|
|
|
2568
|
10
|
|
|
|
|
35
|
my($nds1,$nds2,$path) = _ic_args($self,@args); |
2569
|
10
|
50
|
|
|
|
22
|
return if ($self->err()); |
2570
|
|
|
|
|
|
|
|
2571
|
10
|
|
|
|
|
38
|
_DBG_begin("Contains"); |
2572
|
|
|
|
|
|
|
|
2573
|
10
|
|
|
|
|
31
|
my $flag = _identical_contains($self,$nds1,$nds2,0,$path); |
2574
|
|
|
|
|
|
|
|
2575
|
10
|
|
|
|
|
34
|
_DBG_end($flag); |
2576
|
10
|
|
|
|
|
71
|
return $flag; |
2577
|
|
|
|
|
|
|
} |
2578
|
|
|
|
|
|
|
|
2579
|
|
|
|
|
|
|
sub _ic_args { |
2580
|
20
|
|
|
20
|
|
73
|
my($self,$nds1,$nds2,@args) = @_; |
2581
|
|
|
|
|
|
|
|
2582
|
|
|
|
|
|
|
# |
2583
|
|
|
|
|
|
|
# Parse $new and $path |
2584
|
|
|
|
|
|
|
# |
2585
|
|
|
|
|
|
|
|
2586
|
20
|
|
|
|
|
32
|
my($new,$path); |
2587
|
20
|
50
|
|
|
|
79
|
if (! @args) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2588
|
0
|
|
|
|
|
0
|
$new = 0; |
2589
|
0
|
|
|
|
|
0
|
$path = ""; |
2590
|
|
|
|
|
|
|
} elsif ($#args == 0) { |
2591
|
20
|
50
|
33
|
|
|
113
|
if ($args[0] eq "0" || $args[0] eq "1") { |
2592
|
0
|
|
|
|
|
0
|
$new = $args[0]; |
2593
|
0
|
|
|
|
|
0
|
$path = ""; |
2594
|
|
|
|
|
|
|
} else { |
2595
|
20
|
|
|
|
|
30
|
$new = 0; |
2596
|
20
|
|
|
|
|
33
|
$path = $args[0]; |
2597
|
|
|
|
|
|
|
} |
2598
|
|
|
|
|
|
|
} elsif ($#args == 1) { |
2599
|
0
|
|
|
|
|
0
|
$new = $args[0]; |
2600
|
0
|
|
|
|
|
0
|
$path = $args[1]; |
2601
|
|
|
|
|
|
|
} else { |
2602
|
0
|
|
|
|
|
0
|
die "[identical/contains] invalid arguments"; |
2603
|
|
|
|
|
|
|
} |
2604
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
# |
2606
|
|
|
|
|
|
|
# Check the two NDSes for validity, and return them as refs. |
2607
|
|
|
|
|
|
|
# |
2608
|
|
|
|
|
|
|
|
2609
|
20
|
|
|
|
|
61
|
$nds1 = _nds($self,$nds1,$new,0,0); |
2610
|
20
|
50
|
|
|
|
61
|
if ($self->err()) { |
2611
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndside01"; |
2612
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The first NDS is invalid: $nds1"; |
2613
|
0
|
|
|
|
|
0
|
return; |
2614
|
|
|
|
|
|
|
} |
2615
|
20
|
|
|
|
|
85
|
$nds2 = _nds($self,$nds2,$new,0,0); |
2616
|
20
|
50
|
|
|
|
187
|
if ($self->err()) { |
2617
|
0
|
|
|
|
|
0
|
$$self{"err"} = "ndside02"; |
2618
|
0
|
|
|
|
|
0
|
$$self{"errmsg"} = "The first NDS is invalid: $nds2"; |
2619
|
0
|
|
|
|
|
0
|
return; |
2620
|
|
|
|
|
|
|
} |
2621
|
|
|
|
|
|
|
|
2622
|
20
|
|
|
|
|
64
|
return ($nds1,$nds2,$path); |
2623
|
|
|
|
|
|
|
} |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
sub _identical_contains { |
2626
|
20
|
|
|
20
|
|
41
|
my($self,$nds1,$nds2,$identical,$path) = @_; |
2627
|
20
|
|
|
|
|
47
|
_DBG_enter("_identical_contains"); |
2628
|
|
|
|
|
|
|
|
2629
|
|
|
|
|
|
|
# |
2630
|
|
|
|
|
|
|
# Handle $path |
2631
|
|
|
|
|
|
|
# |
2632
|
|
|
|
|
|
|
|
2633
|
20
|
|
|
|
|
45
|
$path = $self->path($path); |
2634
|
20
|
|
|
|
|
46
|
my @path = $self->path($path); |
2635
|
|
|
|
|
|
|
|
2636
|
|
|
|
|
|
|
# |
2637
|
|
|
|
|
|
|
# We will now recurse through the data structure and get an |
2638
|
|
|
|
|
|
|
# mpath description. |
2639
|
|
|
|
|
|
|
# |
2640
|
|
|
|
|
|
|
# An mpath description will be stored as: |
2641
|
|
|
|
|
|
|
# %desc = ( MPATH => DESC ) |
2642
|
|
|
|
|
|
|
# |
2643
|
|
|
|
|
|
|
# An MPATH is related to a PATH, except that every path element that |
2644
|
|
|
|
|
|
|
# contains an index for an unordered list is transformed to illustrate |
2645
|
|
|
|
|
|
|
# this. For example, for the path: |
2646
|
|
|
|
|
|
|
# /foo/1/bar/2 |
2647
|
|
|
|
|
|
|
# the mpath is: |
2648
|
|
|
|
|
|
|
# /foo/_ul_1/bar/_ul_2 |
2649
|
|
|
|
|
|
|
# (assuming that the 2nd and 4th elements are indices in unorderd |
2650
|
|
|
|
|
|
|
# lists). |
2651
|
|
|
|
|
|
|
# |
2652
|
|
|
|
|
|
|
|
2653
|
20
|
|
|
|
|
31
|
my(%desc1,%desc2); |
2654
|
20
|
50
|
|
|
|
52
|
if ($path ne "/") { |
2655
|
20
|
|
|
|
|
69
|
$nds1 = $self->value($nds1,$path); |
2656
|
20
|
|
|
|
|
62
|
$nds2 = $self->value($nds2,$path); |
2657
|
|
|
|
|
|
|
} |
2658
|
20
|
|
|
|
|
117
|
_ic_desc($self,$nds1,\%desc1,[@path],[@path],0,$self->delim()); |
2659
|
20
|
|
|
|
|
109
|
_ic_desc($self,$nds2,\%desc2,[@path],[@path],0,$self->delim()); |
2660
|
|
|
|
|
|
|
|
2661
|
|
|
|
|
|
|
# |
2662
|
|
|
|
|
|
|
# Now check these description hashes to see if they are identical |
2663
|
|
|
|
|
|
|
# (or contained). This is done recusively. |
2664
|
|
|
|
|
|
|
# |
2665
|
|
|
|
|
|
|
|
2666
|
20
|
|
|
|
|
92
|
my $flag = _ic_compare($self,\%desc1,\%desc2,$identical,$self->delim()); |
2667
|
20
|
|
|
|
|
52
|
_DBG_leave($flag); |
2668
|
20
|
|
|
|
|
244
|
return $flag; |
2669
|
|
|
|
|
|
|
} |
2670
|
|
|
|
|
|
|
|
2671
|
|
|
|
|
|
|
# This compares all elements of two description hashes to see if |
2672
|
|
|
|
|
|
|
# they are identical, or if the second is contained in the first. |
2673
|
|
|
|
|
|
|
# |
2674
|
|
|
|
|
|
|
sub _ic_compare { |
2675
|
187
|
|
|
187
|
|
333
|
my($self,$desc1,$desc2,$identical,$delim) = @_; |
2676
|
187
|
|
|
|
|
417
|
_DBG_enter("_ic_compare"); |
2677
|
187
|
50
|
|
|
|
376
|
if ($_DBG) { |
2678
|
0
|
|
|
|
|
0
|
_DBG_line("DESC1 ="); |
2679
|
0
|
|
|
|
|
0
|
foreach my $mpath (sort(CORE::keys %$desc1)) { |
2680
|
0
|
|
|
|
|
0
|
my $val = $$desc1{$mpath}{"val"} . |
2681
|
0
|
|
|
|
|
0
|
" [" . join(" ",@{ $$desc1{$mpath}{"meles"} }) . "]"; |
2682
|
0
|
|
|
|
|
0
|
_DBG_line(" $mpath\t= $val"); |
2683
|
|
|
|
|
|
|
} |
2684
|
0
|
|
|
|
|
0
|
_DBG_line("DESC2 ="); |
2685
|
0
|
|
|
|
|
0
|
foreach my $mpath (sort(CORE::keys %$desc2)) { |
2686
|
0
|
|
|
|
|
0
|
my $val = $$desc2{$mpath}{"val"} . |
2687
|
0
|
|
|
|
|
0
|
" [" . join(" ",@{ $$desc2{$mpath}{"meles"} }) . "]"; |
2688
|
0
|
|
|
|
|
0
|
_DBG_line(" $mpath\t= $val"); |
2689
|
|
|
|
|
|
|
} |
2690
|
|
|
|
|
|
|
} |
2691
|
|
|
|
|
|
|
|
2692
|
|
|
|
|
|
|
# |
2693
|
|
|
|
|
|
|
# Separate %desc into two sections. Move everything containing any |
2694
|
|
|
|
|
|
|
# unordered list induces to %ul. %desc will end up containing |
2695
|
|
|
|
|
|
|
# everything else (which is handled very simply). |
2696
|
|
|
|
|
|
|
# |
2697
|
|
|
|
|
|
|
|
2698
|
187
|
|
|
|
|
241
|
my(%ul1,%ul2); |
2699
|
187
|
|
|
|
|
445
|
_ic_ul($desc1,\%ul1); |
2700
|
187
|
|
|
|
|
451
|
_ic_ul($desc2,\%ul2); |
2701
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
# |
2703
|
|
|
|
|
|
|
# One trivial case... if %desc2 is bigger than %desc1, (or %ul2 |
2704
|
|
|
|
|
|
|
# is bigger than %ul1) it isn't contained in it. If they are not |
2705
|
|
|
|
|
|
|
# equal in size, they can't be identical. |
2706
|
|
|
|
|
|
|
# |
2707
|
|
|
|
|
|
|
|
2708
|
187
|
|
|
|
|
2274
|
my @d1 = CORE::keys %$desc1; |
2709
|
187
|
|
|
|
|
521
|
my @d2 = CORE::keys %$desc2; |
2710
|
187
|
|
|
|
|
489
|
my @u1 = CORE::keys %ul1; |
2711
|
187
|
|
|
|
|
438
|
my @u2 = CORE::keys %ul2; |
2712
|
187
|
100
|
|
|
|
373
|
if ($identical) { |
2713
|
71
|
100
|
100
|
|
|
641
|
_DBG_leave("Not equal"), return 0 if ($#d1 != $#d2 || |
2714
|
|
|
|
|
|
|
$#u1 != $#u2); |
2715
|
|
|
|
|
|
|
} else { |
2716
|
116
|
100
|
66
|
|
|
648
|
_DBG_leave("Bigger"), return 0 if ($#d1 < $#d2 || |
2717
|
|
|
|
|
|
|
$#u1 < $#u2); |
2718
|
|
|
|
|
|
|
} |
2719
|
|
|
|
|
|
|
|
2720
|
|
|
|
|
|
|
# |
2721
|
|
|
|
|
|
|
# Do the easy part... elements with no unordered lists. All in |
2722
|
|
|
|
|
|
|
# %desc2 must be in %desc1. For identical tests, nothing else |
2723
|
|
|
|
|
|
|
# can exist. |
2724
|
|
|
|
|
|
|
# |
2725
|
|
|
|
|
|
|
|
2726
|
182
|
|
|
|
|
365
|
foreach my $mpath (@d2) { |
2727
|
192
|
100
|
100
|
|
|
1289
|
if (exists $$desc1{$mpath} && |
2728
|
|
|
|
|
|
|
$$desc1{$mpath}{"val"} eq $$desc2{$mpath}{"val"}) { |
2729
|
77
|
|
|
|
|
216
|
delete $$desc1{$mpath}; |
2730
|
77
|
|
|
|
|
211
|
delete $$desc2{$mpath}; |
2731
|
77
|
|
|
|
|
132
|
next; |
2732
|
|
|
|
|
|
|
} else { |
2733
|
115
|
|
|
|
|
228
|
_DBG_leave("Desc differs"); |
2734
|
115
|
|
|
|
|
2268
|
return 0; |
2735
|
|
|
|
|
|
|
} |
2736
|
|
|
|
|
|
|
} |
2737
|
|
|
|
|
|
|
|
2738
|
67
|
|
|
|
|
151
|
@d1 = CORE::keys %$desc1; |
2739
|
67
|
50
|
66
|
|
|
233
|
_DBG_leave("Desc not equal"), return 0 if ($identical && @d1); |
2740
|
|
|
|
|
|
|
|
2741
|
|
|
|
|
|
|
# |
2742
|
|
|
|
|
|
|
# Now do elements containing unordered lists. |
2743
|
|
|
|
|
|
|
# |
2744
|
|
|
|
|
|
|
|
2745
|
67
|
100
|
|
|
|
179
|
if ($#u2 == -1) { |
2746
|
15
|
50
|
66
|
|
|
71
|
_DBG_leave("UL not identical"), return 0 if ($identical && $#u1 > -1); |
2747
|
15
|
|
|
|
|
33
|
_DBG_leave(1); |
2748
|
15
|
|
|
|
|
415
|
return 1; |
2749
|
|
|
|
|
|
|
} |
2750
|
52
|
|
|
|
|
169
|
my $flag = _ic_compare_ul($self,\%ul1,\%ul2,$identical,$delim); |
2751
|
52
|
|
|
|
|
134
|
_DBG_leave($flag); |
2752
|
52
|
|
|
|
|
575
|
return $flag; |
2753
|
|
|
|
|
|
|
} |
2754
|
|
|
|
|
|
|
|
2755
|
|
|
|
|
|
|
# This recurses through %ul1 and %ul2 to try all possible combinations |
2756
|
|
|
|
|
|
|
# of indices for unordered elements. At every level of recusion, we do |
2757
|
|
|
|
|
|
|
# the left-most set of indices. |
2758
|
|
|
|
|
|
|
# |
2759
|
|
|
|
|
|
|
sub _ic_compare_ul { |
2760
|
52
|
|
|
52
|
|
100
|
my($self,$ul1,$ul2,$identical,$delim) = @_; |
2761
|
52
|
|
|
|
|
146
|
_DBG_enter("_ic_compare_ul"); |
2762
|
52
|
50
|
|
|
|
110
|
if ($_DBG) { |
2763
|
0
|
|
|
|
|
0
|
_DBG_line("UL1 ="); |
2764
|
0
|
|
|
|
|
0
|
foreach my $mpath (sort(CORE::keys %$ul1)) { |
2765
|
0
|
|
|
|
|
0
|
my $val = $$ul1{$mpath}{"val"} . |
2766
|
0
|
|
|
|
|
0
|
" [" . join(" ",@{ $$ul1{$mpath}{"meles"} }) . "]"; |
2767
|
0
|
|
|
|
|
0
|
_DBG_line(" $mpath\t= $val"); |
2768
|
|
|
|
|
|
|
} |
2769
|
0
|
|
|
|
|
0
|
_DBG_line("UL2 ="); |
2770
|
0
|
|
|
|
|
0
|
foreach my $mpath (sort(CORE::keys %$ul2)) { |
2771
|
0
|
|
|
|
|
0
|
my $val = $$ul2{$mpath}{"val"} . |
2772
|
0
|
|
|
|
|
0
|
" [" . join(" ",@{ $$ul2{$mpath}{"meles"} }) . "]"; |
2773
|
0
|
|
|
|
|
0
|
_DBG_line(" $mpath\t= $val"); |
2774
|
|
|
|
|
|
|
} |
2775
|
|
|
|
|
|
|
} |
2776
|
|
|
|
|
|
|
|
2777
|
|
|
|
|
|
|
# |
2778
|
|
|
|
|
|
|
# We need to get a list of all similar mpaths up to this level. |
2779
|
|
|
|
|
|
|
# To determine if two mpaths are similar, look at the first element |
2780
|
|
|
|
|
|
|
# in @meles in each. |
2781
|
|
|
|
|
|
|
# |
2782
|
|
|
|
|
|
|
# If both are unordered list indices (not necessarily identical) or |
2783
|
|
|
|
|
|
|
# both are NOT unordered list indices and are identical, then they |
2784
|
|
|
|
|
|
|
# are similar. |
2785
|
|
|
|
|
|
|
# |
2786
|
|
|
|
|
|
|
|
2787
|
52
|
|
|
|
|
60
|
COMPARE: while (1) { |
2788
|
92
|
|
|
|
|
259
|
my @mpath2 = CORE::keys %$ul2; |
2789
|
92
|
100
|
|
|
|
279
|
last COMPARE if (! @mpath2); |
2790
|
|
|
|
|
|
|
|
2791
|
|
|
|
|
|
|
# |
2792
|
|
|
|
|
|
|
# Look at the first element in @meles in one of the $ul entries. |
2793
|
|
|
|
|
|
|
# It will either be an unordered list index or a set of 1 or more |
2794
|
|
|
|
|
|
|
# path elements which do NOT contain unordered list indices. |
2795
|
|
|
|
|
|
|
# |
2796
|
|
|
|
|
|
|
|
2797
|
58
|
|
|
|
|
83
|
my $mpath = $mpath2[0]; |
2798
|
58
|
|
|
|
|
129
|
my $mele = $$ul2{$mpath}{"meles"}[0]; |
2799
|
|
|
|
|
|
|
|
2800
|
58
|
100
|
|
|
|
202
|
if ($mele =~ /^_ul_/) { |
2801
|
|
|
|
|
|
|
|
2802
|
|
|
|
|
|
|
# Get a list of all elements with a first $mele an _ul_ and |
2803
|
|
|
|
|
|
|
# move them to a temporary description hash. |
2804
|
|
|
|
|
|
|
|
2805
|
29
|
|
|
|
|
36
|
my(%tmp1,%tmp2); |
2806
|
29
|
|
|
|
|
71
|
_ic_ul2desc($ul1,\%tmp1,$mele,1); |
2807
|
29
|
|
|
|
|
89
|
_ic_ul2desc($ul2,\%tmp2,$mele,1); |
2808
|
|
|
|
|
|
|
|
2809
|
|
|
|
|
|
|
# Find the number of unique $mele in %ul1 and %ul2 . If |
2810
|
|
|
|
|
|
|
# the number in %ul2 is greater, it can't be contained. It |
2811
|
|
|
|
|
|
|
# can't be identical unless the two numbers are the same. |
2812
|
|
|
|
|
|
|
|
2813
|
29
|
|
|
|
|
95
|
my $max1 = _ic_max_idx(\%tmp1); |
2814
|
29
|
|
|
|
|
61
|
my $max2 = _ic_max_idx(\%tmp2); |
2815
|
|
|
|
|
|
|
|
2816
|
29
|
50
|
|
|
|
79
|
_DBG_leave("Bigger"), return 0 if ($max2 > $max1); |
2817
|
29
|
50
|
66
|
|
|
103
|
_DBG_leave("Not equal"), return 0 if ($identical && $max1 != $max2); |
2818
|
|
|
|
|
|
|
|
2819
|
|
|
|
|
|
|
# Copy all elements from %ul1 to %desc1, but change them |
2820
|
|
|
|
|
|
|
# from _ul_I to J (where J is 0..MAX) |
2821
|
|
|
|
|
|
|
# |
2822
|
|
|
|
|
|
|
# After we set a combination, we need to reset MELES. |
2823
|
|
|
|
|
|
|
|
2824
|
29
|
|
|
|
|
45
|
my $desc1 = {}; |
2825
|
29
|
|
|
|
|
107
|
_ic_permutation(\%tmp1,$desc1,(0..$max1)); |
2826
|
29
|
|
|
|
|
197
|
foreach my $mp (CORE::keys %$desc1) { |
2827
|
132
|
|
|
|
|
252
|
$$desc1{$mp}{"meles"} = _ic_mpath2meles($self,$mp,$delim); |
2828
|
|
|
|
|
|
|
} |
2829
|
|
|
|
|
|
|
|
2830
|
|
|
|
|
|
|
# Try every combination of the elements in %ul2 setting |
2831
|
|
|
|
|
|
|
# _ul_I to J (where J is 1..MAX and MAX comes from %ul1) |
2832
|
|
|
|
|
|
|
|
2833
|
29
|
|
|
|
|
329
|
my $p = new Algorithm::Permute([0..$max1],$max2+1); |
2834
|
|
|
|
|
|
|
|
2835
|
29
|
|
|
|
|
174
|
while (my(@idx) = $p->next) { |
2836
|
|
|
|
|
|
|
|
2837
|
138
|
|
|
|
|
588
|
my $d1 = {}; |
2838
|
138
|
|
|
|
|
210
|
my $d2 = {}; |
2839
|
138
|
|
|
|
|
8102
|
$d1 = dclone($desc1); |
2840
|
138
|
|
|
|
|
554
|
_ic_permutation(\%tmp2,$d2,@idx); |
2841
|
138
|
|
|
|
|
530
|
foreach my $mp (CORE::keys %$d2) { |
2842
|
538
|
|
|
|
|
1018
|
$$d2{$mp}{"meles"} = _ic_mpath2meles($self,$mp,$delim); |
2843
|
|
|
|
|
|
|
} |
2844
|
|
|
|
|
|
|
|
2845
|
|
|
|
|
|
|
next COMPARE |
2846
|
138
|
100
|
|
|
|
388
|
if (_ic_compare($self,$d1,$d2,$identical,$delim)); |
2847
|
|
|
|
|
|
|
} |
2848
|
|
|
|
|
|
|
|
2849
|
9
|
|
|
|
|
24
|
_DBG_leave("Unordered list fails"); |
2850
|
9
|
|
|
|
|
284
|
return 0; |
2851
|
|
|
|
|
|
|
|
2852
|
|
|
|
|
|
|
} else { |
2853
|
|
|
|
|
|
|
|
2854
|
|
|
|
|
|
|
# |
2855
|
|
|
|
|
|
|
# Not an unordered list. |
2856
|
|
|
|
|
|
|
# |
2857
|
|
|
|
|
|
|
# Go through all %ul mpaths and take all elements which |
2858
|
|
|
|
|
|
|
# have the same leading $mele and move them to a new |
2859
|
|
|
|
|
|
|
# %desc hash. Then compare the two %desc hashes. |
2860
|
|
|
|
|
|
|
# |
2861
|
|
|
|
|
|
|
|
2862
|
29
|
|
|
|
|
41
|
my(%desc1,%desc2); |
2863
|
29
|
|
|
|
|
86
|
_ic_ul2desc($ul1,\%desc1,$mele,0); |
2864
|
29
|
|
|
|
|
76
|
_ic_ul2desc($ul2,\%desc2,$mele,0); |
2865
|
|
|
|
|
|
|
|
2866
|
29
|
100
|
|
|
|
132
|
_DBG_leave("Desc fails"), return 0 |
2867
|
|
|
|
|
|
|
if (! _ic_compare($self,\%desc1,\%desc2,$identical,$delim)); |
2868
|
|
|
|
|
|
|
|
2869
|
|
|
|
|
|
|
} |
2870
|
|
|
|
|
|
|
} |
2871
|
|
|
|
|
|
|
|
2872
|
34
|
|
|
|
|
60
|
my @mpath1 = CORE::keys %$ul1; |
2873
|
34
|
50
|
33
|
|
|
93
|
_DBG_leave("Remaining items fail"), return 0 if (@mpath1 && $identical); |
2874
|
34
|
|
|
|
|
82
|
_DBG_leave(1); |
2875
|
34
|
|
|
|
|
83
|
return 1; |
2876
|
|
|
|
|
|
|
} |
2877
|
|
|
|
|
|
|
|
2878
|
|
|
|
|
|
|
# This recurses through a data structure and creates a description of |
2879
|
|
|
|
|
|
|
# every path containing a scalar. The description is a hash of the |
2880
|
|
|
|
|
|
|
# form: |
2881
|
|
|
|
|
|
|
# |
2882
|
|
|
|
|
|
|
# %desc = |
2883
|
|
|
|
|
|
|
# ( MPATH => |
2884
|
|
|
|
|
|
|
# { val => VAL the scalar at the path |
2885
|
|
|
|
|
|
|
# path => PATH the actual path /a/1 |
2886
|
|
|
|
|
|
|
# mpath => MPATH the modified path /a/_ul_1 |
2887
|
|
|
|
|
|
|
# ul => N the number of unordered indices in mpath |
2888
|
|
|
|
|
|
|
# meles => MELES a list of modified elements (see below) |
2889
|
|
|
|
|
|
|
# mele => MELE the part of MELES currently being examined |
2890
|
|
|
|
|
|
|
# } |
2891
|
|
|
|
|
|
|
# ) |
2892
|
|
|
|
|
|
|
# |
2893
|
|
|
|
|
|
|
# Ths MELES list is a list of "elements" where can be combined to form the |
2894
|
|
|
|
|
|
|
# mpath (using the delimiter). Each element of MELES is either an index of |
2895
|
|
|
|
|
|
|
# an unordered list or all adjacent path elements which are not unordered |
2896
|
|
|
|
|
|
|
# list indices. For example, the mpath: |
2897
|
|
|
|
|
|
|
# /a/_ul_1/b/c/_ul_3/_ul_4 |
2898
|
|
|
|
|
|
|
# would become the following MELES |
2899
|
|
|
|
|
|
|
# [ a, _ul_1, b/c, _ul_3, _ul_4 ] |
2900
|
|
|
|
|
|
|
# |
2901
|
|
|
|
|
|
|
# We'll pass both the path and mpath (as listrefs) as arguments as well |
2902
|
|
|
|
|
|
|
# as a flag whether or not we've had any unordered elements in the path |
2903
|
|
|
|
|
|
|
# to this point. |
2904
|
|
|
|
|
|
|
# |
2905
|
|
|
|
|
|
|
sub _ic_desc { |
2906
|
324
|
|
|
324
|
|
616
|
my($self,$nds,$desc,$mpath,$path,$ul,$delim) = @_; |
2907
|
|
|
|
|
|
|
|
2908
|
324
|
100
|
|
|
|
1039
|
if (ref($nds) eq "HASH") { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2909
|
46
|
|
|
|
|
119
|
foreach my $key (CORE::keys %$nds) { |
2910
|
124
|
|
|
|
|
530
|
_ic_desc($self,$$nds{$key},$desc,[@$mpath,$key],[@$path,$key],$ul, |
2911
|
|
|
|
|
|
|
$delim); |
2912
|
|
|
|
|
|
|
} |
2913
|
|
|
|
|
|
|
|
2914
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
2915
|
60
|
|
|
|
|
216
|
my $ordered = $self->get_structure([@$path,0],"ordered"); |
2916
|
|
|
|
|
|
|
|
2917
|
60
|
50
|
|
|
|
150
|
if ($ordered) { |
2918
|
0
|
|
|
|
|
0
|
for (my $i=0; $i<=$#$nds; $i++) { |
2919
|
0
|
|
|
|
|
0
|
_ic_desc($self,$$nds[$i],$desc,[@$mpath,$i],[@$path,$i],$ul,$delim); |
2920
|
|
|
|
|
|
|
} |
2921
|
|
|
|
|
|
|
|
2922
|
|
|
|
|
|
|
} else { |
2923
|
60
|
|
|
|
|
189
|
for (my $i=0; $i<=$#$nds; $i++) { |
2924
|
160
|
|
|
|
|
900
|
_ic_desc($self,$$nds[$i],$desc,[@$mpath,"_ul_$i"],[@$path,$i],$ul+1, |
2925
|
|
|
|
|
|
|
$delim); |
2926
|
|
|
|
|
|
|
} |
2927
|
|
|
|
|
|
|
} |
2928
|
|
|
|
|
|
|
|
2929
|
|
|
|
|
|
|
} elsif (! $self->empty($nds)) { |
2930
|
218
|
|
|
|
|
434
|
my $p = $self->path($path); |
2931
|
218
|
|
|
|
|
405
|
my $mp = $self->path($mpath); |
2932
|
|
|
|
|
|
|
|
2933
|
218
|
|
|
|
|
500
|
$$desc{$mp} = { "val" => $nds, |
2934
|
|
|
|
|
|
|
"path" => $p, |
2935
|
|
|
|
|
|
|
"mpath" => $mp, |
2936
|
|
|
|
|
|
|
"meles" => _ic_mpath2meles($self,$mpath,$delim), |
2937
|
|
|
|
|
|
|
"ul" => $ul |
2938
|
|
|
|
|
|
|
}; |
2939
|
|
|
|
|
|
|
} |
2940
|
|
|
|
|
|
|
} |
2941
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
# Move all elements from %desc to %ul which have unordered list elements |
2943
|
|
|
|
|
|
|
# in them. |
2944
|
|
|
|
|
|
|
# |
2945
|
|
|
|
|
|
|
sub _ic_ul { |
2946
|
374
|
|
|
374
|
|
484
|
my($desc,$ul) = @_; |
2947
|
|
|
|
|
|
|
|
2948
|
374
|
|
|
|
|
958
|
foreach my $mpath (CORE::keys %$desc) { |
2949
|
1594
|
100
|
|
|
|
4034
|
if ($$desc{$mpath}{"ul"}) { |
2950
|
590
|
|
|
|
|
851
|
$$ul{$mpath} = $$desc{$mpath}; |
2951
|
590
|
|
|
|
|
1016
|
delete $$desc{$mpath}; |
2952
|
|
|
|
|
|
|
} |
2953
|
|
|
|
|
|
|
} |
2954
|
|
|
|
|
|
|
} |
2955
|
|
|
|
|
|
|
|
2956
|
|
|
|
|
|
|
# This moves moves all elements from %ul to %desc which have the given |
2957
|
|
|
|
|
|
|
# first element in @meles. |
2958
|
|
|
|
|
|
|
# |
2959
|
|
|
|
|
|
|
# $mele can be an unordered list element (in which case all elements |
2960
|
|
|
|
|
|
|
# with unordered list elements are moved) or not (in which case, all |
2961
|
|
|
|
|
|
|
# elements with the same first $mele are moved). |
2962
|
|
|
|
|
|
|
# |
2963
|
|
|
|
|
|
|
sub _ic_ul2desc { |
2964
|
116
|
|
|
116
|
|
191
|
my($ul,$desc,$mele,$isul) = @_; |
2965
|
|
|
|
|
|
|
|
2966
|
116
|
|
|
|
|
276
|
foreach my $mpath (CORE::keys %$ul) { |
2967
|
583
|
100
|
66
|
|
|
3834
|
if ( ($isul && $$ul{$mpath}{"meles"}[0] =~ /^_ul_/) || |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2968
|
|
|
|
|
|
|
(! $isul && $$ul{$mpath}{"meles"}[0] eq $mele) ) { |
2969
|
|
|
|
|
|
|
|
2970
|
|
|
|
|
|
|
# Move the element to %desc |
2971
|
|
|
|
|
|
|
|
2972
|
512
|
|
|
|
|
955
|
$$desc{$mpath} = $$ul{$mpath}; |
2973
|
512
|
|
|
|
|
696
|
delete $$ul{$mpath}; |
2974
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
# Fix @meles accordingly |
2976
|
|
|
|
|
|
|
|
2977
|
512
|
|
|
|
|
541
|
my @meles = @{ $$desc{$mpath}{"meles"} }; |
|
512
|
|
|
|
|
1329
|
|
2978
|
512
|
|
|
|
|
747
|
my $m = shift(@meles); |
2979
|
|
|
|
|
|
|
|
2980
|
512
|
|
|
|
|
1048
|
$$desc{$mpath}{"meles"} = [ @meles ]; |
2981
|
512
|
|
|
|
|
1554
|
$$desc{$mpath}{"mele"} = $m; |
2982
|
|
|
|
|
|
|
} |
2983
|
|
|
|
|
|
|
} |
2984
|
|
|
|
|
|
|
} |
2985
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
# This goes through a description hash (%desc) and sets the "meles" value |
2987
|
|
|
|
|
|
|
# for each element. |
2988
|
|
|
|
|
|
|
# |
2989
|
|
|
|
|
|
|
sub _ic_mpath2meles { |
2990
|
888
|
|
|
888
|
|
1496
|
my($self,$mpath,$delim) = @_; |
2991
|
888
|
|
|
|
|
1604
|
my(@mpath) = $self->path($mpath); |
2992
|
|
|
|
|
|
|
|
2993
|
888
|
|
|
|
|
1564
|
my @meles = (); |
2994
|
888
|
|
|
|
|
1096
|
my $tmp = ""; |
2995
|
888
|
|
|
|
|
1162
|
foreach my $mele (@mpath) { |
2996
|
2638
|
100
|
|
|
|
4766
|
if ($mele =~ /^_ul_/) { |
2997
|
398
|
100
|
|
|
|
715
|
if ($tmp) { |
2998
|
304
|
|
|
|
|
431
|
push(@meles,$tmp); |
2999
|
304
|
|
|
|
|
372
|
$tmp = ""; |
3000
|
|
|
|
|
|
|
} |
3001
|
398
|
|
|
|
|
704
|
push(@meles,$mele); |
3002
|
|
|
|
|
|
|
} else { |
3003
|
2240
|
100
|
|
|
|
3325
|
if ($tmp) { |
3004
|
1254
|
|
|
|
|
2397
|
$tmp .= "$delim$mele"; |
3005
|
|
|
|
|
|
|
} else { |
3006
|
986
|
|
|
|
|
1781
|
$tmp = $mele; |
3007
|
|
|
|
|
|
|
} |
3008
|
|
|
|
|
|
|
} |
3009
|
|
|
|
|
|
|
} |
3010
|
888
|
100
|
|
|
|
2174
|
if ($tmp) { |
3011
|
682
|
|
|
|
|
1113
|
push(@meles,$tmp); |
3012
|
|
|
|
|
|
|
} |
3013
|
888
|
|
|
|
|
5775
|
return [ @meles ]; |
3014
|
|
|
|
|
|
|
} |
3015
|
|
|
|
|
|
|
|
3016
|
|
|
|
|
|
|
# This goes through all of the elements in a %desc hash. All of them should |
3017
|
|
|
|
|
|
|
# have a descriptor "mele" which is an unordered list index in the form |
3018
|
|
|
|
|
|
|
# _ul_I . Find out how many unique ones there are. |
3019
|
|
|
|
|
|
|
# |
3020
|
|
|
|
|
|
|
sub _ic_max_idx { |
3021
|
58
|
|
|
58
|
|
82
|
my($desc) = @_; |
3022
|
|
|
|
|
|
|
|
3023
|
58
|
|
|
|
|
66
|
my %tmp; |
3024
|
58
|
|
|
|
|
142
|
foreach my $mpath (CORE::keys %$desc) { |
3025
|
256
|
|
|
|
|
373
|
my $mele = $$desc{$mpath}{"mele"}; |
3026
|
256
|
|
|
|
|
475
|
$tmp{$mele} = 1; |
3027
|
|
|
|
|
|
|
} |
3028
|
|
|
|
|
|
|
|
3029
|
58
|
|
|
|
|
170
|
my @tmp = CORE::keys %tmp; |
3030
|
58
|
|
|
|
|
175
|
return $#tmp; |
3031
|
|
|
|
|
|
|
} |
3032
|
|
|
|
|
|
|
|
3033
|
|
|
|
|
|
|
# This copies all elements from one description hash (%tmpdesc) to a final |
3034
|
|
|
|
|
|
|
# description hash (%desc). Along the way, it substitutes all leading |
3035
|
|
|
|
|
|
|
# unordered list indices (_ul_i) with the current permutation index. |
3036
|
|
|
|
|
|
|
# |
3037
|
|
|
|
|
|
|
# So if the list of indices (@idx) is (0,2,1) and the current list of |
3038
|
|
|
|
|
|
|
# unorderd indices is (_ul_0, _ul_1, _ul_2), then every element containing |
3039
|
|
|
|
|
|
|
# a leading _ul_1 in the mpath will be modified and that element will be |
3040
|
|
|
|
|
|
|
# replaced by "2". |
3041
|
|
|
|
|
|
|
# |
3042
|
|
|
|
|
|
|
sub _ic_permutation { |
3043
|
167
|
|
|
167
|
|
326
|
my($tmpdesc,$desc,@idx) = @_; |
3044
|
|
|
|
|
|
|
|
3045
|
|
|
|
|
|
|
# Get a sorted list of all unordered indices: |
3046
|
|
|
|
|
|
|
# (_ul_0, _ul_1, _ul_2) |
3047
|
|
|
|
|
|
|
|
3048
|
167
|
|
|
|
|
180
|
my(%tmp); |
3049
|
167
|
|
|
|
|
535
|
foreach my $mpath (CORE::keys %$tmpdesc) { |
3050
|
670
|
|
|
|
|
1458
|
my $mele = $$tmpdesc{$mpath}{"mele"}; |
3051
|
670
|
|
|
|
|
2240
|
$tmp{$mele} = 1; |
3052
|
|
|
|
|
|
|
} |
3053
|
167
|
|
|
|
|
1628
|
my @tmp = sort(CORE::keys %tmp); |
3054
|
|
|
|
|
|
|
|
3055
|
|
|
|
|
|
|
# Create a hash of unordered list indices and their |
3056
|
|
|
|
|
|
|
# replacement: |
3057
|
|
|
|
|
|
|
# _ul_0 => 0 |
3058
|
|
|
|
|
|
|
# _ul_1 => 2 |
3059
|
|
|
|
|
|
|
# _ul_2 => 1 |
3060
|
|
|
|
|
|
|
|
3061
|
167
|
|
|
|
|
346
|
%tmp = (); |
3062
|
167
|
|
|
|
|
374
|
while (@tmp) { |
3063
|
464
|
|
|
|
|
655
|
my($ul) = shift(@tmp); |
3064
|
464
|
|
|
|
|
604
|
my($idx) = shift(@idx); |
3065
|
464
|
|
|
|
|
1335
|
$tmp{$ul} = $idx; |
3066
|
|
|
|
|
|
|
} |
3067
|
|
|
|
|
|
|
|
3068
|
|
|
|
|
|
|
# Copy the element from %tmpdesc to %desc |
3069
|
|
|
|
|
|
|
# Substitute the unordered list index with the permutation index |
3070
|
|
|
|
|
|
|
# Clear "mele" value |
3071
|
|
|
|
|
|
|
# Decrement "ul" value |
3072
|
|
|
|
|
|
|
|
3073
|
167
|
|
|
|
|
440
|
foreach my $mpath (CORE::keys %$tmpdesc) { |
3074
|
670
|
|
|
|
|
1099
|
my $mele = $$tmpdesc{$mpath}{"mele"}; |
3075
|
670
|
|
|
|
|
949
|
my $idx = $tmp{$mele}; |
3076
|
670
|
|
|
|
|
868
|
my $newmp = $mpath; |
3077
|
670
|
|
|
|
|
7221
|
$newmp =~ s/$mele/$idx/; |
3078
|
|
|
|
|
|
|
|
3079
|
670
|
|
|
|
|
14453
|
$$desc{$newmp} = dclone($$tmpdesc{$mpath}); |
3080
|
670
|
|
|
|
|
1689
|
$$desc{$newmp}{"mpath"} = $newmp; |
3081
|
670
|
|
|
|
|
1157
|
$$desc{$newmp}{"mele"} = ""; |
3082
|
670
|
|
|
|
|
1968
|
$$desc{$newmp}{"ul"}--; |
3083
|
|
|
|
|
|
|
} |
3084
|
|
|
|
|
|
|
} |
3085
|
|
|
|
|
|
|
|
3086
|
|
|
|
|
|
|
############################################################################### |
3087
|
|
|
|
|
|
|
# PRINT |
3088
|
|
|
|
|
|
|
############################################################################### |
3089
|
|
|
|
|
|
|
|
3090
|
|
|
|
|
|
|
sub print { |
3091
|
0
|
|
|
0
|
1
|
0
|
my($self,$nds,%opts) = @_; |
3092
|
0
|
|
|
|
|
0
|
$nds = _nds($self,$nds,1,0,1); |
3093
|
|
|
|
|
|
|
|
3094
|
0
|
0
|
|
|
|
0
|
if (exists $opts{"indent"}) { |
3095
|
0
|
|
|
|
|
0
|
my $opt = $opts{"indent"}; |
3096
|
0
|
0
|
0
|
|
|
0
|
if ($opt !~ /^\d+$/ || |
3097
|
|
|
|
|
|
|
$opt < 1) { |
3098
|
0
|
|
|
|
|
0
|
warn($self,"Invalid option: indent: $opt",1); |
3099
|
0
|
|
|
|
|
0
|
return; |
3100
|
|
|
|
|
|
|
} |
3101
|
|
|
|
|
|
|
} else { |
3102
|
0
|
|
|
|
|
0
|
$opts{"indent"} = 3; |
3103
|
|
|
|
|
|
|
} |
3104
|
|
|
|
|
|
|
|
3105
|
0
|
0
|
|
|
|
0
|
if (exists $opts{"width"}) { |
3106
|
0
|
|
|
|
|
0
|
my $opt = $opts{"width"}; |
3107
|
0
|
0
|
0
|
|
|
0
|
if ($opt !~ /^\d+$/ || |
|
|
|
0
|
|
|
|
|
3108
|
|
|
|
|
|
|
($opt > 0 && $opt < 20)) { |
3109
|
0
|
|
|
|
|
0
|
warn($self,"Invalid option: width: $opt",1); |
3110
|
0
|
|
|
|
|
0
|
return; |
3111
|
|
|
|
|
|
|
} |
3112
|
|
|
|
|
|
|
} else { |
3113
|
0
|
|
|
|
|
0
|
$opts{"width"} = 79; |
3114
|
|
|
|
|
|
|
} |
3115
|
|
|
|
|
|
|
|
3116
|
0
|
0
|
|
|
|
0
|
my $maxlevel = ($opts{"width"} == 0 ? 0 : int( ($opts{"width"} - 10)/ |
3117
|
|
|
|
|
|
|
$opts{"indent"} ) + 1); |
3118
|
0
|
0
|
|
|
|
0
|
if (exists $opts{"maxlevel"}) { |
3119
|
0
|
|
|
|
|
0
|
my $opt = $opts{"maxlevel"}; |
3120
|
0
|
0
|
0
|
|
|
0
|
if ($maxlevel != 0 && $opt > $maxlevel) { |
3121
|
0
|
|
|
|
|
0
|
warn($self,"Maxlevel exceeded: $opt > $maxlevel",1); |
3122
|
0
|
|
|
|
|
0
|
$opts{"maxlevel"} = $maxlevel; |
3123
|
|
|
|
|
|
|
} |
3124
|
|
|
|
|
|
|
} else { |
3125
|
0
|
|
|
|
|
0
|
$opts{"maxlevel"} = $maxlevel; |
3126
|
|
|
|
|
|
|
} |
3127
|
|
|
|
|
|
|
|
3128
|
0
|
|
|
|
|
0
|
return _print($nds,0,1,%opts); |
3129
|
|
|
|
|
|
|
} |
3130
|
|
|
|
|
|
|
|
3131
|
|
|
|
|
|
|
sub _print { |
3132
|
0
|
|
|
0
|
|
0
|
my($nds,$indent,$level,%opts) = @_; |
3133
|
|
|
|
|
|
|
|
3134
|
0
|
|
|
|
|
0
|
my $string; |
3135
|
0
|
|
|
|
|
0
|
my $indentstr = " "x$indent; |
3136
|
0
|
|
|
|
|
0
|
my $nextindent = $indent + $opts{"indent"}; |
3137
|
0
|
0
|
|
|
|
0
|
my $currwidth = ($opts{"width"} == 0 ? 0 : $opts{"width"} - $indent); |
3138
|
|
|
|
|
|
|
|
3139
|
0
|
0
|
|
|
|
0
|
if (ref($nds) eq "HASH") { |
|
|
0
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
# Print |
3141
|
|
|
|
|
|
|
# key : val val is a scalar, and it fits |
3142
|
|
|
|
|
|
|
# key : ... we're at maxlevel, val is a ref, and ... fits |
3143
|
|
|
|
|
|
|
# key : otherwise |
3144
|
|
|
|
|
|
|
# val |
3145
|
|
|
|
|
|
|
|
3146
|
|
|
|
|
|
|
# Find the length of the longest key |
3147
|
0
|
|
|
|
|
0
|
my @keys = CORE::keys %$nds; |
3148
|
0
|
|
|
|
|
0
|
@keys = sort _sortByLength(@keys); |
3149
|
0
|
|
|
|
|
0
|
my $maxl = length($keys[0]); |
3150
|
0
|
|
|
|
|
0
|
my $keyl = 0; |
3151
|
0
|
|
|
|
|
0
|
my $vall = 0; |
3152
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
# Find the length that we'll allocate for keys (the rest if |
3154
|
|
|
|
|
|
|
# for values). |
3155
|
0
|
0
|
0
|
|
|
0
|
if ( $currwidth && ($maxl+1) > $currwidth ) { |
3156
|
|
|
|
|
|
|
# keys won't all fit on the line, so truncate them |
3157
|
0
|
|
|
|
|
0
|
$keyl = $currwidth - 1; |
3158
|
|
|
|
|
|
|
} else { |
3159
|
0
|
|
|
|
|
0
|
$keyl = $maxl; |
3160
|
0
|
0
|
|
|
|
0
|
if ($currwidth == 0) { |
3161
|
0
|
|
|
|
|
0
|
$vall = -1; |
3162
|
|
|
|
|
|
|
} else { |
3163
|
0
|
|
|
|
|
0
|
$vall = $currwidth - ($keyl + 2); # key:_ (include a space) |
3164
|
0
|
0
|
|
|
|
0
|
$vall = 0 if ($vall < 0); |
3165
|
|
|
|
|
|
|
} |
3166
|
|
|
|
|
|
|
} |
3167
|
|
|
|
|
|
|
|
3168
|
|
|
|
|
|
|
# Print each key |
3169
|
0
|
|
|
|
|
0
|
foreach my $key (sort @keys) { |
3170
|
0
|
|
|
|
|
0
|
my $val = $$nds{$key}; |
3171
|
0
|
0
|
|
|
|
0
|
$val = "undef" if (! defined $val); |
3172
|
0
|
0
|
0
|
|
|
0
|
$val = "''" if (! ref($val) && $val eq ""); |
3173
|
0
|
|
|
|
|
0
|
my $k = $key; |
3174
|
0
|
0
|
|
|
|
0
|
if (length($k) > $keyl) { |
|
|
0
|
|
|
|
|
|
3175
|
0
|
|
|
|
|
0
|
$k = substr($k,0,$keyl); |
3176
|
|
|
|
|
|
|
} elsif (length($k) < $keyl) { |
3177
|
0
|
|
|
|
|
0
|
$k = $k . " "x($keyl - length($k)); |
3178
|
|
|
|
|
|
|
} |
3179
|
0
|
|
|
|
|
0
|
$string .= "$indentstr$k" . ":"; |
3180
|
|
|
|
|
|
|
|
3181
|
0
|
0
|
0
|
|
|
0
|
if (! ref($val) && ($vall == -1 || length($val) <= $vall)) { |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
3182
|
0
|
|
|
|
|
0
|
$string .= " $val\n"; |
3183
|
|
|
|
|
|
|
|
3184
|
|
|
|
|
|
|
} elsif (ref($val) && |
3185
|
|
|
|
|
|
|
$opts{"maxlevel"} == $level && |
3186
|
|
|
|
|
|
|
($vall == -1 || $vall > 3)) { |
3187
|
0
|
|
|
|
|
0
|
$string .= " ...\n"; |
3188
|
|
|
|
|
|
|
|
3189
|
|
|
|
|
|
|
} else { |
3190
|
0
|
|
|
|
|
0
|
$string .= "\n"; |
3191
|
0
|
|
|
|
|
0
|
$string .= _print($val,$nextindent,$level+1,%opts); |
3192
|
|
|
|
|
|
|
} |
3193
|
|
|
|
|
|
|
} |
3194
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
} elsif (ref($nds) eq "ARRAY") { |
3196
|
|
|
|
|
|
|
# Print each element as: |
3197
|
|
|
|
|
|
|
# 0 = val val is a scalar, and it fits |
3198
|
|
|
|
|
|
|
# 0 = ... we're at maxlevel, val is a ref, and ... fits |
3199
|
|
|
|
|
|
|
# 0 = otherwise |
3200
|
|
|
|
|
|
|
# val |
3201
|
|
|
|
|
|
|
|
3202
|
|
|
|
|
|
|
# Find the length of the longest index |
3203
|
0
|
|
|
|
|
0
|
my $maxl = length($#$nds + 1); |
3204
|
0
|
|
|
|
|
0
|
my $keyl = 0; |
3205
|
0
|
|
|
|
|
0
|
my $vall = 0; |
3206
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
# Find the length allocated for indices and the rest for values. |
3208
|
0
|
0
|
|
|
|
0
|
if ( ($maxl + 1) > $currwidth ) { |
3209
|
|
|
|
|
|
|
# keys won't all fit on the line, so truncate them |
3210
|
0
|
|
|
|
|
0
|
$keyl = $currwidth - 1; |
3211
|
|
|
|
|
|
|
} else { |
3212
|
0
|
|
|
|
|
0
|
$keyl = $maxl; |
3213
|
0
|
0
|
|
|
|
0
|
if ($currwidth == 0) { |
3214
|
0
|
|
|
|
|
0
|
$vall = -1; |
3215
|
|
|
|
|
|
|
} else { |
3216
|
0
|
|
|
|
|
0
|
$vall = $currwidth - ($keyl + 2); # key:_ (include a space) |
3217
|
0
|
0
|
|
|
|
0
|
$vall = 0 if ($vall < 0); |
3218
|
|
|
|
|
|
|
} |
3219
|
|
|
|
|
|
|
} |
3220
|
|
|
|
|
|
|
|
3221
|
|
|
|
|
|
|
# Print each index |
3222
|
0
|
|
|
|
|
0
|
for (my $key=0; $key <= $#$nds; $key++) { |
3223
|
0
|
|
|
|
|
0
|
my $val = $$nds[$key]; |
3224
|
0
|
0
|
|
|
|
0
|
$val = "undef" if (! defined $val); |
3225
|
0
|
0
|
0
|
|
|
0
|
$val = "''" if (! ref($val) && $val eq ""); |
3226
|
0
|
|
|
|
|
0
|
my $k = $key; |
3227
|
0
|
0
|
|
|
|
0
|
if (length($k) > $keyl) { |
|
|
0
|
|
|
|
|
|
3228
|
0
|
|
|
|
|
0
|
$k = substr($k,0,$keyl); |
3229
|
|
|
|
|
|
|
} elsif (length($k) < $keyl) { |
3230
|
0
|
|
|
|
|
0
|
$k = " "x($keyl - length($k)) . $k; |
3231
|
|
|
|
|
|
|
} |
3232
|
0
|
|
|
|
|
0
|
$string .= "$indentstr$k" . "="; |
3233
|
|
|
|
|
|
|
|
3234
|
0
|
0
|
0
|
|
|
0
|
if (! ref($val) && ($vall == -1 || length($val) <= $vall)) { |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
3235
|
0
|
|
|
|
|
0
|
$string .= " $val\n"; |
3236
|
|
|
|
|
|
|
|
3237
|
|
|
|
|
|
|
} elsif (ref($val) && |
3238
|
|
|
|
|
|
|
$opts{"maxlevel"} == $level && |
3239
|
|
|
|
|
|
|
($vall == -1 || $vall > 3)) { |
3240
|
0
|
|
|
|
|
0
|
$string .= " ...\n"; |
3241
|
|
|
|
|
|
|
|
3242
|
|
|
|
|
|
|
} else { |
3243
|
0
|
|
|
|
|
0
|
$string .= "\n"; |
3244
|
0
|
|
|
|
|
0
|
$string .= _print($val,$nextindent,$level+1,%opts); |
3245
|
|
|
|
|
|
|
} |
3246
|
|
|
|
|
|
|
} |
3247
|
|
|
|
|
|
|
|
3248
|
|
|
|
|
|
|
} else { |
3249
|
0
|
0
|
|
|
|
0
|
$nds = "undef" if (! defined $nds); |
3250
|
0
|
0
|
0
|
|
|
0
|
$nds = "''" if (! ref($nds) && $nds eq ""); |
3251
|
|
|
|
|
|
|
|
3252
|
0
|
0
|
|
|
|
0
|
if (length($nds) > $currwidth) { |
3253
|
0
|
|
|
|
|
0
|
$nds = substr($nds,0,$currwidth-3) . "..."; |
3254
|
|
|
|
|
|
|
} |
3255
|
0
|
|
|
|
|
0
|
$string = "$indentstr$nds\n"; |
3256
|
|
|
|
|
|
|
} |
3257
|
|
|
|
|
|
|
|
3258
|
0
|
|
|
|
|
0
|
return $string; |
3259
|
|
|
|
|
|
|
} |
3260
|
|
|
|
|
|
|
|
3261
|
93
|
|
|
93
|
|
1513
|
no strict "vars"; |
|
93
|
|
|
|
|
227
|
|
|
93
|
|
|
|
|
7947
|
|
3262
|
|
|
|
|
|
|
# This sorts from longest to shortest element |
3263
|
|
|
|
|
|
|
sub _sortByLength { |
3264
|
0
|
|
|
0
|
|
0
|
return (length $b <=> length $a); |
3265
|
|
|
|
|
|
|
} |
3266
|
93
|
|
|
93
|
|
658
|
use strict "vars"; |
|
93
|
|
|
|
|
224
|
|
|
93
|
|
|
|
|
40624
|
|
3267
|
|
|
|
|
|
|
|
3268
|
|
|
|
|
|
|
############################################################################### |
3269
|
|
|
|
|
|
|
# DEBUG ROUTINES |
3270
|
|
|
|
|
|
|
############################################################################### |
3271
|
|
|
|
|
|
|
|
3272
|
|
|
|
|
|
|
# Begin a new debugging session. |
3273
|
|
|
|
|
|
|
sub _DBG_begin { |
3274
|
20
|
|
|
20
|
|
34
|
my($function) = @_; |
3275
|
20
|
50
|
|
|
|
56
|
return unless ($_DBG); |
3276
|
|
|
|
|
|
|
|
3277
|
0
|
|
|
|
|
0
|
$_DBG_FH = new IO::File; |
3278
|
0
|
|
|
|
|
0
|
$_DBG_FH->open(">>$_DBG_OUTPUT"); |
3279
|
0
|
|
|
|
|
0
|
$_DBG_INDENT = 0; |
3280
|
0
|
|
|
|
|
0
|
$_DBG_POINT = 0; |
3281
|
|
|
|
|
|
|
|
3282
|
0
|
|
|
|
|
0
|
_DBG_line("#"x70); |
3283
|
0
|
|
|
|
|
0
|
_DBG_line("# $function"); |
3284
|
0
|
|
|
|
|
0
|
_DBG_line("#"x70); |
3285
|
|
|
|
|
|
|
} |
3286
|
|
|
|
|
|
|
|
3287
|
|
|
|
|
|
|
# End a debugging session. |
3288
|
|
|
|
|
|
|
sub _DBG_end { |
3289
|
20
|
|
|
20
|
|
35
|
my($value) = @_; |
3290
|
20
|
50
|
|
|
|
45
|
return unless ($_DBG); |
3291
|
|
|
|
|
|
|
|
3292
|
0
|
|
|
|
|
0
|
_DBG_line("# Ending: $value"); |
3293
|
0
|
|
|
|
|
0
|
$_DBG_FH->close(); |
3294
|
|
|
|
|
|
|
} |
3295
|
|
|
|
|
|
|
|
3296
|
|
|
|
|
|
|
# Enter a routine. |
3297
|
|
|
|
|
|
|
sub _DBG_enter { |
3298
|
259
|
|
|
259
|
|
528
|
my($routine) = @_; |
3299
|
259
|
50
|
|
|
|
630
|
return unless ($_DBG); |
3300
|
0
|
|
|
|
|
0
|
$_DBG_POINT++; |
3301
|
0
|
|
|
|
|
0
|
$_DBG_INDENT += 3; |
3302
|
|
|
|
|
|
|
|
3303
|
0
|
|
|
|
|
0
|
_DBG_line("### Entering[$_DBG_POINT]: $routine"); |
3304
|
|
|
|
|
|
|
} |
3305
|
|
|
|
|
|
|
|
3306
|
|
|
|
|
|
|
# Leave a routine. |
3307
|
|
|
|
|
|
|
sub _DBG_leave { |
3308
|
259
|
|
|
259
|
|
346
|
my($value) = @_; |
3309
|
259
|
50
|
|
|
|
815
|
return unless ($_DBG); |
3310
|
0
|
|
|
|
|
|
$_DBG_POINT++; |
3311
|
|
|
|
|
|
|
|
3312
|
0
|
|
|
|
|
|
_DBG_line("### Leaving[$_DBG_POINT]: $value"); |
3313
|
0
|
|
|
|
|
|
$_DBG_INDENT -= 3; |
3314
|
|
|
|
|
|
|
} |
3315
|
|
|
|
|
|
|
|
3316
|
|
|
|
|
|
|
# Print a debugging line. |
3317
|
|
|
|
|
|
|
sub _DBG_line { |
3318
|
0
|
|
|
0
|
|
|
my($line) = @_; |
3319
|
0
|
|
|
|
|
|
print $_DBG_FH " "x$_DBG_INDENT,$line,"\n"; |
3320
|
|
|
|
|
|
|
} |
3321
|
|
|
|
|
|
|
|
3322
|
|
|
|
|
|
|
############################################################################### |
3323
|
|
|
|
|
|
|
############################################################################### |
3324
|
|
|
|
|
|
|
|
3325
|
|
|
|
|
|
|
1; |
3326
|
|
|
|
|
|
|
# Local Variables: |
3327
|
|
|
|
|
|
|
# mode: cperl |
3328
|
|
|
|
|
|
|
# indent-tabs-mode: nil |
3329
|
|
|
|
|
|
|
# cperl-indent-level: 3 |
3330
|
|
|
|
|
|
|
# cperl-continued-statement-offset: 2 |
3331
|
|
|
|
|
|
|
# cperl-continued-brace-offset: 0 |
3332
|
|
|
|
|
|
|
# cperl-brace-offset: 0 |
3333
|
|
|
|
|
|
|
# cperl-brace-imaginary-offset: 0 |
3334
|
|
|
|
|
|
|
# cperl-label-offset: -2 |
3335
|
|
|
|
|
|
|
# End: |