cmd-edit.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cstdlib>
00028 #include <cstring>
00029 
00030 #include <string>
00031 
00032 #include <sys/types.h>
00033 #include <unistd.h>
00034 
00035 #include "quit.h"
00036 
00037 #include "cmd-edit.h"
00038 #include "cmd-hist.h"
00039 #include "file-ops.h"
00040 #include "lo-error.h"
00041 #include "lo-utils.h"
00042 #include "oct-env.h"
00043 #include "oct-mutex.h"
00044 #include "oct-time.h"
00045 #include "singleton-cleanup.h"
00046 
00047 command_editor *command_editor::instance = 0;
00048 
00049 std::set<command_editor::startup_hook_fcn> command_editor::startup_hook_set;
00050 
00051 std::set<command_editor::event_hook_fcn> command_editor::event_hook_set;
00052 
00053 static octave_mutex event_hook_lock;
00054 
00055 #if defined (USE_READLINE)
00056 
00057 #include <cstdio>
00058 #include <cstdlib>
00059 
00060 #include "oct-rl-edit.h"
00061 
00062 class
00063 gnu_readline : public command_editor
00064 {
00065 public:
00066 
00067   typedef command_editor::startup_hook_fcn startup_hook_fcn;
00068 
00069   typedef command_editor::event_hook_fcn event_hook_fcn;
00070 
00071   typedef command_editor::completion_fcn completion_fcn;
00072 
00073   gnu_readline (void);
00074 
00075   ~gnu_readline (void) { }
00076 
00077   void do_set_name (const std::string& n);
00078 
00079   std::string do_readline (const std::string& prompt, bool& eof);
00080 
00081   void do_set_input_stream (FILE *f);
00082 
00083   FILE *do_get_input_stream (void);
00084 
00085   void do_set_output_stream (FILE *f);
00086 
00087   FILE *do_get_output_stream (void);
00088 
00089   int do_terminal_rows (void);
00090 
00091   int do_terminal_cols (void);
00092 
00093   void do_clear_screen (void);
00094 
00095   void do_resize_terminal (void);
00096 
00097   std::string newline_chars (void);
00098 
00099   void do_restore_terminal_state (void);
00100 
00101   void do_blink_matching_paren (bool flag);
00102 
00103   void do_set_basic_word_break_characters (const std::string& s);
00104 
00105   void do_set_completer_word_break_characters (const std::string& s);
00106 
00107   void do_set_basic_quote_characters (const std::string& s);
00108 
00109   void do_set_filename_quote_characters (const std::string& s);
00110 
00111   void do_set_completer_quote_characters (const std::string& s);
00112 
00113   void do_set_completion_append_character (char c);
00114 
00115   void do_set_completion_function (completion_fcn f);
00116 
00117   void do_set_quoting_function (quoting_fcn f);
00118 
00119   void do_set_dequoting_function (dequoting_fcn f);
00120 
00121   void do_set_char_is_quoted_function (char_is_quoted_fcn f);
00122 
00123   void do_set_user_accept_line_function (user_accept_line_fcn f);
00124 
00125   completion_fcn do_get_completion_function (void) const;
00126 
00127   quoting_fcn do_get_quoting_function (void) const;
00128 
00129   dequoting_fcn do_get_dequoting_function (void) const;
00130 
00131   char_is_quoted_fcn do_get_char_is_quoted_function (void) const;
00132 
00133   user_accept_line_fcn do_get_user_accept_line_function (void) const;
00134 
00135   string_vector
00136   do_generate_filename_completions (const std::string& text);
00137 
00138   std::string do_get_line_buffer (void) const;
00139 
00140   void do_insert_text (const std::string& text);
00141 
00142   void do_newline (void);
00143 
00144   void do_accept_line (void);
00145 
00146   void do_clear_undo_list (void);
00147 
00148   void set_startup_hook (startup_hook_fcn f);
00149 
00150   void restore_startup_hook (void);
00151 
00152   void set_event_hook (event_hook_fcn f);
00153 
00154   void restore_event_hook (void);
00155 
00156   void do_restore_event_hook (void);
00157 
00158   void do_read_init_file (const std::string& file);
00159 
00160   void do_re_read_init_file (void);
00161 
00162   bool do_filename_completion_desired (bool);
00163 
00164   bool do_filename_quoting_desired (bool);
00165 
00166   static int operate_and_get_next (int, int);
00167 
00168   static int history_search_backward (int, int);
00169 
00170   static int history_search_forward (int, int);
00171 
00172 private:
00173 
00174   startup_hook_fcn previous_startup_hook;
00175 
00176   event_hook_fcn previous_event_hook;
00177 
00178   completion_fcn completion_function;
00179 
00180   quoting_fcn quoting_function;
00181 
00182   dequoting_fcn dequoting_function;
00183 
00184   char_is_quoted_fcn char_is_quoted_function;
00185 
00186   user_accept_line_fcn user_accept_line_function;
00187 
00188   static char *command_generator (const char *text, int state);
00189 
00190   static char *command_quoter (char *text, int match_type, char *quote_pointer);
00191   static char *command_dequoter (char *text, int match_type);
00192 
00193   static int command_char_is_quoted (char *text, int index);
00194 
00195   static int command_accept_line (int count, int key);
00196 
00197   static char **command_completer (const char *text, int start, int end);
00198 };
00199 
00200 gnu_readline::gnu_readline ()
00201   : command_editor (), previous_startup_hook (0),
00202     previous_event_hook (0), completion_function (0),
00203     quoting_function (0), dequoting_function (0),
00204     char_is_quoted_function (0), user_accept_line_function (0)
00205 {
00206   // FIXME -- need interface to rl_add_defun, rl_initialize, and
00207   // a function to set rl_terminal_name
00208 
00209   std::string term = octave_env::getenv ("TERM");
00210 
00211   octave_rl_set_terminal_name (term.c_str ());
00212 
00213   octave_rl_initialize ();
00214 
00215   do_blink_matching_paren (true);
00216 
00217   // Bind operate-and-get-next.
00218 
00219   octave_rl_add_defun ("operate-and-get-next",
00220                        gnu_readline::operate_and_get_next,
00221                        octave_rl_ctrl ('O'));
00222 
00223   // And the history search functions.
00224 
00225   octave_rl_add_defun ("history-search-backward",
00226                        gnu_readline::history_search_backward,
00227                        octave_rl_meta ('P'));
00228 
00229   octave_rl_add_defun ("history-search-forward",
00230                        gnu_readline::history_search_forward,
00231                        octave_rl_meta ('N'));
00232 }
00233 
00234 void
00235 gnu_readline::do_set_name (const std::string& nm)
00236 {
00237   ::octave_rl_set_name (nm.c_str ());
00238 }
00239 
00240 std::string
00241 gnu_readline::do_readline (const std::string& prompt, bool& eof)
00242 {
00243   std::string retval;
00244 
00245   eof = false;
00246 
00247   char *line = 0;
00248 
00249   const char *p = prompt.c_str ();
00250 
00251   BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00252 
00253   line = ::octave_rl_readline (p);
00254 
00255   END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00256 
00257   if (line)
00258     {
00259       retval = line;
00260 
00261       free (line);
00262     }
00263   else
00264     eof = true;
00265 
00266   return retval;
00267 }
00268 
00269 void
00270 gnu_readline::do_set_input_stream (FILE *f)
00271 {
00272   ::octave_rl_set_input_stream (f);
00273 }
00274 
00275 FILE *
00276 gnu_readline::do_get_input_stream (void)
00277 {
00278   return ::octave_rl_get_input_stream ();
00279 }
00280 
00281 void
00282 gnu_readline::do_set_output_stream (FILE *f)
00283 {
00284   ::octave_rl_set_output_stream (f);
00285 }
00286 
00287 FILE *
00288 gnu_readline::do_get_output_stream (void)
00289 {
00290   return ::octave_rl_get_output_stream ();
00291 }
00292 
00293 // GNU readline handles SIGWINCH, so these values have a good chance
00294 // of being correct even if the window changes size (they may be
00295 // wrong if, for example, the luser changes the window size while the
00296 // pager is running, and the signal is handled by the pager instead of
00297 // us.
00298 
00299 int
00300 gnu_readline::do_terminal_rows (void)
00301 {
00302   int sh = ::octave_rl_screen_height ();
00303 
00304   return sh > 0 ? sh : 24;
00305 }
00306 
00307 int
00308 gnu_readline::do_terminal_cols (void)
00309 {
00310   int sw = ::octave_rl_screen_width ();
00311 
00312   return sw > 0 ? sw : 80;
00313 }
00314 
00315 void
00316 gnu_readline::do_clear_screen (void)
00317 {
00318   ::octave_rl_clear_screen ();
00319 }
00320 
00321 void
00322 gnu_readline::do_resize_terminal (void)
00323 {
00324   ::octave_rl_resize_terminal ();
00325 }
00326 
00327 std::string
00328 gnu_readline::newline_chars (void)
00329 {
00330   return "\r\n";
00331 }
00332 
00333 void
00334 gnu_readline::do_restore_terminal_state (void)
00335 {
00336   ::octave_rl_restore_terminal_state ();
00337 }
00338 
00339 void
00340 gnu_readline::do_blink_matching_paren (bool flag)
00341 {
00342   ::octave_rl_enable_paren_matching (flag ? 1 : 0);
00343 }
00344 
00345 void
00346 gnu_readline::do_set_basic_word_break_characters (const std::string& s)
00347 {
00348   ::octave_rl_set_basic_word_break_characters (s.c_str ());
00349 }
00350 
00351 void
00352 gnu_readline::do_set_completer_word_break_characters (const std::string& s)
00353 {
00354   ::octave_rl_set_completer_word_break_characters (s.c_str ());
00355 }
00356 
00357 void
00358 gnu_readline::do_set_basic_quote_characters (const std::string& s)
00359 {
00360   ::octave_rl_set_basic_quote_characters (s.c_str ());
00361 }
00362 
00363 void
00364 gnu_readline::do_set_filename_quote_characters (const std::string& s)
00365 {
00366   ::octave_rl_set_filename_quote_characters (s.c_str ());
00367 }
00368 
00369 void
00370 gnu_readline::do_set_completer_quote_characters (const std::string& s)
00371 {
00372   ::octave_rl_set_completer_quote_characters (s.c_str ());
00373 }
00374 
00375 void
00376 gnu_readline::do_set_completion_append_character (char c)
00377 {
00378   ::octave_rl_set_completion_append_character (c);
00379 }
00380 
00381 void
00382 gnu_readline::do_set_completion_function (completion_fcn f)
00383 {
00384   completion_function = f;
00385 
00386   rl_attempted_completion_fcn_ptr fp
00387     = f ? gnu_readline::command_completer : 0;
00388 
00389   ::octave_rl_set_completion_function (fp);
00390 }
00391 
00392 void
00393 gnu_readline::do_set_quoting_function (quoting_fcn f)
00394 {
00395   quoting_function = f;
00396 
00397   rl_quoting_fcn_ptr fp
00398     = f ? gnu_readline::command_quoter : 0;
00399 
00400   ::octave_rl_set_quoting_function (fp);
00401 }
00402 
00403 void
00404 gnu_readline::do_set_dequoting_function (dequoting_fcn f)
00405 {
00406   dequoting_function = f;
00407 
00408   rl_dequoting_fcn_ptr fp
00409     = f ? gnu_readline::command_dequoter : 0;
00410 
00411   ::octave_rl_set_dequoting_function (fp);
00412 }
00413 
00414 void
00415 gnu_readline::do_set_char_is_quoted_function (char_is_quoted_fcn f)
00416 {
00417   char_is_quoted_function = f;
00418 
00419   rl_char_is_quoted_fcn_ptr fp
00420     = f ? gnu_readline::command_char_is_quoted : 0;
00421 
00422   ::octave_rl_set_char_is_quoted_function (fp);
00423 }
00424 
00425 void
00426 gnu_readline::do_set_user_accept_line_function (user_accept_line_fcn f)
00427 {
00428   user_accept_line_function = f;
00429 
00430   if (f)
00431     octave_rl_add_defun ("accept-line", gnu_readline::command_accept_line,
00432                          ::octave_rl_ctrl ('M'));
00433   else
00434     octave_rl_add_defun ("accept-line", ::octave_rl_newline,
00435                          ::octave_rl_ctrl ('M'));
00436 }
00437 
00438 gnu_readline::completion_fcn
00439 gnu_readline::do_get_completion_function (void) const
00440 {
00441   return completion_function;
00442 }
00443 
00444 gnu_readline::quoting_fcn
00445 gnu_readline::do_get_quoting_function (void) const
00446 {
00447   return quoting_function;
00448 }
00449 
00450 gnu_readline::dequoting_fcn
00451 gnu_readline::do_get_dequoting_function (void) const
00452 {
00453   return dequoting_function;
00454 }
00455 
00456 gnu_readline::char_is_quoted_fcn
00457 gnu_readline::do_get_char_is_quoted_function (void) const
00458 {
00459   return char_is_quoted_function;
00460 }
00461 
00462 gnu_readline::user_accept_line_fcn
00463 gnu_readline::do_get_user_accept_line_function (void) const
00464 {
00465   return user_accept_line_function;
00466 }
00467 
00468 string_vector
00469 gnu_readline::do_generate_filename_completions (const std::string& text)
00470 {
00471   string_vector retval;
00472 
00473   int n = 0;
00474   int count = 0;
00475 
00476   char *fn = 0;
00477 
00478   while (1)
00479     {
00480       fn = ::octave_rl_filename_completion_function (text.c_str (), count);
00481 
00482       if (fn)
00483         {
00484           if (count == n)
00485             {
00486               // Famous last words:  Most large directories will not
00487               // have more than a few hundred files, so we should not
00488               // resize too many times even if the growth is linear...
00489 
00490               n += 100;
00491               retval.resize (n);
00492             }
00493 
00494           retval[count++] = fn;
00495 
00496           free (fn);
00497         }
00498       else
00499         break;
00500     }
00501 
00502   retval.resize (count);
00503 
00504   return retval;
00505 }
00506 
00507 std::string
00508 gnu_readline::do_get_line_buffer (void) const
00509 {
00510   return ::octave_rl_line_buffer ();
00511 }
00512 
00513 void
00514 gnu_readline::do_insert_text (const std::string& text)
00515 {
00516   ::octave_rl_insert_text (text.c_str ());
00517 }
00518 
00519 void
00520 gnu_readline::do_newline (void)
00521 {
00522   ::octave_rl_newline (1, '\n');
00523 }
00524 
00525 void
00526 gnu_readline::do_accept_line (void)
00527 {
00528   command_accept_line (1, '\n');
00529 }
00530 
00531 void
00532 gnu_readline::do_clear_undo_list ()
00533 {
00534   ::octave_rl_clear_undo_list ();
00535 }
00536 
00537 void
00538 gnu_readline::set_startup_hook (startup_hook_fcn f)
00539 {
00540   previous_startup_hook = ::octave_rl_get_startup_hook ();
00541 
00542   if (f != previous_startup_hook)
00543     ::octave_rl_set_startup_hook (f);
00544 }
00545 
00546 void
00547 gnu_readline::restore_startup_hook (void)
00548 {
00549   ::octave_rl_set_startup_hook (previous_startup_hook);
00550 }
00551 
00552 void
00553 gnu_readline::set_event_hook (event_hook_fcn f)
00554 {
00555   previous_event_hook = octave_rl_get_event_hook ();
00556 
00557   ::octave_rl_set_event_hook (f);
00558 }
00559 
00560 void
00561 gnu_readline::restore_event_hook (void)
00562 {
00563   ::octave_rl_set_event_hook (previous_event_hook);
00564 }
00565 
00566 void
00567 gnu_readline::do_read_init_file (const std::string& file)
00568 {
00569   ::octave_rl_read_init_file (file.c_str ());
00570 }
00571 
00572 void
00573 gnu_readline::do_re_read_init_file (void)
00574 {
00575   ::octave_rl_re_read_init_file ();
00576 }
00577 
00578 bool
00579 gnu_readline::do_filename_completion_desired (bool arg)
00580 {
00581   return ::octave_rl_filename_completion_desired (arg);
00582 }
00583 
00584 bool
00585 gnu_readline::do_filename_quoting_desired (bool arg)
00586 {
00587   return ::octave_rl_filename_quoting_desired (arg);
00588 }
00589 
00590 int
00591 gnu_readline::operate_and_get_next (int /* count */, int /* c */)
00592 {
00593   // Accept the current line.
00594 
00595   command_editor::accept_line ();
00596 
00597   // Find the current line, and find the next line to use.
00598 
00599   int x_where = command_history::where ();
00600 
00601   int x_length = command_history::length ();
00602 
00603   if ((command_history::is_stifled ()
00604        && (x_length >= command_history::max_input_history ()))
00605       || (x_where >= x_length - 1))
00606     command_history::set_mark (x_where);
00607   else
00608     command_history::set_mark (x_where + 1);
00609 
00610   command_editor::add_startup_hook (command_history::goto_mark);
00611 
00612   return 0;
00613 }
00614 
00615 int
00616 gnu_readline::history_search_backward (int count, int c)
00617 {
00618   return octave_rl_history_search_backward (count, c);
00619 }
00620 
00621 int
00622 gnu_readline::history_search_forward (int count, int c)
00623 {
00624   return octave_rl_history_search_forward (count, c);
00625 }
00626 
00627 char *
00628 gnu_readline::command_generator (const char *text, int state)
00629 {
00630   char *retval = 0;
00631 
00632   completion_fcn f = command_editor::get_completion_function ();
00633 
00634   std::string tmp = f (text, state);
00635 
00636   size_t len = tmp.length ();
00637 
00638   if (len > 0)
00639     {
00640       retval = static_cast<char *> (gnulib::malloc (len+1));
00641 
00642       strcpy (retval, tmp.c_str ());
00643     }
00644 
00645   return retval;
00646 }
00647 
00648 char *
00649 gnu_readline::command_quoter (char *text, int matches, char *qcp)
00650 {
00651   char *retval = 0;
00652 
00653   quoting_fcn f = command_editor::get_quoting_function ();
00654 
00655   std::string tmp = f (text, matches, *qcp);
00656 
00657   size_t len = tmp.length ();
00658 
00659   if (len > 0)
00660     {
00661       retval = static_cast<char *> (gnulib::malloc (len+1));
00662 
00663       strcpy (retval, tmp.c_str ());
00664     }
00665 
00666   return retval;
00667 }
00668 
00669 char *
00670 gnu_readline::command_dequoter (char *text, int quote)
00671 {
00672   char *retval = 0;
00673 
00674   dequoting_fcn f = command_editor::get_dequoting_function ();
00675 
00676   std::string tmp = f (text, quote);
00677 
00678   size_t len = tmp.length ();
00679 
00680   if (len > 0)
00681     {
00682       retval = static_cast<char *> (gnulib::malloc (len+1));
00683 
00684       strcpy (retval, tmp.c_str ());
00685     }
00686 
00687   return retval;
00688 }
00689 
00690 int
00691 gnu_readline::command_char_is_quoted (char *text, int quote)
00692 {
00693   char_is_quoted_fcn f = command_editor::get_char_is_quoted_function ();
00694 
00695   return f (text, quote);
00696 }
00697 
00698 int
00699 gnu_readline::command_accept_line (int count, int key)
00700 {
00701   user_accept_line_fcn f = command_editor::get_user_accept_line_function ();
00702 
00703   if (f)
00704     f (::octave_rl_line_buffer ());
00705 
00706   ::octave_rl_redisplay ();
00707 
00708   return ::octave_rl_newline (count, key);
00709 }
00710 
00711 char **
00712 gnu_readline::command_completer (const char *text, int, int)
00713 {
00714   char **matches = 0;
00715   matches
00716     = ::octave_rl_completion_matches (text, gnu_readline::command_generator);
00717   return matches;
00718 }
00719 
00720 #endif
00721 
00722 class
00723 default_command_editor : public command_editor
00724 {
00725 public:
00726 
00727   default_command_editor (void)
00728     : command_editor (), input_stream (stdin), output_stream (stdout) { }
00729 
00730   ~default_command_editor (void) { }
00731 
00732   std::string do_readline (const std::string& prompt, bool& eof);
00733 
00734   void do_set_input_stream (FILE *f);
00735 
00736   FILE *do_get_input_stream (void);
00737 
00738   void do_set_output_stream (FILE *f);
00739 
00740   FILE *do_get_output_stream (void);
00741 
00742   string_vector do_generate_filename_completions (const std::string& text);
00743 
00744   std::string do_get_line_buffer (void) const;
00745 
00746   void do_insert_text (const std::string&);
00747 
00748   void do_newline (void);
00749 
00750   void do_accept_line (void);
00751 
00752 private:
00753 
00754   FILE *input_stream;
00755 
00756   FILE *output_stream;
00757 
00758   // No copying!
00759 
00760   default_command_editor (const default_command_editor&);
00761 
00762   default_command_editor& operator = (const default_command_editor&);
00763 };
00764 
00765 std::string
00766 default_command_editor::do_readline (const std::string& prompt, bool& eof)
00767 {
00768   gnulib::fputs (prompt.c_str (), output_stream);
00769   gnulib::fflush (output_stream);
00770 
00771   return octave_fgetl (input_stream, eof);
00772 }
00773 
00774 void
00775 default_command_editor::do_set_input_stream (FILE *f)
00776 {
00777   input_stream = f;
00778 }
00779 
00780 FILE *
00781 default_command_editor::do_get_input_stream (void)
00782 {
00783   return input_stream;
00784 }
00785 
00786 void
00787 default_command_editor::do_set_output_stream (FILE *f)
00788 {
00789   output_stream = f;
00790 }
00791 
00792 FILE *
00793 default_command_editor::do_get_output_stream (void)
00794 {
00795   return output_stream;
00796 }
00797 
00798 string_vector
00799 default_command_editor::do_generate_filename_completions (const std::string&)
00800 {
00801   // FIXME
00802   return string_vector ();
00803 }
00804 
00805 std::string
00806 default_command_editor::do_get_line_buffer (void) const
00807 {
00808   return "";
00809 }
00810 
00811 void
00812 default_command_editor::do_insert_text (const std::string&)
00813 {
00814   // FIXME
00815 }
00816 
00817 void
00818 default_command_editor::do_newline (void)
00819 {
00820   // FIXME
00821 }
00822 
00823 void
00824 default_command_editor::do_accept_line (void)
00825 {
00826   // FIXME
00827 }
00828 
00829 bool
00830 command_editor::instance_ok (void)
00831 {
00832   bool retval = true;
00833 
00834   if (! instance)
00835     {
00836       make_command_editor ();
00837 
00838       if (instance)
00839         singleton_cleanup_list::add (cleanup_instance);
00840     }
00841 
00842   if (! instance)
00843     {
00844       current_liboctave_error_handler
00845         ("unable to create command history object!");
00846 
00847       retval = false;
00848     }
00849 
00850   return retval;
00851 }
00852 
00853 void
00854 command_editor::make_command_editor (void)
00855 {
00856 #if defined (USE_READLINE)
00857   instance = new gnu_readline ();
00858 #else
00859   instance = new default_command_editor ();
00860 #endif
00861 }
00862 
00863 void
00864 command_editor::force_default_editor (void)
00865 {
00866   delete instance;
00867   instance = new default_command_editor ();
00868 }
00869 
00870 int
00871 command_editor::startup_handler (void)
00872 {
00873   for (startup_hook_set_iterator p = startup_hook_set.begin ();
00874        p != startup_hook_set.end (); p++)
00875     {
00876       startup_hook_fcn f = *p;
00877 
00878       if (f)
00879         f ();
00880     }
00881 
00882   return 0;
00883 }
00884 
00885 int
00886 command_editor::event_handler (void)
00887 {
00888   event_hook_lock.lock ();
00889 
00890   std::set<event_hook_fcn> hook_set (event_hook_set);
00891 
00892   event_hook_lock.unlock ();
00893 
00894   for (event_hook_set_iterator p = hook_set.begin ();
00895        p != hook_set.end (); p++)
00896     {
00897       event_hook_fcn f = *p;
00898 
00899       if (f)
00900         f ();
00901     }
00902 
00903   return 0;
00904 }
00905 
00906 void
00907 command_editor::set_name (const std::string& n)
00908 {
00909   if (instance_ok ())
00910     instance->do_set_name (n);
00911 }
00912 
00913 std::string
00914 command_editor::readline (const std::string& prompt)
00915 {
00916   bool eof;
00917 
00918   return readline (prompt, eof);
00919 }
00920 
00921 std::string
00922 command_editor::readline (const std::string& prompt, bool& eof)
00923 {
00924   return (instance_ok ())
00925     ? instance->do_readline (prompt, eof) : std::string ();
00926 }
00927 
00928 void
00929 command_editor::set_input_stream (FILE *f)
00930 {
00931   if (instance_ok ())
00932     instance->do_set_input_stream (f);
00933 }
00934 
00935 FILE *
00936 command_editor::get_input_stream (void)
00937 {
00938   return (instance_ok ())
00939     ? instance->do_get_input_stream () : 0;
00940 }
00941 
00942 void
00943 command_editor::set_output_stream (FILE *f)
00944 {
00945   if (instance_ok ())
00946     instance->do_set_output_stream (f);
00947 }
00948 
00949 FILE *
00950 command_editor::get_output_stream (void)
00951 {
00952   return (instance_ok ())
00953     ? instance->do_get_output_stream () : 0;
00954 }
00955 
00956 int
00957 command_editor::terminal_rows (void)
00958 {
00959   return (instance_ok ())
00960     ? instance->do_terminal_rows () : -1;
00961 }
00962 
00963 int
00964 command_editor::terminal_cols (void)
00965 {
00966   return (instance_ok ())
00967     ? instance->do_terminal_cols () : -1;
00968 }
00969 
00970 void
00971 command_editor::clear_screen (void)
00972 {
00973   if (instance_ok ())
00974     instance->do_clear_screen ();
00975 }
00976 
00977 void
00978 command_editor::resize_terminal (void)
00979 {
00980   if (instance_ok ())
00981     instance->do_resize_terminal ();
00982 }
00983 
00984 std::string
00985 command_editor::decode_prompt_string (const std::string& s)
00986 {
00987   return (instance_ok ())
00988     ? instance->do_decode_prompt_string (s) : std::string ();
00989 }
00990 
00991 int
00992 command_editor::current_command_number (void)
00993 {
00994   return (instance_ok ())
00995     ? instance->command_number : 0;
00996 }
00997 
00998 void
00999 command_editor::reset_current_command_number (int n)
01000 {
01001   if (instance_ok ())
01002     instance->command_number = n;
01003 }
01004 
01005 void
01006 command_editor::increment_current_command_number (void)
01007 {
01008   if (instance_ok ())
01009     instance->command_number++;
01010 }
01011 
01012 void
01013 command_editor::restore_terminal_state (void)
01014 {
01015   if (instance_ok ())
01016     instance->do_restore_terminal_state ();
01017 }
01018 
01019 void
01020 command_editor::blink_matching_paren (bool flag)
01021 {
01022   if (instance_ok ())
01023     instance->do_blink_matching_paren (flag);
01024 }
01025 
01026 void
01027 command_editor::set_basic_word_break_characters (const std::string& s)
01028 {
01029   if (instance_ok ())
01030     instance->do_set_basic_word_break_characters (s);
01031 }
01032 
01033 void
01034 command_editor::set_completer_word_break_characters (const std::string& s)
01035 {
01036   if (instance_ok ())
01037     instance->do_set_completer_word_break_characters (s);
01038 }
01039 
01040 void
01041 command_editor::set_basic_quote_characters (const std::string& s)
01042 {
01043   if (instance_ok ())
01044     instance->do_set_basic_quote_characters (s);
01045 }
01046 
01047 void
01048 command_editor::set_filename_quote_characters (const std::string& s)
01049 {
01050   if (instance_ok ())
01051     instance->do_set_filename_quote_characters (s);
01052 }
01053 
01054 void
01055 command_editor::set_completer_quote_characters (const std::string& s)
01056 {
01057   if (instance_ok ())
01058     instance->do_set_completer_quote_characters (s);
01059 }
01060 
01061 void
01062 command_editor::set_completion_append_character (char c)
01063 {
01064   if (instance_ok ())
01065     instance->do_set_completion_append_character (c);
01066 }
01067 
01068 void
01069 command_editor::set_completion_function (completion_fcn f)
01070 {
01071   if (instance_ok ())
01072     instance->do_set_completion_function (f);
01073 }
01074 
01075 void
01076 command_editor::set_quoting_function (quoting_fcn f)
01077 {
01078   if (instance_ok ())
01079     instance->do_set_quoting_function (f);
01080 }
01081 
01082 void
01083 command_editor::set_dequoting_function (dequoting_fcn f)
01084 {
01085   if (instance_ok ())
01086     instance->do_set_dequoting_function (f);
01087 }
01088 
01089 void
01090 command_editor::set_char_is_quoted_function (char_is_quoted_fcn f)
01091 {
01092   if (instance_ok ())
01093     instance->do_set_char_is_quoted_function (f);
01094 }
01095 
01096 void
01097 command_editor::set_user_accept_line_function (user_accept_line_fcn f)
01098 {
01099   if (instance_ok ())
01100     instance->do_set_user_accept_line_function (f);
01101 }
01102 
01103 command_editor::completion_fcn
01104 command_editor::get_completion_function (void)
01105 {
01106   return (instance_ok ())
01107     ? instance->do_get_completion_function () : 0;
01108 }
01109 
01110 command_editor::quoting_fcn
01111 command_editor::get_quoting_function (void)
01112 {
01113   return (instance_ok ())
01114     ? instance->do_get_quoting_function () : 0;
01115 }
01116 
01117 command_editor::dequoting_fcn
01118 command_editor::get_dequoting_function (void)
01119 {
01120   return (instance_ok ())
01121     ? instance->do_get_dequoting_function () : 0;
01122 }
01123 
01124 command_editor::char_is_quoted_fcn
01125 command_editor::get_char_is_quoted_function (void)
01126 {
01127   return (instance_ok ())
01128     ? instance->do_get_char_is_quoted_function () : 0;
01129 }
01130 
01131 command_editor::user_accept_line_fcn
01132 command_editor::get_user_accept_line_function (void)
01133 {
01134   return (instance_ok ())
01135     ? instance->do_get_user_accept_line_function () : 0;
01136 }
01137 
01138 string_vector
01139 command_editor::generate_filename_completions (const std::string& text)
01140 {
01141   return (instance_ok ())
01142     ? instance->do_generate_filename_completions (text) : string_vector ();
01143 }
01144 
01145 std::string
01146 command_editor::get_line_buffer (void)
01147 {
01148   return (instance_ok ()) ? instance->do_get_line_buffer () : "";
01149 }
01150 
01151 void
01152 command_editor::insert_text (const std::string& text)
01153 {
01154   if (instance_ok ())
01155     instance->do_insert_text (text);
01156 }
01157 
01158 void
01159 command_editor::newline (void)
01160 {
01161   if (instance_ok ())
01162     instance->do_newline ();
01163 }
01164 
01165 void
01166 command_editor::accept_line (void)
01167 {
01168   if (instance_ok ())
01169     instance->do_accept_line ();
01170 }
01171 
01172 void
01173 command_editor::clear_undo_list (void)
01174 {
01175   if (instance_ok ())
01176     instance->do_clear_undo_list ();
01177 }
01178 
01179 void
01180 command_editor::add_startup_hook (startup_hook_fcn f)
01181 {
01182   if (instance_ok ())
01183     {
01184       startup_hook_set.insert (f);
01185 
01186       instance->set_startup_hook (startup_handler);
01187     }
01188 }
01189 
01190 void
01191 command_editor::remove_startup_hook (startup_hook_fcn f)
01192 {
01193   if (instance_ok ())
01194     {
01195       startup_hook_set_iterator p = startup_hook_set.find (f);
01196 
01197       if (p != startup_hook_set.end ())
01198         startup_hook_set.erase (p);
01199 
01200       if (startup_hook_set.empty ())
01201         instance->restore_startup_hook ();
01202     }
01203 }
01204 
01205 void
01206 command_editor::add_event_hook (event_hook_fcn f)
01207 {
01208   octave_autolock guard (event_hook_lock);
01209 
01210   if (instance_ok ())
01211     {
01212       event_hook_set.insert (f);
01213 
01214       instance->set_event_hook (event_handler);
01215     }
01216 }
01217 
01218 void
01219 command_editor::remove_event_hook (event_hook_fcn f)
01220 {
01221   octave_autolock guard (event_hook_lock);
01222 
01223   if (instance_ok ())
01224     {
01225       event_hook_set_iterator p = event_hook_set.find (f);
01226 
01227       if (p != event_hook_set.end ())
01228         event_hook_set.erase (p);
01229 
01230       if (event_hook_set.empty ())
01231         instance->restore_event_hook ();
01232     }
01233 }
01234 
01235 void
01236 command_editor::run_event_hooks (void)
01237 {
01238   event_handler ();
01239 }
01240 
01241 void
01242 command_editor::read_init_file (const std::string& file_arg)
01243 {
01244   if (instance_ok ())
01245     {
01246       std::string file = file_ops::tilde_expand (file_arg);
01247 
01248       instance->do_read_init_file (file);
01249     }
01250 }
01251 
01252 void
01253 command_editor::re_read_init_file (void)
01254 {
01255   if (instance_ok ())
01256     instance->do_re_read_init_file ();
01257 }
01258 
01259 bool
01260 command_editor::filename_completion_desired (bool arg)
01261 {
01262   return (instance_ok ())
01263     ? instance->do_filename_completion_desired (arg) : false;
01264 }
01265 
01266 bool
01267 command_editor::filename_quoting_desired (bool arg)
01268 {
01269   return (instance_ok ())
01270     ? instance->do_filename_quoting_desired (arg) : false;
01271 }
01272 
01273 // Return a string which will be printed as a prompt.  The string may
01274 // contain special characters which are decoded as follows:
01275 //
01276 //      \a      bell (ascii 07)
01277 //      \d      the date
01278 //      \e      escape (ascii 033)
01279 //      \h      the hostname up to the first '.'
01280 //      \H      the hostname
01281 //      \n      CRLF
01282 //      \r      CR
01283 //      \s      the name of the shell (program)
01284 //      \t      the time
01285 //      \T      the time in 12-hour hh:mm:ss format
01286 //      \@      the time in 12-hour hh:mm am/pm format
01287 //      \A      the time in 24-hour hh:mm format
01288 //      \u      your username
01289 //      \w      the current working directory
01290 //      \W      the last element of PWD
01291 //      \!      the history number of this command
01292 //      \#      the command number of this command
01293 //      \$      a $ or a # if you are root
01294 //      \nnn    character code nnn in octal
01295 //      \\      a backslash
01296 //      \[      begin a sequence of non-printing chars
01297 //      \]      end a sequence of non-printing chars
01298 
01299 std::string
01300 command_editor::do_decode_prompt_string (const std::string& s)
01301 {
01302   std::string result;
01303   std::string temp;
01304   size_t i = 0;
01305   size_t slen = s.length ();
01306   int c;
01307 
01308   while (i < slen)
01309     {
01310       c = s[i];
01311 
01312       i++;
01313 
01314       if (c == '\\')
01315         {
01316           c = s[i];
01317 
01318           switch (c)
01319             {
01320             case '0':
01321             case '1':
01322             case '2':
01323             case '3':
01324             case '4':
01325             case '5':
01326             case '6':
01327             case '7':
01328               // Maybe convert an octal number.
01329               {
01330                 int n = read_octal (s.substr (i, 3));
01331 
01332                 temp = "\\";
01333 
01334                 if (n != -1)
01335                   {
01336                     i += 3;
01337                     temp[0] = n;
01338                   }
01339 
01340                 c = 0;
01341                 goto add_string;
01342               }
01343 
01344             case 'a':
01345               {
01346                 temp = '\a';
01347 
01348                 goto add_string;
01349               }
01350 
01351             case 'e':
01352               {
01353                 temp = '\033';
01354 
01355                 goto add_string;
01356               }
01357 
01358             case 'r':
01359               {
01360                 temp = '\r';
01361 
01362                 goto add_string;
01363               }
01364 
01365             case 'd':
01366             case 't':
01367             case 'T':
01368             case '@':
01369             case 'A':
01370               // Make the current time/date into a string.
01371               {
01372                 octave_localtime now;
01373 
01374                 if (c == 'd')
01375                   temp = now.strftime ("%a %b %d");
01376                 else if (c == 't')
01377                   temp = now.strftime ("%H:%M:%S");
01378                 else if (c == 'T')
01379                   temp = now.strftime ("%I:%M:%S");
01380                 else if (c == '@')
01381                   temp = now.strftime ("%I:%M %p");
01382                 else if (c == 'A')
01383                   temp = now.strftime ("%H:%M");
01384 
01385                 goto add_string;
01386               }
01387 
01388             case 'n':
01389               {
01390                 temp = newline_chars ();
01391 
01392                 goto add_string;
01393               }
01394 
01395             case 's':
01396               {
01397                 temp = octave_env::get_program_name ();
01398                 temp = octave_env::base_pathname (temp);
01399 
01400                 goto add_string;
01401               }
01402 
01403             case 'w':
01404             case 'W':
01405               {
01406                 temp = octave_env::get_current_directory ();
01407 
01408                 std::string home_dir = octave_env::get_home_directory ();
01409 
01410                 if (c == 'W' && (home_dir.empty () || temp != home_dir))
01411                   {
01412                     if (temp != "/" && temp != "//")
01413                       {
01414                         size_t pos = temp.rfind ('/');
01415 
01416                         if (pos != std::string::npos && pos != 0)
01417                           temp = temp.substr (pos + 1);
01418                       }
01419                   }
01420                 else
01421                   temp = octave_env::polite_directory_format (temp);
01422 
01423                 goto add_string;
01424               }
01425 
01426             case 'u':
01427               {
01428                 temp = octave_env::get_user_name ();
01429 
01430                 goto add_string;
01431               }
01432 
01433             case 'H':
01434               {
01435                 temp = octave_env::get_host_name ();
01436 
01437                 goto add_string;
01438               }
01439 
01440             case 'h':
01441               {
01442                 temp = octave_env::get_host_name ();
01443 
01444                 size_t pos = temp.find ('.');
01445 
01446                 if (pos != std::string::npos)
01447                   temp.resize (pos);
01448 
01449                 goto add_string;
01450               }
01451 
01452             case '#':
01453               {
01454                 char number_buffer[128];
01455                 sprintf (number_buffer, "%d", command_number);
01456                 temp = number_buffer;
01457 
01458                 goto add_string;
01459               }
01460 
01461             case '!':
01462               {
01463                 char number_buffer[128];
01464                 int num = command_history::current_number ();
01465                 if (num > 0)
01466                   sprintf (number_buffer, "%d", num);
01467                 else
01468                   strcpy (number_buffer, "!");
01469                 temp = number_buffer;
01470 
01471                 goto add_string;
01472               }
01473 
01474             case '$':
01475               {
01476 #if defined (HAVE_GETEUID)
01477                 temp = (::geteuid () == 0 ? "#" : "$");
01478 #else
01479                 temp = "$";
01480 #endif
01481 
01482                 goto add_string;
01483               }
01484 
01485 #if defined (USE_READLINE)
01486             case '[':
01487             case ']':
01488               {
01489                 temp.resize (1);
01490 
01491                 temp[0] = ((c == '[')
01492                            ? ::octave_rl_prompt_start_ignore ()
01493                            : ::octave_rl_prompt_end_ignore ());
01494 
01495                 goto add_string;
01496               }
01497 #endif
01498 
01499             case '\\':
01500               {
01501                 temp = "\\";
01502 
01503                 goto add_string;
01504               }
01505 
01506             default:
01507               {
01508                 temp = "\\ ";
01509                 temp[1] = c;
01510 
01511                 goto add_string;
01512               }
01513 
01514             add_string:
01515               {
01516                 if (c)
01517                   i++;
01518 
01519                 result.append (temp);
01520 
01521                 break;
01522               }
01523             }
01524         }
01525       else
01526         result += c;
01527     }
01528 
01529   return result;
01530 }
01531 
01532 // Return the octal number parsed from STRING, or -1 to indicate that
01533 // the string contained a bad number.
01534 
01535 int
01536 command_editor::read_octal (const std::string& s)
01537 {
01538   int result = 0;
01539   int digits = 0;
01540 
01541   size_t i = 0;
01542   size_t slen = s.length ();
01543 
01544   while (i < slen && s[i] >= '0' && s[i] < '8')
01545     {
01546       digits++;
01547       result = (result * 8) + s[i] - '0';
01548       i++;
01549     }
01550 
01551   if (! digits || result > 0777 || i < slen)
01552     result = -1;
01553 
01554   return result;
01555 }
01556 
01557 void
01558 command_editor::error (int err_num)
01559 {
01560   current_liboctave_error_handler ("%s", gnulib::strerror (err_num));
01561 }
01562 
01563 void
01564 command_editor::error (const std::string& s)
01565 {
01566   current_liboctave_error_handler ("%s", s.c_str ());
01567 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines