00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00158
00159
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
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
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
00512
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
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 }