line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Argv; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
$VERSION = '1.28'; |
4
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
5
|
|
|
|
|
|
|
|
6
|
1
|
50
|
|
1
|
|
1382
|
use constant MSWIN => $^O =~ /MSWin|Windows_NT/i ? 1 : 0; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
131
|
|
7
|
1
|
50
|
|
1
|
|
87
|
use constant CYGWIN => $^O =~ /cygwin/i ? 1 : 0; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
245
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# To support the "FUNCTIONAL INTERFACE" |
10
|
|
|
|
|
|
|
@EXPORT_OK = qw(system exec qv pipe MSWIN CYGWIN); |
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
46
|
|
13
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
167
|
|
14
|
|
|
|
|
|
|
require Exporter; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $class = __PACKAGE__; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my $NUL = MSWIN ? 'NUL' : '/dev/null'; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# Adapted from perltootc (see): an "eponymous meta-object" implementing |
21
|
|
|
|
|
|
|
# "translucent attributes". |
22
|
|
|
|
|
|
|
# For each key in the hash below, a method is automatically generated. |
23
|
|
|
|
|
|
|
# Each method sets the object attr if called as an instance method or |
24
|
|
|
|
|
|
|
# the class attr if called as a class method. They return the instance |
25
|
|
|
|
|
|
|
# attr if it's defined, the class attr otherwise. The method name is |
26
|
|
|
|
|
|
|
# lower-case; e.g. 'qxargs'. The default value of each attribute comes |
27
|
|
|
|
|
|
|
# from the hash value set here, which may be overridden in the environment. |
28
|
1
|
|
|
1
|
|
7
|
use vars qw(%Argv); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
440
|
|
29
|
|
|
|
|
|
|
%Argv = ( |
30
|
|
|
|
|
|
|
AUTOCHOMP => $ENV{ARGV_AUTOCHOMP} || 0, |
31
|
|
|
|
|
|
|
AUTOFAIL => $ENV{ARGV_AUTOFAIL} || 0, |
32
|
|
|
|
|
|
|
AUTOGLOB => $ENV{ARGV_AUTOGLOB} || 0, |
33
|
|
|
|
|
|
|
AUTOQUOTE => defined($ENV{ARGV_AUTOQUOTE}) ? $ENV{ARGV_AUTOQUOTE} : 1, |
34
|
|
|
|
|
|
|
DBGLEVEL => $ENV{ARGV_DBGLEVEL} || 0, |
35
|
|
|
|
|
|
|
DFLTSETS => {'' => 1}, |
36
|
|
|
|
|
|
|
ENVP => undef, |
37
|
|
|
|
|
|
|
EXECWAIT => defined($ENV{ARGV_EXECWAIT}) ? |
38
|
|
|
|
|
|
|
$ENV{ARGV_EXECWAIT} : scalar(MSWIN), |
39
|
|
|
|
|
|
|
INPATHNORM => $ENV{ARGV_INPATHNORM} || 0, |
40
|
|
|
|
|
|
|
MUSTEXEC => $ENV{ARGV_MUSTEXEC} || 0, |
41
|
|
|
|
|
|
|
NOEXEC => $ENV{ARGV_NOEXEC} || 0, |
42
|
|
|
|
|
|
|
OUTPATHNORM => $ENV{ARGV_OUTPATHNORM} || 0, |
43
|
|
|
|
|
|
|
QXARGS => $ENV{ARGV_QXARGS} || -1, |
44
|
|
|
|
|
|
|
QXFAIL => $ENV{ARGV_QXFAIL} || 0, |
45
|
|
|
|
|
|
|
QUIET => defined($ENV{ARGV_QUIET}) ? $ENV{ARGV_QUIET} : 0, |
46
|
|
|
|
|
|
|
STDIN => defined($ENV{ARGV_STDIN}) ? $ENV{ARGV_STDIN} : 0, |
47
|
|
|
|
|
|
|
STDOUT => defined($ENV{ARGV_STDOUT}) ? $ENV{ARGV_STDOUT} : 1, |
48
|
|
|
|
|
|
|
STDERR => defined($ENV{ARGV_STDERR}) ? $ENV{ARGV_STDERR} : 2, |
49
|
|
|
|
|
|
|
SYFAIL => $ENV{ARGV_SYFAIL} || 0, |
50
|
|
|
|
|
|
|
SYXARGS => $ENV{ARGV_SYXARGS} || 0, |
51
|
|
|
|
|
|
|
PIPECB => sub { print shift; return 1 }, |
52
|
|
|
|
|
|
|
); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Generates execution-attribute methods from the table above. Provided |
55
|
|
|
|
|
|
|
# as a class method itself to potentially allow a derived class to |
56
|
|
|
|
|
|
|
# generate more of these. Semantics of these methods are quite |
57
|
|
|
|
|
|
|
# context-driven and are explained in the PODs. |
58
|
|
|
|
|
|
|
sub gen_exec_method { |
59
|
1
|
|
|
1
|
0
|
2
|
my $meta = shift; |
60
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; # must evaluate $meta as a symbolic ref |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
902
|
|
61
|
1
|
50
|
|
|
|
4
|
my @data = @_ ? map {uc} @_ : keys %{$meta}; |
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
10
|
|
62
|
1
|
|
|
|
|
4
|
for my $attr (@data) { |
63
|
21
|
|
100
|
|
|
85
|
$$meta{$attr} ||= 0; |
64
|
21
|
|
|
|
|
2751
|
my $method = lc $attr; |
65
|
|
|
|
|
|
|
*$method = sub { |
66
|
141
|
|
|
141
|
|
2127
|
my $self = shift; |
67
|
|
|
|
|
|
|
# In null context with no args, set boolean value 'on'. |
68
|
141
|
50
|
66
|
|
|
1058
|
@_ = (1) if !@_ && !defined(wantarray); |
69
|
141
|
|
|
|
|
226
|
my $ret = 0; |
70
|
141
|
100
|
|
|
|
384
|
if (ref $self) { |
71
|
139
|
100
|
|
|
|
235
|
if (@_) { |
72
|
9
|
100
|
|
|
|
27
|
if (defined(wantarray)) { |
73
|
4
|
50
|
|
|
|
27
|
if (ref $self->{$attr}) { |
|
|
50
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
unshift(@{$self->{$attr}}, shift); |
|
0
|
|
|
|
|
0
|
|
75
|
|
|
|
|
|
|
} elsif (defined $self->{$attr}) { |
76
|
0
|
|
|
|
|
0
|
$self->{$attr} = [shift, $self->{$attr}]; |
77
|
|
|
|
|
|
|
} else { |
78
|
4
|
|
|
|
|
73
|
$self->{$attr} = [shift]; |
79
|
|
|
|
|
|
|
} |
80
|
4
|
|
|
|
|
43
|
return $self; |
81
|
|
|
|
|
|
|
} else { |
82
|
5
|
|
|
|
|
20
|
$self->{$attr} = shift; |
83
|
5
|
|
|
|
|
14
|
return undef; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} else { |
86
|
130
|
100
|
|
|
|
976
|
$ret = defined($self->{$attr}) ? |
87
|
|
|
|
|
|
|
$self->{$attr} : $class->{$attr}; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} else { |
90
|
2
|
50
|
|
|
|
681
|
if (@_) { |
91
|
2
|
50
|
|
|
|
495
|
if (defined(wantarray)) { |
92
|
0
|
0
|
|
|
|
0
|
if (ref $class->{$attr}) { |
93
|
0
|
|
|
|
|
0
|
unshift(@{$class->{$attr}}, shift); |
|
0
|
|
|
|
|
0
|
|
94
|
|
|
|
|
|
|
} else { |
95
|
0
|
|
|
|
|
0
|
$class->{$attr} = [shift, $class->{$attr}]; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} else { |
98
|
2
|
|
|
|
|
59
|
$class->{$attr} = shift; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
# If setting a class attribute, export it to the |
101
|
|
|
|
|
|
|
# env in case we fork a child also using Argv. |
102
|
2
|
|
|
|
|
45
|
my $ev = uc join('_', $class, $attr); |
103
|
2
|
|
|
|
|
54
|
$ENV{$ev} = $class->{$attr}; |
104
|
2
|
|
|
|
|
16
|
return $self; |
105
|
|
|
|
|
|
|
} else { |
106
|
0
|
|
|
|
|
0
|
$ret = $class->{$attr}; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
} |
109
|
130
|
100
|
100
|
|
|
483
|
if (ref($ret) eq 'ARRAY' && ref($ret->[0]) ne 'CODE') { |
110
|
4
|
|
|
|
|
14
|
my $stack = $ret; |
111
|
4
|
|
|
|
|
6
|
$ret = shift @$stack; |
112
|
4
|
50
|
|
|
|
15
|
if (ref $self) { |
113
|
4
|
50
|
|
|
|
12
|
if (@$stack) { |
114
|
0
|
|
|
|
|
0
|
$self->{$attr} = shift @$stack; |
115
|
|
|
|
|
|
|
} else { |
116
|
4
|
|
|
|
|
15
|
delete $self->{$attr}; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
} else { |
119
|
0
|
|
|
|
|
0
|
$self->{$attr} = shift @$stack; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
} |
122
|
130
|
|
|
|
|
3195
|
return $ret; |
123
|
|
|
|
|
|
|
} |
124
|
21
|
|
|
|
|
167
|
} |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Generate all the attribute methods declared in %Argv above. |
128
|
|
|
|
|
|
|
$class->gen_exec_method; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# Generate methods for diverting stdin, stdout, and stderr in ->qx. |
131
|
|
|
|
|
|
|
{ |
132
|
|
|
|
|
|
|
my %streams = (stdin => 1, stdout => 1, stderr => 2); |
133
|
|
|
|
|
|
|
for my $name (keys %streams) { |
134
|
|
|
|
|
|
|
my $method = "_qx_$name"; |
135
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
765
|
|
136
|
|
|
|
|
|
|
*$method = sub { |
137
|
2
|
|
|
2
|
|
5
|
my $self = shift; |
138
|
2
|
|
|
|
|
3
|
my $r_cmd = shift; |
139
|
2
|
|
|
|
|
3
|
my $nfd = shift; |
140
|
2
|
|
|
|
|
4
|
my $fd = $streams{$name}; |
141
|
2
|
50
|
|
|
|
30
|
if ($nfd !~ m%^[\d-]*$%) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
push(@$r_cmd, "$fd$nfd"); |
143
|
|
|
|
|
|
|
} elsif ($fd == 0) { |
144
|
0
|
0
|
|
|
|
0
|
warn "Error: illegal value '$nfd' for $name" if $nfd > 0; |
145
|
0
|
0
|
|
|
|
0
|
push(@$r_cmd, "<$NUL") if $nfd < 0; |
146
|
|
|
|
|
|
|
} elsif ($nfd == 0) { |
147
|
0
|
|
|
|
|
0
|
push(@$r_cmd, "$fd>$NUL"); |
148
|
|
|
|
|
|
|
} elsif ($nfd == (3-$fd)) { |
149
|
0
|
|
|
|
|
0
|
push(@$r_cmd, sprintf "%d>&%d", $fd, 3-$fd); |
150
|
|
|
|
|
|
|
} elsif ($nfd != $fd) { |
151
|
0
|
|
|
|
|
0
|
warn "Error: illegal value '$nfd' for $name"; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
}; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Getopt::Long::GetOptions() respects '--' but strips it, while |
158
|
|
|
|
|
|
|
# we want to respect '--' and leave it in. Thus this override. |
159
|
|
|
|
|
|
|
sub GetOptions { |
160
|
5
|
50
|
|
5
|
0
|
16
|
@ARGV = map {/^--$/ ? qw(=--= --) : $_} @ARGV; |
|
21
|
|
|
|
|
218
|
|
161
|
5
|
|
|
|
|
36
|
my $ret = Getopt::Long::GetOptions(@_); |
162
|
5
|
50
|
|
|
|
3147
|
@ARGV = map {/^=--=$/ ? qw(--) : $_} @ARGV; |
|
11
|
|
|
|
|
70
|
|
163
|
5
|
|
|
|
|
17
|
return $ret; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# This method is much like the generated exec methods but has some |
167
|
|
|
|
|
|
|
# special-case logic: If called with a param which is true, it starts up |
168
|
|
|
|
|
|
|
# a coprocess. If called with false (aka 0) it shuts down the coprocess |
169
|
|
|
|
|
|
|
# and destroys the IPC::ChildSafe object. If called with no params at |
170
|
|
|
|
|
|
|
# all it returns the existing IPC::ChildSafe object. |
171
|
|
|
|
|
|
|
sub ipc_childsafe { |
172
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
173
|
0
|
|
|
|
|
0
|
my $ipc_state = $_[0]; |
174
|
0
|
|
|
|
|
0
|
my $ipc_obj; |
175
|
0
|
0
|
|
|
|
0
|
if ($ipc_state) { |
176
|
0
|
|
|
|
|
0
|
eval { require IPC::ChildSafe }; |
|
0
|
|
|
|
|
0
|
|
177
|
0
|
0
|
|
|
|
0
|
return undef if $@; |
178
|
0
|
|
|
|
|
0
|
IPC::ChildSafe->VERSION(3.10); |
179
|
0
|
|
|
|
|
0
|
$ipc_obj = IPC::ChildSafe->new(@_); |
180
|
|
|
|
|
|
|
} |
181
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1277
|
|
182
|
0
|
0
|
|
|
|
0
|
if (ref $self) { |
183
|
0
|
0
|
|
|
|
0
|
if (defined $ipc_state) { |
184
|
0
|
|
|
|
|
0
|
$self->{_IPC_CHILDSAFE} = $ipc_obj; |
185
|
0
|
|
|
|
|
0
|
return $self; |
186
|
|
|
|
|
|
|
} else { |
187
|
0
|
0
|
|
|
|
0
|
return exists($self->{_IPC_CHILDSAFE}) ? |
188
|
|
|
|
|
|
|
$self->{_IPC_CHILDSAFE} : $class->{_IPC_CHILDSAFE}; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} else { |
191
|
0
|
0
|
|
|
|
0
|
if (defined $ipc_state) { |
192
|
0
|
|
|
|
|
0
|
$class->{_IPC_CHILDSAFE} = $ipc_obj; |
193
|
0
|
|
|
|
|
0
|
return $self; |
194
|
|
|
|
|
|
|
} else { |
195
|
0
|
|
|
|
|
0
|
return $class->{_IPC_CHILDSAFE}; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Class/instance method. Parses command line for e.g. -/dbg=1. See PODs. |
201
|
|
|
|
|
|
|
sub attropts { |
202
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
203
|
0
|
|
|
|
|
0
|
my $r_argv = undef; |
204
|
0
|
|
|
|
|
0
|
my $prefix = '-/'; |
205
|
0
|
0
|
|
|
|
0
|
if (ref $_[0] eq 'HASH') { |
206
|
0
|
|
|
|
|
0
|
my $cfg = shift; |
207
|
0
|
|
|
|
|
0
|
$r_argv = $cfg->{ARGV}; |
208
|
0
|
|
|
|
|
0
|
$prefix = $cfg->{PREFIX}; |
209
|
|
|
|
|
|
|
} |
210
|
0
|
|
|
|
|
0
|
require Getopt::Long; |
211
|
0
|
|
|
|
|
0
|
local $Getopt::Long::passthrough = 1; |
212
|
0
|
|
|
|
|
0
|
local $Getopt::Long::genprefix = "($prefix)"; |
213
|
0
|
|
|
|
|
0
|
my @flags = map {"$_=i"} ((map lc, keys %Argv::Argv), @_); |
|
0
|
|
|
|
|
0
|
|
214
|
0
|
|
|
|
|
0
|
my %opt; |
215
|
0
|
0
|
|
|
|
0
|
if (ref $self) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
216
|
0
|
0
|
|
|
|
0
|
if ($r_argv) { |
217
|
0
|
|
|
|
|
0
|
local @ARGV = @$r_argv; |
218
|
0
|
|
|
|
|
0
|
GetOptions(\%opt, @flags); |
219
|
0
|
|
|
|
|
0
|
@$r_argv = @ARGV; |
220
|
|
|
|
|
|
|
} else { |
221
|
0
|
|
|
|
|
0
|
local @ARGV = $self->args; |
222
|
0
|
0
|
|
|
|
0
|
if (@ARGV) { |
223
|
0
|
|
|
|
|
0
|
GetOptions(\%opt, @flags); |
224
|
0
|
|
|
|
|
0
|
$self->args(@ARGV); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
} elsif ($r_argv) { |
228
|
0
|
|
|
|
|
0
|
local @ARGV = @$r_argv; |
229
|
0
|
|
|
|
|
0
|
GetOptions(\%opt, @flags); |
230
|
0
|
|
|
|
|
0
|
@$r_argv = @ARGV; |
231
|
|
|
|
|
|
|
} elsif (@ARGV) { |
232
|
0
|
|
|
|
|
0
|
GetOptions(\%opt, @flags); |
233
|
|
|
|
|
|
|
} |
234
|
0
|
|
|
|
|
0
|
for my $method (keys %opt) { |
235
|
0
|
|
|
|
|
0
|
$self->$method($opt{$method}); |
236
|
|
|
|
|
|
|
} |
237
|
0
|
|
|
|
|
0
|
return $self; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
*stdopts = \&attropts; # backward compatibility |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# A class method which returns a summary of operations performed in |
242
|
|
|
|
|
|
|
# printable format. Called with a void context to start data- |
243
|
|
|
|
|
|
|
# collection, with a scalar context to end it and get the report. |
244
|
|
|
|
|
|
|
sub summary { |
245
|
0
|
|
|
0
|
0
|
0
|
my $cls = shift; |
246
|
0
|
|
|
|
|
0
|
my($cmds, $operands); |
247
|
0
|
0
|
|
|
|
0
|
if (!defined wantarray) { |
248
|
0
|
|
|
|
|
0
|
$Argv::Summary = {}; |
249
|
0
|
|
|
|
|
0
|
return; |
250
|
|
|
|
|
|
|
} |
251
|
0
|
0
|
|
|
|
0
|
return unless $Argv::Summary; |
252
|
0
|
|
|
|
|
0
|
my $fmt = "%30s: %4s\t%s\n"; |
253
|
0
|
|
|
|
|
0
|
my $str = sprintf $fmt, "$cls Summary", 'Cmds', 'Operands'; |
254
|
0
|
|
|
|
|
0
|
for (sort keys %{$Argv::Summary}) { |
|
0
|
|
|
|
|
0
|
|
255
|
0
|
|
|
|
|
0
|
my @stats = @{$Argv::Summary->{$_}}; |
|
0
|
|
|
|
|
0
|
|
256
|
0
|
|
|
|
|
0
|
$cmds += $stats[0]; |
257
|
0
|
|
|
|
|
0
|
$operands += $stats[1]; |
258
|
0
|
|
|
|
|
0
|
$str .= sprintf $fmt, $_, $stats[0], $stats[1]; |
259
|
|
|
|
|
|
|
} |
260
|
0
|
0
|
|
|
|
0
|
$str .= sprintf $fmt, 'TOTAL', $cmds, $operands if defined $cmds; |
261
|
0
|
|
|
|
|
0
|
$Argv::Summary = 0; |
262
|
0
|
|
|
|
|
0
|
return $str; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# Constructor. |
266
|
|
|
|
|
|
|
sub new { |
267
|
8
|
|
|
8
|
0
|
586
|
my $proto = shift; |
268
|
8
|
50
|
|
|
|
185
|
my $attrs = shift if ref($_[0]) eq 'HASH'; |
269
|
8
|
|
|
|
|
13
|
my $self; |
270
|
8
|
100
|
|
|
|
56
|
if (ref($proto)) { |
271
|
|
|
|
|
|
|
# As an instance method, make a deep clone of the invoking object. |
272
|
|
|
|
|
|
|
# Some cloners are fast but not commonly installed, others the |
273
|
|
|
|
|
|
|
# reverse. We try them in order of speed and fall back to |
274
|
|
|
|
|
|
|
# Data::Dumper which is slow but core Perl as of 5.6.0. I could |
275
|
|
|
|
|
|
|
# just inherit from Clone or Storable but want to not force |
276
|
|
|
|
|
|
|
# users who don't need cloning to install them. |
277
|
1
|
|
|
|
|
12
|
eval { |
278
|
1
|
|
|
|
|
435
|
require Clone; |
279
|
0
|
|
|
|
|
0
|
Clone->VERSION(0.12); # 0.11 has a bug that breaks Argv |
280
|
0
|
|
|
|
|
0
|
$self = Clone::clone($proto); |
281
|
|
|
|
|
|
|
}; |
282
|
1
|
50
|
|
|
|
25
|
if ($@) { |
283
|
1
|
|
|
|
|
64
|
eval { |
284
|
1
|
|
|
|
|
1333
|
require Storable; |
285
|
1
|
|
|
|
|
4134
|
$self = Storable::dclone($proto); |
286
|
|
|
|
|
|
|
}; |
287
|
|
|
|
|
|
|
} |
288
|
1
|
50
|
|
|
|
4
|
if ($@) { |
289
|
1
|
|
|
|
|
1492
|
require Data::Dumper; |
290
|
|
|
|
|
|
|
# Older Perl versions may not have the XS interface installed, |
291
|
|
|
|
|
|
|
# so try it and fall back to the pure-perl version on failure. |
292
|
1
|
|
|
|
|
6462
|
my $copy = eval { |
293
|
1
|
|
|
|
|
7
|
Data::Dumper->Deepcopy(1)->new([$proto], ['self'])->Dumpxs; |
294
|
|
|
|
|
|
|
}; |
295
|
1
|
50
|
|
|
|
162
|
$copy = Data::Dumper->Deepcopy(1)->new([$proto], ['self'])->Dump |
296
|
|
|
|
|
|
|
if $@; |
297
|
1
|
|
|
|
|
123
|
eval $copy; |
298
|
|
|
|
|
|
|
} |
299
|
1
|
50
|
33
|
|
|
9
|
die $@ if $@ || !$self; |
300
|
|
|
|
|
|
|
# At least some cloners can't clone a code ref... |
301
|
1
|
|
|
|
|
6
|
$self->{PIPECB} = $proto->{PIPECB}; |
302
|
|
|
|
|
|
|
} else { |
303
|
7
|
|
|
|
|
39
|
$self = {}; |
304
|
7
|
50
|
|
|
|
31
|
if ($proto ne __PACKAGE__) { |
305
|
|
|
|
|
|
|
# Inherit class attributes from subclass class attributes. |
306
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
813
|
|
307
|
0
|
|
|
|
|
0
|
for (keys %$proto) { |
308
|
0
|
|
|
|
|
0
|
$self->{$_} = $proto->{$_}; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
7
|
|
|
|
|
41
|
$self->{AV_PROG} = []; |
312
|
7
|
|
|
|
|
35
|
$self->{AV_ARGS} = []; |
313
|
7
|
|
|
|
|
40
|
$self->{PIPECB} = $Argv{PIPECB}; |
314
|
7
|
|
|
|
|
44
|
bless $self, $proto; |
315
|
7
|
|
|
|
|
103
|
$self->optset(''); |
316
|
|
|
|
|
|
|
} |
317
|
8
|
50
|
|
|
|
33
|
$self->attrs($attrs) if $attrs; |
318
|
8
|
100
|
|
|
|
78
|
$self->argv(@_) if @_; |
319
|
8
|
|
|
|
|
49
|
return $self; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
*clone = \&new; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Nothing to do here, just avoiding interaction with AUTOLOAD. |
324
|
0
|
|
|
0
|
|
0
|
sub DESTROY { } |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub AUTOLOAD { |
327
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
328
|
0
|
|
|
|
|
0
|
(my $cmd = $Argv::AUTOLOAD) =~ s/.*:://; |
329
|
0
|
0
|
|
|
|
0
|
return if $cmd eq 'DESTROY'; |
330
|
1
|
|
|
1
|
|
8
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1034
|
|
331
|
|
|
|
|
|
|
# install a new method '$cmd' to avoid autoload next time ... |
332
|
|
|
|
|
|
|
*$cmd = sub { |
333
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
334
|
0
|
0
|
|
|
|
0
|
if (ref $self) { |
335
|
0
|
|
|
|
|
0
|
$self->argv($cmd, @_); |
336
|
|
|
|
|
|
|
} else { |
337
|
0
|
|
|
|
|
0
|
$self->new($cmd, @_); |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
0
|
}; |
340
|
|
|
|
|
|
|
# ... then service this request |
341
|
0
|
|
|
|
|
0
|
return $self->$cmd(@_); |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Instance methods; most class methods are auto-generated above. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# A shorthand way to set a bunch of attributes by passing a hashref |
347
|
|
|
|
|
|
|
# of their names=>values. |
348
|
|
|
|
|
|
|
sub attrs { |
349
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
350
|
0
|
|
|
|
|
0
|
my $attrs = shift; |
351
|
0
|
0
|
|
|
|
0
|
if ($attrs) { |
352
|
0
|
|
|
|
|
0
|
for my $key (keys %$attrs) { |
353
|
0
|
|
|
|
|
0
|
(my $method = $key) =~ s/^-//; |
354
|
0
|
|
|
|
|
0
|
$self->$method($attrs->{$key}); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
0
|
|
|
|
|
0
|
return $self; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# Replace the instance's prog(), opt(), and args() vectors all together. |
361
|
|
|
|
|
|
|
# Without arguments, return the command as it currently looks either as |
362
|
|
|
|
|
|
|
# a list or a string depending on context. |
363
|
|
|
|
|
|
|
sub argv { |
364
|
8
|
|
|
8
|
1
|
16
|
my $self = shift; |
365
|
8
|
50
|
|
|
|
46
|
if (@_) { |
366
|
8
|
50
|
|
|
|
29
|
$self->attrs(shift) if ref($_[0]) eq 'HASH'; |
367
|
8
|
|
|
|
|
24
|
$self->{AV_PROG} = []; |
368
|
8
|
|
|
|
|
22
|
$self->{AV_OPTS}{''} = []; |
369
|
8
|
|
|
|
|
23
|
$self->{AV_ARGS} = []; |
370
|
8
|
50
|
|
|
|
48
|
$self->prog(shift) if @_; |
371
|
8
|
50
|
|
|
|
28
|
$self->attrs(shift) if ref($_[0]) eq 'HASH'; |
372
|
8
|
100
|
|
|
|
30
|
$self->opts(@{shift @_}) if ref $_[0] eq 'ARRAY'; |
|
2
|
|
|
|
|
21
|
|
373
|
8
|
100
|
|
|
|
44
|
$self->args(@_) if @_; |
374
|
8
|
|
|
|
|
14
|
return $self; |
375
|
|
|
|
|
|
|
} else { |
376
|
0
|
|
|
|
|
0
|
my @cmd = ($self->prog, $self->opts, $self->args); |
377
|
0
|
0
|
|
|
|
0
|
if (wantarray) { |
378
|
0
|
|
|
|
|
0
|
return @cmd; |
379
|
|
|
|
|
|
|
} else { |
380
|
0
|
|
|
|
|
0
|
return "@cmd"; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
*cmd = \&argv; # backward compatibility |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# Set or get the 'prog' part of the command line. |
387
|
|
|
|
|
|
|
sub prog { |
388
|
10
|
|
|
10
|
1
|
36
|
my $self = shift; |
389
|
10
|
100
|
|
|
|
39
|
if (@_) { |
|
|
50
|
|
|
|
|
|
390
|
9
|
50
|
|
|
|
53
|
my @prg = ref $_[0] ? @{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
391
|
9
|
|
|
|
|
18
|
@{$self->{AV_PROG}} = @prg; |
|
9
|
|
|
|
|
31
|
|
392
|
|
|
|
|
|
|
} elsif (!defined(wantarray)) { |
393
|
0
|
|
|
|
|
0
|
@{$self->{AV_PROG}} = (); |
|
0
|
|
|
|
|
0
|
|
394
|
|
|
|
|
|
|
} |
395
|
10
|
100
|
|
|
|
30
|
if (@_) { |
396
|
9
|
|
|
|
|
23
|
return $self; |
397
|
|
|
|
|
|
|
} else { |
398
|
1
|
50
|
|
|
|
11
|
return wantarray ? @{$self->{AV_PROG}} : ${$self->{AV_PROG}}[0]; |
|
1
|
|
|
|
|
18
|
|
|
0
|
|
|
|
|
0
|
|
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# Set or get the 'args' part of the command line. |
403
|
|
|
|
|
|
|
sub args { |
404
|
8
|
|
|
8
|
1
|
19
|
my $self = shift; |
405
|
8
|
100
|
|
|
|
418
|
if (@_) { |
|
|
50
|
|
|
|
|
|
406
|
6
|
50
|
|
|
|
87
|
my @args = ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
407
|
6
|
|
|
|
|
12
|
@{$self->{AV_ARGS}} = @args; |
|
6
|
|
|
|
|
634
|
|
408
|
|
|
|
|
|
|
} elsif (!defined(wantarray)) { |
409
|
0
|
|
|
|
|
0
|
@{$self->{AV_ARGS}} = (); |
|
0
|
|
|
|
|
0
|
|
410
|
|
|
|
|
|
|
} |
411
|
8
|
100
|
|
|
|
21
|
if (@_) { |
412
|
6
|
|
|
|
|
128
|
return $self; |
413
|
|
|
|
|
|
|
} else { |
414
|
2
|
|
|
|
|
5
|
return @{$self->{AV_ARGS}}; |
|
2
|
|
|
|
|
79
|
|
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# Generates the parse(), opts(), and flag() method families. During |
419
|
|
|
|
|
|
|
# construction this is used to generate the methods for the anonymous |
420
|
|
|
|
|
|
|
# option set; it can be used explicitly to generate parseXX(), optsXX(), |
421
|
|
|
|
|
|
|
# and argsXX() for optset 'XX'. |
422
|
|
|
|
|
|
|
sub optset { |
423
|
10
|
|
|
10
|
1
|
24
|
my $self = shift; |
424
|
10
|
|
|
|
|
53
|
for (@_) { |
425
|
11
|
|
|
|
|
76
|
my $set = uc $_; |
426
|
11
|
50
|
|
|
|
663
|
next if defined $self->{AV_OPTS}{$set}; |
427
|
11
|
|
|
|
|
65
|
$self->{AV_OPTS}{$set} = []; |
428
|
11
|
|
|
|
|
92
|
$self->{AV_LKG}{$set} = {}; |
429
|
11
|
|
|
|
|
53
|
my($p_meth, $o_meth, $f_meth) = map { $_ . $set } qw(parse opts flag); |
|
33
|
|
|
|
|
151
|
|
430
|
11
|
|
|
|
|
53
|
$self->{AV_DESC}{$set} = []; |
431
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; # needed to muck with symbol table |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3816
|
|
432
|
|
|
|
|
|
|
*$p_meth = sub { |
433
|
5
|
|
|
5
|
|
42
|
my $self = shift; |
434
|
5
|
|
50
|
|
|
27
|
$self->{AV_DESC}{$set} ||= []; |
435
|
5
|
50
|
|
|
|
18
|
if (@_) { |
436
|
5
|
50
|
|
|
|
28
|
if (ref($_[0]) eq 'ARRAY') { |
|
|
50
|
|
|
|
|
|
437
|
0
|
|
|
|
|
0
|
$self->{CFG}{$set} = shift; |
438
|
|
|
|
|
|
|
} elsif (ref($_[0]) eq 'HASH') { |
439
|
0
|
|
|
|
|
0
|
$self->warning("do not provide a linkage specifier"); |
440
|
0
|
|
|
|
|
0
|
shift; |
441
|
|
|
|
|
|
|
} |
442
|
5
|
|
|
|
|
8
|
@{$self->{AV_DESC}{$set}} = @_; |
|
5
|
|
|
|
|
28
|
|
443
|
5
|
|
|
|
|
66
|
$self->factor($set, |
444
|
|
|
|
|
|
|
$self->{AV_DESC}{$set}, $self->{AV_OPTS}{$set}, |
445
|
|
|
|
|
|
|
$self->{AV_ARGS}, $self->{CFG}{$set}); |
446
|
5
|
50
|
|
|
|
27
|
if (defined $self->{AV_OPTS}{$set}) { |
447
|
5
|
|
|
|
|
9
|
my @parsedout = @{$self->{AV_OPTS}{$set}}; |
|
5
|
|
|
|
|
24
|
|
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
} |
450
|
5
|
|
|
|
|
10
|
return @{$self->{AV_OPTS}{$set}}; |
|
5
|
|
|
|
|
23
|
|
451
|
11
|
100
|
|
|
|
188
|
} unless $Argv::{$p_meth}; |
452
|
|
|
|
|
|
|
*$o_meth = sub { |
453
|
6
|
|
|
6
|
|
48
|
my $self = shift; |
454
|
6
|
|
50
|
|
|
44
|
$self->{AV_OPTS}{$set} ||= []; |
455
|
6
|
100
|
66
|
|
|
93
|
if (@_ || !defined(wantarray)) { |
456
|
2
|
|
|
|
|
4
|
@{$self->{AV_OPTS}{$set}} = @_; |
|
2
|
|
|
|
|
6
|
|
457
|
|
|
|
|
|
|
} |
458
|
6
|
100
|
|
|
|
34
|
return @_ ? $self : @{$self->{AV_OPTS}{$set}}; |
|
4
|
|
|
|
|
98
|
|
459
|
11
|
100
|
|
|
|
90
|
} unless $Argv::{$o_meth}; |
460
|
|
|
|
|
|
|
*$f_meth = sub { |
461
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
462
|
0
|
0
|
|
|
|
0
|
if (@_ > 1) { |
463
|
0
|
|
|
|
|
0
|
while(my($key, $val) = splice(@_, 0, 2)) { |
464
|
0
|
|
|
|
|
0
|
$self->{AV_LKG}{$set}{$key} = $val; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
} else { |
467
|
0
|
|
|
|
|
0
|
my $key = shift; |
468
|
0
|
|
|
|
|
0
|
return $self->{AV_LKG}{$set}{$key}; |
469
|
|
|
|
|
|
|
} |
470
|
11
|
100
|
|
|
|
139
|
} unless $Argv::{$f_meth}; |
471
|
|
|
|
|
|
|
} |
472
|
10
|
|
|
|
|
18
|
return keys %{$self->{AV_DESC}}; # this is the set of known optsets. |
|
10
|
|
|
|
|
72
|
|
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# Not generally used except internally; not documented. First arg |
476
|
|
|
|
|
|
|
# is an option set name followed by bunch of array-refs: a pointer |
477
|
|
|
|
|
|
|
# to a list of Getopt::Long-style option descs, a ref to be filled |
478
|
|
|
|
|
|
|
# in with a list of found options, another containing the input |
479
|
|
|
|
|
|
|
# args and to be filled in with the leftovers, and an optional |
480
|
|
|
|
|
|
|
# one containing Getopt::Long-style config options. |
481
|
|
|
|
|
|
|
sub factor { |
482
|
5
|
|
|
5
|
0
|
11
|
my $self = shift; |
483
|
5
|
|
|
|
|
28
|
my($pset, $r_desc, $r_opts, $r_args, $r_cfg) = @_; |
484
|
5
|
|
|
|
|
12
|
my @vgra; |
485
|
|
|
|
|
|
|
{ |
486
|
5
|
|
|
|
|
8
|
local @ARGV = @$r_args; |
|
5
|
|
|
|
|
31
|
|
487
|
5
|
50
|
33
|
|
|
433
|
if ($r_desc && @$r_desc) { |
488
|
5
|
|
|
|
|
4533
|
require Getopt::Long; |
489
|
|
|
|
|
|
|
# Need this version so Configure() returns prev state. |
490
|
5
|
|
|
|
|
35317
|
Getopt::Long->VERSION(2.23); |
491
|
5
|
50
|
33
|
|
|
244
|
if ($r_cfg && @$r_cfg) { |
492
|
0
|
|
|
|
|
0
|
my $prev = Getopt::Long::Configure(@$r_cfg); |
493
|
0
|
|
|
|
|
0
|
GetOptions($self->{AV_LKG}{$pset}, @$r_desc); |
494
|
0
|
|
|
|
|
0
|
Getopt::Long::Configure($prev); |
495
|
|
|
|
|
|
|
} else { |
496
|
5
|
|
|
|
|
27
|
local $Getopt::Long::passthrough = 1; |
497
|
5
|
|
|
|
|
22
|
local $Getopt::Long::autoabbrev = 1; |
498
|
5
|
50
|
|
|
|
34
|
local $Getopt::Long::debug = 1 if $self->dbglevel == 5; |
499
|
5
|
|
|
|
|
39
|
GetOptions($self->{AV_LKG}{$pset}, @$r_desc); |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
} |
502
|
5
|
|
|
|
|
27
|
@vgra = @ARGV; |
503
|
|
|
|
|
|
|
} |
504
|
5
|
|
|
|
|
9
|
my(@opts, @args); |
505
|
5
|
|
|
|
|
15
|
for (reverse @$r_args) { |
506
|
21
|
100
|
100
|
|
|
110
|
if (@vgra && $vgra[$#vgra] eq $_) { |
507
|
11
|
|
|
|
|
36
|
unshift(@args, pop (@vgra)); |
508
|
|
|
|
|
|
|
} else { |
509
|
10
|
|
|
|
|
28
|
unshift(@opts, $_); |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
} |
512
|
5
|
50
|
|
|
|
26
|
@$r_opts = @opts if $r_opts; |
513
|
5
|
|
|
|
|
16
|
@$r_args = @args; |
514
|
5
|
|
|
|
|
18
|
return @opts; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
# Extract and return any of the specified options from object. |
518
|
|
|
|
|
|
|
sub extract { |
519
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
520
|
0
|
|
|
|
|
0
|
my $set = shift; |
521
|
0
|
0
|
|
|
|
0
|
$self->optset($set) unless defined $self->{AV_LKG}{$set}; |
522
|
0
|
|
|
|
|
0
|
my $p_meth = 'parse' . $set; |
523
|
0
|
|
|
|
|
0
|
my $o_meth = 'opts' . $set; |
524
|
0
|
|
|
|
|
0
|
$self->$p_meth(@_); |
525
|
0
|
|
|
|
|
0
|
my @extracts = $self->$o_meth(); |
526
|
0
|
|
|
|
|
0
|
return @extracts; |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
sub argpathnorm { |
530
|
10
|
|
|
10
|
0
|
150
|
my $self = shift; |
531
|
10
|
|
|
|
|
41
|
my $norm = $self->inpathnorm; |
532
|
10
|
50
|
33
|
|
|
38
|
return unless $norm && !ref($norm); |
533
|
0
|
|
|
|
|
0
|
if (CYGWIN) { #for the cygwin shell |
534
|
|
|
|
|
|
|
s%\\%\\\\%g for @_; |
535
|
|
|
|
|
|
|
} |
536
|
0
|
|
|
|
|
0
|
return unless MSWIN; |
537
|
0
|
|
|
|
|
0
|
for my $word (@_) { |
538
|
|
|
|
|
|
|
# If requested, change / for \ in Windows file paths. |
539
|
|
|
|
|
|
|
# This is necessarily an inexact science. |
540
|
0
|
|
|
|
|
0
|
my @fragments = split ' ', $word; |
541
|
0
|
|
|
|
|
0
|
for (@fragments) { |
542
|
0
|
0
|
|
|
|
0
|
if (m%^"?/%) { |
543
|
0
|
0
|
|
|
|
0
|
if (m%(.*/\w+):(.+)%) { |
544
|
|
|
|
|
|
|
# If it looks like an option specifying a path (/opt:path), |
545
|
|
|
|
|
|
|
# normalize only the path part. |
546
|
0
|
|
|
|
|
0
|
my($opt, $path) = ($1, $2); |
547
|
0
|
|
|
|
|
0
|
$path =~ s%/%\\%g; |
548
|
0
|
|
|
|
|
0
|
$_ = "$opt:$path"; |
549
|
|
|
|
|
|
|
} else { |
550
|
|
|
|
|
|
|
# If it contains a slash (any kind) after the initial one |
551
|
|
|
|
|
|
|
# treat it as a full path. This is where you get into |
552
|
|
|
|
|
|
|
# ambiguity with combined options (e.g. /E/I/Q/S) which |
553
|
|
|
|
|
|
|
# could technically be a path. So that's just not allowed |
554
|
|
|
|
|
|
|
# when path-norming. |
555
|
0
|
|
|
|
|
0
|
my $slashes = tr/\/\\//; |
556
|
0
|
0
|
|
|
|
0
|
s%/%\\%g if $slashes > 1; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
} else { |
559
|
0
|
|
|
|
|
0
|
s%/%\\%g; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
} |
562
|
0
|
|
|
|
|
0
|
$word = "@fragments"; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# Quotes @_ in place against shell expansion. Usually called via autoquote attr |
567
|
|
|
|
|
|
|
sub quote { |
568
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
569
|
1
|
|
|
|
|
10
|
for (grep {defined} @_) { |
|
2
|
|
|
|
|
9
|
|
570
|
|
|
|
|
|
|
# Hack - allow user to exempt any arg from quoting by prefixing '^'. |
571
|
2
|
50
|
|
|
|
10
|
next if s%^\^%%; |
572
|
|
|
|
|
|
|
# Special case - turn internal newlines back to literal \n on Win32 |
573
|
2
|
|
|
|
|
4
|
s%\n%\\n%gs if MSWIN; |
574
|
|
|
|
|
|
|
# If arg is already quoted with '': on Unix it's safe, leave alone. |
575
|
|
|
|
|
|
|
# On Windows, replace the single quotes with escaped double quotes. |
576
|
2
|
50
|
|
|
|
17
|
if (m%^'(.*)'$%s) { |
|
|
50
|
|
|
|
|
|
577
|
0
|
|
|
|
|
0
|
$_ = qq(\\"$1\\") if MSWIN; |
578
|
0
|
|
|
|
|
0
|
next; |
579
|
|
|
|
|
|
|
} elsif (m%^".*"$%s) { |
580
|
0
|
|
|
|
|
0
|
$_ = qq(\\"$_\\") if MSWIN || CYGWIN; |
581
|
0
|
|
|
|
|
0
|
next; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
# Skip if contains no special chars. |
584
|
2
|
|
|
|
|
3
|
if (MSWIN) { |
585
|
|
|
|
|
|
|
# On windows globbing is not handled by the shell so we |
586
|
|
|
|
|
|
|
# let '*' go by. |
587
|
|
|
|
|
|
|
next unless m%[^-=:_."\w\\/*]% || tr%\n%%; |
588
|
|
|
|
|
|
|
} else { |
589
|
2
|
50
|
33
|
|
|
58
|
next unless m%[^-=:_."\w\\/]% || m%\\n% || tr%\n%%; |
|
|
|
33
|
|
|
|
|
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
# Special case - leave things that look like redirections alone. |
592
|
0
|
0
|
|
|
|
0
|
next if /^\d?(?:<{1,2})|(?:>{1,2})/; |
593
|
|
|
|
|
|
|
# This is a hack to support MKS-built perl 5.004. Don't know |
594
|
|
|
|
|
|
|
# if the problem is with MKS builds or 5.004 per se. |
595
|
0
|
|
|
|
|
0
|
next if MSWIN && $] < 5.005; |
596
|
|
|
|
|
|
|
# Now quote embedded quotes ... |
597
|
0
|
|
|
|
|
0
|
$_ =~ s%(\\*)"%$1$1\\"%g; |
598
|
|
|
|
|
|
|
# quote a trailing \ so it won't quote the quote (!) ... |
599
|
0
|
|
|
|
|
0
|
s%\\{1}$%\\\\%; |
600
|
|
|
|
|
|
|
# and last the entire string. |
601
|
0
|
|
|
|
|
0
|
$_ = qq("$_"); |
602
|
|
|
|
|
|
|
} |
603
|
1
|
|
|
|
|
4
|
return $self; |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# Submits @_ to Perl's glob() function. Usually invoked via autoglob attr. |
607
|
|
|
|
|
|
|
sub glob { |
608
|
1
|
|
|
1
|
1
|
13
|
my $self = shift; |
609
|
1
|
50
|
|
|
|
35
|
my @orig = @_ ? @_ : $self->args; |
610
|
1
|
50
|
|
|
|
5
|
if (! @orig) { |
611
|
0
|
|
|
|
|
0
|
$self->warning("no arguments to glob"); |
612
|
0
|
|
|
|
|
0
|
return 0; |
613
|
|
|
|
|
|
|
} |
614
|
1
|
|
|
|
|
5
|
my @globbed; |
615
|
1
|
|
|
|
|
3
|
for (@orig) { |
616
|
1
|
50
|
|
|
|
62
|
if (/^'(.*)'$/) { # allow '' to escape globbing |
|
|
50
|
|
|
|
|
|
617
|
0
|
|
|
|
|
0
|
push(@globbed, $1); |
618
|
|
|
|
|
|
|
} elsif (/[*?]/) { |
619
|
1
|
|
|
|
|
4950
|
push(@globbed, glob) |
620
|
|
|
|
|
|
|
} else { |
621
|
0
|
|
|
|
|
0
|
push(@globbed, $_) |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
} |
624
|
1
|
50
|
|
|
|
9
|
if (defined wantarray) { |
625
|
0
|
|
|
|
|
0
|
return @globbed; |
626
|
|
|
|
|
|
|
} else { |
627
|
1
|
|
|
|
|
10
|
$self->args(@globbed); |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# Internal. Takes a list of optset names, returns a list of options. |
632
|
|
|
|
|
|
|
sub _sets2opts { |
633
|
11
|
|
|
11
|
|
17
|
my $self = shift; |
634
|
11
|
|
|
|
|
16
|
my(@sets, @opts); |
635
|
11
|
100
|
|
|
|
48
|
if (! @_) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
636
|
8
|
|
|
|
|
12
|
@sets = keys %{$self->dfltsets}; |
|
8
|
|
|
|
|
47
|
|
637
|
|
|
|
|
|
|
} elsif ($_[0] eq '-') { |
638
|
2
|
|
|
|
|
6
|
@sets = (); |
639
|
|
|
|
|
|
|
} elsif ($_[0] eq '+') { |
640
|
0
|
|
|
|
|
0
|
@sets = $self->optset; |
641
|
|
|
|
|
|
|
} else { |
642
|
1
|
|
|
|
|
4
|
my %known = map {$_ => 1} $self->optset; |
|
1
|
|
|
|
|
11
|
|
643
|
1
|
50
|
|
|
|
3
|
for (@_) { $self->warning("Unknown optset '$_'\n") if !$known{$_} } |
|
1
|
|
|
|
|
8
|
|
644
|
1
|
|
|
|
|
5
|
@sets = @_; |
645
|
|
|
|
|
|
|
} |
646
|
11
|
|
|
|
|
60
|
for my $set (@sets) { |
647
|
9
|
100
|
100
|
|
|
167
|
next unless $self->{AV_OPTS}{$set} && @{$self->{AV_OPTS}{$set}}; |
|
8
|
|
|
|
|
55
|
|
648
|
2
|
|
|
|
|
9
|
push(@opts, @{$self->{AV_OPTS}{$set}}); |
|
2
|
|
|
|
|
10
|
|
649
|
|
|
|
|
|
|
} |
650
|
11
|
|
|
|
|
290
|
return @opts; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# Internal, collects data for use by 'summary' method. |
654
|
|
|
|
|
|
|
sub _addstats { |
655
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
656
|
0
|
|
|
|
|
0
|
my($prg, $argcnt) = @_; |
657
|
0
|
|
0
|
|
|
0
|
my $stats = $Argv::Summary->{$prg} || [0, 0]; |
658
|
0
|
|
|
|
|
0
|
$$stats[0]++; |
659
|
0
|
|
|
|
|
0
|
$$stats[1] += $argcnt; |
660
|
0
|
|
|
|
|
0
|
$Argv::Summary->{$prg} = $stats; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
# Handles ->autofail operations. If given a scalar, exit with the value |
664
|
|
|
|
|
|
|
# of that scalar on failure unless the scalar == 0, in which case |
665
|
|
|
|
|
|
|
# don't exit. If given a ref to a scalar, increment the scalar for |
666
|
|
|
|
|
|
|
# each failure. If given a code ref, call that subroutine. An array ref |
667
|
|
|
|
|
|
|
# is assumed to contain a code ref followed by parameters for the sub. |
668
|
|
|
|
|
|
|
sub fail { |
669
|
2
|
|
|
2
|
0
|
8
|
my($self, $specific) = @_; |
670
|
2
|
|
|
|
|
32
|
my $general = $self->autofail; |
671
|
2
|
100
|
66
|
|
|
58
|
if (my $val = $specific || $general) { |
672
|
1
|
50
|
|
|
|
18
|
if (ref($val) eq 'CODE') { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
673
|
0
|
|
|
|
|
0
|
&$val($self); |
674
|
|
|
|
|
|
|
} elsif (ref($val) eq 'ARRAY') { |
675
|
1
|
|
|
|
|
14
|
my @arr = @$val; |
676
|
1
|
|
|
|
|
7
|
my $func = shift(@arr); |
677
|
1
|
|
|
|
|
57
|
&$func(@arr); |
678
|
|
|
|
|
|
|
} elsif (ref($val) eq 'SCALAR') { |
679
|
0
|
|
|
|
|
0
|
$$val++; |
680
|
|
|
|
|
|
|
} elsif ($val !~ /^\d*$/) { |
681
|
0
|
|
|
|
|
0
|
die $val; |
682
|
|
|
|
|
|
|
} elsif ($val) { |
683
|
0
|
|
|
|
|
0
|
exit $val; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
} |
686
|
2
|
|
|
|
|
61
|
return $self; |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
# Convert lines to UNIX (/) format iff they represent file pathnames. |
690
|
|
|
|
|
|
|
sub unixpath { |
691
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
692
|
0
|
|
|
|
|
0
|
for (@_) { |
693
|
0
|
|
|
|
|
0
|
chomp(my $chomped = $_); |
694
|
0
|
0
|
|
|
|
0
|
s%\\%/%g if -e $chomped; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# A no-op except it prints the current state of the object to stderr. |
699
|
|
|
|
|
|
|
sub objdump { |
700
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
701
|
0
|
|
0
|
|
|
0
|
(my $obj = shift || 'argv') =~ s%^\$%%; |
702
|
0
|
|
|
|
|
0
|
require Data::Dumper; |
703
|
0
|
|
|
|
|
0
|
print STDERR Data::Dumper->new([$self], [$obj])->Dumpxs; |
704
|
0
|
|
|
|
|
0
|
return $self; |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
sub readonly { |
708
|
2
|
|
|
2
|
1
|
6
|
my $self = shift; |
709
|
1
|
|
|
1
|
|
11
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1509
|
|
710
|
2
|
50
|
|
|
|
22
|
if (@_) { |
711
|
0
|
|
|
|
|
0
|
$self->{AV_READONLY} = shift; |
712
|
0
|
|
|
|
|
0
|
return $self; |
713
|
|
|
|
|
|
|
} else { |
714
|
2
|
50
|
|
|
|
16
|
if (exists($self->{AV_READONLY})) { |
715
|
0
|
|
|
|
|
0
|
return $self->{AV_READONLY}; # instance |
716
|
|
|
|
|
|
|
} else { |
717
|
2
|
|
|
|
|
7
|
my $class = ref $self; |
718
|
2
|
50
|
33
|
|
|
45
|
if ($class && exists($class->{AV_READONLY})) { |
719
|
0
|
|
|
|
|
0
|
return $class->{AV_READONLY}; # class |
720
|
|
|
|
|
|
|
} else { |
721
|
2
|
|
|
|
|
67
|
return 'no'; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
sub _read_only { |
728
|
2
|
|
|
2
|
|
23
|
my $self = shift; |
729
|
2
|
|
|
|
|
23
|
return $self->readonly =~ /^y/i; |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# Hidden method for printing debug output. |
733
|
|
|
|
|
|
|
sub _dbg { |
734
|
4
|
|
|
4
|
|
19
|
my $self = shift; |
735
|
4
|
|
|
|
|
64
|
my($level, $prefix, $fh, @txt) = @_; |
736
|
4
|
|
|
|
|
42
|
my @tmp = @txt; |
737
|
4
|
50
|
33
|
|
|
56
|
for (@tmp) { $_ = qq("$_") if /\s/ && !/^"/ } |
|
8
|
|
|
|
|
66
|
|
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
# Print all EV's that were added to or modified from the real env. |
740
|
4
|
|
|
|
|
22
|
my $envp = $self->envp; |
741
|
4
|
50
|
|
|
|
17
|
if ($envp) { |
742
|
0
|
|
|
|
|
0
|
for (sort keys %$envp) { |
743
|
0
|
0
|
0
|
|
|
0
|
next if $ENV{$_} && $ENV{$_} eq $envp->{$_}; |
744
|
0
|
|
|
|
|
0
|
print $fh "+ [\$$_=", $envp->{$_}, "]\n"; |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
|
748
|
4
|
50
|
|
|
|
16
|
$self->objdump if $level >= 3; |
749
|
4
|
|
|
|
|
25
|
my($ifd, $ofd, $efd) = ($self->stdin, $self->stdout, $self->stderr); |
750
|
4
|
50
|
|
|
|
53
|
if ($ifd !~ m%^[\d-]*$%) { |
|
|
50
|
|
|
|
|
|
751
|
0
|
|
|
|
|
0
|
$ifd =~ s%/%\\%g if MSWIN; |
752
|
0
|
|
|
|
|
0
|
push(@tmp, $ifd); |
753
|
|
|
|
|
|
|
} elsif ($ifd < 0) { |
754
|
0
|
|
|
|
|
0
|
push(@tmp, "<$NUL"); |
755
|
|
|
|
|
|
|
} |
756
|
4
|
50
|
|
|
|
93
|
if ($ofd !~ m%^[\d-]*$%) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
757
|
0
|
|
|
|
|
0
|
$ofd =~ s%/%\\%g if MSWIN; |
758
|
0
|
|
|
|
|
0
|
push(@tmp, $ofd); |
759
|
|
|
|
|
|
|
} elsif ($ofd <= 0) { |
760
|
1
|
|
|
|
|
8
|
push(@tmp, "1>$NUL"); |
761
|
|
|
|
|
|
|
} elsif ($ofd != 1) { |
762
|
0
|
|
|
|
|
0
|
push(@tmp, "1>&$ofd"); |
763
|
|
|
|
|
|
|
} |
764
|
4
|
50
|
|
|
|
106
|
if ($efd !~ m%^[\d-]*$%) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
765
|
0
|
|
|
|
|
0
|
$efd =~ s%/%\\%g if MSWIN; |
766
|
0
|
|
|
|
|
0
|
push(@tmp, "2$efd"); |
767
|
|
|
|
|
|
|
} elsif ($efd <= 0) { |
768
|
0
|
|
|
|
|
0
|
push(@tmp, "2>$NUL"); |
769
|
|
|
|
|
|
|
} elsif ($efd != 2) { |
770
|
0
|
|
|
|
|
0
|
push(@tmp, "2>&$efd"); |
771
|
|
|
|
|
|
|
} |
772
|
4
|
|
|
|
|
521
|
print $fh "$prefix @tmp\n"; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# Attempt to derive the value of ARG_MAX (the maximum command-line |
776
|
|
|
|
|
|
|
# length) for the current platform. Windows isn't really POSIX and |
777
|
|
|
|
|
|
|
# in my tests POSIX::ARG_MAX() usually throws an exception. |
778
|
|
|
|
|
|
|
# Therefore, on Windows we catch the exception and set the value |
779
|
|
|
|
|
|
|
# to 32767. I don't know what the actual limit is but 32K seems to |
780
|
|
|
|
|
|
|
# work whereas 64K fails and I haven't tried to narrow that range |
781
|
|
|
|
|
|
|
# (actually a bit of subsequent testing showed 48000 to work and |
782
|
|
|
|
|
|
|
# 50000 to fail, but I still prefer to depend on a round number). |
783
|
|
|
|
|
|
|
# On other platforms, if ARG_MAX is missing we use _POSIX_ARG_MAX |
784
|
|
|
|
|
|
|
# (4096) # as the default (that being the smallest value of ARG_MAX |
785
|
|
|
|
|
|
|
# allowed by the POSIX standard). |
786
|
|
|
|
|
|
|
{ |
787
|
|
|
|
|
|
|
my($_argmax, $_pathmax); |
788
|
|
|
|
|
|
|
sub _arg_max { |
789
|
1
|
|
|
1
|
|
23
|
require Config; |
790
|
1
|
50
|
|
|
|
5
|
if (!defined($_argmax)) { |
791
|
1
|
|
|
|
|
6
|
$_argmax = MSWIN ? 32767 : 4096; |
792
|
1
|
|
|
|
|
8
|
eval { require POSIX; $_argmax = POSIX::ARG_MAX(); }; |
|
1
|
|
|
|
|
1269
|
|
|
1
|
|
|
|
|
8717
|
|
793
|
|
|
|
|
|
|
# The terminating NULL of argv. |
794
|
1
|
|
|
|
|
945
|
$_argmax -= $Config::Config{ptrsize}; |
795
|
|
|
|
|
|
|
} |
796
|
1
|
|
|
|
|
3196
|
return $_argmax; |
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
sub _path_max { |
799
|
2
|
100
|
|
2
|
|
7
|
if (!defined($_pathmax)) { |
800
|
1
|
|
|
|
|
2
|
$_pathmax = MSWIN ? 260 : 1024; |
801
|
1
|
|
|
|
|
4
|
eval { require POSIX; $_pathmax = POSIX::PATH_MAX(); }; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
5
|
|
802
|
|
|
|
|
|
|
} |
803
|
2
|
|
|
|
|
5
|
return $_pathmax; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
# Determine the size of the environment block for subtraction |
808
|
|
|
|
|
|
|
# from the calculated value of ARG_MAX. We allow for an equals |
809
|
|
|
|
|
|
|
# sign and terminating null in each EV, plus the pointer |
810
|
|
|
|
|
|
|
# within the environ array that references it. |
811
|
|
|
|
|
|
|
# Note: Windows limits do not appear to include the environment block. |
812
|
|
|
|
|
|
|
sub _env_size { |
813
|
1
|
|
|
1
|
|
11
|
require Config; |
814
|
1
|
|
|
|
|
2
|
my $envlen = 0; |
815
|
1
|
|
|
|
|
12
|
my $ptrsize = $Config::Config{ptrsize}; |
816
|
1
|
|
|
|
|
22
|
for my $ev (keys %ENV) { |
817
|
19
|
|
|
|
|
21
|
$envlen += length($ev); |
818
|
19
|
100
|
|
|
|
46
|
$envlen += length($ENV{$ev}) if $ENV{$ev}; |
819
|
19
|
|
|
|
|
33
|
$envlen += 2 + $ptrsize; |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
# Need one more pointer's worth for the terminating NULL in 'environ'. |
822
|
1
|
|
|
|
|
6
|
return $envlen + $ptrsize; |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# In the case where the user wants to do qxargs-style chunking by |
826
|
|
|
|
|
|
|
# buffer length rather than argument count, we need to keep pushing |
827
|
|
|
|
|
|
|
# args onto said buffer till we run out of room. |
828
|
|
|
|
|
|
|
sub _chunk_by_length { |
829
|
0
|
|
|
0
|
|
0
|
require Config; |
830
|
0
|
|
|
|
|
0
|
my ($args, $max) = @_; |
831
|
0
|
|
|
|
|
0
|
my @chunk = (); |
832
|
0
|
|
|
|
|
0
|
my $chunklen = 0; |
833
|
0
|
|
|
|
|
0
|
my $extra = $Config::Config{ptrsize} + 1; |
834
|
0
|
|
|
|
|
0
|
while (grep {defined} @{$args}) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
835
|
|
|
|
|
|
|
# Reached max length? |
836
|
0
|
0
|
|
|
|
0
|
if (($chunklen + length(${$args}[0]) + $extra) >= $max) { |
|
0
|
|
|
|
|
0
|
|
837
|
|
|
|
|
|
|
# Always send at least one chunk no matter what. |
838
|
0
|
0
|
|
|
|
0
|
push(@chunk, shift(@{$args})) unless @chunk; |
|
0
|
|
|
|
|
0
|
|
839
|
0
|
|
|
|
|
0
|
last; |
840
|
|
|
|
|
|
|
} else { |
841
|
0
|
|
|
|
|
0
|
$chunklen += length(${$args}[0]) + $extra; |
|
0
|
|
|
|
|
0
|
|
842
|
0
|
|
|
|
|
0
|
push(@chunk, shift(@{$args})); |
|
0
|
|
|
|
|
0
|
|
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
#printf STDERR "CHUNK: $chunklen (MAX=$max, LEFT=%d)\n", scalar(@{$args}); |
846
|
0
|
|
|
|
|
0
|
return @chunk; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
# Wrapper around Perl's exec(). Strawberry Perl 5.12 warns... |
850
|
1
|
|
|
1
|
|
7
|
{ no warnings 'redefine'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6767
|
|
851
|
|
|
|
|
|
|
sub exec { |
852
|
1
|
50
|
33
|
1
|
1
|
35
|
$class->new(@_)->exec if !ref($_[0]) || ref($_[0]) eq 'HASH'; |
853
|
1
|
|
|
|
|
3
|
my $self = shift; |
854
|
1
|
50
|
33
|
|
|
14
|
if ((ref($self) ne $class) && $self->ipc_childsafe) { |
855
|
0
|
|
0
|
|
|
0
|
exit($self->system(@_) || $self->ipc_childsafe->finish); |
856
|
|
|
|
|
|
|
} elsif (MSWIN && $self->execwait) { |
857
|
|
|
|
|
|
|
exit($self->system(@_) >> 8); |
858
|
|
|
|
|
|
|
} else { |
859
|
1
|
|
|
|
|
6
|
my $envp = $self->envp; |
860
|
1
|
|
|
|
|
10
|
my $dbg = $self->dbglevel; |
861
|
1
|
|
|
|
|
27
|
my @cmd = (@{$self->{AV_PROG}}, |
|
1
|
|
|
|
|
11
|
|
862
|
1
|
|
|
|
|
8
|
$self->_sets2opts(@_), @{$self->{AV_ARGS}}); |
863
|
1
|
50
|
33
|
|
|
15
|
if ($self->noexec && !$self->_read_only) { |
864
|
1
|
|
|
|
|
18
|
$self->_dbg($dbg, '-', \*STDERR, @cmd); |
865
|
|
|
|
|
|
|
} else { |
866
|
0
|
|
|
|
|
0
|
my($ifd, $ofd, $efd) = ($self->stdin, $self->stdout, $self->stderr); |
867
|
0
|
0
|
|
|
|
0
|
$self->_dbg($dbg, '+', \*STDERR, @cmd) if $dbg; |
868
|
0
|
|
|
|
|
0
|
open(_I, '<&STDIN'); |
869
|
0
|
|
|
|
|
0
|
open(_O, '>&STDOUT'); |
870
|
0
|
|
|
|
|
0
|
open(_E, '>&STDERR'); |
871
|
0
|
0
|
|
|
|
0
|
if ($ifd !~ m%^[\d-]*$%) { |
|
|
0
|
|
|
|
|
|
872
|
0
|
0
|
|
|
|
0
|
open(STDIN, $ifd) || warn "$ifd: $!"; |
873
|
|
|
|
|
|
|
} elsif ($ifd < 0) { |
874
|
0
|
0
|
|
|
|
0
|
open(STDIN, "<$NUL") || warn "STDIN: $!"; |
875
|
|
|
|
|
|
|
} else { |
876
|
0
|
0
|
|
|
|
0
|
warn "Warning: illegal value '$ifd' for stdin" if $ifd > 0; |
877
|
|
|
|
|
|
|
} |
878
|
0
|
0
|
0
|
|
|
0
|
if ($ofd !~ m%^[\d-]*$% && !$self->quiet) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
879
|
0
|
0
|
|
|
|
0
|
open(STDOUT, $ofd) || warn "$ofd: $!"; |
880
|
|
|
|
|
|
|
} elsif ($ofd <= 0 || $self->quiet) { |
881
|
0
|
0
|
|
|
|
0
|
open(STDOUT, ">$NUL") || warn "STDOUT: $!"; |
882
|
|
|
|
|
|
|
} elsif ($ofd == 2) { |
883
|
0
|
0
|
|
|
|
0
|
open(STDOUT, '>&STDERR') || warn "Can't dup stdout"; |
884
|
|
|
|
|
|
|
} elsif ($ofd != 1) { |
885
|
0
|
|
|
|
|
0
|
warn "Warning: illegal value '$ofd' for stdout"; |
886
|
|
|
|
|
|
|
} |
887
|
0
|
0
|
|
|
|
0
|
if ($efd !~ m%^[\d-]*$%) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
888
|
0
|
0
|
|
|
|
0
|
open(STDERR, $efd) || warn "$efd: $!"; |
889
|
|
|
|
|
|
|
} elsif ($efd <= 0) { |
890
|
0
|
0
|
|
|
|
0
|
open(STDERR, ">$NUL") || warn "STDERR: $!"; |
891
|
|
|
|
|
|
|
} elsif ($efd == 1) { |
892
|
0
|
0
|
|
|
|
0
|
open(STDERR, '>&STDOUT') || warn "Can't dup stderr"; |
893
|
|
|
|
|
|
|
} elsif ($efd > 2) { |
894
|
0
|
|
|
|
|
0
|
warn "Warning: illegal value '$efd' for stderr"; |
895
|
|
|
|
|
|
|
} |
896
|
0
|
|
|
|
|
0
|
my $rc; |
897
|
0
|
0
|
|
|
|
0
|
if ($envp) { |
898
|
0
|
|
|
|
|
0
|
local %ENV = %$envp; |
899
|
0
|
|
|
|
|
0
|
$rc = exec(@cmd); |
900
|
|
|
|
|
|
|
} else { |
901
|
0
|
|
|
|
|
0
|
$rc = exec(@cmd); |
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
# Shouldn't get here but defensive programming and all that ... |
904
|
0
|
0
|
|
|
|
0
|
if ($rc) { |
905
|
0
|
|
|
|
|
0
|
my $error = "$!"; |
906
|
0
|
|
|
|
|
0
|
open(STDIN, '<&_I'); close(_I); |
|
0
|
|
|
|
|
0
|
|
907
|
0
|
|
|
|
|
0
|
open(STDOUT, '>&_O'); close(_O); |
|
0
|
|
|
|
|
0
|
|
908
|
0
|
|
|
|
|
0
|
open(STDERR, '>&_E'); close(_E); |
|
0
|
|
|
|
|
0
|
|
909
|
0
|
|
|
|
|
0
|
die "$0: $cmd[0]: $error\n"; |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
} |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
}} |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
sub lastresults { |
916
|
2
|
|
|
2
|
1
|
21
|
my $self = shift; |
917
|
2
|
50
|
|
|
|
169
|
if (defined(wantarray)) { |
918
|
0
|
|
|
|
|
0
|
my @qxarr = @{$self->{AV_LASTRESULTS}}; |
|
0
|
|
|
|
|
0
|
|
919
|
0
|
|
|
|
|
0
|
my $rc = shift @qxarr; |
920
|
0
|
0
|
|
|
|
0
|
if (wantarray) { |
921
|
0
|
|
|
|
|
0
|
return @qxarr; |
922
|
|
|
|
|
|
|
} else { |
923
|
0
|
|
|
|
|
0
|
return $rc; |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
} else { |
926
|
2
|
|
|
|
|
44
|
$self->{AV_LASTRESULTS} = \@_; |
927
|
|
|
|
|
|
|
} |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
# Internal - service method for system/exec to call into IPC::ChildSafe. |
931
|
|
|
|
|
|
|
sub _ipccmd { |
932
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
933
|
0
|
|
|
|
|
0
|
my $cmd = shift; |
934
|
|
|
|
|
|
|
# Throw out the prog name since it's already running |
935
|
0
|
0
|
|
|
|
0
|
if (@_) { |
936
|
0
|
|
|
|
|
0
|
$cmd = "@_"; |
937
|
|
|
|
|
|
|
} else { |
938
|
0
|
|
|
|
|
0
|
$cmd =~ s/^\w+\s*//; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
# Hack - there's an "impedance mismatch" between instance |
941
|
|
|
|
|
|
|
# methods in this class and the class methods in |
942
|
|
|
|
|
|
|
# IPC::ChildSafe, so we toggle the attrs for every cmd. |
943
|
0
|
|
|
|
|
0
|
my $csobj = $self->ipc_childsafe; |
944
|
0
|
|
|
|
|
0
|
$csobj->dbglevel($self->dbglevel); |
945
|
0
|
0
|
0
|
|
|
0
|
$csobj->noexec($self->noexec) if $self->noexec && !$self->_read_only; |
946
|
0
|
|
|
|
|
0
|
my %results = $csobj->cmd($cmd); |
947
|
0
|
|
|
|
|
0
|
return %results; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
# Wrapper around Perl's system(). |
951
|
|
|
|
|
|
|
sub system { |
952
|
9
|
50
|
33
|
9
|
1
|
352
|
return $class->new(@_)->system if !ref($_[0]) || ref($_[0]) eq 'HASH'; |
953
|
9
|
|
|
|
|
12
|
my $self = shift; |
954
|
9
|
|
|
|
|
50
|
my $envp = $self->envp; |
955
|
9
|
|
|
|
|
17
|
my $rc = 0; |
956
|
9
|
|
|
|
|
78
|
my($ifd, $ofd, $efd) = ($self->stdin, $self->stdout, $self->stderr); |
957
|
9
|
50
|
|
|
|
36
|
$self->args($self->glob) if $self->autoglob; |
958
|
9
|
|
|
|
|
11
|
my @prog = @{$self->{AV_PROG}}; |
|
9
|
|
|
|
|
34
|
|
959
|
9
|
|
|
|
|
75
|
my @opts = $self->_sets2opts(@_); |
960
|
9
|
|
|
|
|
16
|
my @args = @{$self->{AV_ARGS}}; |
|
9
|
|
|
|
|
39
|
|
961
|
9
|
50
|
33
|
|
|
45
|
my $childsafe = ((ref($self) ne $class) && |
962
|
|
|
|
|
|
|
$self->ipc_childsafe && !$self->mustexec) ? 1 : 0; |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# These potentially modify their arguments in place. |
965
|
9
|
|
|
|
|
81
|
$self->argpathnorm(@prog, @args); |
966
|
9
|
50
|
33
|
|
|
26
|
$self->quote(@prog, @opts, @args) |
967
|
|
|
|
|
|
|
if (((MSWIN && (@prog + @opts + @args) > 1) || $childsafe) && |
968
|
|
|
|
|
|
|
$self->autoquote); |
969
|
9
|
|
|
|
|
152
|
my @cmd = (@prog, @opts, @args); |
970
|
9
|
|
|
|
|
37
|
my $dbg = $self->dbglevel; |
971
|
9
|
50
|
|
|
|
20
|
if ($childsafe) { |
972
|
0
|
0
|
|
|
|
0
|
$self->_addstats("@prog", scalar @args) if $Argv::Summary; |
973
|
0
|
0
|
|
|
|
0
|
$self->warning("cannot change \%ENV of child process") if $envp; |
974
|
0
|
0
|
|
|
|
0
|
$self->warning("cannot close stdin of child process") if $ifd; |
975
|
0
|
|
|
|
|
0
|
my %results = $self->_ipccmd(@cmd); |
976
|
0
|
|
|
|
|
0
|
$? = $rc = ($results{status} << 8); |
977
|
0
|
0
|
|
|
|
0
|
if ($self->quiet) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# say nothing |
979
|
|
|
|
|
|
|
} elsif ($ofd !~ m%^[\d-]*$%) { |
980
|
0
|
0
|
|
|
|
0
|
if (open(OFD, $ofd)) { |
981
|
0
|
0
|
|
|
|
0
|
print OFD @{$results{stdout}} if @{$results{stdout}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
982
|
0
|
|
|
|
|
0
|
close OFD; |
983
|
|
|
|
|
|
|
} else { |
984
|
0
|
|
|
|
|
0
|
warn "$ofd: $!"; |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
} elsif ($ofd == 2) { |
987
|
0
|
0
|
|
|
|
0
|
print STDERR @{$results{stdout}} if @{$results{stdout}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
988
|
|
|
|
|
|
|
} else { |
989
|
0
|
0
|
|
|
|
0
|
warn "Warning: illegal value '$ofd' for stdout" if $ofd > 2; |
990
|
0
|
0
|
|
|
|
0
|
print STDOUT @{$results{stdout}} if @{$results{stdout}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
991
|
|
|
|
|
|
|
} |
992
|
0
|
0
|
|
|
|
0
|
if ($efd == 1) { |
|
|
0
|
|
|
|
|
|
993
|
0
|
0
|
|
|
|
0
|
print STDOUT @{$results{stderr}} if @{$results{stderr}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
994
|
|
|
|
|
|
|
} elsif ($efd !~ m%^[\d-]*$%) { |
995
|
0
|
0
|
|
|
|
0
|
if (open(EFD, $efd)) { |
996
|
0
|
0
|
|
|
|
0
|
print EFD @{$results{stderr}} if @{$results{stderr}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
997
|
0
|
|
|
|
|
0
|
close EFD; |
998
|
|
|
|
|
|
|
} else { |
999
|
0
|
|
|
|
|
0
|
warn "$efd: $!"; |
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
} else { |
1002
|
0
|
0
|
|
|
|
0
|
warn "Warning: illegal value '$efd' for stderr" if $efd > 2; |
1003
|
0
|
0
|
|
|
|
0
|
print STDERR @{$results{stderr}} if @{$results{stderr}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1004
|
|
|
|
|
|
|
} |
1005
|
|
|
|
|
|
|
} else { |
1006
|
|
|
|
|
|
|
# Reset to defaults in dbg mode (what's this for?) |
1007
|
9
|
50
|
33
|
|
|
72
|
($ofd, $efd) = (1, 2) if defined($dbg) && $dbg > 2; |
1008
|
9
|
100
|
66
|
|
|
33
|
if ($self->noexec && !$self->_read_only) { |
1009
|
1
|
|
|
|
|
19
|
$self->_dbg($dbg, '-', \*STDERR, @cmd); |
1010
|
1
|
|
|
|
|
8
|
return 0; |
1011
|
|
|
|
|
|
|
} |
1012
|
8
|
|
|
|
|
378
|
open(_I, '<&STDIN'); |
1013
|
8
|
|
|
|
|
114
|
open(_O, '>&STDOUT'); |
1014
|
8
|
|
|
|
|
93
|
open(_E, '>&STDERR'); |
1015
|
|
|
|
|
|
|
|
1016
|
8
|
50
|
|
|
|
356
|
if ($ifd !~ m%^[\d-]*$%) { |
|
|
50
|
|
|
|
|
|
1017
|
0
|
0
|
|
|
|
0
|
open(STDIN, $ifd) || warn "$ifd: $!"; |
1018
|
|
|
|
|
|
|
} elsif ($ifd < 0) { |
1019
|
0
|
0
|
|
|
|
0
|
open(STDIN, "<$NUL") || warn "STDIN: $!"; |
1020
|
|
|
|
|
|
|
} else { |
1021
|
8
|
50
|
|
|
|
23
|
warn "Warning: illegal value '$ifd' for stdin" if $ifd > 0; |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
8
|
50
|
33
|
|
|
103
|
if ($ofd !~ m%^[\d-]*$% && !$self->quiet) { |
|
|
100
|
66
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1025
|
0
|
0
|
|
|
|
0
|
open(STDOUT, $ofd) || warn "$ofd: $!"; |
1026
|
|
|
|
|
|
|
} elsif ($ofd <= 0 || $self->quiet) { |
1027
|
4
|
50
|
|
|
|
247
|
open(STDOUT, ">$NUL") || warn "STDOUT: $!"; |
1028
|
|
|
|
|
|
|
} elsif ($ofd == 2) { |
1029
|
0
|
0
|
|
|
|
0
|
open(STDOUT, '>&STDERR') || warn "Can't dup stdout"; |
1030
|
|
|
|
|
|
|
} elsif ($ofd != 1) { |
1031
|
0
|
|
|
|
|
0
|
warn "Warning: illegal value '$ofd' for stdout"; |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
|
1034
|
8
|
50
|
|
|
|
86
|
if ($efd !~ m%^[\d-]*$%) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1035
|
0
|
0
|
|
|
|
0
|
open(STDERR, $efd) || warn "$efd: $!"; |
1036
|
|
|
|
|
|
|
} elsif ($efd <= 0) { |
1037
|
2
|
50
|
|
|
|
120
|
open(STDERR, ">$NUL") || warn "STDERR: $!"; |
1038
|
|
|
|
|
|
|
} elsif ($efd == 1) { |
1039
|
0
|
0
|
|
|
|
0
|
open(STDERR, '>&STDOUT') || warn "Can't dup stderr"; |
1040
|
|
|
|
|
|
|
} elsif ($efd > 2) { |
1041
|
0
|
|
|
|
|
0
|
warn "Warning: illegal value '$efd' for stderr"; |
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
|
1044
|
8
|
|
|
|
|
50
|
my $limit = $self->syxargs; |
1045
|
8
|
50
|
33
|
|
|
24
|
if ($limit && @args) { |
1046
|
0
|
0
|
|
|
|
0
|
if ($limit == -1) { |
1047
|
0
|
|
|
|
|
0
|
$limit = -_arg_max(); |
1048
|
0
|
|
|
|
|
0
|
$limit += _env_size() if !MSWIN; |
1049
|
|
|
|
|
|
|
# There's no shell used in list-form system() ... |
1050
|
0
|
|
|
|
|
0
|
$limit += _path_max(); # for @prog |
1051
|
0
|
|
|
|
|
0
|
$limit += length("@opts"); |
1052
|
|
|
|
|
|
|
} |
1053
|
0
|
0
|
|
|
|
0
|
while (my @chunk = $limit > 0 ? |
1054
|
|
|
|
|
|
|
splice(@args, 0, $limit) : |
1055
|
|
|
|
|
|
|
_chunk_by_length(\@args, abs($limit))) { |
1056
|
0
|
0
|
|
|
|
0
|
$self->_addstats("@prog", scalar @chunk) if $Argv::Summary; |
1057
|
0
|
|
|
|
|
0
|
@cmd = (@prog, @opts, @chunk); |
1058
|
0
|
0
|
|
|
|
0
|
$self->_dbg($dbg, '+', \*_E, @cmd) if $dbg; |
1059
|
0
|
0
|
|
|
|
0
|
if ($envp) { |
1060
|
0
|
|
|
|
|
0
|
local %ENV = %$envp; |
1061
|
0
|
|
|
|
|
0
|
$rc |= system @cmd; |
1062
|
|
|
|
|
|
|
} else { |
1063
|
0
|
|
|
|
|
0
|
$rc |= system @cmd; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
} else { |
1067
|
8
|
50
|
|
|
|
20
|
$self->_addstats("@prog", scalar @args) if $Argv::Summary; |
1068
|
8
|
100
|
|
|
|
37
|
$self->_dbg($dbg, '+', \*_E, @cmd) if $dbg; |
1069
|
8
|
50
|
|
|
|
318
|
if ($envp) { |
1070
|
0
|
|
|
|
|
0
|
local %ENV = %$envp; |
1071
|
0
|
|
|
|
|
0
|
$rc = system @cmd; |
1072
|
|
|
|
|
|
|
} else { |
1073
|
8
|
|
|
|
|
611974
|
$rc = system @cmd; |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
} |
1076
|
8
|
|
|
|
|
917
|
open(STDIN, '<&_I'); close(_I); |
|
8
|
|
|
|
|
82
|
|
1077
|
8
|
|
|
|
|
333
|
open(STDOUT, '>&_O'); close(_O); |
|
8
|
|
|
|
|
102
|
|
1078
|
8
|
|
|
|
|
173
|
open(STDERR, '>&_E'); close(_E); |
|
8
|
|
|
|
|
1539
|
|
1079
|
|
|
|
|
|
|
} |
1080
|
8
|
50
|
|
|
|
108
|
print STDERR "+ (\$? == $?)\n" if $dbg > 1; |
1081
|
8
|
100
|
|
|
|
117
|
if ($?) { |
1082
|
2
|
|
|
|
|
102
|
$self->lastresults($?>>8, ()); |
1083
|
2
|
|
|
|
|
92
|
$self->fail($self->syfail); |
1084
|
|
|
|
|
|
|
} |
1085
|
8
|
|
|
|
|
1065
|
return $rc; |
1086
|
|
|
|
|
|
|
} |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
# Wrapper around Perl's qx(), aka backquotes. |
1089
|
|
|
|
|
|
|
sub qx { |
1090
|
1
|
50
|
33
|
1
|
1
|
47
|
return $class->new(@_)->qx if !ref($_[0]) || ref($_[0]) eq 'HASH'; |
1091
|
1
|
|
|
|
|
5
|
my $self = shift; |
1092
|
1
|
|
|
|
|
23
|
my $envp = $self->envp; |
1093
|
1
|
|
|
|
|
9
|
my @prog = @{$self->{AV_PROG}}; |
|
1
|
|
|
|
|
10
|
|
1094
|
1
|
|
|
|
|
24
|
my @opts = $self->_sets2opts(@_); |
1095
|
1
|
|
|
|
|
5
|
my @args = @{$self->{AV_ARGS}}; |
|
1
|
|
|
|
|
7
|
|
1096
|
1
|
50
|
33
|
|
|
14
|
my $childsafe = ((ref($self) ne $class) && |
1097
|
|
|
|
|
|
|
$self->ipc_childsafe && !$self->mustexec) ? 1 : 0; |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
# These potentially modify their arguments in place. |
1100
|
1
|
|
|
|
|
1
|
@args = $self->glob(@args) |
1101
|
|
|
|
|
|
|
if MSWIN && $self->autoglob && $childsafe; |
1102
|
1
|
|
|
|
|
12
|
$self->argpathnorm(@prog, @args); |
1103
|
1
|
50
|
33
|
|
|
26
|
$self->quote(@prog, @opts, @args) |
|
|
|
33
|
|
|
|
|
1104
|
|
|
|
|
|
|
if (((@prog + @opts + @args) > 1 || $childsafe) && $self->autoquote); |
1105
|
|
|
|
|
|
|
|
1106
|
1
|
|
|
|
|
6
|
my @cmd = (@prog, @opts, @args); |
1107
|
1
|
|
|
|
|
5
|
my @data; |
1108
|
1
|
|
|
|
|
1
|
my $dbg = 0; |
1109
|
1
|
|
|
|
|
2
|
my $rc = 0; |
1110
|
1
|
|
|
|
|
13
|
my($ifd, $ofd, $efd) = ($self->stdin, $self->stdout, $self->stderr); |
1111
|
1
|
|
33
|
|
|
68
|
my $noexec = $self->noexec && !$self->_read_only; |
1112
|
1
|
50
|
|
|
|
6
|
if ($childsafe) { |
1113
|
0
|
0
|
|
|
|
0
|
$self->_addstats("@prog", scalar @args) if $Argv::Summary; |
1114
|
0
|
0
|
|
|
|
0
|
$self->warning("cannot change \%ENV of child process") if $envp; |
1115
|
0
|
0
|
|
|
|
0
|
$self->warning("cannot close stdin of child process") if $ifd; |
1116
|
0
|
0
|
|
|
|
0
|
if ($noexec) { |
1117
|
0
|
|
|
|
|
0
|
$self->_dbg($dbg, '-', \*STDERR, @cmd); |
1118
|
|
|
|
|
|
|
} else { |
1119
|
0
|
|
|
|
|
0
|
my %results = $self->_ipccmd(@cmd); |
1120
|
0
|
0
|
|
|
|
0
|
if ($ofd <= 0) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
# ignore the results |
1122
|
|
|
|
|
|
|
} elsif ($ofd == 1) { |
1123
|
0
|
|
|
|
|
0
|
push(@data, @{$results{stdout}}); |
|
0
|
|
|
|
|
0
|
|
1124
|
|
|
|
|
|
|
} elsif ($ofd == 2) { |
1125
|
0
|
|
|
|
|
0
|
print STDERR @{$results{stdout}}; |
|
0
|
|
|
|
|
0
|
|
1126
|
|
|
|
|
|
|
} else { |
1127
|
0
|
|
|
|
|
0
|
warn "Warning: illegal value '$ofd' for stdout"; |
1128
|
|
|
|
|
|
|
} |
1129
|
0
|
0
|
|
|
|
0
|
if ($efd == 1) { |
1130
|
0
|
|
|
|
|
0
|
push(@data, @{$results{stderr}}); |
|
0
|
|
|
|
|
0
|
|
1131
|
|
|
|
|
|
|
} else { |
1132
|
0
|
0
|
|
|
|
0
|
print STDERR @{$results{stderr}} if $efd; |
|
0
|
|
|
|
|
0
|
|
1133
|
0
|
0
|
|
|
|
0
|
warn "Warning: illegal value '$efd' for stderr" if $efd > 2; |
1134
|
|
|
|
|
|
|
} |
1135
|
0
|
|
|
|
|
0
|
$? = $rc = $results{status} << 8; |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
} else { |
1138
|
1
|
|
|
|
|
4
|
$dbg = $self->dbglevel; |
1139
|
|
|
|
|
|
|
# Reset to defaults in dbg mode (what's this for?) |
1140
|
1
|
50
|
33
|
|
|
11
|
($ofd, $efd) = (1, 2) if defined($dbg) && $dbg > 2; |
1141
|
1
|
|
|
|
|
11
|
my $limit = $self->qxargs; |
1142
|
1
|
50
|
33
|
|
|
26
|
if ($limit && @args) { |
1143
|
1
|
50
|
|
|
|
5
|
if ($limit == -1) { |
1144
|
1
|
|
|
|
|
10
|
$limit = -_arg_max(); |
1145
|
1
|
|
|
|
|
161
|
$limit += _env_size() if !MSWIN; |
1146
|
1
|
|
|
|
|
6
|
$limit += _path_max(); # for the shell |
1147
|
1
|
|
|
|
|
3
|
$limit += length('-c'); |
1148
|
1
|
|
|
|
|
4
|
$limit += _path_max(); # for @prog |
1149
|
1
|
|
|
|
|
5
|
$limit += length("@opts"); |
1150
|
|
|
|
|
|
|
} |
1151
|
1
|
50
|
|
|
|
13
|
while (my @chunk = $limit > 0 ? |
1152
|
|
|
|
|
|
|
splice(@args, 0, $limit) : |
1153
|
|
|
|
|
|
|
_chunk_by_length(\@args, abs($limit))) { |
1154
|
1
|
50
|
|
|
|
6
|
$self->_addstats("@prog", scalar @chunk) if $Argv::Summary; |
1155
|
1
|
|
|
|
|
6
|
@cmd = (@prog, @opts, @chunk); |
1156
|
1
|
50
|
|
|
|
4
|
if ($noexec) { |
1157
|
0
|
|
|
|
|
0
|
$self->_dbg($dbg, '-', \*STDERR, @cmd); |
1158
|
|
|
|
|
|
|
} else { |
1159
|
1
|
50
|
|
|
|
7
|
$self->_dbg($dbg, '+', \*STDERR, @cmd) if $dbg; |
1160
|
1
|
|
|
|
|
12
|
$self->_qx_stderr(\@cmd, $efd); |
1161
|
1
|
|
|
|
|
5
|
$self->_qx_stdout(\@cmd, $ofd); |
1162
|
1
|
50
|
|
|
|
4
|
if ($envp) { |
1163
|
0
|
|
|
|
|
0
|
local %ENV = %$envp; |
1164
|
0
|
|
|
|
|
0
|
push(@data, qx(@cmd)); |
1165
|
|
|
|
|
|
|
} else { |
1166
|
1
|
|
|
|
|
623152
|
push(@data, qx(@cmd)); |
1167
|
|
|
|
|
|
|
} |
1168
|
1
|
|
33
|
|
|
84
|
$rc ||= $?; |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
} else { |
1172
|
0
|
0
|
|
|
|
0
|
$self->_addstats("@prog", scalar @args) if $Argv::Summary; |
1173
|
0
|
0
|
|
|
|
0
|
if ($noexec) { |
1174
|
0
|
|
|
|
|
0
|
$self->_dbg($dbg, '-', \*STDERR, @cmd); |
1175
|
|
|
|
|
|
|
} else { |
1176
|
0
|
0
|
|
|
|
0
|
$self->_dbg($dbg, '+', \*STDERR, @cmd) if $dbg; |
1177
|
0
|
|
|
|
|
0
|
$self->_qx_stderr(\@cmd, $efd); |
1178
|
0
|
|
|
|
|
0
|
$self->_qx_stdout(\@cmd, $ofd); |
1179
|
0
|
0
|
|
|
|
0
|
if ($envp) { |
1180
|
0
|
|
|
|
|
0
|
local %ENV = %$envp; |
1181
|
0
|
|
|
|
|
0
|
@data = qx(@cmd); |
1182
|
|
|
|
|
|
|
} else { |
1183
|
0
|
|
|
|
|
0
|
@data = qx(@cmd); |
1184
|
|
|
|
|
|
|
} |
1185
|
0
|
|
0
|
|
|
0
|
$rc ||= $?; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
} |
1188
|
1
|
50
|
33
|
|
|
24
|
$? = $rc if $rc && ! $?; |
1189
|
|
|
|
|
|
|
} |
1190
|
1
|
50
|
|
|
|
7
|
print STDERR "+ (\$? == $?)\n" if $dbg > 1; |
1191
|
1
|
50
|
|
|
|
18
|
if ($?) { |
1192
|
0
|
|
|
|
|
0
|
$self->lastresults($?>>8, @data); |
1193
|
0
|
|
|
|
|
0
|
$self->fail($self->qxfail); |
1194
|
|
|
|
|
|
|
} |
1195
|
1
|
|
|
|
|
6
|
$self->unixpath(@data) if MSWIN && $self->outpathnorm; |
1196
|
1
|
50
|
|
|
|
15
|
if (wantarray) { |
1197
|
1
|
50
|
33
|
|
|
24
|
print STDERR map {"+ <- $_"} @data if @data && $dbg >= 2; |
|
0
|
|
|
|
|
0
|
|
1198
|
1
|
50
|
|
|
|
26
|
chomp(@data) if $self->autochomp; |
1199
|
1
|
|
|
|
|
81
|
return @data; |
1200
|
|
|
|
|
|
|
} else { |
1201
|
0
|
|
|
|
|
|
my $data = join('', @data); |
1202
|
0
|
0
|
0
|
|
|
|
print STDERR "+ <- $data" if @data && $dbg >= 2; |
1203
|
0
|
0
|
|
|
|
|
chomp($data) if $self->autochomp; |
1204
|
0
|
|
|
|
|
|
return $data; |
1205
|
|
|
|
|
|
|
} |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
# Can't override qx() in main package so we export an alias instead. |
1208
|
|
|
|
|
|
|
*qv = \&qx; |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
sub pipe { |
1211
|
0
|
0
|
0
|
0
|
1
|
|
return $class->new(@_)->pipe if !ref($_[0]) || ref($_[0]) eq 'HASH'; |
1212
|
|
|
|
|
|
|
|
1213
|
0
|
|
|
|
|
|
my $self = shift; |
1214
|
|
|
|
|
|
|
|
1215
|
0
|
|
|
|
|
|
my $cb = $self->pipecb; |
1216
|
0
|
0
|
|
|
|
|
$self->error("No callback supplied") unless ref($cb) eq 'CODE'; |
1217
|
|
|
|
|
|
|
|
1218
|
0
|
|
|
|
|
|
my ($pipe, $pid) = $self->readpipe(@_); |
1219
|
0
|
|
|
|
|
|
my $line; |
1220
|
0
|
|
|
|
|
|
my $abort = 0; |
1221
|
0
|
|
|
|
|
|
while($line = <$pipe>) { |
1222
|
0
|
0
|
|
|
|
|
chomp($line) if $self->autochomp; |
1223
|
0
|
|
|
|
|
|
my $keepGoing = &$cb($line); |
1224
|
0
|
0
|
|
|
|
|
if (!$keepGoing) { |
1225
|
0
|
0
|
|
|
|
|
if ($self->_read_only) { |
1226
|
0
|
|
|
|
|
|
$abort = 1; |
1227
|
0
|
|
|
|
|
|
last; |
1228
|
|
|
|
|
|
|
} |
1229
|
0
|
|
|
|
|
|
$self->warning("Not abortable unless readonly - continuing!"); |
1230
|
|
|
|
|
|
|
} |
1231
|
|
|
|
|
|
|
} |
1232
|
0
|
|
|
|
|
|
if (MSWIN && $abort) { |
1233
|
|
|
|
|
|
|
# This is somewhat ugly, but due to perl impl details as well as |
1234
|
|
|
|
|
|
|
# the fact that Windows does not have the proper counterpart to |
1235
|
|
|
|
|
|
|
# SIGPIPE, we'll have to 'help' things along... |
1236
|
|
|
|
|
|
|
# |
1237
|
|
|
|
|
|
|
Argv::Win32Utils::killProcessTree($self, $pid); |
1238
|
|
|
|
|
|
|
} |
1239
|
0
|
|
|
|
|
|
my $rc = close($pipe); |
1240
|
0
|
0
|
|
|
|
|
$self->fail($self->qxfail) if !$rc; |
1241
|
0
|
|
|
|
|
|
return $rc; |
1242
|
|
|
|
|
|
|
} |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
# Wrapper around Perl's "open(FOO, ' |')" operator. |
1245
|
|
|
|
|
|
|
sub readpipe { |
1246
|
0
|
0
|
0
|
0
|
0
|
|
return $class->new(@_)->readpipe if !ref($_[0]) || ref($_[0]) eq 'HASH'; |
1247
|
0
|
|
|
|
|
|
my $self = shift; |
1248
|
0
|
|
|
|
|
|
my $envp = $self->envp; |
1249
|
0
|
|
|
|
|
|
my @prog = @{$self->{AV_PROG}}; |
|
0
|
|
|
|
|
|
|
1250
|
0
|
|
|
|
|
|
my @opts = $self->_sets2opts(@_); |
1251
|
0
|
|
|
|
|
|
my @args = @{$self->{AV_ARGS}}; |
|
0
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
# These potentially modify their arguments in place. |
1254
|
0
|
|
|
|
|
|
$self->argpathnorm(@prog, @args); |
1255
|
0
|
0
|
0
|
|
|
|
$self->quote(@prog, @opts, @args) |
1256
|
|
|
|
|
|
|
if (((@prog + @opts + @args) > 1) && $self->autoquote); |
1257
|
|
|
|
|
|
|
|
1258
|
0
|
|
|
|
|
|
my @cmd = (@prog, @opts, @args); |
1259
|
0
|
|
|
|
|
|
my $dbg = 0; |
1260
|
0
|
|
|
|
|
|
my($ifd, $ofd, $efd) = ($self->stdin, $self->stdout, $self->stderr); |
1261
|
0
|
|
0
|
|
|
|
my $noexec = $self->noexec && !$self->_read_only; |
1262
|
0
|
|
|
|
|
|
$dbg = $self->dbglevel; |
1263
|
0
|
0
|
|
|
|
|
$self->_addstats("@prog", scalar @args) if $Argv::Summary; |
1264
|
0
|
0
|
|
|
|
|
if ($noexec) { |
1265
|
0
|
|
|
|
|
|
$self->_dbg($dbg, '-', \*STDERR, @cmd, '|'); |
1266
|
|
|
|
|
|
|
} else { |
1267
|
0
|
|
|
|
|
|
my $handle; |
1268
|
0
|
0
|
|
|
|
|
$self->_dbg($dbg, '+', \*STDERR, @cmd, '|') if $dbg; |
1269
|
0
|
|
|
|
|
|
$self->_qx_stderr(\@cmd, $efd); |
1270
|
0
|
|
|
|
|
|
$self->_qx_stdout(\@cmd, $ofd); |
1271
|
0
|
|
|
|
|
|
my $rc; |
1272
|
0
|
0
|
|
|
|
|
if ($envp) { |
1273
|
0
|
|
|
|
|
|
local %ENV = %$envp; |
1274
|
0
|
|
|
|
|
|
$rc = open($handle, "@cmd |"); |
1275
|
|
|
|
|
|
|
} else { |
1276
|
0
|
|
|
|
|
|
$rc = open($handle, "@cmd |"); |
1277
|
|
|
|
|
|
|
} |
1278
|
0
|
0
|
0
|
|
|
|
$self->fail($self->qxfail) if !$rc || !defined($handle); |
1279
|
0
|
|
|
|
|
|
my $oldfh = select($handle); $| = 1; select($oldfh); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1280
|
0
|
0
|
|
|
|
|
return wantarray ? ($handle, $rc) : $handle; |
1281
|
|
|
|
|
|
|
} |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
# Internal - provide a warning with std format and caller's context. |
1285
|
|
|
|
|
|
|
sub warning { |
1286
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1287
|
0
|
|
|
|
|
|
(my $prog = $0) =~ s%.*[/\\]%%; |
1288
|
1
|
|
|
1
|
|
23
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
142
|
|
1289
|
0
|
|
0
|
|
|
|
carp('Warning: ', ${$self->{AV_PROG}}[-1] || $prog, ': ', @_); |
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
# Internal - provide a fatal error with std format and caller's context. |
1293
|
|
|
|
|
|
|
sub error { |
1294
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1295
|
0
|
|
|
|
|
|
(my $prog = $0) =~ s%.*[/\\]%%; |
1296
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
14
|
|
|
1
|
|
|
|
|
829
|
|
1297
|
0
|
|
0
|
|
|
|
croak('Error: ', ${$self->{AV_PROG}}[-1] || $prog, ': ', @_); |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
# Hack this thing in here to help with *$ Windows. We want to hide it |
1301
|
|
|
|
|
|
|
# as much as possible in the hope that a better way may be found |
1302
|
|
|
|
|
|
|
# someday. Thus it's implemented as an "inner class" rather than |
1303
|
|
|
|
|
|
|
# a separate file. |
1304
|
|
|
|
|
|
|
{ |
1305
|
|
|
|
|
|
|
package Argv::Win32Utils; |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
# Preload this to avoid INIT block failure in Win32::API::Type |
1308
|
|
|
|
|
|
|
# (but it may not be installed at all, which is ok). |
1309
|
|
|
|
|
|
|
eval "require Win32::API"; |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
# For internal use only - attempt to kill the process tree stemming from |
1312
|
|
|
|
|
|
|
# the given pid. |
1313
|
|
|
|
|
|
|
# Attempts several ways using various packages that may or may not be |
1314
|
|
|
|
|
|
|
# present. |
1315
|
|
|
|
|
|
|
sub killProcessTree { |
1316
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1317
|
0
|
|
|
|
|
|
my $pid = shift; |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
# Undocumented way to turn this off in case it causes big problems... |
1320
|
0
|
0
|
|
|
|
|
return 0 if $ENV{ARGV_WIN32UTILS_SKIP_KILLPROCESSTREE}; |
1321
|
|
|
|
|
|
|
|
1322
|
0
|
|
|
|
|
|
require Win32::Process; |
1323
|
|
|
|
|
|
|
|
1324
|
0
|
|
|
|
|
|
my ($implDesc, $impl) = __findImpl($argv); |
1325
|
0
|
0
|
|
|
|
|
print STDERR "Using $implDesc...\n" if $argv->dbglevel > 1; |
1326
|
0
|
|
|
|
|
|
&$impl($argv, $pid); |
1327
|
|
|
|
|
|
|
|
1328
|
0
|
|
|
|
|
|
return 0; |
1329
|
|
|
|
|
|
|
} |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
# For internal use only - attempt to kill a single process |
1332
|
|
|
|
|
|
|
sub killProcess { |
1333
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1334
|
0
|
|
|
|
|
|
my $pid = shift; |
1335
|
|
|
|
|
|
|
|
1336
|
0
|
0
|
|
|
|
|
print STDERR "Killing $pid...\n" if $argv->dbglevel > 1; |
1337
|
0
|
|
|
|
|
|
return Win32::Process::KillProcess($pid, 0); |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# Implementation using Win32::Process::Info |
1341
|
|
|
|
|
|
|
# This pkg can give us a (pruned) pid tree with the expected |
1342
|
|
|
|
|
|
|
# layout right away. |
1343
|
|
|
|
|
|
|
sub __win32_process_info { |
1344
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1345
|
0
|
|
|
|
|
|
my $pid = shift; |
1346
|
|
|
|
|
|
|
|
1347
|
0
|
|
|
|
|
|
my %pidTree = new Win32::Process::Info->Subprocesses($pid); |
1348
|
0
|
|
|
|
|
|
__deepKill($argv, $pid, \%pidTree); |
1349
|
|
|
|
|
|
|
|
1350
|
0
|
|
|
|
|
|
return 0; |
1351
|
|
|
|
|
|
|
} |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
# Implementation using Win32::ToolHelp |
1354
|
|
|
|
|
|
|
# this pkg gives a different view - rework into a pid tree |
1355
|
|
|
|
|
|
|
# by 1) enter all pids as keys, and then 2) add their children. |
1356
|
|
|
|
|
|
|
sub __win32_toolhelp { |
1357
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1358
|
0
|
|
|
|
|
|
my $pid = shift; |
1359
|
|
|
|
|
|
|
|
1360
|
0
|
|
|
|
|
|
my %pidTree; |
1361
|
0
|
|
|
|
|
|
my @allProcesses = Win32::ToolHelp::GetProcesses(); |
1362
|
0
|
|
|
|
|
|
$pidTree{$_->[1]} = [] foreach (@allProcesses); |
1363
|
0
|
|
|
|
|
|
push(@{$pidTree{$_->[5]}}, $_->[1]) foreach (@allProcesses); |
|
0
|
|
|
|
|
|
|
1364
|
0
|
|
|
|
|
|
__deepKill($argv, $pid, \%pidTree); |
1365
|
|
|
|
|
|
|
|
1366
|
0
|
|
|
|
|
|
return 0; |
1367
|
|
|
|
|
|
|
} |
1368
|
|
|
|
|
|
|
|
1369
|
|
|
|
|
|
|
# Kill processes depth first by following the tree. |
1370
|
|
|
|
|
|
|
sub __deepKill { |
1371
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1372
|
0
|
|
|
|
|
|
my $pid = shift; |
1373
|
0
|
|
|
|
|
|
my $pidTree = shift; |
1374
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
# give a parent an opportunity to terminate by itself |
1376
|
|
|
|
|
|
|
# which is likely when their child died |
1377
|
|
|
|
|
|
|
# |
1378
|
0
|
|
|
|
|
|
foreach my $childPid (@{$pidTree->{$pid}}) { |
|
0
|
|
|
|
|
|
|
1379
|
0
|
|
|
|
|
|
__deepKill($argv, $childPid, $pidTree); |
1380
|
|
|
|
|
|
|
} |
1381
|
0
|
|
|
|
|
|
killProcess($argv, $pid); |
1382
|
|
|
|
|
|
|
} |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
# Dynamically find an implementation that can figure out |
1385
|
|
|
|
|
|
|
# the process tree and kill it. |
1386
|
|
|
|
|
|
|
# Fall back to just kill the root pid (which may just be enough). |
1387
|
|
|
|
|
|
|
sub __findImpl { |
1388
|
0
|
|
|
0
|
|
|
my $argv = shift; |
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
# begin with a list to ensure a preferred search order |
1391
|
|
|
|
|
|
|
# but put the list in a hash for easy lookup |
1392
|
|
|
|
|
|
|
# |
1393
|
0
|
|
|
|
|
|
my @implList = ( |
1394
|
|
|
|
|
|
|
"Win32::ToolHelp", \&__win32_toolhelp, |
1395
|
|
|
|
|
|
|
"Win32::Process::Info", \&__win32_process_info, |
1396
|
|
|
|
|
|
|
); |
1397
|
0
|
|
|
|
|
|
my %implHash = @implList; |
1398
|
0
|
|
|
|
|
|
foreach my $implName (@implList) { |
1399
|
0
|
|
|
|
|
|
eval "use $implName"; |
1400
|
0
|
0
|
|
|
|
|
return ("$implName (tree capable)", $implHash{$implName}) unless $@; |
1401
|
|
|
|
|
|
|
} |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
# no luck, use fallback |
1404
|
0
|
|
|
|
|
|
my @helpers = keys(%implHash); |
1405
|
0
|
|
|
|
|
|
$argv->warning("No process tree helper found - install any of these packages: [@helpers]"); |
1406
|
0
|
|
|
|
|
|
return ("Win32::Process (not tree capable)", \&killProcess); |
1407
|
|
|
|
|
|
|
} |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
1; |
1410
|
|
|
|
|
|
|
} |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
1; |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
__END__ |