File Coverage

blib/lib/Config/General/Interpolated.pm
Criterion Covered Total %
statement 53 79 67.0
branch 16 34 47.0
condition n/a
subroutine 8 11 72.7
pod 1 1 100.0
total 78 125 62.4


line stmt bran cond sub pod time code
1             #
2             # Config::General::Interpolated - special Class based on Config::General
3             #
4             # Copyright (c) 2001 by Wei-Hon Chen .
5             # Copyright (c) 2000-2022 by Thomas Linden .
6             # All Rights Reserved. Std. disclaimer applies.
7             # Licensed under the terms of the Artistic License 2.0.
8             #
9              
10             package Config::General::Interpolated;
11             $Config::General::Interpolated::VERSION = "2.16";
12              
13 1     1   5 use strict;
  1         1  
  1         41  
14 1     1   4 use Carp;
  1         2  
  1         65  
15 1     1   4 use Config::General;
  1         1  
  1         1229  
16              
17              
18             # Import stuff from Config::General
19             our @ISA = qw(Config::General);
20              
21              
22             sub new {
23             #
24             # overwrite new() with our own version
25             # and call the parent class new()
26             #
27              
28 0     0 1 0 croak "Deprecated method Config::General::Interpolated::new() called.\n"
29             ."Use Config::General::new() instead and set the -InterPolateVars flag.\n";
30             }
31              
32              
33              
34             sub _set_regex {
35             #
36             # set the regex for finding vars
37             #
38              
39             # the following regex is provided by Autrijus Tang
40             # , and I made some modifications.
41             # thanx, autrijus. :)
42 11     11   46 my $regex = qr{
43             (^|\G|[^\\]) # $1: can be the beginning of the line
44             # or the beginning of next match
45             # but can't begin with a '\'
46             \$ # dollar sign
47             (\{)? # $2: optional opening curly
48             ([a-zA-Z0-9][a-zA-Z0-9_\-\.:\+]*) # $3: capturing variable name (fix of #33447+118746)
49             (?(2) # $4: if there's the opening curly...
50             \} # ... match closing curly
51             )
52             }x;
53 11         39 return $regex;
54             }
55              
56              
57             sub _interpolate {
58             #
59             # interpolate a scalar value and keep the result
60             # on the varstack.
61             #
62             # called directly by Config::General::_parse_value()
63             #
64 115     115   264 my ($this, $config, $key, $value) = @_;
65 115         167 my $quote_counter = 100;
66              
67             # some dirty trick to circumvent single quoted vars to be interpolated
68             # we remove all quotes and replace them with unique random literals,
69             # which will be replaced after interpolation with the original quotes
70             # fixes bug rt#35766
71 115         173 my %quotes;
72              
73 115 100       214 if(! $this->{AllowSingleQuoteInterpolation} ) {
74 113         225 $value =~ s/(\'[^\']+?\')/
75 2005         3871 my $key = "QUOTE" . ($quote_counter++) . "QUOTE";
76 2005         5881 $quotes{ $key } = $1;
77 2005         10563 $key;
78             /gex;
79             }
80              
81 115         737 $value =~ s{$this->{regex}}{
82 28         81 my $con = $1;
83 28         46 my $var = $3;
84 28 50       56 my $var_lc = $this->{LowerCaseNames} ? lc($var) : $var;
85              
86 28 50       53 if (exists $config->{__stack}->{$var_lc}) {
    0          
    0          
87 28         115 $con . $config->{__stack}->{$var_lc};
88             }
89             elsif ($this->{InterPolateEnv}) {
90             # may lead to vulnerabilities, by default flag turned off
91 0 0       0 if (defined($ENV{$var})) {
92 0         0 $con . $ENV{$var};
93             }
94             else {
95 0         0 $con;
96             }
97             }
98             elsif ($this->{StrictVars}) {
99 0         0 croak "Use of uninitialized variable (\$$var) while loading config entry: $key = $value\n";
100             }
101             else {
102             # be cool
103 0         0 $con;
104             }
105             }egx;
106              
107             # re-insert unaltered quotes
108             # fixes bug rt#35766
109 115         611 foreach my $quote (keys %quotes) {
110 2005         77670 $value =~ s/$quote/$quotes{$quote}/;
111             }
112              
113 115         1194 return $value;
114             };
115              
116              
117             sub _interpolate_hash {
118             #
119             # interpolate a complete hash and keep the results
120             # on the varstack.
121             #
122             # called directly by Config::General::new()
123             #
124 11     11   23 my ($this, $config) = @_;
125              
126             # bugfix rt.cpan.org#46184, moved code from _interpolate() to here.
127 11 100       28 if ($this->{InterPolateEnv}) {
128             # may lead to vulnerabilities, by default flag turned off
129 1         7 for my $key (keys %ENV){
130 27         44 $config->{__stack}->{$key}=$ENV{$key};
131             }
132             }
133              
134 11         32 $config = $this->_var_hash_stacker($config);
135              
136 11         29 return $config;
137             }
138              
139             sub _var_hash_stacker {
140             #
141             # build a varstack of a given hash ref
142             #
143 12     12   22 my ($this, $config) = @_;
144              
145 12         17 foreach my $key (keys %{$config}) {
  12         52  
146 8 100       15 next if($key eq "__stack");
147 6 50       23 if (ref($config->{$key}) eq "ARRAY" ) {
    100          
148 0         0 $config->{$key} = $this->_var_array_stacker($config->{$key}, $key);
149             }
150             elsif (ref($config->{$key}) eq "HASH") {
151 1         1 my $tmphash = $config->{$key};
152 1         2 $tmphash->{__stack} = $config->{__stack};
153 1         4 $config->{$key} = $this->_var_hash_stacker($tmphash);
154             }
155             else {
156             # SCALAR
157 5         12 $config->{__stack}->{$key} = $config->{$key};
158             }
159             }
160              
161 12         25 return $config;
162             }
163              
164              
165             sub _var_array_stacker {
166             #
167             # same as _var_hash_stacker but for arrayrefs
168             #
169 0     0   0 my ($this, $config, $key) = @_;
170              
171 0         0 my @new;
172              
173 0         0 foreach my $entry (@{$config}) {
  0         0  
174 0 0       0 if (ref($entry) eq "HASH") {
    0          
175 0         0 $entry = $this->_var_hash_stacker($entry);
176             }
177             elsif (ref($entry) eq "ARRAY") {
178             # ignore this. Arrays of Arrays cannot be created/supported
179             # with Config::General, because they are not accessible by
180             # any key (anonymous array-ref)
181 0         0 next;
182             }
183             else {
184             #### $config->{__stack}->{$key} = $config->{$key};
185             # removed. a array of scalars (eg: option = [1,2,3]) cannot
186             # be used for interpolation (which one shall we use?!), so
187             # we ignore those types of lists.
188             # found by fbicknel, fixes rt.cpan.org#41570
189             }
190 0         0 push @new, $entry;
191             }
192              
193 0         0 return \@new;
194             }
195              
196             sub _clean_stack {
197             #
198             # recursively empty the variable stack
199             #
200 50     50   76 my ($this, $config) = @_;
201             #return $config; # DEBUG
202 50         56 foreach my $key (keys %{$config}) {
  50         102  
203 166 100       266 if ($key eq "__stack") {
204 48         130 delete $config->{__stack};
205 48         64 next;
206             }
207 118 50       264 if (ref($config->{$key}) eq "ARRAY" ) {
    100          
208 0         0 $config->{$key} = $this->_clean_array_stack($config->{$key});
209             }
210             elsif (ref($config->{$key}) eq "HASH") {
211 39         83 $config->{$key} = $this->_clean_stack($config->{$key});
212             }
213             }
214 50         110 return $config;
215             }
216              
217              
218             sub _clean_array_stack {
219             #
220             # same as _var_hash_stacker but for arrayrefs
221             #
222 0     0     my ($this, $config) = @_;
223              
224 0           my @new;
225              
226 0           foreach my $entry (@{$config}) {
  0            
227 0 0         if (ref($entry) eq "HASH") {
    0          
228 0           $entry = $this->_clean_stack($entry);
229             }
230             elsif (ref($entry) eq "ARRAY") {
231             # ignore this. Arrays of Arrays cannot be created/supported
232             # with Config::General, because they are not accessible by
233             # any key (anonymous array-ref)
234 0           next;
235             }
236 0           push @new, $entry;
237             }
238              
239 0           return \@new;
240             }
241              
242             1;
243              
244             __END__