mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
d7e747318f
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.
700 lines
15 KiB
C
700 lines
15 KiB
C
/* Output generating routines for GDB.
|
|
|
|
Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
|
|
|
Contributed by Cygnus Solutions.
|
|
Written by Fernando Nasser for Cygnus.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "expression.h" /* For language.h */
|
|
#include "language.h"
|
|
#include "ui-out.h"
|
|
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <memory>
|
|
|
|
/* A header of a ui_out_table. */
|
|
|
|
class ui_out_hdr
|
|
{
|
|
public:
|
|
|
|
explicit ui_out_hdr (int number, int min_width, ui_align alignment,
|
|
const std::string &name, const std::string &header)
|
|
: m_number (number),
|
|
m_min_width (min_width),
|
|
m_alignment (alignment),
|
|
m_name (name),
|
|
m_header (header)
|
|
{
|
|
}
|
|
|
|
int number () const
|
|
{
|
|
return m_number;
|
|
}
|
|
|
|
int min_width () const
|
|
{
|
|
return m_min_width;
|
|
}
|
|
|
|
ui_align alignment () const
|
|
{
|
|
return m_alignment;
|
|
}
|
|
|
|
const std::string &header () const
|
|
{
|
|
return m_header;
|
|
}
|
|
|
|
const std::string &name () const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
private:
|
|
|
|
/* The number of the table column this header represents, 1-based. */
|
|
int m_number;
|
|
|
|
/* Minimal column width in characters. May or may not be applicable,
|
|
depending on the actual implementation of ui_out. */
|
|
int m_min_width;
|
|
|
|
/* Alignment of the content in the column. May or may not be applicable,
|
|
depending on the actual implementation of ui_out. */
|
|
ui_align m_alignment;
|
|
|
|
/* Internal column name, used to internally refer to the column. */
|
|
std::string m_name;
|
|
|
|
/* Printed header text of the column. */
|
|
std::string m_header;
|
|
};
|
|
|
|
/* A level of nesting (either a list or a tuple) in a ui_out output. */
|
|
|
|
class ui_out_level
|
|
{
|
|
public:
|
|
|
|
explicit ui_out_level (ui_out_type type)
|
|
: m_type (type),
|
|
m_field_count (0)
|
|
{
|
|
}
|
|
|
|
ui_out_type type () const
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
int field_count () const
|
|
{
|
|
return m_field_count;
|
|
}
|
|
|
|
void inc_field_count ()
|
|
{
|
|
m_field_count++;
|
|
}
|
|
|
|
private:
|
|
|
|
/* The type of this level. */
|
|
ui_out_type m_type;
|
|
|
|
/* Count each field; the first element is for non-list fields. */
|
|
int m_field_count;
|
|
};
|
|
|
|
/* Tables are special. Maintain a separate structure that tracks
|
|
their state. At present an output can only contain a single table
|
|
but that restriction might eventually be lifted. */
|
|
|
|
class ui_out_table
|
|
{
|
|
public:
|
|
|
|
/* States (steps) of a table generation. */
|
|
|
|
enum class state
|
|
{
|
|
/* We are generating the table headers. */
|
|
HEADERS,
|
|
|
|
/* We are generating the table body. */
|
|
BODY,
|
|
};
|
|
|
|
explicit ui_out_table (int entry_level, int nr_cols, const std::string &id)
|
|
: m_state (state::HEADERS),
|
|
m_entry_level (entry_level),
|
|
m_nr_cols (nr_cols),
|
|
m_id (id)
|
|
{
|
|
}
|
|
|
|
/* Start building the body of the table. */
|
|
|
|
void start_body ();
|
|
|
|
/* Add a new header to the table. */
|
|
|
|
void append_header (int width, ui_align alignment,
|
|
const std::string &col_name, const std::string &col_hdr);
|
|
|
|
void start_row ();
|
|
|
|
/* Extract the format information for the next header and advance
|
|
the header iterator. Return false if there was no next header. */
|
|
|
|
bool get_next_header (int *colno, int *width, ui_align *alignment,
|
|
const char **col_hdr);
|
|
|
|
bool query_field (int colno, int *width, int *alignment,
|
|
const char **col_name) const;
|
|
|
|
state current_state () const;
|
|
|
|
int entry_level () const;
|
|
|
|
private:
|
|
|
|
state m_state;
|
|
|
|
/* The level at which each entry of the table is to be found. A row
|
|
(a tuple) is made up of entries. Consequently ENTRY_LEVEL is one
|
|
above that of the table. */
|
|
int m_entry_level;
|
|
|
|
/* Number of table columns (as specified in the table_begin call). */
|
|
int m_nr_cols;
|
|
|
|
/* String identifying the table (as specified in the table_begin
|
|
call). */
|
|
std::string m_id;
|
|
|
|
/* Pointers to the column headers. */
|
|
std::vector<std::unique_ptr<ui_out_hdr>> m_headers;
|
|
|
|
/* Iterator over the headers vector, used when printing successive fields. */
|
|
std::vector<std::unique_ptr<ui_out_hdr>>::const_iterator m_headers_iterator;
|
|
};
|
|
|
|
/* See ui-out.h. */
|
|
|
|
void ui_out_table::start_body ()
|
|
{
|
|
if (m_state != state::HEADERS)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("extra table_body call not allowed; there must be only "
|
|
"one table_body after a table_begin and before a "
|
|
"table_end."));
|
|
|
|
/* Check if the number of defined headers matches the number of expected
|
|
columns. */
|
|
if (m_headers.size () != m_nr_cols)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("number of headers differ from number of table "
|
|
"columns."));
|
|
|
|
m_state = state::BODY;
|
|
m_headers_iterator = m_headers.begin ();
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
void ui_out_table::append_header (int width, ui_align alignment,
|
|
const std::string &col_name,
|
|
const std::string &col_hdr)
|
|
{
|
|
if (m_state != state::HEADERS)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("table header must be specified after table_begin and "
|
|
"before table_body."));
|
|
|
|
std::unique_ptr<ui_out_hdr> header (new ui_out_hdr (m_headers.size () + 1,
|
|
width, alignment,
|
|
col_name, col_hdr));
|
|
|
|
m_headers.push_back (std::move (header));
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
void ui_out_table::start_row ()
|
|
{
|
|
m_headers_iterator = m_headers.begin ();
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
bool ui_out_table::get_next_header (int *colno, int *width, ui_align *alignment,
|
|
const char **col_hdr)
|
|
{
|
|
/* There may be no headers at all or we may have used all columns. */
|
|
if (m_headers_iterator == m_headers.end ())
|
|
return false;
|
|
|
|
ui_out_hdr *hdr = m_headers_iterator->get ();
|
|
|
|
*colno = hdr->number ();
|
|
*width = hdr->min_width ();
|
|
*alignment = hdr->alignment ();
|
|
*col_hdr = hdr->header ().c_str ();
|
|
|
|
/* Advance the header pointer to the next entry. */
|
|
m_headers_iterator++;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
bool ui_out_table::query_field (int colno, int *width, int *alignment,
|
|
const char **col_name) const
|
|
{
|
|
/* Column numbers are 1-based, so convert to 0-based index. */
|
|
int index = colno - 1;
|
|
|
|
if (index >= 0 && index < m_headers.size ())
|
|
{
|
|
ui_out_hdr *hdr = m_headers[index].get ();
|
|
|
|
gdb_assert (colno == hdr->number ());
|
|
|
|
*width = hdr->min_width ();
|
|
*alignment = hdr->alignment ();
|
|
*col_name = hdr->name ().c_str ();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
ui_out_table::state ui_out_table::current_state () const
|
|
{
|
|
return m_state;
|
|
}
|
|
|
|
/* See ui-out.h. */
|
|
|
|
int ui_out_table::entry_level () const
|
|
{
|
|
return m_entry_level;
|
|
}
|
|
|
|
int
|
|
ui_out::level () const
|
|
{
|
|
return m_levels.size ();
|
|
}
|
|
|
|
/* The current (inner most) level. */
|
|
|
|
ui_out_level *
|
|
ui_out::current_level () const
|
|
{
|
|
return m_levels.back ().get ();
|
|
}
|
|
|
|
/* Create a new level, of TYPE. */
|
|
void
|
|
ui_out::push_level (ui_out_type type)
|
|
{
|
|
std::unique_ptr<ui_out_level> level (new ui_out_level (type));
|
|
|
|
m_levels.push_back (std::move (level));
|
|
}
|
|
|
|
/* Discard the current level. TYPE is the type of the level being
|
|
discarded. */
|
|
void
|
|
ui_out::pop_level (ui_out_type type)
|
|
{
|
|
/* We had better not underflow the buffer. */
|
|
gdb_assert (m_levels.size () > 0);
|
|
gdb_assert (current_level ()->type () == type);
|
|
|
|
m_levels.pop_back ();
|
|
}
|
|
|
|
/* Mark beginning of a table. */
|
|
|
|
void
|
|
ui_out::table_begin (int nr_cols, int nr_rows, const std::string &tblid)
|
|
{
|
|
if (m_table_up != nullptr)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("tables cannot be nested; table_begin found before \
|
|
previous table_end."));
|
|
|
|
m_table_up.reset (new ui_out_table (level () + 1, nr_cols, tblid));
|
|
|
|
do_table_begin (nr_cols, nr_rows, tblid.c_str ());
|
|
}
|
|
|
|
void
|
|
ui_out::table_header (int width, ui_align alignment,
|
|
const std::string &col_name, const std::string &col_hdr)
|
|
{
|
|
if (m_table_up == nullptr)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("table_header outside a table is not valid; it must be \
|
|
after a table_begin and before a table_body."));
|
|
|
|
m_table_up->append_header (width, alignment, col_name, col_hdr);
|
|
|
|
do_table_header (width, alignment, col_name, col_hdr);
|
|
}
|
|
|
|
void
|
|
ui_out::table_body ()
|
|
{
|
|
if (m_table_up == nullptr)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("table_body outside a table is not valid; it must be "
|
|
"after a table_begin and before a table_end."));
|
|
|
|
m_table_up->start_body ();
|
|
|
|
do_table_body ();
|
|
}
|
|
|
|
void
|
|
ui_out::table_end ()
|
|
{
|
|
if (m_table_up == nullptr)
|
|
internal_error (__FILE__, __LINE__,
|
|
_("misplaced table_end or missing table_begin."));
|
|
|
|
do_table_end ();
|
|
|
|
m_table_up = nullptr;
|
|
}
|
|
|
|
static void
|
|
do_cleanup_table_end (void *data)
|
|
{
|
|
ui_out *uiout = (ui_out *) data;
|
|
|
|
uiout->table_end ();
|
|
}
|
|
|
|
struct cleanup *
|
|
make_cleanup_ui_out_table_begin_end (ui_out *uiout, int nr_cols, int nr_rows,
|
|
const char *tblid)
|
|
{
|
|
uiout->table_begin (nr_cols, nr_rows, tblid);
|
|
return make_cleanup (do_cleanup_table_end, uiout);
|
|
}
|
|
|
|
void
|
|
ui_out::begin (ui_out_type type, const char *id)
|
|
{
|
|
/* Be careful to verify the ``field'' before the new tuple/list is
|
|
pushed onto the stack. That way the containing list/table/row is
|
|
verified and not the newly created tuple/list. This verification
|
|
is needed (at least) for the case where a table row entry
|
|
contains either a tuple/list. For that case bookkeeping such as
|
|
updating the column count or advancing to the next heading still
|
|
needs to be performed. */
|
|
{
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
verify_field (&fldno, &width, &align);
|
|
}
|
|
|
|
push_level (type);
|
|
|
|
/* If the push puts us at the same level as a table row entry, we've
|
|
got a new table row. Put the header pointer back to the start. */
|
|
if (m_table_up != nullptr
|
|
&& m_table_up->current_state () == ui_out_table::state::BODY
|
|
&& m_table_up->entry_level () == level ())
|
|
m_table_up->start_row ();
|
|
|
|
do_begin (type, id);
|
|
}
|
|
|
|
void
|
|
ui_out::end (ui_out_type type)
|
|
{
|
|
pop_level (type);
|
|
|
|
do_end (type);
|
|
}
|
|
|
|
struct ui_out_end_cleanup_data
|
|
{
|
|
struct ui_out *uiout;
|
|
enum ui_out_type type;
|
|
};
|
|
|
|
static void
|
|
do_cleanup_end (void *data)
|
|
{
|
|
struct ui_out_end_cleanup_data *end_cleanup_data
|
|
= (struct ui_out_end_cleanup_data *) data;
|
|
|
|
end_cleanup_data->uiout->end (end_cleanup_data->type);
|
|
xfree (end_cleanup_data);
|
|
}
|
|
|
|
static struct cleanup *
|
|
make_cleanup_ui_out_end (struct ui_out *uiout,
|
|
enum ui_out_type type)
|
|
{
|
|
struct ui_out_end_cleanup_data *end_cleanup_data;
|
|
|
|
end_cleanup_data = XNEW (struct ui_out_end_cleanup_data);
|
|
end_cleanup_data->uiout = uiout;
|
|
end_cleanup_data->type = type;
|
|
return make_cleanup (do_cleanup_end, end_cleanup_data);
|
|
}
|
|
|
|
struct cleanup *
|
|
make_cleanup_ui_out_tuple_begin_end (struct ui_out *uiout,
|
|
const char *id)
|
|
{
|
|
uiout->begin (ui_out_type_tuple, id);
|
|
return make_cleanup_ui_out_end (uiout, ui_out_type_tuple);
|
|
}
|
|
|
|
struct cleanup *
|
|
make_cleanup_ui_out_list_begin_end (struct ui_out *uiout,
|
|
const char *id)
|
|
{
|
|
uiout->begin (ui_out_type_list, id);
|
|
return make_cleanup_ui_out_end (uiout, ui_out_type_list);
|
|
}
|
|
|
|
void
|
|
ui_out::field_int (const char *fldname, int value)
|
|
{
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
verify_field (&fldno, &width, &align);
|
|
|
|
do_field_int (fldno, width, align, fldname, value);
|
|
}
|
|
|
|
void
|
|
ui_out::field_fmt_int (int input_width, ui_align input_align,
|
|
const char *fldname, int value)
|
|
{
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
verify_field (&fldno, &width, &align);
|
|
|
|
do_field_int (fldno, input_width, input_align, fldname, value);
|
|
}
|
|
|
|
/* Documented in ui-out.h. */
|
|
|
|
void
|
|
ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch,
|
|
CORE_ADDR address)
|
|
{
|
|
field_string (fldname, print_core_address (gdbarch, address));
|
|
}
|
|
|
|
void
|
|
ui_out::field_stream (const char *fldname, string_file &stream)
|
|
{
|
|
if (!stream.empty ())
|
|
field_string (fldname, stream.c_str ());
|
|
else
|
|
field_skip (fldname);
|
|
stream.clear ();
|
|
}
|
|
|
|
/* Used to omit a field. */
|
|
|
|
void
|
|
ui_out::field_skip (const char *fldname)
|
|
{
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
verify_field (&fldno, &width, &align);
|
|
|
|
do_field_skip (fldno, width, align, fldname);
|
|
}
|
|
|
|
void
|
|
ui_out::field_string (const char *fldname, const char *string)
|
|
{
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
verify_field (&fldno, &width, &align);
|
|
|
|
do_field_string (fldno, width, align, fldname, string);
|
|
}
|
|
|
|
/* VARARGS */
|
|
void
|
|
ui_out::field_fmt (const char *fldname, const char *format, ...)
|
|
{
|
|
va_list args;
|
|
int fldno;
|
|
int width;
|
|
ui_align align;
|
|
|
|
/* Will not align, but has to call anyway. */
|
|
verify_field (&fldno, &width, &align);
|
|
|
|
va_start (args, format);
|
|
|
|
do_field_fmt (fldno, width, align, fldname, format, args);
|
|
|
|
va_end (args);
|
|
}
|
|
|
|
void
|
|
ui_out::spaces (int numspaces)
|
|
{
|
|
do_spaces (numspaces);
|
|
}
|
|
|
|
void
|
|
ui_out::text (const char *string)
|
|
{
|
|
do_text (string);
|
|
}
|
|
|
|
void
|
|
ui_out::message (const char *format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start (args, format);
|
|
do_message (format, args);
|
|
va_end (args);
|
|
}
|
|
|
|
void
|
|
ui_out::wrap_hint (const char *identstring)
|
|
{
|
|
do_wrap_hint (identstring);
|
|
}
|
|
|
|
void
|
|
ui_out::flush ()
|
|
{
|
|
do_flush ();
|
|
}
|
|
|
|
void
|
|
ui_out::redirect (ui_file *outstream)
|
|
{
|
|
do_redirect (outstream);
|
|
}
|
|
|
|
/* Test the flags against the mask given. */
|
|
ui_out_flags
|
|
ui_out::test_flags (ui_out_flags mask)
|
|
{
|
|
return m_flags & mask;
|
|
}
|
|
|
|
bool
|
|
ui_out::is_mi_like_p ()
|
|
{
|
|
return do_is_mi_like_p ();
|
|
}
|
|
|
|
/* Verify that the field/tuple/list is correctly positioned. Return
|
|
the field number and corresponding alignment (if
|
|
available/applicable). */
|
|
|
|
void
|
|
ui_out::verify_field (int *fldno, int *width, ui_align *align)
|
|
{
|
|
ui_out_level *current = current_level ();
|
|
const char *text;
|
|
|
|
if (m_table_up != nullptr
|
|
&& m_table_up->current_state () != ui_out_table::state::BODY)
|
|
{
|
|
internal_error (__FILE__, __LINE__,
|
|
_("table_body missing; table fields must be \
|
|
specified after table_body and inside a list."));
|
|
}
|
|
|
|
current->inc_field_count ();
|
|
|
|
if (m_table_up != nullptr
|
|
&& m_table_up->current_state () == ui_out_table::state::BODY
|
|
&& m_table_up->entry_level () == level ()
|
|
&& m_table_up->get_next_header (fldno, width, align, &text))
|
|
{
|
|
if (*fldno != current->field_count ())
|
|
internal_error (__FILE__, __LINE__,
|
|
_("ui-out internal error in handling headers."));
|
|
}
|
|
else
|
|
{
|
|
*width = 0;
|
|
*align = ui_noalign;
|
|
*fldno = current->field_count ();
|
|
}
|
|
}
|
|
|
|
/* Access table field parameters. */
|
|
|
|
bool
|
|
ui_out::query_table_field (int colno, int *width, int *alignment,
|
|
const char **col_name)
|
|
{
|
|
if (m_table_up == nullptr)
|
|
return false;
|
|
|
|
return m_table_up->query_field (colno, width, alignment, col_name);
|
|
}
|
|
|
|
/* The constructor. */
|
|
|
|
ui_out::ui_out (ui_out_flags flags)
|
|
: m_flags (flags)
|
|
{
|
|
/* Create the ui-out level #1, the default level. */
|
|
push_level (ui_out_type_tuple);
|
|
}
|
|
|
|
ui_out::~ui_out ()
|
|
{
|
|
}
|