| 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__ |