File Coverage

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