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