Configuration files
Introduction
The class ConfigStream
is useful to parse configuration files
in text format. One may search for a word in the configuration file, extract
the value of a field or benefit from markup substitution.
ConfigStream
derives from ExtStream
. Therefore,
it is advocated to read the section "Extended streams" of this
documentation.
Example
The following example shows how to use a few methods of
ConfigStream
.
# This files demonstrates how flexible configuration files
# read by ConfigStream may be.
# One may want to put a statement at the beginning of its configuration file,
# to describe its content.
Configuration file associated with version <version_number>.
[Domain]
# Dimensions.
Nx = 5, Ny = 6
# First cell.
x_min: -1.5 y_min: 5.2
# Steps.
Delta_x 3.1 # Experiment #2
Delta_y 9.7
[Files]
user: mallet
Home: /home/<user>
Data: <Home>/data/
Programs: <Home>/programs/version-<version_number>/
date: 2004-10-02, version_number: 1.5
#include "Talos.hxx"
using namespace Talos;
int main()
{
ConfigStream file("file.cfg");
cout << "Reading " << file.GetFileName() << "..." << endl;
// Domain variables.
int Nx, Ny;
double x_min, y_min;
float dx, dy;
// Parses the configuration file.
file.Find("[Domain]"); // Searches for section [Domain].
file.GetValue("Nx", Nx);
file.GetValue("Ny", Ny);
file.GetValue("x_min", x_min);
file.GetValue("y_min", y_min);
file.GetValue("Delta_x", dx);
file.GetValue("Delta_y", dy);
cout << "Domain: (" << x_min << ", " << dx << ", " << Nx << ") x ("
<< y_min << ", " << dy << ", " << Ny << ")." << endl;
// Data files.
string data_dir, programs_dir; // Directories.
string note;
file.FindFromBeginning("[Domain]"); // Searches for section [Files].
file.GetValue("Data", data_dir); // With nested markup substitutions.
// Markup <version> is defined after "Programs", but it still works:
file.GetValue("Programs", programs_dir);
cout << "Data directory: " << data_dir << endl;
cout << "Programs directory: " << programs_dir << endl;
// First statement.
file.Rewind();
cout << file.GetLine() << endl;
return 0;
}
Result:
Reading file.cfg...
Domain: (-1.5, 3.1, 5) x (5.2, 9.7, 6).
Data directory: /home/mallet/data/
Programs directory: /home/mallet/programs/version-1.5/
Configuration file associated with version 1.5.
makefile (launch make read_config
):
CC = g++
INCPATH = Talos # Put the path to Talos.
LINK = g++
TARGETS = read read_config read_configs exceptions dates
all: $(TARGETS)
$(TARGETS): % : %.o
$(LINK) -o $@ $<
%.o : %.cpp
$(CC) -I$(INCPATH) -c -o $@ $<
clean:
rm -f $(TARGETS) $(TARGETS:%=%.o)
Comments
ConfigStream
derives from ExtStream
. It is
advocated to read the section "Extended streams" of this documentation to
understand how ExtStream
works. ConfigStream
essentially behaves in the same way as ExtStream
except that it
performs markup substitution.
If a markup substitution fails, an exception is raised.
Multiple configuration files
Dealing with multiple configuration files at the same time is pretty easy
thanks to ConfigStreams
. An instance of
ConfigStreams
is associated with multiple files, but it has
exactly the same abilities as an instance of ConfigStream
.
If file.cfg is split in two files:
# This files demonstrates how flexible configuration files
# read by ConfigStreams may be.
# One may want to put a statement at the beginning of its configuration file,
# to describe its content.
Configuration file associated with version <version_number>.
[Domain]
# Dimensions.
Nx = 5, Ny = 6
# First cell.
x_min: -1.5 y_min: 5.2
# Steps.
Delta_x 3.1 # Experiment #2
Delta_y 9.7
[Files]
user: mallet
Home: /home/<user>
Data: <Home>/data/
Programs: <Home>/programs/version-<version_number>/
date: 2004-10-02, version_number: 1.5
read_configs.cpp (compilation: make
read_configs
):
#include "Talos.hxx"
using namespace Talos;
int main()
{
ConfigStreams file("domain.cfg", "paths.cfg");
cout << "Reading " << file.GetStreams()[0]->GetFileName() << "..." << endl;
cout << "and " << file.GetStreams()[1]->GetFileName() << "..." << endl;
// Domain variables.
int Nx, Ny;
double x_min, y_min;
float dx, dy;
// Parses the configuration file.
file.Find("[Domain]"); // Searches for section [Domain].
file.GetValue("Nx", Nx);
file.GetValue("Ny", Ny);
file.GetValue("x_min", x_min);
file.GetValue("y_min", y_min);
file.GetValue("Delta_x", dx);
file.GetValue("Delta_y", dy);
cout << "Domain: (" << x_min << ", " << dx << ", " << Nx << ") x ("
<< y_min << ", " << dy << ", " << Ny << ")." << endl;
// Data files.
string data_dir, programs_dir; // Directories.
string note;
file.FindFromBeginning("[Domain]"); // Searches for section [Files].
file.GetValue("Data", data_dir); // With nested markup substitutions.
// Markup <version> is defined after "Programs", but it still works:
file.GetValue("Programs", programs_dir);
cout << "Data directory: " << data_dir << endl;
cout << "Programs directory: " << programs_dir << endl;
// First statement.
file.Rewind();
cout << file.GetLine() << endl;
return 0;
}
Result:
Reading domain.cfg...
and paths.cfg...
Domain: (-1.5, 3.1, 5) x (5.2, 9.7, 6).
Data directory: /home/mallet/data/
Programs directory: /home/mallet/programs/version-1.5/
Configuration file associated with version 1.5.
Only the two first lines (in main()
) have changed. The
constructor takes two files and, to get the file names, one has to call
GetStreams
which returns a vector of pointers to the instances of
ConfigStream
(refer to the methods documentation for
details). Otherwise, the whole is managed as if only one file was parsed.
Markup substitution also works across files.