Mercurial > octave
changeset 22094:9203833cab7d
move new interpreter class to separate file
* libinterp/corefcn/interpreter.cc, libinterp/corefcn/interpreter.h:
New files. Move interpreter class and some supporting functions here
from octave.h, octave.cc, toplev.h, and toplev.cc. Move main_loop
into the interpreter class. Handle exiting with a separate exception
object from interrupts, passing the exit status with the object.
Update other files as needed to remove toplev.h or include
interpreter.h instead of toplev.h.
* libinterp/corefcn/module.mk: Update.
* toplev.h: Deprecate.
line wrap: on
line diff
--- a/libgui/graphics/__init_qt__.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libgui/graphics/__init_qt__.cc Mon Jul 11 18:05:53 2016 -0400 @@ -32,7 +32,7 @@ #include <QRegExp> #include "graphics.h" -#include "toplev.h" +#include "interpreter.h" #include "defun.h" #include "Backend.h"
--- a/libinterp/corefcn/cellfun.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/cellfun.cc Mon Jul 11 18:05:53 2016 -0400 @@ -39,11 +39,11 @@ #include "Cell.h" #include "oct-map.h" #include "defun.h" +#include "interpreter.h" #include "parse.h" #include "variables.h" #include "unwind-prot.h" #include "errwarn.h" -#include "toplev.h" #include "utils.h" #include "ov-bool.h"
--- a/libinterp/corefcn/debug.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/debug.cc Mon Jul 11 18:05:53 2016 -0400 @@ -59,7 +59,7 @@ #include "pt-exp.h" #include "pt-stmt.h" #include "sighandlers.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/defaults.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/defaults.cc Mon Jul 11 18:05:53 2016 -0400 @@ -47,7 +47,7 @@ #include "ovl.h" #include "ov.h" #include "parse.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "variables.h" #include <version.h>
--- a/libinterp/corefcn/defun.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/defun.cc Mon Jul 11 18:05:53 2016 -0400 @@ -43,7 +43,7 @@ #include "oct-lvalue.h" #include "pager.h" #include "symtab.h" -#include "toplev.h" +#include "interpreter.h" #include "variables.h" #include "parse.h"
--- a/libinterp/corefcn/dirfns.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/dirfns.cc Mon Jul 11 18:05:53 2016 -0400 @@ -54,7 +54,7 @@ #include "pager.h" #include "procstream.h" #include "sysdep.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/error.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/error.cc Mon Jul 11 18:05:53 2016 -0400 @@ -47,7 +47,7 @@ #include "pt-eval.h" #include "pt-pr-code.h" #include "pt-stmt.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "variables.h"
--- a/libinterp/corefcn/graphics.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/graphics.cc Mon Jul 11 18:05:53 2016 -0400 @@ -48,6 +48,7 @@ #include "error.h" #include "graphics.h" #include "input.h" +#include "interpreter.h" #include "ov.h" #include "ovl.h" #include "oct-map.h" @@ -55,7 +56,6 @@ #include "pager.h" #include "parse.h" #include "text-renderer.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "octave-default-image.h"
--- a/libinterp/corefcn/help.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/help.cc Mon Jul 11 18:05:53 2016 -0400 @@ -60,7 +60,7 @@ #include "pt-pr-code.h" #include "sighandlers.h" #include "symtab.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/input.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/input.cc Mon Jul 11 18:05:53 2016 -0400 @@ -49,13 +49,14 @@ #include "help.h" #include "hook-fcn.h" #include "input.h" +#include "interpreter.h" #include "lex.h" #include "load-path.h" #include "octave.h" #include "octave-link.h" #include "oct-map.h" #include "oct-hist.h" -#include "toplev.h" +#include "interpreter.h" #include "octave-link.h" #include "ovl.h" #include "ov-fcn-handle.h" @@ -68,7 +69,7 @@ #include "sighandlers.h" #include "symtab.h" #include "sysdep.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/corefcn/interpreter.cc Mon Jul 11 18:05:53 2016 -0400 @@ -0,0 +1,1097 @@ +/* + +Copyright (C) 1993-2015 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include <string> +#include <iostream> + +#include "cmd-edit.h" +#include "f77-fcn.h" +#include "file-ops.h" +#include "file-stat.h" +#include "fpucw-wrappers.h" +#include "lo-error.h" +#include "oct-env.h" +#include "str-vec.h" +#include "signal-wrappers.h" +#include "unistd-wrappers.h" + +#include "builtins.h" +#include "defaults.h" +#include "Cell.h" +#include "defun.h" +#include "display.h" +#include "error.h" +#include "file-io.h" +#include "graphics.h" +#include "interpreter.h" +#include "load-path.h" +#include "load-save.h" +#include "octave-link.h" +#include "octave.h" +#include "oct-hist.h" +#include "oct-map.h" +#include "oct-mutex.h" +#include "ops.h" +#include "ovl.h" +#include "ov.h" +#include "ov-classdef.h" +#include "parse.h" +#include "pt-eval.h" +#include "pt-jump.h" +#include "pt-stmt.h" +#include "sighandlers.h" +#include "sysdep.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include <version.h> + +void (*octave_exit) (int) = ::exit; + +// TRUE means the quit() call is allowed. +bool quit_allowed = true; + +// TRUE means we are ready to interpret commands, but not everything +// is ready for interactive use. +bool octave_interpreter_ready = false; + +// TRUE means we've processed all the init code and we are good to go. +bool octave_initialized = false; + +// Kluge. +extern "C" F77_RET_T +F77_FUNC (xerbla, XERBLA) (F77_CONST_CHAR_ARG_DECL, + const octave_idx_type& + F77_CHAR_ARG_LEN_DECL); + +DEFUN (__version_info__, args, , + doc: /* -*- texinfo -*- +@deftypefn {} {retval =} __version_info__ (@var{name}, @var{version}, @var{release}, @var{date}) +Undocumented internal function. +@end deftypefn */) +{ + static octave_map vinfo; + + int nargin = args.length (); + + if (nargin != 0 && nargin != 4) + print_usage (); + + octave_value retval; + + if (nargin == 0) + retval = vinfo; + else if (nargin == 4) + { + if (vinfo.nfields () == 0) + { + vinfo.assign ("Name", args(0)); + vinfo.assign ("Version", args(1)); + vinfo.assign ("Release", args(2)); + vinfo.assign ("Date", args(3)); + } + else + { + octave_idx_type n = vinfo.numel () + 1; + + vinfo.resize (dim_vector (n, 1)); + + octave_value idx (n); + + vinfo.assign (idx, "Name", Cell (octave_value (args(0)))); + vinfo.assign (idx, "Version", Cell (octave_value (args(1)))); + vinfo.assign (idx, "Release", Cell (octave_value (args(2)))); + vinfo.assign (idx, "Date", Cell (octave_value (args(3)))); + } + } + + return retval; +} + +static void +initialize_version_info (void) +{ + octave_value_list args; + + args(3) = OCTAVE_RELEASE_DATE; + args(2) = OCTAVE_RELEASE; + args(1) = OCTAVE_VERSION; + args(0) = "GNU Octave"; + + F__version_info__ (args, 0); +} + +OCTAVE_NORETURN static void +lo_error_handler (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + verror_with_cfn (fmt, args); + va_end (args); + + octave_throw_execution_exception (); +} + +OCTAVE_NORETURN static void +lo_error_with_id_handler (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + verror_with_id_cfn (id, fmt, args); + va_end (args); + + octave_throw_execution_exception (); +} + +static void +initialize_error_handlers () +{ + set_liboctave_error_handler (lo_error_handler); + set_liboctave_error_with_id_handler (lo_error_with_id_handler); + set_liboctave_warning_handler (warning); + set_liboctave_warning_with_id_handler (warning_with_id); +} + +// What internal options get configured by --traditional. + +static void +maximum_braindamage (void) +{ + FPS1 (octave_value (">> ")); + FPS2 (octave_value ("")); + FPS4 (octave_value ("")); + Fbeep_on_error (octave_value (true)); + Fconfirm_recursive_rmdir (octave_value (false)); + Fcrash_dumps_octave_core (octave_value (false)); + Fdisable_diagonal_matrix (octave_value (true)); + Fdisable_permutation_matrix (octave_value (true)); + Fdisable_range (octave_value (true)); + Ffixed_point_format (octave_value (true)); + Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%")); + Fpage_screen_output (octave_value (false)); + Fprint_empty_dimensions (octave_value (false)); + Fsave_default_options (octave_value ("-mat-binary")); + Fstruct_levels_to_print (octave_value (0)); + + disable_warning ("Octave:abbreviated-property-match"); + disable_warning ("Octave:data-file-in-path"); + disable_warning ("Octave:function-name-clash"); + disable_warning ("Octave:possible-matlab-short-circuit-operator"); +} + +void +recover_from_exception (void) +{ + octave::can_interrupt = true; + octave_interrupt_immediately = 0; + octave_interrupt_state = 0; + octave_signal_caught = 0; + octave_exception_state = octave_no_exception; + octave_restore_signal_mask (); + octave::catch_interrupts (); +} + +// Fix up things before exiting. + +static std::list<std::string> octave_atexit_functions; + +DEFUN (quit, args, , + doc: /* -*- texinfo -*- +@deftypefn {} {} exit +@deftypefnx {} {} exit (@var{status}) +@deftypefnx {} {} quit +@deftypefnx {} {} quit (@var{status}) +Exit the current Octave session. + +If the optional integer value @var{status} is supplied, pass that value to +the operating system as Octave's exit status. The default value is zero. + +When exiting, Octave will attempt to run the m-file @file{finish.m} if it +exists. User commands to save the workspace or clean up temporary files +may be placed in that file. Alternatively, another m-file may be scheduled +to run using @code{atexit}. +@seealso{atexit} +@end deftypefn */) +{ + // Confirm OK to shutdown. Note: A dynamic function installation similar + // to overriding polymorphism for which the GUI can install its own "quit" + // yet call this base "quit" could be nice. No link would be needed here. + if (! octave_link::confirm_shutdown ()) + return ovl (); + + if (! quit_allowed) + error ("quit: not supported in embedded mode"); + + int exit_status = 0; + + if (args.length () > 0) + exit_status = args(0).nint_value (); + + // Instead of simply calling exit, we thrown an exception so that no + // matter where the call to quit occurs, we will run the + // unwind_protect stack, clear the OCTAVE_LOCAL_BUFFER allocations, + // etc. before exiting. + + clean_up_and_exit (exit_status); + + return ovl (); +} + +DEFALIAS (exit, quit); + +void +octave_add_atexit_function (const std::string& fname) +{ + octave_atexit_functions.push_front (fname); +} + +bool +octave_remove_atexit_function (const std::string& fname) +{ + bool found = false; + + for (std::list<std::string>::iterator p = octave_atexit_functions.begin (); + p != octave_atexit_functions.end (); p++) + { + if (*p == fname) + { + octave_atexit_functions.erase (p); + found = true; + break; + } + } + + return found; +} + +DEFUN (atexit, args, nargout, + doc: /* -*- texinfo -*- +@deftypefn {} {} atexit (@var{fcn}) +@deftypefnx {} {} atexit (@var{fcn}, @var{flag}) +Register a function to be called when Octave exits. + +For example, + +@example +@group +function last_words () + disp ("Bye bye"); +endfunction +atexit ("last_words"); +@end group +@end example + +@noindent +will print the message @qcode{"Bye bye"} when Octave exits. + +The additional argument @var{flag} will register or unregister @var{fcn} +from the list of functions to be called when Octave exits. If @var{flag} is +true, the function is registered, and if @var{flag} is false, it is +unregistered. For example, after registering the function @code{last_words} +above, + +@example +atexit ("last_words", false); +@end example + +@noindent +will remove the function from the list and Octave will not call +@code{last_words} when it exits. + +Note that @code{atexit} only removes the first occurrence of a function +from the list, so if a function was placed in the list multiple times with +@code{atexit}, it must also be removed from the list multiple times. +@seealso{quit} +@end deftypefn */) +{ + int nargin = args.length (); + + if (nargin < 1 || nargin > 2) + print_usage (); + + std::string arg = args(0).xstring_value ("atexit: FCN argument must be a string"); + + bool add_mode = (nargin == 2) + ? args(1).xbool_value ("atexit: FLAG argument must be a logical value") + : true; + + octave_value_list retval; + + if (add_mode) + octave_add_atexit_function (arg); + else + { + bool found = octave_remove_atexit_function (arg); + + if (nargout > 0) + retval = ovl (found); + } + + return retval; +} + +// 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 = "", + bool verbose = false, bool require_file = true, + const std::string& warn_for = "") +{ + try + { + source_file (file_name, context, verbose, require_file, warn_for); + } + catch (const index_exception& e) + { + recover_from_exception (); + + std::cerr << "error: index exception in " << file_name << ": " + << e.message () << std::endl; + } + catch (const octave_exit_exception& ex) + { + recover_from_exception (); + + clean_up_and_exit (ex.exit_status (), ex.safe_to_return ()); + } + catch (const octave_interrupt_exception&) + { + recover_from_exception (); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + std::cerr << "error: execution exception in " << file_name << std::endl; + } +} + +static void +execute_pkg_add (const std::string& dir) +{ + std::string file_name = octave::sys::file_ops::concat (dir, "PKG_ADD"); + + try + { + load_path::execute_pkg_add (dir); + } + catch (const index_exception& e) + { + recover_from_exception (); + + std::cerr << "error: index exception in " << file_name << ": " + << e.message () << std::endl; + } + catch (const octave_exit_exception& ex) + { + recover_from_exception (); + + clean_up_and_exit (ex.exit_status (), ex.safe_to_return ()); + } + catch (const octave_interrupt_exception&) + { + recover_from_exception (); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + std::cerr << "error: execution exception in " << file_name << std::endl; + } +} + +static void +initialize_load_path (bool set_initial_path) +{ + // Temporarily set the execute_pkg_add function to one that catches + // exceptions. This is better than wrapping load_path::initialize in + // a try-catch block because it will not stop executing PKG_ADD files + // at the first exception. It's also better than changing the default + // execute_pkg_add function to use safe_source file because that will + // normally be evaluated from the normal intepreter loop where + // exceptions are already handled. + + octave::unwind_protect frame; + + frame.add_fcn (load_path::set_add_hook, load_path::get_add_hook ()); + + load_path::set_add_hook (execute_pkg_add); + + load_path::initialize (set_initial_path); +} + +// Initialize by reading startup files. + +static void +execute_startup_files (bool read_site_files, bool read_init_files, + bool verbose_flag, bool inhibit_startup_message) +{ + octave::unwind_protect frame; + + std::string context; + + bool verbose = (verbose_flag && ! inhibit_startup_message); + + bool require_file = false; + + if (read_site_files) + { + // Execute commands from the site-wide configuration file. + // First from the file $(prefix)/lib/octave/site/m/octaverc + // (if it exists), then from the file + // $(prefix)/share/octave/$(version)/m/octaverc (if it exists). + + safe_source_file (Vlocal_site_defaults_file, context, verbose, + require_file); + + safe_source_file (Vsite_defaults_file, context, verbose, require_file); + } + + if (read_init_files) + { + // Try to execute commands from $HOME/$OCTAVE_INITFILE and + // $OCTAVE_INITFILE. If $OCTAVE_INITFILE is not set, + // .octaverc is assumed. + + bool home_rc_already_executed = false; + + std::string initfile = octave::sys::env::getenv ("OCTAVE_INITFILE"); + + if (initfile.empty ()) + initfile = ".octaverc"; + + std::string home_dir = octave::sys::env::get_home_directory (); + + std::string home_rc = octave::sys::env::make_absolute (initfile, home_dir); + + std::string local_rc; + + if (! home_rc.empty ()) + { + safe_source_file (home_rc, context, verbose, require_file); + + // Names alone are not enough. + + octave::sys::file_stat fs_home_rc (home_rc); + + if (fs_home_rc) + { + // We want to check for curr_dir after executing home_rc + // because doing that may change the working directory. + + local_rc = octave::sys::env::make_absolute (initfile); + + home_rc_already_executed = same_file (home_rc, local_rc); + } + } + + if (! home_rc_already_executed) + { + if (local_rc.empty ()) + local_rc = octave::sys::env::make_absolute (initfile); + + safe_source_file (local_rc, context, verbose, require_file); + } + } +} + +namespace octave +{ + interpreter::interpreter (application *app_context, bool embedded) + : m_app_context (app_context), m_embedded (embedded), + m_interactive (false), m_quitting_gracefully (false) + { + cmdline_options options = m_app_context->options (); + + sysdep_init (); + + install_defaults (); + + // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting + setlocale (LC_NUMERIC, "C"); + setlocale (LC_TIME, "C"); + octave::sys::env::putenv ("LC_NUMERIC", "C"); + octave::sys::env::putenv ("LC_TIME", "C"); + + // Initialize the default floating point unit control state. + octave_set_default_fpucw (); + + string_vector all_args = options.all_args (); + + octave_thread::init (); + + set_default_prompts (); + + // Initialize default warning state before --traditional option + // that may reset them. + + initialize_default_warning_state (); + + if (options.traditional ()) + maximum_braindamage (); + + octave_ieee_init (); + + // The idea here is to force xerbla to be referenced so that we will link to + // our own version instead of the one provided by the BLAS library. But + // octave::numeric_limits<double>::NaN () should never be -1, so we + // should never actually call xerbla. FIXME (again!): If this + // becomes a constant expression the test might be optimized away and + // then the reference to the function might also disappear. + + if (octave::numeric_limits<double>::NaN () == -1) + F77_FUNC (xerbla, XERBLA) ("octave", 13 F77_CHAR_ARG_LEN (6)); + + initialize_error_handlers (); + + if (! m_embedded) + octave::install_signal_handlers (); + else + quit_allowed = false; + + initialize_file_io (); + + install_types (); + + install_ops (); + + install_builtins (); + + install_classdef (); + + std::list<std::string> command_line_path = options.command_line_path (); + + for (std::list<std::string>::const_iterator it = command_line_path.begin (); + it != command_line_path.end (); it++) + load_path::set_command_line_path (*it); + + std::string exec_path = options.exec_path (); + if (! exec_path.empty ()) + set_exec_path (exec_path); + + std::string image_path = options.image_path (); + if (! image_path.empty ()) + set_image_path (image_path); + + if (options.no_window_system ()) + display_info::no_window_system (); + + // Is input coming from a terminal? If so, we are probably interactive. + + // If stdin is not a tty, then we are reading commands from a pipe or + // a redirected file. + bool stdin_is_tty = octave_isatty_wrapper (fileno (stdin)); + + m_interactive = (! m_embedded + && ! m_app_context->is_octave_program () + && stdin_is_tty + && octave_isatty_wrapper (fileno (stdout))); + + // Check if the user forced an interactive session. If he + // unnecessarily did so, reset forced_interactive to false. + if (options.forced_interactive ()) + { + if (m_interactive) + options.forced_interactive (false); + else + m_interactive = true; + } + + if ((! m_interactive || options.forced_interactive ()) + && ! options.forced_line_editing ()) + options.line_editing (false); + + // Also skip start-up message unless session is interactive. + if (! m_interactive) + options.inhibit_startup_message (true); + + // Force default line editor if we don't want readline editing. + if (! options.line_editing ()) + octave::command_editor::force_default_editor (); + + // These can come after command line args since none of them set any + // defaults that might be changed by command line options. + + if (options.line_editing ()) + initialize_command_input (); + + octave_interpreter_ready = true; + + initialize_version_info (); + + // Make all command-line arguments available to startup files, + // including PKG_ADD files. + + app_context->intern_argv (options.all_args ()); + + initialize_load_path (options.set_initial_path ()); + + initialize_history (options.read_history_file ()); + } + + int interpreter::execute (void) + { + cmdline_options options = m_app_context->options (); + + if (! options.inhibit_startup_message ()) + std::cout << octave_startup_message () << "\n" << std::endl; + + octave_prepare_hdf5 (); + + execute_startup_files (options.read_site_files (), + options.read_init_files (), + options.verbose_flag (), + options.inhibit_startup_message ()); + + if (! options.inhibit_startup_message () + && reading_startup_message_printed) + std::cout << std::endl; + + // Execute any code specified with --eval 'CODE' + std::string code_to_eval = options.code_to_eval (); + + if (! code_to_eval.empty ()) + { + int parse_status = 0; + + try + { + parse_status = execute_eval_option_code (code_to_eval); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + parse_status = 1; + } + + if (! options.persist ()) + { + m_quitting_gracefully = true; + + clean_up_and_exit (parse_status); + } + } + + // If there is an extra argument, see if it names a file to read. + // Additional arguments are taken as command line options for the script. + + if (m_app_context->have_script_file ()) + { + // If we are running an executable script (#! /bin/octave) then + // we should only see the args passed to the script. + + int exit_status = 0; + + try + { + string_vector script_args = options.remaining_args (); + + m_app_context->intern_argv (script_args); + + execute_command_line_file (script_args[0]); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + exit_status = 1; + } + + // Restore full set of args. + m_app_context->intern_argv (options.all_args ()); + + if (! options.persist ()) + { + m_quitting_gracefully = true; + + clean_up_and_exit (exit_status); + } + } + + // Avoid counting commands executed from startup or script files. + + octave::command_editor::reset_current_command_number (1); + + // Force input to be echoed if not really interactive, + // but the user has forced interactive behavior. + + if (options.forced_interactive ()) + { + octave::command_editor::blink_matching_paren (false); + + // FIXME: is this the right thing to do? + Fecho_executing_commands (octave_value (ECHO_CMD_LINE)); + } + + if (m_embedded) + { + // FIXME: Do we need to do any cleanup here before returning? + // If we don't, what will happen to Octave functions that have been + // registered to execute with atexit, for example? + + return 1; + } + + int retval = main_loop (); + + m_quitting_gracefully = true; + + clean_up_and_exit (retval, true); + + return retval; + } + + int interpreter::execute_eval_option_code (const std::string& code) + { + octave::unwind_protect frame; + + octave_save_signal_mask (); + + octave::can_interrupt = true; + + octave_signal_hook = octave::signal_handler; + octave_interrupt_hook = 0; + octave_bad_alloc_hook = 0; + + octave::catch_interrupts (); + + octave_initialized = true; + + frame.add_method (this, &interpreter::interactive, m_interactive); + + m_interactive = false; + + int parse_status = 0; + + try + { + eval_string (code, false, parse_status, 0); + } + catch (const octave_exit_exception& ex) + { + recover_from_exception (); + + clean_up_and_exit (ex.exit_status (), ex.safe_to_return ()); + } + catch (const octave_interrupt_exception&) + { + recover_from_exception (); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + std::cerr << "error: unhandled execution exception -- eval failed" + << std::endl; + } + + return parse_status; + } + + void interpreter::execute_command_line_file (const std::string& fname) + { + octave::unwind_protect frame; + + octave_save_signal_mask (); + + octave::can_interrupt = true; + + octave_signal_hook = octave::signal_handler; + octave_interrupt_hook = 0; + octave_bad_alloc_hook = 0; + + octave::catch_interrupts (); + + octave_initialized = true; + + frame.add_method (this, &interpreter::interactive, m_interactive); + + frame.add_method (m_app_context, + &application::program_invocation_name, + application::program_invocation_name ()); + + frame.add_method (m_app_context, + &application::program_name, + application::program_name ()); + + m_interactive = false; + + m_app_context->set_program_names (fname); + + std::string context; + bool verbose = false; + bool require_file = true; + + safe_source_file (fname, context, verbose, require_file, "octave"); + } + + int interpreter::main_loop (void) + { + octave_save_signal_mask (); + + octave::can_interrupt = true; + + octave_signal_hook = octave::signal_handler; + octave_interrupt_hook = 0; + octave_bad_alloc_hook = 0; + + octave::catch_interrupts (); + + octave_initialized = true; + + // The big loop. + + octave_lexer *lxr = (octave::application::interactive () + ? new octave_lexer () + : new octave_lexer (stdin)); + + octave_parser parser (*lxr); + + int retval = 0; + do + { + try + { + reset_error_handler (); + + parser.reset (); + + if (symbol_table::at_top_level ()) + tree_evaluator::reset_debug_state (); + + retval = parser.run (); + + if (retval == 0) + { + if (parser.stmt_list) + { + parser.stmt_list->accept (*current_evaluator); + + octave_quit (); + + if (! octave::application::interactive ()) + { + bool quit = (tree_return_command::returning + || tree_break_command::breaking); + + if (tree_return_command::returning) + tree_return_command::returning = 0; + + if (tree_break_command::breaking) + tree_break_command::breaking--; + + if (quit) + break; + } + + if (octave_completion_matches_called) + octave_completion_matches_called = false; + else + octave::command_editor::increment_current_command_number (); + } + else if (parser.lexer.end_of_input) + break; + } + } + catch (const octave_exit_exception& ex) + { + recover_from_exception (); + + clean_up_and_exit (ex.exit_status (), ex.safe_to_return ()); + } + catch (const octave_interrupt_exception&) + { + recover_from_exception (); + + // Required newline when the user does Ctrl+C at the prompt. + if (octave::application::interactive ()) + octave_stdout << "\n"; + } + catch (const index_exception& e) + { + recover_from_exception (); + + std::cerr << "error: unhandled index exception: " + << e.message () << " -- trying to return to prompt" + << std::endl; + } + catch (const octave_execution_exception& e) + { + std::string stack_trace = e.info (); + + if (! stack_trace.empty ()) + std::cerr << stack_trace; + + if (octave::application::interactive ()) + recover_from_exception (); + else + { + // We should exit with a nonzero status. + retval = 1; + break; + } + } + catch (const std::bad_alloc&) + { + recover_from_exception (); + + std::cerr << "error: out of memory -- trying to return to prompt" + << std::endl; + } + +#if defined (DBSTOP_NANINF) + if (Vdebug_on_naninf) + { + if (setjump (naninf_jump) != 0) + debug_or_throw_exception (true); // true = stack trace + } +#endif + } + while (retval == 0); + + if (octave::application::interactive ()) + octave_stdout << "\n"; + + if (retval == EOF) + retval = 0; + + return retval; + } + + void interpreter::clean_up_and_exit (int status, bool safe_to_return) + { + static bool deja_vu = false; + + OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ()); + + while (! octave_atexit_functions.empty ()) + { + std::string fcn = octave_atexit_functions.front (); + + octave_atexit_functions.pop_front (); + + OCTAVE_SAFE_CALL (reset_error_handler, ()); + + OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + } + + if (! deja_vu) + { + deja_vu = true; + + // Process pending events and disasble octave_link event + // processing with this call. + + octave_link::process_events (true); + + // Do this explicitly so that destructors for mex file objects + // are called, so that functions registered with mexAtExit are + // called. + OCTAVE_SAFE_CALL (clear_mex_functions, ()); + + OCTAVE_SAFE_CALL (octave::command_editor::restore_terminal_state, ()); + + // FIXME: is this needed? Can it cause any trouble? + OCTAVE_SAFE_CALL (raw_mode, (0)); + + OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); + + if (! octave::command_history::ignoring_entries ()) + OCTAVE_SAFE_CALL (octave::command_history::clean_up_and_save, ()); + + OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); + + OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); + + OCTAVE_SAFE_CALL (close_files, ()); + + OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); + + OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); + + OCTAVE_SAFE_CALL (sysdep_cleanup, ()); + + OCTAVE_SAFE_CALL (octave_finalize_hdf5, ()); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + + if (! m_quitting_gracefully && octave::application::interactive ()) + { + octave_stdout << "\n"; + + // Yes, we want this to be separate from the call to + // flush_octave_stdout above. + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + } + + // Don't call singleton_cleanup_list::cleanup until we have the + // problems with registering/unregistering types worked out. For + // example, uncomment the following line, then use the make_int + // function from the examples directory to create an integer + // object and then exit Octave. Octave should crash with a + // segfault when cleaning up the typinfo singleton. We need some + // way to force new octave_value_X types that are created in + // .oct files to be unregistered when the .oct file shared library + // is unloaded. + // + // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); + + OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); + } + + if (octave_link::exit (status)) + { + if (safe_to_return) + return; + else + { + // What should we do here? We might be called from some + // location other than the end of octave_execute_interpreter, + // so it might not be safe to return. + + // We have nothing else to do at this point, and the + // octave_link::exit function is supposed to take care of + // exiting for us. Assume that job won't take more than a + // day... + + octave_sleep (86400); // FIXME: really needed? + } + } + else + { + if (octave_exit) + (*octave_exit) (status); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/corefcn/interpreter.h Mon Jul 11 18:05:53 2016 -0400 @@ -0,0 +1,135 @@ +/* + +Copyright (C) 2002-2015 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if ! defined (octave_interpreter_h) +#define octave_interpreter_h 1 + +#include "octave-config.h" + +#include <string> + +#include "quit.h" +#include "str-vec.h" + +typedef void (*octave_exit_func) (int); +extern OCTINTERP_API octave_exit_func octave_exit; + +extern OCTINTERP_API bool quit_allowed; + +extern OCTINTERP_API bool quitting_gracefully; + +extern OCTINTERP_API void recover_from_exception (void); + +extern OCTINTERP_API void +octave_add_atexit_function (const std::string& fname); + +extern OCTINTERP_API bool +octave_remove_atexit_function (const std::string& fname); + +// TRUE means we are ready to interpret commands, but not everything +// is ready for interactive use. +extern OCTINTERP_API bool octave_interpreter_ready; + +// TRUE means we've processed all the init code and we are good to go. +extern OCTINTERP_API bool octave_initialized; + +// Call a function with exceptions handled to avoid problems with +// errors while shutting down. + +#define OCTAVE_IGNORE_EXCEPTION(E) \ + catch (E) \ + { \ + std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \ + recover_from_exception (); \ + } + +#define OCTAVE_SAFE_CALL(F, ARGS) \ + do \ + { \ + try \ + { \ + octave::unwind_protect frame; \ + \ + frame.protect_var (Vdebug_on_error); \ + frame.protect_var (Vdebug_on_warning); \ + \ + Vdebug_on_error = false; \ + Vdebug_on_warning = false; \ + \ + F ARGS; \ + } \ + OCTAVE_IGNORE_EXCEPTION (const octave_interrupt_exception&) \ + OCTAVE_IGNORE_EXCEPTION (const octave_execution_exception&) \ + OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&) \ + } \ + while (0) + +namespace octave +{ + // The application object contains a pointer to the current + // interpreter and the interpreter contains a pointer back to the + // application context so we need a forward declaration for one (or + // both) of them... + + class application; + + class OCTINTERP_API interpreter + { + public: + + interpreter (application *app_context = 0, bool embedded = false); + + ~interpreter (void) { } + + int execute (void); + + int execute_eval_option_code (const std::string& code); + + void execute_command_line_file (const std::string& fname); + + bool interactive (void) const { return m_interactive; } + void interactive (bool arg) { m_interactive = arg; } + + private: + + // No copying, at least not yet... + + interpreter (const interpreter&); + + interpreter& operator = (const interpreter&); + + int main_loop (void); + + void clean_up_and_exit (int status, bool safe_to_return = false); + + application *m_app_context; + + bool m_embedded; + + // TRUE means this is an interactive interpreter (forced or not). + bool m_interactive; + + bool m_quitting_gracefully; + }; +} + +#endif
--- a/libinterp/corefcn/load-path.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/load-path.cc Mon Jul 11 18:05:53 2016 -0400 @@ -37,11 +37,11 @@ #include "defaults.h" #include "defun.h" #include "input.h" +#include "interpreter.h" #include "load-path.h" #include "ov-usr-fcn.h" #include "pager.h" #include "parse.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h"
--- a/libinterp/corefcn/ls-mat-ascii.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/ls-mat-ascii.cc Mon Jul 11 18:05:53 2016 -0400 @@ -49,6 +49,7 @@ #include "defun.h" #include "error.h" #include "errwarn.h" +#include "interpreter.h" #include "lex.h" #include "load-save.h" #include "ls-ascii-helper.h" @@ -59,7 +60,6 @@ #include "pager.h" #include "pt-exp.h" #include "sysdep.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/ls-mat5.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/ls-mat5.cc Mon Jul 11 18:05:53 2016 -0400 @@ -65,7 +65,7 @@ #include "pager.h" #include "pt-exp.h" #include "sysdep.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/mex.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/mex.cc Mon Jul 11 18:05:53 2016 -0400 @@ -40,6 +40,7 @@ #include "Cell.h" #include "call-stack.h" #include "error.h" +#include "interpreter.h" // mxArray must be declared as a class before including mexproto.h. #include "mxarray.h" #include "mexproto.h" @@ -50,7 +51,6 @@ #include "ov-usr-fcn.h" #include "pager.h" #include "parse.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/module.mk Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/module.mk Mon Jul 11 18:05:53 2016 -0400 @@ -48,6 +48,7 @@ libinterp/corefcn/help.h \ libinterp/corefcn/hook-fcn.h \ libinterp/corefcn/input.h \ + libinterp/corefcn/interpreter.h \ libinterp/corefcn/load-path.h \ libinterp/corefcn/load-save.h \ libinterp/corefcn/ls-ascii-helper.h \ @@ -179,6 +180,7 @@ libinterp/corefcn/hook-fcn.cc \ libinterp/corefcn/input.cc \ libinterp/corefcn/inv.cc \ + libinterp/corefcn/interpreter.cc \ libinterp/corefcn/kron.cc \ libinterp/corefcn/load-path.cc \ libinterp/corefcn/load-save.cc \
--- a/libinterp/corefcn/oct-hist.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/oct-hist.cc Mon Jul 11 18:05:53 2016 -0400 @@ -61,7 +61,7 @@ #include "parse.h" #include "sighandlers.h" #include "sysdep.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/oct-stream.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/oct-stream.cc Mon Jul 11 18:05:53 2016 -0400 @@ -50,12 +50,12 @@ #include "error.h" #include "errwarn.h" #include "input.h" +#include "interpreter.h" #include "octave.h" #include "oct-stdstrm.h" #include "oct-stream.h" #include "ov.h" #include "ovl.h" -#include "toplev.h" #include "utils.h" // Programming Note: There are two very different error functions used
--- a/libinterp/corefcn/octave-link.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/octave-link.cc Mon Jul 11 18:05:53 2016 -0400 @@ -32,7 +32,7 @@ #include "oct-mutex.h" #include "pager.h" #include "singleton-cleanup.h" -#include "toplev.h" +#include "interpreter.h" #include "octave-link.h"
--- a/libinterp/corefcn/sighandlers.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/sighandlers.cc Mon Jul 11 18:05:53 2016 -0400 @@ -45,6 +45,7 @@ #include "defun.h" #include "error.h" #include "input.h" +#include "interpreter.h" #include "load-save.h" #include "octave.h" #include "oct-map.h" @@ -53,7 +54,6 @@ #include "pt-eval.h" #include "sighandlers.h" #include "sysdep.h" -#include "toplev.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/sysdep.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/sysdep.cc Mon Jul 11 18:05:53 2016 -0400 @@ -85,7 +85,7 @@ #include "parse.h" #include "sighandlers.h" #include "sysdep.h" -#include "toplev.h" +#include "interpreter.h" #include "utils.h" #include "file-stat.h"
--- a/libinterp/corefcn/toplev.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/toplev.cc Mon Jul 11 18:05:53 2016 -0400 @@ -24,14 +24,10 @@ # include "config.h" #endif -#include <cassert> #include <cerrno> #include <cstdlib> -#include <cstring> #include <new> -#include <fstream> -#include <iostream> #include <sstream> #include <string> @@ -40,18 +36,11 @@ # include <windows.h> #endif -#include "cmd-edit.h" -#include "cmd-hist.h" -#include "file-ops.h" +#include "child-list.h" #include "lo-error.h" -#include "lo-mappers.h" -#include "oct-env.h" #include "oct-fftw.h" #include "oct-locbuf.h" #include "oct-syscalls.h" -#include "quit.h" -#include "signal-wrappers.h" -#include "singleton-cleanup.h" #include "str-vec.h" #include "wait-for-input.h" @@ -62,366 +51,21 @@ #include "defun.h" #include "error.h" #include "file-io.h" -#include "graphics.h" -#include "input.h" -#include "lex.h" -#include "load-save.h" #include "octave.h" -#include "octave-link.h" -#include "oct-hist.h" #include "oct-map.h" #include "ovl.h" #include "ov.h" #include "pager.h" -#include "parse.h" -#include "pathsearch.h" #include "procstream.h" -#include "pt-eval.h" -#include "pt-jump.h" -#include "pt-stmt.h" -#include "sighandlers.h" #include "sysdep.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" -#include "variables.h" -#include "version.h" +#include <version.h> #if ! defined (SHELL_PATH) # define SHELL_PATH "/bin/sh" #endif -void (*octave_exit) (int) = ::exit; - -// TRUE means the quit() call is allowed. -bool quit_allowed = true; - -// TRUE means we are exiting via the builtin exit or quit functions. -bool quitting_gracefully = false; -// This stores the exit status. -int exit_status = 0; - -// TRUE means we are ready to interpret commands, but not everything -// is ready for interactive use. -bool octave_interpreter_ready = false; - -// TRUE means we've processed all the init code and we are good to go. -bool octave_initialized = false; - -void -recover_from_exception (void) -{ - octave::can_interrupt = true; - octave_interrupt_immediately = 0; - octave_interrupt_state = 0; - octave_signal_caught = 0; - octave_exception_state = octave_no_exception; - octave_restore_signal_mask (); - octave::catch_interrupts (); -} - -int -main_loop (void) -{ - octave_save_signal_mask (); - - octave::can_interrupt = true; - - octave_signal_hook = octave::signal_handler; - octave_interrupt_hook = 0; - octave_bad_alloc_hook = 0; - - octave::catch_interrupts (); - - octave_initialized = true; - - // The big loop. - - octave_lexer *lxr = (octave::application::interactive () - ? new octave_lexer () - : new octave_lexer (stdin)); - - octave_parser parser (*lxr); - - int retval = 0; - do - { - try - { - reset_error_handler (); - - parser.reset (); - - if (symbol_table::at_top_level ()) - tree_evaluator::reset_debug_state (); - - retval = parser.run (); - - if (retval == 0) - { - if (parser.stmt_list) - { - parser.stmt_list->accept (*current_evaluator); - - octave_quit (); - - if (! octave::application::interactive ()) - { - bool quit = (tree_return_command::returning - || tree_break_command::breaking); - - if (tree_return_command::returning) - tree_return_command::returning = 0; - - if (tree_break_command::breaking) - tree_break_command::breaking--; - - if (quit) - break; - } - - if (octave_completion_matches_called) - octave_completion_matches_called = false; - else - octave::command_editor::increment_current_command_number (); - } - else if (parser.lexer.end_of_input) - break; - } - } - catch (const octave_interrupt_exception&) - { - recover_from_exception (); - - if (quitting_gracefully) - return exit_status; - - // Required newline when the user does Ctrl+C at the prompt. - if (octave::application::interactive ()) - octave_stdout << "\n"; - } - catch (const index_exception& e) - { - recover_from_exception (); - - std::cerr << "error: unhandled index exception: " - << e.message () << " -- trying to return to prompt" - << std::endl; - } - catch (const octave_execution_exception& e) - { - std::string stack_trace = e.info (); - - if (! stack_trace.empty ()) - std::cerr << stack_trace; - - if (octave::application::interactive ()) - recover_from_exception (); - else - { - // We should exit with a nonzero status. - retval = 1; - break; - } - } - catch (const std::bad_alloc&) - { - recover_from_exception (); - - std::cerr << "error: out of memory -- trying to return to prompt" - << std::endl; - } - -#if defined (DBSTOP_NANINF) - if (Vdebug_on_naninf) - { - if (setjump (naninf_jump) != 0) - debug_or_throw_exception (true); // true = stack trace - } -#endif - } - while (retval == 0); - - if (octave::application::interactive ()) - octave_stdout << "\n"; - - if (retval == EOF) - retval = 0; - - return retval; -} - -// Fix up things before exiting. - -static std::list<std::string> octave_atexit_functions; - -static void -do_octave_atexit (void) -{ - static bool deja_vu = false; - - OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ()); - - while (! octave_atexit_functions.empty ()) - { - std::string fcn = octave_atexit_functions.front (); - - octave_atexit_functions.pop_front (); - - OCTAVE_SAFE_CALL (reset_error_handler, ()); - - OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - } - - if (! deja_vu) - { - deja_vu = true; - - // Process pending events and disasble octave_link event - // processing with this call. - - octave_link::process_events (true); - - // Do this explicitly so that destructors for mex file objects - // are called, so that functions registered with mexAtExit are - // called. - OCTAVE_SAFE_CALL (clear_mex_functions, ()); - - OCTAVE_SAFE_CALL (octave::command_editor::restore_terminal_state, ()); - - // FIXME: is this needed? Can it cause any trouble? - OCTAVE_SAFE_CALL (raw_mode, (0)); - - OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); - - if (! octave::command_history::ignoring_entries ()) - OCTAVE_SAFE_CALL (octave::command_history::clean_up_and_save, ()); - - OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); - - OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); - - OCTAVE_SAFE_CALL (close_files, ()); - - OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); - - OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); - - OCTAVE_SAFE_CALL (sysdep_cleanup, ()); - - OCTAVE_SAFE_CALL (octave_finalize_hdf5, ()); - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - - if (! quitting_gracefully && octave::application::interactive ()) - { - octave_stdout << "\n"; - - // Yes, we want this to be separate from the call to - // flush_octave_stdout above. - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - } - - // Don't call singleton_cleanup_list::cleanup until we have the - // problems with registering/unregistering types worked out. For - // example, uncomment the following line, then use the make_int - // function from the examples directory to create an integer - // object and then exit Octave. Octave should crash with a - // segfault when cleaning up the typinfo singleton. We need some - // way to force new octave_value_X types that are created in - // .oct files to be unregistered when the .oct file shared library - // is unloaded. - // - // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); - - OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); - } -} - -void -clean_up_and_exit (int status, bool safe_to_return) -{ - do_octave_atexit (); - - if (octave_link::exit (status)) - { - if (safe_to_return) - return; - else - { - // What should we do here? We might be called from some - // location other than the end of octave_execute_interpreter, - // so it might not be safe to return. - - // We have nothing else to do at this point, and the - // octave_link::exit function is supposed to take care of - // exiting for us. Assume that job won't take more than a - // day... - - octave_sleep (86400); // FIXME: really needed? - } - } - else - { - if (octave_exit) - (*octave_exit) (status); - } -} - -DEFUN (quit, args, , - doc: /* -*- texinfo -*- -@deftypefn {} {} exit -@deftypefnx {} {} exit (@var{status}) -@deftypefnx {} {} quit -@deftypefnx {} {} quit (@var{status}) -Exit the current Octave session. - -If the optional integer value @var{status} is supplied, pass that value to -the operating system as Octave's exit status. The default value is zero. - -When exiting, Octave will attempt to run the m-file @file{finish.m} if it -exists. User commands to save the workspace or clean up temporary files -may be placed in that file. Alternatively, another m-file may be scheduled -to run using @code{atexit}. -@seealso{atexit} -@end deftypefn */) -{ - // Confirm OK to shutdown. Note: A dynamic function installation similar - // to overriding polymorphism for which the GUI can install its own "quit" - // yet call this base "quit" could be nice. No link would be needed here. - if (! octave_link::confirm_shutdown ()) - return ovl (); - - if (! quit_allowed) - error ("quit: not supported in embedded mode"); - - if (args.length () > 0) - { - int tmp = args(0).nint_value (); - - exit_status = tmp; - } - - // Instead of simply calling exit, we simulate an interrupt - // with a request to exit cleanly so that no matter where the - // call to quit occurs, we will run the unwind_protect stack, - // clear the OCTAVE_LOCAL_BUFFER allocations, etc. before - // exiting. - - quitting_gracefully = true; - - octave_interrupt_state = -1; - - octave_throw_interrupt_exception (); - - return ovl (); -} - -DEFALIAS (exit, quit); - DEFUN (warranty, , , doc: /* -*- texinfo -*- @deftypefn {} {} warranty () @@ -669,97 +313,6 @@ %!error system (1, 2, 3) */ -void -octave_add_atexit_function (const std::string& fname) -{ - octave_atexit_functions.push_front (fname); -} - -bool -octave_remove_atexit_function (const std::string& fname) -{ - bool found = false; - - for (std::list<std::string>::iterator p = octave_atexit_functions.begin (); - p != octave_atexit_functions.end (); p++) - { - if (*p == fname) - { - octave_atexit_functions.erase (p); - found = true; - break; - } - } - - return found; -} - -DEFUN (atexit, args, nargout, - doc: /* -*- texinfo -*- -@deftypefn {} {} atexit (@var{fcn}) -@deftypefnx {} {} atexit (@var{fcn}, @var{flag}) -Register a function to be called when Octave exits. - -For example, - -@example -@group -function last_words () - disp ("Bye bye"); -endfunction -atexit ("last_words"); -@end group -@end example - -@noindent -will print the message @qcode{"Bye bye"} when Octave exits. - -The additional argument @var{flag} will register or unregister @var{fcn} -from the list of functions to be called when Octave exits. If @var{flag} is -true, the function is registered, and if @var{flag} is false, it is -unregistered. For example, after registering the function @code{last_words} -above, - -@example -atexit ("last_words", false); -@end example - -@noindent -will remove the function from the list and Octave will not call -@code{last_words} when it exits. - -Note that @code{atexit} only removes the first occurrence of a function -from the list, so if a function was placed in the list multiple times with -@code{atexit}, it must also be removed from the list multiple times. -@seealso{quit} -@end deftypefn */) -{ - int nargin = args.length (); - - if (nargin < 1 || nargin > 2) - print_usage (); - - std::string arg = args(0).xstring_value ("atexit: FCN argument must be a string"); - - bool add_mode = (nargin == 2) - ? args(1).xbool_value ("atexit: FLAG argument must be a logical value") - : true; - - octave_value_list retval; - - if (add_mode) - octave_add_atexit_function (arg); - else - { - bool found = octave_remove_atexit_function (arg); - - if (nargout > 0) - retval = ovl (found); - } - - return retval; -} - static octave_value find_config_info (const octave_scalar_map& m, const std::string& key) {
--- a/libinterp/corefcn/toplev.h Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/toplev.h Mon Jul 11 18:05:53 2016 -0400 @@ -25,68 +25,8 @@ #include "octave-config.h" -#include <string> - -#include "quit.h" - -typedef void (*octave_exit_func) (int); -extern OCTINTERP_API octave_exit_func octave_exit; - -extern OCTINTERP_API bool quit_allowed; - -extern OCTINTERP_API bool quitting_gracefully; - -extern OCTINTERP_API int exit_status; - -extern OCTINTERP_API void -clean_up_and_exit (int status, bool safe_to_return = false); - -extern OCTINTERP_API void recover_from_exception (void); - -extern OCTINTERP_API int main_loop (void); - -extern OCTINTERP_API void -octave_add_atexit_function (const std::string& fname); - -extern OCTINTERP_API bool -octave_remove_atexit_function (const std::string& fname); - -// TRUE means we are ready to interpret commands, but not everything -// is ready for interactive use. -extern OCTINTERP_API bool octave_interpreter_ready; +#warning "toplev.h has been deprecated; use interpreter.h instead" -// TRUE means we've processed all the init code and we are good to go. -extern OCTINTERP_API bool octave_initialized; - -// Call a function with exceptions handled to avoid problems with -// errors while shutting down. - -#define OCTAVE_IGNORE_EXCEPTION(E) \ - catch (E) \ - { \ - std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \ - recover_from_exception (); \ - } - -#define OCTAVE_SAFE_CALL(F, ARGS) \ - do \ - { \ - try \ - { \ - octave::unwind_protect frame; \ - \ - frame.protect_var (Vdebug_on_error); \ - frame.protect_var (Vdebug_on_warning); \ - \ - Vdebug_on_error = false; \ - Vdebug_on_warning = false; \ - \ - F ARGS; \ - } \ - OCTAVE_IGNORE_EXCEPTION (const octave_interrupt_exception&) \ - OCTAVE_IGNORE_EXCEPTION (const octave_execution_exception&) \ - OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&) \ - } \ - while (0) +#include "interpreter.h" #endif
--- a/libinterp/corefcn/utils.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/utils.cc Mon Jul 11 18:05:53 2016 -0400 @@ -54,6 +54,7 @@ #include "error.h" #include "errwarn.h" #include "input.h" +#include "interpreter.h" #include "lex.h" #include "load-path.h" #include "oct-errno.h" @@ -63,7 +64,6 @@ #include "pager.h" #include "parse.h" #include "sysdep.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/corefcn/variables.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/corefcn/variables.cc Mon Jul 11 18:05:53 2016 -0400 @@ -48,6 +48,7 @@ #include "errwarn.h" #include "help.h" #include "input.h" +#include "interpreter.h" #include "lex.h" #include "load-path.h" #include "octave-link.h" @@ -60,7 +61,6 @@ #include "pager.h" #include "parse.h" #include "symtab.h" -#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h"
--- a/libinterp/dldfcn/__init_fltk__.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/dldfcn/__init_fltk__.cc Mon Jul 11 18:05:53 2016 -0400 @@ -89,7 +89,7 @@ #include "gl2ps-print.h" #include "graphics.h" #include "parse.h" -#include "toplev.h" +#include "interpreter.h" #include "variables.h" #define FLTK_GRAPHICS_TOOLKIT_NAME "fltk"
--- a/libinterp/octave-value/ov-base.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-base.cc Mon Jul 11 18:05:53 2016 -0400 @@ -54,7 +54,7 @@ #include "parse.h" #include "pr-output.h" #include "utils.h" -#include "toplev.h" +#include "interpreter.h" #include "variables.h" builtin_type_t btyp_mixed_numeric (builtin_type_t x, builtin_type_t y)
--- a/libinterp/octave-value/ov-builtin.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-builtin.cc Mon Jul 11 18:05:53 2016 -0400 @@ -31,7 +31,7 @@ #include "ov-builtin.h" #include "ov.h" #include "profiler.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h"
--- a/libinterp/octave-value/ov-class.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-class.cc Mon Jul 11 18:05:53 2016 -0400 @@ -38,6 +38,7 @@ #include "error.h" #include "file-ops.h" #include "errwarn.h" +#include "interpreter.h" #include "load-path.h" #include "ls-hdf5.h" #include "ls-oct-text.h" @@ -52,7 +53,6 @@ #include "pager.h" #include "parse.h" #include "pr-output.h" -#include "toplev.h" #include "unwind-prot.h" #include "variables.h"
--- a/libinterp/octave-value/ov-classdef.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-classdef.cc Mon Jul 11 18:05:53 2016 -0400 @@ -42,7 +42,7 @@ #include "pt-walk.h" #include "singleton-cleanup.h" #include "symtab.h" -#include "toplev.h" +#include "interpreter.h" // Define to 1 to enable debugging statements. #define DEBUG_TRACE 0
--- a/libinterp/octave-value/ov-fcn-handle.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-fcn-handle.cc Mon Jul 11 18:05:53 2016 -0400 @@ -39,6 +39,7 @@ #include "error.h" #include "errwarn.h" #include "input.h" +#include "interpreter.h" #include "oct-hdf5.h" #include "oct-map.h" #include "ov-base.h"
--- a/libinterp/octave-value/ov-fcn-inline.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-fcn-inline.cc Mon Jul 11 18:05:53 2016 -0400 @@ -47,7 +47,7 @@ #include "pr-output.h" #include "variables.h" #include "parse.h" -#include "toplev.h" +#include "interpreter.h" #include "byte-swap.h" #include "ls-ascii-helper.h"
--- a/libinterp/octave-value/ov-mex-fcn.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-mex-fcn.cc Mon Jul 11 18:05:53 2016 -0400 @@ -35,7 +35,7 @@ #include "ov-mex-fcn.h" #include "ov.h" #include "profiler.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h"
--- a/libinterp/octave-value/ov-oncleanup.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-oncleanup.cc Mon Jul 11 18:05:53 2016 -0400 @@ -25,11 +25,11 @@ #endif #include "defun.h" +#include "interpreter.h" #include "ov-oncleanup.h" #include "ov-fcn.h" #include "ov-usr-fcn.h" #include "pt-misc.h" -#include "toplev.h" DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_oncleanup, "onCleanup", "onCleanup");
--- a/libinterp/octave-value/ov-usr-fcn.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave-value/ov-usr-fcn.cc Mon Jul 11 18:05:53 2016 -0400 @@ -48,7 +48,7 @@ #include "pt-stmt.h" #include "pt-walk.h" #include "symtab.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "parse.h"
--- a/libinterp/octave.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave.cc Mon Jul 11 18:05:53 2016 -0400 @@ -26,346 +26,28 @@ # include "config.h" #endif -#include <cassert> -#include <clocale> -#include <cstdlib> -#include <cstring> -#include <ctime> +#include <string> -#include <iostream> - -#include "cmd-edit.h" -#include "f77-fcn.h" #include "file-ops.h" -#include "file-stat.h" -#include "fpucw-wrappers.h" #include "getopt-wrapper.h" #include "lo-error.h" #include "oct-env.h" #include "str-vec.h" -#include "signal-wrappers.h" -#include "unistd-wrappers.h" -#include "build-env.h" -#include "builtins.h" -#include "defaults.h" +#include "builtin-defun-decls.h" #include "Cell.h" #include "defun.h" #include "display.h" #include "error.h" -#include "file-io.h" -#include "help.h" #include "input.h" -#include "lex.h" -#include "load-path.h" -#include "load-save.h" +#include "interpreter.h" #include "octave.h" #include "oct-hist.h" #include "oct-map.h" -#include "oct-mutex.h" #include "ovl.h" -#include "ops.h" #include "options-usage.h" #include "ov.h" -#include "ov-classdef.h" -#include "ov-range.h" -#include "toplev.h" #include "parse.h" -#include "procstream.h" -#include "sighandlers.h" -#include "sysdep.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include <version.h> - -// Kluge. -extern "C" F77_RET_T -F77_FUNC (xerbla, XERBLA) (F77_CONST_CHAR_ARG_DECL, - const octave_idx_type& - F77_CHAR_ARG_LEN_DECL); - -extern void install_builtins (void); - -// Store the command-line options for later use. - -static void -execute_pkg_add (const std::string& dir) -{ - std::string file_name = octave::sys::file_ops::concat (dir, "PKG_ADD"); - - try - { - load_path::execute_pkg_add (dir); - } - catch (const index_exception& e) - { - recover_from_exception (); - - std::cerr << "error: index exception in " << file_name << ": " - << e.message () << std::endl; - } - catch (const octave_interrupt_exception&) - { - recover_from_exception (); - - if (quitting_gracefully) - clean_up_and_exit (exit_status); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - - std::cerr << "error: execution exception in " << file_name << std::endl; - } -} - -static void -initialize_load_path (bool set_initial_path) -{ - // Temporarily set the execute_pkg_add function to one that catches - // exceptions. This is better than wrapping load_path::initialize in - // a try-catch block because it will not stop executing PKG_ADD files - // at the first exception. It's also better than changing the default - // execute_pkg_add function to use safe_source file because that will - // normally be evaluated from the normal intepreter loop where - // exceptions are already handled. - - octave::unwind_protect frame; - - frame.add_fcn (load_path::set_add_hook, load_path::get_add_hook ()); - - load_path::set_add_hook (execute_pkg_add); - - load_path::initialize (set_initial_path); -} - -DEFUN (__version_info__, args, , - doc: /* -*- texinfo -*- -@deftypefn {} {retval =} __version_info__ (@var{name}, @var{version}, @var{release}, @var{date}) -Undocumented internal function. -@end deftypefn */) -{ - static octave_map vinfo; - - int nargin = args.length (); - - if (nargin != 0 && nargin != 4) - print_usage (); - - octave_value retval; - - if (nargin == 0) - retval = vinfo; - else if (nargin == 4) - { - if (vinfo.nfields () == 0) - { - vinfo.assign ("Name", args(0)); - vinfo.assign ("Version", args(1)); - vinfo.assign ("Release", args(2)); - vinfo.assign ("Date", args(3)); - } - else - { - octave_idx_type n = vinfo.numel () + 1; - - vinfo.resize (dim_vector (n, 1)); - - octave_value idx (n); - - vinfo.assign (idx, "Name", Cell (octave_value (args(0)))); - vinfo.assign (idx, "Version", Cell (octave_value (args(1)))); - vinfo.assign (idx, "Release", Cell (octave_value (args(2)))); - vinfo.assign (idx, "Date", Cell (octave_value (args(3)))); - } - } - - return retval; -} - -static void -initialize_version_info (void) -{ - octave_value_list args; - - args(3) = OCTAVE_RELEASE_DATE; - args(2) = OCTAVE_RELEASE; - args(1) = OCTAVE_VERSION; - args(0) = "GNU Octave"; - - F__version_info__ (args, 0); -} - -// 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 = "", - bool verbose = false, bool require_file = true, - const std::string& warn_for = "") -{ - try - { - source_file (file_name, context, verbose, require_file, warn_for); - } - catch (const index_exception& e) - { - recover_from_exception (); - - std::cerr << "error: index exception in " << file_name << ": " - << e.message () << std::endl; - } - catch (const octave_interrupt_exception&) - { - recover_from_exception (); - - if (quitting_gracefully) - clean_up_and_exit (exit_status); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - - std::cerr << "error: execution exception in " << file_name << std::endl; - } -} - -// Initialize by reading startup files. - -static void -execute_startup_files (bool read_site_files, bool read_init_files, - bool verbose_flag, bool inhibit_startup_message) -{ - octave::unwind_protect frame; - - std::string context; - - bool verbose = (verbose_flag && ! inhibit_startup_message); - - bool require_file = false; - - if (read_site_files) - { - // Execute commands from the site-wide configuration file. - // First from the file $(prefix)/lib/octave/site/m/octaverc - // (if it exists), then from the file - // $(prefix)/share/octave/$(version)/m/octaverc (if it exists). - - safe_source_file (Vlocal_site_defaults_file, context, verbose, - require_file); - - safe_source_file (Vsite_defaults_file, context, verbose, require_file); - } - - if (read_init_files) - { - // Try to execute commands from $HOME/$OCTAVE_INITFILE and - // $OCTAVE_INITFILE. If $OCTAVE_INITFILE is not set, - // .octaverc is assumed. - - bool home_rc_already_executed = false; - - std::string initfile = octave::sys::env::getenv ("OCTAVE_INITFILE"); - - if (initfile.empty ()) - initfile = ".octaverc"; - - std::string home_dir = octave::sys::env::get_home_directory (); - - std::string home_rc = octave::sys::env::make_absolute (initfile, home_dir); - - std::string local_rc; - - if (! home_rc.empty ()) - { - safe_source_file (home_rc, context, verbose, require_file); - - // Names alone are not enough. - - octave::sys::file_stat fs_home_rc (home_rc); - - if (fs_home_rc) - { - // We want to check for curr_dir after executing home_rc - // because doing that may change the working directory. - - local_rc = octave::sys::env::make_absolute (initfile); - - home_rc_already_executed = same_file (home_rc, local_rc); - } - } - - if (! home_rc_already_executed) - { - if (local_rc.empty ()) - local_rc = octave::sys::env::make_absolute (initfile); - - safe_source_file (local_rc, context, verbose, require_file); - } - } -} - -OCTAVE_NORETURN static void -lo_error_handler (const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - verror_with_cfn (fmt, args); - va_end (args); - - octave_throw_execution_exception (); -} - -OCTAVE_NORETURN static void -lo_error_with_id_handler (const char *id, const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - verror_with_id_cfn (id, fmt, args); - va_end (args); - - octave_throw_execution_exception (); -} - -static void -initialize_error_handlers () -{ - set_liboctave_error_handler (lo_error_handler); - set_liboctave_error_with_id_handler (lo_error_with_id_handler); - set_liboctave_warning_handler (warning); - set_liboctave_warning_with_id_handler (warning_with_id); -} - -// What internal options get configured by --traditional. - -static void -maximum_braindamage (void) -{ - FPS1 (octave_value (">> ")); - FPS2 (octave_value ("")); - FPS4 (octave_value ("")); - Fbeep_on_error (octave_value (true)); - Fconfirm_recursive_rmdir (octave_value (false)); - Fcrash_dumps_octave_core (octave_value (false)); - Fdisable_diagonal_matrix (octave_value (true)); - Fdisable_permutation_matrix (octave_value (true)); - Fdisable_range (octave_value (true)); - Ffixed_point_format (octave_value (true)); - Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%")); - Fpage_screen_output (octave_value (false)); - Fprint_empty_dimensions (octave_value (false)); - Fsave_default_options (octave_value ("-mat-binary")); - Fstruct_levels_to_print (octave_value (0)); - - disable_warning ("Octave:abbreviated-property-match"); - disable_warning ("Octave:data-file-in-path"); - disable_warning ("Octave:function-name-clash"); - disable_warning ("Octave:possible-matlab-short-circuit-operator"); -} namespace octave { @@ -743,332 +425,6 @@ return execute_interpreter (); } - - interpreter::interpreter (application *app_context, bool embedded) - : m_app_context (app_context), m_embedded (embedded), - m_interactive (false) - { - cmdline_options options = m_app_context->options (); - - sysdep_init (); - - install_defaults (); - - // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting - setlocale (LC_NUMERIC, "C"); - setlocale (LC_TIME, "C"); - octave::sys::env::putenv ("LC_NUMERIC", "C"); - octave::sys::env::putenv ("LC_TIME", "C"); - - // Initialize the default floating point unit control state. - octave_set_default_fpucw (); - - string_vector all_args = options.all_args (); - - octave_thread::init (); - - set_default_prompts (); - - // Initialize default warning state before --traditional option - // that may reset them. - - initialize_default_warning_state (); - - if (options.traditional ()) - maximum_braindamage (); - - octave_ieee_init (); - - // The idea here is to force xerbla to be referenced so that we will link to - // our own version instead of the one provided by the BLAS library. But - // octave::numeric_limits<double>::NaN () should never be -1, so we - // should never actually call xerbla. FIXME (again!): If this - // becomes a constant expression the test might be optimized away and - // then the reference to the function might also disappear. - - if (octave::numeric_limits<double>::NaN () == -1) - F77_FUNC (xerbla, XERBLA) ("octave", 13 F77_CHAR_ARG_LEN (6)); - - initialize_error_handlers (); - - if (! m_embedded) - octave::install_signal_handlers (); - else - quit_allowed = false; - - initialize_file_io (); - - install_types (); - - install_ops (); - - install_builtins (); - - install_classdef (); - - std::list<std::string> command_line_path = options.command_line_path (); - - for (std::list<std::string>::const_iterator it = command_line_path.begin (); - it != command_line_path.end (); it++) - load_path::set_command_line_path (*it); - - std::string exec_path = options.exec_path (); - if (! exec_path.empty ()) - set_exec_path (exec_path); - - std::string image_path = options.image_path (); - if (! image_path.empty ()) - set_image_path (image_path); - - if (options.no_window_system ()) - display_info::no_window_system (); - - // Is input coming from a terminal? If so, we are probably interactive. - - // If stdin is not a tty, then we are reading commands from a pipe or - // a redirected file. - bool stdin_is_tty = octave_isatty_wrapper (fileno (stdin)); - - m_interactive = (! m_embedded - && ! m_app_context->is_octave_program () - && stdin_is_tty - && octave_isatty_wrapper (fileno (stdout))); - - // Check if the user forced an interactive session. If he - // unnecessarily did so, reset forced_interactive to false. - if (options.forced_interactive ()) - { - if (m_interactive) - options.forced_interactive (false); - else - m_interactive = true; - } - - if ((! m_interactive || options.forced_interactive ()) - && ! options.forced_line_editing ()) - options.line_editing (false); - - // Also skip start-up message unless session is interactive. - if (! m_interactive) - options.inhibit_startup_message (true); - - // Force default line editor if we don't want readline editing. - if (! options.line_editing ()) - octave::command_editor::force_default_editor (); - - // These can come after command line args since none of them set any - // defaults that might be changed by command line options. - - if (options.line_editing ()) - initialize_command_input (); - - octave_interpreter_ready = true; - - initialize_version_info (); - - // Make all command-line arguments available to startup files, - // including PKG_ADD files. - - app_context->intern_argv (options.all_args ()); - - initialize_load_path (options.set_initial_path ()); - - initialize_history (options.read_history_file ()); - } - - int interpreter::execute (void) - { - cmdline_options options = m_app_context->options (); - - if (! options.inhibit_startup_message ()) - std::cout << octave_startup_message () << "\n" << std::endl; - - octave_prepare_hdf5 (); - - execute_startup_files (options.read_site_files (), - options.read_init_files (), - options.verbose_flag (), - options.inhibit_startup_message ()); - - if (! options.inhibit_startup_message () - && reading_startup_message_printed) - std::cout << std::endl; - - // Execute any code specified with --eval 'CODE' - std::string code_to_eval = options.code_to_eval (); - - if (! code_to_eval.empty ()) - { - int parse_status = 0; - - try - { - parse_status = execute_eval_option_code (code_to_eval); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - - parse_status = 1; - } - - if (! options.persist ()) - { - quitting_gracefully = true; - - clean_up_and_exit (parse_status); - } - } - - // If there is an extra argument, see if it names a file to read. - // Additional arguments are taken as command line options for the script. - - if (m_app_context->have_script_file ()) - { - // If we are running an executable script (#! /bin/octave) then - // we should only see the args passed to the script. - - exit_status = 0; - - try - { - string_vector script_args = options.remaining_args (); - - m_app_context->intern_argv (script_args); - - execute_command_line_file (script_args[0]); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - - exit_status = 1; - } - - // Restore full set of args. - m_app_context->intern_argv (options.all_args ()); - - if (! options.persist ()) - { - quitting_gracefully = true; - - clean_up_and_exit (exit_status); - } - } - - // Avoid counting commands executed from startup or script files. - - octave::command_editor::reset_current_command_number (1); - - // Force input to be echoed if not really interactive, - // but the user has forced interactive behavior. - - if (options.forced_interactive ()) - { - octave::command_editor::blink_matching_paren (false); - - // FIXME: is this the right thing to do? - Fecho_executing_commands (octave_value (ECHO_CMD_LINE)); - } - - if (m_embedded) - { - // FIXME: Do we need to do any cleanup here before returning? - // If we don't, what will happen to Octave functions that have been - // registered to execute with atexit, for example? - - return 1; - } - - int retval = main_loop (); - - quitting_gracefully = true; - - clean_up_and_exit (retval, true); - - return retval; - } - - int interpreter::execute_eval_option_code (const std::string& code) - { - octave::unwind_protect frame; - - octave_save_signal_mask (); - - octave::can_interrupt = true; - - octave_signal_hook = octave::signal_handler; - octave_interrupt_hook = 0; - octave_bad_alloc_hook = 0; - - octave::catch_interrupts (); - - octave_initialized = true; - - frame.add_method (this, &interpreter::interactive, m_interactive); - - m_interactive = false; - - int parse_status = 0; - - try - { - eval_string (code, false, parse_status, 0); - } - catch (const octave_interrupt_exception&) - { - recover_from_exception (); - - if (quitting_gracefully) - clean_up_and_exit (exit_status); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - - std::cerr << "error: unhandled execution exception -- eval failed" - << std::endl; - } - - return parse_status; - } - - void interpreter::execute_command_line_file (const std::string& fname) - { - octave::unwind_protect frame; - - octave_save_signal_mask (); - - octave::can_interrupt = true; - - octave_signal_hook = octave::signal_handler; - octave_interrupt_hook = 0; - octave_bad_alloc_hook = 0; - - octave::catch_interrupts (); - - octave_initialized = true; - - frame.add_method (this, &interpreter::interactive, m_interactive); - - frame.add_method (m_app_context, - &application::program_invocation_name, - application::program_invocation_name ()); - - frame.add_method (m_app_context, - &application::program_name, - application::program_name ()); - - m_interactive = false; - - m_app_context->set_program_names (fname); - - std::string context; - bool verbose = false; - bool require_file = true; - - safe_source_file (fname, context, verbose, require_file, "octave"); - } } // embedded is int here because octave_main is extern "C".
--- a/libinterp/octave.h Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/octave.h Mon Jul 11 18:05:53 2016 -0400 @@ -173,8 +173,8 @@ // The application object contains a pointer to the current // interpreter and the interpreter contains a pointer back to the - // application context so we need a forward declaration for one of - // them... + // application context so we need a forward declaration for one (or + // both) of them... class interpreter; @@ -330,39 +330,6 @@ embedded_application& operator = (const embedded_application&); }; - - class OCTINTERP_API interpreter - { - public: - - interpreter (application *app_context = 0, bool embedded = false); - - ~interpreter (void) { } - - int execute (void); - - int execute_eval_option_code (const std::string& code); - - void execute_command_line_file (const std::string& fname); - - bool interactive (void) const { return m_interactive; } - void interactive (bool arg) { m_interactive = arg; } - - private: - - // No copying, at least not yet... - - interpreter (const interpreter&); - - interpreter& operator = (const interpreter&); - - application *m_app_context; - - bool m_embedded; - - // TRUE means this is an interactive interpreter (forced or not). - bool m_interactive = false; - }; } #endif
--- a/libinterp/parse-tree/lex.ll Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/parse-tree/lex.ll Mon Jul 11 18:05:53 2016 -0400 @@ -106,6 +106,7 @@ #include "error.h" #include "errwarn.h" #include "input.h" +#include "interpreter.h" #include "lex.h" #include "octave.h" #include "ov.h" @@ -113,7 +114,6 @@ #include "pt-all.h" #include "symtab.h" #include "token.h" -#include "toplev.h" #include "utils.h" #include "variables.h" #include <oct-parse.h> @@ -2321,8 +2321,7 @@ // Only ask for input from stdin if we are expecting interactive // input. - if (! quitting_gracefully - && octave::application::interactive () + if (octave::application::interactive () && ! (reading_fcn_file || reading_classdef_file || reading_script_file
--- a/libinterp/parse-tree/oct-parse.in.yy Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/parse-tree/oct-parse.in.yy Mon Jul 11 18:05:53 2016 -0400 @@ -61,6 +61,7 @@ #include "dynamic-ld.h" #include "error.h" #include "input.h" +#include "interpreter.h" #include "lex.h" #include "load-path.h" #include "oct-hist.h" @@ -69,7 +70,6 @@ #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "ov-null-mat.h" -#include "toplev.h" #include "pager.h" #include "parse.h" #include "pt-all.h"
--- a/libinterp/parse-tree/pt-arg-list.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/parse-tree/pt-arg-list.cc Mon Jul 11 18:05:53 2016 -0400 @@ -41,7 +41,7 @@ #include "pt-id.h" #include "pt-pr-code.h" #include "pt-walk.h" -#include "toplev.h" +#include "interpreter.h" #include "unwind-prot.h" // Argument lists.
--- a/libinterp/parse-tree/pt-bp.h Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/parse-tree/pt-bp.h Mon Jul 11 18:05:53 2016 -0400 @@ -29,7 +29,7 @@ #include "ov-usr-fcn.h" #include "pt-walk.h" #include "pt-pr-code.h" -#include "toplev.h" +#include "interpreter.h" class tree; class tree_decl_command;
--- a/libinterp/parse-tree/pt-eval.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/libinterp/parse-tree/pt-eval.cc Mon Jul 11 18:05:53 2016 -0400 @@ -37,13 +37,13 @@ #include "error.h" #include "errwarn.h" #include "input.h" +#include "interpreter.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "variables.h" #include "pt-all.h" #include "pt-eval.h" #include "symtab.h" -#include "toplev.h" #include "unwind-prot.h" //FIXME: This should be part of tree_evaluator
--- a/liboctave/cruft/misc/cquit.c Tue Jul 12 10:17:45 2016 +0200 +++ b/liboctave/cruft/misc/cquit.c Mon Jul 11 18:05:53 2016 -0400 @@ -59,4 +59,8 @@ sig_atomic_t octave_exception_state = 0; +sig_atomic_t octave_exit_exception_status = 0; + +sig_atomic_t octave_exit_exception_safe_to_return = 0; + volatile sig_atomic_t octave_signal_caught = 0;
--- a/liboctave/cruft/misc/quit.cc Tue Jul 12 10:17:45 2016 +0200 +++ b/liboctave/cruft/misc/quit.cc Mon Jul 11 18:05:53 2016 -0400 @@ -48,6 +48,14 @@ } } +extern OCTAVE_API void +clean_up_and_exit (int exit_status, bool safe_to_return) +{ + octave_exception_state = octave_quit_exception; + + throw octave_exit_exception (exit_status, safe_to_return); +} + void octave_throw_interrupt_exception (void) { @@ -98,6 +106,11 @@ octave_throw_bad_alloc (); break; + case octave_quit_exception: + clean_up_and_exit (octave_exit_exception_status, + octave_exit_exception_safe_to_return); + break; + default: break; }
--- a/liboctave/cruft/misc/quit.h Tue Jul 12 10:17:45 2016 +0200 +++ b/liboctave/cruft/misc/quit.h Mon Jul 11 18:05:53 2016 -0400 @@ -59,6 +59,7 @@ OCTAVE_NORETURN OCTAVE_API extern void octave_jump_to_enclosing_context (void); #if defined (__cplusplus) + class octave_execution_exception { @@ -100,16 +101,55 @@ }; class +octave_exit_exception +{ +public: + + octave_exit_exception (int exit_status = 0, bool safe_to_return = false) + : m_exit_status (exit_status), m_safe_to_return (safe_to_return) + { } + + octave_exit_exception (const octave_exit_exception& ex) + : m_exit_status (ex.m_exit_status), m_safe_to_return (ex.m_safe_to_return) + { } + + octave_exit_exception& operator = (octave_exit_exception& ex) + { + if (this != &ex) + { + m_exit_status = ex.m_exit_status; + m_safe_to_return = ex.m_safe_to_return; + } + + return *this; + } + + ~octave_exit_exception (void) { } + + int exit_status (void) const { return m_exit_status; } + + bool safe_to_return (void) const { return m_safe_to_return; } + +private: + + int m_exit_status; + + bool m_safe_to_return; +}; + +class octave_interrupt_exception { }; + #endif enum octave_exception { octave_no_exception = 0, octave_exec_exception = 1, - octave_alloc_exception = 2 + octave_alloc_exception = 3, + octave_quit_exception = 4 }; OCTAVE_API extern sig_atomic_t octave_interrupt_immediately; @@ -123,6 +163,10 @@ OCTAVE_API extern sig_atomic_t octave_exception_state; +OCTAVE_API extern sig_atomic_t octave_exit_exception_status; + +OCTAVE_API extern sig_atomic_t octave_exit_exception_safe_to_return; + OCTAVE_API extern volatile sig_atomic_t octave_signal_caught; OCTAVE_API extern void octave_handle_signal (void); @@ -136,6 +180,10 @@ OCTAVE_API extern void octave_rethrow_exception (void); #if defined (__cplusplus) + +extern OCTAVE_API void +clean_up_and_exit (int exit_status, bool safe_to_return = false); + inline void octave_quit (void) { if (octave_signal_caught) @@ -234,6 +282,14 @@ octave_exception_state = octave_alloc_exception; \ octave_jump_to_enclosing_context (); \ } \ + catch (const octave_exit_exception& ex) \ + { \ + octave_interrupt_immediately = saved_octave_interrupt_immediately; \ + octave_exception_state = octave_quit_exception; \ + octave_exit_exception_status = ex.exit_status (); \ + octave_exit_exception_safe_to_return = ex.safe_to_return (); \ + octave_jump_to_enclosing_context (); \ + } \ \ octave_interrupt_immediately = saved_octave_interrupt_immediately #endif