line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::Info::Util; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
App::Info::Util - Utility class for App::Info subclasses |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use App::Info::Util; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $util = App::Info::Util->new; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# Subclasses File::Spec. |
14
|
|
|
|
|
|
|
my @paths = $util->paths; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# First directory that exists in a list. |
17
|
|
|
|
|
|
|
my $dir = $util->first_dir(@paths); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# First directory that exists in a path. |
20
|
|
|
|
|
|
|
$dir = $util->first_path($ENV{PATH}); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# First file that exists in a list. |
23
|
|
|
|
|
|
|
my $file = $util->first_file('this.txt', '/that.txt', 'C:\\foo.txt'); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# First file found among file base names and directories. |
26
|
|
|
|
|
|
|
my $files = ['this.txt', 'that.txt']; |
27
|
|
|
|
|
|
|
$file = $util->first_cat_file($files, @paths); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This class subclasses L and adds its own methods in |
32
|
|
|
|
|
|
|
order to offer utility methods to L classes. Although |
33
|
|
|
|
|
|
|
intended to be used by App::Info subclasses, in truth App::Info::Util's |
34
|
|
|
|
|
|
|
utility may be considered more general, so feel free to use it elsewhere. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
The methods added in addition to the usual File::Spec suspects are designed to |
37
|
|
|
|
|
|
|
facilitate locating files and directories on the file system, as well as |
38
|
|
|
|
|
|
|
searching those files. The assumption is that, in order to provide useful |
39
|
|
|
|
|
|
|
meta data about a given software package, an App::Info subclass must find |
40
|
|
|
|
|
|
|
relevant files and directories and parse them with regular expressions. This |
41
|
|
|
|
|
|
|
class offers methods that simplify those tasks. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
44
|
|
|
|
|
|
|
|
45
|
15
|
|
|
15
|
|
36390
|
use strict; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
727
|
|
46
|
15
|
|
|
15
|
|
77
|
use File::Spec (); |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
230
|
|
47
|
15
|
|
|
15
|
|
79
|
use Config; |
|
15
|
|
|
|
|
33
|
|
|
15
|
|
|
|
|
610
|
|
48
|
15
|
|
|
15
|
|
79
|
use vars qw(@ISA $VERSION); |
|
15
|
|
|
|
|
48
|
|
|
15
|
|
|
|
|
36998
|
|
49
|
|
|
|
|
|
|
@ISA = qw(File::Spec); |
50
|
|
|
|
|
|
|
$VERSION = '0.57'; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my %path_dems = ( |
53
|
|
|
|
|
|
|
MacOS => qr',', |
54
|
|
|
|
|
|
|
MSWin32 => qr';', |
55
|
|
|
|
|
|
|
os2 => qr';', |
56
|
|
|
|
|
|
|
VMS => undef, |
57
|
|
|
|
|
|
|
epoc => undef |
58
|
|
|
|
|
|
|
); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
my $path_dem = exists $path_dems{$^O} ? $path_dems{$^O} : qr':'; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head2 new |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $util = App::Info::Util->new; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
This is a very simple constructor that merely returns an App::Info::Util |
69
|
|
|
|
|
|
|
object. Since, like its File::Spec super class, App::Info::Util manages no |
70
|
|
|
|
|
|
|
internal data itself, all methods may be used as class methods, if one prefers |
71
|
|
|
|
|
|
|
to. The constructor here is provided merely as a convenience. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=cut |
74
|
|
|
|
|
|
|
|
75
|
18
|
|
33
|
18
|
1
|
249
|
sub new { bless {}, ref $_[0] || $_[0] } |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
############################################################################## |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head1 OBJECT METHODS |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
In addition to all of the methods offered by its super class, |
82
|
|
|
|
|
|
|
L, App::Info::Util offers the following methods. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=head2 first_dir |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
my @paths = $util->paths; |
87
|
|
|
|
|
|
|
my $dir = $util->first_dir(@dirs); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Returns the first file system directory in @paths that exists on the local |
90
|
|
|
|
|
|
|
file system. Only the first item in @paths that exists as a directory will be |
91
|
|
|
|
|
|
|
returned; any other paths leading to non-directories will be ignored. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub first_dir { |
96
|
10
|
|
|
10
|
1
|
20
|
shift; |
97
|
10
|
100
|
|
|
|
35
|
foreach (@_) { return $_ if -d } |
|
14
|
|
|
|
|
867
|
|
98
|
0
|
|
|
|
|
0
|
return; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
############################################################################## |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head2 first_path |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
my $path = $ENV{PATH}; |
106
|
|
|
|
|
|
|
$dir = $util->first_path($path); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Takes the $path string and splits it into a list of directory paths, based on |
109
|
|
|
|
|
|
|
the path delimiter on the local file system. Then calls C to |
110
|
|
|
|
|
|
|
return the first directory in the path list that exists on the local file |
111
|
|
|
|
|
|
|
system. The path delimiter is specified for the following file systems: |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=over 4 |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=item * MacOS: "," |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item * MSWin32: ";" |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item * os2: ";" |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item * VMS: undef |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
This method always returns undef on VMS. Patches welcome. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item * epoc: undef |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
This method always returns undef on epoch. Patches welcome. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item * Unix: ":" |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
All other operating systems are assumed to be Unix-based. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=back |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=cut |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub first_path { |
138
|
1
|
50
|
|
1
|
1
|
9
|
return unless $path_dem; |
139
|
1
|
|
|
|
|
7
|
shift->first_dir(split /$path_dem/, shift) |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
############################################################################## |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head2 first_file |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
my $file = $util->first_file(@filelist); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Examines each of the files in @filelist and returns the first one that exists |
149
|
|
|
|
|
|
|
on the file system. The file must be a regular file -- directories will be |
150
|
|
|
|
|
|
|
ignored. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=cut |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub first_file { |
155
|
6
|
|
|
6
|
1
|
1002
|
shift; |
156
|
6
|
100
|
|
|
|
15
|
foreach (@_) { return $_ if -f } |
|
9
|
|
|
|
|
162
|
|
157
|
0
|
|
|
|
|
0
|
return; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
############################################################################## |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=head2 first_exe |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $exe = $util->first_exe(@exelist); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Examines each of the files in @exelist and returns the first one that exists |
167
|
|
|
|
|
|
|
on the file system as an executable file. Directories will be ignored. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=cut |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub first_exe { |
172
|
1
|
|
|
1
|
1
|
2
|
shift; |
173
|
1
|
100
|
66
|
|
|
4
|
foreach (@_) { return $_ if -f && -x } |
|
3
|
|
|
|
|
65
|
|
174
|
0
|
|
|
|
|
0
|
return; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
############################################################################## |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head2 first_cat_path |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
my $file = $util->first_cat_path('ick.txt', @paths); |
182
|
|
|
|
|
|
|
$file = $util->first_cat_path(['this.txt', 'that.txt'], @paths); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
The first argument to this method may be either a file or directory base name |
185
|
|
|
|
|
|
|
(that is, a file or directory name without a full path specification), or a |
186
|
|
|
|
|
|
|
reference to an array of file or directory base names. The remaining arguments |
187
|
|
|
|
|
|
|
constitute a list of directory paths. C processes each of |
188
|
|
|
|
|
|
|
these directory paths, concatenates (by the method native to the local |
189
|
|
|
|
|
|
|
operating system) each of the file or directory base names, and returns the |
190
|
|
|
|
|
|
|
first one that exists on the file system. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
For example, let us say that we were looking for a file called either F |
193
|
|
|
|
|
|
|
or F, and it could be in any of the following paths: |
194
|
|
|
|
|
|
|
F, F, F. The method call looks like this: |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $httpd = $util->first_cat_path(['httpd', 'apache'], '/usr/local/bin', |
197
|
|
|
|
|
|
|
'/usr/bin/', '/bin'); |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
If the OS is a Unix variant, C will then look for the first |
200
|
|
|
|
|
|
|
file that exists in this order: |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=over 4 |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item /usr/local/bin/httpd |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=item /usr/local/bin/apache |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=item /usr/bin/httpd |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=item /usr/bin/apache |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=item /bin/httpd |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=item /bin/apache |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=back |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
The first of these complete paths to be found will be returned. If none are |
219
|
|
|
|
|
|
|
found, then undef will be returned. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub first_cat_path { |
224
|
8
|
|
|
8
|
1
|
26
|
my $self = shift; |
225
|
8
|
100
|
|
|
|
40
|
my $files = ref $_[0] ? shift() : [shift()]; |
226
|
8
|
|
|
|
|
43
|
foreach my $p (@_) { |
227
|
22
|
|
|
|
|
42
|
foreach my $f (@$files) { |
228
|
45
|
|
|
|
|
307
|
my $path = $self->catfile($p, $f); |
229
|
45
|
100
|
|
|
|
1203
|
return $path if -e $path; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
} |
232
|
0
|
|
|
|
|
0
|
return; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
############################################################################## |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head2 first_cat_dir |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
my $dir = $util->first_cat_dir('ick.txt', @paths); |
240
|
|
|
|
|
|
|
$dir = $util->first_cat_dir(['this.txt', 'that.txt'], @paths); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Functionally identical to C, except that it returns the |
243
|
|
|
|
|
|
|
directory path in which the first file was found, rather than the full |
244
|
|
|
|
|
|
|
concatenated path. Thus, in the above example, if the file found was |
245
|
|
|
|
|
|
|
F, while C would return that value, |
246
|
|
|
|
|
|
|
C would return F instead. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=cut |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub first_cat_dir { |
251
|
20
|
|
|
20
|
1
|
37
|
my $self = shift; |
252
|
20
|
100
|
|
|
|
377
|
my $files = ref $_[0] ? shift() : [shift()]; |
253
|
20
|
|
|
|
|
49
|
foreach my $p (@_) { |
254
|
70
|
|
|
|
|
111
|
foreach my $f (@$files) { |
255
|
376
|
|
|
|
|
2632
|
my $path = $self->catfile($p, $f); |
256
|
376
|
100
|
|
|
|
6043
|
return $p if -e $path; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
} |
259
|
5
|
|
|
|
|
41
|
return; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
############################################################################## |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head2 first_cat_exe |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
my $exe = $util->first_cat_exe('ick.exe', @paths); |
267
|
|
|
|
|
|
|
$exe = $util->first_cat_exe(['this.exe', 'that.exe'], @paths); |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Functionally identical to C, except that it returns the full |
270
|
|
|
|
|
|
|
path to the first executable file found, rather than simply the first file |
271
|
|
|
|
|
|
|
found. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=cut |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub first_cat_exe { |
276
|
39
|
|
|
39
|
1
|
91
|
my $self = shift; |
277
|
39
|
100
|
|
|
|
247
|
my $files = ref $_[0] ? shift() : [shift()]; |
278
|
39
|
|
|
|
|
160
|
foreach my $p (@_) { |
279
|
130
|
|
|
|
|
233
|
foreach my $f (@$files) { |
280
|
242
|
|
|
|
|
2753
|
my $path = $self->catfile($p, $f); |
281
|
242
|
100
|
66
|
|
|
5701
|
return $path if -f $path && -x $path; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
5
|
|
|
|
|
34
|
return; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
############################################################################## |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head2 search_file |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
my $file = 'foo.txt'; |
292
|
|
|
|
|
|
|
my $regex = qr/(text\s+to\s+find)/; |
293
|
|
|
|
|
|
|
my $value = $util->search_file($file, $regex); |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
Opens C<$file> and executes the C<$regex> regular expression against each line |
296
|
|
|
|
|
|
|
in the file. Once the line matches and one or more values is returned by the |
297
|
|
|
|
|
|
|
match, the file is closed and the value or values returned. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
For example, say F contains the line "Version 6.5, patch level 8", |
300
|
|
|
|
|
|
|
and you need to grab each of the three version parts. All three parts can |
301
|
|
|
|
|
|
|
be grabbed like this: |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
my $regex = qr/Version\s+(\d+)\.(\d+),[^\d]*(\d+)/; |
304
|
|
|
|
|
|
|
my @nums = $util->search_file($file, $regex); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Now C<@nums> will contain the values C<(6, 5, 8)>. Note that in a scalar |
307
|
|
|
|
|
|
|
context, the above search would yield an array reference: |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
my $regex = qr/Version\s+(\d+)\.(\d+),[^\d]*(\d+)/; |
310
|
|
|
|
|
|
|
my $nums = $util->search_file($file, $regex); |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
So now C<$nums> contains C<[6, 5, 8]>. The same does not hold true if the |
313
|
|
|
|
|
|
|
match returns only one value, however. Say F contains the line |
314
|
|
|
|
|
|
|
"king of the who?", and you wish to know who the king is king of. Either |
315
|
|
|
|
|
|
|
of the following two calls would get you the data you need: |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
my $minions = $util->search_file($file, qr/King\s+of\s+(.*)/); |
318
|
|
|
|
|
|
|
my @minions = $util->search_file($file, qr/King\s+of\s+(.*)/); |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
In the first case, because the regular expression contains only one set of |
321
|
|
|
|
|
|
|
parentheses, C will simply return that value: C<$minions> |
322
|
|
|
|
|
|
|
contains the string "the who?". In the latter case, C<@minions> of course |
323
|
|
|
|
|
|
|
contains a single element: C<("the who?")>. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Note that a regular expression without parentheses -- that is, one that |
326
|
|
|
|
|
|
|
doesn't grab values and put them into $1, $2, etc., will never successfully |
327
|
|
|
|
|
|
|
match a line in this method. You must include something to parenthetically |
328
|
|
|
|
|
|
|
match. If you just want to know the value of what was matched, parenthesize |
329
|
|
|
|
|
|
|
the whole thing and if the value returns, you have a match. Also, if you need |
330
|
|
|
|
|
|
|
to match patterns across lines, try using multiple regular expressions with |
331
|
|
|
|
|
|
|
C, instead. |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=cut |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub search_file { |
336
|
7
|
|
|
7
|
1
|
16
|
my ($self, $file, $regex) = @_; |
337
|
7
|
50
|
33
|
|
|
49
|
return unless $file && $regex; |
338
|
7
|
50
|
0
|
|
|
375
|
open F, "<$file" or require Carp && Carp::croak("Cannot open $file: $!\n"); |
339
|
7
|
|
|
|
|
14
|
my @ret; |
340
|
7
|
|
|
|
|
145
|
while () { |
341
|
|
|
|
|
|
|
# If we find a match, we're done. |
342
|
170
|
100
|
|
|
|
699
|
(@ret) = /$regex/ and last; |
343
|
|
|
|
|
|
|
} |
344
|
7
|
|
|
|
|
78
|
close F; |
345
|
|
|
|
|
|
|
# If the match returned an more than one value, always return the full |
346
|
|
|
|
|
|
|
# array. Otherwise, return just the first value in a scalar context. |
347
|
7
|
100
|
|
|
|
34
|
return unless @ret; |
348
|
3
|
50
|
|
|
|
28
|
return wantarray ? @ret : $#ret <= 0 ? $ret[0] : \@ret; |
|
|
100
|
|
|
|
|
|
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
############################################################################## |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=head2 files_in_dir |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
my @files = $util->files_in_dir($dir); |
356
|
|
|
|
|
|
|
@files = $util->files_in_dir($dir, $filter); |
357
|
|
|
|
|
|
|
my $files = $util->files_in_dir($dir); |
358
|
|
|
|
|
|
|
$files = $util->files_in_dir($dir, $filter); |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Returns an list or array reference of all of the files and directories in the |
361
|
|
|
|
|
|
|
file system directory C<$dir>. An optional second argument is a code reference |
362
|
|
|
|
|
|
|
that filters the files. The code reference should examine the C<$_> for a file |
363
|
|
|
|
|
|
|
name and return true if it's a file that you're interested and false if it's |
364
|
|
|
|
|
|
|
not. |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=cut |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub files_in_dir { |
369
|
4
|
|
|
4
|
1
|
27
|
my ($self, $dir, $code) = @_; |
370
|
4
|
50
|
|
|
|
28
|
return unless $dir; |
371
|
4
|
|
|
|
|
26
|
local *DIR; |
372
|
4
|
50
|
0
|
|
|
529
|
opendir DIR, $dir or require Carp && Carp::croak("Cannot open $dir: $!\n"); |
373
|
18
|
|
|
|
|
986
|
my @files = $code |
374
|
4
|
100
|
|
|
|
179
|
? grep { $code->() } readdir DIR |
375
|
|
|
|
|
|
|
: readdir DIR; |
376
|
4
|
|
|
|
|
78
|
closedir DIR; |
377
|
4
|
100
|
|
|
|
97
|
return wantarray ? @files : \@files; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
############################################################################## |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=head2 multi_search_file |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
my @regexen = (qr/(one)/, qr/(two)\s+(three)/); |
385
|
|
|
|
|
|
|
my @matches = $util->multi_search_file($file, @regexen); |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
Like C, this method opens C<$file> and parses it for regular |
388
|
|
|
|
|
|
|
expression matches. This method, however, can take a list of regular |
389
|
|
|
|
|
|
|
expressions to look for, and will return the values found for all of them. |
390
|
|
|
|
|
|
|
Regular expressions that match and return multiple values will be returned as |
391
|
|
|
|
|
|
|
array references, while those that match and return a single value will return |
392
|
|
|
|
|
|
|
just that single value. |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
For example, say you are parsing a file with lines like the following: |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
#define XML_MAJOR_VERSION 1 |
397
|
|
|
|
|
|
|
#define XML_MINOR_VERSION 95 |
398
|
|
|
|
|
|
|
#define XML_MICRO_VERSION 2 |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
You need to get each of these numbers, but calling C for each |
401
|
|
|
|
|
|
|
of them would be wasteful, as each call to C opens the file and |
402
|
|
|
|
|
|
|
parses it. With C, on the other hand, the file will be |
403
|
|
|
|
|
|
|
opened only once, and, once all of the regular expressions have returned |
404
|
|
|
|
|
|
|
matches, the file will be closed and the matches returned. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Thus the above values can be collected like this: |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
my @regexen = ( qr/XML_MAJOR_VERSION\s+(\d+)$/, |
409
|
|
|
|
|
|
|
qr/XML_MINOR_VERSION\s+(\d+)$/, |
410
|
|
|
|
|
|
|
qr/XML_MICRO_VERSION\s+(\d+)$/ ); |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
my @nums = $file->multi_search_file($file, @regexen); |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
The result will be that C<@nums> contains C<(1, 95, 2)>. Note that |
415
|
|
|
|
|
|
|
C tries to do the right thing by only parsing the file |
416
|
|
|
|
|
|
|
until all of the regular expressions have been matched. Thus, a large file |
417
|
|
|
|
|
|
|
with the values you need near the top can be parsed very quickly. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
As with C, C can take regular expressions |
420
|
|
|
|
|
|
|
that match multiple values. These will be returned as array references. For |
421
|
|
|
|
|
|
|
example, say the file you're parsing has files like this: |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
FooApp Version 4 |
424
|
|
|
|
|
|
|
Subversion 2, Microversion 6 |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
To get all of the version numbers, you can either use three regular |
427
|
|
|
|
|
|
|
expressions, as in the previous example: |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
my @regexen = ( qr/FooApp\s+Version\s+(\d+)$/, |
430
|
|
|
|
|
|
|
qr/Subversion\s+(\d+),/, |
431
|
|
|
|
|
|
|
qr/Microversion\s+(\d$)$/ ); |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
my @nums = $file->multi_search_file($file, @regexen); |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
In which case C<@nums> will contain C<(4, 2, 6)>. Or, you can use just two |
436
|
|
|
|
|
|
|
regular expressions: |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
my @regexen = ( qr/FooApp\s+Version\s+(\d+)$/, |
439
|
|
|
|
|
|
|
qr/Subversion\s+(\d+),\s+Microversion\s+(\d$)$/ ); |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
my @nums = $file->multi_search_file($file, @regexen); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
In which case C<@nums> will contain C<(4, [2, 6])>. Note that the two |
444
|
|
|
|
|
|
|
parentheses that return values in the second regular expression cause the |
445
|
|
|
|
|
|
|
matches to be returned as an array reference. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=cut |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
sub multi_search_file { |
450
|
11
|
|
|
11
|
1
|
41
|
my ($self, $file, @regexen) = @_; |
451
|
11
|
50
|
33
|
|
|
100
|
return unless $file && @regexen; |
452
|
11
|
|
|
|
|
32
|
my @each = @regexen; |
453
|
11
|
50
|
0
|
|
|
827
|
open F, "<$file" or require Carp && Carp::croak("Cannot open $file: $!\n"); |
454
|
11
|
|
|
|
|
29
|
my %ret; |
455
|
11
|
|
|
|
|
257
|
while (my $line = ) { |
456
|
41
|
|
|
|
|
72
|
my @splice; |
457
|
|
|
|
|
|
|
# Process each of the regular expresssions. |
458
|
41
|
|
|
|
|
137
|
for (my $i = 0; $i < @each; $i++) { |
459
|
138
|
100
|
|
|
|
1653
|
if ((my @ret) = $line =~ /$each[$i]/) { |
460
|
|
|
|
|
|
|
# We have a match! If there's one match returned, just grab |
461
|
|
|
|
|
|
|
# it. If there's more than one, keep it as an array ref. |
462
|
46
|
100
|
|
|
|
305
|
$ret{$each[$i]} = $#ret > 0 ? \@ret : $ret[0]; |
463
|
|
|
|
|
|
|
# We got values for this regex, so not its place in the @each |
464
|
|
|
|
|
|
|
# array. |
465
|
46
|
|
|
|
|
325
|
push @splice, $i; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
# Remove any regexen that have already found a match. |
469
|
41
|
|
|
|
|
82
|
for (@splice) { splice @each, $_, 1 } |
|
46
|
|
|
|
|
119
|
|
470
|
|
|
|
|
|
|
# If there are no more regexes, we're done -- no need to keep |
471
|
|
|
|
|
|
|
# processing lines in the file! |
472
|
41
|
100
|
|
|
|
266
|
last unless @each; |
473
|
|
|
|
|
|
|
} |
474
|
11
|
|
|
|
|
144
|
close F; |
475
|
11
|
50
|
|
|
|
36
|
return unless %ret; |
476
|
11
|
50
|
|
|
|
139
|
return wantarray ? @ret{@regexen} : \@ret{@regexen}; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
############################################################################## |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=head2 lib_dirs |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
my @dirs = $util->lib_dirs; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Returns a list of possible library directories to be searched. These are |
486
|
|
|
|
|
|
|
gathered from the C and C Config settings. These are |
487
|
|
|
|
|
|
|
useful for passing to C to search typical directories for |
488
|
|
|
|
|
|
|
library files. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=cut |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub lib_dirs { |
493
|
80
|
50
|
|
|
|
325
|
grep { defined and length } |
|
30
|
|
|
|
|
93
|
|
494
|
30
|
|
|
|
|
29775
|
map { split ' ' } |
495
|
10
|
|
|
10
|
1
|
18987
|
grep { defined } |
496
|
|
|
|
|
|
|
# Quote Config access to work around |
497
|
|
|
|
|
|
|
# http://bugs.activestate.com/show_bug.cgi?id=89447 |
498
|
|
|
|
|
|
|
"$Config{libsdirs}", |
499
|
|
|
|
|
|
|
"$Config{loclibpth}", |
500
|
|
|
|
|
|
|
'/sw/lib'; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
1; |
504
|
|
|
|
|
|
|
__END__ |