GNU Octave  4.2.1
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
pager.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-2017 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 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <fstream>
28 #include <iostream>
29 #include <string>
30 
31 #include "cmd-edit.h"
32 #include "oct-env.h"
33 #include "oct-syscalls.h"
34 #include "singleton-cleanup.h"
35 
36 #include "defaults.h"
37 #include "defun.h"
38 #include "error.h"
39 #include "errwarn.h"
40 #include "input.h"
41 #include "octave.h"
42 #include "ovl.h"
43 #include "pager.h"
44 #include "procstream.h"
45 #include "sighandlers.h"
46 #include "unwind-prot.h"
47 #include "utils.h"
48 #include "variables.h"
49 
50 // Our actual connection to the external pager.
52 
53 // TRUE means we write to the diary file.
54 static bool write_to_diary_file = false;
55 
56 // The name of the current diary file.
57 static std::string diary_file ("diary");
58 
59 // The diary file.
60 static std::ofstream external_diary_file;
61 
62 static std::string
64 {
65  std::string pager_binary = octave::sys::env::getenv ("PAGER");
66 
67 #if defined (OCTAVE_DEFAULT_PAGER)
68  if (pager_binary.empty ())
69  pager_binary = OCTAVE_DEFAULT_PAGER;
70 #endif
71 
72  return pager_binary;
73 }
74 
75 // The shell command to run as the pager.
77 
78 // The options to pass to the pager.
80 
81 // TRUE means that if output is going to the pager, it is sent as soon
82 // as it is available. Otherwise, it is buffered and only sent to the
83 // pager when it is time to print another prompt.
84 static bool Vpage_output_immediately = false;
85 
86 // TRUE means all output intended for the screen should be passed
87 // through the pager.
88 static bool Vpage_screen_output = true;
89 
90 static bool really_flush_to_pager = false;
91 
92 static bool flushing_output_to_pager = false;
93 
94 static void
96 {
97  if (external_pager)
98  {
99  octave::child_list::remove (external_pager->pid ());
100 
101  delete external_pager;
102  external_pager = 0;
103  }
104 }
105 
106 static bool
107 pager_event_handler (pid_t pid, int status)
108 {
109  bool retval = false;
110 
111  if (pid > 0)
112  {
113  if (octave::sys::wifexited (status) || octave::sys::wifsignaled (status))
114  {
115  // Avoid warning() since that will put us back in the pager,
116  // which would be bad news.
117 
118  std::cerr << "warning: connection to external pager lost (pid = "
119  << pid << ")" << std::endl;
120  std::cerr << "warning: flushing pending output (please wait)"
121  << std::endl;
122 
123  // Request removal of this PID from the list of child
124  // processes.
125 
126  retval = true;
127  }
128  }
129 
130  return retval;
131 }
132 
133 static std::string
135 {
136  std::string cmd = VPAGER;
137 
138  if (! (cmd.empty () || VPAGER_FLAGS.empty ()))
139  cmd += " " + VPAGER_FLAGS;
140 
141  return cmd;
142 }
143 
144 static void
145 do_sync (const char *msg, int len, bool bypass_pager)
146 {
147  if (msg && len > 0)
148  {
149  if (bypass_pager)
150  {
151  std::cout.write (msg, len);
152  std::cout.flush ();
153  }
154  else
155  {
156  if (! external_pager)
157  {
158  std::string pgr = pager_command ();
159 
160  if (! pgr.empty ())
161  {
162  external_pager = new oprocstream (pgr.c_str ());
163 
164  if (external_pager)
165  octave::child_list::insert (external_pager->pid (),
167  }
168  }
169 
170  if (external_pager)
171  {
172  if (external_pager->good ())
173  {
174  external_pager->write (msg, len);
175 
176  external_pager->flush ();
177 
178 #if defined (EPIPE)
179  if (errno == EPIPE)
180  external_pager->setstate (std::ios::failbit);
181 #endif
182  }
183  else
184  {
185  // FIXME: omething is not right with the
186  // pager. If it died then we should receive a
187  // signal for that. If there is some other problem,
188  // then what?
189  }
190  }
191  else
192  {
193  std::cout.write (msg, len);
194  std::cout.flush ();
195  }
196  }
197  }
198 }
199 
200 // Assume our terminal wraps long lines.
201 
202 static bool
203 more_than_a_screenful (const char *s, int len)
204 {
205  if (s)
206  {
207  int available_rows = octave::command_editor::terminal_rows () - 2;
208 
210 
211  int count = 0;
212 
213  int chars_this_line = 0;
214 
215  for (int i = 0; i < len; i++)
216  {
217  if (*s++ == '\n')
218  {
219  count += chars_this_line / cols + 1;
220  chars_this_line = 0;
221  }
222  else
223  chars_this_line++;
224  }
225 
226  if (count > available_rows)
227  return true;
228  }
229 
230  return false;
231 }
232 
233 int
235 {
236  if (! octave::application::interactive ()
237  || octave::application::forced_interactive ()
238  || really_flush_to_pager
239  || (Vpage_screen_output && Vpage_output_immediately)
240  || ! Vpage_screen_output)
241  {
242  char *buf = eback ();
243 
244  int len = pptr () - buf;
245 
246  bool bypass_pager = (! octave::application::interactive ()
247  || octave::application::forced_interactive ()
248  || ! Vpage_screen_output
249  || (really_flush_to_pager
250  && Vpage_screen_output
251  && ! Vpage_output_immediately
252  && ! more_than_a_screenful (buf, len)));
253 
254  if (len > 0)
255  {
256  do_sync (buf, len, bypass_pager);
257 
259 
260  seekoff (0, std::ios::beg);
261  }
262  }
263 
264  return 0;
265 }
266 
267 void
269 {
270  char *buf = eback () + diary_skip;
271 
272  size_t len = pptr () - buf;
273 
274  octave_diary.write (buf, len);
275 
276  diary_skip = 0;
277 }
278 
279 void
281 {
282  diary_skip = pptr () - eback ();
283 }
284 
285 int
287 {
288  if (write_to_diary_file && external_diary_file)
289  {
290  char *buf = eback ();
291 
292  int len = pptr () - buf;
293 
294  if (len > 0)
295  external_diary_file.write (buf, len);
296  }
297 
298  seekoff (0, std::ios::beg);
299 
300  return 0;
301 }
302 
304 
305 octave_pager_stream::octave_pager_stream (void) : std::ostream (0), pb (0)
306 {
307  pb = new octave_pager_buf ();
308  rdbuf (pb);
309  setf (unitbuf);
310 }
311 
313 {
314  flush ();
315  delete pb;
316 }
317 
318 std::ostream&
320 {
321  return instance_ok () ? *instance : std::cout;
322 }
323 
324 void
326 {
327  if (instance_ok ())
329 }
330 
331 void
333 {
334  if (instance_ok ())
336 }
337 
338 // Reinitialize the pager buffer to avoid hanging on to large internal
339 // buffers when they might not be needed. This function should only be
340 // called when the pager is not in use. For example, just before
341 // getting command-line input.
342 
343 void
345 {
346  if (instance_ok ())
347  instance->do_reset ();
348 }
349 
350 void
352 {
353  if (pb)
355 }
356 
357 void
359 {
360  if (pb)
361  pb->set_diary_skip ();
362 }
363 
364 void
366 {
367  delete pb;
368  pb = new octave_pager_buf ();
369  rdbuf (pb);
370  setf (unitbuf);
371 }
372 
373 bool
375 {
376  bool retval = true;
377 
378  if (! instance)
379  {
380  instance = new octave_pager_stream ();
381 
382  if (instance)
384  }
385 
386  if (! instance)
387  error ("unable to create pager_stream object!");
388 
389  return retval;
390 }
391 
393 
394 octave_diary_stream::octave_diary_stream (void) : std::ostream (0), db (0)
395 {
396  db = new octave_diary_buf ();
397  rdbuf (db);
398  setf (unitbuf);
399 }
400 
402 {
403  flush ();
404  delete db;
405 }
406 
407 std::ostream&
409 {
410  return instance_ok () ? *instance : std::cout;
411 }
412 
413 // Reinitialize the diary buffer to avoid hanging on to large internal
414 // buffers when they might not be needed. This function should only be
415 // called when the pager is not in use. For example, just before
416 // getting command-line input.
417 
418 void
420 {
421  if (instance_ok ())
422  instance->do_reset ();
423 }
424 
425 void
427 {
428  delete db;
429  db = new octave_diary_buf ();
430  rdbuf (db);
431  setf (unitbuf);
432 }
433 
434 bool
436 {
437  bool retval = true;
438 
439  if (! instance)
440  {
441  instance = new octave_diary_stream ();
442 
443  if (instance)
445  }
446 
447  if (! instance)
448  error ("unable to create diary_stream object!");
449 
450  return retval;
451 }
452 
453 void
455 {
456  if (! flushing_output_to_pager)
457  {
459 
460  frame.protect_var (really_flush_to_pager);
461  frame.protect_var (flushing_output_to_pager);
462 
463  really_flush_to_pager = true;
464  flushing_output_to_pager = true;
465 
466  octave_stdout.flush ();
467 
469  }
470 }
471 
472 static void
474 {
475  // Try to flush the current buffer to the diary now, so that things
476  // like
477  //
478  // function foo ()
479  // diary on;
480  // ...
481  // diary off;
482  // endfunction
483  //
484  // will do the right thing.
485 
487 
488  if (external_diary_file.is_open ())
489  {
490  octave_diary.flush ();
491  external_diary_file.close ();
492  }
493 }
494 
495 static void
497 {
498  close_diary_file ();
499 
500  // If there is pending output in the pager buf, it should not go
501  // into the diary file.
502 
504 
505  external_diary_file.open (diary_file.c_str (), std::ios::app);
506 
507  if (! external_diary_file)
508  error ("diary: can't open diary file '%s'", diary_file.c_str ());
509 }
510 
511 DEFUN (diary, args, ,
512  doc: /* -*- texinfo -*-
513 @deftypefn {} {} diary
514 @deftypefnx {} {} diary on
515 @deftypefnx {} {} diary off
516 @deftypefnx {} {} diary @var{filename}
517 Record a list of all commands @emph{and} the output they produce, mixed
518 together just as they appear on the terminal.
519 
520 Valid options are:
521 
522 @table @asis
523 @item on
524 Start recording a session in a file called @file{diary} in the
525 current working directory.
526 
527 @item off
528 Stop recording the session in the diary file.
529 
530 @item @var{filename}
531 Record the session in the file named @var{filename}.
532 @end table
533 
534 With no arguments, @code{diary} toggles the current diary state.
535 @seealso{history, evalc}
536 @end deftypefn */)
537 {
538  int nargin = args.length ();
539 
540  if (nargin > 1)
541  print_usage ();
542 
543  if (diary_file.empty ())
544  diary_file = "diary";
545 
546  if (nargin == 0)
547  {
548  write_to_diary_file = ! write_to_diary_file;
549  open_diary_file ();
550  }
551  else
552  {
553  std::string arg = args(0).xstring_value ("diary: argument must be a string");
554 
555  if (arg == "on")
556  {
557  write_to_diary_file = true;
558  open_diary_file ();
559  }
560  else if (arg == "off")
561  {
562  close_diary_file ();
563  write_to_diary_file = false;
564  }
565  else
566  {
567  diary_file = arg;
568  write_to_diary_file = true;
569  open_diary_file ();
570  }
571  }
572 
573  return ovl ();
574 }
575 
576 DEFUN (__diaryfile__, , ,
577  doc: /* -*- texinfo -*-
578 @deftypefn {} {@var{fname} =} __diaryfile__ ()
579 Undocumented internal function
580 @end deftypefn */)
581 {
582  return ovl (diary_file);
583 }
584 
585 DEFUN (__diarystate__, , ,
586  doc: /* -*- texinfo -*-
587 @deftypefn {} {@var{state} =} __diarystate__ ()
588 Undocumented internal function
589 @end deftypefn */)
590 {
591  return ovl (write_to_diary_file);
592 }
593 
594 DEFUN (more, args, ,
595  doc: /* -*- texinfo -*-
596 @deftypefn {} {} more
597 @deftypefnx {} {} more on
598 @deftypefnx {} {} more off
599 Turn output pagination on or off.
600 
601 Without an argument, @code{more} toggles the current state.
602 
603 The current state can be determined via @code{page_screen_output}.
604 @seealso{page_screen_output, page_output_immediately, PAGER, PAGER_FLAGS}
605 @end deftypefn */)
606 {
607  int nargin = args.length ();
608 
609  if (nargin > 1)
610  print_usage ();
611 
612  if (nargin > 0)
613  {
614  std::string arg = args(0).xstring_value ("more: argument must be string \"on\" or \"off\"");
615 
616  if (arg == "on")
617  Vpage_screen_output = true;
618  else if (arg == "off")
619  Vpage_screen_output = false;
620  else
621  error ("more: argument must be \"on\" or \"off\"");
622  }
623  else
624  Vpage_screen_output = ! Vpage_screen_output;
625 
626  return ovl ();
627 }
628 
629 DEFUN (terminal_size, , ,
630  doc: /* -*- texinfo -*-
631 @deftypefn {} {} terminal_size ()
632 Return a two-element row vector containing the current size of the terminal
633 window in characters (rows and columns).
634 @seealso{list_in_columns}
635 @end deftypefn */)
636 {
637  RowVector size (2, 0.0);
638 
641 
642  return ovl (size);
643 }
644 
645 DEFUN (page_output_immediately, args, nargout,
646  doc: /* -*- texinfo -*-
647 @deftypefn {} {@var{val} =} page_output_immediately ()
648 @deftypefnx {} {@var{old_val} =} page_output_immediately (@var{new_val})
649 @deftypefnx {} {} page_output_immediately (@var{new_val}, "local")
650 Query or set the internal variable that controls whether Octave sends
651 output to the pager as soon as it is available.
652 
653 Otherwise, Octave buffers its output and waits until just before the prompt
654 is printed to flush it to the pager.
655 
656 When called from inside a function with the @qcode{"local"} option, the
657 variable is changed locally for the function and any subroutines it calls.
658 The original variable value is restored when exiting the function.
659 @seealso{page_screen_output, more, PAGER, PAGER_FLAGS}
660 @end deftypefn */)
661 {
662  return SET_INTERNAL_VARIABLE (page_output_immediately);
663 }
664 
665 DEFUN (page_screen_output, args, nargout,
666  doc: /* -*- texinfo -*-
667 @deftypefn {} {@var{val} =} page_screen_output ()
668 @deftypefnx {} {@var{old_val} =} page_screen_output (@var{new_val})
669 @deftypefnx {} {} page_screen_output (@var{new_val}, "local")
670 Query or set the internal variable that controls whether output intended
671 for the terminal window that is longer than one page is sent through a
672 pager.
673 
674 This allows you to view one screenful at a time. Some pagers
675 (such as @code{less}---see @ref{Installation}) are also capable of moving
676 backward on the output.
677 
678 When called from inside a function with the @qcode{"local"} option, the
679 variable is changed locally for the function and any subroutines it calls.
680 The original variable value is restored when exiting the function.
681 @seealso{more, page_output_immediately, PAGER, PAGER_FLAGS}
682 @end deftypefn */)
683 {
684  return SET_INTERNAL_VARIABLE (page_screen_output);
685 }
686 
687 DEFUN (PAGER, args, nargout,
688  doc: /* -*- texinfo -*-
689 @deftypefn {} {@var{val} =} PAGER ()
690 @deftypefnx {} {@var{old_val} =} PAGER (@var{new_val})
691 @deftypefnx {} {} PAGER (@var{new_val}, "local")
692 Query or set the internal variable that specifies the program to use
693 to display terminal output on your system.
694 
695 The default value is normally @qcode{"less"}, @qcode{"more"}, or
696 @qcode{"pg"}, depending on what programs are installed on your system.
697 @xref{Installation}.
698 
699 When called from inside a function with the @qcode{"local"} option, the
700 variable is changed locally for the function and any subroutines it calls.
701 The original variable value is restored when exiting the function.
702 @seealso{PAGER_FLAGS, page_output_immediately, more, page_screen_output}
703 @end deftypefn */)
704 {
706 }
707 
708 DEFUN (PAGER_FLAGS, args, nargout,
709  doc: /* -*- texinfo -*-
710 @deftypefn {} {@var{val} =} PAGER_FLAGS ()
711 @deftypefnx {} {@var{old_val} =} PAGER_FLAGS (@var{new_val})
712 @deftypefnx {} {} PAGER_FLAGS (@var{new_val}, "local")
713 Query or set the internal variable that specifies the options to pass
714 to the pager.
715 
716 When called from inside a function with the @qcode{"local"} option, the
717 variable is changed locally for the function and any subroutines it calls.
718 The original variable value is restored when exiting the function.
719 @seealso{PAGER, more, page_screen_output, page_output_immediately}
720 @end deftypefn */)
721 {
722  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (PAGER_FLAGS);
723 }
static void close_diary_file(void)
Definition: pager.cc:473
void flush_octave_stdout(void)
Definition: pager.cc:454
void do_reset(void)
Definition: pager.cc:426
static void reset(void)
Definition: pager.cc:344
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
static bool pager_event_handler(pid_t pid, int status)
Definition: pager.cc:107
static std::ostream & stream(void)
Definition: pager.cc:319
static bool instance_ok(void)
Definition: pager.cc:435
static bool really_flush_to_pager
Definition: pager.cc:90
void protect_var(T &var)
static void remove(pid_t pid)
Definition: child-list.cc:91
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
static void clear_external_pager(void)
Definition: pager.cc:95
size_t diary_skip
Definition: pager.h:52
#define SET_INTERNAL_VARIABLE(NM)
Definition: variables.h:126
STL namespace.
int sync(void)
Definition: pager.cc:286
#define octave_diary
Definition: pager.h:148
s
Definition: file-io.cc:2682
static bool instance_ok(void)
Definition: pager.cc:374
static void cleanup_instance(void)
Definition: pager.h:135
void set_diary_skip(void)
Definition: pager.cc:280
octave_value arg
Definition: pr-output.cc:3440
static void do_sync(const char *msg, int len, bool bypass_pager)
Definition: pager.cc:145
static std::string getenv(const std::string &name)
Definition: oct-env.cc:235
void do_set_diary_skip(void)
Definition: pager.cc:358
static octave_diary_stream * instance
Definition: pager.h:131
static std::string VPAGER
Definition: pager.cc:76
JNIEnv void * args
Definition: ov-java.cc:67
bool wifsignaled(int status)
octave_pager_buf * pb
Definition: pager.h:89
static int terminal_rows(void)
Definition: cmd-edit.cc:1223
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
#define OCTAVE_DEFAULT_PAGER
Definition: defaults.h:38
~octave_diary_stream(void)
Definition: pager.cc:401
static void add(fptr f)
static void flush_current_contents_to_diary(void)
Definition: pager.cc:325
int nargin
Definition: graphics.cc:10115
static bool Vpage_output_immediately
Definition: pager.cc:84
void do_flush_current_contents_to_diary(void)
Definition: pager.cc:351
static void reset(void)
Definition: pager.cc:419
static bool write_to_diary_file
Definition: pager.cc:54
octave_value retval
Definition: data.cc:6294
octave_pager_stream(void)
Definition: pager.cc:305
static octave_pager_stream * instance
Definition: pager.h:83
static bool more_than_a_screenful(const char *s, int len)
Definition: pager.cc:203
#define SET_NONEMPTY_INTERNAL_STRING_VARIABLE(NM)
Definition: variables.h:129
bool wifexited(int status)
static std::string VPAGER_FLAGS
Definition: pager.cc:79
static void insert(pid_t pid, child::child_event_handler f)
Definition: child-list.cc:58
void flush_current_contents_to_diary(void)
Definition: pager.cc:268
static std::string pager_command(void)
Definition: pager.cc:134
octave::unwind_protect frame
Definition: graphics.cc:11584
pid_t pid(void) const
Definition: procstream.h:59
#define octave_stdout
Definition: pager.h:146
static void open_diary_file(void)
Definition: pager.cc:496
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
static std::string default_pager(void)
Definition: pager.cc:63
static std::string diary_file("diary")
~octave_pager_stream(void)
Definition: pager.cc:312
static void cleanup_instance(void)
Definition: pager.h:87
static void set_diary_skip(void)
Definition: pager.cc:332
octave_diary_buf * db
Definition: pager.h:137
void do_reset(void)
Definition: pager.cc:365
static int terminal_cols(void)
Definition: cmd-edit.cc:1230
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable or any other valid Octave code The number of return their size
Definition: input.cc:871
static std::ofstream external_diary_file
Definition: pager.cc:60
static bool flushing_output_to_pager
Definition: pager.cc:92
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
static bool Vpage_screen_output
Definition: pager.cc:88
static std::ostream & stream(void)
Definition: pager.cc:408
int sync(void)
Definition: pager.cc:234
octave_diary_stream(void)
Definition: pager.cc:394
static oprocstream * external_pager
Definition: pager.cc:51