Config manager documentation
INTRODUCTION
===================
The code presented here is a general config file reader/writer. The parser
itself was created using flex. The syntax of the config file itself might
not be completely logical but it works. Remember that the idea is that the
program itself is used to edit the config file.
1. Overview
2. How does it work ?
2.1 Groups
2.2 Entries
3. How to use it
3.1 General usage
3.2 Config and Plugins
4. What does it look like ?
5. Info
6. Copyright
1. Overview
=============
The purpose of this config class is to remove the burden of parsing and
maintaining a config file. It works as follows: The user creates an
instance of the ConfigClass in their program and specify a config file.
2. How does it work ?
======================
Well it does isn't that enough ? :) The basic idea is that the ConfigClass
holds several structures which contain pointers to variables you use.
When you call the function write_config () the ConfigClass will write
the contents of the variables you provided to a configuration file.
So when you change a variable during the course of your program you
also change the value that will be written to disk.
2.1 Groups
======================
A program usually has a lot of variables. These variables belong to classes
and structures. To make a difference between groups of variables, the group
structure is invented. You can find the groups in the config file in the
form of:
[main]
This defines the group "main". All variables beneath this group belong to
this group untile a new group is defined. One consequence of this method
is that you can have 2 or more variables with the same name. Of course
these variables have to belong to different groups.
One advantage of using groups is the possibility of plugins. A plugin
is a shared library ( or piece of compiled code ) that is loaded and
used at runtime. You can find out more on using plugins with the
config manager in the chapter "Config and Plugins"
2.2 Entries
======================
An entry is a definition of a variable with all it's data. A config variable
is NOT the same as a variable in "C" or "C++". A variable in a
config file is an indicator for one or more values. We'll use the term
entry from now on to indicate such a variable. First an example.
Suppose you've got some code wich operates on colors. You probably want
to save certain color values when you exit your program. You might have
something like:
struct rgb_values
{
float red;
float green;
float blue;
};
in your program.This could be translated into one entry into the config
file which would then look like:
<rgb_values> 0.50 0.50 0.50
The entries are internally structured as follows ( don't worry if you don't
understand it ):
group_entry [main group]
|
+---conf_entry <"variable1"> (var1) (var2) (var3) (var4) .......
|
+---conf_entry <"variable2"> (var1) (var2) ......
.
.
Each line of variables is accompanied by a string which gives enough
information to determen what type of variable is used, the string can
contain the following variable types:
i => integer (int)
f => floating point (float)
s => string (char *)
So for example you've got a line in a config file which looks like:
0.50 0.35 0.60
This would translate into a variable-type string of:
fff
Meaning that the config parser will store and look for 3 floats.
You add an entry to these variables as follows:
temp_config_class->insert_entry ("rgb_values","fff",&red,&green,&blue);
When you add an entry, you effectively add it to the current group.
Now when you've added all the groups and entries, you read in the config
file. The ConfigClass will then try to match the entries you specified
with the values it finds in the file. You've got to remember the following
things when using this class:
1) When you specify a variable which was not found in the file, the
ConfigClass will reset that variable to default. You can specify the
default values by calling the function set_defaults (); For example
you could call this function like:
set_defaults (50,0.10,"main");
2) When you've specified a variable which was not found in the file, then
don't be surprised if you DO find it the next time. This is because
the ConfigClass will write a new config file from it's data which of
course includes the new variable.
3. How to use it ?
=======================
You can use the sources in two ways:
a)
The first way is to take the libconfig.a you will find when the
compilation process is complete and copy it to a default library directory.
You could copy it to /usr/local/lib for example. Do the same
with the include files you find in the main config dir and copy them to
/usr/local/include for example. This should set things up
properly and you can now use the config library in any other program.
b)
The second way is to copy the entire source directory to your own source
directory. So for example, suppose you are working on a project called
foo wich resides in a directory called:
~/foo
You could create a directory called config in the ~/foo directory.
This would give you the following dirs:
~/foo Main source dir
~/foo/config Location of config sources
~/foo/flex Location of the source file for the flex parser
You would then have to edit the Makefile and change the point where it says:
all: $(OBJECTS)
$(AR) -rs $(TARGET) $(OBJECTS)
# cp $(TARGET) ../
Just remove the "#" and make will then copy the libconfig.a to the
foo directory. Now when you create your own Makefiles in the foo
directory don't forget to add -I./config to the default include
directories.
3.1 General Usage
=======================
During the operation of a program, you will have use several steps to
use the config class successfully. The global usage is as follows:
a) Create an instance of the config class
b) Add groups and entries to this instance
c) Let the config instance parse the config file
d) During the course of the program use the variables.
e) Write a config file.
It all begins with the creation of an instance of the ConfigClass,
like so:
ConfigClass *config_object=new ConfigClass (".configrc");
This creates a config object which will do all it's file operations on the
file .configrc NOTE: when you use plugins in combination with the
config lib ALL plugin configurations will end up in the main config file.
It's also possible to add a program or package name to the config-file
header. To do this call the constructor:
ConfigClass *config_object=new ConfigClass (".configrc","MindsEye");
This will add a string to the config header which says:
# This config file belongs to the (MindsEye) package
If you do not specify a config name then the config filename will default
to: .config
You then add groups and entries to this config object. Variables can be
grouped together allowing plugins for example to share one config file.
Adding a group is done by calling:
config_object->add_group ("main_group");
When you now add an entry, you effectively add it to the main_group.
In other words you always add it to the current active group. Unless
you specify a group name with the insert_entry_to_group command.
3.2 Config and Plugins
=======================
Plugins form a special case when it comes to configurations. Well they are
a special case anyway. When you write plugins using the ConfigClass you
have to know how certain things are done by this class. First of all
you have to know how the ConfigClass handles the sequence by which
entries are made and how the class parses the config file.
You have to realise that the ConfigClass can not rely on the fact that
the entries are made first and then the config file is parsed. So one
requirement is that it does not matter in which order things happen.
See chapter 3.1 step b and c
So for example suppose you've created the proper instance and you've added
a bunch of groups and variables to the instance. Then you call the function
which parses the config file. The ConfigClass now has to match entries
it finds in the file with what the user already has inserted.
It can also happen the other way around, where the file has already been
read and the ConfigClass has to see if the entries that are added exist
in the file ( if it can't match an entry it will add it to the current
group)
Why do you have to know all of this ??? Well that's easy. When you load
a plugin you can safely assume that the config class has already loaded
the proper entries. So when you load a plugin and the plugin inserts it's
own entries, the config instance has to match the new entries with the
ones it has already found.
So one important thing when using plugins is to add a special group for
the plugin. Otherwise the variables end up in the current group and the
config instance cannot guaranty the uniqueness of the variable.
4. What does it look like ?
=============================
The config parser uses the following reserved token syntax:
[ ] = group identifier
< > = name identifier
" " = string identifier
Example:
--SOURCE: main.cpp-------------------------------------------------------------
#include <m_config.h>
main (void)
{
float red =0.5,
green=0.5,
blue =0.5;
int path_max=1024;
char last_model [256]="/home/vvelsen/sgi_fonts.3ds";
ConfigClass *temp_config=new ConfigClass (".mindseyerc","MindsEye");
//>--------- group [kernel]
temp_config->insert_group ("kernel");
temp_config->insert_entry ("path_max","i",&path_max);
temp_config->insert_entry ("rgb_values","fff",&red,&green,&blue);
//>--------- group [modeler]
temp_config->insert_group ("modeler");
temp_config->insert_entry ("last_model","s",&last_model);
//>--------- group [plugins]
temp_config->insert_group ("plugins");
//>--------- modify some variables
red=0.10; // you should see this value in the config file
temp_config->write_config ();
delete (temp_config);
}
--OUTPUT: /root/.mindseyerc----------------------------------------------------
# This file was automaticly generated, please do not edit
# by hand unless you know what you're doing
#
# File created by ConfigManager v0.10 on Sun May 25 17:17:29 1997
# Copyright (C) 1997 Martin van Velsen, vvelsen@ronix.ptf.hro.nl
#
# This config file belongs to the (MindsEye) package
#
#--------------------------------------------------------
[kernel]
<path_max> 1024
<rgb_values> 0.100000 0.500000 0.500000
#--------------------------------------------------------
[modeler]
<last_model> "/home/vvelsen/sgi_fonts.3ds"
#--------------------------------------------------------
[plugins]
# end of (.mindseyerc)
5. Info
=========
I'm not that great with autoconf and the likes. That's the reason
you have got to manually install the library and header files.
See the main.cpp file for an example of how to use the configmanager.
Questions and comments about these sources, as well as updates and bug
fixes can be sent to:
Martin van Velsen <vvelsen@ronix.ptf.hro.nl>
6. Copyright
=============
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.