]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/ui-file.c
Return void from gdb_putc
[thirdparty/binutils-gdb.git] / gdb / ui-file.c
CommitLineData
d9fcf2fb 1/* UI_FILE - a generic STDIO like output stream.
349c5d5f 2
4a94e368 3 Copyright (C) 1999-2022 Free Software Foundation, Inc.
d9fcf2fb
JM
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
d9fcf2fb
JM
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
d9fcf2fb 19
581e13c1 20/* Implement the ``struct ui_file'' object. */
d9fcf2fb
JM
21
22#include "defs.h"
23#include "ui-file.h"
bf31fd38 24#include "gdbsupport/gdb_obstack.h"
06cc9596 25#include "gdbsupport/gdb_select.h"
268a13a5 26#include "gdbsupport/filestuff.h"
3cd52293 27#include "cli-out.h"
f64eea3a 28#include "cli/cli-style.h"
3c6c449e 29#include <chrono>
d9fcf2fb 30
d7e74731 31null_file null_stream;
d9fcf2fb 32
d7e74731
PA
33ui_file::ui_file ()
34{}
d9fcf2fb 35
d7e74731
PA
36ui_file::~ui_file ()
37{}
d9fcf2fb 38
d7e74731
PA
39void
40ui_file::printf (const char *format, ...)
d9fcf2fb 41{
d7e74731 42 va_list args;
d9fcf2fb 43
d7e74731 44 va_start (args, format);
19a7b8ab 45 vprintf (format, args);
d7e74731 46 va_end (args);
d9fcf2fb
JM
47}
48
d7e74731
PA
49void
50ui_file::putstr (const char *str, int quoter)
d9fcf2fb 51{
d53fd721
TT
52 while (*str)
53 printchar (*str++, quoter, false);
d9fcf2fb
JM
54}
55
d7e74731 56void
d53fd721 57ui_file::putstrn (const char *str, int n, int quoter, bool async_safe)
d9fcf2fb 58{
d53fd721
TT
59 for (int i = 0; i < n; i++)
60 printchar (str[i], quoter, async_safe);
d9fcf2fb
JM
61}
62
4311246b 63void
d7e74731 64ui_file::putc (int c)
449092f6 65{
a11ac3b3
TT
66 char copy = (char) c;
67 write (&copy, 1);
449092f6
CV
68}
69
d7e74731
PA
70void
71ui_file::vprintf (const char *format, va_list args)
d9fcf2fb 72{
3cd52293
TT
73 ui_out_flags flags = disallow_ui_out_field;
74 cli_ui_out (this, flags).vmessage (m_applied_style, format, args);
d9fcf2fb
JM
75}
76
d53fd721
TT
77/* See ui-file.h. */
78
c8d74a7b
TT
79void
80ui_file::emit_style_escape (const ui_file_style &style)
81{
82 if (can_emit_style_escape () && style != m_applied_style)
83 {
84 m_applied_style = style;
85 this->puts (style.to_ansi ().c_str ());
86 }
87}
88
89/* See ui-file.h. */
90
91void
92ui_file::reset_style ()
93{
94 if (can_emit_style_escape ())
95 {
96 m_applied_style = ui_file_style ();
97 this->puts (m_applied_style.to_ansi ().c_str ());
98 }
99}
100
101/* See ui-file.h. */
102
d53fd721
TT
103void
104ui_file::printchar (int c, int quoter, bool async_safe)
105{
106 char buf[4];
107 int out = 0;
108
109 c &= 0xFF; /* Avoid sign bit follies */
110
111 if (c < 0x20 /* Low control chars */
112 || (c >= 0x7F && c < 0xA0) /* DEL, High controls */
113 || (sevenbit_strings && c >= 0x80))
114 { /* high order bit set */
115 buf[out++] = '\\';
116
117 switch (c)
118 {
119 case '\n':
120 buf[out++] = 'n';
121 break;
122 case '\b':
123 buf[out++] = 'b';
124 break;
125 case '\t':
126 buf[out++] = 't';
127 break;
128 case '\f':
129 buf[out++] = 'f';
130 break;
131 case '\r':
132 buf[out++] = 'r';
133 break;
134 case '\033':
135 buf[out++] = 'e';
136 break;
137 case '\007':
138 buf[out++] = 'a';
139 break;
140 default:
141 {
142 buf[out++] = '0' + ((c >> 6) & 0x7);
143 buf[out++] = '0' + ((c >> 3) & 0x7);
144 buf[out++] = '0' + ((c >> 0) & 0x7);
145 break;
146 }
147 }
148 }
149 else
150 {
151 if (quoter != 0 && (c == '\\' || c == quoter))
152 buf[out++] = '\\';
153 buf[out++] = c;
154 }
155
156 if (async_safe)
157 this->write_async_safe (buf, out);
158 else
159 this->write (buf, out);
160}
161
d7e74731 162\f
01124a23 163
d7e74731
PA
164void
165null_file::write (const char *buf, long sizeof_buf)
d9fcf2fb 166{
d7e74731 167 /* Discard the request. */
d9fcf2fb
JM
168}
169
d7e74731
PA
170void
171null_file::puts (const char *)
2a9d5ccf 172{
d7e74731 173 /* Discard the request. */
2a9d5ccf
HZ
174}
175
d7e74731
PA
176void
177null_file::write_async_safe (const char *buf, long sizeof_buf)
d9fcf2fb 178{
d7e74731 179 /* Discard the request. */
d9fcf2fb
JM
180}
181
d7e74731
PA
182\f
183
8a522c6c
PW
184/* true if the gdb terminal supports styling, and styling is enabled. */
185
186static bool
187term_cli_styling ()
188{
8a522c6c
PW
189 if (!cli_styling)
190 return false;
191
192 const char *term = getenv ("TERM");
193 /* Windows doesn't by default define $TERM, but can support styles
194 regardless. */
195#ifndef _WIN32
196 if (term == nullptr || !strcmp (term, "dumb"))
197 return false;
198#else
199 /* But if they do define $TERM, let us behave the same as on Posix
200 platforms, for the benefit of programs which invoke GDB as their
201 back-end. */
202 if (term && !strcmp (term, "dumb"))
203 return false;
204#endif
205 return true;
206}
207
d7e74731 208\f
d9fcf2fb 209
d7e74731
PA
210string_file::~string_file ()
211{}
d9fcf2fb
JM
212
213void
d7e74731 214string_file::write (const char *buf, long length_buf)
d9fcf2fb 215{
d7e74731 216 m_string.append (buf, length_buf);
d9fcf2fb
JM
217}
218
8a522c6c
PW
219/* See ui-file.h. */
220
221bool
222string_file::term_out ()
223{
224 return m_term_out;
225}
226
227/* See ui-file.h. */
228
229bool
230string_file::can_emit_style_escape ()
231{
232 return m_term_out && term_cli_styling ();
233}
234
d7e74731 235\f
01124a23 236
d7e74731 237stdio_file::stdio_file (FILE *file, bool close_p)
449092f6 238{
d7e74731
PA
239 set_stream (file);
240 m_close_p = close_p;
449092f6
CV
241}
242
d7e74731
PA
243stdio_file::stdio_file ()
244 : m_file (NULL),
245 m_fd (-1),
246 m_close_p (false)
247{}
d9fcf2fb 248
d7e74731 249stdio_file::~stdio_file ()
2a9d5ccf 250{
d7e74731
PA
251 if (m_close_p)
252 fclose (m_file);
2a9d5ccf
HZ
253}
254
d9fcf2fb 255void
d7e74731 256stdio_file::set_stream (FILE *file)
d9fcf2fb 257{
d7e74731
PA
258 m_file = file;
259 m_fd = fileno (file);
d9fcf2fb
JM
260}
261
d7e74731
PA
262bool
263stdio_file::open (const char *name, const char *mode)
d9fcf2fb 264{
d7e74731
PA
265 /* Close the previous stream, if we own it. */
266 if (m_close_p)
267 {
268 fclose (m_file);
269 m_close_p = false;
270 }
5d502164 271
d419f42d 272 gdb_file_up f = gdb_fopen_cloexec (name, mode);
d9fcf2fb 273
d7e74731
PA
274 if (f == NULL)
275 return false;
d9fcf2fb 276
d419f42d 277 set_stream (f.release ());
d7e74731 278 m_close_p = true;
5d502164 279
d7e74731 280 return true;
d9fcf2fb
JM
281}
282
283void
d7e74731 284stdio_file::flush ()
d9fcf2fb 285{
d7e74731 286 fflush (m_file);
d9fcf2fb
JM
287}
288
d7e74731
PA
289long
290stdio_file::read (char *buf, long length_buf)
449092f6 291{
f0881b37
PA
292 /* Wait until at least one byte of data is available, or we get
293 interrupted with Control-C. */
ad960ed2 294 {
ad960ed2 295 fd_set readfds;
f0881b37 296
ad960ed2 297 FD_ZERO (&readfds);
d7e74731
PA
298 FD_SET (m_fd, &readfds);
299 if (interruptible_select (m_fd + 1, &readfds, NULL, NULL, NULL) == -1)
ad960ed2
DJ
300 return -1;
301 }
302
d7e74731 303 return ::read (m_fd, buf, length_buf);
449092f6
CV
304}
305
d7e74731
PA
306void
307stdio_file::write (const char *buf, long length_buf)
d9fcf2fb 308{
bf1d7d9c 309 /* Calling error crashes when we are called from the exception framework. */
d7e74731 310 if (fwrite (buf, length_buf, 1, m_file))
d4fb63e1
TT
311 {
312 /* Nothing. */
313 }
d9fcf2fb
JM
314}
315
d7e74731
PA
316void
317stdio_file::write_async_safe (const char *buf, long length_buf)
01124a23 318{
9f7bc587
DE
319 /* This is written the way it is to avoid a warning from gcc about not using the
320 result of write (since it can be declared with attribute warn_unused_result).
321 Alas casting to void doesn't work for this. */
d7e74731 322 if (::write (m_fd, buf, length_buf))
d4fb63e1
TT
323 {
324 /* Nothing. */
325 }
01124a23
DE
326}
327
d7e74731
PA
328void
329stdio_file::puts (const char *linebuffer)
d9fcf2fb 330{
e4adb939
EZ
331 /* This host-dependent function (with implementations in
332 posix-hdep.c and mingw-hdep.c) is given the opportunity to
333 process the output first in host-dependent way. If it does, it
334 should return non-zero, to avoid calling fputs below. */
335 if (gdb_console_fputs (linebuffer, m_file))
336 return;
bf1d7d9c 337 /* Calling error crashes when we are called from the exception framework. */
d7e74731 338 if (fputs (linebuffer, m_file))
d4fb63e1
TT
339 {
340 /* Nothing. */
341 }
d9fcf2fb
JM
342}
343
d7e74731
PA
344bool
345stdio_file::isatty ()
d9fcf2fb 346{
d7e74731 347 return ::isatty (m_fd);
d9fcf2fb
JM
348}
349
8a522c6c
PW
350/* See ui-file.h. */
351
352bool
353stdio_file::can_emit_style_escape ()
354{
3cd52293 355 return (this->isatty ()
8a522c6c
PW
356 && term_cli_styling ());
357}
358
d7e74731 359\f
2a9d5ccf 360
d7e74731 361/* This is the implementation of ui_file method 'write' for stderr.
ffa4ac95
YQ
362 gdb_stdout is flushed before writing to gdb_stderr. */
363
d7e74731
PA
364void
365stderr_file::write (const char *buf, long length_buf)
ffa4ac95 366{
da5bd37e 367 gdb_stdout->flush ();
d7e74731 368 stdio_file::write (buf, length_buf);
ffa4ac95
YQ
369}
370
d7e74731 371/* This is the implementation of ui_file method 'puts' for stderr.
ffa4ac95
YQ
372 gdb_stdout is flushed before writing to gdb_stderr. */
373
d7e74731
PA
374void
375stderr_file::puts (const char *linebuffer)
ffa4ac95 376{
da5bd37e 377 gdb_stdout->flush ();
d7e74731 378 stdio_file::puts (linebuffer);
ffa4ac95 379}
ffa4ac95 380
d7e74731
PA
381stderr_file::stderr_file (FILE *stream)
382 : stdio_file (stream)
383{}
d9fcf2fb 384
d7e74731 385\f
e4c242d9 386
f3a09c80 387tee_file::tee_file (ui_file *one, ui_file_up &&two)
d7e74731 388 : m_one (one),
f3a09c80 389 m_two (std::move (two))
d7e74731 390{}
e4c242d9 391
d7e74731 392tee_file::~tee_file ()
e4c242d9 393{
e4c242d9
DJ
394}
395
d7e74731
PA
396void
397tee_file::flush ()
e4c242d9 398{
d7e74731
PA
399 m_one->flush ();
400 m_two->flush ();
e4c242d9
DJ
401}
402
d7e74731
PA
403void
404tee_file::write (const char *buf, long length_buf)
e4c242d9 405{
d7e74731
PA
406 m_one->write (buf, length_buf);
407 m_two->write (buf, length_buf);
e4c242d9
DJ
408}
409
d7e74731
PA
410void
411tee_file::write_async_safe (const char *buf, long length_buf)
e4c242d9 412{
d7e74731
PA
413 m_one->write_async_safe (buf, length_buf);
414 m_two->write_async_safe (buf, length_buf);
e4c242d9
DJ
415}
416
d7e74731
PA
417void
418tee_file::puts (const char *linebuffer)
e4c242d9 419{
d7e74731
PA
420 m_one->puts (linebuffer);
421 m_two->puts (linebuffer);
e4c242d9
DJ
422}
423
d7e74731
PA
424bool
425tee_file::isatty ()
e4c242d9 426{
d7e74731 427 return m_one->isatty ();
e4c242d9 428}
8a522c6c
PW
429
430/* See ui-file.h. */
431
432bool
433tee_file::term_out ()
434{
435 return m_one->term_out ();
436}
437
438/* See ui-file.h. */
439
440bool
441tee_file::can_emit_style_escape ()
442{
3cd52293 443 return (m_one->term_out ()
8a522c6c
PW
444 && term_cli_styling ());
445}
0735b091
TT
446
447/* See ui-file.h. */
448
449void
450no_terminal_escape_file::write (const char *buf, long length_buf)
451{
452 std::string copy (buf, length_buf);
453 this->puts (copy.c_str ());
454}
455
456/* See ui-file.h. */
457
458void
459no_terminal_escape_file::puts (const char *buf)
460{
461 while (*buf != '\0')
462 {
463 const char *esc = strchr (buf, '\033');
464 if (esc == nullptr)
465 break;
466
467 int n_read = 0;
468 if (!skip_ansi_escape (esc, &n_read))
469 ++esc;
470
471 this->stdio_file::write (buf, esc - buf);
472 buf = esc + n_read;
473 }
474
475 if (*buf != '\0')
476 this->stdio_file::write (buf, strlen (buf));
477}
3c6c449e
TT
478
479void
480timestamped_file::write (const char *buf, long len)
481{
482 if (debug_timestamp)
483 {
484 /* Print timestamp if previous print ended with a \n. */
485 if (m_needs_timestamp)
486 {
487 using namespace std::chrono;
488
489 steady_clock::time_point now = steady_clock::now ();
490 seconds s = duration_cast<seconds> (now.time_since_epoch ());
491 microseconds us = duration_cast<microseconds> (now.time_since_epoch () - s);
492 std::string timestamp = string_printf ("%ld.%06ld ",
493 (long) s.count (),
494 (long) us.count ());
495 m_stream->puts (timestamp.c_str ());
496 }
497
498 /* Print the message. */
499 m_stream->write (buf, len);
500
501 m_needs_timestamp = (len > 0 && buf[len - 1] == '\n');
502 }
503 else
504 m_stream->write (buf, len);
505}