NAME

ParseConfig - Perl module for parsing configuration files


SYNOPSIS

        use ParseConfig;
        # Default processing ... search for cfg file in 
        # ./.$0.rc, ~/cfg/$0.rc and ~/.$0.rc
        $cfg = new ParseConfig();
        # Specify default cfg file
        $cfg = new ParseConfig(-defcfg=>"$ENV{XX_RUN_CONTROL}/globals.rc");
        # To override cfg file defaults from environment
        $cfg = new ParseConfig(-useenv=>1);
        # To dump values into a hash instead into 'true' vars:
        $config = {};
        $cfg = new ParseConfig(-hash=>$config);
        # Do the work: set-up vars with defaults, patch with cmdl opts
        $cfg->parse();


DESCRIPTION

ParseConfig is a module for processing of configuration files which define some variables to be exported into the callers namespace(s). These variables can be optionally overriden from environment variables and unconditionally from command line arguments. Getopt::Long is used for the last part.

NOTE: Defaults are set for all variables first. Only then the command line options are applied.

The idea is that you don't really want to declare globals inside your perl scripts and even less to provide them some default values that are of limited usefulness. Instead you define them in a config file.

The file is line based, each line has the form:

        <command-line-option> <string-for-getopt> <namespace> <varname> <default>

Lines that match /^#/ or /^\s*$/ are skipped. The namespace can be specified as . and it stands for main.

Eg (for my mkmenu script that generates ssh menus for windowmaker):

        # Login name
        name    =s      main    NAME    "matevz"
        group   =s      main    GROUP   "f9base"
        # Terminal to spawn (think `$TERM -e ssh ...`)
        term    =s      main    TERM    "rxvt"

Then you can run it as 'mkmenu -name root'.

Read the Getopt::Long manual for explanation of the second parameter. For void argument specification (which means bool), use 'b' or 'bool'. To suppress passing of this variable to Getopt::Long use 'x' or 'exclude'.


SYNTAX

new ParseConfig(<options>)

Will create new ParseConfig objects. Options can be set on construction time using the hash syntax -option => value or later by assigning to a data member as in $cfg->{-option = value}. This is the list of options:

-defcfg

Specifies the default location of the configuration file. Can be an array reference to specify several locations to search the file for. Some are predefined, but the ones given here are considered first. See BUILT-IN CONFIG FILE RULES for details. The file list is created on construction time so be careful if you modify the list by hand.

-useenv

If set to non zero values of environment variables will take precedence over config file defaults. Command line options are still more potent. See ENVIRONMENT OVERRIDES.

-hash

If set to a hash reference the variables will be exported into it. See PARSING INTO A HASHREF.

-verbose

If set to non zero ParseConfig will dump a moderate amount of info during parse().

add_post_foo(<sub-ref>)

Adds <sub-ref> to the list of functions that are called after the setting of the variables and patching from command line. Useful when you need to create some compound variables. If -hash is set, the hash reference is passed to these functions as the only argument.

parse()

Does all the job: selects config file to be used, reads it, sets the default values and the calls GetOptions. After that the post functions are invoked.

parse_string(<string>)

Splits string into an array and calls parse(), pretending that this string was the actual command line.

I used this option to recreate certain variables (for job control and dbase insertion) from list of commands that were submitting jobs into the queuing system.


BUILT-IN CONFIG FILE RULES

If you dont specify the default cfg file, ParseConfig searches for it in the following locations:

   $base = `basename $0 .pl`; # can be set with -cfgbase=>'foo'
   `pwd`/${base}.rc
   `pwd`/.${base}.rc
   ~/cfg/${base}.rc
   ~/.${base}.rc

If you do specify the -defcfg it is prepended to the above list. The first found file is used. You can obtain it from $cfg->{Config}. Also, the program name can be obtained from $cfg->{ProgName}.

Will add additional variables enabling a user to fully specify the format of these locations when typical use-cases are gathered (perhaps /etc/... ?).

By creating symlinks to a master script you can have several config files for the same script and get different default behaviour.

If $ARGV[0] of the script using ParseConfig is -cfg, then $ARGV[1] is used as a configuration file and no other locations are scanned.

ParseConfig::parse() dies if it can't find any of these files. It should croak.


DEFAULT VALUES

So far all default values are eval-ed prior to assignment. Which means you can use [] or {} or sub{} to get array/hash/closure reference as a default value. Getopt::Long treats such variables differently ... so read its manual to learn more. But, BEWARE, the command line option arguments are NOT eval-ed. Bug Johan Vromans for this option and then I'll do my part. Then would also add the eval control on per-variable base into the config file.

You can as well instantiate an object ... decide for yourself ... it doesn't sound like such a great idea to me. Getopt::Long isn't too keen of the idea either, so make sure to suppress passing an obj ref to it.

One of the more obscene uses of this feature is to set the default to: remap =s main REMAP do "$ENV{HOME}/.domain.remaps" where the file .domain.remaps is, eg:

        {
         "some.domain:other.domain" => {
          "/u/atlas/matevz" => "/home/matevz",
          "/opt/agnes" => "/opt"
         }
         "foo.domain:some.domain" => {
          "/afs/cern.ch/user/m/matevz" => "/u/atlas/matevz"
         }
        }

This will make $REMAP a hash ref to the above struct.

Of course you are not limited to a single statement ... but then use ;s and know your eval. Don't use newlines or you'll confuse the parser. If you're annoyed by that you/I can fix the parser to grog a trailing \ as a continuation symbol.


ENVIRONMENT OVERRIDES

If $cfg->{-useenv} is true, then the defaults are taken from the environment. The names of perl and environment variable must be the same AND the env-var must be set (ie: defined $ENV{$VARNAME} must be true). The values of env vars are eval-ed, too. So take care.

This means you're asking for trouble if several variables in different namespaces have the same names. Or maybe not, if you know what you are doing.

Probably should set some additional flags that would mean do-not-eval and never-override-from environment. Probably with some prefixes to the default value or to the type of a command line option (like {xs}=s).


MULTIPLE CONFIG FILES

You're free to invoke ParseConfig several times. As in:

        # db options
        $o = new ParseConfig(-defcfg=>"$ENV{PRODDIR}/cfg/db.rc", -useenv=>1);
        $o->parse();
        # Tape options
        $to = new ParseConfig(-defcfg=>"$ENV{PRODDIR}/cfg/tape_${OCEAN}.rc");
        $to->parse();

When invoking the command make sure to use -- between options intended for different config file parsers.


PARSING INTO A HASHREF

By setting $cfg->{-hash} = <some-hash-ref> you can redirect parsing into this hash (instead of namespace globals). A non-main namespace name induces an additional level of hashing.

Example:

Having a config file pcm.rc

        simple          =s      .       SIMPLE          "blak"
        aref            =s      .       AREF            []
        href            =s      Kazaan  HREF            {}

and perl script pcm.pl

        #!/usr/bin/perl
        use ParseConfig;
        use Data::Dumper;
        $XX = {};
        my $cfg = new ParseConfig(-hash=>$XX);
        $cfg->parse();
        print Dumper($XX);

The result of running pcm.pl -aref pepe -aref lojz -href drek=shit -href joska=boob is:

        $VAR1 = {
                  'AREF' => [
                              'pepe',
                              'lojz'
                            ],
                  'Kazaan' => {
                                'HREF' => {
                                            'drek' => 'shit',
                                            'joska' => 'boob'
                                          }
                              },
                  'SIMPLE' => 'blak'
                };


AUTHOR

Matevz Tadel <matevz.tadel@ijs.si>