From 46cabea540f12654cfd1934665ce28b332e5e602 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Wed, 8 Sep 2010 20:54:57 +0000 Subject: [PATCH] Re-write the ParameterHandler class to store its data in a BOOST property_tree container, rather than a hand-written data structure. The primary advantage is that we so gain the ability to write (and later read) data in XML format, for example for consumption by a GUI. git-svn-id: https://svn.dealii.org/trunk@21897 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/parameter_handler.h | 254 ++-- deal.II/base/source/parameter_handler.cc | 1155 ++++++++--------- tests/bits/multiple_parameter_loop_02.cc | 2 +- tests/bits/parameter_handler_12.cc | 15 +- tests/bits/parameter_handler_12/cmp/generic | 2 +- tests/bits/parameter_handler_4/cmp/generic | 4 +- tests/bits/parameter_handler_4a/cmp/generic | 4 +- tests/bits/parameter_handler_write_json.cc | 80 ++ .../parameter_handler_write_json/cmp/generic | 69 + tests/bits/parameter_handler_write_xml.cc | 80 ++ .../parameter_handler_write_xml/cmp/generic | 4 + 11 files changed, 951 insertions(+), 718 deletions(-) create mode 100644 tests/bits/parameter_handler_write_json.cc create mode 100644 tests/bits/parameter_handler_write_json/cmp/generic create mode 100644 tests/bits/parameter_handler_write_xml.cc create mode 100644 tests/bits/parameter_handler_write_xml/cmp/generic diff --git a/deal.II/base/include/base/parameter_handler.h b/deal.II/base/include/base/parameter_handler.h index d2e8b99c62..10a5bafefe 100644 --- a/deal.II/base/include/base/parameter_handler.h +++ b/deal.II/base/include/base/parameter_handler.h @@ -17,6 +17,9 @@ #include #include #include +#include + +#include #include #include @@ -1212,7 +1215,7 @@ namespace Patterns * @ingroup input * * @author Wolfgang Bangerth, October 1997, revised February 1998 - */ + */ class ParameterHandler : public Subscriptor { private: @@ -1249,7 +1252,7 @@ class ParameterHandler : public Subscriptor */ Text = 1, /** - * Write paramteters as a + * Write parameters as a * LaTeX table. */ LaTeX = 2, @@ -1259,6 +1262,21 @@ class ParameterHandler : public Subscriptor * values. */ Description = 3, + + /** + * Write out everything as + * an JSON + * file. + */ + JSON = 5, + /** * Write input for * ParameterHandler without @@ -1388,13 +1406,9 @@ class ParameterHandler : public Subscriptor * otherwise the default * value. If the value of an * undeclared entry is required, - * an empty string is returned - * and assert is used to - * check whether this entry was - * declared (therefore an - * exception may be thrown). + * an exception will be thrown. */ - const std::string & get (const std::string &entry_string) const; + std::string get (const std::string &entry_string) const; /** * Return value of entry @@ -1428,6 +1442,13 @@ class ParameterHandler : public Subscriptor * * The parameter must already exist in * the present subsection. + * + * The function throws an + * exception of type + * ExcValueDoesNotMatchPattern + * if the new value does not + * conform to the pattern for + * this entry. */ void set (const std::string &entry_name, const std::string &new_value); @@ -1442,6 +1463,13 @@ class ParameterHandler : public Subscriptor * string and a bool as arguments, which * is certainly not what is most often * intended. + * + * The function throws an + * exception of type + * ExcValueDoesNotMatchPattern + * if the new value does not + * conform to the pattern for + * this entry. */ void set (const std::string &entry_name, const char *new_value); @@ -1453,6 +1481,13 @@ class ParameterHandler : public Subscriptor * * The parameter must already exist in * the present subsection. + * + * The function throws an + * exception of type + * ExcValueDoesNotMatchPattern + * if the new value does not + * conform to the pattern for + * this entry. */ void set (const std::string &entry_name, const long int &new_value); @@ -1472,6 +1507,13 @@ class ParameterHandler : public Subscriptor * one you can get back out using * get_double() may differ in the 16th * digit. + * + * The function throws an + * exception of type + * ExcValueDoesNotMatchPattern + * if the new value does not + * conform to the pattern for + * this entry. */ void set (const std::string &entry_name, const double &new_value); @@ -1483,6 +1525,13 @@ class ParameterHandler : public Subscriptor * * The parameter must already exist in * the present subsection. + * + * The function throws an + * exception of type + * ExcValueDoesNotMatchPattern + * if the new value does not + * conform to the pattern for + * this entry. */ void set (const std::string &entry_name, const bool &new_value); @@ -1593,9 +1642,9 @@ class ParameterHandler : public Subscriptor /** * Exception */ - DeclException2 (ExcDefaultDoesNotMatchPattern, + DeclException2 (ExcValueDoesNotMatchPattern, std::string, std::string, - << "The default string <" << arg1 + << "The string <" << arg1 << "> does not match the given pattern <" << arg2 << ">"); /** * Exception @@ -1616,88 +1665,56 @@ class ParameterHandler : public Subscriptor //@} private: /** - * Whatever is in a section: - * map of entry names together with - * entry content and regexp, and - * list of subsections. + * The separator used when + * accessing elements of a path + * into the parameter tree. */ - struct Section - { - /** - * Destructor - */ - ~Section (); - - /** - * Number of entries that this - * section has plus all the - * non-subsection entries of all its - * decendents. - */ - unsigned int accumulated_no_of_entries () const; + static const char path_separator = '.'; - /** - * Value of an entry in this section, - * including documentation and the - * pattern it conforms to. - */ - struct EntryContent - { - std::string value; - std::string documentation; - Patterns::PatternBase *pattern; - - /** - * Return whether this entry has - * some form of documentation. - */ - bool has_documentation () const; - }; + /** + * The complete tree of sections + * and entries. If a node in a + * tree is a value, it has a + * number of attributes, namely: + * - its value + * - its default value + * - its documentation + * + * On the other hand, if a node + * in the tree is a directory, + * then none of these attributes + * exist. + */ + boost::property_tree::ptree entries; - /** - * Typedef for a type - * describing all the entries - * in a subsection: this is a - * map from the entry keys to - * a pair of values, one for - * the default string and one - * describing the pattern - * that the entry must match. - */ - typedef - std::map - EntryType; + /** + * A list of patterns that are + * used to describe the + * parameters of this object. The + * are indexed by nodes in the + * property tree. + */ + std::vector > patterns; - /** - * List of entries for this - * section. - */ - EntryType entries; + /** + * Mangle a string so that it + * doesn't contain any special + * characters or spaces. + */ + static std::string mangle (const std::string &s); - /** - * List of subsections of - * this section. - */ - std::map subsections; + /** + * Unmangle a string into its + * original form. + */ + static std::string demangle (const std::string &s); - /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL std::map type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. - */ - unsigned int memory_consumption () const; - }; + /** + * Return whether a given node is + * a parameter node or a + * subsection node. + */ + static bool is_parameter_node (const boost::property_tree::ptree &); /** * Path of presently selected @@ -1707,24 +1724,23 @@ class ParameterHandler : public Subscriptor std::vector subsection_path; /** - * List of default values - * organized as a tree of - * subsections + * Return the string that + * identifies the current path + * into the property tree. This + * is only a path, i.e. it is not + * terminated by the + * path_separator character. */ - Section defaults; + std::string get_current_path () const; /** - * Analogue list of changed - * entries. The tree of - * subsections is there even if - * there are no changed entry - * values in a subsection; - * therefore enter_subsection() - * has to create the tree in both - * Defaults and - * changed_entries. + * Given the name of an entry as + * argument, the function + * computes a full path into the + * parameter tree using the + * current subsection. */ - Section changed_entries; + std::string get_current_full_path (const std::string &name) const; /** * Scan one line of input. @@ -1750,32 +1766,6 @@ class ParameterHandler : public Subscriptor bool scan_line (std::string line, const unsigned int lineno); - /** - * Get a pointer to the - * Section structure in the - * Defaults tree for the - * subsection we are presently - * in. - */ - Section* get_present_defaults_subsection (); - - /** - * Same, const version. - */ - const Section* get_present_defaults_subsection () const; - - /** - * Get a pointer to the Section structure - * in the changed_entries tree - * for the subsection we are presently in. - */ - Section* get_present_changed_subsection (); - - /** - * Same, const version. - */ - const Section* get_present_changed_subsection () const; - friend class MultipleParameterLoop; }; @@ -2175,10 +2165,16 @@ class MultipleParameterLoop : public ParameterHandler void init_branches (); /** - * Initialize the branches in the - * given section. + * Traverse the section currently + * set by + * enter_subsection()/leave_subsection() + * and see which of the entries + * are variante/array + * entries. Then fill the + * multiple_choices variable + * using this information. */ - void init_branches_section (const ParameterHandler::Section &sec); + void init_branches_current_section (); /** * Transfer the entry values for one run diff --git a/deal.II/base/source/parameter_handler.cc b/deal.II/base/source/parameter_handler.cc index c86927e839..85f4ffc2cb 100644 --- a/deal.II/base/source/parameter_handler.cc +++ b/deal.II/base/source/parameter_handler.cc @@ -17,6 +17,11 @@ #include #include +#include +#include +#include +#include + #include #include #include @@ -57,7 +62,7 @@ namespace Patterns // the line if (!(in >> c)) break; - + if ((c != ' ') && (c != '\t')) return false; } @@ -66,7 +71,7 @@ namespace Patterns } - + PatternBase::~PatternBase () {} @@ -119,7 +124,7 @@ namespace Patterns int i; if (!(str >> i)) return false; - + if (!has_only_whitespace (str)) return false; // check whether valid bounds @@ -194,7 +199,7 @@ namespace Patterns double d; if (!(str >> d)) return false; - + if (!has_only_whitespace (str)) return false; // check whether valid bounds @@ -555,6 +560,145 @@ ParameterHandler::~ParameterHandler () +std::string +ParameterHandler::mangle (const std::string &s) +{ + std::string u; + u.reserve (s.size()); + + static const std::string allowed_characters + ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); + + // for all parts of the string, see + // if it is an allowed character or + // not + for (unsigned int i=0; i(s[i])/16]); + u.push_back (hex[static_cast(s[i])%16]); + } + + return u; +} + + + +std::string +ParameterHandler::demangle (const std::string &s) +{ + std::string u; + u.reserve (s.size()); + + for (unsigned int i=0; i(c)); + + // skip the two characters + i += 2; + } + + return u; +} + + + +bool +ParameterHandler::is_parameter_node (const boost::property_tree::ptree &p) +{ + return (p.get_optional("value")); +} + + + +std::string +ParameterHandler::get_current_path () const +{ + if (subsection_path.size() > 0) + { + std::string p = mangle(subsection_path[0]); + for (unsigned int i=1; i for reading." << std::endl; @@ -644,24 +788,7 @@ bool ParameterHandler::read_input_from_string (const char *s) void ParameterHandler::clear () { - subsection_path.clear (); - defaults.entries.clear (); - changed_entries.entries.clear (); - - std::map::iterator p; - - for (p=defaults.subsections.begin(); p!=defaults.subsections.end(); ++p) - delete p->second; - - for (p=changed_entries.subsections.begin(); p!=changed_entries.subsections.end(); ++p) - if (p->second) - { - delete p->second; - Assert (false, ExcInternalError()); - }; - - defaults.subsections.clear (); - changed_entries.subsections.clear (); + entries = boost::property_tree::ptree(); } @@ -672,46 +799,45 @@ ParameterHandler::declare_entry (const std::string &entry, const Patterns::PatternBase &pattern, const std::string &documentation) { - Section* p = get_present_defaults_subsection (); - - // default must match Pattern - Assert (pattern.match (default_value), - ExcDefaultDoesNotMatchPattern(default_value, - pattern.description())); - - // if the entry already existed, - // make sure we don't create a - // memory leak - if (p->entries.find (entry) != p->entries.end()) - delete p->entries[entry].pattern; - - // if the entry didn't yet exist, - // but map::operator[] will create - // it - p->entries[entry].value = default_value; - p->entries[entry].documentation = documentation; - p->entries[entry].pattern = pattern.clone(); + entries.put (get_current_full_path(entry) + path_separator + "value", + default_value); + entries.put (get_current_full_path(entry) + path_separator + "default_value", + default_value); + entries.put (get_current_full_path(entry) + path_separator + "documentation", + documentation); + + // clone the pattern and store its + // index in the node + patterns.push_back (std_cxx1x::shared_ptr + (pattern.clone())); + entries.put (get_current_full_path(entry) + path_separator + "pattern", + static_cast(patterns.size()-1)); + // also store the description of + // the pattern. we do so because we + // may wish to export the whole + // thing as XML or any other format + // so that external tools can work + // on the parameter file; in that + // case, they will have to be able + // to re-create the patterns as far + // as possible + entries.put (get_current_full_path(entry) + path_separator + + "pattern_description", + patterns.back()->description()); } void ParameterHandler::enter_subsection (const std::string &subsection) { - Section* pd = get_present_defaults_subsection (); + const std::string current_path = get_current_path (); - // does subsection already exist? - if (pd->subsections.find (subsection) == pd->subsections.end()) - { - // subsection does not yet exist: - // create entry in Defaults and - // changed_entries trees - pd->subsections[subsection] = new Section(); - - Section* pc = get_present_changed_subsection (); - pc->subsections[subsection] = new Section(); - }; + // if necessary create subsection + if (!entries.get_child_optional (get_current_full_path(subsection))) + entries.add_child (get_current_full_path(subsection), + boost::property_tree::ptree()); - // finally enter subsection + // then enter it subsection_path.push_back (subsection); } @@ -736,34 +862,19 @@ bool ParameterHandler::leave_subsection () -const std::string & +std::string ParameterHandler::get (const std::string &entry_string) const { - const Section* pd = get_present_defaults_subsection (); - const Section* pc = get_present_changed_subsection (); - - // assert that the according entry is - // already declared in the defaults tree - Assert (pd->entries.find (entry_string) != pd->entries.end(), - ExcEntryUndeclared(entry_string)); - - if (pd->entries.find (entry_string) == pd->entries.end()) + // assert that the entry is indeed + // declared + if (boost::optional value + = entries.get_optional (get_current_full_path(entry_string) + path_separator + "value")) + return value.get(); + else { - static const std::string empty_string; - return empty_string; - }; - - - // entry exists; now find out - // whether it was changed: - Section::EntryType::const_iterator ptr; - ptr = pc->entries.find (entry_string); - if (ptr != pc->entries.end()) - return ptr->second.value; - - // not changed. take the value from - // the defaults tree - return pd->entries.find(entry_string)->second.value; + Assert (false, ExcEntryUndeclared(entry_string)); + return ""; + } } @@ -814,21 +925,25 @@ void ParameterHandler::set (const std::string &entry_string, const std::string &new_value) { - const Section* pd = get_present_defaults_subsection (); - Section* pc = get_present_changed_subsection (); - - // assert that the according entry is - // already declared in the defaults tree - Assert (pd->entries.find (entry_string) != pd->entries.end(), - ExcEntryUndeclared(entry_string)); - - // entry exists; now set it (if the entry - // in pc hasn't existed yet, create it and - // set the pattern to the null pointer - // since it isn't used) - if (pc->entries.find (entry_string) == pc->entries.end()) - pc->entries[entry_string].pattern = 0; - pc->entries[entry_string].value = new_value; + // assert that the entry is indeed + // declared + if (entries.get_optional + (get_current_full_path(entry_string) + path_separator + "value")) + { + const unsigned int pattern_index + = entries.get (get_current_full_path(entry_string) + path_separator + "pattern"); + AssertThrow (patterns[pattern_index]->match(new_value), + ExcValueDoesNotMatchPattern (new_value, + entries.get + (get_current_full_path(entry_string) + + path_separator + + "pattern_description"))); + + entries.put (get_current_full_path(entry_string) + path_separator + "value", + new_value); + } + else + AssertThrow (false, ExcEntryUndeclared(entry_string)); } @@ -892,6 +1007,24 @@ ParameterHandler::print_parameters (std::ostream &out, switch (style) { + case XML: + // call the writer + // function and exit as + // there is nothing + // further to do down in + // this function + write_xml (out, entries); + return out; + + case JSON: + // call the writer + // function and exit as + // there is nothing + // further to do down in + // this function + write_json (out, entries); + return out; + case Text: out << "# Listing of Parameters" << std::endl << "# ---------------------" << std::endl; @@ -931,6 +1064,7 @@ ParameterHandler::print_parameters (std::ostream &out, } + // Print a section in the desired style. The styles are separated into // several verbosity classes depending on the higher bits. // @@ -943,24 +1077,31 @@ ParameterHandler::print_parameters_section (std::ostream &out, { AssertThrow (out, ExcIO()); - Section *pd = get_present_defaults_subsection (); - Section *pc = get_present_changed_subsection (); - - // traverse entry list - Section::EntryType::const_iterator ptr; + const boost::property_tree::ptree ¤t_section + = entries.get_child (get_current_path()); switch (style) { case Text: case ShortText: - { - // first find out the longest - // entry name to be able to - // align the equal signs + { + // first find out the longest + // entry name to be able to + // align the equal signs + // + // to do this loop over all + // nodes of the current tree, + // select the parameter nodes + // (and discard sub-tree + // nodes) and take the + // maximum of their lengths unsigned int longest_name = 0; - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - if (ptr->first.length() > longest_name) - longest_name = ptr->first.length(); + for (boost::property_tree::ptree::const_iterator + p = current_section.begin(); + p != current_section.end(); ++p) + if (is_parameter_node (p->second) == true) + longest_name = std::max (longest_name, + demangle(p->first).length()); // likewise find the longest // actual value string to @@ -968,114 +1109,115 @@ ParameterHandler::print_parameters_section (std::ostream &out, // default and documentation // strings unsigned int longest_value = 0; - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - longest_value - = std::max (static_cast (longest_value), - (pc->entries.find(ptr->first) != pc->entries.end() - ? - pc->entries[ptr->first].value - : - pd->entries[ptr->first].value).length()); - - // print entries one by one - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - { - // see whether the - // value is listed in - // the Changed tree and - // if so take it from - // there. otherwise - // take the default - // value from the - // Default tree - const std::string &value - = (pc->entries.find(ptr->first) != pc->entries.end() - ? - pc->entries[ptr->first].value - : - pd->entries[ptr->first].value); - - // if there is documentation, - // then add an empty line (unless - // this is the first entry in a - // subsection), print the - // documentation, and then the - // actual entry; break the - // documentation into readable - // chunks such that the whole - // thing is at most 78 characters - // wide - if ((!(style & 128)) && pd->entries[ptr->first].has_documentation()) - { - if (ptr != pd->entries.begin()) - out << std::endl; - - const std::vector doc_lines - = Utilities:: - break_text_into_lines (pd->entries[ptr->first].documentation, - 78 - indent_level*2 - 2); - - for (unsigned int i=0; ifirst - << std::setw(longest_name-ptr->first.length()+1) << " " - << "= " << value; - - // finally print the - // default value, but - // only if it differs - // from the actual value - if ((!(style & 64)) && value != pd->entries[ptr->first].value) - { - out << std::setw(longest_value-value.length()+1) << " " - << "# "; - out << "default: " << pd->entries[ptr->first].value; - } - - out << std::endl; - } + for (boost::property_tree::ptree::const_iterator + p = current_section.begin(); + p != current_section.end(); ++p) + if (is_parameter_node (p->second) == true) + longest_value = std::max (longest_value, + p->second.get("value").length()); + + + // print entries one by + // one. make sure they are + // sorted by using the + // appropriate iterators + bool first_entry = true; + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == true) + { + const std::string value = p->second.get("value"); + + // if there is documentation, + // then add an empty line (unless + // this is the first entry in a + // subsection), print the + // documentation, and then the + // actual entry; break the + // documentation into readable + // chunks such that the whole + // thing is at most 78 characters + // wide + if ((!(style & 128)) && + !p->second.get("documentation").empty()) + { + if (first_entry == false) + out << std::endl; + else + first_entry = false; + + const std::vector doc_lines + = Utilities:: + break_text_into_lines (p->second.get("documentation"), + 78 - indent_level*2 - 2); + + for (unsigned int i=0; ifirst) + << std::setw(longest_name-demangle(p->first).length()+1) << " " + << "= " << value; + + // finally print the + // default value, but + // only if it differs + // from the actual value + if ((!(style & 64)) && value != p->second.get("default_value")) + { + out << std::setw(longest_value-value.length()+1) << ' ' + << "# "; + out << "default: " << p->second.get("default_value"); + } + + out << std::endl; + } break; } case LaTeX: { - // print entries one by one - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - { - // print name and value - out << "\\item {\\bf " << ptr->first << ":} " - << pd->entries[ptr->first].value - << " ("; - - // if there is a - // documenting string, - // print it as well - if (pd->entries[ptr->first].documentation.length() != 0) - out << pd->entries[ptr->first].documentation << ", "; - - // finally print default - // value - out << "{\\it default:} " - << (pc->entries.find(ptr->first) != pc->entries.end() - ? - pc->entries[ptr->first].value - : - pd->entries[ptr->first].value) - << ")" - << std::endl; - } + // print entries one by + // one. make sure they are + // sorted by using the + // appropriate iterators + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == true) + { + const std::string value = p->second.get("value"); + + // print name and value + out << "\\item {\\bf " << demangle(p->first) << ":} " + << value + << " ("; + + // if there is a + // documenting string, + // print it as well + if (!p->second.get("documentation").empty()) + out <second.get("documentation") << ", "; + + // finally print default + // value + out << "{\\it default:} " + << p->second.get("default_value") + << ")" + << std::endl; + } + break; } @@ -1085,41 +1227,56 @@ ParameterHandler::print_parameters_section (std::ostream &out, // entry name to be able to // align the equal signs unsigned int longest_name = 0; - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - if (ptr->first.length() > longest_name) - longest_name = ptr->first.length(); + for (boost::property_tree::ptree::const_iterator + p = current_section.begin(); + p != current_section.end(); ++p) + if (is_parameter_node (p->second) == true) + longest_name = std::max (longest_name, + demangle(p->first).length()); + + // print entries one by + // one. make sure they are + // sorted by using the + // appropriate iterators + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == true) + { + const std::string value = p->second.get("value"); - // print entries one by one - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - { - // print name and value - out << std::setw(indent_level*2) << "" - << "set " - << ptr->first - << std::setw(longest_name-ptr->first.length()+1) << " " - << " = "; - - // print possible values: - const std::vector description_str - = Utilities::break_text_into_lines (pd->entries[ptr->first].pattern->description(), - 78 - indent_level*2 - 2, '|'); - if (description_str.size() > 1) - { + // print name and value + out << std::setw(indent_level*2) << "" + << "set " + << demangle(p->first) + << std::setw(longest_name-demangle(p->first).length()+1) << " " + << " = "; + + // print possible values: + const std::vector description_str + = Utilities::break_text_into_lines (p->second.get + ("pattern_description"), + 78 - indent_level*2 - 2, '|'); + if (description_str.size() > 1) + { + out << std::endl; + for (unsigned int i=0; i 0) + out << " " << description_str[0] << std::endl; + else out << std::endl; - for (unsigned int i=0; ientries[ptr->first].documentation.length() != 0) - out << std::setw(indent_level*2 + longest_name + 10) << "" - << "(" << pd->entries[ptr->first].documentation << ")" << std::endl; - } + + // if there is a + // documenting string, + // print it as well + if (p->second.get("documentation").length() != 0) + out << std::setw(indent_level*2 + longest_name + 10) << "" + << "(" << p->second.get("documentation") << ")" << std::endl; + } + break; } @@ -1128,30 +1285,37 @@ ParameterHandler::print_parameters_section (std::ostream &out, } - // if there was text before and there are + // if there was text before and there are // sections to come, put two newlines // between the last entry and the first - // subsection; also make sure that the - // subsections will be printed at all - // (i.e. at least one of them is non-empty) - if ((style != Description) - && - (!(style & 128)) - && - (pd->entries.size() != 0) - && - (pd->subsections.size() != 0) - && - (pd->accumulated_no_of_entries() != pd->entries.size())) - out << std::endl << std::endl; - - // now transverse subsections tree; only - // plot a subsection, if it has at least - // one entry somewhere in it - std::map::const_iterator ptrss; - for (ptrss = pd->subsections.begin(); - ptrss != pd->subsections.end(); ++ptrss) - if (ptrss->second->accumulated_no_of_entries() != 0) + // subsection + { + unsigned int n_parameters = 0; + unsigned int n_sections = 0; + for (boost::property_tree::ptree::const_iterator + p = current_section.begin(); + p != current_section.end(); ++p) + if (is_parameter_node (p->second) == true) + ++n_parameters; + else + ++n_sections; + + if ((style != Description) + && + (!(style & 128)) + && + (n_parameters != 0) + && + (n_sections != 0)) + out << std::endl << std::endl; + } + + // now traverse subsections tree, + // in alphabetical order + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == false) { // first print the subsection header switch (style) @@ -1160,12 +1324,12 @@ ParameterHandler::print_parameters_section (std::ostream &out, case Description: case ShortText: out << std::setw(indent_level*2) << "" - << "subsection " << ptrss->first << std::endl; + << "subsection " << demangle(p->first) << std::endl; break; case LaTeX: out << std::endl << "\\item {\\bf " - << "Subsection " << ptrss->first + << "Subsection " << demangle(p->first) << "}" << std::endl << "\\begin{itemize}" << std::endl; @@ -1176,34 +1340,34 @@ ParameterHandler::print_parameters_section (std::ostream &out, // then the contents of the // subsection - enter_subsection (ptrss->first); + enter_subsection (demangle(p->first)); print_parameters_section (out, style, indent_level+1); leave_subsection (); switch (style) { case Text: - // write end of - // subsection. one - // blank line after - // each subsection - out << std::setw(indent_level*2) << "" - << "end" << std::endl - << std::endl; - - // if this is a toplevel - // subsection, then have two - // newlines - if (indent_level == 0) - out << std::endl; + // write end of + // subsection. one + // blank line after + // each subsection + out << std::setw(indent_level*2) << "" + << "end" << std::endl + << std::endl; + + // if this is a toplevel + // subsection, then have two + // newlines + if (indent_level == 0) + out << std::endl; - break; + break; case Description: break; case ShortText: - // write end of - // subsection. - out << std::setw(indent_level*2) << "" - << "end" << std::endl; + // write end of + // subsection. + out << std::setw(indent_level*2) << "" + << "end" << std::endl; break; case LaTeX: out << "\\end{itemize}" @@ -1233,37 +1397,35 @@ ParameterHandler::log_parameters (LogStream &out) void ParameterHandler::log_parameters_section (LogStream &out) { - Section *pd = get_present_defaults_subsection (); - Section *pc = get_present_changed_subsection (); - - // traverse entry list - Section::EntryType::const_iterator ptr; - - // print entries one by one - for (ptr = pd->entries.begin(); ptr != pd->entries.end(); ++ptr) - // see whether the value is - // listed in the Changed tree - // and if so take it from - // there. otherwise take the - // default value from the - // Default tree - if (pc->entries.find(ptr->first) != pc->entries.end()) - out << ptr->first << ": " - << pc->entries[ptr->first].value << std::endl; - else - out << ptr->first << ": " - << ptr->second.value << std::endl; + const boost::property_tree::ptree ¤t_section + = entries.get_child (get_current_path()); + + // print entries one by + // one. make sure they are + // sorted by using the + // appropriate iterators + bool first_entry = true; + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == true) + out << demangle(p->first) << ": " + << p->second.get("value") << std::endl; // now transverse subsections tree - std::map::const_iterator ptrss; - for (ptrss = pd->subsections.begin(); ptrss != pd->subsections.end(); ++ptrss) - { - out.push(ptrss->first); - enter_subsection (ptrss->first); - log_parameters_section (out); - leave_subsection (); - out.pop(); - }; + // now traverse subsections tree, + // in alphabetical order + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == false) + { + out.push (demangle(p->first)); + enter_subsection (demangle(p->first)); + log_parameters_section (out); + leave_subsection (); + out.pop (); + } } @@ -1298,25 +1460,25 @@ ParameterHandler::scan_line (std::string line, // delete this prefix line.erase (0, std::string("subsection").length()+1); - std::string SecName = line; - Section* pc = get_present_changed_subsection (); + const std::string subsection = line; + // check whether subsection exists - if (pc->subsections.find(SecName) == pc->subsections.end()) + if (!entries.get_child_optional (get_current_full_path(subsection))) { std::cerr << "Line " << lineno - << ": There is no such subsection to be entered:" << std::endl; + << ": There is no such subsection to be entered:" << get_current_full_path(subsection) < (get_current_full_path(entry_name) + path_separator + "value")) + { + // if entry was declared: + // does it match the regex? if not, + // don't enter it into the database + // exception: if it contains characters + // which specify it as a multiple loop + // entry, then ignore content + if (entry_value.find ('{') == std::string::npos) + { + const unsigned int pattern_index + = entries.get (get_current_full_path(entry_name) + path_separator + "pattern"); + if (!patterns[pattern_index]->match(entry_value)) + { + std::cerr << "Line " << lineno << ":" << std::endl + << " The entry value" << std::endl + << " " << entry_value << std::endl + << " for the entry named" << std::endl + << " " << entry_name << std::endl + << " does not match the given pattern" << std::endl + << " " << patterns[pattern_index]->description() + << std::endl; + return false; + } + } - // check whether entry was declared - if (pd->entries.find(entry_name) == pd->entries.end()) + entries.put (get_current_full_path(entry_name) + path_separator + "value", + entry_value); + return true; + } + else { std::cerr << "Line " << lineno << ": No such entry was declared:" << std::endl @@ -1363,42 +1556,8 @@ ParameterHandler::scan_line (std::string line, std::cerr << " >" << std::endl; return false; - }; - - // if entry was declared: - // does it match the regex? if not, - // don't enter it into the database - // exception: if it contains characters - // which specify it as a multiple loop - // entry, then ignore content - if (entry_value.find ('{') == std::string::npos) - if (!pd->entries[entry_name].pattern->match(entry_value)) - { - std::cerr << "Line " << lineno << ":" << std::endl - << " The entry value" << std::endl - << " " << entry_value << std::endl - << " for the entry named" << std::endl - << " " << entry_name << std::endl - << " does not match the given pattern" << std::endl - << " " << pd->entries[entry_name].pattern->description() - << std::endl; - return false; - }; - - Section* pc = get_present_changed_subsection (); - // the following lines declare - // this entry if not yet - // existent and overwrites it - // otherwise (the pattern is - // set to a null pointer, since - // we don't need the pattern in - // the entries section -- only - // in the defaults section) - pc->entries[entry_name].value = entry_value; - pc->entries[entry_name].pattern = 0; - - return true; - }; + } + } // this line matched nothing known std::cerr << "Line " << lineno @@ -1409,144 +1568,11 @@ ParameterHandler::scan_line (std::string line, -ParameterHandler::Section* ParameterHandler::get_present_defaults_subsection () -{ - Section* sec = &defaults; - std::vector::const_iterator SecName = subsection_path.begin(); - - while (SecName != subsection_path.end()) - { - sec = sec->subsections[*SecName]; - ++SecName; - }; - - return sec; -} - - - -const ParameterHandler::Section* ParameterHandler::get_present_defaults_subsection () const -{ - Section* sec = const_cast(&defaults); // not nice, but needs to be and - // after all: we do not change @p{sec} - std::vector::const_iterator SecName = subsection_path.begin(); - - while (SecName != subsection_path.end()) - { - sec = sec->subsections[*SecName]; - ++SecName; - }; - - return sec; -} - - - -ParameterHandler::Section* ParameterHandler::get_present_changed_subsection () -{ - Section* sec = &changed_entries; - std::vector::iterator SecName = subsection_path.begin(); - - while (SecName != subsection_path.end()) - { - sec = sec->subsections[*SecName]; - ++SecName; - }; - - return sec; -} - - - -const ParameterHandler::Section* ParameterHandler::get_present_changed_subsection () const -{ - Section* sec = const_cast(&changed_entries); // same as in get_present_default_s... - std::vector::const_iterator SecName = subsection_path.begin(); - - while (SecName != subsection_path.end()) - { - sec = sec->subsections[*SecName]; - ++SecName; - } - - return sec; -} - - - unsigned int ParameterHandler::memory_consumption () const { - return (MemoryConsumption::memory_consumption (subsection_path) + - MemoryConsumption::memory_consumption (defaults) + - MemoryConsumption::memory_consumption (changed_entries)); -} - - - -ParameterHandler::Section::~Section () -{ - // first release the memory pointed - // to by the second component of - // the pair, since we became owner - // of that memory through the - // clone() call - for (EntryType::iterator q=entries.begin(); q!=entries.end(); ++q) - delete q->second.pattern; - // then clear entire map - entries.clear (); - - std::map::iterator p; - - for (p=subsections.begin(); p!=subsections.end(); ++p) - delete p->second; - - subsections.clear (); -} - - - -unsigned int -ParameterHandler::Section:: -accumulated_no_of_entries () const -{ - // number of entries in this section - unsigned int n = entries.size(); - - // then accumulate over all children - for (std::map::const_iterator - s = subsections.begin(); - s != subsections.end(); ++s) - n += s->second->accumulated_no_of_entries(); - - return n; -} - - - -unsigned int -ParameterHandler::Section::memory_consumption () const -{ - unsigned int mem = 0; - for (EntryType::const_iterator i=entries.begin(); i!=entries.end(); ++i) - mem += (MemoryConsumption::memory_consumption (i->first) + - MemoryConsumption::memory_consumption (i->second.value) + - MemoryConsumption::memory_consumption (i->second.documentation) + - MemoryConsumption::memory_consumption (*i->second.pattern)); - for (std::map::const_iterator i=subsections.begin(); - i!=subsections.end(); ++i) - mem += (MemoryConsumption::memory_consumption (i->first) + - MemoryConsumption::memory_consumption (*(i->second))); - return mem; -} - - - -bool -ParameterHandler::Section::EntryContent:: -has_documentation () const -{ - return documentation != ""; +//TODO: add to this an estimate of the memory in the property_tree + return (MemoryConsumption::memory_consumption (subsection_path)); } @@ -1618,31 +1644,12 @@ void MultipleParameterLoop::loop (MultipleParameterLoop::UserClass &uc) void MultipleParameterLoop::init_branches () { multiple_choices.clear (); - - ParameterHandler::Section *sec; - // first check the defaults entries whether it - // contains multiple choices - sec = &defaults; - init_branches_section (*sec); - - // then check changed entries - sec = &changed_entries; - init_branches_section (*sec); + init_branches_current_section (); // split up different values for (unsigned int i=0; i 0) - for (std::vector::reverse_iterator i=multiple_choices.rbegin(); - i != multiple_choices.rend(); ++i) - if (i->different_values.size() == 1) - multiple_choices.erase (i.base()); - // finally calculate number of branches n_branches = 1; for (unsigned int i=0; isecond.value.find('{') != std::string::npos) - multiple_choices.push_back (Entry(subsection_path, - e->first, - e->second.value)); - - - // transverse subsections - std::map::const_iterator s; - for (s = sec.subsections.begin(); s != sec.subsections.end(); ++s) - { - enter_subsection (s->first); - init_branches_section (*s->second); - leave_subsection (); - }; + const boost::property_tree::ptree ¤t_section + = entries.get_child (get_current_path()); + + // check all entries in the present + // subsection whether they are + // multiple entries + // + // we loop over entries in sorted + // order to guarantee backward + // compatibility to an earlier + // implementation + for (boost::property_tree::ptree::const_assoc_iterator + p = current_section.ordered_begin(); + p != current_section.not_found(); ++p) + if (is_parameter_node (p->second) == true) + { + const std::string value = p->second.get("value"); + if (value.find('{') != std::string::npos) + multiple_choices.push_back (Entry(subsection_path, + demangle(p->first), + value)); + } + + // then loop over all subsections + for (boost::property_tree::ptree::const_iterator + p = current_section.begin(); + p != current_section.end(); ++p) + if (is_parameter_node (p->second) == false) + { + enter_subsection (demangle(p->first)); + init_branches_current_section (); + leave_subsection (); + } } + void MultipleParameterLoop::fill_entry_values (const unsigned int run_no) { - int possibilities = 1; + unsigned int possibilities = 1; std::vector::iterator choice; for (choice = multiple_choices.begin(); choice != multiple_choices.end(); ++choice) { - // temporarily enter the subsection tree - // of this multiple entry - subsection_path.swap (choice->subsection_path); - - // set entry - Section* pd = get_present_defaults_subsection (); - int selection = (run_no/possibilities) % choice->different_values.size(); + const unsigned int selection + = (run_no/possibilities) % choice->different_values.size(); std::string entry_value; if (choice->type == Entry::variant) entry_value = choice->different_values[selection]; @@ -1728,45 +1746,24 @@ void MultipleParameterLoop::fill_entry_values (const unsigned int run_no) } else entry_value = choice->different_values[run_no]; - }; + } - // check conformance with regex - if (!pd->entries[choice->entry_name].pattern->match(entry_value)) - { - std::cerr << "In run no. " << run_no+1 << ":" << std::endl - << " The entry value" << std::endl - << " " << entry_value << std::endl - << " for the entry named" << std::endl - << " " << choice->entry_name << std::endl - << " does not match the given pattern" << std::endl - << " " << pd->entries[choice->entry_name].pattern->description() << std::endl - << " Taking default value" << std::endl - << " " << pd->entries[choice->entry_name].value << std::endl; - - // select default instead - entry_value = pd->entries[choice->entry_name].value; - }; - - Section* pc = get_present_changed_subsection (); - // the following lines declare - // this entry if not yet - // existent and overwrites it - // otherwise (the pattern is - // set to a null pointer, since - // we don't need the pattern in - // the entries section -- only - // in the defaults section) - pc->entries[choice->entry_name].value = entry_value; - pc->entries[choice->entry_name].pattern = 0; - - // get out of subsection again + // temporarily enter the + // subsection tree of this + // multiple entry, set the + // value, and get out + // again. the set() operation + // also tests for the + // correctness of the value + // with regard to the pattern + subsection_path.swap (choice->subsection_path); + set (choice->entry_name, entry_value); subsection_path.swap (choice->subsection_path); // move ahead if it was a variant entry if (choice->type == Entry::variant) possibilities *= choice->different_values.size(); - }; - + } } diff --git a/tests/bits/multiple_parameter_loop_02.cc b/tests/bits/multiple_parameter_loop_02.cc index aeacc6a739..156184ade9 100644 --- a/tests/bits/multiple_parameter_loop_02.cc +++ b/tests/bits/multiple_parameter_loop_02.cc @@ -68,7 +68,7 @@ void check (const char *p) HelperClass h; h.declare_parameters (prm); - prm.read_input ("multiple_parameter_loop_02/prm"); + prm.read_input (p); prm.loop (h); } diff --git a/tests/bits/parameter_handler_12.cc b/tests/bits/parameter_handler_12.cc index 2200ea768d..daf4183137 100644 --- a/tests/bits/parameter_handler_12.cc +++ b/tests/bits/parameter_handler_12.cc @@ -1,6 +1,6 @@ //---------------------------- parameter_handler_12.cc --------------------------- // $Id$ -// Version: $Name$ +// Version: $Name$ // // Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors // @@ -25,12 +25,19 @@ void check () ParameterHandler prm; prm.declare_entry ("test_1", "3", Patterns::Integer()); - prm.set ("test_1", "3.1415"); + try + { + prm.set ("test_1", "3.1415"); + } + catch (const ParameterHandler::ExcValueDoesNotMatchPattern &) + { + deallog << "OK" << std::endl; + } deallog << "test_1=" << prm.get ("test_1") << std::endl; } -int main () +int main () { std::ofstream logfile("parameter_handler_12/output"); deallog.attach(logfile); @@ -38,6 +45,6 @@ int main () deallog.threshold_double(1.e-10); check (); - + return 0; } diff --git a/tests/bits/parameter_handler_12/cmp/generic b/tests/bits/parameter_handler_12/cmp/generic index cbd1572054..1efbe5127b 100644 --- a/tests/bits/parameter_handler_12/cmp/generic +++ b/tests/bits/parameter_handler_12/cmp/generic @@ -1,3 +1,3 @@ -DEAL::0 +DEAL::OK DEAL::test_1=3 diff --git a/tests/bits/parameter_handler_4/cmp/generic b/tests/bits/parameter_handler_4/cmp/generic index 3d8de1a31d..2ed6a5448f 100644 --- a/tests/bits/parameter_handler_4/cmp/generic +++ b/tests/bits/parameter_handler_4/cmp/generic @@ -6,7 +6,7 @@ \item {\bf Subsection Testing} \begin{itemize} \item {\bf double:} 3.1415926 (docs 3, {\it default:} 3.1415926) -\item {\bf int:} 1 ({\it default:} 3) -\item {\bf string list:} a (docs 1, {\it default:} a, b, c) +\item {\bf int:} 3 ({\it default:} 1) +\item {\bf string list:} a, b, c (docs 1, {\it default:} a) \end{itemize} \end{itemize} diff --git a/tests/bits/parameter_handler_4a/cmp/generic b/tests/bits/parameter_handler_4a/cmp/generic index 79ccd38b29..1975ec8253 100644 --- a/tests/bits/parameter_handler_4a/cmp/generic +++ b/tests/bits/parameter_handler_4a/cmp/generic @@ -6,8 +6,8 @@ \item {\bf Subsection Testing} \begin{itemize} \item {\bf double:} 3.1415926 (docs 3, {\it default:} 3.1415926) -\item {\bf int:} 1 ({\it default:} 3) -\item {\bf string list:} a (docs 1, {\it default:} a, b, c) +\item {\bf int:} 3 ({\it default:} 1) +\item {\bf string list:} a, b, c (docs 1, {\it default:} a) diff --git a/tests/bits/parameter_handler_write_json.cc b/tests/bits/parameter_handler_write_json.cc new file mode 100644 index 0000000000..e6dc31f3d2 --- /dev/null +++ b/tests/bits/parameter_handler_write_json.cc @@ -0,0 +1,80 @@ +//---------------------------- parameter_handler_write_json.cc --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- parameter_handler_write_json.cc --------------------------- + + +// check ParameterHandler::print_parameters (..., JSON). have a few +// names that contain all sorts of weird (for JSON) characters + +#include "../tests.h" +#include +#include +#include + + +int main () +{ + std::ofstream logfile("parameter_handler_write_json/output"); + deallog.attach(logfile); + deallog.depth_console(0); + deallog.threshold_double(1.e-10); + + ParameterHandler prm; + prm.declare_entry ("int1", + "1", + Patterns::Integer(), + "doc 1"); + prm.declare_entry ("int2", + "2", + Patterns::Integer(), + "doc 2"); + prm.enter_subsection ("ss1"); + { + prm.declare_entry ("double 1", + "1.234", + Patterns::Double(), + "doc 3"); + + prm.enter_subsection ("ss2"); + { + prm.declare_entry ("double 2", + "4.321", + Patterns::Double(), + "doc 4"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // things with strange characters + prm.enter_subsection ("Testing%testing"); + { + prm.declare_entry ("string&list", + "< & > ; /", + Patterns::Anything(), + "docs 1"); + prm.declare_entry ("int*int", + "2", + Patterns::Integer()); + prm.declare_entry ("double+double", + "6.1415926", + Patterns::Double(), + "docs 3"); + } + prm.leave_subsection (); + + + prm.print_parameters (logfile, ParameterHandler::JSON); + logfile << std::endl; + + return 0; +} diff --git a/tests/bits/parameter_handler_write_json/cmp/generic b/tests/bits/parameter_handler_write_json/cmp/generic new file mode 100644 index 0000000000..d8319218cd --- /dev/null +++ b/tests/bits/parameter_handler_write_json/cmp/generic @@ -0,0 +1,69 @@ + +{ + "int1": + { + "value": "1", + "default_value": "1", + "documentation": "doc 1", + "pattern": "0", + "pattern_description": "[Integer range -2147483648...2147483647 (inclusive)]" + }, + "int2": + { + "value": "2", + "default_value": "2", + "documentation": "doc 2", + "pattern": "1", + "pattern_description": "[Integer range -2147483648...2147483647 (inclusive)]" + }, + "ss1": + { + "double_201": + { + "value": "1.234", + "default_value": "1.234", + "documentation": "doc 3", + "pattern": "2", + "pattern_description": "[Floating point range -1.79769e+308...1.79769e+308 (inclusive)]" + }, + "ss2": + { + "double_202": + { + "value": "4.321", + "default_value": "4.321", + "documentation": "doc 4", + "pattern": "3", + "pattern_description": "[Floating point range -1.79769e+308...1.79769e+308 (inclusive)]" + } + } + }, + "Testing_25testing": + { + "string_26list": + { + "value": "< & > ; /", + "default_value": "< & > ; /", + "documentation": "docs 1", + "pattern": "4", + "pattern_description": "[Anything]" + }, + "int_2aint": + { + "value": "2", + "default_value": "2", + "documentation": "", + "pattern": "5", + "pattern_description": "[Integer range -2147483648...2147483647 (inclusive)]" + }, + "double_2bdouble": + { + "value": "6.1415926", + "default_value": "6.1415926", + "documentation": "docs 3", + "pattern": "6", + "pattern_description": "[Floating point range -1.79769e+308...1.79769e+308 (inclusive)]" + } + } +} + diff --git a/tests/bits/parameter_handler_write_xml.cc b/tests/bits/parameter_handler_write_xml.cc new file mode 100644 index 0000000000..8fae816af7 --- /dev/null +++ b/tests/bits/parameter_handler_write_xml.cc @@ -0,0 +1,80 @@ +//---------------------------- parameter_handler_write_xml.cc --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- parameter_handler_write_xml.cc --------------------------- + + +// check ParameterHandler::print_parameters (..., XML). have a few +// names that contain all sorts of weird (for XML) characters + +#include "../tests.h" +#include +#include +#include + + +int main () +{ + std::ofstream logfile("parameter_handler_write_xml/output"); + deallog.attach(logfile); + deallog.depth_console(0); + deallog.threshold_double(1.e-10); + + ParameterHandler prm; + prm.declare_entry ("int1", + "1", + Patterns::Integer(), + "doc 1"); + prm.declare_entry ("int2", + "2", + Patterns::Integer(), + "doc 2"); + prm.enter_subsection ("ss1"); + { + prm.declare_entry ("double 1", + "1.234", + Patterns::Double(), + "doc 3"); + + prm.enter_subsection ("ss2"); + { + prm.declare_entry ("double 2", + "4.321", + Patterns::Double(), + "doc 4"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // things with strange characters + prm.enter_subsection ("Testing%testing"); + { + prm.declare_entry ("string&list", + "< & > ; /", + Patterns::Anything(), + "docs 1"); + prm.declare_entry ("int*int", + "2", + Patterns::Integer()); + prm.declare_entry ("double+double", + "6.1415926", + Patterns::Double(), + "docs 3"); + } + prm.leave_subsection (); + + + prm.print_parameters (logfile, ParameterHandler::XML); + logfile << std::endl; + + return 0; +} diff --git a/tests/bits/parameter_handler_write_xml/cmp/generic b/tests/bits/parameter_handler_write_xml/cmp/generic new file mode 100644 index 0000000000..b749b46865 --- /dev/null +++ b/tests/bits/parameter_handler_write_xml/cmp/generic @@ -0,0 +1,4 @@ + + +11doc 10[Integer range -2147483648...2147483647 (inclusive)]22doc 21[Integer range -2147483648...2147483647 (inclusive)]1.2341.234doc 32[Floating point range -1.79769e+308...1.79769e+308 (inclusive)]4.3214.321doc 43[Floating point range -1.79769e+308...1.79769e+308 (inclusive)]< & > ; /< & > ; /docs 14[Anything]22 +5[Integer range -2147483648...2147483647 (inclusive)]6.14159266.1415926docs 36[Floating point range -1.79769e+308...1.79769e+308 (inclusive)] -- 2.39.5