diff libinterp/corefcn/input.cc @ 25407:ab10403a0b50

new input_system class to manage user input for the interpreter Encapsulate many command-line input functions and data within a new class that is a member of the interpreter object. * input.h, input.cc (input_system): New class. Include data members for former static variables VPS1, VPS2, Vcompletion_append_char, last_debugging_command, Vgud_mode, input_event_hook_functions, and Vmfile_encoding. Change all uses. (is_variable, generate_struct_completions, looks_like_struct): Move here from variables.cc and make static. (set_default_prompts, octave_yes_or_no, do_keyboard, remove_input_event_hook_functions, get_input_from_stdin): Deprecate. (Fadd_input_event_hook, Fremove_input_event_hook, FPS1, FPS2, Fcompletion_append_char, F__request_drawnow__, F__gud_mode__, F__mfile_encoding__, Finput, Fyes_or_no): Define with DEFMETHOD. Change all uses. (input_system::have_input_event_hooks, input_system::add_input_event_hook, input_system::remove_input_event_hook, input_system::clear_input_event_hooks, input_system::run_input_event_hooks): New functions to manage input event hooks. (input_system::yes_or_no, input_system::interactive_input, input_system::get_user_input, input_system::keyboard, input_system::gnu_readline, input_system::get_debug_input): New functions adapted from former file-scope static and global functions. * interpreter.h, interpreter.cc (interpreter::m_input_system): New data member. (interpreter::get_input_system): New function. (interpreter::intepreter): Don't call set_default_prompts. Call input_system::initialize. (interpreter::maximum_braindamage): Call input_system::PS1 and input_system::PS2 directly here. * variables.h, variables.cc (get_struct_elts): Deprecate. * main-window.cc (octave_interpreter::m_app_context): Now pointer to gui_application, not application. (octave_interpreter::octave_interpreter): Arg is now gui_application, not application. Set default prompt strings directly here. * qt-link.h, qt-link.cc (octave_qt_link::do_set_default_prompts): Delete. * octave-link.h, octave-link.cc (octave_link::set_default_prompts, octave_link::do_set_default_prompts): Delete. * hook-fcn.h, hook-fcn.cc (named_hook_function::eval, fcn_handle_hook_function::eval): Move code from .h to .cc file. Make id and is_valid methods const. * interpreter-private.h, interpreter-private.cc (__get_input_system__): New function.
author John W. Eaton <jwe@octave.org>
date Wed, 23 May 2018 17:12:57 -0400
parents ef2b9d4abf4a
children a52e6fb674b1
line wrap: on
line diff
--- a/libinterp/corefcn/input.cc	Thu May 24 00:35:36 2018 -0400
+++ b/libinterp/corefcn/input.cc	Wed May 23 17:12:57 2018 -0400
@@ -76,18 +76,9 @@
 #include "utils.h"
 #include "variables.h"
 
-// Primary prompt string.
-static std::string VPS1;
-
-// Secondary prompt string.
-static std::string VPS2;
-
 // The time we last printed a prompt.
 octave::sys::time Vlast_prompt_time = 0.0;
 
-// Character to append after successful command-line completion attempts.
-static char Vcompletion_append_char = ' ';
-
 // TRUE after a call to completion_matches.
 bool octave_completion_matches_called = false;
 
@@ -103,282 +94,182 @@
 // the terminal.
 bool Vtrack_line_num = true;
 
-// If we are in debugging mode, this is the last command entered, so
-// that we can repeat the previous command if the user just types RET.
-static std::string last_debugging_command = "\n";
-
-// TRUE if we are running in the Emacs GUD mode.
-static bool Vgud_mode = false;
-
-static hook_function_list input_event_hook_functions;
-
-// Codepage which is used to read .m files
-#if defined (OCTAVE_USE_WINDOWS_API)
-static std::string Vmfile_encoding = "system";
-#else
-static std::string Vmfile_encoding = "utf-8";
-#endif
-
-// For octave_quit.
-void
-remove_input_event_hook_functions (void)
+static std::string
+quoting_filename (const std::string& text, int, char quote)
 {
-  input_event_hook_functions.clear ();
+  if (quote)
+    return text;
+  else
+    return ("'" + text);
 }
 
-void
-set_default_prompts (void)
+// Try to parse a partial command line in reverse, excluding trailing TEXT.
+// If it appears a variable has been indexed by () or {},
+// return that expression,
+// to allow autocomplete of field names of arrays of structures.
+static std::string
+find_indexed_expression (const std::string& text)
 {
-  // Use literal "octave" instead of "\\s" to avoid setting the prompt
-  // to "octave.exe" or "octave-gui", etc.
+  std::string line = octave::command_editor::get_line_buffer ();
+
+  int pos = line.length () - text.length ();
+  int curly_count = 0;
+  int paren_count = 0;
+
+  int last = --pos;
+
+  while (pos >= 0 && (line[pos] == ')' || line[pos] == '}'))
+    {
+      if (line[pos] == ')')
+        paren_count++;
+      else if (line[pos] == '}')
+        curly_count++;
 
-  VPS1 = R"(octave:\#> )";
-  VPS2 = "> ";
-  std::string VPS4 = "+ ";
+      while (curly_count + paren_count > 0 && --pos >= 0)
+        {
+          if (line[pos] == ')')
+            paren_count++;
+          else if (line[pos] == '(')
+            paren_count--;
+          else if (line[pos] == '}')
+            curly_count++;
+          else if (line[pos] == '{')
+            curly_count--;
+        }
 
-  octave_link::set_default_prompts (VPS1, VPS2, VPS4);
+      while (--pos >= 0 && line[pos] == ' ')
+        ;
+    }
+
+  while (pos >= 0 && (isalnum (line[pos]) || line[pos] == '_'))
+    pos--;
+
+  if (++pos >= 0)
+    return (line.substr (pos, last + 1 - pos));
+  else
+    return std::string ();
 }
 
-static std::string
-gnu_readline (const std::string& s, bool& eof)
+static inline bool
+is_variable (octave::symbol_table& symtab, const std::string& name)
 {
-  octave_quit ();
+  bool retval = false;
 
-  eof = false;
+  if (! name.empty ())
+    {
+      octave::symbol_scope scope = symtab.current_scope ();
 
-  std::string retval = octave::command_editor::readline (s, eof);
+      octave_value val = scope ? scope.varval (name) : octave_value ();
 
-  if (! eof && retval.empty ())
-    retval = "\n";
+      retval = val.is_defined ();
+    }
 
   return retval;
 }
 
-static inline std::string
-interactive_input (const std::string& s, bool& eof)
+static string_vector
+generate_struct_completions (const std::string& text,
+                             std::string& prefix, std::string& hint)
 {
-  Vlast_prompt_time.stamp ();
+  string_vector names;
+
+  size_t pos = text.rfind ('.');
+  bool array = false;
 
-  if (Vdrawnow_requested && octave::application::interactive ())
+  if (pos != std::string::npos)
     {
-      bool eval_error = false;
+      if (pos == text.length ())
+        hint = "";
+      else
+        hint = text.substr (pos+1);
 
-      try
+      prefix = text.substr (0, pos);
+
+      if (prefix == "")
         {
-          Fdrawnow ();
-        }
-      catch (const octave::execution_exception& e)
-        {
-          eval_error = true;
-
-          std::string stack_trace = e.info ();
-
-          if (! stack_trace.empty ())
-            std::cerr << stack_trace;
-
-          if (octave::application::interactive ())
-            octave::interpreter::recover_from_exception ();
+          array = true;
+          prefix = find_indexed_expression (text);
         }
 
-      octave::flush_stdout ();
+      std::string base_name = prefix;
+
+      pos = base_name.find_first_of ("{(. ");
+
+      if (pos != std::string::npos)
+        base_name = base_name.substr (0, pos);
 
-      // We set Vdrawnow_requested to false even if there is an error in
-      // drawnow so that the error doesn't reappear at every prompt.
+      octave::symbol_table& symtab
+        = octave::__get_symbol_table__ ("generate_struct_completions");
+
+      if (is_variable (symtab, base_name))
+        {
+          int parse_status;
+
+          octave::unwind_protect frame;
+
+          frame.protect_var (discard_error_messages);
+          frame.protect_var (discard_warning_messages);
 
-      Vdrawnow_requested = false;
+          discard_error_messages = true;
+          discard_warning_messages = true;
+
+          try
+            {
+              octave_value tmp = octave::eval_string (prefix, true, parse_status);
+
+              frame.run ();
 
-      if (eval_error)
-        return "\n";
+              if (tmp.is_defined ()
+                  && (tmp.isstruct () || tmp.isjava () || tmp.is_classdef_object ()))
+                names = tmp.map_keys ();
+            }
+          catch (const octave::execution_exception&)
+            {
+              octave::interpreter::recover_from_exception ();
+            }
+        }
     }
 
-  return gnu_readline (s, eof);
+  // Undo look-back that found the array expression,
+  // but insert an extra "." to distinguish from the non-struct case.
+  if (array)
+    prefix = ".";
+
+  return names;
 }
 
-namespace octave
+// FIXME: this will have to be much smarter to work "correctly".
+static bool
+looks_like_struct (const std::string& text, char prev_char)
 {
-  std::string base_reader::octave_gets (bool& eof)
-  {
-    octave_quit ();
-
-    eof = false;
-
-    std::string retval;
-
-    // Process pre input event hook function prior to flushing output and
-    // printing the prompt.
-
-    if (application::interactive ())
-      {
-        if (! Vdebugging)
-          octave_link::exit_debugger_event ();
-
-        octave_link::pre_input_event ();
-
-        octave_link::set_workspace ();
-      }
-
-    bool history_skip_auto_repeated_debugging_command = false;
-
-    std::string ps = (m_pflag > 0) ? VPS1 : VPS2;
-
-    std::string prompt = command_editor::decode_prompt_string (ps);
-
-    pipe_handler_error_count = 0;
-
-    flush_stdout ();
-
-    pager_stream::reset ();
-    diary_stream::reset ();
-
-    octave_diary << prompt;
-
-    retval = interactive_input (prompt, eof);
+  bool retval = (! text.empty ()
+                 && (text != "." || prev_char == ')' || prev_char == '}')
+                 && text.find_first_of (octave::sys::file_ops::dir_sep_chars ()) == std::string::npos
+                 && text.find ("..") == std::string::npos
+                 && text.rfind ('.') != std::string::npos);
 
-    // There is no need to update the load_path cache if there is no
-    // user input.
-    if (retval != "\n"
-        && retval.find_first_not_of (" \t\n\r") != std::string::npos)
-      {
-        load_path& lp = __get_load_path__ ("base_reader::octave_gets");
-
-        lp.update ();
-
-        if (Vdebugging)
-          last_debugging_command = retval;
-        else
-          last_debugging_command = "\n";
-      }
-    else if (Vdebugging)
-      {
-        retval = last_debugging_command;
-        history_skip_auto_repeated_debugging_command = true;
-      }
-
-    if (retval != "\n")
-      {
-        if (! history_skip_auto_repeated_debugging_command)
-          {
-            if (command_history::add (retval))
-              octave_link::append_history (retval);
-          }
-
-        octave_diary << retval;
-
-        if (retval.back () != '\n')
-          octave_diary << "\n";
-      }
-    else
-      octave_diary << "\n";
-
-    // Process post input event hook function after the internal history
-    // list has been updated.
-
-    if (application::interactive ())
-      octave_link::post_input_event ();
-
-    return retval;
-  }
-
-  bool base_reader::reading_fcn_file (void) const
-  {
-    return m_lexer ? m_lexer->m_reading_fcn_file : false;
-  }
+#if 0
+  symbol_record *sr = curr_sym_tab->lookup (text);
 
-  bool base_reader::reading_classdef_file (void) const
-  {
-    return m_lexer ? m_lexer->m_reading_classdef_file : false;
-  }
-
-  bool base_reader::reading_script_file (void) const
-  {
-    return m_lexer ? m_lexer->m_reading_script_file : false;
-  }
-
-  class
-  terminal_reader : public base_reader
-  {
-  public:
-
-    terminal_reader (base_lexer *lxr = nullptr)
-      : base_reader (lxr)
-    { }
-
-    std::string get_input (bool& eof);
-
-    std::string input_source (void) const { return s_in_src; }
+  if (sr && ! sr->is_function ())
+    {
+      int parse_status;
 
-    bool input_from_terminal (void) const { return true; }
-
-  private:
-
-    static const std::string s_in_src;
-  };
-
-  class
-  file_reader : public base_reader
-  {
-  public:
+      octave::unwind_protect frame;
 
-    file_reader (FILE *f_arg, base_lexer *lxr = nullptr)
-      : base_reader (lxr), m_file (f_arg) { }
-
-    std::string get_input (bool& eof);
+      frame.protect_var (discard_error_messages);
 
-    std::string input_source (void) const { return s_in_src; }
-
-    bool input_from_file (void) const { return true; }
-
-  private:
-
-    FILE *m_file;
+      discard_error_messages = true;
 
-    static const std::string s_in_src;
-  };
-
-  class
-  eval_string_reader : public base_reader
-  {
-  public:
+      octave_value tmp = eval_string (text, true, parse_status);
 
-    eval_string_reader (const std::string& str, base_lexer *lxr = nullptr)
-      : base_reader (lxr), m_eval_string (str)
-    { }
-
-    std::string get_input (bool& eof);
-
-    std::string input_source (void) const { return s_in_src; }
-
-    bool input_from_eval_string (void) const { return true; }
-
-  private:
-
-    std::string m_eval_string;
+      frame.run ();
 
-    static const std::string s_in_src;
-  };
-
-  input_reader::input_reader (base_lexer *lxr)
-    : m_rep (new terminal_reader (lxr))
-  { }
-
-  input_reader::input_reader (FILE *file, base_lexer *lxr)
-    : m_rep (new file_reader (file, lxr))
-  { }
+      retval = (tmp.is_defined () && tmp.isstruct ());
+    }
+#endif
 
-  input_reader::input_reader (const std::string& str, base_lexer *lxr)
-    : m_rep (new eval_string_reader (str, lxr))
-  { }
-}
-
-// Fix things up so that input can come from the standard input.  This
-// may need to become much more complicated, which is why it's in a
-// separate function.
-
-FILE *
-get_input_from_stdin (void)
-{
-  octave::command_editor::set_input_stream (stdin);
-  return octave::command_editor::get_input_stream ();
+  return retval;
 }
 
 // FIXME: make this generate filenames when appropriate.
@@ -518,8 +409,13 @@
                   octave::command_editor::set_completion_append_character ('\0');
                 }
               else
-                octave::command_editor::set_completion_append_character
-                  (Vcompletion_append_char);
+                {
+                  octave::input_system& input_sys
+                    = octave::__get_input_system__ ("generate_completion");
+
+                  octave::command_editor::set_completion_append_character
+                    (input_sys.completion_append_char ());
+                }
 
               break;
             }
@@ -529,239 +425,664 @@
   return retval;
 }
 
-static std::string
-quoting_filename (const std::string& text, int, char quote)
+namespace octave
 {
-  if (quote)
-    return text;
-  else
-    return ("'" + text);
-}
-
-// Try to parse a partial command line in reverse, excluding trailing TEXT.
-// If it appears a variable has been indexed by () or {},
-// return that expression,
-// to allow autocomplete of field names of arrays of structures.
-std::string
-find_indexed_expression (const std::string& text)
-{
-  std::string line = octave::command_editor::get_line_buffer ();
+  // Use literal "octave" in default setting for PS1 instead of
+  // "\\s" to avoid setting the prompt to "octave.exe" or
+  // "octave-gui", etc.
 
-  int pos = line.length () - text.length ();
-  int curly_count = 0;
-  int paren_count = 0;
+  input_system::input_system (interpreter& interp)
+    : m_interpreter (interp), m_PS1 (R"(octave:\#> )"), m_PS2 ("> "),
+      m_completion_append_char (' '), m_gud_mode (false),
+      m_mfile_encoding ("utf-8"), m_last_debugging_command ("\n"),
+      m_input_event_hook_functions ()
+  {
+#if defined (OCTAVE_USE_WINDOWS_API)
+    m_mfile_encoding = "system";
+#endif
+  }
 
-  int last = --pos;
-
-  while (pos >= 0 && (line[pos] == ')' || line[pos] == '}'))
+    void input_system::initialize (bool line_editing)
     {
-      if (line[pos] == ')')
-        paren_count++;
-      else if (line[pos] == '}')
-        curly_count++;
-
-      while (curly_count + paren_count > 0 && --pos >= 0)
+// Force default line editor if we don't want readline editing.
+      if (! line_editing)
         {
-          if (line[pos] == ')')
-            paren_count++;
-          else if (line[pos] == '(')
-            paren_count--;
-          else if (line[pos] == '}')
-            curly_count++;
-          else if (line[pos] == '{')
-            curly_count--;
+          command_editor::force_default_editor ();
+          return;
         }
 
-      while (--pos >= 0 && line[pos] == ' ')
-        ;
-    }
+      // If we are using readline, this allows conditional parsing of the
+      // .inputrc file.
+
+      octave::command_editor::set_name ("Octave");
+
+      // FIXME: this needs to include a comma too, but that
+      // causes trouble for the new struct element completion code.
+
+      static const char *s = "\t\n !\"\'*+-/:;<=>(){}[\\]^`~";
+
+      octave::command_editor::set_basic_word_break_characters (s);
+
+      octave::command_editor::set_completer_word_break_characters (s);
 
-  while (pos >= 0 && (isalnum (line[pos]) || line[pos] == '_'))
-    pos--;
+      octave::command_editor::set_basic_quote_characters (R"(")");
+
+      octave::command_editor::set_filename_quote_characters (" \t\n\\\"'@<>=;|&()#$`?*[!:{");
+
+      octave::command_editor::set_completer_quote_characters (R"('")");
+
+      octave::command_editor::set_completion_function (generate_completion);
+
+      octave::command_editor::set_quoting_function (quoting_filename);
+  }
+
+  octave_value
+  input_system::PS1 (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_PS1, args, nargout, "PS1");
+  }
 
-  if (++pos >= 0)
-    return (line.substr (pos, last + 1 - pos));
-  else
-    return std::string ();
-}
+  octave_value
+  input_system::PS2 (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_PS2, args, nargout, "PS2");
+  }
+
+  octave_value
+  input_system::completion_append_char (const octave_value_list& args,
+                                        int nargout)
+  {
+    return set_internal_variable (m_completion_append_char, args, nargout,
+                                  "completion_append_char");
+  }
 
-void
-initialize_command_input (void)
-{
-  // If we are using readline, this allows conditional parsing of the
-  // .inputrc file.
+  octave_value
+  input_system::gud_mode (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_gud_mode, args, nargout, "__gud_mode__");
+  }
 
-  octave::command_editor::set_name ("Octave");
+  octave_value
+  input_system::mfile_encoding (const octave_value_list& args, int nargout)
+  {
+    // Save current value in case there is an error in the additional
+    // validation below.
+
+    std::string saved_encoding = m_mfile_encoding;
+
+    // We must pass the actual variable to change here for temporary
+    // "local" settings to work properly.
+
+    octave_value retval
+      = set_internal_variable (m_mfile_encoding, args, nargout,
+                               "__mfile_encoding__");
+
+    // Additional validation if the encoding has changed.
 
-  // FIXME: this needs to include a comma too, but that
-  // causes trouble for the new struct element completion code.
+    if (m_mfile_encoding != saved_encoding)
+      {
+        if (m_mfile_encoding.empty ())
+          {
+#if defined (OCTAVE_USE_WINDOWS_API)
+            m_mfile_encoding = "system";
+#else
+            m_mfile_encoding = "utf-8";
+#endif
+          }
+        else
+          {
+            std::transform (m_mfile_encoding.begin (),
+                            m_mfile_encoding.end (),
+                            m_mfile_encoding.begin (), ::tolower);
 
-  static const char *s = "\t\n !\"\'*+-/:;<=>(){}[\\]^`~";
+            std::string codepage = (m_mfile_encoding.compare ("system") == 0)
+              ? octave_locale_charset_wrapper () : m_mfile_encoding;
 
-  octave::command_editor::set_basic_word_break_characters (s);
+            // Check for valid codepage.
+            void *codec
+              = octave_iconv_open_wrapper (codepage.c_str (), "utf-8");
+
+            if (errno == EINVAL)
+              {
+                m_mfile_encoding = saved_encoding;
 
-  octave::command_editor::set_completer_word_break_characters (s);
+                error ("__mfile_encoding__: conversion from codepage '%s' not supported",
+                       codepage.c_str ());
+              }
 
-  octave::command_editor::set_basic_quote_characters (R"(")");
+            octave_iconv_close_wrapper (codec);
+          }
+      }
+
+    return retval;
+  }
+
+  bool input_system::yes_or_no (const std::string& prompt)
+  {
+    std::string prompt_string = prompt + "(yes or no) ";
 
-  octave::command_editor::set_filename_quote_characters (" \t\n\\\"'@<>=;|&()#$`?*[!:{");
-  octave::command_editor::set_completer_quote_characters (R"('")");
+    while (1)
+      {
+        bool eof = false;
+
+        std::string input_buf = interactive_input (prompt_string, eof);
 
-  octave::command_editor::set_completion_function (generate_completion);
+        if (input_buf == "yes")
+          return true;
+        else if (input_buf == "no")
+          return false;
+        else
+          message (nullptr, "Please answer yes or no.");
+      }
+  }
+
+  std::string input_system::interactive_input (const std::string& s, bool& eof)
+  {
+    Vlast_prompt_time.stamp ();
+
+    if (Vdrawnow_requested && octave::application::interactive ())
+      {
+        bool eval_error = false;
 
-  octave::command_editor::set_quoting_function (quoting_filename);
-}
+        try
+          {
+            Fdrawnow ();
+          }
+        catch (const octave::execution_exception& e)
+          {
+            eval_error = true;
+
+            std::string stack_trace = e.info ();
 
-static void
-execute_in_debugger_handler (const std::pair<std::string, int>& arg)
-{
-  octave_link::execute_in_debugger_event (arg.first, arg.second);
-}
+            if (! stack_trace.empty ())
+              std::cerr << stack_trace;
+
+            if (octave::application::interactive ())
+              octave::interpreter::recover_from_exception ();
+          }
+
+        octave::flush_stdout ();
+
+        // We set Vdrawnow_requested to false even if there is an error in
+        // drawnow so that the error doesn't reappear at every prompt.
+
+        Vdrawnow_requested = false;
 
-static void
-get_debug_input (octave::interpreter& interp, const std::string& prompt)
-{
-  octave::unwind_protect frame;
+        if (eval_error)
+          return "\n";
+      }
+
+    return gnu_readline (s, eof);
+  }
+
+  // If the user simply hits return, this will produce an empty matrix.
+
+  octave_value_list
+  input_system::get_user_input (const octave_value_list& args, int nargout)
+  {
+    octave_value_list retval;
+
+    int read_as_string = 0;
+
+    if (args.length () == 2)
+      read_as_string++;
 
-  octave::tree_evaluator& tw = interp.get_evaluator ();
+    std::string prompt = args(0).xstring_value ("input: unrecognized argument");
+
+    octave::flush_stdout ();
+
+    octave::pager_stream::reset ();
+    octave::diary_stream::reset ();
+
+    octave_diary << prompt;
 
-  bool silent = tw.quiet_breakpoint_flag (false);
+    bool eof = false;
+
+    std::string input_buf = interactive_input (prompt.c_str (), eof);
 
-  octave::call_stack& cs = interp.get_call_stack ();
+    if (input_buf.empty ())
+      error ("input: reading user-input failed!");
+
+    size_t len = input_buf.length ();
+
+    octave_diary << input_buf;
 
-  octave_user_code *caller = cs.caller_user_code ();
-  std::string nm;
-  int curr_debug_line;
+    if (input_buf[len - 1] != '\n')
+      octave_diary << "\n";
+
+    if (len < 1)
+      return read_as_string ? octave_value ("") : octave_value (Matrix ());
+
+    if (read_as_string)
+      {
+        // FIXME: fix gnu_readline and octave_gets instead!
+        if (input_buf.length () == 1 && input_buf[0] == '\n')
+          retval(0) = "";
+        else
+          retval(0) = input_buf;
+      }
+    else
+      {
+        int parse_status = 0;
+
+        retval = octave::eval_string (input_buf, true, parse_status, nargout);
 
-  if (caller)
-    {
-      nm = caller->fcn_file_name ();
+        if (! Vdebugging && retval.empty ())
+          retval(0) = Matrix ();
+      }
+
+    return retval;
+  }
 
-      if (nm.empty ())
-        nm = caller->name ();
+  octave_value input_system::keyboard (const octave_value_list& args)
+  {
+    octave_value retval;
+
+    int nargin = args.length ();
+
+    assert (nargin == 0 || nargin == 1);
+
+    octave::unwind_protect frame;
+
+    frame.add_fcn (octave::command_history::ignore_entries,
+                   octave::command_history::ignoring_entries ());
 
-      curr_debug_line = cs.caller_user_code_line ();
-    }
-  else
-    curr_debug_line = cs.current_line ();
+    octave::command_history::ignore_entries (false);
+
+    frame.protect_var (Vdebugging);
+
+    octave::call_stack& cs = m_interpreter.get_call_stack ();
+
+    frame.add_method (cs, &octave::call_stack::restore_frame,
+                      cs.current_frame ());
+
+    // FIXME: probably we just want to print one line, not the
+    // entire statement, which might span many lines...
+    //
+    // tree_print_code tpc (octave_stdout);
+    // stmt.accept (tpc);
+
+    Vdebugging = true;
+    Vtrack_line_num = false;
 
-  std::ostringstream buf;
+    std::string prompt = "debug> ";
+    if (nargin > 0)
+      prompt = args(0).string_value ();
+
+    get_debug_input (prompt);
+
+    return retval;
+  }
+
+  bool input_system::have_input_event_hooks (void) const
+  {
+    return ! m_input_event_hook_functions.empty ();
+  }
+
+  void input_system::add_input_event_hook (const hook_function& hook_fcn)
+  {
+    m_input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
+  }
 
-  if (! nm.empty ())
-    {
-      if (Vgud_mode)
-        {
-          static char ctrl_z = 'Z' & 0x1f;
+  bool input_system::remove_input_event_hook (const std::string& hook_fcn_id)
+  {
+    hook_function_list::iterator p
+      = m_input_event_hook_functions.find (hook_fcn_id);
+
+    if (p == m_input_event_hook_functions.end ())
+      return false;
+
+    m_input_event_hook_functions.erase (p);
+    return true;
+  }
+
+  void input_system::clear_input_event_hooks (void)
+  {
+    m_input_event_hook_functions.clear ();
+  }
 
-          buf << ctrl_z << ctrl_z << nm << ':' << curr_debug_line;
-        }
-      else
-        {
-          // FIXME: we should come up with a clean way to detect
-          // that we are stopped on the no-op command that marks the
-          // end of a function or script.
+  void input_system::run_input_event_hooks (void)
+  {
+    m_input_event_hook_functions.run ();
+  }
+
+  std::string
+  input_system::gnu_readline (const std::string& s, bool& eof) const
+  {
+    octave_quit ();
+
+    eof = false;
 
-          if (! silent)
-            {
-              buf << "stopped in " << nm;
+    std::string retval = octave::command_editor::readline (s, eof);
+
+    if (! eof && retval.empty ())
+      retval = "\n";
+
+    return retval;
+  }
+
+  static void
+  execute_in_debugger_handler (const std::pair<std::string, int>& arg)
+  {
+    octave_link::execute_in_debugger_event (arg.first, arg.second);
+  }
 
-              if (curr_debug_line > 0)
-                buf << " at line " << curr_debug_line;
-            }
+  void input_system::get_debug_input (const std::string& prompt)
+  {
+    octave::unwind_protect frame;
+
+    octave::tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+    bool silent = tw.quiet_breakpoint_flag (false);
+
+    octave::call_stack& cs = m_interpreter.get_call_stack ();
+
+    octave_user_code *caller = cs.caller_user_code ();
+    std::string nm;
+    int curr_debug_line;
 
-          octave_link::enter_debugger_event (nm, curr_debug_line);
+    if (caller)
+      {
+        nm = caller->fcn_file_name ();
+
+        if (nm.empty ())
+          nm = caller->name ();
 
-          octave_link::set_workspace ();
+        curr_debug_line = cs.caller_user_code_line ();
+      }
+    else
+      curr_debug_line = cs.current_line ();
 
-          frame.add_fcn (execute_in_debugger_handler,
-                         std::pair<std::string, int> (nm, curr_debug_line));
+    std::ostringstream buf;
+
+    if (! nm.empty ())
+      {
+        if (m_gud_mode)
+          {
+            static char ctrl_z = 'Z' & 0x1f;
 
-          if (! silent)
-            {
-              std::string line_buf;
+            buf << ctrl_z << ctrl_z << nm << ':' << curr_debug_line;
+          }
+        else
+          {
+            // FIXME: we should come up with a clean way to detect
+            // that we are stopped on the no-op command that marks the
+            // end of a function or script.
+
+            if (! silent)
+              {
+                buf << "stopped in " << nm;
+
+                if (curr_debug_line > 0)
+                  buf << " at line " << curr_debug_line;
+              }
+
+            octave_link::enter_debugger_event (nm, curr_debug_line);
+
+            octave_link::set_workspace ();
 
-              if (caller)
-                line_buf = caller->get_code_line (curr_debug_line);
+            frame.add_fcn (execute_in_debugger_handler,
+                           std::pair<std::string, int> (nm, curr_debug_line));
+
+            if (! silent)
+              {
+                std::string line_buf;
+
+                if (caller)
+                  line_buf = caller->get_code_line (curr_debug_line);
 
-              if (! line_buf.empty ())
-                buf << "\n" << curr_debug_line << ": " << line_buf;
-            }
-        }
-    }
+                if (! line_buf.empty ())
+                  buf << "\n" << curr_debug_line << ": " << line_buf;
+              }
+          }
+      }
+
+    if (silent)
+      octave::command_editor::erase_empty_line (true);
+
+    std::string msg = buf.str ();
+
+    if (! msg.empty ())
+      std::cerr << msg << std::endl;
 
-  if (silent)
-    octave::command_editor::erase_empty_line (true);
+    frame.add_method (*this, &octave::input_system::set_PS1, m_PS1);
+    m_PS1 = prompt;
+
+    // FIXME: should debugging be possible in an embedded interpreter?
+
+    octave::application *app = octave::application::app ();
 
-  std::string msg = buf.str ();
+    if (! app->interactive ())
+      {
+
+        frame.add_method (app, &octave::application::interactive,
+                          app->interactive ());
+
+        frame.add_method (app, &octave::application::forced_interactive,
+                          app->forced_interactive ());
 
-  if (! msg.empty ())
-    std::cerr << msg << std::endl;
+        app->interactive (true);
+
+        app->forced_interactive (true);
+      }
+
+    octave::parser curr_parser;
 
-  frame.protect_var (VPS1);
-  VPS1 = prompt;
+    while (Vdebugging)
+      {
+        try
+          {
+            Vtrack_line_num = false;
+
+            reset_error_handler ();
+
+            curr_parser.reset ();
+
+            int retval = curr_parser.run ();
 
-  // FIXME: should debugging be possible in an embedded interpreter?
+            if (octave::command_editor::interrupt (false))
+              break;
+            else
+              {
+                if (retval == 0 && curr_parser.m_stmt_list)
+                  {
+                    curr_parser.m_stmt_list->accept (tw);
 
-  octave::application *app = octave::application::app ();
+                    if (octave_completion_matches_called)
+                      octave_completion_matches_called = false;
+                  }
+
+                octave_quit ();
+              }
+          }
+        catch (const octave::execution_exception& e)
+          {
+            std::string stack_trace = e.info ();
+
+            if (! stack_trace.empty ())
+              std::cerr << stack_trace;
 
-  if (! app->interactive ())
-    {
+            // Ignore errors when in debugging mode;
+            octave::interpreter::recover_from_exception ();
+          }
+      }
+  }
+
+  std::string base_reader::octave_gets (bool& eof)
+  {
+    octave_quit ();
 
-      frame.add_method (app, &octave::application::interactive,
-                        app->interactive ());
+    eof = false;
+
+    std::string retval;
 
-      frame.add_method (app, &octave::application::forced_interactive,
-                        app->forced_interactive ());
+    // Process pre input event hook function prior to flushing output and
+    // printing the prompt.
+
+    if (application::interactive ())
+      {
+        if (! Vdebugging)
+          octave_link::exit_debugger_event ();
 
-      app->interactive (true);
+        octave_link::pre_input_event ();
+
+        octave_link::set_workspace ();
+      }
+
+    bool history_skip_auto_repeated_debugging_command = false;
+
+    input_system& input_sys = __get_input_system__ ("base_reader::octave_gets");
+
+    std::string ps = (m_pflag > 0) ? input_sys.PS1 () : input_sys.PS2 ();
+
+    std::string prompt = command_editor::decode_prompt_string (ps);
+
+    pipe_handler_error_count = 0;
 
-      app->forced_interactive (true);
-    }
+    flush_stdout ();
+
+    pager_stream::reset ();
+    diary_stream::reset ();
+
+    octave_diary << prompt;
+
+    retval = input_sys.interactive_input (prompt, eof);
 
-  octave::parser curr_parser;
+    // There is no need to update the load_path cache if there is no
+    // user input.
+    if (retval != "\n"
+        && retval.find_first_not_of (" \t\n\r") != std::string::npos)
+      {
+        load_path& lp = __get_load_path__ ("base_reader::octave_gets");
+
+        lp.update ();
 
-  while (Vdebugging)
-    {
-      try
-        {
-          Vtrack_line_num = false;
+        if (Vdebugging)
+          input_sys.last_debugging_command (retval);
+        else
+          input_sys.last_debugging_command ("\n");
+      }
+    else if (Vdebugging)
+      {
+        retval = input_sys.last_debugging_command ();
+        history_skip_auto_repeated_debugging_command = true;
+      }
+
+    if (retval != "\n")
+      {
+        if (! history_skip_auto_repeated_debugging_command)
+          {
+            if (command_history::add (retval))
+              octave_link::append_history (retval);
+          }
+
+        octave_diary << retval;
 
-          reset_error_handler ();
+        if (retval.back () != '\n')
+          octave_diary << "\n";
+      }
+    else
+      octave_diary << "\n";
+
+    // Process post input event hook function after the internal history
+    // list has been updated.
+
+    if (application::interactive ())
+      octave_link::post_input_event ();
 
-          curr_parser.reset ();
+    return retval;
+  }
 
-          int retval = curr_parser.run ();
+  bool base_reader::reading_fcn_file (void) const
+  {
+    return m_lexer ? m_lexer->m_reading_fcn_file : false;
+  }
+
+  bool base_reader::reading_classdef_file (void) const
+  {
+    return m_lexer ? m_lexer->m_reading_classdef_file : false;
+  }
 
-          if (octave::command_editor::interrupt (false))
-            break;
-          else
-            {
-              if (retval == 0 && curr_parser.m_stmt_list)
-                {
-                  curr_parser.m_stmt_list->accept (tw);
+  bool base_reader::reading_script_file (void) const
+  {
+    return m_lexer ? m_lexer->m_reading_script_file : false;
+  }
+
+  class
+  terminal_reader : public base_reader
+  {
+  public:
+
+    terminal_reader (base_lexer *lxr = nullptr)
+      : base_reader (lxr)
+    { }
+
+    std::string get_input (bool& eof);
+
+    std::string input_source (void) const { return s_in_src; }
 
-                  if (octave_completion_matches_called)
-                    octave_completion_matches_called = false;
-                }
+    bool input_from_terminal (void) const { return true; }
+
+  private:
+
+    static const std::string s_in_src;
+  };
+
+  class
+  file_reader : public base_reader
+  {
+  public:
+
+    file_reader (FILE *f_arg, base_lexer *lxr = nullptr)
+      : base_reader (lxr), m_file (f_arg) { }
+
+    std::string get_input (bool& eof);
+
+    std::string input_source (void) const { return s_in_src; }
+
+    bool input_from_file (void) const { return true; }
 
-              octave_quit ();
-            }
-        }
-      catch (const octave::execution_exception& e)
-        {
-          std::string stack_trace = e.info ();
+  private:
+
+    FILE *m_file;
+
+    static const std::string s_in_src;
+  };
+
+  class
+  eval_string_reader : public base_reader
+  {
+  public:
+
+    eval_string_reader (const std::string& str, base_lexer *lxr = nullptr)
+      : base_reader (lxr), m_eval_string (str)
+    { }
+
+    std::string get_input (bool& eof);
+
+    std::string input_source (void) const { return s_in_src; }
 
-          if (! stack_trace.empty ())
-            std::cerr << stack_trace;
+    bool input_from_eval_string (void) const { return true; }
+
+  private:
+
+    std::string m_eval_string;
+
+    static const std::string s_in_src;
+  };
 
-          // Ignore errors when in debugging mode;
-          octave::interpreter::recover_from_exception ();
-        }
-    }
-}
+  input_reader::input_reader (base_lexer *lxr)
+    : m_rep (new terminal_reader (lxr))
+  { }
 
-namespace octave
-{
+  input_reader::input_reader (FILE *file, base_lexer *lxr)
+    : m_rep (new file_reader (file, lxr))
+  { }
+
+  input_reader::input_reader (const std::string& str, base_lexer *lxr)
+    : m_rep (new eval_string_reader (str, lxr))
+  { }
+
   const std::string base_reader::s_in_src ("invalid");
 
   const std::string terminal_reader::s_in_src ("terminal");
@@ -786,9 +1107,15 @@
     eof = false;
 
     std::string src_str = octave_fgets (m_file, eof);
-    std::string encoding = Vmfile_encoding.compare ("system") == 0
-                           ? octave_locale_charset_wrapper ()
-                           : Vmfile_encoding;
+
+    octave::input_system& input_sys
+      = octave::__get_input_system__ ("get_input");
+
+    std::string mfile_encoding = input_sys.mfile_encoding ();
+
+    std::string encoding
+      = (mfile_encoding.compare ("system") == 0
+         ? octave_locale_charset_wrapper () : mfile_encoding);
 
     if (encoding.compare ("utf-8") != 0)
     {
@@ -839,67 +1166,8 @@
   }
 }
 
-// If the user simply hits return, this will produce an empty matrix.
-
-static octave_value_list
-get_user_input (const octave_value_list& args, int nargout)
-{
-  octave_value_list retval;
-
-  int read_as_string = 0;
-
-  if (args.length () == 2)
-    read_as_string++;
-
-  std::string prompt = args(0).xstring_value ("input: unrecognized argument");
-
-  octave::flush_stdout ();
-
-  octave::pager_stream::reset ();
-  octave::diary_stream::reset ();
-
-  octave_diary << prompt;
-
-  bool eof = false;
-
-  std::string input_buf = interactive_input (prompt.c_str (), eof);
-
-  if (input_buf.empty ())
-    error ("input: reading user-input failed!");
-
-  size_t len = input_buf.length ();
-
-  octave_diary << input_buf;
-
-  if (input_buf[len - 1] != '\n')
-    octave_diary << "\n";
-
-  if (len < 1)
-    return read_as_string ? octave_value ("") : octave_value (Matrix ());
-
-  if (read_as_string)
-    {
-      // FIXME: fix gnu_readline and octave_gets instead!
-      if (input_buf.length () == 1 && input_buf[0] == '\n')
-        retval(0) = "";
-      else
-        retval(0) = input_buf;
-    }
-  else
-    {
-      int parse_status = 0;
-
-      retval = octave::eval_string (input_buf, true, parse_status, nargout);
-
-      if (! Vdebugging && retval.empty ())
-        retval(0) = Matrix ();
-    }
-
-  return retval;
-}
-
-DEFUN (input, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (input, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{ans} =} input (@var{prompt})
 @deftypefnx {} {@var{ans} =} input (@var{prompt}, "s")
 Print @var{prompt} and wait for user input.
@@ -942,31 +1210,13 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
-  return get_user_input (args, std::max (nargout, 1));
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.get_user_input (args, std::max (nargout, 1));
 }
 
-bool
-octave_yes_or_no (const std::string& prompt)
-{
-  std::string prompt_string = prompt + "(yes or no) ";
-
-  while (1)
-    {
-      bool eof = false;
-
-      std::string input_buf = interactive_input (prompt_string, eof);
-
-      if (input_buf == "yes")
-        return true;
-      else if (input_buf == "no")
-        return false;
-      else
-        message (nullptr, "Please answer yes or no.");
-    }
-}
-
-DEFUN (yes_or_no, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (yes_or_no, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {@var{ans} =} yes_or_no ("@var{prompt}")
 Ask the user a yes-or-no question.
 
@@ -984,61 +1234,14 @@
   if (nargin > 1)
     print_usage ();
 
+  octave::input_system& input_sys = interp.get_input_system ();
+
   std::string prompt;
 
   if (nargin == 1)
     prompt = args(0).xstring_value ("yes_or_no: PROMPT must be a string");
 
-  return ovl (octave_yes_or_no (prompt));
-}
-
-octave_value
-do_keyboard (octave::interpreter& interp, const octave_value_list& args)
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  assert (nargin == 0 || nargin == 1);
-
-  octave::unwind_protect frame;
-
-  frame.add_fcn (octave::command_history::ignore_entries,
-                 octave::command_history::ignoring_entries ());
-
-  octave::command_history::ignore_entries (false);
-
-  frame.protect_var (Vdebugging);
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  frame.add_method (cs, &octave::call_stack::restore_frame,
-                    cs.current_frame ());
-
-  // FIXME: probably we just want to print one line, not the
-  // entire statement, which might span many lines...
-  //
-  // tree_print_code tpc (octave_stdout);
-  // stmt.accept (tpc);
-
-  Vdebugging = true;
-  Vtrack_line_num = false;
-
-  std::string prompt = "debug> ";
-  if (nargin > 0)
-    prompt = args(0).string_value ();
-
-  get_debug_input (interp, prompt);
-
-  return retval;
-}
-
-octave_value
-do_keyboard (const octave_value_list& args)
-{
-  octave::interpreter& interp = octave::__get_interpreter__ ("do_keyboard");
-
-  return do_keyboard (interp, args);
+  return ovl (input_sys.yes_or_no (prompt));
 }
 
 DEFMETHOD (keyboard, interp, args, ,
@@ -1078,7 +1281,9 @@
   tw.quiet_breakpoint_flag (false);
   tw.current_frame (cs.current_frame ());
 
-  do_keyboard (interp, args);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  input_sys.keyboard (args);
 
   return ovl ();
 }
@@ -1218,16 +1423,19 @@
 static int
 internal_input_event_hook_fcn (void)
 {
-  input_event_hook_functions.run ();
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("internal_input_event_hook_fcn");
 
-  if (input_event_hook_functions.empty ())
+  input_sys.run_input_event_hooks ();
+
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::remove_event_hook (internal_input_event_hook_fcn);
 
   return 0;
 }
 
-DEFUN (add_input_event_hook, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (add_input_event_hook, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{id} =} add_input_event_hook (@var{fcn})
 @deftypefnx {} {@var{id} =} add_input_event_hook (@var{fcn}, @var{data})
 Add the named function or function handle @var{fcn} to the list of functions
@@ -1256,18 +1464,20 @@
   if (nargin == 2)
     user_data = args(1);
 
+  octave::input_system& input_sys = interp.get_input_system ();
+
   hook_function hook_fcn (args(0), user_data);
 
-  if (input_event_hook_functions.empty ())
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::add_event_hook (internal_input_event_hook_fcn);
 
-  input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
+  input_sys.add_input_event_hook (hook_fcn);
 
   return ovl (hook_fcn.id ());
 }
 
-DEFUN (remove_input_event_hook, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (remove_input_event_hook, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} remove_input_event_hook (@var{name})
 @deftypefnx {} {} remove_input_event_hook (@var{fcn_id})
 Remove the named function or function handle with the given identifier
@@ -1285,23 +1495,20 @@
 
   bool warn = (nargin < 2);
 
-  hook_function_list::iterator p
-    = input_event_hook_functions.find (hook_fcn_id);
+  octave::input_system& input_sys = interp.get_input_system ();
 
-  if (p != input_event_hook_functions.end ())
-    input_event_hook_functions.erase (p);
-  else if (warn)
+  if (! input_sys.remove_input_event_hook (hook_fcn_id) && warn)
     warning ("remove_input_event_hook: %s not found in list",
              hook_fcn_id.c_str ());
 
-  if (input_event_hook_functions.empty ())
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::remove_event_hook (internal_input_event_hook_fcn);
 
   return ovl ();
 }
 
-DEFUN (PS1, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PS1, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PS1 ()
 @deftypefnx {} {@var{old_val} =} PS1 (@var{new_val})
 @deftypefnx {} {} PS1 (@var{new_val}, "local")
@@ -1339,11 +1546,13 @@
 @seealso{PS2, PS4}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (PS1);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.PS1 (args, nargout);
 }
 
-DEFUN (PS2, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PS2, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PS2 ()
 @deftypefnx {} {@var{old_val} =} PS2 (@var{new_val})
 @deftypefnx {} {} PS2 (@var{new_val}, "local")
@@ -1361,11 +1570,13 @@
 @seealso{PS1, PS4}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (PS2);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.PS2 (args, nargout);
 }
 
-DEFUN (completion_append_char, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (completion_append_char, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} completion_append_char ()
 @deftypefnx {} {@var{old_val} =} completion_append_char (@var{new_val})
 @deftypefnx {} {} completion_append_char (@var{new_val}, "local")
@@ -1379,11 +1590,13 @@
 The original variable value is restored when exiting the function.
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (completion_append_char);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.completion_append_char (args, nargout);
 }
 
-DEFUN (__request_drawnow__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__request_drawnow__, , args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} __request_drawnow__ ()
 @deftypefnx {} {} __request_drawnow__ (@var{flag})
 Undocumented internal function.
@@ -1402,67 +1615,75 @@
   return ovl ();
 }
 
-DEFUN (__gud_mode__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__gud_mode__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {} __gud_mode__ ()
 Undocumented internal function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin > 1)
-    print_usage ();
-
-  octave_value_list retval;
+  octave::input_system& input_sys = interp.get_input_system ();
 
-  if (nargin == 0)
-    retval = ovl (Vgud_mode);
-  else
-    Vgud_mode = args(0).bool_value ();
-
-  return retval;
+  return input_sys.gud_mode (args, nargout);
 }
 
-DEFUN (__mfile_encoding__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__mfile_encoding__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {@var{current_encoding} =} __mfile_encoding__ (@var{new_encoding})
 Set and query the codepage that is used for reading .m files.
 @end deftypefn */)
 {
-  int nargin = args.length ();
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.mfile_encoding (args, nargout);
+}
+
+#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
 
-  if (nargin > 1)
-    print_usage ();
+void
+set_default_prompts (void)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("set_default_prompts");
+
+  input_sys.set_default_prompts ();
+}
+
+bool
+octave_yes_or_no (const std::string& prompt)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("set_default_prompts");
+
+  input_sys.yes_or_no (prompt);
+}
 
-  std::string old_mfile_encoding = Vmfile_encoding;
-  if (nargin > 0)
-    {
-      std::string str = args(0).xstring_value (
-        "__mfile_encoding__: NEW_ENCODING must be a string designating a valid codepage.");
-      if (str.empty ())
-#if defined (OCTAVE_USE_WINDOWS_API)
-        Vmfile_encoding = "system";
-#else
-        Vmfile_encoding = "utf-8";
+octave_value
+do_keyboard (const octave_value_list& args)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("do_keyboard");
+
+  return input_sys.keyboard (args);
+}
+
+void
+remove_input_event_hook_functions (void)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("remove_input_event_hook_functions");
+
+  input_sys.clear_input_event_hooks ();
+}
+
+// Fix things up so that input can come from the standard input.  This
+// may need to become much more complicated, which is why it's in a
+// separate function.
+
+FILE *
+get_input_from_stdin (void)
+{
+  octave::command_editor::set_input_stream (stdin);
+  return octave::command_editor::get_input_stream ();
+}
+
 #endif
-      else
-        {
-          std::transform (str.begin (), str.end (), str.begin (), ::tolower);
-
-          std::string codepage = (str.compare ("system") == 0)
-                                 ? octave_locale_charset_wrapper () : str;
-
-          // check if valid codepage
-          void *codec = octave_iconv_open_wrapper (codepage.c_str (), "utf-8");
-
-          if (errno == EINVAL)
-            error ("__mfile_encoding__: Conversion from codepage '%s' not supported", 
-                   codepage.c_str ());
-
-          octave_iconv_close_wrapper (codec);
-
-          Vmfile_encoding = str;
-        }
-    }
-    return ovl (old_mfile_encoding);
-}