cmd-hist.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 <cstring>
00028 
00029 #include <iostream>
00030 #include <string>
00031 
00032 #include "cmd-edit.h"
00033 #include "cmd-hist.h"
00034 #include "file-ops.h"
00035 #include "lo-error.h"
00036 #include "singleton-cleanup.h"
00037 #include "str-vec.h"
00038 
00039 command_history *command_history::instance = 0;
00040 
00041 #if defined (USE_READLINE)
00042 
00043 #include <cstdlib>
00044 
00045 #include <sys/types.h>
00046 #include <unistd.h>
00047 
00048 #include <fcntl.h>
00049 
00050 #include "oct-rl-hist.h"
00051 
00052 #include "file-stat.h"
00053 
00054 class
00055 gnu_history : public command_history
00056 {
00057 public:
00058 
00059   gnu_history (void)
00060     : command_history (), mark (0) { }
00061 
00062   ~gnu_history (void) { }
00063 
00064   void do_process_histcontrol (const std::string&);
00065 
00066   std::string do_histcontrol (void) const;
00067 
00068   void do_add (const std::string&);
00069 
00070   void do_remove (int);
00071 
00072   int do_where (void) const;
00073 
00074   int do_length (void) const;
00075 
00076   int do_max_input_history (void) const;
00077 
00078   int do_base (void) const;
00079 
00080   int do_current_number (void) const;
00081 
00082   void do_stifle (int);
00083 
00084   int do_unstifle (void);
00085 
00086   int do_is_stifled (void) const;
00087 
00088   void do_set_mark (int);
00089 
00090   int do_goto_mark (void);
00091 
00092   void do_read (const std::string&, bool);
00093 
00094   void do_read_range (const std::string&, int, int, bool);
00095 
00096   void do_write (const std::string&) const;
00097 
00098   void do_append (const std::string&);
00099 
00100   void do_truncate_file (const std::string&, int) const;
00101 
00102   string_vector do_list (int, bool) const;
00103 
00104   std::string do_get_entry (int) const;
00105 
00106   void do_replace_entry (int, const std::string&);
00107 
00108   void do_clean_up_and_save (const std::string&, int);
00109 
00110 private:
00111 
00112   int mark;
00113 };
00114 
00115 void
00116 gnu_history::do_process_histcontrol (const std::string& control_arg)
00117 {
00118   history_control = 0;
00119 
00120   size_t len = control_arg.length ();
00121   size_t beg = 0;
00122 
00123   while (beg < len)
00124     {
00125       if (control_arg[beg] == ':')
00126         beg++;
00127       else
00128         {
00129           size_t end = control_arg.find (":", beg);
00130 
00131           if (end == std::string::npos)
00132             end = len;
00133 
00134           std::string tmp = control_arg.substr (beg, end-beg);
00135 
00136           if (tmp == "erasedups")
00137             history_control |= HC_ERASEDUPS;
00138           else if (tmp == "ignoreboth")
00139             history_control |= HC_IGNDUPS|HC_IGNSPACE;
00140           else if (tmp == "ignoredups")
00141             history_control |= HC_IGNDUPS;
00142           else if (tmp == "ignorespace")
00143             history_control |= HC_IGNSPACE;
00144           else
00145             (*current_liboctave_warning_handler)
00146               ("unknown histcontrol directive %s", tmp.c_str ());
00147 
00148           if (end != std::string::npos)
00149             beg = end + 1;
00150         }
00151     }
00152 }
00153 
00154 std::string
00155 gnu_history::do_histcontrol (void) const
00156 {
00157   // FIXME -- instead of reconstructing this value, should we just save
00158   // the string we were given when constructing the command_history
00159   // object?
00160 
00161   std::string retval;
00162 
00163   if (history_control & HC_IGNSPACE)
00164     retval.append ("ignorespace");
00165 
00166   if (history_control & HC_IGNDUPS)
00167     {
00168       if (retval.length() > 0)
00169         retval.append (":");
00170 
00171       retval.append ("ignoredups");
00172     }
00173 
00174   if (history_control & HC_ERASEDUPS)
00175     {
00176       if (retval.length() > 0)
00177         retval.append (":");
00178 
00179       retval.append ("erasedups");
00180     }
00181 
00182   return retval;
00183 }
00184 
00185 void
00186 gnu_history::do_add (const std::string& s)
00187 {
00188   if (! do_ignoring_entries ())
00189     {
00190       if (s.empty ()
00191           || (s.length () == 1 && (s[0] == '\r' || s[0] == '\n')))
00192         return;
00193 
00194       lines_this_session += ::octave_add_history (s.c_str (), history_control);
00195     }
00196 }
00197 
00198 void
00199 gnu_history::do_remove (int n)
00200 {
00201   ::octave_remove_history (n);
00202 }
00203 
00204 int
00205 gnu_history::do_where (void) const
00206 {
00207   return ::octave_where_history ();
00208 }
00209 
00210 int
00211 gnu_history::do_length (void) const
00212 {
00213   return ::octave_history_length ();
00214 }
00215 
00216 int
00217 gnu_history::do_max_input_history (void) const
00218 {
00219   return ::octave_max_input_history ();
00220 }
00221 
00222 int
00223 gnu_history::do_base (void) const
00224 {
00225   return ::octave_history_base ();
00226 }
00227 
00228 int
00229 gnu_history::do_current_number (void) const
00230 {
00231   return (xsize > 0) ? do_base () + do_where () : -1;
00232 }
00233 
00234 void
00235 gnu_history::do_stifle (int n)
00236 {
00237   ::octave_stifle_history (n);
00238 }
00239 
00240 int
00241 gnu_history::do_unstifle (void)
00242 {
00243   return ::octave_unstifle_history ();
00244 }
00245 
00246 int
00247 gnu_history::do_is_stifled (void) const
00248 {
00249   return ::octave_history_is_stifled ();
00250 }
00251 
00252 void
00253 gnu_history::do_set_mark (int n)
00254 {
00255   mark = n;
00256 }
00257 
00258 int
00259 gnu_history::do_goto_mark (void)
00260 {
00261   if (mark)
00262     {
00263       char *line = ::octave_history_goto_mark (mark);
00264 
00265       if (line)
00266         {
00267           command_editor::insert_text (line);
00268 
00269           command_editor::clear_undo_list ();
00270         }
00271     }
00272 
00273   mark = 0;
00274 
00275   // FIXME -- for operate_and_get_next.
00276   command_editor::remove_startup_hook (command_history::goto_mark);
00277 
00278   return 0;
00279 }
00280 
00281 void
00282 gnu_history::do_read (const std::string& f, bool must_exist)
00283 {
00284   if (! f.empty ())
00285     {
00286       int status = ::octave_read_history (f.c_str ());
00287 
00288       if (status != 0 && must_exist)
00289         error (status);
00290       else
00291         {
00292           lines_in_file = do_where ();
00293 
00294           ::octave_using_history ();
00295         }
00296     }
00297   else
00298     error ("gnu_history::read: missing file name");
00299 }
00300 
00301 void
00302 gnu_history::do_read_range (const std::string& f, int from, int to,
00303                             bool must_exist)
00304 {
00305   if (from < 0)
00306     from = lines_in_file;
00307 
00308   if (! f.empty ())
00309     {
00310       int status = ::octave_read_history_range (f.c_str (), from, to);
00311 
00312       if (status != 0 && must_exist)
00313         error (status);
00314       else
00315         {
00316           lines_in_file = do_where ();
00317 
00318           ::octave_using_history ();
00319         }
00320     }
00321   else
00322     error ("gnu_history::read_range: missing file name");
00323 }
00324 
00325 void
00326 gnu_history::do_write (const std::string& f_arg) const
00327 {
00328   if (initialized)
00329     {
00330       std::string f = f_arg;
00331 
00332       if (f.empty ())
00333         f = xfile;
00334 
00335       if (! f.empty ())
00336         {
00337           int status = ::octave_write_history (f.c_str ());
00338 
00339           if (status != 0)
00340             error (status);
00341         }
00342       else
00343         error ("gnu_history::write: missing file name");
00344     }
00345 }
00346 
00347 void
00348 gnu_history::do_append (const std::string& f_arg)
00349 {
00350   if (initialized)
00351     {
00352       if (lines_this_session)
00353         {
00354           if (lines_this_session < do_where ())
00355             {
00356               // Create file if it doesn't already exist.
00357 
00358               std::string f = f_arg;
00359 
00360               if (f.empty ())
00361                 f = xfile;
00362 
00363               if (! f.empty ())
00364                 {
00365                   file_stat fs (f);
00366 
00367                   if (! fs)
00368                     {
00369                       int tem;
00370 
00371                       tem = gnulib::open (f.c_str (), O_CREAT, 0666);
00372                       gnulib::close (tem);
00373                     }
00374 
00375                   int status
00376                     = ::octave_append_history (lines_this_session, f.c_str ());
00377 
00378                   if (status != 0)
00379                     error (status);
00380                   else
00381                     lines_in_file += lines_this_session;
00382 
00383                   lines_this_session = 0;
00384                 }
00385               else
00386                 error ("gnu_history::append: missing file name");
00387             }
00388         }
00389     }
00390 }
00391 
00392 void
00393 gnu_history::do_truncate_file (const std::string& f_arg, int n) const
00394 {
00395   if (initialized)
00396     {
00397       std::string f = f_arg;
00398 
00399       if (f.empty ())
00400         f = xfile;
00401 
00402       if (! f.empty ())
00403         ::octave_history_truncate_file (f.c_str (), n);
00404       else
00405         error ("gnu_history::truncate_file: missing file name");
00406     }
00407 }
00408 
00409 string_vector
00410 gnu_history::do_list (int limit, bool number_lines) const
00411 {
00412   string_vector retval;
00413 
00414   if (limit)
00415     retval = ::octave_history_list (limit, number_lines);
00416 
00417   return retval;
00418 }
00419 
00420 std::string
00421 gnu_history::do_get_entry (int n) const
00422 {
00423   std::string retval;
00424 
00425   char *line = ::octave_history_get (do_base () + n);
00426 
00427   if (line)
00428     retval = line;
00429 
00430   return retval;
00431 }
00432 
00433 void
00434 gnu_history::do_replace_entry (int which, const std::string& line)
00435 {
00436   ::octave_replace_history_entry (which, line.c_str ());
00437 }
00438 
00439 void
00440 gnu_history::do_clean_up_and_save (const std::string& f_arg, int n)
00441 {
00442   if (initialized)
00443     {
00444       std::string f = f_arg;
00445 
00446       if (f.empty ())
00447         f = xfile;
00448 
00449       if (! f.empty ())
00450         {
00451           if (n < 0)
00452             n = xsize;
00453 
00454           stifle (n);
00455 
00456           do_write (f.c_str ());
00457         }
00458       else
00459         error ("gnu_history::clean_up_and_save: missing file name");
00460     }
00461 }
00462 
00463 #endif
00464 
00465 bool
00466 command_history::instance_ok (void)
00467 {
00468   bool retval = true;
00469 
00470   if (! instance)
00471     {
00472       make_command_history ();
00473 
00474       if (instance)
00475         singleton_cleanup_list::add (cleanup_instance);
00476     }
00477 
00478   if (! instance)
00479     {
00480       (*current_liboctave_error_handler)
00481         ("unable to create command history object!");
00482 
00483       retval = false;
00484     }
00485 
00486   return retval;
00487 }
00488 
00489 void
00490 command_history::make_command_history (void)
00491 {
00492 #if defined (USE_READLINE)
00493   instance = new gnu_history ();
00494 #else
00495   instance = new command_history ();
00496 #endif
00497 }
00498 
00499 void
00500 command_history::initialize (bool read_history_file,
00501                              const std::string& f_arg, int sz,
00502                              const std::string & control_arg)
00503 {
00504   if (instance_ok ())
00505     instance->do_initialize (read_history_file, f_arg, sz, control_arg);
00506 }
00507 
00508 bool
00509 command_history::is_initialized (void)
00510 {
00511   // We just want to check the status of an existing instance, not
00512   // create one.
00513   return instance && instance->do_is_initialized ();
00514 }
00515 
00516 void
00517 command_history::set_file (const std::string& f_arg)
00518 {
00519   if (instance_ok ())
00520     {
00521       std::string f = file_ops::tilde_expand (f_arg);
00522 
00523       instance->do_set_file (f);
00524     }
00525 }
00526 
00527 std::string
00528 command_history::file (void)
00529 {
00530   return (instance_ok ())
00531     ? instance->do_file () : std::string ();
00532 }
00533 
00534 void
00535 command_history::process_histcontrol (const std::string& control_arg)
00536 {
00537   if (instance_ok ())
00538     instance->do_process_histcontrol(control_arg);
00539 }
00540 
00541 std::string
00542 command_history::histcontrol (void)
00543 {
00544   return (instance_ok ())
00545     ? instance->do_histcontrol () : std::string ();
00546 }
00547 
00548 void
00549 command_history::set_size (int n)
00550 {
00551   if (instance_ok ())
00552     instance->do_set_size (n);
00553 }
00554 
00555 int
00556 command_history::size (void)
00557 {
00558   return (instance_ok ())
00559     ? instance->do_size () : 0;
00560 }
00561 
00562 void
00563 command_history::ignore_entries (bool flag)
00564 {
00565   if (instance_ok ())
00566     instance->do_ignore_entries (flag);
00567 }
00568 
00569 bool
00570 command_history::ignoring_entries (void)
00571 {
00572   return (instance_ok ())
00573     ? instance->do_ignoring_entries () : false;
00574 }
00575 
00576 void
00577 command_history::add (const std::string& s)
00578 {
00579   if (instance_ok ())
00580     instance->do_add (s);
00581 }
00582 
00583 void
00584 command_history::remove (int n)
00585 {
00586   if (instance_ok ())
00587     instance->do_remove (n);
00588 }
00589 
00590 int
00591 command_history::where (void)
00592 {
00593   return (instance_ok ())
00594     ? instance->do_where () : 0;
00595 }
00596 
00597 int
00598 command_history::length (void)
00599 {
00600   return (instance_ok ())
00601     ? instance->do_length () : 0;
00602 }
00603 
00604 int
00605 command_history::max_input_history (void)
00606 {
00607   return (instance_ok ())
00608     ? instance->do_max_input_history () : 0;
00609 }
00610 
00611 int
00612 command_history::base (void)
00613 {
00614   return (instance_ok ())
00615     ? instance->do_base () : 0;
00616 }
00617 
00618 int
00619 command_history::current_number (void)
00620 {
00621   return (instance_ok ())
00622     ? instance->do_current_number () : 0;
00623 }
00624 
00625 void
00626 command_history::stifle (int n)
00627 {
00628   if (instance_ok ())
00629     instance->do_stifle (n);
00630 }
00631 
00632 int
00633 command_history::unstifle (void)
00634 {
00635   return (instance_ok ())
00636     ? instance->do_unstifle () : 0;
00637 }
00638 
00639 int
00640 command_history::is_stifled (void)
00641 {
00642   return (instance_ok ())
00643     ? instance->do_is_stifled () : 0;
00644 }
00645 
00646 void
00647 command_history::set_mark (int n)
00648 {
00649   if (instance_ok ())
00650     instance->do_set_mark (n);
00651 }
00652 
00653 int
00654 command_history::goto_mark (void)
00655 {
00656   return (instance_ok ())
00657     ? instance->do_goto_mark () : 0;
00658 }
00659 
00660 void
00661 command_history::read (bool must_exist)
00662 {
00663   read (file (), must_exist);
00664 }
00665 
00666 void
00667 command_history::read (const std::string& f, bool must_exist)
00668 {
00669   if (instance_ok ())
00670     instance->do_read (f, must_exist);
00671 }
00672 
00673 void
00674 command_history::read_range (int from, int to, bool must_exist)
00675 {
00676   read_range (file (), from, to, must_exist);
00677 }
00678 
00679 void
00680 command_history::read_range (const std::string& f, int from, int to,
00681                              bool must_exist)
00682 {
00683   if (instance_ok ())
00684     instance->do_read_range (f, from, to, must_exist);
00685 }
00686 
00687 void
00688 command_history::write (const std::string& f)
00689 {
00690   if (instance_ok ())
00691     instance->do_write (f);
00692 }
00693 
00694 void
00695 command_history::append (const std::string& f)
00696 {
00697   if (instance_ok ())
00698     instance->do_append (f);
00699 }
00700 
00701 void
00702 command_history::truncate_file (const std::string& f, int n)
00703 {
00704   if (instance_ok ())
00705     instance->do_truncate_file (f, n);
00706 }
00707 
00708 string_vector
00709 command_history::list (int limit, bool number_lines)
00710 {
00711   return (instance_ok ())
00712     ? instance->do_list (limit, number_lines) : string_vector ();
00713 }
00714 
00715 std::string
00716 command_history::get_entry (int n)
00717 {
00718   return (instance_ok ())
00719     ? instance->do_get_entry (n) : std::string ();
00720 }
00721 
00722 void
00723 command_history::replace_entry (int which, const std::string& line)
00724 {
00725   if (instance_ok ())
00726     instance->do_replace_entry (which, line);
00727 }
00728 
00729 void
00730 command_history::clean_up_and_save (const std::string& f, int n)
00731 {
00732   if (instance_ok ())
00733     instance->do_clean_up_and_save (f, n);
00734 }
00735 
00736 void
00737 command_history::do_process_histcontrol (const std::string&)
00738 {
00739   (*current_liboctave_warning_handler)
00740     ("readline is not linked, so history control is not available");
00741 }
00742 
00743 void
00744 command_history::do_initialize (bool read_history_file,
00745                                 const std::string& f_arg, int sz,
00746                                 const std::string & control_arg)
00747 {
00748   command_history::set_file (f_arg);
00749   command_history::set_size (sz);
00750   command_history::process_histcontrol (control_arg);
00751 
00752   if (read_history_file)
00753     command_history::read (false);
00754 
00755   initialized = true;
00756 }
00757 
00758 bool
00759 command_history::do_is_initialized (void) const
00760 {
00761   return initialized;
00762 }
00763 
00764 void
00765 command_history::do_set_file (const std::string& f)
00766 {
00767   xfile = f;
00768 }
00769 
00770 std::string
00771 command_history::do_file (void)
00772 {
00773   return xfile;
00774 }
00775 
00776 void
00777 command_history::do_set_size (int n)
00778 {
00779   xsize = n;
00780 }
00781 
00782 int
00783 command_history::do_size (void) const
00784 {
00785   return xsize;
00786 }
00787 
00788 void
00789 command_history::do_ignore_entries (bool flag)
00790 {
00791   ignoring_additions = flag;
00792 }
00793 
00794 bool
00795 command_history::do_ignoring_entries (void) const
00796 {
00797   return ignoring_additions;
00798 }
00799 
00800 void
00801 command_history::do_add (const std::string&)
00802 {
00803 }
00804 
00805 void
00806 command_history::do_remove (int)
00807 {
00808 }
00809 
00810 int
00811 command_history::do_where (void) const
00812 {
00813   return 0;
00814 }
00815 
00816 int
00817 command_history::do_length (void) const
00818 {
00819   return 0;
00820 }
00821 
00822 int
00823 command_history::do_max_input_history (void) const
00824 {
00825   return 0;
00826 }
00827 
00828 int
00829 command_history::do_base (void) const
00830 {
00831   return 0;
00832 }
00833 
00834 int
00835 command_history::do_current_number (void) const
00836 {
00837   return (xsize > 0) ? do_base () + do_where () : -1;
00838 }
00839 
00840 void
00841 command_history::do_stifle (int)
00842 {
00843 }
00844 
00845 int
00846 command_history::do_unstifle (void)
00847 {
00848   return -1;
00849 }
00850 
00851 int
00852 command_history::do_is_stifled (void) const
00853 {
00854   return 0;
00855 }
00856 
00857 void
00858 command_history::do_set_mark (int)
00859 {
00860 }
00861 
00862 int
00863 command_history::do_goto_mark (void)
00864 {
00865   return 0;
00866 }
00867 
00868 void
00869 command_history::do_read (const std::string& f, bool)
00870 {
00871   if (f.empty ())
00872     error ("command_history::read: missing file name");
00873 }
00874 
00875 void
00876 command_history::do_read_range (const std::string& f, int, int, bool)
00877 {
00878   if (f.empty ())
00879     error ("command_history::read_range: missing file name");
00880 }
00881 
00882 void
00883 command_history::do_write (const std::string& f_arg) const
00884 {
00885   if (initialized)
00886     {
00887       std::string f = f_arg;
00888 
00889       if (f.empty ())
00890         f = xfile;
00891 
00892       if (f.empty ())
00893         error ("command_history::write: missing file name");
00894     }
00895 }
00896 
00897 void
00898 command_history::do_append (const std::string& f_arg)
00899 {
00900   if (initialized)
00901     {
00902       if (lines_this_session)
00903         {
00904           if (lines_this_session < do_where ())
00905             {
00906               // Create file if it doesn't already exist.
00907 
00908               std::string f = f_arg;
00909 
00910               if (f.empty ())
00911                 f = xfile;
00912 
00913               if (f.empty ())
00914                 error ("command_history::append: missing file name");
00915             }
00916         }
00917     }
00918 }
00919 
00920 void
00921 command_history::do_truncate_file (const std::string& f_arg, int) const
00922 {
00923   if (initialized)
00924     {
00925       std::string f = f_arg;
00926 
00927       if (f.empty ())
00928         f = xfile;
00929 
00930       if (f.empty ())
00931         error ("command_history::truncate_file: missing file name");
00932     }
00933 }
00934 
00935 string_vector
00936 command_history::do_list (int, bool) const
00937 {
00938   return string_vector ();
00939 }
00940 
00941 std::string
00942 command_history::do_get_entry (int) const
00943 {
00944   return std::string ();
00945 }
00946 
00947 void
00948 command_history::do_replace_entry (int, const std::string&)
00949 {
00950 }
00951 
00952 void
00953 command_history::do_clean_up_and_save (const std::string& f_arg, int)
00954 {
00955   if (initialized)
00956     {
00957       std::string f = f_arg;
00958 
00959       if (f.empty ())
00960         f = xfile;
00961 
00962       if (f.empty ())
00963         error ("command_history::clean_up_and_save: missing file name");
00964     }
00965 }
00966 
00967 void
00968 command_history::error (int err_num) const
00969 {
00970   (*current_liboctave_error_handler) ("%s", gnulib::strerror (err_num));
00971 }
00972 
00973 void
00974 command_history::error (const std::string& s) const
00975 {
00976   (*current_liboctave_error_handler) ("%s", s.c_str ());
00977 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines