line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mail::ExpandAliases; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ------------------------------------------------------------------- |
4
|
|
|
|
|
|
|
# Mail::ExpandAliases - Expand aliases from /etc/aliases files |
5
|
|
|
|
|
|
|
# Copyright (C) 2002 darren chamberlain |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or |
8
|
|
|
|
|
|
|
# modify it under the terms of the GNU General Public License as |
9
|
|
|
|
|
|
|
# published by the Free Software Foundation; version 2. |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, but |
12
|
|
|
|
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of |
13
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14
|
|
|
|
|
|
|
# General Public License for more details. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
17
|
|
|
|
|
|
|
# along with this program; if not, write to the Free Software |
18
|
|
|
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
19
|
|
|
|
|
|
|
# 02111-1307 USA |
20
|
|
|
|
|
|
|
# ------------------------------------------------------------------- |
21
|
|
|
|
|
|
|
# Design of this class: |
22
|
|
|
|
|
|
|
# |
23
|
|
|
|
|
|
|
# - Read aliases file |
24
|
|
|
|
|
|
|
# |
25
|
|
|
|
|
|
|
# - Parse aliases file |
26
|
|
|
|
|
|
|
# |
27
|
|
|
|
|
|
|
# o Read file, normalize |
28
|
|
|
|
|
|
|
# |
29
|
|
|
|
|
|
|
# + Skip malformed lines |
30
|
|
|
|
|
|
|
# |
31
|
|
|
|
|
|
|
# + Join multi-line entries |
32
|
|
|
|
|
|
|
# |
33
|
|
|
|
|
|
|
# + Discard comments |
34
|
|
|
|
|
|
|
# |
35
|
|
|
|
|
|
|
# o Create internal structure |
36
|
|
|
|
|
|
|
# |
37
|
|
|
|
|
|
|
# - On call to expand |
38
|
|
|
|
|
|
|
# |
39
|
|
|
|
|
|
|
# o Start with first alias, and expand |
40
|
|
|
|
|
|
|
# |
41
|
|
|
|
|
|
|
# o Expand each alias, unless: |
42
|
|
|
|
|
|
|
# |
43
|
|
|
|
|
|
|
# + It is non-local |
44
|
|
|
|
|
|
|
# |
45
|
|
|
|
|
|
|
# + It has already been seen |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
# - Return list of responses |
48
|
|
|
|
|
|
|
# ------------------------------------------------------------------- |
49
|
|
|
|
|
|
|
|
50
|
2
|
|
|
2
|
|
5324
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
76
|
|
51
|
2
|
|
|
2
|
|
10
|
use vars qw($VERSION $DEBUG @POSSIBLE_ALIAS_FILES); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
210
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
$VERSION = 0.49; |
54
|
|
|
|
|
|
|
$DEBUG = 0 unless defined $DEBUG; |
55
|
|
|
|
|
|
|
@POSSIBLE_ALIAS_FILES = qw(/etc/aliases |
56
|
|
|
|
|
|
|
/etc/mail/aliases |
57
|
|
|
|
|
|
|
/etc/postfix/aliases |
58
|
|
|
|
|
|
|
/etc/exim/aliases); |
59
|
|
|
|
|
|
|
|
60
|
2
|
|
|
2
|
|
12
|
use constant PARSED => 0; # Parsed aliases |
|
2
|
|
|
|
|
16
|
|
|
2
|
|
|
|
|
159
|
|
61
|
2
|
|
|
2
|
|
9
|
use constant CACHED => 1; # Caches lookups |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
98
|
|
62
|
2
|
|
|
2
|
|
9
|
use constant FILE => 2; # "Main" aliases file |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3208
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
65
|
|
|
|
|
|
|
# import(@files) |
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
# Allow for compile-time additions to @POSSIBLE_ALIAS_FILES |
68
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
69
|
|
|
|
|
|
|
sub import { |
70
|
4
|
|
|
4
|
|
409
|
my $class = shift; |
71
|
|
|
|
|
|
|
|
72
|
4
|
|
|
|
|
100
|
for my $x (@_) { |
73
|
0
|
0
|
|
|
|
0
|
if ($x =~ /^debug$/i) { |
|
|
0
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
$DEBUG = 1; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
elsif (-f "$x") { |
77
|
0
|
|
|
|
|
0
|
unshift @POSSIBLE_ALIAS_FILES, $x; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub new { |
83
|
2
|
|
|
2
|
0
|
1220
|
my ($class, $file) = @_; |
84
|
2
|
|
|
|
|
11
|
my $self = bless [ { }, { }, "" ] => $class; |
85
|
|
|
|
|
|
|
|
86
|
2
|
100
|
|
|
|
9
|
$self->[ FILE ] = (grep { -e $_ && -r _ } |
|
10
|
|
|
|
|
222
|
|
87
|
|
|
|
|
|
|
($file, @POSSIBLE_ALIAS_FILES))[0]; |
88
|
2
|
|
|
|
|
16
|
$self->debug("Using alias file " . $self->[ FILE ]); |
89
|
2
|
|
|
|
|
9
|
$self->init(); |
90
|
|
|
|
|
|
|
|
91
|
2
|
|
|
|
|
12
|
return $self; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub debug { |
95
|
64
|
|
|
64
|
0
|
117
|
my $class = shift; |
96
|
64
|
|
33
|
|
|
140
|
$class = ref $class || $class; |
97
|
64
|
50
|
|
|
|
139
|
if ($DEBUG) { |
98
|
|
|
|
|
|
|
warn "[ $class ] $_\n" |
99
|
0
|
|
|
|
|
0
|
for (@_); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
104
|
|
|
|
|
|
|
# init($file) |
105
|
|
|
|
|
|
|
# |
106
|
|
|
|
|
|
|
# Parse file, extracting aliases. Note that this is a (more or less) |
107
|
|
|
|
|
|
|
# literal representation of the file; expansion of aliases happens at |
108
|
|
|
|
|
|
|
# run time, as aliases are requested. |
109
|
|
|
|
|
|
|
# # ---------------------------------------------------------------------- |
110
|
|
|
|
|
|
|
sub init { |
111
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
112
|
2
|
|
33
|
|
|
13
|
my $file = shift || $self->[ FILE ]; |
113
|
2
|
50
|
|
|
|
9
|
return $self unless defined $file; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Chapter 24 of the sendmail book |
116
|
|
|
|
|
|
|
# (www.oreilly.com/catalog/sendmail/) describes the process of |
117
|
|
|
|
|
|
|
# looking for aliases thusly: |
118
|
|
|
|
|
|
|
# |
119
|
|
|
|
|
|
|
# "The aliases(5) file is composed of lines of text. Any line that |
120
|
|
|
|
|
|
|
# begins with a # is a comment and is ignored. Empty lines (those |
121
|
|
|
|
|
|
|
# that contain only a newline character) are also ignored. Any |
122
|
|
|
|
|
|
|
# lines that begins with a space or tab is joined (appended) to the |
123
|
|
|
|
|
|
|
# line above it. All other lines are text are viewed as alias |
124
|
|
|
|
|
|
|
# lines. The format for an alias line is: |
125
|
|
|
|
|
|
|
# |
126
|
|
|
|
|
|
|
# local: alias |
127
|
|
|
|
|
|
|
# |
128
|
|
|
|
|
|
|
# "The local must begin a line. It is an address in the form of a |
129
|
|
|
|
|
|
|
# local recipient address... The colon follows the local on |
130
|
|
|
|
|
|
|
# the same line and may be preceded with spaces or tabs. If the |
131
|
|
|
|
|
|
|
# colon is missing, sendmail prints and syslog(3)'s the following |
132
|
|
|
|
|
|
|
# error message and skips that alias line: |
133
|
|
|
|
|
|
|
# |
134
|
|
|
|
|
|
|
# missing colon |
135
|
|
|
|
|
|
|
# |
136
|
|
|
|
|
|
|
# "The alias (to the right of the colon) is one or more addresses on |
137
|
|
|
|
|
|
|
# the same line. Indented continuation lines are permitted. Each |
138
|
|
|
|
|
|
|
# address should be separated from the next by a comma and optional |
139
|
|
|
|
|
|
|
# space characters. A typical alias looks like this: |
140
|
|
|
|
|
|
|
# |
141
|
|
|
|
|
|
|
# root: jim, sysadmin@server, gunther ^ | indenting whitespace |
142
|
|
|
|
|
|
|
# |
143
|
|
|
|
|
|
|
# "Here, root is hte local address to be aliases. When mail is to |
144
|
|
|
|
|
|
|
# be locally delivered to root, it is looked up in the aliases(5) |
145
|
|
|
|
|
|
|
# file. If found, root is replaced with the three addresses show |
146
|
|
|
|
|
|
|
# earlier, and mail is instead delivered to those other three |
147
|
|
|
|
|
|
|
# addresses. |
148
|
|
|
|
|
|
|
# |
149
|
|
|
|
|
|
|
# "This process of looking up and possibly aliases local recipients |
150
|
|
|
|
|
|
|
# is repeated for each recipient until no more aliases are found in |
151
|
|
|
|
|
|
|
# the aliases(5) file. That is, for example, if one of the aliases |
152
|
|
|
|
|
|
|
# for root is jim, and if jim also exists to the left of a colon in |
153
|
|
|
|
|
|
|
# the aliases file, he too is replaced with his alias: |
154
|
|
|
|
|
|
|
# |
155
|
|
|
|
|
|
|
# jim: jim@otherhost |
156
|
|
|
|
|
|
|
# |
157
|
|
|
|
|
|
|
# "The list of addresses to the right of the colon may be mail |
158
|
|
|
|
|
|
|
# addresses (such as gunther or jim@otherhost), the name of a |
159
|
|
|
|
|
|
|
# program to run (such as /etc/relocated), the name of a file onto |
160
|
|
|
|
|
|
|
# which to append (such as /usr/share/archive), or the name of a |
161
|
|
|
|
|
|
|
# file to read for additional addresses (using :include:)." |
162
|
|
|
|
|
|
|
|
163
|
2
|
|
|
|
|
13
|
$self->debug("Opening alias file '$file'"); |
164
|
2
|
50
|
|
|
|
19
|
my $fh = File::Aliases->new($file) |
165
|
|
|
|
|
|
|
or die "Can't open $file: $!"; |
166
|
|
|
|
|
|
|
|
167
|
2
|
|
|
|
|
11
|
while (my $line = $fh->next) { |
168
|
50
|
|
|
|
|
59
|
chomp($line); |
169
|
50
|
100
|
|
|
|
143
|
next if $line =~ /^#/; |
170
|
30
|
50
|
|
|
|
87
|
next if $line =~ /^\s*$/; |
171
|
|
|
|
|
|
|
|
172
|
30
|
|
|
|
|
116
|
$line =~ s/\s+/ /g; |
173
|
30
|
|
|
|
|
37
|
my ($orig, $alias, @expandos); |
174
|
|
|
|
|
|
|
|
175
|
30
|
|
|
|
|
35
|
$orig = $line; |
176
|
30
|
50
|
|
|
|
122
|
if ($line =~ s/^([^:]+)\s*:\s*//) { |
177
|
30
|
|
|
|
|
64
|
$alias = lc $1; |
178
|
30
|
|
|
|
|
120
|
$self->debug("$. => '$alias'"); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
else { |
181
|
0
|
|
|
|
|
0
|
local $DEBUG = 1; |
182
|
0
|
|
|
|
|
0
|
$self->debug("$file line $.: missing colon"); |
183
|
0
|
|
|
|
|
0
|
next; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
44
|
|
|
|
|
109
|
@expandos = |
187
|
|
|
|
|
|
|
#grep !/^$alias$/, |
188
|
30
|
|
|
|
|
71
|
map { s/^\s*//; s/\s*$//; $_ } |
|
44
|
|
|
|
|
174
|
|
|
44
|
|
|
|
|
112
|
|
189
|
|
|
|
|
|
|
split /,/, $line; |
190
|
|
|
|
|
|
|
|
191
|
30
|
|
|
|
|
109
|
$self->debug($alias, map "\t$_", @expandos); |
192
|
30
|
|
|
|
|
127
|
$self->[ PARSED ]->{ $alias } = \@expandos; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
2
|
|
|
|
|
46
|
return $self; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
199
|
|
|
|
|
|
|
# expand($name) |
200
|
|
|
|
|
|
|
# |
201
|
|
|
|
|
|
|
# Expands $name to @addresses. If @addresses is empty, return $name. |
202
|
|
|
|
|
|
|
# In list context, returns a list of the matching expansions; in |
203
|
|
|
|
|
|
|
# scalar context, returns a reference to an array of expansions. |
204
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
205
|
|
|
|
|
|
|
sub expand { |
206
|
26
|
|
|
26
|
0
|
5442
|
my ($self, $name, $original, $lcname, %answers, @answers, @names, $n); |
207
|
26
|
|
|
|
|
30
|
$self = shift; |
208
|
26
|
|
50
|
|
|
53
|
$name = shift || return $name; |
209
|
26
|
|
|
|
|
28
|
$original = shift; |
210
|
26
|
|
|
|
|
37
|
$lcname = lc $name; |
211
|
|
|
|
|
|
|
|
212
|
26
|
100
|
100
|
|
|
85
|
return $name if (defined $original && $name eq $original); |
213
|
|
|
|
|
|
|
|
214
|
24
|
100
|
|
|
|
58
|
return @{ $self->[ CACHED ]->{ $lcname } } |
|
4
|
|
|
|
|
43
|
|
215
|
|
|
|
|
|
|
if (defined $self->[ CACHED ]->{ $lcname }); |
216
|
|
|
|
|
|
|
|
217
|
20
|
100
|
|
|
|
22
|
if (@names = @{ $self->[ PARSED ]->{ $lcname } || [ ] }) { |
|
20
|
100
|
|
|
|
99
|
|
218
|
13
|
|
|
|
|
27
|
my $c = $self->[ CACHED ]->{ $lcname } = [ ]; |
219
|
|
|
|
|
|
|
|
220
|
13
|
|
|
|
|
24
|
for $n (@names) { |
221
|
18
|
|
|
|
|
71
|
$n =~ s/^[\s'"]*//g; |
222
|
18
|
|
|
|
|
100
|
$n =~ s/['"\s]*$//g; |
223
|
18
|
|
|
|
|
33
|
my $type = substr $n, 0, 1; |
224
|
|
|
|
|
|
|
|
225
|
18
|
100
|
100
|
|
|
100
|
if ($type eq '|' or $type eq '/') { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# |/path/to/program |
227
|
|
|
|
|
|
|
# /path/to/mbox |
228
|
4
|
|
|
|
|
9
|
$answers{ $n }++; |
229
|
4
|
|
|
|
|
16
|
push @$c, $n; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
elsif ($type eq ':') { |
233
|
|
|
|
|
|
|
# :include: |
234
|
|
|
|
|
|
|
#$n =~ s/:include:\s*//ig; |
235
|
|
|
|
|
|
|
#$self->parse($n); |
236
|
0
|
|
|
|
|
0
|
warn "Skipping include file $n\n"; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
elsif ($type eq '\\') { |
240
|
|
|
|
|
|
|
# \foo |
241
|
|
|
|
|
|
|
# literal, non-escaped value, useful for |
242
|
|
|
|
|
|
|
# aliases like: |
243
|
|
|
|
|
|
|
# foo: \foo, bar |
244
|
|
|
|
|
|
|
# where mail to foo, a local user, should also |
245
|
|
|
|
|
|
|
# go to bar. |
246
|
1
|
|
|
|
|
4
|
$n =~ s/^\\//; |
247
|
1
|
|
|
|
|
2
|
$answers{ $n }++; |
248
|
1
|
|
|
|
|
4
|
push @$c, $n; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
else { |
252
|
13
|
|
66
|
|
|
57
|
for ($self->expand($n, $original || $name)) { |
253
|
13
|
|
|
|
|
52
|
$answers{ $_ }++ |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Add to the cache |
259
|
13
|
|
|
|
|
45
|
@answers = sort keys %answers; |
260
|
13
|
|
|
|
|
28
|
$self->[ CACHED ]->{ $lcname } = \@answers; |
261
|
13
|
50
|
|
|
|
67
|
return wantarray ? @answers : \@answers; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
7
|
|
|
|
|
23
|
return $name; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
268
|
|
|
|
|
|
|
# reload() |
269
|
|
|
|
|
|
|
# |
270
|
|
|
|
|
|
|
# Reset the instance. Clears out parsed aliases and empties the cache. |
271
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
272
|
|
|
|
|
|
|
sub reload { |
273
|
0
|
|
|
0
|
0
|
0
|
my ($self, $file) = @_; |
274
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
0
|
%{ $self->[ PARSED ] } = (); |
|
0
|
|
|
|
|
0
|
|
276
|
0
|
|
|
|
|
0
|
%{ $self->[ CACHED ] } = (); |
|
0
|
|
|
|
|
0
|
|
277
|
0
|
0
|
|
|
|
0
|
$self->[ FILE ] = $file if defined $file; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
0
|
$self->parse; |
280
|
|
|
|
|
|
|
|
281
|
0
|
|
|
|
|
0
|
return $self; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
285
|
|
|
|
|
|
|
# aliases() |
286
|
|
|
|
|
|
|
# |
287
|
|
|
|
|
|
|
# Lists the aliases. |
288
|
|
|
|
|
|
|
# In list context, returns an array; |
289
|
|
|
|
|
|
|
# in scalar context, returns a reference to an array. |
290
|
|
|
|
|
|
|
# |
291
|
|
|
|
|
|
|
# From a patch submitted by Thomas Kishel |
292
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
293
|
|
|
|
|
|
|
sub aliases { |
294
|
0
|
|
|
0
|
0
|
0
|
my ($self, @answers); |
295
|
0
|
|
|
|
|
0
|
$self = shift; |
296
|
0
|
|
|
|
|
0
|
@answers = sort keys %{ $self->[ PARSED ] }; |
|
0
|
|
|
|
|
0
|
|
297
|
0
|
0
|
|
|
|
0
|
return wantarray ? @answers : \@answers; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
301
|
|
|
|
|
|
|
# exists($alias) |
302
|
|
|
|
|
|
|
# |
303
|
|
|
|
|
|
|
# Determine if an alias exists not not |
304
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
305
|
|
|
|
|
|
|
sub exists { |
306
|
2
|
|
|
2
|
0
|
4
|
my ($self, $alias) = @_; |
307
|
2
|
|
|
|
|
14
|
return CORE::exists($self->[ PARSED ]->{ $alias }); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
311
|
|
|
|
|
|
|
# check($alias) |
312
|
|
|
|
|
|
|
# |
313
|
|
|
|
|
|
|
# Returns the unexpanded form an an alias. I.e., exactly what is in the |
314
|
|
|
|
|
|
|
# file, without expansion. |
315
|
|
|
|
|
|
|
# |
316
|
|
|
|
|
|
|
# Unlike expand, if $alias does not exist in the file, check() returns |
317
|
|
|
|
|
|
|
# the empty array. Otherwise, $alias returns an array (in list context) |
318
|
|
|
|
|
|
|
# or a reference to an array (in scalar context) to the items in the |
319
|
|
|
|
|
|
|
# aliases file. |
320
|
|
|
|
|
|
|
# |
321
|
|
|
|
|
|
|
# You can emulate expand() by calling check recusrively. |
322
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
323
|
|
|
|
|
|
|
sub check { |
324
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
325
|
0
|
|
|
|
|
0
|
my $ret; |
326
|
|
|
|
|
|
|
|
327
|
0
|
0
|
|
|
|
0
|
if (my $name = shift) { |
328
|
0
|
|
|
|
|
0
|
$ret = $self->[ PARSED ]->{ $name } |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
0
|
|
0
|
|
|
0
|
$ret ||= []; |
332
|
|
|
|
|
|
|
|
333
|
0
|
0
|
|
|
|
0
|
return wantarray ? @$ret : [ @$ret ]; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
package File::Aliases; |
337
|
2
|
|
|
2
|
|
13
|
use constant FH => 0; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
100
|
|
338
|
2
|
|
|
2
|
|
11
|
use constant BUFFER => 1; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
102
|
|
339
|
|
|
|
|
|
|
|
340
|
2
|
|
|
2
|
|
1788
|
use IO::File; |
|
2
|
|
|
|
|
22590
|
|
|
2
|
|
|
|
|
691
|
|
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# This package ensures that each read (i.e., calls to next() -- |
343
|
|
|
|
|
|
|
# I'm too lazy to implement this as a tied file handle so it can |
344
|
|
|
|
|
|
|
# be used in <>) returns a single alias entry, which may span |
345
|
|
|
|
|
|
|
# multiple lines. |
346
|
|
|
|
|
|
|
# |
347
|
|
|
|
|
|
|
# XXX I suppose I could simply subclass IO::File, and rename next |
348
|
|
|
|
|
|
|
# to readline. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub new { |
351
|
2
|
|
|
2
|
|
5
|
my $class = shift; |
352
|
2
|
|
|
|
|
4
|
my $file = shift; |
353
|
2
|
|
|
|
|
20
|
my $fh = IO::File->new($file); |
354
|
|
|
|
|
|
|
|
355
|
2
|
|
|
|
|
231
|
my $self = bless [ $fh, '' ] => $class; |
356
|
2
|
50
|
|
|
|
75
|
$self->[ BUFFER ] = <$fh> |
357
|
|
|
|
|
|
|
if $fh; |
358
|
|
|
|
|
|
|
|
359
|
2
|
|
|
|
|
18
|
return $self; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
sub next { |
363
|
52
|
|
|
52
|
|
56
|
my $self = shift; |
364
|
52
|
|
|
|
|
82
|
my $buffer = $self->[ BUFFER ]; |
365
|
52
|
|
|
|
|
57
|
my $fh = $self->[ FH ]; |
366
|
|
|
|
|
|
|
|
367
|
52
|
50
|
|
|
|
95
|
return "" |
368
|
|
|
|
|
|
|
unless defined $fh; |
369
|
|
|
|
|
|
|
|
370
|
52
|
|
|
|
|
63
|
$self->[ BUFFER ] = ""; |
371
|
52
|
|
|
|
|
178
|
while (<$fh>) { |
372
|
66
|
100
|
|
|
|
167
|
if (/^\S/) { |
373
|
48
|
|
|
|
|
93
|
$self->[ BUFFER ] = $_; |
374
|
48
|
|
|
|
|
55
|
last; |
375
|
|
|
|
|
|
|
} else { |
376
|
18
|
|
|
|
|
49
|
$buffer .= $_; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
52
|
|
|
|
|
157
|
return $buffer; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
1; |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
__END__ |