Finished advanced section for programmers.
1 parent 04070ba commit 4d22384a719b25408c71314954c006b0dd9dd157
@tundra tundra authored on 21 Apr 2004
Showing 1 changed file
View
112
tconfpy.3
recognized by \*(TC. This is the "User's View" of the package, but
both programmers and people writing configuration files will find this
helpful.
 
.B ADVANCED TOPICS
.B ADVANCED TOPICS FOR PROGRAMMERS
describes some ways to combine the various \*(TC features to
do some fairly nifty things.
 
.B INSTALLATION
preceding \'.literal\' will also generate a warning message, and the
statement will be ignored.
 
 
.SH ADVANCED TOPICS
.SH ADVANCED TOPICS FOR PROGRAMMERS
 
Here are some ideas on how you might combine \*(TC features
to enhance your own applications.
 
.SS Guaranteeing A Correct Base Configuration
 
While it is always nice to give users lots of "knobs" to turn, the
problem is that the more options you give them, the more they can
misconfigure a program. This is especially a problem when you are
doing technical support. You'd really like to get them to a
"standard" configuration and then work from there to help solve their
problem. If your write your program with this in mind, \*(TC gives
you several ways to easily do this:
 
.IP \(bu 4
Provide a "standard" system-, or even, enterprise-wide configuration
file for your application. This file presumably has all the program
options set to "sane" values. All the user has to do is create
a configuration file with one line in it:
 
.nf
.include /wherever/the/standard/config/file/is
.fi
 
.IP \(bu 4
Predefine every option variable the program will support. Populate the
initial symbol table passed to \'ParseConfig()\' with these definitions.
By properly setting the \'Type\', \'LegalVals\', and \'Min/Max\' for
each of these variables ahead of time, you can prevent the user from
ever entering option values that make no sense or are dangerous.
 
.IP \(bu 4
Make sure ever program option has a reasonable \'Default\' value in
its variable descriptor. Recall that this attribute is provided for
the programmer's convenience. (When a variable descriptor is first
instantiated, it defaults to a string type and sets the default
attribute to an empty string. However, you can change both type and
default value under program control.) If you predefine a variable in the
initial symbol table passed to the parser, \*(TC will leave this
attribute alone. However, variables that are created for the first
time in the configuration file will have this attribute set to the
first value assigned to the variable. Now provide a "reset" feature
in your application. All it has to do is scan through the symbol
table and set each option to its default value.
 
 
.SS Enforcing Mandatory Configurations
 
The \*(TC type and value validation features give you a handy way to
enforce what the legal values for a particular option may be.
However, you may want to go further than this. For instance, you may
only want to give certain classes of users the ability to change
certain options. This is easily done. First, predefine all the
options of interest in the symbol table prior to calling the \*(TC
parser. Next, have your program decide which options the current user
is permitted to change. Finally, mark all the options they may not
change as "Read Only", by setting the "Writeable" attribute for those
options to "False". Now call the parser.
 
This general approach allows you to write programs that support a
wide range of options which are enablde/disabled on a per-user,
per-machine, per-domain, per-ip, per-company... basis.
 
.SS Iterative Parsing
 
There may be situations where one "pass" through a configuration
file may not be enough. For example, your program may need to
read an initial configuration to decide how to further process
the remainder of a configuration file. Although it sounds
complicated, it is actually pretty easy to do. The idea
is to have the program set some variable that selects
which part of the configuration file to process, and then call
the parser. When the parser returns the symbol table, the program
examines the results, makes whatever adjustments to the symbol
table it needs to, and passes it back to the parser for another
"go". You can keep doing this as often as needed. For instance:
 
.nf
 
# Program calls the parser with PASS set to 1
 
.if PASS == 1
# Do 1st Pass Stuff
.endif
 
 
# Program examines the results of the first pass, does
# what is has to, and sets PASS to 2
 
.if PASS == 2
# Do 2nd Pass Stuff
.endif
 
# And so on
.if
 
In fact, you can even make this iterative parsing "goal driven".
The program can keep calling the parser, modifing the results,
and calling the parser again until some "goal" is met. The goal
could be that a particular variable gets defined (like \'CONFIGDONE\').
The goal might be that a variable is set to a particular value
(like, \'SYSTEMS=3\').
 
It might even be tempting to keep parsing iteratively until \*(TC no
longer returns any errors. This is not recommended, though. A
well-formed configuration file should have no errors on any pass.
Iterating until \*(TC no longer detects errors makes it hard to
debug complex configuration files. It is tough to distinguish
actual configuration errors from errors would be resolved in a
future parsing pass.
 
 
.SH INSTALLATION