File Coverage

blib/lib/Bot/Pastebot/Conf.pm
Criterion Covered Total %
statement 12 81 14.8
branch 0 40 0.0
condition 0 3 0.0
subroutine 4 9 44.4
pod 0 5 0.0
total 16 138 11.5


line stmt bran cond sub pod time code
1             # Configuration reading and holding.
2              
3             package Bot::Pastebot::Conf;
4              
5 1     1   724 use strict;
  1         1  
  1         29  
6 1     1   5 use Carp qw(croak);
  1         1  
  1         43  
7              
8 1     1   13 use base qw(Exporter);
  1         2  
  1         337  
9             our @EXPORT_OK = qw(
10             get_names_by_type get_items_by_name load
11             SCALAR LIST REQUIRED
12             );
13              
14             sub SCALAR () { 0x01 }
15             sub LIST () { 0x02 }
16             sub REQUIRED () { 0x04 }
17              
18             my ($section, $section_line, %item, %config);
19              
20             sub flush_section {
21 0     0 0   my ($conf_file, $conf_definition) = @_;
22              
23 0 0         return unless defined $section;
24              
25 0 0         unless (exists $item{name}) {
26 0           die(
27             "conf error: ",
28             "section `$section' has no `name' at $conf_file line $section_line"
29             );
30             }
31              
32 0           foreach my $item_name (sort keys %{$conf_definition->{$section}}) {
  0            
33 0           my $item_type = $conf_definition->{$section}->{$item_name};
34              
35 0 0         if ($item_type & REQUIRED) {
36 0 0         die(
37             "conf error: section `$section' ",
38             "requires item `$item_name' ",
39             "at $conf_file line $section_line\n"
40             ) unless exists $item{$item_name};
41             }
42             }
43              
44             die(
45 0 0         "conf error: section `$section' ",
46             "item `$item{name}' is redefined at $conf_file line $section_line\n"
47             ) if exists $config{$item{name}};
48              
49 0           my $name = $item{name};
50 0           $config{$name} = { %item, type => $section };
51             }
52              
53             # Parse some configuration.
54              
55             sub get_conf_file {
56 1     1   2067 use Getopt::Std;
  1         42  
  1         677  
57              
58 0     0 0   my %opts;
59 0           getopts("f:", \%opts);
60              
61 0           my $conf_file = $opts{"f"};
62 0           my @conf;
63 0 0         if (defined $conf_file) {
64 0           @conf = ($conf_file);
65             }
66             else {
67 0           my $f = "pastebot.conf";
68 0           @conf = (
69             "./$f", "$ENV{HOME}/$f", "/usr/local/etc/pastebot/$f", "/etc/pastebot/$f"
70             );
71              
72 0           foreach my $try ( @conf ) {
73 0 0         next unless -f $try;
74 0           $conf_file = $try;
75 0           last;
76             }
77             }
78              
79 0 0 0       unless (defined $conf_file and -f $conf_file) {
80 0           die(
81             "\nconf error: Cannot read configuration file [$conf_file], tried: @conf"
82             );
83             }
84              
85 0           return $conf_file;
86             }
87              
88             sub load {
89 0     0 0   my ($class, $conf_file, $conf_definition) = @_;
90              
91 0 0         open(MPH, "<", $conf_file) or
92             die "\nconf error: Cannot open configuration file [$conf_file]: $!";
93              
94 0           while (<MPH>) {
95 0           chomp;
96 0           s/\s*(?<!\\)\#.*$//; # remove comments ('#' not preceded by a '\')
97 0 0         next if /^\s*$/;
98              
99 0           s/\\\#/\#/g; # '\#' -> '#'
100              
101             # Section item.
102 0 0         if (/^\s+(\S+)\s+(.*?)\s*$/) {
103              
104 0 0         die(
105             "conf error: ",
106             "can't use an indented item ($1) outside of an unindented section ",
107             "at $conf_file line $.\n"
108             ) unless defined $section;
109              
110 0 0         die(
111             "conf error: item `$1' does not belong in section `$section' ",
112             "at $conf_file line $.\n"
113             ) unless exists $conf_definition->{$section}->{$1};
114              
115 0 0         if (exists $item{$1}) {
116 0 0         if (ref($item{$1}) eq 'ARRAY') {
117 0           push @{$item{$1}}, $2;
  0            
118             }
119             else {
120 0           die "conf error: option $1 redefined at $conf_file line $.\n";
121             }
122             }
123             else {
124 0 0         if ($conf_definition->{$section}->{$1} & LIST) {
125 0           $item{$1} = [ $2 ];
126             }
127             else {
128 0           $item{$1} = $2;
129             }
130             }
131 0           next;
132             }
133              
134             # Section leader.
135 0 0         if (/^(\S+)\s*$/) {
136              
137             # A new section ends the previous one.
138 0           flush_section($conf_file, $conf_definition);
139              
140 0           $section = $1;
141 0           $section_line = $.;
142 0           undef %item;
143              
144             # Pre-initialize any lists in the section.
145 0           while (my ($item_name, $item_flags) = each %{$conf_definition->{$section}}) {
  0            
146 0 0         if ($item_flags & LIST) {
147 0           $item{$item_name} = [];
148             }
149             }
150              
151 0           next;
152             }
153              
154 0           die "conf error: syntax error in $conf_file at line $.\n";
155             }
156              
157 0           flush_section($conf_file);
158              
159 0           close MPH;
160             }
161              
162             sub get_names_by_type {
163 0     0 0   my $type = shift;
164 0           my @names;
165              
166 0           while (my ($name, $item) = each %config) {
167 0 0         next unless $item->{type} eq $type;
168 0           push @names, $name;
169             }
170              
171 0           return @names;
172             }
173              
174             sub get_items_by_name {
175 0     0 0   my $name = shift;
176 0 0         return () unless exists $config{$name};
177 0           return %{$config{$name}};
  0            
178             }
179              
180             1;