changeset 27930:ea1898178973

simplify handling of temporary output buffer in evalc * oct-parse.yy (Fevalc): Use stringbuf instead of stringstream. Eliminate unnecessary try/catch block around call to Feval. Use single unwind_action object to restore previous output buffers for octave_stdout and std::cerr. (restore_octave_stdout, restore_octave_stderr): Delete.
author John W. Eaton <jwe@octave.org>
date Fri, 10 Jan 2020 14:19:28 -0500
parents 265b386f8b20
children 0fa21907e54c
files libinterp/parse-tree/oct-parse.yy
diffstat 1 files changed, 30 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/oct-parse.yy	Fri Jan 10 12:10:13 2020 -0800
+++ b/libinterp/parse-tree/oct-parse.yy	Fri Jan 10 14:19:28 2020 -0500
@@ -5489,20 +5489,6 @@
   return interp.evalin (context, try_code, nargout);
 }
 
-static void
-restore_octave_stdout (std::streambuf *buf)
-{
-  octave_stdout.flush ();
-  octave_stdout.rdbuf (buf);
-}
-
-static void
-restore_octave_stderr (std::streambuf *buf)
-{
-  std::cerr.flush ();
-  std::cerr.rdbuf (buf);
-}
-
 DEFMETHOD (evalc, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{s} =} evalc (@var{try})
@@ -5532,44 +5518,44 @@
 @seealso{eval, diary}
 @end deftypefn */)
 {
-  octave_value_list retval;
-
   int nargin = args.length ();
 
   if (nargin == 0 || nargin > 2)
     print_usage ();
 
-  // redirect stdout/stderr to capturing buffer
-  std::ostringstream buffer;
-
-  std::ostream& out_stream = octave_stdout;
-  std::ostream& err_stream = std::cerr;
-
-  out_stream.flush ();
-  err_stream.flush ();
-
-  std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ());
-  std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ());
-
-  octave::unwind_protect frame;
-
-  frame.add_fcn (restore_octave_stdout, old_out_buf);
-  frame.add_fcn (restore_octave_stderr, old_err_buf);
-
-  // call standard eval function
+  // Flush pending output and redirect stdout/stderr to capturing
+  // buffer.
+
+  octave_stdout.flush ();
+  std::cerr.flush ();
+
+  std::stringbuf buffer;
+
+  std::streambuf *old_out_buf = octave_stdout.rdbuf (&buffer);
+  std::streambuf *old_err_buf = std::cerr.rdbuf (&buffer);
+
+  // Restore previous output buffers no matter how control exits this
+  // function.  There's no need to flush here.  That has already
+  // happened for the normal execution path.  If an error happens during
+  // the eval, then the message is stored in the exception object and we
+  // will display it later, after the buffers have been restored.
+
+  octave::unwind_action act ([old_out_buf, old_err_buf] (void)
+                             {
+                               octave_stdout.rdbuf (old_out_buf);
+                               std::cerr.rdbuf (old_err_buf);
+                             });
+
+  // Call standard eval function.
 
   int eval_nargout = std::max (0, nargout - 1);
 
-  try
-    {
-      retval = Feval (interp, args, eval_nargout);
-    }
-  catch (const octave::execution_exception& ee)
-    {
-      buffer << "error: " << ee.message () << std::endl;
-
-      throw;
-    }
+  octave_value_list retval = Feval (interp, args, eval_nargout);
+
+  // Make sure we capture all pending output.
+
+  octave_stdout.flush ();
+  std::cerr.flush ();
 
   retval.prepend (buffer.str ());