line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright 2001-2006 The Apache Software Foundation |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
4
|
|
|
|
|
|
|
# you may not use this file except in compliance with the License. |
5
|
|
|
|
|
|
|
# You may obtain a copy of the License at |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0 |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software |
10
|
|
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, |
11
|
|
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12
|
|
|
|
|
|
|
# See the License for the specific language governing permissions and |
13
|
|
|
|
|
|
|
# limitations under the License. |
14
|
|
|
|
|
|
|
# |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package AxKit2::Config; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
AxKit2::Config - Configuration class |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
This class is a parser for the configuration files. This document also describes |
25
|
|
|
|
|
|
|
the API for the classes that implement the configuration, which are |
26
|
|
|
|
|
|
|
C, C and C. |
27
|
|
|
|
|
|
|
It's just easier to type C so we're putting the docs here to be |
28
|
|
|
|
|
|
|
nice :-) |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=cut |
31
|
|
|
|
|
|
|
|
32
|
9
|
|
|
9
|
|
47
|
use strict; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
251
|
|
33
|
9
|
|
|
9
|
|
43
|
use warnings; |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
186
|
|
34
|
|
|
|
|
|
|
|
35
|
9
|
|
|
9
|
|
43
|
use AxKit2::Client; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
200
|
|
36
|
9
|
|
|
9
|
|
4588
|
use AxKit2::Config::Global; |
|
9
|
|
|
|
|
26
|
|
|
9
|
|
|
|
|
233
|
|
37
|
9
|
|
|
9
|
|
5321
|
use AxKit2::Config::Server; |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
368
|
|
38
|
9
|
|
|
9
|
|
59
|
use AxKit2::Config::Location; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
197
|
|
39
|
9
|
|
|
9
|
|
8896
|
use File::Spec::Functions qw(rel2abs); |
|
9
|
|
|
|
|
8573
|
|
|
9
|
|
|
|
|
24633
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
our %CONFIG; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(Plugin => \&TAKE1, sub { my $conf = shift; AxKit2::Client->load_plugin($conf, $_[0]); $conf->add_plugin($_[0]); }); |
44
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(Port => \&TAKE1, sub { my $conf = shift; $conf->port($_[0]) }); |
45
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(DocumentRoot => \&TAKE1, sub { my $conf = shift; $conf->docroot(rel2abs($_[0])) }); |
46
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(ConsolePort => \&TAKE1, sub { my $conf = shift; $conf->isa('AxKit2::Config::Global') || die "ConsolePort only allowed at global level"; $conf->console_port($_[0]) }); |
47
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(ConsoleAddr => \&TAKE1, sub { my $conf = shift; $conf->isa('AxKit2::Config::Global') || die "ConsoleAddr only allowed at global level"; $conf->console_addr($_[0]) }); |
48
|
|
|
|
|
|
|
__PACKAGE__->add_config_param(PluginDir => \&TAKE1, sub { my $conf = shift; $conf->plugin_dir($_[0]) }); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
our $GLOBAL = AxKit2::Config::Global->new(); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub new { |
53
|
0
|
|
|
0
|
0
|
0
|
my ($class, $file) = @_; |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
0
|
my $self = bless { |
56
|
|
|
|
|
|
|
servers => [], |
57
|
|
|
|
|
|
|
}, $class; |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
0
|
$self->parse_config($file); |
60
|
|
|
|
|
|
|
|
61
|
0
|
|
|
|
|
0
|
return $self; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub global { |
65
|
0
|
|
|
0
|
0
|
0
|
return $GLOBAL; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub add_config_param { |
69
|
54
|
|
|
54
|
0
|
82
|
my $class = shift; |
70
|
54
|
|
50
|
|
|
154
|
my $key = shift || die "add_config_param() requires a key"; |
71
|
54
|
|
50
|
|
|
118
|
my $validate = shift || die "add_config_param() requires a validate routine"; |
72
|
54
|
|
50
|
|
|
143
|
my $store = shift || die "add_config_param() requires a store routine"; |
73
|
|
|
|
|
|
|
|
74
|
54
|
50
|
|
|
|
137
|
if ($key !~ m/_/) { |
75
|
54
|
|
|
|
|
148
|
$key =~ s/([A-Z]+)([A-Z])/$1_$2/g; |
76
|
54
|
|
|
|
|
336
|
$key =~ s/([a-z0-9])([A-Z])/$1_$2/g; |
77
|
|
|
|
|
|
|
} |
78
|
54
|
|
|
|
|
113
|
$key = lc($key); |
79
|
|
|
|
|
|
|
|
80
|
54
|
50
|
|
|
|
133
|
if (exists $CONFIG{$key}) { |
81
|
0
|
|
|
|
|
0
|
die "Config key '$key' already exists"; |
82
|
|
|
|
|
|
|
} |
83
|
54
|
|
|
|
|
144
|
$CONFIG{$key} = [$validate, $store]; |
84
|
54
|
|
|
|
|
161
|
$key =~ s/_//g; |
85
|
54
|
|
|
|
|
237
|
$CONFIG{$key} = [$validate, $store]; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub servers { |
89
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
90
|
0
|
|
|
|
|
|
return @{$self->{servers}}; |
|
0
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub parse_config { |
94
|
0
|
|
|
0
|
0
|
|
my ($self, $file) = @_; |
95
|
|
|
|
|
|
|
|
96
|
0
|
0
|
|
|
|
|
open(my $fh, $file) || die "open($file): $!"; |
97
|
0
|
|
|
|
|
|
local $self->{_fh} = $fh; |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
my $global = $self->global; |
100
|
0
|
|
|
|
|
|
while ($self->_configline) { |
101
|
0
|
0
|
|
|
|
|
if (/^/i) { |
102
|
0
|
|
0
|
|
|
|
my $name = $2 || ""; |
103
|
0
|
|
|
|
|
|
$self->_parse_server($global, $name); |
104
|
0
|
|
|
|
|
|
next; |
105
|
|
|
|
|
|
|
} |
106
|
0
|
|
|
|
|
|
_generic_config($global, $_); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub _parse_server { |
111
|
0
|
|
|
0
|
|
|
my ($self, $global, $name) = @_; |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my $server = AxKit2::Config::Server->new($global, $name); |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
my $closing = 0; |
116
|
0
|
|
|
|
|
|
while ($self->_configline) { |
117
|
0
|
0
|
|
|
|
|
if (/^/i) { |
|
|
0
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
my $path = $1; |
119
|
0
|
|
|
|
|
|
my $loc = $self->_parse_location($server, $path); |
120
|
0
|
|
|
|
|
|
$server->add_location($loc); |
121
|
0
|
|
|
|
|
|
next; |
122
|
|
|
|
|
|
|
} |
123
|
0
|
|
|
|
|
|
elsif (/<\/Server>/i) { $closing++; last; } |
|
0
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
_generic_config($server, $_); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
0
|
0
|
|
|
|
|
my $forserver = $name ? "for server named $name " : ""; |
128
|
0
|
0
|
|
|
|
|
die "No line ${forserver}in config file" unless $closing; |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
push @{$self->{servers}}, $server; |
|
0
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
|
return; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub _parse_location { |
136
|
0
|
|
|
0
|
|
|
my ($self, $server, $path) = @_; |
137
|
|
|
|
|
|
|
|
138
|
0
|
|
|
|
|
|
my $location = AxKit2::Config::Location->new($server, $path); |
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
my $closing = 0; |
141
|
0
|
|
|
|
|
|
while ($self->_configline) { |
142
|
0
|
0
|
|
|
|
|
if (/<\/Location>/i) { $closing++; last; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
_generic_config($location, $_); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
0
|
0
|
|
|
|
|
die "No line for path: $path in config file" unless $closing; |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
return $location; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub _generic_config { |
152
|
0
|
|
|
0
|
|
|
my ($conf, $line) = @_; |
153
|
0
|
|
|
|
|
|
my ($key, $rest) = split(/\s+/, $line, 2); |
154
|
0
|
|
|
|
|
|
$key = lc($key); |
155
|
0
|
|
|
|
|
|
$key =~ s/-/_/g; |
156
|
0
|
0
|
0
|
|
|
|
if (!$CONFIG{$key} || ($key =~ s/_//g && !$CONFIG{$key})) { |
|
|
|
0
|
|
|
|
|
157
|
0
|
|
|
|
|
|
die "Invalid line in server config: $line"; |
158
|
|
|
|
|
|
|
} |
159
|
0
|
|
|
|
|
|
my $cfg = $CONFIG{$key}; |
160
|
0
|
|
|
|
|
|
my @vals = $cfg->[0]->($rest); # validate and clean |
161
|
0
|
|
|
|
|
|
$cfg->[1]->($conf, @vals); # save value(s) |
162
|
0
|
|
|
|
|
|
return; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _configline { |
166
|
0
|
|
|
0
|
|
|
my $self = shift; |
167
|
0
|
0
|
|
|
|
|
die "No filehandle!" unless $self->{_fh}; |
168
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
while ($_ = $self->{_fh}->getline) { |
170
|
0
|
0
|
|
|
|
|
return unless defined $_; |
171
|
|
|
|
|
|
|
|
172
|
0
|
0
|
|
|
|
|
next unless /\S/; |
173
|
|
|
|
|
|
|
# skip comments |
174
|
0
|
0
|
|
|
|
|
next if /^\s*#/; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# cleanup whitespace |
177
|
0
|
|
|
|
|
|
s/^\s*//; s/\s*$//; |
|
0
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
chomp; |
180
|
|
|
|
|
|
|
|
181
|
0
|
0
|
|
|
|
|
if (s/\\$//) { |
182
|
|
|
|
|
|
|
# continuation line... |
183
|
0
|
|
|
|
|
|
my $line = $_; |
184
|
0
|
|
|
|
|
|
$_ = $line . $self->_configline; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
0
|
|
|
|
|
|
return $_; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub _get_quoted { |
192
|
0
|
|
|
0
|
|
|
my $line = shift; |
193
|
0
|
|
|
|
|
|
my $quotechar = shift; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
my $out = ''; |
196
|
0
|
|
|
|
|
|
$line =~ s/^$quotechar//; |
197
|
0
|
|
|
|
|
|
while ($line =~ /\G(.*?)([\\$quotechar])/gc) { |
198
|
0
|
|
|
|
|
|
$out .= $1; |
199
|
0
|
|
|
|
|
|
my $token = $2; |
200
|
0
|
0
|
|
|
|
|
if ($token eq "\\") { |
|
|
0
|
|
|
|
|
|
201
|
0
|
0
|
|
|
|
|
$line =~ /\G([$quotechar\\])/gc || die "invalid escape char"; |
202
|
0
|
|
|
|
|
|
$out .= $1; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
elsif ($token eq $quotechar) { |
205
|
0
|
|
|
|
|
|
$line =~ /\G\s*(.*)$/gc; |
206
|
0
|
|
|
|
|
|
return $out, $1; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
} |
209
|
0
|
|
|
|
|
|
die "Invalid quoted string"; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub TAKEBOOL { |
213
|
0
|
|
|
0
|
0
|
|
my $str = shift; |
214
|
0
|
0
|
|
|
|
|
$str =~ /^(y(?:es)?|1|on|true)$/i and return 1; |
215
|
0
|
0
|
|
|
|
|
$str =~ /^(no?|0|off|false)$/i and return 0; |
216
|
0
|
|
|
|
|
|
die "Unkown boolean value: $str"; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub TAKE1 { |
220
|
0
|
|
|
0
|
0
|
|
my $str = shift; |
221
|
0
|
|
|
|
|
|
my @vals = TAKEMANY($str); |
222
|
0
|
0
|
|
|
|
|
if (@vals != 1) { |
223
|
0
|
|
|
|
|
|
die "Invalid number of params"; |
224
|
|
|
|
|
|
|
} |
225
|
0
|
|
|
|
|
|
return $vals[0]; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub TAKEMANY { |
229
|
0
|
|
|
0
|
0
|
|
my $str = shift; |
230
|
0
|
|
|
|
|
|
my @vals; |
231
|
0
|
|
|
|
|
|
while (length($str)) { |
232
|
0
|
0
|
|
|
|
|
if ($str =~ /^(["'])/) { |
233
|
0
|
|
|
|
|
|
my $val; |
234
|
0
|
|
|
|
|
|
($val, $str) = _get_quoted($str, $1); |
235
|
0
|
|
|
|
|
|
push @vals, $val; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
else { |
238
|
0
|
0
|
|
|
|
|
$str =~ s/^(\S+)\s*// || die "bad format"; |
239
|
0
|
|
|
|
|
|
push @vals, $1; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
} |
242
|
0
|
0
|
|
|
|
|
die "No data found" unless @vals; |
243
|
0
|
|
|
|
|
|
return @vals; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
__END__ |