ui-file.c 9.4 KB

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