Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy

This patch starts from the desire to eliminate
make_cleanup_ui_file_delete, but then goes beyond.  It makes ui_file &
friends a real C++ class hierarchy, and switches temporary
ui_file-like objects to stack-based allocation.

- mem_fileopen -> string_file

mem_fileopen is replaced with a new string_file class that is treated
as a value class created on the stack.  This alone eliminates most
make_cleanup_ui_file_delete calls, and, simplifies code a whole lot
(diffstat shows around 1k loc dropped.)

string_file's internal buffer is a std::string, thus the "string" in
the name.  This simplifies the implementation much, compared to
mem_fileopen, which managed growing its internal buffer manually.

- ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone

The new string_file class has a string() method that provides direct
writable access to the internal std::string buffer.  This replaced
ui_file_as_string, which forced a copy of the same data the stream had
inside.  With direct access via a writable reference, we can instead
move the string out of the string_stream, avoiding deep string
copying.

Related, ui_file_xstrdup calls are replaced with xstrdup'ping the
stream's string, and ui_file_obsavestring is replaced by
obstack_copy0.

With all those out of the way, getting rid of the weird ui_file_put
mechanism was possible.

- New ui_file::printf, ui_file::puts, etc. methods

These simplify / clarify client code.  I considered splitting
client-code changes, like these, e.g.:

  -  stb = mem_fileopen ();
  -  fprintf_unfiltered (stb, "%s%s%s",
  -		      _("The valid values are:\n"),
  -		      regdesc,
  -		      _("The default is \"std\"."));
  +  string_file stb;
  +  stb.printf ("%s%s%s",
  +	      _("The valid values are:\n"),
  +	      regdesc,
  +	      _("The default is \"std\"."));

In two steps, with the first step leaving fprintf_unfiltered (etc.)
calls in place, and only afterwards do a pass to change all those to
call stb.printf etc..  I didn't do that split, because (when I tried),
it turned out to be pointless make-work: the first pass would have to
touch the fprintf_unfiltered line anyway, to replace "stb" with
"&stb".

- gdb_fopen replaced with stack-based objects

This avoids the need for cleanups or unique_ptr's.  I.e., this:

      struct ui_file *file = gdb_fopen (filename, "w");
      if (filename == NULL)
 	perror_with_name (filename);
      cleanups = make_cleanup_ui_file_delete (file);
      // use file.
      do_cleanups (cleanups);

is replaced with this:

      stdio_file file;
      if (!file.open (filename, "w"))
 	perror_with_name (filename);
      // use file.

- odd contorsions in null_file_write / null_file_fputs around when to
  call to_fputs / to_write eliminated.

- Global null_stream object

A few places that were allocating a ui_file in order to print to
"nowhere" are adjusted to instead refer to a new 'null_stream' global
stream.

- TUI's tui_sfileopen eliminated.  TUI's ui_file much simplified

The TUI's ui_file was serving a dual purpose.  It supported being used
as string buffer, and supported being backed by a stdio FILE.  The
string buffer part is gone, replaced by using of string_file.  The
'FILE *' support is now much simplified, by making the TUI's ui_file
inherit from stdio_file.

gdb/ChangeLog:
2017-02-02  Pedro Alves  <palves@redhat.com>

	* ada-lang.c (type_as_string): Use string_file.
	* ada-valprint.c (ada_print_floating): Use string_file.
	* ada-varobj.c (ada_varobj_scalar_image)
	(ada_varobj_get_value_image): Use string_file.
	* aix-thread.c (aix_thread_extra_thread_info): Use string_file.
	* arm-tdep.c (_initialize_arm_tdep): Use string_printf.
	* breakpoint.c (update_inserted_breakpoint_locations)
	(insert_breakpoint_locations, reattach_breakpoints)
	(print_breakpoint_location, print_one_detail_ranged_breakpoint)
	(print_it_watchpoint): Use string_file.
	(save_breakpoints): Use stdio_file.
	* c-exp.y (oper): Use string_file.
	* cli/cli-logging.c (set_logging_redirect): Use ui_file_up and
	tee_file.
	(pop_output_files): Use delete.
	(handle_redirections): Use stdio_file and tee_file.
	* cli/cli-setshow.c (do_show_command): Use string_file.
	* compile/compile-c-support.c (c_compute_program): Use
	string_file.
	* compile/compile-c-symbols.c (generate_vla_size): Take a
	'string_file &' instead of a 'ui_file *'.
	(generate_c_for_for_one_variable): Take a 'string_file &' instead
	of a 'ui_file *'.  Use string_file.
	(generate_c_for_variable_locations): Take a 'string_file &'
	instead of a 'ui_file *'.
	* compile/compile-internal.h (generate_c_for_for_one_variable):
	Take a 'string_file &' instead of a 'ui_file *'.
	* compile/compile-loc2c.c (push, pushf, unary, binary)
	(print_label, pushf_register_address, pushf_register)
	(do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a
	'ui_file *'.  Adjust.
	* compile/compile.c (compile_to_object): Use string_file.
	* compile/compile.h (compile_dwarf_expr_to_c)
	(compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a
	'ui_file *'.
	* cp-support.c (inspect_type): Use string_file and obstack_copy0.
	(replace_typedefs_qualified_name): Use string_file and
	obstack_copy0.
	* disasm.c (gdb_pretty_print_insn): Use string_file.
	(gdb_disassembly): Adjust reference the null_stream global.
	(do_ui_file_delete): Delete.
	(gdb_insn_length): Use null_stream.
	* dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file.
	* dwarf2loc.c (dwarf2_compile_property_to_c)
	(locexpr_generate_c_location, loclist_generate_c_location): Take a
	'string_file &' instead of a 'ui_file *'.
	* dwarf2loc.h (dwarf2_compile_property_to_c): Likewise.
	* dwarf2read.c (do_ui_file_peek_last): Delete.
	(dwarf2_compute_name): Use string_file.
	* event-top.c (gdb_setup_readline): Use stdio_file.
	* gdbarch.sh (verify_gdbarch): Use string_file.
	* gdbtypes.c (safe_parse_type): Use null_stream.
	* guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use
	string_file.
	* guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a
	'string_file *' instead of a 'ui_file *'.
	(gdbscm_arch_disassemble): Use string_file.
	* guile/scm-frame.c (frscm_print_frame_smob): Use string_file.
	* guile/scm-ports.c (class ioscm_file_port): Now a class that
	inherits from ui_file.
	(ioscm_file_port_delete, ioscm_file_port_rewind)
	(ioscm_file_port_put): Delete.
	(ioscm_file_port_write): Rename to ...
	(ioscm_file_port::write): ... this.  Remove file_port_magic
	checks.
	(ioscm_file_port_new): Delete.
	(ioscm_with_output_to_port_worker): Use ioscm_file_port and
	ui_file_up.
	* guile/scm-type.c (tyscm_type_name): Use string_file.
	* guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print):
	Use string_file.
	* infcmd.c (print_return_value_1): Use string_file.
	* infrun.c (print_target_wait_results): Use string_file.
	* language.c (add_language): Use string_file.
	* location.c (explicit_to_string_internal): Use string_file.
	* main.c (captured_main_1): Use null_file.
	* maint.c (maintenance_print_architecture): Use stdio_file.
	* mi/mi-cmd-stack.c (list_arg_or_local): Use string_file.
	* mi/mi-common.h (struct mi_interp) <out, err, log, targ,
	event_channel>: Change type to mi_console_file pointer.
	* mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush)
	(mi_console_file_delete): Delete.
	(struct mi_console_file): Delete.
	(mi_console_file_magic): Delete.
	(mi_console_file_new): Delete.
	(mi_console_file::mi_console_file): New.
	(mi_console_file_delete): Delete.
	(mi_console_file_fputs): Delete.
	(mi_console_file::write): New.
	(mi_console_raw_packet): Delete.
	(mi_console_file::flush): New.
	(mi_console_file_flush): Delete.
	(mi_console_set_raw): Rename to ...
	(mi_console_file::set_raw): ... this.
	* mi/mi-console.h (class mi_console_file): New class.
	(mi_console_file_new, mi_console_set_raw): Delete.
	* mi/mi-interp.c (mi_interpreter_init): Use mi_console_file.
	(mi_set_logging): Use delete and tee_file.  Adjust.
	* mi/mi-main.c (output_register): Use string_file.
	(mi_cmd_data_evaluate_expression): Use string_file.
	(mi_cmd_data_read_memory): Use string_file.
	(mi_cmd_execute, print_variable_or_computed): Use string_file.
	* mi/mi-out.c (mi_ui_out::main_stream): New.
	(mi_ui_out::rewind): Use main_stream and
	string_file.
	(mi_ui_out::put): Use main_stream and string_file.
	(mi_ui_out::mi_ui_out): Remove 'stream' parameter.
	Allocate a 'string_file' instead.
	(mi_out_new): Don't allocate a mem_fileopen stream here.
	* mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter.
	(mi_ui_out::main_stream): Declare method.
	* printcmd.c (eval_command): Use string_file.
	* psymtab.c (maintenance_print_psymbols): Use stdio_file.
	* python/py-arch.c (archpy_disassemble): Use string_file.
	* python/py-breakpoint.c (bppy_get_commands): Use string_file.
	* python/py-frame.c (frapy_str): Use string_file.
	* python/py-framefilter.c (py_print_type, py_print_single_arg):
	Use string_file.
	* python/py-type.c (typy_str): Use string_file.
	* python/py-unwind.c (unwind_infopy_str): Use string_file.
	* python/py-value.c (valpy_str): Use string_file.
	* record-btrace.c (btrace_insn_history): Use string_file.
	* regcache.c (regcache_print): Use stdio_file.
	* reggroups.c (maintenance_print_reggroups): Use stdio_file.
	* remote.c (escape_buffer): Use string_file.
	* rust-lang.c (rust_get_disr_info): Use string_file.
	* serial.c (serial_open_ops_1): Use stdio_file.
	(do_serial_close): Use delete.
	* stack.c (print_frame_arg): Use string_file.
	(print_frame_args): Remove local mem_fileopen stream, not used.
	(print_frame): Use string_file.
	* symmisc.c (maintenance_print_symbols): Use stdio_file.
	* symtab.h (struct symbol_computed_ops) <generate_c_location>:
	Take a 'string_file *' instead of a 'ui_file *'.
	* top.c (new_ui): Use stdio_file and stderr_file.
	(free_ui): Use delete.
	(execute_command_to_string): Use string_file.
	(quit_confirm): Use string_file.
	* tracepoint.c (collection_list::append_exp): Use string_file.
	* tui/tui-disasm.c (tui_disassemble): Use string_file.
	* tui/tui-file.c: Don't include "ui-file.h".
	(enum streamtype, struct tui_stream): Delete.
	(tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen)
	(tui_file_isatty, tui_file_rewind, tui_file_put): Delete.
	(tui_file::tui_file): New method.
	(tui_file_fputs): Delete.
	(tui_file_get_strbuf): Delete.
	(tui_file::puts): New method.
	(tui_file_adjust_strbuf): Delete.
	(tui_file_flush): Delete.
	(tui_file::flush): New method.
	* tui/tui-file.h: Tweak intro comment.
	Include ui-file.h.
	(tui_fileopen, tui_sfileopen, tui_file_get_strbuf)
	(tui_file_adjust_strbuf): Delete declarations.
	(class tui_file): New class.
	* tui/tui-io.c (tui_initialize_io): Use tui_file.
	* tui/tui-regs.c (tui_restore_gdbout): Use delete.
	(tui_register_format): Use string_stream.
	* tui/tui-stack.c (tui_make_status_line): Use string_file.
	(tui_get_function_from_frame): Use string_file.
	* typeprint.c (type_to_string): Use string_file.
	* ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete.
	(null_stream): New global.
	(ui_file_delete): Delete.
	(ui_file::ui_file): New.
	(null_file_isatty): Delete.
	(ui_file::~ui_file): New.
	(null_file_rewind): Delete.
	(ui_file::printf): New.
	(null_file_put): Delete.
	(null_file_flush): Delete.
	(ui_file::putstr): New.
	(null_file_write): Delete.
	(ui_file::putstrn): New.
	(null_file_read): Delete.
	(ui_file::putc): New.
	(null_file_fputs): Delete.
	(null_file_write_async_safe): Delete.
	(ui_file::vprintf): New.
	(null_file_delete): Delete.
	(null_file::write): New.
	(null_file_fseek): Delete.
	(null_file::puts): New.
	(ui_file_data): Delete.
	(null_file::write_async_safe): New.
	(gdb_flush, ui_file_isatty): Adjust.
	(ui_file_put, ui_file_rewind): Delete.
	(ui_file_write): Adjust.
	(ui_file_write_for_put): Delete.
	(ui_file_write_async_safe, ui_file_read): Adjust.
	(ui_file_fseek): Delete.
	(fputs_unfiltered): Adjust.
	(set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind)
	(set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe)
	(set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek)
	(set_ui_file_data): Delete.
	(string_file::~string_file, string_file::write)
	(struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup)
	(do_ui_file_as_string, ui_file_as_string): Delete.
	(do_ui_file_obsavestring, ui_file_obsavestring): Delete.
	(struct mem_file): Delete.
	(mem_file_new): Delete.
	(stdio_file::stdio_file): New.
	(mem_file_delete): Delete.
	(stdio_file::stdio_file): New.
	(mem_fileopen): Delete.
	(stdio_file::~stdio_file): New.
	(mem_file_rewind): Delete.
	(stdio_file::set_stream): New.
	(mem_file_put): Delete.
	(stdio_file::open): New.
	(mem_file_write): Delete.
	(stdio_file_magic, struct stdio_file): Delete.
	(stdio_file_new, stdio_file_delete, stdio_file_flush): Delete.
	(stdio_file::flush): New.
	(stdio_file_read): Rename to ...
	(stdio_file::read): ... this.  Adjust.
	(stdio_file_write): Rename to ...
	(stdio_file::write): ... this.  Adjust.
	(stdio_file_write_async_safe): Rename to ...
	(stdio_file::write_async_safe) ... this.  Adjust.
	(stdio_file_fputs): Rename to ...
	(stdio_file::puts) ... this.  Adjust.
	(stdio_file_isatty): Delete.
	(stdio_file_fseek): Delete.
	(stdio_file::isatty): New.
	(stderr_file_write): Rename to ...
	(stderr_file::write) ... this.  Adjust.
	(stderr_file_fputs): Rename to ...
	(stderr_file::puts) ... this.  Adjust.
	(stderr_fileopen, stdio_fileopen, gdb_fopen): Delete.
	(stderr_file::stderr_file): New.
	(tee_file_magic): Delete.
	(struct tee_file): Delete.
	(tee_file::tee_file): New.
	(tee_file_new): Delete.
	(tee_file::~tee_file): New.
	(tee_file_delete): Delete.
	(tee_file_flush): Rename to ...
	(tee_file::flush): ... this.  Adjust.
	(tee_file_write): Rename to ...
	(tee_file::write): ... this.  Adjust.
	(tee_file::write_async_safe): New.
	(tee_file_fputs): Rename to ...
	(tee_file::puts): ... this.  Adjust.
	(tee_file_isatty): Rename to ...
	(tee_file::isatty): ... this.  Adjust.
	* ui-file.h (struct obstack, struct ui_file): Don't
	forward-declare.
	(ui_file_new, ui_file_flush_ftype, set_ui_file_flush)
	(ui_file_write_ftype)
	(set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs)
	(ui_file_write_async_safe_ftype, set_ui_file_write_async_safe)
	(ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype)
	(set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind)
	(ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put)
	(ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype)
	(set_ui_file_fseek): Delete.
	(ui_file_data, ui_file_delete, ui_file_rewind)
	(struct ui_file): New.
	(ui_file_up): New.
	(class null_file): New.
	(null_stream): Declare.
	(ui_file_write_for_put, ui_file_put): Delete.
	(ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring):
	Delete.
	(ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen)
	(gdb_fopen, tee_file_new): Delete.
	(struct string_file): New.
	(struct stdio_file): New.
	(stdio_file_up): New.
	(struct stderr_file): New.
	(class tee_file): New.
	* ui-out.c (ui_out::field_stream): Take a 'string_file &' instead
	of a 'ui_file *'.  Adjust.
	* ui-out.h (class ui_out) <field_stream>: Likewise.
	* utils.c (do_ui_file_delete, make_cleanup_ui_file_delete)
	(null_stream): Delete.
	(error_stream): Take a 'string_file &' instead of a 'ui_file *'.
	Adjust.
	* utils.h (struct ui_file): Delete forward declaration..
	(make_cleanup_ui_file_delete, null_stream): Delete declarations.
	(error_stream): Take a 'string_file &' instead of a
	'ui_file *'.
	* varobj.c (varobj_value_get_print_value): Use string_file.
	* xtensa-tdep.c (xtensa_verify_config): Use string_file.
	* gdbarch.c: Regenerate.
This commit is contained in:
Pedro Alves
2017-02-02 11:11:47 +00:00
parent 187808b04f
commit d7e747318f
81 changed files with 1364 additions and 2122 deletions

View File

@ -19,140 +19,246 @@
#ifndef UI_FILE_H
#define UI_FILE_H
struct obstack;
struct ui_file;
#include <string>
/* Create a generic ui_file object with null methods. */
/* The abstract ui_file base class. */
extern struct ui_file *ui_file_new (void);
class ui_file
{
public:
ui_file ();
virtual ~ui_file () = 0;
/* Override methods used by specific implementations of a UI_FILE
object. */
/* Public non-virtual API. */
typedef void (ui_file_flush_ftype) (struct ui_file *stream);
extern void set_ui_file_flush (struct ui_file *stream,
ui_file_flush_ftype *flush);
void printf (const char *, ...) ATTRIBUTE_PRINTF (2, 3);
/* NOTE: Both fputs and write methods are available. Default
implementations that mapping one onto the other are included. */
typedef void (ui_file_write_ftype) (struct ui_file *stream,
const char *buf, long length_buf);
extern void set_ui_file_write (struct ui_file *stream,
ui_file_write_ftype *fputs);
/* Print a string whose delimiter is QUOTER. Note that these
routines should only be called for printing things which are
independent of the language of the program being debugged. */
void putstr (const char *str, int quoter);
typedef void (ui_file_fputs_ftype) (const char *, struct ui_file *stream);
extern void set_ui_file_fputs (struct ui_file *stream,
ui_file_fputs_ftype *fputs);
void putstrn (const char *str, int n, int quoter);
/* This version of "write" is safe for use in signal handlers.
It's not guaranteed that all existing output will have been
flushed first.
Implementations are also free to ignore some or all of the request.
fputs_async is not provided as the async versions are rarely used,
no point in having both for a rarely used interface. */
typedef void (ui_file_write_async_safe_ftype)
(struct ui_file *stream, const char *buf, long length_buf);
extern void set_ui_file_write_async_safe
(struct ui_file *stream, ui_file_write_async_safe_ftype *write_async_safe);
int putc (int c);
typedef long (ui_file_read_ftype) (struct ui_file *stream,
char *buf, long length_buf);
extern void set_ui_file_read (struct ui_file *stream,
ui_file_read_ftype *fread);
void vprintf (const char *, va_list) ATTRIBUTE_PRINTF (2, 0);
typedef int (ui_file_isatty_ftype) (struct ui_file *stream);
extern void set_ui_file_isatty (struct ui_file *stream,
ui_file_isatty_ftype *isatty);
/* Methods below are both public, and overridable by ui_file
subclasses. */
typedef void (ui_file_rewind_ftype) (struct ui_file *stream);
extern void set_ui_file_rewind (struct ui_file *stream,
ui_file_rewind_ftype *rewind);
virtual void write (const char *buf, long length_buf) = 0;
typedef void (ui_file_put_method_ftype) (void *object, const char *buffer,
long length_buffer);
typedef void (ui_file_put_ftype) (struct ui_file *stream,
ui_file_put_method_ftype *method,
void *context);
extern void set_ui_file_put (struct ui_file *stream, ui_file_put_ftype *put);
/* This version of "write" is safe for use in signal handlers. It's
not guaranteed that all existing output will have been flushed
first. Implementations are also free to ignore some or all of
the request. puts_async is not provided as the async versions
are rarely used, no point in having both for a rarely used
interface. */
virtual void write_async_safe (const char *buf, long length_buf)
{ gdb_assert_not_reached ("write_async_safe"); }
typedef void (ui_file_delete_ftype) (struct ui_file * stream);
extern void set_ui_file_data (struct ui_file *stream, void *data,
ui_file_delete_ftype *to_delete);
/* Some ui_files override this to provide a efficient implementation
that avoids a strlen. */
virtual void puts (const char *str)
{ this->write (str, strlen (str)); }
typedef int (ui_file_fseek_ftype) (struct ui_file *stream, long offset,
int whence);
extern void set_ui_file_fseek (struct ui_file *stream,
ui_file_fseek_ftype *fseek_ptr);
virtual long read (char *buf, long length_buf)
{ gdb_assert_not_reached ("can't read from this file type"); }
extern void *ui_file_data (struct ui_file *file);
virtual bool isatty ()
{ return false; }
virtual void flush ()
{}
};
extern void gdb_flush (struct ui_file *);
typedef std::unique_ptr<ui_file> ui_file_up;
extern void ui_file_delete (struct ui_file *stream);
/* A ui_file that writes to nowhere. */
extern void ui_file_rewind (struct ui_file *stream);
class null_file : public ui_file
{
public:
void write (const char *buf, long length_buf) override;
void write_async_safe (const char *buf, long sizeof_buf) override;
void puts (const char *str) override;
};
/* A preallocated null_file stream. */
extern null_file null_stream;
extern void gdb_flush (ui_file *);
extern int ui_file_isatty (struct ui_file *);
extern void ui_file_write (struct ui_file *file, const char *buf,
long length_buf);
/* A wrapper for ui_file_write that is suitable for use by
ui_file_put. */
extern void ui_file_write_for_put (void *data, const char *buffer,
long length_buffer);
extern void ui_file_write_async_safe (struct ui_file *file, const char *buf,
long length_buf);
/* NOTE: copies left to right. */
extern void ui_file_put (struct ui_file *src,
ui_file_put_method_ftype *write, void *dest);
/* Returns a freshly allocated buffer containing the entire contents
of FILE (as determined by ui_file_put()) with a NUL character
appended. LENGTH, if not NULL, is set to the size of the buffer
minus that appended NUL. */
extern char *ui_file_xstrdup (struct ui_file *file, long *length);
/* Returns a std::string containing the entire contents of FILE (as
determined by ui_file_put()). */
extern std::string ui_file_as_string (struct ui_file *file);
/* Similar to ui_file_xstrdup, but return a new string allocated on
OBSTACK. */
extern char *ui_file_obsavestring (struct ui_file *file,
struct obstack *obstack, long *length);
extern long ui_file_read (struct ui_file *file, char *buf, long length_buf);
extern int ui_file_fseek (struct ui_file *file, long offset, int whence);
/* A std::string-based ui_file. Can be used as a scratch buffer for
collecting output. */
/* Create/open a memory based file. Can be used as a scratch buffer
for collecting output. */
extern struct ui_file *mem_fileopen (void);
class string_file : public ui_file
{
public:
string_file () {}
~string_file () override;
/* Override ui_file methods. */
void write (const char *buf, long length_buf) override;
/* Open/create a STDIO based UI_FILE using the already open FILE. */
extern struct ui_file *stdio_fileopen (FILE *file);
long read (char *buf, long length_buf) override
{ gdb_assert_not_reached ("a string_file is not readable"); }
/* Likewise, for stderr-like streams. */
extern struct ui_file *stderr_fileopen (FILE *file);
/* string_file-specific public API. */
/* Accesses the std::string containing the entire output collected
so far.
/* Open NAME returning an STDIO based UI_FILE. */
extern struct ui_file *gdb_fopen (const char *name, const char *mode);
Returns a non-const reference so that it's easy to move the
string contents out of the string_file. E.g.:
string_file buf;
buf.printf (....);
buf.printf (....);
return std::move (buf.string ());
*/
std::string &string () { return m_string; }
/* Provide a few convenience methods with the same API as the
underlying std::string. */
const char *data () const { return m_string.data (); }
const char *c_str () const { return m_string.c_str (); }
size_t size () const { return m_string.size (); }
bool empty () const { return m_string.empty (); }
void clear () { return m_string.clear (); }
private:
/* The internal buffer. */
std::string m_string;
};
/* A ui_file implementation that maps directly onto <stdio.h>'s FILE.
A stdio_file can either own its underlying file, or not. If it
owns the file, then destroying the stdio_file closes the underlying
file, otherwise it is left open. */
class stdio_file : public ui_file
{
public:
/* Create a ui_file from a previously opened FILE. CLOSE_P
indicates whether the underlying file should be closed when the
stdio_file is destroyed. */
explicit stdio_file (FILE *file, bool close_p = false);
/* Create an stdio_file that is not managing any file yet. Call
open to actually open something. */
stdio_file ();
~stdio_file () override;
/* Open NAME in mode MODE, and own the resulting file. Returns true
on success, false otherwise. If the stdio_file previously owned
a file, it is closed. */
bool open (const char *name, const char *mode);
void flush () override;
void write (const char *buf, long length_buf) override;
void write_async_safe (const char *buf, long length_buf) override;
void puts (const char *) override;
long read (char *buf, long length_buf) override;
bool isatty () override;
private:
/* Sets the internal stream to FILE, and saves the FILE's file
descriptor in M_FD. */
void set_stream (FILE *file);
/* The file. */
FILE *m_file;
/* The associated file descriptor is extracted ahead of time for
stdio_file::write_async_safe's benefit, in case fileno isn't
async-safe. */
int m_fd;
/* If true, M_FILE is closed on destruction. */
bool m_close_p;
};
typedef std::unique_ptr<stdio_file> stdio_file_up;
/* Like stdio_file, but specifically for stderr.
This exists because there is no real line-buffering on Windows, see
<http://msdn.microsoft.com/en-us/library/86cebhfs%28v=vs.71%29.aspx>
so the stdout is either fully-buffered or non-buffered. We can't
make stdout non-buffered, because of two concerns:
1. Non-buffering hurts performance.
2. Non-buffering may change GDB's behavior when it is interacting
with a front-end, such as Emacs.
We leave stdout as fully buffered, but flush it first when
something is written to stderr.
Note that the 'write_async_safe' method is not overridden, because
there's no way to flush a stream in an async-safe manner.
Fortunately, it doesn't really matter, because:
1. That method is only used for printing internal debug output
from signal handlers.
2. Windows hosts don't have a concept of async-safeness. Signal
handlers run in a separate thread, so they can call the regular
non-async-safe output routines freely.
*/
class stderr_file : public stdio_file
{
public:
explicit stderr_file (FILE *stream);
/* Override the output routines to flush gdb_stdout before deferring
to stdio_file for the actual outputting. */
void write (const char *buf, long length_buf) override;
void puts (const char *linebuffer) override;
};
/* A ui_file implementation that maps onto two ui-file objects. */
class tee_file : public ui_file
{
public:
/* Create a file which writes to both ONE and TWO. CLOSE_ONE and
CLOSE_TWO indicate whether the original files should be closed
when the new file is closed. */
tee_file (ui_file *one, bool close_one,
ui_file *two, bool close_two);
~tee_file () override;
void write (const char *buf, long length_buf) override;
void write_async_safe (const char *buf, long length_buf) override;
void puts (const char *) override;
bool isatty () override;
void flush () override;
private:
/* The two underlying ui_files, and whether they should each be
closed on destruction. */
ui_file *m_one, *m_two;
bool m_close_one, m_close_two;
};
/* Create a file which writes to both ONE and TWO. CLOSE_ONE
and CLOSE_TWO indicate whether the original files should be
closed when the new file is closed. */
extern struct ui_file *tee_file_new (struct ui_file *one,
int close_one,
struct ui_file *two,
int close_two);
#endif