Reading Configuration Files (Perl Cookbook, 2nd Edition)

## 8.16. Reading Configuration Files

### 8.16.1. Problem

You want to allow users of your program to change its behavior through configuration files.

### 8.16.2. Solution

Either process a file in trivial VAR=VALUE format, setting a hash key-value pair for each setting:

>     while (<CONFIG>) {
>         chomp;                  # no newline
>         s/#.*//;                # no comments
>         s/^\s+//;               # no leading white
>         s/\s+$//;               # no trailing white
>         next unless length;     # anything left?
>         my ($var, $value) = split(/\s*=\s*/, $_, 2);
>         $User_Preferences{$var} = $value;
>     }

or better yet, treat the config file as full Perl code:

>     do "$ENV{HOME}/.progrc";

### 8.16.3. Discussion

The first solution lets you read config files in a trivial format like this (comments and empty lines are allowed):

>     # set class C net
>     NETMASK = 255.255.255.0
>     MTU     = 296

>     DEVICE  = cua1
>     RATE    = 115200
>     MODE    = adaptive

After you're done, you can pull in a setting by using something like `$User_Preferences{"RATE"}` to find the value 115200. If you wanted the config file to set the global variable by that name, instead of assigning to the hash, use this:

>     no strict "refs";
>     $$var = $value;

and the `$RATE` variable would contain 115200.

The second solution uses `do` to pull in raw Perl code directly. When used with an expression instead of a block, `do` interprets the expression as a filename. This is nearly identical to using `require`, but without risk of taking a fatal exception. In the second format, the config file would look like:

>     # set class C net
>     $NETMASK = "255.255.255.0";
>     $MTU     = 0x128;
>     # Brent, please turn on the modem
>     $DEVICE  = "cua1";
>     $RATE    = 115_200;
>     $MODE    = "adaptive";

If you don't see the point of having extra punctuation and live code, consider this: you can have all of Perl at your disposal. You can now add arbitrary logic and tests to your simple assignments:

>     if ($DEVICE =~ /1$/) {
>         $RATE =  28_800;
>     } else {
>         $RATE = 115_200;
>     }

Many programs support system and personal configuration files. If you want the user's choices to override the system ones, load the user file second:

>     $APPDFLT = "/usr/local/share/myprog";

>     do "$APPDFLT/sysconfig.pl";
>     do "$ENV{HOME}/.myprogrc";

If you want to ignore the system config file when the user has his own, test the return value of the `do`.

>     do "$APPDFLT/sysconfig.pl"
>         or
>     do "$ENV{HOME}/.myprogrc";

You might wonder what package those files are compiled in. They will be in the same package that `do` itself was compiled into. Typically you'll direct users to set particular variables, which, being unqualified globals, will end up in the current package. If you'd prefer unqualified variables go into a particular package, do this:

>     { package Settings; do "$ENV{HOME}/.myprogrc" }

As with a file read using `require` or `use`, those read using `do` count as a separate and unrelated lexical scope. That means the configuration file can't access its caller's lexical (`my`) variables, nor can the caller find any such variables that might have been set in the file. It also means that the user's code isn't held accountable to a lexically scoped pragma like `use` `strict` or `use` `warnings`, which may be in effect in the caller.

If you don't want clean partitioning of variable visibility, you can get the config file's code executed in your own lexical scope. If you have a `cat` program or its technical equivalent handy, you could write yourself a hand-rolled `do`:

>     eval `cat $ENV{HOME}/.myprogrc`;

We've never actually seen anyone (except Larry Wall himself) use that approach in production code.

For one thing, `do` is a lot easier to type. Also, it respects the `@INC` path, which is normally searched if a full path is not specified, but, unlike using a `require`, no implicit error checking happens under `do`. This means you don't have to wrap it in an `eval` to catch exceptions that would otherwise cause your program to die, because `do` already functions as an `eval`.

You can still check for errors on your own if you'd like:

>     $file = "someprog.pl";
>     unless ($return = do $file) {
>         warn "couldn't parse $file: $@"         if $@;
>         warn "couldn't do $file: $!"            unless defined $return;
>         warn "couldn't run $file"               unless $return;
>     }

This is much simpler for the programmer to source in code than it would be to invent and then parse a complicated, new syntax. It's also much easier on the users than forcing them to learn the syntax rules of yet another configuration file. Even better, you give the user access to a powerful algorithmic programming language.

One reasonable concern is security. How do you know that the file hasn't been tampered with by someone other than the user? The traditional approach here is to do nothing, trusting the directory and file permissions. Nine times out of ten, this is also the right approach. Most projects just aren't worth being that paranoid over. For those that are, see the next recipe.

### 8.16.4. See Also

The `eval` and `require` functions in perlfunc(1) and in Chapter 29 of Programming Perl; Recipe 8.17

Copyright © 2003 O'Reilly & Associates. All rights reserved.