1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
|
<TITLE>Config manager documentation</TITLE>
<BODY BGCOLOR="#ffffff" TEXT="#000000" LINK="#0000ff" VLINK="#0000ff">
</BODY>
<PRE>
<CENTER>
<B>INTRODUCTION</B>
===================
</CENTER>
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.
<HR>
1. <B>Overview</B>
2. <B>How does it work ?</B>
2.1 <B>Groups</B>
2.2 <B>Entries</B>
3. <B>How to use it</B>
3.1 <B>General usage</B>
3.2 <B>Config and Plugins</B>
4. <B>What does it look like ?</B>
5. <B>Info</B>
6. <B>Copyright</B>
<HR>
<CENTER>
1. <B>Overview</B>
=============
</CENTER>
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.
<HR>
<CENTER>
2. <B>How does it work ?</B>
======================
</CENTER>
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.
<HR>
<CENTER>
2.1 <B>Groups</B>
======================
</CENTER>
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:
<FONT COLOR="0000ff">[main]</FONT>
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"
<HR>
<CENTER>
2.2 <B>Entries</B>
======================
</CENTER>
An entry is a definition of a variable with all it's data. A config variable
is <B>NOT</B> 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:
<FONT COLOR="0000ff">
struct rgb_values
{
float red;
float green;
float blue;
};
</FONT>
in your program.This could be translated into one entry into the config
file which would then look like:
<FONT COLOR="0000ff">
<rgb_values> 0.50 0.50 0.50
</FONT>
The entries are internally structured as follows ( don't worry if you don't
understand it ):
<HR>
<FONT COLOR="0000ff">
group_entry [main group]
|
+---conf_entry <"variable1"> (var1) (var2) (var3) (var4) .......
|
+---conf_entry <"variable2"> (var1) (var2) ......
.
.
</FONT>
<HR>
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:
<FONT COLOR="0000ff">
i => integer (int)
f => floating point (float)
s => string (char *)
</FONT>
So for example you've got a line in a config file which looks like:
<FONT COLOR="0000ff"><rgb_values> 0.50 0.35 0.60</FONT>
This would translate into a variable-type string of:
<FONT COLOR="0000ff">fff</FONT>
Meaning that the config parser will store and look for 3 floats.
You add an entry to these variables as follows:
<FONT COLOR="0000ff">temp_config_class->insert_entry ("rgb_values","fff",&red,&green,&blue);</FONT>
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:
<FONT COLOR="0000ff">set_defaults (50,0.10,"main");</FONT>
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.
<HR>
<CENTER>
3. <B>How to use it ?</B>
=======================
</CENTER>
You can use the sources in two ways:
<B>a)</B>
The first way is to take the <B>libconfig.a</B> you will find when the
compilation process is complete and copy it to a default library directory.
You could copy it to <B>/usr/local/lib</B> for example. Do the same
with the include files you find in the main config dir and copy them to
<B>/usr/local/include</B> for example. This should set things up
properly and you can now use the config library in any other program.
<HR>
<B>b)</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
<B>foo</B> wich resides in a directory called:
<FONT COLOR="0000ff">
~/foo
</FONT>
You could create a directory called config in the ~/foo directory.
This would give you the following dirs:
<FONT COLOR="0000ff">~/foo</FONT> Main source dir
<FONT COLOR="0000ff">~/foo/config</FONT> Location of config sources
<FONT COLOR="0000ff">~/foo/flex</FONT> Location of the source file for the flex parser
You would then have to edit the Makefile and change the point where it says:
<FONT COLOR="0000ff">
all: $(OBJECTS)
$(AR) -rs $(TARGET) $(OBJECTS)
# cp $(TARGET) ../
</FONT>
Just remove the "#" and <B>make</B> will then copy the libconfig.a to the
<B>foo</B> directory. Now when you create your own Makefiles in the foo
directory don't forget to add <B>-I./config</B> to the default include
directories.
<HR>
<CENTER>
3.1 <B>General Usage</B>
=======================
</CENTER>
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:
<FONT COLOR="0000ff">ConfigClass *config_object=new ConfigClass (".configrc");</FONT>
This creates a config object which will do all it's file operations on the
file <B>.configrc</B> 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:
<FONT COLOR="0000ff">ConfigClass *config_object=new ConfigClass (".configrc","MindsEye");</FONT>
This will add a string to the config header which says:
<FONT COLOR="0000ff"># This config file belongs to the (MindsEye) package</FONT>
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:
<FONT COLOR="0000ff">config_object->add_group ("main_group");</FONT>
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.
<HR>
<CENTER>
3.2 <B>Config and Plugins</B>
=======================
</CENTER>
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>b</B> and <B>c</B>
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.
<HR>
<CENTER>
4. <B>What does it look like ?</B>
=============================
</CENTER>
The config parser uses the following reserved token syntax:
[ ] = group identifier
< > = name identifier
" " = string identifier
<HR>
Example:
--SOURCE: main.cpp-------------------------------------------------------------
<FONT COLOR="0000ff">
#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);
}
</FONT>
--OUTPUT: /root/.mindseyerc----------------------------------------------------
<FONT COLOR="0000ff">
# 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)
</FONT>
<HR>
<CENTER>
5. <B>Info</B>
=========
</CENTER>
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>
<HR>
<CENTER>
6. <B>Copyright</B>
=============
</CENTER>
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.
</PRE>
|