This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d7e747318f4d04af033f16325f9b6d74f67079ec

commit d7e747318f4d04af033f16325f9b6d74f67079ec
Author: Pedro Alves <palves@redhat.com>
Date:   Thu Feb 2 11:11:47 2017 +0000

    Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
    
    This patch starts from the desire to eliminate
    make_cleanup_ui_file_delete, but then goes beyond.  It makes ui_file &
    friends a real C++ class hierarchy, and switches temporary
    ui_file-like objects to stack-based allocation.
    
    - mem_fileopen -> string_file
    
    mem_fileopen is replaced with a new string_file class that is treated
    as a value class created on the stack.  This alone eliminates most
    make_cleanup_ui_file_delete calls, and, simplifies code a whole lot
    (diffstat shows around 1k loc dropped.)
    
    string_file's internal buffer is a std::string, thus the "string" in
    the name.  This simplifies the implementation much, compared to
    mem_fileopen, which managed growing its internal buffer manually.
    
    - ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone
    
    The new string_file class has a string() method that provides direct
    writable access to the internal std::string buffer.  This replaced
    ui_file_as_string, which forced a copy of the same data the stream had
    inside.  With direct access via a writable reference, we can instead
    move the string out of the string_stream, avoiding deep string
    copying.
    
    Related, ui_file_xstrdup calls are replaced with xstrdup'ping the
    stream's string, and ui_file_obsavestring is replaced by
    obstack_copy0.
    
    With all those out of the way, getting rid of the weird ui_file_put
    mechanism was possible.
    
    - New ui_file::printf, ui_file::puts, etc. methods
    
    These simplify / clarify client code.  I considered splitting
    client-code changes, like these, e.g.:
    
      -  stb = mem_fileopen ();
      -  fprintf_unfiltered (stb, "%s%s%s",
      -		      _("The valid values are:\n"),
      -		      regdesc,
      -		      _("The default is \"std\"."));
      +  string_file stb;
      +  stb.printf ("%s%s%s",
      +	      _("The valid values are:\n"),
      +	      regdesc,
      +	      _("The default is \"std\"."));
    
    In two steps, with the first step leaving fprintf_unfiltered (etc.)
    calls in place, and only afterwards do a pass to change all those to
    call stb.printf etc..  I didn't do that split, because (when I tried),
    it turned out to be pointless make-work: the first pass would have to
    touch the fprintf_unfiltered line anyway, to replace "stb" with
    "&stb".
    
    - gdb_fopen replaced with stack-based objects
    
    This avoids the need for cleanups or unique_ptr's.  I.e., this:
    
          struct ui_file *file = gdb_fopen (filename, "w");
          if (filename == NULL)
     	perror_with_name (filename);
          cleanups = make_cleanup_ui_file_delete (file);
          // use file.
          do_cleanups (cleanups);
    
    is replaced with this:
    
          stdio_file file;
          if (!file.open (filename, "w"))
     	perror_with_name (filename);
          // use file.
    
    - odd contorsions in null_file_write / null_file_fputs around when to
      call to_fputs / to_write eliminated.
    
    - Global null_stream object
    
    A few places that were allocating a ui_file in order to print to
    "nowhere" are adjusted to instead refer to a new 'null_stream' global
    stream.
    
    - TUI's tui_sfileopen eliminated.  TUI's ui_file much simplified
    
    The TUI's ui_file was serving a dual purpose.  It supported being used
    as string buffer, and supported being backed by a stdio FILE.  The
    string buffer part is gone, replaced by using of string_file.  The
    'FILE *' support is now much simplified, by making the TUI's ui_file
    inherit from stdio_file.
    
    gdb/ChangeLog:
    2017-02-02  Pedro Alves  <palves@redhat.com>
    
    	* ada-lang.c (type_as_string): Use string_file.
    	* ada-valprint.c (ada_print_floating): Use string_file.
    	* ada-varobj.c (ada_varobj_scalar_image)
    	(ada_varobj_get_value_image): Use string_file.
    	* aix-thread.c (aix_thread_extra_thread_info): Use string_file.
    	* arm-tdep.c (_initialize_arm_tdep): Use string_printf.
    	* breakpoint.c (update_inserted_breakpoint_locations)
    	(insert_breakpoint_locations, reattach_breakpoints)
    	(print_breakpoint_location, print_one_detail_ranged_breakpoint)
    	(print_it_watchpoint): Use string_file.
    	(save_breakpoints): Use stdio_file.
    	* c-exp.y (oper): Use string_file.
    	* cli/cli-logging.c (set_logging_redirect): Use ui_file_up and
    	tee_file.
    	(pop_output_files): Use delete.
    	(handle_redirections): Use stdio_file and tee_file.
    	* cli/cli-setshow.c (do_show_command): Use string_file.
    	* compile/compile-c-support.c (c_compute_program): Use
    	string_file.
    	* compile/compile-c-symbols.c (generate_vla_size): Take a
    	'string_file &' instead of a 'ui_file *'.
    	(generate_c_for_for_one_variable): Take a 'string_file &' instead
    	of a 'ui_file *'.  Use string_file.
    	(generate_c_for_variable_locations): Take a 'string_file &'
    	instead of a 'ui_file *'.
    	* compile/compile-internal.h (generate_c_for_for_one_variable):
    	Take a 'string_file &' instead of a 'ui_file *'.
    	* compile/compile-loc2c.c (push, pushf, unary, binary)
    	(print_label, pushf_register_address, pushf_register)
    	(do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a
    	'ui_file *'.  Adjust.
    	* compile/compile.c (compile_to_object): Use string_file.
    	* compile/compile.h (compile_dwarf_expr_to_c)
    	(compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a
    	'ui_file *'.
    	* cp-support.c (inspect_type): Use string_file and obstack_copy0.
    	(replace_typedefs_qualified_name): Use string_file and
    	obstack_copy0.
    	* disasm.c (gdb_pretty_print_insn): Use string_file.
    	(gdb_disassembly): Adjust reference the null_stream global.
    	(do_ui_file_delete): Delete.
    	(gdb_insn_length): Use null_stream.
    	* dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file.
    	* dwarf2loc.c (dwarf2_compile_property_to_c)
    	(locexpr_generate_c_location, loclist_generate_c_location): Take a
    	'string_file &' instead of a 'ui_file *'.
    	* dwarf2loc.h (dwarf2_compile_property_to_c): Likewise.
    	* dwarf2read.c (do_ui_file_peek_last): Delete.
    	(dwarf2_compute_name): Use string_file.
    	* event-top.c (gdb_setup_readline): Use stdio_file.
    	* gdbarch.sh (verify_gdbarch): Use string_file.
    	* gdbtypes.c (safe_parse_type): Use null_stream.
    	* guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use
    	string_file.
    	* guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a
    	'string_file *' instead of a 'ui_file *'.
    	(gdbscm_arch_disassemble): Use string_file.
    	* guile/scm-frame.c (frscm_print_frame_smob): Use string_file.
    	* guile/scm-ports.c (class ioscm_file_port): Now a class that
    	inherits from ui_file.
    	(ioscm_file_port_delete, ioscm_file_port_rewind)
    	(ioscm_file_port_put): Delete.
    	(ioscm_file_port_write): Rename to ...
    	(ioscm_file_port::write): ... this.  Remove file_port_magic
    	checks.
    	(ioscm_file_port_new): Delete.
    	(ioscm_with_output_to_port_worker): Use ioscm_file_port and
    	ui_file_up.
    	* guile/scm-type.c (tyscm_type_name): Use string_file.
    	* guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print):
    	Use string_file.
    	* infcmd.c (print_return_value_1): Use string_file.
    	* infrun.c (print_target_wait_results): Use string_file.
    	* language.c (add_language): Use string_file.
    	* location.c (explicit_to_string_internal): Use string_file.
    	* main.c (captured_main_1): Use null_file.
    	* maint.c (maintenance_print_architecture): Use stdio_file.
    	* mi/mi-cmd-stack.c (list_arg_or_local): Use string_file.
    	* mi/mi-common.h (struct mi_interp) <out, err, log, targ,
    	event_channel>: Change type to mi_console_file pointer.
    	* mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush)
    	(mi_console_file_delete): Delete.
    	(struct mi_console_file): Delete.
    	(mi_console_file_magic): Delete.
    	(mi_console_file_new): Delete.
    	(mi_console_file::mi_console_file): New.
    	(mi_console_file_delete): Delete.
    	(mi_console_file_fputs): Delete.
    	(mi_console_file::write): New.
    	(mi_console_raw_packet): Delete.
    	(mi_console_file::flush): New.
    	(mi_console_file_flush): Delete.
    	(mi_console_set_raw): Rename to ...
    	(mi_console_file::set_raw): ... this.
    	* mi/mi-console.h (class mi_console_file): New class.
    	(mi_console_file_new, mi_console_set_raw): Delete.
    	* mi/mi-interp.c (mi_interpreter_init): Use mi_console_file.
    	(mi_set_logging): Use delete and tee_file.  Adjust.
    	* mi/mi-main.c (output_register): Use string_file.
    	(mi_cmd_data_evaluate_expression): Use string_file.
    	(mi_cmd_data_read_memory): Use string_file.
    	(mi_cmd_execute, print_variable_or_computed): Use string_file.
    	* mi/mi-out.c (mi_ui_out::main_stream): New.
    	(mi_ui_out::rewind): Use main_stream and
    	string_file.
    	(mi_ui_out::put): Use main_stream and string_file.
    	(mi_ui_out::mi_ui_out): Remove 'stream' parameter.
    	Allocate a 'string_file' instead.
    	(mi_out_new): Don't allocate a mem_fileopen stream here.
    	* mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter.
    	(mi_ui_out::main_stream): Declare method.
    	* printcmd.c (eval_command): Use string_file.
    	* psymtab.c (maintenance_print_psymbols): Use stdio_file.
    	* python/py-arch.c (archpy_disassemble): Use string_file.
    	* python/py-breakpoint.c (bppy_get_commands): Use string_file.
    	* python/py-frame.c (frapy_str): Use string_file.
    	* python/py-framefilter.c (py_print_type, py_print_single_arg):
    	Use string_file.
    	* python/py-type.c (typy_str): Use string_file.
    	* python/py-unwind.c (unwind_infopy_str): Use string_file.
    	* python/py-value.c (valpy_str): Use string_file.
    	* record-btrace.c (btrace_insn_history): Use string_file.
    	* regcache.c (regcache_print): Use stdio_file.
    	* reggroups.c (maintenance_print_reggroups): Use stdio_file.
    	* remote.c (escape_buffer): Use string_file.
    	* rust-lang.c (rust_get_disr_info): Use string_file.
    	* serial.c (serial_open_ops_1): Use stdio_file.
    	(do_serial_close): Use delete.
    	* stack.c (print_frame_arg): Use string_file.
    	(print_frame_args): Remove local mem_fileopen stream, not used.
    	(print_frame): Use string_file.
    	* symmisc.c (maintenance_print_symbols): Use stdio_file.
    	* symtab.h (struct symbol_computed_ops) <generate_c_location>:
    	Take a 'string_file *' instead of a 'ui_file *'.
    	* top.c (new_ui): Use stdio_file and stderr_file.
    	(free_ui): Use delete.
    	(execute_command_to_string): Use string_file.
    	(quit_confirm): Use string_file.
    	* tracepoint.c (collection_list::append_exp): Use string_file.
    	* tui/tui-disasm.c (tui_disassemble): Use string_file.
    	* tui/tui-file.c: Don't include "ui-file.h".
    	(enum streamtype, struct tui_stream): Delete.
    	(tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen)
    	(tui_file_isatty, tui_file_rewind, tui_file_put): Delete.
    	(tui_file::tui_file): New method.
    	(tui_file_fputs): Delete.
    	(tui_file_get_strbuf): Delete.
    	(tui_file::puts): New method.
    	(tui_file_adjust_strbuf): Delete.
    	(tui_file_flush): Delete.
    	(tui_file::flush): New method.
    	* tui/tui-file.h: Tweak intro comment.
    	Include ui-file.h.
    	(tui_fileopen, tui_sfileopen, tui_file_get_strbuf)
    	(tui_file_adjust_strbuf): Delete declarations.
    	(class tui_file): New class.
    	* tui/tui-io.c (tui_initialize_io): Use tui_file.
    	* tui/tui-regs.c (tui_restore_gdbout): Use delete.
    	(tui_register_format): Use string_stream.
    	* tui/tui-stack.c (tui_make_status_line): Use string_file.
    	(tui_get_function_from_frame): Use string_file.
    	* typeprint.c (type_to_string): Use string_file.
    	* ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete.
    	(null_stream): New global.
    	(ui_file_delete): Delete.
    	(ui_file::ui_file): New.
    	(null_file_isatty): Delete.
    	(ui_file::~ui_file): New.
    	(null_file_rewind): Delete.
    	(ui_file::printf): New.
    	(null_file_put): Delete.
    	(null_file_flush): Delete.
    	(ui_file::putstr): New.
    	(null_file_write): Delete.
    	(ui_file::putstrn): New.
    	(null_file_read): Delete.
    	(ui_file::putc): New.
    	(null_file_fputs): Delete.
    	(null_file_write_async_safe): Delete.
    	(ui_file::vprintf): New.
    	(null_file_delete): Delete.
    	(null_file::write): New.
    	(null_file_fseek): Delete.
    	(null_file::puts): New.
    	(ui_file_data): Delete.
    	(null_file::write_async_safe): New.
    	(gdb_flush, ui_file_isatty): Adjust.
    	(ui_file_put, ui_file_rewind): Delete.
    	(ui_file_write): Adjust.
    	(ui_file_write_for_put): Delete.
    	(ui_file_write_async_safe, ui_file_read): Adjust.
    	(ui_file_fseek): Delete.
    	(fputs_unfiltered): Adjust.
    	(set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind)
    	(set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe)
    	(set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek)
    	(set_ui_file_data): Delete.
    	(string_file::~string_file, string_file::write)
    	(struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup)
    	(do_ui_file_as_string, ui_file_as_string): Delete.
    	(do_ui_file_obsavestring, ui_file_obsavestring): Delete.
    	(struct mem_file): Delete.
    	(mem_file_new): Delete.
    	(stdio_file::stdio_file): New.
    	(mem_file_delete): Delete.
    	(stdio_file::stdio_file): New.
    	(mem_fileopen): Delete.
    	(stdio_file::~stdio_file): New.
    	(mem_file_rewind): Delete.
    	(stdio_file::set_stream): New.
    	(mem_file_put): Delete.
    	(stdio_file::open): New.
    	(mem_file_write): Delete.
    	(stdio_file_magic, struct stdio_file): Delete.
    	(stdio_file_new, stdio_file_delete, stdio_file_flush): Delete.
    	(stdio_file::flush): New.
    	(stdio_file_read): Rename to ...
    	(stdio_file::read): ... this.  Adjust.
    	(stdio_file_write): Rename to ...
    	(stdio_file::write): ... this.  Adjust.
    	(stdio_file_write_async_safe): Rename to ...
    	(stdio_file::write_async_safe) ... this.  Adjust.
    	(stdio_file_fputs): Rename to ...
    	(stdio_file::puts) ... this.  Adjust.
    	(stdio_file_isatty): Delete.
    	(stdio_file_fseek): Delete.
    	(stdio_file::isatty): New.
    	(stderr_file_write): Rename to ...
    	(stderr_file::write) ... this.  Adjust.
    	(stderr_file_fputs): Rename to ...
    	(stderr_file::puts) ... this.  Adjust.
    	(stderr_fileopen, stdio_fileopen, gdb_fopen): Delete.
    	(stderr_file::stderr_file): New.
    	(tee_file_magic): Delete.
    	(struct tee_file): Delete.
    	(tee_file::tee_file): New.
    	(tee_file_new): Delete.
    	(tee_file::~tee_file): New.
    	(tee_file_delete): Delete.
    	(tee_file_flush): Rename to ...
    	(tee_file::flush): ... this.  Adjust.
    	(tee_file_write): Rename to ...
    	(tee_file::write): ... this.  Adjust.
    	(tee_file::write_async_safe): New.
    	(tee_file_fputs): Rename to ...
    	(tee_file::puts): ... this.  Adjust.
    	(tee_file_isatty): Rename to ...
    	(tee_file::isatty): ... this.  Adjust.
    	* ui-file.h (struct obstack, struct ui_file): Don't
    	forward-declare.
    	(ui_file_new, ui_file_flush_ftype, set_ui_file_flush)
    	(ui_file_write_ftype)
    	(set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs)
    	(ui_file_write_async_safe_ftype, set_ui_file_write_async_safe)
    	(ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype)
    	(set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind)
    	(ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put)
    	(ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype)
    	(set_ui_file_fseek): Delete.
    	(ui_file_data, ui_file_delete, ui_file_rewind)
    	(struct ui_file): New.
    	(ui_file_up): New.
    	(class null_file): New.
    	(null_stream): Declare.
    	(ui_file_write_for_put, ui_file_put): Delete.
    	(ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring):
    	Delete.
    	(ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen)
    	(gdb_fopen, tee_file_new): Delete.
    	(struct string_file): New.
    	(struct stdio_file): New.
    	(stdio_file_up): New.
    	(struct stderr_file): New.
    	(class tee_file): New.
    	* ui-out.c (ui_out::field_stream): Take a 'string_file &' instead
    	of a 'ui_file *'.  Adjust.
    	* ui-out.h (class ui_out) <field_stream>: Likewise.
    	* utils.c (do_ui_file_delete, make_cleanup_ui_file_delete)
    	(null_stream): Delete.
    	(error_stream): Take a 'string_file &' instead of a 'ui_file *'.
    	Adjust.
    	* utils.h (struct ui_file): Delete forward declaration..
    	(make_cleanup_ui_file_delete, null_stream): Delete declarations.
    	(error_stream): Take a 'string_file &' instead of a
    	'ui_file *'.
    	* varobj.c (varobj_value_get_print_value): Use string_file.
    	* xtensa-tdep.c (xtensa_verify_config): Use string_file.
    	* gdbarch.c: Regenerate.

Diff:
---
 gdb/ChangeLog                   | 291 +++++++++++++++
 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                   | 296 ++++++++++-----
 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 +-
 81 files changed, 1350 insertions(+), 2108 deletions(-)

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

[diff truncated at 100000 bytes]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]