changeset 16435:22c0e0df1dbc

Merge in Adam's changes
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Thu, 04 Apr 2013 15:45:58 -0400
parents aa81cfa5c359 (current diff) 2c8860d563e5 (diff)
children 39847dcd2568
files libgui/src/octave-adapter/octave-event-listener.h libgui/src/octave-adapter/octave-link.cc libgui/src/octave-adapter/octave-link.h libgui/src/octave-adapter/octave-main-thread.cc libgui/src/octave-adapter/octave-main-thread.h libinterp/corefcn/__execute_edit_hook__.cc
diffstat 33 files changed, 1007 insertions(+), 1784 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/qterminal/libqterminal/unix/SelfListener.cpp	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/qterminal/libqterminal/unix/SelfListener.cpp	Thu Apr 04 15:45:58 2013 -0400
@@ -23,7 +23,7 @@
 }
 
 void SelfListener::run() {
-    char buf[4096];
+    char buf[4096 + 1];
     int len;
     bool running = true;
     while(running) {
--- a/libgui/src/history-dockwidget.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/history-dockwidget.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -120,40 +120,24 @@
 }
 
 void
-history_dock_widget::request_history_model_update ()
+history_dock_widget::set_history (const QStringList& hist)
 {
-  octave_link::post_event (this, &history_dock_widget::update_history_callback);
+  _history_model->setStringList (hist);
+  _history_list_view->scrollToBottom ();
 }
 
 void
-history_dock_widget::reset_model ()
+history_dock_widget::append_history (const QString& hist_entry)
+{
+  QStringList lst = _history_model->stringList ();
+  lst.append (hist_entry);
+  _history_model->setStringList (lst);
+  _history_list_view->scrollToBottom ();
+}
+
+void
+history_dock_widget::clear_history (void)
 {
   _history_model->setStringList (QStringList ());
 }
 
-void
-history_dock_widget::update_history_callback (void)
-{
-  // Determine the client's (our) history length and the one of the server.
-  int clientHistoryLength = _history_model->rowCount ();
-  int serverHistoryLength = command_history::length ();
-
-  // If were behind the server, iterate through all new entries and add
-  // them to our history.
-  if (clientHistoryLength < serverHistoryLength)
-    {
-      int elts_to_add = serverHistoryLength - clientHistoryLength;
-
-      _history_model->insertRows (clientHistoryLength, elts_to_add);
-
-      for (int i = clientHistoryLength; i < serverHistoryLength; i++)
-        {
-          std::string entry = command_history::get_entry (i);
-
-          _history_model->setData (_history_model->index (i),
-                      QString::fromUtf8 (entry.data (), entry.size ()));
-        }
-
-      _history_list_view->scrollToBottom ();
-    }
-}
--- a/libgui/src/history-dockwidget.h	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/history-dockwidget.h	Thu Apr 04 15:45:58 2013 -0400
@@ -35,11 +35,10 @@
   public:
   history_dock_widget (QWidget *parent = 0);
 
-  void update_history_callback (void);
-
 public slots:
-  void request_history_model_update ();
-  void reset_model ();
+  void set_history (const QStringList& hist);
+  void append_history (const QString& hist_entry);
+  void clear_history (void);
 
 signals:
   void information (const QString& message);
--- a/libgui/src/main-window.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/main-window.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -42,7 +42,6 @@
 #include "file-editor.h"
 #endif
 #include "main-window.h"
-#include "octave-link.h"
 #include "settings-dialog.h"
 
 #include "builtins.h"
@@ -60,7 +59,6 @@
 {
   // We have to set up all our windows, before we finally launch octave.
   construct ();
-  octave_link::launch_octave ();
 }
 
 main_window::~main_window ()
@@ -72,6 +70,9 @@
   if (_octave_qt_event_listener)
     delete _octave_qt_event_listener;
 
+  octave_link::connect_link (0);
+  delete _octave_qt_link;
+
 #ifdef HAVE_QSCINTILLA
   if (_file_editor)
     delete _file_editor;
@@ -155,7 +156,7 @@
 }
 
 void
-main_window::handle_clear_history_request()
+main_window::handle_clear_history_request (void)
 {
   octave_link::post_event (this, &main_window::clear_history_callback);
 }
@@ -288,12 +289,6 @@
 }
 
 void
-main_window::update_history (void)
-{
-  _history_dock_widget->update_history_callback ();
-}
-
-void
 main_window::change_current_working_directory ()
 {
   QString directory =
@@ -494,39 +489,6 @@
 }
 
 void
-main_window::handle_insert_debugger_pointer_request (const QString& file, int line)
-{
-#ifdef HAVE_QSCINTILLA
-  _file_editor->handle_insert_debugger_pointer_request (file, line);
-#endif
-}
-
-void
-main_window::handle_delete_debugger_pointer_request (const QString& file, int line)
-{
-#ifdef HAVE_QSCINTILLA
-  _file_editor->handle_delete_debugger_pointer_request (file, line);
-#endif
-}
-
-void
-main_window::handle_update_dbstop_marker_request (bool insert,
-                                                  const QString& file, int line)
-{
-#ifdef HAVE_QSCINTILLA
-  _file_editor->handle_update_dbstop_marker_request (insert, file, line);
-#endif
-}
-
-void
-main_window::handle_edit_file_request (const QString& file)
-{
-#ifdef HAVE_QSCINTILLA
-  _file_editor->handle_edit_file_request (file);
-#endif
-}
-
-void
 main_window::debug_continue ()
 {
   octave_link::post_event (this, &main_window::debug_continue_callback);
@@ -1165,7 +1127,6 @@
   setStatusBar (_status_bar);
 
   _octave_qt_event_listener = new octave_qt_event_listener ();
-  octave_link::register_event_listener (_octave_qt_event_listener);
 
   connect (_octave_qt_event_listener,
            SIGNAL (current_directory_has_changed_signal (QString)),
@@ -1178,11 +1139,6 @@
            SLOT (update_workspace ()));
 
   connect (_octave_qt_event_listener,
-           SIGNAL (update_history_signal ()),
-           this,
-           SLOT (update_history ()));
-
-  connect (_octave_qt_event_listener,
            SIGNAL (entered_debug_mode_signal ()),
            this,
            SLOT(handle_entered_debug_mode ()));
@@ -1192,23 +1148,47 @@
            this,
            SLOT (handle_quit_debug_mode ()));
 
-  connect (_octave_qt_event_listener,
-           SIGNAL (insert_debugger_pointer_signal (const QString&, int)), this,
+  // FIXME -- is it possible to eliminate the event_listenter?
+
+  _octave_qt_link = new octave_qt_link ();
+
+  connect (_octave_qt_link,
+           SIGNAL (set_history_signal (const QStringList&)),
+           _history_dock_widget, SLOT (set_history (const QStringList&)));
+
+  connect (_octave_qt_link,
+           SIGNAL (append_history_signal (const QString&)),
+           _history_dock_widget, SLOT (append_history (const QString&)));
+
+  connect (_octave_qt_link,
+           SIGNAL (clear_history_signal (void)),
+           _history_dock_widget, SLOT (clear_history (void)));
+
+  connect (_octave_qt_link,
+           SIGNAL (update_dbstop_marker_signal (bool, const QString&, int)),
+           _file_editor,
+           SLOT (handle_update_dbstop_marker_request (bool, const QString&, int)));
+
+  connect (_octave_qt_link,
+           SIGNAL (edit_file_signal (const QString&)),
+           _file_editor,
+           SLOT (handle_edit_file_request (const QString&)));
+
+  connect (_octave_qt_link,
+           SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
+           _file_editor,
            SLOT (handle_insert_debugger_pointer_request (const QString&, int)));
 
-  connect (_octave_qt_event_listener,
-           SIGNAL (delete_debugger_pointer_signal (const QString&, int)), this,
+  connect (_octave_qt_link,
+           SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
+           _file_editor,
            SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
 
-  connect (_octave_qt_event_listener,
-           SIGNAL (update_dbstop_marker_signal (bool, const QString&, int)),
-           this,
-           SLOT (handle_update_dbstop_marker_request (bool, const QString&, int)));
+  _octave_qt_link->execute_interpreter ();
 
-  connect (_octave_qt_event_listener,
-           SIGNAL (edit_file_signal (const QString&)),
-           this,
-           SLOT (handle_edit_file_request(const QString&)));
+  octave_link::connect_link (_octave_qt_link);
+
+  octave_link::register_event_listener (_octave_qt_event_listener);
 }
 
 void
@@ -1232,9 +1212,7 @@
 void
 main_window::clear_history_callback (void)
 {
-  command_history::clear ();
-
-  _history_dock_widget->reset_model ();
+  Fhistory (ovl ("-c"));
 }
 
 void
--- a/libgui/src/main-window.h	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/main-window.h	Thu Apr 04 15:45:58 2013 -0400
@@ -50,6 +50,7 @@
 #include "terminal-dockwidget.h"
 #include "documentation-dockwidget.h"
 #include "octave-qt-event-listener.h"
+#include "octave-qt-link.h"
 
 /**
  * \class MainWindow
@@ -70,7 +71,7 @@
   void handle_save_workspace_request ();
   void handle_load_workspace_request ();
   void handle_clear_workspace_request ();
-  void handle_clear_history_request ();
+  void handle_clear_history_request (void);
   void handle_command_double_clicked (const QString& command);
   void new_file ();
   void open_file ();
@@ -86,7 +87,6 @@
   void reset_windows ();
   void current_working_directory_has_changed (const QString& directory);
   void update_workspace (void);
-  void update_history (void);
   void change_current_working_directory ();
   void set_current_working_directory (const QString& directory);
   void current_working_directory_up ();
@@ -107,10 +107,6 @@
 
   void handle_entered_debug_mode ();
   void handle_quit_debug_mode ();
-  void handle_insert_debugger_pointer_request (const QString& file, int line);
-  void handle_delete_debugger_pointer_request (const QString& file, int line);
-  void handle_update_dbstop_marker_request (bool insert, const QString& file, int line);
-  void handle_edit_file_request (const QString& file);
   void debug_continue ();
   void debug_step_into ();
   void debug_step_over ();
@@ -178,6 +174,8 @@
 
   octave_qt_event_listener *_octave_qt_event_listener;
 
+  octave_qt_link *_octave_qt_link;
+
   // Flag for closing whole application
   bool                      _closing;
 };
--- a/libgui/src/module.mk	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/module.mk	Thu Apr 04 15:45:58 2013 -0400
@@ -72,13 +72,13 @@
   src/moc-history-dockwidget.cc \
   src/moc-main-window.cc \
   src/moc-octave-qt-event-listener.cc \
+  src/moc-octave-qt-link.cc \
   src/moc-settings-dialog.cc \
   src/moc-terminal-dockwidget.cc \
   src/moc-color-picker.cc \
   src/moc-welcome-wizard.cc \
   src/moc-workspace-model.cc \
   src/moc-workspace-view.cc \
-  src/octave-adapter/moc-octave-main-thread.cc \
   src/qtinfo/moc-parser.cc \
   src/qtinfo/moc-webinfo.cc \
   src/moc-octave-dock-widget.cc
@@ -104,11 +104,10 @@
   src/m-editor/find-dialog.h \
   src/m-editor/lexer-octave-gui.h \
   src/main-window.h \
-  src/octave-adapter/octave-event-listener.h \
-  src/octave-adapter/octave-link.h \
-  src/octave-adapter/octave-main-thread.h \
   src/octave-gui.h \
+  src/octave-main-thread.h \
   src/octave-qt-event-listener.h \
+  src/octave-qt-link.h \
   src/qtinfo/parser.h \
   src/qtinfo/webinfo.h \
   src/resource-manager.h \
@@ -129,10 +128,10 @@
   src/m-editor/find-dialog.cc \
   src/m-editor/lexer-octave-gui.cc \
   src/main-window.cc \
-  src/octave-adapter/octave-link.cc \
-  src/octave-adapter/octave-main-thread.cc \
   src/octave-gui.cc \
+  src/octave-main-thread.cc \
   src/octave-qt-event-listener.cc \
+  src/octave-qt-link.cc \
   src/qtinfo/parser.cc \
   src/qtinfo/webinfo.cc \
   src/resource-manager.cc \
@@ -153,7 +152,6 @@
   -I$(srcdir)/qterminal/libqterminal \
   -Isrc -I$(srcdir)/src \
   -I$(srcdir)/src/m-editor \
-  -I$(srcdir)/src/octave-adapter \
   -I$(srcdir)/src/qtinfo \
   -I$(top_srcdir)/liboctave/cruft/misc \
   -I$(top_srcdir)/liboctave/array \
--- a/libgui/src/octave-adapter/octave-event-listener.h	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
-
-Copyright (C) 2011-2012 Jacob Dawid
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-Octave is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef OCTAVEEVENTLISTENER_H
-#define OCTAVEEVENTLISTENER_H
-
-#include <string>
-
-class octave_event_listener
-{
-  public:
-    octave_event_listener () { }
-    virtual ~octave_event_listener () { }
-
-    virtual void
-    current_directory_has_changed (const std::string& directory) = 0;
-
-    virtual void
-    update_workspace (void) = 0;
-
-    virtual void
-    update_history (void) = 0;
-
-    virtual void
-    insert_debugger_pointer (const std::string& file, int line) = 0;
-
-    virtual void
-    delete_debugger_pointer (const std::string& file, int line) = 0;
-
-    virtual void
-    update_dbstop_marker (bool insert, const std::string& file, int line) = 0;
-
-    virtual void edit_file (const std::string& file) = 0;
-
-    virtual void about_to_exit () = 0;
-
-    virtual void entered_debug_mode () = 0;
-    virtual void quit_debug_mode () = 0;
-};
-
-#endif // OCTAVEEVENTLISTENER_H
--- a/libgui/src/octave-adapter/octave-link.cc	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-/*
-
-Copyright (C) 2011-2012 Jacob Dawid
-Copyright (C) 2011-2012 John P. Swensen
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-Octave is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "cmd-edit.h"
-#include "oct-env.h"
-#include "oct-mutex.h"
-#include "singleton-cleanup.h"
-#include "symtab.h"
-#include "toplev.h"
-
-#include "octave-link.h"
-
-static int
-octave_readline_hook (void)
-{
-  octave_link::entered_readline_hook ();
-  octave_link::generate_events ();
-  octave_link::process_events ();
-  octave_link::finished_readline_hook ();
-
-  return 0;
-}
-
-static void
-octave_exit_hook (int)
-{
-  octave_link::about_to_exit ();
-}
-
-octave_link *octave_link::instance = 0;
-
-octave_link::octave_link (void)
-  : event_listener (0), event_queue_mutex (new octave_mutex ()),
-    gui_event_queue (), last_cwd (), debugging (false)
-{ }
-
-void
-octave_link::do_launch_octave (void)
-{
-  // Create both threads.
-  main_thread = new octave_main_thread ();
-
-  command_editor::add_event_hook (octave_readline_hook);
-
-  octave_exit = octave_exit_hook;
-
-  // Start the first one.
-  main_thread->start ();
-}
-
-void
-octave_link::do_register_event_listener (octave_event_listener *el)
-{
-  event_listener = el;
-}
-
-void
-octave_link::do_generate_events (void)
-{
-  std::string current_working_directory = octave_env::get_current_directory ();
-
-  if (current_working_directory != last_cwd)
-    {
-      last_cwd = current_working_directory;
-
-      if (event_listener)
-        event_listener->current_directory_has_changed (last_cwd);
-    }
-
-  if (debugging != Vdebugging)
-    {
-      debugging = Vdebugging;
-
-      if (event_listener)
-        {
-          if (debugging)
-            event_listener->entered_debug_mode ();
-          else
-            event_listener->quit_debug_mode ();
-        }
-    }
-}
-
-void
-octave_link::do_process_events (void)
-{
-  event_queue_mutex->lock ();
-
-  gui_event_queue.run ();
-
-  event_queue_mutex->unlock ();
-}
-
-void
-octave_link::do_about_to_exit (void)
-{
-  event_queue_mutex->lock ();
-
-  gui_event_queue.discard ();
-
-  event_queue_mutex->unlock ();
-
-  if (event_listener)
-    event_listener->about_to_exit ();
-}
-
-std::string
-octave_link::do_last_working_directory (void)
-{
-  return last_cwd;
-}
-
-void
-octave_link::do_update_workspace (void)
-{
-  if (event_listener)
-    {
-      event_listener->update_workspace ();
-
-      do_process_events ();
-    }
-}
-
-void
-octave_link::do_update_history (void)
-{
-  if (event_listener)
-    {
-      event_listener->update_history ();
-
-      do_process_events ();
-    }
-}
-
-void
-octave_link::do_insert_debugger_pointer (const octave_value_list& args)
-{
-  if (event_listener)
-    {
-      if (args.length () == 1)
-        {
-          octave_scalar_map m = args(0).scalar_map_value ();
-
-          if (! error_state)
-            {
-              octave_value ov_file = m.getfield ("file");
-              octave_value ov_line = m.getfield ("line");
-
-              std::string file = ov_file.string_value ();
-              int line = ov_line.int_value ();
-
-              if (! error_state)
-                {
-                  event_listener->insert_debugger_pointer (file, line);
-
-                  do_process_events ();
-                }
-              else
-                ::error ("invalid struct in debug pointer callback");
-            }
-          else
-            ::error ("expecting struct in debug pointer callback");
-        }
-      else
-        ::error ("invalid call to debug pointer callback");
-    }
-}
-
-void
-octave_link::do_delete_debugger_pointer (const octave_value_list& args)
-{
-  if (event_listener)
-    {
-      if (args.length () == 1)
-        {
-          octave_scalar_map m = args(0).scalar_map_value ();
-
-          if (! error_state)
-            {
-              octave_value ov_file = m.getfield ("file");
-              octave_value ov_line = m.getfield ("line");
-
-              std::string file = ov_file.string_value ();
-              int line = ov_line.int_value ();
-
-              if (! error_state)
-                {
-                  event_listener->delete_debugger_pointer (file, line);
-
-                  do_process_events ();
-                }
-              else
-                ::error ("invalid struct in debug pointer callback");
-            }
-          else
-            ::error ("expecting struct in debug pointer callback");
-        }
-      else
-        ::error ("invalid call to debug pointer callback");
-    }
-}
-
-void
-octave_link::do_pre_input_event_hook_fcn (void)
-{
-  do_update_workspace ();
-}
-
-void
-octave_link::do_post_input_event_hook_fcn (void)
-{
-  do_update_history ();
-}
-
-void
-octave_link::do_enter_debugger_event_hook_fcn (const octave_value_list& args)
-{
-  do_insert_debugger_pointer (args);
-}
-
-void
-octave_link::do_exit_debugger_event_hook_fcn (const octave_value_list& args)
-{
-  do_delete_debugger_pointer (args);
-}
-
-void
-octave_link::do_update_breakpoint_hook_fcn
-  (bool insert, const octave_value_list& args)
-{
-  if (event_listener)
-    {
-      if (args.length () == 1)
-        {
-          octave_scalar_map m = args(0).scalar_map_value ();
-
-          if (! error_state)
-            {
-              octave_value ov_file = m.getfield ("file");
-              octave_value ov_line = m.getfield ("line");
-
-              std::string file = ov_file.string_value ();
-              int line = ov_line.int_value ();
-
-              if (! error_state)
-                {
-                  event_listener->update_dbstop_marker (insert, file, line);
-
-                  do_process_events ();
-                }
-              else
-                ::error ("invalid struct in dbstop marker callback");
-            }
-          else
-            ::error ("expecting struct in dbstop marker callback");
-        }
-      else
-        ::error ("invalid call to dbstop marker callback");
-    }
-}
-
-void
-octave_link::do_edit_file (const octave_value_list& args)
-{
-  if (event_listener)
-    {
-      if (args.length () == 1)
-        {
-          std::string file = args(0).string_value ();
-
-          if (! error_state)
-            {
-              event_listener->edit_file (file);
-              do_process_events ();
-
-            }
-          else
-            ::error ("expecting file name in edit file callback");
-        }
-      else
-        ::error ("invalid call to edit file callback");
-    }
-}
-
-bool
-octave_link::instance_ok (void)
-{
-  bool retval = true;
-
-  if (! instance)
-    {
-      instance = new octave_link ();
-
-      if (instance)
-        singleton_cleanup_list::add (cleanup_instance);
-    }
-
-  if (! instance)
-    {
-      ::error ("unable to create octave_link object!");
-
-      retval = false;
-    }
-
-  return retval;
-}
--- a/libgui/src/octave-adapter/octave-link.h	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-/*
-
-Copyright (C) 2011-2012 Jacob Dawid
-Copyright (C) 2011-2012 John P. Swensen
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-Octave is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef OCTAVELINK_H
-#define OCTAVELINK_H
-
-#include <string>
-
-class octave_mutex;
-
-#include "oct-obj.h"
-
-#include "event-queue.h"
-
-#include "octave-main-thread.h"
-#include "octave-event-listener.h"
-
-// \class OctaveLink
-// \brief Provides threadsafe access to octave.
-// \author Jacob Dawid
-//
-// This class is a wrapper around octave and provides thread safety by
-// buffering access operations to octave and executing them in the
-// readline event hook, which lives in the octave thread.
-
-class octave_link
-{
-protected:
-
-  octave_link (void);
-
-public:
-
-  ~octave_link (void) { }
-
-  static void launch_octave (void)
-  {
-    if (instance_ok ())
-      instance->do_launch_octave ();
-  }
-
-  static void register_event_listener (octave_event_listener *el)
-  {
-    if (instance_ok ())
-      instance->do_register_event_listener (el);
-  }
-
-  static void generate_events (void)
-  {
-    if (instance_ok ())
-      instance->do_generate_events ();
-  }
-
-  static void process_events (void)
-  {
-    if (instance_ok ())
-      instance->do_process_events ();
-  }
-
-  template <class T>
-  static void post_event (T *obj, void (T::*method) (void))
-  {
-    if (instance_ok ())
-      instance->do_post_event (obj, method);
-  }
-
-  template <class T, class A>
-  static void post_event (T *obj, void (T::*method) (A), A arg)
-  {
-    if (instance_ok ())
-      instance->do_post_event (obj, method, arg);
-  }
-
-  template <class T, class A>
-  static void post_event (T *obj, void (T::*method) (const A&), const A& arg)
-  {
-    if (instance_ok ())
-      instance->do_post_event (obj, method, arg);
-  }
-
-  static void about_to_exit (void)
-  {
-    if (instance_ok ())
-      instance->do_about_to_exit ();
-  }
-
-  static void entered_readline_hook (void)
-  {
-    if (instance_ok ())
-      instance->do_entered_readline_hook ();
-  }
-
-  static void finished_readline_hook (void)
-  {
-    if (instance_ok ())
-      instance->do_finished_readline_hook ();
-  }
-
-  static std::string last_working_directory (void)
-  {
-    return instance_ok ()
-      ? instance->do_last_working_directory () : std::string ();
-  }
-
-  static void update_workspace (void)
-  {
-    if (instance_ok ())
-      instance->do_update_workspace ();
-  }
-
-  static void update_history (void)
-  {
-    if (instance_ok ())
-      instance->do_update_history ();
-  }
-
-  static void pre_input_event_hook_fcn (void)
-  {
-    if (instance_ok ())
-      instance->do_pre_input_event_hook_fcn ();
-  }
-
-  static void post_input_event_hook_fcn (void)
-  {
-    if (instance_ok ())
-      instance->do_post_input_event_hook_fcn ();
-  }
-
-  static void enter_debugger_event_hook_fcn (const octave_value_list& args)
-  {
-    if (instance_ok ())
-      instance->do_enter_debugger_event_hook_fcn (args);
-  }
-
-  static void exit_debugger_event_hook_fcn (const octave_value_list& args)
-  {
-    if (instance_ok ())
-      instance->do_exit_debugger_event_hook_fcn (args);
-  }
-
-  static void
-  update_breakpoint_hook_fcn (bool insert, const octave_value_list& args)
-  {
-    if (instance_ok ())
-      instance->do_update_breakpoint_hook_fcn (insert, args);
-  }
-
-  static void
-  edit_file (const octave_value_list& args)
-  {
-    if (instance_ok ())
-      instance->do_edit_file (args);
-  }
-
-private:
-
-  static octave_link *instance;
-
-  static void cleanup_instance (void) { delete instance; instance = 0; }
-
-  // No copying!
-
-  octave_link (const octave_link&);
-
-  octave_link& operator = (const octave_link&);
-
-  static bool instance_ok (void);
-
-  octave_event_listener *event_listener;
-
-  // Thread running octave_main.
-  octave_main_thread *main_thread;
-
-  // Semaphore to lock access to the event queue.
-  octave_mutex *event_queue_mutex;
-
-  // Event Queue.
-  event_queue gui_event_queue;
-
-  // Stores the last known current working directory of octave.
-  std::string last_cwd;
-
-  bool debugging;
-
-  void do_launch_octave (void);
-  void do_register_event_listener (octave_event_listener *oel);
-
-  void do_generate_events (void);
-  void do_process_events (void);
-
-  template <class T>
-  void do_post_event (T *obj, void (T::*method) (void))
-  {
-    gui_event_queue.add_method (obj, method);
-  }
-
-  template <class T, class A>
-  void do_post_event (T *obj, void (T::*method) (A), A arg)
-  {
-    gui_event_queue.add_method (obj, method, arg);
-  }
-
-  template <class T, class A>
-  void do_post_event (T *obj, void (T::*method) (const A&), const A& arg)
-  {
-    gui_event_queue.add_method (obj, method, arg);
-  }
-
-  void do_about_to_exit (void);
-
-  void do_entered_readline_hook (void) { }
-  void do_finished_readline_hook (void) { }
-
-  std::string do_last_working_directory (void);
-  void do_update_workspace (void);
-  void do_update_history (void);
-  void do_insert_debugger_pointer (const octave_value_list& args);
-  void do_delete_debugger_pointer (const octave_value_list& args);
-
-  void do_pre_input_event_hook_fcn (void);
-  void do_post_input_event_hook_fcn (void);
-  void do_enter_debugger_event_hook_fcn (const octave_value_list& args);
-  void do_exit_debugger_event_hook_fcn (const octave_value_list& args);
-  void do_update_breakpoint_hook_fcn (bool insert,
-                                      const octave_value_list& args);
-
-  void do_edit_file (const octave_value_list& args);
-};
-
-#endif // OCTAVELINK_H
--- a/libgui/src/octave-adapter/octave-main-thread.cc	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
-
-Copyright (C) 2011-2012 Jacob Dawid
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-Octave is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <clocale>
-#include <string>
-
-#include "builtin-defun-decls.h"
-#include "octave.h"
-#include "ov-builtin.h"
-#include "ov-fcn-handle.h"
-
-#include "octave-main-thread.h"
-#include "octave-link.h"
-
-static octave_value_list
-pre_input_event_hook_fcn (const octave_value_list&, int)
-{
-  octave_value_list retval;
-
-  octave_link::pre_input_event_hook_fcn ();
-
-  return retval;
-}
-
-static octave_value_list
-post_input_event_hook_fcn (const octave_value_list&, int)
-{
-  octave_value_list retval;
-
-  octave_link::post_input_event_hook_fcn ();
-
-  return retval;
-}
-
-static octave_value_list
-enter_debugger_event_hook_fcn (const octave_value_list& args, int)
-{
-  octave_value_list retval;
-
-  octave_link::enter_debugger_event_hook_fcn (args);
-
-  return retval;
-}
-
-static octave_value_list
-exit_debugger_event_hook_fcn (const octave_value_list& args, int)
-{
-  octave_value_list retval;
-
-  octave_link::exit_debugger_event_hook_fcn (args);
-
-  return retval;
-}
-
-static octave_value_list
-dbstop_hook_fcn (const octave_value_list& args, int)
-{
-  octave_value_list retval;
-
-  octave_link::update_breakpoint_hook_fcn (true, args);
-
-  return retval;
-}
-
-static octave_value_list
-dbclear_hook_fcn (const octave_value_list& args, int)
-{
-  octave_value_list retval;
-
-  octave_link::update_breakpoint_hook_fcn (false, args);
-
-  return retval;
-}
-
-static octave_value_list
-edit_hook_fcn (const octave_value_list& args, int)
-{
-  octave_value_list retval;
-
-  octave_link::edit_file (args);
-
-  return retval;
-}
-
-octave_main_thread::octave_main_thread () : QThread ()
-{
-}
-
-void
-octave_main_thread::run ()
-{
-  // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting
-  setlocale (LC_NUMERIC, "C");
-
-  emit ready ();
-
-  octave_initialize_interpreter (octave_cmdline_argc, octave_cmdline_argv,
-                                 octave_embedded);
-
-  octave_value pre_fcn (new octave_builtin (pre_input_event_hook_fcn));
-  octave_value pre_fcn_handle (new octave_fcn_handle (pre_fcn));
-  Fadd_pre_input_event_hook (pre_fcn_handle);
-
-  octave_value post_fcn (new octave_builtin (post_input_event_hook_fcn));
-  octave_value post_fcn_handle (new octave_fcn_handle (post_fcn));
-  Fadd_post_input_event_hook (post_fcn_handle);
-
-  octave_value enter_debugger_fcn (new octave_builtin (enter_debugger_event_hook_fcn));
-  octave_value enter_debugger_fcn_handle (new octave_fcn_handle (enter_debugger_fcn));
-  Fadd_enter_debugger_event_hook (enter_debugger_fcn_handle);
-
-  octave_value exit_debugger_fcn (new octave_builtin (exit_debugger_event_hook_fcn));
-  octave_value exit_debugger_fcn_handle (new octave_fcn_handle (exit_debugger_fcn));
-  Fadd_exit_debugger_event_hook (exit_debugger_fcn_handle);
-
-  octave_value dbstop_fcn (new octave_builtin (dbstop_hook_fcn));
-  octave_value dbstop_fcn_handle (new octave_fcn_handle (dbstop_fcn));
-  Fadd_dbstop_hook (dbstop_fcn_handle);
-
-  octave_value dbclear_fcn (new octave_builtin (dbclear_hook_fcn));
-  octave_value dbclear_fcn_handle (new octave_fcn_handle (dbclear_fcn));
-  Fadd_dbclear_hook (dbclear_fcn_handle);
-
-  octave_value edit_fcn (new octave_builtin (edit_hook_fcn));
-  octave_value edit_fcn_handle (new octave_fcn_handle (edit_fcn));
-  Fadd_edit_hook (edit_fcn_handle);
-
-  // Prime the history list.
-  octave_link::update_history ();
-
-  octave_execute_interpreter ();
-}
--- a/libgui/src/octave-adapter/octave-main-thread.h	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
-
-Copyright (C) 2011-2012 Jacob Dawid
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-Octave is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef OCTAVEMAINTHREAD_H
-#define OCTAVEMAINTHREAD_H
-
-#include <QThread>
-
-/**
-  * \class octave_main
-  * \brief This class represents a thread just running octave_main.
-  * \author Jacob Dawid
-  */
-class octave_main_thread : public QThread
-{
-  Q_OBJECT
-public:
-  /** Creates a new thread running octave_main. */
-  octave_main_thread ();
-
-signals:
-  /** This signal will be emitted when the thread is about to actually
-    * run octave_main. */
-  void ready();
-
-protected:
-  /** Runs octave_main. */
-  void run ();
-};
-
-#endif // OCTAVEMAINTHREAD_H
--- a/libgui/src/octave-gui.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/octave-gui.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -80,7 +80,7 @@
 int
 octave_start_gui (int argc, char *argv[])
 {
-  dissociate_terminal ();
+  // dissociate_terminal ();
 
   QApplication application (argc, argv);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/octave-main-thread.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,55 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <clocale>
+#include <string>
+
+#include "builtin-defun-decls.h"
+#include "octave.h"
+#include "ov-builtin.h"
+#include "ov-fcn-handle.h"
+
+#include "octave-main-thread.h"
+#include "octave-link.h"
+
+void
+octave_main_thread::run (void)
+{
+  // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting
+  setlocale (LC_NUMERIC, "C");
+
+  octave_initialize_interpreter (octave_cmdline_argc, octave_cmdline_argv,
+                                 octave_embedded);
+
+  octave_execute_interpreter ();
+}
+
+void
+octave_main_thread::execute_interpreter (void)
+{
+  start ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/octave-main-thread.h	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,49 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef OCTAVEMAINTHREAD_H
+#define OCTAVEMAINTHREAD_H
+
+#include <QThread>
+
+/**
+  * \class octave_main
+  * \brief This class represents a thread just running octave_main.
+  * \author Jacob Dawid
+  */
+class octave_main_thread : public QThread
+{
+public:
+  // Create a new thread for running the octave interpreter.
+  octave_main_thread (void) : QThread () { }
+
+  // Start the thread and initialize and execute the octave
+  // interpreter.
+  void execute_interpreter (void);
+
+protected:
+  // Avoid exec.  Run the octave interpreter in the new thread.
+  void run (void);
+};
+
+#endif // OCTAVEMAINTHREAD_H
--- a/libgui/src/octave-qt-event-listener.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/octave-qt-event-listener.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -48,41 +48,6 @@
 }
 
 void
-octave_qt_event_listener::update_history (void)
-{
-  emit update_history_signal ();
-}
-
-void
-octave_qt_event_listener::insert_debugger_pointer (const std::string& file,
-                                                   int line)
-{
-  emit insert_debugger_pointer_signal (QString::fromStdString (file), line);
-}
-
-void
-octave_qt_event_listener::delete_debugger_pointer (const std::string& file,
-                                                   int line)
-{
-  emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
-}
-
-void
-octave_qt_event_listener::update_dbstop_marker (bool insert,
-                                                const std::string& file,
-                                                int line)
-{
-  emit update_dbstop_marker_signal (insert, QString::fromStdString (file),
-                                    line);
-}
-
-void
-octave_qt_event_listener::edit_file (const std::string& file)
-{
-  emit edit_file_signal (QString::fromStdString (file));
-}
-
-void
 octave_qt_event_listener::about_to_exit ()
 {
   qApp->quit ();
--- a/libgui/src/octave-qt-event-listener.h	Thu Apr 04 20:18:54 2013 +0100
+++ b/libgui/src/octave-qt-event-listener.h	Thu Apr 04 15:45:58 2013 -0400
@@ -36,11 +36,6 @@
 
   void current_directory_has_changed (const std::string& directory);
   void update_workspace (void);
-  void update_history (void);
-  void insert_debugger_pointer (const std::string& file, int line);
-  void delete_debugger_pointer (const std::string& file, int line);
-  void update_dbstop_marker (bool insert, const std::string& file, int line);
-  void edit_file (const std::string& file);
   void about_to_exit ();
 
   void entered_debug_mode ();
@@ -49,11 +44,6 @@
 signals:
   void current_directory_has_changed_signal (const QString& directory);
   void update_workspace_signal (void);
-  void update_history_signal (void);
-  void insert_debugger_pointer_signal (const QString& file, int line);
-  void delete_debugger_pointer_signal (const QString& file, int line);
-  void update_dbstop_marker_signal (bool insert, const QString& file, int line);
-  void edit_file_signal (const QString& file);
   void entered_debug_mode_signal ();
   void quit_debug_mode_signal ();
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/octave-qt-link.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,128 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+Copyright (C) 2011-2012 John P. Swensen
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QStringList>
+
+#include "str-vec.h"
+
+#include "octave-qt-link.h"
+
+octave_qt_link::octave_qt_link (void)
+  : octave_link (), main_thread (new octave_main_thread)
+{
+}
+
+void
+octave_qt_link::execute_interpreter (void)
+{
+  main_thread->execute_interpreter ();
+}
+
+void
+octave_qt_link::do_update_workspace (void)
+{
+  if (event_listener)
+    {
+      event_listener->update_workspace ();
+
+      do_process_events ();
+    }
+}
+
+void
+octave_qt_link::do_set_history (const string_vector& hist)
+{
+  QStringList qt_hist;
+
+  for (octave_idx_type i = 0; i < hist.length (); i++)
+    qt_hist.append (QString::fromStdString (hist[i]));
+
+  emit set_history_signal (qt_hist);
+}
+
+void
+octave_qt_link::do_append_history (const std::string& hist_entry)
+{
+  emit append_history_signal (QString::fromStdString (hist_entry));
+}
+
+void
+octave_qt_link::do_clear_history (void)
+{
+  emit clear_history_signal ();
+}
+
+void
+octave_qt_link::do_pre_input_event (void)
+{
+  do_update_workspace ();
+}
+
+void
+octave_qt_link::do_post_input_event (void)
+{
+}
+
+void
+octave_qt_link::do_enter_debugger_event (const std::string& file, int line)
+{
+  do_insert_debugger_pointer (file, line);
+}
+
+void
+octave_qt_link::do_exit_debugger_event (const std::string& file, int line)
+{
+  do_delete_debugger_pointer (file, line);
+}
+
+void
+octave_qt_link::do_update_breakpoint (bool insert,
+                                      const std::string& file, int line)
+{
+  emit update_dbstop_marker_signal (insert, QString::fromStdString (file), line);
+}
+
+bool
+octave_qt_link::do_edit_file (const std::string& file)
+{
+  emit edit_file_signal (QString::fromStdString (file));
+
+  return true;
+}
+
+void
+octave_qt_link::do_insert_debugger_pointer (const std::string& file, int line)
+{
+  emit insert_debugger_pointer_signal (QString::fromStdString (file), line);
+}
+
+void
+octave_qt_link::do_delete_debugger_pointer (const std::string& file, int line)
+{
+  emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/octave-qt-link.h	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,102 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+Copyright (C) 2011-2012 John P. Swensen
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef OCTAVE_QT_LINK_H
+#define OCTAVE_QT_LINK_H
+
+#include <string>
+
+#include <QObject>
+#include <QString>
+
+#include "octave-link.h"
+#include "octave-main-thread.h"
+
+// \class OctaveLink
+// \brief Provides threadsafe access to octave.
+// \author Jacob Dawid
+//
+// This class is a wrapper around octave and provides thread safety by
+// buffering access operations to octave and executing them in the
+// readline event hook, which lives in the octave thread.
+
+class octave_qt_link : public QObject, public octave_link
+{
+  Q_OBJECT
+
+public:
+
+  octave_qt_link (void);
+
+  ~octave_qt_link (void) { }
+
+  void execute_interpreter (void);
+
+  void do_update_workspace (void);
+
+  void do_set_history (const string_vector& hist);
+  void do_append_history (const std::string& hist_entry);
+  void do_clear_history (void);
+
+  void do_pre_input_event (void);
+  void do_post_input_event (void);
+
+  void do_enter_debugger_event (const std::string& file, int line);
+  void do_exit_debugger_event (const std::string& file, int line);
+
+  void do_update_breakpoint (bool insert, const std::string& file, int line);
+
+  bool do_edit_file (const std::string& file);
+
+private:
+
+  // No copying!
+
+  octave_qt_link (const octave_qt_link&);
+
+  octave_qt_link& operator = (const octave_qt_link&);
+
+  void do_insert_debugger_pointer (const std::string& file, int line);
+
+  void do_delete_debugger_pointer (const std::string& file, int line);
+
+  // Thread running octave_main.
+  octave_main_thread *main_thread;
+
+signals:
+
+  void set_history_signal (const QStringList& hist);
+  void append_history_signal (const QString& hist_entry);
+  void clear_history_signal (void);
+
+  void update_dbstop_marker_signal (bool insert, const QString& file, int line);
+
+  void edit_file_signal (const QString& file);
+
+  void insert_debugger_pointer_signal (const QString&, int);
+
+  void delete_debugger_pointer_signal (const QString&, int);
+};
+
+#endif
--- a/libinterp/corefcn/__execute_edit_hook__.cc	Thu Apr 04 20:18:54 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
-
-Copyright (C) 2013 John W. Eaton
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or (at
-your option) any later version.
-
-Octave is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "defun.h"
-#include "error.h"
-#include "defun.h"
-#include "hook-fcn.h"
-#include "oct-obj.h"
-
-static hook_function_list edit_hook_functions;
-
-DEFUN (add_edit_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_edit_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_edit_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of functions to call\n\
-to handle editing files.  The function should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{file}, @var{data})\n\
-@end example\n\
-\n\
-If @var{data} is omitted, Octave calls the function without one argument.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_edit_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          edit_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_edit_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_edit_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_edit_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_input_event_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call to handle editing files.\n\
-@seealso{add_edit_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = edit_hook_functions.find (hook_fcn_id);
-
-          if (p != edit_hook_functions.end ())
-            edit_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_edit_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_edit_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (__execute_edit_hook__, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{status} =} __execute_edit_hook__ (@var{file})\n\
-Undocumented internal function.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  if (edit_hook_functions.empty ())
-    retval = false;
-  else
-    {
-      edit_hook_functions.run (args);
-
-      retval = true;
-    }
-
-  return retval;
-}
-
-/*
-## No test needed for internal helper function.
-%!assert (1)
-*/
--- a/libinterp/corefcn/module.mk	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/corefcn/module.mk	Thu Apr 04 15:45:58 2013 -0400
@@ -27,7 +27,6 @@
 COREFCN_SRC = \
   corefcn/__contourc__.cc \
   corefcn/__dispatch__.cc \
-  corefcn/__execute_edit_hook__.cc \
   corefcn/__lin_interpn__.cc \
   corefcn/__pchip_deriv__.cc \
   corefcn/__qp__.cc \
--- a/libinterp/interp-core/ls-mat5.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interp-core/ls-mat5.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -82,6 +82,7 @@
 #endif
 
 #define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8)
+#define INT8(l) ((l) == miINT8 || (l) == miUINT8 || (l) == miUTF8)
 
 
 // The subsystem data block
@@ -674,7 +675,7 @@
       dims(1) = 1;
     }
 
-  if (read_mat5_tag (is, swap, type, len) || type != miINT8)
+  if (read_mat5_tag (is, swap, type, len) || !INT8(type))
     {
       error ("load: invalid array name subelement");
       goto early_read_error;
@@ -1059,7 +1060,7 @@
           {
             int32_t fn_type;
             int32_t fn_len;
-            if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8)
+            if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type))
               {
                 error ("load: invalid field name subelement");
                 goto data_read_error;
@@ -1120,7 +1121,7 @@
       {
         isclass = true;
 
-        if (read_mat5_tag (is, swap, type, len) || type != miINT8)
+        if (read_mat5_tag (is, swap, type, len) || !INT8(type))
           {
             error ("load: invalid class name");
             goto skip_ahead;
@@ -1170,7 +1171,7 @@
 
         // field name subelement.  The length of this subelement tells
         // us how many fields there are.
-        if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8)
+        if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type))
           {
             error ("load: invalid field name subelement");
             goto data_read_error;
--- a/libinterp/interp-core/module.mk	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interp-core/module.mk	Thu Apr 04 15:45:58 2013 -0400
@@ -35,6 +35,7 @@
   interp-core/mex.h \
   interp-core/mexproto.h \
   interp-core/mxarray.in.h \
+  interp-core/octave-event-listener.h \
   interp-core/oct-errno.h \
   interp-core/oct-fstrm.h \
   interp-core/oct-hdf5.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/interp-core/octave-event-listener.h	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,46 @@
+/*
+
+Copyright (C) 2011-2012 Jacob Dawid
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef OCTAVEEVENTLISTENER_H
+#define OCTAVEEVENTLISTENER_H
+
+#include <string>
+
+class octave_event_listener
+{
+  public:
+    octave_event_listener () { }
+    virtual ~octave_event_listener () { }
+
+    virtual void
+    current_directory_has_changed (const std::string& directory) = 0;
+
+    virtual void
+    update_workspace (void) = 0;
+
+    virtual void about_to_exit () = 0;
+
+    virtual void entered_debug_mode () = 0;
+    virtual void quit_debug_mode () = 0;
+};
+
+#endif // OCTAVEEVENTLISTENER_H
--- a/libinterp/interpfcn/debug.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interpfcn/debug.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -37,9 +37,9 @@
 #include "defun.h"
 #include "error.h"
 #include "help.h"
-#include "hook-fcn.h"
 #include "input.h"
 #include "pager.h"
+#include "octave-link.h"
 #include "oct-obj.h"
 #include "utils.h"
 #include "parse.h"
@@ -186,17 +186,6 @@
   return dbg_fcn;
 }
 
-octave_value
-location_info (const std::string& fname, int line)
-{
-  octave_scalar_map location_info_map;
-
-  location_info_map.setfield ("file", fname);
-  location_info_map.setfield ("line", line);
-
-  return octave_value (location_info_map);
-}
-
 static void
 parse_dbfunction_params (const char *who, const octave_value_list& args,
                          std::string& symbol_name, bp_table::intmap& lines)
@@ -285,201 +274,6 @@
   return retval;
 }
 
-static hook_function_list dbstop_hook_functions;
-static hook_function_list dbclear_hook_functions;
-
-DEFUN (add_dbstop_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_dbstop_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_dbstop_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of\n\
-functions to call when a debugger breakpoint is set.  The function\n\
-should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{location}, @var{data})\n\
-@end example\n\
-\n\
-in which @var{location} is a structure containing the following elements:\n\
-\n\
-@table @code\n\
-@item file\n\
-The name of the file where the breakpoint is located.\n\
-@item line\n\
-The line number corresponding to the breakpoint.\n\
-@end table\n\
-\n\
-If @var{data} is omitted when the hook function is added, the hook\n\
-function is called with a single argument.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_dbstop_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          dbstop_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_dbstop_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_dbstop_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_dbstop_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_dbstop_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call when a debugger breakpoint is set.\n\
-@seealso{add_dbstop_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = dbstop_hook_functions.find (hook_fcn_id);
-
-          if (p != dbstop_hook_functions.end ())
-            dbstop_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_dbstop_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_dbstop_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (add_dbclear_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_dbclear_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_dbclear_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of\n\
-functions to call when a debugger breakpoint is cleared.  The function\n\
-should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{location}, @var{data})\n\
-@end example\n\
-\n\
-in which @var{location} is a structure containing the following elements:\n\
-\n\
-@table @code\n\
-@item file\n\
-The name of the file where the breakpoint is located.\n\
-@item line\n\
-The line number corresponding to the breakpoint.\n\
-@end table\n\
-\n\
-If @var{data} is omitted when the hook function is added, the hook\n\
-function is called with a single argument.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_dbclear_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          dbclear_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_dbclear_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_dbclear_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_dbclear_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_dbclear_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call when a debugger breakpoint is cleared.\n\
-@seealso{add_dbclear_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = dbclear_hook_functions.find (hook_fcn_id);
-
-          if (p != dbclear_hook_functions.end ())
-            dbclear_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_dbclear_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_dbclear_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
 bp_table::intmap
 bp_table::do_add_breakpoint (const std::string& fname,
                              const bp_table::intmap& line)
@@ -513,8 +307,7 @@
                       std::string file = dbg_fcn->fcn_file_name ();
 
                       if (! file.empty ())
-                        dbstop_hook_functions.run
-                          (location_info (file, retval[i]));
+                        octave_link::update_breakpoint (true, file, retval[i]);
                     }
                 }
             }
@@ -569,8 +362,7 @@
                           cmds->delete_breakpoint (lineno);
 
                           if (! file.empty ())
-                            dbclear_hook_functions.run
-                              (location_info (file, lineno));
+                            octave_link::update_breakpoint (false, file, lineno);
                         }
                     }
 
@@ -619,7 +411,7 @@
               retval[i] = lineno;
 
               if (! file.empty ())
-                dbclear_hook_functions.run (location_info (file, lineno));
+                octave_link::update_breakpoint (false, file, lineno);
             }
 
           bp_set_iterator it = bp_set.find (fname);
--- a/libinterp/interpfcn/debug.h	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interpfcn/debug.h	Thu Apr 04 15:45:58 2013 -0400
@@ -131,6 +131,4 @@
 
 extern std::string get_file_line (const std::string& fname, size_t line);
 
-extern octave_value location_info (const std::string& fname, int line);
-
 #endif
--- a/libinterp/interpfcn/input.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interpfcn/input.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -53,6 +53,7 @@
 #include "input.h"
 #include "lex.h"
 #include "load-path.h"
+#include "octave-link.h"
 #include "oct-map.h"
 #include "oct-hist.h"
 #include "toplev.h"
@@ -122,11 +123,7 @@
 // The filemarker used to separate filenames from subfunction names
 char Vfilemarker = '>';
 
-static hook_function_list pre_input_event_hook_functions;
 static hook_function_list input_event_hook_functions;
-static hook_function_list post_input_event_hook_functions;
-static hook_function_list enter_debugger_event_hook_functions;
-static hook_function_list exit_debugger_event_hook_functions;
 
 // For octave_quit.
 void
@@ -215,7 +212,7 @@
   // printing the prompt.
 
   if (interactive || forced_interactive)
-    pre_input_event_hook_functions.run ();
+    octave_link::pre_input_event ();
 
   bool history_skip_auto_repeated_debugging_command = false;
 
@@ -255,7 +252,12 @@
   if (retval != "\n")
     {
       if (! history_skip_auto_repeated_debugging_command)
-        command_history::add (retval);
+        {
+          command_history::add (retval);
+
+          if (! command_history::ignoring_entries ())
+            octave_link::append_history (retval);
+        }
 
       octave_diary << retval;
 
@@ -271,7 +273,7 @@
   // list has been updated.
 
   if (interactive || forced_interactive)
-    post_input_event_hook_functions.run ();
+    octave_link::post_input_event ();
 
   return retval;
 }
@@ -458,9 +460,9 @@
 }
 
 static void
-exit_debugger_cleanup (const octave_value& loc_info)
+exit_debugger_handler (const std::pair<std::string, int>& arg)
 {
-  exit_debugger_event_hook_functions.run (loc_info);
+  octave_link::exit_debugger_event (arg.first, arg.second);
 }
 
 static void
@@ -510,11 +512,10 @@
 
           if (have_file)
             {
-              octave_value loc_info = location_info (nm, curr_debug_line);
+              octave_link::enter_debugger_event (nm, curr_debug_line);
 
-              enter_debugger_event_hook_functions.run (loc_info);
-
-              frame.add_fcn (exit_debugger_cleanup, loc_info);
+              frame.add_fcn (exit_debugger_handler,
+                             std::pair<std::string, int> (nm, curr_debug_line));
 
               std::string line_buf
                 = get_file_line (nm, curr_debug_line);
@@ -1091,94 +1092,6 @@
   return retval;
 }
 
-DEFUN (add_pre_input_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_pre_input_event_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_pre_input_event_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of functions to call\n\
-immediately prior to prompting for interactive user input.  The\n\
-function should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{data})\n\
-@end example\n\
-\n\
-If @var{data} is omitted, Octave calls the function without any\n\
-arguments.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_pre_input_event_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          pre_input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_pre_input_event_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_pre_input_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_pre_input_event_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_input_event_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call immediately prior to prompting for\n\
-interactive user input.\n\
-@seealso{add_pre_input_event_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = pre_input_event_hook_functions.find (hook_fcn_id);
-
-          if (p != pre_input_event_hook_functions.end ())
-            pre_input_event_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_pre_input_event_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_pre_input_event_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
- 
 static int
 internal_input_event_hook_fcn (void)
 {
@@ -1284,288 +1197,6 @@
   return retval;
 }
 
-DEFUN (add_post_input_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_post_input_event_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_post_input_event_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of functions to call\n\
-immediately after accepting interactive user input.  The function\n\
-should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{data})\n\
-@end example\n\
-\n\
-If @var{data} is omitted, Octave calls the function without any\n\
-arguments.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_post_input_event_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          post_input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_post_input_event_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_post_input_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_post_input_event_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_post_input_event_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call immediately after accepting\n\
-interactive user input.\n\
-@seealso{add_post_input_event_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = post_input_event_hook_functions.find (hook_fcn_id);
-
-          if (p != post_input_event_hook_functions.end ())
-            post_input_event_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_post_input_event_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_post_input_event_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (add_enter_debugger_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_enter_debugger_event_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_enter_debugger_event_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of\n\
-functions to call when a debugger breakpoint is reached.  The function\n\
-should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{location}, @var{data})\n\
-@end example\n\
-\n\
-in which @var{location} is a structure containing the following elements:\n\
-\n\
-@table @code\n\
-@item file\n\
-The name of the file where the breakpoint is located.\n\
-@item line\n\
-The line number corresponding to the breakpoint.\n\
-@end table\n\
-\n\
-If @var{data} is omitted when the hook function is added, the hook\n\
-function is called with a single argument.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_enter_debugger_event_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          enter_debugger_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_enter_debugger_event_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_enter_debugger_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_enter_debugger_event_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_enter_debugger_event_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call immediately after accepting\n\
-interactive user input.\n\
-@seealso{add_enter_debugger_event_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = enter_debugger_event_hook_functions.find (hook_fcn_id);
-
-          if (p != enter_debugger_event_hook_functions.end ())
-            enter_debugger_event_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_enter_debugger_event_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_enter_debugger_event_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (add_exit_debugger_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn  {Built-in Function} {@var{id} =} add_exit_debugger_event_hook (@var{fcn})\n\
-@deftypefnx {Built-in Function} {@var{id} =} add_exit_debugger_event_hook (@var{fcn}, @var{data})\n\
-Add the named function or function handle @var{fcn} to the list of\n\
-functions to call when continuing execution after a debugger breakpoint.\n\
-The function should have the form\n\
-\n\
-@example\n\
-@var{fcn} (@var{location}, @var{data})\n\
-@end example\n\
-\n\
-in which @var{location} is a structure containing the following elements:\n\
-\n\
-@table @code\n\
-@item file\n\
-The name of the file where the breakpoint is located.\n\
-@item line\n\
-The line number corresponding to the breakpoint.\n\
-@end table\n\
-\n\
-If @var{data} is omitted when the hook function is added, the hook\n\
-function is called with a single argument.\n\
-\n\
-The returned identifier may be used to remove the function handle from\n\
-the list of input hook functions.\n\
-@seealso{remove_exit_debugger_event_hook}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      octave_value user_data;
-
-      if (nargin == 2)
-        user_data = args(1);
-
-      hook_function hook_fcn (args(0), user_data);
-
-      if (! error_state)
-        {
-          exit_debugger_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
-
-          retval = hook_fcn.id ();
-        }
-      else
-        error ("add_exit_debugger_event_hook: expecting string as first arg");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (remove_exit_debugger_event_hook, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} remove_exit_debugger_event_hook (@var{name})\n\
-@deftypefnx {Built-in Function} {} remove_exit_debugger_event_hook (@var{fcn_id})\n\
-Remove the named function or function handle with the given identifier\n\
-from the list of functions to call immediately after accepting\n\
-interactive user input.\n\
-@seealso{add_exit_debugger_event_hook}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin == 2)
-    {
-      std::string hook_fcn_id = args(0).string_value ();
-
-      bool warn = (nargin < 2);
-
-      if (! error_state)
-        {
-          hook_function_list::iterator p
-            = exit_debugger_event_hook_functions.find (hook_fcn_id);
-
-          if (p != exit_debugger_event_hook_functions.end ())
-            exit_debugger_event_hook_functions.erase (p);
-          else if (warn)
-            warning ("remove_exit_debugger_event_hook: %s not found in list",
-                     hook_fcn_id.c_str ());
-        }
-      else
-        error ("remove_exit_debugger_event_hook: argument not valid as a hook function name or id");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
 DEFUN (PS1, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} PS1 ()\n\
--- a/libinterp/interpfcn/module.mk	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interpfcn/module.mk	Thu Apr 04 15:45:58 2013 -0400
@@ -16,6 +16,7 @@
   interpfcn/load-path.h \
   interpfcn/load-save.h \
   interpfcn/ls-oct-ascii.h \
+  interpfcn/octave-link.h \
   interpfcn/oct-hist.h \
   interpfcn/pager.h \
   interpfcn/pr-output.h \
@@ -42,6 +43,7 @@
   interpfcn/load-path.cc \
   interpfcn/load-save.cc \
   interpfcn/ls-oct-ascii.cc \
+  interpfcn/octave-link.cc \
   interpfcn/oct-hist.cc \
   interpfcn/pager.cc \
   interpfcn/pr-output.cc \
--- a/libinterp/interpfcn/oct-hist.cc	Thu Apr 04 20:18:54 2013 +0100
+++ b/libinterp/interpfcn/oct-hist.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -48,6 +48,7 @@
 #include "cmd-hist.h"
 #include "file-ops.h"
 #include "lo-mappers.h"
+#include "octave-link.h"
 #include "oct-env.h"
 #include "oct-time.h"
 #include "str-vec.h"
@@ -186,18 +187,29 @@
             command_history::write ();
 
           else if (option == "-r")
-            // Read entire file.
-            command_history::read ();
+            {
+              // Read entire file.
+              command_history::read ();
+              octave_link::set_history (command_history::list ());
+            }
 
           else if (option == "-n")
-            // Read 'new' history from file.
-            command_history::read_range ();
+            {
+              // Read 'new' history from file.
+              command_history::read_range ();
+              octave_link::set_history (command_history::list ());
+            }
 
           else
             panic_impossible ();
 
           return hlist;
         }
+      else if (option == "-c")
+        {
+          command_history::clear ();
+          octave_link::clear_history ();
+        }
       else if (option == "-q")
         numbered_output = false;
       else if (option == "--")
@@ -354,7 +366,10 @@
         tmp.resize (len - 1);
 
       if (! tmp.empty ())
-        command_history::add (tmp);
+        {
+          command_history::add (tmp);
+          octave_link::append_history (tmp);
+        }
     }
 }
 
@@ -601,6 +616,8 @@
                                default_history_file (),
                                default_history_size (),
                                octave_env::getenv ("OCTAVE_HISTCONTROL"));
+
+  octave_link::set_history (command_history::list ());
 }
 
 void
@@ -611,7 +628,10 @@
   std::string timestamp = now.strftime (Vhistory_timestamp_format_string);
 
   if (! timestamp.empty ())
-    command_history::add (timestamp);
+    {
+      command_history::add (timestamp); 
+      octave_link::append_history (timestamp);
+   }
 }
 
 DEFUN (edit_history, args, ,
@@ -671,6 +691,9 @@
 @itemx -@var{n}\n\
 Display only the most recent @var{n} lines of history.\n\
 \n\
+@item -c\n\
+Clear the history list.\n\
+\n\
 @item -q\n\
 Don't number the displayed lines of history.  This is useful for cutting\n\
 and pasting commands using the X Window System.\n\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/interpfcn/octave-link.cc	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,167 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+Copyright (C) 2011-2012 John P. Swensen
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "cmd-edit.h"
+#include "defun.h"
+#include "oct-env.h"
+#include "oct-mutex.h"
+#include "singleton-cleanup.h"
+#include "symtab.h"
+#include "toplev.h"
+
+#include "octave-link.h"
+
+static int
+octave_readline_hook (void)
+{
+  octave_link::entered_readline_hook ();
+  octave_link::generate_events ();
+  octave_link::process_events ();
+  octave_link::finished_readline_hook ();
+
+  return 0;
+}
+
+static void
+octave_exit_hook (int)
+{
+  octave_link::about_to_exit ();
+}
+
+octave_link *octave_link::instance = 0;
+
+octave_link::octave_link (void)
+  : event_listener (0), event_queue_mutex (new octave_mutex ()),
+    gui_event_queue (), last_cwd (), debugging (false)
+{
+  command_editor::add_event_hook (octave_readline_hook);
+
+  octave_exit = octave_exit_hook;
+}
+
+// OBJ should be an object of a class that is derived from the base
+// class octave_link, or 0 to disconnect the link.  It is the
+// responsibility of the caller to delete obj.
+
+void
+octave_link::connect_link (octave_link* obj)
+{
+  if (obj && instance)
+    ::error ("octave_link is already linked!");
+  else
+    instance = obj;
+}
+
+void
+octave_link::do_register_event_listener (octave_event_listener *el)
+{
+  event_listener = el;
+}
+
+void
+octave_link::do_generate_events (void)
+{
+  std::string current_working_directory = octave_env::get_current_directory ();
+
+  if (current_working_directory != last_cwd)
+    {
+      last_cwd = current_working_directory;
+
+      if (event_listener)
+        event_listener->current_directory_has_changed (last_cwd);
+    }
+
+  if (debugging != Vdebugging)
+    {
+      debugging = Vdebugging;
+
+      if (event_listener)
+        {
+          if (debugging)
+            event_listener->entered_debug_mode ();
+          else
+            event_listener->quit_debug_mode ();
+        }
+    }
+}
+
+void
+octave_link::do_process_events (void)
+{
+  event_queue_mutex->lock ();
+
+  gui_event_queue.run ();
+
+  event_queue_mutex->unlock ();
+}
+
+void
+octave_link::do_about_to_exit (void)
+{
+  event_queue_mutex->lock ();
+
+  gui_event_queue.discard ();
+
+  event_queue_mutex->unlock ();
+
+  if (event_listener)
+    event_listener->about_to_exit ();
+}
+
+std::string
+octave_link::do_last_working_directory (void)
+{
+  return last_cwd;
+}
+
+bool
+octave_link::instance_ok (void)
+{
+  return instance != 0;
+}
+
+DEFUN (__octave_link_edit_file__, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} __octave_link_edit_file__ (@var{file})\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  if (args.length () == 1)
+    {
+      std::string file = args(0).string_value ();
+
+      if (! error_state)
+        retval = octave_link::edit_file (file);
+      else
+        error ("expecting file name as argument");
+    }
+
+  return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/interpfcn/octave-link.h	Thu Apr 04 15:45:58 2013 -0400
@@ -0,0 +1,257 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+Copyright (C) 2011-2012 Jacob Dawid
+Copyright (C) 2011-2012 John P. Swensen
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_link_h)
+#define octave_link_h 1
+
+#include <string>
+
+#include "event-queue.h"
+#include "octave-event-listener.h"
+
+class octave_mutex;
+class string_vector;
+
+// \class OctaveLink
+// \brief Provides threadsafe access to octave.
+// \author Jacob Dawid
+//
+// This class is a wrapper around octave and provides thread safety by
+// buffering access operations to octave and executing them in the
+// readline event hook, which lives in the octave thread.
+
+class octave_link
+{
+protected:
+
+  octave_link (void);
+
+public:
+
+  virtual ~octave_link (void) { }
+
+  static void register_event_listener (octave_event_listener *el)
+  {
+    if (instance_ok ())
+      instance->do_register_event_listener (el);
+  }
+
+  static void generate_events (void)
+  {
+    if (instance_ok ())
+      instance->do_generate_events ();
+  }
+
+  static void process_events (void)
+  {
+    if (instance_ok ())
+      instance->do_process_events ();
+  }
+
+  template <class T>
+  static void post_event (T *obj, void (T::*method) (void))
+  {
+    if (instance_ok ())
+      instance->do_post_event (obj, method);
+  }
+
+  template <class T, class A>
+  static void post_event (T *obj, void (T::*method) (A), A arg)
+  {
+    if (instance_ok ())
+      instance->do_post_event (obj, method, arg);
+  }
+
+  template <class T, class A>
+  static void post_event (T *obj, void (T::*method) (const A&), const A& arg)
+  {
+    if (instance_ok ())
+      instance->do_post_event (obj, method, arg);
+  }
+
+  static void about_to_exit (void)
+  {
+    if (instance_ok ())
+      instance->do_about_to_exit ();
+  }
+
+  static void entered_readline_hook (void)
+  {
+    if (instance_ok ())
+      instance->do_entered_readline_hook ();
+  }
+
+  static void finished_readline_hook (void)
+  {
+    if (instance_ok ())
+      instance->do_finished_readline_hook ();
+  }
+
+  static std::string last_working_directory (void)
+  {
+    return instance_ok ()
+      ? instance->do_last_working_directory () : std::string ();
+  }
+
+  static void update_workspace (void)
+  {
+    if (instance_ok ())
+      instance->do_update_workspace ();
+  }
+
+  static void set_history (const string_vector& hist)
+  {
+    if (instance_ok ())
+      instance->do_set_history (hist);
+  }
+
+  static void append_history (const std::string& hist_entry)
+  {
+    if (instance_ok ())
+      instance->do_append_history (hist_entry);
+  }
+
+  static void clear_history (void)
+  {
+    if (instance_ok ())
+      instance->do_clear_history ();
+  }
+
+  static void pre_input_event (void)
+  {
+    if (instance_ok ())
+      instance->do_pre_input_event ();
+  }
+
+  static void post_input_event (void)
+  {
+    if (instance_ok ())
+      instance->do_post_input_event ();
+  }
+
+  static void enter_debugger_event (const std::string& file, int line)
+  {
+    if (instance_ok ())
+      instance->do_enter_debugger_event (file, line);
+  }
+
+  static void exit_debugger_event (const std::string& file, int line)
+  {
+    if (instance_ok ())
+      instance->do_exit_debugger_event (file, line);
+  }
+
+  static void
+  update_breakpoint (bool insert, const std::string& file, int line)
+  {
+    if (instance_ok ())
+      instance->do_update_breakpoint (insert, file, line);
+  }
+
+  static bool
+  edit_file (const std::string& file)
+  {
+    return instance_ok () ? instance->do_edit_file (file) : false;
+  }
+
+  static void connect_link (octave_link *);
+
+private:
+
+  static octave_link *instance;
+
+  static void cleanup_instance (void) { delete instance; instance = 0; }
+
+  // No copying!
+
+  octave_link (const octave_link&);
+
+  octave_link& operator = (const octave_link&);
+
+  static bool instance_ok (void);
+
+protected:
+
+  octave_event_listener *event_listener;
+
+  // Semaphore to lock access to the event queue.
+  octave_mutex *event_queue_mutex;
+
+  // Event Queue.
+  event_queue gui_event_queue;
+
+  // Stores the last known current working directory of octave.
+  std::string last_cwd;
+
+  bool debugging;
+
+  void do_register_event_listener (octave_event_listener *oel);
+
+  void do_generate_events (void);
+  void do_process_events (void);
+
+  template <class T>
+  void do_post_event (T *obj, void (T::*method) (void))
+  {
+    gui_event_queue.add_method (obj, method);
+  }
+
+  template <class T, class A>
+  void do_post_event (T *obj, void (T::*method) (A), A arg)
+  {
+    gui_event_queue.add_method (obj, method, arg);
+  }
+
+  template <class T, class A>
+  void do_post_event (T *obj, void (T::*method) (const A&), const A& arg)
+  {
+    gui_event_queue.add_method (obj, method, arg);
+  }
+
+  void do_about_to_exit (void);
+
+  void do_entered_readline_hook (void) { }
+  void do_finished_readline_hook (void) { }
+
+  std::string do_last_working_directory (void);
+
+  virtual void do_update_workspace (void) = 0;
+
+  virtual void do_set_history (const string_vector& hist) = 0;
+  virtual void do_append_history (const std::string& hist_entry) = 0;
+  virtual void do_clear_history (void) = 0;
+
+  virtual void do_pre_input_event (void) = 0;
+  virtual void do_post_input_event (void) = 0;
+
+  virtual void do_enter_debugger_event (const std::string& file, int line) = 0;
+  virtual void do_exit_debugger_event (const std::string& file, int line) = 0;
+
+  virtual void do_update_breakpoint (bool insert,
+                                     const std::string& file, int line) = 0;
+
+  virtual bool do_edit_file (const std::string& file) = 0;
+};
+
+#endif // OCTAVELINK_H
--- a/scripts/miscellaneous/edit.m	Thu Apr 04 20:18:54 2013 +0100
+++ b/scripts/miscellaneous/edit.m	Thu Apr 04 15:45:58 2013 -0400
@@ -563,7 +563,7 @@
   ## Give the hook function a chance.  If that fails, fall back
   ## on running an editor with the system function.
 
-  status = __execute_edit_hook__ (file);
+  status = __octave_link_edit_file__ (file);
 
   if (! status)
     system (sprintf (undo_string_escapes (editor),
--- a/scripts/signal/fftfilt.m	Thu Apr 04 20:18:54 2013 +0100
+++ b/scripts/signal/fftfilt.m	Thu Apr 04 15:45:58 2013 -0400
@@ -94,53 +94,99 @@
   endif
 
   y = y(1:r_x, :);
-  if (transpose)
-    y = y.';
+
+  ## Final cleanups:
+
+  ## - If both b and x are real, y should be real.
+  ## - If b is real and x is imaginary, y should be imaginary.
+  ## - If b is imaginary and x is real, y should be imaginary.
+  ## - If both b and x are imaginary, y should be real.
+  xisreal = zeros (1,size(x,2));
+  xisimag = xisreal;
+  for cx = 1:size(x,2)
+    if (all (imag (x(:,cx)) == 0))
+      xisreal (cx) = 1;
+    elseif (all (real (x (:,cx)) == 0))
+      xisimag (cx) = 1;
+    endif
+  endfor
+  xisreal = find(xisreal);
+  xisimag = find(xisimag);
+  if (all (imag (b) == 0))
+    y (:,xisreal) = real (y (:,xisreal));
+    y (:,xisimag) = complex (real (y (:,xisimag)) * 0, imag (y (:,xisimag)));
+  elseif (all (real (b) == 0))
+    y (:,xisreal) = complex (real (y (:,xisreal)) * 0, imag (y (:,xisreal)));
+    y (:,xisimag) = real (y (:,xisimag));
   endif
 
-  ## Final cleanups: If both x and b are real, y should be real.
-  ## If both x and b are integer, y should be integer.
+  ## - If both x and b are integer in both real and imaginary
+  ##   components, y should be integer.
+  if (! any (b - fix (b)))
+    idx = find (! any (x - fix (x)));
+    y (:, idx) = round (y (:, idx));
+  endif
 
-  if (isreal (b) && isreal (x))
-    y = real (y);
-  endif
-  if (! any (b - fix (b)))
-    idx = !any (x - fix (x));
-    y(:, idx) = round (y(:, idx));
+  ## Transpose after cleanup, otherwise rounding fails.
+  if (transpose)
+    y = y.';
   endif
 
 endfunction
 
 
 %!shared b, x, r
+
 %!test
 %! b = [1 1];
 %! x = [1, zeros(1,9)];
-%! assert (fftfilt (b,  x  ), [1 1 0 0 0 0 0 0 0 0]  , eps);
-%! assert (fftfilt (b,  x.'), [1 1 0 0 0 0 0 0 0 0].', eps);
-%! assert (fftfilt (b.',x  ), [1 1 0 0 0 0 0 0 0 0]  , eps);
-%! assert (fftfilt (b.',x.'), [1 1 0 0 0 0 0 0 0 0].', eps);
+%! assert (fftfilt (b,  x  ), [1 1 0 0 0 0 0 0 0 0]  );
+%! assert (fftfilt (b,  x.'), [1 1 0 0 0 0 0 0 0 0].');
+%! assert (fftfilt (b.',x  ), [1 1 0 0 0 0 0 0 0 0]  );
+%! assert (fftfilt (b.',x.'), [1 1 0 0 0 0 0 0 0 0].');
+%! assert (fftfilt (b,  [x.' x.']), [1 1 0 0 0 0 0 0 0 0].'*[1 1]);
+%! assert (fftfilt (b,  [x.'+eps x.']) == [1 1 0 0 0 0 0 0 0 0].'*[1 1], [false(10, 1) true(10, 1)]);
 
 %!test
 %! r = sqrt (1/2) * (1+i);
 %! b = b*r;
-%! assert (fftfilt (b, x  ), r*[1 1 0 0 0 0 0 0 0 0]  , eps);
-%! assert (fftfilt (b, r*x), r*r*[1 1 0 0 0 0 0 0 0 0], eps);
-%! assert (fftfilt (b, x.'), r*[1 1 0 0 0 0 0 0 0 0].', eps);
+%! assert (fftfilt (b, x  ), r*[1 1 0 0 0 0 0 0 0 0]  , eps  );
+%! assert (fftfilt (b, r*x), r*r*[1 1 0 0 0 0 0 0 0 0], 2*eps);
+%! assert (fftfilt (b, x.'), r*[1 1 0 0 0 0 0 0 0 0].', eps  );
 
 %!test
-%! b = [1 1];
-%! x = zeros (10,3); x(1,1)=-1; x(1,2)=1;
+%! b  = [1 1];
+%! x  = zeros (10,3); x(1,1)=-1; x(1,2)=1;
 %! y0 = zeros (10,3); y0(1:2,1)=-1; y0(1:2,2)=1;
-%! y = fftfilt (b, x);
-%! assert (y,y0);
+%! y  = fftfilt (b, x);
+%! assert (y0, y);
+%! y  = fftfilt (b*i, x);
+%! assert (y0*i, y);
+%! y  = fftfilt (b, x*i);
+%! assert (y0*i, y);
+%! y  = fftfilt (b*i, x*i);
+%! assert (-y0, y);
+%! x  = rand (10, 1);
+%! y  = fftfilt (b, [x x*i]);
+%! assert (true, isreal (y(:,1)));
+%! assert (false, any (real (y(:,2))));
 
 %!test
 %! b  = rand (10, 1);
 %! x  = rand (10, 1);
 %! y0 = filter (b, 1, x);
-%! y  = filter (b, 1, x);
-%! assert (y, y0);
+%! y  = fftfilt (b, x);
+%! assert (y0, y, 16*eps);
+%! y0 = filter (b*i, 1, x*i);
+%! y  = fftfilt (b*i, x*i);
+%! assert (y0, y, 16*eps);
+
+%!test
+%! b  = rand (10, 1) + i*rand (10, 1);
+%! x  = rand (10, 1) + i*rand (10, 1);
+%! y0 = filter (b, 1, x);
+%! y  = fftfilt (b, x);
+%! assert (y0, y, 55*eps);
 
 %% Test input validation
 %!error fftfilt (1)
--- a/scripts/sparse/svds.m	Thu Apr 04 20:18:54 2013 +0100
+++ b/scripts/sparse/svds.m	Thu Apr 04 15:45:58 2013 -0400
@@ -103,7 +103,7 @@
   endif
 
   if (nargin < 4)
-    opts.tol = 1e-10 / root2;
+    opts.tol = 0;   ## use ARPACK default
     opts.disp = 0;
     opts.maxit = 300;
   else
@@ -111,7 +111,7 @@
       error ("svds: OPTS must be a structure");
     endif
     if (!isfield (opts, "tol"))
-      opts.tol = 1e-10 / root2;
+      opts.tol = 0;   ## use ARPACK default
     else
       opts.tol = opts.tol / root2;
     endif
@@ -152,7 +152,6 @@
     b_opts = opts;
     ## Call to eigs is always a symmetric matrix by construction
     b_opts.issym = true;
-    b_opts.tol = opts.tol / max_a;
     b_sigma = sigma;
     if (!ischar (b_sigma))
       b_sigma = b_sigma / max_a;
@@ -235,14 +234,14 @@
     endif
 
     if (nargout > 3)
-      flag = norm (A*v - u*s, 1) > root2 * opts.tol * norm (A, 1);
+      flag = (flag != 0);
     endif
   endif
 
 endfunction
 
 
-%!shared n, k, A, u, s, v, opts, rand_state, randn_state
+%!shared n, k, A, u, s, v, opts, rand_state, randn_state, tol
 %! n = 100;
 %! k = 7;
 %! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),0.4*n*ones(1,n),ones(1,n-2)]);
@@ -263,13 +262,15 @@
 %! [u2,s2,v2,flag] = svds (A,k);
 %! s2 = diag (s2);
 %! assert (flag, !1);
-%! assert (s2, s(end:-1:end-k+1), 1e-10);
+%! tol = 10 * eps() * norm(s2, 1);
+%! assert (s2, s(end:-1:end-k+1), tol);
 %!
 %!testif HAVE_ARPACK, HAVE_UMFPACK
 %! [u2,s2,v2,flag] = svds (A,k,0,opts);
 %! s2 = diag (s2);
 %! assert (flag, !1);
-%! assert (s2, s(k:-1:1), 1e-10);
+%! tol = 10 * eps() * norm(s2, 1);
+%! assert (s2, s(k:-1:1), tol);
 %!
 %!testif HAVE_ARPACK, HAVE_UMFPACK
 %! idx = floor (n/2);
@@ -278,7 +279,8 @@
 %! [u2,s2,v2,flag] = svds (A,k,sigma,opts);
 %! s2 = diag (s2);
 %! assert (flag, !1);
-%! assert (s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), 1e-10);
+%! tol = 10 * eps() * norm(s2, 1);
+%! assert (s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), tol);
 %!
 %!testif HAVE_ARPACK
 %! [u2,s2,v2,flag] = svds (zeros (10), k);