1 /* UI_FILE - a generic STDIO like output stream. 2 3 Copyright (C) 1999-2020 Free Software Foundation, Inc. 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 9 the Free Software Foundation; either version 3 of the License, or 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 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 /* Implement the ``struct ui_file'' object. */ 21 22 #include "defs.h" 23 #include "ui-file.h" 24 #include "gdb_obstack.h" 25 #include "gdbsupport/gdb_select.h" 26 #include "gdbsupport/filestuff.h" 27 #include "cli/cli-style.h" 28 29 null_file null_stream; 30 31 ui_file::ui_file () 32 {} 33 34 ui_file::~ui_file () 35 {} 36 37 void 38 ui_file::printf (const char *format, ...) 39 { 40 va_list args; 41 42 va_start (args, format); 43 vfprintf_unfiltered (this, format, args); 44 va_end (args); 45 } 46 47 void 48 ui_file::putstr (const char *str, int quoter) 49 { 50 fputstr_unfiltered (str, quoter, this); 51 } 52 53 void 54 ui_file::putstrn (const char *str, int n, int quoter) 55 { 56 fputstrn_unfiltered (str, n, quoter, fputc_unfiltered, this); 57 } 58 59 int 60 ui_file::putc (int c) 61 { 62 return fputc_unfiltered (c, this); 63 } 64 65 void 66 ui_file::vprintf (const char *format, va_list args) 67 { 68 vfprintf_unfiltered (this, format, args); 69 } 70 71 72 73 void 74 null_file::write (const char *buf, long sizeof_buf) 75 { 76 /* Discard the request. */ 77 } 78 79 void 80 null_file::puts (const char *) 81 { 82 /* Discard the request. */ 83 } 84 85 void 86 null_file::write_async_safe (const char *buf, long sizeof_buf) 87 { 88 /* Discard the request. */ 89 } 90 91 92 93 /* true if the gdb terminal supports styling, and styling is enabled. */ 94 95 static bool 96 term_cli_styling () 97 { 98 if (!cli_styling) 99 return false; 100 101 const char *term = getenv ("TERM"); 102 /* Windows doesn't by default define $TERM, but can support styles 103 regardless. */ 104 #ifndef _WIN32 105 if (term == nullptr || !strcmp (term, "dumb")) 106 return false; 107 #else 108 /* But if they do define $TERM, let us behave the same as on Posix 109 platforms, for the benefit of programs which invoke GDB as their 110 back-end. */ 111 if (term && !strcmp (term, "dumb")) 112 return false; 113 #endif 114 return true; 115 } 116 117 118 119 string_file::~string_file () 120 {} 121 122 void 123 string_file::write (const char *buf, long length_buf) 124 { 125 m_string.append (buf, length_buf); 126 } 127 128 /* See ui-file.h. */ 129 130 bool 131 string_file::term_out () 132 { 133 return m_term_out; 134 } 135 136 /* See ui-file.h. */ 137 138 bool 139 string_file::can_emit_style_escape () 140 { 141 return m_term_out && term_cli_styling (); 142 } 143 144 145 146 stdio_file::stdio_file (FILE *file, bool close_p) 147 { 148 set_stream (file); 149 m_close_p = close_p; 150 } 151 152 stdio_file::stdio_file () 153 : m_file (NULL), 154 m_fd (-1), 155 m_close_p (false) 156 {} 157 158 stdio_file::~stdio_file () 159 { 160 if (m_close_p) 161 fclose (m_file); 162 } 163 164 void 165 stdio_file::set_stream (FILE *file) 166 { 167 m_file = file; 168 m_fd = fileno (file); 169 } 170 171 bool 172 stdio_file::open (const char *name, const char *mode) 173 { 174 /* Close the previous stream, if we own it. */ 175 if (m_close_p) 176 { 177 fclose (m_file); 178 m_close_p = false; 179 } 180 181 gdb_file_up f = gdb_fopen_cloexec (name, mode); 182 183 if (f == NULL) 184 return false; 185 186 set_stream (f.release ()); 187 m_close_p = true; 188 189 return true; 190 } 191 192 void 193 stdio_file::flush () 194 { 195 fflush (m_file); 196 } 197 198 long 199 stdio_file::read (char *buf, long length_buf) 200 { 201 /* Wait until at least one byte of data is available, or we get 202 interrupted with Control-C. */ 203 { 204 fd_set readfds; 205 206 FD_ZERO (&readfds); 207 FD_SET (m_fd, &readfds); 208 if (interruptible_select (m_fd + 1, &readfds, NULL, NULL, NULL) == -1) 209 return -1; 210 } 211 212 return ::read (m_fd, buf, length_buf); 213 } 214 215 void 216 stdio_file::write (const char *buf, long length_buf) 217 { 218 /* Calling error crashes when we are called from the exception framework. */ 219 if (fwrite (buf, length_buf, 1, m_file)) 220 { 221 /* Nothing. */ 222 } 223 } 224 225 void 226 stdio_file::write_async_safe (const char *buf, long length_buf) 227 { 228 /* This is written the way it is to avoid a warning from gcc about not using the 229 result of write (since it can be declared with attribute warn_unused_result). 230 Alas casting to void doesn't work for this. */ 231 if (::write (m_fd, buf, length_buf)) 232 { 233 /* Nothing. */ 234 } 235 } 236 237 void 238 stdio_file::puts (const char *linebuffer) 239 { 240 /* This host-dependent function (with implementations in 241 posix-hdep.c and mingw-hdep.c) is given the opportunity to 242 process the output first in host-dependent way. If it does, it 243 should return non-zero, to avoid calling fputs below. */ 244 if (gdb_console_fputs (linebuffer, m_file)) 245 return; 246 /* Calling error crashes when we are called from the exception framework. */ 247 if (fputs (linebuffer, m_file)) 248 { 249 /* Nothing. */ 250 } 251 } 252 253 bool 254 stdio_file::isatty () 255 { 256 return ::isatty (m_fd); 257 } 258 259 /* See ui-file.h. */ 260 261 bool 262 stdio_file::can_emit_style_escape () 263 { 264 return ((this == gdb_stdout || this == gdb_stderr) 265 && this->isatty () 266 && term_cli_styling ()); 267 } 268 269 270 271 /* This is the implementation of ui_file method 'write' for stderr. 272 gdb_stdout is flushed before writing to gdb_stderr. */ 273 274 void 275 stderr_file::write (const char *buf, long length_buf) 276 { 277 gdb_stdout->flush (); 278 stdio_file::write (buf, length_buf); 279 } 280 281 /* This is the implementation of ui_file method 'puts' for stderr. 282 gdb_stdout is flushed before writing to gdb_stderr. */ 283 284 void 285 stderr_file::puts (const char *linebuffer) 286 { 287 gdb_stdout->flush (); 288 stdio_file::puts (linebuffer); 289 } 290 291 stderr_file::stderr_file (FILE *stream) 292 : stdio_file (stream) 293 {} 294 295 296 297 tee_file::tee_file (ui_file *one, ui_file_up &&two) 298 : m_one (one), 299 m_two (std::move (two)) 300 {} 301 302 tee_file::~tee_file () 303 { 304 } 305 306 void 307 tee_file::flush () 308 { 309 m_one->flush (); 310 m_two->flush (); 311 } 312 313 void 314 tee_file::write (const char *buf, long length_buf) 315 { 316 m_one->write (buf, length_buf); 317 m_two->write (buf, length_buf); 318 } 319 320 void 321 tee_file::write_async_safe (const char *buf, long length_buf) 322 { 323 m_one->write_async_safe (buf, length_buf); 324 m_two->write_async_safe (buf, length_buf); 325 } 326 327 void 328 tee_file::puts (const char *linebuffer) 329 { 330 m_one->puts (linebuffer); 331 m_two->puts (linebuffer); 332 } 333 334 bool 335 tee_file::isatty () 336 { 337 return m_one->isatty (); 338 } 339 340 /* See ui-file.h. */ 341 342 bool 343 tee_file::term_out () 344 { 345 return m_one->term_out (); 346 } 347 348 /* See ui-file.h. */ 349 350 bool 351 tee_file::can_emit_style_escape () 352 { 353 return ((this == gdb_stdout || this == gdb_stderr) 354 && m_one->term_out () 355 && term_cli_styling ()); 356 } 357 358 /* See ui-file.h. */ 359 360 void 361 no_terminal_escape_file::write (const char *buf, long length_buf) 362 { 363 std::string copy (buf, length_buf); 364 this->puts (copy.c_str ()); 365 } 366 367 /* See ui-file.h. */ 368 369 void 370 no_terminal_escape_file::puts (const char *buf) 371 { 372 while (*buf != '\0') 373 { 374 const char *esc = strchr (buf, '\033'); 375 if (esc == nullptr) 376 break; 377 378 int n_read = 0; 379 if (!skip_ansi_escape (esc, &n_read)) 380 ++esc; 381 382 this->stdio_file::write (buf, esc - buf); 383 buf = esc + n_read; 384 } 385 386 if (*buf != '\0') 387 this->stdio_file::write (buf, strlen (buf)); 388 } 389