diff --git a/dune/common/Makefile.am b/dune/common/Makefile.am index ed5d9d73738ccf38508d0ea329456819867e751b..84503f2192512fbd91a7d2fbe02fb1f75224013f 100644 --- a/dune/common/Makefile.am +++ b/dune/common/Makefile.am @@ -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 \ diff --git a/dune/common/parametertreeparser.cc b/dune/common/parametertreeparser.cc new file mode 100644 index 0000000000000000000000000000000000000000..35a90b2f126b4af82d55ecf06d1494d42c938ec0 --- /dev/null +++ b/dune/common/parametertreeparser.cc @@ -0,0 +1,155 @@ +// -*- 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(); + } + + } + +} diff --git a/dune/common/parametertreeparser.hh b/dune/common/parametertreeparser.hh new file mode 100644 index 0000000000000000000000000000000000000000..f848dbd82e1d0d63564e201e7103a4f057a6ddd9 --- /dev/null +++ b/dune/common/parametertreeparser.hh @@ -0,0 +1,125 @@ +// -*- 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