* 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",
* 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 = "");
* Parse input from a string to populate known parameter fields. The lines
* in the string must be separated by <tt>@\n</tt> 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 = "");
* 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<void (const std::string &value)> &action);
AssertThrow (input, ExcIO());
// store subsections we are currently in
- std::vector<std::string> saved_path = subsection_path;
+ const std::vector<std::string> saved_path = subsection_path;
std::string input_line;
std::string fully_concatenated_line;
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;
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)
{