line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Getargs::Original - remember the original arguments a program was invoked |
4
|
|
|
|
|
|
|
with |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 SYNOPSIS |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
In your main program: |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use Getargs::Original; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Later on somewhere else |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
require Getargs::Original; |
15
|
|
|
|
|
|
|
exec @{ Getargs::Original->args }; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 DESCRIPTION |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Common behaviour for a daemon is to re-exec itself upon receipt of a signal |
20
|
|
|
|
|
|
|
(typically SIGHUP). It is also common to use modules like Getopt::Long to |
21
|
|
|
|
|
|
|
parse command line arguments when the program first starts. To achieve both |
22
|
|
|
|
|
|
|
of these tasks one must store the original contents of C<$0> and C<@ARGV>, |
23
|
|
|
|
|
|
|
as argument processing usually removes elements from @ARGV. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
B simplifies this task by storing the contents of $0 and |
26
|
|
|
|
|
|
|
@ARGV when it is first used in a program. Later on when the original |
27
|
|
|
|
|
|
|
arguments are required, a singleton instance of B can be |
28
|
|
|
|
|
|
|
used to retrieve the arguments. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
B is not meant to be instantiated as an object. All of |
31
|
|
|
|
|
|
|
the methods are called as class methods. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=begin testing |
34
|
1
|
|
|
|
|
41
|
|
35
|
|
|
|
|
|
|
# damn lexical scoping in pod2test... |
36
|
1
|
|
|
1
|
|
618
|
use vars qw|$dollar_zero @orig_argv|; |
|
1
|
|
|
|
|
105
|
|
|
1
|
|
|
|
|
53573
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# stick a couple of things onto @ARGV |
39
|
0
|
|
|
|
|
0
|
push @ARGV, qw|foo bar baz|; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# stash away our $0 and @ARGV for testing purposes |
42
|
0
|
|
|
|
|
0
|
$dollar_zero = $0; |
43
|
1
|
|
|
|
|
7
|
@orig_argv = @ARGV; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# use the module then clear out @ARGV |
46
|
1
|
|
|
1
|
|
4
|
use_ok('Getargs::Original'); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2503
|
|
|
1
|
|
|
|
|
974
|
|
|
1
|
|
|
|
|
5
|
|
47
|
1
|
|
|
|
|
4
|
undef @ARGV; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# make sure that the program was stored |
50
|
1
|
|
|
|
|
7
|
my $rx = qr/$dollar_zero/; |
51
|
1
|
|
|
|
|
2418
|
like( Getargs::Original->program, $rx, 'program name looks correct'); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# make sure the args were stored |
54
|
1
|
|
|
|
|
26
|
is_deeply( scalar Getargs::Original->args, \@orig_argv, 'args look correct'); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=end testing |
57
|
1
|
|
|
|
|
7
|
|
58
|
1
|
|
|
|
|
751
|
=cut |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
package Getargs::Original; |
61
|
|
|
|
|
|
|
|
62
|
1
|
|
|
1
|
|
1053
|
use strict; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
19
|
|
|
1
|
|
|
|
|
5
|
|
63
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
|
1
|
|
|
|
|
6
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
our $VERSION = 0.001_000; |
66
|
|
|
|
|
|
|
|
67
|
1
|
|
|
1
|
|
3
|
use File::Spec; |
|
1
|
|
|
|
|
59
|
|
|
1
|
|
|
|
|
5
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
use Class::MethodMaker( |
70
|
1
|
|
|
|
|
945
|
static_list => '_argv', |
71
|
|
|
|
|
|
|
static_get_set => [ qw| |
72
|
|
|
|
|
|
|
orig_program |
73
|
|
|
|
|
|
|
base_dir |
74
|
|
|
|
|
|
|
resolved |
75
|
|
|
|
|
|
|
|], |
76
|
1
|
|
|
1
|
|
2
|
); |
|
1
|
|
|
|
|
40
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# remember how this program was run |
79
|
|
|
|
|
|
|
Getargs::Original->orig_program($0); |
80
|
|
|
|
|
|
|
Getargs::Original->_argv_push($0, @ARGV); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head1 RESOLVING THE PATH OF $0 |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
In normal operation, the path of $0 is made absolute using |
85
|
|
|
|
|
|
|
Crel2abs()>. Sometimes it is desireable for the canonical |
86
|
|
|
|
|
|
|
name of the program run to be rooted in a particular directory. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Take for example a scenario where the canonical path to programs is |
89
|
|
|
|
|
|
|
F but F is a symlink to another filesystem which |
90
|
|
|
|
|
|
|
can differ from machine to machine. When the full path to $0 is resolved, |
91
|
|
|
|
|
|
|
the path will be the true filesystem and not F. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
This distinction may not matter to most, but if system monitoring tools are |
94
|
|
|
|
|
|
|
looking for a program to be running with a specific path then things will |
95
|
|
|
|
|
|
|
break. F is not the same as F |
96
|
|
|
|
|
|
|
after all. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
To address this, B provides a way to specify the base |
99
|
|
|
|
|
|
|
directory used for resolution of C<$0>. By passing a directory to the |
100
|
|
|
|
|
|
|
B method the resolved path to C<$0> will be calculated relative to |
101
|
|
|
|
|
|
|
that directory. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 METHODS |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head2 argv() |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Returns the original value of $0 and @ARGV as a list reference in scalar |
108
|
|
|
|
|
|
|
context and a list in array context. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
If the B method has been called then the first element of the |
111
|
|
|
|
|
|
|
list returned will be a relative path rooted in the directory that |
112
|
|
|
|
|
|
|
B was called with. If B has not been called then the |
113
|
|
|
|
|
|
|
first element of the list will be the absolute path to $0. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Resolution of $0 is performed the first time that the B method (or |
116
|
|
|
|
|
|
|
the shortcuts described below) are called. As such if relative resolution is |
117
|
|
|
|
|
|
|
desired then the B method must be called prior to the first use |
118
|
|
|
|
|
|
|
of B, B or B. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=begin testing |
121
|
|
|
|
|
|
|
|
122
|
1
|
|
|
|
|
3
|
# test without base dir set |
123
|
1
|
|
|
|
|
1
|
Getargs::Original->resolved(0); |
124
|
1
|
|
|
|
|
37
|
my $expected = File::Spec->rel2abs($0); |
125
|
|
|
|
|
|
|
is( Getargs::Original->program, $expected, |
126
|
1
|
|
|
|
|
41
|
'program without base dir set is correct'); |
127
|
1
|
|
|
|
|
6
|
|
128
|
1
|
|
|
|
|
737
|
# test with base dir set |
129
|
1
|
|
|
|
|
53
|
Getargs::Original->resolved(0); |
130
|
|
|
|
|
|
|
Getargs::Original->base_dir('foo'); |
131
|
1
|
|
|
|
|
145
|
$expected = File::Spec->catfile('foo', File::Spec->abs2rel($0, 'foo')); |
132
|
1
|
|
|
|
|
33
|
is( Getargs::Original->program, $expected, |
133
|
1
|
|
|
|
|
711
|
'program with base dir set is correct'); |
134
|
1
|
|
|
|
|
45
|
|
135
|
|
|
|
|
|
|
# another base dir test (this may break on non-UNIX - have to |
136
|
|
|
|
|
|
|
# see what CPAN-Testers comes up with) |
137
|
|
|
|
|
|
|
Getargs::Original->resolved(0); |
138
|
1
|
|
|
|
|
195
|
Getargs::Original->base_dir('/opt/foo/'); |
139
|
1
|
|
|
|
|
6
|
$expected = File::Spec->catfile('/opt/foo/', File::Spec->abs2rel($0, '/opt/foo/')); |
140
|
|
|
|
|
|
|
is( Getargs::Original->program, $expected, |
141
|
|
|
|
|
|
|
'program with base dir set is correct'); |
142
|
|
|
|
|
|
|
|
143
|
1
|
|
|
|
|
717
|
=end testing |
|
1
|
|
|
|
|
3
|
|
144
|
1
|
|
|
|
|
2
|
|
145
|
|
|
|
|
|
|
=cut |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub argv |
148
|
|
|
|
|
|
|
{ |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# if $0 has been resolved, just return the args |
151
|
1
|
50
|
|
6
|
1
|
24631
|
return Getargs::Original->_argv if( Getargs::Original->resolved ); |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# otherwise resolve $0 as relative or absolute |
154
|
1
|
|
|
|
|
11
|
my $program = Getargs::Original->orig_program; |
155
|
6
|
100
|
|
|
|
220
|
if( my $base_dir = Getargs::Original->base_dir ) { |
156
|
6
|
|
|
|
|
249
|
$program = File::Spec->catfile( |
157
|
|
|
|
|
|
|
$base_dir, |
158
|
|
|
|
|
|
|
File::Spec->abs2rel($program, $base_dir), |
159
|
|
|
|
|
|
|
); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
else { |
162
|
6
|
|
|
|
|
233
|
$program = File::Spec->rel2abs($program); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# set the resolved value |
166
|
3
|
|
|
|
|
356
|
Getargs::Original->_argv_set(0, $program); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# note that we have completed resolution |
169
|
3
|
|
|
|
|
103
|
Getargs::Original->resolved(1); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# return the args |
172
|
6
|
|
|
|
|
208
|
return Getargs::Original->_argv; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head2 program() |
177
|
1
|
|
|
|
|
2
|
|
178
|
1
|
|
|
|
|
2
|
Returns the original value of $0. A shortcut to saying |
179
|
1
|
|
|
|
|
37
|
|
180
|
1
|
|
|
|
|
44
|
$originalargs->argv->[0]; |
181
|
|
|
|
|
|
|
|
182
|
1
|
|
|
|
|
33
|
=for testing |
183
|
1
|
|
|
|
|
6
|
Getargs::Original->clear_resolved; |
184
|
|
|
|
|
|
|
Getargs::Original->clear_base_dir; |
185
|
|
|
|
|
|
|
my $expected = File::Spec->rel2abs($0); |
186
|
|
|
|
|
|
|
is( Getargs::Original->program, $expected, '$0 is correct'); |
187
|
1
|
|
|
|
|
698
|
|
|
1
|
|
|
|
|
2
|
|
188
|
1
|
|
|
|
|
2
|
=cut |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub program |
191
|
|
|
|
|
|
|
{ |
192
|
|
|
|
|
|
|
|
193
|
6
|
|
|
5
|
1
|
274
|
return Getargs::Original->argv->[0]; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head2 args() |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Returns the original value of @ARGV. A shortcut to saying |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $numargs = $originalargs->_argv_count; |
202
|
1
|
|
|
|
|
2
|
$originalargs->argv->[1..$numargs] |
203
|
|
|
|
|
|
|
|
204
|
1
|
|
|
|
|
2
|
As with B arguments are returned as a list or list reference |
205
|
1
|
|
|
|
|
6
|
depending on calling context. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=for testing |
208
|
|
|
|
|
|
|
is_deeply( scalar Getargs::Original->args, \@orig_argv, 'args are correct'); |
209
|
1
|
|
|
|
|
878
|
|
|
1
|
|
|
|
|
2
|
|
210
|
1
|
|
|
|
|
2
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub args |
213
|
|
|
|
|
|
|
{ |
214
|
|
|
|
|
|
|
|
215
|
6
|
|
|
2
|
1
|
319
|
my $num_args = Getargs::Original->_argv_count - 1; |
216
|
5
|
|
|
|
|
17
|
my @args = Getargs::Original->_argv; |
217
|
2
|
|
|
|
|
73
|
@args = @args[1..$num_args]; |
218
|
2
|
50
|
|
|
|
75
|
return wantarray ? @args : \@args; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=head2 base_dir() |
223
|
|
|
|
|
|
|
|
224
|
1
|
|
|
|
|
1
|
Sets or gets the base directory used for resolution of $0. See L<"RESOLVING |
225
|
|
|
|
|
|
|
THE PATH OF $0"> above for more detail. Returns the previous base directory. |
226
|
|
|
|
|
|
|
|
227
|
1
|
|
|
|
|
2
|
=begin testing |
228
|
1
|
|
|
|
|
36
|
|
229
|
1
|
|
|
|
|
699
|
# base dir shouldn't be defined yet |
230
|
|
|
|
|
|
|
ok( ! defined Getargs::Original->base_dir, 'base dir not defined'); |
231
|
|
|
|
|
|
|
|
232
|
1
|
|
|
|
|
39
|
# set and test |
233
|
1
|
|
|
|
|
557
|
Getargs::Original->base_dir('foo'); |
234
|
|
|
|
|
|
|
ok( defined Getargs::Original->base_dir, 'base dir is defined'); |
235
|
|
|
|
|
|
|
is( Getargs::Original->base_dir(), 'foo', 'base dir set to foo'); |
236
|
|
|
|
|
|
|
|
237
|
1
|
|
|
|
|
677
|
=end testing |
|
1
|
|
|
|
|
2
|
|
238
|
1
|
|
|
|
|
3
|
|
239
|
|
|
|
|
|
|
=head2 resolved() |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Sets or gets the flag indicating whether $0 has been resolved. Returns the |
242
|
|
|
|
|
|
|
previous state of the flag. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Using this method as a set accessor should only be required if the B |
245
|
1
|
|
|
|
|
2
|
method or one of it's shortcuts was inadvertently called prior to the |
246
|
1
|
|
|
|
|
2
|
B method being called. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=begin testing |
249
|
1
|
|
|
|
|
41
|
|
250
|
|
|
|
|
|
|
# reset state |
251
|
|
|
|
|
|
|
Getargs::Original->resolved(0); |
252
|
1
|
|
|
|
|
46
|
is( Getargs::Original->resolved, 0, '$0 has not been resolved'); |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# cause $0 to be resolved |
255
|
1
|
|
|
|
|
854
|
Getargs::Original->argv; |
256
|
1
|
|
|
|
|
53
|
|
257
|
|
|
|
|
|
|
# make sure things are now resolved |
258
|
|
|
|
|
|
|
is( Getargs::Original->resolved, 1, '$0 has been resolved'); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=end testing |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=cut |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# keep require happy |
265
|
|
|
|
|
|
|
1; |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
__END__ |