line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Getopt::Euclid; |
2
|
|
|
|
|
|
|
|
3
|
65
|
|
|
65
|
|
292127
|
use version; our $VERSION = version->declare('0.4.5'); |
|
65
|
|
|
|
|
126479
|
|
|
65
|
|
|
|
|
396
|
|
4
|
|
|
|
|
|
|
|
5
|
65
|
|
|
65
|
|
6000
|
use warnings; |
|
65
|
|
|
|
|
138
|
|
|
65
|
|
|
|
|
1667
|
|
6
|
65
|
|
|
65
|
|
347
|
use strict; |
|
65
|
|
|
|
|
133
|
|
|
65
|
|
|
|
|
1140
|
|
7
|
65
|
|
|
65
|
|
1145
|
use 5.005000; # perl 5.5.0 |
|
65
|
|
|
|
|
454
|
|
8
|
65
|
|
|
65
|
|
361
|
use Carp; |
|
65
|
|
|
|
|
134
|
|
|
65
|
|
|
|
|
5355
|
|
9
|
65
|
|
|
65
|
|
30724
|
use Symbol (); |
|
65
|
|
|
|
|
52594
|
|
|
65
|
|
|
|
|
2074
|
|
10
|
65
|
|
|
65
|
|
425
|
use re 'eval'; # for matcher regex |
|
65
|
|
|
|
|
128
|
|
|
65
|
|
|
|
|
4077
|
|
11
|
65
|
|
|
65
|
|
34678
|
use Pod::Select; |
|
65
|
|
|
|
|
129351
|
|
|
65
|
|
|
|
|
7432
|
|
12
|
65
|
|
|
65
|
|
34287
|
use Pod::PlainText; |
|
65
|
|
|
|
|
274721
|
|
|
65
|
|
|
|
|
3752
|
|
13
|
65
|
|
|
65
|
|
528
|
use File::Basename; |
|
65
|
|
|
|
|
140
|
|
|
65
|
|
|
|
|
7305
|
|
14
|
65
|
|
|
65
|
|
28352
|
use File::Spec::Functions qw(splitpath catpath catfile); |
|
65
|
|
|
|
|
54359
|
|
|
65
|
|
|
|
|
5038
|
|
15
|
65
|
|
|
65
|
|
482
|
use List::Util qw( first ); |
|
65
|
|
|
|
|
148
|
|
|
65
|
|
|
|
|
7703
|
|
16
|
65
|
|
|
65
|
|
46540
|
use Text::Balanced qw(extract_multiple extract_bracketed extract_variable extract_delimited); |
|
65
|
|
|
|
|
1125791
|
|
|
65
|
|
|
|
|
160960
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Set some module variables |
20
|
|
|
|
|
|
|
my $skip_keyword = 'Getopt::Euclid'; # Ignore files with a first line containing this keyword. |
21
|
|
|
|
|
|
|
my $pod_file_msg = "# This file was generated dynamically by $skip_keyword. Do not edit it."; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my $has_run = 0; |
24
|
|
|
|
|
|
|
my $has_processed_pod = 0; |
25
|
|
|
|
|
|
|
my $export_lvl = 1; |
26
|
|
|
|
|
|
|
my @pod_names; |
27
|
|
|
|
|
|
|
my $minimal_keys; |
28
|
|
|
|
|
|
|
my $vars_prefix; |
29
|
|
|
|
|
|
|
my $defer = 0; |
30
|
|
|
|
|
|
|
my $matcher; |
31
|
|
|
|
|
|
|
my %requireds; |
32
|
|
|
|
|
|
|
my %options; |
33
|
|
|
|
|
|
|
my %longnames; |
34
|
|
|
|
|
|
|
our $man; # --man message |
35
|
|
|
|
|
|
|
my $help; # --help message |
36
|
|
|
|
|
|
|
my $usage; # --usage message |
37
|
|
|
|
|
|
|
my $version; # --version message |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my $optional_re; |
40
|
|
|
|
|
|
|
$optional_re = qr{ \[ [^[]* (?: (??{$optional_re}) [^[]* )* \] }xms; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# Global variables |
44
|
|
|
|
|
|
|
our $SCRIPT_NAME; |
45
|
|
|
|
|
|
|
our $SCRIPT_VERSION; # for ticket # 55259 |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Convert arg specification syntax to Perl regex syntax |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my %std_matcher_for = ( |
51
|
|
|
|
|
|
|
integer => '[+-]?\\d+(?:[eE][+]?\d+)?', |
52
|
|
|
|
|
|
|
number => '[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\d+)?', |
53
|
|
|
|
|
|
|
input => '\S+', |
54
|
|
|
|
|
|
|
output => '\S+', |
55
|
|
|
|
|
|
|
string => '\S+', |
56
|
|
|
|
|
|
|
q{} => '\S+', |
57
|
|
|
|
|
|
|
); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
_make_equivalent( |
60
|
|
|
|
|
|
|
\%std_matcher_for, |
61
|
|
|
|
|
|
|
integer => [qw( int i +int +i 0+int 0+i +integer 0+integer )], |
62
|
|
|
|
|
|
|
number => [qw( num n +num +n 0+num 0+n +number 0+number )], |
63
|
|
|
|
|
|
|
input => [qw( readable in )], |
64
|
|
|
|
|
|
|
output => [qw( writable writeable out )], |
65
|
|
|
|
|
|
|
string => [qw( str s )], |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
my %std_constraint_for = ( |
69
|
|
|
|
|
|
|
'string' => sub { 1 }, # Always okay (matcher ensures this) |
70
|
|
|
|
|
|
|
'integer' => sub { 1 }, # Always okay (matcher ensures this) |
71
|
|
|
|
|
|
|
'+integer' => sub { $_[0] > 0 }, |
72
|
|
|
|
|
|
|
'0+integer' => sub { $_[0] >= 0 }, |
73
|
|
|
|
|
|
|
'number' => sub { 1 }, # Always okay (matcher ensures this) |
74
|
|
|
|
|
|
|
'+number' => sub { $_[0] > 0 }, |
75
|
|
|
|
|
|
|
'0+number' => sub { $_[0] >= 0 }, |
76
|
|
|
|
|
|
|
'input' => sub { $_[0] eq '-' || -r $_[0] }, |
77
|
|
|
|
|
|
|
'output' => sub { |
78
|
|
|
|
|
|
|
my ( $vol, $dir ) = splitpath( $_[0] ); |
79
|
|
|
|
|
|
|
$dir = ($vol && $dir) ? catpath($vol, $dir) : '.'; |
80
|
|
|
|
|
|
|
$_[0] eq '-' ? 1 : -e $_[0] ? -w $_[0] : -w $dir; |
81
|
|
|
|
|
|
|
}, |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
_make_equivalent( |
85
|
|
|
|
|
|
|
\%std_constraint_for, |
86
|
|
|
|
|
|
|
'integer' => [qw( int i )], |
87
|
|
|
|
|
|
|
'+integer' => [qw( +int +i )], |
88
|
|
|
|
|
|
|
'0+integer' => [qw( 0+int 0+i )], |
89
|
|
|
|
|
|
|
'number' => [qw( num n )], |
90
|
|
|
|
|
|
|
'+number' => [qw( +num +n )], |
91
|
|
|
|
|
|
|
'0+number' => [qw( 0+num 0+n )], |
92
|
|
|
|
|
|
|
'string' => [qw( str s )], |
93
|
|
|
|
|
|
|
'input' => [qw( in readable )], |
94
|
|
|
|
|
|
|
'output' => [qw( out writable writeable )], |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub Getopt::Euclid::Importer::DESTROY { |
99
|
0
|
0
|
0
|
0
|
|
0
|
return if $has_run || $^C; # No errors when only compiling |
100
|
0
|
|
|
|
|
0
|
croak '.pm file cannot define an explicit import() when using Getopt::Euclid'; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub import { |
105
|
69
|
|
|
69
|
|
1983
|
shift @_; |
106
|
69
|
|
100
|
|
|
199
|
@_ = grep { !( /:minimal_keys/ and $minimal_keys = 1 ) } @_; |
|
11
|
|
|
|
|
110
|
|
107
|
69
|
|
66
|
|
|
135
|
@_ = grep { !( /:vars(?:<(\w+)>)?/ and $vars_prefix = $1 || 'ARGV_' ) } @_; |
|
6
|
|
|
|
|
51
|
|
108
|
69
|
|
100
|
|
|
134
|
@_ = grep { !( /:defer/ and $defer = 1 ) } @_; |
|
4
|
|
|
|
|
29
|
|
109
|
69
|
|
|
|
|
375
|
croak "Unknown mode ('$_')" for @_; |
110
|
68
|
100
|
|
|
|
275
|
$export_lvl++ if not $defer; |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# No POD parsing and argument processing in Perl compile mode (ticket 34195) |
113
|
68
|
100
|
|
|
|
338
|
return if $^C; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Get name of caller program and its modules in @pod_names |
116
|
67
|
100
|
|
|
|
166
|
return unless _get_pod_names(); |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# Extract POD of given files |
119
|
63
|
|
|
|
|
335
|
__PACKAGE__->process_pods( [reverse @pod_names] ); |
120
|
63
|
|
|
|
|
184
|
undef @pod_names; |
121
|
63
|
|
|
|
|
113
|
$has_run = 1; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Parse POD + parse and export arguments |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
###### |
126
|
|
|
|
|
|
|
#use Data::Dumper; print "ARGV: ".Dumper(\@ARGV); |
127
|
|
|
|
|
|
|
###### |
128
|
|
|
|
|
|
|
|
129
|
63
|
100
|
|
|
|
454
|
__PACKAGE__->process_args( \@ARGV ) unless $defer; |
130
|
|
|
|
|
|
|
|
131
|
36
|
|
|
|
|
5023
|
return 1; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub process_pods { |
136
|
|
|
|
|
|
|
# Extract POD content from list of Perl scripts (.pl) and modules (.pm) and |
137
|
|
|
|
|
|
|
# their corresponding .pod file if available. When given the argument |
138
|
|
|
|
|
|
|
# {-strict => 1}, do not look for .pod files. |
139
|
64
|
|
|
64
|
1
|
2294
|
my ($self, $perl_files, $args) = @_; |
140
|
|
|
|
|
|
|
|
141
|
64
|
|
|
|
|
116
|
my $pod_string = ''; |
142
|
35
|
50
|
|
35
|
|
18718
|
open my $pod_fh, '>', \$pod_string |
|
35
|
|
|
|
|
465
|
|
|
35
|
|
|
|
|
206
|
|
|
64
|
|
|
|
|
1931
|
|
143
|
|
|
|
|
|
|
or croak "Could not open filehandle to variable because $!"; |
144
|
64
|
|
|
|
|
25809
|
for my $perl_file (@$perl_files) { |
145
|
|
|
|
|
|
|
|
146
|
67
|
|
|
|
|
121
|
my $got_pod_file = 0; |
147
|
|
|
|
|
|
|
|
148
|
67
|
50
|
|
|
|
239
|
if ( not $args->{-strict} ) { |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Find corresponding .pod file |
151
|
67
|
|
|
|
|
5967
|
my ($name_re, $path, $suffix) = fileparse($perl_file, qr/\.[^.]*/); |
152
|
67
|
|
|
|
|
758
|
my $pod_file = catfile( $path, $name_re.'.pod' ); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Get POD either from .pod file (preferably) or from Perl file |
155
|
67
|
100
|
|
|
|
2647
|
if ( -e $pod_file ) { |
156
|
|
|
|
|
|
|
# Get .pod file content |
157
|
6
|
50
|
|
|
|
244
|
open my $in, '<', $pod_file |
158
|
|
|
|
|
|
|
or croak "Could not open file $pod_file because $!"; |
159
|
6
|
|
|
|
|
159
|
my $first_line = <$in>; |
160
|
6
|
|
|
|
|
28
|
chomp $first_line; |
161
|
6
|
100
|
|
|
|
92
|
if ( not ($first_line =~ m/$skip_keyword/) ) { |
162
|
|
|
|
|
|
|
# Skip G::E auto-generated files since they lack important data |
163
|
4
|
|
|
|
|
26
|
print $pod_fh "$first_line\n"; |
164
|
4
|
|
|
|
|
178
|
print $pod_fh $_ while <$in>; |
165
|
4
|
|
|
|
|
14
|
$got_pod_file = 1; |
166
|
|
|
|
|
|
|
} |
167
|
6
|
|
|
|
|
87
|
close $in; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
67
|
100
|
|
|
|
273
|
if (not $got_pod_file) { |
172
|
|
|
|
|
|
|
# Parse POD content of Perl file |
173
|
63
|
|
|
|
|
409
|
podselect( {-output => $pod_fh}, $perl_file ); |
174
|
|
|
|
|
|
|
} |
175
|
67
|
100
|
|
|
|
175180
|
print $pod_fh "\n" if $pod_string; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
} |
178
|
64
|
|
|
|
|
215
|
close $pod_fh; |
179
|
64
|
|
|
|
|
181
|
$man = $pod_string; |
180
|
64
|
|
|
|
|
233
|
return 1; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub process_args { |
185
|
|
|
|
|
|
|
# First, parse the POD specifications. Then, parse the given array of |
186
|
|
|
|
|
|
|
# arguments (\@ARGV or other) and populate %ARGV (or export specific |
187
|
|
|
|
|
|
|
# variable names). |
188
|
70
|
|
|
70
|
1
|
46955
|
my ($self, $args, $options) = @_; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Parse POD |
191
|
70
|
100
|
|
|
|
225
|
if (not $has_processed_pod) { |
192
|
64
|
|
|
|
|
214
|
_parse_pod(); |
193
|
51
|
|
|
|
|
112
|
$has_processed_pod = 1; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Set options for argument parsing |
197
|
57
|
100
|
|
|
|
217
|
if (defined $options) { |
198
|
2
|
100
|
|
|
|
10
|
if (exists $options->{-minimal_keys}) { |
199
|
1
|
|
|
|
|
3
|
$minimal_keys = 1; |
200
|
|
|
|
|
|
|
} |
201
|
2
|
100
|
|
|
|
9
|
if (exists $options->{-vars}) { |
202
|
1
|
|
|
|
|
3
|
$vars_prefix = $options->{-vars}; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
57
|
|
|
|
|
173
|
%ARGV = (); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Handle standard args... |
209
|
57
|
50
|
|
629
|
|
688
|
if ( first { $_ eq '--man' } @$args ) { |
|
629
|
50
|
|
|
|
1127
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
_print_pod( __PACKAGE__->man(), 'paged' ); |
211
|
0
|
|
|
|
|
0
|
exit; |
212
|
629
|
|
|
629
|
|
960
|
} elsif ( first { $_ eq '--usage' } @$args ) { |
213
|
0
|
|
|
|
|
0
|
print __PACKAGE__->usage(); |
214
|
0
|
|
|
|
|
0
|
exit; |
215
|
629
|
|
|
629
|
|
1130
|
} elsif ( first { $_ eq '--help' } @$args ) { |
216
|
0
|
|
|
|
|
0
|
_print_pod( __PACKAGE__->help(), 'paged' ); |
217
|
0
|
|
|
|
|
0
|
exit; |
218
|
629
|
|
|
629
|
|
1066
|
} elsif ( first { $_ eq '--version' } @$args ) { |
219
|
0
|
|
|
|
|
0
|
print __PACKAGE__->version(); |
220
|
0
|
|
|
|
|
0
|
exit; |
221
|
629
|
|
|
629
|
|
856
|
} elsif ( first { $_ eq '--podfile' } @$args ) { |
222
|
|
|
|
|
|
|
# Option meant for authors |
223
|
0
|
|
|
|
|
0
|
my $podfile = podfile( ); |
224
|
0
|
|
|
|
|
0
|
print "Wrote POD manual in file $podfile\n"; |
225
|
0
|
|
|
|
|
0
|
exit; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Subroutine to report problems during parsing... |
229
|
|
|
|
|
|
|
*_bad_arglist = sub { |
230
|
16
|
|
|
16
|
|
51
|
my (@msg) = @_; |
231
|
16
|
|
|
|
|
55
|
my $msg = join q{}, @msg; |
232
|
16
|
|
|
|
|
46
|
$msg = _rectify_arg($msg); |
233
|
16
|
|
|
|
|
111
|
$msg =~ s/\n?\z/\n/xms; |
234
|
16
|
|
|
|
|
231
|
warn "$msg\nTry this for usage help: $SCRIPT_NAME --help\n". |
235
|
|
|
|
|
|
|
"Or this for full manual: $SCRIPT_NAME --man\n\n"; |
236
|
16
|
|
|
|
|
94
|
exit 2; # Traditional "bad arg list" value |
237
|
57
|
|
|
|
|
860
|
}; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# Run matcher... |
240
|
57
|
|
|
|
|
181
|
my $argv = join( q{ }, map { $_ = _escape_arg($_) } @$args ); |
|
629
|
|
|
|
|
1011
|
|
241
|
57
|
|
|
|
|
467
|
my $all_args_ref = { %options, %requireds }; |
242
|
57
|
100
|
|
|
|
276
|
if ( my $error = _doesnt_match( $matcher, $argv, $all_args_ref ) ) { |
243
|
7
|
|
|
|
|
39
|
_bad_arglist($error); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# Check that all requireds have been found... |
247
|
50
|
|
|
|
|
123
|
my @missing; |
248
|
50
|
|
|
|
|
258
|
while ( my ($req) = each %requireds ) { |
249
|
101
|
100
|
|
|
|
595
|
push @missing, "\t$req\n" if !exists $ARGV{$req}; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
_bad_arglist( |
252
|
50
|
50
|
|
|
|
196
|
'Missing required argument', |
|
|
100
|
|
|
|
|
|
253
|
|
|
|
|
|
|
( @missing == 1 ? q{} : q{s} ), |
254
|
|
|
|
|
|
|
":\n", @missing |
255
|
|
|
|
|
|
|
) if @missing; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# Back-translate \0-quoted spaces and \1-quoted tabs... |
258
|
49
|
|
|
|
|
191
|
_rectify_all_args(); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# Check exclusive variables, variable constraints and fill in defaults... |
261
|
49
|
|
|
|
|
418
|
_verify_args($all_args_ref); |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Clean up @$args since everything must have been parsed |
264
|
41
|
|
|
|
|
140
|
@$args = (); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# Clean up %ARGV |
267
|
41
|
|
|
|
|
140
|
for my $arg_name ( keys %ARGV ) { |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Flatten non-repeatables... |
270
|
260
|
|
|
|
|
557
|
my $vals = delete $ARGV{$arg_name}; |
271
|
260
|
|
|
|
|
514
|
my $repeatable = $all_args_ref->{$arg_name}{is_repeatable}; |
272
|
260
|
100
|
|
|
|
526
|
if ($repeatable) { |
273
|
4
|
|
|
|
|
5
|
pop @{$vals}; |
|
4
|
|
|
|
|
6
|
|
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
260
|
|
|
|
|
366
|
for my $val ( @{$vals} ) { |
|
260
|
|
|
|
|
500
|
|
277
|
260
|
|
|
|
|
335
|
my $var_count = keys %{$val}; |
|
260
|
|
|
|
|
417
|
|
278
|
|
|
|
|
|
|
$val = $var_count == 0 |
279
|
|
|
|
|
|
|
? 1 # Boolean -> true |
280
|
|
|
|
|
|
|
: $var_count == 1 |
281
|
260
|
100
|
|
|
|
704
|
? ( values %{$val} )[0] # Single var -> var's val |
|
214
|
50
|
|
|
|
503
|
|
282
|
|
|
|
|
|
|
: $val # Otherwise keep hash |
283
|
|
|
|
|
|
|
; |
284
|
260
|
|
|
|
|
573
|
my $false_vals = $all_args_ref->{$arg_name}{false_vals}; |
285
|
260
|
|
|
|
|
351
|
my %vars_opt_vals; |
286
|
|
|
|
|
|
|
|
287
|
260
|
|
|
|
|
523
|
for my $arg_flag ( _get_variants($arg_name) ) { |
288
|
480
|
|
|
|
|
729
|
my $variant_val = $val; |
289
|
480
|
100
|
100
|
|
|
1298
|
if ( $false_vals && $arg_flag =~ m{\A $false_vals \z}xms ) { |
290
|
14
|
100
|
|
|
|
38
|
$variant_val = $variant_val ? 0 : 1; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
480
|
100
|
|
|
|
855
|
if ($repeatable) { |
294
|
25
|
|
|
|
|
29
|
push @{ $ARGV{$arg_flag} }, $variant_val; |
|
25
|
|
|
|
|
55
|
|
295
|
|
|
|
|
|
|
} else { |
296
|
455
|
|
|
|
|
902
|
$ARGV{$arg_flag} = $variant_val; |
297
|
|
|
|
|
|
|
} |
298
|
480
|
100
|
|
|
|
1016
|
$vars_opt_vals{$arg_flag} = $ARGV{$arg_flag} if $vars_prefix; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
260
|
100
|
|
|
|
813
|
if ($vars_prefix) { |
302
|
28
|
|
|
|
|
87
|
_minimize_entries_of( \%vars_opt_vals ); |
303
|
28
|
|
|
|
|
69
|
my $maximal = _longestname( keys %vars_opt_vals ); |
304
|
28
|
|
|
|
|
86
|
_export_var( $vars_prefix, $maximal, $vars_opt_vals{$maximal} ); |
305
|
28
|
|
|
|
|
105
|
delete $longnames{$maximal}; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
41
|
100
|
|
|
|
223
|
if ($vars_prefix) { |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# Export any unspecified options to keep use strict happy |
313
|
3
|
|
|
|
|
16
|
while ( my ($opt_name, $arg_name) = each %longnames ) { |
314
|
17
|
|
|
|
|
33
|
my $arg_info = $all_args_ref->{$arg_name}; |
315
|
17
|
|
|
|
|
24
|
my $val; |
316
|
17
|
100
|
100
|
|
|
66
|
if ( $arg_info->{is_repeatable} or $arg_name =~ />\.\.\./ ) { |
317
|
|
|
|
|
|
|
# Empty arrayref for repeatable options |
318
|
3
|
|
|
|
|
4
|
$val = []; |
319
|
|
|
|
|
|
|
} else { |
320
|
14
|
100
|
|
|
|
20
|
if (keys %{ $arg_info->{var} } > 1) { |
|
14
|
|
|
|
|
38
|
|
321
|
|
|
|
|
|
|
# Empty hashref for non-repeatable options with multiple placeholders |
322
|
1
|
|
|
|
|
3
|
$val = {}; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
} |
325
|
17
|
|
|
|
|
51
|
_export_var( $vars_prefix, $opt_name, $val ); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
|
330
|
41
|
100
|
|
|
|
134
|
if ($minimal_keys) { |
331
|
6
|
|
|
|
|
23
|
_minimize_entries_of( \%ARGV ); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
41
|
|
|
|
|
168
|
return 1; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub podfile { |
339
|
|
|
|
|
|
|
# Write the given POD doc into a .pod file, overwriting any existing .pod file |
340
|
1
|
50
|
|
1
|
1
|
1478
|
return if not -e $0; |
341
|
1
|
|
|
|
|
58
|
my ($name_re, $path, $suffix) = fileparse($0, qr/\.[^.]*/); |
342
|
1
|
|
|
|
|
11
|
my $pod_file = catfile( $path, $name_re.'.pod' ); |
343
|
1
|
50
|
|
|
|
145
|
open my $out_fh, '>', $pod_file or croak "Could not write file $pod_file because $!"; |
344
|
1
|
|
|
|
|
11
|
print $out_fh $pod_file_msg."\n\n".__PACKAGE__->man(); |
345
|
1
|
|
|
|
|
56
|
close $out_fh; |
346
|
1
|
|
|
|
|
10
|
return $pod_file; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub man { |
351
|
6
|
|
|
6
|
1
|
21370
|
return $man; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
sub usage { |
356
|
1
|
|
|
1
|
1
|
681
|
return $usage; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub help { |
361
|
2
|
|
|
2
|
1
|
1567
|
return $help; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub version { |
366
|
1
|
|
|
1
|
1
|
643
|
return $version; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# # # # # # # # Utility subs # # # # # # # # |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Recursively remove decorations on %ARGV keys |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub AUTOLOAD { |
375
|
9
|
|
|
9
|
|
19
|
our $AUTOLOAD; |
376
|
9
|
|
|
|
|
50
|
$AUTOLOAD =~ s{.*::}{main::}xms; |
377
|
65
|
|
|
65
|
|
635
|
no strict 'refs'; |
|
65
|
|
|
|
|
180
|
|
|
65
|
|
|
|
|
455354
|
|
378
|
9
|
|
|
|
|
66
|
goto &$AUTOLOAD; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub _parse_pod { |
383
|
|
|
|
|
|
|
# Set up parsing rules... |
384
|
64
|
|
|
64
|
|
268
|
my $space_re = qr{ [^\S\n]* }xms; |
385
|
64
|
|
|
|
|
210
|
my $head_start_re = qr{ ^=head1 }xms; |
386
|
64
|
|
|
|
|
1344
|
my $head_end_re = qr{ (?= $head_start_re | \z) }xms; |
387
|
64
|
|
|
|
|
296
|
my $pod_cmd_re = qr{ = [^\W\d]\w+ [^\n]* (?= \n\n )}xms; |
388
|
64
|
|
|
|
|
1556
|
my $pod_cut_re = qr{ (?! \n\n ) = cut $space_re (?= \n\n )}xms; |
389
|
|
|
|
|
|
|
|
390
|
64
|
|
|
|
|
2254
|
my $name_re = qr{ $space_re NAME $space_re \n }xms; |
391
|
64
|
|
|
|
|
2295
|
my $vers_re = qr{ $space_re VERSION $space_re \n }xms; |
392
|
64
|
|
|
|
|
2097
|
my $usage_re = qr{ $space_re USAGE $space_re \n }xms; |
393
|
|
|
|
|
|
|
|
394
|
64
|
|
|
|
|
333
|
my $std_re = qr{ STANDARD | STD | PROGRAM | SCRIPT | CLI | COMMAND(?:-|\s)?LINE }xms; |
395
|
64
|
|
|
|
|
2576
|
my $arg_re = qr{ $space_re (?:PARAM(?:ETER)?|ARG(?:UMENT)?)S? }xms; |
396
|
|
|
|
|
|
|
|
397
|
64
|
|
|
|
|
6572
|
my $options_re = qr{ $space_re $std_re? $space_re OPTION(?:AL|S)? $arg_re? $space_re \n }xms; |
398
|
64
|
|
|
|
|
6708
|
my $required_re = qr{ $space_re $std_re? $space_re (?:REQUIRED|MANDATORY) $arg_re? $space_re \n }xms; |
399
|
|
|
|
|
|
|
|
400
|
64
|
|
|
|
|
427
|
my $euclid_arg = qr{ ^=item \s* ([^\n]*?) \s* \n\s*\n |
401
|
|
|
|
|
|
|
( |
402
|
|
|
|
|
|
|
.*? |
403
|
|
|
|
|
|
|
(?: |
404
|
|
|
|
|
|
|
^=for \s* (?i: Euclid) .*? \n\s*\n |
405
|
|
|
|
|
|
|
| (?= ^=[^\W\d]\w* | \z) |
406
|
|
|
|
|
|
|
) |
407
|
|
|
|
|
|
|
) |
408
|
|
|
|
|
|
|
}xms; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# Clean up line delimiters |
411
|
64
|
|
|
|
|
2348
|
$man =~ s{ [\n\r] }{\n}gx; |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# Clean up significant entities... |
414
|
64
|
|
|
|
|
260
|
$man =~ s{ E }{<}gxms; |
415
|
64
|
|
|
|
|
167
|
$man =~ s{ E }{>}gxms; |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# Put program name in man |
418
|
64
|
100
|
|
|
|
1507
|
$SCRIPT_NAME = (-e $0) ? (splitpath $0)[-1] : 'one-liner'; |
419
|
64
|
100
|
|
|
|
5089
|
$man =~ s{ ($head_start_re $name_re \s*) .*? (- .*)? $head_end_re } |
|
52
|
|
|
|
|
1306
|
|
420
|
|
|
|
|
|
|
{$1.$SCRIPT_NAME.($2 ? " $2" : "\n\n")}xems; |
421
|
|
|
|
|
|
|
|
422
|
64
|
|
|
|
|
3700
|
# Put version number in man |
423
|
|
|
|
|
|
|
($SCRIPT_VERSION) = |
424
|
64
|
100
|
|
|
|
414
|
$man =~ m/$head_start_re $vers_re .*? (\d+(?:[._]\d+)+) .*? $head_end_re /xms; |
425
|
14
|
|
|
|
|
56
|
if ( !defined $SCRIPT_VERSION ) { |
426
|
|
|
|
|
|
|
$SCRIPT_VERSION = $main::VERSION; |
427
|
64
|
100
|
|
|
|
324
|
} |
428
|
14
|
100
|
|
|
|
1050
|
if ( !defined $SCRIPT_VERSION ) { |
429
|
|
|
|
|
|
|
$SCRIPT_VERSION = (-e $0) ? localtime((stat $0)[9]) : 'one-liner'; |
430
|
64
|
|
|
|
|
3837
|
} |
431
|
|
|
|
|
|
|
$man =~ s{ ($head_start_re $vers_re \s*) .*? (\s*) $head_end_re } |
432
|
|
|
|
|
|
|
{$1This document refers to $SCRIPT_NAME version $SCRIPT_VERSION $2}xms; |
433
|
64
|
|
|
|
|
258
|
|
434
|
64
|
|
|
|
|
8578
|
# Extra info from PODs |
435
|
|
|
|
|
|
|
my ($options, $opt_name, $required, $req_name, $licence); |
436
|
51
|
|
|
|
|
359
|
while ($man =~ m/$head_start_re ($required_re) (.*?) $head_end_re /gxms) { |
437
|
51
|
50
|
|
|
|
218
|
# Required arguments |
438
|
51
|
|
50
|
|
|
1045
|
my ( $more_req_name, $more_required ) = ($1, $2); |
|
|
|
50
|
|
|
|
|
439
|
|
|
|
|
|
|
$req_name = $more_req_name if not defined $req_name; |
440
|
64
|
|
|
|
|
9707
|
$required = ( $more_required || q{} ) . ( $required || q{} ); |
441
|
|
|
|
|
|
|
} |
442
|
55
|
|
|
|
|
429
|
while ($man =~ m/$head_start_re ($options_re) (.*?) $head_end_re /gxms) { |
443
|
55
|
50
|
|
|
|
233
|
# Optional arguments |
444
|
55
|
|
50
|
|
|
1011
|
my ( $more_opt_name, $more_options ) = ($1, $2); |
|
|
|
50
|
|
|
|
|
445
|
|
|
|
|
|
|
$opt_name = $more_opt_name if not defined $opt_name; |
446
|
64
|
|
|
|
|
6608
|
$options = ( $more_options || q{} ) . ( $options || q{} ); |
447
|
|
|
|
|
|
|
} |
448
|
47
|
|
|
|
|
265
|
while ($man =~ m/$head_start_re [^\n]+ (?i: licen[sc]e | copyright ) .*? \n \s* (.*?) \s* $head_end_re /gxms) { |
449
|
47
|
|
50
|
|
|
552
|
# License information |
|
|
|
50
|
|
|
|
|
450
|
|
|
|
|
|
|
my ($more_licence) = ($1, $2); |
451
|
|
|
|
|
|
|
$licence = ( $more_licence || q{} ) . ( $licence || q{} ); |
452
|
|
|
|
|
|
|
} |
453
|
64
|
|
|
|
|
222
|
|
454
|
128
|
100
|
|
|
|
416
|
# Clean up interface titles... |
455
|
106
|
|
|
|
|
699
|
for my $name_re ( $opt_name, $req_name ) { |
456
|
|
|
|
|
|
|
next if !defined $name_re; |
457
|
|
|
|
|
|
|
$name_re =~ s{\A \s+ | \s+ \z}{}gxms; |
458
|
|
|
|
|
|
|
} |
459
|
64
|
|
|
|
|
153
|
|
460
|
64
|
|
|
|
|
150
|
# Extract the actual interface and store each arg entry into a hash of specifications... |
461
|
64
|
|
100
|
|
|
6187
|
my $seq = 0; |
462
|
120
|
|
|
|
|
487
|
my $seen = {}; |
463
|
120
|
|
|
|
|
1420
|
while ( ( $required || q{} ) =~ m{ $euclid_arg }gxms ) { |
464
|
|
|
|
|
|
|
$seen = _register_specs( $1, $2, $seq, \%requireds, \%longnames, $seen ); |
465
|
64
|
|
100
|
|
|
5960
|
$seq++; |
466
|
418
|
|
|
|
|
1189
|
} |
467
|
417
|
|
|
|
|
4903
|
while ( ( $options || q{} ) =~ m{ $euclid_arg }gxms ) { |
468
|
|
|
|
|
|
|
$seen = _register_specs( $1, $2, $seq, \%options, \%longnames, $seen ); |
469
|
63
|
|
|
|
|
253
|
$seq++; |
470
|
63
|
|
|
|
|
265
|
} |
471
|
|
|
|
|
|
|
undef $seen; |
472
|
|
|
|
|
|
|
_minimize_entries_of( \%longnames ); |
473
|
63
|
|
|
|
|
440
|
|
474
|
63
|
|
|
|
|
269
|
# Extract Euclid information... |
475
|
|
|
|
|
|
|
my $all_specs = {%requireds, %options}; |
476
|
|
|
|
|
|
|
_process_euclid_specs( $all_specs ); |
477
|
52
|
|
|
|
|
182
|
|
478
|
51
|
|
|
|
|
163
|
# Insert default values (if any) in the program's documentation |
479
|
|
|
|
|
|
|
$required = _insert_default_values(\%requireds); |
480
|
|
|
|
|
|
|
$options = _insert_default_values(\%options ); |
481
|
|
|
|
|
|
|
|
482
|
51
|
|
|
|
|
266
|
# One-line representation of interface... |
|
140
|
|
|
|
|
346
|
|
483
|
|
|
|
|
|
|
my $arg_summary = join ' ', (sort |
484
|
|
|
|
|
|
|
{ $requireds{$a}{'seq'} <=> $requireds{$b}{'seq'} } |
485
|
51
|
|
|
|
|
511
|
(keys %requireds)); |
486
|
|
|
|
|
|
|
|
487
|
51
|
100
|
|
|
|
205
|
1 while $arg_summary =~ s/\[ [^][]* \]//gxms; |
488
|
42
|
100
|
|
|
|
187
|
|
489
|
42
|
|
|
|
|
155
|
if ($opt_name) { |
490
|
|
|
|
|
|
|
$arg_summary .= ' ' if $arg_summary; |
491
|
51
|
|
|
|
|
327
|
$arg_summary .= lc "[$opt_name]"; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
$arg_summary =~ s/\s+/ /gxms; |
494
|
51
|
|
|
|
|
3652
|
|
495
|
51
|
|
|
|
|
8594
|
# Manual message |
496
|
51
|
|
|
|
|
10197
|
$man =~ s{ ($head_start_re $usage_re \s*) .*? (\s*) $head_end_re } {$1$SCRIPT_NAME $arg_summary$2}xms; |
497
|
|
|
|
|
|
|
$man =~ s{ ($head_start_re $required_re \s*) .*? (\s*) $head_end_re } {$1$required$2}xms; |
498
|
|
|
|
|
|
|
$man =~ s{ ($head_start_re $options_re \s*) .*? (\s*) $head_end_re } {$1$options$2}xms; |
499
|
51
|
|
|
|
|
312
|
|
500
|
51
|
|
|
|
|
163
|
# Usage message |
501
|
51
|
|
|
|
|
163
|
$usage = " $SCRIPT_NAME $arg_summary\n"; |
502
|
51
|
|
|
|
|
133
|
$usage .= " $SCRIPT_NAME --help\n"; |
503
|
51
|
|
|
|
|
140
|
$usage .= " $SCRIPT_NAME --man\n"; |
504
|
|
|
|
|
|
|
$usage .= " $SCRIPT_NAME --usage\n"; |
505
|
|
|
|
|
|
|
$usage .= " $SCRIPT_NAME --version\n"; |
506
|
51
|
|
|
|
|
299
|
|
507
|
51
|
100
|
100
|
|
|
610
|
# Help message |
508
|
|
|
|
|
|
|
$help = "=head1 \L\uUsage:\E\n\n$usage\n"; |
509
|
51
|
100
|
100
|
|
|
609
|
$help .= "=head1 \L\u$req_name:\E\n\n$required\n\n" |
510
|
|
|
|
|
|
|
if ( $req_name || q{} ) =~ /\S/; |
511
|
|
|
|
|
|
|
$help .= "=head1 \L\u$opt_name:\E\n\n$options\n\n" |
512
|
51
|
|
|
|
|
189
|
if ( $opt_name || q{} ) =~ /\S/; |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
$usage = "Usage:\n".$usage; |
515
|
51
|
|
|
|
|
191
|
|
516
|
51
|
100
|
|
|
|
296
|
# Version message |
517
|
|
|
|
|
|
|
$version = "This is $SCRIPT_NAME version $SCRIPT_VERSION\n"; |
518
|
|
|
|
|
|
|
$version .= "\n$licence\n" if $licence; |
519
|
51
|
|
|
|
|
335
|
|
520
|
|
|
|
|
|
|
# Convert arg specifications to regexes... |
521
|
|
|
|
|
|
|
_convert_to_regex( $all_specs ); |
522
|
51
|
|
|
|
|
220
|
|
523
|
435
|
|
|
|
|
1464
|
# Build matcher... |
524
|
1017
|
|
|
|
|
1591
|
my @arg_list = ( values(%requireds), values(%options) ); |
|
435
|
|
|
|
|
1117
|
|
525
|
51
|
|
|
|
|
157
|
$matcher = join '|', map { $_->{matcher} } |
|
1
|
|
|
|
|
4
|
|
|
435
|
|
|
|
|
850
|
|
526
|
51
|
|
|
|
|
323
|
sort( { $b->{name} cmp $a->{name} } grep { $_->{name} =~ /^[^<]/ } @arg_list ), |
527
|
51
|
|
|
|
|
461
|
sort( { $a->{seq} <=> $b->{seq} } grep { $_->{name} =~ /^[<]/ } @arg_list ); |
528
|
|
|
|
|
|
|
$matcher .= '|(?> (.+)) (?{ push @errors, $^N }) (?!)'; |
529
|
51
|
|
|
|
|
639
|
$matcher = '(?:' . $matcher . ')'; |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
return 1; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
538
|
|
|
538
|
|
2094
|
|
535
|
538
|
|
|
|
|
1122
|
sub _register_specs { |
536
|
538
|
|
|
|
|
2664
|
my ($name_re, $spec, $seq, $storage, $longnames, $seen) = @_; |
537
|
|
|
|
|
|
|
my @variants = _get_variants($name_re); |
538
|
|
|
|
|
|
|
$storage->{$name_re} = { |
539
|
|
|
|
|
|
|
seq => $seq, |
540
|
|
|
|
|
|
|
src => $spec, |
541
|
|
|
|
|
|
|
name => $name_re, |
542
|
538
|
100
|
|
|
|
1314
|
variants => \@variants, |
543
|
41
|
|
|
|
|
85
|
}; |
544
|
|
|
|
|
|
|
if ($minimal_keys) { |
545
|
|
|
|
|
|
|
my $minimal = _minimize_name($name_re); |
546
|
41
|
100
|
|
|
|
349
|
croak "Internal error: minimalist mode caused arguments ". |
547
|
40
|
|
|
|
|
87
|
"'$name_re' and '".$seen->{$minimal}."' to clash" |
548
|
|
|
|
|
|
|
if $seen->{$minimal}; |
549
|
537
|
|
|
|
|
1143
|
$seen->{$minimal} = $name_re; |
550
|
537
|
|
|
|
|
1452
|
} |
551
|
|
|
|
|
|
|
$longnames->{ _longestname(@variants) } = $name_re; |
552
|
|
|
|
|
|
|
return $seen; |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
63
|
|
|
63
|
|
188
|
|
556
|
63
|
|
|
|
|
137
|
sub _process_euclid_specs { |
557
|
|
|
|
|
|
|
my ($args) = @_; |
558
|
|
|
|
|
|
|
my %all_var_list; |
559
|
|
|
|
|
|
|
my %excluded_by_def; |
560
|
63
|
|
|
|
|
398
|
|
561
|
|
|
|
|
|
|
ARG: |
562
|
|
|
|
|
|
|
while ( (undef, my $arg) = each %$args ) { |
563
|
488
|
|
|
|
|
1224
|
|
564
|
486
|
|
|
|
|
1780
|
# Validate and record variable names seen here... |
565
|
378
|
|
|
|
|
1268
|
my $var_list = _validate_name( $arg->{name} ); |
566
|
|
|
|
|
|
|
while (my ($var_name, undef) = each %$var_list) { |
567
|
|
|
|
|
|
|
$all_var_list{$var_name} = undef; |
568
|
|
|
|
|
|
|
} |
569
|
486
|
100
|
|
|
|
3325
|
|
570
|
|
|
|
|
|
|
# Process arguments with a Euclid specification further |
571
|
238
|
|
|
|
|
677
|
$arg->{src} =~ s{^ =for \s+ Euclid\b [^\n]* \s* (.*) \z}{}ixms |
572
|
|
|
|
|
|
|
or next ARG; |
573
|
238
|
|
|
|
|
669
|
my $info = $1; |
574
|
|
|
|
|
|
|
|
575
|
238
|
|
|
|
|
391
|
$arg->{is_repeatable} = $info =~ s{^ \s* repeatable \s*? $}{}xms; |
576
|
238
|
|
|
|
|
671
|
|
577
|
10
|
|
|
|
|
25
|
my @false_vals; |
578
|
10
|
|
|
|
|
69
|
while ( $info =~ s{^ \s* false \s*[:=] \s* ([^\n]*)}{}xms ) { |
579
|
10
|
|
|
|
|
20
|
my $regex = $1; |
|
0
|
|
|
|
|
0
|
|
580
|
10
|
|
|
|
|
32
|
1 while $regex =~ s/ \[ ([^]]*) \] /(?:$1)?/gxms; |
581
|
|
|
|
|
|
|
$regex =~ s/ (\s+) /$1.'[\\s\\0\\1]*'/egxms; |
582
|
238
|
100
|
|
|
|
550
|
push @false_vals, $regex; |
583
|
8
|
|
|
|
|
33
|
} |
584
|
|
|
|
|
|
|
if (@false_vals) { |
585
|
|
|
|
|
|
|
$arg->{false_vals} = '(?:' . join( '|', @false_vals ) . ')'; |
586
|
238
|
|
|
|
|
1278
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
while ( |
589
|
403
|
|
|
|
|
1793
|
$info =~ m{\G \s* (([^.]+)\.([^:=\s]+) \s*[:=]\s* ([^\n]*)) }gcxms ) |
590
|
|
|
|
|
|
|
{ |
591
|
|
|
|
|
|
|
my ( $spec, $var, $field, $val ) = ( $1, $2, $3, $4 ); |
592
|
403
|
100
|
|
|
|
4198
|
|
593
|
1
|
|
|
|
|
8
|
# Check for misplaced fields... |
594
|
|
|
|
|
|
|
if ( $arg->{name} !~ m{\Q<$var>}xms ) { |
595
|
|
|
|
|
|
|
_fail( "Invalid constraint: $spec\n(No <$var> placeholder in ". |
596
|
|
|
|
|
|
|
"argument: $arg->{name})" ); |
597
|
|
|
|
|
|
|
} |
598
|
402
|
100
|
100
|
|
|
1652
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
599
|
2
|
|
|
|
|
10
|
# Decode... |
600
|
|
|
|
|
|
|
if ( $field eq 'type.error' ) { |
601
|
238
|
|
|
|
|
616
|
$arg->{var}{$var}{type_error} = $val; |
602
|
238
|
|
|
|
|
1298
|
} elsif ( $field eq 'type' ) { |
603
|
|
|
|
|
|
|
$val = _qualify_variables_fully( $val ); |
604
|
238
|
|
|
|
|
911
|
my ( $matchtype, $comma, $constraint ) = |
605
|
238
|
100
|
66
|
|
|
1042
|
$val =~ m{(/(?:\.|.)+/ | [^,\s]+)\s*(?:(,))?\s*(.*)}xms; |
|
|
100
|
|
|
|
|
|
606
|
18
|
|
|
|
|
384
|
$arg->{var}{$var}{type} = $matchtype; |
607
|
|
|
|
|
|
|
if ( $comma && length $constraint ) { |
608
|
18
|
|
|
|
|
217
|
( $arg->{var}{$var}{constraint_desc} = $constraint ) =~ |
609
|
18
|
50
|
|
|
|
2076
|
s/\s*\b\Q$var\E\b\s*//g; |
610
|
|
|
|
|
|
|
$constraint =~ s/\b\Q$var\E\b/\$_[0]/g; |
611
|
|
|
|
|
|
|
$arg->{var}{$var}{constraint} = eval "sub{ $constraint }" |
612
|
38
|
|
|
|
|
129
|
or _fail("Invalid .type constraint: $spec\n($@)"); |
613
|
|
|
|
|
|
|
} elsif ( length $constraint ) { |
614
|
38
|
50
|
|
|
|
3351
|
$arg->{var}{$var}{constraint_desc} = $constraint; |
615
|
|
|
|
|
|
|
$arg->{var}{$var}{constraint} = |
616
|
|
|
|
|
|
|
eval "sub{ \$_[0] $constraint }" |
617
|
182
|
|
|
|
|
436
|
or _fail("Invalid .type constraint: $spec\n($@)"); |
618
|
|
|
|
|
|
|
} else { |
619
|
|
|
|
|
|
|
$arg->{var}{$var}{constraint_desc} = $matchtype; |
620
|
4
|
|
|
4
|
|
13
|
$arg->{var}{$var}{constraint} = |
621
|
182
|
100
|
|
|
|
1383
|
$matchtype =~ m{\A\s*/.*/\s*\z}xms |
|
|
100
|
|
|
|
|
|
622
|
|
|
|
|
|
|
? sub { 1 } |
623
|
|
|
|
|
|
|
: $std_constraint_for{$matchtype} |
624
|
|
|
|
|
|
|
or _fail("Unknown .type constraint: $spec"); |
625
|
|
|
|
|
|
|
} |
626
|
154
|
|
|
|
|
352
|
|
627
|
154
|
100
|
|
|
|
10137
|
} elsif ( ($field eq 'default') || ($field eq 'opt_default') ) { |
628
|
|
|
|
|
|
|
$val = _qualify_variables_fully( $val ); |
629
|
153
|
|
|
|
|
706
|
eval "\$val = $val; 1" |
630
|
153
|
|
|
|
|
370
|
or _fail("Invalid .$field value: $spec\n($@)"); |
631
|
|
|
|
|
|
|
$arg->{var}{$var}{$field} = $val; |
632
|
153
|
100
|
|
|
|
504
|
my $has_field = 'has_'.$field; |
633
|
|
|
|
|
|
|
$arg->{$has_field} = exists $arg->{$has_field} ? |
634
|
|
|
|
|
|
|
$arg->{$has_field}++ : |
635
|
153
|
100
|
|
|
|
627
|
1; |
636
|
|
|
|
|
|
|
|
637
|
7
|
100
|
|
|
|
28
|
if ($field eq 'opt_default') { |
638
|
1
|
|
|
|
|
7
|
# Check that placeholders with optional defaults have a flagged argument |
639
|
|
|
|
|
|
|
if ( $arg->{name} =~ m{^<}xms ) { |
640
|
|
|
|
|
|
|
_fail( "Invalid .$field constraint: $spec\nParameter ". |
641
|
|
|
|
|
|
|
"$arg->{name} must have a flag" ); |
642
|
6
|
100
|
|
|
|
90
|
} |
643
|
1
|
|
|
|
|
7
|
# Check that placeholders with optional defaults is optional |
644
|
|
|
|
|
|
|
if ( $arg->{name} !~ m{\Q[<$var>]}xms ) { |
645
|
|
|
|
|
|
|
_fail( "Invalid .$field constraint: $spec\nPlaceholder". |
646
|
|
|
|
|
|
|
" <$var> must be optional, i.e. [<$var>], to have ". |
647
|
|
|
|
|
|
|
"an optional default in argument: $arg->{name}" ); |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
} |
650
|
1
|
|
|
|
|
4
|
|
651
|
|
|
|
|
|
|
} elsif ( $field eq 'excludes.error' ) { |
652
|
6
|
|
|
|
|
32
|
$arg->{var}{$var}{excludes_error} = $val; |
653
|
6
|
|
|
|
|
13
|
} elsif ( $field eq 'excludes' ) { |
|
6
|
|
|
|
|
22
|
|
654
|
8
|
100
|
|
|
|
41
|
$arg->{var}{$var}{excludes} = [ split '\s*,\s*', $val ]; |
655
|
1
|
|
|
|
|
5
|
for my $excl_var (@{$arg->{var}{$var}{excludes}}) { |
656
|
|
|
|
|
|
|
if ($var eq $excl_var) { |
657
|
|
|
|
|
|
|
_fail( "Invalid .excludes value for variable <$var>: ". |
658
|
|
|
|
|
|
|
"<$excl_var> cannot exclude itself." ); |
659
|
|
|
|
|
|
|
} |
660
|
1
|
|
|
|
|
5
|
} |
661
|
|
|
|
|
|
|
} else { |
662
|
|
|
|
|
|
|
_fail("Unknown specification: $spec"); |
663
|
|
|
|
|
|
|
} |
664
|
231
|
|
|
|
|
395
|
} |
|
487
|
|
|
|
|
1745
|
|
665
|
256
|
|
|
|
|
370
|
# Record variables excluded by another that has a default |
|
256
|
|
|
|
|
868
|
|
666
|
7
|
100
|
|
|
|
26
|
while (my ($var_name, $var_data) = each %{$arg->{var}}) { |
667
|
7
|
50
|
|
|
|
22
|
for my $excl_var (@{$arg->{var}{$var_name}{excludes}}) { |
668
|
|
|
|
|
|
|
$excluded_by_def{$excl_var}{default}{$var_name} = 1 if $arg->{has_default}; |
669
|
|
|
|
|
|
|
$excluded_by_def{$excl_var}{opt_default}{$var_name} = 1 if $arg->{has_opt_default}; |
670
|
231
|
100
|
|
|
|
1619
|
} |
671
|
1
|
|
|
|
|
6
|
} |
672
|
|
|
|
|
|
|
if ( $info =~ m{\G \s* ([^\s\0\1] [^\n]*) }gcxms ) { |
673
|
|
|
|
|
|
|
_fail("Unknown specification: $1"); |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
|
677
|
53
|
|
|
|
|
288
|
# Validate and complete .excludes specs |
678
|
448
|
|
|
|
|
600
|
|
|
690
|
|
|
|
|
2079
|
|
679
|
|
|
|
|
|
|
while ( (undef, my $arg) = each %$args ) { |
680
|
243
|
|
|
|
|
340
|
while ( my ($var, $var_specs) = each %{$arg->{var}} ) { |
|
243
|
|
|
|
|
462
|
|
681
|
7
|
100
|
|
|
|
18
|
# Check for invalid placeholder name in .excludes specifications |
682
|
1
|
|
|
|
|
5
|
for my $excl_var (@{$var_specs->{excludes}}) { |
683
|
|
|
|
|
|
|
if (not exists $all_var_list{$excl_var}) { |
684
|
|
|
|
|
|
|
_fail( "Invalid .excludes value for variable <$var>: ". |
685
|
|
|
|
|
|
|
"<$excl_var> does not exist\n" ); |
686
|
|
|
|
|
|
|
} |
687
|
242
|
|
|
|
|
380
|
} |
688
|
484
|
100
|
100
|
|
|
1410
|
# Remove default for placeholders excluded by others that have a default |
689
|
3
|
|
|
|
|
6
|
for my $type ( 'default', 'opt_default' ) { |
690
|
3
|
|
|
|
|
8
|
if ( (exists $arg->{var}->{$var}->{$type}) && (exists $excluded_by_def{$var}{$type}) ) { |
691
|
3
|
100
|
|
|
|
9
|
delete $arg->{var}->{$var}->{$type}; |
692
|
2
|
|
|
|
|
7
|
$arg->{"has_$type"}--; |
693
|
|
|
|
|
|
|
if ($arg->{"has_$type"} == 0) { |
694
|
|
|
|
|
|
|
delete $arg->{"has_$type"}; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
} |
699
|
52
|
|
|
|
|
185
|
} |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
return 1; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
sub _qualify_variables_fully { |
706
|
|
|
|
|
|
|
# Restore fully-qualified name to variables: |
707
|
|
|
|
|
|
|
# $x becomes $main::x |
708
|
|
|
|
|
|
|
# $::x becomes $main::x |
709
|
|
|
|
|
|
|
# $Package::x stays as $Package::x |
710
|
|
|
|
|
|
|
# /^asdf$/ stays as /^asdf$/ |
711
|
392
|
|
|
392
|
|
827
|
# '$10' stays as '$10' |
712
|
392
|
100
|
|
|
|
1073
|
# Note: perlvar indicates that ' can also be used instead of :: |
713
|
9
|
|
|
|
|
14
|
my ($val) = @_; |
714
|
9
|
|
|
294
|
|
57
|
if ($val =~ m/[\$\@\%]/) { # Avoid expensive Text::Balanced operations when there are no variables |
|
294
|
|
|
|
|
20113
|
|
715
|
10
|
100
|
|
|
|
705
|
my $new_val; |
716
|
|
|
|
|
|
|
for my $s (extract_multiple($val,[{Quoted=>sub{extract_delimited($_[0])}}],undef,0)) { |
717
|
9
|
|
|
|
|
16
|
if (not ref $s) { |
|
9
|
|
|
|
|
24
|
|
718
|
|
|
|
|
|
|
# A non-quoted section... may contain variables to fix |
719
|
11
|
100
|
|
|
|
37
|
for my $var_name ( @{_get_variable_names($s)} ) { |
720
|
|
|
|
|
|
|
# Skip fully qualified names, such as '$Package::x' |
721
|
10
|
|
|
|
|
35
|
next if $var_name =~ m/main(?:'|::)/; |
722
|
|
|
|
|
|
|
# Remove sigils from beginning of variable name: $ @ % { |
723
|
10
|
|
|
|
|
33
|
$var_name =~ s/^[\$\@\%\{]+//; |
724
|
10
|
100
|
|
|
|
161
|
# Substitute non-fully qualified vars, e.g. '$x' or '$::x', by '$main::x' |
725
|
9
|
|
|
|
|
30
|
my $new_name = Symbol::qualify($var_name, 'main'); |
726
|
9
|
|
|
|
|
112
|
next if $new_name eq $var_name; |
727
|
|
|
|
|
|
|
$var_name = quotemeta( $var_name ); |
728
|
9
|
|
|
|
|
30
|
$s =~ s/$var_name/$new_name/; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
$new_val .= $s; |
731
|
1
|
|
|
|
|
4
|
} else { |
732
|
|
|
|
|
|
|
# A quoted section, to keep as-is |
733
|
|
|
|
|
|
|
$new_val .= $$s; |
734
|
9
|
|
|
|
|
53
|
} |
735
|
|
|
|
|
|
|
} |
736
|
383
|
|
|
|
|
949
|
return $new_val; |
737
|
|
|
|
|
|
|
} else { |
738
|
|
|
|
|
|
|
return $val; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub _get_variable_names { |
744
|
|
|
|
|
|
|
# Get an arrayref of the variables names found in the provided string. |
745
|
9
|
|
|
9
|
|
25
|
# This function is a hack, needed only because of Text::Balanced ticket #78855: |
746
|
9
|
|
|
|
|
13
|
# https://rt.cpan.org/Public/Bug/Display.html?id=78855 |
747
|
9
|
|
|
172
|
|
66
|
my ($str) = @_; |
|
172
|
|
|
|
|
10290
|
|
748
|
|
|
|
|
|
|
my $vars = []; |
749
|
|
|
|
|
|
|
for my $var (extract_multiple($str,[sub{extract_variable($_[0],'')}],undef,1)) { |
750
|
13
|
|
|
|
|
1391
|
# Name must start with underscore or a letter, e.g. $t $$h{a} ${$h}{a} $h->{a} @_ |
751
|
13
|
|
|
|
|
59
|
# Skip special or invalid names, e.g. $/ $1 |
752
|
13
|
100
|
|
|
|
51
|
my $tmp = $var; |
753
|
11
|
|
|
|
|
27
|
$tmp =~ s/(?:{|})//g; |
754
|
|
|
|
|
|
|
next if not $tmp =~ m/^[\$\@\%]+[_a-z]/i; |
755
|
9
|
|
|
|
|
91
|
push @$vars, $var; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
return $vars; |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
|
760
|
700
|
|
|
700
|
|
1088
|
|
761
|
700
|
|
|
|
|
1402
|
sub _minimize_name { |
762
|
700
|
|
|
|
|
2345
|
my ($name_re) = @_; |
763
|
700
|
|
|
|
|
1166
|
$name_re =~ s{[][]}{}gxms; # remove all square brackets |
764
|
700
|
|
|
|
|
1237
|
$name_re =~ s{\A \W+ ([\w-]*) .* \z}{$1}gxms; |
765
|
|
|
|
|
|
|
$name_re =~ s{-}{_}gxms; |
766
|
|
|
|
|
|
|
return $name_re; |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
97
|
|
|
97
|
|
461
|
|
770
|
97
|
50
|
|
|
|
354
|
sub _minimize_entries_of { |
771
|
|
|
|
|
|
|
my ($arg_ref) = @_; |
772
|
97
|
|
|
|
|
372
|
return if ref $arg_ref ne 'HASH'; |
773
|
659
|
|
|
|
|
1162
|
|
774
|
659
|
|
|
|
|
1738
|
for my $old_key (keys %$arg_ref) { |
775
|
|
|
|
|
|
|
my $new_key = _minimize_name($old_key); |
776
|
|
|
|
|
|
|
$arg_ref->{$new_key} = delete $arg_ref->{$old_key}; |
777
|
97
|
|
|
|
|
260
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
return 1; |
780
|
|
|
|
|
|
|
} |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
|
783
|
62
|
|
|
62
|
|
193
|
# Do match, recursively trying to expand cuddles... |
784
|
|
|
|
|
|
|
sub _doesnt_match { |
785
|
62
|
|
|
|
|
119
|
my ( $matcher, $argv, $arg_specs_ref ) = @_; |
786
|
62
|
|
|
|
|
169
|
|
787
|
62
|
|
|
|
|
142
|
our @errors; # 'our' instead of 'my' because it is needed for the re pragma |
788
|
|
|
|
|
|
|
local @errors = (); |
789
|
|
|
|
|
|
|
%ARGV = (); |
790
|
|
|
|
|
|
|
|
791
|
62
|
|
|
|
|
64655
|
# Match arguments, populate %ARGV and @errors |
792
|
|
|
|
|
|
|
# Note that the matcher needs the pragma: use re 'eval'; |
793
|
|
|
|
|
|
|
$argv =~ m{\A (?: \s* $matcher )* \s* \z}xms; |
794
|
62
|
|
|
|
|
431
|
|
795
|
12
|
100
|
|
|
|
61
|
# Report errors in passed arguments |
796
|
5
|
|
|
|
|
23
|
for my $error (@errors) { |
797
|
5
|
|
|
|
|
71
|
if ( $error =~ m/\A ((\W) (\w) (\w+))/xms ) { |
798
|
5
|
100
|
|
|
|
33
|
my ( $bundle, $marker, $firstchar, $chars ) = ( $1, $2, $3, $4 ); |
799
|
|
|
|
|
|
|
$argv =~ s{\Q$bundle\E}{$marker$firstchar $marker$chars}xms; |
800
|
|
|
|
|
|
|
return if !_doesnt_match( $matcher, $argv, $arg_specs_ref ); |
801
|
10
|
|
|
|
|
23
|
} |
|
10
|
|
|
|
|
39
|
|
802
|
54
|
|
|
|
|
115
|
ARG: |
803
|
54
|
|
|
|
|
74
|
for my $arg_spec_ref ( values %{$arg_specs_ref} ) { |
804
|
|
|
|
|
|
|
our $bad_type; |
805
|
54
|
100
|
100
|
|
|
5279
|
local $bad_type; |
806
|
|
|
|
|
|
|
next ARG |
807
|
|
|
|
|
|
|
if $error !~ m/\A [\s\0\1]* ($arg_spec_ref->{generic_matcher})/xms |
808
|
|
|
|
|
|
|
|| !$bad_type; |
809
|
4
|
|
|
|
|
22
|
|
810
|
4
|
|
|
|
|
110
|
my $msg = _type_error( $bad_type->{arg}, $bad_type->{var}, |
811
|
|
|
|
|
|
|
$bad_type->{val}, $bad_type->{type}, $bad_type->{type_error} ); |
812
|
6
|
|
|
|
|
62
|
return $msg; |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
return "Unknown argument: $error"; |
815
|
50
|
|
|
|
|
462
|
} |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
return 0; # No error |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
629
|
|
|
629
|
|
938
|
|
821
|
629
|
|
|
|
|
1014
|
sub _escape_arg { |
822
|
629
|
|
|
|
|
1686
|
my $arg = shift; |
823
|
|
|
|
|
|
|
my ($num_replaced) = ($arg =~ tr/ \t/\0\1/); |
824
|
|
|
|
|
|
|
return $arg; |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
428
|
|
|
428
|
|
695
|
|
828
|
428
|
|
|
|
|
850
|
sub _rectify_arg { |
829
|
428
|
|
|
|
|
1421
|
my $arg = shift; |
830
|
|
|
|
|
|
|
my ($num_replaced) = ($arg =~ tr/\0\1/ \t/); |
831
|
|
|
|
|
|
|
return $arg; |
832
|
|
|
|
|
|
|
} |
833
|
|
|
|
|
|
|
|
834
|
49
|
|
|
49
|
|
263
|
|
835
|
275
|
|
|
|
|
427
|
sub _rectify_all_args { |
|
275
|
|
|
|
|
650
|
|
836
|
286
|
50
|
|
|
|
581
|
while ( my (undef, $arg_list) = each %ARGV ) { |
837
|
286
|
|
|
|
|
407
|
for my $arg ( @{$arg_list} ) { |
|
286
|
|
|
|
|
717
|
|
838
|
312
|
100
|
|
|
|
578
|
if ( ref $arg eq 'HASH' ) { |
839
|
35
|
|
|
|
|
41
|
for my $var ( values %{$arg} ) { |
|
135
|
|
|
|
|
202
|
|
|
35
|
|
|
|
|
53
|
|
840
|
|
|
|
|
|
|
if ( ref $var eq 'ARRAY' ) { |
841
|
277
|
|
|
|
|
508
|
$var = [ map { _rectify_arg($_) } @{$var} ]; |
842
|
|
|
|
|
|
|
} else { |
843
|
|
|
|
|
|
|
$var = _rectify_arg($var); |
844
|
|
|
|
|
|
|
} |
845
|
0
|
0
|
|
|
|
0
|
} |
846
|
0
|
|
|
|
|
0
|
} else { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
847
|
|
|
|
|
|
|
if ( ref $arg eq 'ARRAY' ) { |
848
|
0
|
|
|
|
|
0
|
$arg = [ map { _rectify_arg($_) } @{$arg} ]; |
849
|
|
|
|
|
|
|
} else { |
850
|
|
|
|
|
|
|
$arg = _rectify_arg($arg); |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
} |
853
|
49
|
|
|
|
|
101
|
} |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
return 1; |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
|
858
|
49
|
|
|
49
|
|
270
|
|
859
|
|
|
|
|
|
|
sub _verify_args { |
860
|
|
|
|
|
|
|
my ($arg_specs_ref) = @_; |
861
|
49
|
|
|
|
|
110
|
# Check exclusive variables, variable constraints and fill in defaults... |
862
|
49
|
|
|
|
|
328
|
# Handle mutually exclusive arguments |
863
|
275
|
|
|
|
|
369
|
my %seen_vars; |
|
275
|
|
|
|
|
479
|
|
864
|
286
|
|
|
|
|
371
|
while ( my ($arg_name, $arg_elems) = each %ARGV ) { |
|
598
|
|
|
|
|
1814
|
|
865
|
312
|
100
|
|
|
|
945
|
for my $elem (@{$arg_elems}) { |
866
|
|
|
|
|
|
|
while ( my ($var_name) = each (%{$elem}) ) { |
867
|
|
|
|
|
|
|
$seen_vars{$var_name} = $arg_name if $var_name; |
868
|
|
|
|
|
|
|
} |
869
|
|
|
|
|
|
|
} |
870
|
49
|
|
|
|
|
124
|
} |
|
489
|
|
|
|
|
1097
|
|
871
|
443
|
|
|
|
|
583
|
|
|
785
|
|
|
|
|
1849
|
|
872
|
|
|
|
|
|
|
while ( my ($arg_name, $arg) = each %{$arg_specs_ref} ) { |
873
|
345
|
|
|
|
|
424
|
while ( my ($var_name, $var) = each %{$arg->{var}} ) { |
|
345
|
|
|
|
|
753
|
|
874
|
11
|
50
|
66
|
|
|
44
|
# Enforce placeholders that cannot be specified with others |
875
|
|
|
|
|
|
|
for my $excluded_var ( @{$var->{excludes}} ) { |
876
|
3
|
|
|
|
|
11
|
if (exists $seen_vars{$var_name} && |
877
|
3
|
|
|
|
|
4
|
exists $seen_vars{$excluded_var}) { |
878
|
3
|
100
|
|
|
|
9
|
my $excl_arg = $seen_vars{$excluded_var}; |
879
|
1
|
|
|
|
|
2
|
my $msg; |
880
|
|
|
|
|
|
|
if (exists $var->{excludes_error}) { |
881
|
2
|
|
|
|
|
13
|
$msg = $var->{excludes_error}; |
882
|
|
|
|
|
|
|
} else { |
883
|
|
|
|
|
|
|
$msg = |
884
|
|
|
|
|
|
|
qq{Invalid "$excl_arg" argument.\n<$excluded_var> }. |
885
|
|
|
|
|
|
|
qq{cannot be specified with <$var_name> because }. |
886
|
3
|
|
|
|
|
8
|
qq{argument "$arg_name" excludes <$excluded_var>}; |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
_bad_arglist($msg); |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
} |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
46
|
|
|
|
|
167
|
# Enforce constraints and fill in defaults... |
|
445
|
|
|
|
|
1190
|
|
895
|
|
|
|
|
|
|
ARG: |
896
|
|
|
|
|
|
|
while (my ($arg_name, $arg_specs) = each %{$arg_specs_ref} ) { |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
# Skip non-existent/non-defaulting/non-optional-defaulting arguments |
899
|
|
|
|
|
|
|
next ARG |
900
|
404
|
100
|
100
|
|
|
1314
|
if !exists $ARGV{$arg_name} |
|
|
|
100
|
|
|
|
|
901
|
|
|
|
|
|
|
&& !( $arg_specs->{has_default} |
902
|
|
|
|
|
|
|
|| $arg_specs->{has_opt_default} ); |
903
|
280
|
|
|
|
|
378
|
|
|
280
|
|
|
|
|
849
|
|
904
|
280
|
|
|
|
|
422
|
# Ensure all vars exist within arg... |
|
280
|
|
|
|
|
673
|
|
905
|
256
|
|
|
|
|
427
|
my @vars = keys %{$arg_specs->{placeholders}}; |
906
|
256
|
|
|
|
|
375
|
for my $index ( 0 .. $#{ $ARGV{$arg_name} } ) { |
|
256
|
|
|
|
|
393
|
|
|
256
|
|
|
|
|
425
|
|
907
|
|
|
|
|
|
|
my $entry = $ARGV{$arg_name}[$index]; |
908
|
|
|
|
|
|
|
@{$entry}{@vars} = @{$entry}{@vars}; |
909
|
|
|
|
|
|
|
|
910
|
256
|
|
|
|
|
435
|
# Get arg specs... |
911
|
|
|
|
|
|
|
VAR: |
912
|
258
|
|
|
|
|
399
|
for my $var (@vars) { |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
my $arg_vars = $arg_specs->{var}->{$var}; |
915
|
258
|
50
|
|
|
|
498
|
|
916
|
|
|
|
|
|
|
# Check constraints on vars... |
917
|
258
|
100
|
66
|
|
|
1211
|
if ( exists $ARGV{$arg_name} ) { |
|
|
50
|
33
|
|
|
|
|
918
|
|
|
|
|
|
|
|
919
|
228
|
100
|
|
|
|
560
|
if ( ref $entry eq 'HASH' && defined $entry->{$var} ) { |
920
|
|
|
|
|
|
|
# Named vars... |
921
|
35
|
|
|
|
|
61
|
for my $val ( |
922
|
|
|
|
|
|
|
ref $entry->{$var} eq 'ARRAY' |
923
|
|
|
|
|
|
|
? @{ $entry->{$var} } |
924
|
|
|
|
|
|
|
: $entry->{$var} |
925
|
328
|
100
|
100
|
|
|
2101
|
) |
926
|
|
|
|
|
|
|
{ |
927
|
|
|
|
|
|
|
if ( $arg_vars->{constraint} && |
928
|
|
|
|
|
|
|
!$arg_vars->{constraint}->($val) ) { |
929
|
5
|
|
|
|
|
29
|
_bad_arglist( _type_error($arg_name, $var, $val, |
930
|
|
|
|
|
|
|
$arg_vars->{constraint_desc}, |
931
|
|
|
|
|
|
|
$arg_vars->{type_error}) ); |
932
|
223
|
|
|
|
|
683
|
} |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
next VAR; |
935
|
0
|
0
|
|
|
|
0
|
} elsif ( ref $entry ne 'HASH' && defined $entry ) { |
936
|
|
|
|
|
|
|
# Unnamed vars... |
937
|
0
|
|
|
|
|
0
|
for my $val ( |
938
|
|
|
|
|
|
|
ref $entry eq 'ARRAY' |
939
|
|
|
|
|
|
|
? @{$entry} |
940
|
|
|
|
|
|
|
: $entry |
941
|
0
|
0
|
0
|
|
|
0
|
) |
942
|
|
|
|
|
|
|
{ |
943
|
|
|
|
|
|
|
if ( $arg_vars->{constraint} && |
944
|
|
|
|
|
|
|
!$arg_vars->{constraint}->($val) ) { |
945
|
0
|
|
|
|
|
0
|
_bad_arglist( _type_error( $arg_name, $var, $val, |
946
|
|
|
|
|
|
|
$arg_vars->{constraint_desc}, |
947
|
|
|
|
|
|
|
$arg_vars->{type_error}) ); |
948
|
0
|
0
|
|
|
|
0
|
} |
949
|
|
|
|
|
|
|
$entry->{$var} = '' |
950
|
0
|
|
|
|
|
0
|
unless defined( $ARGV{$arg_name} ); |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
next VAR; |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
} |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
# Assign placeholder defaults (if necessary)... |
957
|
30
|
100
|
100
|
|
|
189
|
next ARG |
958
|
|
|
|
|
|
|
if !exists $arg_vars->{default} |
959
|
|
|
|
|
|
|
&& !exists $arg_vars->{opt_default}; |
960
|
|
|
|
|
|
|
|
961
|
17
|
100
|
|
|
|
58
|
$entry->{$var} = exists $arg_vars->{opt_default} ? |
962
|
|
|
|
|
|
|
$arg_vars->{opt_default} : |
963
|
|
|
|
|
|
|
$arg_vars->{default}; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
} |
966
|
262
|
100
|
|
|
|
373
|
|
|
262
|
|
|
|
|
809
|
|
967
|
35
|
|
|
|
|
81
|
# Handle defaults for missing args... |
968
|
|
|
|
|
|
|
if ( !@{ $ARGV{$arg_name} } ) { |
969
|
36
|
|
|
|
|
63
|
for my $var (@vars) { |
970
|
|
|
|
|
|
|
# Assign defaults (if necessary)... |
971
|
36
|
100
|
|
|
|
95
|
my $arg_vars = $arg_specs->{var}->{$var}; |
972
|
|
|
|
|
|
|
next ARG |
973
|
|
|
|
|
|
|
if !exists $arg_vars->{default}; # no default specified |
974
|
31
|
|
|
|
|
99
|
|
|
31
|
|
|
|
|
80
|
|
975
|
5
|
100
|
|
|
|
12
|
# Omit default if it conflicts with a specified parameter |
976
|
3
|
|
|
|
|
7
|
for my $excl_var ( @{$arg_specs->{var}->{$var}->{excludes}} ) { |
977
|
|
|
|
|
|
|
if (exists $seen_vars{$excl_var}) { |
978
|
|
|
|
|
|
|
next ARG; |
979
|
|
|
|
|
|
|
} |
980
|
28
|
|
|
|
|
104
|
} |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
$ARGV{$arg_name}[0]{$var} = $arg_vars->{default}; |
983
|
|
|
|
|
|
|
} |
984
|
41
|
|
|
|
|
183
|
} |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
return 1; |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
|
989
|
9
|
|
|
9
|
|
51
|
|
990
|
9
|
|
|
|
|
30
|
sub _type_error { |
991
|
9
|
|
|
|
|
35
|
my ($arg_name, $var_name, $var_val, $var_constraint, $var_error) = @_; |
992
|
9
|
100
|
|
|
|
27
|
my $msg = qq{Invalid "$arg_name" argument.\n}; |
993
|
3
|
|
|
|
|
7
|
$var_name =~ s{\W+}{}gxms; |
994
|
3
|
|
|
|
|
61
|
if ( $var_error ) { |
995
|
|
|
|
|
|
|
$msg = $var_error; |
996
|
6
|
|
|
|
|
28
|
$msg =~ s{(?)}{$var_val}gxms; |
997
|
|
|
|
|
|
|
} else { |
998
|
|
|
|
|
|
|
$msg = qq{<$var_name> must be $var_constraint but the supplied value }. |
999
|
9
|
|
|
|
|
36
|
qq{("$var_val") is not.}; |
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
return $msg; |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
51
|
|
|
51
|
|
157
|
|
1005
|
|
|
|
|
|
|
sub _convert_to_regex { |
1006
|
|
|
|
|
|
|
my ($args_ref) = @_; |
1007
|
51
|
|
|
|
|
117
|
|
1008
|
|
|
|
|
|
|
# Regexp to capture the start of a new argument |
1009
|
51
|
|
|
|
|
99
|
my $no_esc_ws = '(?!\0)'; # no escaped whitespaces |
1010
|
51
|
|
|
|
|
115
|
|
|
486
|
|
|
|
|
1273
|
|
1011
|
435
|
|
|
|
|
681
|
my @arg_variants; |
|
435
|
|
|
|
|
1041
|
|
1012
|
|
|
|
|
|
|
while ( my ($arg_name, $arg_specs) = each %{$args_ref} ) { |
1013
|
|
|
|
|
|
|
push @arg_variants, @{$arg_specs->{variants}}; |
1014
|
51
|
|
|
|
|
266
|
} |
1015
|
51
|
|
|
|
|
201
|
|
1016
|
51
|
|
|
|
|
204
|
my $no_match = join('|',@arg_variants); |
1017
|
|
|
|
|
|
|
$no_match = _escape_specials($no_match); |
1018
|
51
|
|
|
|
|
138
|
$no_match = '(?!(?:'.$no_match.')'.$no_esc_ws.')'; |
|
486
|
|
|
|
|
1478
|
|
1019
|
435
|
|
|
|
|
711
|
|
1020
|
|
|
|
|
|
|
while ( my ($arg_name, $arg) = each %{$args_ref} ) { |
1021
|
|
|
|
|
|
|
my $regex = $arg_name; |
1022
|
435
|
|
|
|
|
776
|
|
1023
|
435
|
|
|
|
|
972
|
# Quotemeta specials... |
1024
|
|
|
|
|
|
|
$regex = _escape_specials($regex); |
1025
|
|
|
|
|
|
|
$regex = "(?:$regex)"; |
1026
|
435
|
|
|
|
|
2271
|
|
1027
|
435
|
|
|
|
|
1282
|
# Convert optionals... |
|
321
|
|
|
|
|
1231
|
|
1028
|
435
|
|
|
|
|
786
|
1 while $regex =~ s/ \[ ([^]]*) \] /(?:$1)?/gxms; |
1029
|
|
|
|
|
|
|
$regex =~ s/ (\s+) /$1.'\s*'.$no_esc_ws/egxms; |
1030
|
|
|
|
|
|
|
my $generic = $regex; |
1031
|
|
|
|
|
|
|
|
1032
|
347
|
|
|
|
|
975
|
# Set the matcher |
1033
|
347
|
|
|
|
|
526
|
$regex =~ |
1034
|
347
|
|
100
|
|
|
1256
|
s{ < (.*?) >(\.\.\.|) } |
1035
|
347
|
|
|
|
|
967
|
{ my ($var_name, $var_rep) = ($1, $2); |
1036
|
|
|
|
|
|
|
$var_name =~ s/(\s+)\[\\s\\0\\1]\*/$1/gxms; |
1037
|
|
|
|
|
|
|
my $type = $arg->{var}{$var_name}{type} || q{}; |
1038
|
|
|
|
|
|
|
$arg->{placeholders}->{$var_name} = undef; |
1039
|
347
|
100
|
|
|
|
1518
|
my $matcher = |
|
|
50
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
$type =~ m{\A\s*/.*/\s*\z}xms |
1041
|
347
|
100
|
|
|
|
1947
|
? eval "qr$type" |
1042
|
|
|
|
|
|
|
: $std_matcher_for{ $type } |
1043
|
|
|
|
|
|
|
or _fail("Unknown type ($type) in specification: $arg_name"); |
1044
|
|
|
|
|
|
|
$var_rep ? |
1045
|
|
|
|
|
|
|
"(?:[\\s\\0\\1]*$no_match($matcher)(?{push \@{(\$ARGV{q{$arg_name}}||=[{}])->[-1]{q{$var_name}}}, \$^N}))+" |
1046
|
435
|
100
|
|
|
|
1360
|
: |
1047
|
167
|
|
|
|
|
414
|
"(?:$no_match($matcher)(?{(\$ARGV{q{$arg_name}}||=[{}])->[-1]{q{$var_name}} = \$^N}))"; |
1048
|
|
|
|
|
|
|
}gexms |
1049
|
|
|
|
|
|
|
or do { |
1050
|
435
|
100
|
|
|
|
956
|
$regex .= "(?{(\$ARGV{q{$arg_name}}||=[{}])->[-1]{q{}} = 1})"; |
1051
|
6
|
|
|
|
|
19
|
}; |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
if ( $arg->{is_repeatable} ) { |
1054
|
|
|
|
|
|
|
$arg->{matcher} = "$regex (?:(?
|
1055
|
|
|
|
|
|
|
} else { |
1056
|
429
|
100
|
|
|
|
2120
|
$arg->{matcher} = "(??{exists\$ARGV{q{$arg_name}}?'(?!)':''}) " |
1057
|
|
|
|
|
|
|
. ( |
1058
|
|
|
|
|
|
|
$arg->{false_vals} |
1059
|
|
|
|
|
|
|
? "(?:$arg->{false_vals} (?:(? 0 }] }) | $regex (?:(? 1}] }))" |
1060
|
|
|
|
|
|
|
: "$regex (?:(?
|
1061
|
|
|
|
|
|
|
); |
1062
|
435
|
|
|
|
|
1508
|
} |
1063
|
347
|
|
|
|
|
784
|
|
1064
|
347
|
|
|
|
|
485
|
# Set the generic matcher |
1065
|
347
|
|
100
|
|
|
1107
|
$generic =~ |
1066
|
347
|
|
100
|
|
|
1173
|
s{ < (.*?) > } |
1067
|
|
|
|
|
|
|
{ my $var_name = $1; |
1068
|
|
|
|
|
|
|
$var_name =~ s/(\s+)\[\\s\\0\\1]\*/$1/gxms; |
1069
|
347
|
100
|
|
|
|
1165
|
my $type = $arg->{var}{$var_name}{type} || q{}; |
1070
|
347
|
|
|
|
|
1770
|
my $type_error = $arg->{var}{$var_name}{type_error} || q{}; |
1071
|
|
|
|
|
|
|
my $matcher = $type =~ m{\A\s*/.*/\s*\z}xms |
1072
|
|
|
|
|
|
|
? eval "qr$type" |
1073
|
|
|
|
|
|
|
: $std_matcher_for{ $type }; |
1074
|
435
|
|
|
|
|
1238
|
"(?:($matcher|([^\\s\\0\\1]+)" |
1075
|
|
|
|
|
|
|
. "(?{\$bad_type ||= " |
1076
|
51
|
|
|
|
|
168
|
. "{arg=>q{$arg_name},type=>q{$type},type_error=>q{$type_error}, var=>q{<$var_name>},val=>\$^N};})))" |
1077
|
|
|
|
|
|
|
}gexms; |
1078
|
|
|
|
|
|
|
$arg->{generic_matcher} = $generic; |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
return 1; |
1081
|
|
|
|
|
|
|
} |
1082
|
486
|
|
|
486
|
|
765
|
|
1083
|
486
|
|
|
|
|
972
|
|
1084
|
486
|
|
|
|
|
1218
|
sub _escape_specials { |
1085
|
|
|
|
|
|
|
# Escape quotemeta special characters |
1086
|
|
|
|
|
|
|
my $arg = shift; |
1087
|
|
|
|
|
|
|
$arg =~ s{([@#\$^*()+{}?])}{\\$1}gxms; |
1088
|
|
|
|
|
|
|
return $arg; |
1089
|
0
|
|
|
0
|
|
0
|
} |
1090
|
|
|
|
|
|
|
|
1091
|
0
|
0
|
|
|
|
0
|
|
1092
|
|
|
|
|
|
|
sub _print_pod { |
1093
|
0
|
0
|
|
|
|
0
|
my ( $pod, $paged ) = @_; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
if ($paged) { |
1096
|
|
|
|
|
|
|
# Page output |
1097
|
0
|
0
|
|
|
|
0
|
eval { require IO::Pager::Page } or eval { require IO::Page }; |
1098
|
0
|
|
|
|
|
0
|
} |
1099
|
0
|
|
|
|
|
0
|
|
1100
|
|
|
|
|
|
|
# Convert POD to plaintext, wrapping the lines at 76 chars and print to STDOUT |
1101
|
0
|
|
|
|
|
0
|
open my $parser_in, '<', \$pod or croak "Could not read from variable because $!"; |
1102
|
|
|
|
|
|
|
Pod::PlainText->new()->parse_from_filehandle($parser_in); |
1103
|
|
|
|
|
|
|
close $parser_in; |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
return 1; |
1106
|
|
|
|
|
|
|
} |
1107
|
|
|
|
|
|
|
|
1108
|
488
|
|
|
488
|
|
925
|
|
1109
|
488
|
100
|
|
|
|
1493
|
sub _validate_name { |
1110
|
303
|
|
|
|
|
497
|
# Check that the argument name only has pairs of < > brackets (ticket 34199) |
1111
|
303
|
|
|
|
|
462
|
# Return the name of the variables that this argument specifies |
1112
|
303
|
|
|
3455
|
|
1898
|
my ($name) = @_; |
|
3455
|
|
|
|
|
251756
|
|
1113
|
842
|
100
|
|
|
|
36487
|
if ($name =~ m/[<>]/) { # skip expensive Text::Balance functions if possible |
1114
|
393
|
|
|
|
|
1720
|
my %var_names; |
1115
|
393
|
100
|
|
|
|
1180
|
my $pos = 0; |
1116
|
2
|
|
|
|
|
7
|
for my $s (extract_multiple($name,[sub{extract_bracketed($_[0],'<>')}],undef,0)) { |
1117
|
|
|
|
|
|
|
next if not $s =~ m/[<>]/; |
1118
|
391
|
|
|
|
|
600
|
$s =~ s/^<(.*)>$/$1/; |
1119
|
391
|
100
|
|
|
|
1290
|
if ( $s =~ m/[<>]/ ) { |
1120
|
|
|
|
|
|
|
_fail( 'Invalid argument specification: '.$name ); |
1121
|
301
|
|
|
|
|
1547
|
} |
1122
|
|
|
|
|
|
|
$pos++; |
1123
|
185
|
|
|
|
|
408
|
$var_names{$s} = $pos if not exists $var_names{$s}; |
1124
|
|
|
|
|
|
|
} |
1125
|
|
|
|
|
|
|
return \%var_names; |
1126
|
|
|
|
|
|
|
} else { |
1127
|
|
|
|
|
|
|
return {}; |
1128
|
|
|
|
|
|
|
} |
1129
|
798
|
|
|
798
|
|
30267
|
} |
1130
|
|
|
|
|
|
|
|
1131
|
798
|
|
|
|
|
2485
|
|
1132
|
823
|
|
|
|
|
3877
|
sub _get_variants { |
1133
|
|
|
|
|
|
|
my @arg_desc = shift =~ m{ [^[|]+ (?: $optional_re [^[|]* )* }gmxs; |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
for (@arg_desc) { |
1136
|
798
|
100
|
|
|
|
2527
|
s{^ \s+ | \s+ $}{}gxms; |
1137
|
|
|
|
|
|
|
} |
1138
|
761
|
|
|
|
|
3489
|
|
1139
|
|
|
|
|
|
|
# Only consider first "word"... |
1140
|
|
|
|
|
|
|
return $1 if $arg_desc[0] =~ m/\A (< [^>]+ >)/xms; |
1141
|
761
|
|
|
|
|
1302
|
|
1142
|
761
|
|
|
|
|
1525
|
$arg_desc[0] =~ s/\A ([^\s<]+) \s* (?: < .*)? \z/$1/xms; |
1143
|
3047
|
|
|
|
|
4867
|
|
1144
|
3047
|
|
|
|
|
4473
|
# Variants are all those with and without each optional component... |
1145
|
|
|
|
|
|
|
my %variants; |
1146
|
3047
|
100
|
|
|
|
7754
|
while (@arg_desc) { |
1147
|
1164
|
|
|
|
|
2172
|
my $arg_desc_with = shift @arg_desc; |
1148
|
|
|
|
|
|
|
my $arg_desc_without = $arg_desc_with; |
1149
|
3047
|
100
|
|
|
|
7090
|
|
1150
|
1164
|
|
|
|
|
2222
|
if ( $arg_desc_without =~ s/ \[ [^][]* \] //xms ) { |
1151
|
1164
|
|
|
|
|
2659
|
push @arg_desc, $arg_desc_without; |
1152
|
1097
|
|
|
|
|
1594
|
} |
1153
|
1097
|
|
|
|
|
3050
|
if ( $arg_desc_with =~ m/ [[(] ([^][()]*) [])] /xms ) { |
1154
|
1097
|
|
|
|
|
2523
|
my $option = $1; |
1155
|
|
|
|
|
|
|
for my $alternative ( split /\|/, $option ) { |
1156
|
|
|
|
|
|
|
my $arg_desc = $arg_desc_with; |
1157
|
|
|
|
|
|
|
$arg_desc =~ s{[[(] [^][()]* [])]}{$alternative}xms; |
1158
|
3047
|
|
|
|
|
6624
|
push @arg_desc, $arg_desc; |
1159
|
3047
|
|
|
|
|
7667
|
} |
1160
|
3047
|
|
|
|
|
7635
|
} |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
$arg_desc_with =~ s/[][]//gxms; |
1163
|
761
|
|
|
|
|
3034
|
$arg_desc_with =~ s/\b[^-\w] .* \z//xms; |
1164
|
|
|
|
|
|
|
$variants{$arg_desc_with} = 1; |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
return keys %variants; |
1168
|
565
|
50
|
|
565
|
|
2019
|
} |
|
537
|
|
|
|
|
1688
|
|
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
sub _longestname { |
1172
|
|
|
|
|
|
|
return ( sort { length $a <=> length $b || $a cmp $b } @_ )[-1]; |
1173
|
45
|
|
|
45
|
|
88
|
} |
1174
|
45
|
|
|
|
|
82
|
|
1175
|
45
|
|
|
|
|
105
|
|
1176
|
45
|
|
50
|
|
|
167
|
sub _export_var { |
1177
|
65
|
|
|
65
|
|
629
|
my ( $prefix, $key, $value ) = @_; |
|
65
|
|
|
|
|
143
|
|
|
65
|
|
|
|
|
22128
|
|
1178
|
45
|
100
|
|
|
|
88
|
my $export_as = $prefix . $key; |
|
45
|
|
|
|
|
257
|
|
1179
|
45
|
|
|
|
|
128
|
$export_as =~ s{\W}{_}gxms; # mainly for '-' |
1180
|
|
|
|
|
|
|
my $callpkg = caller( $export_lvl + ($Exporter::ExportLevel || 0) ); |
1181
|
|
|
|
|
|
|
no strict 'refs'; |
1182
|
|
|
|
|
|
|
*{"$callpkg\::$export_as"} = ( ref $value ) ? $value : \$value; |
1183
|
|
|
|
|
|
|
return 1; |
1184
|
|
|
|
|
|
|
} |
1185
|
130
|
|
|
130
|
|
538
|
|
1186
|
|
|
|
|
|
|
|
1187
|
130
|
|
|
|
|
768
|
# Utility sub to factor out hash key aliasing... |
1188
|
910
|
|
|
|
|
1417
|
sub _make_equivalent { |
1189
|
2730
|
|
|
|
|
5921
|
my ( $hash_ref, %alias_hash ) = @_; |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
while ( my ( $name_re, $aliases ) = each %alias_hash ) { |
1192
|
|
|
|
|
|
|
for my $alias (@$aliases) { |
1193
|
130
|
|
|
|
|
339
|
$hash_ref->{$alias} = $hash_ref->{$name_re}; |
1194
|
|
|
|
|
|
|
} |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
return 1; |
1198
|
|
|
|
|
|
|
} |
1199
|
12
|
|
|
12
|
|
34
|
|
1200
|
12
|
|
|
|
|
2808
|
|
1201
|
|
|
|
|
|
|
# Report problems in specification and die |
1202
|
|
|
|
|
|
|
sub _fail { |
1203
|
|
|
|
|
|
|
my (@msg) = @_; |
1204
|
|
|
|
|
|
|
croak "Getopt::Euclid: @msg"; |
1205
|
|
|
|
|
|
|
} |
1206
|
67
|
|
|
67
|
|
449
|
|
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
sub _get_pod_names { |
1209
|
67
|
50
|
|
|
|
238
|
# Parse the POD of the caller program and its modules. |
1210
|
0
|
|
|
|
|
0
|
my @caller = caller(1); |
1211
|
0
|
|
|
|
|
0
|
|
1212
|
0
|
|
|
|
|
0
|
# Sanity check |
1213
|
|
|
|
|
|
|
if ($has_run) { |
1214
|
|
|
|
|
|
|
carp 'Getopt::Euclid loaded a second time'; |
1215
|
|
|
|
|
|
|
warn "Second attempt to parse command-line was ignored\n"; |
1216
|
67
|
100
|
|
|
|
316
|
return 0; |
1217
|
4
|
|
|
|
|
20
|
} |
1218
|
4
|
|
|
|
|
10
|
|
1219
|
|
|
|
|
|
|
# Handle calls from .pm files |
1220
|
65
|
|
|
65
|
|
585
|
if ( $caller[1] =~ m/[.]pm \z/xms ) { |
|
65
|
|
|
|
|
189
|
|
|
65
|
|
|
|
|
48752
|
|
1221
|
|
|
|
|
|
|
my @caller = caller(1); # at import()'s level |
1222
|
4
|
50
|
|
|
|
5
|
push @pod_names, $caller[1]; |
|
4
|
|
|
|
|
41
|
|
1223
|
4
|
|
|
|
|
6
|
# Install this import() sub as module's import sub... |
1224
|
4
|
|
|
|
|
25
|
no strict 'refs'; |
1225
|
4
|
|
|
4
|
|
70
|
croak '.pm file cannot define an explicit import() when using Getopt::Euclid' |
|
4
|
|
|
|
|
17
|
|
1226
|
4
|
|
|
|
|
25
|
if *{"$caller[0]::import"}{CODE}; |
1227
|
|
|
|
|
|
|
my $lambda; # Needed so the anon sub is generated at run-time |
1228
|
4
|
|
|
|
|
152
|
*{"$caller[0]::import"} |
1229
|
|
|
|
|
|
|
= bless sub { $lambda = 1; goto &Getopt::Euclid::import }, |
1230
|
|
|
|
|
|
|
'Getopt::Euclid::Importer'; |
1231
|
|
|
|
|
|
|
|
1232
|
63
|
100
|
|
|
|
1761
|
return 0; |
1233
|
|
|
|
|
|
|
} |
1234
|
63
|
|
|
|
|
416
|
|
1235
|
|
|
|
|
|
|
# Add name of caller program |
1236
|
|
|
|
|
|
|
push @pod_names, $0 if (-e $0); # When calling perl -e '...', $0 is '-e', i.e. not a actual file |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
return 1; |
1239
|
103
|
|
|
103
|
|
228
|
} |
1240
|
103
|
|
|
|
|
189
|
|
1241
|
|
|
|
|
|
|
|
1242
|
103
|
|
|
|
|
469
|
sub _insert_default_values { |
|
880
|
|
|
|
|
1500
|
|
1243
|
436
|
|
|
|
|
778
|
my ($args) = @_; |
1244
|
436
|
|
|
|
|
697
|
my $pod_string = ''; |
1245
|
436
|
|
|
|
|
822
|
# Retrieve item names in sequential order |
1246
|
|
|
|
|
|
|
for my $item_name ( sort { $args->{$a}->{'seq'} <=> $args->{$b}->{'seq'} } (keys %$args) ) { |
1247
|
436
|
|
|
|
|
586
|
my $item_spec = $args->{$item_name}->{'src'}; |
|
672
|
|
|
|
|
2016
|
|
1248
|
|
|
|
|
|
|
$item_spec =~ s/=for(.*)//ms; |
1249
|
236
|
|
|
|
|
388
|
$pod_string .= "=item $item_name\n\n"; |
1250
|
472
|
|
|
|
|
746
|
# Get list of variable for this argument |
1251
|
472
|
100
|
|
|
|
864
|
while ( my ($var_name, $var) = each %{$args->{$item_name}->{var}} ) { |
1252
|
132
|
100
|
|
|
|
467
|
# Get default for this variable |
|
|
50
|
|
|
|
|
|
1253
|
1
|
|
|
|
|
2
|
for my $default_type ( 'default', 'opt_default' ) { |
|
1
|
|
|
|
|
13
|
|
1254
|
|
|
|
|
|
|
my $var_default; |
1255
|
131
|
|
|
|
|
242
|
if (exists $var->{$default_type}) { |
1256
|
|
|
|
|
|
|
if (ref($var->{$default_type}) eq 'ARRAY') { |
1257
|
0
|
|
|
|
|
0
|
$var_default = join(' ', @{$var->{$default_type}}); |
1258
|
|
|
|
|
|
|
} elsif (ref($var->{$default_type}) eq '') { |
1259
|
|
|
|
|
|
|
$var_default = $var->{$default_type}; |
1260
|
340
|
|
|
|
|
484
|
} else { |
1261
|
|
|
|
|
|
|
carp 'Getopt::Euclid found an unexpected default value type'; |
1262
|
472
|
|
|
|
|
4265
|
} |
1263
|
|
|
|
|
|
|
} else { |
1264
|
|
|
|
|
|
|
$var_default = 'none'; |
1265
|
436
|
100
|
|
|
|
1110
|
} |
1266
|
1
|
|
|
|
|
4
|
$item_spec =~ s/$var_name\.$default_type/$var_default/g; |
1267
|
1
|
|
|
|
|
6
|
} |
1268
|
|
|
|
|
|
|
} |
1269
|
|
|
|
|
|
|
if ($item_spec =~ m/(\S+(\.(?:opt_)?default))/) { |
1270
|
435
|
|
|
|
|
845
|
my ($reference, $default_type) = ($1, $2); |
1271
|
|
|
|
|
|
|
_fail( "Invalid reference to field $reference in argument ". |
1272
|
102
|
|
|
|
|
343
|
"description:\n$item_spec" ); |
1273
|
102
|
|
|
|
|
309
|
} |
1274
|
|
|
|
|
|
|
$pod_string .= $item_spec; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
$pod_string = "=over\n\n".$pod_string."=back\n\n"; |
1277
|
|
|
|
|
|
|
return $pod_string; |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
1; # Magic true value required at end of module |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
=head1 NAME |
1285
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
Getopt::Euclid - Executable Uniform Command-Line Interface Descriptions |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
=head1 VERSION |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
This document describes Getopt::Euclid version 0.4.5 |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
use Getopt::Euclid; |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
if ($ARGV{-i}) { |
1297
|
|
|
|
|
|
|
print "Interactive mode...\n"; |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
for my $x (0..$ARGV{-size}{h}-1) { |
1301
|
|
|
|
|
|
|
for my $y (0..$ARGV{-size}{w}-1) { |
1302
|
|
|
|
|
|
|
do_something_with($x, $y); |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
__END__ |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
=head1 NAME |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
yourprog - Your program here |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
=head1 VERSION |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
This documentation refers to yourprog version 1.9.4 |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
=head1 USAGE |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
yourprog [options] -s[ize]=x -o[ut][file] |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
=head1 REQUIRED ARGUMENTS |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
=over |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
=item -s[ize]=x |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
Specify size of simulation |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
=for Euclid: |
1329
|
|
|
|
|
|
|
h.type: int > 0 |
1330
|
|
|
|
|
|
|
h.default: 24 |
1331
|
|
|
|
|
|
|
w.type: int >= 10 |
1332
|
|
|
|
|
|
|
w.default: 80 |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
=item -o[ut][file] |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
Specify output file |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=for Euclid: |
1339
|
|
|
|
|
|
|
file.type: writable |
1340
|
|
|
|
|
|
|
file.default: '-' |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
=back |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
=head1 OPTIONS |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
=over |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
=item -i |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
Specify interactive simulation |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
=item -l[[en][gth]] |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
Length of simulation. The default is l.default |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
=for Euclid: |
1357
|
|
|
|
|
|
|
l.type: int > 0 |
1358
|
|
|
|
|
|
|
l.default: 99 |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
=item --debug [] |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
Set the log level. Default is log_level.default but if you provide --debug, |
1363
|
|
|
|
|
|
|
then it is log_level.opt_default. |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
=for Euclid: |
1366
|
|
|
|
|
|
|
log_level.type: int |
1367
|
|
|
|
|
|
|
log_level.default: 0 |
1368
|
|
|
|
|
|
|
log_level.opt_default: 1 |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
=item --version |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
=item --usage |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
=item --help |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
=item --man |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
Print the usual program information |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=back |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
Remainder of documentation starts here... |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
=head1 AUTHOR |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
Damian Conway (DCONWAY@CPAN.org) |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
=head1 BUGS |
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
There are undoubtedly serious bugs lurking somewhere in this code. |
1391
|
|
|
|
|
|
|
Bug reports and other feedback are most welcome. |
1392
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
Copyright (c) 2005, Damian Conway. All Rights Reserved. |
1396
|
|
|
|
|
|
|
This module is free software. It may be used, redistributed |
1397
|
|
|
|
|
|
|
and/or modified under the terms of the Perl Artistic License |
1398
|
|
|
|
|
|
|
(see http://www.perl.com/perl/misc/Artistic.html) |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
Getopt::Euclid uses your program's own POD documentation to create a powerful |
1404
|
|
|
|
|
|
|
command-line argument parser. This ensures that your program's documented interface |
1405
|
|
|
|
|
|
|
and its actual interface always agree. |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
The created command-line argument parser includes many features such as argument |
1408
|
|
|
|
|
|
|
type checking, required arguments, exclusive arguments, optional arguments with |
1409
|
|
|
|
|
|
|
default values, automatic usage message, ... |
1410
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
To use the module, simply write the following at the top of your program: |
1412
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
use Getopt::Euclid; |
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
This will cause Getopt::Euclid to be require'd and its import method will be |
1416
|
|
|
|
|
|
|
called. It is important that the import method be allowed to run, so do not |
1417
|
|
|
|
|
|
|
invoke Getopt::Euclid in the following manner: |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
# Will not work |
1420
|
|
|
|
|
|
|
use Getopt::Euclid (); |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
When the module is loaded within a regular Perl program, it will: |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
=over |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
=item 1. |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
locate any POD in the same *.pl file or its associated *.pod file. |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
=item 2. |
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
extract information from that POD, most especially from |
1433
|
|
|
|
|
|
|
the C<=head1 REQUIRED ARGUMENTS> and C<=head1 OPTIONS> sections, |
1434
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
=item 3. |
1436
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
build a parser that parses the arguments and options the POD specifies, |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
=item 4. |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
remove the command-line arguments from C<@ARGV> and parse them, and |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
=item 5. |
1444
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
put the results in the global C<%ARGV> variable (or into specifically named |
1446
|
|
|
|
|
|
|
optional variables, if you request that -- see L). |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
=back |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
As a special case, if the module is loaded within some other module |
1451
|
|
|
|
|
|
|
(i.e. from within a C<.pm> file), it still locates and extracts POD |
1452
|
|
|
|
|
|
|
information, but instead of parsing C<@ARGV> immediately, it caches that |
1453
|
|
|
|
|
|
|
information and installs an C subroutine in the caller module. |
1454
|
|
|
|
|
|
|
This new C acts just like Getopt::Euclid's own import, except |
1455
|
|
|
|
|
|
|
that it adds the POD from the caller module to the POD of the callee. |
1456
|
|
|
|
|
|
|
|
1457
|
|
|
|
|
|
|
All of which just means you can put some or all of your CLI specification |
1458
|
|
|
|
|
|
|
in a module, rather than in the application's source file. |
1459
|
|
|
|
|
|
|
See L for more details. |
1460
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
=head1 INTERFACE |
1462
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
=head2 Program interface |
1464
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
You write: |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
use Getopt::Euclid; |
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
and your command-line is parsed automagically. |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
=head2 Module interface |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
=over |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
=item import() |
1476
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
You write: |
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
use Getopt::Euclid; |
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
and your module will then act just like Getopt::Euclid (i.e. you can use |
1482
|
|
|
|
|
|
|
your module I of Getopt::Euclid>, except that your module's POD |
1483
|
|
|
|
|
|
|
will also be prepended to the POD of any module that loads yours. In |
1484
|
|
|
|
|
|
|
other words, you can use Getopt::Euclid in a module to create a standard |
1485
|
|
|
|
|
|
|
set of CLI arguments, which can then be added to any application simply |
1486
|
|
|
|
|
|
|
by loading your module. |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
To accomplish this trick Getopt::Euclid installs an C |
1489
|
|
|
|
|
|
|
subroutine in your module. If your module already has an C |
1490
|
|
|
|
|
|
|
subroutine defined, terrible things happen. So do not do that. |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
You may also short-circuit the import method within your calling program to |
1493
|
|
|
|
|
|
|
have the POD from several modules included for argument parsing. |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
use Module1::Getopt (); # No argument parsing |
1496
|
|
|
|
|
|
|
use Module2::Getopt (); # No argument parsing |
1497
|
|
|
|
|
|
|
use Getopt::Euclid; # Arguments parsed |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
=item process_args() |
1500
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
Alternatively, to parse arguments from a source different from C<@ARGV>, use the |
1502
|
|
|
|
|
|
|
C subroutine. |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
use Getopt::Euclid qw(:defer); |
1505
|
|
|
|
|
|
|
my @args = ( '-in', 'file.txt', '-out', 'results.txt' ); |
1506
|
|
|
|
|
|
|
Getopt::Euclid->process_args(\@args); |
1507
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
If you want to use the :minimal or :vars mode in this type of scenario, you can |
1509
|
|
|
|
|
|
|
pass extra options to C: |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
use Getopt::Euclid qw(:defer); |
1512
|
|
|
|
|
|
|
my @args = ( '-in', 'file.txt', '-out', 'results.txt' ); |
1513
|
|
|
|
|
|
|
Getopt::Euclid->process_args(\@args, {-minimal => 1, -vars => 'prefix_'}); |
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
This is particularly when you plan on processing POD manually. |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
=item process_pods() |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
Similarly, to parse argument specifications from a source different than the |
1520
|
|
|
|
|
|
|
current script (and its dependencies), use the C subroutine. |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
use Getopt::Euclid (); |
1523
|
|
|
|
|
|
|
my @pods = ( 'script.pl', 'Module.pm' ); |
1524
|
|
|
|
|
|
|
$Getopt::Euclid::MAN = Getopt::Euclid->process_pods(\@pods, {-strict => 1}); |
1525
|
|
|
|
|
|
|
my @args = ( '-in', 'file.txt', '-out', 'results.txt' ); |
1526
|
|
|
|
|
|
|
Getopt::Euclid->process_args(\@args); |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
By default, this method will look for .pod files associated with the given .pl |
1529
|
|
|
|
|
|
|
and .pm files and use these .pod files preferentially when available. Set |
1530
|
|
|
|
|
|
|
-strict to 1 to only use the given files. |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
=back |
1533
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
=head2 POD interface |
1535
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
This is where all the action is. POD markup can be placed in a .pod file that |
1537
|
|
|
|
|
|
|
has the same prefix as the corresponding Perl file. Alternatively, POD can be |
1538
|
|
|
|
|
|
|
inserted anywhere in the Perl code, but is typically added either after an |
1539
|
|
|
|
|
|
|
__END__ statement (like in the L), or interspersed in the code: |