File Coverage

blib/lib/Config/IOD.pm
Criterion Covered Total %
statement 75 77 97.4
branch 43 46 93.4
condition 5 9 55.5
subroutine 6 6 100.0
pod n/a
total 129 138 93.4


line stmt bran cond sub pod time code
1             package Config::IOD;
2              
3 15     15   4358 use 5.010001;
  15         81  
4 15     15   67 use strict;
  15         27  
  15         358  
5 15     15   73 use warnings;
  15         23  
  15         413  
6              
7 15     15   5367 use parent qw(Config::IOD::Base);
  15         4070  
  15         69  
8              
9             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
10             our $DATE = '2022-05-02'; # DATE
11             our $DIST = 'Config-IOD'; # DIST
12             our $VERSION = '0.353'; # VERSION
13              
14             sub _init_read {
15 118     118   271976 my $self = shift;
16              
17 118         290 $self->{_cur_section} = $self->{default_section};
18              
19             # for checking when allow_duplicate_key=0
20 118         222 $self->{_key_mem} = {}; # key=section name, value=hash of key->1
21              
22 118         336 $self->SUPER::_init_read;
23             }
24              
25             our $re_directive_abo =
26             qr/^(;?)(\s*)!
27             (\s*)(\w+)(\s*)(.*)
28             (\R?)\z/x;
29             our $re_directive =
30             qr/^(;)(\s*)!
31             (\s*)(\w+)(\s*)(.*)
32             (\R?)\z/x;
33              
34             sub _read_string {
35 122     122   8943 my ($self, $str) = @_;
36              
37 122         188 my $res = [];
38              
39             my $directive_re = $self->{allow_bang_only} ?
40 122 100       296 $re_directive_abo : $re_directive;
41              
42 122         508 my @lines = split /^/, $str;
43 122         355 local $self->{_linum} = 0;
44             LINE:
45 122         237 for my $line (@lines) {
46 887         1006 $self->{_linum}++;
47              
48             # blank line
49 887 100       1888 if ($line !~ /\S/) {
50 189         367 push @$res, [
51             'B',
52             $line, # RAW
53             ];
54 189         239 next LINE;
55             }
56              
57             # section line
58 698 100       1772 if ($line =~ /^(\s*)\[(\s*)(.+?)(\s*)\]
59             (?: (\s*)([;#])(.*))?
60             (\R?)\z/x) {
61 152         890 push @$res, [
62             'S',
63             $1, # COL_S_WS1
64             $2, # COL_S_WS2
65             $3, # COL_S_SECTION
66             $4, # COL_S_WS3
67             $5, # COL_S_WS4
68             $6, # COL_S_COMMENT_CHAR
69             $7, # COL_S_COMMENT
70             $8, # COL_S_NL
71             ];
72 152         334 $self->{_cur_section} = $3;
73 152         252 next LINE;
74             }
75              
76             # directive line
77 546         612 my $line0 = $line;
78 546 100 100     2818 if ($self->{enable_directive} && $line =~ s/$directive_re//) {
79 29         155 push @$res, [
80             'D',
81             $1, # COL_D_COMMENT_CHAR
82             $2, # COL_D_WS1
83             $3, # COL_D_WS2
84             $4, # COL_D_DIRECTIVE
85             $5, # COL_D_WS3
86             $6, # COL_D_ARGS_RAW
87             $7, # COL_D_NL
88             ];
89 29         69 my $directive = $4;
90 29 100       65 if ($self->{allow_directives}) {
91             $self->_err("Directive '$directive' is not in ".
92             "allow_directives list")
93 3         19 unless grep { $_ eq $directive }
94 3 100       4 @{$self->{allow_directives}};
  3         7  
95             }
96 28 100       53 if ($self->{disallow_directives}) {
97             $self->_err("Directive '$directive' is in ".
98             "disallow_directives list")
99 3         16 if grep { $_ eq $directive }
100 3 100       4 @{$self->{disallow_directives}};
  3         6  
101             }
102 26         109 my $args = $self->_parse_command_line($6);
103 26 100       1406 if (!defined($args)) {
104 1         24 $self->_err("Invalid arguments syntax '$6'");
105             }
106 25 100       80 if ($directive eq 'include') {
    100          
    100          
107 7         9 my $path;
108 7 100       15 if (! @$args) {
    50          
109 1         4 $self->_err("Missing filename to include");
110             } elsif (@$args > 1) {
111 0         0 $self->_err("Extraneous arguments");
112             } else {
113 6         11 $path = $args->[0];
114             }
115 6         14 my $res = $self->_push_include_stack($path);
116 6 100       560 if ($res->[0] != 200) {
117 1         8 $self->_err("Can't include '$path': $res->[1]");
118             }
119 5         9 $path = $res->[2];
120 5         14 $self->_read_string($self->_read_file($path));
121 4         15 $self->_pop_include_stack;
122             } elsif ($directive eq 'merge') {
123             } elsif ($directive eq 'noop') {
124             } else {
125 3 100       10 if ($self->{ignore_unknown_directive}) {
126             } else {
127 2         8 $self->_err("Unknown directive '$directive'");
128             }
129             }
130 20         76 next LINE;
131             }
132              
133             L1:
134             # comment line
135 517 100       1503 if ($line =~ /^(\s*)([;#])(.*?)
136             (\R?)\z/x) {
137 65         256 push @$res, [
138             'C',
139             $1, # COL_C_WS1
140             $2, # COL_C_COMMENT_CHAR
141             $3, # COL_C_COMMENT
142             $4, # COL_C_NL
143             ];
144 65         143 next LINE;
145             }
146              
147             # key line
148 452 100       2235 if ($line =~ /^(\s*)([^=]+?)(\s*)=
149             (\s*)(.*?)
150             (\R?)\z/x) {
151 447         1711 push @$res, [
152             'K',
153             $1, # COL_K_WS1
154             $2, # COL_K_KEY
155             $3, # COL_K_WS2
156             $4, # COL_K_WS3
157             $5, # COL_K_VALUE_RAW
158             $6, # COL_K_NL
159             ];
160              
161 447 0 33     984 if ($self->{warn_perl} && !$4 && substr($5, 0, 1) eq '>') {
      33        
162 0         0 $self->_warn("Probably using Perl syntax instead of INI: $line");
163             }
164              
165 447 100       653 if (!$self->{allow_duplicate_key}) {
166 2         4 my $kmem = $self->{_key_mem};
167 2 100       9 if ($kmem->{$self->{_cur_section}}{$2}) {
168 1         6 $self->_err(
169             "Duplicate key: $2 (section $self->{_cur_section})");
170             }
171 1         3 $kmem->{$self->{_cur_section}}{$2} = 1;
172             }
173 446         667 next LINE;
174             }
175              
176 5         17 $self->_err("Invalid syntax");
177             }
178              
179             # make sure we always end with newline
180 107 100       211 if (@$res) {
181 98 100       340 $res->[-1][-1] .= "\n"
182             unless $res->[-1][-1] =~ /\R\z/;
183             }
184              
185 107         8045 require Config::IOD::Document;
186 107         464 Config::IOD::Document->new(_parser=>$self, _parsed=>$res);
187             }
188              
189             1;
190             # ABSTRACT: Read and write IOD/INI configuration files
191              
192             __END__