package Getopt::Long;
-# RCS Status : $Id: GetoptLong.pm,v 2.72 2005-04-28 21:18:33+02 jv Exp $
+# RCS Status : $Id: Long.pm,v 2.73 2007/01/27 20:00:34 jv Exp $
# Author : Johan Vromans
# Created On : Tue Sep 11 15:00:12 1990
# Last Modified By: Johan Vromans
-# Last Modified On: Wed Dec 14 21:17:21 2005
-# Update Count : 1458
+# Last Modified On: Sat Jan 27 20:59:00 2007
+# Update Count : 1552
# Status : Released
################ Copyright ################
-# This program is Copyright 1990,2005 by Johan Vromans.
+# This program is Copyright 1990,2007 by Johan Vromans.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Perl Artistic License or the
# GNU General Public License as published by the Free Software
use strict;
use vars qw($VERSION);
-$VERSION = 2.35_01;
+$VERSION = 2.36;
# For testing versions only.
-#use vars qw($VERSION_STRING);
-#$VERSION_STRING = "2.35";
+use vars qw($VERSION_STRING);
+$VERSION_STRING = "2.36";
use Exporter;
use vars qw(@ISA @EXPORT @EXPORT_OK);
# Exported subroutines.
sub GetOptions(@); # always
+sub GetOptionsFromArray($@); # on demand
+sub GetOptionsFromString($@); # on demand
sub Configure(@); # on demand
sub HelpMessage(@); # on demand
sub VersionMessage(@); # in demand
BEGIN {
# Init immediately so their contents can be used in the 'use vars' below.
@EXPORT = qw(&GetOptions $REQUIRE_ORDER $PERMUTE $RETURN_IN_ORDER);
- @EXPORT_OK = qw(&HelpMessage &VersionMessage &Configure);
+ @EXPORT_OK = qw(&HelpMessage &VersionMessage &Configure
+ &GetOptionsFromArray &GetOptionsFromString);
}
# User visible variables.
sub ConfigDefaults();
sub ParseOptionSpec($$);
sub OptCtl($);
-sub FindOption($$$$);
+sub FindOption($$$$$);
sub ValidValue ($$$$$);
################ Local Variables ################
#use constant CTL_RANGE => ;
#use constant CTL_REPEAT => ;
+# Rather liberal patterns to match numbers.
+use constant PAT_INT => "[-+]?_*[0-9][0-9_]*";
+use constant PAT_XINT =>
+ "(?:".
+ "[-+]?_*[1-9][0-9_]*".
+ "|".
+ "0x_*[0-9a-f][0-9a-f_]*".
+ "|".
+ "0b_*[01][01_]*".
+ "|".
+ "0[0-7_]*".
+ ")";
+use constant PAT_FLOAT => "[-+]?[0-9._]+(\.[0-9_]+)?([eE][-+]?[0-9_]+)?";
+
sub GetOptions(@) {
+ # Shift in default array.
+ unshift(@_, \@ARGV);
+ # Try to keep caller() and Carp consitent.
+ goto &GetOptionsFromArray;
+}
+
+sub GetOptionsFromString($@) {
+ my ($string) = shift;
+ require Text::ParseWords;
+ my $args = [ Text::ParseWords::shellwords($string) ];
+ $caller ||= (caller)[0]; # current context
+ my $ret = GetOptionsFromArray($args, @_);
+ return ( $ret, $args ) if wantarray;
+ if ( @$args ) {
+ $ret = 0;
+ warn("GetOptionsFromString: Excess data \"@$args\" in string \"$string\"\n");
+ }
+ $ret;
+}
- my @optionlist = @_; # local copy of the option descriptions
+sub GetOptionsFromArray($@) {
+
+ my ($argv, @optionlist) = @_; # local copy of the option descriptions
my $argend = '--'; # option list terminator
my %opctl = (); # table of option specs
my $pkg = $caller || (caller)[0]; # current context
local ($^W) = 0;
print STDERR
("Getopt::Long $Getopt::Long::VERSION (",
- '$Revision: 2.72 $', ") ",
+ '$Revision: 2.73 $', ") ",
"called from package \"$pkg\".",
"\n ",
- "ARGV: (@ARGV)",
+ "argv: (@$argv)",
"\n ",
"autoabbrev=$autoabbrev,".
"bundling=$bundling,",
elsif ( $rl eq "HASH" ) {
$opctl{$name}[CTL_DEST] = CTL_DEST_HASH;
}
- elsif ( $rl eq "SCALAR" ) {
+ elsif ( $rl eq "SCALAR" || $rl eq "REF" ) {
# if ( $opctl{$name}[CTL_DEST] == CTL_DEST_ARRAY ) {
# my $t = $linkage{$orig};
# $$t = $linkage{$orig} = [];
# Process argument list
my $goon = 1;
- while ( $goon && @ARGV > 0 ) {
+ while ( $goon && @$argv > 0 ) {
# Get next argument.
- $opt = shift (@ARGV);
+ $opt = shift (@$argv);
print STDERR ("=> arg \"", $opt, "\"\n") if $debug;
# Double dash is option list terminator.
my $ctl; # the opctl entry
($found, $opt, $ctl, $arg, $key) =
- FindOption ($prefix, $argend, $opt, \%opctl);
+ FindOption ($argv, $prefix, $argend, $opt, \%opctl);
if ( $found ) {
print STDERR ("=> ref(\$L{$opt}) -> ",
ref($linkage{$opt}), "\n") if $debug;
- if ( ref($linkage{$opt}) eq 'SCALAR' ) {
+ if ( ref($linkage{$opt}) eq 'SCALAR'
+ || ref($linkage{$opt}) eq 'REF' ) {
if ( $ctl->[CTL_TYPE] eq '+' ) {
print STDERR ("=> \$\$L{$opt} += \"$arg\"\n")
if $debug;
local $@;
local $SIG{__DIE__} = '__DEFAULT__';
eval {
- &{$linkage{$opt}}($opt,
- $ctl->[CTL_DEST] == CTL_DEST_HASH ? ($key) : (),
- $arg);
+ &{$linkage{$opt}}
+ (Getopt::Long::CallBack->new
+ (name => $opt,
+ ctl => $ctl,
+ opctl => \%opctl,
+ linkage => \%linkage,
+ prefix => $prefix,
+ ),
+ $ctl->[CTL_DEST] == CTL_DEST_HASH ? ($key) : (),
+ $arg);
};
$@;
};
# Need more args?
if ( $argcnt < $ctl->[CTL_AMIN] ) {
- if ( @ARGV ) {
- if ( ValidValue($ctl, $ARGV[0], 1, $argend, $prefix) ) {
- $arg = shift(@ARGV);
+ if ( @$argv ) {
+ if ( ValidValue($ctl, $argv->[0], 1, $argend, $prefix) ) {
+ $arg = shift(@$argv);
+ $arg =~ tr/_//d if $ctl->[CTL_TYPE] =~ /^[iIo]$/;
($key,$arg) = $arg =~ /^([^=]+)=(.*)/
if $ctl->[CTL_DEST] == CTL_DEST_HASH;
next;
}
- warn("Value \"$ARGV[0]\" invalid for option $opt\n");
+ warn("Value \"$$argv[0]\" invalid for option $opt\n");
$error++;
}
else {
}
# Any more args?
- if ( @ARGV && ValidValue($ctl, $ARGV[0], 0, $argend, $prefix) ) {
- $arg = shift(@ARGV);
+ if ( @$argv && ValidValue($ctl, $argv->[0], 0, $argend, $prefix) ) {
+ $arg = shift(@$argv);
+ $arg =~ tr/_//d if $ctl->[CTL_TYPE] =~ /^[iIo]$/;
($key,$arg) = $arg =~ /^([^=]+)=(.*)/
if $ctl->[CTL_DEST] == CTL_DEST_HASH;
next;
# ...otherwise, terminate.
else {
# Push this one back and exit.
- unshift (@ARGV, $tryopt);
+ unshift (@$argv, $tryopt);
return ($error == 0);
}
# Push back accumulated arguments
print STDERR ("=> restoring \"", join('" "', @ret), "\"\n")
if $debug;
- unshift (@ARGV, @ret);
+ unshift (@$argv, @ret);
}
return ($error == 0);
}
# Option lookup.
-sub FindOption ($$$$) {
+sub FindOption ($$$$$) {
# returns (1, $opt, $ctl, $arg, $key) if okay,
# returns (1, undef) if option in error,
# returns (0) otherwise.
- my ($prefix, $argend, $opt, $opctl) = @_;
+ my ($argv, $prefix, $argend, $opt, $opctl) = @_;
print STDERR ("=> find \"$opt\"\n") if $debug;
# Pretend one char when bundling.
if ( $bundling == 1 && length($starter) == 1 ) {
$opt = substr($opt,0,1);
- unshift (@ARGV, $starter.$rest) if defined $rest;
+ unshift (@$argv, $starter.$rest) if defined $rest;
}
warn ("Unknown option: ", $opt, "\n");
$error++;
$opt =~ s/^no-?//i; # strip NO prefix
$arg = 0; # supply explicit value
}
- unshift (@ARGV, $starter.$rest) if defined $rest;
+ unshift (@$argv, $starter.$rest) if defined $rest;
return (1, $opt, $ctl, $arg);
}
# Check if there is an option argument available.
if ( defined $optarg
? ($optarg eq '')
- : !(defined $rest || @ARGV > 0) ) {
+ : !(defined $rest || @$argv > 0) ) {
# Complain if this option needs an argument.
if ( $mand ) {
return (0) if $passthrough;
# Get (possibly optional) argument.
$arg = (defined $rest ? $rest
- : (defined $optarg ? $optarg : shift (@ARGV)));
+ : (defined $optarg ? $optarg : shift (@$argv)));
# Get key if this is a "name=value" pair for a hash option.
my $key;
warn ("Option $opt, key \"$key\", requires a value\n");
$error++;
# Push back.
- unshift (@ARGV, $starter.$rest) if defined $rest;
+ unshift (@$argv, $starter.$rest) if defined $rest;
return (1, undef);
}
}
# A mandatory string takes anything.
return (1, $opt, $ctl, $arg, $key) if $mand;
+ # Same for optional string as a hash value
+ return (1, $opt, $ctl, $arg, $key)
+ if $ctl->[CTL_DEST] == CTL_DEST_HASH;
+
# An optional string takes almost anything.
return (1, $opt, $ctl, $arg, $key)
if defined $optarg || defined $rest;
if ($arg eq $argend ||
$arg =~ /^$prefix.+/) {
# Push back.
- unshift (@ARGV, $arg);
+ unshift (@$argv, $arg);
# Supply empty value.
$arg = '';
}
|| $type eq 'I' # numeric/integer w/ incr default
|| $type eq 'o' ) { # dec/oct/hex/bin value
- my $o_valid =
- $type eq 'o' ? "[-+]?[1-9][0-9]*|0x[0-9a-f]+|0b[01]+|0[0-7]*"
- : "[-+]?[0-9]+";
+ my $o_valid = $type eq 'o' ? PAT_XINT : PAT_INT;
if ( $bundling && defined $rest
&& $rest =~ /^($key_valid)($o_valid)(.*)$/si ) {
($key, $arg, $rest) = ($1, $2, $+);
chop($key) if $key;
$arg = ($type eq 'o' && $arg =~ /^0/) ? oct($arg) : 0+$arg;
- unshift (@ARGV, $starter.$rest) if defined $rest && $rest ne '';
+ unshift (@$argv, $starter.$rest) if defined $rest && $rest ne '';
}
- elsif ( $arg =~ /^($o_valid)$/si ) {
+ elsif ( $arg =~ /^$o_valid$/si ) {
+ $arg =~ tr/_//d;
$arg = ($type eq 'o' && $arg =~ /^0/) ? oct($arg) : 0+$arg;
}
else {
if ( defined $optarg || $mand ) {
if ( $passthrough ) {
- unshift (@ARGV, defined $rest ? $starter.$rest : $arg)
+ unshift (@$argv, defined $rest ? $starter.$rest : $arg)
unless defined $optarg;
return (0);
}
"number expected)\n");
$error++;
# Push back.
- unshift (@ARGV, $starter.$rest) if defined $rest;
+ unshift (@$argv, $starter.$rest) if defined $rest;
return (1, undef);
}
else {
# Push back.
- unshift (@ARGV, defined $rest ? $starter.$rest : $arg);
+ unshift (@$argv, defined $rest ? $starter.$rest : $arg);
if ( $type eq 'I' ) {
# Fake incremental type.
my @c = @$ctl;
# We require at least one digit before a point or 'e',
# and at least one digit following the point and 'e'.
# [-]NN[.NN][eNN]
+ my $o_valid = PAT_FLOAT;
if ( $bundling && defined $rest &&
- $rest =~ /^($key_valid)([-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?)(.*)$/s ) {
+ $rest =~ /^($key_valid)($o_valid)(.*)$/s ) {
+ $arg =~ tr/_//d;
($key, $arg, $rest) = ($1, $2, $+);
chop($key) if $key;
- unshift (@ARGV, $starter.$rest) if defined $rest && $rest ne '';
+ unshift (@$argv, $starter.$rest) if defined $rest && $rest ne '';
}
- elsif ( $arg !~ /^[-+]?[0-9.]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/ ) {
+ elsif ( $arg =~ /^$o_valid$/ ) {
+ $arg =~ tr/_//d;
+ }
+ else {
if ( defined $optarg || $mand ) {
if ( $passthrough ) {
- unshift (@ARGV, defined $rest ? $starter.$rest : $arg)
+ unshift (@$argv, defined $rest ? $starter.$rest : $arg)
unless defined $optarg;
return (0);
}
$opt, " (real number expected)\n");
$error++;
# Push back.
- unshift (@ARGV, $starter.$rest) if defined $rest;
+ unshift (@$argv, $starter.$rest) if defined $rest;
return (1, undef);
}
else {
# Push back.
- unshift (@ARGV, defined $rest ? $starter.$rest : $arg);
+ unshift (@$argv, defined $rest ? $starter.$rest : $arg);
# Supply default value.
$arg = 0.0;
}
|| $type eq 'I' # numeric/integer w/ incr default
|| $type eq 'o' ) { # dec/oct/hex/bin value
- my $o_valid =
- $type eq 'o' ? "[-+]?[1-9][0-9]*|0x[0-9a-f]+|0b[01]+|0[0-7]*"
- : "[-+]?[0-9]+";
-
+ my $o_valid = $type eq 'o' ? PAT_XINT : PAT_INT;
return $arg =~ /^$o_valid$/si;
}
# We require at least one digit before a point or 'e',
# and at least one digit following the point and 'e'.
# [-]NN[.NN][eNN]
- return $arg =~ /^[-+]?[0-9.]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/;
+ my $o_valid = PAT_FLOAT;
+ return $arg =~ /^$o_valid$/;
}
die("ValidValue: Cannot happen\n");
}
elsif ( $try eq 'ignorecase' or $try eq 'ignore_case' ) {
$ignorecase = $action;
}
- elsif ( $try eq 'ignore_case_always' ) {
+ elsif ( $try eq 'ignorecase_always' or $try eq 'ignore_case_always' ) {
$ignorecase = $action ? 2 : 0;
}
elsif ( $try eq 'bundling' ) {
shift->SUPER::VERSION(@_);
}
+package Getopt::Long::CallBack;
+
+sub new {
+ my ($pkg, %atts) = @_;
+ bless { %atts }, $pkg;
+}
+
+sub name {
+ my $self = shift;
+ ''.$self->{name};
+}
+
+use overload
+ # Treat this object as an oridinary string for legacy API.
+ '""' => \&name,
+ '0+' => sub { 0 },
+ fallback => 1;
+
1;
################ Documentation ################
See L<Pod::Usage> for details.
-=head2 Storing option values in a hash
+=head2 Parsing options from an arbitrary array
+
+By default, GetOptions parses the options that are present in the
+global array C<@ARGV>. A special entry C<GetOptionsFromArray> can be
+used to parse options from an arbitrary array.
+
+ use Getopt::Long qw(GetOptionsFromArray);
+ $ret = GetOptionsFromArray(\@myopts, ...);
+
+When used like this, the global C<@ARGV> is not touched at all.
+
+The following two calls behave identically:
+
+ $ret = GetOptions( ... );
+ $ret = GetOptionsFromArray(\@ARGV, ... );
+
+=head2 Parsing options from an arbitrary string
+
+A special entry C<GetOptionsFromString> can be used to parse options
+from an arbitrary string.
+
+ use Getopt::Long qw(GetOptionsFromString);
+ $ret = GetOptionsFromString($string, ...);
+
+The contents of the string are split into arguments using a call to
+C<Text::ParseWords::shellwords>. As with C<GetOptionsFromArray>, the
+global C<@ARGV> is not touched.
+
+It is possible that, upon completion, not all arguments in the string
+have been processed. C<GetOptionsFromString> will, when called in list
+context, return both the return status and an array reference to any
+remaining arguments:
+
+ ($ret, $args) = GetOptionsFromString($string, ... );
+
+If any arguments remain, and C<GetOptionsFromString> was not called in
+list context, a message will be given and C<GetOptionsFromString> will
+return failure.
+
+=head2 Storing options values in a hash
Sometimes, for example when there are a lot of options, having a
separate variable for each of them can be cumbersome. GetOptions()
-supports, as an alternative mechanism, storing options in a hash.
+supports, as an alternative mechanism, storing options values in a
+hash.
To obtain this, a reference to a hash must be passed I<as the first
argument> to GetOptions(). For each option that is specified on the
strongly encouraged to use the C<Configure> routine that was introduced
in version 2.17. Besides, it is much easier.
+=head1 Tips and Techniques
+
+=head2 Pushing multiple values in a hash option
+
+Sometimes you want to combine the best of hashes and arrays. For
+example, the command line:
+
+ --list add=first --list add=second --list add=third
+
+where each successive 'list add' option will push the value of add
+into array ref $list->{'add'}. The result would be like
+
+ $list->{add} = [qw(first second third)];
+
+This can be accomplished with a destination routine:
+
+ GetOptions('list=s%' =>
+ sub { push(@{$list{$_[1]}}, $_[2]) });
+
=head1 Trouble Shooting
=head2 GetOptions does not return a false result when an option is not supplied
=head1 COPYRIGHT AND DISCLAIMER
-This program is Copyright 1990,2005 by Johan Vromans.
+This program is Copyright 1990,2007 by Johan Vromans.
This program is free software; you can redistribute it and/or
modify it under the terms of the Perl Artistic License or the
GNU General Public License as published by the Free Software