AnsweredAssumed Answered

Perl SDK tip: Reading values from config file

Question asked by keith_k on Nov 8, 2008
Latest reply on Nov 15, 2008 by rpollard
Friday seems like a good day to share a tip.  In addition to hopefully being a useful piece of information to others, I am interested in getting other perspectives or ideas on this issue...

The Code Wizard outputs the following Perl when you tell it you want to read values from a config file:
getopts("d:l:",\%options);
$config   = Nimbus::CFG->new("$prgname.cfg");
$loglevel = $options{d} || $config->{setup}->{loglevel} || 0;
$logfile  = $options{l} || $config->{setup}->{logfile}  || "$prgname.log";
This also includes the code to accept values from the command line, using the following priority to set each variable:
  1. Command line option
  2. Config file value
  3. Default value hard-coded in script
I like this style of Perl code in general.  The problem is that the "or" operator in Perl considers zero to be false, even though zero might be a valid value for some of your variables.  This means that if your default value for something is greater than zero, you cannot set it to zero in the config file.  Or if you have something set higher than zero in the config file, you cannot override that on the command line.

This will not be an issue in most cases, but I wanted a solution that would work even in uncommon cases.  I created a subroutine called set_option() that I use in all of my Perl probes, and I think it operates more closely to how Nimsoft intended.  Here is a sample of how I typically use it:
# Defaults
$loglevel = 0;
$logfile  = "$prgname.log";

sub set_option {
    # Search through all values passed
    foreach my $value ( @_ ) {
        return $value if defined $value;
    }
    # No values were defined
    return undef;
}

getopts("d:l:",\%options);
$config   = Nimbus::CFG->new("$prgname.cfg");
$loglevel = set_option($options{d}, $config->{setup}->{loglevel}, $loglevel);
$logfile  = set_option($options{l}, $config->{setup}->{logfile},  $logfile);
As you can see, the set_option() subroutine only skips a value if it is undefined.  If the value is zero, it is used.

As an added bonus (and not related to the above issue), I created the set_option_binary() subroutine to set a variable to zero or one based on the common yes/no values you would typically find in NimBUS config files.  I wanted to be able to use yes/no in my configs, but I wanted an easy way to check the variables throughout the script without comparing them to strings every time.  Here is the subroutine:
sub set_option_binary {
    # Search through all values passed
    foreach my $value ( @_ ) {
        next unless defined $value;
        return 0 if $value eq "no" or $value eq "0";
        return 1 if $value eq "yes" or $value eq "1";
        # The value was not valid - keep looking
    }
    # No values were defined
    return undef;
}
Like the set_option() subroutine, the set_option_binary() subroutine accepts a list of values, making it suitable for processing a command line option, config file value, and default all in a single call.  After it finds a defined value, it treats 0 or no as false (setting the value to 0) and 1 or yes as true (setting the value to 1).  It considers other values invalid and moves on.  If it finds no valid values (which should not be the case if you have a hard-coded default in your script), it returns undef, which would be equivalent to false.

Any ideas for improvement or other ways to address these issues?

Regards,
Keith

Outcomes