Mercurial > hg > octave-nkf
view liboctave/cmd-edit.cc @ 4200:1f04df06e1a6
[project @ 2002-11-22 16:25:49 by jwe]
author | jwe |
---|---|
date | Fri, 22 Nov 2002 16:25:49 +0000 |
parents | 62afb31c1f85 |
children | c0a23a13eea2 |
line wrap: on
line source
/* Copyright (C) 1996, 1997 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 2, 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, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <cstdlib> #include <cstring> #include <string> #ifdef HAVE_UNISTD_H #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #include <unistd.h> #endif #include "cmd-edit.h" #include "cmd-hist.h" #include "lo-error.h" #include "lo-utils.h" #include "oct-env.h" #include "oct-time.h" command_editor *command_editor::instance = 0; #if defined (USE_READLINE) #include <cstdio> #include <cstdlib> #include "oct-rl-edit.h" class gnu_readline : public command_editor { public: typedef command_editor::startup_hook_fcn startup_hook_fcn; typedef command_editor::event_hook_fcn event_hook_hook_fcn; typedef command_editor::completion_fcn completion_fcn; gnu_readline (void); ~gnu_readline (void) { } void do_set_name (const std::string& n); std::string do_readline (const std::string& prompt, bool& eof); void do_set_input_stream (FILE *f); FILE *do_get_input_stream (void); void do_set_output_stream (FILE *f); FILE *do_get_output_stream (void); int do_terminal_rows (void); int do_terminal_cols (void); void do_clear_screen (void); void do_resize_terminal (void); std::string newline_chars (void); void do_restore_terminal_state (void); void do_blink_matching_paren (bool flag); void do_set_basic_word_break_characters (const std::string& s); void do_set_completer_word_break_characters (const std::string& s); void do_set_basic_quote_characters (const std::string& s); void do_set_completion_append_character (char c); void do_set_completion_function (completion_fcn f); completion_fcn do_get_completion_function (void) const; void do_insert_text (const std::string& text); void do_newline (void); void do_clear_undo_list (void); void do_set_startup_hook (startup_hook_fcn f); void do_restore_startup_hook (void); void do_set_event_hook (event_hook_fcn f); void do_restore_event_hook (void); void do_read_init_file (const std::string& file); bool do_filename_completion_desired (bool); static int operate_and_get_next (int, int); static int history_search_backward (int, int); static int history_search_forward (int, int); private: startup_hook_fcn previous_startup_hook; event_hook_fcn previous_event_hook; completion_fcn completion_function; static char *command_generator (const char *text, int state); static char **command_completer (const char *text, int start, int end); }; gnu_readline::gnu_readline () : command_editor (), previous_startup_hook (0), previous_event_hook (0), completion_function (0) { // XXX FIXME XXX -- need interface to rl_add_defun, rl_initialize, and // a function to set rl_terminal_name std::string term = octave_env::getenv ("TERM"); octave_rl_set_terminal_name (term.c_str ()); octave_rl_initialize (); do_blink_matching_paren (true); /* Bind operate-and-get-next. */ octave_rl_add_defun ("operate-and-get-next", gnu_readline::operate_and_get_next, octave_rl_ctrl ('O')); /* And the history search functions. */ octave_rl_add_defun ("history-search-backward", gnu_readline::history_search_backward, octave_rl_meta ('P')); octave_rl_add_defun ("history-search-forward", gnu_readline::history_search_forward, octave_rl_meta ('N')); } void gnu_readline::do_set_name (const std::string& nm) { ::octave_rl_set_name (nm.c_str ()); } std::string gnu_readline::do_readline (const std::string& prompt, bool& eof) { std::string retval; eof = false; char *line = ::octave_rl_readline (prompt.c_str ()); if (line) { retval = line; free (line); } else eof = true; return retval; } void gnu_readline::do_set_input_stream (FILE *f) { ::octave_rl_set_input_stream (f); } FILE * gnu_readline::do_get_input_stream (void) { return ::octave_rl_get_input_stream (); } void gnu_readline::do_set_output_stream (FILE *f) { ::octave_rl_set_output_stream (f); } FILE * gnu_readline::do_get_output_stream (void) { return ::octave_rl_get_output_stream (); } // GNU readline handles SIGWINCH, so these values have a good chance // of being correct even if the window changes size (they may be // wrong if, for example, the luser changes the window size while the // pager is running, and the signal is handled by the pager instead of // us. int gnu_readline::do_terminal_rows (void) { int sh = ::octave_rl_screen_height (); return sh > 0 ? sh : 24; } int gnu_readline::do_terminal_cols (void) { int sw = ::octave_rl_screen_width (); return sw > 0 ? sw : 80; } void gnu_readline::do_clear_screen (void) { ::octave_rl_clear_screen (); } void gnu_readline::do_resize_terminal (void) { ::octave_rl_resize_terminal (); } std::string gnu_readline::newline_chars (void) { return "\r\n"; } void gnu_readline::do_restore_terminal_state (void) { ::octave_rl_restore_terminal_state (); } void gnu_readline::do_blink_matching_paren (bool flag) { ::octave_rl_enable_paren_matching (flag ? 1 : 0); } void gnu_readline::do_set_basic_word_break_characters (const std::string& s) { ::octave_rl_set_basic_word_break_characters (s.c_str ()); } void gnu_readline::do_set_completer_word_break_characters (const std::string& s) { ::octave_rl_set_completer_word_break_characters (s.c_str ()); } void gnu_readline::do_set_basic_quote_characters (const std::string& s) { ::octave_rl_set_basic_quote_characters (s.c_str ()); } void gnu_readline::do_set_completion_append_character (char c) { ::octave_rl_set_completion_append_character (c); } void gnu_readline::do_set_completion_function (completion_fcn f) { completion_function = f; rl_attempted_completion_fcn_ptr fp = f ? gnu_readline::command_completer : 0; ::octave_rl_set_completion_function (fp); } gnu_readline::completion_fcn gnu_readline::do_get_completion_function (void) const { return completion_function; } void gnu_readline::do_insert_text (const std::string& text) { ::octave_rl_insert_text (text.c_str ()); } void gnu_readline::do_newline (void) { ::octave_rl_newline (); } void gnu_readline::do_clear_undo_list () { ::octave_rl_clear_undo_list (); } void gnu_readline::do_set_startup_hook (startup_hook_fcn f) { previous_startup_hook = ::octave_rl_get_startup_hook (); ::octave_rl_set_startup_hook (f); } void gnu_readline::do_restore_startup_hook (void) { ::octave_rl_set_startup_hook (previous_startup_hook); } void gnu_readline::do_set_event_hook (event_hook_fcn f) { previous_event_hook = octave_rl_get_event_hook (); ::octave_rl_set_event_hook (f); } void gnu_readline::do_restore_event_hook (void) { ::octave_rl_set_event_hook (previous_event_hook); } void gnu_readline::do_read_init_file (const std::string& file) { ::octave_rl_read_init_file (file.c_str ()); } bool gnu_readline::do_filename_completion_desired (bool arg) { return ::octave_rl_filename_completion_desired (arg); } int gnu_readline::operate_and_get_next (int /* count */, int /* c */) { // Accept the current line. command_editor::newline (); // Find the current line, and find the next line to use. int x_where = command_history::where (); int x_length = command_history::length (); if ((command_history::is_stifled () && (x_length >= command_history::max_input_history ())) || (x_where >= x_length - 1)) command_history::set_mark (x_where); else command_history::set_mark (x_where + 1); command_editor::set_startup_hook (command_history::goto_mark); return 0; } int gnu_readline::history_search_backward (int count, int c) { return octave_rl_history_search_backward (count, c); } int gnu_readline::history_search_forward (int count, int c) { return octave_rl_history_search_forward (count, c); } char * gnu_readline::command_generator (const char *text, int state) { char *retval = 0; completion_fcn f = command_editor::get_completion_function (); std::string tmp = f (text, state); size_t len = tmp.length (); if (len > 0) { retval = static_cast<char *> (malloc (len+1)); strcpy (retval, tmp.c_str ()); } return retval; } char ** gnu_readline::command_completer (const char *text, int, int) { char **matches = 0; matches = ::octave_rl_completion_matches (text, gnu_readline::command_generator); return matches; } #endif class default_command_editor : public command_editor { public: default_command_editor (void) : command_editor (), input_stream (stdin), output_stream (stdout) { } ~default_command_editor (void) { } std::string do_readline (const std::string& prompt, bool& eof); void do_set_input_stream (FILE *f); FILE *do_get_input_stream (void); void do_set_output_stream (FILE *f); FILE *do_get_output_stream (void); void do_insert_text (const std::string&); void do_newline (void); private: FILE *input_stream; FILE *output_stream; }; std::string default_command_editor::do_readline (const std::string& prompt, bool& eof) { eof = false; fprintf (output_stream, prompt.c_str ()); fflush (output_stream); return octave_fgetl (input_stream); } void default_command_editor::do_set_input_stream (FILE *f) { input_stream = f; } FILE * default_command_editor::do_get_input_stream (void) { return input_stream; } void default_command_editor::do_set_output_stream (FILE *f) { output_stream = f; } FILE * default_command_editor::do_get_output_stream (void) { return output_stream; } void default_command_editor::do_insert_text (const std::string&) { // XXX FIXME XXX } void default_command_editor::do_newline (void) { // XXX FIXME XXX } bool command_editor::instance_ok (void) { bool retval = true; if (! instance) make_command_editor (); if (! instance) { current_liboctave_error_handler ("unable to create command history object!"); retval = false; } return retval; } void command_editor::make_command_editor (void) { #if defined (USE_READLINE) instance = new gnu_readline (); #else instance = new default_command_editor (); #endif } void command_editor::set_name (const std::string& n) { if (instance_ok ()) instance->do_set_name (n); } std::string command_editor::readline (const std::string& prompt) { bool eof; return readline (prompt, eof); } std::string command_editor::readline (const std::string& prompt, bool& eof) { return (instance_ok ()) ? instance->do_readline (prompt, eof) : std::string (); } void command_editor::set_input_stream (FILE *f) { if (instance_ok ()) instance->do_set_input_stream (f); } FILE * command_editor::get_input_stream (void) { return (instance_ok ()) ? instance->do_get_input_stream () : 0; } void command_editor::set_output_stream (FILE *f) { if (instance_ok ()) instance->do_set_output_stream (f); } FILE * command_editor::get_output_stream (void) { return (instance_ok ()) ? instance->do_get_output_stream () : 0; } int command_editor::terminal_rows (void) { return (instance_ok ()) ? instance->do_terminal_rows () : -1; } int command_editor::terminal_cols (void) { return (instance_ok ()) ? instance->do_terminal_cols () : -1; } void command_editor::clear_screen (void) { if (instance_ok ()) instance->do_clear_screen (); } void command_editor::resize_terminal (void) { if (instance_ok ()) instance->do_resize_terminal (); } std::string command_editor::decode_prompt_string (const std::string& s) { return (instance_ok ()) ? instance->do_decode_prompt_string (s) : std::string (); } int command_editor::current_command_number (void) { return (instance_ok ()) ? instance->command_number : 0; } void command_editor::reset_current_command_number (int n) { if (instance_ok ()) instance->command_number = n; } void command_editor::increment_current_command_number (void) { if (instance_ok ()) instance->command_number++; } void command_editor::restore_terminal_state (void) { if (instance_ok ()) instance->do_restore_terminal_state (); } void command_editor::blink_matching_paren (bool flag) { if (instance_ok ()) instance->do_blink_matching_paren (flag); } void command_editor::set_basic_word_break_characters (const std::string& s) { if (instance_ok ()) instance->do_set_basic_word_break_characters (s); } void command_editor::set_completer_word_break_characters (const std::string& s) { if (instance_ok ()) instance->do_set_completer_word_break_characters (s); } void command_editor::set_basic_quote_characters (const std::string& s) { if (instance_ok ()) instance->do_set_basic_quote_characters (s); } void command_editor::set_completion_append_character (char c) { if (instance_ok ()) instance->do_set_completion_append_character (c); } void command_editor::set_completion_function (completion_fcn f) { if (instance_ok ()) instance->do_set_completion_function (f); } command_editor::completion_fcn command_editor::get_completion_function (void) { return (instance_ok ()) ? instance->do_get_completion_function () : 0; } void command_editor::insert_text (const std::string& text) { if (instance_ok ()) instance->do_insert_text (text); } void command_editor::newline (void) { if (instance_ok ()) instance->do_newline (); } void command_editor::clear_undo_list (void) { if (instance_ok ()) instance->do_clear_undo_list (); } void command_editor::set_startup_hook (startup_hook_fcn f) { if (instance_ok ()) instance->do_set_startup_hook (f); } void command_editor::restore_startup_hook (void) { if (instance_ok ()) instance->do_restore_startup_hook (); } void command_editor::set_event_hook (event_hook_fcn f) { if (instance_ok ()) instance->do_set_event_hook (f); } void command_editor::restore_event_hook (void) { if (instance_ok ()) instance->do_restore_event_hook (); } void command_editor::read_init_file (const std::string& file) { if (instance_ok ()) instance->do_read_init_file (file); } bool command_editor::filename_completion_desired (bool arg) { return (instance_ok ()) ? instance->do_filename_completion_desired (arg) : false; } // Return a string which will be printed as a prompt. The string may // contain special characters which are decoded as follows: // // \t the time // \d the date // \n CRLF // \s the name of the shell (program) // \w the current working directory // \W the last element of PWD // \u your username // \h the hostname // \# the command number of this command // \! the history number of this command // \$ a $ or a # if you are root // \<octal> character code in octal // \\ a backslash std::string command_editor::do_decode_prompt_string (const std::string& s) { std::string result; std::string temp; size_t i = 0; size_t slen = s.length (); int c; while (i < slen) { c = s[i]; i++; if (c == '\\') { c = s[i]; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // Maybe convert an octal number. { int n = read_octal (s.substr (i, 3)); temp = "\\"; if (n != -1) { i += 3; temp[0] = n; } c = 0; goto add_string; } case 't': case 'd': // Make the current time/date into a string. { octave_time now; temp = now.ctime (); if (c == 't') { temp = temp.substr (11); temp.resize (8); } else temp.resize (10); goto add_string; } case 'n': { temp = newline_chars (); goto add_string; } case 's': { temp = octave_env::get_program_name (); temp = octave_env::base_pathname (temp); goto add_string; } case 'w': case 'W': { temp = octave_env::getcwd (); if (c == 'W') { size_t pos = temp.rfind ('/'); if (pos != NPOS && pos != 0) temp = temp.substr (pos + 1); } else temp = octave_env::polite_directory_format (temp); goto add_string; } case 'u': { temp = octave_env::get_user_name (); goto add_string; } case 'H': { temp = octave_env::get_host_name (); goto add_string; } case 'h': { temp = octave_env::get_host_name (); size_t pos = temp.find ('.'); if (pos != NPOS) temp.resize (pos); goto add_string; } case '#': { char number_buffer[128]; sprintf (number_buffer, "%d", command_number); temp = number_buffer; goto add_string; } case '!': { char number_buffer[128]; int num = command_history::current_number (); if (num > 0) sprintf (number_buffer, "%d", num); else strcpy (number_buffer, "!"); temp = number_buffer; goto add_string; } case '$': { #if defined (HAVE_GETEUID) temp = (::geteuid () == 0 ? "#" : "$"); #else temp = "$"; #endif goto add_string; } #if defined (USE_READLINE) case '[': case ']': { temp.resize (2); temp[0] = '\001'; temp[1] = ((c == '[') ? ::octave_rl_prompt_start_ignore () : ::octave_rl_prompt_end_ignore ()); goto add_string; } #endif case '\\': { temp = "\\"; goto add_string; } default: { temp = "\\ "; temp[1] = c; goto add_string; } add_string: { if (c) i++; result.append (temp); break; } } } else result += c; } return result; } // Return the octal number parsed from STRING, or -1 to indicate that // the string contained a bad number. int command_editor::read_octal (const std::string& s) { int result = 0; int digits = 0; size_t i = 0; size_t slen = s.length (); while (i < slen && s[i] >= '0' && s[i] < '8') { digits++; result = (result * 8) + s[i] - '0'; i++; } if (! digits || result > 0777 || i < slen) result = -1; return result; } void command_editor::error (int err_num) { current_liboctave_error_handler ("%s", strerror (err_num)); } void command_editor::error (const std::string& s) { current_liboctave_error_handler ("%s", s.c_str ()); } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */