File Coverage

blib/lib/Config/IniFiles.pm
Criterion Covered Total %
statement 798 882 90.4
branch 292 388 75.2
condition 64 117 54.7
subroutine 117 127 92.1
pod 39 39 100.0
total 1310 1553 84.3


line stmt bran cond sub pod time code
1             package Config::IniFiles;
2              
3             require 5.008;
4 37     37   2474009 use strict;
  37         430  
  37         1106  
5 37     37   189 use warnings;
  37         66  
  37         1542  
6              
7             our $VERSION = '3.000001';
8 37     37   215 use Carp;
  37         66  
  37         2349  
9 37     37   16984 use Symbol 'gensym', 'qualify_to_ref'; # For the 'any data type' hack
  37         28555  
  37         2406  
10 37     37   265 use Fcntl qw( SEEK_SET SEEK_CUR );
  37         74  
  37         2031  
11              
12 37     37   228 use List::Util 1.33 qw(any none);
  37         746  
  37         3792  
13              
14 37     37   272 use File::Basename qw( dirname );
  37         72  
  37         2799  
15 37     37   26093 use File::Temp qw/ tempfile /;
  37         716361  
  37         286773  
16              
17             @Config::IniFiles::errors = ();
18              
19             # $Header: /home/shlomi/progs/perl/cpan/Config/IniFiles/config-inifiles-cvsbackup/config-inifiles/IniFiles.pm,v 2.41 2003-12-08 10:50:56 domq Exp $
20              
21              
22             sub _nocase
23             {
24 4840     4840   6988 my $self = shift;
25              
26 4840 100       8881 if (@_)
27             {
28 95 100       317 $self->{nocase} = ( shift(@_) ? 1 : 0 );
29             }
30              
31 4840         9864 return $self->{nocase};
32             }
33              
34             sub _is_parm_in_sect
35             {
36 1568     1568   2902 my ( $self, $sect, $parm ) = @_;
37              
38 1568     2987   4598 return any { $_ eq $parm } @{ $self->{myparms}{$sect} };
  2987         5913  
  1568         5175  
39             }
40              
41             sub new
42             {
43 85     85 1 37880 my $class = shift;
44 85         346 my %parms = @_;
45              
46 85         180 my $errs = 0;
47 85         192 my @groups = ();
48              
49 85         697 my $self = bless {
50             default => '',
51             fallback => undef,
52             fallback_used => 0,
53             imported => undef,
54             v => {},
55             cf => undef,
56             nomultiline => 0,
57             handle_trailing_comment => 0,
58             }, $class;
59              
60 85 100 66     681 if ( ref( $parms{-import} )
    50          
61             && ( $parms{-import}->isa('Config::IniFiles') ) )
62             {
63 9         22 $self->{imported} = $parms{-import}; # ReadConfig will load the data
64 9         20 $self->{negativedeltas} = 1;
65             }
66             elsif ( defined $parms{-import} )
67             {
68 0         0 carp "Invalid -import value \"$parms{-import}\" was ignored.";
69             } # end if
70 85         180 delete $parms{-import};
71              
72             # Copy the original parameters so we
73             # can use them when we build new sections
74 85         238 %{ $self->{startup_settings} } = %parms;
  85         416  
75              
76             # Parse options
77 85         203 my ( $k, $v );
78 85         330 $self->_nocase(0);
79              
80             # Handle known parameters first in this order,
81             # because each() could return parameters in any order
82 85 100       285 if ( defined( $v = delete $parms{'-file'} ) )
83             {
84             # Should we be pedantic and check that the file exists?
85             # .. no, because now it could be a handle, IO:: object or something else
86 68         156 $self->{cf} = $v;
87             }
88 85 100       280 if ( defined( $v = delete $parms{'-nocase'} ) )
89             {
90 10         26 $self->_nocase($v);
91             }
92 85 100       323 if ( defined( $v = delete $parms{'-default'} ) )
93             {
94 7 50       20 $self->{default} = $self->_nocase ? lc($v) : $v;
95             }
96 85 100       299 if ( defined( $v = delete $parms{'-fallback'} ) )
97             {
98 1 50       3 $self->{fallback} = $self->_nocase ? lc($v) : $v;
99             }
100 85 50       250 if ( defined( $v = delete $parms{'-reloadwarn'} ) )
101             {
102 0 0       0 $self->{reloadwarn} = $v ? 1 : 0;
103             }
104 85 100       244 if ( defined( $v = delete $parms{'-nomultiline'} ) )
105             {
106 1 50       4 $self->{nomultiline} = $v ? 1 : 0;
107             }
108 85 100       233 if ( defined( $v = delete $parms{'-allowcontinue'} ) )
109             {
110 1 50       5 $self->{allowcontinue} = $v ? 1 : 0;
111             }
112 85 100       218 if ( defined( $v = delete $parms{'-allowempty'} ) )
113             {
114 11 50       36 $self->{allowempty} = $v ? 1 : 0;
115             }
116 85 50       244 if ( defined( $v = delete $parms{'-negativedeltas'} ) )
117             {
118 0 0       0 $self->{negativedeltas} = $v ? 1 : 0;
119             }
120 85 100       220 if ( defined( $v = delete $parms{'-commentchar'} ) )
121             {
122 2 50 33     22 if ( !defined $v || length($v) != 1 )
    50          
123             {
124 0         0 carp "Comment character must be unique.";
125 0         0 $errs++;
126             }
127             elsif ( $v =~ /[\[\]=\w]/ )
128             {
129             # must not be square bracket, equal sign or alphanumeric
130 0         0 carp "Illegal comment character.";
131 0         0 $errs++;
132             }
133             else
134             {
135 2         18 $self->{comment_char} = $v;
136             }
137             }
138 85 100       233 if ( defined( $v = delete $parms{'-allowedcommentchars'} ) )
139             {
140             # must not be square bracket, equal sign or alphanumeric
141 2 50 33     14 if ( !defined $v || $v =~ /[\[\]=\w]/ )
142             {
143 0         0 carp "Illegal value for -allowedcommentchars.";
144 0         0 $errs++;
145             }
146             else
147             {
148 2         6 $self->{allowed_comment_char} = $v;
149             }
150             }
151              
152 85 100       237 if ( defined( $v = delete $parms{'-handle_trailing_comment'} ) )
153             {
154 4 100       14 $self->{handle_trailing_comment} = $v ? 1 : 0;
155             }
156 85 100       253 if ( defined( $v = delete $parms{'-php_compat'} ) )
157             {
158 1 50       4 $self->{php_compat} = $v ? 1 : 0;
159             }
160              
161 85 100       310 $self->{comment_char} = '#' unless exists $self->{comment_char};
162             $self->{allowed_comment_char} = ';'
163 85 100       253 unless exists $self->{allowed_comment_char};
164              
165             # make sure that comment character is always allowed
166 85         217 $self->{allowed_comment_char} .= $self->{comment_char};
167              
168 85         181 $self->{_comments_at_end_of_file} = [];
169              
170             # Any other parameters are unknown
171 85         349 while ( ( $k, $v ) = each %parms )
172             {
173 0         0 carp "Unknown named parameter $k=>$v";
174 0         0 $errs++;
175             }
176              
177 85 50       216 return undef if $errs;
178              
179 85 100       275 if ( $self->ReadConfig )
180             {
181 81         789 return $self;
182             }
183             else
184             {
185 4         86 return undef;
186             }
187             }
188              
189              
190             sub _caseify
191             {
192 4737     4737   7868 my ( $self, @refs ) = @_;
193              
194 4737 100       8391 if ( $self->_nocase )
195             {
196 1348         2469 foreach my $ref (grep { defined } @refs[0..1])
  2696         5927  
197             {
198 1774         2365 ${$ref} = lc( ${$ref} );
  1774         3105  
  1774         2833  
199             }
200             }
201              
202 4737 100       8730 if ( $self->{php_compat} )
203             {
204 27         54 foreach my $ref (grep { defined } @refs[1..1])
  27         88  
205             {
206 17         23 ${$ref} =~ s{\[\]$}{};
  17         49  
207             }
208 27         57 foreach my $ref (grep { defined } @refs[2..$#refs])
  4         9  
209             {
210 4 100       6 if (length(${$ref}) >= 2)
  4         17  
211             {
212 2         6 my $quote = substr(${$ref}, 0, 1);
  2         7  
213 2 50 66     12 if (($quote eq q{"} or $quote eq q{'}) and substr(${$ref}, -1, 1) eq $quote)
  2   33     8  
214             {
215 2         3 ${$ref} = substr(${$ref}, 1, -1);
  2         4  
  2         5  
216 2         3 ${$ref} =~ s{$quote$quote}{}g;
  2         26  
217 2 100       8 ${$ref} =~ s{\\$quote}{$quote}g if $quote eq q{"};
  1         22  
218             }
219             }
220             }
221             }
222              
223 4737         7217 return;
224             }
225              
226             sub val
227             {
228 107     107 1 15405 my ( $self, $sect, $parm, $def ) = @_;
229              
230             # Always return undef on bad parameters
231 107 50 33     504 if ( not( defined($sect) && defined($parm) ) )
232             {
233 0         0 return;
234             }
235              
236 107         367 $self->_caseify( \$sect, \$parm );
237              
238             my $val_sect =
239             defined( $self->{v}{$sect}{$parm} )
240             ? $sect
241 107 100       393 : $self->{default};
242              
243 107         239 my $val = $self->{v}{$val_sect}{$parm};
244              
245             # If the value is undef, make it $def instead (which could just be undef)
246 107 100       251 if ( !defined($val) )
247             {
248 7         13 $val = $def;
249             }
250              
251             # Return the value in the desired context
252 107 100       324 if (wantarray)
    100          
253             {
254 34 100       118 if ( ref($val) eq "ARRAY" )
    100          
255             {
256 12         53 return @$val;
257             }
258             elsif ( defined($val) )
259             {
260 20         110 return $val;
261             }
262             else
263             {
264 2         6 return;
265             }
266             }
267             elsif ( ref($val) eq "ARRAY" )
268             {
269 5 50       76 return join( ( defined($/) ? $/ : "\n" ), @$val );
270             }
271             else
272             {
273 68         285 return $val;
274             }
275             }
276              
277              
278             sub exists
279             {
280 2     2 1 15 my ( $self, $sect, $parm ) = @_;
281              
282 2         11 $self->_caseify( \$sect, \$parm );
283              
284 2         19 return ( exists $self->{v}{$sect}{$parm} );
285             }
286              
287              
288             sub push
289             {
290 92     92 1 270 my ( $self, $sect, $parm, @vals ) = @_;
291              
292 92 50       207 return undef if not defined $sect;
293 92 50       201 return undef if not defined $parm;
294              
295 92         280 $self->_caseify( \$sect, \$parm );
296              
297 92 50       254 return undef if ( !defined( $self->{v}{$sect}{$parm} ) );
298              
299 92 50       222 return 1 if ( !@vals );
300              
301 92         262 $self->_touch_parameter( $sect, $parm );
302              
303             $self->{EOT}{$sect}{$parm} = 'EOT'
304 92 100       348 if ( !defined $self->{EOT}{$sect}{$parm} );
305              
306             $self->{v}{$sect}{$parm} = [ $self->{v}{$sect}{$parm} ]
307 92 100       354 unless ( ref( $self->{v}{$sect}{$parm} ) eq "ARRAY" );
308              
309 92         148 CORE::push @{ $self->{v}{$sect}{$parm} }, @vals;
  92         295  
310 92         197 return 1;
311             }
312              
313              
314             sub setval
315             {
316 1     1 1 1219 my $self = shift;
317 1         3 my $sect = shift;
318 1         2 my $parm = shift;
319 1         4 my @val = @_;
320              
321 1 50       3 return undef if not defined $sect;
322 1 50       3 return undef if not defined $parm;
323              
324 1         4 $self->_caseify( \$sect, \$parm );
325              
326 1 50       4 if ( defined( $self->{v}{$sect}{$parm} ) )
327             {
328 0         0 $self->_touch_parameter( $sect, $parm );
329 0 0       0 if ( @val > 1 )
330             {
331 0         0 $self->{v}{$sect}{$parm} = \@val;
332 0         0 $self->{EOT}{$sect}{$parm} = 'EOT';
333             }
334             else
335             {
336 0         0 $self->{v}{$sect}{$parm} = shift @val;
337             }
338 0         0 return 1;
339             }
340             else
341             {
342 1         3 return undef;
343             }
344             }
345              
346              
347             sub newval
348             {
349 638     638 1 4714 my $self = shift;
350 638         949 my $sect = shift;
351 638         952 my $parm = shift;
352 638         1302 my @val = @_;
353              
354 638 50       1312 return undef if not defined $sect;
355 638 50       1176 return undef if not defined $parm;
356              
357 638         1674 $self->_caseify( \$sect, \$parm );
358              
359 638         1634 $self->AddSection($sect);
360              
361 638 100   896   2260 if ( none { $_ eq $parm } @{ $self->{parms}{$sect} } )
  896         1442  
  638         2495  
362             {
363 611         890 CORE::push( @{ $self->{parms}{$sect} }, $parm );
  611         1482  
364             }
365              
366 638         2632 $self->_touch_parameter( $sect, $parm );
367 638 100       1443 if ( @val > 1 )
368             {
369 112         333 $self->{v}{$sect}{$parm} = \@val;
370 112 100       375 if ( !defined $self->{EOT}{$sect}{$parm} )
371             {
372 105         276 $self->{EOT}{$sect}{$parm} = 'EOT';
373             }
374             }
375             else
376             {
377 526         1494 $self->{v}{$sect}{$parm} = shift @val;
378             }
379 638         1225 return 1;
380             }
381              
382              
383             sub delval
384             {
385 6     6 1 1977 my $self = shift;
386 6         16 my $sect = shift;
387 6         14 my $parm = shift;
388              
389 6 50       22 return undef if not defined $sect;
390 6 50       18 return undef if not defined $parm;
391              
392 6         28 $self->_caseify( \$sect, \$parm );
393              
394 6         17 $self->{parms}{$sect} = [ grep { $_ ne $parm } @{ $self->{parms}{$sect} } ];
  24         74  
  6         23  
395 6         29 $self->_touch_parameter( $sect, $parm );
396 6         17 delete $self->{v}{$sect}{$parm};
397              
398 6         33 return 1;
399             }
400              
401              
402             # Auxiliary function to make deep (aliasing-free) copies of data
403             # structures. Ignores blessed objects in tree (could be taught not
404             # to, if needed)
405             sub _deepcopy
406             {
407 411     411   580 my $ref = shift;
408              
409 411 100       694 if ( !ref($ref) )
410             {
411 206         511 return $ref;
412             }
413              
414 205 100       765 if ( UNIVERSAL::isa( $ref, "ARRAY" ) )
415             {
416 64         129 return [ map { _deepcopy($_) } @$ref ];
  118         209  
417             }
418              
419 141 50       252 if ( UNIVERSAL::isa( $ref, "HASH" ) )
420             {
421 141         201 my $return = {};
422 141         317 foreach my $k ( keys %$ref )
423             {
424 178         285 $return->{$k} = _deepcopy( $ref->{$k} );
425             }
426 141         307 return $return;
427             }
428              
429 0         0 carp "Unhandled data structure in $ref, cannot _deepcopy()";
430             }
431              
432             # Internal method, gets the next line, taking proper care of line endings.
433             sub _nextline
434             {
435 2057     2057   3152 my ( $self, $fh ) = @_;
436 2057         2998 my $s = '';
437 2057 100       3973 if ( !exists $self->{line_ends} )
438             {
439             # no $self->{line_ends} is a hint set by caller that we are at
440             # the first line (kludge kludge).
441             {
442 82         141 local $/ = \1;
  82         444  
443 82         150 my $nextchar;
444             do
445 82         132 {
446 1108         3063 $nextchar = <$fh>;
447 1108 100       2703 return undef if ( !defined $nextchar );
448 1096         2668 $s .= $nextchar;
449             } until ($s =~ m/((\015|\012|\025|\n)$)/s);
450 70         348 $self->{line_ends} = $1;
451 70 100       411 if ( $nextchar eq "\x0d" )
452             {
453             # peek at the next char
454 4         11 $nextchar = <$fh>;
455 4 100       31 if ( $nextchar eq "\x0a" )
456             {
457 3         14 $self->{line_ends} .= "\x0a";
458             }
459             else
460             {
461 1         14 seek $fh, -1, SEEK_CUR();
462             }
463             }
464             }
465              
466             # If there's a UTF BOM (Byte-Order-Mark) in the first
467             # character of the first line then remove it before processing
468             # ( http://www.unicode.org/unicode/faq/utf_bom.html#22 )
469 70         319 $s =~ s/\A//;
470              
471 70         422 return $s;
472             }
473             else
474             {
475 1975         6443 local $/ = $self->{line_ends};
476 1975         8210 return scalar <$fh>;
477             }
478             }
479              
480             # Internal method, closes or resets the file handle. To be called
481             # whenever ReadConfig() returns.
482             sub _rollback
483             {
484 82     82   274 my ( $self, $fh ) = @_;
485              
486             # Only close if this is a filename, if it's
487             # an open handle, then just roll back to the start
488 82 100       333 if ( !ref( $self->{cf} ) )
489             {
490 70         859 close($fh);
491             }
492             else
493             {
494             # Attempt to rollback to beginning, no problem if this fails (e.g. STDIN)
495 12         106 seek( $fh, 0, SEEK_SET() );
496             } # end if
497             }
498              
499             sub _no_filename
500             {
501 115     115   192 my $self = shift;
502              
503 115         217 my $fn = $self->{cf};
504              
505 115   66     752 return ( not( defined($fn) && length($fn) ) );
506             }
507              
508             sub _read_line_num
509             {
510 4170     4170   5724 my $self = shift;
511              
512 4170 100       7608 if (@_)
513             {
514 2059         3104 $self->{_read_line_num} = shift;
515             }
516              
517 4170         8140 return $self->{_read_line_num};
518             }
519              
520             # Reads the next line and removes the end of line from it.
521             sub _read_next_line
522             {
523 2057     2057   3624 my ( $self, $fh ) = @_;
524              
525 2057         3810 my $line = $self->_nextline($fh);
526              
527 2057 100       4920 if ( !defined($line) )
528             {
529 80         294 return undef;
530             }
531              
532 1977         3460 $self->_read_line_num( $self->_read_line_num() + 1 );
533              
534             # Remove line ending char(s)
535 1977         9688 $line =~ s/(\015\012?|\012|\025|\n)\z//;
536              
537 1977         5848 return $line;
538             }
539              
540             sub _add_error
541             {
542 6     6   17 my ( $self, $msg ) = @_;
543              
544 6         13 CORE::push( @Config::IniFiles::errors, $msg );
545              
546 6         12 return;
547             }
548              
549             # The current section - used for parsing.
550             sub _curr_sect
551             {
552 5577     5577   7518 my $self = shift;
553              
554 5577 100       10243 if (@_)
555             {
556 416         760 $self->{_curr_sect} = shift;
557             }
558              
559 5577         12520 return $self->{_curr_sect};
560             }
561              
562             # The current parameter - used for parsing.
563             sub _curr_parm
564             {
565 3766     3766   5151 my $self = shift;
566              
567 3766 100       6530 if (@_)
568             {
569 771         1305 $self->{_curr_parm} = shift;
570             }
571              
572 3766         8398 return $self->{_curr_parm};
573             }
574              
575             # Current location - section and parameter.
576             sub _curr_loc
577             {
578 2306     2306   3332 my $self = shift;
579              
580 2306         3622 return ( $self->_curr_sect, $self->_curr_parm );
581             }
582              
583             # The current value - used in parsing.
584             sub _curr_val
585             {
586 2084     2084   2843 my $self = shift;
587              
588 2084 100       3637 if (@_)
589             {
590 804         1429 $self->{_curr_val} = shift;
591             }
592              
593 2084         4392 return $self->{_curr_val};
594             }
595              
596             sub _curr_cmts
597             {
598 2323     2323   3249 my $self = shift;
599              
600 2323 100       4192 if (@_)
601             {
602 1104         1812 $self->{_curr_cmts} = shift;
603             }
604              
605 2323         5308 return $self->{_curr_cmts};
606             }
607              
608             sub _curr_end_comment
609             {
610 1940     1940   2691 my $self = shift;
611              
612 1940 100       3559 if (@_)
613             {
614 1251         2104 $self->{_curr_end_comment} = shift;
615             }
616              
617 1940         3692 return $self->{_curr_end_comment};
618             }
619              
620             my $RET_CONTINUE = 1;
621             my $RET_BREAK;
622              
623             sub _ReadConfig_handle_comment
624             {
625 120     120   245 my ( $self, $line ) = @_;
626              
627 120 100 66     407 if ( $self->{negativedeltas}
628             and my ($to_delete) =
629             $line =~ m/\A$self->{comment_char} (.*) is deleted\z/ )
630             {
631 2 100       11 if ( my ($sect) = $to_delete =~ m/\A\[(.*)\]\z/ )
632             {
633 1         3 $self->DeleteSection($sect);
634             }
635             else
636             {
637 1         4 $self->delval( $self->_curr_sect, $to_delete );
638             }
639             }
640             else
641             {
642 118         168 CORE::push( @{ $self->_curr_cmts }, $line );
  118         225  
643             }
644              
645 120         460 return $RET_CONTINUE;
646             }
647              
648             sub _ReadConfig_new_section
649             {
650 333     333   625 my ( $self, $sect ) = @_;
651              
652 333         956 $self->_caseify( undef, \$sect );
653              
654 333         812 $self->_curr_sect($sect);
655 333         615 $self->AddSection( $self->_curr_sect );
656 333         757 $self->SetSectionComment( $self->_curr_sect, @{ $self->_curr_cmts } );
  333         639  
657 333         945 $self->_curr_cmts( [] );
658              
659 333         1314 return $RET_CONTINUE;
660             }
661              
662             sub _handle_fallback_sect
663             {
664 691     691   1093 my ($self) = @_;
665              
666 691 100 100     1337 if ( ( !defined( $self->_curr_sect ) ) and defined( $self->{fallback} ) )
667             {
668 1         4 $self->_curr_sect( $self->{fallback} );
669 1         2 $self->{fallback_used}++;
670             }
671              
672 691         1159 return;
673             }
674              
675             sub _ReadConfig_load_value
676             {
677 689     689   1086 my ( $self, $val_aref ) = @_;
678              
679             # Now load value
680 689 100 100     1306 if ( exists $self->{v}{ $self->_curr_sect }{ $self->_curr_parm }
      100        
681             && exists $self->{myparms}{ $self->_curr_sect }
682             && $self->_is_parm_in_sect( $self->_curr_loc ) )
683             {
684 92         199 $self->push( $self->_curr_loc, @$val_aref );
685             }
686             else
687             {
688             # Loaded parameters shadow imported ones, instead of appending
689             # to them
690 597         1192 $self->newval( $self->_curr_loc, @$val_aref );
691             }
692              
693 689         1357 return;
694             }
695              
696             sub _test_for_fallback_or_no_sect
697             {
698 691     691   1231 my ( $self, $fh ) = @_;
699              
700 691         1626 $self->_handle_fallback_sect;
701              
702 691 100       1254 if ( !defined $self->_curr_sect )
703             {
704 2         7 $self->_add_error(
705             sprintf( '%d: %s',
706             $self->_read_line_num(),
707             qq#parameter found outside a section# )
708             );
709 2         9 $self->_rollback($fh);
710 2         13 return $RET_BREAK;
711             }
712              
713 689         1565 return $RET_CONTINUE;
714             }
715              
716             sub _ReadConfig_handle_here_doc_param
717             {
718 129     129   282 my ( $self, $fh, $eotmark, $val_aref ) = @_;
719              
720 129         202 my $foundeot = 0;
721 129         320 my $startline = $self->_read_line_num();
722              
723             HERE_DOC_LOOP:
724 129         324 while ( defined( my $line = $self->_read_next_line($fh) ) )
725             {
726 497 100       1037 if ( $line eq $eotmark )
727             {
728 129         200 $foundeot = 1;
729 129         298 last HERE_DOC_LOOP;
730             }
731             else
732             {
733             # Untaint
734 368         1026 my ($contents) = $line =~ /(.*)/ms;
735 368         1031 CORE::push( @$val_aref, $contents );
736             }
737             }
738              
739 129 50       315 if ( !$foundeot )
740             {
741 0         0 $self->_add_error(
742             sprintf( '%d: %s',
743             $startline, qq#no end marker ("$eotmark") found# )
744             );
745 0         0 $self->_rollback();
746 0         0 return $RET_BREAK;
747             }
748              
749 129         357 return $RET_CONTINUE;
750             }
751              
752             sub _ReadConfig_handle_non_here_doc_param
753             {
754 560     560   968 my ( $self, $fh, $val_aref ) = @_;
755              
756 560         916 my $allCmt = $self->{allowed_comment_char};
757 560         821 my $end_commenthandle = $self->{handle_trailing_comment};
758              
759             # process continuation lines, if any
760 560         1461 $self->_process_continue_val($fh);
761              
762             # we should split value and comments if there is any comment
763 560 100 66     1344 if ( $end_commenthandle
764             and my ( $value_to_assign, $end_comment_to_assign ) =
765             $self->_curr_val =~ /(.*?)\s*[$allCmt]\s*(.*)$/ )
766             {
767 4         15 $self->_curr_val($value_to_assign);
768 4         17 $self->_curr_end_comment($end_comment_to_assign);
769             }
770             else
771             {
772 556         1008 $self->_curr_end_comment(q{});
773             }
774              
775 560         1015 @{$val_aref} = ( $self->_curr_val );
  560         929  
776              
777 560         979 return;
778             }
779              
780             sub _ReadConfig_populate_values
781             {
782 689     689   1228 my ( $self, $val_aref, $eotmark ) = @_;
783              
784 689         1602 $self->_ReadConfig_load_value($val_aref);
785              
786 689         1447 $self->SetParameterComment( $self->_curr_loc, @{ $self->_curr_cmts } );
  689         1263  
787 689         1894 $self->_curr_cmts( [] );
788 689 100       1383 if ( defined $eotmark )
789             {
790 129         286 $self->SetParameterEOT( $self->_curr_loc, $eotmark );
791             }
792              
793             # if handle_trailing_comment is off, this line makes no sense, since all $end_comment=""
794 689         1335 $self->SetParameterTrailingComment( $self->_curr_loc,
795             $self->_curr_end_comment );
796              
797 689         1187 return;
798             }
799              
800             sub _ReadConfig_param_assignment
801             {
802 691     691   1488 my ( $self, $fh, $line, $parm, $value_to_assign ) = @_;
803              
804 691         1966 $self->_caseify( undef, \$parm, \$value_to_assign );
805              
806 691         1628 $self->_curr_val($value_to_assign);
807 691         1595 $self->_curr_end_comment( undef() );
808              
809 691 100       1417 if ( !defined( $self->_test_for_fallback_or_no_sect($fh) ) )
810             {
811              
812 2         10 return $RET_BREAK;
813             }
814              
815 689         1609 $self->_curr_parm($parm);
816              
817 689         1056 my @val = ();
818 689         880 my $eotmark;
819              
820 689 100       1259 if ( ($eotmark) = $self->_curr_val =~ /\A<<(.*)$/ )
821             {
822 129 50       363 if (
823             !defined(
824             $self->_ReadConfig_handle_here_doc_param(
825             $fh, $eotmark, \@val
826             )
827             )
828             )
829             {
830 0         0 return $RET_BREAK;
831             }
832             }
833             else
834             {
835 560         1321 $self->_ReadConfig_handle_non_here_doc_param( $fh, \@val );
836             }
837              
838 689         1956 $self->_ReadConfig_populate_values( \@val, $eotmark );
839              
840 689         2919 return $RET_CONTINUE;
841             }
842              
843             # Return 1 to continue - undef to terminate the loop.
844             sub _ReadConfig_handle_line
845             {
846 1478     1478   2609 my ( $self, $fh, $line ) = @_;
847              
848 1478         2388 my $allCmt = $self->{allowed_comment_char};
849              
850             # ignore blank lines
851 1478 100       4796 if ( $line =~ /\A\s*\z/ )
852             {
853 331         1371 return $RET_CONTINUE;
854             }
855              
856             # collect comments
857 1147 100       5108 if ( $line =~ /\A\s*[$allCmt]/ )
858             {
859 120         309 return $self->_ReadConfig_handle_comment($line);
860             }
861              
862             # New Section
863 1027 100       3595 if ( my ($sect) = $line =~ /\A\s*\[\s*(\S|\S.*\S)\s*\]\s*\z/ )
864             {
865 333         876 return $self->_ReadConfig_new_section($sect);
866             }
867              
868             # New parameter
869 694 100       3937 if ( my ( $parm, $value_to_assign ) =
870             $line =~ /^\s*([^=]*?[^=\s])\s*=\s*(.*)$/ )
871             {
872 691         1680 return $self->_ReadConfig_param_assignment( $fh, $line, $parm,
873             $value_to_assign );
874             }
875              
876             $self->_add_error(
877 3         7 sprintf(
878             "Line %d in file %s is malformed:\n\t\%s",
879             $self->_read_line_num(),
880             $self->GetFileName(), $line
881             )
882             );
883              
884 3         10 return $RET_CONTINUE;
885             }
886              
887             sub _ReadConfig_lines_loop
888             {
889 82     82   218 my ( $self, $fh ) = @_;
890              
891 82         283 $self->_curr_sect( undef() );
892 82         239 $self->_curr_parm( undef() );
893 82         253 $self->_curr_val( undef() );
894 82         268 $self->_curr_cmts( [] );
895              
896 82         255 while ( defined( my $line = $self->_read_next_line($fh) ) )
897             {
898 1478 100       3137 if (
899             !defined( scalar( $self->_ReadConfig_handle_line( $fh, $line ) ) ) )
900             {
901 2         10 return undef;
902             }
903             }
904              
905 80         312 return 1;
906             }
907              
908             sub ReadConfig
909             {
910 99     99 1 239 my $self = shift;
911              
912 99         226 @Config::IniFiles::errors = ();
913              
914             # Initialize (and clear out) storage hashes
915 99         225 $self->{sects} = [];
916 99         290 $self->{parms} = {};
917 99         300 $self->{group} = {};
918 99         278 $self->{v} = {};
919 99         207 $self->{sCMT} = {};
920 99         252 $self->{pCMT} = {};
921 99         201 $self->{EOT} = {};
922             $self->{mysects} =
923 99         197 []; # A pair of hashes to remember which params are loaded
924 99         216 $self->{myparms} = {}; # or set using the API vs. imported - useful for
925             $self->{peCMT} =
926 99         227 {}; # this will store trailing comments at the end of single-line params
927 99         191 $self->{e} = {}; # If a section already exists
928 99         201 $self->{mye} = {}; # If a section already exists
929             # import shadowing, see below, and WriteConfig($fn, -delta=>1)
930              
931 99 100       261 if ( defined $self->{imported} )
932             {
933 13         30 foreach my $field (qw(sects parms group v sCMT pCMT EOT e))
934             {
935 104         201 $self->{$field} = _deepcopy( $self->{imported}->{$field} );
936             }
937             }
938              
939 99 100       305 if ( $self->_no_filename )
940             {
941 17         58 return 1;
942             }
943              
944             # If we want warnings, then send one to the STDERR log
945 82 50       279 if ( $self->{reloadwarn} )
946             {
947 0         0 my ( $ss, $mm, $hh, $DD, $MM, $YY ) = ( localtime(time) )[ 0 .. 5 ];
948             printf STDERR
949             "PID %d reloading config file %s at %d.%02d.%02d %02d:%02d:%02d\n",
950 0         0 $$, $self->{cf}, $YY + 1900, $MM + 1, $DD, $hh, $mm, $ss;
951             }
952              
953             # Get a filehandle, allowing almost any type of 'file' parameter
954 82         310 my $fh = $self->_make_filehandle( $self->{cf} );
955 82 50       610 if ( !$fh )
956             {
957 0         0 carp "Failed to open $self->{cf}: $!";
958 0         0 return undef;
959             }
960              
961             # Get mod time of file so we can retain it (if not from STDIN)
962             # also check if it's a real file (could have been a filehandle made from a scalar).
963 82 100 100     1142 if ( ref($fh) ne "IO::Scalar" && -e $fh )
964             {
965 78         935 my @stats = stat $fh;
966 78 50       700 $self->{file_mode} = sprintf( "%04o", $stats[2] ) if defined $stats[2];
967             }
968              
969             # The first lines of the file must be blank, comments or start with [
970 82         192 my $first = '';
971              
972 82         172 delete $self->{line_ends}; # Marks start of parsing for _nextline()
973              
974 82         322 $self->_read_line_num(0);
975              
976 82 100       247 if ( !defined( $self->_ReadConfig_lines_loop($fh) ) )
977             {
978 2         11 return undef;
979             }
980              
981             # Special case: return undef if file is empty. (suppress this line to
982             # restore the more intuitive behaviour of accepting empty files)
983 80 100 100     180 if ( !keys %{ $self->{v} } && !$self->{allowempty} )
  80         433  
984             {
985 1         5 $self->_add_error("Empty file treated as error");
986 1         4 $self->_rollback($fh);
987 1         7 return undef;
988             }
989              
990 79 100       327 if ( defined( my $defaultsect = $self->{startup_settings}->{-default} ) )
991             {
992 11         66 $self->AddSection($defaultsect);
993             }
994              
995 79         167 $self->_SetEndComments( @{ $self->_curr_cmts } );
  79         220  
996              
997 79         272 $self->_rollback($fh);
998 79 100       611 return ( @Config::IniFiles::errors ? undef : 1 );
999             }
1000              
1001              
1002             sub Sections
1003             {
1004 4     4 1 17 my $self = shift;
1005              
1006 4         7 return @{ _aref_or_empty( $self->{sects} ) };
  4         15  
1007             }
1008              
1009              
1010             sub SectionExists
1011             {
1012 994     994 1 1885 my $self = shift;
1013 994         1541 my $sect = shift;
1014              
1015 994 50       1865 return undef if not defined $sect;
1016              
1017 994         2295 $self->_caseify( \$sect );
1018              
1019 994 100       2916 return ( ( exists $self->{e}{$sect} ) ? 1 : 0 );
1020             }
1021              
1022              
1023             sub _AddSection_Helper
1024             {
1025 354     354   682 my ( $self, $sect ) = @_;
1026 354         854 $self->{e}{$sect} = 1;
1027 354         515 CORE::push @{ $self->{sects} }, $sect;
  354         856  
1028 354         953 $self->_touch_section($sect);
1029              
1030 354         958 $self->SetGroupMember($sect);
1031              
1032             # Set up the parameter names and values lists
1033 354   50     1818 $self->{parms}{$sect} ||= [];
1034              
1035 354 100       961 if ( !defined( $self->{v}{$sect} ) )
1036             {
1037 353         725 $self->{sCMT}{$sect} = [];
1038 353         764 $self->{pCMT}{$sect} = {}; # Comments above parameters
1039 353         689 $self->{parms}{$sect} = [];
1040 353         678 $self->{v}{$sect} = {};
1041             }
1042              
1043 354         671 return;
1044             }
1045              
1046             sub AddSection
1047             {
1048 988     988 1 1845 my ( $self, $sect ) = @_;
1049              
1050 988 50       1940 return undef if not defined $sect;
1051              
1052 988         2349 $self->_caseify( \$sect );
1053              
1054 988 100       2140 if ( $self->SectionExists($sect) )
1055             {
1056 636         1027 return;
1057             }
1058              
1059 352         873 return $self->_AddSection_Helper($sect);
1060             }
1061              
1062             # Marks a section as modified by us (this includes deleted by us).
1063             sub _touch_section
1064             {
1065 1891     1891   3099 my ( $self, $sect ) = @_;
1066              
1067 1891   50     3944 $self->{mysects} ||= [];
1068              
1069 1891 100       3888 unless ( exists $self->{mye}{$sect} )
1070             {
1071 363         510 CORE::push @{ $self->{mysects} }, $sect;
  363         757  
1072 363         768 $self->{mye}{$sect} = 1;
1073             }
1074              
1075 1891         2849 return;
1076             }
1077              
1078             # Marks a parameter as modified by us (this includes deleted by us).
1079             sub _touch_parameter
1080             {
1081 1458     1458   2729 my ( $self, $sect, $parm ) = @_;
1082              
1083 1458         3284 $self->_touch_section($sect);
1084 1458 50       2748 return if ( !exists $self->{v}{$sect} );
1085 1458   100     3788 $self->{myparms}{$sect} ||= [];
1086              
1087 1458 100       2890 if ( !$self->_is_parm_in_sect( $sect, $parm ) )
1088             {
1089 637         945 CORE::push @{ $self->{myparms}{$sect} }, $parm;
  637         1515  
1090             }
1091              
1092 1458         4072 return;
1093             }
1094              
1095              
1096             sub DeleteSection
1097             {
1098 7     7 1 18 my $self = shift;
1099 7         14 my $sect = shift;
1100              
1101 7 50       19 return undef if not defined $sect;
1102              
1103 7         36 $self->_caseify( \$sect );
1104              
1105             # This is done the fast way, change if data structure changes!!
1106 7         26 delete $self->{v}{$sect};
1107 7         16 delete $self->{sCMT}{$sect};
1108 7         18 delete $self->{pCMT}{$sect};
1109 7         16 delete $self->{EOT}{$sect};
1110 7         14 delete $self->{parms}{$sect};
1111 7         16 delete $self->{myparms}{$sect};
1112 7         14 delete $self->{e}{$sect};
1113              
1114 7         12 $self->{sects} = [ grep { $_ ne $sect } @{ $self->{sects} } ];
  29         66  
  7         19  
1115 7         30 $self->_touch_section($sect);
1116              
1117 7         24 $self->RemoveGroupMember($sect);
1118              
1119 7         18 return 1;
1120             } # end DeleteSection
1121              
1122              
1123             sub RenameSection
1124             {
1125 1     1 1 3 my $self = shift;
1126 1         3 my $old_sect = shift;
1127 1         2 my $new_sect = shift;
1128 1         3 my $include_groupmembers = shift;
1129             return undef
1130 1 50       3 unless $self->CopySection( $old_sect, $new_sect,
1131             $include_groupmembers );
1132 1         6 return $self->DeleteSection($old_sect);
1133              
1134             } # end RenameSection
1135              
1136              
1137             sub CopySection
1138             {
1139 2     2 1 4 my $self = shift;
1140 2         5 my $old_sect = shift;
1141 2         3 my $new_sect = shift;
1142 2         3 my $include_groupmembers = shift;
1143              
1144 2 50 33     16 if ( not defined $old_sect
      33        
1145             or not defined $new_sect
1146             or !$self->SectionExists($old_sect)
1147             or $self->SectionExists($new_sect) )
1148             {
1149 0         0 return undef;
1150             }
1151              
1152 2         7 $self->_caseify( \$new_sect );
1153 2         7 $self->_AddSection_Helper($new_sect);
1154              
1155             # This is done the fast way, change if data structure changes!!
1156 2         5 foreach my $key (qw(v sCMT pCMT EOT parms myparms e))
1157             {
1158 14 100       36 next unless exists $self->{$key}{$old_sect};
1159             $self->{$key}{$new_sect} =
1160 11         20 Config::IniFiles::_deepcopy( $self->{$key}{$old_sect} );
1161             }
1162              
1163 2 50       5 if ($include_groupmembers)
1164             {
1165 0         0 foreach my $old_groupmember ( $self->GroupMembers($old_sect) )
1166             {
1167 0         0 my $new_groupmember = $old_groupmember;
1168 0         0 $new_groupmember =~ s/\A\Q$old_sect\E/$new_sect/;
1169 0         0 $self->CopySection( $old_groupmember, $new_groupmember );
1170             }
1171             }
1172              
1173 2         28 return 1;
1174             } # end CopySection
1175              
1176              
1177             sub _aref_or_empty
1178             {
1179 32     32   73 my ($aref) = @_;
1180              
1181 32 100 66     226 return ( ( defined($aref) and ref($aref) eq 'ARRAY' ) ? $aref : [] );
1182             }
1183              
1184             sub Parameters
1185             {
1186 22     22 1 769 my $self = shift;
1187 22         36 my $sect = shift;
1188              
1189 22 50       51 return undef if not defined $sect;
1190              
1191 22         61 $self->_caseify( \$sect );
1192              
1193 22         32 return @{ _aref_or_empty( $self->{parms}{$sect} ) };
  22         56  
1194             }
1195              
1196              
1197             sub Groups
1198             {
1199 2     2 1 14 my $self = shift;
1200              
1201 2 50       10 if ( ref( $self->{group} ) eq 'HASH' )
1202             {
1203 2         36 return keys %{ $self->{group} };
  2         17  
1204             }
1205             else
1206             {
1207 0         0 return ();
1208             }
1209             }
1210              
1211              
1212             sub _group_member_handling_skeleton
1213             {
1214 361     361   757 my ( $self, $sect, $method ) = @_;
1215              
1216 361 50       783 return undef if not defined $sect;
1217              
1218 361 100       1582 if ( !( my ($group) = ( $sect =~ /\A(\S+)\s+\S/ ) ) )
1219             {
1220 234         473 return 1;
1221             }
1222             else
1223             {
1224 127         426 return $self->$method( $sect, $group );
1225             }
1226             }
1227              
1228             sub _SetGroupMember_helper
1229             {
1230 127     127   264 my ( $self, $sect, $group ) = @_;
1231              
1232 127 100       309 if ( not exists( $self->{group}{$group} ) )
1233             {
1234 69         214 $self->{group}{$group} = [];
1235             }
1236              
1237 127 50   86   468 if ( none { $_ eq $sect } @{ $self->{group}{$group} } )
  86         187  
  127         579  
1238             {
1239 127         190 CORE::push @{ $self->{group}{$group} }, $sect;
  127         296  
1240             }
1241              
1242 127         430 return;
1243             }
1244              
1245             sub SetGroupMember
1246             {
1247 354     354 1 705 my ( $self, $sect ) = @_;
1248              
1249 354         823 return $self->_group_member_handling_skeleton( $sect,
1250             '_SetGroupMember_helper' );
1251             }
1252              
1253              
1254             sub _RemoveGroupMember_helper
1255             {
1256 0     0   0 my ( $self, $sect, $group ) = @_;
1257              
1258 0 0       0 if ( !exists $self->{group}{$group} )
1259             {
1260 0         0 return;
1261             }
1262              
1263             $self->{group}{$group} =
1264 0         0 [ grep { $_ ne $sect } @{ $self->{group}{$group} } ];
  0         0  
  0         0  
1265              
1266 0         0 return;
1267             }
1268              
1269             sub RemoveGroupMember
1270             {
1271 7     7 1 16 my ( $self, $sect ) = @_;
1272              
1273 7         20 return $self->_group_member_handling_skeleton( $sect,
1274             '_RemoveGroupMember_helper' );
1275             }
1276              
1277              
1278             sub GroupMembers
1279             {
1280 6     6 1 925 my ( $self, $group ) = @_;
1281              
1282 6 50       19 return undef if not defined $group;
1283              
1284 6         23 $self->_caseify( \$group );
1285              
1286 6         9 return @{ _aref_or_empty( $self->{group}{$group} ) };
  6         24  
1287             }
1288              
1289              
1290             sub SetWriteMode
1291             {
1292 5     5 1 60 my ( $self, $mode ) = @_;
1293              
1294 5 50 33     63 if ( not( defined($mode) && ( $mode =~ m/[0-7]{3}/ ) ) )
1295             {
1296 0         0 return undef;
1297             }
1298              
1299 5         21 return ( $self->{file_mode} = $mode );
1300             }
1301              
1302              
1303             sub GetWriteMode
1304             {
1305 0     0 1 0 my $self = shift;
1306              
1307 0         0 return $self->{file_mode};
1308             }
1309              
1310              
1311             sub _write_config_to_filename
1312             {
1313 23     23   66 my ( $self, $filename, %parms ) = @_;
1314              
1315 23 100       534 if ( -e $filename )
1316             {
1317 7 50       105 if ( not( -w $filename ) )
1318             {
1319             #carp "File $filename is not writable. Refusing to write config";
1320 0         0 return undef;
1321             }
1322 7         85 my $mode = ( stat $filename )[2];
1323 7         59 $self->{file_mode} = sprintf "%04o", ( $mode & 0777 );
1324              
1325             #carp "Using mode $self->{file_mode} for file $file";
1326             }
1327              
1328 23         69 my ( $fh, $new_file );
1329              
1330             # We need to trap the exception that tempfile() may throw and instead
1331             # carp() and return undef() because that was the previous behaviour:
1332             #
1333             # See RT #77039 ( https://rt.cpan.org/Ticket/Display.html?id=77039 )
1334 23         127 eval {
1335 23         1473 ( $fh, $new_file ) =
1336             tempfile( "temp.ini-XXXXXXXXXX", DIR => dirname($filename) );
1337              
1338             # Convert the filehandle to a "text" filehandle suitable for use
1339             # on Windows (and other platforms).
1340             #
1341             # This may break compatibility for ultra-old perls (ones before 5.6.0)
1342             # so I say - Good Riddance!
1343 23 50       9420 if ( $^O =~ m/\AMSWin/ )
1344             {
1345 0         0 binmode $fh, ':crlf';
1346             }
1347             };
1348              
1349 23 50       86 if ($@)
1350             {
1351 0         0 carp("Unable to write temp config file: $!");
1352 0         0 return undef;
1353             }
1354              
1355 23         197 $self->OutputConfigToFileHandle( $fh, $parms{-delta} );
1356 23         956 close($fh);
1357 23 50       1725 if ( !rename( $new_file, $filename ) )
1358             {
1359 0         0 carp "Unable to rename temp config file ($new_file) to ${filename}: $!";
1360 0         0 return undef;
1361             }
1362 23 100       124 if ( exists $self->{file_mode} )
1363             {
1364 19         314 chmod oct( $self->{file_mode} ), $filename;
1365             }
1366              
1367 23         210 return 1;
1368             }
1369              
1370             sub _write_config_with_a_made_fh
1371             {
1372 3     3   10 my ( $self, $fh, %parms ) = @_;
1373              
1374             # Only roll back if it's not STDIN (if it is, Carp)
1375 3 50       12 if ( $fh == \*STDIN )
1376             {
1377 0         0 carp "Cannot write configuration file to STDIN.";
1378             }
1379             else
1380             {
1381 3         22 seek( $fh, 0, SEEK_SET() );
1382              
1383             # Make sure to keep the previous junk out.
1384             # See:
1385             # https://rt.cpan.org/Public/Bug/Display.html?id=103496
1386 3         140 truncate( $fh, 0 );
1387 3         21 $self->OutputConfigToFileHandle( $fh, $parms{-delta} );
1388 3         104 seek( $fh, 0, SEEK_SET() );
1389             } # end if
1390              
1391 3         45 return 1;
1392             }
1393              
1394             sub _write_config_to_fh
1395             {
1396 3     3   8 my ( $self, $file, %parms ) = @_;
1397              
1398             # Get a filehandle, allowing almost any type of 'file' parameter
1399             ## NB: If this were a filename, this would fail because _make_file
1400             ## opens a read-only handle, but we have already checked that case
1401             ## so re-using the logic is ok [JW/WADG]
1402 3         19 my $fh = $self->_make_filehandle($file);
1403              
1404 3 50       11 if ( !$fh )
1405             {
1406 0         0 carp "Could not find a filehandle for the input stream ($file): $!";
1407 0         0 return undef;
1408             }
1409              
1410 3         13 return $self->_write_config_with_a_made_fh( $fh, %parms );
1411             }
1412              
1413             sub WriteConfig
1414             {
1415 26     26 1 1593 my ( $self, $file, %parms ) = @_;
1416              
1417 26 50       85 return undef unless defined $file;
1418              
1419             # If we are using a filename, then do mode checks and write to a
1420             # temporary file to avoid a race condition
1421 26 100       78 if ( !ref($file) )
1422             {
1423 23         120 return $self->_write_config_to_filename( $file, %parms );
1424             }
1425              
1426             # Otherwise, reset to the start of the file and write, unless we are using
1427             # STDIN
1428             else
1429             {
1430 3         14 return $self->_write_config_to_fh( $file, %parms );
1431             }
1432             }
1433              
1434              
1435             sub RewriteConfig
1436             {
1437 16     16 1 1943 my $self = shift;
1438              
1439 16 50       88 if ( $self->_no_filename )
1440             {
1441 0         0 return 1;
1442             }
1443              
1444 16         105 return $self->WriteConfig( $self->{cf} );
1445             }
1446              
1447              
1448             sub GetFileName
1449             {
1450 5     5 1 13 my $self = shift;
1451              
1452 5         26 return $self->{cf};
1453             }
1454              
1455              
1456             sub SetFileName
1457             {
1458 12     12 1 1413 my ( $self, $new_filename ) = @_;
1459              
1460 12 50       57 if ( length($new_filename) > 0 )
1461             {
1462 12         85 return ( $self->{cf} = $new_filename );
1463             }
1464             else
1465             {
1466 0         0 return undef;
1467             }
1468             }
1469              
1470              
1471             sub _calc_eot_mark
1472             {
1473 65     65   149 my ( $self, $sect, $parm, $val ) = @_;
1474              
1475 65   100     194 my $eotmark = $self->{EOT}{$sect}{$parm} || 'EOT';
1476              
1477             # Make sure the $eotmark does not occur inside the string.
1478 65         355 my @letters = ( 'A' .. 'Z' );
1479 65         164 my $joined_val = join( q{ }, @$val );
1480 65         205 while ( index( $joined_val, $eotmark ) >= 0 )
1481             {
1482 2         11 $eotmark .= $letters[ rand(@letters) ];
1483             }
1484              
1485 65         241 return $eotmark;
1486             }
1487              
1488             sub _OutputParam
1489             {
1490 212     212   450 my ( $self, $sect, $parm, $val, $end_comment, $output_cb ) = @_;
1491              
1492             my $line_loop = sub {
1493 202     202   411 my ($mapper) = @_;
1494              
1495 202         394 foreach my $line ( @{$val}[ 0 .. $#$val - 1 ] )
  202         444  
1496             {
1497 135         230 $output_cb->( $mapper->($line) );
1498             }
1499 202 100       418 $output_cb->(
1500             $mapper->( $val->[-1] ),
1501             ( $end_comment ? (" $self->{comment_char} $end_comment") : () ),
1502             );
1503 202         346 return;
1504 212         799 };
1505              
1506 212 100 66     754 if ( !@$val )
    100          
1507             {
1508             # An empty variable - see:
1509             # https://rt.cpan.org/Public/Bug/Display.html?id=68554
1510 10         45 $output_cb->("$parm=");
1511             }
1512             elsif ( ( @$val == 1 ) or $self->{nomultiline} )
1513             {
1514 137     138   442 $line_loop->( sub { my ($line) = @_; return "$parm=$line"; } );
  138         260  
  138         515  
1515             }
1516             else
1517             {
1518 65         163 my $eotmark = $self->_calc_eot_mark( $sect, $parm, $val );
1519              
1520 65         211 $output_cb->("$parm= <<$eotmark");
1521 65     199   240 $line_loop->( sub { my ($line) = @_; return $line; } );
  199         346  
  199         458  
1522 65         186 $output_cb->($eotmark);
1523             }
1524              
1525 212         916 return;
1526             }
1527              
1528             sub OutputConfig
1529             {
1530 0     0 1 0 my ( $self, $delta ) = @_;
1531              
1532 0         0 return $self->OutputConfigToFileHandle( select(), $delta );
1533             }
1534              
1535             sub _output_comments
1536             {
1537 370     370   725 my ( $self, $print_line, $comments_aref ) = @_;
1538              
1539 370 100       810 if ( ref($comments_aref) eq 'ARRAY' )
1540             {
1541 167         318 foreach my $comment (@$comments_aref)
1542             {
1543 34         63 $print_line->($comment);
1544             }
1545             }
1546              
1547 370         561 return;
1548             }
1549              
1550             sub _process_continue_val
1551             {
1552 560     560   940 my ( $self, $fh ) = @_;
1553              
1554 560 100       1187 if ( not $self->{allowcontinue} )
1555             {
1556 533         882 return;
1557             }
1558              
1559 27         44 my $val = $self->_curr_val;
1560              
1561 27         75 while ( $val =~ s/\\\z// )
1562             {
1563 2         5 $val .= $self->_read_next_line($fh);
1564             }
1565              
1566 27         61 $self->_curr_val($val);
1567              
1568 27         67 return;
1569             }
1570              
1571             sub _output_param_total
1572             {
1573 213     213   460 my ( $self, $sect, $parm, $print_line, $split_val, $delta ) = @_;
1574 213 100       514 if ( !defined $self->{v}{$sect}{$parm} )
1575             {
1576 1 50       4 if ($delta)
1577             {
1578 1         5 $print_line->("$self->{comment_char} $parm is deleted");
1579             }
1580             else
1581             {
1582 0 0       0 warn "Weird unknown parameter $parm" if $^W;
1583             }
1584 1         3 return;
1585             }
1586              
1587 212         707 $self->_output_comments( $print_line, $self->{pCMT}{$sect}{$parm} );
1588              
1589 212         461 my $val = $self->{v}{$sect}{$parm};
1590 212         430 my $end_comment = $self->{peCMT}{$sect}{$parm};
1591              
1592 212 50       499 return if !defined($val); # No parameter exists !!
1593              
1594 212 100       467 $self->_OutputParam( $sect, $parm, $split_val->($val),
1595             ( defined($end_comment) ? $end_comment : "" ), $print_line, );
1596              
1597 212         445 return;
1598             }
1599              
1600             sub _output_section
1601             {
1602 132     132   346 my ( $self, $sect, $print_line, $split_val, $delta, $position ) = @_;
1603              
1604 132 100       339 if ( !defined $self->{v}{$sect} )
1605             {
1606 1 50       4 if ($delta)
1607             {
1608 1         6 $print_line->("$self->{comment_char} [$sect] is deleted");
1609             }
1610             else
1611             {
1612 0 0       0 warn "Weird unknown section $sect" if $^W;
1613             }
1614 1         4 return;
1615             }
1616 131 50       299 return if not defined $self->{v}{$sect};
1617 131 100       369 $print_line->() if ( $position > 0 );
1618 131         358 $self->_output_comments( $print_line, $self->{sCMT}{$sect} );
1619              
1620 131 100 100     327 if ( !( $self->{fallback_used} and $sect eq $self->{fallback} ) )
1621             {
1622 130         376 $print_line->("[$sect]");
1623             }
1624 131 50       411 return if ref( $self->{v}{$sect} ) ne 'HASH';
1625              
1626 131 100       196 foreach my $parm ( @{ $self->{ $delta ? "myparms" : "parms" }{$sect} } )
  131         389  
1627             {
1628 213         484 $self->_output_param_total( $sect, $parm, $print_line, $split_val,
1629             $delta );
1630             }
1631              
1632 131         244 return;
1633             }
1634              
1635             sub OutputConfigToFileHandle
1636             {
1637             # We need no strict 'refs' to be able to print to $fh if it points
1638             # to a glob filehandle.
1639 37     37   490 no strict 'refs';
  37         93  
  37         70491  
1640 27     27 1 205 my ( $self, $fh, $delta ) = @_;
1641              
1642             my $ors =
1643             $self->{line_ends}
1644 27   50     164 || $\
1645             || "\n"; # $\ is normally unset, but use input by default
1646             my $print_line = sub {
1647 749 50   749   962 print {$fh} ( @_, $ors )
  749         2000  
1648             or die
1649             "Config-IniFiles cannot print to filehandle (out-of-space?). Aborting!";
1650 749         1172 return;
1651 27         149 };
1652             my $split_val = sub {
1653 212     212   367 my ($val) = @_;
1654              
1655             return (
1656 212 100       1427 ( ref($val) eq 'ARRAY' )
1657             ? $val
1658             : [ split /[$ors]/, $val, -1 ]
1659             );
1660 27         105 };
1661              
1662 27         59 my $position = 0;
1663              
1664 27 100       50 foreach my $sect ( @{ $self->{ $delta ? "mysects" : "sects" } } )
  27         135  
1665             {
1666 132         337 $self->_output_section( $sect, $print_line, $split_val, $delta,
1667             $position++ );
1668             }
1669              
1670 27         141 $self->_output_comments( $print_line, [ $self->_GetEndComments() ] );
1671              
1672 27         183 return 1;
1673             }
1674              
1675              
1676             sub SetSectionComment
1677             {
1678 335     335 1 757 my ( $self, $sect, @comment ) = @_;
1679              
1680 335 100 66     1305 if ( not( defined($sect) && @comment ) )
1681             {
1682 265         490 return undef;
1683             }
1684              
1685 70         254 $self->_caseify( \$sect );
1686              
1687 70         167 $self->_touch_section($sect);
1688              
1689             # At this point it's possible to have a comment for a section that
1690             # doesn't exist. This comment will not get written to the INI file.
1691 70         170 $self->{sCMT}{$sect} = $self->_markup_comments( \@comment );
1692              
1693 70         194 return scalar @comment;
1694             }
1695              
1696             # this helper makes sure that each line is preceded with the correct comment
1697             # character
1698             sub _markup_comments
1699             {
1700 101     101   183 my ( $self, $comment_aref ) = @_;
1701              
1702 101         184 my $allCmt = $self->{allowed_comment_char};
1703 101         178 my $cmtChr = $self->{comment_char};
1704              
1705 101         853 my $is_comment = qr/\A\s*[$allCmt]/;
1706              
1707             # TODO : Maybe create a qr// out of it.
1708 101 100       261 return [ map { ( $_ =~ $is_comment ) ? $_ : "$cmtChr $_" } @$comment_aref ];
  117         1084  
1709             }
1710              
1711              
1712             sub _return_comment
1713             {
1714 9     9   19 my ( $self, $comment_aref ) = @_;
1715              
1716 9 50       30 my $delim = defined($/) ? $/ : "\n";
1717              
1718 9 100       49 return wantarray() ? @$comment_aref : join( $delim, @$comment_aref );
1719             }
1720              
1721             sub GetSectionComment
1722             {
1723 8     8 1 1262 my ( $self, $sect ) = @_;
1724              
1725 8 50       24 return undef if not defined $sect;
1726              
1727 8         51 $self->_caseify( \$sect );
1728              
1729 8 100       23 if ( !exists $self->{sCMT}{$sect} )
1730             {
1731 3         16 return undef;
1732             }
1733              
1734 5         16 return $self->_return_comment( $self->{sCMT}{$sect} );
1735             }
1736              
1737              
1738             sub DeleteSectionComment
1739             {
1740 2     2 1 698 my $self = shift;
1741 2         4 my $sect = shift;
1742              
1743 2 50       18 return undef if not defined $sect;
1744              
1745 2         10 $self->_caseify( \$sect );
1746 2         8 $self->_touch_section($sect);
1747              
1748 2         6 delete $self->{sCMT}{$sect};
1749              
1750 2         6 return;
1751             }
1752              
1753              
1754             sub SetParameterComment
1755             {
1756 690     690 1 1463 my ( $self, $sect, $parm, @comment ) = @_;
1757              
1758 690 100 33     3377 if ( not( defined($sect) && defined($parm) && @comment ) )
      66        
1759             {
1760 659         1162 return undef;
1761             }
1762              
1763 31         106 $self->_caseify( \$sect, \$parm );
1764              
1765 31         101 $self->_touch_parameter( $sect, $parm );
1766              
1767             # Note that at this point, it's possible to have a comment for a parameter,
1768             # without that parameter actually existing in the INI file.
1769 31         113 $self->{pCMT}{$sect}{$parm} = $self->_markup_comments( \@comment );
1770              
1771 31         88 return scalar @comment;
1772             }
1773              
1774             sub _SetEndComments
1775             {
1776 79     79   180 my $self = shift;
1777 79         195 my @comments = @_;
1778              
1779 79         213 $self->{_comments_at_end_of_file} = \@comments;
1780              
1781 79         173 return 1;
1782             }
1783              
1784             sub _GetEndComments
1785             {
1786 27     27   93 my $self = shift;
1787              
1788 27         48 return @{ $self->{_comments_at_end_of_file} };
  27         133  
1789             }
1790              
1791              
1792             sub GetParameterComment
1793             {
1794 4     4 1 1412 my ( $self, $sect, $parm ) = @_;
1795              
1796 4 50 33     23 if ( not( defined($sect) && defined($parm) ) )
1797             {
1798 0         0 return undef;
1799             }
1800              
1801 4         14 $self->_caseify( \$sect, \$parm );
1802              
1803 4 50 33     20 if (
1804             not( exists( $self->{pCMT}{$sect} )
1805             && exists( $self->{pCMT}{$sect}{$parm} ) )
1806             )
1807             {
1808 0         0 return undef;
1809             }
1810              
1811 4         11 return $self->_return_comment( $self->{pCMT}{$sect}{$parm} );
1812             }
1813              
1814              
1815             sub DeleteParameterComment
1816             {
1817 1     1 1 4 my ( $self, $sect, $parm ) = @_;
1818              
1819 1 50 33     8 if ( not( defined($sect) && defined($parm) ) )
1820             {
1821 0         0 return undef;
1822             }
1823              
1824 1         5 $self->_caseify( \$sect, \$parm );
1825              
1826             # If the parameter doesn't exist, our goal has already been achieved
1827 1 50 33     7 if ( exists( $self->{pCMT}{$sect} )
1828             && exists( $self->{pCMT}{$sect}{$parm} ) )
1829             {
1830 1         4 $self->_touch_parameter( $sect, $parm );
1831 1         3 delete $self->{pCMT}{$sect}{$parm};
1832             }
1833              
1834 1         3 return 1;
1835             }
1836              
1837              
1838             sub GetParameterEOT
1839             {
1840 0     0 1 0 my ( $self, $sect, $parm ) = @_;
1841              
1842 0 0 0     0 if ( not( defined($sect) && defined($parm) ) )
1843             {
1844 0         0 return undef;
1845             }
1846              
1847 0         0 $self->_caseify( \$sect, \$parm );
1848              
1849 0         0 return $self->{EOT}{$sect}{$parm};
1850             }
1851              
1852              
1853             sub SetParameterEOT
1854             {
1855 129     129 1 303 my ( $self, $sect, $parm, $EOT ) = @_;
1856              
1857 129 50 33     698 if ( not( defined($sect) && defined($parm) && defined($EOT) ) )
      33        
1858             {
1859 0         0 return undef;
1860             }
1861              
1862 129         384 $self->_caseify( \$sect, \$parm );
1863              
1864 129         354 $self->_touch_parameter( $sect, $parm );
1865              
1866 129         298 $self->{EOT}{$sect}{$parm} = $EOT;
1867              
1868 129         223 return;
1869             }
1870              
1871              
1872             sub DeleteParameterEOT
1873             {
1874 0     0 1 0 my ( $self, $sect, $parm ) = @_;
1875              
1876 0 0 0     0 if ( not( defined($sect) && defined($parm) ) )
1877             {
1878 0         0 return undef;
1879             }
1880              
1881 0         0 $self->_caseify( \$sect, \$parm );
1882              
1883 0         0 $self->_touch_parameter( $sect, $parm );
1884 0         0 delete $self->{EOT}{$sect}{$parm};
1885              
1886 0         0 return;
1887             }
1888              
1889              
1890             sub SetParameterTrailingComment
1891             {
1892 690     690 1 1402 my ( $self, $sect, $parm, $cmt ) = @_;
1893              
1894 690 100 33     3094 if ( not( defined($sect) && defined($parm) && defined($cmt) ) )
      66        
1895             {
1896 129         233 return undef;
1897             }
1898              
1899 561         1478 $self->_caseify( \$sect, \$parm );
1900              
1901             # confirm the parameter exist
1902 561 50       1339 return undef if not exists $self->{v}{$sect}{$parm};
1903              
1904 561         1410 $self->_touch_parameter( $sect, $parm );
1905 561         1455 $self->{peCMT}{$sect}{$parm} = $cmt;
1906              
1907 561         918 return 1;
1908             }
1909              
1910              
1911             sub GetParameterTrailingComment
1912             {
1913 5     5 1 14 my ( $self, $sect, $parm ) = @_;
1914              
1915 5 50 33     26 if ( not( defined($sect) && defined($parm) ) )
1916             {
1917 0         0 return undef;
1918             }
1919              
1920 5         15 $self->_caseify( \$sect, \$parm );
1921              
1922             # confirm the parameter exist
1923 5 50       13 return undef if not exists $self->{v}{$sect}{$parm};
1924 5         21 return $self->{peCMT}{$sect}{$parm};
1925             }
1926              
1927              
1928             sub Delete
1929             {
1930 1     1 1 3 my $self = shift;
1931              
1932 1         4 foreach my $section ( $self->Sections() )
1933             {
1934 1         4 $self->DeleteSection($section);
1935             }
1936              
1937 1         3 return 1;
1938             } # end Delete
1939              
1940              
1941             ############################################################
1942             #
1943             # TIEHASH Methods
1944             #
1945             # Description:
1946             # These methods allow you to tie a hash to the
1947             # Config::IniFiles object. Note that, when tied, the
1948             # user wants to look at thinks like $ini{sec}{parm}, but the
1949             # TIEHASH only provides one level of hash interface, so the
1950             # root object gets asked for a $ini{sec}, which this
1951             # implements. To further tie the {parm} hash, the internal
1952             # class Config::IniFiles::_section, is provided, below.
1953             #
1954             ############################################################
1955             # ----------------------------------------------------------
1956             # Date Modification Author
1957             # ----------------------------------------------------------
1958             # 2000May09 Created method JW
1959             # ----------------------------------------------------------
1960             sub TIEHASH
1961             {
1962 6     6   3616 my $class = shift;
1963 6         26 my %parms = @_;
1964              
1965             # Get a new object
1966 6         35 my $self = $class->new(%parms);
1967              
1968 6         36 return $self;
1969             } # end TIEHASH
1970              
1971             # ----------------------------------------------------------
1972             # Date Modification Author
1973             # ----------------------------------------------------------
1974             # 2000May09 Created method JW
1975             # ----------------------------------------------------------
1976             sub FETCH
1977             {
1978 33     33   4808 my $self = shift;
1979 33         65 my ($key) = @_;
1980              
1981 33   100     117 $self->{_section_cache} ||= {};
1982              
1983 33         106 $self->_caseify( \$key );
1984 33 100       87 return if ( !$self->{v}{$key} );
1985              
1986 32 100       159 return $self->{_section_cache}->{$key} if exists $self->{_section_cache}->{$key};
1987              
1988 11         16 my %retval;
1989 11         70 tie %retval, 'Config::IniFiles::_section', $self, $key;
1990 11         86 return $self->{_section_cache}->{$key} = \%retval;
1991              
1992             } # end FETCH
1993              
1994             # ----------------------------------------------------------
1995             # Date Modification Author
1996             # ----------------------------------------------------------
1997             # 2000Jun14 Fixed bug where wrong ref was saved JW
1998             # 2000Oct09 Fixed possible but in %parms with defaults JW
1999             # 2001Apr04 Fixed -nocase problem in storing JW
2000             # ----------------------------------------------------------
2001             sub STORE
2002             {
2003 4     4   1010 my $self = shift;
2004 4         11 my ( $key, $ref ) = @_;
2005              
2006 4 50       14 return undef unless ref($ref) eq 'HASH';
2007              
2008 4         15 $self->_caseify( \$key );
2009              
2010 4         12 $self->AddSection($key);
2011 4         13 $self->{v}{$key} = {%$ref};
2012 4         11 $self->{parms}{$key} = [ keys %$ref ];
2013 4         11 $self->{myparms}{$key} = [ keys %$ref ];
2014              
2015 4         12 return 1;
2016             } # end STORE
2017              
2018             # ----------------------------------------------------------
2019             # Date Modification Author
2020             # ----------------------------------------------------------
2021             # 2000May09 Created method JW
2022             # 2000Dec17 Now removes comments, groups and EOTs too JW
2023             # 2001Arp04 Fixed -nocase problem JW
2024             # ----------------------------------------------------------
2025             sub DELETE
2026             {
2027 1     1   588 my $self = shift;
2028 1         5 my ($key) = @_;
2029              
2030 1         4 my $retval = $self->FETCH($key);
2031 1         5 $self->DeleteSection($key);
2032 1         4 return $retval;
2033             } # end DELETE
2034              
2035             # ----------------------------------------------------------
2036             # Date Modification Author
2037             # ----------------------------------------------------------
2038             # 2000May09 Created method JW
2039             # ----------------------------------------------------------
2040             sub CLEAR
2041             {
2042 0     0   0 my $self = shift;
2043              
2044 0         0 return $self->Delete();
2045             } # end CLEAR
2046              
2047             # ----------------------------------------------------------
2048             # Date Modification Author
2049             # ----------------------------------------------------------
2050             # 2000May09 Created method JW
2051             # ----------------------------------------------------------
2052             sub FIRSTKEY
2053             {
2054 1     1   10 my $self = shift;
2055              
2056 1         2 $self->{tied_enumerator} = 0;
2057 1         5 return $self->NEXTKEY();
2058             } # end FIRSTKEY
2059              
2060             # ----------------------------------------------------------
2061             # Date Modification Author
2062             # ----------------------------------------------------------
2063             # 2000May09 Created method JW
2064             # ----------------------------------------------------------
2065             sub NEXTKEY
2066             {
2067 11     11   16 my $self = shift;
2068 11         18 my ($last) = @_;
2069              
2070 11         15 my $i = $self->{tied_enumerator}++;
2071 11         19 my $key = $self->{sects}[$i];
2072 11 100       22 return if ( !defined $key );
2073 10 50       40 return wantarray ? ( $key, $self->FETCH($key) ) : $key;
2074             } # end NEXTKEY
2075              
2076             # ----------------------------------------------------------
2077             # Date Modification Author
2078             # ----------------------------------------------------------
2079             # 2000May09 Created method JW
2080             # 2001Apr04 Fixed -nocase bug and false true bug JW
2081             # ----------------------------------------------------------
2082             sub EXISTS
2083             {
2084 0     0   0 my $self = shift;
2085 0         0 my ($key) = @_;
2086 0         0 return $self->SectionExists($key);
2087             } # end EXISTS
2088              
2089             # ----------------------------------------------------------
2090             # DESTROY is used by TIEHASH and the Perl garbage collector,
2091             # ----------------------------------------------------------
2092             # Date Modification Author
2093             # ----------------------------------------------------------
2094             # 2000May09 Created method JW
2095             # ----------------------------------------------------------
2096             sub DESTROY
2097       0     {
2098             # my $self = shift;
2099             } # end if
2100              
2101             # ----------------------------------------------------------
2102             # Sub: _make_filehandle
2103             #
2104             # Args: $thing
2105             # $thing An input source
2106             #
2107             # Description: Takes an input source - a filehandle,
2108             # filehandle glob, reference to a filehandle glob, IO::File
2109             # object or scalar filename - and returns a file handle to
2110             # read from it with.
2111             # ----------------------------------------------------------
2112             # Date Modification Author
2113             # ----------------------------------------------------------
2114             # 06Dec2001 Added to support input from any source JW
2115             # ----------------------------------------------------------
2116             sub _make_filehandle
2117             {
2118 85     85   153 my $self = shift;
2119              
2120             #
2121             # This code is 'borrowed' from Lincoln D. Stein's GD.pm module
2122             # with modification for this module. Thanks Lincoln!
2123             #
2124              
2125 37     37   354 no strict 'refs';
  37         91  
  37         8128  
2126 85         157 my $thing = shift;
2127              
2128 85 100       264 if ( ref($thing) eq "SCALAR" )
2129             {
2130 3 50       8 if ( eval { require IO::Scalar; $IO::Scalar::VERSION >= 2.109; } )
  3         904  
  3         7184  
2131             {
2132 3         20 return IO::Scalar->new($thing);
2133             }
2134             else
2135             {
2136 0 0       0 warn "SCALAR reference as file descriptor requires IO::stringy "
2137             . "v2.109 or later"
2138             if ($^W);
2139 0         0 return;
2140             }
2141             }
2142              
2143 82 100       498 return $thing if defined( fileno $thing );
2144              
2145             # otherwise try qualifying it into caller's package
2146 69         383 my $fh = qualify_to_ref( $thing, caller(1) );
2147 69 50       2144 return $fh if defined( fileno $fh );
2148              
2149             # otherwise treat it as a file to open
2150 69         236 $fh = gensym;
2151 69 50       3438 open( $fh, $thing ) || return;
2152              
2153 69         362 return $fh;
2154             } # end _make_filehandle
2155              
2156             ############################################################
2157             #
2158             # INTERNAL PACKAGE: Config::IniFiles::_section
2159             #
2160             # Description:
2161             # This package is used to provide a single-level TIEHASH
2162             # interface to the sections in the IniFile. When tied, the
2163             # user wants to look at thinks like $ini{sec}{parm}, but the
2164             # TIEHASH only provides one level of hash interface, so the
2165             # root object gets asked for a $ini{sec} and must return a
2166             # has reference that accurately covers the '{parm}' part.
2167             #
2168             # This package is only used when tied and is inter-woven
2169             # between the sections and their parameters when the TIEHASH
2170             # method is called by Perl. It's a very simple implementation
2171             # of a tied hash object that simply maps onto the object API.
2172             #
2173             ############################################################
2174             # Date Modification Author
2175             # ----------------------------------------------------------
2176             # 2000.May.09 Created to excapsulate TIEHASH interface JW
2177             ############################################################
2178             package Config::IniFiles::_section;
2179              
2180 37     37   290 use strict;
  37         86  
  37         956  
2181 37     37   220 use warnings;
  37         86  
  37         1713  
2182 37     37   252 use Carp;
  37         98  
  37         2962  
2183 37     37   280 use vars qw( $VERSION );
  37         101  
  37         19321  
2184              
2185             $Config::IniFiles::_section::VERSION = 2.16;
2186              
2187             # ----------------------------------------------------------
2188             # Sub: Config::IniFiles::_section::TIEHASH
2189             #
2190             # Args: $class, $config, $section
2191             # $class The class that this is being tied to.
2192             # $config The parent Config::IniFiles object
2193             # $section The section this tied object refers to
2194             #
2195             # Description: Builds the object that implements accesses to
2196             # the tied hash.
2197             # ----------------------------------------------------------
2198             # Date Modification Author
2199             # ----------------------------------------------------------
2200             # ----------------------------------------------------------
2201             sub TIEHASH
2202             {
2203 11     11   27 my $proto = shift;
2204 11   33     70 my $class = ref($proto) || $proto;
2205 11         30 my ( $config, $section ) = @_;
2206              
2207             # Make a new object
2208 11         51 return bless { config => $config, section => $section }, $class;
2209             } # end TIEHASH
2210              
2211             # ----------------------------------------------------------
2212             # Sub: Config::IniFiles::_section::FETCH
2213             #
2214             # Args: $key
2215             # $key The name of the key whose value to get
2216             #
2217             # Description: Returns the value associated with $key. If
2218             # the value is a list, returns a list reference.
2219             # ----------------------------------------------------------
2220             # Date Modification Author
2221             # ----------------------------------------------------------
2222             # 2000Jun15 Fixed bugs in -default handler JW
2223             # 2000Dec07 Fixed another bug in -deault handler JW
2224             # 2002Jul04 Returning scalar values (Bug:447532) AS
2225             # ----------------------------------------------------------
2226             sub FETCH
2227             {
2228 22     22   123 my ( $self, $key ) = @_;
2229 22         62 my @retval = $self->{config}->val( $self->{section}, $key );
2230 22 100       100 return ( @retval <= 1 ) ? $retval[0] : \@retval;
2231             } # end FETCH
2232              
2233             # ----------------------------------------------------------
2234             # Sub: Config::IniFiles::_section::STORE
2235             #
2236             # Args: $key, @val
2237             # $key The key under which to store the value
2238             # @val The value to store, either an array or a scalar
2239             #
2240             # Description: Sets the value for the specified $key
2241             # ----------------------------------------------------------
2242             # Date Modification Author
2243             # ----------------------------------------------------------
2244             # 2001Apr04 Fixed -nocase bug JW
2245             # ----------------------------------------------------------
2246             sub STORE
2247             {
2248 11     11   32 my ( $self, $key, @val ) = @_;
2249 11         45 return $self->{config}->newval( $self->{section}, $key, @val );
2250             } # end STORE
2251              
2252             # ----------------------------------------------------------
2253             # Sub: Config::IniFiles::_section::DELETE
2254             #
2255             # Args: $key
2256             # $key The key to remove from the hash
2257             #
2258             # Description: Removes the specified key from the hash and
2259             # returns its former value.
2260             # ----------------------------------------------------------
2261             # Date Modification Author
2262             # ----------------------------------------------------------
2263             # 2001Apr04 Fixed -nocase bug JW
2264             # ----------------------------------------------------------
2265             sub DELETE
2266             {
2267 1     1   3 my ( $self, $key ) = @_;
2268 1         4 my $retval = $self->{config}->val( $self->{section}, $key );
2269 1         5 $self->{config}->delval( $self->{section}, $key );
2270 1         3 return $retval;
2271             } # end DELETE
2272              
2273             # ----------------------------------------------------------
2274             # Sub: Config::IniFiles::_section::CLEAR
2275             #
2276             # Args: (None)
2277             #
2278             # Description: Empties the entire hash
2279             # ----------------------------------------------------------
2280             # Date Modification Author
2281             # ----------------------------------------------------------
2282             # ----------------------------------------------------------
2283             sub CLEAR
2284             {
2285 1     1   3 my ($self) = @_;
2286 1         4 return $self->{config}->DeleteSection( $self->{section} );
2287             } # end CLEAR
2288              
2289             # ----------------------------------------------------------
2290             # Sub: Config::IniFiles::_section::EXISTS
2291             #
2292             # Args: $key
2293             # $key The key to look for
2294             #
2295             # Description: Returns whether the key exists
2296             # ----------------------------------------------------------
2297             # Date Modification Author
2298             # ----------------------------------------------------------
2299             # 2001Apr04 Fixed -nocase bug JW
2300             # ----------------------------------------------------------
2301             sub EXISTS
2302             {
2303 0     0   0 my ( $self, $key ) = @_;
2304 0         0 return $self->{config}->exists( $self->{section}, $key );
2305             } # end EXISTS
2306              
2307             # ----------------------------------------------------------
2308             # Sub: Config::IniFiles::_section::FIRSTKEY
2309             #
2310             # Args: (None)
2311             #
2312             # Description: Returns the first key in the hash
2313             # ----------------------------------------------------------
2314             # Date Modification Author
2315             # ----------------------------------------------------------
2316             # ----------------------------------------------------------
2317             sub FIRSTKEY
2318             {
2319 4     4   9 my $self = shift;
2320              
2321 4         19 $self->{tied_enumerator} = 0;
2322 4         14 return $self->NEXTKEY();
2323             } # end FIRSTKEY
2324              
2325             # ----------------------------------------------------------
2326             # Sub: Config::IniFiles::_section::NEXTKEY
2327             #
2328             # Args: $last
2329             # $last The last key accessed by the iterator
2330             #
2331             # Description: Returns the next key in line
2332             # ----------------------------------------------------------
2333             # Date Modification Author
2334             # ----------------------------------------------------------
2335             # ----------------------------------------------------------
2336             sub NEXTKEY
2337             {
2338 13     13   63 my $self = shift;
2339 13         27 my ($last) = @_;
2340              
2341 13         26 my $i = $self->{tied_enumerator}++;
2342 13         31 my @keys = $self->{config}->Parameters( $self->{section} );
2343 13         29 my $key = $keys[$i];
2344 13 100       45 return if ( !defined $key );
2345 10 50       73 return wantarray ? ( $key, $self->FETCH($key) ) : $key;
2346             } # end NEXTKEY
2347              
2348             # ----------------------------------------------------------
2349             # Sub: Config::IniFiles::_section::DESTROY
2350             #
2351             # Args: (None)
2352             #
2353             # Description: Called on cleanup
2354             # ----------------------------------------------------------
2355             # Date Modification Author
2356             # ----------------------------------------------------------
2357             # ----------------------------------------------------------
2358             sub DESTROY
2359       0     {
2360             # my $self = shift
2361             } # end DESTROY
2362              
2363             1;
2364              
2365              
2366              
2367             1;
2368              
2369             # Please keep the following within the last four lines of the file
2370             #[JW for editor]:mode=perl:tabSize=8:indentSize=2:noTabs=true:indentOnEnter=true:
2371              
2372             __END__