The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Config::Param - all you want to do with parameters for your program (or someone else's)

SYNOPSIS

Just use the module, define your parameters

        use Config::Param;

        # the definitions in flat array
        # remember: parameters help / h and config / I are predefined!
        my @pardef =
        (
           'parm1', $default1,  'a', 'help text for scalar 1'
          ,'parm2', $default2,  'b', 'help text for scalar 2'
          ,'parmA', \@defaultA, 'A', 'help text for array A'
          ,'parmH', \@defaultH, 'H', 'help text for hash H'
          ,'parmX', $defaultX,  '', 'help text for last one (scalar)'
        );

and call the parser,

        $parm_ref = Config::Param::get(@pardef);

        print "Value of parameter 'parm1': $parm_ref->{parm1}\n";
        print "Contents of array 'parmA': @{$parm_ref->{parmA}}\n";

possibly including some extra configuration,

        my %config =
        (
          'info' => 'program info text',
          'version' => '1.2.3'
          # possibly more configuration key/value pairs
        );
        $parm_ref = Config::Param::get(\%config, @pardef);

or

        $parm_ref = Config::Param::get(\%config,\@pardef); 

or

        $parm_ref = Config::Param::get(\%config,\@pardef,\@cmdline_args); 

The most complicated call is this, making only sense when disabling final exit:

        $config{noexit} = 1; # or nofinals
        $parm_ref = Config::Param::get(\%config,\@pardef,\@cmdline_args, $errors); 

This will return a count of errors encountered (bad setup, bad command line args). With default configuration, the routine would not return on error, but end the program. Errors will be mentioned to STDERR in any case.

Finally, you can use a Config::Param object to do what Config::Param::get does:

        # equivalent to
        # $parm_ref = Config::Param::get(\%config,\@pardef);
        my $pars = Config::Param->new(\%config, \@pardef);
        $pars->parse_args(\@ARGV);
        $pars->use_config_files();
        $pars->apply_args();
        $pars->final_action();
        $parm_ref = $pars->{param};

DESCRIPTION

The basic task is to take some description of offered parameters and return a hash ref with values for these parameters, influenced by the command line and/or configuration files. The simple loop from many years ago now is about the most comprehensive solution for a program's param space that I am aware of, while still supporting the one-shot usage via a single function call and a flat description of parameters.

It handles command line parameters (somewhat flexible regarding the number of "-", but insisting on the equal sign in --name=value), defining and handling standard parameters for generating helpful usage messages and parses as well as generates configuration files.

command line parameter processing

Process command line options/switches/parameters/... , be it short or long style, supporting clustering of short options. Interprets --parm=value / -p=value with the obvious effect; sets option to 1 (which is true) when just --option / -o is given. Also, though somewhat counterintuitive but sort of a standard already and logically following the idea that "-" is true, ++option / +o will set the value to 0 (false). The form "--parm value" is not supported as no simple bullet-proof generic way to do that came across my mind. There is the fundamental problem of deciding if we have a parameter value or some other command line data like a file name to process. Since this problem still persists with the "=" used in assignment when one considers a file with a name like "--i_look_like_an_option", which is perfectly possible, Param also looks out for "--" as a final delimiter for the named parameter part, which is also quite common behaviour. The command line arguments after "--" stay in the input array (usually @ARGV) and can be used by the calling program. The parsed parameters as well as the optional "--" are removed; so, if you want to retain your @ARGV, just provide a copy.

You can have scalars, hashes or arrays (references, of course) as values for your parameters. The hash/array type is chosen when you provide an (anonymous) hash/array reference as default value.

Hash values are set via prefixing a key with following "=" before the actual value:

        --hashpar=name=value

A nifty feature is the support of operators. Instead of --parm=value you can do do --parm.=value to append something to the existing value. When -p is the short form of --parm, the same happens through -p.=value or, saving one character, -p.value (but not --parm.value, here the dot would be considered part of the parameter name). So "--parm=a --parm.=b -p.c" results in the value of parm being "abc".

This is especially important for sanely working with hashes and arrays:

        --hashpar.=name=value --hashpar.=name2=value2
        --arraypar=value --arraypar.=value2

The plain "=" operator resets the whole array/hash! Besides ".=", these operators are available:

=

Direct assignment.

.= or short .

String concatenation for scalar parameters, pushing values for array and hash parameters.

+= or short +

Numeric addition to scalar value.

-= or short -

Numeric substraction to scalar value.

*= or short *

Numeric multiplication of scalar value.

/= or short /

Numeric division of scalar value.

You can omit the = for the short-form (one-letter) of parameters on the command line when using special operators, but not in the configuration file. There it is needed for parser safety. The operators extend to the multiline value parsing in config files, though (see the section on config file syntax).

See the lazy configuration switch for a modified command line syntax, saving you some typing of "-" chars.

automatic usage/version message creation

Based on the parameter definition Config::Param automatically prints the expected usage/help message when the (predefined!) --help / -h was given, with the info string in advance when defined, and exits the program. You can turn this behaviour off, of course. An example for the generated part of the help message:

        par_acceptor v1.0.0 - Param test program that accepts
        any parameter given

        Generic parameter example (list of real parameters
        follows):
                par_acceptor -s -xyz -s=value --long --long=value [--] [files/stuff]
        Just mentioning -s equals -s=1 (true), while +s equals
        -s=0 (false).
        Using separator "--" makes sure that parameter parsing
        stops.

        Recognized parameters:
        NAME, SHORT   VALUE [# DESCRIPTION]
        ballaballa .. '0' # a parameter with meta data
        bla ......... ['1']
        blu ......... '42'
        config, I ... [] # Which configfile(s) to use
                      (overriding automatic search in likely
                      paths);
                      special: just -I or --config causes
                      printing a current config file to STDOUT
        help, h ..... 1 # show the help message; 1: normal
                      help, >1: more help; "par": help for
                      paramter "par" only
        includepar .. 'I got included, yeah!'
        version ..... 0 # print out the program version

Note: When printing to a terminal, Config::Param tries to determine the screen width and does a bit of formatting to help readability of the parameter table.

configuration file parsing

The module also introduces a simple but flexible configuration file facility. Configuration means simply setting the same parameters that are available to the command line.

The second and last predefined parameter called "config" (short: I) is for giving a file (or several ones, see below!) to process before the command line options are applied (what the user typed is always the last word). If none is given, some guessing may take place to find an appropriate file (see below). When just -I or --config is given (no =!), then a file with the current configuration ist written to STDOUT and the program exits (unless ignorefinals is set). When you give the lonely -I or --config once, you'll get a explained config file with comments and meta info, when you give the option twice, you get a condensed file with only the raw settings and a small header telling for which program it is.

Config files are parsed before applying command line arguments, so that the latter can override settings.

configuration file creation

Well, of course the module will also create the configuration files it consumes, giving --conf or -I without further argument triggers writing of a configuration file to standard output and exit of program

Configuration file syntax

The syntax of the configuration files is based on simple name and value pairs, similar to INI files (no sections, though you can use dots in parameter names to mimick them). In a configuration file, only the long name of a parameter is used:

        mode = "something"

sets the parameter mode to the value something. Actually,

        mode = something

would do the same. The whitespace around the operator (here: =) and before the line break is ignored. You want to use (double) quotes when defining a value that begins or ends with whitespace:

        mode = " something spacy "

Consequently, you have to use quotes around the value if it starts with a quote character:

        mode = ""something with a quote"

The stuff between the first " and the last " will be used as value (you do not need to quote your quotes individually). If you want your strings to contain multiple lines (or just a single actual newline character), you can use this, which should look familiar from Perl:

        mode <<EOT
        a line
        another line
        bla
        EOT

You can replace the EOT with anything you like... even nothing - then, the next empty line marks the end. Only rule is that the end marker should not appear in the multiline value itself (alone on a line). Please note that this not being actual Perl syntax, there are no semicolons here.

Also, the last line end before the end marker is stripped, so if you want it included, add an empty line:

        mode <<EOT
        a line

        EOT

You can also use the funny operators introduced for command line parameters by replacing the = with .=, +=, -=, /=, *= as you like. That works for the <<EOT multiline construct, too, just make it .<<EOT for appending and likewise +<<EOT, -<<EOT , /<<EOT, *<<EOT for the other operations.

Also, just mentioning the parameter name sets it to a true value, like simple mentioning on command line. And that is actually one reason for not just using another markup or serialization format for configuration files: The specification in the file follows the same concepts you have on the command line (esp. regarding operator use). It is the same language, although with some slight deviation, like the here document and string quoting, which is matter of the shell in the case of command lines.

Comments in the config file start with "#" and are supposed to be on lines on their own (otherwise, they will get parsed as part of a parameter value). Special tokens for the parser (see see parse_file method, with the optional parameter) start with "=", the important one is inclusion of other config files:

        =include anotherconfigfile

This will locate anotherconfigfile (relative paths are relative to the current config file, also search paths are used) and load its settings in-place, then continue with the current file. Note that there is no check for inclusion loops (yet). The file name starts with the first non-whitespace after =include and continues until the end of line. No quoting.

There are more tokens in a fully annotated output of config files. Example:

        # I skipped  block of comments explaining the config file syntax.
        =param file for par_acceptor
        =version 1.0.0

        =info Param test program that accepts any parameter given

        =long ballaballa type scalar
        =help a parameter with meta data

        ballaballa = "0"

Only the last line in this example is relevant to the program itself (named "par_acceptor" here). The rest is auxilliary information for outsiders.

One last note: If a parameter value is undefined, no assignment is written to the config file. So a config file can never intentionally set a value to undefined state. You can start out with undef values, but as soon as the parameter got set one time to something else, it won't go back undef.

The config keys

Note that the hash ref you give to the constructor is taken over by the object; if you want to preserver the original hash, you have to make a copy yourself. It is the same with parameter definitions as array ref; consumed by initialization.

info (some text)

A text to print out before the parameter info when giving help.

program

name of the program/package, used in search for config file and for output of config files/messages; default is basename($0)

version

Version string for your program; this activates the definition of a --version switch to print it.

verbose (0 / 1)

When not 0, be verbose about the work being done. There may be different verbosity levels in the future, but for now value 4 is no different from 1. You can set $Config::Param::verbose to the same effect, globally.

multi (0 / 1)

If activated, potentially parses all located default config files in a row instead of choosing one (currently this is about generic and host config file; might get extended to system global vs. $HOME).

confdir (directory path)

Define a directory for searching of config files, overriding the internal default of "../etc" relative to the directory containing the program (or the program dir itself if no etc there); explicitly given files are always searched in the current working directory first if the given form does not already specify an existing file completely.

file (single file name/path or array ref of those)

Define the default config file (s), overriding the internal default of confdir/programname.conf or (being more powerful if existing) confdir/programname.hostname.conf . The .conf suffix will be added if needed. A word on the hostname: This is a possibility to use one configuration directory for several hosts (p.ex. mounted over NFS).

BEWARE: Every smartness has its catch - when you do a `myprogram -I=my -I > my.conf` the newly created (and empty) file my.conf in the currect directoy is found and used as config file for reading, resulting in the program defaults being written regardless of what another existing my.conf would say!

nofile (0 / 1)

Prevent automatic parsing of configuration files.

gimme (0 / 1)

Give help end exit if no command line arguments are there.

lazy (0 / 1)

Switch to the "lazy" syntax that allows omitting the "-" and "--" in -p and --parameter (same with "+" and "++") most of the times but absolutely requires the separation of other stuff with /-+/ (read this as PERL regex;-).

nofinals (0 / 1)

Do not take final action on certain switches (help, version, config file printing). Normally (with nofinals == 0), Param would exit your program on processing these.

noexit (0 / 1)

Do final actions, but do not exit on those. Also prevents dying in constructor (and by extension, the get routine). You are supposed to check the error list.

notinfile (listref)

list with parameters (long names) not to include in config file printing, help and config are always left out as they make no sense in files (config might make sense, but there is =include to handle that).

nanny (0 / 1)

give parameter help and exit() when encountering unknown parameters in config files; otherwise just complain - this is disabled by nofinals.

fuzzy (0 / 1)

handle --non-existing-parameter by simply stopping parsing there (treat it as first file or such to be handled by your program), otherwise complain and dump help info + exit.

nocomplain (0 / 1)

do not complain about missing config file or the like

hidenonshort

hide parameters that don't have a short name in --help output (p.ex. multiline stuff that one doesn't want to see outside of config files)

binmode (undef / :utf8 / :latin1 / ...)

Set the binmode (text encoding) for parsed files.

ignore_unkown

Do not complain on unknown parameters, just swallow silently. The actual value is important: 1 == only ignore unknowns in config files, 2 == also ignore unknowns on command line (overridden by the fuzzy operation).

accept_unkown

Silently add parameters (long names only) to the party as scalars when encountering corresponding settings. Similar to ignore_unknown, the value 1 means adding from config files only, value 2 also adds from command line (overruled by the fuzzy operation).

This also activates partial usage of parameter meta data in the config file if it appears before the actual assignment. In that case, you can even add non-scalar parameters externally.

output

Specify a handle to print help messages and config files to instead of STDOUT.

linewidth

Set a line width for paragraph formatting (otherwise terminal is queried).

silenterr

Integer for preventing printout of errors. You can prevent other printery by not enabling verbose mode and preventing finals or setting output to some sink.

author

Set some text to print when information about the author is expected.

Copyright and license info.

tagline

The one-line reason for your program to exist. The motto, whatever. If not given, the first line of the info string is used. Please give either none or both of tagline and usage.

usage

Usage string summing up basic calling of the program. If not present, the info string might get harvested for that, if it contains such:

        usage: program [parameters] some.conf [parameters] [param names]

or

        usage:
          program [parameters] some.conf [parameters] [param names]

(with arbitrary number of empty lines in between). Please give either none or both of tagline and usage.

MEMBERS

The simple procedural interface consists of mainly one function, but also some:

get
        $parm_ref = Config::Param::get(\%config,\@pardef,\@cmdline_args, $errors);
        $parm_ref = Config::Param::get(@pardef);

This basically returns a hashref with parsed parameter values, from different variants of input (see SYNOPSIS). You can also fetch a reference to the error string array, which only makes sense when disabling final actions, which would happen normally (the function not returning at all).

valid_name
        be_happy() if Config::Param::valid_name($long, $short);

Purely syntactical check for valid parameter names (letters, not (too many) funky symbols).

valid_type
        be_happy() if Config::Param::valid_type($value);

This does not mean that Config::Param will do the correct thing with your complex cross-blessed data structure; just that it thinks that it can, and will work with it as parameter intialization.

valid_def
        be_happy() if Config::Param::valid_def(\%single_pardef);

Checks if a single parameter definition given as hash is formally correct (name and type). If you hand in a second argument, the type code is stored there.

hashdef
        $parhash = Config::Param::hashdef(@def_array);
builtins
        $builtin_names = Config::Param::builtins(\%config);
        print "$name is used as long or short" if $builtin_names->{$name};

As it is an error to try and define a parmameter that conflicts with predfined long/short names, this returns a hash for easy checking if something is used already (depending on %config).

sane_pardef
        $problem = Config::Param::sane_pardef(\%config,\@pardef);
        die "bad parameter specification: $problem\n" if $problem;

This checks the parameter definition for issues (noted in $problem string) and brings it into the preferred form for internal consumption. Returns empty string if no problem encountered. The provided config is supposed to be identical to the one used later.

Using this function, you can prevent Config::Param::get() or Config::Param->new() from blowing up (using die()) on bad parameter specifications. If you do not take that extra care, it is assumed that blowing up is what you want on errors.

escape_pod

Little function that takes a string and returns it with potential POD directives neutralized.

The module also offers a class to work with. Most class members return 1 (true) on success, 0 on failure, also incrementing the error counter. That class has the following interesting members:

new

The constructor that normally wants this usage:

        $param = Config::Param->new(\%config, \@pardef);

Parameter definitions are a plain array or an array of hashes/arrays:

        @params = (  'long1',0,'l','some parameter'
                    ,'long2',1,'L','another parameter' );
        @params = (  ['long1',0,'l','some parameter']
                    ,['long2',1] ); # omitted stuff empty/undef by default
        @pardef =
        (
                {
                         long=>'long1'
                        ,value=>0,
                        ,short=>'l'
                        ,help=>'some parameter'
                }
                , ['long2',1,'L','another parameter']
        );

You can mix hash and array refs with each other, but not with plain values. if the first element is no reference, Config::Param checks if the total count is a multiple of 4 to catch sloppyness on your side.

If it is ever decided to extend the definition of parameters for Config::Param, that extension will be possible via hash/array ref specifications.

It is possible to omit config hash and parameter definition and this can make sense if you intend to create the param space later on (p.ex. from a config file with meta data).

        $param = Config::Param->new(\%config);
        $param = Config::Param->new();
        # then do something to define parameters
define

A method to define one single parameter:

        $param->define({long=>$longname, value=>$value, short=>$short, help=>$desc});

Here, the help can be a string or a reference to a string (a reference is stored, anyway).

find_config_files

Use confdir and program to find possible config files (setting the the config parameter, it it is not set already).

        $param->find_config_files();
parse_args

Parse given command line argument list, storing its settings in internal operator queue (step 1 of usual work).

        $param->parse_args(\@ARGV);
use_config_files

Apply possible operations on config parameter and parse files indicated by that (step 2 of usual work).

        $param->use_config_files();
apply_args

Apply the operations defined by the parsed argument list to the parameters (step 3 of usual work).

        $param->apply_args();
final_action

Possibly execute final action as determined by parameter values or encountered errors, like printing help or a configuration file and exit (step 4 or usual work). Without something special to do, it just returns nothing.

        $param->final_action();
parse_file

Parse given configuration file. Optional parameter (when true) triggers full usage of meta data to complete/override setup.

        $param->parse_file($file, $construct);

Print config file to given handle. Optional parameter gives a level of bareness, stripping meta info.

        $param->print_file(\*STDOUT, $bare);
current_setup

Return configuration hash and parameter definition array that corresponds to the current state (copies that can be destroyed at will).

        ($config, $pardef) = $param->current_setup();
        $param_copy = Config::Param->new($config, $pardef);
par_content
        # dump in perl-parseable format, with some pretty indent
        $string = $param->par_content($name, 'dump', 2);
        # lines without other quoting
        $string = $param->par_content($name, 'lines');

Return a string representing the content to given parameter key, with optional choice of format. Default is 'dump' with indent 0. Other choice is 'lines' for putting the value on a line or multiple lines, in case of arrays/hashes (newlines in values just happen, too, undef values result in empty lines, empty arrays/hashes in nothing at all). The third parameter chooses the indent style (see Data::Dumper).

Print POD to configured output. This utilizes the parameter space plus the meta data you provided in the config hash, including the possible extra sections. Writing the documentation by hand would suck, wouldn't it? Never forget a parameter in the man page again!

There are some member variables that are of interest (messing with those can have consequences, of course):

param

This is the internal parameter hash. If using the object interface, that is how you can actually access your configuration.

help
        $par_description = ${$param->{help}{$name}};
short
        $par_short = $param->{short}{$name}
long
        $par_short = $param->{long}{$shortname}
files

An array of files that have been parsed. You are free to reset that to be empty before loading a configuration file explicitly. After parsing, you have the list of all files that have been included (the intially given one plus files that have been included from there on).

errors

An array of collected error messages. You are free to empty it to indicate a fresh start.

Members not documented here can not be relied upon for future releases.

SEE ALSO

This module evolved from a simple loop for command line argument processing, that I thought was quicker written than to search for an already existing module for that. While just using some Getopt may have been a bit quicker, this wouldn't fully do what I want and what numerous scripts I have written rely on. It may fully do what you want, though - so better check this before blaming me for wasting your time with installing Config::Param.

This being yet another entry in the Config/Getopt category, there are lots of alternative packages doing similar things (see http://search.cpan.org/modlist/Option_Parameter_Config_Processing). But when you limit your search to packages that do command line processing, parsing of config files and do handle standard behaviour like generating usage messages, the crowd is well reduced. You might want to check out App::Options, which has the same basic functionality, but of course different enough in the details as well as basic philosophy to let me justify the existence of this module, at least to myself.

There is also Getopt::Euclid, which somewhat works like the inverse, generating your parameter space from verbose description (POD) instead of generating the latter from the Perl data structure you provide. In any case, it is not concerned with config files.

AUTHOR

Thomas Orgis <thomas@orgis.org>

COPYRIGHT AND LICENSE

Copyright (C) 2004-2012, Thomas Orgis.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.