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-21'; # DATE
4             our $VERSION = '0.351'; # VERSION
5              
6 15     15   5945 use 5.010001;
  15         98  
7 15     15   75 use strict;
  15         42  
  15         444  
8 15     15   87 use warnings;
  15         40  
  15         520  
9              
10 15     15   7537 use parent qw(Config::IOD::Base);
  15         5043  
  15         83  
11              
12             sub _init_read {
13 118     118   338548 my $self = shift;
14              
15 118         346 $self->{_cur_section} = $self->{default_section};
16              
17             # for checking when allow_duplicate_key=0
18 118         267 $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   11722 my ($self, $str) = @_;
34              
35 122         234 my $res = [];
36              
37             my $directive_re = $self->{allow_bang_only} ?
38 122 100       331 $re_directive_abo : $re_directive;
39              
40 122         605 my @lines = split /^/, $str;
41 122         380 local $self->{_linum} = 0;
42             LINE:
43 122         280 for my $line (@lines) {
44 887         1169 $self->{_linum}++;
45              
46             # blank line
47 887 100       2414 if ($line !~ /\S/) {
48 189         437 push @$res, [
49             'B',
50             $line, # RAW
51             ];
52 189         324 next LINE;
53             }
54              
55             # section line
56 698 100       2062 if ($line =~ /^(\s*)\[(\s*)(.+?)(\s*)\]
57             (?: (\s*)([;#])(.*))?
58             (\R?)\z/x) {
59 152         939 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         373 $self->{_cur_section} = $3;
71 152         295 next LINE;
72             }
73              
74             # directive line
75 546         783 my $line0 = $line;
76 546 100 100     3482 if ($self->{enable_directive} && $line =~ s/$directive_re//) {
77 29         175 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         68 my $directive = $4;
88 29 100       78 if ($self->{allow_directives}) {
89             $self->_err("Directive '$directive' is not in ".
90             "allow_directives list")
91 3         20 unless grep { $_ eq $directive }
92 3 100       3 @{$self->{allow_directives}};
  3         8  
93             }
94 28 100       71 if ($self->{disallow_directives}) {
95             $self->_err("Directive '$directive' is in ".
96             "disallow_directives list")
97 3         16 if grep { $_ eq $directive }
98 3 100       4 @{$self->{disallow_directives}};
  3         7  
99             }
100 26         99 my $args = $self->_parse_command_line($6);
101 26 100       1699 if (!defined($args)) {
102 1         16 $self->_err("Invalid arguments syntax '$6'");
103             }
104 25 100       95 if ($directive eq 'include') {
    100          
    100          
105 7         19 my $path;
106 7 100       27 if (! @$args) {
    50          
107 1         4 $self->_err("Missing filename to include");
108             } elsif (@$args > 1) {
109 0         0 $self->_err("Extraneous arguments");
110             } else {
111 6         14 $path = $args->[0];
112             }
113 6         18 my $res = $self->_push_include_stack($path);
114 6 100       1111 if ($res->[0] != 200) {
115 1         8 $self->_err("Can't include '$path': $res->[1]");
116             }
117 5         13 $path = $res->[2];
118 5         17 $self->_read_string($self->_read_file($path));
119 4         19 $self->_pop_include_stack;
120             } elsif ($directive eq 'merge') {
121             } elsif ($directive eq 'noop') {
122             } else {
123 3 100       14 if ($self->{ignore_unknown_directive}) {
124             } else {
125 2         9 $self->_err("Unknown directive '$directive'");
126             }
127             }
128 20         86 next LINE;
129             }
130              
131             L1:
132             # comment line
133 517 100       1799 if ($line =~ /^(\s*)([;#])(.*?)
134             (\R?)\z/x) {
135 65         309 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         144 next LINE;
143             }
144              
145             # key line
146 452 100       2824 if ($line =~ /^(\s*)([^=]+?)(\s*)=
147             (\s*)(.*?)
148             (\R?)\z/x) {
149 447         2318 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       1016 if (!$self->{allow_duplicate_key}) {
159 2         4 my $kmem = $self->{_key_mem};
160 2 100       14 if ($kmem->{$self->{_cur_section}}{$2}) {
161 1         8 $self->_err(
162             "Duplicate key: $2 (section $self->{_cur_section})");
163             }
164 1         5 $kmem->{$self->{_cur_section}}{$2} = 1;
165             }
166 446         840 next LINE;
167             }
168              
169 5         25 $self->_err("Invalid syntax");
170             }
171              
172             # make sure we always end with newline
173 107 100       277 if (@$res) {
174 98 100       398 $res->[-1][-1] .= "\n"
175             unless $res->[-1][-1] =~ /\R\z/;
176             }
177              
178 107         10022 require Config::IOD::Document;
179 107         578 Config::IOD::Document->new(_parser=>$self, _parsed=>$res);
180             }
181              
182             1;
183             # ABSTRACT: Read and write IOD/INI configuration files
184              
185             __END__