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