changeset 21075:5ed379c8decd

Add new function evalc to core. * NEWS: Announce new function. * eval.txi: Add DOCSTRING to manual. * pager.cc (Fdiary): Add seealso link to evalc. * __unimplemented__.m: Remove evalc from list of unimplemented fcns. * oct-parse.in.yy (Fevalc): New function with BIST tests. * oct-parse.in.yy (Feval): Add seealso link to evalc.
author Oliver Heimlich <oheim@posteo.de>
date Fri, 15 Jan 2016 09:19:46 -0800
parents 9ff2ae6cd5b0
children b433f9990452
files NEWS doc/interpreter/eval.txi libinterp/corefcn/pager.cc libinterp/parse-tree/oct-parse.in.yy scripts/help/__unimplemented__.m
diffstat 5 files changed, 156 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Jan 14 16:56:46 2016 -0500
+++ b/NEWS	Fri Jan 15 09:19:46 2016 -0800
@@ -61,6 +61,7 @@
  ** Other new functions added in 4.2:
 
       deg2rad
+      evalc
       hash
       im2double
       psi
@@ -96,12 +97,11 @@
       java_debug              read_readline_init_file
       java_invoke             saving_history
 
- ** The global error_state variable in Octave's C++ API has been
-    deprecated and will be removed in a future version.  Now the error
-    and print_usage functions throw an exception
-    (octave_execution_exception) after displaying the error message.
-    This makes the error and print_usage functions in C++ work more like
-    the corresponding functions in the scripting language.
+ ** The global error_state variable in Octave's C++ API has been deprecated
+    and will be removed in a future version.  Now the error and print_usage
+    functions throw an exception (octave_execution_exception) after displaying
+    the error message.  This makes the error and print_usage functions in C++
+    work more like the corresponding functions in the scripting language.
 
  ** The default error handlers in liboctave have been updated to use
     exceptions.  After displaying an error message they no longer return
@@ -109,12 +109,11 @@
     customized through the global variables "current_liboctave_error_handler"
     and "current_liboctave_error_with_id_handler".  If a programmer has
     installed their own custom error handling routines when directly linking
-    with liboctave then these must be updated to throw an exception and
-    not return to the calling program. 
+    with liboctave then these must be updated to throw an exception and not
+    return to the calling program. 
 
- ** New configure option, --enable-address-sanitizer-flags, to build
-    Octave with memory allocator checks (similar to those provided by
-    valgrind) built in.
+ ** New configure option, --enable-address-sanitizer-flags, to build Octave
+    with memory allocator checks (similar to those in valgrind) built in.
 
 Summary of important user-visible changes for version 4.0:
 ---------------------------------------------------------
--- a/doc/interpreter/eval.txi	Thu Jan 14 16:56:46 2016 -0500
+++ b/doc/interpreter/eval.txi	Fri Jan 15 09:19:46 2016 -0800
@@ -29,6 +29,11 @@
 
 @DOCSTRING(eval)
 
+The @code{evalc} function additionally captures any console output
+produced by the evaluated expression.
+
+@DOCSTRING(evalc)
+
 @menu
 * Calling a Function by its Name::
 * Evaluation in a Different Context::
--- a/libinterp/corefcn/pager.cc	Thu Jan 14 16:56:46 2016 -0500
+++ b/libinterp/corefcn/pager.cc	Fri Jan 15 09:19:46 2016 -0800
@@ -528,7 +528,7 @@
 @end table\n\
 \n\
 With no arguments, @code{diary} toggles the current diary state.\n\
-@seealso{history}\n\
+@seealso{history, evalc}\n\
 @end deftypefn")
 {
   int nargin = args.length ();
--- a/libinterp/parse-tree/oct-parse.in.yy	Thu Jan 14 16:56:46 2016 -0500
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri Jan 15 09:19:46 2016 -0800
@@ -3,6 +3,7 @@
 Copyright (C) 1993-2015 John W. Eaton
 Copyright (C) 2009 David Grundberg
 Copyright (C) 2009-2010 VZLU Prague
+Copyright (C) 2016 Oliver Heimlich
 
 This file is part of Octave.
 
@@ -5001,7 +5002,7 @@
 Consider using try/catch blocks or unwind_protect/unwind_protect_cleanup\n\
 blocks instead.  These techniques have higher performance and don't introduce\n\
 the security considerations that the evaluation of arbitrary code does.\n\
-@seealso{evalin}\n\
+@seealso{evalin, evalc, assignin, feval}\n\
 @end deftypefn")
 {
   octave_value_list retval;
@@ -5216,6 +5217,144 @@
   return retval;
 }
 
+DEFUN (evalc, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn  {} {@var{s} =} evalc (@var{try})\n\
+@deftypefnx {} {@var{s} =} evalc (@var{try}, @var{catch})\n\
+Parse and evaluate the string @var{try} as if it were an Octave program,\n\
+while capturing the output into the return variable @var{s}.\n\
+\n\
+If execution fails, evaluate the optional string @var{catch}.\n\
+\n\
+This function behaves like @code{eval}, but any output or warning messages\n\
+which would normally be written to the console are captured and returned in\n\
+the string @var{s}.\n\
+\n\
+The @code{diary} is disabled during the execution of this function.  When\n\
+@code{system} is used, any output produced by external programs is @emph{not}\n\
+captured, unless their output is captured by the @code{system} function\n\
+itself.\n\
+\n\
+@example\n\
+@group\n\
+s = evalc (\"t = 42\"), t\n\
+  @result{} s = t =  42\n\
+\n\
+  @result{} t =  42\n\
+@end group\n\
+@end example\n\
+@seealso{eval, diary}\n\
+@end deftypefn")
+{
+  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 ());
+
+
+  // call standard eval function
+  octave_value_list retval;
+  int eval_nargout = std::max (0, nargout - 1);
+
+  const octave_execution_exception* eval_exception = 0;
+  try
+    {
+      retval = Feval (args, eval_nargout);
+    }
+  catch (const octave_execution_exception& e)
+    {
+      // hold back exception from eval until we have restored streams
+      eval_exception = &e;
+    }
+
+  // stop capturing buffer and restore stdout/stderr
+  out_stream.flush ();
+  err_stream.flush ();
+
+  out_stream.rdbuf (old_out_buf);
+  err_stream.rdbuf (old_err_buf);
+
+  if (eval_exception)
+    {
+      // Print error message again, which was lost because of the stderr buffer
+      // Note: this keeps error_state and last_error_stack intact
+      message_with_id ("error", last_error_id ().c_str (),
+                       last_error_message ().c_str ());
+      // rethrow original exception from above
+      throw *eval_exception;
+    }
+
+  retval.prepend (buffer.str ());
+  return retval;
+}
+
+/*
+
+%!assert (evalc ("1"), "ans =  1\n")
+%!assert (evalc ("1;"), "")
+
+%!test
+%! [s, y] = evalc ("1");
+%! assert (s, "");
+%! assert (y, 1);
+
+%!test
+%! [s, y] = evalc ("1;");
+%! assert (s, "");
+%! assert (y, 1);
+
+%!test
+%! assert (evalc ("y = 2"), "y =  2\n");
+%! assert (y, 2);
+
+%!test
+%! assert (evalc ("y = 3;"), "");
+%! assert (y, 3);
+
+%!test
+%! [s, a, b] = evalc ("deal (1, 2)");
+%! assert (s, "");
+%! assert (a, 1);
+%! assert (b, 2);
+
+%!function [a, b] = __f_evalc ()
+%!  printf ("foo");
+%!  fprintf (stdout, "bar");
+%!  disp (pi)
+%!  a = 1;
+%!  b = 2;
+%!endfunction
+%!test
+%! [s, a, b] = evalc ("__f_evalc ()");
+%! assert (s, "foobar 3.1416\n");
+%! assert (a, 1);
+%! assert (b, 2);
+
+%!error <foo> (evalc ("error ('foo')"))
+%!error <bar> (evalc ("error ('foo')", "error ('bar')"))
+
+%!test
+%! warning ("off", "quiet", "local");
+%! assert (evalc ("warning ('foo')"), "warning: foo\n");
+
+%!test
+%! warning ("off", "quiet", "local");
+%! assert (evalc ("error ('foo')", "warning ('bar')"), "warning: bar\n");
+
+*/
+
 DEFUN (__parser_debug_flag__, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn  {} {@var{val} =} __parser_debug_flag__ ()\n\
--- a/scripts/help/__unimplemented__.m	Thu Jan 14 16:56:46 2016 -0500
+++ b/scripts/help/__unimplemented__.m	Fri Jan 15 09:19:46 2016 -0800
@@ -636,7 +636,6 @@
   "echodemo",
   "empty",
   "enumeration",
-  "evalc",
   "events",
   "export2wsdlg",
   "figurepalette",