GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
cmd-hist.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cstring>
28 
29 #include <iostream>
30 #include <sstream>
31 #include <string>
32 
33 #include "cmd-edit.h"
34 #include "cmd-hist.h"
35 #include "file-ops.h"
36 #include "lo-error.h"
37 #include "singleton-cleanup.h"
38 #include "str-vec.h"
39 
41 
42 #if defined (USE_READLINE)
43 
44 #include <cstdlib>
45 
46 #include <sys/types.h>
47 #include <unistd.h>
48 
49 #include <fcntl.h>
50 
51 #include "oct-rl-hist.h"
52 
53 #include "file-stat.h"
54 
55 class
56 gnu_history : public command_history
57 {
58 public:
59 
60  gnu_history (void)
61  : command_history (), mark (0) { }
62 
63  ~gnu_history (void) { }
64 
65  void do_process_histcontrol (const std::string&);
66 
67  std::string do_histcontrol (void) const;
68 
69  bool do_add (const std::string&);
70 
71  void do_remove (int);
72 
73  void do_clear (void);
74 
75  int do_where (void) const;
76 
77  int do_length (void) const;
78 
79  int do_max_input_history (void) const;
80 
81  int do_base (void) const;
82 
83  int do_current_number (void) const;
84 
85  void do_stifle (int);
86 
87  int do_unstifle (void);
88 
89  int do_is_stifled (void) const;
90 
91  void do_set_mark (int);
92 
93  int do_goto_mark (void);
94 
95  void do_read (const std::string&, bool);
96 
97  void do_read_range (const std::string&, int, int, bool);
98 
99  void do_write (const std::string&) const;
100 
101  void do_append (const std::string&);
102 
103  void do_truncate_file (const std::string&, int) const;
104 
105  string_vector do_list (int, bool) const;
106 
107  std::string do_get_entry (int) const;
108 
109  void do_replace_entry (int, const std::string&);
110 
111  void do_clean_up_and_save (const std::string&, int);
112 
113 private:
114 
115  int mark;
116 };
117 
118 void
119 gnu_history::do_process_histcontrol (const std::string& control_arg)
120 {
121  history_control = 0;
122 
123  size_t len = control_arg.length ();
124  size_t beg = 0;
125 
126  while (beg < len)
127  {
128  if (control_arg[beg] == ':')
129  beg++;
130  else
131  {
132  size_t end = control_arg.find (":", beg);
133 
134  if (end == std::string::npos)
135  end = len;
136 
137  std::string tmp = control_arg.substr (beg, end-beg);
138 
139  if (tmp == "erasedups")
140  history_control |= HC_ERASEDUPS;
141  else if (tmp == "ignoreboth")
142  history_control |= HC_IGNDUPS|HC_IGNSPACE;
143  else if (tmp == "ignoredups")
144  history_control |= HC_IGNDUPS;
145  else if (tmp == "ignorespace")
146  history_control |= HC_IGNSPACE;
147  else
149  ("unknown histcontrol directive %s", tmp.c_str ());
150 
151  if (end != std::string::npos)
152  beg = end + 1;
153  }
154  }
155 }
156 
157 std::string
158 gnu_history::do_histcontrol (void) const
159 {
160  // FIXME: instead of reconstructing this value, should we just save
161  // the string we were given when constructing the command_history object?
162 
163  std::string retval;
164 
165  if (history_control & HC_IGNSPACE)
166  retval.append ("ignorespace");
167 
168  if (history_control & HC_IGNDUPS)
169  {
170  if (retval.length () > 0)
171  retval.append (":");
172 
173  retval.append ("ignoredups");
174  }
175 
176  if (history_control & HC_ERASEDUPS)
177  {
178  if (retval.length () > 0)
179  retval.append (":");
180 
181  retval.append ("erasedups");
182  }
183 
184  return retval;
185 }
186 
187 bool
188 gnu_history::do_add (const std::string& s)
189 {
190  if (! do_ignoring_entries ())
191  {
192  if (s.empty ()
193  || (s.length () == 1 && (s[0] == '\r' || s[0] == '\n')))
194  return false;
195 
196  // Strip newline before adding to list
197  std::string stmp = s;
198  int stmp_len = stmp.length ();
199  if (stmp[stmp_len - 1] == '\n')
200  stmp.resize (stmp_len - 1);
201 
202  int added = ::octave_add_history (stmp.c_str (), history_control);
203  lines_this_session += added;
204  return (added > 0) ? true : false;
205  }
206  return false;
207 }
208 
209 void
210 gnu_history::do_remove (int n)
211 {
213 }
214 
215 void
216 gnu_history::do_clear (void)
217 {
219 }
220 
221 int
222 gnu_history::do_where (void) const
223 {
225 }
226 
227 int
228 gnu_history::do_length (void) const
229 {
231 }
232 
233 int
234 gnu_history::do_max_input_history (void) const
235 {
237 }
238 
239 int
240 gnu_history::do_base (void) const
241 {
243 }
244 
245 int
246 gnu_history::do_current_number (void) const
247 {
248  return (xsize > 0) ? do_base () + do_where () : -1;
249 }
250 
251 void
252 gnu_history::do_stifle (int n)
253 {
255 }
256 
257 int
258 gnu_history::do_unstifle (void)
259 {
261 }
262 
263 int
264 gnu_history::do_is_stifled (void) const
265 {
267 }
268 
269 void
270 gnu_history::do_set_mark (int n)
271 {
272  mark = n;
273 }
274 
275 int
276 gnu_history::do_goto_mark (void)
277 {
278  if (mark)
279  {
281 
282  if (line)
283  {
285 
287  }
288  }
289 
290  mark = 0;
291 
292  // FIXME: for operate_and_get_next.
294 
295  return 0;
296 }
297 
298 void
299 gnu_history::do_read (const std::string& f, bool must_exist)
300 {
301  if (! f.empty ())
302  {
303  int status = ::octave_read_history (f.c_str ());
304 
305  if (status != 0 && must_exist)
306  {
307  std::string msg = "reading file '" + f + "'";
308 
309  error (status, msg);
310  }
311  else
312  {
313  lines_in_file = do_where ();
314 
316  }
317  }
318  else
319  error ("gnu_history::read: missing file name");
320 }
321 
322 void
323 gnu_history::do_read_range (const std::string& f, int from, int to,
324  bool must_exist)
325 {
326  if (from < 0)
327  from = lines_in_file;
328 
329  if (! f.empty ())
330  {
331  int status = ::octave_read_history_range (f.c_str (), from, to);
332 
333  if (status != 0 && must_exist)
334  {
335  std::ostringstream buf;
336  buf << "reading lines " << from << " to " << to
337  << " from file '" << f << "'";
338 
339  error (status, buf.str ());
340  }
341  else
342  {
343  lines_in_file = do_where ();
344 
346  }
347  }
348  else
349  error ("gnu_history::read_range: missing file name");
350 }
351 
352 void
353 gnu_history::do_write (const std::string& f_arg) const
354 {
355  if (initialized)
356  {
357  std::string f = f_arg;
358 
359  if (f.empty ())
360  f = xfile;
361 
362  if (! f.empty ())
363  {
364  int status = ::octave_write_history (f.c_str ());
365 
366  if (status != 0)
367  {
368  std::string msg = "writing file '" + f + "'";
369 
370  error (status, msg);
371  }
372  }
373  else
374  error ("gnu_history::write: missing file name");
375  }
376 }
377 
378 void
379 gnu_history::do_append (const std::string& f_arg)
380 {
381  if (initialized)
382  {
383  if (lines_this_session)
384  {
385  if (lines_this_session < do_where ())
386  {
387  // Create file if it doesn't already exist.
388 
389  std::string f = f_arg;
390 
391  if (f.empty ())
392  f = xfile;
393 
394  if (! f.empty ())
395  {
396  file_stat fs (f);
397 
398  if (! fs)
399  {
400  int tem;
401 
402  tem = gnulib::open (f.c_str (), O_CREAT, 0666);
403  gnulib::close (tem);
404  }
405 
406  int status
407  = ::octave_append_history (lines_this_session, f.c_str ());
408 
409  if (status != 0)
410  {
411  std::string msg = "appending to file '" + f_arg + "'";
412 
413  error (status, msg);
414  }
415  else
416  lines_in_file += lines_this_session;
417 
418  lines_this_session = 0;
419  }
420  else
421  error ("gnu_history::append: missing file name");
422  }
423  }
424  }
425 }
426 
427 void
428 gnu_history::do_truncate_file (const std::string& f_arg, int n) const
429 {
430  if (initialized)
431  {
432  std::string f = f_arg;
433 
434  if (f.empty ())
435  f = xfile;
436 
437  if (! f.empty ())
438  ::octave_history_truncate_file (f.c_str (), n);
439  else
440  error ("gnu_history::truncate_file: missing file name");
441  }
442 }
443 
445 gnu_history::do_list (int limit, bool number_lines) const
446 {
447  string_vector retval;
448 
449  if (limit)
450  retval = ::octave_history_list (limit, number_lines);
451 
452  return retval;
453 }
454 
455 std::string
456 gnu_history::do_get_entry (int n) const
457 {
458  std::string retval;
459 
460  char *line = ::octave_history_get (do_base () + n);
461 
462  if (line)
463  retval = line;
464 
465  return retval;
466 }
467 
468 void
469 gnu_history::do_replace_entry (int which, const std::string& line)
470 {
471  ::octave_replace_history_entry (which, line.c_str ());
472 }
473 
474 void
475 gnu_history::do_clean_up_and_save (const std::string& f_arg, int n)
476 {
477  if (initialized)
478  {
479  std::string f = f_arg;
480 
481  if (f.empty ())
482  f = xfile;
483 
484  if (! f.empty ())
485  {
486  if (n < 0)
487  n = xsize;
488 
489  stifle (n);
490 
491  do_write (f.c_str ());
492  }
493  else
494  error ("gnu_history::clean_up_and_save: missing file name");
495  }
496 }
497 
498 #endif
499 
500 bool
502 {
503  bool retval = true;
504 
505  if (! instance)
506  {
508 
509  if (instance)
511  }
512 
513  if (! instance)
514  {
515  (*current_liboctave_error_handler)
516  ("unable to create command history object!");
517 
518  retval = false;
519  }
520 
521  return retval;
522 }
523 
524 void
526 {
527 #if defined (USE_READLINE)
528  instance = new gnu_history ();
529 #else
530  instance = new command_history ();
531 #endif
532 }
533 
534 void
536  const std::string& f_arg, int sz,
537  const std::string & control_arg)
538 {
539  if (instance_ok ())
540  instance->do_initialize (read_history_file, f_arg, sz, control_arg);
541 }
542 
543 bool
545 {
546  // We just want to check the status of an existing instance, not
547  // create one.
548  return instance && instance->do_is_initialized ();
549 }
550 
551 void
552 command_history::set_file (const std::string& f_arg)
553 {
554  if (instance_ok ())
555  {
556  std::string f = file_ops::tilde_expand (f_arg);
557 
558  instance->do_set_file (f);
559  }
560 }
561 
562 std::string
564 {
565  return (instance_ok ())
566  ? instance->do_file () : std::string ();
567 }
568 
569 void
570 command_history::process_histcontrol (const std::string& control_arg)
571 {
572  if (instance_ok ())
573  instance->do_process_histcontrol (control_arg);
574 }
575 
576 std::string
578 {
579  return (instance_ok ())
580  ? instance->do_histcontrol () : std::string ();
581 }
582 
583 void
585 {
586  if (instance_ok ())
587  instance->do_set_size (n);
588 }
589 
590 int
592 {
593  return (instance_ok ())
594  ? instance->do_size () : 0;
595 }
596 
597 void
599 {
600  if (instance_ok ())
601  instance->do_ignore_entries (flag);
602 }
603 
604 bool
606 {
607  return (instance_ok ())
608  ? instance->do_ignoring_entries () : false;
609 }
610 
611 bool
612 command_history::add (const std::string& s)
613 {
614  if (instance_ok ())
615  return instance->do_add (s);
616  return false;
617 }
618 
619 void
621 {
622  if (instance_ok ())
623  instance->do_remove (n);
624 }
625 
626 void
628 {
629  if (instance_ok ())
630  instance->do_clear ();
631 }
632 
633 int
635 {
636  return (instance_ok ())
637  ? instance->do_where () : 0;
638 }
639 
640 int
642 {
643  return (instance_ok ())
644  ? instance->do_length () : 0;
645 }
646 
647 int
649 {
650  return (instance_ok ())
651  ? instance->do_max_input_history () : 0;
652 }
653 
654 int
656 {
657  return (instance_ok ())
658  ? instance->do_base () : 0;
659 }
660 
661 int
663 {
664  return (instance_ok ())
665  ? instance->do_current_number () : 0;
666 }
667 
668 void
670 {
671  if (instance_ok ())
672  instance->do_stifle (n);
673 }
674 
675 int
677 {
678  return (instance_ok ())
679  ? instance->do_unstifle () : 0;
680 }
681 
682 int
684 {
685  return (instance_ok ())
686  ? instance->do_is_stifled () : 0;
687 }
688 
689 void
691 {
692  if (instance_ok ())
693  instance->do_set_mark (n);
694 }
695 
696 int
698 {
699  return (instance_ok ())
700  ? instance->do_goto_mark () : 0;
701 }
702 
703 void
704 command_history::read (bool must_exist)
705 {
706  read (file (), must_exist);
707 }
708 
709 void
710 command_history::read (const std::string& f, bool must_exist)
711 {
712  if (instance_ok ())
713  instance->do_read (f, must_exist);
714 }
715 
716 void
717 command_history::read_range (int from, int to, bool must_exist)
718 {
719  read_range (file (), from, to, must_exist);
720 }
721 
722 void
723 command_history::read_range (const std::string& f, int from, int to,
724  bool must_exist)
725 {
726  if (instance_ok ())
727  instance->do_read_range (f, from, to, must_exist);
728 }
729 
730 void
731 command_history::write (const std::string& f)
732 {
733  if (instance_ok ())
734  instance->do_write (f);
735 }
736 
737 void
738 command_history::append (const std::string& f)
739 {
740  if (instance_ok ())
741  instance->do_append (f);
742 }
743 
744 void
745 command_history::truncate_file (const std::string& f, int n)
746 {
747  if (instance_ok ())
748  instance->do_truncate_file (f, n);
749 }
750 
752 command_history::list (int limit, bool number_lines)
753 {
754  return (instance_ok ())
755  ? instance->do_list (limit, number_lines) : string_vector ();
756 }
757 
758 std::string
760 {
761  return (instance_ok ())
762  ? instance->do_get_entry (n) : std::string ();
763 }
764 
765 void
766 command_history::replace_entry (int which, const std::string& line)
767 {
768  if (instance_ok ())
769  instance->do_replace_entry (which, line);
770 }
771 
772 void
773 command_history::clean_up_and_save (const std::string& f, int n)
774 {
775  if (instance_ok ())
777 }
778 
779 void
781 {
782  (*current_liboctave_warning_handler)
783  ("readline is not linked, so history control is not available");
784 }
785 
786 void
788  const std::string& f_arg, int sz,
789  const std::string & control_arg)
790 {
794 
795  if (read_history_file)
796  command_history::read (false);
797 
798  initialized = true;
799 }
800 
801 bool
803 {
804  return initialized;
805 }
806 
807 void
808 command_history::do_set_file (const std::string& f)
809 {
810  xfile = f;
811 }
812 
813 std::string
815 {
816  return xfile;
817 }
818 
819 void
821 {
822  xsize = n;
823 }
824 
825 int
827 {
828  return xsize;
829 }
830 
831 void
833 {
834  ignoring_additions = flag;
835 }
836 
837 bool
839 {
840  return ignoring_additions;
841 }
842 
843 bool
844 command_history::do_add (const std::string&)
845 {
846  return false;
847 }
848 
849 void
851 {
852 }
853 
854 void
856 {
857 }
858 
859 int
861 {
862  return 0;
863 }
864 
865 int
867 {
868  return 0;
869 }
870 
871 int
873 {
874  return 0;
875 }
876 
877 int
879 {
880  return 0;
881 }
882 
883 int
885 {
886  return (xsize > 0) ? do_base () + do_where () : -1;
887 }
888 
889 void
891 {
892 }
893 
894 int
896 {
897  return -1;
898 }
899 
900 int
902 {
903  return 0;
904 }
905 
906 void
908 {
909 }
910 
911 int
913 {
914  return 0;
915 }
916 
917 void
918 command_history::do_read (const std::string& f, bool)
919 {
920  if (f.empty ())
921  error ("command_history::read: missing file name");
922 }
923 
924 void
925 command_history::do_read_range (const std::string& f, int, int, bool)
926 {
927  if (f.empty ())
928  error ("command_history::read_range: missing file name");
929 }
930 
931 void
932 command_history::do_write (const std::string& f_arg) const
933 {
934  if (initialized)
935  {
936  std::string f = f_arg;
937 
938  if (f.empty ())
939  f = xfile;
940 
941  if (f.empty ())
942  error ("command_history::write: missing file name");
943  }
944 }
945 
946 void
947 command_history::do_append (const std::string& f_arg)
948 {
949  if (initialized)
950  {
951  if (lines_this_session)
952  {
953  if (lines_this_session < do_where ())
954  {
955  // Create file if it doesn't already exist.
956 
957  std::string f = f_arg;
958 
959  if (f.empty ())
960  f = xfile;
961 
962  if (f.empty ())
963  error ("command_history::append: missing file name");
964  }
965  }
966  }
967 }
968 
969 void
970 command_history::do_truncate_file (const std::string& f_arg, int) const
971 {
972  if (initialized)
973  {
974  std::string f = f_arg;
975 
976  if (f.empty ())
977  f = xfile;
978 
979  if (f.empty ())
980  error ("command_history::truncate_file: missing file name");
981  }
982 }
983 
985 command_history::do_list (int, bool) const
986 {
987  return string_vector ();
988 }
989 
990 std::string
992 {
993  return std::string ();
994 }
995 
996 void
997 command_history::do_replace_entry (int, const std::string&)
998 {
999 }
1000 
1001 void
1002 command_history::do_clean_up_and_save (const std::string& f_arg, int)
1003 {
1004  if (initialized)
1005  {
1006  std::string f = f_arg;
1007 
1008  if (f.empty ())
1009  f = xfile;
1010 
1011  if (f.empty ())
1012  error ("command_history::clean_up_and_save: missing file name");
1013  }
1014 }
1015 
1016 void
1017 command_history::error (int err_num, const std::string& msg) const
1018 {
1019  if (msg.empty ())
1020  (*current_liboctave_error_handler) ("%s", gnulib::strerror (err_num));
1021  else
1022  (*current_liboctave_error_handler) ("%s: %s", msg.c_str (),
1023  gnulib::strerror (err_num));
1024 }
1025 
1026 void
1027 command_history::error (const std::string& s) const
1028 {
1029  (*current_liboctave_error_handler) ("%s", s.c_str ());
1030 }