File Coverage

blib/lib/Config/IOD.pm
Criterion Covered Total %
statement 74 75 98.6
branch 43 44 97.7
condition 3 3 100.0
subroutine 6 6 100.0
pod n/a
total 126 128 98.4


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