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

NAME

Getopt::FileConfig - Perl module for parsing configuration files

SYNOPSIS

  use Getopt::FileConfig;

  # Default processing ... search for cfg file in the following locations:
  #   ./$base.rc ./.$base.rc, ~/cfg/$base.rc and ~/.$base.rc
  # where $base is 'basename $0 .any-suffix'.
  $cfg = new Getopt::FileConfig();

  # Specify default cfg file
  $cfg = new Getopt::FileConfig(-defcfg=>"$ENV{XX_RUN_CONTROL}/globals.rc");

  # To override cfg file defaults from environment
  $cfg = new Getopt::FileConfig(-useenv=>1);

  # To dump values into a hash instead into 'true' vars:
  $config = {};
  $cfg = new Getopt::FileConfig(-hash=>$config);

  # Do the work: set-up vars with defaults, patch with cmdl opts
  $cfg->parse();             # parses @ARGV
  $cfg->parse(\@my_array);   # parses any array

DESCRIPTION

Getopt::FileConfig 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

$cfg = new Getopt::FileConfig(<options>)

Will create new Getopt::FileConfig 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:

-cfgbase

Changes the prefix used to search for configuration files. By default, the $cfgbase is extracted from $0:

   $0 =~ m!([^/]+?)(?:\.[^.]*)?$!;
   $cfgbase = $1;

which is good, as you can use symlinks to the same executable to get different default values. Locations searched by default are:

  $ENV{PWD}/${cfgbase}.rc,
  $ENV{PWD}/.${cfgbase}.rc,
  $ENV{HOME}/cfg/${cfgbase}.rc,
  $ENV{HOME}/.${cfgbase}.rc;

$cfgbase that is used is stored into $cfg->{ProgName}.

-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 Getopt::FileConfig 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(<nothing-or-array-ref>)

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. If nothing as passes, @ARGV is used.

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, Getopt::FileConfig 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 Getopt::FileConfig is -cfg, then $ARGV[1] is used as a configuration file and no other locations are scanned.

Getopt::FileConfig::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 write in the config file:

  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 Getopt::FileConfig several times. As in:

  # db options
  $o = new Getopt::FileConfig(-defcfg=>"$ENV{PRODDIR}/cfg/db.rc", -useenv=>1);
  $o->parse();
  # Tape options
  $to = new Getopt::FileConfig(-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 Getopt::FileConfig;
  use Data::Dumper;

  $XX = {};
  my $cfg = new Getopt::FileConfig(-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>