public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Luis Machado <lgustavo@codesourcery.com>
To: Pedro Alves <palves@redhat.com>, <gdb-patches@sourceware.org>
Subject: Re: [PATCH v4 2/2] Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
Date: Wed, 01 Feb 2017 17:37:00 -0000	[thread overview]
Message-ID: <a1194bed-b33a-d874-2fa2-b0a1ff793eea@codesourcery.com> (raw)
In-Reply-To: <1485909045-30285-3-git-send-email-palves@redhat.com>

Two comments close to the end.

On 01/31/2017 06:30 PM, Pedro Alves wrote:
> 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:
> yyyy-mm-dd  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.
> ---
>  gdb/ada-lang.c                  |  12 +-
>  gdb/ada-valprint.c              |   9 +-
>  gdb/ada-varobj.c                |  23 +-
>  gdb/aix-thread.c                |  18 +-
>  gdb/arm-tdep.c                  |  13 +-
>  gdb/breakpoint.c                |  97 +++--
>  gdb/c-exp.y                     |   8 +-
>  gdb/cli/cli-logging.c           |  55 ++-
>  gdb/cli/cli-setshow.c           |  36 +-
>  gdb/compile/compile-c-support.c |  62 ++--
>  gdb/compile/compile-c-symbols.c |  21 +-
>  gdb/compile/compile-internal.h  |   2 +-
>  gdb/compile/compile-loc2c.c     | 107 +++---
>  gdb/compile/compile.c           |   9 +-
>  gdb/compile/compile.h           |   4 +-
>  gdb/cp-support.c                |  38 +-
>  gdb/disasm-selftests.c          |   4 +-
>  gdb/disasm.c                    |  18 +-
>  gdb/dummy-frame.c               |   9 +-
>  gdb/dwarf2loc.c                 |   6 +-
>  gdb/dwarf2loc.h                 |   2 +-
>  gdb/dwarf2read.c                |  48 +--
>  gdb/event-top.c                 |   4 +-
>  gdb/gdbarch.c                   |  32 +-
>  gdb/gdbarch.sh                  |  20 +-
>  gdb/gdbtypes.c                  |   3 +-
>  gdb/guile/scm-breakpoint.c      |  12 +-
>  gdb/guile/scm-disasm.c          |  16 +-
>  gdb/guile/scm-frame.c           |   9 +-
>  gdb/guile/scm-ports.c           |  95 ++---
>  gdb/guile/scm-type.c            |  14 +-
>  gdb/guile/scm-value.c           |  29 +-
>  gdb/infcmd.c                    |  12 +-
>  gdb/infrun.c                    |  36 +-
>  gdb/language.c                  |  38 +-
>  gdb/location.c                  |  43 +--
>  gdb/main.c                      |   2 +-
>  gdb/maint.c                     |   9 +-
>  gdb/mi/mi-cmd-stack.c           |  17 +-
>  gdb/mi/mi-common.h              |  12 +-
>  gdb/mi/mi-console.c             | 135 ++-----
>  gdb/mi/mi-console.h             |  36 +-
>  gdb/mi/mi-interp.c              |  22 +-
>  gdb/mi/mi-main.c                |  61 ++-
>  gdb/mi/mi-out.c                 |  27 +-
>  gdb/mi/mi-out.h                 |   7 +-
>  gdb/printcmd.c                  |  11 +-
>  gdb/psymtab.c                   |  19 +-
>  gdb/python/py-arch.c            |  30 +-
>  gdb/python/py-breakpoint.c      |  13 +-
>  gdb/python/py-frame.c           |   9 +-
>  gdb/python/py-framefilter.c     |  32 +-
>  gdb/python/py-type.c            |  19 +-
>  gdb/python/py-unwind.c          |  24 +-
>  gdb/python/py-value.c           |  16 +-
>  gdb/regcache.c                  |   9 +-
>  gdb/reggroups.c                 |   9 +-
>  gdb/remote.c                    |  12 +-
>  gdb/rust-lang.c                 |   9 +-
>  gdb/serial.c                    |   9 +-
>  gdb/stack.c                     |  28 +-
>  gdb/symmisc.c                   |  14 +-
>  gdb/symtab.h                    |   2 +-
>  gdb/top.c                       |  51 +--
>  gdb/tracepoint.c                |   7 +-
>  gdb/tui/tui-disasm.c            |  18 +-
>  gdb/tui/tui-file.c              | 230 +-----------
>  gdb/tui/tui-file.h              |  18 +-
>  gdb/tui/tui-io.c                |   4 +-
>  gdb/tui/tui-regs.c              |  21 +-
>  gdb/tui/tui-stack.c             |  33 +-
>  gdb/typeprint.c                 |  17 +-
>  gdb/ui-file.c                   | 802 +++++++---------------------------------
>  gdb/ui-file.h                   | 295 ++++++++++-----
>  gdb/ui-out.c                    |  10 +-
>  gdb/ui-out.h                    |   2 +-
>  gdb/utils.c                     |  33 +-
>  gdb/utils.h                     |   8 +-
>  gdb/varobj.c                    |  29 +-
>  gdb/xtensa-tdep.c               |  31 +-
>  80 files changed, 1058 insertions(+), 2108 deletions(-)
>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 381752b..502710a 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -7602,17 +7602,11 @@ ada_value_struct_elt (struct value *arg, char *name, int no_err)
>  static std::string
>  type_as_string (struct type *type)
>  {
> -  struct ui_file *tmp_stream = mem_fileopen ();
> -  struct cleanup *old_chain;
> -
> -  tmp_stream = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (tmp_stream);
> +  string_file tmp_stream;
>
> -  type_print (type, "", tmp_stream, -1);
> -  std::string str = ui_file_as_string (tmp_stream);
> +  type_print (type, "", &tmp_stream, -1);
>
> -  do_cleanups (old_chain);
> -  return str;
> +  return std::move (tmp_stream.string ());
>  }
>
>  /* Given a type TYPE, look up the type of the component of type named NAME.
> diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
> index 0a9e325..804cf40 100644
> --- a/gdb/ada-valprint.c
> +++ b/gdb/ada-valprint.c
> @@ -298,12 +298,11 @@ static void
>  ada_print_floating (const gdb_byte *valaddr, struct type *type,
>  		    struct ui_file *stream)
>  {
> -  struct ui_file *tmp_stream = mem_fileopen ();
> -  struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_stream);
> +  string_file tmp_stream;
>
> -  print_floating (valaddr, type, tmp_stream);
> +  print_floating (valaddr, type, &tmp_stream);
>
> -  std::string s = ui_file_as_string (tmp_stream);
> +  std::string &s = tmp_stream.string ();
>    size_t skip_count = 0;
>
>    /* Modify for Ada rules.  */
> @@ -342,8 +341,6 @@ ada_print_floating (const gdb_byte *valaddr, struct type *type,
>      }
>    else
>      fprintf_filtered (stream, "%s", &s[skip_count]);
> -
> -  do_cleanups (cleanups);
>  }
>
>  void
> diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
> index 52e3247..34d9c7b 100644
> --- a/gdb/ada-varobj.c
> +++ b/gdb/ada-varobj.c
> @@ -79,14 +79,10 @@ ada_varobj_decode_var (struct value **value_ptr, struct type **type_ptr)
>  static std::string
>  ada_varobj_scalar_image (struct type *type, LONGEST val)
>  {
> -  struct ui_file *buf = mem_fileopen ();
> -  struct cleanup *cleanups = make_cleanup_ui_file_delete (buf);
> +  string_file buf;
>
> -  ada_print_scalar (type, val, buf);
> -  std::string result = ui_file_as_string (buf);
> -  do_cleanups (cleanups);
> -
> -  return result;
> +  ada_print_scalar (type, val, &buf);
> +  return std::move (buf.string ());
>  }
>
>  /* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair designates
> @@ -808,17 +804,10 @@ static std::string
>  ada_varobj_get_value_image (struct value *value,
>  			    struct value_print_options *opts)
>  {
> -  struct ui_file *buffer;
> -  struct cleanup *old_chain;
> -
> -  buffer = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (buffer);
> -
> -  common_val_print (value, buffer, 0, opts, current_language);
> -  std::string result = ui_file_as_string (buffer);
> +  string_file buffer;
>
> -  do_cleanups (old_chain);
> -  return result;
> +  common_val_print (value, &buffer, 0, opts, current_language);
> +  return std::move (buffer.string ());
>  }
>
>  /* Assuming that the (VALUE, TYPE) pair designates an array varobj,
> diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
> index ea64220..cf1a462 100644
> --- a/gdb/aix-thread.c
> +++ b/gdb/aix-thread.c
> @@ -1749,7 +1749,6 @@ static char *
>  aix_thread_extra_thread_info (struct target_ops *self,
>  			      struct thread_info *thread)
>  {
> -  struct ui_file *buf;
>    int status;
>    pthdb_pthread_t pdtid;
>    pthdb_tid_t tid;
> @@ -1762,43 +1761,42 @@ aix_thread_extra_thread_info (struct target_ops *self,
>    if (!PD_TID (thread->ptid))
>      return NULL;
>
> -  buf = mem_fileopen ();
> +  string_file buf;
>
>    pdtid = thread->priv->pdtid;
>    tid = thread->priv->tid;
>
>    if (tid != PTHDB_INVALID_TID)
>      /* i18n: Like "thread-identifier %d, [state] running, suspended" */
> -    fprintf_unfiltered (buf, _("tid %d"), (int)tid);
> +    buf.printf (_("tid %d"), (int)tid);
>
>    status = pthdb_pthread_state (pd_session, pdtid, &state);
>    if (status != PTHDB_SUCCESS)
>      state = PST_NOTSUP;
> -  fprintf_unfiltered (buf, ", %s", state2str (state));
> +  buf.printf (", %s", state2str (state));
>
>    status = pthdb_pthread_suspendstate (pd_session, pdtid,
>  				       &suspendstate);
>    if (status == PTHDB_SUCCESS && suspendstate == PSS_SUSPENDED)
>      /* i18n: Like "Thread-Id %d, [state] running, suspended" */
> -    fprintf_unfiltered (buf, _(", suspended"));
> +    buf.printf (_(", suspended"));
>
>    status = pthdb_pthread_detachstate (pd_session, pdtid,
>  				      &detachstate);
>    if (status == PTHDB_SUCCESS && detachstate == PDS_DETACHED)
>      /* i18n: Like "Thread-Id %d, [state] running, detached" */
> -    fprintf_unfiltered (buf, _(", detached"));
> +    buf.printf (_(", detached"));
>
>    pthdb_pthread_cancelpend (pd_session, pdtid, &cancelpend);
>    if (status == PTHDB_SUCCESS && cancelpend)
>      /* i18n: Like "Thread-Id %d, [state] running, cancel pending" */
> -    fprintf_unfiltered (buf, _(", cancel pending"));
> +    buf.printf (_(", cancel pending"));
>
> -  ui_file_write (buf, "", 1);
> +  buf.write ("", 1);
>
>    xfree (ret);			/* Free old buffer.  */
>
> -  ret = ui_file_xstrdup (buf, NULL);
> -  ui_file_delete (buf);
> +  ret = xstrdup (buf.c_str ());
>
>    return ret;
>  }
> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 0ae311f..88ed391 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -9576,13 +9576,11 @@ extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
>  void
>  _initialize_arm_tdep (void)
>  {
> -  struct ui_file *stb;
>    long length;
>    const char *setname;
>    const char *setdesc;
>    const char *const *regnames;
>    int i;
> -  static std::string helptext;
>    char regdesc[1024], *rdptr = regdesc;
>    size_t rest = sizeof (regdesc);
>
> @@ -9648,13 +9646,10 @@ _initialize_arm_tdep (void)
>    valid_disassembly_styles[num_disassembly_options] = NULL;
>
>    /* Create the help text.  */
> -  stb = mem_fileopen ();
> -  fprintf_unfiltered (stb, "%s%s%s",
> -		      _("The valid values are:\n"),
> -		      regdesc,
> -		      _("The default is \"std\"."));
> -  helptext = ui_file_as_string (stb);
> -  ui_file_delete (stb);
> +  std::string helptext = string_printf ("%s%s%s",
> +					_("The valid values are:\n"),
> +					regdesc,
> +					_("The default is \"std\"."));
>
>    add_setshow_enum_cmd("disassembler", no_class,
>  		       valid_disassembly_styles, &disassembly_style,
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 867dbb9..a76b3e4 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -3061,14 +3061,13 @@ update_inserted_breakpoint_locations (void)
>    int hw_breakpoint_error = 0;
>    int hw_bp_details_reported = 0;
>
> -  struct ui_file *tmp_error_stream = mem_fileopen ();
> -  struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
> +  string_file tmp_error_stream;
>
>    /* Explicitly mark the warning -- this will only be printed if
>       there was an error.  */
> -  fprintf_unfiltered (tmp_error_stream, "Warning:\n");
> +  tmp_error_stream.puts ("Warning:\n");
>
> -  save_current_space_and_thread ();
> +  struct cleanup *cleanups = save_current_space_and_thread ();
>
>    ALL_BP_LOCATIONS (bl, blp_tmp)
>      {
> @@ -3093,7 +3092,7 @@ update_inserted_breakpoint_locations (void)
>  	  && ptid_equal (inferior_ptid, null_ptid))
>  	continue;
>
> -      val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
> +      val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks,
>  				    &hw_breakpoint_error, &hw_bp_details_reported);
>        if (val)
>  	error_flag = val;
> @@ -3121,14 +3120,13 @@ insert_breakpoint_locations (void)
>    int hw_breakpoint_error = 0;
>    int hw_bp_error_explained_already = 0;
>
> -  struct ui_file *tmp_error_stream = mem_fileopen ();
> -  struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
> -
> +  string_file tmp_error_stream;
> +
>    /* Explicitly mark the warning -- this will only be printed if
>       there was an error.  */
> -  fprintf_unfiltered (tmp_error_stream, "Warning:\n");
> +  tmp_error_stream.puts ("Warning:\n");
>
> -  save_current_space_and_thread ();
> +  struct cleanup *cleanups = save_current_space_and_thread ();
>
>    ALL_BP_LOCATIONS (bl, blp_tmp)
>      {
> @@ -3152,7 +3150,7 @@ insert_breakpoint_locations (void)
>  	  && ptid_equal (inferior_ptid, null_ptid))
>  	continue;
>
> -      val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
> +      val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks,
>  				    &hw_breakpoint_error, &hw_bp_error_explained_already);
>        if (val)
>  	error_flag = val;
> @@ -3187,9 +3185,9 @@ insert_breakpoint_locations (void)
>  	      remove_breakpoint (loc);
>
>  	  hw_breakpoint_error = 1;
> -	  fprintf_unfiltered (tmp_error_stream,
> -			      "Could not insert hardware watchpoint %d.\n",
> -			      bpt->number);
> +	  tmp_error_stream.printf ("Could not insert "
> +				   "hardware watchpoint %d.\n",
> +				   bpt->number);
>  	  error_flag = -1;
>  	}
>      }
> @@ -3200,8 +3198,7 @@ insert_breakpoint_locations (void)
>           message about possibly exhausted resources.  */
>        if (hw_breakpoint_error && !hw_bp_error_explained_already)
>  	{
> -	  fprintf_unfiltered (tmp_error_stream,
> -			      "Could not insert hardware breakpoints:\n\
> +	  tmp_error_stream.printf ("Could not insert hardware breakpoints:\n\
>  You may have requested too many hardware breakpoints/watchpoints.\n");
>  	}
>        target_terminal_ours_for_output ();
> @@ -3283,7 +3280,6 @@ reattach_breakpoints (int pid)
>    struct cleanup *old_chain;
>    struct bp_location *bl, **blp_tmp;
>    int val;
> -  struct ui_file *tmp_error_stream;
>    int dummy1 = 0, dummy2 = 0, dummy3 = 0;
>    struct inferior *inf;
>    struct thread_info *tp;
> @@ -3297,8 +3293,7 @@ reattach_breakpoints (int pid)
>
>    inferior_ptid = tp->ptid;
>
> -  tmp_error_stream = mem_fileopen ();
> -  make_cleanup_ui_file_delete (tmp_error_stream);
> +  string_file tmp_error_stream;
>
>    ALL_BP_LOCATIONS (bl, blp_tmp)
>    {
> @@ -3308,7 +3303,7 @@ reattach_breakpoints (int pid)
>      if (bl->inserted)
>        {
>  	bl->inserted = 0;
> -	val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2, &dummy3);
> +	val = insert_bp_location (bl, &tmp_error_stream, &dummy1, &dummy2, &dummy3);
>  	if (val != 0)
>  	  {
>  	    do_cleanups (old_chain);
> @@ -6179,14 +6174,11 @@ print_breakpoint_location (struct breakpoint *b,
>      }
>    else if (loc)
>      {
> -      struct ui_file *stb = mem_fileopen ();
> -      struct cleanup *stb_chain = make_cleanup_ui_file_delete (stb);
> +      string_file stb;
>
> -      print_address_symbolic (loc->gdbarch, loc->address, stb,
> +      print_address_symbolic (loc->gdbarch, loc->address, &stb,
>  			      demangle, "");
>        uiout->field_stream ("at", stb);
> -
> -      do_cleanups (stb_chain);
>      }
>    else
>      {
> @@ -10293,8 +10285,7 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b,
>  {
>    CORE_ADDR address_start, address_end;
>    struct bp_location *bl = b->loc;
> -  struct ui_file *stb = mem_fileopen ();
> -  struct cleanup *cleanup = make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    gdb_assert (bl);
>
> @@ -10302,13 +10293,11 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b,
>    address_end = address_start + bl->length - 1;
>
>    uiout->text ("\taddress range: ");
> -  fprintf_unfiltered (stb, "[%s, %s]",
> -		      print_core_address (bl->gdbarch, address_start),
> -		      print_core_address (bl->gdbarch, address_end));
> +  stb.printf ("[%s, %s]",
> +	      print_core_address (bl->gdbarch, address_start),
> +	      print_core_address (bl->gdbarch, address_end));
>    uiout->field_stream ("addr", stb);
>    uiout->text ("\n");
> -
> -  do_cleanups (cleanup);
>  }
>
>  /* Implement the "print_mention" breakpoint_ops method for
> @@ -10740,7 +10729,6 @@ print_it_watchpoint (bpstat bs)
>  {
>    struct cleanup *old_chain;
>    struct breakpoint *b;
> -  struct ui_file *stb;
>    enum print_stop_action result;
>    struct watchpoint *w;
>    struct ui_out *uiout = current_uiout;
> @@ -10750,12 +10738,13 @@ print_it_watchpoint (bpstat bs)
>    b = bs->breakpoint_at;
>    w = (struct watchpoint *) b;
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  old_chain = make_cleanup (null_cleanup, NULL);
>
>    annotate_watchpoint (b->number);
>    maybe_print_thread_hit_breakpoint (uiout);
>
> +  string_file stb;
> +
>    switch (b->type)
>      {
>      case bp_watchpoint:
> @@ -10766,10 +10755,10 @@ print_it_watchpoint (bpstat bs)
>        mention (b);
>        make_cleanup_ui_out_tuple_begin_end (uiout, "value");
>        uiout->text ("\nOld value = ");
> -      watchpoint_value_print (bs->old_val, stb);
> +      watchpoint_value_print (bs->old_val, &stb);
>        uiout->field_stream ("old", stb);
>        uiout->text ("\nNew value = ");
> -      watchpoint_value_print (w->val, stb);
> +      watchpoint_value_print (w->val, &stb);
>        uiout->field_stream ("new", stb);
>        uiout->text ("\n");
>        /* More than one watchpoint may have been triggered.  */
> @@ -10783,7 +10772,7 @@ print_it_watchpoint (bpstat bs)
>        mention (b);
>        make_cleanup_ui_out_tuple_begin_end (uiout, "value");
>        uiout->text ("\nValue = ");
> -      watchpoint_value_print (w->val, stb);
> +      watchpoint_value_print (w->val, &stb);
>        uiout->field_stream ("value", stb);
>        uiout->text ("\n");
>        result = PRINT_UNKNOWN;
> @@ -10799,7 +10788,7 @@ print_it_watchpoint (bpstat bs)
>  	  mention (b);
>  	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
>  	  uiout->text ("\nOld value = ");
> -	  watchpoint_value_print (bs->old_val, stb);
> +	  watchpoint_value_print (bs->old_val, &stb);
>  	  uiout->field_stream ("old", stb);
>  	  uiout->text ("\nNew value = ");
>  	}
> @@ -10813,7 +10802,7 @@ print_it_watchpoint (bpstat bs)
>  	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
>  	  uiout->text ("\nValue = ");
>  	}
> -      watchpoint_value_print (w->val, stb);
> +      watchpoint_value_print (w->val, &stb);
>        uiout->field_stream ("new", stb);
>        uiout->text ("\n");
>        result = PRINT_UNKNOWN;
> @@ -15669,7 +15658,6 @@ save_breakpoints (char *filename, int from_tty,
>    struct breakpoint *tp;
>    int any = 0;
>    struct cleanup *cleanup;
> -  struct ui_file *fp;
>    int extra_trace_bits = 0;
>
>    if (filename == 0 || *filename == 0)
> @@ -15705,14 +15693,15 @@ save_breakpoints (char *filename, int from_tty,
>
>    filename = tilde_expand (filename);
>    cleanup = make_cleanup (xfree, filename);
> -  fp = gdb_fopen (filename, "w");
> -  if (!fp)
> +
> +  stdio_file fp;
> +
> +  if (!fp.open (filename, "w"))
>      error (_("Unable to open file '%s' for saving (%s)"),
>  	   filename, safe_strerror (errno));
> -  make_cleanup_ui_file_delete (fp);
>
>    if (extra_trace_bits)
> -    save_trace_state_variables (fp);
> +    save_trace_state_variables (&fp);
>
>    ALL_BREAKPOINTS (tp)
>    {
> @@ -15724,23 +15713,23 @@ save_breakpoints (char *filename, int from_tty,
>      if (filter && !filter (tp))
>        continue;
>
> -    tp->ops->print_recreate (tp, fp);
> +    tp->ops->print_recreate (tp, &fp);
>
>      /* Note, we can't rely on tp->number for anything, as we can't
>         assume the recreated breakpoint numbers will match.  Use $bpnum
>         instead.  */
>
>      if (tp->cond_string)
> -      fprintf_unfiltered (fp, "  condition $bpnum %s\n", tp->cond_string);
> +      fp.printf ("  condition $bpnum %s\n", tp->cond_string);
>
>      if (tp->ignore_count)
> -      fprintf_unfiltered (fp, "  ignore $bpnum %d\n", tp->ignore_count);
> +      fp.printf ("  ignore $bpnum %d\n", tp->ignore_count);
>
>      if (tp->type != bp_dprintf && tp->commands)
>        {
> -	fprintf_unfiltered (fp, "  commands\n");
> +	fp.puts ("  commands\n");
>  	
> -	current_uiout->redirect (fp);
> +	current_uiout->redirect (&fp);
>  	TRY
>  	  {
>  	    print_command_lines (current_uiout, tp->commands->commands, 2);
> @@ -15753,11 +15742,11 @@ save_breakpoints (char *filename, int from_tty,
>  	END_CATCH
>
>  	current_uiout->redirect (NULL);
> -	fprintf_unfiltered (fp, "  end\n");
> +	fp.puts ("  end\n");
>        }
>
>      if (tp->enable_state == bp_disabled)
> -      fprintf_unfiltered (fp, "disable $bpnum\n");
> +      fp.puts ("disable $bpnum\n");
>
>      /* If this is a multi-location breakpoint, check if the locations
>         should be individually disabled.  Watchpoint locations are
> @@ -15769,12 +15758,12 @@ save_breakpoints (char *filename, int from_tty,
>
>  	for (loc = tp->loc; loc != NULL; loc = loc->next, n++)
>  	  if (!loc->enabled)
> -	    fprintf_unfiltered (fp, "disable $bpnum.%d\n", n);
> +	    fp.printf ("disable $bpnum.%d\n", n);
>        }
>    }
>
>    if (extra_trace_bits && *default_collect)
> -    fprintf_unfiltered (fp, "set default-collect %s\n", default_collect);
> +    fp.printf ("set default-collect %s\n", default_collect);
>
>    if (from_tty)
>      printf_filtered (_("Saved to file '%s'.\n"), filename);
> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
> index 8a92cce..2753c6e 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -1555,13 +1555,11 @@ oper:	OPERATOR NEW
>  	|	OPERATOR OBJC_LBRAC ']'
>  			{ $$ = operator_stoken ("[]"); }
>  	|	OPERATOR conversion_type_id
> -			{ struct ui_file *buf = mem_fileopen ();
> +			{ string_file buf;
>
> -			  c_print_type ($2, NULL, buf, -1, 0,
> +			  c_print_type ($2, NULL, &buf, -1, 0,
>  					&type_print_raw_options);
> -			  std::string name = ui_file_as_string (buf);
> -			  ui_file_delete (buf);
> -			  $$ = operator_stoken (name.c_str ());
> +			  $$ = operator_stoken (buf.c_str ());
>  			}
>  	;
>
> diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c
> index 9428624..f165896 100644
> --- a/gdb/cli/cli-logging.c
> +++ b/gdb/cli/cli-logging.c
> @@ -76,7 +76,7 @@ static struct ui_file *logging_no_redirect_file;
>  static void
>  set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c)
>  {
> -  struct cleanup *cleanups;
> +  ui_file_up destroy_old_stdout;
>    struct ui_file *output, *new_logging_no_redirect_file;
>    struct ui_out *uiout = current_uiout;
>
> @@ -85,15 +85,13 @@ set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c)
>        || (logging_redirect == 0 && logging_no_redirect_file != NULL))
>      return;
>
> -  cleanups = make_cleanup (null_cleanup, NULL);
> -
>    if (logging_redirect != 0)
>      {
>        gdb_assert (logging_no_redirect_file != NULL);
>
>        /* ui_out_redirect still has not been called for next
>  	 gdb_stdout.  */
> -      make_cleanup_ui_file_delete (gdb_stdout);
> +      destroy_old_stdout.reset (gdb_stdout);
>
>        output = logging_no_redirect_file;
>        new_logging_no_redirect_file = NULL;
> @@ -105,9 +103,7 @@ set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c)
>    else
>      {
>        gdb_assert (logging_no_redirect_file == NULL);
> -      output = tee_file_new (saved_output.out, 0, gdb_stdout, 0);
> -      if (output == NULL)
> -	perror_with_name (_("set logging"));
> +      output = new tee_file (saved_output.out, 0, gdb_stdout, 0);
>        new_logging_no_redirect_file = gdb_stdout;
>
>        if (from_tty)
> @@ -135,8 +131,6 @@ set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c)
>
>    uiout->redirect (NULL);
>    uiout->redirect (output);
> -
> -  do_cleanups (cleanups);
>  }
>
>  static void
> @@ -152,7 +146,7 @@ pop_output_files (void)
>  {
>    if (logging_no_redirect_file)
>      {
> -      ui_file_delete (logging_no_redirect_file);
> +      delete logging_no_redirect_file;
>        logging_no_redirect_file = NULL;
>      }
>
> @@ -160,7 +154,7 @@ pop_output_files (void)
>      {
>        /* Only delete one of the files -- they are all set to the same
>  	 value.  */
> -      ui_file_delete (gdb_stdout);
> +      delete gdb_stdout;
>
>        gdb_stdout = saved_output.out;
>        gdb_stderr = saved_output.err;
> @@ -184,9 +178,8 @@ pop_output_files (void)
>  static void
>  handle_redirections (int from_tty)
>  {
> -  struct cleanup *cleanups;
> -  struct ui_file *output;
> -  struct ui_file *no_redirect_file = NULL;
> +  ui_file_up output;
> +  ui_file_up no_redirect_file;
>
>    if (saved_filename != NULL)
>      {
> @@ -195,36 +188,30 @@ handle_redirections (int from_tty)
>        return;
>      }
>
> -  output = gdb_fopen (logging_filename, logging_overwrite ? "w" : "a");
> -  if (output == NULL)
> +  stdio_file_up log (new stdio_file ());
> +  if (!log->open (logging_filename, logging_overwrite ? "w" : "a"))
>      perror_with_name (_("set logging"));
> -  cleanups = make_cleanup_ui_file_delete (output);
>
>    /* Redirects everything to gdb_stdout while this is running.  */
>    if (!logging_redirect)
>      {
> -      no_redirect_file = output;
> +      no_redirect_file = std::move (log);
> +      output.reset (new tee_file (gdb_stdout, 0, no_redirect_file.get (), 0));
>
> -      output = tee_file_new (gdb_stdout, 0, no_redirect_file, 0);
> -      if (output == NULL)
> -	perror_with_name (_("set logging"));
> -      make_cleanup_ui_file_delete (output);
>        if (from_tty)
>  	fprintf_unfiltered (gdb_stdout, "Copying output to %s.\n",
>  			    logging_filename);
> -      logging_no_redirect_file = no_redirect_file;
>      }
>    else
>      {
>        gdb_assert (logging_no_redirect_file == NULL);
> +      output = std::move (log);
>
>        if (from_tty)
>  	fprintf_unfiltered (gdb_stdout, "Redirecting output to %s.\n",
>  			    logging_filename);
>      }
>
> -  discard_cleanups (cleanups);
> -
>    saved_filename = xstrdup (logging_filename);
>    saved_output.out = gdb_stdout;
>    saved_output.err = gdb_stderr;
> @@ -233,18 +220,22 @@ handle_redirections (int from_tty)
>    saved_output.targerr = gdb_stdtargerr;
>
>    /* Let the interpreter do anything it needs.  */
> -  if (current_interp_set_logging (1, output, no_redirect_file) == 0)
> +  if (current_interp_set_logging (1, output.get (),
> +				  no_redirect_file.get ()) == 0)
>      {
> -      gdb_stdout = output;
> -      gdb_stdlog = output;
> -      gdb_stderr = output;
> -      gdb_stdtarg = output;
> -      gdb_stdtargerr = output;
> +      gdb_stdout = output.get ();
> +      gdb_stdlog = output.get ();
> +      gdb_stderr = output.get ();
> +      gdb_stdtarg = output.get ();
> +      gdb_stdtargerr = output.get ();
>      }
>
> +  output.release ();
> +  logging_no_redirect_file = no_redirect_file.release ();
> +
>    /* Don't do the redirect for MI, it confuses MI's ui-out scheme.  */
>    if (!current_uiout->is_mi_like_p ())
> -    current_uiout->redirect (output);
> +    current_uiout->redirect (gdb_stdout);
>  }
>
>  static void
> diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
> index 9298665..218e1f3 100644
> --- a/gdb/cli/cli-setshow.c
> +++ b/gdb/cli/cli-setshow.c
> @@ -568,13 +568,10 @@ void
>  do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
>  {
>    struct ui_out *uiout = current_uiout;
> -  struct cleanup *old_chain;
> -  struct ui_file *stb;
>
>    gdb_assert (c->type == show_cmd);
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    /* Possibly call the pre hook.  */
>    if (c->pre_show_hook)
> @@ -584,29 +581,29 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
>      {
>      case var_string:
>        if (*(char **) c->var)
> -	fputstr_filtered (*(char **) c->var, '"', stb);
> +	stb.putstr (*(char **) c->var, '"');
>        break;
>      case var_string_noescape:
>      case var_optional_filename:
>      case var_filename:
>      case var_enum:
>        if (*(char **) c->var)
> -	fputs_filtered (*(char **) c->var, stb);
> +	stb.puts (*(char **) c->var);
>        break;
>      case var_boolean:
> -      fputs_filtered (*(int *) c->var ? "on" : "off", stb);
> +      stb.puts (*(int *) c->var ? "on" : "off");
>        break;
>      case var_auto_boolean:
>        switch (*(enum auto_boolean*) c->var)
>  	{
>  	case AUTO_BOOLEAN_TRUE:
> -	  fputs_filtered ("on", stb);
> +	  stb.puts ("on");
>  	  break;
>  	case AUTO_BOOLEAN_FALSE:
> -	  fputs_filtered ("off", stb);
> +	  stb.puts ("off");
>  	  break;
>  	case AUTO_BOOLEAN_AUTO:
> -	  fputs_filtered ("auto", stb);
> +	  stb.puts ("auto");
>  	  break;
>  	default:
>  	  internal_error (__FILE__, __LINE__,
> @@ -619,24 +616,24 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
>      case var_zuinteger:
>        if (c->var_type == var_uinteger
>  	  && *(unsigned int *) c->var == UINT_MAX)
> -	fputs_filtered ("unlimited", stb);
> +	stb.puts ("unlimited");
>        else
> -	fprintf_filtered (stb, "%u", *(unsigned int *) c->var);
> +	stb.printf ("%u", *(unsigned int *) c->var);
>        break;
>      case var_integer:
>      case var_zinteger:
>        if (c->var_type == var_integer
>  	  && *(int *) c->var == INT_MAX)
> -	fputs_filtered ("unlimited", stb);
> +	stb.puts ("unlimited");
>        else
> -	fprintf_filtered (stb, "%d", *(int *) c->var);
> +	stb.printf ("%d", *(int *) c->var);
>        break;
>      case var_zuinteger_unlimited:
>        {
>  	if (*(int *) c->var == -1)
> -	  fputs_filtered ("unlimited", stb);
> +	  stb.puts ("unlimited");
>  	else
> -	  fprintf_filtered (stb, "%d", *(int *) c->var);
> +	  stb.printf ("%d", *(int *) c->var);
>        }
>        break;
>      default:
> @@ -653,14 +650,11 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
>      uiout->field_stream ("value", stb);
>    else
>      {
> -      std::string value = ui_file_as_string (stb);
> -
>        if (c->show_value_func != NULL)
> -	c->show_value_func (gdb_stdout, from_tty, c, value.c_str ());
> +	c->show_value_func (gdb_stdout, from_tty, c, stb.c_str ());
>        else
> -	deprecated_show_value_hack (gdb_stdout, from_tty, c, value.c_str ());
> +	deprecated_show_value_hack (gdb_stdout, from_tty, c, stb.c_str ());
>      }
> -  do_cleanups (old_chain);
>
>    c->func (c, NULL, from_tty);
>  }
> diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
> index 877bfb7..7ad0a87 100644
> --- a/gdb/compile/compile-c-support.c
> +++ b/gdb/compile/compile-c-support.c
> @@ -333,15 +333,12 @@ c_compute_program (struct compile_instance *inst,
>  		   const struct block *expr_block,
>  		   CORE_ADDR expr_pc)
>  {
> -  struct ui_file *buf, *var_stream = NULL;
> -  std::string code;
> -  struct cleanup *cleanup;
>    struct compile_c_instance *context = (struct compile_c_instance *) inst;
>
> -  buf = mem_fileopen ();
> -  cleanup = make_cleanup_ui_file_delete (buf);
> +  string_file buf;
> +  string_file var_stream;
>
> -  write_macro_definitions (expr_block, expr_pc, buf);
> +  write_macro_definitions (expr_block, expr_pc, &buf);
>
>    /* Do not generate local variable information for "raw"
>       compilations.  In this case we aren't emitting our own function
> @@ -355,21 +352,17 @@ c_compute_program (struct compile_instance *inst,
>  	 before generating the function header, so we can define the
>  	 register struct before the function body.  This requires a
>  	 temporary stream.  */
> -      var_stream = mem_fileopen ();
> -      make_cleanup_ui_file_delete (var_stream);
>        registers_used = generate_c_for_variable_locations (context,
>  							  var_stream, gdbarch,
>  							  expr_block, expr_pc);
>        make_cleanup (xfree, registers_used);
>
> -      fputs_unfiltered ("typedef unsigned int"
> -			" __attribute__ ((__mode__(__pointer__)))"
> -			" __gdb_uintptr;\n",
> -			buf);
> -      fputs_unfiltered ("typedef int"
> -			" __attribute__ ((__mode__(__pointer__)))"
> -			" __gdb_intptr;\n",
> -			buf);
> +      buf.puts ("typedef unsigned int"
> +		" __attribute__ ((__mode__(__pointer__)))"
> +		" __gdb_uintptr;\n");
> +      buf.puts ("typedef int"
> +		" __attribute__ ((__mode__(__pointer__)))"
> +		" __gdb_intptr;\n");
>
>        /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size.  */
>        for (i = 0; i < 4; ++i)
> @@ -377,24 +370,23 @@ c_compute_program (struct compile_instance *inst,
>  	  const char *mode = c_get_mode_for_size (1 << i);
>
>  	  gdb_assert (mode != NULL);
> -	  fprintf_unfiltered (buf,
> -			      "typedef int"
> -			      " __attribute__ ((__mode__(__%s__)))"
> -			      " __gdb_int_%s;\n",
> -			      mode, mode);
> +	  buf.printf ("typedef int"
> +		      " __attribute__ ((__mode__(__%s__)))"
> +		      " __gdb_int_%s;\n",
> +		      mode, mode);
>  	}
>
> -      generate_register_struct (buf, gdbarch, registers_used);
> +      generate_register_struct (&buf, gdbarch, registers_used);
>      }
>
> -  add_code_header (inst->scope, buf);
> +  add_code_header (inst->scope, &buf);
>
>    if (inst->scope == COMPILE_I_SIMPLE_SCOPE
>        || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
>        || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE)
>      {
> -      ui_file_put (var_stream, ui_file_write_for_put, buf);
> -      fputs_unfiltered ("#pragma GCC user_expression\n", buf);
> +      buf.write (var_stream.c_str (), var_stream.size ());
> +      buf.puts ("#pragma GCC user_expression\n");
>      }
>
>    /* The user expression has to be in its own scope, so that "extern"
> @@ -402,15 +394,15 @@ c_compute_program (struct compile_instance *inst,
>       declaration is in the same scope as the declaration provided by
>       gdb.  */
>    if (inst->scope != COMPILE_I_RAW_SCOPE)
> -    fputs_unfiltered ("{\n", buf);
> +    buf.puts ("{\n");
>
> -  fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
> +  buf.puts ("#line 1 \"gdb command line\"\n");
>
>    switch (inst->scope)
>      {
>      case COMPILE_I_PRINT_ADDRESS_SCOPE:
>      case COMPILE_I_PRINT_VALUE_SCOPE:
> -      fprintf_unfiltered (buf,
> +      buf.printf (
>  "__auto_type " COMPILE_I_EXPR_VAL " = %s;\n"
>  "typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
>  "memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n"
> @@ -420,22 +412,20 @@ c_compute_program (struct compile_instance *inst,
>  			   ? "&" : ""));
>        break;
>      default:
> -      fputs_unfiltered (input, buf);
> +      buf.puts (input);
>        break;
>      }
>
> -  fputs_unfiltered ("\n", buf);
> +  buf.puts ("\n");
>
>    /* For larger user expressions the automatic semicolons may be
>       confusing.  */
>    if (strchr (input, '\n') == NULL)
> -    fputs_unfiltered (";\n", buf);
> +    buf.puts (";\n");
>
>    if (inst->scope != COMPILE_I_RAW_SCOPE)
> -    fputs_unfiltered ("}\n", buf);
> +    buf.puts ("}\n");
>
> -  add_code_footer (inst->scope, buf);
> -  code = ui_file_as_string (buf);
> -  do_cleanups (cleanup);
> -  return code;
> +  add_code_footer (inst->scope, &buf);
> +  return std::move (buf.string ());
>  }
> diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
> index 6010006..9282cfc 100644
> --- a/gdb/compile/compile-c-symbols.c
> +++ b/gdb/compile/compile-c-symbols.c
> @@ -584,7 +584,7 @@ symbol_seen (htab_t hashtab, struct symbol *sym)
>
>  static void
>  generate_vla_size (struct compile_c_instance *compiler,
> -		   struct ui_file *stream,
> +		   string_file &stream,
>  		   struct gdbarch *gdbarch,
>  		   unsigned char *registers_used,
>  		   CORE_ADDR pc,
> @@ -640,7 +640,7 @@ generate_vla_size (struct compile_c_instance *compiler,
>
>  static void
>  generate_c_for_for_one_variable (struct compile_c_instance *compiler,
> -				 struct ui_file *stream,
> +				 string_file &stream,
>  				 struct gdbarch *gdbarch,
>  				 unsigned char *registers_used,
>  				 CORE_ADDR pc,
> @@ -651,14 +651,14 @@ generate_c_for_for_one_variable (struct compile_c_instance *compiler,
>      {
>        if (is_dynamic_type (SYMBOL_TYPE (sym)))
>  	{
> -	  struct ui_file *size_file = mem_fileopen ();
> -	  struct cleanup *cleanup = make_cleanup_ui_file_delete (size_file);
> +	  /* We need to emit to a temporary buffer in case an error
> +	     occurs in the middle.  */
> +	  string_file local_file;
>
> -	  generate_vla_size (compiler, size_file, gdbarch, registers_used, pc,
> +	  generate_vla_size (compiler, local_file, gdbarch, registers_used, pc,
>  			     SYMBOL_TYPE (sym), sym);
> -	  ui_file_put (size_file, ui_file_write_for_put, stream);
>
> -	  do_cleanups (cleanup);
> +	  stream.write (local_file.c_str (), local_file.size ());
>  	}
>
>        if (SYMBOL_COMPUTED_OPS (sym) != NULL)
> @@ -667,14 +667,13 @@ generate_c_for_for_one_variable (struct compile_c_instance *compiler,
>  	  struct cleanup *cleanup = make_cleanup (xfree, generated_name);
>  	  /* We need to emit to a temporary buffer in case an error
>  	     occurs in the middle.  */
> -	  struct ui_file *local_file = mem_fileopen ();
> +	  string_file local_file;
>
> -	  make_cleanup_ui_file_delete (local_file);
>  	  SYMBOL_COMPUTED_OPS (sym)->generate_c_location (sym, local_file,
>  							  gdbarch,
>  							  registers_used,
>  							  pc, generated_name);
> -	  ui_file_put (local_file, ui_file_write_for_put, stream);
> +	  stream.write (local_file.c_str (), local_file.size ());
>
>  	  do_cleanups (cleanup);
>  	}
> @@ -719,7 +718,7 @@ generate_c_for_for_one_variable (struct compile_c_instance *compiler,
>
>  unsigned char *
>  generate_c_for_variable_locations (struct compile_c_instance *compiler,
> -				   struct ui_file *stream,
> +				   string_file &stream,
>  				   struct gdbarch *gdbarch,
>  				   const struct block *block,
>  				   CORE_ADDR pc)
> diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
> index 4bf5bf9..0c53f8c 100644
> --- a/gdb/compile/compile-internal.h
> +++ b/gdb/compile/compile-internal.h
> @@ -135,7 +135,7 @@ extern struct compile_instance *new_compile_instance (struct gcc_c_context *fe);
>
>  extern unsigned char *generate_c_for_variable_locations
>       (struct compile_c_instance *compiler,
> -      struct ui_file *stream,
> +      string_file &stream,
>        struct gdbarch *gdbarch,
>        const struct block *block,
>        CORE_ADDR pc);
> diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
> index 81684d1..f1296e8 100644
> --- a/gdb/compile/compile-loc2c.c
> +++ b/gdb/compile/compile-loc2c.c
> @@ -435,9 +435,9 @@ compute_stack_depth (enum bfd_endian byte_order, unsigned int addr_size,
>  /* Emit code to push a constant.  */
>
>  static void
> -push (int indent, struct ui_file *stream, ULONGEST l)
> +push (int indent, string_file &stream, ULONGEST l)
>  {
> -  fprintfi_filtered (indent, stream,
> +  fprintfi_filtered (indent, &stream,
>  		     "__gdb_stack[++__gdb_tos] = (" GCC_UINTPTR ") %s;\n",
>  		     hex_string (l));
>  }
> @@ -445,57 +445,57 @@ push (int indent, struct ui_file *stream, ULONGEST l)
>  /* Emit code to push an arbitrary expression.  This works like
>     printf.  */
>
> -static void pushf (int indent, struct ui_file *stream, const char *format, ...)
> +static void pushf (int indent, string_file &stream, const char *format, ...)
>    ATTRIBUTE_PRINTF (3, 4);
>
>  static void
> -pushf (int indent, struct ui_file *stream, const char *format, ...)
> +pushf (int indent, string_file &stream, const char *format, ...)
>  {
>    va_list args;
>
> -  fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos + 1] = ");
> +  fprintfi_filtered (indent, &stream, "__gdb_stack[__gdb_tos + 1] = ");
>    va_start (args, format);
> -  vfprintf_filtered (stream, format, args);
> +  stream.vprintf (format, args);
>    va_end (args);
> -  fprintf_filtered (stream, ";\n");
> +  stream.puts (";\n");
>
> -  fprintfi_filtered (indent, stream, "++__gdb_tos;\n");
> +  fprintfi_filtered (indent, &stream, "++__gdb_tos;\n");
>  }
>
>  /* Emit code for a unary expression -- one which operates in-place on
>     the top-of-stack.  This works like printf.  */
>
> -static void unary (int indent, struct ui_file *stream, const char *format, ...)
> +static void unary (int indent, string_file &stream, const char *format, ...)
>    ATTRIBUTE_PRINTF (3, 4);
>
>  static void
> -unary (int indent, struct ui_file *stream, const char *format, ...)
> +unary (int indent, string_file &stream, const char *format, ...)
>  {
>    va_list args;
>
> -  fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos] = ");
> +  fprintfi_filtered (indent, &stream, "__gdb_stack[__gdb_tos] = ");
>    va_start (args, format);
> -  vfprintf_filtered (stream, format, args);
> +  stream.vprintf (format, args);
>    va_end (args);
> -  fprintf_filtered (stream, ";\n");
> +  stream.puts (";\n");
>  }
>
>  /* Emit code for a unary expression -- one which uses the top two
>     stack items, popping the topmost one.  This works like printf.  */
> -static void binary (int indent, struct ui_file *stream, const char *format, ...)
> +static void binary (int indent, string_file &stream, const char *format, ...)
>    ATTRIBUTE_PRINTF (3, 4);
>
>  static void
> -binary (int indent, struct ui_file *stream, const char *format, ...)
> +binary (int indent, string_file &stream, const char *format, ...)
>  {
>    va_list args;
>
> -  fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos - 1] = ");
> +  fprintfi_filtered (indent, &stream, "__gdb_stack[__gdb_tos - 1] = ");
>    va_start (args, format);
> -  vfprintf_filtered (stream, format, args);
> +  stream.vprintf (format, args);
>    va_end (args);
> -  fprintf_filtered (stream, ";\n");
> -  fprintfi_filtered (indent, stream, "--__gdb_tos;\n");
> +  stream.puts (";\n");
> +  fprintfi_filtered (indent, &stream, "--__gdb_tos;\n");
>  }
>
>  /* Print the name of a label given its "SCOPE", an arbitrary integer
> @@ -503,10 +503,9 @@ binary (int indent, struct ui_file *stream, const char *format, ...)
>     corresponding to the label's point of definition.  */
>
>  static void
> -print_label (struct ui_file *stream, unsigned int scope, int target)
> +print_label (string_file &stream, unsigned int scope, int target)
>  {
> -  fprintf_filtered (stream, "__label_%u_%s",
> -		    scope, pulongest (target));
> +  stream.printf ("__label_%u_%s", scope, pulongest (target));
>  }
>
>  /* Emit code that pushes a register's address on the stack.
> @@ -514,7 +513,7 @@ print_label (struct ui_file *stream, unsigned int scope, int target)
>     register was needed by this expression.  */
>
>  static void
> -pushf_register_address (int indent, struct ui_file *stream,
> +pushf_register_address (int indent, string_file &stream,
>  			unsigned char *registers_used,
>  			struct gdbarch *gdbarch, int regnum)
>  {
> @@ -535,7 +534,7 @@ pushf_register_address (int indent, struct ui_file *stream,
>     register's value before it is pushed.  */
>
>  static void
> -pushf_register (int indent, struct ui_file *stream,
> +pushf_register (int indent, string_file &stream,
>  		unsigned char *registers_used,
>  		struct gdbarch *gdbarch, int regnum, uint64_t offset)
>  {
> @@ -584,7 +583,7 @@ pushf_register (int indent, struct ui_file *stream,
>     things.  */
>
>  static void
> -do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
> +do_compile_dwarf_expr_to_c (int indent, string_file &stream,
>  			    const char *type_name,
>  			    const char *result_name,
>  			    struct symbol *sym, CORE_ADDR pc,
> @@ -609,9 +608,9 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>
>    ++scope;
>
> -  fprintfi_filtered (indent, stream, "__attribute__ ((unused)) %s %s;\n",
> +  fprintfi_filtered (indent, &stream, "__attribute__ ((unused)) %s %s;\n",
>  		     type_name, result_name);
> -  fprintfi_filtered (indent, stream, "{\n");
> +  fprintfi_filtered (indent, &stream, "{\n");
>    indent += 2;
>
>    stack_depth = compute_stack_depth (byte_order, addr_size,
> @@ -648,20 +647,20 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  		 "compiled code."),
>  	       SYMBOL_PRINT_NAME (sym));
>
> -      fprintfi_filtered (indent, stream, "%s = %s;\n",
> +      fprintfi_filtered (indent, &stream, "%s = %s;\n",
>  			 result_name,
>  			 core_addr_to_string (value_address (val)));
> -      fprintfi_filtered (indent - 2, stream, "}\n");
> +      fprintfi_filtered (indent - 2, &stream, "}\n");
>        do_cleanups (cleanup);
>        return;
>      }
>
> -  fprintfi_filtered (indent, stream, GCC_UINTPTR " __gdb_stack[%d];\n",
> +  fprintfi_filtered (indent, &stream, GCC_UINTPTR " __gdb_stack[%d];\n",
>  		     stack_depth);
>
>    if (need_tempvar)
> -    fprintfi_filtered (indent, stream, GCC_UINTPTR " __gdb_tmp;\n");
> -  fprintfi_filtered (indent, stream, "int __gdb_tos = -1;\n");
> +    fprintfi_filtered (indent, &stream, GCC_UINTPTR " __gdb_tmp;\n");
> +  fprintfi_filtered (indent, &stream, "int __gdb_tos = -1;\n");
>
>    if (initial != NULL)
>      pushf (indent, stream, "%s", core_addr_to_string (*initial));
> @@ -672,13 +671,13 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>        uint64_t uoffset, reg;
>        int64_t offset;
>
> -      print_spaces (indent - 2, stream);
> +      print_spaces (indent - 2, &stream);
>        if (info[op_ptr - base].label)
>  	{
>  	  print_label (stream, scope, op_ptr - base);
> -	  fprintf_filtered (stream, ":;");
> +	  stream.puts (":;");
>  	}
> -      fprintf_filtered (stream, "/* %s */\n", get_DW_OP_name (op));
> +      stream.printf ("/* %s */\n", get_DW_OP_name (op));
>
>        /* This is handy for debugging the generated code:
>        fprintf_filtered (stream, "if (__gdb_tos != %d) abort ();\n",
> @@ -919,7 +918,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  	  break;
>
>  	case DW_OP_drop:
> -	  fprintfi_filtered (indent, stream, "--__gdb_tos;\n");
> +	  fprintfi_filtered (indent, &stream, "--__gdb_tos;\n");
>  	  break;
>
>  	case DW_OP_pick:
> @@ -929,13 +928,13 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  	  break;
>
>  	case DW_OP_swap:
> -	  fprintfi_filtered (indent, stream,
> +	  fprintfi_filtered (indent, &stream,
>  			     "__gdb_tmp = __gdb_stack[__gdb_tos - 1];\n");
> -	  fprintfi_filtered (indent, stream,
> +	  fprintfi_filtered (indent, &stream,
>  			     "__gdb_stack[__gdb_tos - 1] = "
>  			     "__gdb_stack[__gdb_tos];\n");
> -	  fprintfi_filtered (indent, stream, ("__gdb_stack[__gdb_tos] = "
> -					      "__gdb_tmp;\n"));
> +	  fprintfi_filtered (indent, &stream, ("__gdb_stack[__gdb_tos] = "
> +					       "__gdb_tmp;\n"));
>  	  break;
>
>  	case DW_OP_over:
> @@ -943,15 +942,15 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  	  break;
>
>  	case DW_OP_rot:
> -	  fprintfi_filtered (indent, stream, ("__gdb_tmp = "
> -					      "__gdb_stack[__gdb_tos];\n"));
> -	  fprintfi_filtered (indent, stream,
> +	  fprintfi_filtered (indent, &stream, ("__gdb_tmp = "
> +					       "__gdb_stack[__gdb_tos];\n"));
> +	  fprintfi_filtered (indent, &stream,
>  			     "__gdb_stack[__gdb_tos] = "
>  			     "__gdb_stack[__gdb_tos - 1];\n");
> -	  fprintfi_filtered (indent, stream,
> +	  fprintfi_filtered (indent, &stream,
>  			     "__gdb_stack[__gdb_tos - 1] = "
>  			     "__gdb_stack[__gdb_tos -2];\n");
> -	  fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos - 2] = "
> +	  fprintfi_filtered (indent, &stream, "__gdb_stack[__gdb_tos - 2] = "
>  			     "__gdb_tmp;\n");
>  	  break;
>
> @@ -973,7 +972,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>
>  	    /* Cast to a pointer of the desired type, then
>  	       dereference.  */
> -	    fprintfi_filtered (indent, stream,
> +	    fprintfi_filtered (indent, &stream,
>  			       "__gdb_stack[__gdb_tos] = "
>  			       "*((__gdb_int_%s *) "
>  			       "__gdb_stack[__gdb_tos]);\n",
> @@ -1099,19 +1098,19 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  	case DW_OP_skip:
>  	  offset = extract_signed_integer (op_ptr, 2, byte_order);
>  	  op_ptr += 2;
> -	  fprintfi_filtered (indent, stream, "goto ");
> +	  fprintfi_filtered (indent, &stream, "goto ");
>  	  print_label (stream, scope, op_ptr + offset - base);
> -	  fprintf_filtered (stream, ";\n");
> +	  stream.puts (";\n");
>  	  break;
>
>  	case DW_OP_bra:
>  	  offset = extract_signed_integer (op_ptr, 2, byte_order);
>  	  op_ptr += 2;
> -	  fprintfi_filtered (indent, stream,
> +	  fprintfi_filtered (indent, &stream,
>  			     "if ((( " GCC_INTPTR
>  			     ") __gdb_stack[__gdb_tos--]) != 0) goto ");
>  	  print_label (stream, scope, op_ptr + offset - base);
> -	  fprintf_filtered (stream, ";\n");
> +	  stream.puts (";\n");
>  	  break;
>
>  	case DW_OP_nop:
> @@ -1122,9 +1121,9 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  	}
>      }
>
> -  fprintfi_filtered (indent, stream, "%s = __gdb_stack[__gdb_tos];\n",
> +  fprintfi_filtered (indent, &stream, "%s = __gdb_stack[__gdb_tos];\n",
>  		     result_name);
> -  fprintfi_filtered (indent - 2, stream, "}\n");
> +  fprintfi_filtered (indent - 2, &stream, "}\n");
>
>    do_cleanups (cleanup);
>  }
> @@ -1132,7 +1131,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  /* See compile.h.  */
>
>  void
> -compile_dwarf_expr_to_c (struct ui_file *stream, const char *result_name,
> +compile_dwarf_expr_to_c (string_file &stream, const char *result_name,
>  			 struct symbol *sym, CORE_ADDR pc,
>  			 struct gdbarch *arch, unsigned char *registers_used,
>  			 unsigned int addr_size,
> @@ -1147,7 +1146,7 @@ compile_dwarf_expr_to_c (struct ui_file *stream, const char *result_name,
>  /* See compile.h.  */
>
>  void
> -compile_dwarf_bounds_to_c (struct ui_file *stream,
> +compile_dwarf_bounds_to_c (string_file &stream,
>  			   const char *result_name,
>  			   const struct dynamic_prop *prop,
>  			   struct symbol *sym, CORE_ADDR pc,
> diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
> index 0ae2125..b525f61 100644
> --- a/gdb/compile/compile.c
> +++ b/gdb/compile/compile.c
> @@ -494,22 +494,19 @@ compile_to_object (struct command_line *cmd, const char *cmd_string,
>    /* From the provided expression, build a scope to pass to the
>       compiler.  */
>
> -  std::string input_buf;
> +  string_file input_buf;
>    const char *input;
>
>    if (cmd != NULL)
>      {
> -      struct ui_file *stream = mem_fileopen ();
>        struct command_line *iter;
>
> -      make_cleanup_ui_file_delete (stream);
>        for (iter = cmd->body_list[0]; iter; iter = iter->next)
>  	{
> -	  fputs_unfiltered (iter->line, stream);
> -	  fputs_unfiltered ("\n", stream);
> +	  input_buf.puts (iter->line);
> +	  input_buf.puts ("\n");
>  	}
>
> -      input_buf = ui_file_as_string (stream);
>        input = input_buf.c_str ();
>      }
>    else if (cmd_string != NULL)
> diff --git a/gdb/compile/compile.h b/gdb/compile/compile.h
> index a46ee6d..7438599 100644
> --- a/gdb/compile/compile.h
> +++ b/gdb/compile/compile.h
> @@ -55,7 +55,7 @@ extern void eval_compile_command (struct command_line *cmd,
>     PER_CU is the per-CU object used for looking up various other
>     things.  */
>
> -extern void compile_dwarf_expr_to_c (struct ui_file *stream,
> +extern void compile_dwarf_expr_to_c (string_file &stream,
>  				     const char *result_name,
>  				     struct symbol *sym,
>  				     CORE_ADDR pc,
> @@ -90,7 +90,7 @@ extern void compile_dwarf_expr_to_c (struct ui_file *stream,
>     PER_CU is the per-CU object used for looking up various other
>     things.  */
>
> -extern void compile_dwarf_bounds_to_c (struct ui_file *stream,
> +extern void compile_dwarf_bounds_to_c (string_file &stream,
>  				       const char *result_name,
>  				       const struct dynamic_prop *prop,
>  				       struct symbol *sym, CORE_ADDR pc,
> diff --git a/gdb/cp-support.c b/gdb/cp-support.c
> index f4498f1..1b0900e 100644
> --- a/gdb/cp-support.c
> +++ b/gdb/cp-support.c
> @@ -192,7 +192,6 @@ inspect_type (struct demangle_parse_info *info,
>  	  int is_anon;
>  	  struct type *type;
>  	  std::unique_ptr<demangle_parse_info> i;
> -	  struct ui_file *buf;
>
>  	  /* Get the real type of the typedef.  */
>  	  type = check_typedef (otype);
> @@ -228,23 +227,21 @@ inspect_type (struct demangle_parse_info *info,
>  		type = last;
>  	    }
>
> -	  buf = mem_fileopen ();
> +	  string_file buf;
>  	  TRY
> -	  {
> -	    type_print (type, "", buf, -1);
> -	  }
> -
> +	    {
> +	      type_print (type, "", &buf, -1);
> +	    }
>  	  /* If type_print threw an exception, there is little point
>  	     in continuing, so just bow out gracefully.  */
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> -	      ui_file_delete (buf);
>  	      return 0;
>  	    }
>  	  END_CATCH
>
> -	  name = ui_file_obsavestring (buf, &info->obstack, &len);
> -	  ui_file_delete (buf);
> +	  len = buf.size ();
> +	  name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
>
>  	  /* Turn the result into a new tree.  Note that this
>  	     tree will contain pointers into NAME, so NAME cannot
> @@ -301,7 +298,7 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>  {
>    long len;
>    char *name;
> -  struct ui_file *buf = mem_fileopen ();
> +  string_file buf;
>    struct demangle_component *comp = ret_comp;
>
>    /* Walk each node of the qualified name, reconstructing the name of
> @@ -315,9 +312,9 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>  	{
>  	  struct demangle_component newobj;
>
> -	  ui_file_write (buf, d_left (comp)->u.s_name.s,
> -			 d_left (comp)->u.s_name.len);
> -	  name = ui_file_obsavestring (buf, &info->obstack, &len);
> +	  buf.write (d_left (comp)->u.s_name.s, d_left (comp)->u.s_name.len);
> +	  len = buf.size ();
> +	  name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
>  	  newobj.type = DEMANGLE_COMPONENT_NAME;
>  	  newobj.u.s_name.s = name;
>  	  newobj.u.s_name.len = len;
> @@ -330,12 +327,11 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>  		 string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
>  		 node.  */
>
> -	      ui_file_rewind (buf);
> +	      buf.clear ();
>  	      n = cp_comp_to_string (&newobj, 100);
>  	      if (n == NULL)
>  		{
>  		  /* If something went astray, abort typedef substitutions.  */
> -		  ui_file_delete (buf);
>  		  return;
>  		}
>
> @@ -360,14 +356,13 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>  	  if (name == NULL)
>  	    {
>  	      /* If something went astray, abort typedef substitutions.  */
> -	      ui_file_delete (buf);
>  	      return;
>  	    }
> -	  fputs_unfiltered (name, buf);
> +	  buf.puts (name);
>  	  xfree (name);
>  	}
>
> -      ui_file_write (buf, "::", 2);
> +      buf.write ("::", 2);
>        comp = d_right (comp);
>      }
>
> @@ -377,8 +372,9 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>
>    if (comp->type == DEMANGLE_COMPONENT_NAME)
>      {
> -      ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
> -      name = ui_file_obsavestring (buf, &info->obstack, &len);
> +      buf.write (comp->u.s_name.s, comp->u.s_name.len);
> +      len = buf.size ();
> +      name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
>
>        /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
>  	 with a DEMANGLE_COMPONENT_NAME node containing the whole
> @@ -390,8 +386,6 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
>      }
>    else
>      replace_typedefs (info, comp, finder, data);
> -
> -  ui_file_delete (buf);
>  }
>
>
> diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
> index c89c5ed..7d0b006 100644
> --- a/gdb/disasm-selftests.c
> +++ b/gdb/disasm-selftests.c
> @@ -113,7 +113,7 @@ print_one_insn_test (struct gdbarch *gdbarch)
>  				    const gdb_byte *insn,
>  				    size_t len)
>        : gdb_disassembler (gdbarch,
> -			  (verbose ? gdb_stdout : null_stream ()),
> +			  (verbose ? gdb_stdout : &null_stream),
>  			  gdb_disassembler_test::read_memory),
>  	m_insn (insn), m_len (len)
>      {
> @@ -173,7 +173,7 @@ memory_error_test (struct gdbarch *gdbarch)
>    {
>    public:
>      gdb_disassembler_test (struct gdbarch *gdbarch)
> -      : gdb_disassembler (gdbarch, null_stream (),
> +      : gdb_disassembler (gdbarch, &null_stream,
>  			  gdb_disassembler_test::read_memory)
>      {
>      }
> diff --git a/gdb/disasm.c b/gdb/disasm.c
> index 59ebef0..92bca99 100644
> --- a/gdb/disasm.c
> +++ b/gdb/disasm.c
> @@ -248,8 +248,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>    if (name != NULL)
>      xfree (name);
>
> -  struct ui_file *stb = mem_fileopen ();
> -  make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    if (flags & DISASSEMBLY_RAW_INSN)
>      {
> @@ -260,28 +259,23 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>
>        /* Build the opcodes using a temporary stream so we can
>  	 write them out in a single go for the MI.  */
> -      struct ui_file *opcode_stream = mem_fileopen ();
> -      struct cleanup *cleanups =
> -	make_cleanup_ui_file_delete (opcode_stream);
> +      string_file opcode_stream;
>
> -      size = gdb_print_insn (gdbarch, pc, stb, NULL);
> +      size = gdb_print_insn (gdbarch, pc, &stb, NULL);
>        end_pc = pc + size;
>
>        for (;pc < end_pc; ++pc)
>  	{
>  	  read_code (pc, &data, 1);
> -	  fprintf_filtered (opcode_stream, "%s%02x",
> -			    spacer, (unsigned) data);
> +	  opcode_stream.printf ("%s%02x", spacer, (unsigned) data);
>  	  spacer = " ";
>  	}
>
>        uiout->field_stream ("opcodes", opcode_stream);
>        uiout->text ("\t");
> -
> -      do_cleanups (cleanups);
>      }
>    else
> -    size = gdb_print_insn (gdbarch, pc, stb, NULL);
> +    size = gdb_print_insn (gdbarch, pc, &stb, NULL);
>
>    uiout->field_stream ("inst", stb);
>    do_cleanups (ui_out_chain);
> @@ -856,7 +850,7 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
>  int
>  gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
>  {
> -  return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
> +  return gdb_print_insn (gdbarch, addr, &null_stream, NULL);
>  }
>
>  /* fprintf-function for gdb_buffered_insn_length.  This function is a
> diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
> index e81d8e9..2a84b28 100644
> --- a/gdb/dummy-frame.c
> +++ b/gdb/dummy-frame.c
> @@ -409,14 +409,11 @@ maintenance_print_dummy_frames (char *args, int from_tty)
>      fprint_dummy_frames (gdb_stdout);
>    else
>      {
> -      struct cleanup *cleanups;
> -      struct ui_file *file = gdb_fopen (args, "w");
> +      stdio_file file;
>
> -      if (file == NULL)
> +      if (!file.open (args, "w"))
>  	perror_with_name (_("maintenance print dummy-frames"));
> -      cleanups = make_cleanup_ui_file_delete (file);
> -      fprint_dummy_frames (file);
> -      do_cleanups (cleanups);
> +      fprint_dummy_frames (&file);
>      }
>  }
>
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index 7fca76b..0357e51 100644
> --- a/gdb/dwarf2loc.c
> +++ b/gdb/dwarf2loc.c
> @@ -2645,7 +2645,7 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop,
>  /* See dwarf2loc.h.  */
>
>  void
> -dwarf2_compile_property_to_c (struct ui_file *stream,
> +dwarf2_compile_property_to_c (string_file &stream,
>  			      const char *result_name,
>  			      struct gdbarch *gdbarch,
>  			      unsigned char *registers_used,
> @@ -4361,7 +4361,7 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
>  /* symbol_computed_ops 'generate_c_location' method.  */
>
>  static void
> -locexpr_generate_c_location (struct symbol *sym, struct ui_file *stream,
> +locexpr_generate_c_location (struct symbol *sym, string_file &stream,
>  			     struct gdbarch *gdbarch,
>  			     unsigned char *registers_used,
>  			     CORE_ADDR pc, const char *result_name)
> @@ -4571,7 +4571,7 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
>  /* symbol_computed_ops 'generate_c_location' method.  */
>
>  static void
> -loclist_generate_c_location (struct symbol *sym, struct ui_file *stream,
> +loclist_generate_c_location (struct symbol *sym, string_file &stream,
>  			     struct gdbarch *gdbarch,
>  			     unsigned char *registers_used,
>  			     CORE_ADDR pc, const char *result_name)
> diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
> index 24e660c..d6cdbd2 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -151,7 +151,7 @@ int dwarf2_evaluate_property (const struct dynamic_prop *prop,
>     evaluated.
>     SYM the originating symbol, used for error reporting.  */
>
> -void dwarf2_compile_property_to_c (struct ui_file *stream,
> +void dwarf2_compile_property_to_c (string_file &stream,
>  				   const char *result_name,
>  				   struct gdbarch *gdbarch,
>  				   unsigned char *registers_used,
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index b5dc510..774ed73 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -8409,17 +8409,6 @@ die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu)
>      }
>  }
>
> -/* Retrieve the last character from a mem_file.  */
> -
> -static void
> -do_ui_file_peek_last (void *object, const char *buffer, long length)
> -{
> -  char *last_char_p = (char *) object;
> -
> -  if (length > 0)
> -    *last_char_p = buffer[length - 1];
> -}
> -
>  /* Compute the fully qualified name of DIE in CU.  If PHYSNAME is nonzero,
>     compute the physname for the object, which include a method's:
>     - formal parameters (C++),
> @@ -8478,21 +8467,21 @@ dwarf2_compute_name (const char *name,
>  	{
>  	  long length;
>  	  const char *prefix;
> -	  struct ui_file *buf;
>  	  const char *canonical_name = NULL;
>
> +	  string_file buf;
> +
>  	  prefix = determine_prefix (die, cu);
> -	  buf = mem_fileopen ();
>  	  if (*prefix != '\0')
>  	    {
>  	      char *prefixed_name = typename_concat (NULL, prefix, name,
>  						     physname, cu);
>
> -	      fputs_unfiltered (prefixed_name, buf);
> +	      buf.puts (prefixed_name);
>  	      xfree (prefixed_name);
>  	    }
>  	  else
> -	    fputs_unfiltered (name, buf);
> +	    buf.puts (name);
>
>  	  /* Template parameters may be specified in the DIE's DW_AT_name, or
>  	     as children with DW_TAG_template_type_param or
> @@ -8537,25 +8526,25 @@ dwarf2_compute_name (const char *name,
>
>  		  if (first)
>  		    {
> -		      fputs_unfiltered ("<", buf);
> +		      buf.puts ("<");
>  		      first = 0;
>  		    }
>  		  else
> -		    fputs_unfiltered (", ", buf);
> +		    buf.puts (", ");
>
>  		  attr = dwarf2_attr (child, DW_AT_type, cu);
>  		  if (attr == NULL)
>  		    {
>  		      complaint (&symfile_complaints,
>  				 _("template parameter missing DW_AT_type"));
> -		      fputs_unfiltered ("UNKNOWN_TYPE", buf);
> +		      buf.puts ("UNKNOWN_TYPE");
>  		      continue;
>  		    }
>  		  type = die_type (child, cu);
>
>  		  if (child->tag == DW_TAG_template_type_param)
>  		    {
> -		      c_print_type (type, "", buf, -1, 0, &type_print_raw_options);
> +		      c_print_type (type, "", &buf, -1, 0, &type_print_raw_options);
>  		      continue;
>  		    }
>
> @@ -8565,7 +8554,7 @@ dwarf2_compute_name (const char *name,
>  		      complaint (&symfile_complaints,
>  				 _("template parameter missing "
>  				   "DW_AT_const_value"));
> -		      fputs_unfiltered ("UNKNOWN_VALUE", buf);
> +		      buf.puts ("UNKNOWN_VALUE");
>  		      continue;
>  		    }
>
> @@ -8576,7 +8565,7 @@ dwarf2_compute_name (const char *name,
>  		  if (TYPE_NOSIGN (type))
>  		    /* GDB prints characters as NUMBER 'CHAR'.  If that's
>  		       changed, this can use value_print instead.  */
> -		    c_printchar (value, type, buf);
> +		    c_printchar (value, type, &buf);
>  		  else
>  		    {
>  		      struct value_print_options opts;
> @@ -8599,7 +8588,7 @@ dwarf2_compute_name (const char *name,
>  			 the radix.  */
>  		      get_formatted_print_options (&opts, 'd');
>  		      opts.raw = 1;
> -		      value_print (v, buf, &opts);
> +		      value_print (v, &buf, &opts);
>  		      release_value (v);
>  		      value_free (v);
>  		    }
> @@ -8611,12 +8600,10 @@ dwarf2_compute_name (const char *name,
>  		{
>  		  /* Close the argument list, with a space if necessary
>  		     (nested templates).  */
> -		  char last_char = '\0';
> -		  ui_file_put (buf, do_ui_file_peek_last, &last_char);
> -		  if (last_char == '>')
> -		    fputs_unfiltered (" >", buf);
> +		  if (!buf.empty () && buf.string ().back () == '>')
> +		    buf.puts (" >");
>  		  else
> -		    fputs_unfiltered (">", buf);
> +		    buf.puts (">");
>  		}
>  	    }
>
> @@ -8628,7 +8615,7 @@ dwarf2_compute_name (const char *name,
>  	    {
>  	      struct type *type = read_type_die (die, cu);
>
> -	      c_type_print_args (type, buf, 1, cu->language,
> +	      c_type_print_args (type, &buf, 1, cu->language,
>  				 &type_print_raw_options);
>
>  	      if (cu->language == language_cplus)
> @@ -8643,12 +8630,11 @@ dwarf2_compute_name (const char *name,
>  		      && TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_PTR
>  		      && TYPE_CONST (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type,
>  									0))))
> -		    fputs_unfiltered (" const", buf);
> +		    buf.puts (" const");
>  		}
>  	    }
>
> -	  std::string intermediate_name = ui_file_as_string (buf);
> -	  ui_file_delete (buf);
> +	  const std::string &intermediate_name = buf.string ();
>
>  	  if (cu->language == language_cplus)
>  	    canonical_name
> diff --git a/gdb/event-top.c b/gdb/event-top.c
> index ae4f704..5d8d077 100644
> --- a/gdb/event-top.c
> +++ b/gdb/event-top.c
> @@ -1237,8 +1237,8 @@ gdb_setup_readline (int editing)
>       mess it up here.  The sync stuff should really go away over
>       time.  */
>    if (!batch_silent)
> -    gdb_stdout = stdio_fileopen (ui->outstream);
> -  gdb_stderr = stderr_fileopen (ui->errstream);
> +    gdb_stdout = new stdio_file (ui->outstream);
> +  gdb_stderr = new stderr_file (ui->errstream);
>    gdb_stdlog = gdb_stderr;  /* for moment */
>    gdb_stdtarg = gdb_stderr; /* for moment */
>    gdb_stdtargerr = gdb_stderr; /* for moment */
> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
> index 8bd0c19..266f2e9 100644
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -497,17 +497,13 @@ gdbarch_free (struct gdbarch *arch)
>  static void
>  verify_gdbarch (struct gdbarch *gdbarch)
>  {
> -  struct ui_file *log;
> -  struct cleanup *cleanups;
> -  long length;
> +  string_file log;
>
> -  log = mem_fileopen ();
> -  cleanups = make_cleanup_ui_file_delete (log);
>    /* fundamental */
>    if (gdbarch->byte_order == BFD_ENDIAN_UNKNOWN)
> -    fprintf_unfiltered (log, "\n\tbyte-order");
> +    log.puts ("\n\tbyte-order");
>    if (gdbarch->bfd_arch_info == NULL)
> -    fprintf_unfiltered (log, "\n\tbfd_arch_info");
> +    log.puts ("\n\tbfd_arch_info");
>    /* Check those that need to be defined for the given multi-arch level.  */
>    /* Skip verify of bits_big_endian, invalid_p == 0 */
>    /* Skip verify of short_bit, invalid_p == 0 */
> @@ -542,7 +538,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of pseudo_register_read_value, has predicate.  */
>    /* Skip verify of pseudo_register_write, has predicate.  */
>    if (gdbarch->num_regs == -1)
> -    fprintf_unfiltered (log, "\n\tnum_regs");
> +    log.puts ("\n\tnum_regs");
>    /* Skip verify of num_pseudo_regs, invalid_p == 0 */
>    /* Skip verify of ax_pseudo_register_collect, has predicate.  */
>    /* Skip verify of ax_pseudo_register_push_stack, has predicate.  */
> @@ -556,7 +552,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of sdb_reg_to_regnum, invalid_p == 0 */
>    /* Skip verify of dwarf2_reg_to_regnum, invalid_p == 0 */
>    if (gdbarch->register_name == 0)
> -    fprintf_unfiltered (log, "\n\tregister_name");
> +    log.puts ("\n\tregister_name");
>    /* Skip verify of register_type, has predicate.  */
>    /* Skip verify of dummy_id, has predicate.  */
>    /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
> @@ -579,14 +575,14 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of return_value, has predicate.  */
>    /* Skip verify of return_in_first_hidden_param_p, invalid_p == 0 */
>    if (gdbarch->skip_prologue == 0)
> -    fprintf_unfiltered (log, "\n\tskip_prologue");
> +    log.puts ("\n\tskip_prologue");
>    /* Skip verify of skip_main_prologue, has predicate.  */
>    /* Skip verify of skip_entrypoint, has predicate.  */
>    if (gdbarch->inner_than == 0)
> -    fprintf_unfiltered (log, "\n\tinner_than");
> +    log.puts ("\n\tinner_than");
>    /* Skip verify of breakpoint_from_pc, invalid_p == 0 */
>    if (gdbarch->breakpoint_kind_from_pc == 0)
> -    fprintf_unfiltered (log, "\n\tbreakpoint_kind_from_pc");
> +    log.puts ("\n\tbreakpoint_kind_from_pc");
>    /* Skip verify of sw_breakpoint_from_kind, invalid_p == 0 */
>    /* Skip verify of breakpoint_kind_from_current_state, invalid_p == 0 */
>    /* Skip verify of adjust_breakpoint_address, has predicate.  */
> @@ -607,7 +603,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of software_single_step, has predicate.  */
>    /* Skip verify of single_step_through_delay, has predicate.  */
>    if (gdbarch->print_insn == 0)
> -    fprintf_unfiltered (log, "\n\tprint_insn");
> +    log.puts ("\n\tprint_insn");
>    /* Skip verify of skip_trampoline_code, invalid_p == 0 */
>    /* Skip verify of skip_solib_resolver, invalid_p == 0 */
>    /* Skip verify of in_solib_return_trampoline, invalid_p == 0 */
> @@ -641,9 +637,9 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of displaced_step_hw_singlestep, invalid_p == 0 */
>    /* Skip verify of displaced_step_fixup, has predicate.  */
>    if ((! gdbarch->displaced_step_free_closure) != (! gdbarch->displaced_step_copy_insn))
> -    fprintf_unfiltered (log, "\n\tdisplaced_step_free_closure");
> +    log.puts ("\n\tdisplaced_step_free_closure");
>    if ((! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn))
> -    fprintf_unfiltered (log, "\n\tdisplaced_step_location");
> +    log.puts ("\n\tdisplaced_step_location");
>    /* Skip verify of relocate_instruction, has predicate.  */
>    /* Skip verify of overlay_update, has predicate.  */
>    /* Skip verify of core_read_description, has predicate.  */
> @@ -696,12 +692,10 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* Skip verify of gcc_target_options, invalid_p == 0 */
>    /* Skip verify of gnu_triplet_regexp, invalid_p == 0 */
>    /* Skip verify of addressable_memory_unit_size, invalid_p == 0 */
> -  std::string buf = ui_file_as_string (log);
> -  if (!buf.empty ())
> +  if (!log.empty ())
>      internal_error (__FILE__, __LINE__,
>                      _("verify_gdbarch: the following are invalid ...%s"),
> -                    buf.c_str ());
> -  do_cleanups (cleanups);
> +                    log.c_str ());
>  }
>
>
> diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
> index 2958cab..54549b6 100755
> --- a/gdb/gdbarch.sh
> +++ b/gdb/gdbarch.sh
> @@ -1875,17 +1875,13 @@ cat <<EOF
>  static void
>  verify_gdbarch (struct gdbarch *gdbarch)
>  {
> -  struct ui_file *log;
> -  struct cleanup *cleanups;
> -  long length;
> +  string_file log;
>
> -  log = mem_fileopen ();
> -  cleanups = make_cleanup_ui_file_delete (log);
>    /* fundamental */
>    if (gdbarch->byte_order == BFD_ENDIAN_UNKNOWN)
> -    fprintf_unfiltered (log, "\n\tbyte-order");
> +    log.puts ("\n\tbyte-order");
>    if (gdbarch->bfd_arch_info == NULL)
> -    fprintf_unfiltered (log, "\n\tbfd_arch_info");
> +    log.puts ("\n\tbfd_arch_info");
>    /* Check those that need to be defined for the given multi-arch level.  */
>  EOF
>  function_list | while do_read
> @@ -1914,21 +1910,19 @@ do
>  	elif [ -n "${invalid_p}" ]
>  	then
>  	    printf "  if (${invalid_p})\n"
> -	    printf "    fprintf_unfiltered (log, \"\\\\n\\\\t${function}\");\n"
> +	    printf "    log.puts (\"\\\\n\\\\t${function}\");\n"
>  	elif [ -n "${predefault}" ]
>  	then
>  	    printf "  if (gdbarch->${function} == ${predefault})\n"
> -	    printf "    fprintf_unfiltered (log, \"\\\\n\\\\t${function}\");\n"
> +	    printf "    log.puts (\"\\\\n\\\\t${function}\");\n"
>  	fi
>      fi
>  done
>  cat <<EOF
> -  std::string buf = ui_file_as_string (log);
> -  if (!buf.empty ())
> +  if (!log.empty ())
>      internal_error (__FILE__, __LINE__,
>                      _("verify_gdbarch: the following are invalid ...%s"),
> -                    buf.c_str ());
> -  do_cleanups (cleanups);
> +                    log.c_str ());
>  }
>  EOF
>
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 21cc005..5e5db27 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -2459,7 +2459,7 @@ safe_parse_type (struct gdbarch *gdbarch, char *p, int length)
>
>    /* Suppress error messages.  */
>    saved_gdb_stderr = gdb_stderr;
> -  gdb_stderr = ui_file_new ();
> +  gdb_stderr = &null_stream;
>
>    /* Call parse_and_eval_type() without fear of longjmp()s.  */
>    TRY
> @@ -2473,7 +2473,6 @@ safe_parse_type (struct gdbarch *gdbarch, char *p, int length)
>    END_CATCH
>
>    /* Stop suppressing error messages.  */
> -  ui_file_delete (gdb_stderr);
>    gdb_stderr = saved_gdb_stderr;
>
>    return type;
> diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
> index b2e7c96..71cffbb 100644
> --- a/gdb/guile/scm-breakpoint.c
> +++ b/gdb/guile/scm-breakpoint.c
> @@ -978,8 +978,6 @@ gdbscm_breakpoint_commands (SCM self)
>      = bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
>    struct breakpoint *bp;
>    long length;
> -  struct ui_file *string_file;
> -  struct cleanup *chain;
>    SCM result;
>
>    bp = bp_smob->bp;
> @@ -987,10 +985,9 @@ gdbscm_breakpoint_commands (SCM self)
>    if (bp->commands == NULL)
>      return SCM_BOOL_F;
>
> -  string_file = mem_fileopen ();
> -  chain = make_cleanup_ui_file_delete (string_file);
> +  string_file buf;
>
> -  current_uiout->redirect (string_file);
> +  current_uiout->redirect (&buf);
>    TRY
>      {
>        print_command_lines (current_uiout, breakpoint_commands (bp), 0);
> @@ -998,15 +995,12 @@ gdbscm_breakpoint_commands (SCM self)
>    current_uiout->redirect (NULL);
>    CATCH (except, RETURN_MASK_ALL)
>      {
> -      do_cleanups (chain);
>        gdbscm_throw_gdb_exception (except);
>      }
>    END_CATCH
>
> -  std::string cmdstr = ui_file_as_string (string_file);
> -  result = gdbscm_scm_from_c_string (cmdstr.c_str ());
> +  result = gdbscm_scm_from_c_string (buf.c_str ());
>
> -  do_cleanups (chain);
>    return result;
>  }
>
> diff --git a/gdb/guile/scm-disasm.c b/gdb/guile/scm-disasm.c
> index 25cae5a..f8cbad6 100644
> --- a/gdb/guile/scm-disasm.c
> +++ b/gdb/guile/scm-disasm.c
> @@ -146,7 +146,7 @@ gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
>  static int
>  gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
>  			     SCM port, ULONGEST offset, CORE_ADDR memaddr,
> -			     struct ui_file *stream, int *branch_delay_insns)
> +			     string_file *stream, int *branch_delay_insns)
>  {
>    gdbscm_disassembler di (gdbarch, stream, port, offset);
>
> @@ -245,33 +245,29 @@ gdbscm_arch_disassemble (SCM self, SCM start_scm, SCM rest)
>    for (pc = start, i = 0; pc <= end && i < count; )
>      {
>        int insn_len = 0;
> -      struct ui_file *memfile = mem_fileopen ();
> -      struct cleanup *cleanups = make_cleanup_ui_file_delete (memfile);
> +      string_file buf;
>
>        TRY
>  	{
>  	  if (using_port)
>  	    {
>  	      insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
> -						      pc, memfile, NULL);
> +						      pc, &buf, NULL);
>  	    }
>  	  else
> -	    insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
> +	    insn_len = gdb_print_insn (gdbarch, pc, &buf, NULL);
>  	}
>        CATCH (except, RETURN_MASK_ALL)
>  	{
> -	  GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
> +	  GDBSCM_HANDLE_GDB_EXCEPTION (except);
>  	}
>        END_CATCH
>
> -      std::string as = ui_file_as_string (memfile);
> -
> -      result = scm_cons (dascm_make_insn (pc, as.c_str (), insn_len),
> +      result = scm_cons (dascm_make_insn (pc, buf.c_str (), insn_len),
>  			 result);
>
>        pc += insn_len;
>        i++;
> -      do_cleanups (cleanups);
>      }
>
>    return scm_reverse_x (result, SCM_EOL);
> diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
> index 9b5159e..994f92d 100644
> --- a/gdb/guile/scm-frame.c
> +++ b/gdb/guile/scm-frame.c
> @@ -156,15 +156,12 @@ static int
>  frscm_print_frame_smob (SCM self, SCM port, scm_print_state *pstate)
>  {
>    frame_smob *f_smob = (frame_smob *) SCM_SMOB_DATA (self);
> -  struct ui_file *strfile;
>
>    gdbscm_printf (port, "#<%s ", frame_smob_name);
>
> -  strfile = mem_fileopen ();
> -  fprint_frame_id (strfile, f_smob->frame_id);
> -  std::string s = ui_file_as_string (strfile);
> -  gdbscm_printf (port, "%s", s.c_str ());
> -  ui_file_delete (strfile);
> +  string_file strfile;
> +  fprint_frame_id (&strfile, f_smob->frame_id);
> +  gdbscm_printf (port, "%s", strfile.c_str ());
>
>    scm_puts (">", port);
>
> diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
> index 4a1c864..fb3a47b 100644
> --- a/gdb/guile/scm-ports.c
> +++ b/gdb/guile/scm-ports.c
> @@ -37,11 +37,18 @@
>
>  /* A ui-file for sending output to Guile.  */
>
> -typedef struct
> +class ioscm_file_port : public ui_file
>  {
> -  int *magic;
> -  SCM port;
> -} ioscm_file_port;
> +public:
> +  /* Return a ui_file that writes to PORT.  */
> +  explicit ioscm_file_port (SCM port);
> +
> +  void flush () override;
> +  void write (const char *buf, long length_buf) override;
> +
> +private:
> +  SCM m_port;
> +};
>
>  /* Data for a memory port.  */
>
> @@ -431,74 +438,21 @@ gdbscm_error_port (void)
>  \f
>  /* Support for sending GDB I/O to Guile ports.  */
>
> -static void
> -ioscm_file_port_delete (struct ui_file *file)
> -{
> -  ioscm_file_port *stream = (ioscm_file_port *) ui_file_data (file);
> -
> -  if (stream->magic != &file_port_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("ioscm_file_port_delete: bad magic number"));
> -  xfree (stream);
> -}
> -
> -static void
> -ioscm_file_port_rewind (struct ui_file *file)
> -{
> -  ioscm_file_port *stream = (ioscm_file_port *) ui_file_data (file);
> -
> -  if (stream->magic != &file_port_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("ioscm_file_port_rewind: bad magic number"));
> -
> -  scm_truncate_file (stream->port, 0);
> -}
> +ioscm_file_port::ioscm_file_port (SCM port)
> +  : m_port (port)
> +{}
>
> -static void
> -ioscm_file_port_put (struct ui_file *file,
> -		     ui_file_put_method_ftype *write,
> -		     void *dest)
> +void
> +ioscm_file_port::flush ()
>  {
> -  ioscm_file_port *stream = (ioscm_file_port *) ui_file_data (file);
> -
> -  if (stream->magic != &file_port_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("ioscm_file_port_put: bad magic number"));
> -
> -  /* This function doesn't meld with ports very well.  */
>  }
>
> -static void
> -ioscm_file_port_write (struct ui_file *file,
> -		       const char *buffer,
> -		       long length_buffer)
> +void
> +ioscm_file_port::write (const char *buffer, long length_buffer)
>  {
> -  ioscm_file_port *stream = (ioscm_file_port *) ui_file_data (file);
> -
> -  if (stream->magic != &file_port_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("ioscm_pot_file_write: bad magic number"));
> -
> -  scm_c_write (stream->port, buffer, length_buffer);
> +  scm_c_write (m_port, buffer, length_buffer);
>  }
>
> -/* Return a ui_file that writes to PORT.  */
> -
> -static struct ui_file *
> -ioscm_file_port_new (SCM port)
> -{
> -  ioscm_file_port *stream = XCNEW (ioscm_file_port);
> -  struct ui_file *file = ui_file_new ();
> -
> -  set_ui_file_data (file, stream, ioscm_file_port_delete);
> -  set_ui_file_rewind (file, ioscm_file_port_rewind);
> -  set_ui_file_put (file, ioscm_file_port_put);
> -  set_ui_file_write (file, ioscm_file_port_write);
> -  stream->magic = &file_port_magic;
> -  stream->port = port;
> -
> -  return file;
> -}
>  \f
>  /* Helper routine for with-{output,error}-to-port.  */
>
> @@ -506,7 +460,6 @@ static SCM
>  ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
>  				  const char *func_name)
>  {
> -  struct ui_file *port_file;
>    struct cleanup *cleanups;
>    SCM result;
>
> @@ -520,21 +473,19 @@ ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
>    make_cleanup_restore_integer (&current_ui->async);
>    current_ui->async = 0;
>
> -  port_file = ioscm_file_port_new (port);
> -
> -  make_cleanup_ui_file_delete (port_file);
> +  ui_file_up port_file (new ioscm_file_port (port));
>
>    scoped_restore save_file = make_scoped_restore (oport == GDB_STDERR
>  						  ? &gdb_stderr : &gdb_stdout);
>
>    if (oport == GDB_STDERR)
> -    gdb_stderr = port_file;
> +    gdb_stderr = port_file.get ();
>    else
>      {
> -      current_uiout->redirect (port_file);
> +      current_uiout->redirect (port_file.get ());
>        make_cleanup_ui_out_redirect_pop (current_uiout);
>
> -      gdb_stdout = port_file;
> +      gdb_stdout = port_file.get ();
>      }
>
>    result = gdbscm_safe_call_0 (thunk, NULL);
> diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
> index f5de011..42a8ad2 100644
> --- a/gdb/guile/scm-type.c
> +++ b/gdb/guile/scm-type.c
> @@ -107,18 +107,10 @@ tyscm_type_name (struct type *type)
>  {
>    TRY
>      {
> -      struct cleanup *old_chain;
> -      struct ui_file *stb;
> +      string_file stb;
>
> -      stb = mem_fileopen ();
> -      old_chain = make_cleanup_ui_file_delete (stb);
> -
> -      LA_PRINT_TYPE (type, "", stb, -1, 0, &type_print_raw_options);
> -
> -      std::string name = ui_file_as_string (stb);
> -      do_cleanups (old_chain);
> -
> -      return name;
> +      LA_PRINT_TYPE (type, "", &stb, -1, 0, &type_print_raw_options);
> +      return std::move (stb.string ());
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/guile/scm-value.c b/gdb/guile/scm-value.c
> index b4f32b6..ebccfb6 100644
> --- a/gdb/guile/scm-value.c
> +++ b/gdb/guile/scm-value.c
> @@ -157,15 +157,10 @@ vlscm_print_value_smob (SCM self, SCM port, scm_print_state *pstate)
>
>    TRY
>      {
> -      struct ui_file *stb = mem_fileopen ();
> -      struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
> +      string_file stb;
>
> -      common_val_print (v_smob->value, stb, 0, &opts, current_language);
> -
> -      std::string s = ui_file_as_string (stb);
> -      scm_puts (s.c_str (), port);
> -
> -      do_cleanups (old_chain);
> +      common_val_print (v_smob->value, &stb, 0, &opts, current_language);
> +      scm_puts (stb.c_str (), port);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> @@ -1277,21 +1272,15 @@ gdbscm_value_print (SCM self)
>      = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
>    struct value *value = v_smob->value;
>    struct value_print_options opts;
> -  std::string s;
> -  SCM result;
>
>    get_user_print_options (&opts);
>    opts.deref_ref = 0;
>
> +  string_file stb;
> +
>    TRY
>      {
> -      struct ui_file *stb = mem_fileopen ();
> -      struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
> -
> -      common_val_print (value, stb, 0, &opts, current_language);
> -      s = ui_file_as_string (stb);
> -
> -      do_cleanups (old_chain);
> +      common_val_print (value, &stb, 0, &opts, current_language);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> @@ -1304,10 +1293,8 @@ gdbscm_value_print (SCM self)
>       IWBN to use scm_take_locale_string here, but we'd have to temporarily
>       override the default port conversion handler because contrary to
>       documentation it doesn't necessarily free the input string.  */
> -  result = scm_from_stringn (s.c_str (), s.size (), host_charset (),
> -			     SCM_FAILED_CONVERSION_QUESTION_MARK);
> -
> -  return result;
> +  return scm_from_stringn (stb.c_str (), stb.size (), host_charset (),
> +			   SCM_FAILED_CONVERSION_QUESTION_MARK);
>  }
>  \f
>  /* (parse-and-eval string) -> <gdb:value>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index d761117..d836162 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1670,21 +1670,19 @@ print_return_value_1 (struct ui_out *uiout, struct return_value_info *rv)
>    if (rv->value != NULL)
>      {
>        struct value_print_options opts;
> -      struct ui_file *stb;
> -      struct cleanup *old_chain;
>
>        /* Print it.  */
> -      stb = mem_fileopen ();
> -      old_chain = make_cleanup_ui_file_delete (stb);
>        uiout->text ("Value returned is ");
>        uiout->field_fmt ("gdb-result-var", "$%d",
> -			rv->value_history_index);
> +			 rv->value_history_index);
>        uiout->text (" = ");
>        get_no_prettyformat_print_options (&opts);
> -      value_print (rv->value, stb, &opts);
> +
> +      string_file stb;
> +
> +      value_print (rv->value, &stb, &opts);
>        uiout->field_stream ("return-value", stb);
>        uiout->text ("\n");
> -      do_cleanups (old_chain);
>      }
>    else
>      {
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 41f1fdd..1e5e9f1 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -3438,40 +3438,32 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
>  			   const struct target_waitstatus *ws)
>  {
>    char *status_string = target_waitstatus_to_string (ws);
> -  struct ui_file *tmp_stream = mem_fileopen ();
> +  string_file stb;
>
>    /* The text is split over several lines because it was getting too long.
>       Call fprintf_unfiltered (gdb_stdlog) once so that the text is still
>       output as a unit; we want only one timestamp printed if debug_timestamp
>       is set.  */
>
> -  fprintf_unfiltered (tmp_stream,
> -		      "infrun: target_wait (%d.%ld.%ld",
> -		      ptid_get_pid (waiton_ptid),
> -		      ptid_get_lwp (waiton_ptid),
> -		      ptid_get_tid (waiton_ptid));
> +  stb.printf ("infrun: target_wait (%d.%ld.%ld",
> +	      ptid_get_pid (waiton_ptid),
> +	      ptid_get_lwp (waiton_ptid),
> +	      ptid_get_tid (waiton_ptid));
>    if (ptid_get_pid (waiton_ptid) != -1)
> -    fprintf_unfiltered (tmp_stream,
> -			" [%s]", target_pid_to_str (waiton_ptid));
> -  fprintf_unfiltered (tmp_stream, ", status) =\n");
> -  fprintf_unfiltered (tmp_stream,
> -		      "infrun:   %d.%ld.%ld [%s],\n",
> -		      ptid_get_pid (result_ptid),
> -		      ptid_get_lwp (result_ptid),
> -		      ptid_get_tid (result_ptid),
> -		      target_pid_to_str (result_ptid));
> -  fprintf_unfiltered (tmp_stream,
> -		      "infrun:   %s\n",
> -		      status_string);
> -
> -  std::string text = ui_file_as_string (tmp_stream);
> +    stb.printf (" [%s]", target_pid_to_str (waiton_ptid));
> +  stb.printf (", status) =\n");
> +  stb.printf ("infrun:   %d.%ld.%ld [%s],\n",
> +	      ptid_get_pid (result_ptid),
> +	      ptid_get_lwp (result_ptid),
> +	      ptid_get_tid (result_ptid),
> +	      target_pid_to_str (result_ptid));
> +  stb.printf ("infrun:   %s\n", status_string);
>
>    /* This uses %s in part to handle %'s in the text, but also to avoid
>       a gcc error: the format attribute requires a string literal.  */
> -  fprintf_unfiltered (gdb_stdlog, "%s", text.c_str ());
> +  fprintf_unfiltered (gdb_stdlog, "%s", stb.c_str ());
>
>    xfree (status_string);
> -  ui_file_delete (tmp_stream);
>  }
>
>  /* Select a thread at random, out of those which are resumed and have
> diff --git a/gdb/language.c b/gdb/language.c
> index a40eb87..31c5c59 100644
> --- a/gdb/language.c
> +++ b/gdb/language.c
> @@ -539,9 +539,6 @@ add_language (const struct language_defn *lang)
>    static const char **language_names = NULL;
>    /* For the "help set language" command.  */
>
> -  int i;
> -  struct ui_file *tmp_stream;
> -
>    if (lang->la_magic != LANG_MAGIC)
>      {
>        fprintf_unfiltered (gdb_stderr,
> @@ -569,9 +566,9 @@ add_language (const struct language_defn *lang)
>    language_names = XRESIZEVEC (const char *, language_names,
>  			       languages_size + 1);
>
> -  for (i = 0; i < languages_size; ++i)
> +  for (int i = 0; i < languages_size; ++i)
>      language_names[i] = languages[i]->la_name;
> -  language_names[i] = NULL;
> +  language_names[languages_size] = NULL;
>
>    /* Add the filename extensions.  */
>    if (lang->la_filename_extensions != NULL)
> @@ -584,37 +581,32 @@ add_language (const struct language_defn *lang)
>      }
>
>    /* Build the "help set language" docs.  */
> -  tmp_stream = mem_fileopen ();
> +  string_file doc;
>
> -  fprintf_unfiltered (tmp_stream,
> -		      _("Set the current source language.\n"
> -			"The currently understood settings are:\n\nlocal or "
> -			"auto    Automatic setting based on source file\n"));
> +  doc.printf (_("Set the current source language.\n"
> +		"The currently understood settings are:\n\nlocal or "
> +		"auto    Automatic setting based on source file\n"));
>
> -  for (i = 0; i < languages_size; ++i)
> +  for (int i = 0; i < languages_size; ++i)
>      {
>        /* Already dealt with these above.  */
>        if (languages[i]->la_language == language_unknown
>  	  || languages[i]->la_language == language_auto)
>  	continue;
>
> -      /* FIXME: i18n: for now assume that the human-readable name
> -	 is just a capitalization of the internal name.  */
> -      fprintf_unfiltered (tmp_stream, "%-16s Use the %c%s language\n",
> -			  languages[i]->la_name,
> -			  /* Capitalize first letter of language
> -			     name.  */
> -			  toupper (languages[i]->la_name[0]),
> -			  languages[i]->la_name + 1);
> +      /* FIXME: i18n: for now assume that the human-readable name is
> +	 just a capitalization of the internal name.  */
> +      doc.printf ("%-16s Use the %c%s language\n",
> +		  languages[i]->la_name,
> +		  /* Capitalize first letter of language name.  */
> +		  toupper (languages[i]->la_name[0]),
> +		  languages[i]->la_name + 1);
>      }
>
> -  std::string language_set_doc = ui_file_as_string (tmp_stream);
> -  ui_file_delete (tmp_stream);
> -
>    add_setshow_enum_cmd ("language", class_support,
>  			(const char **) language_names,
>  			&language,
> -			language_set_doc.c_str (),
> +			doc.c_str (),
>  			_("Show the current source language."),
>  			NULL, set_language_command,
>  			show_language_command,
> diff --git a/gdb/location.c b/gdb/location.c
> index 37da6df..fbd09e2 100644
> --- a/gdb/location.c
> +++ b/gdb/location.c
> @@ -227,59 +227,52 @@ static char *
>  explicit_to_string_internal (int as_linespec,
>  			     const struct explicit_location *explicit_loc)
>  {
> -  struct ui_file *buf;
> -  char space, *result;
>    int need_space = 0;
> -  struct cleanup *cleanup;
> -
> -  space = as_linespec ? ':' : ' ';
> -  buf = mem_fileopen ();
> -  cleanup = make_cleanup_ui_file_delete (buf);
> +  char space = as_linespec ? ':' : ' ';
> +  string_file buf;
>
>    if (explicit_loc->source_filename != NULL)
>      {
>        if (!as_linespec)
> -	fputs_unfiltered ("-source ", buf);
> -      fputs_unfiltered (explicit_loc->source_filename, buf);
> +	buf.puts ("-source ");
> +      buf.puts (explicit_loc->source_filename);
>        need_space = 1;
>      }
>
>    if (explicit_loc->function_name != NULL)
>      {
>        if (need_space)
> -	fputc_unfiltered (space, buf);
> +	buf.putc (space);
>        if (!as_linespec)
> -	fputs_unfiltered ("-function ", buf);
> -      fputs_unfiltered (explicit_loc->function_name, buf);
> +	buf.puts ("-function ");
> +      buf.puts (explicit_loc->function_name);
>        need_space = 1;
>      }
>
>    if (explicit_loc->label_name != NULL)
>      {
>        if (need_space)
> -	fputc_unfiltered (space, buf);
> +	buf.putc (space);
>        if (!as_linespec)
> -	fputs_unfiltered ("-label ", buf);
> -      fputs_unfiltered (explicit_loc->label_name, buf);
> +	buf.puts ("-label ");
> +      buf.puts (explicit_loc->label_name);
>        need_space = 1;
>      }
>
>    if (explicit_loc->line_offset.sign != LINE_OFFSET_UNKNOWN)
>      {
>        if (need_space)
> -	fputc_unfiltered (space, buf);
> +	buf.putc (space);
>        if (!as_linespec)
> -	fputs_unfiltered ("-line ", buf);
> -      fprintf_filtered (buf, "%s%d",
> -			(explicit_loc->line_offset.sign == LINE_OFFSET_NONE ? ""
> -			 : (explicit_loc->line_offset.sign
> -			    == LINE_OFFSET_PLUS ? "+" : "-")),
> -			explicit_loc->line_offset.offset);
> +	buf.puts ("-line ");
> +      buf.printf ("%s%d",
> +		  (explicit_loc->line_offset.sign == LINE_OFFSET_NONE ? ""
> +		   : (explicit_loc->line_offset.sign
> +		      == LINE_OFFSET_PLUS ? "+" : "-")),
> +		  explicit_loc->line_offset.offset);
>      }
>
> -  result = ui_file_xstrdup (buf, NULL);
> -  do_cleanups (cleanup);
> -  return result;
> +  return xstrdup (buf.c_str ());
>  }
>
>  /* See description in location.h.  */
> diff --git a/gdb/main.c b/gdb/main.c
> index f5387b6..30e27c2 100644
> --- a/gdb/main.c
> +++ b/gdb/main.c
> @@ -763,7 +763,7 @@ captured_main_1 (struct captured_main_args *context)
>  	    break;
>  	  case 'B':
>  	    batch_flag = batch_silent = 1;
> -	    gdb_stdout = ui_file_new();
> +	    gdb_stdout = new null_file ();
>  	    break;
>  	  case 'D':
>  	    if (optarg[0] == '\0')
> diff --git a/gdb/maint.c b/gdb/maint.c
> index 77b56af..d95f658 100644
> --- a/gdb/maint.c
> +++ b/gdb/maint.c
> @@ -403,14 +403,11 @@ maintenance_print_architecture (char *args, int from_tty)
>      gdbarch_dump (gdbarch, gdb_stdout);
>    else
>      {
> -      struct cleanup *cleanups;
> -      struct ui_file *file = gdb_fopen (args, "w");
> +      stdio_file file;
>
> -      if (file == NULL)
> +      if (!file.open (args, "w"))
>  	perror_with_name (_("maintenance print architecture"));
> -      cleanups = make_cleanup_ui_file_delete (file);
> -      gdbarch_dump (gdbarch, file);
> -      do_cleanups (cleanups);
> +      gdbarch_dump (gdbarch, &file);
>      }
>  }
>
> diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
> index efaf49d..acb44a2 100644
> --- a/gdb/mi/mi-cmd-stack.c
> +++ b/gdb/mi/mi-cmd-stack.c
> @@ -488,7 +488,6 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
>  {
>    struct cleanup *old_chain;
>    struct ui_out *uiout = current_uiout;
> -  struct ui_file *stb;
>
>    gdb_assert (!arg->val || !arg->error);
>    gdb_assert ((values == PRINT_NO_VALUES && arg->val == NULL
> @@ -511,15 +510,16 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
>  					 TYPE_LENGTH (value_type (arg->val))))))
>      return;
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  old_chain = make_cleanup (null_cleanup, NULL);
>
>    if (values != PRINT_NO_VALUES || what == all)
>      make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
>
> -  fputs_filtered (SYMBOL_PRINT_NAME (arg->sym), stb);
> +  string_file stb;
> +
> +  stb.puts (SYMBOL_PRINT_NAME (arg->sym));
>    if (arg->entry_kind == print_entry_values_only)
> -    fputs_filtered ("@entry", stb);
> +    stb.puts ("@entry");
>    uiout->field_stream ("name", stb);
>
>    if (what == all && SYMBOL_IS_ARGUMENT (arg->sym))
> @@ -528,7 +528,7 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
>    if (values == PRINT_SIMPLE_VALUES)
>      {
>        check_typedef (arg->sym->type);
> -      type_print (arg->sym->type, "", stb, -1);
> +      type_print (arg->sym->type, "", &stb, -1);
>        uiout->field_stream ("type", stb);
>      }
>
> @@ -546,7 +546,7 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
>
>  	      get_no_prettyformat_print_options (&opts);
>  	      opts.deref_ref = 1;
> -	      common_val_print (arg->val, stb, 0, &opts,
> +	      common_val_print (arg->val, &stb, 0, &opts,
>  				language_def (SYMBOL_LANGUAGE (arg->sym)));
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
> @@ -556,8 +556,7 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
>  	  END_CATCH
>  	}
>        if (error_message != NULL)
> -	fprintf_filtered (stb, _("<error reading variable: %s>"),
> -			  error_message);
> +	stb.printf (_("<error reading variable: %s>"), error_message);
>        uiout->field_stream ("value", stb);
>      }
>
> diff --git a/gdb/mi/mi-common.h b/gdb/mi/mi-common.h
> index 0d39cb7..e82b4a3 100644
> --- a/gdb/mi/mi-common.h
> +++ b/gdb/mi/mi-common.h
> @@ -19,6 +19,8 @@
>  #ifndef MI_COMMON_H
>  #define MI_COMMON_H
>
> +struct mi_console_file;
> +
>  /* Represents the reason why GDB is sending an asynchronous command to
>     the front end.  NOTE: When modifing this, don't forget to update
>     gdb.texinfo!  */
> @@ -51,11 +53,11 @@ const char *async_reason_lookup (enum async_reply_reason reason);
>  struct mi_interp
>  {
>    /* MI's output channels */
> -  struct ui_file *out;
> -  struct ui_file *err;
> -  struct ui_file *log;
> -  struct ui_file *targ;
> -  struct ui_file *event_channel;
> +  mi_console_file *out;
> +  mi_console_file *err;
> +  mi_console_file *log;
> +  mi_console_file *targ;
> +  mi_console_file *event_channel;
>
>    /* Raw console output.  */
>    struct ui_file *raw_stdout;
> diff --git a/gdb/mi/mi-console.c b/gdb/mi/mi-console.c
> index afb5e94..7c1c2ac 100644
> --- a/gdb/mi/mi-console.c
> +++ b/gdb/mi/mi-console.c
> @@ -26,118 +26,56 @@
>
>  #include "defs.h"
>  #include "mi-console.h"
> -static ui_file_fputs_ftype mi_console_file_fputs;
> -static ui_file_flush_ftype mi_console_file_flush;
> -static ui_file_delete_ftype mi_console_file_delete;
> -
> -struct mi_console_file
> -  {
> -    int *magic;
> -    struct ui_file *raw;
> -    struct ui_file *buffer;
> -    const char *prefix;
> -    char quote;
> -  };
> -
> -/* Use the address of this otherwise-unused global as a magic number
> -   identifying this class of ui_file objects.  */
> -static int mi_console_file_magic;
>
>  /* Create a console that wraps the given output stream RAW with the
>     string PREFIX and quoting it with QUOTE.  */
>
> -struct ui_file *
> -mi_console_file_new (struct ui_file *raw, const char *prefix, char quote)
> -{
> -  struct ui_file *ui_file = ui_file_new ();
> -  struct mi_console_file *mi_console = XNEW (struct mi_console_file);
> -
> -  mi_console->magic = &mi_console_file_magic;
> -  mi_console->raw = raw;
> -  mi_console->buffer = mem_fileopen ();
> -  mi_console->prefix = prefix;
> -  mi_console->quote = quote;
> -  set_ui_file_fputs (ui_file, mi_console_file_fputs);
> -  set_ui_file_flush (ui_file, mi_console_file_flush);
> -  set_ui_file_data (ui_file, mi_console, mi_console_file_delete);
> -
> -  return ui_file;
> -}
> -
> -static void
> -mi_console_file_delete (struct ui_file *file)
> -{
> -  struct mi_console_file *mi_console
> -    = (struct mi_console_file *) ui_file_data (file);
> -
> -  if (mi_console->magic != &mi_console_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mi_console_file_delete: bad magic number"));
> +mi_console_file::mi_console_file (ui_file *raw, const char *prefix, char quote)
> +  : m_raw (raw),
> +    m_prefix (prefix),
> +    m_quote (quote)
> +{}
>
> -  xfree (mi_console);
> -}
> -
> -static void
> -mi_console_file_fputs (const char *buf, struct ui_file *file)
> +void
> +mi_console_file::write (const char *buf, long length_buf)
>  {
> -  struct mi_console_file *mi_console
> -    = (struct mi_console_file *) ui_file_data (file);
> -
> -  if (mi_console->magic != &mi_console_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    "mi_console_file_fputs: bad magic number");
> -
> +  size_t prev_size = m_buffer.size ();
>    /* Append the text to our internal buffer.  */
> -  fputs_unfiltered (buf, mi_console->buffer);
> -  /* Flush when an embedded newline is present anywhere in the buffer.  */
> -  if (strchr (buf, '\n') != NULL)
> -    gdb_flush (file);
> +  m_buffer.write (buf, length_buf);
> +  /* Flush when an embedded newline is present anywhere in the
> +     buffer.  */
> +  if (strchr (m_buffer.c_str () + prev_size, '\n') != NULL)
> +    this->flush ();
>  }
>
> -/* Transform a byte sequence into a console output packet.  */
> -
> -static void
> -mi_console_raw_packet (void *data, const char *buf, long length_buf)
> +void
> +mi_console_file::flush ()
>  {
> -  struct mi_console_file *mi_console = (struct mi_console_file *) data;
> -
> -  if (mi_console->magic != &mi_console_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mi_console_raw_packet: bad magic number"));
> +  const std::string &str = m_buffer.string ();
>
> -  if (length_buf > 0)
> +  /* Transform a byte sequence into a console output packet.  */
> +  if (!str.empty ())
>      {
> -      fputs_unfiltered (mi_console->prefix, mi_console->raw);
> -      if (mi_console->quote)
> +      size_t length_buf = str.size ();
> +      const char *buf = str.data ();
> +
> +      fputs_unfiltered (m_prefix, m_raw);
> +      if (m_quote)
>  	{
> -	  fputc_unfiltered (mi_console->quote, mi_console->raw);
> -	  fputstrn_unfiltered (buf, length_buf,
> -			       mi_console->quote, mi_console->raw);
> -	  fputc_unfiltered (mi_console->quote, mi_console->raw);
> -	  fputc_unfiltered ('\n', mi_console->raw);
> +	  fputc_unfiltered (m_quote, m_raw);
> +	  fputstrn_unfiltered (buf, length_buf, m_quote, m_raw);
> +	  fputc_unfiltered (m_quote, m_raw);
> +	  fputc_unfiltered ('\n', m_raw);
>  	}
>        else
>  	{
> -	  fputstrn_unfiltered (buf, length_buf, 0, mi_console->raw);
> -	  fputc_unfiltered ('\n', mi_console->raw);
> +	  fputstrn_unfiltered (buf, length_buf, 0, m_raw);
> +	  fputc_unfiltered ('\n', m_raw);
>  	}
> -      gdb_flush (mi_console->raw);
> +      gdb_flush (m_raw);
>      }
> -}
> -
> -static void
> -mi_console_file_flush (struct ui_file *file)
> -{
> -  struct mi_console_file *mi_console
> -    = (struct mi_console_file *) ui_file_data (file);
> -
> -  if (mi_console->magic != &mi_console_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mi_console_file_flush: bad magic number"));
> -
> -  ui_file_put (mi_console->buffer, mi_console_raw_packet, mi_console);
> -  ui_file_rewind (mi_console->buffer);
>
> +  m_buffer.clear ();
>  }
>
>  /* Change the underlying stream of the console directly; this is
> @@ -145,14 +83,7 @@ mi_console_file_flush (struct ui_file *file)
>     logging enable/disable.  */
>
>  void
> -mi_console_set_raw (struct ui_file *file, struct ui_file *raw)
> +mi_console_file::set_raw (ui_file *raw)
>  {
> -  struct mi_console_file *mi_console
> -    = (struct mi_console_file *) ui_file_data (file);
> -
> -  if (mi_console->magic != &mi_console_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mi_console_file_set_raw: bad magic number"));
> -
> -  mi_console->raw = raw;
> +  m_raw = raw;
>  }
> diff --git a/gdb/mi/mi-console.h b/gdb/mi/mi-console.h
> index 64355a7..289013f 100644
> --- a/gdb/mi/mi-console.h
> +++ b/gdb/mi/mi-console.h
> @@ -20,11 +20,37 @@
>  #ifndef MI_CONSOLE_H
>  #define MI_CONSOLE_H
>
> -extern struct ui_file *mi_console_file_new (struct ui_file *raw,
> -					    const char *prefix,
> -					    char quote);
> +/* An output stream for MI.  Wraps a given output stream with a prefix
> +   and handles quoting.  This stream is locally buffered.  */
>
> -extern void mi_console_set_raw (struct ui_file *console,
> -				struct ui_file *raw);
> +class mi_console_file : public ui_file
> +{
> +public:
> +  /* Create a console that wraps the given output stream RAW with the
> +     string PREFIX and quoting it with QUOTE.  */
> +  mi_console_file (ui_file *raw, const char *prefix, char quote);
> +
> +  /* MI-specific API.  */
> +  void set_raw (ui_file *raw);
> +
> +  /* ui_file-specific methods.  */
> +
> +  void flush () override;
> +
> +  void write (const char *buf, long length_buf) override;
> +
> +private:
> +  /* The wrapped raw output stream.  */
> +  ui_file *m_raw;
> +
> +  /* The local buffer.  */
> +  string_file m_buffer;
> +
> +  /* The prefix.  */
> +  const char *m_prefix;
> +
> +  /* The quote char.  */
> +  char m_quote;
> +};
>
>  #endif
> diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
> index 76f4f8c..f167a53 100644
> --- a/gdb/mi/mi-interp.c
> +++ b/gdb/mi/mi-interp.c
> @@ -126,11 +126,11 @@ mi_interpreter_init (struct interp *interp, int top_level)
>
>    /* Create MI console channels, each with a different prefix so they
>       can be distinguished.  */
> -  mi->out = mi_console_file_new (mi->raw_stdout, "~", '"');
> -  mi->err = mi_console_file_new (mi->raw_stdout, "&", '"');
> +  mi->out = new mi_console_file (mi->raw_stdout, "~", '"');
> +  mi->err = new mi_console_file (mi->raw_stdout, "&", '"');
>    mi->log = mi->err;
> -  mi->targ = mi_console_file_new (mi->raw_stdout, "@", '"');
> -  mi->event_channel = mi_console_file_new (mi->raw_stdout, "=", 0);
> +  mi->targ = new mi_console_file (mi->raw_stdout, "@", '"');
> +  mi->event_channel = new mi_console_file (mi->raw_stdout, "=", 0);
>
>    name = interp_name (interp);
>    /* INTERP_MI selects the most recent released version.  "mi2" was
> @@ -1391,8 +1391,8 @@ mi_set_logging (struct interp *interp, int start_log,
>  	 it), and create one based on raw_stdout instead.  */
>        if (logfile)
>  	{
> -	  ui_file_delete (out);
> -	  out = tee_file_new (mi->raw_stdout, 0, logfile, 0);
> +	  delete out;
> +	  out = new tee_file (mi->raw_stdout, false, logfile, false);
>  	}
>
>        mi->saved_raw_stdout = mi->raw_stdout;
> @@ -1404,11 +1404,11 @@ mi_set_logging (struct interp *interp, int start_log,
>        mi->saved_raw_stdout = NULL;
>      }
>
> -  mi_console_set_raw (mi->out, mi->raw_stdout);
> -  mi_console_set_raw (mi->err, mi->raw_stdout);
> -  mi_console_set_raw (mi->log, mi->raw_stdout);
> -  mi_console_set_raw (mi->targ, mi->raw_stdout);
> -  mi_console_set_raw (mi->event_channel, mi->raw_stdout);
> +  mi->out->set_raw (mi->raw_stdout);
> +  mi->err->set_raw (mi->raw_stdout);
> +  mi->log->set_raw (mi->raw_stdout);
> +  mi->targ->set_raw (mi->raw_stdout);
> +  mi->event_channel->set_raw (mi->raw_stdout);
>
>    return 1;
>  }
> diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
> index 57c23eb..b249f2d 100644
> --- a/gdb/mi/mi-main.c
> +++ b/gdb/mi/mi-main.c
> @@ -1267,7 +1267,6 @@ output_register (struct frame_info *frame, int regnum, int format,
>    struct value *val = value_of_register (regnum, frame);
>    struct cleanup *tuple_cleanup;
>    struct value_print_options opts;
> -  struct ui_file *stb;
>
>    if (skip_unavailable && !value_entirely_available (val))
>      return;
> @@ -1281,14 +1280,13 @@ output_register (struct frame_info *frame, int regnum, int format,
>    if (format == 'r')
>      format = 'z';
>
> -  stb = mem_fileopen ();
> -  make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    get_formatted_print_options (&opts, format);
>    opts.deref_ref = 1;
>    val_print (value_type (val),
>  	     value_embedded_offset (val), 0,
> -	     stb, 0, val, &opts, current_language);
> +	     &stb, 0, val, &opts, current_language);
>    uiout->field_stream ("value", stb);
>
>    do_cleanups (tuple_cleanup);
> @@ -1358,15 +1356,10 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc)
>  void
>  mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
>  {
> -  struct cleanup *old_chain;
>    struct value *val;
> -  struct ui_file *stb;
>    struct value_print_options opts;
>    struct ui_out *uiout = current_uiout;
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> -
>    if (argc != 1)
>      error (_("-data-evaluate-expression: "
>  	     "Usage: -data-evaluate-expression expression"));
> @@ -1375,14 +1368,14 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
>
>    val = evaluate_expression (expr.get ());
>
> +  string_file stb;
> +
>    /* Print the result of the expression evaluation.  */
>    get_user_print_options (&opts);
>    opts.deref_ref = 0;
> -  common_val_print (val, stb, 0, &opts, current_language);
> +  common_val_print (val, &stb, 0, &opts, current_language);
>
>    uiout->field_stream ("value", stb);
> -
> -  do_cleanups (old_chain);
>  }
>
>  /* This is the -data-read-memory command.
> @@ -1522,15 +1515,13 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
>
>    /* Build the result as a two dimentional table.  */
>    {
> -    struct ui_file *stream;
> -    struct cleanup *cleanup_stream;
>      int row;
>      int row_byte;
> +    struct cleanup *cleanup_list;
>
> -    stream = mem_fileopen ();
> -    cleanup_stream = make_cleanup_ui_file_delete (stream);
> +    string_file stream;
>
> -    make_cleanup_ui_out_list_begin_end (uiout, "memory");
> +    cleanup_list = make_cleanup_ui_out_list_begin_end (uiout, "memory");
>      for (row = 0, row_byte = 0;
>  	 row < nr_rows;
>  	 row++, row_byte += nr_cols * word_size)
> @@ -1557,9 +1548,9 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
>  	      }
>  	    else
>  	      {
> -		ui_file_rewind (stream);
> +		stream.clear ();
>  		print_scalar_formatted (&mbuf[col_byte], word_type, &opts,
> -					word_asize, stream);
> +					word_asize, &stream);
>  		uiout->field_stream (NULL, stream);
>  	      }
>  	  }
> @@ -1568,22 +1559,22 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
>  	  {
>  	    int byte;
>
> -	    ui_file_rewind (stream);
> +	    stream.clear ();
>  	    for (byte = row_byte;
>  		 byte < row_byte + word_size * nr_cols; byte++)
>  	      {
>  		if (byte >= nr_bytes)
> -		  fputc_unfiltered ('X', stream);
> +		  stream.putc ('X');
>  		else if (mbuf[byte] < 32 || mbuf[byte] > 126)
> -		  fputc_unfiltered (aschar, stream);
> +		  stream.putc (aschar);
>  		else
> -		  fputc_unfiltered (mbuf[byte], stream);
> +		  stream.putc (mbuf[byte]);
>  	      }
>  	    uiout->field_stream ("ascii", stream);
>  	  }
>  	do_cleanups (cleanup_tuple);
>        }
> -    do_cleanups (cleanup_stream);
> +    do_cleanups (cleanup_list);
>    }
>  }
>
> @@ -2317,15 +2308,12 @@ mi_cmd_execute (struct mi_parse *parse)
>    else
>      {
>        /* FIXME: DELETE THIS.  */
> -      struct ui_file *stb;
> -
> -      stb = mem_fileopen ();
> +      string_file stb;
>
> -      fputs_unfiltered ("Undefined mi command: ", stb);
> -      fputstr_unfiltered (parse->command, '"', stb);
> -      fputs_unfiltered (" (missing implementation)", stb);
> +      stb.puts ("Undefined mi command: ");
> +      stb.putstr (parse->command, '"');
> +      stb.puts (" (missing implementation)");
>
> -      make_cleanup_ui_file_delete (stb);
>        error_stream (stb);
>      }
>    do_cleanups (cleanup);
> @@ -2705,12 +2693,10 @@ print_variable_or_computed (const char *expression, enum print_values values)
>  {
>    struct cleanup *old_chain;
>    struct value *val;
> -  struct ui_file *stb;
>    struct type *type;
>    struct ui_out *uiout = current_uiout;
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    expression_up expr = parse_expression (expression);
>
> @@ -2719,6 +2705,7 @@ print_variable_or_computed (const char *expression, enum print_values values)
>    else
>      val = evaluate_expression (expr.get ());
>
> +  old_chain = make_cleanup (null_cleanup, NULL);
>    if (values != PRINT_NO_VALUES)
>      make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
>    uiout->field_string ("name", expression);
> @@ -2727,7 +2714,7 @@ print_variable_or_computed (const char *expression, enum print_values values)
>      {
>      case PRINT_SIMPLE_VALUES:
>        type = check_typedef (value_type (val));
> -      type_print (value_type (val), "", stb, -1);
> +      type_print (value_type (val), "", &stb, -1);
>        uiout->field_stream ("type", stb);
>        if (TYPE_CODE (type) != TYPE_CODE_ARRAY
>  	  && TYPE_CODE (type) != TYPE_CODE_STRUCT
> @@ -2737,7 +2724,7 @@ print_variable_or_computed (const char *expression, enum print_values values)
>
>  	  get_no_prettyformat_print_options (&opts);
>  	  opts.deref_ref = 1;
> -	  common_val_print (val, stb, 0, &opts, current_language);
> +	  common_val_print (val, &stb, 0, &opts, current_language);
>  	  uiout->field_stream ("value", stb);
>  	}
>        break;
> @@ -2747,7 +2734,7 @@ print_variable_or_computed (const char *expression, enum print_values values)
>
>  	get_no_prettyformat_print_options (&opts);
>  	opts.deref_ref = 1;
> -	common_val_print (val, stb, 0, &opts, current_language);
> +	common_val_print (val, &stb, 0, &opts, current_language);
>  	uiout->field_stream ("value", stb);
>        }
>        break;
> diff --git a/gdb/mi/mi-out.c b/gdb/mi/mi-out.c
> index 5a5aef9..6181140 100644
> --- a/gdb/mi/mi-out.c
> +++ b/gdb/mi/mi-out.c
> @@ -236,23 +236,31 @@ mi_ui_out::close (ui_out_type type)
>    m_suppress_field_separator = false;
>  }
>
> +string_file *
> +mi_ui_out::main_stream ()
> +{
> +  gdb_assert (m_streams.size () == 1);
> +
> +  return (string_file *) m_streams.back ();
> +}
> +
>  /* Clear the buffer.  */
>
>  void
>  mi_ui_out::rewind ()
>  {
> -  ui_file_rewind (m_streams.back ());
> +  main_stream ()->clear ();
>  }
>
>  /* Dump the buffer onto the specified stream.  */
>
>  void
> -mi_ui_out::put (ui_file *stream)
> +mi_ui_out::put (ui_file *where)
>  {
> -  ui_file *outstream = m_streams.back ();
> +  string_file *mi_stream = main_stream ();
>
> -  ui_file_put (outstream, ui_file_write_for_put, stream);
> -  ui_file_rewind (outstream);
> +  where->write (mi_stream->data (), mi_stream->size ());
> +  mi_stream->clear ();
>  }
>
>  /* Return the current MI version.  */
> @@ -265,13 +273,12 @@ mi_ui_out::version ()
>
>  /* Constructor for an `mi_out_data' object.  */
>
> -mi_ui_out::mi_ui_out (int mi_version, ui_file *stream)
> +mi_ui_out::mi_ui_out (int mi_version)
>  : m_suppress_field_separator (false),
>    m_suppress_output (false),
>    m_mi_version (mi_version)
>  {
> -  gdb_assert (stream != NULL);
> -
> +  string_file *stream = new string_file ();
>    m_streams.push_back (stream);
>  }
>
> @@ -284,9 +291,7 @@ mi_ui_out::~mi_ui_out ()
>  mi_ui_out *
>  mi_out_new (int mi_version)
>  {
> -  ui_file *stream = mem_fileopen ();
> -
> -  return new mi_ui_out (mi_version, stream);
> +  return new mi_ui_out (mi_version);
>  }
>
>  /* Helper function to return the given UIOUT as an mi_ui_out.  It is an error
> diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h
> index e82d44d..fea94f2 100644
> --- a/gdb/mi/mi-out.h
> +++ b/gdb/mi/mi-out.h
> @@ -30,7 +30,7 @@ class mi_ui_out : public ui_out
>  {
>  public:
>
> -  explicit mi_ui_out (int mi_version, ui_file *stream);
> +  explicit mi_ui_out (int mi_version);
>    virtual ~mi_ui_out ();
>
>    /* MI-specific */
> @@ -78,6 +78,11 @@ private:
>    void open (const char *name, ui_out_type type);
>    void close (ui_out_type type);
>
> +  /* Convenience method that returns the MI out's string stream cast
> +     to its appropriate type.  Assumes/asserts that output was not
> +     redirected.  */
> +  string_file *main_stream ();
> +
>    bool m_suppress_field_separator;
>    bool m_suppress_output;
>    int m_mi_version;
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index e4711e9..dab4f53 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -2717,18 +2717,13 @@ printf_command (char *arg, int from_tty)
>  static void
>  eval_command (char *arg, int from_tty)
>  {
> -  struct ui_file *ui_out = mem_fileopen ();
> -  struct cleanup *cleanups = make_cleanup_ui_file_delete (ui_out);
> +  string_file stb;
>
> -  ui_printf (arg, ui_out);
> +  ui_printf (arg, &stb);
>
> -  std::string expanded = ui_file_as_string (ui_out);
> -
> -  expanded = insert_user_defined_cmd_args (expanded.c_str ());
> +  std::string expanded = insert_user_defined_cmd_args (stb.c_str ());
>
>    execute_command (&expanded[0], from_tty);
> -
> -  do_cleanups (cleanups);
>  }
>
>  void
> diff --git a/gdb/psymtab.c b/gdb/psymtab.c
> index 3acc226..1fad8a0 100644
> --- a/gdb/psymtab.c
> +++ b/gdb/psymtab.c
> @@ -1965,6 +1965,8 @@ maintenance_print_psymbols (char *args, int from_tty)
>    if (address_arg != NULL && source_arg != NULL)
>      error (_("Must specify at most one of -pc and -source"));
>
> +  stdio_file arg_outfile;
> +
>    if (argv[outfile_idx] != NULL)
>      {
>        char *outfile_name;
> @@ -1973,10 +1975,9 @@ maintenance_print_psymbols (char *args, int from_tty)
>  	error (_("Junk at end of command"));
>        outfile_name = tilde_expand (argv[outfile_idx]);
>        make_cleanup (xfree, outfile_name);
> -      outfile = gdb_fopen (outfile_name, FOPEN_WT);
> -      if (outfile == NULL)
> +      if (!arg_outfile.open (outfile_name, FOPEN_WT))
>  	perror_with_name (outfile_name);
> -      make_cleanup_ui_file_delete (outfile);
> +      outfile = &arg_outfile;
>      }
>
>    if (address_arg != NULL)
> @@ -2011,9 +2012,8 @@ maintenance_print_psymbols (char *args, int from_tty)
>  	    {
>  	      if (!printed_objfile_header)
>  		{
> -		  fprintf_filtered (outfile,
> -				    "\nPartial symtabs for objfile %s\n",
> -				    objfile_name (objfile));
> +		  outfile->printf ("\nPartial symtabs for objfile %s\n",
> +				  objfile_name (objfile));
>  		  printed_objfile_header = 1;
>  		}
>  	      dump_psymtab (objfile, ps, outfile);
> @@ -2039,9 +2039,8 @@ maintenance_print_psymbols (char *args, int from_tty)
>  		{
>  		  if (!printed_objfile_header)
>  		    {
> -		      fprintf_filtered (outfile,
> -					"\nPartial symtabs for objfile %s\n",
> -					objfile_name (objfile));
> +		      outfile->printf ("\nPartial symtabs for objfile %s\n",
> +				       objfile_name (objfile));
>  		      printed_objfile_header = 1;
>  		    }
>  		  dump_psymtab (objfile, ps, outfile);
> @@ -2056,7 +2055,7 @@ maintenance_print_psymbols (char *args, int from_tty)
>  	  && source_arg == NULL
>  	  && objfile->psymtabs_addrmap != NULL)
>  	{
> -	  fprintf_filtered (outfile, "\n");
> +	  outfile->puts ("\n");
>  	  dump_psymtab_addrmap (objfile, NULL, outfile);
>  	}
>      }
> diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c
> index 13cc9ba..8d0ec33 100644
> --- a/gdb/python/py-arch.c
> +++ b/gdb/python/py-arch.c
> @@ -193,54 +193,38 @@ archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
>         || (end_obj == NULL && count_obj == NULL && pc == start);)
>      {
>        int insn_len = 0;
> -      struct ui_file *memfile = mem_fileopen ();
>        gdbpy_ref insn_dict (PyDict_New ());
>
>        if (insn_dict == NULL)
> -        {
> -          ui_file_delete (memfile);
> -
> -          return NULL;
> -        }
> +	return NULL;
>        if (PyList_Append (result_list.get (), insn_dict.get ()))
> -        {
> -          ui_file_delete (memfile);
> +	return NULL;  /* PyList_Append Sets the exception.  */
>
> -          return NULL;  /* PyList_Append Sets the exception.  */
> -        }
> +      string_file stb;
>
>        TRY
>          {
> -          insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
> +          insn_len = gdb_print_insn (gdbarch, pc, &stb, NULL);
>          }
>        CATCH (except, RETURN_MASK_ALL)
>          {
> -          ui_file_delete (memfile);
> -
>  	  gdbpy_convert_exception (except);
>  	  return NULL;
>          }
>        END_CATCH
>
> -      std::string as = ui_file_as_string (memfile);
> -
>        if (PyDict_SetItemString (insn_dict.get (), "addr",
>                                  gdb_py_long_from_ulongest (pc))
>            || PyDict_SetItemString (insn_dict.get (), "asm",
> -                                   PyString_FromString (!as.empty ()
> -							? as.c_str ()
> +                                   PyString_FromString (!stb.empty ()
> +							? stb.c_str ()
>  							: "<unknown>"))
>            || PyDict_SetItemString (insn_dict.get (), "length",
>                                     PyInt_FromLong (insn_len)))
> -        {
> -          ui_file_delete (memfile);
> -
> -          return NULL;
> -        }
> +	return NULL;
>
>        pc += insn_len;
>        i++;
> -      ui_file_delete (memfile);
>      }
>
>    return result_list.release ();
> diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
> index f268b2b..ac64900 100644
> --- a/gdb/python/py-breakpoint.c
> +++ b/gdb/python/py-breakpoint.c
> @@ -485,19 +485,16 @@ bppy_get_commands (PyObject *self, void *closure)
>    gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
>    struct breakpoint *bp = self_bp->bp;
>    long length;
> -  struct ui_file *string_file;
>    PyObject *result;
> -  struct cleanup *chain;
>
>    BPPY_REQUIRE_VALID (self_bp);
>
>    if (! self_bp->bp->commands)
>      Py_RETURN_NONE;
>
> -  string_file = mem_fileopen ();
> -  chain = make_cleanup_ui_file_delete (string_file);
> +  string_file stb;
>
> -  current_uiout->redirect (string_file);
> +  current_uiout->redirect (&stb);
>    TRY
>      {
>        print_command_lines (current_uiout, breakpoint_commands (bp), 0);
> @@ -505,17 +502,13 @@ bppy_get_commands (PyObject *self, void *closure)
>    CATCH (except, RETURN_MASK_ALL)
>      {
>        current_uiout->redirect (NULL);
> -      do_cleanups (chain);
>        gdbpy_convert_exception (except);
>        return NULL;
>      }
>    END_CATCH
>
>    current_uiout->redirect (NULL);
> -  std::string cmdstr = ui_file_as_string (string_file);
> -  result = host_string_to_python_string (cmdstr.c_str ());
> -  do_cleanups (chain);
> -  return result;
> +  return host_string_to_python_string (stb.c_str ());
>  }
>
>  /* Python function to get the breakpoint type.  */
> diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
> index 048e7c1..8f5ddd0 100644
> --- a/gdb/python/py-frame.c
> +++ b/gdb/python/py-frame.c
> @@ -80,13 +80,10 @@ frame_object_to_frame_info (PyObject *obj)
>  static PyObject *
>  frapy_str (PyObject *self)
>  {
> -  PyObject *result;
> -  struct ui_file *strfile;
> +  string_file strfile;
>
> -  strfile = mem_fileopen ();
> -  fprint_frame_id (strfile, ((frame_object *) self)->frame_id);
> -  std::string s = ui_file_as_string (strfile);
> -  return PyString_FromString (s.c_str ());
> +  fprint_frame_id (&strfile, ((frame_object *) self)->frame_id);
> +  return PyString_FromString (strfile.c_str ());
>  }
>
>  /* Implementation of gdb.Frame.is_valid (self) -> Boolean.
> diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
> index bdd9911..9dc01ba 100644
> --- a/gdb/python/py-framefilter.c
> +++ b/gdb/python/py-framefilter.c
> @@ -208,15 +208,11 @@ py_print_type (struct ui_out *out, struct value *val)
>
>    TRY
>      {
> -      struct ui_file *stb;
> -      struct cleanup *cleanup;
> -
> -      stb = mem_fileopen ();
> -      cleanup = make_cleanup_ui_file_delete (stb);
>        check_typedef (value_type (val));
> -      type_print (value_type (val), "", stb, -1);
> +
> +      string_file stb;
> +      type_print (value_type (val), "", &stb, -1);
>        out->field_stream ("type", stb);
> -      do_cleanups (cleanup);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> @@ -280,14 +276,10 @@ py_print_value (struct ui_out *out, struct value *val,
>      {
>        TRY
>  	{
> -	  struct ui_file *stb;
> -	  struct cleanup *cleanup;
> +	  string_file stb;
>
> -	  stb = mem_fileopen ();
> -	  cleanup = make_cleanup_ui_file_delete (stb);
> -	  common_val_print (val, stb, indent, opts, language);
> +	  common_val_print (val, &stb, indent, opts, language);
>  	  out->field_stream ("value", stb);
> -	  do_cleanups (cleanup);
>  	}
>        CATCH (except, RETURN_MASK_ALL)
>  	{
> @@ -393,26 +385,22 @@ py_print_single_arg (struct ui_out *out,
>  	 entry value options.  */
>        if (fa != NULL)
>  	{
> -	  struct ui_file *stb;
> +	  string_file stb;
>
> -	  stb = mem_fileopen ();
> -	  make_cleanup_ui_file_delete (stb);
> -	  fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
> +	  fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (fa->sym),
>  				   SYMBOL_LANGUAGE (fa->sym),
>  				   DMGL_PARAMS | DMGL_ANSI);
>  	  if (fa->entry_kind == print_entry_values_compact)
>  	    {
> -	      fputs_filtered ("=", stb);
> +	      stb.puts ("=");
>
> -	      fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
> +	      fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (fa->sym),
>  				       SYMBOL_LANGUAGE (fa->sym),
>  				       DMGL_PARAMS | DMGL_ANSI);
>  	    }
>  	  if (fa->entry_kind == print_entry_values_only
>  	      || fa->entry_kind == print_entry_values_compact)
> -	    {
> -	      fputs_filtered ("@entry", stb);
> -	    }
> +	    stb.puts ("@entry");
>  	  out->field_stream ("name", stb);
>  	}
>        else
> diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
> index 7862829..f6e8dd6 100644
> --- a/gdb/python/py-type.c
> +++ b/gdb/python/py-type.c
> @@ -967,22 +967,13 @@ typy_template_argument (PyObject *self, PyObject *args)
>  static PyObject *
>  typy_str (PyObject *self)
>  {
> -  std::string thetype;
> +  string_file thetype;
>    PyObject *result;
>
>    TRY
>      {
> -      struct cleanup *old_chain;
> -      struct ui_file *stb;
> -
> -      stb = mem_fileopen ();
> -      old_chain = make_cleanup_ui_file_delete (stb);
> -
> -      LA_PRINT_TYPE (type_object_to_type (self), "", stb, -1, 0,
> +      LA_PRINT_TYPE (type_object_to_type (self), "", &thetype, -1, 0,
>  		     &type_print_raw_options);
> -
> -      thetype = ui_file_as_string (stb);
> -      do_cleanups (old_chain);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> @@ -990,10 +981,8 @@ typy_str (PyObject *self)
>      }
>    END_CATCH
>
> -  result = PyUnicode_Decode (thetype.c_str (), thetype.length (),
> -			     host_charset (), NULL);
> -
> -  return result;
> +  return PyUnicode_Decode (thetype.c_str (), thetype.size (),
> +			   host_charset (), NULL);
>  }
>
>  /* Implement the richcompare method.  */
> diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
> index 690412a..d1b63ad 100644
> --- a/gdb/python/py-unwind.c
> +++ b/gdb/python/py-unwind.c
> @@ -198,12 +198,11 @@ pyuw_object_attribute_to_pointer (PyObject *pyo, const char *attr_name,
>  static PyObject *
>  unwind_infopy_str (PyObject *self)
>  {
> -  struct ui_file *strfile = mem_fileopen ();
>    unwind_info_object *unwind_info = (unwind_info_object *) self;
> -  PyObject *result;
> +  string_file stb;
>
> -  fprintf_unfiltered (strfile, "Frame ID: ");
> -  fprint_frame_id (strfile, unwind_info->frame_id);
> +  stb.puts ("Frame ID: ");
> +  fprint_frame_id (&stb, unwind_info->frame_id);
>    {
>      char *sep = "";
>      int i;
> @@ -211,18 +210,18 @@ unwind_infopy_str (PyObject *self)
>      saved_reg *reg;
>
>      get_user_print_options (&opts);
> -    fprintf_unfiltered (strfile, "\nSaved registers: (");
> +    stb.printf ("\nSaved registers: (");
>      for (i = 0; VEC_iterate (saved_reg, unwind_info->saved_regs, i, reg); i++)
>        {
>          struct value *value = value_object_to_value (reg->value);
>
> -        fprintf_unfiltered (strfile, "%s(%d, ", sep, reg->number);
> +        stb.printf ("%s(%d, ", sep, reg->number);
>          if (value != NULL)
>            {
>              TRY
>                {
> -                value_print (value, strfile, &opts);
> -                fprintf_unfiltered (strfile, ")");
> +                value_print (value, &stb, &opts);
> +                stb.puts (")");
>                }
>              CATCH (except, RETURN_MASK_ALL)
>                {
> @@ -231,16 +230,13 @@ unwind_infopy_str (PyObject *self)
>              END_CATCH
>            }
>          else
> -          fprintf_unfiltered (strfile, "<BAD>)");
> +          stb.puts ("<BAD>)");
>          sep = ", ";
>        }
> -    fprintf_unfiltered (strfile, ")");
> +    stb.puts (")");
>    }
>
> -  std::string s = ui_file_as_string (strfile);
> -  result = PyString_FromString (s.c_str ());
> -  ui_file_delete (strfile);
> -  return result;
> +  return PyString_FromString (stb.c_str ());
>  }
>
>  /* Create UnwindInfo instance for given PendingFrame and frame ID.
> diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
> index 8f3164b..8e4d06d 100644
> --- a/gdb/python/py-value.c
> +++ b/gdb/python/py-value.c
> @@ -867,23 +867,17 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
>  static PyObject *
>  valpy_str (PyObject *self)
>  {
> -  std::string s;
> -  PyObject *result;
>    struct value_print_options opts;
>
>    get_user_print_options (&opts);
>    opts.deref_ref = 0;
>
> +  string_file stb;
> +
>    TRY
>      {
> -      struct ui_file *stb = mem_fileopen ();
> -      struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
> -
> -      common_val_print (((value_object *) self)->value, stb, 0,
> +      common_val_print (((value_object *) self)->value, &stb, 0,
>  			&opts, python_language);
> -      s = ui_file_as_string (stb);
> -
> -      do_cleanups (old_chain);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> @@ -891,9 +885,7 @@ valpy_str (PyObject *self)
>      }
>    END_CATCH
>
> -  result = PyUnicode_Decode (s.c_str (), s.length (), host_charset (), NULL);
> -
> -  return result;
> +  return PyUnicode_Decode (stb.c_str (), stb.size (), host_charset (), NULL);
>  }
>
>  /* Implements gdb.Value.is_optimized_out.  */
> diff --git a/gdb/regcache.c b/gdb/regcache.c
> index 9d28aa2..eed1bd8 100644
> --- a/gdb/regcache.c
> +++ b/gdb/regcache.c
> @@ -1498,14 +1498,11 @@ regcache_print (char *args, enum regcache_dump_what what_to_dump)
>      regcache_dump (get_current_regcache (), gdb_stdout, what_to_dump);
>    else
>      {
> -      struct cleanup *cleanups;
> -      struct ui_file *file = gdb_fopen (args, "w");
> +      stdio_file file;
>
> -      if (file == NULL)
> +      if (!file.open (args, "w"))
>  	perror_with_name (_("maintenance print architecture"));
> -      cleanups = make_cleanup_ui_file_delete (file);
> -      regcache_dump (get_current_regcache (), file, what_to_dump);
> -      do_cleanups (cleanups);
> +      regcache_dump (get_current_regcache (), &file, what_to_dump);
>      }
>  }
>
> diff --git a/gdb/reggroups.c b/gdb/reggroups.c
> index 693b378..ae7d4ce 100644
> --- a/gdb/reggroups.c
> +++ b/gdb/reggroups.c
> @@ -270,14 +270,11 @@ maintenance_print_reggroups (char *args, int from_tty)
>      reggroups_dump (gdbarch, gdb_stdout);
>    else
>      {
> -      struct cleanup *cleanups;
> -      struct ui_file *file = gdb_fopen (args, "w");
> +      stdio_file file;
>
> -      if (file == NULL)
> +      if (!file.open (args, "w"))
>  	perror_with_name (_("maintenance print reggroups"));
> -      cleanups = make_cleanup_ui_file_delete (file);
> -      reggroups_dump (gdbarch, file);
> -      do_cleanups (cleanups);
> +      reggroups_dump (gdbarch, &file);
>      }
>  }
>
> diff --git a/gdb/remote.c b/gdb/remote.c
> index c4cec91..3befbd3 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -8674,16 +8674,10 @@ remote_send (char **buf,
>  static std::string
>  escape_buffer (const char *buf, int n)
>  {
> -  struct cleanup *old_chain;
> -  struct ui_file *stb;
> -
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
> -  fputstrn_unfiltered (buf, n, '\\', stb);
> -  std::string str = ui_file_as_string (stb);
> -  do_cleanups (old_chain);
> -  return str;
> +  stb.putstrn (buf, n, '\\');
> +  return std::move (stb.string ());
>  }
>
>  /* Display a null-terminated packet on stdout, for debugging, using C
> diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
> index 4445812..dd72cd9 100644
> --- a/gdb/rust-lang.c
> +++ b/gdb/rust-lang.c
> @@ -125,7 +125,6 @@ rust_get_disr_info (struct type *type, const gdb_byte *valaddr,
>    int i;
>    struct disr_info ret;
>    struct type *disr_type;
> -  struct ui_file *temp_file;
>    struct value_print_options opts;
>    struct cleanup *cleanup;
>    const char *name_segment;
> @@ -229,17 +228,16 @@ rust_get_disr_info (struct type *type, const gdb_byte *valaddr,
>    if (strcmp (TYPE_FIELD_NAME (disr_type, 0), "RUST$ENUM$DISR") != 0)
>      error (_("Rust debug format has changed"));
>
> -  temp_file = mem_fileopen ();
> -  cleanup = make_cleanup_ui_file_delete (temp_file);
> +  string_file temp_file;
>    /* The first value of the first field (or any field)
>       is the discriminant value.  */
>    c_val_print (TYPE_FIELD_TYPE (disr_type, 0),
>  	       (embedded_offset + TYPE_FIELD_BITPOS (type, 0) / 8
>  		+ TYPE_FIELD_BITPOS (disr_type, 0) / 8),
> -	       address, temp_file,
> +	       address, &temp_file,
>  	       0, val, &opts);
>
> -  ret.name = ui_file_as_string (temp_file);
> +  ret.name = std::move (temp_file.string ());
>    name_segment = rust_last_path_segment (ret.name.c_str ());
>    if (name_segment != NULL)
>      {
> @@ -271,7 +269,6 @@ rust_get_disr_info (struct type *type, const gdb_byte *valaddr,
>  	     TYPE_TAG_NAME (type), ret.name.c_str ());
>      }
>
> -  do_cleanups (cleanup);
>    return ret;
>  }
>
> diff --git a/gdb/serial.c b/gdb/serial.c
> index afb7075..b48b977 100644
> --- a/gdb/serial.c
> +++ b/gdb/serial.c
> @@ -251,9 +251,12 @@ serial_open_ops_1 (const struct serial_ops *ops, const char *open_name)
>
>    if (serial_logfile != NULL)
>      {
> -      serial_logfp = gdb_fopen (serial_logfile, "w");
> -      if (serial_logfp == NULL)
> +      stdio_file_up file (new stdio_file ());
> +
> +      if (!file->open (serial_logfile, "w"))
>  	perror_with_name (serial_logfile);
> +
> +      serial_logfp = file.release ();
>      }
>
>    return scb;
> @@ -315,7 +318,7 @@ do_serial_close (struct serial *scb, int really_close)
>        serial_current_type = 0;
>
>        /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr?  */
> -      ui_file_delete (serial_logfp);
> +      delete serial_logfp;
>        serial_logfp = NULL;
>      }
>
> diff --git a/gdb/stack.c b/gdb/stack.c
> index 4c9e14e..e24aaf3 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -225,11 +225,9 @@ print_frame_arg (const struct frame_arg *arg)
>  {
>    struct ui_out *uiout = current_uiout;
>    struct cleanup *old_chain;
> -  struct ui_file *stb;
>    const char *error_message = NULL;
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> +  string_file stb;
>
>    gdb_assert (!arg->val || !arg->error);
>    gdb_assert (arg->entry_kind == print_entry_values_no
> @@ -239,22 +237,22 @@ print_frame_arg (const struct frame_arg *arg)
>
>    annotate_arg_begin ();
>
> -  make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
> -  fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (arg->sym),
> +  old_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
> +  fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (arg->sym),
>  			   SYMBOL_LANGUAGE (arg->sym), DMGL_PARAMS | DMGL_ANSI);
>    if (arg->entry_kind == print_entry_values_compact)
>      {
>        /* It is OK to provide invalid MI-like stream as with
>  	 PRINT_ENTRY_VALUE_COMPACT we never use MI.  */
> -      fputs_filtered ("=", stb);
> +      stb.puts ("=");
>
> -      fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (arg->sym),
> +      fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (arg->sym),
>  			       SYMBOL_LANGUAGE (arg->sym),
>  			       DMGL_PARAMS | DMGL_ANSI);
>      }
>    if (arg->entry_kind == print_entry_values_only
>        || arg->entry_kind == print_entry_values_compact)
> -    fputs_filtered ("@entry", stb);
> +    stb.puts ("@entry");
>    uiout->field_stream ("name", stb);
>    annotate_arg_name_end ();
>    uiout->text ("=");
> @@ -294,7 +292,7 @@ print_frame_arg (const struct frame_arg *arg)
>  	      /* True in "summary" mode, false otherwise.  */
>  	      opts.summary = !strcmp (print_frame_arguments, "scalars");
>
> -	      common_val_print (arg->val, stb, 2, &opts, language);
> +	      common_val_print (arg->val, &stb, 2, &opts, language);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> @@ -303,8 +301,7 @@ print_frame_arg (const struct frame_arg *arg)
>  	  END_CATCH
>  	}
>        if (error_message != NULL)
> -	fprintf_filtered (stb, _("<error reading variable: %s>"),
> -			  error_message);
> +	stb.printf (_("<error reading variable: %s>"), error_message);
>      }
>
>    uiout->field_stream ("value", stb);
> @@ -1158,7 +1155,6 @@ print_frame (struct frame_info *frame, int print_level,
>    struct ui_out *uiout = current_uiout;
>    char *funname = NULL;
>    enum language funlang = language_unknown;
> -  struct ui_file *stb;
>    struct cleanup *old_chain, *list_chain;
>    struct value_print_options opts;
>    struct symbol *func;
> @@ -1167,11 +1163,9 @@ print_frame (struct frame_info *frame, int print_level,
>
>    pc_p = get_frame_pc_if_available (frame, &pc);
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
>
>    find_frame_funname (frame, &funname, &funlang, &func);
> -  make_cleanup (xfree, funname);
> +  old_chain = make_cleanup (xfree, funname);
>
>    annotate_frame_begin (print_level ? frame_relative_level (frame) : 0,
>  			gdbarch, pc);
> @@ -1199,7 +1193,9 @@ print_frame (struct frame_info *frame, int print_level,
>  	uiout->text (" in ");
>        }
>    annotate_frame_function_name ();
> -  fprintf_symbol_filtered (stb, funname ? funname : "??",
> +
> +  string_file stb;
> +  fprintf_symbol_filtered (&stb, funname ? funname : "??",
>  			   funlang, DMGL_ANSI);
>    uiout->field_stream ("func", stb);
>    uiout->wrap_hint ("   ");
> diff --git a/gdb/symmisc.c b/gdb/symmisc.c
> index 811183c..07d571a 100644
> --- a/gdb/symmisc.c
> +++ b/gdb/symmisc.c
> @@ -457,6 +457,8 @@ maintenance_print_symbols (char *args, int from_tty)
>    if (address_arg != NULL && source_arg != NULL)
>      error (_("Must specify at most one of -pc and -source"));
>
> +  stdio_file arg_outfile;
> +
>    if (argv[outfile_idx] != NULL)
>      {
>        char *outfile_name;
> @@ -465,10 +467,9 @@ maintenance_print_symbols (char *args, int from_tty)
>  	error (_("Junk at end of command"));
>        outfile_name = tilde_expand (argv[outfile_idx]);
>        make_cleanup (xfree, outfile_name);
> -      outfile = gdb_fopen (outfile_name, FOPEN_WT);
> -      if (outfile == NULL)
> +      if (!arg_outfile.open (outfile_name, FOPEN_WT))
>  	perror_with_name (outfile_name);
> -      make_cleanup_ui_file_delete (outfile);
> +      outfile = &arg_outfile;
>      }
>
>    if (address_arg != NULL)
> @@ -744,6 +745,8 @@ maintenance_print_msymbols (char *args, int from_tty)
>      }
>    outfile_idx = i;
>
> +  stdio_file arg_outfile;
> +
>    if (argv[outfile_idx] != NULL)
>      {
>        char *outfile_name;
> @@ -752,10 +755,9 @@ maintenance_print_msymbols (char *args, int from_tty)
>  	error (_("Junk at end of command"));
>        outfile_name = tilde_expand (argv[outfile_idx]);
>        make_cleanup (xfree, outfile_name);
> -      outfile = gdb_fopen (outfile_name, FOPEN_WT);
> -      if (outfile == NULL)
> +      if (!arg_outfile.open (outfile_name, FOPEN_WT))
>  	perror_with_name (outfile_name);
> -      make_cleanup_ui_file_delete (outfile);
> +      outfile = &arg_outfile;
>      }
>
>    ALL_OBJFILES (objfile)
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index f4cfdf6..88bdd27 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -674,7 +674,7 @@ struct symbol_computed_ops
>       The generated C code must assign the location to a local
>       variable; this variable's name is RESULT_NAME.  */
>
> -  void (*generate_c_location) (struct symbol *symbol, struct ui_file *stream,
> +  void (*generate_c_location) (struct symbol *symbol, string_file &stream,
>  			       struct gdbarch *gdbarch,
>  			       unsigned char *registers_used,
>  			       CORE_ADDR pc, const char *result_name);
> diff --git a/gdb/top.c b/gdb/top.c
> index f712bea..6bf9d8c0 100644
> --- a/gdb/top.c
> +++ b/gdb/top.c
> @@ -272,9 +272,9 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream)
>
>    ui->input_interactive_p = ISATTY (ui->instream);
>
> -  ui->m_gdb_stdin = stdio_fileopen (ui->instream);
> -  ui->m_gdb_stdout = stdio_fileopen (ui->outstream);
> -  ui->m_gdb_stderr = stderr_fileopen (ui->errstream);
> +  ui->m_gdb_stdin = new stdio_file (ui->instream);
> +  ui->m_gdb_stdout = new stdio_file (ui->outstream);
> +  ui->m_gdb_stderr = new stderr_file (ui->errstream);
>    ui->m_gdb_stdlog = ui->m_gdb_stderr;
>
>    ui->prompt_state = PROMPT_NEEDED;
> @@ -296,9 +296,9 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream)
>  static void
>  free_ui (struct ui *ui)
>  {
> -  ui_file_delete (ui->m_gdb_stdin);
> -  ui_file_delete (ui->m_gdb_stdout);
> -  ui_file_delete (ui->m_gdb_stderr);
> +  delete ui->m_gdb_stdin;
> +  delete ui->m_gdb_stdout;
> +  delete ui->m_gdb_stderr;
>
>    xfree (ui);
>  }
> @@ -693,7 +693,6 @@ execute_command (char *p, int from_tty)
>  std::string
>  execute_command_to_string (char *p, int from_tty)
>  {
> -  struct ui_file *str_file;
>    struct cleanup *cleanup;
>
>    /* GDB_STDOUT should be better already restored during these
> @@ -702,31 +701,27 @@ execute_command_to_string (char *p, int from_tty)
>
>    scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
>
> -  str_file = mem_fileopen ();
> +  string_file str_file;
>
> -  make_cleanup_ui_file_delete (str_file);
> -
> -  current_uiout->redirect (str_file);
> +  current_uiout->redirect (&str_file);
>    make_cleanup_ui_out_redirect_pop (current_uiout);
>
>    scoped_restore save_stdout
> -    = make_scoped_restore (&gdb_stdout, str_file);
> +    = make_scoped_restore (&gdb_stdout, &str_file);
>    scoped_restore save_stderr
> -    = make_scoped_restore (&gdb_stderr, str_file);
> +    = make_scoped_restore (&gdb_stderr, &str_file);
>    scoped_restore save_stdlog
> -    = make_scoped_restore (&gdb_stdlog, str_file);
> +    = make_scoped_restore (&gdb_stdlog, &str_file);
>    scoped_restore save_stdtarg
> -    = make_scoped_restore (&gdb_stdtarg, str_file);
> +    = make_scoped_restore (&gdb_stdtarg, &str_file);
>    scoped_restore save_stdtargerr
> -    = make_scoped_restore (&gdb_stdtargerr, str_file);
> +    = make_scoped_restore (&gdb_stdtargerr, &str_file);
>
>    execute_command (p, from_tty);
>
> -  std::string retval = ui_file_as_string (str_file);
> -
>    do_cleanups (cleanup);
>
> -  return retval;
> +  return std::move (str_file.string ());
>  }
>
>  \f
> @@ -1569,26 +1564,18 @@ print_inferior_quit_action (struct inferior *inf, void *arg)
>  int
>  quit_confirm (void)
>  {
> -  struct ui_file *stb;
> -  struct cleanup *old_chain;
> -
>    /* Don't even ask if we're only debugging a core file inferior.  */
>    if (!have_live_inferiors ())
>      return 1;
>
>    /* Build the query string as a single string.  */
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> -
> -  fprintf_filtered (stb, _("A debugging session is active.\n\n"));
> -  iterate_over_inferiors (print_inferior_quit_action, stb);
> -  fprintf_filtered (stb, _("\nQuit anyway? "));
> +  string_file stb;
>
> -  std::string str = ui_file_as_string (stb);
> -
> -  do_cleanups (old_chain);
> +  stb.puts (_("A debugging session is active.\n\n"));
> +  iterate_over_inferiors (print_inferior_quit_action, &stb);
> +  stb.puts (_("\nQuit anyway? "));
>
> -  return query ("%s", str.c_str ());
> +  return query ("%s", stb.c_str ());
>  }
>
>  /* Prepare to exit GDB cleanly by undoing any changes made to the
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index 18b569e..2da6fdd 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1304,12 +1304,11 @@ collection_list::stringify ()
>  void
>  collection_list::append_exp (struct expression *exp)
>  {
> -  struct ui_file *tmp_stream = mem_fileopen ();
> +  string_file tmp_stream;
>
> -  print_expression (exp, tmp_stream);
> +  print_expression (exp, &tmp_stream);
>
> -  m_computed.push_back (ui_file_as_string (tmp_stream));
> -  ui_file_delete (tmp_stream);
> +  m_computed.push_back (std::move (tmp_stream.string ()));
>  }
>
>  void
> diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
> index 2d1cadd..123a906 100644
> --- a/gdb/tui/tui-disasm.c
> +++ b/gdb/tui/tui-disasm.c
> @@ -54,10 +54,7 @@ static CORE_ADDR
>  tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines,
>  		 CORE_ADDR pc, int count)
>  {
> -  struct ui_file *gdb_dis_out;
> -
> -  /* Now init the ui_file structure.  */
> -  gdb_dis_out = tui_sfileopen (256);
> +  string_file gdb_dis_out;
>
>    /* Now construct each line.  */
>    for (; count > 0; count--, asm_lines++)
> @@ -67,20 +64,19 @@ tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines,
>        if (asm_lines->insn)
>          xfree (asm_lines->insn);
>
> -      print_address (gdbarch, pc, gdb_dis_out);
> +      print_address (gdbarch, pc, &gdb_dis_out);
>        asm_lines->addr = pc;
> -      asm_lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out));
> +      asm_lines->addr_string = xstrdup (gdb_dis_out.c_str ());
>
> -      ui_file_rewind (gdb_dis_out);
> +      gdb_dis_out.clear ();
>
> -      pc = pc + gdb_print_insn (gdbarch, pc, gdb_dis_out, NULL);
> +      pc = pc + gdb_print_insn (gdbarch, pc, &gdb_dis_out, NULL);
>
> -      asm_lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out));
> +      asm_lines->insn = xstrdup (gdb_dis_out.c_str ());
>
>        /* Reset the buffer to empty.  */
> -      ui_file_rewind (gdb_dis_out);
> +      gdb_dis_out.clear ();
>      }
> -  ui_file_delete (gdb_dis_out);
>    return pc;
>  }
>
> diff --git a/gdb/tui/tui-file.c b/gdb/tui/tui-file.c
> index 4dc6370..2f895b7 100644
> --- a/gdb/tui/tui-file.c
> +++ b/gdb/tui/tui-file.c
> @@ -17,145 +17,14 @@
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>
>  #include "defs.h"
> -#include "ui-file.h"
>  #include "tui/tui-file.h"
>  #include "tui/tui-io.h"
>  #include "tui/tui-command.h"
>  #include "tui.h"
>
> -/* A ``struct ui_file'' that is compatible with all the legacy
> -   code.  */
> -
> -/* new */
> -enum streamtype
> -{
> -  afile,
> -  astring
> -};
> -
> -/* new */
> -struct tui_stream
> -{
> -  int *ts_magic;
> -  enum streamtype ts_streamtype;
> -  FILE *ts_filestream;
> -  char *ts_strbuf;
> -  int ts_buflen;
> -};
> -
> -static ui_file_flush_ftype tui_file_flush;
> -extern ui_file_fputs_ftype tui_file_fputs;
> -static ui_file_isatty_ftype tui_file_isatty;
> -static ui_file_rewind_ftype tui_file_rewind;
> -static ui_file_put_ftype tui_file_put;
> -static ui_file_delete_ftype tui_file_delete;
> -static struct ui_file *tui_file_new (void);
> -static int tui_file_magic;
> -
> -static struct ui_file *
> -tui_file_new (void)
> -{
> -  struct tui_stream *tui = XNEW (struct tui_stream);
> -  struct ui_file *file = ui_file_new ();
> -
> -  set_ui_file_data (file, tui, tui_file_delete);
> -  set_ui_file_flush (file, tui_file_flush);
> -  set_ui_file_fputs (file, tui_file_fputs);
> -  set_ui_file_isatty (file, tui_file_isatty);
> -  set_ui_file_rewind (file, tui_file_rewind);
> -  set_ui_file_put (file, tui_file_put);
> -  tui->ts_magic = &tui_file_magic;
> -  return file;
> -}
> -
> -static void
> -tui_file_delete (struct ui_file *file)
> -{
> -  struct tui_stream *tmpstream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (tmpstream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_delete: bad magic number"));
> -  if ((tmpstream->ts_streamtype == astring)
> -      && (tmpstream->ts_strbuf != NULL))
> -    {
> -      xfree (tmpstream->ts_strbuf);
> -    }
> -  xfree (tmpstream);
> -}
> -
> -struct ui_file *
> -tui_fileopen (FILE *stream)
> -{
> -  struct ui_file *file = tui_file_new ();
> -  struct tui_stream *tmpstream = (struct tui_stream *) ui_file_data (file);
> -
> -  tmpstream->ts_streamtype = afile;
> -  tmpstream->ts_filestream = stream;
> -  tmpstream->ts_strbuf = NULL;
> -  tmpstream->ts_buflen = 0;
> -  return file;
> -}
> -
> -struct ui_file *
> -tui_sfileopen (int n)
> -{
> -  struct ui_file *file = tui_file_new ();
> -  struct tui_stream *tmpstream = (struct tui_stream *) ui_file_data (file);
> -
> -  tmpstream->ts_streamtype = astring;
> -  tmpstream->ts_filestream = NULL;
> -  if (n > 0)
> -    {
> -      tmpstream->ts_strbuf = XNEWVEC (char, n + 1);
> -      tmpstream->ts_strbuf[0] = '\0';
> -    }
> -  else
> -    /* Do not allocate the buffer now.  The first time something is
> -       printed one will be allocated by tui_file_adjust_strbuf().  */
> -    tmpstream->ts_strbuf = NULL;
> -  tmpstream->ts_buflen = n;
> -  return file;
> -}
> -
> -static int
> -tui_file_isatty (struct ui_file *file)
> -{
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_isatty: bad magic number"));
> -  if (stream->ts_streamtype == afile)
> -    return (isatty (fileno (stream->ts_filestream)));
> -  else
> -    return 0;
> -}
> -
> -static void
> -tui_file_rewind (struct ui_file *file)
> -{
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_rewind: bad magic number"));
> -  stream->ts_strbuf[0] = '\0';
> -}
> -
> -static void
> -tui_file_put (struct ui_file *file,
> -	      ui_file_put_method_ftype *write,
> -	      void *dest)
> -{
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_put: bad magic number"));
> -  if (stream->ts_streamtype == astring)
> -    write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
> -}
> +tui_file::tui_file (FILE *stream)
> +  : stdio_file (stream)
> +{}
>
>  /* All TUI I/O sent to the *_filtered and *_unfiltered functions
>     eventually ends up here.  The fputs_unfiltered_hook is primarily
> @@ -164,91 +33,22 @@ tui_file_put (struct ui_file *file,
>     gdb_stderr are sent to the hook.  Everything else is sent on to
>     fputs to allow file I/O to be handled appropriately.  */
>
> -/* FIXME: Should be broken up and moved to a TUI specific file.  */
> -
>  void
> -tui_file_fputs (const char *linebuffer, struct ui_file *file)
> -{
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_streamtype == astring)
> -    {
> -      tui_file_adjust_strbuf (strlen (linebuffer), file);
> -      strcat (stream->ts_strbuf, linebuffer);
> -    }
> -  else
> -    {
> -      tui_puts (linebuffer);
> -      /* gdb_stdout is buffered, and the caller must gdb_flush it at
> -	 appropriate times.  Other streams are not so buffered.  */
> -      if (file != gdb_stdout)
> -	tui_refresh_cmd_win ();
> -    }
> -}
> -
> -char *
> -tui_file_get_strbuf (struct ui_file *file)
> +tui_file::puts (const char *linebuffer)
>  {
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_get_strbuf: bad magic number"));
> -  return (stream->ts_strbuf);
> +  tui_puts (linebuffer);
> +  /* gdb_stdout is buffered, and the caller must gdb_flush it at
> +     appropriate times.  Other streams are not so buffered.  */
> +  if (this != gdb_stdout)
> +    tui_refresh_cmd_win ();
>  }
>
> -/* Adjust the length of the buffer by the amount necessary to
> -   accomodate appending a string of length N to the buffer
> -   contents.  */
>  void
> -tui_file_adjust_strbuf (int n, struct ui_file *file)
> -{
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -  int non_null_chars;
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_adjust_strbuf: bad magic number"));
> -
> -  if (stream->ts_streamtype != astring)
> -    return;
> -
> -  if (stream->ts_strbuf)
> -    {
> -      /* There is already a buffer allocated.  */
> -      non_null_chars = strlen (stream->ts_strbuf);
> -
> -      if (n > (stream->ts_buflen - non_null_chars - 1))
> -	{
> -	  stream->ts_buflen = n + non_null_chars + 1;
> -	  stream->ts_strbuf
> -	    = XRESIZEVEC (char, stream->ts_strbuf, stream->ts_buflen);
> -	}
> -    }
> -  else
> -    /* No buffer yet, so allocate one of the desired size.  */
> -    stream->ts_strbuf = XNEWVEC (char, n + 1);
> -}
> -
> -static void
> -tui_file_flush (struct ui_file *file)
> +tui_file::flush ()
>  {
> -  struct tui_stream *stream = (struct tui_stream *) ui_file_data (file);
> -
> -  if (stream->ts_magic != &tui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tui_file_flush: bad magic number"));
> -
> -  switch (stream->ts_streamtype)
> -    {
> -    case astring:
> -      break;
> -    case afile:
> -      /* gdb_stdout is buffered.  Other files are always flushed on
> -	 every write.  */
> -      if (file == gdb_stdout)
> -	tui_refresh_cmd_win ();
> -      fflush (stream->ts_filestream);
> -      break;
> -    }
> +  /* gdb_stdout is buffered.  Other files are always flushed on
> +     every write.  */
> +  if (this == gdb_stdout)
> +    tui_refresh_cmd_win ();
> +  stdio_file::flush ();
>  }
> diff --git a/gdb/tui/tui-file.h b/gdb/tui/tui-file.h
> index 0e90cdf..aceaab6 100644
> --- a/gdb/tui/tui-file.h
> +++ b/gdb/tui/tui-file.h
> @@ -1,4 +1,4 @@
> -/* UI_FILE - a generic STDIO like output stream.
> +/* TUI_FILE - a STDIO-like output stream for the TUI.
>     Copyright (C) 1999-2017 Free Software Foundation, Inc.
>
>     This file is part of GDB.
> @@ -19,9 +19,17 @@
>  #ifndef TUI_FILE_H
>  #define TUI_FILE_H
>
> -extern struct ui_file *tui_fileopen (FILE *);
> -extern struct ui_file *tui_sfileopen (int);
> -extern char *tui_file_get_strbuf (struct ui_file *);
> -extern void tui_file_adjust_strbuf (int, struct ui_file *);
> +#include "ui-file.h"
> +
> +/* A STDIO-like output stream for the TUI.  */
> +
> +class tui_file : public stdio_file
> +{
> +public:
> +  explicit tui_file (FILE *stream);
> +
> +  void flush () override;
> +  void puts (const char *) override;
> +};
>
>  #endif
> diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
> index 6f00f84..433762b 100644
> --- a/gdb/tui/tui-io.c
> +++ b/gdb/tui/tui-io.c
> @@ -528,8 +528,8 @@ tui_initialize_io (void)
>  #endif
>
>    /* Create tui output streams.  */
> -  tui_stdout = tui_fileopen (stdout);
> -  tui_stderr = tui_fileopen (stderr);
> +  tui_stdout = new tui_file (stdout);
> +  tui_stderr = new tui_file (stderr);
>    tui_out = tui_out_new (tui_stdout);
>
>    /* Create the default UI.  */
> diff --git a/gdb/tui/tui-regs.c b/gdb/tui/tui-regs.c
> index fc7913b..7d116ee8 100644
> --- a/gdb/tui/tui-regs.c
> +++ b/gdb/tui/tui-regs.c
> @@ -711,7 +711,7 @@ TUI command to control the register window."), tuicmd);
>  static void
>  tui_restore_gdbout (void *ui)
>  {
> -  ui_file_delete (gdb_stdout);
> +  delete gdb_stdout;
>    gdb_stdout = (struct ui_file*) ui;
>    pagination_enabled = 1;
>  }
> @@ -723,29 +723,26 @@ static char *
>  tui_register_format (struct frame_info *frame, int regnum)
>  {
>    struct gdbarch *gdbarch = get_frame_arch (frame);
> -  struct ui_file *stream;
>    struct ui_file *old_stdout;
>    struct cleanup *cleanups;
>    char *p, *s;
>    char *ret;
>
> +  string_file stream;
> +
>    pagination_enabled = 0;
>    old_stdout = gdb_stdout;
> -  stream = tui_sfileopen (256);
> -  gdb_stdout = stream;
> +  gdb_stdout = &stream;
>    cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
> -  gdbarch_print_registers_info (gdbarch, stream, frame, regnum, 1);
> -
> -  /* Save formatted output in the buffer.  */
> -  p = tui_file_get_strbuf (stream);
> +  gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
>
>    /* Remove the possible \n.  */
> -  s = strrchr (p, '\n');
> -  if (s && s[1] == 0)
> -    *s = 0;
> +  std::string &str = stream.string ();
> +  if (!str.empty () && str.back () == '\n')
> +    str.resize (str.size () - 1);
>
>    /* Expand tabs into spaces, since ncurses on MS-Windows doesn't.  */
> -  ret = tui_expand_tabs (p, 0);
> +  ret = tui_expand_tabs (str.c_str (), 0);
>
>    do_cleanups (cleanups);
>
> diff --git a/gdb/tui/tui-stack.c b/gdb/tui/tui-stack.c
> index 945a716..21a8bac 100644
> --- a/gdb/tui/tui-stack.c
> +++ b/gdb/tui/tui-stack.c
> @@ -68,12 +68,9 @@ tui_make_status_line (struct tui_locator_element *loc)
>    int status_size;
>    int i, proc_width;
>    const char *pid_name;
> -  const char *pc_buf;
>    int target_width;
>    int pid_width;
>    int line_width;
> -  int pc_width;
> -  struct ui_file *pc_out;
>
>    if (ptid_equal (inferior_ptid, null_ptid))
>      pid_name = "No process";
> @@ -102,12 +99,14 @@ tui_make_status_line (struct tui_locator_element *loc)
>      line_width = MIN_LINE_WIDTH;
>
>    /* Translate PC address.  */
> -  pc_out = tui_sfileopen (128);
> +  string_file pc_out;
> +
>    fputs_filtered (loc->gdbarch? paddress (loc->gdbarch, loc->addr) : "??",
> -		  pc_out);
> -  pc_buf = tui_file_get_strbuf (pc_out);
> -  pc_width = strlen (pc_buf);
> -
> +		  &pc_out);
> +
> +  const char *pc_buf = pc_out.c_str ();
> +  int pc_width = pc_out.size ();
> +
>    /* First determine the amount of proc name width we have available.
>       The +1 are for a space separator between fields.
>       The -1 are to take into account the \0 counted by sizeof.  */
> @@ -204,7 +203,6 @@ tui_make_status_line (struct tui_locator_element *loc)
>      string[i] = ' ';
>    string[status_size] = (char) 0;
>
> -  ui_file_delete (pc_out);
>    return string;
>  }
>
> @@ -215,21 +213,21 @@ static char*
>  tui_get_function_from_frame (struct frame_info *fi)
>  {
>    static char name[256];
> -  struct ui_file *stream = tui_sfileopen (256);
> -  char *p;
> +  string_file stream;
>
>    print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
> -			  stream, demangle, "");
> -  p = tui_file_get_strbuf (stream);
> +			  &stream, demangle, "");
>
>    /* Use simple heuristics to isolate the function name.  The symbol
>       can be demangled and we can have function parameters.  Remove
>       them because the status line is too short to display them.  */
> -  if (*p == '<')
> -    p++;
> -  strncpy (name, p, sizeof (name) - 1);
> +  const char *d = stream.c_str ();
> +  if (*d == '<')
> +    d++;
> +  strncpy (name, d, sizeof (name) - 1);
>    name[sizeof (name) - 1] = 0;
> -  p = strchr (name, '(');
> +
> +  char *p = strchr (name, '(');
>    if (!p)
>      p = strchr (name, '>');
>    if (p)
> @@ -237,7 +235,6 @@ tui_get_function_from_frame (struct frame_info *fi)
>    p = strchr (name, '+');
>    if (p)
>      *p = 0;
> -  ui_file_delete (stream);
>    return name;
>  }
>
> diff --git a/gdb/typeprint.c b/gdb/typeprint.c
> index 56e993e..a22c6fb 100644
> --- a/gdb/typeprint.c
> +++ b/gdb/typeprint.c
> @@ -371,26 +371,19 @@ type_print (struct type *type, const char *varstring, struct ui_file *stream,
>  std::string
>  type_to_string (struct type *type)
>  {
> -  std::string s;
> -  struct ui_file *stb;
> -  struct cleanup *old_chain;
> -
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> -
>    TRY
>      {
> -      type_print (type, "", stb, -1);
> -      s = ui_file_as_string (stb);
> +      string_file stb;
> +
> +      type_print (type, "", &stb, -1);
> +      return std::move (stb.string ());
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
>      }
>    END_CATCH
>
> -  do_cleanups (old_chain);
> -
> -  return s;
> +  return {};
>  }
>
>  /* Print type of EXP, or last thing in value history if EXP == NULL.
> diff --git a/gdb/ui-file.c b/gdb/ui-file.c
> index 3dce511..60e3274 100644
> --- a/gdb/ui-file.c
> +++ b/gdb/ui-file.c
> @@ -25,193 +25,80 @@
>  #include "gdb_select.h"
>  #include "filestuff.h"
>
> -static ui_file_isatty_ftype null_file_isatty;
> -static ui_file_write_ftype null_file_write;
> -static ui_file_write_ftype null_file_write_async_safe;
> -static ui_file_fputs_ftype null_file_fputs;
> -static ui_file_read_ftype null_file_read;
> -static ui_file_flush_ftype null_file_flush;
> -static ui_file_delete_ftype null_file_delete;
> -static ui_file_rewind_ftype null_file_rewind;
> -static ui_file_put_ftype null_file_put;
> -static ui_file_fseek_ftype null_file_fseek;
> -
> -struct ui_file
> -  {
> -    int *magic;
> -    ui_file_flush_ftype *to_flush;
> -    ui_file_write_ftype *to_write;
> -    ui_file_write_async_safe_ftype *to_write_async_safe;
> -    ui_file_fputs_ftype *to_fputs;
> -    ui_file_read_ftype *to_read;
> -    ui_file_delete_ftype *to_delete;
> -    ui_file_isatty_ftype *to_isatty;
> -    ui_file_rewind_ftype *to_rewind;
> -    ui_file_put_ftype *to_put;
> -    ui_file_fseek_ftype *to_fseek;
> -    void *to_data;
> -  };
> -int ui_file_magic;
> -
> -struct ui_file *
> -ui_file_new (void)
> -{
> -  struct ui_file *file = XNEW (struct ui_file);
> -
> -  file->magic = &ui_file_magic;
> -  set_ui_file_data (file, NULL, null_file_delete);
> -  set_ui_file_flush (file, null_file_flush);
> -  set_ui_file_write (file, null_file_write);
> -  set_ui_file_write_async_safe (file, null_file_write_async_safe);
> -  set_ui_file_fputs (file, null_file_fputs);
> -  set_ui_file_read (file, null_file_read);
> -  set_ui_file_isatty (file, null_file_isatty);
> -  set_ui_file_rewind (file, null_file_rewind);
> -  set_ui_file_put (file, null_file_put);
> -  set_ui_file_fseek (file, null_file_fseek);
> -  return file;
> -}
> +null_file null_stream;
>
> -void
> -ui_file_delete (struct ui_file *file)
> -{
> -  file->to_delete (file);
> -  xfree (file);
> -}
> +ui_file::ui_file ()
> +{}
>
> -static int
> -null_file_isatty (struct ui_file *file)
> -{
> -  return 0;
> -}
> +ui_file::~ui_file ()
> +{}
>
> -static void
> -null_file_rewind (struct ui_file *file)
> +void
> +ui_file::printf (const char *format, ...)
>  {
> -  return;
> -}
> +  va_list args;
>
> -static void
> -null_file_put (struct ui_file *file,
> -	       ui_file_put_method_ftype *write,
> -	       void *dest)
> -{
> -  return;
> +  va_start (args, format);
> +  vfprintf_unfiltered (this, format, args);
> +  va_end (args);
>  }
>
> -static void
> -null_file_flush (struct ui_file *file)
> +void
> +ui_file::putstr (const char *str, int quoter)
>  {
> -  return;
> +  fputstr_unfiltered (str, quoter, this);
>  }
>
> -static void
> -null_file_write (struct ui_file *file,
> -		 const char *buf,
> -		 long sizeof_buf)
> +void
> +ui_file::putstrn (const char *str, int n, int quoter)
>  {
> -  if (file->to_fputs == null_file_fputs)
> -    /* Both the write and fputs methods are null.  Discard the
> -       request.  */
> -    return;
> -  else
> -    {
> -      /* The fputs method isn't null, slowly pass the write request
> -         onto that.  FYI, this isn't as bad as it may look - the
> -         current (as of 1999-11-07) printf_* function calls fputc and
> -         fputc does exactly the below.  By having a write function it
> -         is possible to clean up that code.  */
> -      int i;
> -      char b[2];
> -
> -      b[1] = '\0';
> -      for (i = 0; i < sizeof_buf; i++)
> -	{
> -	  b[0] = buf[i];
> -	  file->to_fputs (b, file);
> -	}
> -      return;
> -    }
> +  fputstrn_unfiltered (str, n, quoter, this);
>  }
>
> -static long
> -null_file_read (struct ui_file *file,
> -		char *buf,
> -		long sizeof_buf)
> +int
> +ui_file::putc (int c)
>  {
> -  errno = EBADF;
> -  return 0;
> +  return fputc_unfiltered (c, this);
>  }
>
> -static void
> -null_file_fputs (const char *buf, struct ui_file *file)
> +void
> +ui_file::vprintf (const char *format, va_list args)
>  {
> -  if (file->to_write == null_file_write)
> -    /* Both the write and fputs methods are null.  Discard the
> -       request.  */
> -    return;
> -  else
> -    {
> -      /* The write method was implemented, use that.  */
> -      file->to_write (file, buf, strlen (buf));
> -    }
> +  vfprintf_unfiltered (this, format, args);
>  }
>
> -static void
> -null_file_write_async_safe (struct ui_file *file,
> -			    const char *buf,
> -			    long sizeof_buf)
> -{
> -  return;
> -}
> +\f
>
> -static void
> -null_file_delete (struct ui_file *file)
> +void
> +null_file::write (const char *buf, long sizeof_buf)
>  {
> -  return;
> +  /* Discard the request.  */
>  }
>
> -static int
> -null_file_fseek (struct ui_file *stream, long offset, int whence)
> +void
> +null_file::puts (const char *)
>  {
> -  errno = EBADF;
> -
> -  return -1;
> +  /* Discard the request.  */
>  }
>
> -void *
> -ui_file_data (struct ui_file *file)
> +void
> +null_file::write_async_safe (const char *buf, long sizeof_buf)
>  {
> -  if (file->magic != &ui_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("ui_file_data: bad magic number"));
> -  return file->to_data;
> +  /* Discard the request.  */
>  }
>
> +\f
> +
>  void
>  gdb_flush (struct ui_file *file)
>  {
> -  file->to_flush (file);
> +  file->flush ();
>  }
>
>  int
>  ui_file_isatty (struct ui_file *file)
>  {
> -  return file->to_isatty (file);
> -}
> -
> -void
> -ui_file_rewind (struct ui_file *file)
> -{
> -  file->to_rewind (file);
> -}
> -
> -void
> -ui_file_put (struct ui_file *file,
> -	      ui_file_put_method_ftype *write,
> -	      void *dest)
> -{
> -  file->to_put (file, write, dest);
> +  return file->isatty ();
>  }
>
>  void
> @@ -219,13 +106,7 @@ ui_file_write (struct ui_file *file,
>  		const char *buf,
>  		long length_buf)
>  {
> -  file->to_write (file, buf, length_buf);
> -}
> -
> -void
> -ui_file_write_for_put (void *data, const char *buffer, long length_buffer)
> -{
> -  ui_file_write ((struct ui_file *) data, buffer, length_buffer);
> +  file->write (buf, length_buf);
>  }
>
>  void
> @@ -233,622 +114,215 @@ ui_file_write_async_safe (struct ui_file *file,
>  			  const char *buf,
>  			  long length_buf)
>  {
> -  file->to_write_async_safe (file, buf, length_buf);
> +  file->write_async_safe (buf, length_buf);
>  }
>
>  long
>  ui_file_read (struct ui_file *file, char *buf, long length_buf)
>  {
> -  return file->to_read (file, buf, length_buf);
> -}
> -
> -int
> -ui_file_fseek (struct ui_file *file, long offset, int whence)
> -{
> -  return file->to_fseek (file, offset, whence);
> +  return file->read (buf, length_buf);
>  }
>
>  void
>  fputs_unfiltered (const char *buf, struct ui_file *file)
>  {
> -  file->to_fputs (buf, file);
> +  file->puts (buf);
>  }
>
> -void
> -set_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush_ptr)
> -{
> -  file->to_flush = flush_ptr;
> -}
> -
> -void
> -set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty_ptr)
> -{
> -  file->to_isatty = isatty_ptr;
> -}
> -
> -void
> -set_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind_ptr)
> -{
> -  file->to_rewind = rewind_ptr;
> -}
> +\f
>
> -void
> -set_ui_file_put (struct ui_file *file, ui_file_put_ftype *put_ptr)
> -{
> -  file->to_put = put_ptr;
> -}
> +string_file::~string_file ()
> +{}
>
>  void
> -set_ui_file_write (struct ui_file *file,
> -		    ui_file_write_ftype *write_ptr)
> +string_file::write (const char *buf, long length_buf)
>  {
> -  file->to_write = write_ptr;
> +  m_string.append (buf, length_buf);
>  }
>
> -void
> -set_ui_file_write_async_safe (struct ui_file *file,
> -			      ui_file_write_async_safe_ftype *write_async_safe_ptr)
> -{
> -  file->to_write_async_safe = write_async_safe_ptr;
> -}
> +\f
>
> -void
> -set_ui_file_read (struct ui_file *file, ui_file_read_ftype *read_ptr)
> +stdio_file::stdio_file (FILE *file, bool close_p)
>  {
> -  file->to_read = read_ptr;
> +  set_stream (file);
> +  m_close_p = close_p;
>  }
>
> -void
> -set_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs_ptr)
> -{
> -  file->to_fputs = fputs_ptr;
> -}
> +stdio_file::stdio_file ()
> +  : m_file (NULL),
> +    m_fd (-1),
> +    m_close_p (false)
> +{}
>
> -void
> -set_ui_file_fseek (struct ui_file *file, ui_file_fseek_ftype *fseek_ptr)
> +stdio_file::~stdio_file ()
>  {
> -  file->to_fseek = fseek_ptr;
> +  if (m_close_p)
> +    fclose (m_file);
>  }
>
>  void
> -set_ui_file_data (struct ui_file *file, void *data,
> -		  ui_file_delete_ftype *delete_ptr)
> +stdio_file::set_stream (FILE *file)
>  {
> -  file->to_data = data;
> -  file->to_delete = delete_ptr;
> +  m_file = file;
> +  m_fd = fileno (file);
>  }
>
> -/* ui_file utility function for converting a ``struct ui_file'' into
> -   a memory buffer.  */
> -
> -struct accumulated_ui_file
> +bool
> +stdio_file::open (const char *name, const char *mode)
>  {
> -  char *buffer;
> -  long length;
> -};
> -
> -static void
> -do_ui_file_xstrdup (void *context, const char *buffer, long length)
> -{
> -  struct accumulated_ui_file *acc = (struct accumulated_ui_file *) context;
> -
> -  if (acc->buffer == NULL)
> -    acc->buffer = (char *) xmalloc (length + 1);
> -  else
> -    acc->buffer = (char *) xrealloc (acc->buffer, acc->length + length + 1);
> -  memcpy (acc->buffer + acc->length, buffer, length);
> -  acc->length += length;
> -  acc->buffer[acc->length] = '\0';
> -}
> -
> -char *
> -ui_file_xstrdup (struct ui_file *file, long *length)
> -{
> -  struct accumulated_ui_file acc;
> -
> -  acc.buffer = NULL;
> -  acc.length = 0;
> -  ui_file_put (file, do_ui_file_xstrdup, &acc);
> -  if (acc.buffer == NULL)
> -    acc.buffer = xstrdup ("");
> -  if (length != NULL)
> -    *length = acc.length;
> -  return acc.buffer;
> -}
> -
> -/* ui_file utility function for converting a ``struct ui_file'' into a
> -   std:string.  */
> -
> -static void
> -do_ui_file_as_string (void *context, const char *buffer, long length)
> -{
> -  std::string *str = (std::string *) context;
> -
> -  *str = std::string (buffer, length);
> -}
> -
> -/* See ui-file.h.  */
> -
> -std::string
> -ui_file_as_string (struct ui_file *file)
> -{
> -  std::string str;
> -
> -  ui_file_put (file, do_ui_file_as_string, &str);
> -  return str;
> -}
> -
> -static void
> -do_ui_file_obsavestring (void *context, const char *buffer, long length)
> -{
> -  struct obstack *obstack = (struct obstack *) context;
> -
> -  obstack_grow (obstack, buffer, length);
> -}
> -
> -char *
> -ui_file_obsavestring (struct ui_file *file, struct obstack *obstack,
> -		      long *length)
> -{
> -  ui_file_put (file, do_ui_file_obsavestring, obstack);
> -  *length = obstack_object_size (obstack);
> -  obstack_1grow (obstack, '\0');
> -  return (char *) obstack_finish (obstack);
> -}
> -\f
> -/* A pure memory based ``struct ui_file'' that can be used an output
> -   buffer.  The buffers accumulated contents are available via
> -   ui_file_put().  */
> -
> -struct mem_file
> -  {
> -    int *magic;
> -    char *buffer;
> -    int sizeof_buffer;
> -    int length_buffer;
> -  };
> -
> -static ui_file_rewind_ftype mem_file_rewind;
> -static ui_file_put_ftype mem_file_put;
> -static ui_file_write_ftype mem_file_write;
> -static ui_file_delete_ftype mem_file_delete;
> -static struct ui_file *mem_file_new (void);
> -static int mem_file_magic;
> -
> -static struct ui_file *
> -mem_file_new (void)
> -{
> -  struct mem_file *stream = XNEW (struct mem_file);
> -  struct ui_file *file = ui_file_new ();
> -
> -  set_ui_file_data (file, stream, mem_file_delete);
> -  set_ui_file_rewind (file, mem_file_rewind);
> -  set_ui_file_put (file, mem_file_put);
> -  set_ui_file_write (file, mem_file_write);
> -  stream->magic = &mem_file_magic;
> -  stream->buffer = NULL;
> -  stream->sizeof_buffer = 0;
> -  stream->length_buffer = 0;
> -  return file;
> -}
> -
> -static void
> -mem_file_delete (struct ui_file *file)
> -{
> -  struct mem_file *stream = (struct mem_file *) ui_file_data (file);
> +  /* Close the previous stream, if we own it.  */
> +  if (m_close_p)
> +    {
> +      fclose (m_file);
> +      m_close_p = false;
> +    }
>
> -  if (stream->magic != &mem_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mem_file_delete: bad magic number"));
> -  if (stream->buffer != NULL)
> -    xfree (stream->buffer);
> -  xfree (stream);
> -}
> +  FILE *f = gdb_fopen_cloexec (name, mode);
>
> -struct ui_file *
> -mem_fileopen (void)
> -{
> -  return mem_file_new ();
> -}
> +  if (f == NULL)
> +    return false;
>
> -static void
> -mem_file_rewind (struct ui_file *file)
> -{
> -  struct mem_file *stream = (struct mem_file *) ui_file_data (file);
> +  set_stream (f);
> +  m_close_p = true;
>
> -  if (stream->magic != &mem_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mem_file_rewind: bad magic number"));
> -  stream->length_buffer = 0;
> -}
> -
> -static void
> -mem_file_put (struct ui_file *file,
> -	      ui_file_put_method_ftype *write,
> -	      void *dest)
> -{
> -  struct mem_file *stream = (struct mem_file *) ui_file_data (file);
> -
> -  if (stream->magic != &mem_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mem_file_put: bad magic number"));
> -  if (stream->length_buffer > 0)
> -    write (dest, stream->buffer, stream->length_buffer);
> +  return true;
>  }
>
>  void
> -mem_file_write (struct ui_file *file,
> -		const char *buffer,
> -		long length_buffer)
> -{
> -  struct mem_file *stream = (struct mem_file *) ui_file_data (file);
> -
> -  if (stream->magic != &mem_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("mem_file_write: bad magic number"));
> -  if (stream->buffer == NULL)
> -    {
> -      stream->length_buffer = length_buffer;
> -      stream->sizeof_buffer = length_buffer;
> -      stream->buffer = (char *) xmalloc (stream->sizeof_buffer);
> -      memcpy (stream->buffer, buffer, length_buffer);
> -    }
> -  else
> -    {
> -      int new_length = stream->length_buffer + length_buffer;
> -
> -      if (new_length >= stream->sizeof_buffer)
> -	{
> -	  stream->sizeof_buffer = new_length;
> -	  stream->buffer
> -	    = (char *) xrealloc (stream->buffer, stream->sizeof_buffer);
> -	}
> -      memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
> -      stream->length_buffer = new_length;
> -    }
> -}
> -\f
> -/* ``struct ui_file'' implementation that maps directly onto
> -   <stdio.h>'s FILE.  */
> -
> -static ui_file_write_ftype stdio_file_write;
> -static ui_file_write_async_safe_ftype stdio_file_write_async_safe;
> -static ui_file_fputs_ftype stdio_file_fputs;
> -static ui_file_read_ftype stdio_file_read;
> -static ui_file_isatty_ftype stdio_file_isatty;
> -static ui_file_delete_ftype stdio_file_delete;
> -static struct ui_file *stdio_file_new (FILE *file, int close_p);
> -static ui_file_flush_ftype stdio_file_flush;
> -static ui_file_fseek_ftype stdio_file_fseek;
> -
> -static int stdio_file_magic;
> -
> -struct stdio_file
> -  {
> -    int *magic;
> -    FILE *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 fd;
> -    int close_p;
> -  };
> -
> -static struct ui_file *
> -stdio_file_new (FILE *file, int close_p)
> -{
> -  struct ui_file *ui_file = ui_file_new ();
> -  struct stdio_file *stdio = XNEW (struct stdio_file);
> -
> -  stdio->magic = &stdio_file_magic;
> -  stdio->file = file;
> -  stdio->fd = fileno (file);
> -  stdio->close_p = close_p;
> -  set_ui_file_data (ui_file, stdio, stdio_file_delete);
> -  set_ui_file_flush (ui_file, stdio_file_flush);
> -  set_ui_file_write (ui_file, stdio_file_write);
> -  set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe);
> -  set_ui_file_fputs (ui_file, stdio_file_fputs);
> -  set_ui_file_read (ui_file, stdio_file_read);
> -  set_ui_file_isatty (ui_file, stdio_file_isatty);
> -  set_ui_file_fseek (ui_file, stdio_file_fseek);
> -  return ui_file;
> -}
> -
> -static void
> -stdio_file_delete (struct ui_file *file)
> -{
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_delete: bad magic number"));
> -  if (stdio->close_p)
> -    {
> -      fclose (stdio->file);
> -    }
> -  xfree (stdio);
> -}
> -
> -static void
> -stdio_file_flush (struct ui_file *file)
> +stdio_file::flush ()
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_flush: bad magic number"));
> -  fflush (stdio->file);
> +  fflush (m_file);
>  }
>
> -static long
> -stdio_file_read (struct ui_file *file, char *buf, long length_buf)
> +long
> +stdio_file::read (char *buf, long length_buf)
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_read: bad magic number"));
> -
>    /* Wait until at least one byte of data is available, or we get
>       interrupted with Control-C.  */
>    {
>      fd_set readfds;
>
>      FD_ZERO (&readfds);
> -    FD_SET (stdio->fd, &readfds);
> -    if (interruptible_select (stdio->fd + 1, &readfds, NULL, NULL, NULL) == -1)
> +    FD_SET (m_fd, &readfds);
> +    if (interruptible_select (m_fd + 1, &readfds, NULL, NULL, NULL) == -1)
>        return -1;
>    }
>
> -  return read (stdio->fd, buf, length_buf);
> +  return ::read (m_fd, buf, length_buf);
>  }
>
> -static void
> -stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
> +void
> +stdio_file::write (const char *buf, long length_buf)
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_write: bad magic number"));
>    /* Calling error crashes when we are called from the exception framework.  */
> -  if (fwrite (buf, length_buf, 1, stdio->file))
> +  if (fwrite (buf, length_buf, 1, m_file))
>      {
>        /* Nothing.  */
>      }
>  }
>
> -static void
> -stdio_file_write_async_safe (struct ui_file *file,
> -			     const char *buf, long length_buf)
> +void
> +stdio_file::write_async_safe (const char *buf, long length_buf)
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    {
> -      /* gettext isn't necessarily async safe, so we can't use _("error message") here.
> -	 We could extract the correct translation ahead of time, but this is an extremely
> -	 rare event, and one of the other stdio_file_* routines will presumably catch
> -	 the problem anyway.  For now keep it simple and ignore the error here.  */
> -      return;
> -    }
> -
>    /* This is written the way it is to avoid a warning from gcc about not using the
>       result of write (since it can be declared with attribute warn_unused_result).
>       Alas casting to void doesn't work for this.  */
> -  if (write (stdio->fd, buf, length_buf))
> +  if (::write (m_fd, buf, length_buf))
>      {
>        /* Nothing.  */
>      }
>  }
>
> -static void
> -stdio_file_fputs (const char *linebuffer, struct ui_file *file)
> +void
> +stdio_file::puts (const char *linebuffer)
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_fputs: bad magic number"));
>    /* Calling error crashes when we are called from the exception framework.  */
> -  if (fputs (linebuffer, stdio->file))
> +  if (fputs (linebuffer, m_file))
>      {
>        /* Nothing.  */
>      }
>  }
>
> -static int
> -stdio_file_isatty (struct ui_file *file)
> +bool
> +stdio_file::isatty ()
>  {
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_isatty: bad magic number"));
> -  return (isatty (stdio->fd));
> +  return ::isatty (m_fd);
>  }
>
> -static int
> -stdio_file_fseek (struct ui_file *file, long offset, int whence)
> -{
> -  struct stdio_file *stdio = (struct stdio_file *) ui_file_data (file);
> -
> -  if (stdio->magic != &stdio_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("stdio_file_fseek: bad magic number"));
> -
> -  return fseek (stdio->file, offset, whence);
> -}
> +\f
>
> -#ifdef __MINGW32__
> -/* This is the implementation of ui_file method to_write for stderr.
> +/* This is the implementation of ui_file method 'write' for stderr.
>     gdb_stdout is flushed before writing to gdb_stderr.  */
>
> -static void
> -stderr_file_write (struct ui_file *file, const char *buf, long length_buf)
> +void
> +stderr_file::write (const char *buf, long length_buf)
>  {
>    gdb_flush (gdb_stdout);
> -  stdio_file_write (file, buf, length_buf);
> +  stdio_file::write (buf, length_buf);
>  }
>
> -/* This is the implementation of ui_file method to_fputs for stderr.
> +/* This is the implementation of ui_file method 'puts' for stderr.
>     gdb_stdout is flushed before writing to gdb_stderr.  */
>
> -static void
> -stderr_file_fputs (const char *linebuffer, struct ui_file *file)
> +void
> +stderr_file::puts (const char *linebuffer)
>  {
>    gdb_flush (gdb_stdout);
> -  stdio_file_fputs (linebuffer, file);
> +  stdio_file::puts (linebuffer);
>  }
> -#endif
> -
> -struct ui_file *
> -stderr_fileopen (FILE *stream)
> -{
> -  struct ui_file *ui_file = stdio_fileopen (stream);
> -
> -#ifdef __MINGW32__
> -  /* 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 front-end, such as Emacs.
> -
> -     We decided to leave stdout as fully buffered, but flush it first
> -     when something is written to stderr.  */
> -
> -  /* Method 'to_write_async_safe' is not overwritten, because there's
> -     no way to flush a stream in an async-safe manner.  Fortunately,
> -     it doesn't really matter, because:
> -     - that method is only used for printing internal debug output
> -       from signal handlers.
> -     - 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.  */
> -  set_ui_file_write (ui_file, stderr_file_write);
> -  set_ui_file_fputs (ui_file, stderr_file_fputs);
> -#endif
>
> -  return ui_file;
> -}
> -
> -/* Like fdopen().  Create a ui_file from a previously opened FILE.  */
> -
> -struct ui_file *
> -stdio_fileopen (FILE *file)
> -{
> -  return stdio_file_new (file, 0);
> -}
> +stderr_file::stderr_file (FILE *stream)
> +  : stdio_file (stream)
> +{}
>
> -struct ui_file *
> -gdb_fopen (const char *name, const char *mode)
> -{
> -  FILE *f = gdb_fopen_cloexec (name, mode);
> -
> -  if (f == NULL)
> -    return NULL;
> -  return stdio_file_new (f, 1);
> -}
> -
> -/* ``struct ui_file'' implementation that maps onto two ui-file objects.  */
> -
> -static ui_file_write_ftype tee_file_write;
> -static ui_file_fputs_ftype tee_file_fputs;
> -static ui_file_isatty_ftype tee_file_isatty;
> -static ui_file_delete_ftype tee_file_delete;
> -static ui_file_flush_ftype tee_file_flush;
> +\f
>
> -static int tee_file_magic;
> +tee_file::tee_file (ui_file *one, bool close_one,
> +		    ui_file *two, bool close_two)
> +  : m_one (one),
> +    m_two (two),
> +    m_close_one (close_one),
> +    m_close_two (close_two)
> +{}
>
> -struct tee_file
> -  {
> -    int *magic;
> -    struct ui_file *one, *two;
> -    int close_one, close_two;
> -  };
> -
> -struct ui_file *
> -tee_file_new (struct ui_file *one, int close_one,
> -	      struct ui_file *two, int close_two)
> +tee_file::~tee_file ()
>  {
> -  struct ui_file *ui_file = ui_file_new ();
> -  struct tee_file *tee = XNEW (struct tee_file);
> -
> -  tee->magic = &tee_file_magic;
> -  tee->one = one;
> -  tee->two = two;
> -  tee->close_one = close_one;
> -  tee->close_two = close_two;
> -  set_ui_file_data (ui_file, tee, tee_file_delete);
> -  set_ui_file_flush (ui_file, tee_file_flush);
> -  set_ui_file_write (ui_file, tee_file_write);
> -  set_ui_file_fputs (ui_file, tee_file_fputs);
> -  set_ui_file_isatty (ui_file, tee_file_isatty);
> -  return ui_file;
> +  if (m_close_one)
> +    delete m_one;
> +  if (m_close_two)
> +    delete m_two;
>  }
>
> -static void
> -tee_file_delete (struct ui_file *file)
> +void
> +tee_file::flush ()
>  {
> -  struct tee_file *tee = (struct tee_file *) ui_file_data (file);
> -
> -  if (tee->magic != &tee_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tee_file_delete: bad magic number"));
> -  if (tee->close_one)
> -    ui_file_delete (tee->one);
> -  if (tee->close_two)
> -    ui_file_delete (tee->two);
> -
> -  xfree (tee);
> +  m_one->flush ();
> +  m_two->flush ();
>  }
>
> -static void
> -tee_file_flush (struct ui_file *file)
> +void
> +tee_file::write (const char *buf, long length_buf)
>  {
> -  struct tee_file *tee = (struct tee_file *) ui_file_data (file);
> -
> -  if (tee->magic != &tee_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tee_file_flush: bad magic number"));
> -  tee->one->to_flush (tee->one);
> -  tee->two->to_flush (tee->two);
> +  m_one->write (buf, length_buf);
> +  m_two->write (buf, length_buf);
>  }
>
> -static void
> -tee_file_write (struct ui_file *file, const char *buf, long length_buf)
> +void
> +tee_file::write_async_safe (const char *buf, long length_buf)
>  {
> -  struct tee_file *tee = (struct tee_file *) ui_file_data (file);
> -
> -  if (tee->magic != &tee_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tee_file_write: bad magic number"));
> -  ui_file_write (tee->one, buf, length_buf);
> -  ui_file_write (tee->two, buf, length_buf);
> +  m_one->write_async_safe (buf, length_buf);
> +  m_two->write_async_safe (buf, length_buf);
>  }
>
> -static void
> -tee_file_fputs (const char *linebuffer, struct ui_file *file)
> +void
> +tee_file::puts (const char *linebuffer)
>  {
> -  struct tee_file *tee = (struct tee_file *) ui_file_data (file);
> -
> -  if (tee->magic != &tee_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tee_file_fputs: bad magic number"));
> -  tee->one->to_fputs (linebuffer, tee->one);
> -  tee->two->to_fputs (linebuffer, tee->two);
> +  m_one->puts (linebuffer);
> +  m_two->puts (linebuffer);
>  }
>
> -static int
> -tee_file_isatty (struct ui_file *file)
> +bool
> +tee_file::isatty ()
>  {
> -  struct tee_file *tee = (struct tee_file *) ui_file_data (file);
> -
> -  if (tee->magic != &tee_file_magic)
> -    internal_error (__FILE__, __LINE__,
> -		    _("tee_file_isatty: bad magic number"));
> -
> -  return ui_file_isatty (tee->one);
> +  return m_one->isatty ();
>  }
> diff --git a/gdb/ui-file.h b/gdb/ui-file.h
> index 4ad3940..1cb9693 100644
> --- a/gdb/ui-file.h
> +++ b/gdb/ui-file.h
> @@ -19,140 +19,245 @@
>  #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.  */
> +
> +class ui_file
> +{
> +public:
> +  ui_file ();
> +  virtual ~ui_file () = 0;
> +
> +  /* Public non-virtual API.  */
>
> -extern struct ui_file *ui_file_new (void);
> +  void printf (const char *, ...) ATTRIBUTE_PRINTF (2, 3);
>
> -/* Override methods used by specific implementations of a UI_FILE
> -   object.  */
> +  /* 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_flush_ftype) (struct ui_file *stream);
> -extern void set_ui_file_flush (struct ui_file *stream,
> -			       ui_file_flush_ftype *flush);
> +  void putstrn (const char *str, int n, int quoter);
>
> -/* 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);
> +  int putc (int c);
>
> -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 vprintf (const char *, va_list) ATTRIBUTE_PRINTF (2, 0);
>
> -/* 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);
> +  /* Methods below are both public, and overridable by ui_file
> +     subclasses.  */
>
> -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);
> +  virtual void write (const char *buf, long length_buf) = 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);
> +  /* 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_rewind_ftype) (struct ui_file *stream);
> -extern void set_ui_file_rewind (struct ui_file *stream,
> -				ui_file_rewind_ftype *rewind);
> +  virtual void puts (const char *str)
> +  { this->write (str, strlen (str)); }
>
> -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);
> +  virtual long read (char *buf, long length_buf)
> +  { gdb_assert_not_reached ("can't read from this file type"); }
>
> -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);
> +  virtual bool isatty ()
> +  { return false; }
>
> -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 void flush ()
> +  {}
> +};
>
> -extern void *ui_file_data (struct ui_file *file);
> +typedef std::unique_ptr<ui_file> ui_file_up;
>
> +/* A ui_file that writes to nowhere.  */
>
> -extern void gdb_flush (struct ui_file *);
> +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;
> +};
>
> -extern void ui_file_delete (struct ui_file *stream);
> +/* A preallocated null_file stream.  */
> +extern null_file null_stream;
>
> -extern void ui_file_rewind (struct ui_file *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);
> +extern long ui_file_read (struct ui_file *file, char *buf, long length_buf);
>
> -/* 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);
> +/* A std::string-based ui_file.  Can be used as a scratch buffer for
> +   collecting output.  */
>
> -/* 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);
> +class string_file : public ui_file
> +{
> +public:
> +  string_file () {}
> +  ~string_file () override;
>
> -/* 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);
> +  /* Override ui_file methods.  */
>
> -extern long ui_file_read (struct ui_file *file, char *buf, long length_buf);
> +  void write (const char *buf, long length_buf) override;
> +
> +  long read (char *buf, long length_buf) override
> +  { gdb_assert_not_reached ("a string_file is not readable"); }
> +
> +  /* string_file-specific public API.  */
> +
> +  /* Accesses the std::string containing the entire output collected
> +     so far.
> +
> +     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 the the 'write_async_safe' method is not overwritten, because


Extra "the".

Did you mean overridden instead of overwritten?


> +   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.
>
> -extern int ui_file_fseek (struct ui_file *file, long offset, int whence);
> +    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);
>
> -/* Create/open a memory based file.  Can be used as a scratch buffer
> -   for collecting output.  */
> -extern struct ui_file *mem_fileopen (void);
> +  /* Flushes gdb_stdout before writing to the underlying stream.  */
> +  void write (const char *buf, long length_buf) override;
>

I noticed the above declaration and ...

> +  /* Flushes gdb_stdout before writing to the underlying stream.  */
> +  void puts (const char *linebuffer) override;

... the above declaration both have the same documentation. Do they 
accomplish the same?

> +};
>
> +/* A ui_file implementation that maps onto two ui-file objects.  */
>
> -/* Open/create a STDIO based UI_FILE using the already open FILE.  */
> -extern struct ui_file *stdio_fileopen (FILE *file);
> +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;
>
> -/* Likewise, for stderr-like streams.  */
> -extern struct ui_file *stderr_fileopen (FILE *file);
> +  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;
>
> -/* Open NAME returning an STDIO based UI_FILE.  */
> -extern struct ui_file *gdb_fopen (const char *name, const char *mode);
> +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
> diff --git a/gdb/ui-out.c b/gdb/ui-out.c
> index fdcd454..42cffbe 100644
> --- a/gdb/ui-out.c
> +++ b/gdb/ui-out.c
> @@ -529,15 +529,13 @@ ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch,
>  }
>
>  void
> -ui_out::field_stream (const char *fldname, ui_file *stream)
> +ui_out::field_stream (const char *fldname, string_file &stream)
>  {
> -  std::string buffer = ui_file_as_string (stream);
> -
> -  if (!buffer.empty ())
> -    field_string (fldname, buffer.c_str ());
> +  if (!stream.empty ())
> +    field_string (fldname, stream.c_str ());
>    else
>      field_skip (fldname);
> -  ui_file_rewind (stream);
> +  stream.clear ();
>  }
>
>  /* Used to omit a field.  */
> diff --git a/gdb/ui-out.h b/gdb/ui-out.h
> index b8bea97..d54843d 100644
> --- a/gdb/ui-out.h
> +++ b/gdb/ui-out.h
> @@ -108,7 +108,7 @@ class ui_out
>    void field_core_addr (const char *fldname, struct gdbarch *gdbarch,
>  			CORE_ADDR address);
>    void field_string (const char *fldname, const char *string);
> -  void field_stream (const char *fldname, ui_file *stream);
> +  void field_stream (const char *fldname, string_file &stream);
>    void field_skip (const char *fldname);
>    void field_fmt (const char *fldname, const char *format, ...)
>      ATTRIBUTE_PRINTF (3, 4);
> diff --git a/gdb/utils.c b/gdb/utils.c
> index ab87143..3dc2f03 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -187,33 +187,6 @@ make_cleanup_obstack_free (struct obstack *obstack)
>    return make_cleanup (do_obstack_free, obstack);
>  }
>
> -static void
> -do_ui_file_delete (void *arg)
> -{
> -  ui_file_delete ((struct ui_file *) arg);
> -}
> -
> -struct cleanup *
> -make_cleanup_ui_file_delete (struct ui_file *arg)
> -{
> -  return make_cleanup (do_ui_file_delete, arg);
> -}
> -
> -struct ui_file *
> -null_stream (void)
> -{
> -  /* A simple implementation of singleton pattern.  */
> -  static struct ui_file *stream = NULL;
> -
> -  if (stream == NULL)
> -    {
> -      stream = ui_file_new ();
> -      /* Delete it on gdb exit.  */
> -      make_final_cleanup (do_ui_file_delete, stream);
> -    }
> -  return stream;
> -}
> -
>  /* Helper function for make_cleanup_ui_out_redirect_pop.  */
>
>  static void
> @@ -460,11 +433,9 @@ verror (const char *string, va_list args)
>  }
>
>  void
> -error_stream (struct ui_file *stream)
> +error_stream (const string_file &stream)
>  {
> -  std::string message = ui_file_as_string (stream);
> -
> -  error (("%s"), message.c_str ());
> +  error (("%s"), stream.c_str ());
>  }
>
>  /* Emit a message and abort.  */
> diff --git a/gdb/utils.h b/gdb/utils.h
> index 9e71cc2..f138702 100644
> --- a/gdb/utils.h
> +++ b/gdb/utils.h
> @@ -66,9 +66,6 @@ char **gdb_buildargv (const char *);
>
>  extern struct cleanup *make_cleanup_freeargv (char **);
>
> -struct ui_file;
> -extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *);
> -
>  struct ui_out;
>  extern struct cleanup *
>    make_cleanup_ui_out_redirect_pop (struct ui_out *uiout);
> @@ -189,9 +186,6 @@ extern struct ui_file *gdb_stdtarg;
>  extern struct ui_file *gdb_stdtargerr;
>  extern struct ui_file *gdb_stdtargin;
>
> -/* Return a null stream.  */
> -extern struct ui_file *null_stream (void);
> -
>  /* Set the screen dimensions to WIDTH and HEIGHT.  */
>
>  extern void set_screen_width_and_height (int width, int height);
> @@ -306,7 +300,7 @@ extern void (*deprecated_error_begin_hook) (void);
>
>  extern char *warning_pre_print;
>
> -extern void error_stream (struct ui_file *) ATTRIBUTE_NORETURN;
> +extern void error_stream (const string_file &) ATTRIBUTE_NORETURN;
>
>  extern void demangler_vwarning (const char *file, int line,
>  			       const char *, va_list ap)
> diff --git a/gdb/varobj.c b/gdb/varobj.c
> index bcca6c6..3b2771f5 100644
> --- a/gdb/varobj.c
> +++ b/gdb/varobj.c
> @@ -2400,8 +2400,6 @@ varobj_value_get_print_value (struct value *value,
>  			      enum varobj_display_formats format,
>  			      const struct varobj *var)
>  {
> -  struct ui_file *stb;
> -  struct cleanup *old_chain;
>    struct value_print_options opts;
>    struct type *type = NULL;
>    long len = 0;
> @@ -2413,9 +2411,7 @@ varobj_value_get_print_value (struct value *value,
>    if (value == NULL)
>      return std::string ();
>
> -  stb = mem_fileopen ();
> -  old_chain = make_cleanup_ui_file_delete (stb);
> -
> +  string_file stb;
>    std::string thevalue;
>
>  #if HAVE_PYTHON
> @@ -2430,10 +2426,7 @@ varobj_value_get_print_value (struct value *value,
>  	  /* First check to see if we have any children at all.  If so,
>  	     we simply return {...}.  */
>  	  if (dynamic_varobj_has_child_method (var))
> -	    {
> -	      do_cleanups (old_chain);
> -	      return "{...}";
> -	    }
> +	    return "{...}";
>
>  	  if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst))
>  	    {
> @@ -2441,7 +2434,7 @@ varobj_value_get_print_value (struct value *value,
>
>  	      gdbpy_ref output (apply_varobj_pretty_printer (value_formatter,
>  							     &replacement,
> -							     stb));
> +							     &stb));
>
>  	      /* If we have string like output ...  */
>  	      if (output != NULL)
> @@ -2484,10 +2477,7 @@ varobj_value_get_print_value (struct value *value,
>  			  type = builtin_type (gdbarch)->builtin_char;
>
>  			  if (!string_print)
> -			    {
> -			      do_cleanups (old_chain);
> -			      return thevalue;
> -			    }
> +			    return thevalue;
>  			}
>  		      else
>  			gdbpy_print_stack ();
> @@ -2507,20 +2497,17 @@ varobj_value_get_print_value (struct value *value,
>
>    /* If the THEVALUE has contents, it is a regular string.  */
>    if (!thevalue.empty ())
> -    LA_PRINT_STRING (stb, type, (gdb_byte *) thevalue.c_str (),
> +    LA_PRINT_STRING (&stb, type, (gdb_byte *) thevalue.c_str (),
>  		     len, encoding.get (), 0, &opts);
>    else if (string_print)
>      /* Otherwise, if string_print is set, and it is not a regular
>         string, it is a lazy string.  */
> -    val_print_string (type, encoding.get (), str_addr, len, stb, &opts);
> +    val_print_string (type, encoding.get (), str_addr, len, &stb, &opts);
>    else
>      /* All other cases.  */
> -    common_val_print (value, stb, 0, &opts, current_language);
> -
> -  thevalue = ui_file_as_string (stb);
> +    common_val_print (value, &stb, 0, &opts, current_language);
>
> -  do_cleanups (old_chain);
> -  return thevalue;
> +  return std::move (stb.string ());
>  }
>
>  int
> diff --git a/gdb/xtensa-tdep.c b/gdb/xtensa-tdep.c
> index 978b13a..376f4c7 100644
> --- a/gdb/xtensa-tdep.c
> +++ b/gdb/xtensa-tdep.c
> @@ -3063,45 +3063,38 @@ xtensa_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
>  static void
>  xtensa_verify_config (struct gdbarch *gdbarch)
>  {
> -  struct ui_file *log;
> -  struct cleanup *cleanups;
> -  struct gdbarch_tdep *tdep;
> -
> -  tdep = gdbarch_tdep (gdbarch);
> -  log = mem_fileopen ();
> -  cleanups = make_cleanup_ui_file_delete (log);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  string_file log;
>
>    /* Verify that we got a reasonable number of AREGS.  */
>    if ((tdep->num_aregs & -tdep->num_aregs) != tdep->num_aregs)
> -    fprintf_unfiltered (log, _("\
> +    log.printf (_("\
>  \n\tnum_aregs: Number of AR registers (%d) is not a power of two!"),
> -			tdep->num_aregs);
> +		tdep->num_aregs);
>
>    /* Verify that certain registers exist.  */
>
>    if (tdep->pc_regnum == -1)
> -    fprintf_unfiltered (log, _("\n\tpc_regnum: No PC register"));
> +    log.printf (_("\n\tpc_regnum: No PC register"));
>    if (tdep->isa_use_exceptions && tdep->ps_regnum == -1)
> -    fprintf_unfiltered (log, _("\n\tps_regnum: No PS register"));
> +    log.printf (_("\n\tps_regnum: No PS register"));
>
>    if (tdep->isa_use_windowed_registers)
>      {
>        if (tdep->wb_regnum == -1)
> -	fprintf_unfiltered (log, _("\n\twb_regnum: No WB register"));
> +	log.printf (_("\n\twb_regnum: No WB register"));
>        if (tdep->ws_regnum == -1)
> -	fprintf_unfiltered (log, _("\n\tws_regnum: No WS register"));
> +	log.printf (_("\n\tws_regnum: No WS register"));
>        if (tdep->ar_base == -1)
> -	fprintf_unfiltered (log, _("\n\tar_base: No AR registers"));
> +	log.printf (_("\n\tar_base: No AR registers"));
>      }
>
>    if (tdep->a0_base == -1)
> -    fprintf_unfiltered (log, _("\n\ta0_base: No Ax registers"));
> +    log.printf (_("\n\ta0_base: No Ax registers"));
>
> -  std::string buf = ui_file_as_string (log);
> -  if (!buf.empty ())
> +  if (!log.empty ())
>      internal_error (__FILE__, __LINE__,
> -		    _("the following are invalid: %s"), buf.c_str ());
> -  do_cleanups (cleanups);
> +		    _("the following are invalid: %s"), log.c_str ());
>  }
>
>
>

Otherwise looks good to me.

Great cleanup. Thanks!

  reply	other threads:[~2017-02-01 17:37 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-01  0:30 [PATCH v4 0/2] Eliminate cleanups & make ui_file a C++ " Pedro Alves
2017-02-01  0:30 ` [PATCH v4 1/2] Add back gdb_pretty_print_insn Pedro Alves
2017-02-01 17:01   ` Luis Machado
2017-02-01 18:10   ` Simon Marchi
2017-02-01 18:26     ` Simon Marchi
2017-02-02  0:00       ` Pedro Alves
2017-02-01 20:02     ` Pedro Alves
2017-02-01 20:31       ` Pedro Alves
2017-02-01 23:50         ` Pedro Alves
2017-02-02  1:20           ` Simon Marchi
2017-02-02 11:37             ` [pushed] Reuse buffers across gdb_pretty_print_insn calls (Re: [PATCH v4 1/2] Add back gdb_pretty_print_insn) Pedro Alves
2017-02-01  0:31 ` [PATCH v4 2/2] Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy Pedro Alves
2017-02-01 17:37   ` Luis Machado [this message]
2017-02-01 22:49     ` Pedro Alves
2017-02-01 23:24       ` Luis Machado
2017-02-02  0:02         ` Pedro Alves
2017-02-27 19:43           ` Edjunior Barbosa Machado
2017-03-07 14:02             ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a1194bed-b33a-d874-2fa2-b0a1ff793eea@codesourcery.com \
    --to=lgustavo@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    --cc=palves@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).