File Coverage

blib/lib/Getopt/Mixed.pm
Criterion Covered Total %
statement 97 128 75.7
branch 45 92 48.9
condition 11 32 34.3
subroutine 9 12 75.0
pod 0 8 0.0
total 162 272 59.5


line stmt bran cond sub pod time code
1             #---------------------------------------------------------------------
2             package Getopt::Mixed;
3             #
4             # Copyright 1995 Christopher J. Madsen
5             #
6             # Author: Christopher J. Madsen
7             # Created: 1 Jan 1995
8             #
9             # This program is free software; you can redistribute it and/or modify
10             # it under the same terms as Perl itself.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
15             # GNU General Public License or the Artistic License for more details.
16             #
17             # ABSTRACT: [OBSOLETE] getopt processing with both long and short options
18             #---------------------------------------------------------------------
19              
20             require 5.000;
21 2     2   45544 use strict;
  2         4  
  2         79  
22 2     2   9 use Carp;
  2         5  
  2         228  
23              
24 2         654 use vars qw(
25             @EXPORT @EXPORT_OK @ISA %options
26             $PERMUTE $REQUIRE_ORDER $RETURN_IN_ORDER $VERSION
27             $badOption $checkArg $checkType $floatRegexp $group $ignoreCase
28             $intRegexp $option $optionEnd $optionStart $order $typeChars
29 2     2   11 );
  2         4  
30              
31             require Exporter;
32             @ISA = qw(Exporter);
33             @EXPORT = ();
34             @EXPORT_OK = qw(abortMsg getOptions nextOption);
35              
36             #=====================================================================
37             # Package Global Variables:
38              
39             BEGIN
40             {
41 2     2   5 $VERSION = '1.12';
42              
43             # The permissible settings for $order:
44 2         4 $REQUIRE_ORDER = 0;
45 2         4 $PERMUTE = 1;
46 2         4 $RETURN_IN_ORDER = 2;
47              
48             # Regular expressions:
49 2         4 $intRegexp = '^[-+]?\d+$'; # Match an integer
50 2         4 $floatRegexp = '^[-+]?(\d*\.?\d+|\d+\.)$'; # Match a real number
51 2         4803 $typeChars = 'sif'; # Match type characters
52             } # end BEGIN
53              
54             #=====================================================================
55             # Subroutines:
56             #---------------------------------------------------------------------
57             # Initialize the option processor:
58             #
59             # You should set any customization variables *after* calling init.
60             #
61             # For a description of option declarations, see the documentation at
62             # the end of this file.
63             #
64             # Input:
65             # List of option declarations (separated by whitespace)
66             # If the first argument is entirely non-alphanumeric characters
67             # with no whitespace, it is the characters that start options.
68              
69             sub init
70             {
71 1     1 0 4 undef %options;
72 1         2 my($opt,$type);
73              
74 1         4 $ignoreCase = 1; # Ignore case by default
75 1         4 $optionStart = "-"; # Dash is the default option starter
76              
77             # If the first argument is entirely non-alphanumeric characters
78             # with no whitespace, it is the desired value for $optionStart:
79 1 50       9 $optionStart = shift @_ if $_[0] =~ /^[^a-z0-9\s]+$/i;
80              
81 1         4 foreach $group (@_) {
82             # Ignore case unless there are upper-case options:
83 2 100       23 $ignoreCase = 0 if $group =~ /[A-Z]/;
84 2         11 foreach $option (split(/\s+/,$group)) {
85 13 50       121 croak "Invalid option declaration `$option'"
86             unless $option =~ /^([^=:>]+)([=:][$typeChars]|>[^=:>]+)?$/o;
87 13         26 $opt = $1;
88 13   100     37 $type = $2 || "";
89 13 100       39 if ($type =~ /^>(.*)$/) {
90 4         8 $type = $1;
91 4 50 33     24 croak "Invalid synonym `$option'"
92             if (not defined $options{$type}
93             or $options{$type} =~ /^[^:=]/);
94             } # end if synonym
95 13         39 $options{$opt} = $type;
96             } # end foreach option
97             } # end foreach group
98              
99             # Handle POSIX compliancy:
100 1 50       8 if (defined $ENV{"POSIXLY_CORRECT"}) {
101 0         0 $order = $REQUIRE_ORDER;
102             } else {
103 1         2 $order = $PERMUTE;
104             }
105              
106 1         2 $optionEnd = 0;
107 1         4 $badOption = \&badOption;
108 1         3 $checkArg = \&checkArg;
109             } # end init
110              
111             #---------------------------------------------------------------------
112             # Clean up when we're done:
113             #
114             # This just releases the memory used by the %options hash.
115             #
116             # If 'help' was defined as an option, a new hash with just 'help' is
117             # created, in case the program calls abortMsg.
118              
119             sub cleanup
120             {
121 1     1 0 3 my $help = defined($options{'help'});
122 1         6 undef %options;
123 1 50       7 $options{'help'} = "" if $help;
124             } # end cleanup
125              
126             #---------------------------------------------------------------------
127             # Abort program with message:
128             #
129             # Prints program name and arguments to STDERR
130             # If --help is an option, prints message saying 'Try --help'
131             # Exits with code 1
132              
133             sub abortMsg
134             {
135 0     0 0 0 my $name = $0;
136 0         0 $name =~ s|^.+[\\/]||; # Remove any directories from name
137 0         0 print STDERR $name,": ",@_,"\n";
138 0 0       0 print STDERR "Try `$name --help' for more information.\n"
139             if defined $options{"help"};
140 0         0 exit 1;
141             } # end abortMsg
142              
143             #---------------------------------------------------------------------
144             # Standard function for handling bad options:
145             #
146             # Prints an error message and exits.
147             #
148             # You can override this by setting $Getopt::Mixed::badOption to a
149             # function reference.
150             #
151             # Input:
152             # Index into @ARGV
153             # The option that caused the error
154             # An optional string describing the problem
155             # Currently, this can be
156             # undef The option was not recognized
157             # 'ambiguous' The option could match several long options
158             #
159             # Note:
160             # The option has already been removed from @ARGV. To put it back,
161             # you can say:
162             # splice(@ARGV,$_[0],0,$_[1]);
163             #
164             # If your function returns, it should return whatever you want
165             # nextOption to return.
166              
167             sub badOption
168             {
169 0     0 0 0 my ($index, $option, $problem) = @_;
170              
171 0 0       0 $problem = 'unrecognized' unless $problem;
172              
173 0         0 abortMsg("$problem option `$option'");
174             } # end badOption
175              
176             #---------------------------------------------------------------------
177             # Make sure we have the proper argument for this option:
178             #
179             # You can override this by setting $Getopt::Mixed::checkArg to a
180             # function reference.
181             #
182             # Input:
183             # $i: Position of argument in @ARGV
184             # $value: The text appended to the option (undef if no text)
185             # $option: The pretty name of the option (as the user typed it)
186             # $type: The type of the option
187             #
188             # Returns:
189             # The value of the option's argument
190              
191             sub checkArg
192             {
193 3     3 0 7 my ($i,$value,$option,$type) = @_;
194              
195 3 50 33     19 abortMsg("option `$option' does not take an argument")
196             if (not $type and defined $value);
197              
198 3 100       11 if ($type =~ /^=/) {
199             # An argument is required for this option:
200 2 100       7 $value = splice(@ARGV,$i,1) unless defined $value;
201 2 50       4 abortMsg("option `$option' requires an argument")
202             unless defined $value;
203             }
204              
205 3 50 33     26 if ($type =~ /i$/) {
    100          
    50          
206 0 0 0     0 abortMsg("option `$option' requires integer argument")
207             if (defined $value and $value !~ /$intRegexp/o);
208             }
209             elsif ($type =~ /f$/) {
210 1 50 33     56 abortMsg("option `$option' requires numeric argument")
211             if (defined $value and $value !~ /$floatRegexp/o);
212             }
213             elsif ($type =~ /^[=:]/ and ref($checkType)) {
214 0         0 $value = &$checkType($i,$value,$option,$type);
215             }
216              
217 3 50 33     11 $value = "" if not defined $value and $type =~ /^:/;
218              
219 3         7 $value;
220             } # end checkArg
221              
222             #---------------------------------------------------------------------
223             # Find a match for an incomplete long option:
224             #
225             # Input:
226             # The option text to match
227             #
228             # Returns:
229             # The option that matched, or
230             # undef, if no option matched, or
231             # (undef, 'ambiguous'), if multiple options matched
232              
233             sub findMatch
234             {
235 0     0 0 0 my $opt = shift;
236              
237 0         0 $opt =~ s/-/[^-]*-/g;
238 0         0 $opt .= ".*";
239              
240 0         0 my @matches = grep(/^$opt$/, keys %options);
241              
242 0 0       0 return undef if $#matches < 0;
243 0 0       0 return $matches[0] if $#matches == 0;
244              
245 0         0 $opt = $matches[0];
246 0 0       0 $opt = $options{$opt} if $options{$opt} =~ /^[^=:]/;
247              
248 0         0 foreach (@matches) {
249 0 0 0     0 return (undef, 'ambiguous')
250             unless $_ eq $opt or $options{$_} eq $opt;
251             }
252              
253 0         0 $opt;
254             } # end findMatch
255              
256             #---------------------------------------------------------------------
257             # Return the next option:
258             #
259             # Returns a list of 3 elements: (OPTION, VALUE, PRETTYNAME), where
260             # OPTION is the name of the option,
261             # VALUE is its argument, and
262             # PRETTYNAME is the option as the user entered it.
263             # Returns the null list if there are no more options to process
264             #
265             # If $order is $RETURN_IN_ORDER, and this is a normal argument (not an
266             # option), OPTION will be the null string, VALUE will be the argument,
267             # and PRETTYNAME will be undefined.
268              
269             sub nextOption
270             {
271 4 50   4 0 14 return () if $#ARGV < 0; # No more arguments
272              
273 4 50       9 if ($optionEnd) {
274             # We aren't processing any more options:
275 0 0       0 return ("", shift @ARGV) if $order == $RETURN_IN_ORDER;
276 0         0 return ();
277             }
278              
279             # Find the next option:
280 4         6 my $i = 0;
281 4   66     29 while (length($ARGV[$i]) < 2 or
282             index($optionStart,substr($ARGV[$i],0,1)) < 0) {
283 1 50       4 return () if $order == $REQUIRE_ORDER;
284 1 50       4 return ("", shift @ARGV) if $order == $RETURN_IN_ORDER;
285 1         2 ++$i;
286 1 50       6 return () if $i > $#ARGV;
287             } # end while
288              
289             # Process the option:
290 3         3 my($option,$opt,$value,$optType,$prettyOpt);
291 3         6 $option = $ARGV[$i];
292 3 100       10 if (substr($option,0,1) eq substr($option,1,1)) {
293             # If the option start character is repeated, it's a long option:
294 1         2 splice @ARGV,$i,1;
295 1 50       4 if (length($option) == 2) {
296             # A double dash by itself marks the end of the options:
297 0         0 $optionEnd = 1; # Don't process any more options
298 0         0 return nextOption();
299             } # end if bare double dash
300 1         2 $opt = substr($option,2);
301 1 50       4 if ($opt =~ /^([^=]+)=(.*)$/) {
302 0         0 $opt = $1;
303 0         0 $value = $2;
304             } # end if option is followed by value
305 1 50       3 $opt =~ tr/A-Z/a-z/ if $ignoreCase;
306 1         3 $prettyOpt = substr($option,0,2) . $opt;
307 1         1 my $problem;
308 1 50 33     9 ($opt, $problem) = findMatch($opt)
309             unless defined $options{$opt} and length($opt) > 1;
310 1 50       4 return &$badOption($i,$option,$problem) unless $opt;
311 1         2 $optType = $options{$opt};
312 1 50       5 if ($optType =~ /^[^:=]/) {
313 0         0 $opt = $optType;
314 0         0 $optType = $options{$opt};
315             }
316 1         2 $value = &$checkArg($i,$value,$prettyOpt,$optType);
317             } # end if long option
318             else {
319             # It's a short option:
320 2         4 $opt = substr($option,1,1);
321 2 50       6 $opt =~ tr/A-Z/a-z/ if $ignoreCase;
322 2 50       6 return &$badOption($i,$option) unless defined $options{$opt};
323 2         3 $optType = $options{$opt};
324 2 100       27 if ($optType =~ /^[^:=]/) {
325 1         3 $opt = $optType;
326 1         3 $optType = $options{$opt};
327             }
328 2 50 33     12 if (length($option) == 2 or $optType) {
329             # This is the last option in the group, so remove the group:
330 2         6 splice(@ARGV,$i,1);
331             } else {
332             # Just remove this option from the group:
333 0         0 substr($ARGV[$i],1,1) = "";
334             }
335 2 50       6 if ($optType) {
336 2 50       7 $value = (length($option) > 2) ? substr($option,2) : undef;
337 2 50       10 $value =~ s/^=// if $value; # Allow either -d3 or -d=3
338             } # end if option takes an argument
339 2         4 $prettyOpt = substr($option,0,2);
340 2         6 $value = &$checkArg($i,$value,$prettyOpt,$optType);
341             } # end else short option
342 3         16 ($opt,$value,$prettyOpt);
343             } # end nextOption
344              
345             #---------------------------------------------------------------------
346             # Get options:
347             #
348             # Input:
349             # The same as for init()
350             # If no parameters are supplied, init() is NOT called. This allows
351             # you to call init() yourself and then change the configuration
352             # variables.
353             #
354             # Output Variables:
355             # Sets $opt_X for each `-X' option encountered.
356             #
357             # Note that if --apple is a synonym for -a, then --apple will cause
358             # $opt_a to be set, not $opt_apple.
359              
360             sub getOptions
361             {
362 1 50   1 0 440 &init if $#_ >= 0; # Pass arguments (if any) on to init
363              
364             # If you want to use $RETURN_IN_ORDER, you have to call
365             # nextOption yourself; getOptions doesn't support it:
366 1 50       3 $order = $PERMUTE if $order == $RETURN_IN_ORDER;
367              
368 1         2 my ($option,$value,$package);
369              
370 1         5 $package = (caller)[0];
371              
372 1         5 while (($option, $value) = nextOption()) {
373 3         36 $option =~ s/\W/_/g; # Make a legal Perl identifier
374 3 50       8 $value = 1 unless defined $value;
375 3         8 my $code = "\$" . $package . "::opt_$option = \$value;";
376 3         8 $code =~ /(.+)/; # Untaint it
377 3         201 eval $1;
378             } # end while
379              
380 1         3 cleanup();
381             } # end getOptions
382              
383             #=====================================================================
384             # Package return value:
385              
386             $VERSION;
387              
388             __END__