File Coverage

blib/lib/Config/INI/RefVars.pm
Criterion Covered Total %
statement 154 156 98.7
branch 67 72 93.0
condition 10 11 90.9
subroutine 21 21 100.0
pod 10 10 100.0
total 262 270 97.0


line stmt bran cond sub pod time code
1             package Config::INI::RefVars;
2 14     14   1623855 use 5.010;
  14         54  
3 14     14   86 use strict;
  14         26  
  14         495  
4 14     14   76 use warnings;
  14         45  
  14         799  
5 14     14   90 use Carp;
  14         34  
  14         1092  
6              
7 14     14   94 use feature ":5.10";
  14         36  
  14         2576  
8              
9 14     14   89 use Config;
  14         28  
  14         693  
10 14     14   6444 use File::Spec::Functions qw(catdir rel2abs splitpath);
  14         12215  
  14         1550  
11              
12             our $VERSION = '0.21';
13              
14 14     14   112 use constant DFLT_TOCOPY_SECTION => "__TOCOPY__";
  14         32  
  14         1615  
15              
16 14     14   103 use constant FLD_KEY_PREFIX => __PACKAGE__ . ' __ ';
  14         30  
  14         1918  
17              
18 14         86679 use constant {EXPANDED => FLD_KEY_PREFIX . 'EXPANDED',
19              
20             CMNT_VL => FLD_KEY_PREFIX . 'CMNT_VL',
21             TOCOPY_SECTION => FLD_KEY_PREFIX . 'TOCOPY_SECTION',
22             CURR_TOCP_SECTION => FLD_KEY_PREFIX . 'CURR_TOCP_SECTION',
23             TOCOPY_VARS => FLD_KEY_PREFIX . 'TOCOPY_VARS',
24             NOT_TOCOPY => FLD_KEY_PREFIX . 'NOT_TOCOPY',
25             SECTIONS => FLD_KEY_PREFIX . 'SECTIONS',
26             SECTIONS_H => FLD_KEY_PREFIX . 'SECTIONS_H',
27             SRC_NAME => FLD_KEY_PREFIX . 'SRC_NAME',
28             VARIABLES => FLD_KEY_PREFIX . 'VARIABLES',
29             GLOBAL_VARS => FLD_KEY_PREFIX . 'GLOBAL_VARS',
30             GLOBAL_MODE => FLD_KEY_PREFIX . 'GLOBAL_MODE',
31             VREF_RE => FLD_KEY_PREFIX . 'VREF_RE',
32             SEPARATOR => FLD_KEY_PREFIX . 'SEPARATOR',
33             BACKUP => FLD_KEY_PREFIX . 'BACKUP',
34             VARNAME_CHK_RE => FLD_KEY_PREFIX . 'VARNAME_CHK_RE',
35 14     14   71 };
  14         32  
36              
37             my %Globals = ('=:' => catdir("", "",),
38             '=::' => $Config{path_sep},
39             '=VERSION' => $VERSION);
40              
41              
42             # Match punctuation chars, but not the underscores.
43             my $Modifier_Char = '[^_[:^punct:]]';
44              
45             my ($_look_up, $_x_var_name, $_expand_vars);
46              
47             my $_check_tocopy_vars = sub {
48             my ($self, $tocopy_vars, $set) = @_;
49             croak("'tocopy_vars': expected HASH ref") if ref($tocopy_vars) ne 'HASH';
50             $tocopy_vars = { %$tocopy_vars };
51             while (my ($var, $value) = each(%$tocopy_vars)) {
52             croak("'tocopy_vars': value of '$var' is a ref, expected scalar") if ref($value);
53             if (!defined($value)) {
54             carp("'tocopy_vars': value '$var' is undef - treated as empty string");
55             $tocopy_vars->{$var} = "";
56             }
57             croak("'tocopy_vars': variable '$var': name is not permitted")
58             if ($var =~ /^\s*$/ || $var =~ /^[[=;]/);
59             }
60             # @{$self->{+TOCOPY_VARS}}{keys(%$tocopy_vars)} = values(%$tocopy_vars) if $set;
61             $self->{+TOCOPY_VARS} = {%$tocopy_vars} if $set;
62             return $tocopy_vars;
63             };
64              
65              
66             my $_check_not_tocopy = sub {
67             my ($self, $not_tocopy, $set) = @_;
68             my $ref = ref($not_tocopy);
69             if ($ref eq 'ARRAY') {
70             foreach my $v (@$not_tocopy) {
71             croak("'not_tocopy': undefined value in array") if !defined($v);
72             croak("'not_tocopy': unexpected ref value in array") if ref($v);
73             }
74             $not_tocopy = {map {$_ => undef} @$not_tocopy};
75             }
76             elsif ($ref eq 'HASH') {
77             $not_tocopy = %{$not_tocopy};
78             }
79             else {
80             croak("'not_tocopy': unexpected type: must be ARRAY or HASH ref");
81             }
82             $self->{+NOT_TOCOPY}= $not_tocopy if $set;
83             return $not_tocopy;
84             };
85              
86              
87             sub new {
88 104     104 1 2798165 my ($class, %args) = @_;
89 104         245 state $allowed_keys = {map {$_ => undef} qw(tocopy_section tocopy_vars not_tocopy global_mode
  84         235  
90             separator cmnt_vl varname_chk_re)};
91 104         532 _check_args(\%args, $allowed_keys);
92 103         218 my $self = {};
93 103 100       439 croak("'tocopy_section': must not be a reference") if ref($args{tocopy_section});
94 102 100       314 if (exists($args{separator})) {
95 7         18 state $allowed_sep_chars = "#!%&',./:~\\";
96 7         18 my $sep = $args{separator};
97 7 100       43 croak("'separator': unexpected ref type, must be a scalar") if ref($sep);
98 6 100       298 croak("'separator': invalid value. Allowed chars: $allowed_sep_chars")
99             if $sep !~ m{^[\Q$allowed_sep_chars\E]+$};
100 5         17 $self->{+SEPARATOR} = $sep;
101 5         128 $self->{+VREF_RE} = qr/^(.*?)(?:\Q$sep\E)(.*)$/;
102             }
103             else {
104 95         632 $self->{+VREF_RE} = qr/^\[\s*(.*?)\s*\](.*)$/;
105             }
106 100         282 $self->{+CMNT_VL} = $args{cmnt_vl};
107 100   100     613 $self->{+TOCOPY_SECTION} = $args{tocopy_section} // DFLT_TOCOPY_SECTION;
108 100 100       359 $self->$_check_tocopy_vars($args{tocopy_vars}, 1) if exists($args{tocopy_vars});
109 95 100       271 $self->$_check_not_tocopy($args{not_tocopy}, 1) if exists($args{not_tocopy});
110 92         247 $self->{+GLOBAL_MODE} = !!$args{global_mode};
111 92 100       253 if (exists($args{varname_chk_re})) {
112 1 50       6 croak("'varname_chk_re': must be a compiled regex") if ref($args{varname_chk_re}) ne 'Regexp';
113 1         3 $self->{+VARNAME_CHK_RE} = $args{varname_chk_re};
114             }
115 92         487 return bless($self, $class);
116             }
117              
118              
119             my $_expand_value = sub {
120             return $_[0]->$_expand_vars($_[1], undef, $_[2]);
121             };
122              
123             #
124             # We assume that this is called when the target section is still empty and if
125             # tocopy vars exist.
126             #
127             my $_cp_tocopy_vars = sub {
128             my ($self, $to_sect_name) = @_;
129             my $comm_sec = $self->{+VARIABLES}{$self->{+TOCOPY_SECTION}} // die("no tocopy vars");
130             my $not_tocopy = $self->{+NOT_TOCOPY};
131             my $to_sec = $self->{+VARIABLES}{$to_sect_name} //= {};
132             my $expanded = $self->{+EXPANDED};
133             foreach my $comm_var (keys(%$comm_sec)) {
134             next if exists($not_tocopy->{$comm_var});
135             $to_sec->{$comm_var} = $comm_sec->{$comm_var};
136             my $comm_x_var_name = "[$comm_sec]$comm_var"; # see _x_var_name()
137             $expanded->{"[$to_sect_name]$comm_var"} = undef if exists($expanded->{$comm_x_var_name});
138             }
139             };
140              
141              
142             my $_parse_ini = sub {
143             my ($self, $src) = @_;
144             my $src_name;
145             if (ref($src)) {
146             croak("Internal error: argument is not an ARRAY ref") if ref($src) ne 'ARRAY';
147             $src_name = $self->{+SRC_NAME};
148             }
149             else {
150             $src_name = $src;
151             $src = [do { local (*ARGV); @ARGV = ($src_name); <> }];
152             }
153             my $curr_section;
154             my $cmnt_vl = $self->{+CMNT_VL};
155             my $sections = $self->{+SECTIONS};
156             my $sections_h = $self->{+SECTIONS_H};
157             my $expanded = $self->{+EXPANDED};
158             my $variables = $self->{+VARIABLES};
159             my $tocopy_sec = $self->{+TOCOPY_SECTION};
160             my $tocopy_vars = $variables->{$tocopy_sec}; # hash key need not to exist!
161             my $global_mode = $self->{+GLOBAL_MODE};
162             my $vnm_chk_re = $self->{+VARNAME_CHK_RE};
163              
164             my $tocopy_sec_declared;
165              
166             my $i; # index in for() loop
167             my $_fatal = sub { croak("'$src_name': ", $_[0], " at line ", $i + 1); };
168              
169             my $set_curr_section = sub {
170             $curr_section = shift;
171             if ($curr_section eq $tocopy_sec) {
172             $_fatal->("tocopy section '$tocopy_sec' must be first section") if @$sections;
173             $tocopy_vars = $variables->{$tocopy_sec} = {} if !$tocopy_vars;
174             $tocopy_sec_declared = 1;
175             }
176             elsif ($tocopy_vars && !$global_mode) {
177             $self->$_cp_tocopy_vars($curr_section);
178             }
179             else {
180             $variables->{$curr_section} = {};
181             }
182             $_fatal->("'$curr_section': duplicate header") if exists($sections_h->{$curr_section});
183             $sections_h->{$curr_section} = @$sections; # Index!
184             push(@$sections, $curr_section);
185             };
186              
187             for ($i = 0; $i < @$src; ++$i) {
188             my $line = $src->[$i];
189             if (index($line, ";!") == 0 || index($line, "=") == 0) {
190             $_fatal->("directives are not yet supported");
191             }
192             $line =~ s/^\s+//;
193             next if $line eq "" || $line =~ /^[;#]/;
194             $line =~ s/\s+$//;
195             # section header
196             if (index($line, "[") == 0) {
197             $line =~ s/\s*[#;][^\]]*$//;
198             $line =~ /^\[\s*(.*?)\s*\]$/ or $_fatal->("invalid section header");
199             $set_curr_section->($1);
200             next;
201             }
202              
203             # var = val
204             $line =~ s/\s+;.*$// if $cmnt_vl;
205             $set_curr_section->($tocopy_sec) if !defined($curr_section);
206             $line =~ /^(.*?)\s*($Modifier_Char*?)=(?:\s*)(.*)/ or
207             $_fatal->("neither section header nor key definition");
208             my ($var_name, $modifier, $value) = ($1, $2, $3);
209             if ($vnm_chk_re) {
210             croak("'$var_name': var name does not match varname_chk_re") if $var_name !~ $vnm_chk_re;
211             }
212             my $x_var_name = $self->$_x_var_name($curr_section, $var_name);
213             my $exp_flag = exists($expanded->{$x_var_name});
214             $_fatal->("empty variable name") if $var_name eq "";
215             my $sect_vars = $variables->{$curr_section} //= {};
216             if ($modifier eq "") {
217             delete $expanded->{$x_var_name} if $exp_flag;
218             $sect_vars->{$var_name} = $value;
219             }
220             elsif ($modifier eq '?') {
221             $sect_vars->{$var_name} = $value if !exists($sect_vars->{$var_name});
222             }
223             elsif ($modifier eq '??') {
224             $sect_vars->{$var_name} = $value if (!exists($sect_vars->{$var_name})
225             || $sect_vars->{$var_name} eq "");
226             }
227             elsif ($modifier eq '+') {
228             if (exists($sect_vars->{$var_name})) {
229             $sect_vars->{$var_name} .= " "
230             . ($exp_flag ? $self->$_expand_value($curr_section, $value) : $value);
231             }
232             else {
233             $sect_vars->{$var_name} = $value;
234             }
235             }
236             elsif ($modifier eq '.') {
237             $sect_vars->{$var_name} = ($sect_vars->{$var_name} // "")
238             . ($exp_flag ? $self->$_expand_value($curr_section, $value) : $value);
239             }
240             elsif ($modifier eq ':') {
241             delete $expanded->{$x_var_name} if $exp_flag; # Needed to make _expand_vars corectly!
242             $sect_vars->{$var_name} = $self->$_expand_vars($curr_section, $var_name, $value, undef, 1);
243             }
244             elsif ($modifier eq '+>') {
245             if (exists($sect_vars->{$var_name})) {
246             $sect_vars->{$var_name} =
247             ($exp_flag ? $self->$_expand_value($curr_section, $value) : $value)
248             . ' ' . $sect_vars->{$var_name};
249             }
250             else {
251             $sect_vars->{$var_name} = $value;
252             }
253             }
254             elsif ($modifier eq '.>') {
255             $sect_vars->{$var_name} =
256             ($exp_flag ? $self->$_expand_value($curr_section, $value) : $value)
257             . ($sect_vars->{$var_name} // "");
258             }
259             else {
260             $_fatal->("'$modifier': unsupported modifier");
261             }
262             }
263             return ($tocopy_sec_declared, $curr_section);
264             };
265              
266              
267             sub parse_ini {
268 154     154 1 242577 my $self = shift;
269 154         720 my %args = (cleanup => 1,
270             @_ );
271 154         331 state $allowed_keys = {map {$_ => undef} qw(cleanup src src_name
  72         190  
272             tocopy_section tocopy_vars not_tocopy)};
273 154         269 state $dflt_src_name = "INI data";
274 154         534 _check_args(\%args, $allowed_keys);
275 153         354 foreach my $scalar_arg (qw(tocopy_section src_name)) {
276 305 100       861 croak("'$scalar_arg': must not be a reference") if ref($args{$scalar_arg});
277             }
278 151 100       574 delete $self->{+SRC_NAME} if exists($self->{+SRC_NAME});
279 151 100       439 $self->{+SRC_NAME} = $args{src_name} if exists($args{src_name});
280             my ( $cleanup, $src, $tocopy_section, $tocopy_vars, $not_tocopy) =
281 151         624 @args{qw(cleanup src tocopy_section tocopy_vars not_tocopy)};
282              
283 151 100       457 croak("'src': missing mandatory argument") if !defined($src);
284 150   100     653 my $backup = $self->{+BACKUP} //= {};
285 150 100       456 if (defined($tocopy_section)) {
286 8         23 $backup->{tocopy_section} = $self->{+TOCOPY_SECTION};
287 8         35 $self->{+TOCOPY_SECTION} = $tocopy_section;
288             }
289             else {
290 142         305 $tocopy_section = $self->{+TOCOPY_SECTION};
291             }
292 150         414 $self->{+CURR_TOCP_SECTION} = $tocopy_section;
293 150         344 $Globals{'=TO_CP_SEC'} = $tocopy_section;
294 150 100       367 if ($tocopy_vars) {
295 16         60 $backup->{tocopy_vars} = $self->{+TOCOPY_VARS};
296 16         132 $self->$_check_tocopy_vars($tocopy_vars, 1);
297             }
298 145 100       345 if ($not_tocopy) {
299 10         27 $backup->{not_tocopy} = $self->{+NOT_TOCOPY};
300 10         42 $self->$_check_not_tocopy($not_tocopy, 1)
301             }
302 142         463 $self->{+SECTIONS} = [];
303 142         389 $self->{+SECTIONS_H} = {};
304 142         462 $self->{+EXPANDED} = {};
305             $self->{+VARIABLES} =
306 142 100       781 {$tocopy_section => ($self->{+TOCOPY_VARS} ? {%{$self->{+TOCOPY_VARS}}} : {})};
  24         166  
307              
308 142         1500 my $global_vars = $self->{+GLOBAL_VARS} = {%Globals};
309 142         320 my $variables = $self->{+VARIABLES};
310 142         336 my $tocopy_sec_vars = $variables->{$tocopy_section};
311 142 100       420 if (my $ref_src = ref($src)) {
312 88 100       373 $self->{+SRC_NAME} = $dflt_src_name if !exists($self->{+SRC_NAME});
313 88 100       231 if ($ref_src eq 'ARRAY') {
314 87         257 $src = [@$src];
315 87         200 foreach my $entry (@$src) {
316 525 100       945 croak("'src': unexpected ref type in array") if ref($entry);
317 524 50       978 if (!defined($entry)) {
318 0         0 carp("'src': undef entry - treated as empty string");
319 0         0 $entry = "";
320             }
321             }
322             }
323             else {
324 1         15 croak("'src': $ref_src: ref type not allowed");
325             }
326             }
327             else {
328 54 100       165 if (index($src, "\n") < 0) {
329 10         25 my $path = $src;
330 10         21 $src = [do { local (*ARGV); @ARGV = ($path); <> }];
  10         127  
  10         40  
  10         1334  
331 10 50       96 $self->{+SRC_NAME} = $path if !exists($self->{+SRC_NAME});
332 10         61 my ($vol, $dirs, $file) = splitpath(rel2abs($path));
333 10 50 50     766 @{$global_vars}{'=INIfile', '=INIdir'} = ($file, catdir(length($vol // "") ? $vol : (),
  10         57  
334             $dirs));
335             }
336             else {
337 44         293 $src = [split(/\n/, $src)];
338 44 50       185 $self->{+SRC_NAME} = $dflt_src_name if !exists($self->{+SRC_NAME});
339             }
340             }
341 140         361 $global_vars->{'=srcname'} = $self->{+SRC_NAME};
342              
343 140         424 my ($tocopy_sec_declared, undef) = $self->$_parse_ini($src);
344              
345             my @sections = (exists($self->{+SECTIONS_H}{$tocopy_section}) ? () : $tocopy_section,
346 127 100       434 @{$self->{+SECTIONS}}
  127         412  
347             );
348 127         301 foreach my $section (@sections) {
349 334         557 my $sec_vars = $variables->{$section};
350 334         1116 while (my ($variable, $value) = each(%$sec_vars)) {
351 740         1536 $sec_vars->{$variable} = $self->$_expand_vars($section, $variable, $value);
352             }
353             }
354 122 100       315 if ($cleanup) {
355 117         185 while (my ($section, $sec_vars) = each(%{$variables})) {
  425         1152  
356 308         711 foreach my $var (keys(%$sec_vars)) {
357 653 100       1387 delete $sec_vars->{$var} if index($var, '=') >= 0;
358             }
359             }
360 117 100 100     624 delete $variables->{$self->{+TOCOPY_SECTION}} if (!$tocopy_sec_declared && !%$tocopy_sec_vars);
361             }
362             else {
363 5 100       20 if ($self->{+GLOBAL_MODE}) {
364 2         2 while (my ($section, $sec_vars) = each(%{$variables})) {
  8         16  
365 6         10 $sec_vars->{'='} = $section;
366             }
367 2         7 @{$tocopy_sec_vars}{keys(%$global_vars)} = values(%$global_vars);
  2         7  
368             }
369             else {
370 3         8 while (my ($section, $sec_vars) = each(%{$variables})) {
  12         45  
371 9         24 $sec_vars->{'='} = $section;
372 9         31 @{$sec_vars}{keys(%$global_vars)} = values(%$global_vars);
  9         62  
373             }
374             }
375             }
376 122 100       331 $self->{+TOCOPY_SECTION} = $backup->{tocopy_section} if exists($backup->{tocopy_section});
377 122 100       365 $self->{+TOCOPY_VARS} = $backup->{tocopy_vars} if exists($backup->{tocopy_vars});
378 122 100       276 $self->{+NOT_TOCOPY} = $backup->{not_tocopy} if exists($backup->{not_tocopy});
379 122         741 $backup = {};
380 122         815 return $self;
381             }
382              
383              
384 11     11 1 72 sub current_tocopy_section {$_[0]->{+CURR_TOCP_SECTION}}
385 22     22 1 147 sub tocopy_section {$_[0]->{+TOCOPY_SECTION}}
386 20     20 1 108 sub global_mode {$_[0]->{+GLOBAL_MODE}}
387 23 100   23 1 1859 sub sections { defined($_[0]->{+SECTIONS}) ? [@{$_[0]->{+SECTIONS}}] : undef}
  22         157  
388 22 100   22 1 8154 sub sections_h { defined($_[0]->{+SECTIONS_H}) ? +{ %{$_[0]->{+SECTIONS_H}} } : undef }
  21         154  
389 13     13 1 70 sub separator {$_[0]->{+SEPARATOR}}
390 7     7 1 642 sub src_name {$_[0]->{+SRC_NAME}}
391 120   100 120 1 10445 sub variables { my $vars = $_[0]->{+VARIABLES} // return undef;
392 119         378 return {map {$_ => {%{$vars->{$_}}}} keys(%$vars)};
  248         366  
  248         2181  
393             }
394              
395              
396             $_look_up = sub {
397             my ($self, $curr_sect, $variable) = @_;
398             my $matched = $variable =~ $self->{+VREF_RE};
399             my ($v_section, $v_basename) = $matched ? ($1, $2) : ($curr_sect, $variable);
400             my $v_value;
401             my $variables = $self->{+VARIABLES};
402             my $tocopy_section = $self->{+TOCOPY_SECTION};
403             if (!exists($variables->{$v_section})) {
404             $v_value = "";
405             }
406             elsif (exists($variables->{$v_section}{$v_basename})) {
407             $v_value = $variables->{$v_section}{$v_basename};
408             }
409             elsif ($v_basename !~ /\S/) {
410             $v_value = $v_basename;
411             }
412             elsif ($v_basename eq '=') {
413             $v_value = $v_section;
414             }
415             elsif ($v_basename =~ /^=(?:ENV|env):\s*(.*)$/) {
416             $v_value = $ENV{$1} // "";
417             }
418             elsif ($v_basename =~ /^=CONFIG:\s*(.*)$/) {
419             $v_value = $Config{$1} // "";
420             }
421             elsif (exists($self->{+GLOBAL_VARS}{$v_basename})) {
422             $v_value = $self->{+GLOBAL_VARS}{$v_basename};
423             }
424             elsif ($self->{+GLOBAL_MODE} && exists($variables->{$tocopy_section}{$v_basename})) {
425             if (!$matched && $curr_sect ne $tocopy_section && exists($self->{+NOT_TOCOPY}{$v_basename})) {
426             $v_value = "";
427             }
428             else {
429             $v_value = $variables->{$tocopy_section}{$v_basename};
430             }
431             }
432             else {
433             $v_value = "";
434             }
435             die("Internal error") if !defined($v_value);
436             return wantarray ? ($v_section, $v_basename, $v_value) : $v_value;
437             };
438              
439             # extended var name
440             $_x_var_name = sub {
441             my ($self, $curr_sect, $variable) = @_;
442              
443             if ($variable =~ $self->{+VREF_RE}) {
444             return ($2, "[$1]$2");
445             }
446             else {
447             return ($variable, "[$curr_sect]$variable");
448             }
449             };
450              
451              
452             $_expand_vars = sub {
453             my ($self, $curr_sect, $variable, $value, $seen, $not_seen) = @_;
454             my $top = !$seen;
455             my @result = ("");
456             my $level = 0;
457             my $x_variable_name;
458             if (defined($variable)) {
459             ((my $var_basename), $x_variable_name) = $self->$_x_var_name($curr_sect, $variable);
460             return $self->$_look_up($curr_sect, $variable) if (exists($self->{+EXPANDED}{$x_variable_name})
461             || $var_basename =~ /^=(?:ENV|CONFIG):/);
462             croak("recursive variable '", $x_variable_name, "' references itself")
463             if exists($seen->{$x_variable_name});
464             $seen->{$x_variable_name} = undef if !$not_seen;
465             }
466             foreach my $token (split(/(\$\(|\))/, $value)) {
467             if ($token eq '$(') {
468             ++$level;
469             }
470             elsif ($token eq ')' && $level) {
471             # Now $result[$level] contains the name of a referenced variable.
472             if ($result[$level] eq '==') {
473             $result[$level - 1] .= $variable;
474             }
475             else {
476             $result[$level - 1] .=
477             $self->$_expand_vars($self->$_look_up($curr_sect, $result[$level]), $seen);
478             }
479             pop(@result);
480             --$level;
481             }
482             else {
483             $result[$level] .= $token;
484             }
485             }
486             croak("'$x_variable_name': unterminated variable reference") if $level;
487             $value = $result[0];
488             if ($x_variable_name) {
489             $self->{+EXPANDED}{$x_variable_name} = undef if $top;
490             delete $seen->{$x_variable_name};
491             }
492             return $value;
493             };
494              
495              
496             #
497             # This is a function, not a method!
498             #
499             sub _check_args {
500 258     258   685 my ($args, $allowed_args) = @_;
501 258         856 foreach my $key (keys(%$args)) {
502 400 100       1286 croak("'$key': unsupported argument") if !exists($allowed_args->{$key});
503             }
504 256         709 delete @{$args}{ grep { !defined($args->{$_}) } keys(%$args) };
  256         638  
  396         1002  
505             }
506              
507              
508             1; # End of Config::INI::RefVars
509              
510              
511              
512             __END__