Mercurial > octave
comparison libinterp/corefcn/pager.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
comparison
equal
deleted
inserted
replaced
31605:e88a07dec498 | 31607:aac27ad79be6 |
---|---|
52 #include "utils.h" | 52 #include "utils.h" |
53 #include "variables.h" | 53 #include "variables.h" |
54 | 54 |
55 OCTAVE_BEGIN_NAMESPACE(octave) | 55 OCTAVE_BEGIN_NAMESPACE(octave) |
56 | 56 |
57 static bool | 57 static bool |
58 pager_event_handler (pid_t pid, int status) | 58 pager_event_handler (pid_t pid, int status) |
59 { | 59 { |
60 bool retval = false; | 60 bool retval = false; |
61 | 61 |
62 if (pid > 0) | 62 if (pid > 0) |
63 { | 63 { |
64 if (sys::wifexited (status) || sys::wifsignaled (status)) | 64 if (sys::wifexited (status) || sys::wifsignaled (status)) |
65 { | 65 { |
66 // Avoid warning() since that will put us back in the pager, | 66 // Avoid warning() since that will put us back in the pager, |
67 // which would be bad news. | 67 // which would be bad news. |
68 | 68 |
69 std::cerr << "warning: connection to external pager lost (pid = " | 69 std::cerr << "warning: connection to external pager lost (pid = " |
70 << pid << ')' << std::endl; | 70 << pid << ')' << std::endl; |
71 std::cerr << "warning: flushing pending output (please wait)" | 71 std::cerr << "warning: flushing pending output (please wait)" |
72 << std::endl; | 72 << std::endl; |
73 | 73 |
74 // Request removal of this PID from the list of child | 74 // Request removal of this PID from the list of child |
75 // processes. | 75 // processes. |
76 | 76 |
77 retval = true; | 77 retval = true; |
78 } | 78 } |
79 } | 79 } |
80 | 80 |
81 return retval; | 81 return retval; |
82 } | 82 } |
83 | 83 |
84 // Assume our terminal wraps long lines. | 84 // Assume our terminal wraps long lines. |
85 | 85 |
86 static bool | 86 static bool |
87 more_than_a_screenful (const char *s, int len) | 87 more_than_a_screenful (const char *s, int len) |
88 { | 88 { |
89 if (s) | 89 if (s) |
90 { | 90 { |
91 int available_rows = command_editor::terminal_rows () - 2; | 91 int available_rows = command_editor::terminal_rows () - 2; |
92 | 92 |
93 int cols = command_editor::terminal_cols (); | 93 int cols = command_editor::terminal_cols (); |
94 | 94 |
95 int count = 0; | 95 int count = 0; |
96 | 96 |
97 int chars_this_line = 0; | 97 int chars_this_line = 0; |
98 | 98 |
99 for (int i = 0; i < len; i++) | 99 for (int i = 0; i < len; i++) |
100 { | 100 { |
101 if (*s++ == '\n') | 101 if (*s++ == '\n') |
102 { | 102 { |
103 count += chars_this_line / cols + 1; | 103 count += chars_this_line / cols + 1; |
104 chars_this_line = 0; | 104 chars_this_line = 0; |
105 } | 105 } |
106 else | 106 else |
107 chars_this_line++; | 107 chars_this_line++; |
108 } | 108 } |
109 | 109 |
110 if (count > available_rows) | 110 if (count > available_rows) |
111 return true; | |
112 } | |
113 | |
114 return false; | |
115 } | |
116 | |
117 static std::string default_pager (void) | |
118 { | |
119 std::string pager_binary = sys::env::getenv ("PAGER"); | |
120 | |
121 if (pager_binary.empty ()) | |
122 pager_binary = config::default_pager (); | |
123 | |
124 return pager_binary; | |
125 } | |
126 | |
127 int | |
128 pager_buf::sync (void) | |
129 { | |
130 output_system& output_sys = __get_output_system__ (); | |
131 | |
132 char *buf = pbase (); | |
133 | |
134 int len = pptr () - buf; | |
135 | |
136 if (output_sys.sync (buf, len)) | |
137 { | |
138 flush_current_contents_to_diary (); | |
139 | |
140 seekoff (0, std::ios::beg); | |
141 } | |
142 | |
143 return 0; | |
144 } | |
145 | |
146 void | |
147 pager_buf::flush_current_contents_to_diary (void) | |
148 { | |
149 char *buf = pbase () + m_diary_skip; | |
150 | |
151 std::size_t len = pptr () - buf; | |
152 | |
153 octave_diary.write (buf, len); | |
154 | |
155 m_diary_skip = 0; | |
156 } | |
157 | |
158 void | |
159 pager_buf::set_diary_skip (void) | |
160 { | |
161 m_diary_skip = pptr () - pbase (); | |
162 } | |
163 | |
164 int | |
165 diary_buf::sync (void) | |
166 { | |
167 output_system& output_sys = __get_output_system__ (); | |
168 | |
169 std::ofstream& external_diary_file = output_sys.external_diary_file (); | |
170 | |
171 if (output_sys.write_to_diary_file () && external_diary_file) | |
172 { | |
173 char *buf = pbase (); | |
174 | |
175 int len = pptr () - buf; | |
176 | |
177 if (len > 0) | |
178 external_diary_file.write (buf, len); | |
179 } | |
180 | |
181 seekoff (0, std::ios::beg); | |
182 | |
183 return 0; | |
184 } | |
185 | |
186 pager_stream::pager_stream (void) : std::ostream (nullptr), m_pb (nullptr) | |
187 { | |
188 m_pb = new pager_buf (); | |
189 rdbuf (m_pb); | |
190 setf (unitbuf); | |
191 } | |
192 | |
193 pager_stream::~pager_stream (void) | |
194 { | |
195 flush (); | |
196 delete m_pb; | |
197 } | |
198 | |
199 std::ostream& pager_stream::stream (void) | |
200 { | |
201 return *this; | |
202 } | |
203 | |
204 void pager_stream::flush_current_contents_to_diary (void) | |
205 { | |
206 if (m_pb) | |
207 m_pb->flush_current_contents_to_diary (); | |
208 } | |
209 | |
210 void pager_stream::set_diary_skip (void) | |
211 { | |
212 if (m_pb) | |
213 m_pb->set_diary_skip (); | |
214 } | |
215 | |
216 // Reinitialize the pager buffer to avoid hanging on to large internal | |
217 // buffers when they might not be needed. This function should only be | |
218 // called when the pager is not in use. For example, just before | |
219 // getting command-line input. | |
220 | |
221 void pager_stream::reset (void) | |
222 { | |
223 delete m_pb; | |
224 m_pb = new pager_buf (); | |
225 rdbuf (m_pb); | |
226 setf (unitbuf); | |
227 } | |
228 | |
229 diary_stream::diary_stream (void) : std::ostream (nullptr), m_db (nullptr) | |
230 { | |
231 m_db = new diary_buf (); | |
232 rdbuf (m_db); | |
233 setf (unitbuf); | |
234 } | |
235 | |
236 diary_stream::~diary_stream (void) | |
237 { | |
238 flush (); | |
239 delete m_db; | |
240 } | |
241 | |
242 std::ostream& diary_stream::stream (void) | |
243 { | |
244 return *this; | |
245 } | |
246 | |
247 // Reinitialize the diary buffer to avoid hanging on to large internal | |
248 // buffers when they might not be needed. This function should only be | |
249 // called when the pager is not in use. For example, just before | |
250 // getting command-line input. | |
251 | |
252 void diary_stream::reset (void) | |
253 { | |
254 delete m_db; | |
255 m_db = new diary_buf (); | |
256 rdbuf (m_db); | |
257 setf (unitbuf); | |
258 } | |
259 | |
260 void flush_stdout (void) | |
261 { | |
262 output_system& output_sys = __get_output_system__ (); | |
263 | |
264 output_sys.flush_stdout (); | |
265 } | |
266 | |
267 output_system::output_system (interpreter& interp) | |
268 : m_interpreter (interp), m_pager_stream (), m_diary_stream (), | |
269 m_external_pager (nullptr), m_external_diary_file (), | |
270 m_diary_file_name ("diary"), m_PAGER (default_pager ()), | |
271 m_PAGER_FLAGS (), m_page_output_immediately (false), | |
272 m_page_screen_output (false), m_write_to_diary_file (false), | |
273 m_really_flush_to_pager (false), m_flushing_output_to_pager (false) | |
274 { } | |
275 | |
276 octave_value output_system::PAGER (const octave_value_list& args, | |
277 int nargout) | |
278 { | |
279 return set_internal_variable (m_PAGER, args, nargout, "PAGER", false); | |
280 } | |
281 | |
282 octave_value output_system::PAGER_FLAGS (const octave_value_list& args, | |
283 int nargout) | |
284 { | |
285 return set_internal_variable (m_PAGER_FLAGS, args, nargout, | |
286 "PAGER_FLAGS", false); | |
287 } | |
288 | |
289 octave_value | |
290 output_system::page_output_immediately (const octave_value_list& args, | |
291 int nargout) | |
292 { | |
293 return set_internal_variable (m_page_output_immediately, args, nargout, | |
294 "page_output_immediately"); | |
295 } | |
296 | |
297 octave_value | |
298 output_system::page_screen_output (const octave_value_list& args, | |
299 int nargout) | |
300 { | |
301 return set_internal_variable (m_page_screen_output, args, nargout, | |
302 "page_screen_output"); | |
303 } | |
304 | |
305 std::string output_system::pager_command (void) const | |
306 { | |
307 std::string cmd = m_PAGER; | |
308 | |
309 if (! (cmd.empty () || m_PAGER_FLAGS.empty ())) | |
310 cmd += ' ' + m_PAGER_FLAGS; | |
311 | |
312 return cmd; | |
313 } | |
314 | |
315 void output_system::reset (void) | |
316 { | |
317 flush_stdout (); | |
318 | |
319 m_pager_stream.reset (); | |
320 m_diary_stream.reset (); | |
321 } | |
322 | |
323 void output_system::flush_stdout (void) | |
324 { | |
325 if (! m_flushing_output_to_pager) | |
326 { | |
327 unwind_protect_var<bool> restore_var1 (m_really_flush_to_pager); | |
328 unwind_protect_var<bool> restore_var2 (m_flushing_output_to_pager); | |
329 | |
330 m_really_flush_to_pager = true; | |
331 m_flushing_output_to_pager = true; | |
332 | |
333 std::ostream& pager_ostream = m_pager_stream.stream (); | |
334 | |
335 pager_ostream.flush (); | |
336 | |
337 clear_external_pager (); | |
338 } | |
339 } | |
340 | |
341 void output_system::close_diary (void) | |
342 { | |
343 // Try to flush the current buffer to the diary now, so that things | |
344 // like | |
345 // | |
346 // function foo () | |
347 // diary on; | |
348 // ... | |
349 // diary off; | |
350 // endfunction | |
351 // | |
352 // will do the right thing. | |
353 | |
354 m_pager_stream.flush_current_contents_to_diary (); | |
355 | |
356 if (m_external_diary_file.is_open ()) | |
357 { | |
358 octave_diary.flush (); | |
359 m_external_diary_file.close (); | |
360 } | |
361 } | |
362 | |
363 void output_system::open_diary (void) | |
364 { | |
365 close_diary (); | |
366 | |
367 // If there is pending output in the pager buf, it should not go | |
368 // into the diary file. | |
369 | |
370 m_pager_stream.set_diary_skip (); | |
371 | |
372 m_external_diary_file.open (m_diary_file_name.c_str (), std::ios::app); | |
373 | |
374 if (! m_external_diary_file) | |
375 error ("diary: can't open diary file '%s'", m_diary_file_name.c_str ()); | |
376 } | |
377 | |
378 bool output_system::sync (const char *buf, int len) | |
379 { | |
380 // FIXME: The following seems to be a bit of a mess. | |
381 | |
382 if (m_interpreter.server_mode () | |
383 || ! m_interpreter.interactive () | |
384 || application::forced_interactive () | |
385 || m_really_flush_to_pager | |
386 || (m_page_screen_output && m_page_output_immediately) | |
387 || ! m_page_screen_output) | |
388 { | |
389 bool bypass_pager = (m_interpreter.server_mode () | |
390 || ! m_interpreter.interactive () | |
391 || application::forced_interactive () | |
392 || ! m_page_screen_output | |
393 || (m_really_flush_to_pager | |
394 && m_page_screen_output | |
395 && ! m_page_output_immediately | |
396 && ! more_than_a_screenful (buf, len))); | |
397 | |
398 if (len > 0) | |
399 { | |
400 do_sync (buf, len, bypass_pager); | |
401 | |
111 return true; | 402 return true; |
112 } | 403 } |
113 | 404 } |
114 return false; | 405 |
115 } | 406 return false; |
116 | 407 } |
117 static std::string default_pager (void) | 408 |
118 { | 409 void output_system::clear_external_pager (void) |
119 std::string pager_binary = sys::env::getenv ("PAGER"); | 410 { |
120 | 411 if (m_external_pager) |
121 if (pager_binary.empty ()) | 412 { |
122 pager_binary = config::default_pager (); | 413 child_list& kids = m_interpreter.get_child_list (); |
123 | 414 |
124 return pager_binary; | 415 kids.remove (m_external_pager->pid ()); |
125 } | 416 |
126 | 417 delete m_external_pager; |
127 int | 418 m_external_pager = nullptr; |
128 pager_buf::sync (void) | 419 } |
129 { | 420 } |
130 output_system& output_sys = __get_output_system__ (); | 421 |
131 | 422 void output_system::start_external_pager (void) |
132 char *buf = pbase (); | 423 { |
133 | 424 if (m_external_pager) |
134 int len = pptr () - buf; | 425 return; |
135 | 426 |
136 if (output_sys.sync (buf, len)) | 427 std::string pgr = pager_command (); |
137 { | 428 |
138 flush_current_contents_to_diary (); | 429 if (! pgr.empty ()) |
139 | 430 { |
140 seekoff (0, std::ios::beg); | 431 m_external_pager = new oprocstream (pgr.c_str ()); |
141 } | 432 |
142 | 433 child_list& kids = m_interpreter.get_child_list (); |
143 return 0; | 434 |
144 } | 435 kids.insert (m_external_pager->pid (), |
145 | 436 pager_event_handler); |
146 void | 437 } |
147 pager_buf::flush_current_contents_to_diary (void) | 438 } |
148 { | 439 |
149 char *buf = pbase () + m_diary_skip; | 440 void output_system::do_sync (const char *msg, int len, bool bypass_pager) |
150 | 441 { |
151 std::size_t len = pptr () - buf; | 442 if (msg && len > 0) |
152 | 443 { |
153 octave_diary.write (buf, len); | 444 if (bypass_pager) |
154 | 445 { |
155 m_diary_skip = 0; | 446 if (m_interpreter.server_mode ()) |
156 } | 447 { |
157 | 448 event_manager& evmgr = m_interpreter.get_event_manager (); |
158 void | 449 |
159 pager_buf::set_diary_skip (void) | 450 evmgr.interpreter_output (std::string (msg, len)); |
160 { | 451 } |
161 m_diary_skip = pptr () - pbase (); | 452 else |
162 } | 453 { |
163 | 454 std::cout.write (msg, len); |
164 int | 455 std::cout.flush (); |
165 diary_buf::sync (void) | 456 } |
166 { | 457 } |
167 output_system& output_sys = __get_output_system__ (); | 458 else |
168 | 459 { |
169 std::ofstream& external_diary_file = output_sys.external_diary_file (); | 460 start_external_pager (); |
170 | 461 |
171 if (output_sys.write_to_diary_file () && external_diary_file) | 462 if (m_external_pager) |
172 { | 463 { |
173 char *buf = pbase (); | 464 if (m_external_pager->good ()) |
174 | 465 { |
175 int len = pptr () - buf; | 466 m_external_pager->write (msg, len); |
176 | 467 |
177 if (len > 0) | 468 m_external_pager->flush (); |
178 external_diary_file.write (buf, len); | |
179 } | |
180 | |
181 seekoff (0, std::ios::beg); | |
182 | |
183 return 0; | |
184 } | |
185 | |
186 pager_stream::pager_stream (void) : std::ostream (nullptr), m_pb (nullptr) | |
187 { | |
188 m_pb = new pager_buf (); | |
189 rdbuf (m_pb); | |
190 setf (unitbuf); | |
191 } | |
192 | |
193 pager_stream::~pager_stream (void) | |
194 { | |
195 flush (); | |
196 delete m_pb; | |
197 } | |
198 | |
199 std::ostream& pager_stream::stream (void) | |
200 { | |
201 return *this; | |
202 } | |
203 | |
204 void pager_stream::flush_current_contents_to_diary (void) | |
205 { | |
206 if (m_pb) | |
207 m_pb->flush_current_contents_to_diary (); | |
208 } | |
209 | |
210 void pager_stream::set_diary_skip (void) | |
211 { | |
212 if (m_pb) | |
213 m_pb->set_diary_skip (); | |
214 } | |
215 | |
216 // Reinitialize the pager buffer to avoid hanging on to large internal | |
217 // buffers when they might not be needed. This function should only be | |
218 // called when the pager is not in use. For example, just before | |
219 // getting command-line input. | |
220 | |
221 void pager_stream::reset (void) | |
222 { | |
223 delete m_pb; | |
224 m_pb = new pager_buf (); | |
225 rdbuf (m_pb); | |
226 setf (unitbuf); | |
227 } | |
228 | |
229 diary_stream::diary_stream (void) : std::ostream (nullptr), m_db (nullptr) | |
230 { | |
231 m_db = new diary_buf (); | |
232 rdbuf (m_db); | |
233 setf (unitbuf); | |
234 } | |
235 | |
236 diary_stream::~diary_stream (void) | |
237 { | |
238 flush (); | |
239 delete m_db; | |
240 } | |
241 | |
242 std::ostream& diary_stream::stream (void) | |
243 { | |
244 return *this; | |
245 } | |
246 | |
247 // Reinitialize the diary buffer to avoid hanging on to large internal | |
248 // buffers when they might not be needed. This function should only be | |
249 // called when the pager is not in use. For example, just before | |
250 // getting command-line input. | |
251 | |
252 void diary_stream::reset (void) | |
253 { | |
254 delete m_db; | |
255 m_db = new diary_buf (); | |
256 rdbuf (m_db); | |
257 setf (unitbuf); | |
258 } | |
259 | |
260 void flush_stdout (void) | |
261 { | |
262 output_system& output_sys = __get_output_system__ (); | |
263 | |
264 output_sys.flush_stdout (); | |
265 } | |
266 | |
267 output_system::output_system (interpreter& interp) | |
268 : m_interpreter (interp), m_pager_stream (), m_diary_stream (), | |
269 m_external_pager (nullptr), m_external_diary_file (), | |
270 m_diary_file_name ("diary"), m_PAGER (default_pager ()), | |
271 m_PAGER_FLAGS (), m_page_output_immediately (false), | |
272 m_page_screen_output (false), m_write_to_diary_file (false), | |
273 m_really_flush_to_pager (false), m_flushing_output_to_pager (false) | |
274 { } | |
275 | |
276 octave_value output_system::PAGER (const octave_value_list& args, | |
277 int nargout) | |
278 { | |
279 return set_internal_variable (m_PAGER, args, nargout, "PAGER", false); | |
280 } | |
281 | |
282 octave_value output_system::PAGER_FLAGS (const octave_value_list& args, | |
283 int nargout) | |
284 { | |
285 return set_internal_variable (m_PAGER_FLAGS, args, nargout, | |
286 "PAGER_FLAGS", false); | |
287 } | |
288 | |
289 octave_value | |
290 output_system::page_output_immediately (const octave_value_list& args, | |
291 int nargout) | |
292 { | |
293 return set_internal_variable (m_page_output_immediately, args, nargout, | |
294 "page_output_immediately"); | |
295 } | |
296 | |
297 octave_value | |
298 output_system::page_screen_output (const octave_value_list& args, | |
299 int nargout) | |
300 { | |
301 return set_internal_variable (m_page_screen_output, args, nargout, | |
302 "page_screen_output"); | |
303 } | |
304 | |
305 std::string output_system::pager_command (void) const | |
306 { | |
307 std::string cmd = m_PAGER; | |
308 | |
309 if (! (cmd.empty () || m_PAGER_FLAGS.empty ())) | |
310 cmd += ' ' + m_PAGER_FLAGS; | |
311 | |
312 return cmd; | |
313 } | |
314 | |
315 void output_system::reset (void) | |
316 { | |
317 flush_stdout (); | |
318 | |
319 m_pager_stream.reset (); | |
320 m_diary_stream.reset (); | |
321 } | |
322 | |
323 void output_system::flush_stdout (void) | |
324 { | |
325 if (! m_flushing_output_to_pager) | |
326 { | |
327 unwind_protect_var<bool> restore_var1 (m_really_flush_to_pager); | |
328 unwind_protect_var<bool> restore_var2 (m_flushing_output_to_pager); | |
329 | |
330 m_really_flush_to_pager = true; | |
331 m_flushing_output_to_pager = true; | |
332 | |
333 std::ostream& pager_ostream = m_pager_stream.stream (); | |
334 | |
335 pager_ostream.flush (); | |
336 | |
337 clear_external_pager (); | |
338 } | |
339 } | |
340 | |
341 void output_system::close_diary (void) | |
342 { | |
343 // Try to flush the current buffer to the diary now, so that things | |
344 // like | |
345 // | |
346 // function foo () | |
347 // diary on; | |
348 // ... | |
349 // diary off; | |
350 // endfunction | |
351 // | |
352 // will do the right thing. | |
353 | |
354 m_pager_stream.flush_current_contents_to_diary (); | |
355 | |
356 if (m_external_diary_file.is_open ()) | |
357 { | |
358 octave_diary.flush (); | |
359 m_external_diary_file.close (); | |
360 } | |
361 } | |
362 | |
363 void output_system::open_diary (void) | |
364 { | |
365 close_diary (); | |
366 | |
367 // If there is pending output in the pager buf, it should not go | |
368 // into the diary file. | |
369 | |
370 m_pager_stream.set_diary_skip (); | |
371 | |
372 m_external_diary_file.open (m_diary_file_name.c_str (), std::ios::app); | |
373 | |
374 if (! m_external_diary_file) | |
375 error ("diary: can't open diary file '%s'", m_diary_file_name.c_str ()); | |
376 } | |
377 | |
378 bool output_system::sync (const char *buf, int len) | |
379 { | |
380 // FIXME: The following seems to be a bit of a mess. | |
381 | |
382 if (m_interpreter.server_mode () | |
383 || ! m_interpreter.interactive () | |
384 || application::forced_interactive () | |
385 || m_really_flush_to_pager | |
386 || (m_page_screen_output && m_page_output_immediately) | |
387 || ! m_page_screen_output) | |
388 { | |
389 bool bypass_pager = (m_interpreter.server_mode () | |
390 || ! m_interpreter.interactive () | |
391 || application::forced_interactive () | |
392 || ! m_page_screen_output | |
393 || (m_really_flush_to_pager | |
394 && m_page_screen_output | |
395 && ! m_page_output_immediately | |
396 && ! more_than_a_screenful (buf, len))); | |
397 | |
398 if (len > 0) | |
399 { | |
400 do_sync (buf, len, bypass_pager); | |
401 | |
402 return true; | |
403 } | |
404 } | |
405 | |
406 return false; | |
407 } | |
408 | |
409 void output_system::clear_external_pager (void) | |
410 { | |
411 if (m_external_pager) | |
412 { | |
413 child_list& kids = m_interpreter.get_child_list (); | |
414 | |
415 kids.remove (m_external_pager->pid ()); | |
416 | |
417 delete m_external_pager; | |
418 m_external_pager = nullptr; | |
419 } | |
420 } | |
421 | |
422 void output_system::start_external_pager (void) | |
423 { | |
424 if (m_external_pager) | |
425 return; | |
426 | |
427 std::string pgr = pager_command (); | |
428 | |
429 if (! pgr.empty ()) | |
430 { | |
431 m_external_pager = new oprocstream (pgr.c_str ()); | |
432 | |
433 child_list& kids = m_interpreter.get_child_list (); | |
434 | |
435 kids.insert (m_external_pager->pid (), | |
436 pager_event_handler); | |
437 } | |
438 } | |
439 | |
440 void output_system::do_sync (const char *msg, int len, bool bypass_pager) | |
441 { | |
442 if (msg && len > 0) | |
443 { | |
444 if (bypass_pager) | |
445 { | |
446 if (m_interpreter.server_mode ()) | |
447 { | |
448 event_manager& evmgr = m_interpreter.get_event_manager (); | |
449 | |
450 evmgr.interpreter_output (std::string (msg, len)); | |
451 } | |
452 else | |
453 { | |
454 std::cout.write (msg, len); | |
455 std::cout.flush (); | |
456 } | |
457 } | |
458 else | |
459 { | |
460 start_external_pager (); | |
461 | |
462 if (m_external_pager) | |
463 { | |
464 if (m_external_pager->good ()) | |
465 { | |
466 m_external_pager->write (msg, len); | |
467 | |
468 m_external_pager->flush (); | |
469 | 469 |
470 #if defined (EPIPE) | 470 #if defined (EPIPE) |
471 if (errno == EPIPE) | 471 if (errno == EPIPE) |
472 m_external_pager->setstate (std::ios::failbit); | 472 m_external_pager->setstate (std::ios::failbit); |
473 #endif | 473 #endif |
474 } | 474 } |
475 else | 475 else |
476 { | 476 { |
477 // FIXME: something is not right with the | 477 // FIXME: something is not right with the |
478 // pager. If it died then we should receive a | 478 // pager. If it died then we should receive a |
479 // signal for that. If there is some other problem, | 479 // signal for that. If there is some other problem, |
480 // then what? | 480 // then what? |
481 } | 481 } |
482 } | 482 } |
483 else | 483 else |
484 { | 484 { |
485 std::cout.write (msg, len); | 485 std::cout.write (msg, len); |
486 std::cout.flush (); | 486 std::cout.flush (); |
487 } | 487 } |
488 } | 488 } |
489 } | 489 } |
490 } | 490 } |
491 | 491 |
492 std::ostream& __stdout__ (void) | 492 std::ostream& __stdout__ (void) |
493 { | 493 { |
494 output_system& output_sys = __get_output_system__ (); | 494 output_system& output_sys = __get_output_system__ (); |
495 | 495 |
496 return output_sys.__stdout__ (); | 496 return output_sys.__stdout__ (); |
497 } | 497 } |
498 | 498 |
499 std::ostream& __diary__ (void) | 499 std::ostream& __diary__ (void) |
500 { | 500 { |
501 output_system& output_sys = __get_output_system__ (); | 501 output_system& output_sys = __get_output_system__ (); |
502 | 502 |
503 return output_sys.__diary__ (); | 503 return output_sys.__diary__ (); |
504 } | 504 } |
505 | 505 |
506 DEFMETHOD (diary, interp, args, nargout, | 506 DEFMETHOD (diary, interp, args, nargout, |
507 doc: /* -*- texinfo -*- | 507 doc: /* -*- texinfo -*- |
508 @deftypefn {} {} diary | 508 @deftypefn {} {} diary |
509 @deftypefnx {} {} diary on | 509 @deftypefnx {} {} diary on |