File Coverage

blib/lib/Tie/Cfg.pm
Criterion Covered Total %
statement 130 150 86.6
branch 36 40 90.0
condition 2 3 66.6
subroutine 10 14 71.4
pod 0 1 0.0
total 178 208 85.5


line stmt bran cond sub pod time code
1             package Tie::Cfg;
2              
3 3     3   43722 use strict;
  3         6  
  3         291  
4 3     3   2403 use LockFile::Simple;
  3         21243  
  3         132  
5 3     3   18 use vars qw($VERSION %cnf);
  3         57  
  3         5055  
6              
7             $VERSION="0.32";
8              
9             sub TIEHASH {
10 36     36   4248551 my $class = shift;
11 36         1062 my $args = { READ => undef,
12             WRITE => undef,
13             MODE => 0640,
14             LOCK => undef,
15             SEP => "=",
16             REGSEP => undef,
17             COMMENT => ";",
18             REGCOMMENT => undef,
19             CHANGE => undef,
20             @_
21             };
22 36         96 my $file = $args->{READ};
23 36         83 my $outfile = $args->{WRITE};
24 36         69 my $lock = $args->{LOCK};
25 36         99 my $mode = $args->{MODE};
26 36         79 my $sep = $args->{SEP};
27 36         52 my $splitsep= $args->{REGSEP};
28 36         52 my $comment = $args->{COMMENT};
29 36         46 my $regcmnt = $args->{REGCOMMENT};
30            
31 36 100       118 if (not $splitsep) { $splitsep=$sep; }
  30         42  
32 36 100       92 if (not $regcmnt) { $regcmnt=$comment; }
  30         42  
33              
34 36         67 my %cnf = ();
35 36         61 my $fh;
36             my $val;
37 0         0 my $key;
38 36         68 my $prekey="";
39            
40 36 100       114 $outfile="" if (not $outfile);
41              
42 36         527 my $node = {
43             CNF => {},
44             FILE => $outfile,
45             MODE => $mode,
46             LOCK => undef,
47             SEP => $sep,
48             SSEP => $splitsep,
49             CMNT => $comment,
50             SCMNT => $regcmnt,
51             };
52              
53 36 100 66     241 if ($lock and $outfile) {
54 10         443 $node->{LOCK}=LockFile::Simple->make(-max => 30, -delay => 1, -nfs => 1);
55 10         1556 $node->{LOCK}->lock($outfile);
56             }
57              
58 36 100       12012833 if (-e $file) {
59              
60 27         84 my $section="";
61            
62 27         1180 open $fh, $file;
63            
64 27         493 while (<$fh>) {
65 683 100       2374 next if /^\s*$/;
66 661 100       3033 next if /^\s*$regcmnt/;
67            
68 639 100       1594 if (/^\s*\[.*\]\s*$/) {
69 126         150 $section=$_;
70 126         386 $section=~s/^\s*\[//;
71 126         384 $section=~s/\]\s*$//;
72 126         197 $section=~s/^\s+//;
73 126         167 $section=~s/\s+$//;
74            
75 126         142 $prekey="";
76 126         1295 for (split /\./,$section) {
77 246         414 $prekey.="{$_}";
78             }
79            
80 126         410 next;
81             }
82            
83 513         1780 ($key,$val) = split /$splitsep/,$_,2;
84 513         1107 $key=~s/^\s+//;$key=~s/\s+$//;
  513         717  
85 513         697 $val=~s/^\s+//;$val=~s/\s+$//;
  513         1576  
86              
87 513         609 for my $chg (@{$args->{CHANGE}}) {
  513         1301  
88 2         10 $val=__change($chg,$val);
89             }
90            
91 513 100       1246 if ($key=~/([\[][0-9]+[\]])$/) {
92 132         128 my $index;
93 132         143 $index=$key;
94            
95 132         411 $key=~s/([\[][0-9]+[\]])$//;
96            
97 132         249 $index=substr($index,length($key));
98 132         252 $index=~s/[\[]//;
99 132         482 $index=~s/[\]]//;
100            
101 132         5247 eval('$cnf'."$prekey"."{$key}[$index]=".'"'."$val".'"');
102             }
103             else {
104 381         20205 eval('$cnf'."$prekey"."{$key}=".'"'."$val".'"');
105             }
106             }
107 27         328 close $fh;
108            
109 27         85 $node->{CNF}=\%cnf;
110             }
111              
112 36         115 my $this=bless $node, $class;
113              
114              
115 36         312 return $this;
116             }
117              
118             sub getHash {
119 0     0 0 0 my $s=shift;
120 0         0 my $r;
121 0         0 ($s,$r)=split /\./,$s,2;
122 0         0 my %c;
123            
124 0         0 return $c{s}
125             }
126              
127             sub __change {
128 2     2   5 my $change=shift;
129 2         4 my $value=shift;
130 2         11 my $from;
131             my $to;
132 0         0 my $g;
133              
134 2 50       8 if (not $to) {
135 2 50       14 if ($change=~/g$/) {
136 0         0 $g="g";
137             }
138 2         14 $change=~s/^s//;
139 2         8 $change=~s/^\///;
140 2         3 $change=~s/g$//;
141 2         42 $change=~s/\/$//;
142 2         9 ($from,$to)=split /\//,$change,2;
143             }
144              
145 2 50       6 if (not defined $g) { $g=""; }
  2         7  
146              
147 2 50       6 if ($g eq "g") {
148 0         0 $value=~s/$from/$to/g;
149             }
150             else {
151 2         22 $value=~s/$from/$to/;
152             }
153              
154              
155 2         10 $value;
156             }
157              
158              
159             sub FETCH {
160 551     551   6790 my $self = shift;
161 551         600 my $key = shift;
162 551         20225 return $self->{CNF}->{$key};
163             }
164              
165             sub STORE {
166 88     88   2833 my $self = shift;
167 88         109 my $key = shift;
168 88         137 my $val = shift;
169 88         7146 $self->{CNF}->{$key}=$val;
170 88         234 return $val;
171             }
172              
173             sub DELETE {
174 0     0   0 my $self = shift;
175 0         0 my $key = shift;
176 0         0 delete $self->{CNF}->{$key};
177             }
178              
179             sub EXISTS {
180 55     55   4961 my $self = shift;
181 55         79 my $key = shift;
182 55         204 return exists $self->{CNF}->{$key};
183             }
184              
185             sub FIRSTKEY {
186 0     0   0 my $self = shift;
187 0         0 my $temp = keys %{$self->{CNF}};
  0         0  
188 0         0 return scalar each %{$self->{CNF}};
  0         0  
189             }
190              
191             sub NEXTKEY {
192 0     0   0 my $self = shift;
193 0         0 return scalar each %{$self->{CNF}};
  0         0  
194             }
195              
196             sub DESTROY {
197 36     36   15004330 my $self = shift;
198 36         60 my $fh;
199            
200 36 100       185 if ($self->{FILE}) {
201 31         276699 open $fh,">",$self->{FILE};
202            
203 31         349 print $fh $self->{CMNT}," Tie::Cfg version $VERSION (c) H. Oesterholt-Dijkema, license perl\n";
204 31         58 print $fh "\n";
205            
206 31         185 __write_self($self->{CNF},$fh,0,$self->{SEP},$self->{CMNT},"");
207            
208 31         1980 close $fh;
209 31         957 chmod $self->{MODE},$self->{FILE};
210              
211 31 100       370 if ($self->{LOCK}) {
212 10         68 $self->{LOCK}->unlock($self->{FILE});
213             }
214             }
215             }
216              
217              
218             sub __write_self {
219 208     208   271 my $cfg = shift;
220 208         217 my $fh = shift;
221 208         206 my $depth = shift;
222 208         292 my $sep = shift;
223 208         216 my $cmnt = shift;
224 208         248 my $section = shift;
225            
226 208         203 my $key;
227             my $value;
228            
229             # Pass 1, Keys that are no sections
230            
231 208 100       416 if ($section) {
232 177         336 print $fh "[$section]\n";
233             }
234            
235 208         246 while (($key,$value) = each %{$cfg}) {
  807         2523  
236 599 100       1379 if (ref($value) ne "HASH") {
237 422 100       636 if (ref($value) eq "ARRAY") {
238 15         25 my $idx=0;
239 15         18 for my $element (@{$value}) {
  15         36  
240 165         339 print $fh "$key","[$idx]","$sep","$element\n";
241 165         221 $idx+=1;
242             }
243             }
244             else {
245 407         1145 print $fh "$key","$sep","$value\n";
246             }
247             }
248             }
249            
250             # Pass 2, keys that are sections
251            
252 208         263 while (($key,$value) = each %{$cfg}) {
  807         2381  
253 599 100       1558 if (ref($value) eq "HASH") {
254             # OK, It's a section
255            
256 177 100       308 if ($depth==0) {
257 69         183 __write_self($value,$fh,$depth+1,$sep,$cmnt,$key);
258             }
259             else {
260 108         347 __write_self($value,$fh,$depth+1,$sep,$cmnt,$section.".".$key);
261             }
262            
263             }
264             }
265            
266             }
267              
268             =pod
269              
270             =head1 NAME
271              
272             Tie::Cfg - Ties simple configuration (.ini) files to hashes.
273             Handles arrays and recurrent sections.
274              
275             =head1 WARNING
276              
277             This version breaks previous versions as the default mode is '.ini' mode.
278              
279             =head1 SYNOPSIS
280              
281             use Tie::Cfg;
282            
283             ### Sample 1
284              
285             tie my %conf, 'Tie::Cfg',
286             READ => "/etc/connect.cfg",
287             WRITE => "/etc/connect.cfg",
288             MODE => 0600,
289             LOCK => 1;
290              
291             $conf{test}="this is a test";
292              
293             untie %conf;
294            
295             ### Sample 2
296              
297             my $limit="10000k";
298              
299             tie my %files, 'Tie::Cfg',
300             READ => "find $dirs -xdev -type f -size +$limit -printf \"%h/%f:%k\\n\" |", SEP => ':';
301              
302             if (exists $files{"/etc/passwd"}) {
303             print "You've got a /etc/passwd file!\n";
304             }
305              
306             while (($file,$size) = each %newdb) {
307             print "Wow! Another file bigger than $limit ($size)\n";
308             }
309            
310             untie %files;
311            
312             ### Sample 3
313            
314             tie my %cfg, 'Tie::Cfg', READ => "config.cfg", WRITE => "config.cfg", SEP => ':', COMMENT => '#';
315            
316             my $counter=$cfg{"counter"};
317             $counter+=1;
318             $cfg{"counter"}=$counter;
319             $cfg{"counter"}+=1;
320            
321             untie %cfg;
322            
323             ### Reading and writing an INI file
324            
325             tie my %ini, 'Tie::Cfg', READ => "config.ini", WRITE => "config.ini";
326            
327             my $counter=$ini{"section1"|{"counter1"};
328             $counter+=1;
329             $ini{"section1"}{"counter1"}=$counter;
330              
331             untie %ini;
332              
333             ### INI file with subsections
334            
335             tie my %ini, 'Tie::Cfg', READ => "config.ini";
336            
337             my $counter=$ini{"section1"}{"counter1"};
338             $counter+=1;
339             $ini{"section1"}{"counter1"}=$counter;
340            
341             $ini{"section1"}{"subsection1"}{"parameter"}="value";
342            
343             my @array;
344             for(1..10) { push @array,$_; }
345             $ini{"section1"}{"array"}{"a"}=@array;
346              
347             untie %ini;
348              
349             ### CHANGE option
350              
351             tie my %paths, 'Tie::Cfg', READ => "paths.ini",
352             CHANGE => [ "s/PREFIX/$myprefix/", "s/CONF/$myconfidir/" ];
353              
354             # Do something here
355            
356             untie %paths;
357              
358              
359             =head1 DESCRIPTION
360              
361             This module reads in a configuration file at 'tie' and writes it at 'untie'.
362              
363             You can use file locking to prevent others from accessing the configuration file,
364             but this should only be used if the configuration file is used as a small data file
365             to hold a few entries that can be concurrently accessed.
366             Note! In this case a persistent ".lock" file will be created.
367              
368             Mode is used to set access permissions; defaults to 0640. It's only set
369             if a file should be written (i.e. using the WRITE keyword).
370              
371             INIMODE lets you choose between Windows alike .ini configuration files and simple
372             key[:=]value entried files.
373              
374             Sections are addressed using a hash within a hash: For a tied %cfg the assignment:
375              
376             $cfg{"section"}{"key"}="value"
377            
378             will write in the configuration file:
379              
380             [section]
381             key=value
382              
383             Keys that end on [\[][0-9]+[\]] will be interpreted as arrays and will show up
384             in the tied hash as an array element. For example:
385              
386             [array-section]
387             var[0]=1
388             var[1]=2
389             var[2]=3
390              
391             will show up in a tied %cfg hash like:
392              
393             for (0..2) {
394             print $cfg{"array-section"}{"var"}[$_],"\n";
395             }
396            
397             Hashes of hashes are permitted:
398              
399             $cfg{"key"}{"subkey"}{"subsubkey"}{"subsubsubkey"}{"par"}="value";
400            
401             will show up in the configuration file as:
402              
403             [key.subkey.subsubkey.subsubsubkey]
404             par=value
405              
406              
407             =head1 PREREQUISITE
408              
409             Perl's Version >= 5.6.0! Please don't test this module with
410             anything earlier.
411              
412             =head1 AUTHOR
413              
414             Hans Oesterholt-Dijkema
415              
416             =head1 BUGS
417              
418             Probably.
419              
420             =head1 LICENCE
421              
422             Perl.
423              
424             =end
425              
426