| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Prefer numeric version for backwards compatibility |
|
2
|
13
|
|
|
13
|
|
1344161
|
BEGIN { require 5.010000 }; ## no critic ( RequireUseStrict, RequireUseWarnings ) |
|
3
|
13
|
|
|
13
|
|
72
|
use strict; |
|
|
13
|
|
|
|
|
35
|
|
|
|
13
|
|
|
|
|
496
|
|
|
4
|
13
|
|
|
13
|
|
62
|
use warnings; |
|
|
13
|
|
|
|
|
28
|
|
|
|
13
|
|
|
|
|
6397
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Getopt::Guided; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
$Getopt::Guided::VERSION = 'v3.1.2'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Options Delimiter constant |
|
11
|
|
|
|
|
|
|
sub OD () { '-' } |
|
12
|
|
|
|
|
|
|
# End Of Options Delimiter constant |
|
13
|
|
|
|
|
|
|
sub EOOD () { '--' } |
|
14
|
|
|
|
|
|
|
# Flag Indicator Character Class constant |
|
15
|
|
|
|
|
|
|
sub FICC () { '[!+]' } |
|
16
|
|
|
|
|
|
|
# Option-Argument Indicator Character Class constant |
|
17
|
|
|
|
|
|
|
sub OAICC () { '[,:]' } |
|
18
|
|
|
|
|
|
|
# Perl boolean true constant ( IV == 1 ) |
|
19
|
|
|
|
|
|
|
sub TRUE () { !!1 } |
|
20
|
|
|
|
|
|
|
# Perl boolean false constant |
|
21
|
|
|
|
|
|
|
sub FALSE () { !!0 } |
|
22
|
|
|
|
|
|
|
# Common exit status constants |
|
23
|
|
|
|
|
|
|
sub EXIT_SUCCESS () { 0 } |
|
24
|
|
|
|
|
|
|
sub EXIT_FAILURE () { 1 } |
|
25
|
|
|
|
|
|
|
sub EXIT_USAGE () { 2 } |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
@Getopt::Guided::EXPORT_OK = |
|
28
|
|
|
|
|
|
|
qw( EOOD EXIT_SUCCESS EXIT_FAILURE EXIT_USAGE getopts processopts readopts print_version_info ); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub program_name () { |
|
31
|
14
|
|
|
14
|
0
|
117
|
require File::Basename; |
|
32
|
14
|
|
|
|
|
1214
|
File::Basename::basename( $0 ) |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub croakf ( $@ ) { |
|
36
|
13
|
100
|
|
13
|
0
|
147371
|
@_ = ( ( @_ == 1 ? shift : sprintf shift, @_ ) . ', stopped' ); |
|
37
|
13
|
|
|
|
|
108
|
require Carp; |
|
38
|
13
|
|
|
|
|
1917
|
goto &Carp::croak |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub import { |
|
42
|
13
|
|
|
13
|
|
1776
|
my $module = shift; |
|
43
|
|
|
|
|
|
|
|
|
44
|
13
|
|
|
|
|
24
|
our @EXPORT_OK; |
|
45
|
13
|
|
|
|
|
41
|
my $target = caller; |
|
46
|
13
|
|
|
|
|
127
|
for my $function ( @_ ) { |
|
47
|
|
|
|
|
|
|
croakf "%s: '%s' is not exported", $module, $function |
|
48
|
38
|
100
|
|
|
|
91
|
unless grep { $function eq $_ } @EXPORT_OK; |
|
|
304
|
|
|
|
|
607
|
|
|
49
|
13
|
|
|
13
|
|
104
|
no strict 'refs'; ## no critic ( ProhibitNoStrict ) |
|
|
13
|
|
|
|
|
26
|
|
|
|
13
|
|
|
|
|
2219
|
|
|
50
|
37
|
|
|
|
|
205
|
*{ "$target\::$function" } = $module->can( $function ) |
|
|
37
|
|
|
|
|
77964
|
|
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Implementation is based on m//gc with \G |
|
55
|
|
|
|
|
|
|
sub parse_spec ( $;\%$ ) { |
|
56
|
64
|
|
|
64
|
0
|
167
|
my ( $spec, $spec_as_hash, $spec_length_expected ) = @_; |
|
57
|
|
|
|
|
|
|
|
|
58
|
64
|
100
|
|
|
|
186
|
$spec_as_hash = {} unless defined $spec_as_hash; |
|
59
|
|
|
|
|
|
|
|
|
60
|
64
|
|
|
|
|
106
|
my $spec_length_got; |
|
61
|
13
|
|
|
13
|
|
119
|
no warnings qw( uninitialized ); ## no critic ( ProhibitNoWarnings ) |
|
|
13
|
|
|
|
|
29
|
|
|
|
13
|
|
|
|
|
22359
|
|
|
62
|
64
|
|
|
|
|
354
|
while ( $spec =~ m/\G ( [[:alnum:]] ) ( ${ \( FICC ) } | ${ \( OAICC ) } | )/gcox ) { |
|
|
8
|
|
|
|
|
42
|
|
|
|
8
|
|
|
|
|
2430
|
|
|
63
|
115
|
|
|
|
|
355
|
my ( $name, $indicator ) = ( $1, $2 ); |
|
64
|
|
|
|
|
|
|
croakf "%s parameter contains option '%s' multiple times", '$spec', $name |
|
65
|
115
|
100
|
|
|
|
274
|
if exists $spec_as_hash->{ $name }; |
|
66
|
114
|
|
|
|
|
276
|
$spec_as_hash->{ $name } = $indicator; |
|
67
|
114
|
|
|
|
|
339
|
++$spec_length_got |
|
68
|
|
|
|
|
|
|
} |
|
69
|
63
|
|
|
|
|
130
|
my $offset = pos $spec; |
|
70
|
63
|
100
|
100
|
|
|
419
|
croakf "%s parameter isn't a non-empty string of alphanumeric characters", '$spec' |
|
71
|
|
|
|
|
|
|
unless defined $offset and $offset == length $spec; |
|
72
|
57
|
100
|
100
|
|
|
195
|
croakf '%s parameter specifies %d options (expected: %d)', '$spec', $spec_length_got, $spec_length_expected |
|
73
|
|
|
|
|
|
|
if defined $spec_length_expected and $spec_length_got != $spec_length_expected; |
|
74
|
|
|
|
|
|
|
|
|
75
|
56
|
|
|
|
|
180
|
$spec_as_hash |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02> |
|
79
|
|
|
|
|
|
|
sub getopts ( $\%;\@ ) { |
|
80
|
50
|
|
|
50
|
0
|
1019276
|
my ( $spec, $opts, $argv ) = @_; |
|
81
|
|
|
|
|
|
|
|
|
82
|
50
|
100
|
|
|
|
225
|
my $spec_as_hash = ref $spec eq 'HASH' ? $spec : parse_spec $spec; |
|
83
|
44
|
100
|
|
|
|
130
|
croakf "%s parameter isn't an empty hash", '%$opts' |
|
84
|
|
|
|
|
|
|
if %$opts; |
|
85
|
43
|
100
|
|
|
|
126
|
$argv = \@ARGV unless defined $argv; |
|
86
|
|
|
|
|
|
|
|
|
87
|
43
|
|
|
|
|
124
|
my @argv_backup = @$argv; |
|
88
|
43
|
|
|
|
|
82
|
my @error; |
|
89
|
|
|
|
|
|
|
# Guideline 4, Guideline 9 |
|
90
|
43
|
|
100
|
|
|
349
|
while ( @$argv and my ( $name, $rest ) = ( $argv->[ 0 ] =~ m/\A ${ \( OD ) } (.) (.*)/ox ) ) { |
|
|
6
|
|
|
|
|
168
|
|
|
91
|
|
|
|
|
|
|
# Guideline 10 |
|
92
|
123
|
100
|
|
|
|
315
|
shift @$argv, last |
|
93
|
|
|
|
|
|
|
if $argv->[ 0 ] eq EOOD; |
|
94
|
|
|
|
|
|
|
@error = ( 'illegal option', $name ), last |
|
95
|
122
|
100
|
|
|
|
251
|
unless exists $spec_as_hash->{ $name }; ## no critic ( ProhibitNegativeExpressionsInUnlessAndUntilConditions ) |
|
96
|
|
|
|
|
|
|
|
|
97
|
118
|
|
|
|
|
185
|
my $indicator = $spec_as_hash->{ $name }; |
|
98
|
118
|
100
|
|
|
|
282
|
if ( $indicator =~ m/\A ${ \( OAICC ) } \z/ox ) { |
|
|
5
|
|
|
|
|
140
|
|
|
99
|
|
|
|
|
|
|
# Case: Option has an option-argument |
|
100
|
|
|
|
|
|
|
# Shift delimeted option name |
|
101
|
55
|
|
|
|
|
86
|
shift @$argv; |
|
102
|
|
|
|
|
|
|
# Extract option-argument value |
|
103
|
55
|
|
|
|
|
82
|
my $value; |
|
104
|
55
|
100
|
|
|
|
106
|
if ( $rest ne '' ) { |
|
105
|
6
|
|
|
|
|
13
|
$value = $rest; |
|
106
|
|
|
|
|
|
|
} else { |
|
107
|
|
|
|
|
|
|
# Guideline 7 |
|
108
|
49
|
100
|
|
|
|
121
|
@error = ( 'option requires an argument', $name ), last |
|
109
|
|
|
|
|
|
|
unless @$argv; |
|
110
|
|
|
|
|
|
|
# Guideline 6, Guideline 8 |
|
111
|
47
|
100
|
|
|
|
108
|
@error = ( 'option requires an argument', $name ), last |
|
112
|
|
|
|
|
|
|
unless defined( $value = shift @$argv ); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
# Store option-argument value |
|
115
|
52
|
100
|
|
|
|
105
|
if ( $indicator eq ':' ) { |
|
116
|
|
|
|
|
|
|
# Standard behaviour: Overwrite option-argument |
|
117
|
31
|
|
|
|
|
163
|
$opts->{ $name } = $value |
|
118
|
|
|
|
|
|
|
} else { |
|
119
|
|
|
|
|
|
|
# Create and fill list of option-arguments ( $indicator eq ',' ) |
|
120
|
21
|
100
|
|
|
|
53
|
$opts->{ $name } = [] unless exists $opts->{ $name }; |
|
121
|
21
|
|
|
|
|
30
|
push @{ $opts->{ $name } }, $value |
|
|
21
|
|
|
|
|
105
|
|
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
} else { |
|
124
|
|
|
|
|
|
|
# Case: Option is a flag |
|
125
|
63
|
100
|
|
|
|
200
|
if ( not exists $opts->{ $name } ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Initialisation |
|
127
|
45
|
|
|
|
|
122
|
$opts->{ $name } = TRUE |
|
128
|
|
|
|
|
|
|
} elsif ( $indicator eq '!' ) { |
|
129
|
|
|
|
|
|
|
# Negate logically |
|
130
|
1
|
|
|
|
|
2
|
$opts->{ $name } = not $opts->{ $name } |
|
131
|
|
|
|
|
|
|
} elsif ( $indicator eq '+' ) { |
|
132
|
|
|
|
|
|
|
# Increment |
|
133
|
14
|
|
|
|
|
23
|
++$opts->{ $name } |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
# Guideline 5 |
|
136
|
63
|
100
|
|
|
|
126
|
if ( $rest eq '' ) { |
|
137
|
|
|
|
|
|
|
# Shift delimeted option name |
|
138
|
47
|
|
|
|
|
210
|
shift @$argv |
|
139
|
|
|
|
|
|
|
} else { |
|
140
|
16
|
|
|
|
|
99
|
$argv->[ 0 ] = OD . $rest ## no critic ( RequireLocalizedPunctuationVars ) |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
43
|
100
|
|
|
|
118
|
if ( @error ) { |
|
147
|
|
|
|
|
|
|
# Restore to avoid side effects |
|
148
|
7
|
|
|
|
|
22
|
@$argv = @argv_backup; ## no critic ( RequireLocalizedPunctuationVars ) |
|
149
|
7
|
|
|
|
|
20
|
%$opts = (); |
|
150
|
|
|
|
|
|
|
# Prepare and print warning message: |
|
151
|
|
|
|
|
|
|
# Program name, type of error, and invalid option character |
|
152
|
7
|
|
|
|
|
25
|
warn sprintf( "%s: %s -- %s\n", program_name(), @error ) ## no critic ( RequireCarping ) |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
43
|
|
|
|
|
692
|
@error == 0 |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# Prepare and print version info message: |
|
159
|
|
|
|
|
|
|
# - Program name and version (first line) |
|
160
|
|
|
|
|
|
|
# - Interpreter name ("perl") and version (second line) |
|
161
|
|
|
|
|
|
|
sub print_version_info { |
|
162
|
|
|
|
|
|
|
# call frame 0: processopts() (the caller) calls print_version_info() |
|
163
|
|
|
|
|
|
|
# the caller's package name is Getopt::Guided |
|
164
|
|
|
|
|
|
|
# call frame 1: a run() function/method (the caller) usually calls processopts() |
|
165
|
|
|
|
|
|
|
# the caller's package name is whatever it is (could be "main") |
|
166
|
3
|
|
100
|
3
|
0
|
239867
|
printf STDOUT "%s %s\nperl v%vd\n", program_name(), ( caller( 1 ) // 'main' )->VERSION, $^V; |
|
167
|
3
|
|
|
|
|
139
|
EOOD |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub processopts ( \@@ ) { |
|
171
|
17
|
|
|
17
|
0
|
882096
|
my $argv = shift; |
|
172
|
17
|
|
|
|
|
35
|
my $spec_as_array = do { my $t = 0; [ grep $t ^= 1, @_ ] }; ## no critic ( RequireBlockGrep ) |
|
|
17
|
|
|
|
|
31
|
|
|
|
17
|
|
|
|
|
119
|
|
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Check each option specification individually (1) |
|
175
|
17
|
|
|
|
|
30
|
my $spec_as_hash; |
|
176
|
17
|
|
|
|
|
77
|
parse_spec $_, %$spec_as_hash, 1 for @$spec_as_array; |
|
177
|
|
|
|
|
|
|
|
|
178
|
15
|
100
|
|
|
|
58
|
return FALSE unless getopts $spec_as_hash, my %opts, @$argv; |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# This ordered processing is a feature! |
|
181
|
13
|
|
|
|
|
46
|
for ( my $i = 0 ; $i < @_ ; $i += 2 ) { |
|
182
|
|
|
|
|
|
|
# If $_[ $i ] refers to a flag with no indicator, the split still returns |
|
183
|
|
|
|
|
|
|
# the empty string (not undef!) as the value for the indicator |
|
184
|
18
|
|
|
|
|
5507
|
my ( $name, $indicator ) = split //, $_[ $i ]; |
|
185
|
18
|
100
|
|
|
|
55
|
if ( exists $opts{ $name } ) { |
|
186
|
16
|
|
|
|
|
54
|
my $value = delete $opts{ $name }; |
|
187
|
16
|
|
|
|
|
39
|
my $dest = $_[ $i + 1 ]; |
|
188
|
16
|
|
|
|
|
34
|
my $dest_ref_type = ref $dest; |
|
189
|
16
|
100
|
100
|
|
|
77
|
if ( $dest_ref_type eq 'SCALAR' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
190
|
4
|
|
|
|
|
10
|
${ $dest } = $value |
|
|
4
|
|
|
|
|
16
|
|
|
191
|
|
|
|
|
|
|
} elsif ( $dest_ref_type eq 'ARRAY' and $indicator eq ',' ) { |
|
192
|
1
|
|
|
|
|
3
|
@{ $dest } = @$value |
|
|
1
|
|
|
|
|
6
|
|
|
193
|
|
|
|
|
|
|
} elsif ( $dest_ref_type eq 'CODE' ) { |
|
194
|
|
|
|
|
|
|
# Callbacks are called in scalar context |
|
195
|
|
|
|
|
|
|
# If EOOD is the return value of the callback, |
|
196
|
|
|
|
|
|
|
# processopts() will terminate early. The return value will be |
|
197
|
|
|
|
|
|
|
# a special TRUE value. Using $name is not sufficient because 0 and 1 |
|
198
|
|
|
|
|
|
|
# a posible values for $name. |
|
199
|
10
|
100
|
100
|
|
|
37
|
return ( OD . $name ) |
|
200
|
|
|
|
|
|
|
if ( $dest->( $value, $name, $indicator ) // '' ) eq EOOD |
|
201
|
|
|
|
|
|
|
} else { |
|
202
|
1
|
|
|
|
|
6
|
croakf "'%s' is an unsupported destination reference type for the '%s' indicator", $dest_ref_type, $indicator |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
8
|
|
|
|
|
4238
|
TRUE |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub readopts ( \@ ) { |
|
211
|
4
|
|
|
4
|
0
|
255068
|
my ( $argv ) = @_; |
|
212
|
|
|
|
|
|
|
|
|
213
|
4
|
|
|
|
|
33
|
require File::Spec::Functions; |
|
214
|
4
|
100
|
|
|
|
15
|
return unless -f ( my $file = File::Spec::Functions::catfile( $ENV{ XDG_CONFIG_HOME }, program_name() . 'rc' ) ); |
|
215
|
|
|
|
|
|
|
|
|
216
|
3
|
50
|
|
1
|
|
169
|
open my $fh, '<:encoding(UTF-8)', $file ## no critic ( RequireBriefOpen ) |
|
|
1
|
|
|
|
|
888
|
|
|
|
1
|
|
|
|
|
37
|
|
|
|
1
|
|
|
|
|
7
|
|
|
217
|
|
|
|
|
|
|
or croakf "Cannot open file '%s' for reading (%s)", $file, $!; |
|
218
|
|
|
|
|
|
|
|
|
219
|
3
|
|
|
|
|
1770
|
while ( <$fh> ) { |
|
220
|
5
|
|
|
|
|
40
|
chomp; |
|
221
|
5
|
50
|
|
|
|
32
|
next if m/\A (?: \#.* | ) \z/x; |
|
222
|
5
|
100
|
|
|
|
29
|
if ( m/\A ( [[:alnum:]] ) (?: \ ( .+ ) )? \z/x ) { |
|
223
|
4
|
100
|
|
|
|
24
|
unshift @$argv, ( OD . $1, defined $2 ? $2 : () ); |
|
224
|
|
|
|
|
|
|
next |
|
225
|
4
|
|
|
|
|
34
|
} |
|
226
|
1
|
|
|
|
|
8
|
croakf "File '%s' contains the invalid line '%s'", $file, $_ |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
return |
|
230
|
2
|
|
|
|
|
47
|
} |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
1 |