From: Wolfgang Bangerth Date: Fri, 21 Apr 2017 23:30:27 +0000 (-0600) Subject: Provide some guarantees with regard to exceptions. X-Git-Tag: v9.0.0-rc1~1655^2~2 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95251b5db4d66ddcad83ccb5915719572749bfe8;p=dealii.git Provide some guarantees with regard to exceptions. --- diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index f2d2241901..739386d8f0 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -1744,6 +1744,23 @@ public: * If non-empty @p last_line is provided, the ParameterHandler object * will stop parsing lines after encountering @p last_line . * This is handy when adding extra data that shall be parsed manually. + * + * The function sets the value of all parameters it encounters in the + * input file to the provided value. Parameters not explicitly listed + * in the input file are left at the value they previously held, which + * will be the default value provided to declare_entry() unless one + * has previously read a different input file. + * + * Each parameter value is matched against the pattern for this + * parameter that was provided to declare_entry(), and for each parameter + * all associated actions that may previously have been set by + * add_action() are executed. If a parameter does not satisfy its + * pattern, or if an associated action throws an exception, then the + * value provided for the parameter is not set and the current + * object reverts to the subsection it was in before the current + * function was called. No further processing of the input stream + * occurs, that is everything that comes after the parameter whose + * value does not satisfy its pattern is ignored. */ virtual void parse_input (std::istream &input, const std::string &filename = "input file", @@ -1753,9 +1770,9 @@ public: * Parse the given file to provide values for known parameter fields. The * PathSearch class "PARAMETERS" is used to find the file. * - * If non-empty @p last_line is provided, the ParameterHandler object - * will stop parsing lines after encountering @p last_line . - * This is handy when adding extra data that shall be parsed manually. + * The function in essence reads the entire file into a stream and + * then calls the other parse_input() function with that stream. See + * there for more information. */ virtual void parse_input (const std::string &filename, const std::string &last_line = ""); @@ -1764,9 +1781,9 @@ public: * Parse input from a string to populate known parameter fields. The lines * in the string must be separated by @\n characters. * - * If non-empty @p last_line is provided, the ParameterHandler object - * will stop parsing lines after encountering @p last_line . - * This is handy when adding extra data that shall be parsed manually. + * The function in essence reads the entire file into a stream and + * then calls the other parse_input() function with that stream. See + * there for more information. */ virtual void parse_input_from_string (const char *s, const std::string &last_line = ""); @@ -1843,6 +1860,14 @@ public: * there is no guarantee about the order in which they will be read * from an input file, you will not want to rely on the values these * functions would return. + * + * @note Throwing an exception in an action is generally not a good + * idea, but yields fundamentally the same result as if one tries to + * read a parameter from a file for which the value does not satisfy + * the pattern associated with the parameter. In other words, the + * value just read is discarded, and ParameterHandler::parse_input() + * stops to read any further content from the file. See + * ParameterHandler::parse_input() for more information. */ void add_action (const std::string &entry, const std::function &action); diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index c072193074..9573cbee36 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -1620,7 +1620,7 @@ void ParameterHandler::parse_input (std::istream &input, AssertThrow (input, ExcIO()); // store subsections we are currently in - std::vector saved_path = subsection_path; + const std::vector saved_path = subsection_path; std::string input_line; std::string fully_concatenated_line; @@ -1631,6 +1631,39 @@ void ParameterHandler::parse_input (std::istream &input, unsigned int current_line_n = 0; unsigned int current_logical_line_n = 0; + // define an action that tries to scan a line. + // + // if that fails, i.e., if scan_line throws + // an exception either because a parameter doesn't match its + // pattern or because an associated action throws an exception, + // then try to rewind the set of subsections to the same + // point where we were when the current function was called. + // this at least allows to read parameters from a predictable + // state, rather than leave the subsection stack in some + // unknown state. + // + // after unwinding the subsection stack, just re-throw the exception + auto scan_line_or_cleanup = + [this, &saved_path](const std::string &line, + const std::string &filename, + const unsigned int line_number) + { + try + { + scan_line (line, filename, line_number); + } + catch (...) + { + while ((saved_path != subsection_path) + && + (subsection_path.size() > 0)) + leave_subsection (); + + throw; + } + }; + + while (std::getline (input, input_line)) { ++current_line_n; @@ -1672,17 +1705,21 @@ void ParameterHandler::parse_input (std::istream &input, if (!is_concatenated) { - scan_line (fully_concatenated_line, filename, current_logical_line_n); + scan_line_or_cleanup (fully_concatenated_line, + filename, + current_logical_line_n); + fully_concatenated_line.clear(); } } // While it does not make much sense for anyone to actually do this, allow - // the last line to end in a backslash. + // the last line to end in a backslash. to do do, we need to parse + // whatever was left in the stash of concatenated lines if (is_concatenated) - { - scan_line (fully_concatenated_line, filename, current_line_n); - } + scan_line_or_cleanup (fully_concatenated_line, + filename, + current_line_n); if (saved_path != subsection_path) {