File Coverage

blib/lib/Config/Record.pm
Criterion Covered Total %
statement 310 364 85.1
branch 167 260 64.2
condition 47 60 78.3
subroutine 19 19 100.0
pod 7 7 100.0
total 550 710 77.4


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Config::Record by Daniel Berrange
4             #
5             # Copyright (C) 2000-2007 Daniel P. Berrange
6             #
7             # This program is free software; you can redistribute it and/or modify
8             # it under the terms of the GNU General Public License as published by
9             # the Free Software Foundation; either version 2 of the License, or
10             # (at your option) any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License
18             # along with this program; if not, write to the Free Software
19             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20             #
21             # $Id: Record.pm,v 1.12 2006/01/27 16:25:50 dan Exp $
22              
23             package Config::Record;
24              
25 3     3   105889 use strict;
  3         9  
  3         125  
26 3     3   17 use warnings;
  3         7  
  3         101  
27 3     3   17 use Carp qw(confess cluck);
  3         11  
  3         291  
28 3     3   3712 use IO::File;
  3         38850  
  3         484  
29              
30 3     3   30 use warnings::register;
  3         8  
  3         893  
31              
32 3     3   27 use vars qw($VERSION);
  3         8  
  3         17356  
33              
34             $VERSION = "1.1.2";
35              
36             sub new {
37 11     11 1 4740 my $proto = shift;
38 11   66     78 my $class = ref($proto) || $proto;
39 11         29 my $self = {};
40 11         57 my %params = @_;
41            
42 11 100       64 $self->{record} = exists $params{record} ? $params{record} : {};
43 11 100       52 $self->{features} = exists $params{features} ? $params{features} : {};
44 11         29 $self->{debug} = $params{debug};
45 11         35 $self->{filename} = undef;
46            
47 11         33 bless $self, $class;
48            
49 11 100       41 if (defined $params{file}) {
50 7         30 $self->load($params{file});
51             }
52            
53 11         295 return $self;
54             }
55              
56              
57             sub load {
58 9     9 1 282 my $self = shift;
59            
60 9         14 my $file;
61 9 50       28 if (@_) {
    0          
62 9         20 $file = shift;
63             } elsif ($self->{filename}) {
64 0         0 $file = $self->{filename};
65             } else {
66 0         0 die "no filename was specified";
67             }
68            
69 9         16 my $fh;
70 9 100       28 if (ref($file)) {
71 4 50       48 if (!$file->isa("IO::Handle")) {
72 0         0 confess "file must be an instance of IO::Handle";
73             }
74 4         9 $fh = $file;
75             } else {
76 5 50       46 $fh = IO::File->new($file)
77             or confess "cannot read from $file: $!";
78 5         513 $self->{filename} = $file;
79             }
80            
81 9         42 local $/ = undef;
82 9         278 my $data = <$fh>;
83 9 100       61 $self->{record} = $self->_parse($data, ref($file) ? "" : $file);
84 9 50       81 $fh->close
85             or confess "cannot close file: $!";
86             }
87              
88              
89             sub _parse {
90 12     12   31 my $self = shift;
91 12         24 my $data = shift;
92 12         21 my $filename = shift;
93              
94 12         36 my $value = {};
95 12         28 my @stack = $value;
96 12         23 my $here;
97             my $continuation;
98              
99 12         23 my $LABEL = '((?:\w|-|\.)+)';
100             # Hairy ! Escaping the escape chars really obscures the regex.
101             # Need to allow any character except \ or "
102             # unless they are written as \\ or \"
103 12         20 my $QUOTED_LABEL = '((?:(?:[^"\\\])|(?:\\\\")|(?:\\\\\\\\))+)';
104 12         17 my $TRAILING_WHITESPACE = '\s*(?:\#.*)?';
105 12         17 my $lineno = 0;
106              
107 12         297 my @lines = split /\n/, $data;
108              
109 12         45 foreach my $line (@lines) {
110 545         690 $lineno++;
111 545 0       2606 warn $lineno . ": '" . $line . "' here='" .
    0          
    50          
112             (defined $here ? $here : '') . "' continue='" .
113             (defined $continuation ? $continuation : '') .
114             "'\n" if $self->{debug};
115 545 100       2761 next if $line =~ m|^\s*#|;
116 536 100       1622 next if $line =~ m|^\s*$|;
117              
118 518 100       1465 if ($here) {
    100          
119 56 100       260 if ($line =~ /\s*${here}\s*$/) { # EOF
120 16 50       47 warn "$lineno: End of here doc\n" if $self->{debug};
121 16         25 $here = undef;
122 16         32 $continuation = undef;
123             } else { # ...
124 40 50       105 warn "$lineno: Middle of here doc\n" if $self->{debug};
125 40         43 ${$continuation} .= $line . "\n";
  40         136  
126             }
127             } elsif ($continuation) {
128 12 50 66     107 if ($line =~ /^\s*"(.*?)"\s*(\\)?\s*$/ || # "..."
129             $line =~ /^\s*(.*?)\s*(\\)?\s*$/) { # ...
130 12 50       34 warn "$lineno: Continuation\n" if $self->{debug};
131 12         38 ${$continuation} .= $1;
  12         33  
132 12 50       56 $continuation = undef unless $2;
133             } else {
134 0         0 warn "$lineno: unexpected input '$line'\n";
135             }
136             } else {
137 450 100 100     25867 if ($line =~ /^\s*$LABEL\s*=\s*\(${TRAILING_WHITESPACE}$/ || # foo = (
    100 66        
    100 100        
    100 66        
    100 66        
    100 66        
    100 66        
    100 66        
    100 100        
    100 66        
    100 100        
    50 100        
      66        
      100        
      66        
138             ($self->{features}->{quotedkeys} &&
139             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*\(${TRAILING_WHITESPACE}$/)) { # " foo " = (
140 42 50       116 warn "$lineno: Key '$1' with array\n" if $self->{debug};
141 42 50       115 if (ref($value) eq "ARRAY") {
142 0         0 confess "unexpected key,value pair in $filename at line $lineno";
143             }
144            
145 42         82 my $key = $1;
146              
147 42 100       124 if ($self->{features}->{quotedkeys}) {
148 28         61 $key =~ s,\\("|\\),$1,g;
149             }
150            
151 42         81 my $new = [];
152 42         104 $value->{$key} = $new;
153 42         60 $value = $new;
154 42         103 push @stack, $value;
155             } elsif ($line =~ /^\s*\(${TRAILING_WHITESPACE}$/) { # (
156 8 50       22 warn "$lineno: Start of array\n" if $self->{debug};
157 8 50       27 if (ref($value) ne "ARRAY") {
158 0         0 confess "unexpected array entry in $filename at line $lineno";
159             }
160            
161 8         13 my $new = [];
162 8         12 push @{$value}, $new;
  8         17  
163 8         17 $value = $new;
164 8         23 push @stack, $value;
165             } elsif ($line =~ /^\s*\)${TRAILING_WHITESPACE}$/) { # )
166 50 50       133 warn "$lineno: End of array\n" if $self->{debug};
167 50 50       134 if (ref($value) ne "ARRAY") {
168 0         0 confess "mismatched closing round bracket in $filename at line $lineno";
169             }
170 50 50       116 if ($#stack == 0) {
171 0         0 confess "too many closing curley bracket in $filename at line $lineno";
172             }
173            
174 50         71 pop @stack;
175 50         147 $value = $stack[$#stack];
176             } elsif ($line =~ /^\s*$LABEL\s*=\s*{${TRAILING_WHITESPACE}$/ || # foo = {
177             ($self->{features}->{quotedkeys} &&
178             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*{${TRAILING_WHITESPACE}$/)) { # " foo " = {
179 37 50       101 warn "$lineno: Key '$1' with hash\n" if $self->{debug};
180 37 50       103 if (ref($value) eq "ARRAY") {
181 0         0 confess "unexpected key,value pair in $filename at line $lineno";
182             }
183            
184 37         75 my $key = $1;
185            
186 37 100       108 if ($self->{features}->{quotedkeys}) {
187 24         82 $key =~ s,\\("|\\),$1,g;
188             }
189              
190 37         71 my $new = {};
191 37         102 $value->{$key} = $new;
192 37         52 $value = $new;
193 37         110 push @stack, $value;
194             } elsif ($line =~ /^\s*{${TRAILING_WHITESPACE}$/) { # {
195 33 50       94 warn "$lineno: Start of hash\n" if $self->{debug};
196 33 50       91 if (ref($value) ne "ARRAY") {
197 0         0 confess "unexpected array entry in $filename at line $lineno";
198             }
199            
200 33         67 my $new = {};
201 33         404 push @{$value}, $new;
  33         63  
202 33         51 $value = $new;
203 33         96 push @stack, $value;
204             } elsif ($line =~ /^\s*}${TRAILING_WHITESPACE}$/) { # }
205 70 50       216 warn "$lineno: End of hash\n" if $self->{debug};
206 70 50       178 if (ref($value) eq "ARRAY") {
207 0         0 confess "mismatched closing curly bracket in $filename at line $lineno";
208             }
209 70 50       163 if ($#stack == 0) {
210 0         0 confess "too many closing curley bracket in $filename at line $lineno";
211             }
212            
213 70         110 pop @stack;
214 70         227 $value = $stack[$#stack];
215             } elsif ($self->{features}->{includes} &&
216             ($line =~ /^\s*$LABEL\s*=\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/ || # foo = @include(filename)
217             ($self->{features}->{quotedkeys} &&
218             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/))) { # " foo " = @include(filename)
219 1 50       3 warn "$lineno: Include file\n" if $self->{debug};
220 1         3 my $key = $1;
221 1         2 my $file = $2;
222              
223 1 50       5 if ($self->{features}->{quotedkeys}) {
224 0         0 $key =~ s,\\("|\\),$1,g;
225             }
226              
227 1 50       5 my $fh = IO::File->new($file)
228             or confess "cannot read from $file: $!";
229              
230 1         56 local $/ = undef;
231 1         23 my $data = <$fh>;
232 1 50       28 my $record = $self->_parse($data, ref($file) ? "" : $file);
233 1 50       9 $fh->close
234             or confess "cannot close file: $!";
235              
236 1         25 $value->{$key} = $record;
237             } elsif ($line =~ /^\s*$LABEL\s*=\s*<<(\w+)\s*$/ || # foo = <
238             ($self->{features}->{quotedkeys} &&
239             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*<<(\w+)\s*$/)) { # " foo " = <
240 8 50       28 warn "$lineno: Key '$1' with here doc\n" if $self->{debug};
241 8         22 my $key = $1;
242 8         15 my $val = "";
243            
244 8 100       26 if ($self->{features}->{quotedkeys}) {
245 4         9 $key =~ s,\\("|\\),$1,g;
246             }
247              
248 8         23 $value->{$key} = $val;
249              
250 8         19 $here = $2;
251 8         28 $continuation = \$value->{$key};
252             } elsif ($line =~ /^\s*$LABEL\s*=\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/ || # foo = "..."
253             ($self->{features}->{quotedkeys} &&
254             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/) || # " foo " = "..."
255             $line =~ /^\s*$LABEL\s*=\s*(.*?)(\\)?\s*$/ || # foo = ...
256             ($self->{features}->{quotedkeys} &&
257             $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*(.*?)(\\)?\s*$/)) { # " foo " = ...
258 130 50       520 warn "$lineno: Key '$1' with string\n" if $self->{debug};
259 130         261 my $key = $1;
260 130         211 my $val = $2;
261            
262 130 100       353 if ($self->{features}->{quotedkeys}) {
263 76         163 $key =~ s,\\("|\\),$1,g;
264             }
265              
266 130 50       314 if (ref($value) eq "ARRAY") {
267 0         0 confess "expecting value, found key, value pair at line $lineno";
268             }
269            
270 130         507 $value->{$key} = $val;
271 130 50 66     445 warn "$lineno: Start continuation\n" if $3 && $self->{debug};
272 130 100       596 $continuation = \$value->{$key} if $3;
273             } elsif ($line =~ /^\s*<<(\w+)\s*$/) { # <
274 8 50       26 warn "$lineno: Start of here doc\n" if $self->{debug};
275 8         15 my $val = "";
276            
277 8 50       26 if (ref($value) ne "ARRAY") {
278 0         0 confess "expecting key,value pair, found value at line $lineno";
279             }
280              
281 8         14 push @{$value}, $val;
  8         16  
282            
283 8         108 $here = $1;
284 8         17 $continuation = \$value->[$#{$value}];
  8         32  
285             } elsif ($self->{features}->{includes} &&
286             ($line =~ /^\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/)) { # @include(filename)
287 2 50       11 warn "$lineno: Include file\n" if $self->{debug};
288 2         3 my $file = $1;
289              
290 2 50       10 my $fh = IO::File->new($file)
291             or confess "cannot read from $file: $!";
292              
293 2         103 local $/ = undef;
294 2         29 my $data = <$fh>;
295 2 50       9 my $record = $self->_parse($data, ref($file) ? "" : $file);
296 2 50       6 $fh->close
297             or confess "cannot close file: $!";
298              
299 2 50       29 if (ref($value) ne "ARRAY") {
300 0         0 confess "expecting key,value pair, found value at line $lineno";
301             }
302            
303 2         2 push @{$value}, $record;
  2         11  
304             } elsif ($line =~ /^\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/ || # "..."
305             $line =~ /^\s*(.*?)(\\)?\s*$/) { # ...
306 61 50       261 warn "$lineno: Value\n" if $self->{debug};
307 61         113 my $val = $1;
308            
309 61 50       164 if (ref($value) ne "ARRAY") {
310 0         0 confess "expecting key,value pair, found value at line $lineno";
311             }
312            
313 61         77 push @{$value}, $val;
  61         149  
314            
315 61 100       366 $continuation = \$value->[$#{$value}] if $2;
  6         26  
316             } else {
317 0         0 warn "Unexpected value '$line'\n";
318             }
319             }
320             }
321 12 50       64 if ($#stack != 0) {
322 0         0 confess "missing closing bracket in $filename at line $lineno";
323             }
324            
325 12         102 return $stack[$#stack];
326             }
327            
328             sub save {
329 2     2 1 981 my $self = shift;
330            
331 2         5 my $file;
332 2 50       10 if (@_) {
    0          
333 2         7 $file = shift;
334             } elsif ($self->{filename}) {
335 0         0 $file = $self->{filename};
336             } else {
337 0         0 die "no filename was specified";
338             }
339            
340 2         4 my $fh;
341 2 50       9 if (ref($file)) {
342 0 0       0 if (!$file->isa("IO::Handle")) {
343 0         0 confess "file must be an instance of IO::Handle";
344             }
345 0         0 $fh = $file;
346             } else {
347 2 50       19 $fh = IO::File->new(">$file")
348             or confess "cannot write to $file: $!";
349 2         198 $self->{filename} = $file;
350             }
351              
352 2         6 foreach my $key (keys %{$self->{record}}) {
  2         12  
353 22         60 print $fh $self->_format_key($key), " = ";
354 22         75 $self->_format($fh, $self->{record}->{$key}, "");
355             }
356            
357 2         18 $fh->close();
358             }
359              
360             sub _format {
361 79     79   123 my $self = shift;
362 79         108 my $fh = shift;
363 79         124 my $value = shift;
364 79         119 my $indent = shift;
365              
366 79         131 my $ref = ref($value);
367            
368 79 100       152 if ($ref) {
369 29 100       91 if ($ref eq "HASH") {
    50          
370 17         8634 $self->_format_hash($fh, $value, $indent);
371             } elsif ($ref eq "ARRAY") {
372 12         38 $self->_format_array($fh, $value, $indent);
373             } else {
374 0         0 confess "unhandled reference $ref. Configuration files" .
375             "can only contain unblessed scalars, array or hash references";
376             }
377             } else {
378 50         123 $self->_format_scalar($fh, $value, $indent);
379             }
380             }
381              
382             sub _format_hash {
383 17     17   29 my $self = shift;
384 17         25 my $fh = shift;
385 17         26 my $record = shift;
386 17         27 my $indent = shift;
387            
388 17         32 print $fh "{\n";
389 17         26 foreach my $key (keys %{$record}) {
  17         69  
390 30         88 print $fh "$indent ", $self->_format_key($key), " = ";
391 30         131 $self->_format($fh, $record->{$key}, "$indent ");
392             }
393 17         94 print $fh "$indent}\n";
394             }
395              
396             sub _format_array {
397 12     12   17 my $self = shift;
398 12         21 my $fh = shift;
399 12         19 my $list = shift;
400 12         20 my $indent = shift;
401            
402 12         42 print $fh "(\n";
403 12         16 foreach my $element (@{$list}) {
  12         30  
404 27         52 print $fh "$indent ";
405 27         79 $self->_format($fh, $element, "$indent ");
406            
407             }
408 12         50 print $fh "$indent)\n";
409             }
410              
411             sub _format_scalar {
412 50     50   69 my $self = shift;
413 50         68 my $fh = shift;
414 50         69 my $value = shift;
415 50         72 my $indent = shift;
416            
417 50 100 66     370 if ($value =~ /\n/) {
    100          
418 4 50       22 $value .= "\n" unless $value =~ /\n$/;
419 4         9 print $fh "<
420 4         7 print $fh $value;
421 4         14 print $fh "EOF\n";
422             } elsif ($value =~ /^\s+/ ||
423             $value =~ /\s+$/) {
424             # XXX split long lines with \
425             # XXX escape embedded "
426 5         28 print $fh "\"$value\"\n";
427             } else {
428             # XXX split long lines with \
429 41         164 print $fh "$value\n";
430             }
431             }
432              
433             sub _format_key {
434 52     52   74 my $self = shift;
435 52         76 my $key = shift;
436 52 100       139 if ($self->{features}->{quotedkeys}) {
437 33 100       139 if ($key =~ /^((?:\w|-|\.)+)$/) {
438 23         57 return $key;
439             } else {
440 10         23 $key =~ s/\\/\\\\/g;
441 10         21 $key =~ s/"/\\"/g;
442 10         46 return '"' . $key . '"';
443             }
444             } else {
445 19         78 return $key;
446             }
447             }
448              
449              
450             sub view {
451 6     6 1 1557 my $self = shift;
452 6         10 my $key = shift;
453            
454 6         23 my $value = $self->get($key, @_);
455              
456 6 100 100     55 if (!ref($value) ||
457             ref($value) ne "HASH") {
458 4         709 confess "value for $key is not a hash";
459             }
460 2         13 return $self->new(record => $value,
461             debug => $self->{debug},
462             features => $self->{features});
463             }
464              
465              
466             sub get {
467 124     124 1 3466 my $self = shift;
468 124         339 my $key = shift;
469            
470 124         154 my @key;
471              
472 124 50       372 warn "Key: '" . $key . "'\n" if $self->{debug};
473 124         636 foreach (split /((?
474 375 100       1048 next if m,^/$,;
475 249 50       757 warn " -> '" . $_ . "'\n" if $self->{debug};
476 249         546 push @key, $_;
477             }
478              
479 124         272 my $entry = $self->{record};
480 124         170 my $context;
481 124         250 foreach my $fragment (@key) {
482 247 100       629 $context = defined $context ? $context . "/" . $fragment : $fragment;
483            
484 247 100       890 if ($fragment =~ /^\[(\d+)\]$/) {
    100          
485 49         102 my $index = $1;
486 49 100       129 if (ref($entry) ne "ARRAY") {
487 2 50       9 if (@_) {
488 0         0 return shift;
489             }
490 2         302 confess "cannot find array value at '$context' for parameter '$key'";
491             }
492 47 100       59 if ($#{$entry} < $index) {
  47         148  
493 2 50       17 if (@_) {
494 0         0 return shift;
495             }
496 2         503 confess "cannot find array value at '$context' for parameter '$key'";
497             }
498 45         111 $entry = $entry->[$index];
499             } elsif ($self->{features}->{quotedkeys}) {
500 105         171 $fragment =~ s/\\(\[|\]|\/|\\)/$1/g;
501 105 50       269 warn "Quote '$fragment'\n" if $self->{debug};
502 105 50       280 if (ref($entry) ne "HASH") {
503 0 0       0 if (@_) {
504 0         0 return shift;
505             }
506 0         0 confess "cannot find hash value at '$context' for parameter '$key'";
507             }
508 105 100       271 if (!exists $entry->{$fragment}) {
509 4 50       15 if (@_) {
510 4         23 return shift;
511             }
512 0         0 confess "cannot find hash value at '$context' for parameter '$key'";
513             }
514 101         254 $entry = $entry->{$fragment};
515             } else {
516 93 50       210 warn "NonQuote '$fragment'\n" if $self->{debug};
517 93 50       451 if ($fragment =~ /((?:\w|-|\.)+)/) {
518 93 50       234 if (ref($entry) ne "HASH") {
519 0 0       0 if (@_) {
520 0         0 return shift;
521             }
522 0         0 confess "cannot find hash value at '$context' for parameter '$key'";
523             }
524 93 100       312 if (!exists $entry->{$fragment}) {
525 4 50       18 if (@_) {
526 4         29 return shift;
527             }
528 0         0 confess "cannot find hash value at '$context' for parameter '$key'";
529             }
530 89         337 $entry = $entry->{$fragment};
531             } else {
532 0         0 confess "fragment '$fragment' should be alphanumeric, or an array index";
533             }
534             }
535             }
536            
537 112         645 return $entry;
538             }
539              
540              
541             sub set {
542 6     6 1 2637 my $self = shift;
543 6         15 my $key = shift;
544 6         10 my $value = shift;
545            
546 6         10 my @key;
547 6 50       25 warn "Key: '" . $key . "'\n" if $self->{debug};
548 6         83 foreach (split /((?
549 10 100       32 next if m,^/$,;
550 8 50       25 warn " -> '" . $_ . "'\n" if $self->{debug};
551 8         22 push @key, $_;
552             }
553              
554              
555 6         17 my $entry = $self->{record};
556 6         12 my $context;
557 6         27 while (defined (my $fragment = shift @key)) {
558 8 100       25 $context = defined $context ? $context . "/" . $fragment : $fragment;
559            
560 8 100       43 if ($fragment =~ /^\[(\d+)\]$/) {
    100          
561 2         6 my $index = $1;
562 2 50       10 if (ref($entry) ne "ARRAY") {
563 0         0 confess "cannot find array value at $context for parameter $key";
564             }
565 2 50       7 if (@key) {
566 0 0       0 if (exists $entry->[$index]) {
567 0         0 $entry = $entry->[$index];
568             } else {
569 0 0       0 if ($key[0] =~ /^\[(\d+)\]$/) {
570 0         0 $entry->[$index] = [];
571             } else {
572 0         0 $entry->[$index] = {};
573             }
574 0         0 $entry = $entry->[$index];
575             }
576             } else {
577 2         15 $entry->[$index] = $value;
578             }
579             } elsif ($self->{features}->{quotedkeys}) {
580 3         8 $fragment =~ s/\\(\[|\]|\/|\\)/$1/g;
581 3 50       11 warn "Quote '$fragment'\n" if $self->{debug};
582 3 50       11 if (ref($entry) ne "HASH") {
583 0         0 confess "cannot find hash value at $context for parameter $key";
584             }
585 3 100       9 if (@key) {
586 1 50       5 if (exists $entry->{$fragment}) {
587 1         5 $entry = $entry->{$fragment};
588             } else {
589 0 0       0 if ($key[0] =~ /^\[(\d+)\]$/) {
590 0         0 $entry->{$fragment} = [];
591             } else {
592 0         0 $entry->{$fragment} = {};
593             }
594 0         0 $entry = $entry->[$fragment];
595             }
596             } else {
597 2         15 $entry->{$fragment} = $value;
598             }
599             } else {
600 3 50       11 warn "NonQuote '$fragment'\n" if $self->{debug};
601 3 50       19 if ($fragment =~ /((?:\w|-|\.)+)/) {
602 3 50       10 if (ref($entry) ne "HASH") {
603 0         0 confess "cannot find hash value at $context for parameter $key";
604             }
605 3 100       9 if (@key) {
606 1 50       14 if (exists $entry->{$fragment}) {
607 1         11 $entry = $entry->{$fragment};
608             } else {
609 0 0       0 if ($key[0] =~ /^\[(\d+)\]$/) {
610 0         0 $entry->{$fragment} = [];
611             } else {
612 0         0 $entry->{$fragment} = {};
613             }
614 0         0 $entry = $entry->[$fragment];
615             }
616             } else {
617 2         15 $entry->{$fragment} = $value;
618             }
619             } else {
620 0         0 confess "fragment '$fragment' should be alphanumeric, or an array index";
621             }
622             }
623             }
624             }
625              
626              
627             sub record {
628 4     4 1 10 my $self = shift;
629            
630 4         20 return $self->{record};
631             }
632              
633             1 # So that the require or use succeeds.
634