File Coverage

blib/lib/Config/General.pm
Criterion Covered Total %
statement 553 690 80.1
branch 300 418 71.7
condition 68 111 61.2
subroutine 37 39 94.8
pod 8 9 88.8
total 966 1267 76.2


line stmt bran cond sub pod time code
1             #
2             # Config::General.pm - Generic Config Module
3             #
4             # Purpose: Provide a convenient way for loading
5             # config values from a given file and
6             # return it as hash structure
7             #
8             # Copyright (c) 2000-2016 Thomas Linden .
9             # All Rights Reserved. Std. disclaimer applies.
10             # Artistic License, same as perl itself. Have fun.
11             #
12             # namespace
13             package Config::General;
14              
15 1     1   24439 use strict;
  1         1  
  1         23  
16 1     1   2 use warnings;
  1         1  
  1         20  
17 1     1   523 use English '-no_match_vars';
  1         2540  
  1         4  
18              
19 1     1   621 use IO::File;
  1         6637  
  1         79  
20 1     1   384 use FileHandle;
  1         548  
  1         4  
21 1     1   697 use File::Spec::Functions qw(splitpath file_name_is_absolute catfile catpath);
  1         677  
  1         71  
22 1     1   5 use File::Glob qw/:glob/;
  1         1  
  1         144  
23              
24              
25             # on debian with perl > 5.8.4 croak() doesn't work anymore without this.
26             # There is some require statement which dies 'cause it can't find Carp::Heavy,
27             # I really don't understand, what the hell they made, but the debian perl
28             # installation is definitely bullshit, damn!
29 1     1   375 use Carp::Heavy;
  1         87  
  1         22  
30              
31              
32 1     1   3 use Carp;
  1         1  
  1         36  
33 1     1   3 use Exporter;
  1         0  
  1         31  
34              
35             $Config::General::VERSION = "2.63";
36              
37 1     1   3 use vars qw(@ISA @EXPORT_OK);
  1         0  
  1         34  
38 1     1   3 use base qw(Exporter);
  1         1  
  1         85  
39             @EXPORT_OK = qw(ParseConfig SaveConfig SaveConfigString);
40              
41 1     1   4 use constant _UTF8_BOM => "\x{ef}\x{bb}\x{bf}";
  1         0  
  1         5435  
42              
43             sub new {
44             #
45             # create new Config::General object
46             #
47 71     71 1 27864 my($this, @param ) = @_;
48 71   66     240 my $class = ref($this) || $this;
49              
50             # define default options
51 71         908 my $self = {
52             # sha256 of current date
53             # hopefully this lowers the probability that
54             # this matches any configuration key or value out there
55             # bugfix for rt.40925
56             EOFseparator => 'ad7d7b87f5b81d2a0d5cb75294afeb91aa4801b1f8e8532dc1b633c0e1d47037',
57             SlashIsDirectory => 0,
58             AllowMultiOptions => 1,
59             MergeDuplicateOptions => 0,
60             MergeDuplicateBlocks => 0,
61             LowerCaseNames => 0,
62             ApacheCompatible => 0,
63             UseApacheInclude => 0,
64             IncludeRelative => 0,
65             IncludeDirectories => 0,
66             IncludeGlob => 0,
67             IncludeAgain => 0,
68             AutoLaunder => 0,
69             AutoTrue => 0,
70             AutoTrueFlags => {
71             true => '^(on|yes|true|1)$',
72             false => '^(off|no|false|0)$',
73             },
74             DefaultConfig => {},
75             String => '',
76             level => 1,
77             InterPolateVars => 0,
78             InterPolateEnv => 0,
79             ExtendedAccess => 0,
80             SplitPolicy => 'guess', # also possible: whitespace, equalsign and custom
81             SplitDelimiter => 0, # must be set by the user if SplitPolicy is 'custom'
82             StoreDelimiter => 0, # will be set by me unless user uses 'custom' policy
83             CComments => 1, # by default turned on
84             BackslashEscape => 0, # deprecated
85             StrictObjects => 1, # be strict on non-existent keys in OOP mode
86             StrictVars => 1, # be strict on undefined variables in Interpolate mode
87             Tie => q(), # could be set to a perl module for tie'ing new hashes
88             parsed => 0, # internal state stuff for variable interpolation
89             files => {}, # which files we have read, if any
90             UTF8 => 0,
91             SaveSorted => 0,
92             ForceArray => 0, # force single value array if value enclosed in []
93             AllowSingleQuoteInterpolation => 0,
94             NoEscape => 0,
95             NormalizeBlock => 0,
96             NormalizeOption => 0,
97             NormalizeValue => 0,
98             Plug => {},
99             UseApacheIfDefine => 0,
100             Define => {}
101             };
102              
103             # create the class instance
104 71         135 bless $self, $class;
105              
106 71 100       120 if ($#param >= 1) {
    100          
107             # use of the new hash interface!
108 61         92 $self->_prepare(@param);
109             }
110             elsif ($#param == 0) {
111             # use of the old style
112 9         16 $self->{ConfigFile} = $param[0];
113 9 50       19 if (ref($self->{ConfigFile}) eq 'HASH') {
114 0         0 $self->{ConfigHash} = delete $self->{ConfigFile};
115             }
116             }
117             else {
118             # this happens if $#param == -1,1 thus no param was given to new!
119 1         2 $self->{config} = $self->_hashref();
120 1         1 $self->{parsed} = 1;
121             }
122              
123             # find split policy to use for option/value separation
124 70         108 $self->_splitpolicy();
125              
126             # bless into variable interpolation module if necessary
127 70         74 $self->_blessvars();
128              
129             # process as usual
130 70 100       109 if (!$self->{parsed}) {
131 69         83 $self->_process();
132             }
133              
134 62 100       92 if ($self->{InterPolateVars}) {
135 11         23 $self->{config} = $self->_clean_stack($self->{config});
136             }
137              
138             # bless into OOP namespace if required
139 62         84 $self->_blessoop();
140              
141 62         138 return $self;
142             }
143              
144              
145              
146             sub _process {
147             #
148             # call _read() and _parse() on the given config
149 69     69   47 my($self) = @_;
150              
151 69 100 33     166 if ($self->{DefaultConfig} && $self->{InterPolateVars}) {
152 11         23 $self->{DefaultConfig} = $self->_interpolate_hash($self->{DefaultConfig}); # FIXME: _hashref() ?
153             }
154 69 100 33     216 if (exists $self->{StringContent}) {
    100          
    50          
155             # consider the supplied string as config file
156 14         23 $self->_read($self->{StringContent}, 'SCALAR');
157 14         23 $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content});
158             }
159             elsif (exists $self->{ConfigHash}) {
160 11 100       21 if (ref($self->{ConfigHash}) eq 'HASH') {
161             # initialize with given hash
162 10         9 $self->{config} = $self->{ConfigHash};
163 10         11 $self->{parsed} = 1;
164             }
165             else {
166 1         100 croak "Config::General: Parameter -ConfigHash must be a hash reference!\n";
167             }
168             }
169             elsif (ref($self->{ConfigFile}) eq 'GLOB' || ref($self->{ConfigFile}) eq 'FileHandle') {
170             # use the file the glob points to
171 0         0 $self->_read($self->{ConfigFile});
172 0         0 $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content});
173             }
174             else {
175 44 50       51 if ($self->{ConfigFile}) {
176             # open the file and read the contents in
177 44         60 $self->{configfile} = $self->{ConfigFile};
178 44 50       96 if ( file_name_is_absolute($self->{ConfigFile}) ) {
179             # look if this is an absolute path and save the basename if it is absolute
180 0         0 my ($volume, $path, undef) = splitpath($self->{ConfigFile});
181 0         0 $path =~ s#/$##; # remove eventually existing trailing slash
182 0 0       0 if (! $self->{ConfigPath}) {
183 0         0 $self->{ConfigPath} = [];
184             }
185 0         0 unshift @{$self->{ConfigPath}}, catpath($volume, $path, q());
  0         0  
186             }
187 44         254 $self->_open($self->{configfile});
188             # now, we parse immediately, getall simply returns the whole hash
189 41         77 $self->{config} = $self->_hashref();
190 41         71 $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content});
191             }
192             else {
193             # hm, no valid config file given, so try it as an empty object
194 0         0 $self->{config} = $self->_hashref();
195 0         0 $self->{parsed} = 1;
196             }
197             }
198             }
199              
200              
201             sub _blessoop {
202             #
203             # bless into ::Extended if necessary
204 62     62   38 my($self) = @_;
205 62 100       97 if ($self->{ExtendedAccess}) {
206             # we are blessing here again, to get into the ::Extended namespace
207             # for inheriting the methods available over there, which we doesn't have.
208 11         15 bless $self, 'Config::General::Extended';
209 11         10 eval {
210 11         749 require Config::General::Extended;
211             };
212 11 50       21 if ($EVAL_ERROR) {
213 0         0 croak "Config::General: " . $EVAL_ERROR;
214             }
215             }
216             # return $self;
217             }
218              
219             sub _blessvars {
220             #
221             # bless into ::Interpolated if necessary
222 70     70   54 my($self) = @_;
223 70 100 66     170 if ($self->{InterPolateVars} || $self->{InterPolateEnv}) {
224             # InterPolateEnv implies InterPolateVars
225 11         10 $self->{InterPolateVars} = 1;
226              
227             # we are blessing here again, to get into the ::InterPolated namespace
228             # for inheriting the methods available overthere, which we doesn't have here.
229 11         23 bless $self, 'Config::General::Interpolated';
230 11         13 eval {
231 11         628 require Config::General::Interpolated;
232             };
233 11 50       18 if ($EVAL_ERROR) {
234 0         0 croak "Config::General: " . $EVAL_ERROR;
235             }
236             # pre-compile the variable regexp
237 11         23 $self->{regex} = $self->_set_regex();
238             }
239             }
240              
241              
242             sub _splitpolicy {
243             #
244             # find out what split policy to use
245 70     70   65 my($self) = @_;
246 70 100       96 if ($self->{SplitPolicy} ne 'guess') {
247 2 50       8 if ($self->{SplitPolicy} eq 'whitespace') {
    50          
    50          
248 0         0 $self->{SplitDelimiter} = '\s+';
249 0 0       0 if (!$self->{StoreDelimiter}) {
250 0         0 $self->{StoreDelimiter} = q( );
251             }
252             }
253             elsif ($self->{SplitPolicy} eq 'equalsign') {
254 0         0 $self->{SplitDelimiter} = '\s*=\s*';
255 0 0       0 if (!$self->{StoreDelimiter}) {
256 0         0 $self->{StoreDelimiter} = ' = ';
257             }
258             }
259             elsif ($self->{SplitPolicy} eq 'custom') {
260 2 50       5 if (! $self->{SplitDelimiter} ) {
261 0         0 croak "Config::General: SplitPolicy set to 'custom' but no SplitDelimiter set.\n";
262             }
263             }
264             else {
265 0         0 croak "Config::General: Unsupported SplitPolicy: $self->{SplitPolicy}.\n";
266             }
267             }
268             else {
269 68 50       95 if (!$self->{StoreDelimiter}) {
270 68         90 $self->{StoreDelimiter} = q( );
271             }
272             }
273             }
274              
275             sub _prepare {
276             #
277             # prepare the class parameters, mangle them, if there
278             # are options to reset or to override, do it here.
279 61     61   126 my ($self, %conf) = @_;
280              
281             # save the parameter list for ::Extended's new() calls
282 61         81 $self->{Params} = \%conf;
283              
284             # be backwards compatible
285 61 100       121 if (exists $conf{-file}) {
286 6         11 $self->{ConfigFile} = delete $conf{-file};
287             }
288 61 50       105 if (exists $conf{-hash}) {
289 0         0 $self->{ConfigHash} = delete $conf{-hash};
290             }
291              
292             # store input, file, handle, or array
293 61 100       131 if (exists $conf{-ConfigFile}) {
294 29         56 $self->{ConfigFile} = delete $conf{-ConfigFile};
295             }
296 61 100       92 if (exists $conf{-ConfigHash}) {
297 11         17 $self->{ConfigHash} = delete $conf{-ConfigHash};
298             }
299              
300             # store search path for relative configs, if any
301 61 50       87 if (exists $conf{-ConfigPath}) {
302 0         0 my $configpath = delete $conf{-ConfigPath};
303 0 0       0 $self->{ConfigPath} = ref $configpath eq 'ARRAY' ? $configpath : [$configpath];
304             }
305              
306             # handle options which contains values we need (strings, hashrefs or the like)
307 61 100       81 if (exists $conf{-String} ) {
308 15 100       27 if (not ref $conf{-String}) {
    100          
309 13 50       29 if ( $conf{-String}) {
310 13         16 $self->{StringContent} = $conf{-String};
311             }
312 13         17 delete $conf{-String};
313             }
314             # re-implement arrayref support, removed after 2.22 as _read were
315             # re-organized
316             # fixed bug#33385
317             elsif(ref($conf{-String}) eq 'ARRAY') {
318 1         2 $self->{StringContent} = join "\n", @{$conf{-String}};
  1         3  
319             }
320             else {
321 1         106 croak "Config::General: Parameter -String must be a SCALAR or ARRAYREF!\n";
322             }
323 14         14 delete $conf{-String};
324             }
325 60 100       76 if (exists $conf{-Tie}) {
326 1 50       3 if ($conf{-Tie}) {
327 1         3 $self->{Tie} = delete $conf{-Tie};
328 1         2 $self->{DefaultConfig} = $self->_hashref();
329             }
330             }
331              
332 60 100       91 if (exists $conf{-FlagBits}) {
333 2 50 33     11 if ($conf{-FlagBits} && ref($conf{-FlagBits}) eq 'HASH') {
334 2         3 $self->{FlagBits} = 1;
335 2         4 $self->{FlagBitsFlags} = $conf{-FlagBits};
336             }
337 2         3 delete $conf{-FlagBits};
338             }
339              
340 60 100       75 if (exists $conf{-DefaultConfig}) {
341 3 100 66     23 if ($conf{-DefaultConfig} && ref($conf{-DefaultConfig}) eq 'HASH') {
    50 33        
342 2         3 $self->{DefaultConfig} = $conf{-DefaultConfig};
343             }
344             elsif ($conf{-DefaultConfig} && ref($conf{-DefaultConfig}) eq q()) {
345 1         3 $self->_read($conf{-DefaultConfig}, 'SCALAR');
346 1         2 $self->{DefaultConfig} = $self->_parse($self->_hashref(), $self->{content});
347 1         1 $self->{content} = ();
348             }
349 3         6 delete $conf{-DefaultConfig};
350             }
351              
352             # handle options which may either be true or false
353             # allowing "human" logic about what is true and what is not
354 60         113 foreach my $entry (keys %conf) {
355 75         58 my $key = $entry;
356 75         166 $key =~ s/^\-//;
357 75 50       109 if (! exists $self->{$key}) {
358 0         0 croak "Config::General: Unknown parameter: $entry => \"$conf{$entry}\" (key: <$key>)\n";
359             }
360 75 100       284 if ($conf{$entry} =~ /$self->{AutoTrueFlags}->{true}/io) {
    100          
361 61         81 $self->{$key} = 1;
362             }
363             elsif ($conf{$entry} =~ /$self->{AutoTrueFlags}->{false}/io) {
364 6         12 $self->{$key} = 0;
365             }
366             else {
367             # keep it untouched
368 8         13 $self->{$key} = $conf{$entry};
369             }
370             }
371              
372 60 100       92 if ($self->{MergeDuplicateOptions}) {
373             # override if not set by user
374 6 50       12 if (! exists $conf{-AllowMultiOptions}) {
375 6         5 $self->{AllowMultiOptions} = 0;
376             }
377             }
378              
379 60 50       78 if ($self->{ApacheCompatible}) {
380             # turn on all apache compatibility options which has
381             # been incorporated during the years...
382 0         0 $self->{UseApacheInclude} = 1;
383 0         0 $self->{IncludeRelative} = 1;
384 0         0 $self->{IncludeDirectories} = 1;
385 0         0 $self->{IncludeGlob} = 1;
386 0         0 $self->{SlashIsDirectory} = 1;
387 0         0 $self->{SplitPolicy} = 'whitespace';
388 0         0 $self->{CComments} = 0;
389 0         0 $self->{UseApacheIfDefine} = 1;
390             }
391              
392 60 100       109 if ($self->{UseApacheIfDefine}) {
393 3 50       7 if (exists $conf{-Define}) {
394 3         5 my $ref = ref($conf{-Define});
395              
396 3 100       10 if ($ref eq '') {
    50          
    100          
    50          
397 1         3 $self->{Define} = {$conf{-Define} => 1};
398             }
399             elsif ($ref eq 'SCALAR') {
400 0         0 $self->{Define} = {${$conf{-Define}} = 1};
  0         0  
401             }
402             elsif ($ref eq 'ARRAY') {
403 1         2 my %h = map { $_ => 1 } @{$conf{-Define}};
  1         4  
  1         3  
404 1         2 $self->{Define} = \%h;
405             }
406             elsif ($ref eq 'HASH') {
407 1         3 $self->{Define} = $conf{-Define};
408             }
409             else {
410 0         0 croak qq{Config::General: Unsupported ref '$ref' for 'Define'};
411             }
412              
413 3         6 delete $conf{-Define};
414             }
415              
416             }
417             }
418              
419             sub getall {
420             #
421             # just return the whole config hash
422             #
423 49     49 1 394 my($this) = @_;
424 49 50       67 return (exists $this->{config} ? %{$this->{config}} : () );
  49         240  
425             }
426              
427              
428             sub files {
429             #
430             # return a list of files opened so far
431             #
432 1     1 1 4 my($this) = @_;
433 1 50       2 return (exists $this->{files} ? keys %{$this->{files}} : () );
  1         3  
434             }
435              
436              
437             sub _open {
438             #
439             # open the config file, or expand a directory or glob or include
440             #
441 71     71   74 my($this, $basefile, $basepath) = @_;
442 71         53 my $cont;
443              
444 71         89 ($cont, $basefile, $basepath) = $this->_hook('pre_open', $basefile, $basepath);
445 71 50       116 return if(!$cont);
446              
447 71         45 my($fh, $configfile);
448              
449 71 100       78 if($basepath) {
450             # if this doesn't work we can still try later the global config path to use
451 8         47 $configfile = catfile($basepath, $basefile);
452             }
453             else {
454 63         55 $configfile = $basefile;
455             }
456              
457 71         179 my $glob = qr/[*?\[\{\\]/;
458 71 50       182 if ($^O =~ /win/i) {
459             # fix for rt.cpan.org#116340: do only consider a backslash
460             # as meta escape char, but not if it appears on it's own,
461             # as it happens on windows platforms.
462 0         0 $glob = qr/(\\[*?\[\{\\]|[*?\[\{])/;
463             }
464              
465 71 100 100     167 if ($this->{IncludeGlob} and $configfile =~ /$glob/) {
466             # Something like: *.conf (or maybe dir/*.conf) was included; expand it and
467             # pass each expansion through this method again.
468 4         4 local $_;
469 4         245 my @include = grep { -f $_ } bsd_glob($configfile, GLOB_BRACE | GLOB_QUOTE);
  6         50  
470              
471             # applied patch by AlexK fixing rt.cpan.org#41030
472 4 50 66     18 if ( !@include && defined $this->{ConfigPath} ) {
473 0         0 foreach my $dir (@{$this->{ConfigPath}}) {
  0         0  
474 0         0 my ($volume, $path, undef) = splitpath($basefile);
475 0 0       0 if ( -d catfile( $dir, $path ) ) {
476 0         0 push @include, grep { -f $_ } bsd_glob(catfile($dir, $basefile), GLOB_BRACE | GLOB_QUOTE);
  0         0  
477 0         0 last;
478             }
479             }
480             }
481              
482             # Multiple results or no expansion results (which is fine,
483             # include foo/* shouldn't fail if there isn't anything matching)
484             # rt.cpan.org#79869: local $this->{IncludeGlob};
485 4         7 foreach my $file (@include) {
486 6         13 $this->_open($file);
487             }
488 4         13 return;
489             }
490              
491 67 100       774 if (!-e $configfile) {
492 3         4 my $found;
493 3 50       8 if (defined $this->{ConfigPath}) {
494             # try to find the file within ConfigPath
495 0         0 foreach my $dir (@{$this->{ConfigPath}}) {
  0         0  
496 0 0       0 if( -e catfile($dir, $basefile) ) {
497 0         0 $configfile = catfile($dir, $basefile);
498 0         0 $found = 1;
499 0         0 last; # found it
500             }
501             }
502             }
503 3 50       4 if (!$found) {
504 3 50       5 my $path_message = defined $this->{ConfigPath} ? q( within ConfigPath: ) . join(q(.), @{$this->{ConfigPath}}) : q();
  0         0  
505 3         401 croak qq{Config::General The file "$basefile" does not exist$path_message!};
506             }
507             }
508              
509 64         203 local ($RS) = $RS;
510 64 50       103 if (! $RS) {
511 0         0 carp(q(\$RS (INPUT_RECORD_SEPARATOR) is undefined. Guessing you want a line feed character));
512 0         0 $RS = "\n";
513             }
514              
515 64 100 66     670 if (-d $configfile and $this->{IncludeDirectories}) {
    50          
    50          
516             # A directory was included; include all the files inside that directory in ASCII order
517 1         3 local *INCLUDEDIR;
518 1 50       27 opendir INCLUDEDIR, $configfile or croak "Config::General: Could not open directory $configfile!($!)\n";
519 1         16 my @files = sort grep { -f catfile($configfile, $_) } catfile($configfile, $_), readdir INCLUDEDIR;
  9         75  
520 1         11 closedir INCLUDEDIR;
521 1         3 local $this->{CurrentConfigFilePath} = $configfile;
522 1         2 for (@files) {
523 5         14 my $file = catfile($configfile, $_);
524 5 50 33     14 if (! exists $this->{files}->{$file} or $this->{IncludeAgain} ) {
525             # support re-read if used urged us to do so, otherwise ignore the file
526 5         7 $fh = $this->_openfile_for_read($file);
527 5         27 $this->{files}->{"$file"} = 1;
528 5         9 $this->_read($fh);
529             }
530             else {
531 0         0 warn "File $file already loaded. Use -IncludeAgain to load it again.\n";
532             }
533             }
534             }
535             elsif (-d $configfile) {
536 0         0 croak "Config::General: config file argument is a directory, expecting a file!\n";
537             }
538             elsif (-e _) {
539 63 100 100     125 if (exists $this->{files}->{$configfile} and not $this->{IncludeAgain}) {
540             # do not read the same file twice, just return
541 1         10 warn "File $configfile already loaded. Use -IncludeAgain to load it again.\n";
542 1         7 return;
543             }
544             else {
545 62         100 $fh = $this->_openfile_for_read($configfile);
546 62         113 $this->{files}->{$configfile} = 1;
547              
548 62         118 my ($volume, $path, undef) = splitpath($configfile);
549 62         620 local $this->{CurrentConfigFilePath} = catpath($volume, $path, q());
550              
551 62         341 $this->_read($fh);
552             }
553             }
554 62         578 return;
555             }
556              
557              
558             sub _openfile_for_read {
559             #
560             # actually open a file, turn on utf8 mode if requested by bom
561             #
562 67     67   60 my ($this, $file) = @_;
563              
564 67 50       249 my $fh = IO::File->new( $file, 'r')
565             or croak "Config::General: Could not open $file!($!)\n";
566              
567             # attempt to read an initial utf8 byte-order mark (BOM)
568 67         3948 my $n_read = sysread $fh, my $read_BOM, length(_UTF8_BOM);
569 67   66     229 my $has_BOM = $n_read == length(_UTF8_BOM) && $read_BOM eq _UTF8_BOM;
570              
571             # set utf8 perlio layer if BOM was found or if option -UTF8 is turned on
572 67 100 100     223 binmode $fh, ":utf8" if $this->{UTF8} || $has_BOM;
573              
574             # rewind to beginning of file if we read chars that were not the BOM
575 67 100 66     247 sysseek $fh, 0, 0 if $n_read && !$has_BOM;
576              
577 67         90 return $fh;
578             }
579              
580              
581              
582             sub _read {
583             #
584             # store the config contents in @content
585             # and prepare it somewhat for easier parsing later
586             # (comments, continuing lines, and stuff)
587             #
588 82     82   80 my($this, $fh, $flag) = @_;
589              
590              
591 82         65 my(@stuff, @content, $c_comment, $longline, $hier, $hierend, @hierdoc);
592 82         74 local $_ = q();
593              
594 82 100 66     178 if ($flag && $flag eq 'SCALAR') {
595 15 50       16 if (ref($fh) eq 'ARRAY') {
596 0         0 @stuff = @{$fh};
  0         0  
597             }
598             else {
599 15         62 @stuff = split /\n/, $fh;
600             }
601             }
602             else {
603 67         910 @stuff = <$fh>;
604             }
605              
606 82         94 my $cont;
607 82         128 ($cont, $fh, @stuff) = $this->_hook('pre_read', $fh, @stuff);
608 82 50       167 return if(!$cont);
609              
610 82 100       113 if ($this->{UseApacheIfDefine}) {
611 3         7 $this->_process_apache_ifdefine(\@stuff);
612             }
613              
614 82         98 foreach (@stuff) {
615 766 50       876 if ($this->{AutoLaunder}) {
616 0 0       0 if (m/^(.*)$/) {
617 0         0 $_ = $1;
618             }
619             }
620              
621 766         543 chomp;
622              
623              
624 766 100       837 if ($hier) {
625             # inside here-doc, only look for $hierend marker
626 25 100       76 if (/^(\s*)\Q$hierend\E\s*$/) {
627 7         8 my $indent = $1; # preserve indentation
628 7         12 $hier .= ' ' . $this->{EOFseparator}; # bugfix of rt.40925
629             # _parse will also preserver indentation
630 7 50       10 if ($indent) {
631 0         0 foreach (@hierdoc) {
632 0         0 s/^$indent//; # i.e. the end was: " EOF" then we remove " " from every here-doc line
633 0         0 $hier .= $_ . "\n"; # and store it in $hier
634             }
635             }
636             else {
637 7         16 $hier .= join "\n", @hierdoc; # there was no indentation of the end-string, so join it 1:1
638             }
639 7         6 push @{$this->{content}}, $hier; # push it onto the content stack
  7         9  
640 7         14 @hierdoc = ();
641 7         5 undef $hier;
642 7         5 undef $hierend;
643             }
644             else {
645             # everything else onto the stack
646 18         14 push @hierdoc, $_;
647             }
648 25         26 next;
649             }
650              
651 741 50       809 if ($this->{CComments}) {
652             # look for C-Style comments, if activated
653 741 100       1590 if (/(\s*\/\*.*\*\/\s*)/) {
    100          
    100          
654             # single c-comment on one line
655 2         7 s/\s*\/\*.*\*\/\s*//;
656             }
657             elsif (/^\s*\/\*/) {
658             # the beginning of a C-comment ("/*"), from now on ignore everything.
659 15 50       19 if (/\*\/\s*$/) {
660             # C-comment end is already there, so just ignore this line!
661 0         0 $c_comment = 0;
662             }
663             else {
664 15         12 $c_comment = 1;
665             }
666             }
667             elsif (/\*\//) {
668 15 50       20 if (!$c_comment) {
669 0         0 warn "invalid syntax: found end of C-comment without previous start!\n";
670             }
671 15         11 $c_comment = 0; # the current C-comment ends here, go on
672 15         35 s/^.*\*\///; # if there is still stuff, it will be read
673             }
674 741 100       803 next if($c_comment); # ignore EVERYTHING from now on, IF it IS a C-Comment
675             }
676              
677             # Remove comments and empty lines
678 589         556 s/(? .* bugfix rt.cpan.org#44600
679 589 50       681 next if /^\s*#/;
680              
681             # look for multiline option, indicated by a trailing backslash
682 589 100       668 if (/(?
683 9         9 chop; # remove trailing backslash
684 9         15 s/^\s*//;
685 9         11 $longline .= $_;
686 9         8 next;
687             }
688              
689             # transform explicit-empty blocks to conforming blocks
690             # rt.cpan.org#80006 added \s* before $/
691 580 100 66     1489 if (!$this->{ApacheCompatible} && /\s*<([^\/]+?.*?)\/>\s*$/) {
692 3         6 my $block = $1;
693 3 50       5 if ($block !~ /\"/) {
694 3 50       7 if ($block !~ /\s[^\s]/) {
695             # fix of bug 7957, add quotation to pure slash at the
696             # end of a block so that it will be considered as directory
697             # unless the block is already quoted or contains whitespaces
698             # and no quotes.
699 3 50       4 if ($this->{SlashIsDirectory}) {
700 3         4 push @{$this->{content}}, '<' . $block . '"/">';
  3         7  
701 3         5 next;
702             }
703             }
704             }
705 0         0 my $orig = $_;
706 0         0 $orig =~ s/\/>$/>/;
707 0         0 $block =~ s/\s\s*.*$//;
708 0         0 push @{$this->{content}}, $orig, "";
  0         0  
709 0         0 next;
710             }
711              
712              
713             # look for here-doc identifier
714 577 100       594 if ($this->{SplitPolicy} eq 'guess') {
715 507 100       938 if (/^\s*([^=]+?)\s*=\s*<<\s*(.+?)\s*$/) {
    100          
716             # try equal sign (fix bug rt#36607)
717 2         3 $hier = $1; # the actual here-doc variable name
718 2         3 $hierend = $2; # the here-doc identifier, i.e. "EOF"
719 2         2 next;
720             }
721             elsif (/^\s*(\S+?)\s+<<\s*(.+?)\s*$/) {
722             # try whitespace
723 5         8 $hier = $1; # the actual here-doc variable name
724 5         4 $hierend = $2; # the here-doc identifier, i.e. "EOF"
725 5         6 next;
726             }
727             }
728             else {
729             # no guess, use one of the configured strict split policies
730 70 100       217 if (/^\s*(.+?)($this->{SplitDelimiter})<<\s*(.+?)\s*$/) {
731 1         3 $hier = $1; # the actual here-doc variable name
732 1         1 $hierend = $3; # the here-doc identifier, i.e. "EOF"
733 1         2 next;
734             }
735             }
736              
737              
738              
739             ###
740             ### any "normal" config lines from now on
741             ###
742              
743 569 100       515 if ($longline) {
744             # previous stuff was a longline and this is the last line of the longline
745 5         9 s/^\s*//;
746 5         6 $longline .= $_;
747 5         3 push @{$this->{content}}, $longline; # push it onto the content stack
  5         8  
748 5         4 undef $longline;
749 5         5 next;
750             }
751             else {
752             # ignore empty lines
753 564 100       914 next if /^\s*$/;
754              
755             # look for include statement(s)
756 433         259 my $incl_file;
757 433         299 my $path = '';
758 433 100 66     908 if ( $this->{IncludeRelative} and defined $this->{CurrentConfigFilePath}) {
    50          
759 87         74 $path = $this->{CurrentConfigFilePath};
760             }
761             elsif (defined $this->{ConfigPath}) {
762             # fetch pathname of base config file, assuming the 1st one is the path of it
763 0         0 $path = $this->{ConfigPath}->[0];
764             }
765              
766             # bugfix rt.cpan.org#38635: support quoted filenames
767 433 100       402 if ($this->{UseApacheInclude}) {
768 16         8 my $opt = '';
769 16 100       56 if (/^\s*(include|includeoptional)\s*(["'])(.*?)(?
    100          
770 1         3 $incl_file = $3;
771 1         1 $opt = $1;
772             }
773             elsif (/^\s*(include|includeoptional)\s+(.+?)\s*$/i) {
774 3         4 $incl_file = $2;
775 3         5 $opt = $1;
776             }
777 16 100       20 if ($incl_file) {
778 4 50 66     18 if ($this->{IncludeGlob} && $opt =~ /opt/i && $incl_file !~ /[*?\[\{\\]/) {
      66        
779             # fix rt#107108
780             # glob enabled && optional include && file is not already a glob:
781             # turn it into a singular matching glob, like:
782             # "file" => "[f][i][l][e]" and:
783             # "dir/file" => "dir/[f][i][l][e]"
784             # which IS a glob but only matches that particular file. if it
785             # doesn't exist, it will be ignored by _open(), just what
786             # we'd like to have when using IncludeOptional.
787 2         6 my ($vol,$dirs,$file) = splitpath( $incl_file );
788 2         21 $incl_file = catpath($vol, $dirs, join '', map { "[$_]" } split //, $file);
  29         32  
789             }
790             }
791             }
792             else {
793 417 50       740 if (/^\s*<>\\s*$/i) {
    100          
794 0         0 $incl_file = $2;
795             }
796             elsif (/^\s*<>\s*$/i) {
797 17         31 $incl_file = $1;
798             }
799             }
800              
801 433 100       379 if ($incl_file) {
802 21 100 66     65 if ( $this->{IncludeRelative} && $path && !file_name_is_absolute($incl_file) ) {
      66        
803             # include the file from within location of $this->{configfile}
804 8         49 $this->_open( $incl_file, $path );
805             }
806             else {
807             # include the file from within pwd, or absolute
808 13         30 $this->_open($incl_file);
809             }
810             }
811             else {
812             # standard entry, (option = value)
813 412         233 push @{$this->{content}}, $_;
  412         680  
814             }
815              
816             }
817              
818             }
819              
820 81         161 ($cont, $this->{content}) = $this->_hook('post_read', $this->{content});
821 81         200 return 1;
822             }
823              
824              
825             sub _process_apache_ifdefine {
826             #
827             # Loop trough config lines and exclude all those entries
828             # for which there's no IFDEF but which reside inside an IFDEF.
829             #
830             # Called from _read(), if UseApacheIfDefine is enabled, returns
831             # the modified array.
832 3     3   4 my($this, $rawlines) = @_;
833              
834 3         3 my @filtered;
835 3         1 my $includeFlag = 1;
836 3         4 my $blockLevel = 0;
837              
838 3         3 foreach (@{$rawlines}) {
  3         4  
839 9 100 33     46 if (/^<\s*IfDefine\s+([!]*)("[^"]+"|\S+)\s*>/i) {
    100          
    50          
    50          
840             # new IFDEF block, mark following content to be included if
841             # the DEF is known, otherwise skip it til end of IFDEF
842 3         7 my ($negate, $define) = ($1 eq '!',$2);
843              
844 3         3 $blockLevel++;
845 3         6 $includeFlag &= ((not $negate) & (exists $this->{Define}{$define}));
846             } elsif (/^<\s*\/IfDefine\s*>/i) {
847 3         4 $blockLevel--;
848 3         3 $includeFlag = $blockLevel == 0;
849             } elsif ($includeFlag && /\s*Define\s+("[^"]+"|\S+)/i) {
850             # inline Define, add it to our list
851 0         0 $this->{Define}{$1} = 1;
852             } elsif ($includeFlag) {
853 3         4 push @filtered, $_;
854             }
855             }
856              
857 3 50       6 if ($blockLevel) {
858 0         0 croak qq(Config::General: Block has no EndBlock statement!\n);
859             }
860              
861 3         7 @$rawlines = @filtered; # replace caller array
862             }
863              
864              
865             sub _parse {
866             #
867             # parse the contents of the file
868             #
869 138     138   109 my($this, $config, $content) = @_;
870 138         95 my(@newcontent, $block, $blockname, $chunk,$block_level);
871 138         136 local $_;
872              
873 138         76 foreach (@{$content}) { # loop over content stack
  138         170  
874 621         437 chomp;
875 621         693 $chunk++;
876 621         768 $_ =~ s/^\s+//; # strip spaces @ end and begin
877 621         888 $_ =~ s/\s+$//;
878              
879             #
880             # build option value assignment, split current input
881             # using whitespace, equal sign or optionally here-doc
882             # separator EOFseparator
883 621         351 my ($option,$value);
884 621 100       954 if (/$this->{EOFseparator}/) {
885 7         49 ($option,$value) = split /\s*$this->{EOFseparator}\s*/, $_, 2; # separated by heredoc-finding in _open()
886             }
887             else {
888 614 100       612 if ($this->{SplitPolicy} eq 'guess') {
889             # again the old regex. use equalsign SplitPolicy to get the
890             # 2.00 behavior. the new regexes were too odd.
891 499         1492 ($option,$value) = split /\s*=\s*|\s+/, $_, 2;
892             }
893             else {
894             # no guess, use one of the configured strict split policies
895 115         305 ($option,$value) = split /$this->{SplitDelimiter}/, $_, 2;
896             }
897             }
898              
899 621 50       919 if($this->{NormalizeOption}) {
900 0         0 $option = $this->{NormalizeOption}($option);
901             }
902              
903 621 100 100     1534 if ($value && $value =~ /^"/ && $value =~ /"$/) {
      100        
904 9         17 $value =~ s/^"//; # remove leading and trailing "
905 9         16 $value =~ s/"$//;
906             }
907 621 100       1022 if (! defined $block) { # not inside a block @ the moment
    100          
    100          
908 335 100       576 if (/^<([^\/]+?.*?)>$/) { # look if it is a block
    50          
909 86         116 $block = $1; # store block name
910 86 100       95 if ($block =~ /^"([^"]+)"$/) {
911             # quoted block, unquote it and do not split
912 1         2 $block =~ s/"//g;
913             }
914             else {
915             # If it is a named block store the name separately; allow the block and name to each be quoted
916 85 50       207 if ($block =~ /^(?:"([^"]+)"|(\S+))(?:\s+(?:"([^"]+)"|(.*)))?$/) {
917 85   66     200 $block = $1 || $2;
918 85   66     168 $blockname = $3 || $4;
919             }
920             }
921 86 50       114 if($this->{NormalizeBlock}) {
922 0         0 $block = $this->{NormalizeBlock}($block);
923 0 0       0 if (defined $blockname) {
924 0         0 $blockname = $this->{NormalizeBlock}($blockname);
925 0 0       0 if($blockname eq "") {
926             # if, after normalization no blockname is left, remove it
927 0         0 $blockname = undef;
928             }
929             }
930             }
931 86 100       96 if ($this->{InterPolateVars}) {
932             # interpolate block(name), add "<" and ">" to the key, because
933             # it is sure that such keys does not exist otherwise.
934 30         77 $block = $this->_interpolate($config, "<$block>", $block);
935 30 100       45 if (defined $blockname) {
936 12         30 $blockname = $this->_interpolate($config, "<$blockname>", "$blockname");
937             }
938             }
939 86 50       103 if ($this->{LowerCaseNames}) {
940 0         0 $block = lc $block; # only for blocks lc(), if configured via new()
941             }
942 86         72 $this->{level} += 1;
943 86         78 undef @newcontent;
944 86         97 next;
945             }
946             elsif (/^<\/(.+?)>$/) { # it is an end block, but we don't have a matching block!
947 0         0 croak "Config::General: EndBlock \"<\/$1>\" has no StartBlock statement (level: $this->{level}, chunk $chunk)!\n";
948             }
949             else { # insert key/value pair into actual node
950 249 50       295 if ($this->{LowerCaseNames}) {
951 0         0 $option = lc $option;
952             }
953              
954 249 100       249 if (exists $config->{$option}) {
955 25 100       29 if ($this->{MergeDuplicateOptions}) {
956 5         7 $config->{$option} = $this->_parse_value($config, $option, $value);
957              
958             # bugfix rt.cpan.org#33216
959 5 100       10 if ($this->{InterPolateVars}) {
960             # save pair on local stack
961 2         5 $config->{__stack}->{$option} = $config->{$option};
962             }
963             }
964             else {
965 20 50       25 if (! $this->{AllowMultiOptions} ) {
966             # no, duplicates not allowed
967 0         0 croak "Config::General: Option \"$option\" occurs more than once (level: $this->{level}, chunk $chunk)!\n";
968             }
969             else {
970             # yes, duplicates allowed
971 20 100       31 if (ref($config->{$option}) ne 'ARRAY') { # convert scalar to array
972 13         13 my $savevalue = $config->{$option};
973 13         13 delete $config->{$option};
974 13         9 push @{$config->{$option}}, $savevalue;
  13         23  
975             }
976 20         22 eval {
977             # check if arrays are supported by the underlying hash
978 20         11 my $i = scalar @{$config->{$option}};
  20         24  
979             };
980 20 50       21 if ($EVAL_ERROR) {
981 0         0 $config->{$option} = $this->_parse_value($config, $option, $value);
982             }
983             else {
984             # it's already an array, just push
985 20         9 push @{$config->{$option}}, $this->_parse_value($config, $option, $value);
  20         31  
986             }
987             }
988             }
989             }
990             else {
991 224 100 66     423 if($this->{ForceArray} && defined $value && $value =~ /^\[\s*(.+?)\s*\]$/) {
      66        
992             # force single value array entry
993 2         2 push @{$config->{$option}}, $this->_parse_value($config, $option, $1);
  2         6  
994             }
995             else {
996             # standard config option, insert key/value pair into node
997 222         279 $config->{$option} = $this->_parse_value($config, $option, $value);
998              
999 222 100       391 if ($this->{InterPolateVars}) {
1000             # save pair on local stack
1001 72         129 $config->{__stack}->{$option} = $config->{$option};
1002             }
1003             }
1004             }
1005             }
1006             }
1007             elsif (/^<([^\/]+?.*?)>$/) { # found a start block inside a block, don't forget it
1008 21         16 $block_level++; # $block_level indicates wether we are still inside a node
1009 21         26 push @newcontent, $_; # push onto new content stack for later recursive call of _parse()
1010             }
1011             elsif (/^<\/(.+?)>$/) {
1012 107 100       102 if ($block_level) { # this endblock is not the one we are searching for, decrement and push
1013 21         15 $block_level--; # if it is 0, then the endblock was the one we searched for, see below
1014 21         28 push @newcontent, $_; # push onto new content stack
1015             }
1016             else { # calling myself recursively, end of $block reached, $block_level is 0
1017 86 100       92 if (defined $blockname) {
1018             # a named block, make it a hashref inside a hash within the current node
1019              
1020 42 100       70 if (! exists $config->{$block}) {
1021             # Make sure that the hash is not created implicitly
1022 30         41 $config->{$block} = $this->_hashref();
1023              
1024 30 100       58 if ($this->{InterPolateVars}) {
1025             # inherit current __stack to new block
1026 9         13 $config->{$block}->{__stack} = $this->_copy($config->{__stack});
1027             }
1028             }
1029              
1030 42 100       111 if (ref($config->{$block}) eq '') {
    100          
    50          
1031 1         101 croak "Config::General: Block <$block> already exists as scalar entry!\n";
1032             }
1033             elsif (ref($config->{$block}) eq 'ARRAY') {
1034 2         216 croak "Config::General: Cannot append named block <$block $blockname> to array of scalars!\n"
1035             ."Block <$block> or scalar '$block' occurs more than once.\n"
1036             ."Turn on -MergeDuplicateBlocks or make sure <$block> occurs only once in the config.\n";
1037             }
1038             elsif (exists $config->{$block}->{$blockname}) {
1039             # the named block already exists, make it an array
1040 0 0       0 if ($this->{MergeDuplicateBlocks}) {
1041             # just merge the new block with the same name as an existing one into
1042             # this one.
1043 0         0 $config->{$block}->{$blockname} = $this->_parse($config->{$block}->{$blockname}, \@newcontent);
1044             }
1045             else {
1046 0 0       0 if (! $this->{AllowMultiOptions}) {
1047 0         0 croak "Config::General: Named block \"<$block $blockname>\" occurs more than once (level: $this->{level}, chunk $chunk)!\n";
1048             }
1049             else { # preserve existing data
1050 0         0 my $savevalue = $config->{$block}->{$blockname};
1051 0         0 delete $config->{$block}->{$blockname};
1052 0         0 my @ar;
1053 0 0       0 if (ref $savevalue eq 'ARRAY') {
1054 0         0 push @ar, @{$savevalue}; # preserve array if any
  0         0  
1055             }
1056             else {
1057 0         0 push @ar, $savevalue;
1058             }
1059 0         0 push @ar, $this->_parse( $this->_hashref(), \@newcontent); # append it
1060 0         0 $config->{$block}->{$blockname} = \@ar;
1061             }
1062             }
1063             }
1064             else {
1065             # the first occurrence of this particular named block
1066 39         49 my $tmphash = $this->_hashref();
1067              
1068 39 100       55 if ($this->{InterPolateVars}) {
1069             # inherit current __stack to new block
1070 12         17 $tmphash->{__stack} = $this->_copy($config->{__stack});
1071             }
1072              
1073 39         66 $config->{$block}->{$blockname} = $this->_parse($tmphash, \@newcontent);
1074             }
1075             }
1076             else {
1077             # standard block
1078 44 100       53 if (exists $config->{$block}) {
1079 5 100       11 if (ref($config->{$block}) eq '') {
1080 1         103 croak "Config::General: Cannot create hashref from <$block> because there is\n"
1081             ."already a scalar option '$block' with value '$config->{$block}'\n";
1082             }
1083              
1084             # the block already exists, make it an array
1085 4 100       6 if ($this->{MergeDuplicateBlocks}) {
1086             # just merge the new block with the same name as an existing one into
1087             # this one.
1088 2         6 $config->{$block} = $this->_parse($config->{$block}, \@newcontent);
1089             }
1090             else {
1091 2 50       3 if (! $this->{AllowMultiOptions}) {
1092 0         0 croak "Config::General: Block \"<$block>\" occurs more than once (level: $this->{level}, chunk $chunk)!\n";
1093             }
1094             else {
1095 2         3 my $savevalue = $config->{$block};
1096 2         2 delete $config->{$block};
1097 2         3 my @ar;
1098 2 50       4 if (ref $savevalue eq "ARRAY") {
1099 0         0 push @ar, @{$savevalue};
  0         0  
1100             }
1101             else {
1102 2         2 push @ar, $savevalue;
1103             }
1104              
1105             # fixes rt#31529
1106 2         3 my $tmphash = $this->_hashref();
1107 2 50       7 if ($this->{InterPolateVars}) {
1108             # inherit current __stack to new block
1109 0         0 $tmphash->{__stack} = $this->_copy($config->{__stack});
1110             }
1111              
1112 2         4 push @ar, $this->_parse( $tmphash, \@newcontent);
1113              
1114 2         7 $config->{$block} = \@ar;
1115             }
1116             }
1117             }
1118             else {
1119             # the first occurrence of this particular block
1120 39         53 my $tmphash = $this->_hashref();
1121              
1122 39 100       60 if ($this->{InterPolateVars}) {
1123             # inherit current __stack to new block
1124 16         23 $tmphash->{__stack} = $this->_copy($config->{__stack});
1125             }
1126              
1127 39         68 $config->{$block} = $this->_parse($tmphash, \@newcontent);
1128             }
1129             }
1130 82         65 undef $blockname;
1131 82         43 undef $block;
1132 82         70 $this->{level} -= 1;
1133 82         83 next;
1134             }
1135             }
1136             else { # inside $block, just push onto new content stack
1137 158         201 push @newcontent, $_;
1138             }
1139             }
1140 134 50       173 if ($block) {
1141             # $block is still defined, which means, that it had
1142             # no matching endblock!
1143 0         0 croak "Config::General: Block \"<$block>\" has no EndBlock statement (level: $this->{level}, chunk $chunk)!\n";
1144             }
1145 134         274 return $config;
1146             }
1147              
1148              
1149             sub _copy {
1150             #
1151             # copy the contents of one hash into another
1152             # to circumvent invalid references
1153             # fixes rt.cpan.org bug #35122
1154 37     37   29 my($this, $source) = @_;
1155 37         38 my %hash = ();
1156 37         21 while (my ($key, $value) = each %{$source}) {
  425         626  
1157 388         390 $hash{$key} = $value;
1158             }
1159 37         54 return \%hash;
1160             }
1161              
1162              
1163             sub _parse_value {
1164             #
1165             # parse the value if value parsing is turned on
1166             # by either -AutoTrue and/or -FlagBits
1167             # otherwise just return the given value unchanged
1168             #
1169 249     249   240 my($this, $config, $option, $value) =@_;
1170              
1171 249         147 my $cont;
1172 249         266 ($cont, $option, $value) = $this->_hook('pre_parse_value', $option, $value);
1173 249 50       350 return $value if(!$cont);
1174              
1175             # avoid "Use of uninitialized value"
1176 249 100       282 if (! defined $value) {
1177             # patch fix rt#54583
1178             # Return an input undefined value without trying transformations
1179 4         8 return $value;
1180             }
1181              
1182 245 50       287 if($this->{NormalizeValue}) {
1183 0         0 $value = $this->{NormalizeValue}($value);
1184             }
1185              
1186 245 100       268 if ($this->{InterPolateVars}) {
1187 73         126 $value = $this->_interpolate($config, $option, $value);
1188             }
1189              
1190             # make true/false values to 1 or 0 (-AutoTrue)
1191 245 100       312 if ($this->{AutoTrue}) {
1192 46 100       179 if ($value =~ /$this->{AutoTrueFlags}->{true}/io) {
    100          
1193 7         7 $value = 1;
1194             }
1195             elsif ($value =~ /$this->{AutoTrueFlags}->{false}/io) {
1196 9         9 $value = 0;
1197             }
1198             }
1199              
1200             # assign predefined flags or undef for every flag | flag ... (-FlagBits)
1201 245 100       299 if ($this->{FlagBits}) {
1202 35 100       48 if (exists $this->{FlagBitsFlags}->{$option}) {
1203 2         8 my %__flags = map { $_ => 1 } split /\s*\|\s*/, $value;
  5         9  
1204 2         2 foreach my $flag (keys %{$this->{FlagBitsFlags}->{$option}}) {
  2         7  
1205 6 100       7 if (exists $__flags{$flag}) {
1206 5         5 $__flags{$flag} = $this->{FlagBitsFlags}->{$option}->{$flag};
1207             }
1208             else {
1209 1         2 $__flags{$flag} = undef;
1210             }
1211             }
1212 2         3 $value = \%__flags;
1213             }
1214             }
1215              
1216 245 100       283 if (!$this->{NoEscape}) {
1217             # are there any escaped characters left? put them out as is
1218 244         269 $value =~ s/\\([\$\\\"#])/$1/g;
1219             }
1220              
1221 245         276 ($cont, $option, $value) = $this->_hook('post_parse_value', $option, $value);
1222              
1223 245         432 return $value;
1224             }
1225              
1226              
1227              
1228             sub _hook {
1229 728     728   916 my ($this, $hook, @arguments) = @_;
1230 728 50       930 if(exists $this->{Plug}->{$hook}) {
1231 0         0 my $sub = $this->{Plug}->{$hook};
1232 0         0 my @hooked = &$sub(@arguments);
1233 0         0 return @hooked;
1234             }
1235 728         1440 return (1, @arguments);
1236             }
1237              
1238              
1239              
1240             sub save {
1241             #
1242             # this is the old version of save() whose API interface
1243             # has been changed. I'm very sorry 'bout this.
1244             #
1245             # I'll try to figure out, if it has been called correctly
1246             # and if yes, feed the call to Save(), otherwise croak.
1247             #
1248 0     0 0 0 my($this, $one, @two) = @_;
1249              
1250 0 0 0     0 if ( (@two && $one) && ( (scalar @two) % 2 == 0) ) {
      0        
1251             # @two seems to be a hash
1252 0         0 my %h = @two;
1253 0         0 $this->save_file($one, \%h);
1254             }
1255             else {
1256 0         0 croak q(Config::General: The save() method is deprecated. Use the new save_file() method instead!);
1257             }
1258 0         0 return;
1259             }
1260              
1261              
1262             sub save_file {
1263             #
1264             # save the config back to disk
1265             #
1266 7     7 1 4765 my($this, $file, $config) = @_;
1267 7         7 my $fh;
1268             my $config_string;
1269              
1270 7 50       10 if (!$file) {
1271 0         0 croak "Config::General: Filename is required!";
1272             }
1273             else {
1274 7 50       10 if ($this->{UTF8}) {
1275 0         0 $fh = IO::File->new;
1276 0 0       0 open($fh, ">:utf8", $file)
1277             or croak "Config::General: Could not open $file in UTF8 mode!($!)\n";
1278             }
1279             else {
1280 7 50       32 $fh = IO::File->new( "$file", 'w')
1281             or croak "Config::General: Could not open $file!($!)\n";
1282             }
1283 7 100       703 if (!$config) {
1284 5 50       10 if (exists $this->{config}) {
1285 5         18 $config_string = $this->_store(0, $this->{config});
1286             }
1287             else {
1288 0         0 croak "Config::General: No config hash supplied which could be saved to disk!\n";
1289             }
1290             }
1291             else {
1292 2         10 $config_string = $this->_store(0, $config);
1293             }
1294              
1295 6 50       8 if ($config_string) {
1296 6         6 print {$fh} $config_string;
  6         50  
1297             }
1298             else {
1299             # empty config for whatever reason, I don't care
1300 0         0 print {$fh} q();
  0         0  
1301             }
1302              
1303 6         171 close $fh;
1304             }
1305 6         24 return;
1306             }
1307              
1308              
1309              
1310             sub save_string {
1311             #
1312             # return the saved config as a string
1313             #
1314 1     1 1 70 my($this, $config) = @_;
1315              
1316 1 50 33     7 if (!$config || ref($config) ne 'HASH') {
1317 0 0       0 if (exists $this->{config}) {
1318 0         0 return $this->_store(0, $this->{config});
1319             }
1320             else {
1321 0         0 croak "Config::General: No config hash supplied which could be saved to disk!\n";
1322             }
1323             }
1324             else {
1325 1         2 return $this->_store(0, $config);
1326             }
1327 0         0 return;
1328             }
1329              
1330              
1331              
1332             sub _store {
1333             #
1334             # internal sub for saving a block
1335             #
1336 31     31   25 my($this, $level, $config) = @_;
1337 31         30 local $_;
1338 31         35 my $indent = q( ) x $level;
1339              
1340 31         19 my $config_string = q();
1341              
1342 31 100       84 foreach my $entry ( $this->{SaveSorted} ? sort keys %$config : keys %$config ) {
1343             # fix rt#104548
1344 93 100       149 if ($entry =~ /[<>\n\r]/) {
1345 1         130 croak "Config::General: current key contains invalid characters: $entry!\n";
1346             }
1347              
1348 92 100       146 if (ref($config->{$entry}) eq 'ARRAY') {
    100          
1349 5 100 66     12 if( $this->{ForceArray} && scalar @{$config->{$entry}} == 1 && ! ref($config->{$entry}->[0]) ) {
  1   66     8  
1350             # a single value array forced to stay as array
1351 1         4 $config_string .= $this->_write_scalar($level, $entry, '[' . $config->{$entry}->[0] . ']');
1352             }
1353             else {
1354 4 50       9 foreach my $line ( $this->{SaveSorted} ? sort @{$config->{$entry}} : @{$config->{$entry}} ) {
  0         0  
  4         6  
1355 10 100       12 if (ref($line) eq 'HASH') {
1356 2         4 $config_string .= $this->_write_hash($level, $entry, $line);
1357             }
1358             else {
1359 8         11 $config_string .= $this->_write_scalar($level, $entry, $line);
1360             }
1361             }
1362             }
1363             }
1364             elsif (ref($config->{$entry}) eq 'HASH') {
1365 21         31 $config_string .= $this->_write_hash($level, $entry, $config->{$entry});
1366             }
1367             else {
1368 66         123 $config_string .= $this->_write_scalar($level, $entry, $config->{$entry});
1369             }
1370             }
1371              
1372 30         52 return $config_string;
1373             }
1374              
1375              
1376             sub _write_scalar {
1377             #
1378             # internal sub, which writes a scalar
1379             # it returns it, in fact
1380             #
1381 75     75   70 my($this, $level, $entry, $line) = @_;
1382              
1383 75         71 my $indent = q( ) x $level;
1384              
1385 75         36 my $config_string;
1386              
1387             # patch fix rt#54583
1388 75 50 66     226 if ( ! defined $line ) {
    100          
1389 0         0 $config_string .= $indent . $entry . "\n";
1390             }
1391             elsif ($line =~ /\n/ || $line =~ /\\$/) {
1392             # it is a here doc
1393 3         1 my $delimiter;
1394 3         4 my $tmplimiter = 'EOF';
1395 3         5 while (!$delimiter) {
1396             # create a unique here-doc identifier
1397 3 50       18 if ($line =~ /$tmplimiter/s) {
1398 0         0 $tmplimiter .= '%';
1399             }
1400             else {
1401 3         8 $delimiter = $tmplimiter;
1402             }
1403             }
1404 3         8 my @lines = split /\n/, $line;
1405 3         7 $config_string .= $indent . $entry . $this->{StoreDelimiter} . "<<$delimiter\n";
1406 3         5 foreach (@lines) {
1407 8         9 $config_string .= $indent . $_ . "\n";
1408             }
1409 3         6 $config_string .= $indent . "$delimiter\n";
1410             }
1411             else {
1412             # a simple stupid scalar entry
1413              
1414 72 50       90 if (!$this->{NoEscape}) {
1415             # re-escape contained $ or # or \ chars
1416 72         97 $line =~ s/([#\$\\\"])/\\$1/g;
1417             }
1418              
1419             # bugfix rt.cpan.org#42287
1420 72 100 100     251 if ($line =~ /^\s/ or $line =~ /\s$/) {
1421             # need to quote it
1422 2         4 $line = "\"$line\"";
1423             }
1424 72         107 $config_string .= $indent . $entry . $this->{StoreDelimiter} . $line . "\n";
1425             }
1426              
1427 75         118 return $config_string;
1428             }
1429              
1430             sub _write_hash {
1431             #
1432             # internal sub, which writes a hash (block)
1433             # it returns it, in fact
1434             #
1435 23     23   21 my($this, $level, $entry, $line) = @_;
1436              
1437 23         17 my $indent = q( ) x $level;
1438 23         13 my $config_string;
1439              
1440 23 50       37 if ($entry =~ /\s/) {
1441             # quote the entry if it contains whitespaces
1442 0         0 $entry = q(") . $entry . q(");
1443             }
1444              
1445             # check if the next level key points to a hash and is the only one
1446             # in this case put out a named block
1447             # fixes rt.77667
1448 23         14 my $num = scalar keys %{$line};
  23         26  
1449 23 100       29 if($num == 1) {
1450 17         13 my $key = (keys %{$line})[0];
  17         19  
1451 17 100       29 if(ref($line->{$key}) eq 'HASH') {
1452 11         17 $config_string .= $indent . qq(<$entry $key>\n);
1453 11         19 $config_string .= $this->_store($level + 1, $line->{$key});
1454 11         15 $config_string .= $indent . qq(\n";
1455 11         17 return $config_string;
1456             }
1457             }
1458            
1459 12         17 $config_string .= $indent . q(<) . $entry . ">\n";
1460 12         18 $config_string .= $this->_store($level + 1, $line);
1461 12         12 $config_string .= $indent . q(\n";
1462              
1463 12         20 return $config_string
1464             }
1465              
1466              
1467             sub _hashref {
1468             #
1469             # return a probably tied new empty hash ref
1470             #
1471 154     154   121 my($this) = @_;
1472 154 100       167 if ($this->{Tie}) {
1473 1         1 eval {
1474 1         49 eval qq{require $this->{Tie}};
1475             };
1476 1 50       3 if ($EVAL_ERROR) {
1477 0         0 croak q(Config::General: Could not create a tied hash of type: ) . $this->{Tie} . q(: ) . $EVAL_ERROR;
1478             }
1479 1         1 my %hash;
1480 1         3 tie %hash, $this->{Tie};
1481 1         9 return \%hash;
1482             }
1483             else {
1484 153         219 return {};
1485             }
1486             }
1487              
1488              
1489             #
1490             # Procedural interface
1491             #
1492             sub ParseConfig {
1493             #
1494             # @_ may contain everything which is allowed for new()
1495             #
1496 3     3 1 1215 return (new Config::General(@_))->getall();
1497             }
1498              
1499             sub SaveConfig {
1500             #
1501             # 2 parameters are required, filename and hash ref
1502             #
1503 1     1 1 9 my ($file, $hash) = @_;
1504              
1505 1 50 33     6 if (!$file || !$hash) {
1506 0         0 croak q{Config::General::SaveConfig(): filename and hash argument required.};
1507             }
1508             else {
1509 1 50       2 if (ref($hash) ne 'HASH') {
1510 0         0 croak q(Config::General::SaveConfig() The second parameter must be a reference to a hash!);
1511             }
1512             else {
1513 1         6 (new Config::General(-ConfigHash => $hash))->save_file($file);
1514             }
1515             }
1516 1         6 return;
1517             }
1518              
1519             sub SaveConfigString {
1520             #
1521             # same as SaveConfig, but return the config,
1522             # instead of saving it
1523             #
1524 0     0 1   my ($hash) = @_;
1525              
1526 0 0         if (!$hash) {
1527 0           croak q{Config::General::SaveConfigString(): Hash argument required.};
1528             }
1529             else {
1530 0 0         if (ref($hash) ne 'HASH') {
1531 0           croak q(Config::General::SaveConfigString() The parameter must be a reference to a hash!);
1532             }
1533             else {
1534 0           return (new Config::General(-ConfigHash => $hash))->save_string();
1535             }
1536             }
1537 0           return;
1538             }
1539              
1540              
1541              
1542             # keep this one
1543             1;
1544             __END__