ConfigFile.pm


MODULE

ConfigFile - reads a configuration file and dumps its information into a table.

This is RCS version: $Revision: 3.1 $.


SYNOPSIS

use ConfigFile;


DESCRIPTION

ConfigFile::new creates a single object which opens a specified configuration file and places all this information into tables which can then be accessed through simple methods. The point of this interface is to make it easy to create useful configuration files for differing system adminstration tasks that need to be accomplished on numerous machines.


FORMAT

The configuration file format is generalized into two sections: DEFAULT blocks which specify default behaviors (i.e. default properties) which may be included by NAME blocks which specify the default behaviors for specific entities (machines, for example). Comments are as in shell and Perl: anything after a #.

The DEFAULT block looks like this:

DEFAULT default_tag property0 value0 property0 value0 ... propertyN valueN END

The default_tag may be any atomic string and is used by NAME blocks to include properties.

A NAME block looks like this:

NAME machine_name DEFAULT some_tag DEFAULT some_other_tag property0 value0 property1 value1 ... propertyN valueN END

NOTE: it is important to know that when asking for the value of a property for an entry, the explicit properties are checked first, then the default blocks are checked in the order they are specified in the block This is to allow you to override defaults on a particular entry without having to reenter other useful defaults

Information is extracted from the file via the get method. From the above example you could call

$answer = $config->get('machine_name', 'property0')

and you would get 'value0' back as your answer.

If the flexibility (and associated syntax) of the NAME blocks is too much for your application, you may instead use the GLOBAL directive. For example:

GLOBAL port 5001 other-port 5002 tmp /tmp/myapp

The GLOBAL directive must be at the end of the configuration file. The get syntax for GLOBALs is simpler:

$answer = $config->get('port');

The values of properties may be extended over multiple lines if in the value position you place the token '@{'. All following lines, until a matching '@}' is found are assigned to the propery. For example:

NAME button-1 DEFAULT button-defaults Command @{ $my_name = &some_perl_code($id, $v1); if (! defined $my_name) { exit(1); } else { &wahoo($my_name); } @} Label Quit END

Text included between '@{' and '@}' does NOT get tokenized, comments are ignored (that is, included in the property), but macro substitution does take place.


MACROS

In addition to the simple property/value association assignment, this configuration file tool allows basic macro substitution and conditional assignment of values to properties.

NOTE: all the @@-directives must be syntactically complete on a single line. That is, you cannot spread a complex conditional or assignment statement over several lines.

A value is assigned to a macro in the following way:

@@define symbol This is a value.

The @@define directive has global scope, it can occur at the top level or in a DEFAULT or NAME block, but is in effect for all sections of the configuration file following it.

Macros may be accessed by prefixing the symbol name with @$, and may occur anywhere in the file. So @$symbol will have the string ``This is a value.'' substituted for it.

There is a primitive conditional facility which is intended to interact with the macros:

@@ifdefined SOME_VAR ... @@ifndefined SOME_VAR ... @@ifequal val1 val2 ... @@ifnequal val1 val2 ...

Where...

val ::= { @$VARIABLE | atomic-string } ... ::= { @@directive | property value }

Notice that you can do things like the following:

@@ifequal @$OS_SHORT solaris @@define PS_FLAGS -ef

or this:

NAME bob @@ifequal @$OS_SHORT solaris ps_flags -ef @@ifequal @$OS_SHORT sunos ps_flags -auxw END

This last form assigns the value -ef to the NAME bob block property ps_flags if the program is run on a Solaris machine. It is an error to use this form outside a block.

Notice the syntax for @@ifdefined:

@@ifndefined HOSTNAME @@define BRAIN_DAMAGE hostname-damage

You do not prefix the macro name with @$ when testing if it is defined or not.

EXPERIMENTAL: Certain macros are defined when the ConfigFile object is created. As of this version, only SunOS and Solaris will assign all of these properly.

@$COMMENT - The character '#'. @$DATE - The date/time when the config file was read. @$DATETAG - YYMonDD @$OS - 'uname' @$OS - 'uname -n' @$OS_VERSION - 'uname -r' @$OSVERSION - @$OS . @$OS_VERSION (i.e. SunOS5.5.1) @$ARCH - 'uname -p' @$OS_SHORT - sunos | solaris

Of course, these may be overwritten in your own configuration files.


SYNOPSIS


ConfigFile::new

$my_config = new ConfigFile(File => 'config.txt'); $my_config = new ConfigFile;

This opens and parses the configuration file specified.


ConfigFile::read

$my_config->read('config.txt');

This reads the specified config file. All the interesting work happens here. One useful trick you can use this for is to read in several configuration files, one of which may simply assign macro values.

Returns undef for certain errors.


ConfigFile::set_default

$my_config->set_default('default_tag');

If you call ConfigFile::get for an entity which does not have an entry the default return value is undef. This call sets up a default set of properties for entities without explicit NAME blocks.


ConfigFile::get

$value = $my_config->get('name', 'property'); $value = $my_config->get('name', 'property', 'default_tag'); $value = $my_config->get('name');

The first form of ConfigFile::get looks for the value and returns undef if there is no such entry or property. The second form looks for the property of a entity, but if no such entity is specified in a NAME block, returns the value for the default block, but will return undef if there is no such DEFAULT default_tag block or property. See above for in ConfigFile::set_default for a nicer way to deal with defaults.

The last form is for GLOBAL properties.


ConfigFile::get_all

@list = $my_config->get_all('name'); @list = $my_config->get_all;

This returns a list of all non-default properties for the specified block. The second form, without arguments, returns a list of all GLOBAL properties.

Note that this returns a list of the property names, not the actual values.


ConfigFile::set

$my_config->set('name', 'property', $value);

This assigns the value of a property for a specific entry.


ConfigFile::add_default

$my_config->add_default('name', 'default_tag');

This acts exactly like a DEFAULT some_tag clause in a NAME block. This is the way to add finer grained default behavior than is offered by ConfigFile::set_default .


ConfigFile::defaults

@defaults = $my_config->defaults('name');

Returns a list of DEFAULTs available to this NAME block. Returns undef if there is no such NAME or if it has no DEFAULTs.


ConfigFile::define

$my_config->define('macro', 'value');

This corresponds to the @@define directive in the configuration language. Obviously, this is only useful before a call to ConfigFile::read . For the above example, you will need to reference ``@$macro'' to get interpolation.


AUTHOR

William S. Annis <annis@biostat.wisc.edu>.

http://www.biostat.wisc.edu/~annis


HISTORY

A large part of this code was extracted from a program I wrote to monitor the disk use on an army of machines. I found the configuration file parsing and tabling took up a very large part of that code.

This module has subsequently been used in a number of applications. It is used in all parts of my machine monotoring system, Mom. It has also been put to quite peculiar use as a definition language for GUIs using PerlTk.

ConfigFile 1.1 General Idea.

ConfigFile 1.3 Stable, working version. Used in several applications at the BCG.

ConfigFile 2.1 IA version with @@define, @@if* forms and GLOBAL block.

ConfigFile 2.5 Stable version with many bugfixes. Used in several applications.

ConfigFile 2.6 External release: ConfigFile-1.0.

ConfigFile 3.0 New, sensible methods: read, get_all, defaults. Removed some of the die calls.

ConfigFile 3.1 Can define macros from the Perl interface. External release: ConfigFile-1.1.


COMMENTS and BUGS

The parsing of the file could be a little less delicate and cranky. In particular, tokens must be separated by whitespace. Bad syntax with multi-line properties returns errors with line numbers rather distant from the real problem.

This documentation could be clearer.