An often needed facility for a large program is the configuration file. The requirement always starts out with "we just need a couple of values." Then there's always a couple of more, and then more. And the inevitable steady stream of "can you make it do X". Here is a bare bones processor that will produce a %hash containing simple "key, value" pairs. However, each value can be a perl expression. This allows you the luxury of quoted strings, expressions and even subroutine calls into your program if you wish. WARNING: This assumes that those with access to the config files are not going to attempt mischief. If you need to prevent config file authors from performing certain actions, you'll need to configure and add a "Safe" eval object.
use strict ; my(@list, $lineno, %hash) ; $lineno = 1 ; while( <DATA> ) { next if /^\s*\#/ ; # line commented out next if /^\s*$/ ; # all whitespace print $_, " => " ; no strict ; # lets barewords be converted to strings @list = eval $_ ; use strict ; # back to strict error checking ## ## check for errors ## if( $@ ) { print STDERR "Error in config on line $lineno: $@\n" ; next ; } ## ## check to make sure we didn't more than we were expecting ## if( @list > 2 ) { print STDERR "Warning line $lineno produced more data than exp +ected\n" ; } if( @list < 2 ) { print STDERR "Warning line $lineno didn't give a key, value\n" + } print "@list[0,1]\n\n" ; if( exists $hash{$list[0]} ) { print STDERR "Warning line $lineno overwrites previous value\n +" ; } $hash{$list[0]} = $list[1] ; } continue { $lineno++ ; # increment lineno each pass through the loop } __DATA__ # comment line entry0, value0 entryx, $ENV{HOME} entryy, "string with \"quote\" in it" entry1, "value 1a with local var \$lineno = $lineno" # comment ignored entry2, "value $ENV{HOME} with an env var" ## ## we can even evaluate expressions ## entry9, (3+3)*1.5 entry_trig, sin(3.14159/2) ## ## test the warnings ## bogus_entry, " ## ## line with than one result ## entry_warning, 4, 5 entry_waringx entry_dup, 0 entry_dup, 1

Replies are listed 'Best First'.
Re: Config File Processing
by jeffa (Bishop) on Oct 10, 2003 at 19:45 UTC
    And the first attempt at solving the problem is "roll your own!" ... which is usually a bad idea. While your code works, should i really use it? Wouldn't i be better off using an existing Config module instead? I think so.
    use Tie::IxHash; use Config::General; tie my %conf, 'Tie::IxHash'; %conf = ParseConfig(\*DATA); for (keys %conf) { my $output = eval "$conf{$_}"; print "$_: ", $@ ? "$conf{$_} - $@\n" : "$output\n"; }
    While it doesn't work completely, this shows that it is very easy to make Config::General do what you want. "Out of the box", it parsed all of your config file.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)