comparison libinterp/corefcn/interpreter.cc @ 31607:aac27ad79be6 stable

maint: Re-indent code after switch to using namespace macros. * build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc, __ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc, __pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h, besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc, call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc, debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc, dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h, error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h, event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc, file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h, gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h, graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc, gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h, interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h, inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc, latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h, lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc, matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h, oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc, oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h, oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h, octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc, pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc, settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc, sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc, syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h, symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h, text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc, url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h, variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc, __init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc, gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc, cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h, cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h, cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc, ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc, ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc, ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h, ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc, ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc, ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc, ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc, ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h, ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc, ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc, ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h, octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc, op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h, anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h, comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h, parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h, pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h, pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc, pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc, pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h, pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h, pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h, pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h, pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h, idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h, aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h, gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc, lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h, oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc, oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h, randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h, sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc, sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h, file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h, lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h, oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc, oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h, action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h, cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h, lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h, lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc, oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc, oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc, oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc, pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc, url-transfer.h: Re-indent code after switch to using namespace macros.
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 18:02:15 -0800
parents e88a07dec498
children d9970470108a
comparison
equal deleted inserted replaced
31605:e88a07dec498 31607:aac27ad79be6
285 print_usage (); 285 print_usage ();
286 286
287 std::string arg = args(0).xstring_value ("atexit: FCN argument must be a string"); 287 std::string arg = args(0).xstring_value ("atexit: FCN argument must be a string");
288 288
289 bool add_mode = (nargin == 2) 289 bool add_mode = (nargin == 2)
290 ? args(1).xbool_value ("atexit: FLAG argument must be a logical value") 290 ? args(1).xbool_value ("atexit: FLAG argument must be a logical value")
291 : true; 291 : true;
292 292
293 octave_value_list retval; 293 octave_value_list retval;
294 294
295 if (add_mode) 295 if (add_mode)
296 interp.add_atexit_fcn (arg); 296 interp.add_atexit_fcn (arg);
312 @end deftypefn */) 312 @end deftypefn */)
313 { 313 {
314 return ovl (interp.traditional ()); 314 return ovl (interp.traditional ());
315 } 315 }
316 316
317 temporary_file_list::~temporary_file_list (void) 317 temporary_file_list::~temporary_file_list (void)
318 {
319 cleanup ();
320 }
321
322 void temporary_file_list::insert (const std::string& file)
323 {
324 m_files.insert (file);
325 }
326
327 void temporary_file_list::cleanup (void)
328 {
329 while (! m_files.empty ())
330 {
331 auto it = m_files.begin ();
332
333 octave_unlink_wrapper (it->c_str ());
334
335 m_files.erase (it);
336 }
337 }
338
339 // The time we last time we changed directories.
340 sys::time Vlast_chdir_time = 0.0;
341
342 // Execute commands from a file and catch potential exceptions in a consistent
343 // way. This function should be called anywhere we might parse and execute
344 // commands from a file before we have entered the main loop in
345 // toplev.cc.
346
347 static int safe_source_file (const std::string& file_name,
348 const std::string& context = "",
349 bool verbose = false,
350 bool require_file = true)
351 {
352 interpreter& interp = __get_interpreter__ ();
353
354 try
355 {
356 source_file (file_name, context, verbose, require_file);
357 }
358 catch (const interrupt_exception&)
359 {
360 interp.recover_from_exception ();
361
362 return 1;
363 }
364 catch (const execution_exception& ee)
365 {
366 interp.handle_exception (ee);
367
368 return 1;
369 }
370
371 return 0;
372 }
373
374 static void initialize_version_info (void)
375 {
376 octave_value_list args;
377
378 args(3) = OCTAVE_RELEASE_DATE;
379 args(2) = config::release ();
380 args(1) = OCTAVE_VERSION;
381 args(0) = "GNU Octave";
382
383 F__version_info__ (args, 0);
384 }
385
386 static void xerbla_abort (void)
387 {
388 error ("Fortran procedure terminated by call to XERBLA");
389 }
390
391 static void initialize_xerbla_error_handler (void)
392 {
393 // The idea here is to force xerbla to be referenced so that we will
394 // link to our own version instead of the one provided by the BLAS
395 // library. But numeric_limits<double>::NaN () should never be -1, so
396 // we should never actually call xerbla. FIXME (again!): If this
397 // becomes a constant expression the test might be optimized away and
398 // then the reference to the function might also disappear.
399
400 if (numeric_limits<double>::NaN () == -1)
401 F77_FUNC (xerbla, XERBLA) ("octave", 13 F77_CHAR_ARG_LEN (6));
402
403 typedef void (*xerbla_handler_ptr) (void);
404
405 typedef void (*octave_set_xerbla_handler_ptr) (xerbla_handler_ptr);
406
407 dynamic_library libs ("");
408
409 if (libs)
410 {
411 octave_set_xerbla_handler_ptr octave_set_xerbla_handler
412 = reinterpret_cast<octave_set_xerbla_handler_ptr>
413 (libs.search ("octave_set_xerbla_handler"));
414
415 if (octave_set_xerbla_handler)
416 octave_set_xerbla_handler (xerbla_abort);
417 }
418 }
419
420 OCTAVE_NORETURN static void
421 lo_error_handler (const char *fmt, ...)
422 {
423 va_list args;
424 va_start (args, fmt);
425 verror_with_cfn (fmt, args);
426 va_end (args);
427
428 throw execution_exception ();
429 }
430
431 OCTAVE_NORETURN static void
432 lo_error_with_id_handler (const char *id, const char *fmt, ...)
433 {
434 va_list args;
435 va_start (args, fmt);
436 verror_with_id_cfn (id, fmt, args);
437 va_end (args);
438
439 throw execution_exception ();
440 }
441
442 static void initialize_error_handlers (void)
443 {
444 set_liboctave_error_handler (lo_error_handler);
445 set_liboctave_error_with_id_handler (lo_error_with_id_handler);
446 set_liboctave_warning_handler (warning);
447 set_liboctave_warning_with_id_handler (warning_with_id);
448 }
449
450 // Create an interpreter object and perform initialization up to the
451 // point of setting reading command history and setting the load
452 // path.
453
454 interpreter::interpreter (application *app_context)
455 : m_app_context (app_context),
456 m_tmp_files (),
457 m_atexit_fcns (),
458 m_display_info (),
459 m_environment (),
460 m_settings (),
461 m_error_system (*this),
462 m_evaluator (*this),
463 m_help_system (*this),
464 m_input_system (*this),
465 m_output_system (*this),
466 m_history_system (*this),
467 m_dynamic_loader (*this),
468 m_load_path (*this),
469 m_load_save_system (*this),
470 m_type_info (),
471 m_symbol_table (*this),
472 m_stream_list (*this),
473 m_child_list (),
474 m_url_handle_manager (),
475 m_cdef_manager (*this),
476 m_gtk_manager (),
477 m_event_manager (*this),
478 m_gh_manager (nullptr),
479 m_interactive (false),
480 m_read_site_files (true),
481 m_read_init_files (m_app_context != nullptr),
482 m_verbose (false),
483 m_traditional (false),
484 m_inhibit_startup_message (false),
485 m_load_path_initialized (false),
486 m_history_initialized (false),
487 m_interrupt_all_in_process_group (true),
488 m_cancel_quit (false),
489 m_executing_finish_script (false),
490 m_executing_atexit (false),
491 m_initialized (false)
492 {
493 // FIXME: When thread_local storage is used by default, this message
494 // should change to say something like
495 //
496 // only one Octave interpreter may be active in any given thread
497
498 if (m_instance)
499 throw std::runtime_error
500 ("only one Octave interpreter may be active");
501
502 m_instance = this;
503
504 #if defined (OCTAVE_HAVE_WINDOWS_UTF8_LOCALE)
505 // Force a UTF-8 locale on Windows if possible
506 std::setlocale (LC_ALL, ".UTF8");
507 #else
508 std::setlocale (LC_ALL, "");
509 #endif
510 // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting
511 std::setlocale (LC_NUMERIC, "C");
512 std::setlocale (LC_TIME, "C");
513 sys::env::putenv ("LC_NUMERIC", "C");
514 sys::env::putenv ("LC_TIME", "C");
515
516 // Initialize the default floating point unit control state.
517 octave_set_default_fpucw ();
518
519 thread::init ();
520
521 octave_ieee_init ();
522
523 initialize_xerbla_error_handler ();
524
525 initialize_error_handlers ();
526
527 if (m_app_context)
528 {
529 install_signal_handlers ();
530 octave_unblock_signal_by_name ("SIGTSTP");
531 }
532 else
533 quit_allowed = false;
534
535 if (! m_app_context)
536 m_display_info.initialize ();
537
538 bool line_editing = false;
539
540 if (m_app_context)
541 {
542 // Embedded interpreters don't execute command line options.
543 const cmdline_options& options = m_app_context->options ();
544
545 // Make all command-line arguments available to startup files,
546 // including PKG_ADD files.
547
548 string_vector args = options.all_args ();
549
550 m_app_context->intern_argv (args);
551 intern_nargin (args.numel () - 1);
552
553 bool is_octave_program = m_app_context->is_octave_program ();
554
555 std::list<std::string> command_line_path = options.command_line_path ();
556
557 for (const auto& pth : command_line_path)
558 m_load_path.set_command_line_path (pth);
559
560 std::string exec_path = options.exec_path ();
561 if (! exec_path.empty ())
562 m_environment.exec_path (exec_path);
563
564 std::string image_path = options.image_path ();
565 if (! image_path.empty ())
566 m_environment.image_path (image_path);
567
568 if (! options.no_window_system ())
569 m_display_info.initialize ();
570
571 // Is input coming from a terminal? If so, we are probably
572 // interactive.
573
574 // If stdin is not a tty, then we are reading commands from a
575 // pipe or a redirected file.
576 bool stdin_is_tty = octave_isatty_wrapper (fileno (stdin));
577
578 m_interactive = (! is_octave_program && stdin_is_tty
579 && octave_isatty_wrapper (fileno (stdout)));
580
581 // Don't force interactive if we're already interactive (bug #60696).
582 bool forced_interactive = options.forced_interactive ();
583 if (m_interactive)
584 {
585 m_app_context->forced_interactive (false);
586 forced_interactive = false;
587 }
588
589 // Check if the user forced an interactive session.
590 if (forced_interactive)
591 m_interactive = true;
592
593 line_editing = options.line_editing ();
594 if ((! m_interactive || forced_interactive)
595 && ! options.forced_line_editing ())
596 line_editing = false;
597
598 m_traditional = options.traditional ();
599
600 // FIXME: if possible, perform the following actions directly
601 // instead of using the interpreter-level functions.
602
603 if (options.echo_commands ())
604 m_evaluator.echo
605 (tree_evaluator::ECHO_SCRIPTS | tree_evaluator::ECHO_FUNCTIONS
606 | tree_evaluator::ECHO_ALL);
607
608 std::string docstrings_file = options.docstrings_file ();
609 if (! docstrings_file.empty ())
610 Fbuilt_in_docstrings_file (*this, octave_value (docstrings_file));
611
612 std::string doc_cache_file = options.doc_cache_file ();
613 if (! doc_cache_file.empty ())
614 Fdoc_cache_file (*this, octave_value (doc_cache_file));
615
616 std::string info_file = options.info_file ();
617 if (! info_file.empty ())
618 Finfo_file (*this, octave_value (info_file));
619
620 std::string info_program = options.info_program ();
621 if (! info_program.empty ())
622 Finfo_program (*this, octave_value (info_program));
623
624 std::string texi_macros_file = options.texi_macros_file ();
625 if (! texi_macros_file.empty ())
626 Ftexi_macros_file (*this, octave_value (texi_macros_file));
627 }
628
629 // FIXME: we defer creation of the gh_manager object because it
630 // creates a root_figure object that requires the display_info
631 // object, but that is currently only accessible through the global
632 // interpreter object and that is not available until after the
633 // interpreter::instance pointer is set (above). It would be better
634 // if m_gh_manager could be an object value instead of a pointer and
635 // created as part of the interpreter initialization. To do that,
636 // we should either make the display_info object independent of the
637 // interpreter object (does it really need to cache any
638 // information?) or defer creation of the root_figure object until
639 // it is actually needed.
640 m_gh_manager = new gh_manager (*this);
641
642 m_input_system.initialize (line_editing);
643
644 // These can come after command line args since none of them set any
645 // defaults that might be changed by command line options.
646
647 initialize_version_info ();
648
649 // This should be done before initializing the load path because
650 // some PKG_ADD files might need --traditional behavior.
651
652 if (m_traditional)
653 maximum_braindamage ();
654
655 octave_interpreter_ready = true;
656 }
657
658 OCTAVE_THREAD_LOCAL interpreter *interpreter::m_instance = nullptr;
659
660 interpreter::~interpreter (void)
661 {
662 if (! m_app_context)
663 shutdown ();
664
665 delete m_gh_manager;
666 }
667
668 void interpreter::intern_nargin (octave_idx_type nargs)
669 {
670 m_evaluator.set_auto_fcn_var (stack_frame::NARGIN, nargs);
671 }
672
673 // Read the history file unless a command-line option inhibits that.
674
675 void interpreter::initialize_history (bool read_history_file)
676 {
677 if (! m_history_initialized)
678 {
679 // Allow command-line option to override.
680
681 if (m_app_context)
682 {
683 const cmdline_options& options = m_app_context->options ();
684
685 read_history_file = options.read_history_file ();
686
687 if (! read_history_file)
688 command_history::ignore_entries ();
689 }
690
691 m_history_system.initialize (read_history_file);
692
693 if (! m_app_context)
694 command_history::ignore_entries ();
695
696 m_history_initialized = true;
697 }
698 }
699
700 // Set the initial path to the system default unless command-line
701 // option says to leave it empty.
702
703 void interpreter::initialize_load_path (bool set_initial_path)
704 {
705 if (! m_load_path_initialized)
706 {
707 // Allow command-line option to override.
708
709 if (m_app_context)
710 {
711 const cmdline_options& options = m_app_context->options ();
712
713 set_initial_path = options.set_initial_path ();
714 }
715
716 // Temporarily set the execute_pkg_add function to one that
717 // catches exceptions. This is better than wrapping
718 // load_path::initialize in a try-catch block because it will
719 // not stop executing PKG_ADD files at the first exception.
720 // It's also better than changing the default execute_pkg_add
721 // function to use safe_source file because that will normally
722 // be evaluated from the normal interpreter loop where exceptions
723 // are already handled.
724
725 unwind_action restore_add_hook (&load_path::set_add_hook, &m_load_path,
726 m_load_path.get_add_hook ());
727
728 m_load_path.set_add_hook ([=] (const std::string& dir)
729 { this->execute_pkg_add (dir); });
730
731 m_load_path.initialize (set_initial_path);
732
733 m_load_path_initialized = true;
734 }
735 }
736
737 // This may be called separately from execute
738
739 void interpreter::initialize (void)
740 {
741 if (m_initialized)
742 return;
743
744 if (m_app_context)
745 {
746 const cmdline_options& options = m_app_context->options ();
747
748 if (options.experimental_terminal_widget ())
749 {
750 if (! options.gui ())
751 display_startup_message ();
752 }
753 else
754 display_startup_message ();
755 }
756 else
757 display_startup_message ();
758
759 // Wait to read the history file until the interpreter reads input
760 // files and begins evaluating commands.
761
762 initialize_history ();
763
764 // Initializing the load path may execute PKG_ADD files, so can't be
765 // done until the interpreter is ready to execute commands.
766
767 // Deferring it to the execute step also allows the path to be
768 // initialized between creating and execute the interpreter, for
769 // example, to set a custom path for an embedded interpreter.
770
771 initialize_load_path ();
772
773 octave_save_signal_mask ();
774
775 can_interrupt = true;
776
777 octave_signal_hook = respond_to_pending_signals;
778 octave_interrupt_hook = nullptr;
779
780 catch_interrupts ();
781
782 // FIXME: could we eliminate this variable or make it not be global?
783 // Global used to communicate with signal handler.
784 octave_initialized = true;
785
786 m_initialized = true;
787 }
788
789 // Note: this function is currently only used with the new
790 // experimental terminal widget.
791
792 void interpreter::get_line_and_eval (void)
793 {
794 m_evaluator.get_line_and_eval ();
795 }
796
797 // Note: the following class is currently only used with the new
798 // experimental terminal widget.
799
800 class cli_input_reader
801 {
802 public:
803
804 cli_input_reader (interpreter& interp)
805 : m_interpreter (interp), m_thread () { }
806
807 cli_input_reader (const cli_input_reader&) = delete;
808
809 cli_input_reader& operator = (const cli_input_reader&) = delete;
810
811 ~cli_input_reader (void)
318 { 812 {
319 cleanup (); 813 // FIXME: Would it be better to ensure that
814 // interpreter::get_line_and_eval exits and then call
815 // m_thread.join () here?
816
817 m_thread.detach ();
320 } 818 }
321 819
322 void temporary_file_list::insert (const std::string& file) 820 void start (void)
323 { 821 {
324 m_files.insert (file); 822 m_thread = std::thread (&interpreter::get_line_and_eval, &m_interpreter);
325 } 823 }
326 824
327 void temporary_file_list::cleanup (void) 825 private:
328 { 826
329 while (! m_files.empty ()) 827 interpreter& m_interpreter;
330 { 828
331 auto it = m_files.begin (); 829 std::thread m_thread;
332 830 };
333 octave_unlink_wrapper (it->c_str ()); 831
334 832 void interpreter::parse_and_execute (const std::string& input,
335 m_files.erase (it); 833 bool& incomplete_parse)
336 } 834 {
337 } 835 m_evaluator.parse_and_execute (input, incomplete_parse);
338 836 }
339 // The time we last time we changed directories. 837
340 sys::time Vlast_chdir_time = 0.0; 838 // FIXME: this function is intended to be executed only once. Should
341 839 // we enforce that restriction?
342 // Execute commands from a file and catch potential exceptions in a consistent 840
343 // way. This function should be called anywhere we might parse and execute 841 int interpreter::execute (void)
344 // commands from a file before we have entered the main loop in 842 {
345 // toplev.cc. 843 int exit_status = 0;
346 844
347 static int safe_source_file (const std::string& file_name, 845 try
348 const std::string& context = "", 846 {
349 bool verbose = false, 847 initialize ();
350 bool require_file = true) 848
351 { 849 execute_startup_files ();
352 interpreter& interp = __get_interpreter__ (); 850
353 851 if (m_app_context)
354 try 852 {
355 { 853 const cmdline_options& options = m_app_context->options ();
356 source_file (file_name, context, verbose, require_file); 854
357 } 855 if (m_app_context->have_eval_option_code ())
358 catch (const interrupt_exception&) 856 {
359 { 857 int status = execute_eval_option_code ();
360 interp.recover_from_exception (); 858
361 859 if (status )
362 return 1; 860 exit_status = status;
363 } 861
364 catch (const execution_exception& ee) 862 if (! options.persist ())
365 { 863 {
366 interp.handle_exception (ee); 864 shutdown ();
367 865
368 return 1; 866 return exit_status;
369 } 867 }
370 868 }
371 return 0; 869
372 } 870 // If there is an extra argument, see if it names a file to
373 871 // read. Additional arguments are taken as command line options
374 static void initialize_version_info (void) 872 // for the script.
375 { 873
376 octave_value_list args; 874 if (m_app_context->have_script_file ())
377 875 {
378 args(3) = OCTAVE_RELEASE_DATE; 876 int status = execute_command_line_file ();
379 args(2) = config::release (); 877
380 args(1) = OCTAVE_VERSION; 878 if (status)
381 args(0) = "GNU Octave"; 879 exit_status = status;
382 880
383 F__version_info__ (args, 0); 881 if (! options.persist ())
384 } 882 {
385 883 shutdown ();
386 static void xerbla_abort (void) 884
387 { 885 return exit_status;
388 error ("Fortran procedure terminated by call to XERBLA"); 886 }
389 } 887 }
390 888
391 static void initialize_xerbla_error_handler (void) 889 if (options.forced_interactive ())
392 { 890 command_editor::blink_matching_paren (false);
393 // The idea here is to force xerbla to be referenced so that we will 891
394 // link to our own version instead of the one provided by the BLAS 892 if (options.server ())
395 // library. But numeric_limits<double>::NaN () should never be -1, so 893 exit_status = server_loop ();
396 // we should never actually call xerbla. FIXME (again!): If this 894 else if (options.experimental_terminal_widget ())
397 // becomes a constant expression the test might be optimized away and 895 {
398 // then the reference to the function might also disappear. 896 if (options.gui ())
399 897 {
400 if (numeric_limits<double>::NaN () == -1) 898 m_event_manager.start_gui (true);
401 F77_FUNC (xerbla, XERBLA) ("octave", 13 F77_CHAR_ARG_LEN (6)); 899
402 900 exit_status = server_loop ();
403 typedef void (*xerbla_handler_ptr) (void); 901 }
404 902 else
405 typedef void (*octave_set_xerbla_handler_ptr) (xerbla_handler_ptr); 903 {
406 904 // Use an object so that the thread started for the
407 dynamic_library libs (""); 905 // reader will be cleaned up no matter how we exit
408 906 // this function.
409 if (libs) 907
410 { 908 cli_input_reader reader (*this);
411 octave_set_xerbla_handler_ptr octave_set_xerbla_handler 909
412 = reinterpret_cast<octave_set_xerbla_handler_ptr> 910 reader.start ();
413 (libs.search ("octave_set_xerbla_handler")); 911
414 912 exit_status = server_loop ();
415 if (octave_set_xerbla_handler) 913 }
416 octave_set_xerbla_handler (xerbla_abort); 914 }
417 } 915 else
418 } 916 exit_status = main_loop ();
419 917
420 OCTAVE_NORETURN static void 918 shutdown ();
421 lo_error_handler (const char *fmt, ...) 919 }
422 { 920 }
423 va_list args; 921 catch (const exit_exception& xe)
424 va_start (args, fmt); 922 {
425 verror_with_cfn (fmt, args); 923 exit_status = xe.exit_status ();
426 va_end (args); 924
427
428 throw execution_exception ();
429 }
430
431 OCTAVE_NORETURN static void
432 lo_error_with_id_handler (const char *id, const char *fmt, ...)
433 {
434 va_list args;
435 va_start (args, fmt);
436 verror_with_id_cfn (id, fmt, args);
437 va_end (args);
438
439 throw execution_exception ();
440 }
441
442 static void initialize_error_handlers (void)
443 {
444 set_liboctave_error_handler (lo_error_handler);
445 set_liboctave_error_with_id_handler (lo_error_with_id_handler);
446 set_liboctave_warning_handler (warning);
447 set_liboctave_warning_with_id_handler (warning_with_id);
448 }
449
450 // Create an interpreter object and perform initialization up to the
451 // point of setting reading command history and setting the load
452 // path.
453
454 interpreter::interpreter (application *app_context)
455 : m_app_context (app_context),
456 m_tmp_files (),
457 m_atexit_fcns (),
458 m_display_info (),
459 m_environment (),
460 m_settings (),
461 m_error_system (*this),
462 m_evaluator (*this),
463 m_help_system (*this),
464 m_input_system (*this),
465 m_output_system (*this),
466 m_history_system (*this),
467 m_dynamic_loader (*this),
468 m_load_path (*this),
469 m_load_save_system (*this),
470 m_type_info (),
471 m_symbol_table (*this),
472 m_stream_list (*this),
473 m_child_list (),
474 m_url_handle_manager (),
475 m_cdef_manager (*this),
476 m_gtk_manager (),
477 m_event_manager (*this),
478 m_gh_manager (nullptr),
479 m_interactive (false),
480 m_read_site_files (true),
481 m_read_init_files (m_app_context != nullptr),
482 m_verbose (false),
483 m_traditional (false),
484 m_inhibit_startup_message (false),
485 m_load_path_initialized (false),
486 m_history_initialized (false),
487 m_interrupt_all_in_process_group (true),
488 m_cancel_quit (false),
489 m_executing_finish_script (false),
490 m_executing_atexit (false),
491 m_initialized (false)
492 {
493 // FIXME: When thread_local storage is used by default, this message
494 // should change to say something like
495 //
496 // only one Octave interpreter may be active in any given thread
497
498 if (m_instance)
499 throw std::runtime_error
500 ("only one Octave interpreter may be active");
501
502 m_instance = this;
503
504 #if defined (OCTAVE_HAVE_WINDOWS_UTF8_LOCALE)
505 // Force a UTF-8 locale on Windows if possible
506 std::setlocale (LC_ALL, ".UTF8");
507 #else
508 std::setlocale (LC_ALL, "");
509 #endif
510 // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting
511 std::setlocale (LC_NUMERIC, "C");
512 std::setlocale (LC_TIME, "C");
513 sys::env::putenv ("LC_NUMERIC", "C");
514 sys::env::putenv ("LC_TIME", "C");
515
516 // Initialize the default floating point unit control state.
517 octave_set_default_fpucw ();
518
519 thread::init ();
520
521 octave_ieee_init ();
522
523 initialize_xerbla_error_handler ();
524
525 initialize_error_handlers ();
526
527 if (m_app_context)
528 {
529 install_signal_handlers ();
530 octave_unblock_signal_by_name ("SIGTSTP");
531 }
532 else
533 quit_allowed = false;
534
535 if (! m_app_context)
536 m_display_info.initialize ();
537
538 bool line_editing = false;
539
540 if (m_app_context)
541 {
542 // Embedded interpreters don't execute command line options.
543 const cmdline_options& options = m_app_context->options ();
544
545 // Make all command-line arguments available to startup files,
546 // including PKG_ADD files.
547
548 string_vector args = options.all_args ();
549
550 m_app_context->intern_argv (args);
551 intern_nargin (args.numel () - 1);
552
553 bool is_octave_program = m_app_context->is_octave_program ();
554
555 std::list<std::string> command_line_path = options.command_line_path ();
556
557 for (const auto& pth : command_line_path)
558 m_load_path.set_command_line_path (pth);
559
560 std::string exec_path = options.exec_path ();
561 if (! exec_path.empty ())
562 m_environment.exec_path (exec_path);
563
564 std::string image_path = options.image_path ();
565 if (! image_path.empty ())
566 m_environment.image_path (image_path);
567
568 if (! options.no_window_system ())
569 m_display_info.initialize ();
570
571 // Is input coming from a terminal? If so, we are probably
572 // interactive.
573
574 // If stdin is not a tty, then we are reading commands from a
575 // pipe or a redirected file.
576 bool stdin_is_tty = octave_isatty_wrapper (fileno (stdin));
577
578 m_interactive = (! is_octave_program && stdin_is_tty
579 && octave_isatty_wrapper (fileno (stdout)));
580
581 // Don't force interactive if we're already interactive (bug #60696).
582 bool forced_interactive = options.forced_interactive ();
583 if (m_interactive)
584 {
585 m_app_context->forced_interactive (false);
586 forced_interactive = false;
587 }
588
589 // Check if the user forced an interactive session.
590 if (forced_interactive)
591 m_interactive = true;
592
593 line_editing = options.line_editing ();
594 if ((! m_interactive || forced_interactive)
595 && ! options.forced_line_editing ())
596 line_editing = false;
597
598 m_traditional = options.traditional ();
599
600 // FIXME: if possible, perform the following actions directly
601 // instead of using the interpreter-level functions.
602
603 if (options.echo_commands ())
604 m_evaluator.echo
605 (tree_evaluator::ECHO_SCRIPTS | tree_evaluator::ECHO_FUNCTIONS
606 | tree_evaluator::ECHO_ALL);
607
608 std::string docstrings_file = options.docstrings_file ();
609 if (! docstrings_file.empty ())
610 Fbuilt_in_docstrings_file (*this, octave_value (docstrings_file));
611
612 std::string doc_cache_file = options.doc_cache_file ();
613 if (! doc_cache_file.empty ())
614 Fdoc_cache_file (*this, octave_value (doc_cache_file));
615
616 std::string info_file = options.info_file ();
617 if (! info_file.empty ())
618 Finfo_file (*this, octave_value (info_file));
619
620 std::string info_program = options.info_program ();
621 if (! info_program.empty ())
622 Finfo_program (*this, octave_value (info_program));
623
624 std::string texi_macros_file = options.texi_macros_file ();
625 if (! texi_macros_file.empty ())
626 Ftexi_macros_file (*this, octave_value (texi_macros_file));
627 }
628
629 // FIXME: we defer creation of the gh_manager object because it
630 // creates a root_figure object that requires the display_info
631 // object, but that is currently only accessible through the global
632 // interpreter object and that is not available until after the
633 // interpreter::instance pointer is set (above). It would be better
634 // if m_gh_manager could be an object value instead of a pointer and
635 // created as part of the interpreter initialization. To do that,
636 // we should either make the display_info object independent of the
637 // interpreter object (does it really need to cache any
638 // information?) or defer creation of the root_figure object until
639 // it is actually needed.
640 m_gh_manager = new gh_manager (*this);
641
642 m_input_system.initialize (line_editing);
643
644 // These can come after command line args since none of them set any
645 // defaults that might be changed by command line options.
646
647 initialize_version_info ();
648
649 // This should be done before initializing the load path because
650 // some PKG_ADD files might need --traditional behavior.
651
652 if (m_traditional)
653 maximum_braindamage ();
654
655 octave_interpreter_ready = true;
656 }
657
658 OCTAVE_THREAD_LOCAL interpreter *interpreter::m_instance = nullptr;
659
660 interpreter::~interpreter (void)
661 {
662 if (! m_app_context)
663 shutdown (); 925 shutdown ();
664 926 }
665 delete m_gh_manager; 927
666 } 928 return exit_status;
667 929 }
668 void interpreter::intern_nargin (octave_idx_type nargs) 930
669 { 931 // Call a function with exceptions handled to avoid problems with
670 m_evaluator.set_auto_fcn_var (stack_frame::NARGIN, nargs); 932 // errors while shutting down.
671 }
672
673 // Read the history file unless a command-line option inhibits that.
674
675 void interpreter::initialize_history (bool read_history_file)
676 {
677 if (! m_history_initialized)
678 {
679 // Allow command-line option to override.
680
681 if (m_app_context)
682 {
683 const cmdline_options& options = m_app_context->options ();
684
685 read_history_file = options.read_history_file ();
686
687 if (! read_history_file)
688 command_history::ignore_entries ();
689 }
690
691 m_history_system.initialize (read_history_file);
692
693 if (! m_app_context)
694 command_history::ignore_entries ();
695
696 m_history_initialized = true;
697 }
698 }
699
700 // Set the initial path to the system default unless command-line
701 // option says to leave it empty.
702
703 void interpreter::initialize_load_path (bool set_initial_path)
704 {
705 if (! m_load_path_initialized)
706 {
707 // Allow command-line option to override.
708
709 if (m_app_context)
710 {
711 const cmdline_options& options = m_app_context->options ();
712
713 set_initial_path = options.set_initial_path ();
714 }
715
716 // Temporarily set the execute_pkg_add function to one that
717 // catches exceptions. This is better than wrapping
718 // load_path::initialize in a try-catch block because it will
719 // not stop executing PKG_ADD files at the first exception.
720 // It's also better than changing the default execute_pkg_add
721 // function to use safe_source file because that will normally
722 // be evaluated from the normal interpreter loop where exceptions
723 // are already handled.
724
725 unwind_action restore_add_hook (&load_path::set_add_hook, &m_load_path,
726 m_load_path.get_add_hook ());
727
728 m_load_path.set_add_hook ([=] (const std::string& dir)
729 { this->execute_pkg_add (dir); });
730
731 m_load_path.initialize (set_initial_path);
732
733 m_load_path_initialized = true;
734 }
735 }
736
737 // This may be called separately from execute
738
739 void interpreter::initialize (void)
740 {
741 if (m_initialized)
742 return;
743
744 if (m_app_context)
745 {
746 const cmdline_options& options = m_app_context->options ();
747
748 if (options.experimental_terminal_widget ())
749 {
750 if (! options.gui ())
751 display_startup_message ();
752 }
753 else
754 display_startup_message ();
755 }
756 else
757 display_startup_message ();
758
759 // Wait to read the history file until the interpreter reads input
760 // files and begins evaluating commands.
761
762 initialize_history ();
763
764 // Initializing the load path may execute PKG_ADD files, so can't be
765 // done until the interpreter is ready to execute commands.
766
767 // Deferring it to the execute step also allows the path to be
768 // initialized between creating and execute the interpreter, for
769 // example, to set a custom path for an embedded interpreter.
770
771 initialize_load_path ();
772
773 octave_save_signal_mask ();
774
775 can_interrupt = true;
776
777 octave_signal_hook = respond_to_pending_signals;
778 octave_interrupt_hook = nullptr;
779
780 catch_interrupts ();
781
782 // FIXME: could we eliminate this variable or make it not be global?
783 // Global used to communicate with signal handler.
784 octave_initialized = true;
785
786 m_initialized = true;
787 }
788
789 // Note: this function is currently only used with the new
790 // experimental terminal widget.
791
792 void interpreter::get_line_and_eval (void)
793 {
794 m_evaluator.get_line_and_eval ();
795 }
796
797 // Note: the following class is currently only used with the new
798 // experimental terminal widget.
799
800 class cli_input_reader
801 {
802 public:
803
804 cli_input_reader (interpreter& interp)
805 : m_interpreter (interp), m_thread () { }
806
807 cli_input_reader (const cli_input_reader&) = delete;
808
809 cli_input_reader& operator = (const cli_input_reader&) = delete;
810
811 ~cli_input_reader (void)
812 {
813 // FIXME: Would it be better to ensure that
814 // interpreter::get_line_and_eval exits and then call
815 // m_thread.join () here?
816
817 m_thread.detach ();
818 }
819
820 void start (void)
821 {
822 m_thread = std::thread (&interpreter::get_line_and_eval, &m_interpreter);
823 }
824
825 private:
826
827 interpreter& m_interpreter;
828
829 std::thread m_thread;
830 };
831
832 void interpreter::parse_and_execute (const std::string& input,
833 bool& incomplete_parse)
834 {
835 m_evaluator.parse_and_execute (input, incomplete_parse);
836 }
837
838 // FIXME: this function is intended to be executed only once. Should
839 // we enforce that restriction?
840
841 int interpreter::execute (void)
842 {
843 int exit_status = 0;
844
845 try
846 {
847 initialize ();
848
849 execute_startup_files ();
850
851 if (m_app_context)
852 {
853 const cmdline_options& options = m_app_context->options ();
854
855 if (m_app_context->have_eval_option_code ())
856 {
857 int status = execute_eval_option_code ();
858
859 if (status )
860 exit_status = status;
861
862 if (! options.persist ())
863 {
864 shutdown ();
865
866 return exit_status;
867 }
868 }
869
870 // If there is an extra argument, see if it names a file to
871 // read. Additional arguments are taken as command line options
872 // for the script.
873
874 if (m_app_context->have_script_file ())
875 {
876 int status = execute_command_line_file ();
877
878 if (status)
879 exit_status = status;
880
881 if (! options.persist ())
882 {
883 shutdown ();
884
885 return exit_status;
886 }
887 }
888
889 if (options.forced_interactive ())
890 command_editor::blink_matching_paren (false);
891
892 if (options.server ())
893 exit_status = server_loop ();
894 else if (options.experimental_terminal_widget ())
895 {
896 if (options.gui ())
897 {
898 m_event_manager.start_gui (true);
899
900 exit_status = server_loop ();
901 }
902 else
903 {
904 // Use an object so that the thread started for the
905 // reader will be cleaned up no matter how we exit
906 // this function.
907
908 cli_input_reader reader (*this);
909
910 reader.start ();
911
912 exit_status = server_loop ();
913 }
914 }
915 else
916 exit_status = main_loop ();
917
918 shutdown ();
919 }
920 }
921 catch (const exit_exception& xe)
922 {
923 exit_status = xe.exit_status ();
924
925 shutdown ();
926 }
927
928 return exit_status;
929 }
930
931 // Call a function with exceptions handled to avoid problems with
932 // errors while shutting down.
933 933
934 #define OCTAVE_IGNORE_EXCEPTION(E) \ 934 #define OCTAVE_IGNORE_EXCEPTION(E) \
935 catch (E) \ 935 catch (E) \
936 { \ 936 { \
937 recover_from_exception (); \ 937 recover_from_exception (); \
963 OCTAVE_IGNORE_EXCEPTION (const execution_exception&) \ 963 OCTAVE_IGNORE_EXCEPTION (const execution_exception&) \
964 OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&) \ 964 OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&) \
965 } \ 965 } \
966 while (0) 966 while (0)
967 967
968 void interpreter::shutdown (void) 968 void interpreter::shutdown (void)
969 { 969 {
970 // Attempt to prevent more than one call to shutdown. 970 // Attempt to prevent more than one call to shutdown.
971 971
972 if (! m_initialized) 972 if (! m_initialized)
973 return; 973 return;
974 974
975 m_initialized = false; 975 m_initialized = false;
976 976
977 OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); 977 OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0));
978 978
979 // Any atexit functions added after this function call won't be 979 // Any atexit functions added after this function call won't be
980 // executed. Each atexit function is executed with 980 // executed. Each atexit function is executed with
981 // OCTAVE_SAFE_CALL, so we don't need that here. 981 // OCTAVE_SAFE_CALL, so we don't need that here.
982 982
983 execute_atexit_fcns (); 983 execute_atexit_fcns ();
984 984
985 // Clear all functions and variables while the event manager is 985 // Clear all functions and variables while the event manager is
986 // still processing events and notify the event manager. This way, 986 // still processing events and notify the event manager. This way,
987 // the workspace model will be cleared before the GUI exits. 987 // the workspace model will be cleared before the GUI exits.
988 988
989 // FIXME: This approach seems a bit fragile since there could be 989 // FIXME: This approach seems a bit fragile since there could be
990 // other places in the GUI that have references to interpreter 990 // other places in the GUI that have references to interpreter
991 // objects. How can we reliably ensure that they are all removed 991 // objects. How can we reliably ensure that they are all removed
992 // before the interpreter exits? Maybe the best solution is to 992 // before the interpreter exits? Maybe the best solution is to
993 // always start the GUI from the interpreter and close it when the 993 // always start the GUI from the interpreter and close it when the
994 // interpreter exits? However, the workspace model is owned by the 994 // interpreter exits? However, the workspace model is owned by the
995 // base_qobject object not the workspace viewer or the main window, 995 // base_qobject object not the workspace viewer or the main window,
996 // so simply closing the GUI window(s) is not sufficient. See also 996 // so simply closing the GUI window(s) is not sufficient. See also
997 // bug #61994. 997 // bug #61994.
998 998
999 // Note that we don't force symbols to be cleared, so we will 999 // Note that we don't force symbols to be cleared, so we will
1000 // respect mlock at this point. Later, we'll force all variables 1000 // respect mlock at this point. Later, we'll force all variables
1001 // and functions to be cleared. 1001 // and functions to be cleared.
1002 1002
1003 OCTAVE_SAFE_CALL (clear_all, ()); 1003 OCTAVE_SAFE_CALL (clear_all, ());
1004 OCTAVE_SAFE_CALL (m_event_manager.clear_workspace, ()); 1004 OCTAVE_SAFE_CALL (m_event_manager.clear_workspace, ());
1005 1005
1006 // If we are attached to a GUI, queue and event to close it (only 1006 // If we are attached to a GUI, queue and event to close it (only
1007 // works with the new terminal widget), process pending events and 1007 // works with the new terminal widget), process pending events and
1008 // disable the link. 1008 // disable the link.
1009 1009
1010 OCTAVE_SAFE_CALL (m_event_manager.close_gui, ()); 1010 OCTAVE_SAFE_CALL (m_event_manager.close_gui, ());
1011 OCTAVE_SAFE_CALL (m_event_manager.process_events, (true)); 1011 OCTAVE_SAFE_CALL (m_event_manager.process_events, (true));
1012 OCTAVE_SAFE_CALL (m_event_manager.disable, ()); 1012 OCTAVE_SAFE_CALL (m_event_manager.disable, ());
1013 1013
1014 OCTAVE_SAFE_CALL (m_input_system.clear_input_event_hooks, ()); 1014 OCTAVE_SAFE_CALL (m_input_system.clear_input_event_hooks, ());
1015 1015
1016 // We may still have some figures. Close them. 1016 // We may still have some figures. Close them.
1017 1017
1018 OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); 1018 OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0));
1019 1019
1020 // What is supposed to happen if a figure has a closerequestfcn or 1020 // What is supposed to happen if a figure has a closerequestfcn or
1021 // deletefcn callback registered that creates other figures or 1021 // deletefcn callback registered that creates other figures or
1022 // variables? What if those variables are classdef objects with 1022 // variables? What if those variables are classdef objects with
1023 // destructors that can create figures? The possibilities are 1023 // destructors that can create figures? The possibilities are
1024 // endless. At some point, we have to give up and force execution 1024 // endless. At some point, we have to give up and force execution
1025 // to end. 1025 // to end.
1026 1026
1027 // Note that we again don't force symbols to be cleared, so we 1027 // Note that we again don't force symbols to be cleared, so we
1028 // continue to respect mlock here. Later, we'll force all variables 1028 // continue to respect mlock here. Later, we'll force all variables
1029 // and functions to be cleared. 1029 // and functions to be cleared.
1030 1030
1031 OCTAVE_SAFE_CALL (clear_all, ()); 1031 OCTAVE_SAFE_CALL (clear_all, ());
1032 1032
1033 // Do this explicitly so that destructors for mex file objects 1033 // Do this explicitly so that destructors for mex file objects
1034 // are called, so that functions registered with mexAtExit are 1034 // are called, so that functions registered with mexAtExit are
1035 // called. 1035 // called.
1036 1036
1037 OCTAVE_SAFE_CALL (m_symbol_table.clear_mex_functions, ()); 1037 OCTAVE_SAFE_CALL (m_symbol_table.clear_mex_functions, ());
1038 1038
1039 OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); 1039 OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
1040 1040
1041 OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ()); 1041 OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ());
1042 1042
1043 if (! command_history::ignoring_entries ()) 1043 if (! command_history::ignoring_entries ())
1044 OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); 1044 OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
1045 1045
1046 OCTAVE_SAFE_CALL (m_gtk_manager.unload_all_toolkits, ()); 1046 OCTAVE_SAFE_CALL (m_gtk_manager.unload_all_toolkits, ());
1047 1047
1048 // Now that the graphics toolkits have been unloaded, force all 1048 // Now that the graphics toolkits have been unloaded, force all
1049 // symbols to be cleared. 1049 // symbols to be cleared.
1050 1050
1051 OCTAVE_SAFE_CALL (clear_all, (true)); 1051 OCTAVE_SAFE_CALL (clear_all, (true));
1052 1052
1053 // FIXME: May still need something like this to ensure that 1053 // FIXME: May still need something like this to ensure that
1054 // destructors for class objects will run properly. Should that be 1054 // destructors for class objects will run properly. Should that be
1055 // done earlier? Before or after atexit functions are executed? 1055 // done earlier? Before or after atexit functions are executed?
1056 // What will happen if the destructor for an obect attempts to 1056 // What will happen if the destructor for an obect attempts to
1057 // display a figure? 1057 // display a figure?
1058 1058
1059 OCTAVE_SAFE_CALL (m_symbol_table.cleanup, ()); 1059 OCTAVE_SAFE_CALL (m_symbol_table.cleanup, ());
1060 1060
1061 OCTAVE_SAFE_CALL (sysdep_cleanup, ()); 1061 OCTAVE_SAFE_CALL (sysdep_cleanup, ());
1062 1062
1063 OCTAVE_SAFE_CALL (flush_stdout, ()); 1063 OCTAVE_SAFE_CALL (flush_stdout, ());
1064 1064
1065 // Don't call singleton_cleanup_list::cleanup until we have the 1065 // Don't call singleton_cleanup_list::cleanup until we have the
1066 // problems with registering/unregistering types worked out. For 1066 // problems with registering/unregistering types worked out. For
1067 // example, uncomment the following line, then use the make_int 1067 // example, uncomment the following line, then use the make_int
1068 // function from the examples directory to create an integer 1068 // function from the examples directory to create an integer
1069 // object and then exit Octave. Octave should crash with a 1069 // object and then exit Octave. Octave should crash with a
1070 // segfault when cleaning up the typinfo singleton. We need some 1070 // segfault when cleaning up the typinfo singleton. We need some
1071 // way to force new octave_value_X types that are created in 1071 // way to force new octave_value_X types that are created in
1072 // .oct files to be unregistered when the .oct file shared library 1072 // .oct files to be unregistered when the .oct file shared library
1073 // is unloaded. 1073 // is unloaded.
1074 // 1074 //
1075 // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); 1075 // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
1076 } 1076 }
1077 1077
1078 void interpreter::execute_atexit_fcns (void) 1078 void interpreter::execute_atexit_fcns (void)
1079 { 1079 {
1080 // Prevent atexit functions from adding new functions to the list. 1080 // Prevent atexit functions from adding new functions to the list.
1081 m_executing_atexit = true; 1081 m_executing_atexit = true;
1082 1082
1083 while (! m_atexit_fcns.empty ()) 1083 while (! m_atexit_fcns.empty ())
1084 { 1084 {
1085 std::string fcn = m_atexit_fcns.front (); 1085 std::string fcn = m_atexit_fcns.front ();
1086 1086
1087 m_atexit_fcns.pop_front (); 1087 m_atexit_fcns.pop_front ();
1088 1088
1089 OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); 1089 OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
1090 1090
1091 OCTAVE_SAFE_CALL (flush_stdout, ()); 1091 OCTAVE_SAFE_CALL (flush_stdout, ());
1092 } 1092 }
1093 } 1093 }
1094 1094
1095 void interpreter::display_startup_message (void) const 1095 void interpreter::display_startup_message (void) const
1096 { 1096 {
1097 bool inhibit_startup_message = false; 1097 bool inhibit_startup_message = false;
1098 1098
1099 if (m_app_context) 1099 if (m_app_context)
1100 { 1100 {
1101 const cmdline_options& options = m_app_context->options (); 1101 const cmdline_options& options = m_app_context->options ();
1102 1102
1103 inhibit_startup_message = options.inhibit_startup_message (); 1103 inhibit_startup_message = options.inhibit_startup_message ();
1104 } 1104 }
1105 1105
1106 if (m_interactive && ! inhibit_startup_message) 1106 if (m_interactive && ! inhibit_startup_message)
1107 std::cout << octave_startup_message () << "\n" << std::endl; 1107 std::cout << octave_startup_message () << "\n" << std::endl;
1108 } 1108 }
1109 1109
1110 // Initialize by reading startup files. Return non-zero if an exception 1110 // Initialize by reading startup files. Return non-zero if an exception
1111 // occurs when reading any of them, but don't exit early because of an 1111 // occurs when reading any of them, but don't exit early because of an
1112 // exception. 1112 // exception.
1113 1113
1114 int interpreter::execute_startup_files (void) 1114 int interpreter::execute_startup_files (void)
1115 { 1115 {
1116 bool read_site_files = m_read_site_files; 1116 bool read_site_files = m_read_site_files;
1117 bool read_init_files = m_read_init_files; 1117 bool read_init_files = m_read_init_files;
1118 bool verbose = m_verbose; 1118 bool verbose = m_verbose;
1119 bool inhibit_startup_message = m_inhibit_startup_message; 1119 bool inhibit_startup_message = m_inhibit_startup_message;
1120 1120
1121 if (m_app_context) 1121 if (m_app_context)
1122 { 1122 {
1123 const cmdline_options& options = m_app_context->options (); 1123 const cmdline_options& options = m_app_context->options ();
1124 1124
1125 read_site_files = options.read_site_files (); 1125 read_site_files = options.read_site_files ();
1126 read_init_files = options.read_init_files (); 1126 read_init_files = options.read_init_files ();
1127 verbose = options.verbose_flag (); 1127 verbose = options.verbose_flag ();
1128 inhibit_startup_message = options.inhibit_startup_message (); 1128 inhibit_startup_message = options.inhibit_startup_message ();
1129 } 1129 }
1130 1130
1131 verbose = (verbose && ! inhibit_startup_message); 1131 verbose = (verbose && ! inhibit_startup_message);
1132 1132
1133 bool require_file = false; 1133 bool require_file = false;
1134 1134
1135 std::string context; 1135 std::string context;
1136 1136
1137 int exit_status = 0; 1137 int exit_status = 0;
1138 1138
1139 if (read_site_files) 1139 if (read_site_files)
1140 { 1140 {
1141 // Execute commands from the site-wide configuration file. 1141 // Execute commands from the site-wide configuration file.
1142 // First from the file $(prefix)/lib/octave/site/m/octaverc 1142 // First from the file $(prefix)/lib/octave/site/m/octaverc
1143 // (if it exists), then from the file 1143 // (if it exists), then from the file
1144 // $(prefix)/share/octave/$(version)/m/octaverc (if it exists). 1144 // $(prefix)/share/octave/$(version)/m/octaverc (if it exists).
1145 1145
1146 int status = safe_source_file (config::local_site_defaults_file (), 1146 int status = safe_source_file (config::local_site_defaults_file (),
1147 context, verbose, require_file); 1147 context, verbose, require_file);
1148 1148
1149 if (status) 1149 if (status)
1150 exit_status = status; 1150 exit_status = status;
1151 1151
1152 status = safe_source_file (config::site_defaults_file (), 1152 status = safe_source_file (config::site_defaults_file (),
1153 context, verbose, require_file); 1153 context, verbose, require_file);
1154 1154
1155 if (status) 1155 if (status)
1156 exit_status = status; 1156 exit_status = status;
1157 } 1157 }
1158 1158
1159 if (read_init_files) 1159 if (read_init_files)
1160 { 1160 {
1161 // Try to execute commands from the Matlab compatible startup.m file 1161 // Try to execute commands from the Matlab compatible startup.m file
1162 // if it exists anywhere in the load path when starting Octave. 1162 // if it exists anywhere in the load path when starting Octave.
1163 std::string ff_startup_m = file_in_path ("startup.m", ""); 1163 std::string ff_startup_m = file_in_path ("startup.m", "");
1164 1164
1165 if (! ff_startup_m.empty ()) 1165 if (! ff_startup_m.empty ())
1166 { 1166 {
1167 int parse_status = 0; 1167 int parse_status = 0;
1168 1168
1169 try 1169 try
1170 { 1170 {
1171 eval_string (std::string ("startup"), false, parse_status, 0); 1171 eval_string (std::string ("startup"), false, parse_status, 0);
1172 } 1172 }
1173 catch (const interrupt_exception&) 1173 catch (const interrupt_exception&)
1174 { 1174 {
1175 recover_from_exception (); 1175 recover_from_exception ();
1176 } 1176 }
1177 catch (const execution_exception& ee) 1177 catch (const execution_exception& ee)
1178 { 1178 {
1179 handle_exception (ee); 1179 handle_exception (ee);
1180 } 1180 }
1181 } 1181 }
1182 1182
1183 // Try to execute commands from $CONFIG/octave/octaverc, where 1183 // Try to execute commands from $CONFIG/octave/octaverc, where
1184 // $CONFIG is the platform-dependent location for user local 1184 // $CONFIG is the platform-dependent location for user local
1185 // configuration files. 1185 // configuration files.
1186 1186
1187 std::string user_config_dir = sys::env::get_user_config_directory (); 1187 std::string user_config_dir = sys::env::get_user_config_directory ();
1188 1188
1189 std::string cfg_dir = user_config_dir + sys::file_ops::dir_sep_str () 1189 std::string cfg_dir = user_config_dir + sys::file_ops::dir_sep_str ()
1190 + "octave"; 1190 + "octave";
1191 1191
1192 std::string cfg_rc = sys::env::make_absolute ("octaverc", cfg_dir); 1192 std::string cfg_rc = sys::env::make_absolute ("octaverc", cfg_dir);
1193 1193
1194 if (! cfg_rc.empty ()) 1194 if (! cfg_rc.empty ())
1195 { 1195 {
1196 int status = safe_source_file (cfg_rc, context, verbose, 1196 int status = safe_source_file (cfg_rc, context, verbose,
1197 require_file); 1197 require_file);
1198 1198
1199 if (status) 1199 if (status)
1200 exit_status = status; 1200 exit_status = status;
1201 } 1201 }
1202 1202
1203 // Try to execute commands from $HOME/$OCTAVE_INITFILE and 1203 // Try to execute commands from $HOME/$OCTAVE_INITFILE and
1204 // $OCTAVE_INITFILE. If $OCTAVE_INITFILE is not set, 1204 // $OCTAVE_INITFILE. If $OCTAVE_INITFILE is not set,
1205 // .octaverc is assumed. 1205 // .octaverc is assumed.
1206 1206
1207 bool home_rc_already_executed = false; 1207 bool home_rc_already_executed = false;
1208 1208
1209 std::string initfile = sys::env::getenv ("OCTAVE_INITFILE"); 1209 std::string initfile = sys::env::getenv ("OCTAVE_INITFILE");
1210 1210
1211 if (initfile.empty ()) 1211 if (initfile.empty ())
1212 initfile = ".octaverc"; 1212 initfile = ".octaverc";
1213 1213
1214 std::string home_dir = sys::env::get_home_directory (); 1214 std::string home_dir = sys::env::get_home_directory ();
1215 1215
1216 std::string home_rc = sys::env::make_absolute (initfile, home_dir); 1216 std::string home_rc = sys::env::make_absolute (initfile, home_dir);
1217 1217
1218 std::string local_rc; 1218 std::string local_rc;
1219 1219
1220 if (! home_rc.empty ()) 1220 if (! home_rc.empty ())
1221 { 1221 {
1222 int status = safe_source_file (home_rc, context, verbose, 1222 int status = safe_source_file (home_rc, context, verbose,
1223 require_file); 1223 require_file);
1224 1224
1225 if (status) 1225 if (status)
1226 exit_status = status; 1226 exit_status = status;
1227 1227
1228 // Names alone are not enough. 1228 // Names alone are not enough.
1229 1229
1230 sys::file_stat fs_home_rc (home_rc); 1230 sys::file_stat fs_home_rc (home_rc);
1231 1231
1232 if (fs_home_rc) 1232 if (fs_home_rc)
1233 { 1233 {
1234 // We want to check for curr_dir after executing home_rc 1234 // We want to check for curr_dir after executing home_rc
1235 // because doing that may change the working directory. 1235 // because doing that may change the working directory.
1236 1236
1237 local_rc = sys::env::make_absolute (initfile);
1238
1239 home_rc_already_executed = same_file (home_rc, local_rc);
1240 }
1241 }
1242
1243 if (! home_rc_already_executed)
1244 {
1245 if (local_rc.empty ())
1246 local_rc = sys::env::make_absolute (initfile); 1237 local_rc = sys::env::make_absolute (initfile);
1247 1238
1248 int status = safe_source_file (local_rc, context, verbose, 1239 home_rc_already_executed = same_file (home_rc, local_rc);
1249 require_file); 1240 }
1250 1241 }
1251 if (status) 1242
1252 exit_status = status; 1243 if (! home_rc_already_executed)
1253 } 1244 {
1254 } 1245 if (local_rc.empty ())
1255 1246 local_rc = sys::env::make_absolute (initfile);
1256 if (m_interactive && verbose) 1247
1257 std::cout << std::endl; 1248 int status = safe_source_file (local_rc, context, verbose,
1258 1249 require_file);
1259 return exit_status; 1250
1260 } 1251 if (status)
1261 1252 exit_status = status;
1262 // Execute any code specified with --eval 'CODE' 1253 }
1263 1254 }
1264 int interpreter::execute_eval_option_code (void) 1255
1265 { 1256 if (m_interactive && verbose)
1266 if (! m_app_context) 1257 std::cout << std::endl;
1267 return 0; 1258
1268 1259 return exit_status;
1269 const cmdline_options& options = m_app_context->options (); 1260 }
1270 1261
1271 std::string code_to_eval = options.code_to_eval (); 1262 // Execute any code specified with --eval 'CODE'
1272 1263
1273 unwind_protect_var<bool> upv (m_interactive, false); 1264 int interpreter::execute_eval_option_code (void)
1274 1265 {
1275 int parse_status = 0; 1266 if (! m_app_context)
1276 1267 return 0;
1277 try 1268
1278 { 1269 const cmdline_options& options = m_app_context->options ();
1279 eval_string (code_to_eval, false, parse_status, 0); 1270
1280 } 1271 std::string code_to_eval = options.code_to_eval ();
1281 catch (const interrupt_exception&) 1272
1282 { 1273 unwind_protect_var<bool> upv (m_interactive, false);
1283 recover_from_exception (); 1274
1284 1275 int parse_status = 0;
1285 return 1; 1276
1286 } 1277 try
1287 catch (const execution_exception& ee) 1278 {
1288 { 1279 eval_string (code_to_eval, false, parse_status, 0);
1289 handle_exception (ee); 1280 }
1290 1281 catch (const interrupt_exception&)
1291 return 1; 1282 {
1292 } 1283 recover_from_exception ();
1293 1284
1294 return parse_status; 1285 return 1;
1295 } 1286 }
1296 1287 catch (const execution_exception& ee)
1297 int interpreter::execute_command_line_file (void) 1288 {
1298 { 1289 handle_exception (ee);
1299 if (! m_app_context) 1290
1300 return 0; 1291 return 1;
1301 1292 }
1302 const cmdline_options& options = m_app_context->options (); 1293
1303 1294 return parse_status;
1304 string_vector args = options.all_args (); 1295 }
1305 1296
1306 void (interpreter::*interactive_fptr) (bool) = &interpreter::interactive; 1297 int interpreter::execute_command_line_file (void)
1307 unwind_action restore_interactive (interactive_fptr, this, m_interactive); 1298 {
1308 1299 if (! m_app_context)
1309 unwind_action restore_argv (&application::intern_argv, m_app_context, args); 1300 return 0;
1310 1301
1311 unwind_action restore_nargin (&interpreter::intern_nargin, this, 1302 const cmdline_options& options = m_app_context->options ();
1312 args.numel () - 1); 1303
1313 1304 string_vector args = options.all_args ();
1314 void (application::*program_invocation_name_fptr) (const std::string&) 1305
1315 = &application::program_invocation_name; 1306 void (interpreter::*interactive_fptr) (bool) = &interpreter::interactive;
1316 unwind_action restore_program_invocation_name 1307 unwind_action restore_interactive (interactive_fptr, this, m_interactive);
1317 (program_invocation_name_fptr, m_app_context, 1308
1318 application::program_invocation_name ()); 1309 unwind_action restore_argv (&application::intern_argv, m_app_context, args);
1319 1310
1320 void (application::*program_name_fptr) (const std::string&) 1311 unwind_action restore_nargin (&interpreter::intern_nargin, this,
1321 = &application::program_name; 1312 args.numel () - 1);
1322 unwind_action restore_program_name 1313
1323 (program_name_fptr, m_app_context, application::program_name ()); 1314 void (application::*program_invocation_name_fptr) (const std::string&)
1324 1315 = &application::program_invocation_name;
1325 m_interactive = false; 1316 unwind_action restore_program_invocation_name
1326 1317 (program_invocation_name_fptr, m_app_context,
1327 // If we are running an executable script (#! /bin/octave) then 1318 application::program_invocation_name ());
1328 // we should only see the args passed to the script. 1319
1329 1320 void (application::*program_name_fptr) (const std::string&)
1330 string_vector script_args = options.remaining_args (); 1321 = &application::program_name;
1331 1322 unwind_action restore_program_name
1332 m_app_context->intern_argv (script_args); 1323 (program_name_fptr, m_app_context, application::program_name ());
1333 intern_nargin (script_args.numel () - 1); 1324
1334 1325 m_interactive = false;
1335 std::string fname = script_args[0]; 1326
1336 1327 // If we are running an executable script (#! /bin/octave) then
1337 m_app_context->set_program_names (fname); 1328 // we should only see the args passed to the script.
1338 1329
1339 std::string context; 1330 string_vector script_args = options.remaining_args ();
1340 bool verbose = false; 1331
1341 bool require_file = true; 1332 m_app_context->intern_argv (script_args);
1342 1333 intern_nargin (script_args.numel () - 1);
1343 return safe_source_file (fname, context, verbose, require_file); 1334
1344 } 1335 std::string fname = script_args[0];
1345 1336
1346 int interpreter::main_loop (void) 1337 m_app_context->set_program_names (fname);
1347 { 1338
1348 command_editor::add_event_hook (release_unreferenced_dynamic_libraries); 1339 std::string context;
1349 1340 bool verbose = false;
1350 return m_evaluator.repl (); 1341 bool require_file = true;
1351 } 1342
1352 1343 return safe_source_file (fname, context, verbose, require_file);
1353 int interpreter::server_loop (void) 1344 }
1354 { 1345
1355 return m_evaluator.server_loop (); 1346 int interpreter::main_loop (void)
1356 } 1347 {
1357 1348 command_editor::add_event_hook (release_unreferenced_dynamic_libraries);
1358 tree_evaluator& interpreter::get_evaluator (void) 1349
1359 { 1350 return m_evaluator.repl ();
1360 return m_evaluator; 1351 }
1361 } 1352
1362 1353 int interpreter::server_loop (void)
1363 stream_list& interpreter::get_stream_list (void) 1354 {
1364 { 1355 return m_evaluator.server_loop ();
1365 return m_stream_list; 1356 }
1366 } 1357
1367 1358 tree_evaluator& interpreter::get_evaluator (void)
1368 url_handle_manager& interpreter::get_url_handle_manager (void) 1359 {
1369 { 1360 return m_evaluator;
1370 return m_url_handle_manager; 1361 }
1371 } 1362
1372 1363 stream_list& interpreter::get_stream_list (void)
1373 symbol_scope 1364 {
1374 interpreter::get_top_scope (void) const 1365 return m_stream_list;
1375 { 1366 }
1376 return m_evaluator.get_top_scope (); 1367
1377 } 1368 url_handle_manager& interpreter::get_url_handle_manager (void)
1378 1369 {
1379 symbol_scope 1370 return m_url_handle_manager;
1380 interpreter::get_current_scope (void) const 1371 }
1381 { 1372
1382 return m_evaluator.get_current_scope (); 1373 symbol_scope
1383 } 1374 interpreter::get_top_scope (void) const
1384 1375 {
1385 symbol_scope 1376 return m_evaluator.get_top_scope ();
1386 interpreter::require_current_scope (const std::string& who) const 1377 }
1387 { 1378
1388 symbol_scope scope = get_current_scope (); 1379 symbol_scope
1389 1380 interpreter::get_current_scope (void) const
1390 if (! scope) 1381 {
1391 error ("%s: symbol table scope missing", who.c_str ()); 1382 return m_evaluator.get_current_scope ();
1392 1383 }
1393 return scope; 1384
1394 } 1385 symbol_scope
1395 1386 interpreter::require_current_scope (const std::string& who) const
1396 profiler& interpreter::get_profiler (void) 1387 {
1397 { 1388 symbol_scope scope = get_current_scope ();
1398 return m_evaluator.get_profiler (); 1389
1399 } 1390 if (! scope)
1400 1391 error ("%s: symbol table scope missing", who.c_str ());
1401 int interpreter::chdir (const std::string& dir) 1392
1402 { 1393 return scope;
1403 std::string xdir = sys::file_ops::tilde_expand (dir); 1394 }
1404 1395
1405 int cd_ok = sys::env::chdir (xdir); 1396 profiler& interpreter::get_profiler (void)
1406 1397 {
1407 if (! cd_ok) 1398 return m_evaluator.get_profiler ();
1408 error ("%s: %s", dir.c_str (), std::strerror (errno)); 1399 }
1409 1400
1410 Vlast_chdir_time.stamp (); 1401 int interpreter::chdir (const std::string& dir)
1411 1402 {
1412 // FIXME: should these actions be handled as a list of functions 1403 std::string xdir = sys::file_ops::tilde_expand (dir);
1413 // to call so users can add their own chdir handlers? 1404
1414 1405 int cd_ok = sys::env::chdir (xdir);
1415 m_load_path.read_dir_config ("."); 1406
1416 m_load_path.update (); 1407 if (! cd_ok)
1417 1408 error ("%s: %s", dir.c_str (), std::strerror (errno));
1418 m_event_manager.directory_changed (sys::env::get_current_directory ()); 1409
1419 1410 Vlast_chdir_time.stamp ();
1420 return cd_ok; 1411
1421 } 1412 // FIXME: should these actions be handled as a list of functions
1422 1413 // to call so users can add their own chdir handlers?
1423 void interpreter::mlock (bool skip_first) const 1414
1424 { 1415 m_load_path.read_dir_config (".");
1425 m_evaluator.mlock (skip_first); 1416 m_load_path.update ();
1426 } 1417
1427 1418 m_event_manager.directory_changed (sys::env::get_current_directory ());
1428 void interpreter::munlock (bool skip_first) const 1419
1429 { 1420 return cd_ok;
1430 m_evaluator.munlock (skip_first); 1421 }
1431 } 1422
1432 1423 void interpreter::mlock (bool skip_first) const
1433 bool interpreter::mislocked (bool skip_first) const 1424 {
1434 { 1425 m_evaluator.mlock (skip_first);
1435 return m_evaluator.mislocked (skip_first); 1426 }
1436 } 1427
1437 1428 void interpreter::munlock (bool skip_first) const
1438 void interpreter::munlock (const char *nm) 1429 {
1439 { 1430 m_evaluator.munlock (skip_first);
1440 if (! nm) 1431 }
1441 error ("munlock: invalid value for NAME"); 1432
1442 1433 bool interpreter::mislocked (bool skip_first) const
1443 munlock (std::string (nm)); 1434 {
1444 } 1435 return m_evaluator.mislocked (skip_first);
1445 1436 }
1446 void interpreter::munlock (const std::string& nm) 1437
1447 { 1438 void interpreter::munlock (const char *nm)
1448 octave_value val = m_symbol_table.find_function (nm); 1439 {
1449 1440 if (! nm)
1450 if (val.is_defined ()) 1441 error ("munlock: invalid value for NAME");
1451 { 1442
1452 octave_function *fcn = val.function_value (); 1443 munlock (std::string (nm));
1453 1444 }
1454 if (fcn) 1445
1455 fcn->unlock (); 1446 void interpreter::munlock (const std::string& nm)
1456 } 1447 {
1457 } 1448 octave_value val = m_symbol_table.find_function (nm);
1458 1449
1459 bool interpreter::mislocked (const char *nm) 1450 if (val.is_defined ())
1460 { 1451 {
1461 if (! nm) 1452 octave_function *fcn = val.function_value ();
1462 error ("mislocked: invalid value for NAME"); 1453
1463 1454 if (fcn)
1464 return mislocked (std::string (nm)); 1455 fcn->unlock ();
1465 } 1456 }
1466 1457 }
1467 bool interpreter::mislocked (const std::string& nm) 1458
1468 { 1459 bool interpreter::mislocked (const char *nm)
1469 bool retval = false; 1460 {
1470 1461 if (! nm)
1471 octave_value val = m_symbol_table.find_function (nm); 1462 error ("mislocked: invalid value for NAME");
1472 1463
1473 if (val.is_defined ()) 1464 return mislocked (std::string (nm));
1474 { 1465 }
1475 octave_function *fcn = val.function_value (); 1466
1476 1467 bool interpreter::mislocked (const std::string& nm)
1477 if (fcn) 1468 {
1478 retval = fcn->islocked (); 1469 bool retval = false;
1479 } 1470
1480 1471 octave_value val = m_symbol_table.find_function (nm);
1481 return retval; 1472
1482 } 1473 if (val.is_defined ())
1483 1474 {
1484 std::string interpreter::mfilename (const std::string& opt) const 1475 octave_function *fcn = val.function_value ();
1485 { 1476
1486 return m_evaluator.mfilename (opt); 1477 if (fcn)
1487 } 1478 retval = fcn->islocked ();
1488 1479 }
1489 octave_value_list interpreter::eval_string (const std::string& eval_str, 1480
1490 bool silent, int& parse_status, 1481 return retval;
1491 int nargout) 1482 }
1492 { 1483
1493 return m_evaluator.eval_string (eval_str, silent, parse_status, nargout); 1484 std::string interpreter::mfilename (const std::string& opt) const
1494 } 1485 {
1495 1486 return m_evaluator.mfilename (opt);
1496 octave_value interpreter::eval_string (const std::string& eval_str, 1487 }
1497 bool silent, int& parse_status) 1488
1498 { 1489 octave_value_list interpreter::eval_string (const std::string& eval_str,
1499 return m_evaluator.eval_string (eval_str, silent, parse_status); 1490 bool silent, int& parse_status,
1500 } 1491 int nargout)
1501 1492 {
1502 octave_value_list interpreter::eval_string (const octave_value& arg, 1493 return m_evaluator.eval_string (eval_str, silent, parse_status, nargout);
1503 bool silent, int& parse_status, 1494 }
1504 int nargout) 1495
1505 { 1496 octave_value interpreter::eval_string (const std::string& eval_str,
1506 return m_evaluator.eval_string (arg, silent, parse_status, nargout); 1497 bool silent, int& parse_status)
1507 } 1498 {
1508 1499 return m_evaluator.eval_string (eval_str, silent, parse_status);
1509 octave_value_list interpreter::eval (const std::string& try_code, 1500 }
1501
1502 octave_value_list interpreter::eval_string (const octave_value& arg,
1503 bool silent, int& parse_status,
1504 int nargout)
1505 {
1506 return m_evaluator.eval_string (arg, silent, parse_status, nargout);
1507 }
1508
1509 octave_value_list interpreter::eval (const std::string& try_code,
1510 int nargout)
1511 {
1512 return m_evaluator.eval (try_code, nargout);
1513 }
1514
1515 octave_value_list interpreter::eval (const std::string& try_code,
1516 const std::string& catch_code,
1517 int nargout)
1518 {
1519 return m_evaluator.eval (try_code, catch_code, nargout);
1520 }
1521
1522 octave_value_list interpreter::evalin (const std::string& context,
1523 const std::string& try_code,
1510 int nargout) 1524 int nargout)
1511 { 1525 {
1512 return m_evaluator.eval (try_code, nargout); 1526 return m_evaluator.evalin (context, try_code, nargout);
1513 } 1527 }
1514 1528
1515 octave_value_list interpreter::eval (const std::string& try_code, 1529 octave_value_list interpreter::evalin (const std::string& context,
1530 const std::string& try_code,
1516 const std::string& catch_code, 1531 const std::string& catch_code,
1517 int nargout) 1532 int nargout)
1518 { 1533 {
1519 return m_evaluator.eval (try_code, catch_code, nargout); 1534 return m_evaluator.evalin (context, try_code, catch_code, nargout);
1520 } 1535 }
1521 1536
1522 octave_value_list interpreter::evalin (const std::string& context, 1537 //! Evaluate an Octave function (built-in or interpreted) and return
1523 const std::string& try_code, 1538 //! the list of result values.
1524 int nargout) 1539 //!
1525 { 1540 //! @param name The name of the function to call.
1526 return m_evaluator.evalin (context, try_code, nargout); 1541 //! @param args The arguments to the function.
1527 } 1542 //! @param nargout The number of output arguments expected.
1528 1543 //! @return A list of output values. The length of the list is not
1529 octave_value_list interpreter::evalin (const std::string& context, 1544 //! necessarily the same as @c nargout.
1530 const std::string& try_code, 1545
1531 const std::string& catch_code, 1546 octave_value_list interpreter::feval (const char *name,
1532 int nargout) 1547 const octave_value_list& args,
1533 { 1548 int nargout)
1534 return m_evaluator.evalin (context, try_code, catch_code, nargout); 1549 {
1535 } 1550 return feval (std::string (name), args, nargout);
1536 1551 }
1537 //! Evaluate an Octave function (built-in or interpreted) and return 1552
1538 //! the list of result values. 1553 octave_value_list interpreter::feval (const std::string& name,
1539 //! 1554 const octave_value_list& args,
1540 //! @param name The name of the function to call. 1555 int nargout)
1541 //! @param args The arguments to the function. 1556 {
1542 //! @param nargout The number of output arguments expected. 1557 octave_value fcn = m_symbol_table.find_function (name, args);
1543 //! @return A list of output values. The length of the list is not 1558
1544 //! necessarily the same as @c nargout. 1559 if (fcn.is_undefined ())
1545 1560 error ("feval: function '%s' not found", name.c_str ());
1546 octave_value_list interpreter::feval (const char *name, 1561
1547 const octave_value_list& args, 1562 octave_function *of = fcn.function_value ();
1548 int nargout) 1563
1549 { 1564 return of->call (m_evaluator, nargout, args);
1550 return feval (std::string (name), args, nargout); 1565 }
1551 } 1566
1552 1567 octave_value_list interpreter::feval (octave_function *fcn,
1553 octave_value_list interpreter::feval (const std::string& name, 1568 const octave_value_list& args,
1554 const octave_value_list& args, 1569 int nargout)
1555 int nargout) 1570 {
1556 { 1571 if (fcn)
1557 octave_value fcn = m_symbol_table.find_function (name, args); 1572 return fcn->call (m_evaluator, nargout, args);
1558 1573
1559 if (fcn.is_undefined ()) 1574 return octave_value_list ();
1560 error ("feval: function '%s' not found", name.c_str ()); 1575 }
1561 1576
1562 octave_function *of = fcn.function_value (); 1577 octave_value_list interpreter::feval (const octave_value& val,
1563 1578 const octave_value_list& args,
1564 return of->call (m_evaluator, nargout, args); 1579 int nargout)
1565 } 1580 {
1566 1581 // FIXME: do we really want to silently return an empty ovl if
1567 octave_value_list interpreter::feval (octave_function *fcn, 1582 // the function object is undefined? It's essentially what the
1568 const octave_value_list& args, 1583 // version above that accepts a pointer to an octave_function
1569 int nargout) 1584 // object does and some code was apparently written to rely on it
1570 { 1585 // (for example, __ode15__).
1571 if (fcn) 1586
1572 return fcn->call (m_evaluator, nargout, args); 1587 if (val.is_undefined ())
1573
1574 return octave_value_list ();
1575 }
1576
1577 octave_value_list interpreter::feval (const octave_value& val,
1578 const octave_value_list& args,
1579 int nargout)
1580 {
1581 // FIXME: do we really want to silently return an empty ovl if
1582 // the function object is undefined? It's essentially what the
1583 // version above that accepts a pointer to an octave_function
1584 // object does and some code was apparently written to rely on it
1585 // (for example, __ode15__).
1586
1587 if (val.is_undefined ())
1588 return ovl ();
1589
1590 if (val.is_function ())
1591 {
1592 return feval (val.function_value (), args, nargout);
1593 }
1594 else if (val.is_function_handle () || val.is_inline_function ())
1595 {
1596 // This covers function handles, inline functions, and anonymous
1597 // functions.
1598
1599 std::list<octave_value_list> arg_list;
1600 arg_list.push_back (args);
1601
1602 // FIXME: could we make octave_value::subsref a const method?
1603 // It would be difficult because there are instances of
1604 // incrementing the reference count inside subsref methods,
1605 // which means they can't be const with the current way of
1606 // handling reference counting.
1607
1608 octave_value xval = val;
1609 return xval.subsref ("(", arg_list, nargout);
1610 }
1611 else if (val.is_string ())
1612 {
1613 return feval (val.string_value (), args, nargout);
1614 }
1615 else
1616 error ("feval: first argument must be a string, inline function, or a function handle");
1617
1618 return ovl (); 1588 return ovl ();
1619 } 1589
1620 1590 if (val.is_function ())
1621 //! Evaluate an Octave function (built-in or interpreted) and return 1591 {
1622 //! the list of result values. 1592 return feval (val.function_value (), args, nargout);
1623 //! 1593 }
1624 //! @param args The first element of @c args is the function to call. 1594 else if (val.is_function_handle () || val.is_inline_function ())
1625 //! It may be the name of the function as a string, a function 1595 {
1626 //! handle, or an inline function. The remaining arguments are 1596 // This covers function handles, inline functions, and anonymous
1627 //! passed to the function. 1597 // functions.
1628 //! @param nargout The number of output arguments expected. 1598
1629 //! @return A list of output values. The length of the list is not 1599 std::list<octave_value_list> arg_list;
1630 //! necessarily the same as @c nargout. 1600 arg_list.push_back (args);
1631 1601
1632 octave_value_list interpreter::feval (const octave_value_list& args, 1602 // FIXME: could we make octave_value::subsref a const method?
1633 int nargout) 1603 // It would be difficult because there are instances of
1634 { 1604 // incrementing the reference count inside subsref methods,
1635 if (args.length () == 0) 1605 // which means they can't be const with the current way of
1636 error ("feval: first argument must be a string, inline function, or a function handle"); 1606 // handling reference counting.
1637 1607
1638 octave_value f_arg = args(0); 1608 octave_value xval = val;
1639 1609 return xval.subsref ("(", arg_list, nargout);
1640 octave_value_list tmp_args = args.slice (1, args.length () - 1, true); 1610 }
1641 1611 else if (val.is_string ())
1642 return feval (f_arg, tmp_args, nargout); 1612 {
1643 } 1613 return feval (val.string_value (), args, nargout);
1644 1614 }
1645 octave_value interpreter::make_function_handle (const std::string& name) 1615 else
1646 { 1616 error ("feval: first argument must be a string, inline function, or a function handle");
1647 return m_evaluator.make_fcn_handle (name); 1617
1648 } 1618 return ovl ();
1649 1619 }
1650 void interpreter::install_variable (const std::string& name, 1620
1651 const octave_value& value, bool global) 1621 //! Evaluate an Octave function (built-in or interpreted) and return
1652 { 1622 //! the list of result values.
1653 m_evaluator.install_variable (name, value, global); 1623 //!
1654 } 1624 //! @param args The first element of @c args is the function to call.
1655 1625 //! It may be the name of the function as a string, a function
1656 octave_value interpreter::global_varval (const std::string& name) const 1626 //! handle, or an inline function. The remaining arguments are
1657 { 1627 //! passed to the function.
1658 return m_evaluator.global_varval (name); 1628 //! @param nargout The number of output arguments expected.
1659 } 1629 //! @return A list of output values. The length of the list is not
1660 1630 //! necessarily the same as @c nargout.
1661 void interpreter::global_assign (const std::string& name, 1631
1662 const octave_value& val) 1632 octave_value_list interpreter::feval (const octave_value_list& args,
1663 { 1633 int nargout)
1664 m_evaluator.global_assign (name, val); 1634 {
1665 } 1635 if (args.length () == 0)
1666 1636 error ("feval: first argument must be a string, inline function, or a function handle");
1667 octave_value interpreter::top_level_varval (const std::string& name) const 1637
1668 { 1638 octave_value f_arg = args(0);
1669 return m_evaluator.top_level_varval (name); 1639
1670 } 1640 octave_value_list tmp_args = args.slice (1, args.length () - 1, true);
1671 1641
1672 void interpreter::top_level_assign (const std::string& name, 1642 return feval (f_arg, tmp_args, nargout);
1673 const octave_value& val) 1643 }
1674 { 1644
1675 m_evaluator.top_level_assign (name, val); 1645 octave_value interpreter::make_function_handle (const std::string& name)
1676 } 1646 {
1677 1647 return m_evaluator.make_fcn_handle (name);
1678 bool interpreter::is_variable (const std::string& name) const 1648 }
1679 { 1649
1680 return m_evaluator.is_variable (name); 1650 void interpreter::install_variable (const std::string& name,
1681 } 1651 const octave_value& value, bool global)
1682 1652 {
1683 bool interpreter::is_local_variable (const std::string& name) const 1653 m_evaluator.install_variable (name, value, global);
1684 { 1654 }
1685 return m_evaluator.is_local_variable (name); 1655
1686 } 1656 octave_value interpreter::global_varval (const std::string& name) const
1687 1657 {
1688 octave_value interpreter::varval (const std::string& name) const 1658 return m_evaluator.global_varval (name);
1689 { 1659 }
1690 return m_evaluator.varval (name); 1660
1691 } 1661 void interpreter::global_assign (const std::string& name,
1692 1662 const octave_value& val)
1693 void interpreter::assign (const std::string& name, 1663 {
1664 m_evaluator.global_assign (name, val);
1665 }
1666
1667 octave_value interpreter::top_level_varval (const std::string& name) const
1668 {
1669 return m_evaluator.top_level_varval (name);
1670 }
1671
1672 void interpreter::top_level_assign (const std::string& name,
1673 const octave_value& val)
1674 {
1675 m_evaluator.top_level_assign (name, val);
1676 }
1677
1678 bool interpreter::is_variable (const std::string& name) const
1679 {
1680 return m_evaluator.is_variable (name);
1681 }
1682
1683 bool interpreter::is_local_variable (const std::string& name) const
1684 {
1685 return m_evaluator.is_local_variable (name);
1686 }
1687
1688 octave_value interpreter::varval (const std::string& name) const
1689 {
1690 return m_evaluator.varval (name);
1691 }
1692
1693 void interpreter::assign (const std::string& name,
1694 const octave_value& val)
1695 {
1696 m_evaluator.assign (name, val);
1697 }
1698
1699 void interpreter::assignin (const std::string& context,
1700 const std::string& name,
1694 const octave_value& val) 1701 const octave_value& val)
1695 { 1702 {
1696 m_evaluator.assign (name, val); 1703 m_evaluator.assignin (context, name, val);
1697 } 1704 }
1698 1705
1699 void interpreter::assignin (const std::string& context, 1706 void interpreter::source_file (const std::string& file_name,
1700 const std::string& name, 1707 const std::string& context, bool verbose,
1701 const octave_value& val) 1708 bool require_file)
1702 { 1709 {
1703 m_evaluator.assignin (context, name, val); 1710 m_evaluator.source_file (file_name, context, verbose, require_file);
1704 } 1711 }
1705 1712
1706 void interpreter::source_file (const std::string& file_name, 1713 bool interpreter::at_top_level (void) const
1707 const std::string& context, bool verbose, 1714 {
1708 bool require_file) 1715 return m_evaluator.at_top_level ();
1709 { 1716 }
1710 m_evaluator.source_file (file_name, context, verbose, require_file); 1717
1711 } 1718 bool interpreter::isglobal (const std::string& name) const
1712 1719 {
1713 bool interpreter::at_top_level (void) const 1720 return m_evaluator.is_global (name);
1714 { 1721 }
1715 return m_evaluator.at_top_level (); 1722
1716 } 1723 octave_value interpreter::find (const std::string& name)
1717 1724 {
1718 bool interpreter::isglobal (const std::string& name) const 1725 return m_evaluator.find (name);
1719 { 1726 }
1720 return m_evaluator.is_global (name); 1727
1721 } 1728 void interpreter::clear_all (bool force)
1722 1729 {
1723 octave_value interpreter::find (const std::string& name) 1730 m_evaluator.clear_all (force);
1724 { 1731 }
1725 return m_evaluator.find (name); 1732
1726 } 1733 void interpreter::clear_objects (void)
1727 1734 {
1728 void interpreter::clear_all (bool force) 1735 m_evaluator.clear_objects ();
1729 { 1736 }
1730 m_evaluator.clear_all (force); 1737
1731 } 1738 void interpreter::clear_variable (const std::string& name)
1732 1739 {
1733 void interpreter::clear_objects (void) 1740 m_evaluator.clear_variable (name);
1734 { 1741 }
1735 m_evaluator.clear_objects (); 1742
1736 } 1743 void interpreter::clear_variable_pattern (const std::string& pattern)
1737 1744 {
1738 void interpreter::clear_variable (const std::string& name) 1745 m_evaluator.clear_variable_pattern (pattern);
1739 { 1746 }
1740 m_evaluator.clear_variable (name); 1747
1741 } 1748 void interpreter::clear_variable_regexp (const std::string& pattern)
1742 1749 {
1743 void interpreter::clear_variable_pattern (const std::string& pattern) 1750 m_evaluator.clear_variable_regexp (pattern);
1744 { 1751 }
1745 m_evaluator.clear_variable_pattern (pattern); 1752
1746 } 1753 void interpreter::clear_variables (void)
1747 1754 {
1748 void interpreter::clear_variable_regexp (const std::string& pattern) 1755 m_evaluator.clear_variables ();
1749 { 1756 }
1750 m_evaluator.clear_variable_regexp (pattern); 1757
1751 } 1758 void interpreter::clear_global_variable (const std::string& name)
1752 1759 {
1753 void interpreter::clear_variables (void) 1760 m_evaluator.clear_global_variable (name);
1754 { 1761 }
1755 m_evaluator.clear_variables (); 1762
1756 } 1763 void interpreter::clear_global_variable_pattern (const std::string& pattern)
1757 1764 {
1758 void interpreter::clear_global_variable (const std::string& name) 1765 m_evaluator.clear_global_variable_pattern (pattern);
1759 { 1766 }
1760 m_evaluator.clear_global_variable (name); 1767
1761 } 1768 void interpreter::clear_global_variable_regexp (const std::string& pattern)
1762 1769 {
1763 void interpreter::clear_global_variable_pattern (const std::string& pattern) 1770 m_evaluator.clear_global_variable_regexp (pattern);
1764 { 1771 }
1765 m_evaluator.clear_global_variable_pattern (pattern); 1772
1766 } 1773 void interpreter::clear_global_variables (void)
1767 1774 {
1768 void interpreter::clear_global_variable_regexp (const std::string& pattern) 1775 m_evaluator.clear_global_variables ();
1769 { 1776 }
1770 m_evaluator.clear_global_variable_regexp (pattern); 1777
1771 } 1778 void interpreter::clear_functions (bool force)
1772 1779 {
1773 void interpreter::clear_global_variables (void) 1780 m_symbol_table.clear_functions (force);
1774 { 1781 }
1775 m_evaluator.clear_global_variables (); 1782
1776 } 1783 void interpreter::clear_function (const std::string& name)
1777 1784 {
1778 void interpreter::clear_functions (bool force) 1785 m_symbol_table.clear_function (name);
1779 { 1786 }
1780 m_symbol_table.clear_functions (force); 1787
1781 } 1788 void interpreter::clear_symbol (const std::string& name)
1782 1789 {
1783 void interpreter::clear_function (const std::string& name) 1790 m_evaluator.clear_symbol (name);
1784 { 1791 }
1785 m_symbol_table.clear_function (name); 1792
1786 } 1793 void interpreter::clear_function_pattern (const std::string& pat)
1787 1794 {
1788 void interpreter::clear_symbol (const std::string& name) 1795 m_symbol_table.clear_function_pattern (pat);
1789 { 1796 }
1790 m_evaluator.clear_symbol (name); 1797
1791 } 1798 void interpreter::clear_function_regexp (const std::string& pat)
1792 1799 {
1793 void interpreter::clear_function_pattern (const std::string& pat) 1800 m_symbol_table.clear_function_regexp (pat);
1794 { 1801 }
1795 m_symbol_table.clear_function_pattern (pat); 1802
1796 } 1803 void interpreter::clear_symbol_pattern (const std::string& pat)
1797 1804 {
1798 void interpreter::clear_function_regexp (const std::string& pat) 1805 return m_evaluator.clear_symbol_pattern (pat);
1799 { 1806 }
1800 m_symbol_table.clear_function_regexp (pat); 1807
1801 } 1808 void interpreter::clear_symbol_regexp (const std::string& pat)
1802 1809 {
1803 void interpreter::clear_symbol_pattern (const std::string& pat) 1810 return m_evaluator.clear_symbol_regexp (pat);
1804 { 1811 }
1805 return m_evaluator.clear_symbol_pattern (pat); 1812
1806 } 1813 std::list<std::string> interpreter::global_variable_names (void)
1807 1814 {
1808 void interpreter::clear_symbol_regexp (const std::string& pat) 1815 return m_evaluator.global_variable_names ();
1809 { 1816 }
1810 return m_evaluator.clear_symbol_regexp (pat); 1817
1811 } 1818 std::list<std::string> interpreter::top_level_variable_names (void)
1812 1819 {
1813 std::list<std::string> interpreter::global_variable_names (void) 1820 return m_evaluator.top_level_variable_names ();
1814 { 1821 }
1815 return m_evaluator.global_variable_names (); 1822
1816 } 1823 std::list<std::string> interpreter::variable_names (void)
1817 1824 {
1818 std::list<std::string> interpreter::top_level_variable_names (void) 1825 return m_evaluator.variable_names ();
1819 { 1826 }
1820 return m_evaluator.top_level_variable_names (); 1827
1821 } 1828 std::list<std::string> interpreter::user_function_names (void)
1822 1829 {
1823 std::list<std::string> interpreter::variable_names (void) 1830 return m_symbol_table.user_function_names ();
1824 { 1831 }
1825 return m_evaluator.variable_names (); 1832
1826 } 1833 std::list<std::string> interpreter::autoloaded_functions (void) const
1827 1834 {
1828 std::list<std::string> interpreter::user_function_names (void) 1835 return m_evaluator.autoloaded_functions ();
1829 { 1836 }
1830 return m_symbol_table.user_function_names (); 1837
1831 } 1838 // May be used to send an interrupt signal to the the interpreter from
1832 1839 // another thread (for example, the GUI).
1833 std::list<std::string> interpreter::autoloaded_functions (void) const 1840
1834 { 1841 void interpreter::interrupt (void)
1835 return m_evaluator.autoloaded_functions (); 1842 {
1836 } 1843 static int sigint = 0;
1837 1844 static bool first = true;
1838 // May be used to send an interrupt signal to the the interpreter from 1845
1839 // another thread (for example, the GUI). 1846 if (first)
1840 1847 {
1841 void interpreter::interrupt (void) 1848 octave_get_sig_number ("SIGINT", &sigint);
1842 { 1849 first = false;
1843 static int sigint = 0; 1850 }
1844 static bool first = true; 1851
1845 1852 // Send SIGINT to Octave and (optionally) all other processes in its
1846 if (first) 1853 // process group. The signal handler for SIGINT will set a global
1847 { 1854 // variable indicating an interrupt has happened. That variable is
1848 octave_get_sig_number ("SIGINT", &sigint); 1855 // checked in many places in the Octave interpreter and eventually
1849 first = false; 1856 // results in an interrupt_exception being thrown. Finally, that
1850 } 1857 // exception is caught and returns control to one of the
1851 1858 // read-eval-print loops or to the server loop. We use a signal
1852 // Send SIGINT to Octave and (optionally) all other processes in its 1859 // instead of just setting the global variables here so that we will
1853 // process group. The signal handler for SIGINT will set a global 1860 // probably send interrupt signals to any subprocesses as well as
1854 // variable indicating an interrupt has happened. That variable is 1861 // interrupt execution of the interpreter.
1855 // checked in many places in the Octave interpreter and eventually 1862
1856 // results in an interrupt_exception being thrown. Finally, that 1863 pid_t pid
1857 // exception is caught and returns control to one of the 1864 = m_interrupt_all_in_process_group ? 0 : octave_getpid_wrapper ();
1858 // read-eval-print loops or to the server loop. We use a signal 1865
1859 // instead of just setting the global variables here so that we will 1866 octave_kill_wrapper (pid, sigint);
1860 // probably send interrupt signals to any subprocesses as well as 1867 }
1861 // interrupt execution of the interpreter. 1868
1862 1869 void interpreter::pause (void)
1863 pid_t pid 1870 {
1864 = m_interrupt_all_in_process_group ? 0 : octave_getpid_wrapper (); 1871 // FIXME: To be reliable, these tree_evaluator functions must be
1865 1872 // made thread safe.
1866 octave_kill_wrapper (pid, sigint); 1873
1867 } 1874 m_evaluator.break_on_next_statement (true);
1868 1875 m_evaluator.reset_debug_state ();
1869 void interpreter::pause (void) 1876 }
1870 { 1877
1871 // FIXME: To be reliable, these tree_evaluator functions must be 1878 void interpreter::stop (void)
1872 // made thread safe. 1879 {
1873 1880 // FIXME: To be reliable, these tree_evaluator functions must be
1874 m_evaluator.break_on_next_statement (true); 1881 // made thread safe.
1875 m_evaluator.reset_debug_state (); 1882
1876 } 1883 if (m_evaluator.in_debug_repl ())
1877 1884 m_evaluator.dbquit (true);
1878 void interpreter::stop (void) 1885 else
1879 { 1886 interrupt ();
1880 // FIXME: To be reliable, these tree_evaluator functions must be 1887 }
1881 // made thread safe. 1888
1882 1889 void interpreter::resume (void)
1883 if (m_evaluator.in_debug_repl ()) 1890 {
1884 m_evaluator.dbquit (true); 1891 // FIXME: To be reliable, these tree_evaluator functions must be
1885 else 1892 // made thread safe.
1886 interrupt (); 1893
1887 } 1894 // FIXME: Should there be any feeback about not doing anything if
1888 1895 // not in debug mode?
1889 void interpreter::resume (void) 1896
1890 { 1897 if (m_evaluator.in_debug_repl ())
1891 // FIXME: To be reliable, these tree_evaluator functions must be 1898 m_evaluator.dbcont ();
1892 // made thread safe. 1899 }
1893 1900
1894 // FIXME: Should there be any feeback about not doing anything if 1901 // Provided for convenience. Will be removed once we eliminate the
1895 // not in debug mode? 1902 // old terminal widget.
1896 1903 bool interpreter::experimental_terminal_widget (void) const
1897 if (m_evaluator.in_debug_repl ()) 1904 {
1898 m_evaluator.dbcont (); 1905 if (! m_app_context)
1899 } 1906 return false;
1900 1907
1901 // Provided for convenience. Will be removed once we eliminate the 1908 // Embedded interpreters don't execute command line options.
1902 // old terminal widget. 1909 const cmdline_options& options = m_app_context->options ();
1903 bool interpreter::experimental_terminal_widget (void) const 1910
1904 { 1911 return options.experimental_terminal_widget ();
1905 if (! m_app_context) 1912 }
1906 return false; 1913
1907 1914 void interpreter::add_debug_watch_expression (const std::string& expr)
1908 // Embedded interpreters don't execute command line options. 1915 {
1909 const cmdline_options& options = m_app_context->options (); 1916 m_evaluator.add_debug_watch_expression (expr);
1910 1917 }
1911 return options.experimental_terminal_widget (); 1918
1912 } 1919 void interpreter::remove_debug_watch_expression (const std::string& expr)
1913 1920 {
1914 void interpreter::add_debug_watch_expression (const std::string& expr) 1921 m_evaluator.remove_debug_watch_expression (expr);
1915 { 1922 }
1916 m_evaluator.add_debug_watch_expression (expr); 1923
1917 } 1924 void interpreter::clear_debug_watch_expressions (void)
1918 1925 {
1919 void interpreter::remove_debug_watch_expression (const std::string& expr) 1926 m_evaluator.clear_debug_watch_expressions ();
1920 { 1927 }
1921 m_evaluator.remove_debug_watch_expression (expr); 1928
1922 } 1929 std::set<std::string> interpreter::debug_watch_expressions (void) const
1923 1930 {
1924 void interpreter::clear_debug_watch_expressions (void) 1931 return m_evaluator.debug_watch_expressions ();
1925 { 1932 }
1926 m_evaluator.clear_debug_watch_expressions (); 1933
1927 } 1934 void interpreter::handle_exception (const execution_exception& ee)
1928 1935 {
1929 std::set<std::string> interpreter::debug_watch_expressions (void) const 1936 m_error_system.save_exception (ee);
1930 { 1937
1931 return m_evaluator.debug_watch_expressions (); 1938 // FIXME: use a separate stream instead of std::cerr directly so that
1932 } 1939 // error messages can be redirected more easily? Pass the message
1933 1940 // to an event manager function?
1934 void interpreter::handle_exception (const execution_exception& ee) 1941 m_error_system.display_exception (ee);
1935 { 1942
1936 m_error_system.save_exception (ee); 1943 recover_from_exception ();
1937 1944 }
1938 // FIXME: use a separate stream instead of std::cerr directly so that 1945
1939 // error messages can be redirected more easily? Pass the message 1946 void interpreter::recover_from_exception (void)
1940 // to an event manager function? 1947 {
1941 m_error_system.display_exception (ee); 1948 if (octave_interrupt_state)
1942 1949 m_event_manager.interpreter_interrupted ();
1943 recover_from_exception (); 1950
1944 } 1951 can_interrupt = true;
1945 1952 octave_interrupt_state = 0;
1946 void interpreter::recover_from_exception (void) 1953 octave_signal_caught = 0;
1947 { 1954 octave_restore_signal_mask ();
1948 if (octave_interrupt_state) 1955 catch_interrupts ();
1949 m_event_manager.interpreter_interrupted (); 1956 }
1950 1957
1951 can_interrupt = true; 1958 void interpreter::mark_for_deletion (const std::string& file)
1952 octave_interrupt_state = 0; 1959 {
1953 octave_signal_caught = 0; 1960 m_tmp_files.insert (file);
1954 octave_restore_signal_mask (); 1961 }
1955 catch_interrupts (); 1962
1956 } 1963 void interpreter::cleanup_tmp_files (void)
1957 1964 {
1958 void interpreter::mark_for_deletion (const std::string& file) 1965 m_tmp_files.cleanup ();
1959 { 1966 }
1960 m_tmp_files.insert (file); 1967
1961 } 1968 void interpreter::quit (int exit_status, bool force, bool confirm)
1962 1969 {
1963 void interpreter::cleanup_tmp_files (void) 1970 if (! force)
1964 { 1971 {
1965 m_tmp_files.cleanup (); 1972 try
1966 } 1973 {
1967 1974 bool cancel = false;
1968 void interpreter::quit (int exit_status, bool force, bool confirm) 1975
1969 { 1976 if (symbol_exist ("finish.m", "file"))
1970 if (! force) 1977 {
1971 { 1978 unwind_protect_var<bool> upv1 (m_executing_finish_script, true);
1972 try 1979 unwind_protect_var<bool> upv2 (m_cancel_quit);
1973 { 1980
1974 bool cancel = false; 1981 evalin ("base", "finish", 0);
1975 1982
1976 if (symbol_exist ("finish.m", "file")) 1983 cancel = m_cancel_quit;
1977 { 1984 }
1978 unwind_protect_var<bool> upv1 (m_executing_finish_script, true); 1985
1979 unwind_protect_var<bool> upv2 (m_cancel_quit); 1986 if (cancel)
1980 1987 return;
1981 evalin ("base", "finish", 0); 1988
1982 1989 // Check for confirmation.
1983 cancel = m_cancel_quit; 1990
1984 } 1991 if (confirm && ! m_event_manager.confirm_shutdown ())
1985 1992 return;
1986 if (cancel) 1993 }
1987 return; 1994 catch (const execution_exception&)
1988 1995 {
1989 // Check for confirmation. 1996 // Catch execution_exceptions so we don't throw an
1990 1997 // exit_exception if there is an in finish.m. But throw it
1991 if (confirm && ! m_event_manager.confirm_shutdown ()) 1998 // again so that will be handled as any other
1992 return; 1999 // execution_exception by the evaluator. This way, errors
1993 } 2000 // will be ignored properly and we won't exit if quit is
1994 catch (const execution_exception&) 2001 // called recursively from finish.m.
1995 { 2002
1996 // Catch execution_exceptions so we don't throw an 2003 throw;
1997 // exit_exception if there is an in finish.m. But throw it 2004 }
1998 // again so that will be handled as any other 2005 }
1999 // execution_exception by the evaluator. This way, errors 2006
2000 // will be ignored properly and we won't exit if quit is 2007 throw exit_exception (exit_status);
2001 // called recursively from finish.m. 2008 }
2002 2009
2003 throw; 2010 void interpreter::add_atexit_fcn (const std::string& fname)
2004 } 2011 {
2005 } 2012 if (m_executing_atexit)
2006 2013 return;
2007 throw exit_exception (exit_status); 2014
2008 } 2015 m_atexit_fcns.push_front (fname);
2009 2016 }
2010 void interpreter::add_atexit_fcn (const std::string& fname) 2017
2011 { 2018 bool interpreter::remove_atexit_fcn (const std::string& fname)
2012 if (m_executing_atexit) 2019 {
2013 return; 2020 bool found = false;
2014 2021
2015 m_atexit_fcns.push_front (fname); 2022 for (auto it = m_atexit_fcns.begin ();
2016 } 2023 it != m_atexit_fcns.end (); it++)
2017 2024 {
2018 bool interpreter::remove_atexit_fcn (const std::string& fname) 2025 if (*it == fname)
2019 { 2026 {
2020 bool found = false; 2027 m_atexit_fcns.erase (it);
2021 2028 found = true;
2022 for (auto it = m_atexit_fcns.begin (); 2029 break;
2023 it != m_atexit_fcns.end (); it++) 2030 }
2024 { 2031 }
2025 if (*it == fname) 2032
2026 { 2033 return found;
2027 m_atexit_fcns.erase (it); 2034 }
2028 found = true; 2035
2029 break; 2036 // What internal options get configured by --traditional.
2030 } 2037
2031 } 2038 void interpreter::maximum_braindamage (void)
2032 2039 {
2033 return found; 2040 m_input_system.PS1 (">> ");
2034 } 2041 m_input_system.PS2 ("");
2035 2042
2036 // What internal options get configured by --traditional. 2043 m_evaluator.PS4 ("");
2037 2044
2038 void interpreter::maximum_braindamage (void) 2045 m_load_save_system.crash_dumps_octave_core (false);
2039 { 2046 m_load_save_system.save_default_options ("-mat-binary");
2040 m_input_system.PS1 (">> "); 2047
2041 m_input_system.PS2 (""); 2048 m_history_system.timestamp_format_string ("%%-- %D %I:%M %p --%%");
2042 2049
2043 m_evaluator.PS4 (""); 2050 m_error_system.beep_on_error (true);
2044 2051
2045 m_load_save_system.crash_dumps_octave_core (false); 2052 Fconfirm_recursive_rmdir (octave_value (false));
2046 m_load_save_system.save_default_options ("-mat-binary"); 2053 Foptimize_diagonal_matrix (octave_value (false));
2047 2054 Foptimize_permutation_matrix (octave_value (false));
2048 m_history_system.timestamp_format_string ("%%-- %D %I:%M %p --%%"); 2055 Foptimize_range (octave_value (false));
2049 2056 Ffixed_point_format (octave_value (true));
2050 m_error_system.beep_on_error (true); 2057 Fprint_empty_dimensions (octave_value (false));
2051 2058 Fprint_struct_array_contents (octave_value (true));
2052 Fconfirm_recursive_rmdir (octave_value (false)); 2059 Fstruct_levels_to_print (octave_value (0));
2053 Foptimize_diagonal_matrix (octave_value (false)); 2060
2054 Foptimize_permutation_matrix (octave_value (false)); 2061 m_error_system.disable_warning ("Octave:abbreviated-property-match");
2055 Foptimize_range (octave_value (false)); 2062 m_error_system.disable_warning ("Octave:colon-nonscalar-argument");
2056 Ffixed_point_format (octave_value (true)); 2063 m_error_system.disable_warning ("Octave:data-file-in-path");
2057 Fprint_empty_dimensions (octave_value (false)); 2064 m_error_system.disable_warning ("Octave:empty-index");
2058 Fprint_struct_array_contents (octave_value (true)); 2065 m_error_system.disable_warning ("Octave:function-name-clash");
2059 Fstruct_levels_to_print (octave_value (0)); 2066 m_error_system.disable_warning ("Octave:possible-matlab-short-circuit-operator");
2060 2067 }
2061 m_error_system.disable_warning ("Octave:abbreviated-property-match"); 2068
2062 m_error_system.disable_warning ("Octave:colon-nonscalar-argument"); 2069 void interpreter::execute_pkg_add (const std::string& dir)
2063 m_error_system.disable_warning ("Octave:data-file-in-path"); 2070 {
2064 m_error_system.disable_warning ("Octave:empty-index"); 2071 try
2065 m_error_system.disable_warning ("Octave:function-name-clash"); 2072 {
2066 m_error_system.disable_warning ("Octave:possible-matlab-short-circuit-operator"); 2073 m_load_path.execute_pkg_add (dir);
2067 } 2074 }
2068 2075 catch (const interrupt_exception&)
2069 void interpreter::execute_pkg_add (const std::string& dir) 2076 {
2070 { 2077 recover_from_exception ();
2071 try 2078 }
2072 { 2079 catch (const execution_exception& ee)
2073 m_load_path.execute_pkg_add (dir); 2080 {
2074 } 2081 handle_exception (ee);
2075 catch (const interrupt_exception&) 2082 }
2076 { 2083 }
2077 recover_from_exception ();
2078 }
2079 catch (const execution_exception& ee)
2080 {
2081 handle_exception (ee);
2082 }
2083 }
2084 2084
2085 OCTAVE_END_NAMESPACE(octave) 2085 OCTAVE_END_NAMESPACE(octave)