#!/usr/local/bin/perl package Argv ; use strict 'vars' ; # declare all internal variables for use of strict during testing. my( $opt, $opt_num, $opt_ref, $opt_name, $opt_names, $opt_count, $opt_list_ref, $opt_ref_type, $env_opts, @env_opts, $env_name, $short_name, $long_name, %long_name_to_opt, %short_name_to_opt, $var_name, $arg, $arg_val, @arg_vals, @val_range, @set_vals, %set_vals, $prefix, $long_prefix, $argv_end_opt, $argv_env_name, @argv_permuted_args, $usage, $usage_text, $default_val, $mutex, %mutex_opt, $sub_opt, @sub_opts, %file_is_to_op, $file_test, $control_hash_ref, $argv_end_token, $permute, $debug, $opt_val, $bool_opt_val, $sub_name, %no_long_name_to_opt, ) ; # initialize hash to convert from 'file_is' attributes to perl file test ops %file_is_to_op = ( 'plain' => '-f', 'dir' => '-d', 'symlink' => '-l', 'block' => '-b', 'char' => '-c', ) ; # Argv's main external routine sub Parse { ( $opt_list_ref, $control_hash_ref ) = @_ ; # check that the options descriptions is a ref to an array if ( ref $opt_list_ref ne 'ARRAY' ) { die "Options ref is not ARRAY, it is ", ref $opt_list_ref, "\n" ; } # parse the control hash ref &parse_control ; # preprocess the option descriptions &preprocess_opt_list ; # parse @ARGV for options &parse_argv ; # assign option values and defaults to their variables &assign_opt_vals ; # put the permuted argument in the front of @ARGV unshift( @ARGV, @argv_permuted_args ) ; } # parse the control value hash sub parse_control { # if no ref to the control value hash was passed in, make a empty one if ( ! defined( $control_hash_ref ) ) { $control_hash_ref = {} ; } # check that this is is a ref to a hash if ( ref $control_hash_ref ne 'HASH' ) { die "Control ref is not HASH, it is ", ref $control_hash_ref, "\n" ; } # assign control values from the hash or by default $long_prefix = exists( $control_hash_ref->{'long_prefix'} ) ? $control_hash_ref->{'long_prefix'} : '-' ; $argv_end_token = exists( $control_hash_ref->{'argv_end'} ) ? $control_hash_ref->{'argv_opt_end'} : '--' ; $argv_env_name = exists( $control_hash_ref->{'argv_env_name'} ) ? $control_hash_ref->{'argv_env_name'} : '' ; $permute = exists( $control_hash_ref->{'permute'} ) ? $control_hash_ref->{'permute'} : 1 ; $debug = exists( $control_hash_ref->{'debug'} ) ? $control_hash_ref->{'debug'} : 0 ; if ( $debug > 0 ) { print STDERR "Control Values: Long Prefix = '$long_prefix' Permute = '$permute' Debug = '$debug' Argv_env_name = '$argv_env_name' Argv_end_token = '$argv_end_token' " ; } } # preprocess all the option descriptions sub preprocess_opt_list { # loop over the option description list # use index numbers for error messages foreach $opt_num ( 0 .. $#{$opt_list_ref } ) { # get this item in the list and get its ref type $opt_ref = $opt_list_ref->[$opt_num] ; $opt_ref_type = ref $opt_ref ; # see if it is a ref if ( ! defined( $opt_ref_type ) ) { print STDERR "Argv: Option number $opt_num' is not a ref\n" ; exit -1 ; } # see if it is a HASH ref if ( $opt_ref_type ne 'HASH' ) { print STDERR "Argv: Option number $opt_num is not a HASH ref, it is a $opt_ref_type\n" ; return ; } # preprocess this option &preprocess_opt( $opt_num ) ; } } # This routine preprocesses each option description. These are the # operations it performs on each option: # # It checks for the short and long names and sets the default # value of the 'var' attribute if needed. # # It builds three hashes to convert command line option names to # a ref to their option description: long name to opt, long name with # 'no' prefix to to and short name to opt. # # It sets the default of boolean options if needed # # It converts a 'set' attribute to a 'set_vals' attribute sub preprocess_opt { # get the option number my( $opt_num ) = @_ ; # get the short, long and variable names $short_name = $opt_ref->{'short'} ; $long_name = $opt_ref->{'long'} ; $var_name = $opt_ref->{'var'} ; if ( $debug > 3 ) { print STDERR " Argv: short = '$short_name' long = '$long_name' var = '$var_name'\n" ; } # see if a long name is defined if ( defined( $long_name ) ) { # store the ref to this option indexed by the long name $long_name_to_opt{ $long_name } = $opt_ref ; # set the default variable name unless it has one $var_name = "opt_$long_name" unless defined( $var_name ) ; # save the long name for error messages $opt_names = $long_name ; # see if this is a boolean with a 'no' attribute if ( ! defined( $opt_ref->{'count'} ) && defined( $opt_ref->{'no'} ) ) { # store the ref to this option indexed by the long name with 'no' prefixed $no_long_name_to_opt{ "no$long_name" } = $opt_ref ; } } else { # no long name found $opt_names = undef ; } # see if a short name is defined if ( defined( $short_name ) ) { # check the that the short name length is 1 if ( length( $short_name ) != 1 ) { print STDERR "Argv: Option number $opt_num's short name $short_name is longer than 1\n" ; exit -1 ; } # store the ref to this option indexed by the short name $short_name_to_opt{ $short_name } = $opt_ref ; # set the default variable name unless it has one $var_name = "opt_$short_name" unless defined( $var_name ) ; if ( defined( $opt_names ) ) { # append the short name for error messages $opt_names = "$short_name/$opt_names" ; } else { $opt_names = $short_name ; } } # check to see that either a long or short name was found if ( ! defined( $opt_names ) ) { print STDERR "Argv: Option number $opt_num has no name\n" ; exit -1 ; } # save the names and the variable name in the option description $opt_ref->{'names'} = $opt_names ; $opt_ref->{'var'} = $var_name ; # see if this is a boolean with no default if ( ! defined( $opt_ref->{'count'} ) && ! defined( $opt_ref->{'default'} ) ) { # give the boolean a default of 0 $opt_ref->{'default'} = 0 ; } # see if this is not a boolean and it has a 'set' attribute if ( defined( $opt_ref->{'count'} ) && defined( $opt_ref->{'set'} ) ) { # get the array of values from the 'set' attribute @set_vals = @{$opt_ref->{'set'}} ; # initialize the 'set_vals' attribute with the keys and values of the # hash being the same. # this uses a hash slice @{$opt_ref->{'set_vals'}}{ @set_vals } = @set_vals ; } } # parse the options in @ARGV sub parse_argv { # see if there is program environment variable and it exists if ( defined( $argv_env_name ) ) { $env_opts = $ENV{ $argv_env_name } ; if ( defined( $env_opts ) ) { # split the ENV value on white space @env_opts = split( ' ', $env_opts ) ; if ( $debug > 1 ) { print STDERR "Argv: Options from ENV $argv_env_name =\n\t\t'", join( "'\n\t\t'", @env_opts ), "'\n" ; } # put these options in front of @ARGV for parsing unshift( @ARGV, @env_opts ) ; } } # loop over the tokens in @ARGV # NOTE: @ARGV can grow if bundled short options get parsed while( @ARGV ) { # get option token $opt = shift @ARGV ; if ( $debug > 5 ) { print STDERR "Argv: Option token = '$opt'\n" ; } # see if this mark the end @ARGV if ( $opt eq $argv_end_token ) { if ( $debug > 2 ) { print STDERR "Argv: argv end option found\n"; } # found end of @ARGV marker; done parsing return ; } # here come the big re # # this matches the required prefix ('-' or the long prefix) # followed by a string up an '=' and another string # # the '=' and its argument string are optional $opt =~ /^(-|\Q$long_prefix\E)([^=]+)(=(.+))?$/o ; if ( $debug > 3 ) { print STDERR "prefix: '$1' option: '$2' equal: '$3' arg: '$4'\n" ; } $prefix = $1 ; # see if this has no prefix which means it is a positional argument if ( ! defined( $prefix ) ) { # see if we permute the positional arg (move it past options in @ARGV) if ( $permute ) { if ( $debug > 4 ) { print STDERR "Argv: permuted arg = '$opt'\n" ; } # save the permuted arg for later when it get put back in front of @ARGV push( @argv_permuted_args, $opt ) ; next ; } else { if ( $debug > 4 ) { print STDERR "Argv: first positional arg = '$opt'\n" ; } # put the arg back in front of @ARGV and stop parsing unshift( @ARGV, $opt ) ; return ; } } # get the option name from the re $opt_name = $2 ; # see if the '=' was found if ( defined( $3 ) ) { if ( $debug > 5 ) { print STDERR "Argv: option=arg found\n" ; } # put the argument back into @ARGV for later use unshift( @ARGV, $4 ) ; } if ( $debug > 5 ) { print STDERR "Argv: option name: '$opt_name'\n" ; } # clear any old option ref we may have had $opt_ref = undef ; # look for a long prefix if ( $prefix eq $long_prefix ) { # see if this long name is found $opt_ref = $long_name_to_opt{ $opt_name } ; # if not found look for a 'no' prefix long name if ( ! defined( $opt_ref ) ) { $opt_ref = $no_long_name_to_opt{ $opt_name } ; # 'no' prefix found! make the boolean value 0 if ( defined( $opt_ref ) ) { if ( $debug > 3 ) { print STDERR "Argv: option $opt_name has a 'no' prefix\n" ; } $bool_opt_val = 0 ; } } } # see if the long name wasn't found if ( ! defined( $opt_ref ) ) { # this must be a short name. # see if it is bundled (if the string is more than 1 char) if ( length( $opt_name ) > 1 ) { &parse_bundled_opts ; next ; } # a single letter name, get its option $opt_ref = $short_name_to_opt{ $opt_name } ; # if the short name wasn't found, error if ( ! defined( $opt_ref ) ) { print STDERR "Argv: Option '$opt_name' is unknown\n" ; &print_usage ; } # set the boolean option value $bool_opt_val = 1 ; } # see if this is a 'usage' or a 'help' option and call thos routines if so if ( defined( $opt_ref->{'is_usage'} ) ) { &print_usage ; } if ( defined( $opt_ref->{'is_help'} ) ) { &print_help ; } # store the the used name of this option in its description $opt_ref->{'argv_name'} = $opt_name ; # see if this option has a mutex attribute $mutex = $opt_ref->{'mutex'} ; if ( defined( $mutex ) ) { # see if this mutex was set before if ( defined( $mutex_opt{ $mutex } ) ) { print STDERR "Options '$opt_name' and '$mutex_opt{ $mutex }' are mutually exclusive\n" ; &print_usage ; } # mutex was not used before; mark it used $mutex_opt{ $mutex } = $opt_name ; if ( $debug > 5 ) { print STDERR "Argv: option: '$opt_name' has mutex '$mutex'\n" ; } } # $var_name = $opt_ref->{'var'} ; $opt_count = $opt_ref->{'count'} ; #print "var name $var_name count $opt_count\n" ; if ( ! defined( $opt_count ) ) { $opt_ref->{'value'} = $bool_opt_val ; } elsif ( $opt_count == 1 ) { if ( @ARGV < 1 ) { print STDERR "Missing argument for opt '$opt_name'\n" ; &print_usage ; } $arg_val = shift @ARGV ; #print "ARGV arg val: $arg_val\n" ; if ( defined( $opt_ref->{'subopt'} ) ) { @sub_opts = split( ',', $arg_val ) ; @sub_opts = map { /(.+)=(.+)/ ? ("$long_prefix$1", $2) : "$long_prefix$_" } @sub_opts ; unshift( @ARGV, @sub_opts ) ; #print "sub ARGV @ARGV\n" ; } &check_arg_vals( $arg_val ) ; if ( defined( $opt_ref->{'multi'} ) ) { push( @{$opt_ref->{'value'}}, $arg_val ) ; } else { $opt_ref->{'value'} = $arg_val ; } } else { if ( @ARGV >= $opt_count ) { @arg_vals = splice( @ARGV, 0, $opt_count ) ; #print "ARGV arg vals: @arg_vals\n" ; &check_arg_vals( @arg_vals ) ; @{$opt_ref->{'value'}} = @arg_vals ; } else { print STDERR "Missing arguments for opt '$opt_name'\n" ; exit -1 ; } } } } # This routine parses a bundled string of single letter (short) # options. When it is done the unbundled options (each with a '-' # prefix) and a possible attached scalar argument are pushed back into # @ARGV for parsing sub parse_bundled_opts { my( $opt_char, $bundled_text, @flag_opts ) ; # save the bundled text for the error message $bundled_text = $opt_name ; # loop until no more letters in bundled string while( $opt_name ne '' ) { # get the first letter and rest of the string $opt_char = substr( $opt_name, 0, 1 ) ; $opt_name = substr( $opt_name, 1 ) ; print STDERR "Argv: Bundled char $opt_char\n" if $debug > 2 ; # look up this single letter option $opt_ref = $short_name_to_opt{ $opt_char } ; # see if it not found, then error if ( ! defined( $opt_ref ) ) { print STDERR "Argv: Bundled option '$opt_char' in '$bundled_text' is unknown\n" ; &print_usage ; } # save this option with the 'short' prefix char push( @flag_opts, "-$opt_char" ) ; # see if this was a scalar option if ( defined( $opt_ref->{'count'} ) ) { # see if this is an attached scalar argument # use the rest of the token for the argument if there are any chars in it push( @flag_opts, $opt_name ) if $opt_name ne '' ; last ; } } # put these unbundled option back into @ARGV for parsing unshift( @ARGV, @flag_opts ) ; } sub check_arg_vals { my( @arg_values ) = @_ ; $sub_name = $opt_ref->{'sub'} ; if ( defined( $sub_name ) && defined( &{"::$sub_name"} ) ) { if ( &{"::$sub_name"}( $opt_ref, @arg_values ) == 1 ) { return ; } &print_usage ; } #print "check vals: @arg_values\n" ; my( $arg_val ) ; foreach $arg_val ( @arg_values ) { if ( defined( $opt_ref->{'is_int'} ) ) { if ( $arg_val !~ /^[+-]?\d+$/ ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not an integer\n" ; &print_usage ; } } if ( defined( $opt_ref->{'is_hex'} ) ) { if ( $arg_val !~ /^(0[xX])?[a-fA-F\d]+$/ ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not hex\n" ; &print_usage ; } } if ( defined( $opt_ref->{'is_oct'} ) ) { if ( $arg_val !~ /^0[0-7]+$/ ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not octal\n" ; &print_usage ; } } if ( defined( $opt_ref->{'is_float'} ) ) { #/^(\+|-)?(\d+\.?\d*|\.\d+)([eE](\+|-)?\d+)?$/ unless ( $arg_val =~ /^[+-]?(\d+)?(\.)?(\d+)?([eE][+-]?\d+)?$/ && ($1 ne '' || $3 ne '') && ( $2 || $4 ) ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not a float\n" ; &print_usage ; } } if ( defined( $opt_ref->{'file_is'} ) ) { $file_test = $file_is_to_op{$opt_ref->{'file_is'}} ; #print "file test $file_test\n" ; if ( defined( $file_test ) && ! eval "$file_test '$arg_val'" ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not a $opt_ref->{'file_is'} file\n" ; &print_usage ; } } if ( defined( $opt_ref->{'set_vals'} ) ) { %set_vals = %{$opt_ref->{'set_vals'}} ; $arg_val = $set_vals{ $arg_val } ; if ( ! defined( $arg_val ) ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' is not in set:\n\t{", join( ' | ', sort keys %set_vals ), " }\n" ; &print_usage ; } } if ( defined( $opt_ref->{'range'} ) ) { @val_range = @{$opt_ref->{'range'}} ; #print "RANGE var $var_name range @val_range\n" ; if ( $arg_val < $val_range[0] ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' < range [@val_range]\n" ; &print_usage ; } if ( $arg_val > $val_range[1] ) { print STDERR "\nOption '$opt_ref->{'argv_name'}' value '$arg_val' > range [@val_range]\n" ; &print_usage ; } } } } sub assign_opt_vals { # local( $opt_val ) ; foreach $opt_ref ( @{$opt_list_ref } ) { $var_name = $opt_ref->{'var'} ; $opt_count = $opt_ref->{'count'} ; # $opt_val = ( exists( $opt_ref->{'value'} ) ) ? # $opt_ref->{'value'} : undef ; $opt_val = $opt_ref->{'value'} ; if ( ! defined( $opt_val ) ) { $env_name = $opt_ref->{'env'} ; if ( defined( $env_name ) ) { if ( ! defined( $opt_count ) ) { $opt_val = 1 ; } elsif ( $opt_count == 1 ) { $opt_val = $ENV{ $env_name } ; } else { $opt_val = [ split( ' ', $ENV{ $env_name } ) ] ; } } } if ( ! defined( $opt_val ) ) { $default_val = $opt_ref->{'default'} ; if ( defined( $default_val ) ) { $opt_val = $default_val ; } } #print "var $var_name value $opt_val default $default_val\n" ; if ( ! defined( $opt_count ) ) { if ( defined( $opt_ref->{'invert'} ) ) { #print "val $opt_val\n"; $opt_val = ( $opt_val ) ? 0 : 1 ; #print "ival $opt_val\n"; } ${"::$var_name"} = $opt_val ; } else { #print "2name $var_name opt val $opt_val default $default_val \n" ; if ( defined( $opt_val ) ) { if ( defined( ref( $opt_val ) ) ) { #print "name $var_name opt val $opt_val default $default_val \n" ; @{"::$var_name"} = @{$opt_val} ; #print "var $var_name array: @{$opt_val}\n" ; #print "main var $var_name array: ", @{"main::$var_name"}, "\n" ; } else { #print "var $var_name scalar: $opt_val\n" ; ${"::$var_name"} = $opt_val ; } } elsif ( defined( $opt_ref->{'required'} ) ) { print STDERR "\nRequired option '$opt_ref->{'names'}' has no value\n" ; &print_usage ; } } } } sub print_usage { if ( defined( &::usage ) ) { &::usage ; exit( -1 ) ; } $usage_text = "\nUsage: $0 " ; foreach $opt_ref ( @{$opt_list_ref } ) { $usage = $opt_ref->{'usage'} ; #print "'$usage'\n" ; next unless defined( $usage_text ) ; if ( length( $usage_text ) + length( $usage ) < 70 ) { $usage_text .= " $usage" ; } else { print STDERR "$usage_text\n" ; $usage_text = "\t$usage" ; } } print STDERR "$usage_text\n\n" ; exit -1 ; } sub print_help { if ( defined( &::help ) ) { &::help ; exit( -1 ) ; } print STDERR "\n\nHelp for $0\n\n" ; foreach $opt_ref ( @{$opt_list_ref } ) { print STDERR $opt_ref->{'help'} ; } print STDERR "\n\n" ; exit -1 ; } 1 ; __END__ =head1 NAME =item B - A flexible and extendable attribute based Argv parser for Perl5 =head1 SYNOPSIS =item The B package is an attribute based parser for command line options of Perl5 scripts. It is designed to be very easy to use, highly flexible and user extendable. It handles all standard styles of options and arguments including single character options and long options with a user selectable prefix. It has a large set of argument validation checks and support for usage and help strings. =head1 DESCRIPTION =item Each B option is described by a set of attribute/value pairs, implemented as a hash reference. A ref to a list of these hashes is the main argument to the B parser (see I section). All attributes are optional except for either I or I. Attributes control the type of an option, how to get its arguments (if any) and how to check the validity of those arguments. Option attributes come in variety of flavors; boolean attributes just need to be defined (their value is ignored but should be 1 for style reasons), scalar attributes have a single scalar value and array and hash attributes take those aggregates. A special case, the I attribute can take any type of value. Options can be booleans, scalars, arrays or hashes and argument values can be checked in a variety ways including numeric forms (integer, hex, octal, float), file types (plain, directory, character and block devices), value range, set membership, and by custom user code. Option values can be set (in decreasing priority) by command line arguments, a program specific environment variable, option specific environment variables and option defaults. Options can have their own usage and help text which and can be printed by the Argv package upon error detection or if a specified option is parsed. =head1 USAGE =item The B package has one entry point, B which takes 2 arguments, a reference to an array of option descriptions and an optional reference to a hash of control values. An option description is a hash comprised of attribute keys and their values. The control argument is a hash of keys and values which affect global behavior of the Argv package. The simplest option description has just either a I or a I attribute (or both but it must have at least one). These specify the string to look for in @ARGV with the appropriate prefix. The Perl variable name that get the argument value defaults to opt_ if that attribute is set or then opt_. You can set the variable name with the I attribute. The Perl data type of the variable is controlled by several attributes: I, I and I. An option with no I attribute is a boolean and one with I = 1 is a simple scalar. See L for more. NOTE: These are symbols used in the descriptions below: 1 is used to enable boolean attributes is any text string is an integer is any scalar value is an array ref e.g. [ 1, 2 ] is a hash ref e.g. { 'x' => 1, 'y' => 2 } is a file test name (plain, dir, symlink, block, char) B should be called in the BEGIN routine of main:: so it can be executed before any other code and can affect internal perl variable such as @INC. Emulation of the basic Getops package would look like this: BEGIN { $argv_opts = [ # boolean option -a sets variable $opt_a { 'short' => 'a' }, # boolean option -bbb sets variable $opt_bbb { 'long' => 'bbb' }, # boolean option -c or -ccc sets variable $opt_ccc { 'short' => 'c', 'long' => 'ccc' }, # scalar option -d or -ddd sets variable $ddd_val { 'short' => 'd', 'long' => 'ddd' 'count => 1, 'var' => 'ddd_val' } ] ; &Argv::Parse( $argv_opts ) ; } =head1 CONTROL VALUES =item These values control global behavior of the B package. They are passed to B as a hash ref in the second argument. If it is not used or any control values aren't set in the hash, the default values will be used. Here is an example of how to set up the control value hash: BEGIN { $argv_opts = [ { 'short' => 'a' }, { 'short' => 'b' }, ] ; $argv_control = { 'argv_env_name>' => 'OPT_ENV', 'argv_end_token' => '++', 'long_prefix>' => '--', 'permute>' => 0, # 'debug>' => 1, # comment out debug tracing } ; &Argv::Parse( $argv_opts, $argv_control ) ; } These are the supported control values for the B package. If this argument is not used or a control key is not used, a default value is assigned to each control variable. =head2 Program Environment Variable =item 'I'> => # name of env variable =item This sets the name of the program's environment variable which is parsed for options before the command line is parsed. If this variable exists it is split on white space and its tokens are unshifted into @ARGV which is then parsed as usual. These options are parsed before command line options and they can be overridden the command line. There is no default value. =head2 End of Argv Options =item 'I' => '++' # stop parsing after ++ is seen This is the token which is recognized as the end of option tokens on the command line. All tokens after this are left in @ARGV for the program to use. The default is the POSIX value of '--'. The example above changes it to '++'. =head2 Long Name Prefix =item 'I' => '--' # long options marked with -- =item This is the prefix string which marks a token as a long name option. Its default is '-' which is the same as for short options. Commonly used values are C<'+' and '--'>. =head2 Permute Arguments =item 'I' => 0 # turn off permuting =item This is a boolean control value which allows positional arguments to be permuted to after any named options. Any option token which doesn't has a valid prefix is saved and later unshifted into @ARGV for use by the program. For example, (assuming only boolean options) 'C<-a foo -b bar>' would have the flags 'a' and 'b' set to 1 with @ARGV set to ('foo', 'bar' ). The default value for I is 1. The example above turns of argument permuting. =head2 Debug Trace Level =item 'I' => 2 # print values and tokens =item This control value which set the debug trace level in Argv. If it is grater than 0 the debug trace values are printed. The higher the value, the more that gets printed. Its default value is 0 which mean nothing gets printed. This is a rough description of what each debug level prints: Level Prints 0 Nothing 1 Control values 2 Program environment variable value 3 Prgogram flow and option values 4 Each token as it is parsed 5 Preprocess phase 6 Complete list of option descriptions after parsing =head1 OPTION TYPES =item Argv options can be one of 5 types: boolean, scalar, multi-value scalar, array and subopt. See L for examples of boolean and scalar option descriptions. =head2 Boolean =item Boolean options take no arguments and are guaranteed to have a value of 0 or 1. They are stored into scalar variables. Boolean option short names can be bundled (e.g. -abc) The logical sense of the option value is inverted by using the boolean attribute I (e.g. option C<-a> has a value of 0 while its default value is 1). The I attribute allows an optional 'no' prefix in front of long boolean option names and if the prefix is found, the option value is 0 instead of 1. If a boolean option has no I attribute it is given one with a value of 0. =head2 Scalar =item Scalar options must have 1 argument and they are stored in scalar variables. If the Scalar arguments can be attached (e.g. C<-I/dir1>) or loose. A scalar option short name can be at the end of a bundled set of boolean option short names and its argument can be attached or loose (e.g. C<-abcI/dir1 -abcI> /dir1 ). =head2 Multi-Value Scalar =item Multi-value scalar options have the same behavior as scalar options but can appear multiple times in @ARGV. They are stored in array variables. The most well known use is for multiple include path options of the form C<-I/dir1 -I/dir2> ). The following is an example of that: { 'short' => 'I', # no long name 'count => 1, # scalar option 'multi => 1, # multiple values allowed 'var' => 'inc_args # store args in var @inc_args } =head2 Array =item Array options must have the requested number of arguments and are stored in array variables. If The following example describes a option with three arguments. It would parse either: -A -array { 'short' => 'A', # short name 'long' => 'array', # long name 'count => 3, # 3 arguments needed 'var' => 'array_args # values into var @array_args } =head2 Subopt =item A subopt option has an single argument which is in the form of a suboption, i.e. a comma separated list of keywords, each with an optional '=' and value (e.g C<-o> ro,root=foo,bg). It is stored in a hash variable with the keys found in the argument and the values found or 1 if there is no value. =head1 OPTION ATTRIBUTES =item These are descriptions of all the supported optionsattributes in the B package. They are grouped int these catagories: B, B, B, B, B and B. NOTE: You can add any custom attributes to an option description and access them in the I to validate the argument. The B package ignores any attributes it doesn't use. =head2 Name Attributes These attributes control the names to be parsed in @ARGV and the name of the option variable: =item 'I' => # Short name of option =item 'I' => # Long name of option =item 'I' => # Name of option variable =item The I attribute defines the single letter name of an option and the I attribute defines a long name for an option. One of these MUST be defined or B will print an error message and exit. These attributes control the default name for the Perl variable name for this option. If I is set the the variable name is 'opt_' with the value I appended to it. If the I attribute is not set then the I attribute value is appended. You can define the name of the option variable directly with the I attribute. Remember that these attributes only control the name of the variable and not its type. You could have different options with the same variable name but with differing types. =head2 Type Attributes =item These attributes control the type of an option: =item 'I' => # Count of arguments for option =item 'I' => 1 # Scalar opt is multivalued array =item 'I' => 1 # Scalar argument is suboption The I attribute divided options into three categories: boolean, scalar and array. If I is not defined, the option is boolean and it takes no arguments and will have a value of 0 or 1. If I equals one, the option is scalar and it takes one argument which must exist. If I is greater than one, then it is an array option and it takes I arguments which must exist. All the arguments are assigned to an array option variable. If the I attribute is set and the array option value comes from the environment, the environment string is split on blanks. You can set the I attribute to change the split string. The boolean attributes I and I modify the processing of the scalar value. If I is set, then the option variable is an array and the scalar values are pushed onto the array. If I is set then the scalar value is parsed for suboptions keywords and optional values. The keywords and values are assigned to a hash option variable. If a keyword has no value, it is given the value 1. If the I attribute is set and array option value comes from the environment, the environment string is split on ',' (comma). You can set the I attribute to change the split string. As a side effect, multiple occurences of a I option can be parsed and the suboptions are added to the same hash variable. If this is not desired, you can set a unique value of the I attribute so only one I option is allowed. If the option has the I attribute set, then only those keys found in the set are allowed in the suboption. See the I section for examples of boolean and scalar options. See the I