Skip to content
Snippets Groups Projects
Commit b920a3e4 authored by Oliver Sander's avatar Oliver Sander
Browse files

Provide the existing parsing facilities for ParameterTrees in a separate file

This code used to be in ConfigParser, which I will deprecate in a second.
The new implementation is inspired by boost: each parser is a global method
in a namespace.  In our case, that namespace is a class ParameterTreeParser,
because it needs to have some private methods (ltrim and rtrim, to be
precise).  On demand, parsers for more formats can be added to this class/file.

I do not insist on any of the details of this new code. However, I wanted
to have the many architectural change before the creation of the 2.2 release
branch.

[[Imported from SVN: r6346]]
parent 17e55c83
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@ libcommon_la_SOURCES = \
configparser.cc \
ios_state.cc \
parametertree.cc \
parametertreeparser.cc \
path.cc \
exceptions.cc \
stdstreams.cc
......@@ -62,6 +63,7 @@ commoninclude_HEADERS = \
mpitraits.hh \
nullptr.hh \
parametertree.hh \
parametertreeparser.hh \
path.hh \
poolallocator.hh \
precision.hh \
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#include "parametertreeparser.hh"
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <string>
#include <sstream>
#include <fstream>
#include <set>
#include <dune/common/exceptions.hh>
std::string Dune::ParameterTreeParser::ltrim(const std::string& s)
{
std::size_t firstNonWS = s.find_first_not_of(" \t\n\r");
if (firstNonWS!=std::string::npos)
return s.substr(firstNonWS);
return std::string();
}
std::string Dune::ParameterTreeParser::rtrim(const std::string& s)
{
std::size_t lastNonWS = s.find_last_not_of(" \t\n\r");
if (lastNonWS!=std::string::npos)
return s.substr(0, lastNonWS+1);
return std::string();
}
void Dune::ParameterTreeParser::readINITree(std::string file,
ParameterTree& pt,
bool overwrite)
{
std::ifstream in(file.c_str());
if (!in)
DUNE_THROW(Dune::IOError, "Could not open configuration file " << file);
readINITree(in, pt, "file '" + file + "'", overwrite);
}
void Dune::ParameterTreeParser::readINITree(std::istream& in,
ParameterTree& pt,
bool overwrite)
{
readINITree(in, pt, "stream", overwrite);
}
void Dune::ParameterTreeParser::readINITree(std::istream& in,
ParameterTree& pt,
const std::string srcname,
bool overwrite)
{
std::string prefix;
std::set<std::string> keysInFile;
while(!in.eof())
{
std::string line;
getline(in, line);
line = ltrim(line);
switch (line[0]) {
case '#' :
break;
case '[' :
line = rtrim(line);
if (line[line.length()-1] == ']')
{
prefix = rtrim(ltrim(line.substr(1, line.length()-2)));
if (prefix != "")
prefix += ".";
}
break;
default :
std::string::size_type comment = line.find("#");
line = line.substr(0,comment);
std::string::size_type mid = line.find("=");
if (mid != std::string::npos)
{
std::string key = prefix+rtrim(ltrim(line.substr(0, mid)));
std::string value = ltrim(line.substr(mid+1));
if (value.length()>0)
{
// handle quoted strings
if ((value[0]=='\'')or (value[0]=='"'))
{
char quote = value[0];
value=value.substr(1);
while (*(rtrim(value).rbegin())!=quote)
{
if (not in.eof())
{
std::string l;
getline(in, l);
value = value+"\n"+l;
}
else
value = value+quote;
}
value = rtrim(value);
value = value.substr(0,value.length()-1);
}
else
value = rtrim(value);
}
if (keysInFile.count(key) != 0)
DUNE_THROW(Exception, "Key '" << key <<
"' appears twice in " << srcname << " !");
else
{
if(overwrite || ! pt.hasKey(key))
pt[key] = value;
keysInFile.insert(key);
}
}
break;
}
}
}
void Dune::ParameterTreeParser::readOptions(int argc, char* argv [],
ParameterTree& pt)
{
std::string v = "";
std::string k = "";
for(int i=1; i<argc; i++)
{
std::string s(argv[i]);
if ((argv[i][0]=='-') && (argv[i][1]!='\000'))
{
k = argv[i]+1;
continue;
}
else
{
if (k.size())
pt[k] = argv[i];
k.clear();
}
}
}
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_PARAMETER_PARSER_HH
#define DUNE_PARAMETER_PARSER_HH
#include <istream>
#include <string>
#include <dune/common/parametertree.hh>
namespace Dune {
/** \brief Parser for hierarchical configuration files
* \ingroup Common
*
* This class parses config files into a hierarchical structure.
* Config files should look like this
*
\verbatim
# this file configures fruit colors in fruitsalad
##these are no fruit but could also appear in fruit salad
honeydewmelon = yellow
watermelon = green
fruit.tropicalfruit.orange = orange
[fruit]
strawberry = red
pomegranate = red
[fruit.pipfruit]
apple = green/red/yellow
pear = green
[fruit.stonefruit]
cherry = red
plum = purple
\endverbatim
*
*
* If a '[prefix]' statement appears all following entries use this prefix
* until the next '[prefix]' statement. Fruitsalads for example contain:
\verbatim
honeydewmelon = yellow
fruit.tropicalfruit.orange = orange
fruit.pipfruit.apple = green/red/yellow
fruit.stonefruit.cherry = red
\endverbatim
*
* All keys with a common 'prefix.' belong to the same substructure called
* 'prefix'. Leading and trailing spaces and tabs are removed from the
* values unless you use single or double quotes around them. Using single
* or double quotes you can also have multiline values.
*
*/
class ParameterTreeParser
{
static std::string ltrim(const std::string& s);
static std::string rtrim(const std::string& s);
public:
/** \brief parse C++ stream
*
* Parses C++ stream and build hierarchical config structure.
*
* \param in The stream to parse
* \param overwrite Whether to overwrite already existing values.
* If false, values in the stream will be ignored
* if the key is already present.
*
* \note This method is identical to parseStream(std::istream&,
* const std::string&, bool) with the exception that that
* method allows to give a custom name for the stream.
*/
static void readINITree(std::istream& in, ParameterTree& pt,
bool overwrite);
/** \brief parse C++ stream
*
* Parses C++ stream and build hierarchical config structure.
*
* \param in The stream to parse
* \param srcname Name of the configuration source for error
* messages, "stdin" or a filename.
* \param overwrite Whether to overwrite already existing values.
* If false, values in the stream will be ignored
* if the key is already present.
*/
static void readINITree(std::istream& in, ParameterTree& pt,
const std::string srcname = "stream",
bool overwrite = true);
/** \brief parse file
*
* Parses file with given name and build hierarchical config structure.
*
* \param file filename
* \param overwrite Whether to overwrite already existing values.
* If false, values in the stream will be ignored
* if the key is already present.
*/
static void readINITree(std::string file, ParameterTree& pt, bool overwrite = true);
/** \brief parse command line
*
* Parses command line options and build hierarchical ParameterTree structure.
*
* \param argc arg count
* \param argv arg values
*/
static void readOptions(int argc, char* argv [], ParameterTree& pt);
};
} // end namespace Dune
#endif // DUNE_PARAMETER_PARSER_HH
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment