diff -r f25c14056b7c doc/interpreter/eval.txi
--- a/doc/interpreter/eval.txi	Thu Jan 14 14:00:32 2016 -0500
+++ b/doc/interpreter/eval.txi	Fri Jan 15 01:50:46 2016 +0100
@@ -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::
diff -r f25c14056b7c libinterp/corefcn/pager.cc
--- a/libinterp/corefcn/pager.cc	Thu Jan 14 14:00:32 2016 -0500
+++ b/libinterp/corefcn/pager.cc	Fri Jan 15 01:50:46 2016 +0100
@@ -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 ();
diff -r f25c14056b7c libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.in.yy	Thu Jan 14 14:00:32 2016 -0500
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri Jan 15 01:50:46 2016 +0100
@@ -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.
 
@@ -4938,7 +4939,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}\n\
 @end deftypefn")
 {
   octave_value_list retval;
@@ -5153,6 +5154,139 @@
   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\
+whilst capturing its output.\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 as \n\
+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")
+{
+  octave_value_list retval;
+
+  const 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
+  int eval_nargout = 0;
+  if (nargout > 0)
+    eval_nargout = nargout - 1;
+
+  const octave_execution_exception* eval_exception = NULL;
+  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 != NULL)
+    {
+      // 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')"))
+%!assert (evalc ("warning ('foo')"), "warning: foo\n")
+%!assert (evalc ("error ('foo')", "warning ('bar')"), "warning: bar\n")
+
+*/
+
 DEFUN (__parser_debug_flag__, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn  {} {@var{val} =} __parser_debug_flag__ ()\n\
diff -r f25c14056b7c scripts/help/__unimplemented__.m
--- a/scripts/help/__unimplemented__.m	Thu Jan 14 14:00:32 2016 -0500
+++ b/scripts/help/__unimplemented__.m	Fri Jan 15 01:50:46 2016 +0100
@@ -636,7 +636,6 @@
   "echodemo",
   "empty",
   "enumeration",
-  "evalc",
   "events",
   "export2wsdlg",
   "figurepalette",
