changeset 11368:944b7e20fc5a

improve handling of exceptions for startup files
author John W. Eaton <jwe@octave.org>
date Wed, 15 Dec 2010 02:05:27 -0500
parents b2191ebea12f
children 52907ec4aa44
files liboctave/ChangeLog liboctave/cmd-hist.cc liboctave/cmd-hist.h src/ChangeLog src/oct-hist.cc src/octave.cc
diffstat 6 files changed, 239 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Wed Dec 15 00:44:10 2010 -0500
+++ b/liboctave/ChangeLog	Wed Dec 15 02:05:27 2010 -0500
@@ -1,3 +1,21 @@
+2010-12-15  John W. Eaton  <jwe@octave.org>
+
+	* cmd-hist.cc (command_history::do_clean_up_and_save,
+	command_history::do_truncate_file,
+	command_history::do_append, command_history::do_write,
+	gnu_history::do_clean_up_and_save, gnu_history::do_truncate_file,
+	gnu_history::do_append, gnu_history::do_write,
+	gnu_history::do_read_range):
+	Don't do anything if not initialized.
+
+	* cmd-hist.cc, cmd-hist.h (command_history::initialize,
+	command_history::is_initialized): New static functions.
+	(command_history::do_initialize,
+	command_history::do_is_initialized): New member functions.
+
+	* cmd-hist.h (command_history::initialized): New data member.
+	(comand_history::command_history): Initialize it.
+
 2010-12-14  John W. Eaton  <jwe@octave.org>
 
 	* lo-mappers.h (xcopysign (double)): Call copysign, not copysignf.
--- a/liboctave/cmd-hist.cc	Wed Dec 15 00:44:10 2010 -0500
+++ b/liboctave/cmd-hist.cc	Wed Dec 15 02:05:27 2010 -0500
@@ -253,60 +253,66 @@
 void
 gnu_history::do_write (const std::string& f_arg)
 {
-  std::string f = f_arg;
-
-  if (f.empty ())
-    f = xfile;
-
-  if (! f.empty ())
+  if (initialized)
     {
-      int status = ::octave_write_history (f.c_str ());
+      std::string f = f_arg;
+
+      if (f.empty ())
+        f = xfile;
 
-      if (status != 0)
-        error (status);
+      if (! f.empty ())
+        {
+          int status = ::octave_write_history (f.c_str ());
+
+          if (status != 0)
+            error (status);
+        }
+      else
+        error ("gnu_history::write: missing file name");
     }
-  else
-    error ("gnu_history::write: missing file name");
 }
 
 void
 gnu_history::do_append (const std::string& f_arg)
 {
-  if (lines_this_session)
+  if (initialized)
     {
-      if (lines_this_session < do_where ())
+      if (lines_this_session)
         {
-          // Create file if it doesn't already exist.
-
-          std::string f = f_arg;
+          if (lines_this_session < do_where ())
+            {
+              // Create file if it doesn't already exist.
 
-          if (f.empty ())
-            f = xfile;
+              std::string f = f_arg;
 
-          if (! f.empty ())
-            {
-              file_stat fs (f);
+              if (f.empty ())
+                f = xfile;
 
-              if (! fs)
+              if (! f.empty ())
                 {
-                  int tem;
+                  file_stat fs (f);
 
-                  tem = gnulib::open (f.c_str (), O_CREAT, 0666);
-                  gnulib::close (tem);
-                }
+                  if (! fs)
+                    {
+                      int tem;
 
-              int status
-                = ::octave_append_history (lines_this_session, f.c_str ());
+                      tem = gnulib::open (f.c_str (), O_CREAT, 0666);
+                      gnulib::close (tem);
+                    }
 
-              if (status != 0)
-                error (status);
-              else
-                lines_in_file += lines_this_session;
+                  int status
+                    = ::octave_append_history (lines_this_session, f.c_str ());
 
-              lines_this_session = 0;
+                  if (status != 0)
+                    error (status);
+                  else
+                    lines_in_file += lines_this_session;
+
+                  lines_this_session = 0;
+                }
+              else
+                error ("gnu_history::append: missing file name");
             }
-          else
-            error ("gnu_history::append: missing file name");
         }
     }
 }
@@ -314,15 +320,18 @@
 void
 gnu_history::do_truncate_file (const std::string& f_arg, int n)
 {
-  std::string f = f_arg;
-
-  if (f.empty ())
-    f = xfile;
+  if (initialized)
+    {
+      std::string f = f_arg;
 
-  if (! f.empty ())
-    ::octave_history_truncate_file (f.c_str (), n);
-  else
-    error ("gnu_history::truncate_file: missing file name");
+      if (f.empty ())
+        f = xfile;
+
+      if (! f.empty ())
+        ::octave_history_truncate_file (f.c_str (), n);
+      else
+        error ("gnu_history::truncate_file: missing file name");
+    }
 }
 
 string_vector
@@ -358,22 +367,25 @@
 void
 gnu_history::do_clean_up_and_save (const std::string& f_arg, int n)
 {
-  std::string f = f_arg;
-
-  if (f.empty ())
-    f = xfile;
-
-  if (! f.empty ())
+  if (initialized)
     {
-      if (n < 0)
-        n = xsize;
+      std::string f = f_arg;
 
-      stifle (n);
+      if (f.empty ())
+        f = xfile;
 
-      do_write (f.c_str ());
+      if (! f.empty ())
+        {
+          if (n < 0)
+            n = xsize;
+
+          stifle (n);
+
+          do_write (f.c_str ());
+        }
+      else
+        error ("gnu_history::clean_up_and_save: missing file name");
     }
-  else
-    error ("gnu_history::clean_up_and_save: missing file name");
 }
 
 #endif
@@ -408,6 +420,22 @@
 }
 
 void
+command_history::initialize (bool read_history_file,
+                             const std::string& f_arg, int sz)
+{
+  if (instance_ok ())
+    instance->do_initialize (read_history_file, f_arg, sz);
+}
+
+bool
+command_history::is_initialized (void)
+{
+  // We just want to check the status of an existing instance, not
+  // create one.
+  return instance && instance->do_is_initialized ();
+}
+
+void
 command_history::set_file (const std::string& f_arg)
 {
   if (instance_ok ())
@@ -614,6 +642,25 @@
 }
 
 void
+command_history::do_initialize (bool read_history_file,
+                                const std::string& f_arg, int sz)
+{
+  command_history::set_file (f_arg);
+  command_history::set_size (sz);
+
+  if (read_history_file)
+    command_history::read (false);
+
+  initialized = true;
+}
+
+bool
+command_history::do_is_initialized (void) const
+{
+  return initialized;
+}
+
+void
 command_history::do_set_file (const std::string& f)
 {
   xfile = f;
@@ -734,31 +781,37 @@
 void
 command_history::do_write (const std::string& f_arg)
 {
-  std::string f = f_arg;
+  if (initialized)
+    {
+      std::string f = f_arg;
 
-  if (f.empty ())
-    f = xfile;
+      if (f.empty ())
+        f = xfile;
 
-  if (f.empty ())
-    error ("command_history::write: missing file name");
+      if (f.empty ())
+        error ("command_history::write: missing file name");
+    }
 }
 
 void
 command_history::do_append (const std::string& f_arg)
 {
-  if (lines_this_session)
+  if (initialized)
     {
-      if (lines_this_session < do_where ())
+      if (lines_this_session)
         {
-          // Create file if it doesn't already exist.
+          if (lines_this_session < do_where ())
+            {
+              // Create file if it doesn't already exist.
 
-          std::string f = f_arg;
+              std::string f = f_arg;
 
-          if (f.empty ())
-            f = xfile;
+              if (f.empty ())
+                f = xfile;
 
-          if (f.empty ())
-            error ("command_history::append: missing file name");
+              if (f.empty ())
+                error ("command_history::append: missing file name");
+            }
         }
     }
 }
@@ -766,13 +819,16 @@
 void
 command_history::do_truncate_file (const std::string& f_arg, int)
 {
-  std::string f = f_arg;
+  if (initialized)
+    {
+      std::string f = f_arg;
 
-  if (f.empty ())
-    f = xfile;
+      if (f.empty ())
+        f = xfile;
 
-  if (f.empty ())
-    error ("command_history::truncate_file: missing file name");
+      if (f.empty ())
+        error ("command_history::truncate_file: missing file name");
+    }
 }
 
 string_vector
@@ -795,13 +851,16 @@
 void
 command_history::do_clean_up_and_save (const std::string& f_arg, int)
 {
-  std::string f = f_arg;
+  if (initialized)
+    {
+      std::string f = f_arg;
 
-  if (f.empty ())
-    f = xfile;
+      if (f.empty ())
+        f = xfile;
 
-  if (f.empty ())
-    error ("command_history::clean_up_and_save: missing file name");
+      if (f.empty ())
+        error ("command_history::clean_up_and_save: missing file name");
+    }
 }
 
 void
--- a/liboctave/cmd-hist.h	Wed Dec 15 00:44:10 2010 -0500
+++ b/liboctave/cmd-hist.h	Wed Dec 15 02:05:27 2010 -0500
@@ -34,13 +34,17 @@
 protected:
 
   command_history (void)
-    : ignoring_additions (false), lines_in_file (0),
+    : initialized (false), ignoring_additions (false), lines_in_file (0),
       lines_this_session (0), xfile (), xsize (-1) { }
 
 public:
 
   virtual ~command_history (void) { }
 
+  static void initialize (bool, const std::string&, int);
+
+  static bool is_initialized (void);
+
   static void set_file (const std::string&);
 
   static std::string file (void);
@@ -128,6 +132,10 @@
 
   virtual std::string do_file (void);
 
+  virtual void do_initialize (bool, const std::string&, int);
+
+  virtual bool do_is_initialized (void) const;
+
   virtual void do_set_size (int);
 
   virtual int do_size (void);
@@ -182,6 +190,10 @@
 
   void error (const std::string&);
 
+  // TRUE means we have initialized the history file name and number of
+  // lines to save.
+  bool initialized;
+
   // TRUE means we are ignoring new additions.
   bool ignoring_additions;
 
--- a/src/ChangeLog	Wed Dec 15 00:44:10 2010 -0500
+++ b/src/ChangeLog	Wed Dec 15 02:05:27 2010 -0500
@@ -1,3 +1,13 @@
+2010-12-15  John W. Eaton  <jwe@octave.org>
+
+	* oct-hist.cc (initialize_history): Call command_history::initialize.
+
+	* octave.cc (gripe_safe_source_exception): New function.
+	(safe_source_file): New function.
+	(execute_startup_files): Call safe_source_file instead of source_file.
+	(execute_command_line_file): Likewise.  Don't handle exceptions here.
+	(execute_eval_option_code): Also catch octave_execution	exception.
+
 2010-12-15  John W. Eaton  <jwe@octave.org>
 
 	* lex.h (lexical_feedback::defining_func): Now int instead of bool.
--- a/src/oct-hist.cc	Wed Dec 15 00:44:10 2010 -0500
+++ b/src/oct-hist.cc	Wed Dec 15 02:05:27 2010 -0500
@@ -520,11 +520,7 @@
 void
 initialize_history (bool read_history_file)
 {
-  command_history::set_file (Vhistory_file);
-  command_history::set_size (Vhistory_size);
-
-  if (read_history_file)
-    command_history::read (false);
+  command_history::initialize (read_history_file, Vhistory_file, Vhistory_size);
 }
 
 void
--- a/src/octave.cc	Wed Dec 15 00:44:10 2010 -0500
+++ b/src/octave.cc	Wed Dec 15 02:05:27 2010 -0500
@@ -275,6 +275,51 @@
   F__version_info__ (args, 0);
 }
 
+static void
+gripe_safe_source_exception (const std::string& file, const std::string& msg)
+{
+  std::cerr << "error: " << msg << "\n"
+            << "error: execution of " << file << " failed\n"
+            << "error: trying to make my way to a command prompt"
+            << std::endl;
+}
+
+// Execute commands from a file and catch potential exceptions in a
+// consistent way.  This function should be called anywhere we might
+// parse and execute commands from a file before before we have entered
+// the main loop in toplev.cc.
+
+static void
+safe_source_file (const std::string& file_name,
+                  const std::string& context = std::string (),
+                  bool verbose = false, bool require_file = true,
+                  const std::string& warn_for = std::string ())
+{
+  try
+    {
+      source_file (file_name, context, verbose, require_file, warn_for);
+    }
+  catch (octave_interrupt_exception)
+    {
+      recover_from_exception ();
+      octave_stdout << "\n";
+      if (quitting_gracefully)
+        clean_up_and_exit (exit_status);
+    }
+  catch (octave_execution_exception)
+    {
+      recover_from_exception ();
+      gripe_safe_source_exception (file_name, "unhandled execution exception");
+    }
+  catch (std::bad_alloc)
+    {
+      recover_from_exception ();
+      gripe_safe_source_exception
+        (file_name,
+         "memory exhausted or requested size too large for range of Octave's index type");
+    }
+}
+
 // Initialize by reading startup files.
 
 static void
@@ -299,9 +344,10 @@
       // (if it exists), then from the file
       // $(prefix)/share/octave/$(version)/m/octaverc (if it exists).
 
-      source_file (Vlocal_site_defaults_file, context, verbose, require_file);
+      safe_source_file (Vlocal_site_defaults_file, context, verbose,
+                        require_file);
 
-      source_file (Vsite_defaults_file, context, verbose, require_file);
+      safe_source_file (Vsite_defaults_file, context, verbose, require_file);
     }
 
   if (read_init_files)
@@ -325,7 +371,7 @@
 
       if (! home_rc.empty ())
         {
-          source_file (home_rc, context, verbose, require_file);
+          safe_source_file (home_rc, context, verbose, require_file);
 
           // Names alone are not enough.
 
@@ -347,7 +393,7 @@
           if (local_rc.empty ())
             local_rc = octave_env::make_absolute (initfile);
 
-          source_file (local_rc, context, verbose, require_file);
+          safe_source_file (local_rc, context, verbose, require_file);
         }
     }
 }
@@ -386,6 +432,12 @@
       if (quitting_gracefully)
         clean_up_and_exit (exit_status);
     }
+  catch (octave_execution_exception)
+    {
+      recover_from_exception ();
+      std::cerr << "error: unhandled execution exception -- eval failed"
+                << std::endl;
+    }
   catch (std::bad_alloc)
     {
       std::cerr << "error: memory exhausted or requested size too large for range of Octave's index type -- eval failed"
@@ -438,26 +490,11 @@
 
   octave_program_name = tmp;
 
-  try
-    {
-      std::string context;
-      bool verbose = false;
-      bool require_file = true;
+  std::string context;
+  bool verbose = false;
+  bool require_file = true;
 
-      source_file (fname, context, verbose, require_file, "octave");
-    }
-  catch (octave_interrupt_exception)
-    {
-      recover_from_exception ();
-      octave_stdout << "\n";
-      if (quitting_gracefully)
-        clean_up_and_exit (exit_status);
-    }
-  catch (std::bad_alloc)
-    {
-      std::cerr << "error: memory exhausted or requested size too large for range of Octave's index type -- execution of "
-                << fname << " failed" << std::endl;
-    }
+  safe_source_file (fname, context, verbose, require_file, "octave");
 }
 
 // Usage message with extra help.