| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Config::Parser::Ini; | 
| 2 | 10 |  |  | 10 |  | 339820 | use strict; | 
|  | 10 |  |  |  |  | 67 |  | 
|  | 10 |  |  |  |  | 351 |  | 
| 3 | 10 |  |  | 10 |  | 61 | use warnings; | 
|  | 10 |  |  |  |  | 15 |  | 
|  | 10 |  |  |  |  | 325 |  | 
| 4 | 10 |  |  | 10 |  | 63 | use parent 'Config::Parser'; | 
|  | 10 |  |  |  |  | 20 |  | 
|  | 10 |  |  |  |  | 67 |  | 
| 5 | 10 |  |  | 10 |  | 443 | use Carp; | 
|  | 10 |  |  |  |  | 14 |  | 
|  | 10 |  |  |  |  | 568 |  | 
| 6 | 10 |  |  | 10 |  | 56 | use Text::ParseWords; | 
|  | 10 |  |  |  |  | 18 |  | 
|  | 10 |  |  |  |  | 7369 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | sub parse { | 
| 9 | 20 |  |  | 20 | 1 | 454 | my $self = shift; | 
| 10 | 20 |  | 33 |  |  | 76 | $self->{_filename} = shift // confess "No filename given"; | 
| 11 | 20 |  |  |  |  | 118 | local %_ = @_; | 
| 12 | 20 |  |  |  |  | 168 | $self->debug(1, "parsing $self->{_filename}"); | 
| 13 | 20 |  |  |  |  | 218 | $self->_readconfig($self->{_filename}, %_); | 
| 14 | 20 |  |  |  |  | 78 | return $self; | 
| 15 |  |  |  |  |  |  | } | 
| 16 |  |  |  |  |  |  |  | 
| 17 | 0 |  |  | 0 | 1 | 0 | sub filename { shift->{_filename} } | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | # _readconfig(FILE) | 
| 20 |  |  |  |  |  |  | sub _readconfig { | 
| 21 | 20 |  |  | 20 |  | 31 | my $self = shift; | 
| 22 | 20 |  |  |  |  | 30 | my $file = shift; | 
| 23 | 20 |  |  |  |  | 43 | local %_ = @_; | 
| 24 | 20 |  |  |  |  | 38 | my $fh = delete $_{fh}; | 
| 25 | 20 |  |  |  |  | 29 | my $need_close; | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 20 |  |  |  |  | 75 | $self->debug(1, "reading file $file"); | 
| 28 | 20 | 100 |  |  |  | 133 | unless ($fh) { | 
| 29 |  |  |  |  |  |  | open($fh, "<", $file) | 
| 30 | 9 | 50 |  |  |  | 320 | or do { | 
| 31 | 0 |  |  |  |  | 0 | $self->error("can't open configuration file $file: $!"); | 
| 32 | 0 |  |  |  |  | 0 | $self->{_error_count}++; | 
| 33 | 0 |  |  |  |  | 0 | return 0; | 
| 34 |  |  |  |  |  |  | }; | 
| 35 | 9 |  |  |  |  | 31 | $need_close = 1; | 
| 36 |  |  |  |  |  |  | } | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 20 |  | 100 |  |  | 94 | my $line = delete $_{line} // 0; | 
| 39 | 20 |  |  |  |  | 39 | my @path; | 
| 40 |  |  |  |  |  |  | my $include; | 
| 41 |  |  |  |  |  |  |  | 
| 42 | 20 |  |  |  |  | 267 | while (<$fh>) { | 
| 43 | 135 |  |  |  |  | 28315 | ++$line; | 
| 44 | 135 |  |  |  |  | 188 | chomp; | 
| 45 | 135 | 50 |  |  |  | 332 | if (/\\$/) { | 
| 46 | 0 |  |  |  |  | 0 | chop; | 
| 47 | 0 |  |  |  |  | 0 | $_ .= <$fh>; | 
| 48 | 0 |  |  |  |  | 0 | redo; | 
| 49 |  |  |  |  |  |  | } | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 135 |  |  |  |  | 564 | s/^\s+//; | 
| 52 | 135 |  |  |  |  | 360 | s/\s+$//; | 
| 53 | 135 |  |  |  |  | 182 | s/#.*//; | 
| 54 | 135 | 100 |  |  |  | 310 | next if ($_ eq ""); | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 116 |  |  |  |  | 375 | my $locus = new Text::Locus($file, $line); | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 116 | 100 |  |  |  | 3553 | if (/^\[(.+?)\]$/) { | 
|  |  | 50 |  |  |  |  |  | 
| 59 | 37 |  |  |  |  | 114 | @path = parse_line('\s+', 0, $1); | 
| 60 | 37 | 50 | 66 |  |  | 2715 | if (@path == 1 && $path[0] eq 'include') { | 
| 61 | 0 |  |  |  |  | 0 | $include = 1; | 
| 62 |  |  |  |  |  |  | } else { | 
| 63 | 37 |  |  |  |  | 61 | $include = 0; | 
| 64 | 37 |  |  |  |  | 220 | $self->add_node(\@path, | 
| 65 |  |  |  |  |  |  | new Config::AST::Node::Section(locus => $locus)); | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  | } elsif (/([\w_-]+)\s*=\s*(.*)/) { | 
| 68 | 79 |  |  |  |  | 261 | my ($k, $v) = ($1, $2); | 
| 69 | 79 | 50 |  |  |  | 176 | $k = lc($k) if $self->{_ci}; #FIXME:private member | 
| 70 |  |  |  |  |  |  |  | 
| 71 | 79 | 50 |  |  |  | 123 | if ($include) { | 
| 72 | 0 | 0 |  |  |  | 0 | if ($k eq 'path') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 73 | 0 |  |  |  |  | 0 | $self->_readconfig($v); | 
| 74 |  |  |  |  |  |  | } elsif ($k eq 'pathopt') { | 
| 75 | 0 | 0 |  |  |  | 0 | $self->_readconfig($v) if -f $v; | 
| 76 |  |  |  |  |  |  | } elsif ($k eq 'glob') { | 
| 77 | 0 |  |  |  |  | 0 | foreach my $file (bsd_glob($v, 0)) { | 
| 78 | 0 |  |  |  |  | 0 | $self->_readconfig($file); | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  | } else { | 
| 81 | 0 |  |  |  |  | 0 | $self->error("keyword \"$k\" is unknown", locus => $locus); | 
| 82 | 0 |  |  |  |  | 0 | $self->{_error_count}++; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  | } else { | 
| 85 | 79 |  |  |  |  | 290 | $self->add_value([@path, $k], $v, $locus); | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  | } else { | 
| 88 | 0 |  |  |  |  | 0 | $self->error("malformed line", locus => $locus); | 
| 89 | 0 |  |  |  |  | 0 | $self->{_error_count}++; | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  | } | 
| 92 | 20 | 100 |  |  |  | 4270 | close $fh if $need_close; | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | 1; | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | =head1 NAME | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | Config::Parser::Ini - configuration file parser for ini-style files | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | $cfg = new Config::Parser::Ini($filename); | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | $val = $cfg->get('dir', 'tmp'); | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | print $val->value; | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | print $val->locus; | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | $val = $cfg->tree->Dir->Tmp; | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | An I is a textual file consisting of settings | 
| 116 |  |  |  |  |  |  | grouped into one or more sections.  A I has the form | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | KEYWORD = VALUE | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | where I is the setting name and I is its value. | 
| 121 |  |  |  |  |  |  | Syntactically, I is anything to the right of the equals sign and up | 
| 122 |  |  |  |  |  |  | to the linefeed character terminating the line (ASCII 10), not including | 
| 123 |  |  |  |  |  |  | the leading and trailing whitespace characters. | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | Each setting occupies one line.  Very long lines can be split over several | 
| 126 |  |  |  |  |  |  | physical lines by ending each line fragment except the last with a backslash | 
| 127 |  |  |  |  |  |  | character appearing right before the linefeed character. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | A I begins with a section declaration in the following form: | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | [NAME NAME...] | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | Here, square brackets form part of the syntax.  Any number of Is | 
| 134 |  |  |  |  |  |  | can be present inside the square brackets.  The first I must follow the | 
| 135 |  |  |  |  |  |  | usual rules for a valid identifier name.  Rest of Is can contain any | 
| 136 |  |  |  |  |  |  | characters, provided that any I that includes non-alphanumeric characters | 
| 137 |  |  |  |  |  |  | is enclosed in a pair of double-quotes.  Any double-quotes and backslash | 
| 138 |  |  |  |  |  |  | characters appearing within the quoted string must be escaped by prefixing | 
| 139 |  |  |  |  |  |  | them with a single backslash. | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | The B module is a framework for parsing such files. | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | In the simplest case, the usage of this module is as simple as in the following | 
| 144 |  |  |  |  |  |  | fragment: | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | use Config::Parser::Ini; | 
| 147 |  |  |  |  |  |  | my $cf = new Config::Parser::Ini(filename => "config.ini"); | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | On success, this returns a valid B object.  On error, | 
| 150 |  |  |  |  |  |  | the diagnostic message is issued using the B method (see the description | 
| 151 |  |  |  |  |  |  | of the method in B(3)) and the module croaks. | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | This usage, although simple, has one major drawback - no checking is performed | 
| 154 |  |  |  |  |  |  | on the input file, except for the syntax check.  To fix this, you can supply | 
| 155 |  |  |  |  |  |  | a dictionary (or I) of allowed keywords along with their values. | 
| 156 |  |  |  |  |  |  | Such a dictionary is itself a valid ini file, where the value of each | 
| 157 |  |  |  |  |  |  | keyword describes its properties.  The dictionary is placed in the B<__DATA__> | 
| 158 |  |  |  |  |  |  | section of the source file which invokes the B constructor. | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | Expanding the example above: | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | use Config::Parser::Ini; | 
| 163 |  |  |  |  |  |  | my $cf = new Config::Parser::Ini(filename => "config.ini"); | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | __DATA__ | 
| 166 |  |  |  |  |  |  | [core] | 
| 167 |  |  |  |  |  |  | root = STRING :default / | 
| 168 |  |  |  |  |  |  | umask = OCTAL | 
| 169 |  |  |  |  |  |  | [user] | 
| 170 |  |  |  |  |  |  | uid = NUMBER | 
| 171 |  |  |  |  |  |  | gid = NUMBER | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | This code specifies that the configuration file can contain at most two | 
| 174 |  |  |  |  |  |  | sections: C<[core]> and C<[user]>. Two keywords are defined within each | 
| 175 |  |  |  |  |  |  | section.  Data types are specified for each keyword, so the parser will | 
| 176 |  |  |  |  |  |  | bail out in case of type mismatches. If the B setting is not | 
| 177 |  |  |  |  |  |  | present in the configuration, the default one will be created with the | 
| 178 |  |  |  |  |  |  | value C>. | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | It is often advisable to create a subclass of B and | 
| 181 |  |  |  |  |  |  | use it for parsing.  For instance: | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | package App::MyConf; | 
| 184 |  |  |  |  |  |  | use Config::Parser::Ini; | 
| 185 |  |  |  |  |  |  | 1; | 
| 186 |  |  |  |  |  |  | __DATA__ | 
| 187 |  |  |  |  |  |  | [core] | 
| 188 |  |  |  |  |  |  | root = STRING :default / | 
| 189 |  |  |  |  |  |  | umask = OCTAL | 
| 190 |  |  |  |  |  |  | [user] | 
| 191 |  |  |  |  |  |  | uid = NUMBER | 
| 192 |  |  |  |  |  |  | gid = NUMBER | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | Then, to parse the configuration file, it will suffice to do: | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | $cf = my App::MyConf(filename => "config.ini"); | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | One advantage of this approach is that it will allow you to install | 
| 199 |  |  |  |  |  |  | additional validation for the configuration statements using the | 
| 200 |  |  |  |  |  |  | B<:check> option.  The argument to this option is the name of a | 
| 201 |  |  |  |  |  |  | method which will be invoked after parsing the statement in order | 
| 202 |  |  |  |  |  |  | to verify its value.  It is described in detail below (see the section | 
| 203 |  |  |  |  |  |  | B in the documentation of B). | 
| 204 |  |  |  |  |  |  | For example, if you wish to ensure that the value of the C setting | 
| 205 |  |  |  |  |  |  | in C section points to an existing directory, you would do: | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | package App::MyConf; | 
| 208 |  |  |  |  |  |  | use Config::Parser::Ini; | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | sub dir_exists { | 
| 211 |  |  |  |  |  |  | my ($self, $valref, $prev_value, $locus) = @_; | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | unless (-d $$valref) { | 
| 214 |  |  |  |  |  |  | $self->error("$$valref: directory does not exist", | 
| 215 |  |  |  |  |  |  | locus => $locus); | 
| 216 |  |  |  |  |  |  | return 0; | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  | return 1; | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | 1; | 
| 221 |  |  |  |  |  |  | __DATA__ | 
| 222 |  |  |  |  |  |  | [core] | 
| 223 |  |  |  |  |  |  | root = STRING :default / :check=dir_exists | 
| 224 |  |  |  |  |  |  | umask = OCTAL | 
| 225 |  |  |  |  |  |  | [user] | 
| 226 |  |  |  |  |  |  | uid = NUMBER | 
| 227 |  |  |  |  |  |  | gid = NUMBER | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | =head1 CONSTRUCTOR | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | $cfg = new Config::Parser::Ini(%opts) | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | Creates a new parser object.  Keyword arguments are: | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | =over 4 | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | =item B | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | Name of the file to parse.  If not supplied, you will have to | 
| 240 |  |  |  |  |  |  | call the B<$cfg-Eparse> method explicitly after you are returned a | 
| 241 |  |  |  |  |  |  | valid B<$cfg>. | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | =item B | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | Optional line where the configuration starts in B.  It is used to | 
| 246 |  |  |  |  |  |  | keep track of statement location in the file for correct diagnostics.  If | 
| 247 |  |  |  |  |  |  | not supplied, B<1> is assumed. | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | =item B | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | File handle to read from.  If it is not supplied, new handle will be | 
| 252 |  |  |  |  |  |  | created by using B on the supplied filename. | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | =item B | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | Dictionary of allowed configuration statements in the file.  You will not | 
| 257 |  |  |  |  |  |  | need this parameter.  It is listed here for completeness sake.  Refer to | 
| 258 |  |  |  |  |  |  | the B constructor for details. | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | =back | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | =head1 METHODS | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | All methods are inherited from B.  Please see its | 
| 265 |  |  |  |  |  |  | documentation for details. | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | B(3), B(3). | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | =cut |