]> https://gitweb.dealii.org/ - dealii.git/commitdiff
fix ParameterHandler::leave_subsection and parsing 455/head
authorTimo Heister <timo.heister@gmail.com>
Mon, 19 Jan 2015 13:07:28 +0000 (08:07 -0500)
committerTimo Heister <timo.heister@gmail.com>
Mon, 19 Jan 2015 21:47:40 +0000 (16:47 -0500)
- leave_subsection() had a bool return value for success that doesn't
make sense because an Assert() would never allow false to be returned.
Remove this.
- read_input() would not complain about unbalanced 'subsection'/'end' in
the input. Instead, the ParameterHandler would just stay in that
subsection and so weird error messages about undefined entries would
show up later.
- One could argue that read_input() should always start and end with an
empty subsection path, but we didn't enforce this in the past and it
might be useful to read separate files not into the "top level".

doc/news/changes.h
include/deal.II/base/parameter_handler.h
source/base/parameter_handler.cc
tests/bits/parameter_handler_19.cc [new file with mode: 0644]
tests/bits/parameter_handler_19.debug.output [new file with mode: 0644]

index 348d5817a4a6072f779e9488fbb4e6def5478386..9b0d93dd259fa9718e52e5b879c40929e66a1ec9 100644 (file)
@@ -38,6 +38,13 @@ inconvenience this causes.
 </p>
 
 <ol>
+  <li> Changed: ParameterHandler::leave_subsection() no longer returns a bool
+  indicating if there was a subsection to leave. This never worked in the
+  first place, because an exception was thrown.
+  <br>
+  (Timo Heister, 2015/01/19)
+  </li>
+  
   <li> Changed: Make.global_options was completely redesigned. It still
   contains Makefile sourcable information, but they now closely mimic the
   declarative style of deal.IIConfig.cmake. Thus, projects that still use
@@ -239,6 +246,12 @@ inconvenience this causes.
 <h3>Specific improvements</h3>
 
 <ol>
+  <li> Fixed: ParameterHandler::read_input() now checks that
+  'subsection'/'end' are balanced in the input.
+  <br>
+  (Timo Heister, 2015/01/19)
+  </li>
+
   <li> Fixed: In 3d, when you set the <code>colorize</code> flag of
   GridGenerator::hyper_shell(), the faces of the domain were colored but
   the edges were not. This was an oversight because to refine correctly,
index 1f3639c17a151dddc538f022ee15d1fb54387376..68ed0b91b2ce6631a79fdece0e8122b08c7160fe 100644 (file)
@@ -1653,10 +1653,9 @@ public:
   void enter_subsection (const std::string &subsection);
 
   /**
-   * Leave present subsection. Return <tt>false</tt> if there is no subsection
-   * to leave; <tt>true</tt> otherwise.
+   * Leave present subsection.
    */
-  bool leave_subsection ();
+  void leave_subsection ();
 
   /**
    * Return value of entry <tt>entry_string</tt>.  If the entry was changed,
index fb42ac87a0d6019180703f28fb637343c1d41edf..03f3f35adbc09ed0a0c18c96e3742aa173883900 100644 (file)
@@ -1317,6 +1317,9 @@ bool ParameterHandler::read_input (std::istream &input,
 {
   AssertThrow (input, ExcIO());
 
+  // store subsections we are currently in
+  std::vector<std::string> saved_path = subsection_path;
+
   std::string line;
   int lineno=0;
   bool status = true;
@@ -1327,6 +1330,27 @@ bool ParameterHandler::read_input (std::istream &input,
       status &= scan_line (line, filename, lineno);
     }
 
+  if (status && (saved_path != subsection_path))
+    {
+      std::cerr << "Unbalanced 'subsection'/'end' in file <" << filename
+                << ">." << std::endl;
+      if (saved_path.size()>0)
+        {
+          std::cerr << "Path before loading input:" << std::endl;
+          for (unsigned int i=0; i<saved_path.size(); ++i)
+            std::cerr << std::setw(i*2+4) << " "
+                      << "subsection " << saved_path[i] << std::endl;
+        }
+      std::cerr << "Current path:" << std::endl;
+      for (unsigned int i=0; i<subsection_path.size(); ++i)
+        std::cerr << std::setw(i*2+4) << " "
+                  << "subsection " << subsection_path[i] << std::endl;
+
+      // restore subsection we started with and return failure:
+      subsection_path = saved_path;
+      return false;
+    }
+
   return status;
 }
 
@@ -1601,21 +1625,14 @@ void ParameterHandler::enter_subsection (const std::string &subsection)
 
 
 
-bool ParameterHandler::leave_subsection ()
+void ParameterHandler::leave_subsection ()
 {
   // assert there is a subsection that
   // we may leave
-  // (use assert since this is a logical
-  // error in a program. When reading input
-  // the scan_line function has to check
-  // whether there is a subsection to be left!)
   Assert (subsection_path.size() != 0, ExcAlreadyAtTopLevel());
 
-  if (subsection_path.size() == 0)
-    return false;
-
-  subsection_path.pop_back ();
-  return true;
+  if (subsection_path.size() > 0)
+    subsection_path.pop_back ();
 }
 
 
@@ -2434,7 +2451,11 @@ ParameterHandler::scan_line (std::string         line,
           return false;
         }
       else
-        return leave_subsection ();
+        {
+          leave_subsection ();
+          return true;
+        }
+
     }
 
   // regular entry
diff --git a/tests/bits/parameter_handler_19.cc b/tests/bits/parameter_handler_19.cc
new file mode 100644 (file)
index 0000000..ff66fa7
--- /dev/null
@@ -0,0 +1,109 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2002 - 2014 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// ParameterHandler does not complain if you parse input that doesn't close
+// all subsections.
+
+
+#include "../tests.h"
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/parameter_handler.h>
+#include <fstream>
+
+void check ()
+{
+
+  ParameterHandler prm;
+  prm.declare_entry ("dim", "3",Patterns::Integer());
+  prm.enter_subsection("test");
+  prm.declare_entry ("x", "1",Patterns::Integer());
+  prm.leave_subsection();
+  prm.enter_subsection("test2");
+  prm.declare_entry ("y", "1",Patterns::Integer());
+  prm.leave_subsection();
+
+
+  deallog << "* no subsection to leave: " << std::endl;
+  try
+    {
+      prm.leave_subsection();
+    }
+  catch (std::exception &e)
+    {
+      deallog << "Exception " << e.what() << std::endl;
+    }
+
+
+
+  deallog << std::endl << "* read_input with missing 'end':" << std::endl;
+
+  std::string s = "set dim=2\nsubsection test\n\n"; // note: missing "end"
+  bool success = prm.read_input_from_string (s.c_str());
+  deallog << "success? " << success << " (should fail)" << std::endl;
+
+  // make sure read_input resets the current path:
+  try
+    {
+      prm.leave_subsection();
+      deallog << "error, why could we leave a subsection?" << std::endl;
+    }
+  catch (std::exception &e)
+    {
+      deallog << "Exception " << e.what() << std::endl;
+    }
+
+
+
+  deallog << std::endl << "* Check non empty path before read_input()" << std::endl;
+
+  {
+    prm.enter_subsection("test");
+    std::string s = "set x=5\n";
+    bool success = prm.read_input_from_string (s.c_str());
+    deallog << "success? "
+           << success
+           << " (should work), x correct? "
+           << (prm.get_integer("x")==5) << std::endl;
+    prm.leave_subsection();
+  }
+
+
+  deallog << std::endl << "* Check read_input() catches messing with path:" << std::endl;
+  {
+    prm.enter_subsection("test");
+    std::string s = "end\nsubsection test2\nset y=7\n";
+    bool success = prm.read_input_from_string (s.c_str());
+    deallog << "success = " << success << " -- (should fail)" << std::endl;
+    prm.leave_subsection();
+  }
+
+}
+
+
+int main ()
+{
+  deal_II_exceptions::disable_abort_on_exception();
+
+  std::ofstream logfile("output");
+  deallog.attach(logfile);
+  deallog.depth_console(0);
+  deallog.threshold_double(1.e-10);
+
+  check ();
+
+  return 0;
+}
diff --git a/tests/bits/parameter_handler_19.debug.output b/tests/bits/parameter_handler_19.debug.output
new file mode 100644 (file)
index 0000000..c80e0cd
--- /dev/null
@@ -0,0 +1,35 @@
+
+DEAL::* no subsection to leave: 
+DEAL::Exception 
+--------------------------------------------------------
+An error occurred in file <parameter_handler.cc> in function
+    void dealii::ParameterHandler::leave_subsection()
+The violated condition was: 
+    subsection_path.size() != 0
+The name and call sequence of the exception was:
+    ExcAlreadyAtTopLevel()
+Additional Information: 
+(none)
+--------------------------------------------------------
+
+DEAL::
+DEAL::* read_input with missing 'end':
+DEAL::success? 0 (should fail)
+DEAL::Exception 
+--------------------------------------------------------
+An error occurred in file <parameter_handler.cc> in function
+    void dealii::ParameterHandler::leave_subsection()
+The violated condition was: 
+    subsection_path.size() != 0
+The name and call sequence of the exception was:
+    ExcAlreadyAtTopLevel()
+Additional Information: 
+(none)
+--------------------------------------------------------
+
+DEAL::
+DEAL::* Check non empty path before read_input()
+DEAL::success? 1 (should work), x correct? 1
+DEAL::
+DEAL::* Check read_input() catches messing with path:
+DEAL::success = 0 -- (should fail)

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.