1/* MI Command Set - output generating routines. 2 3 Copyright (C) 2000-2023 Free Software Foundation, Inc. 4 5 Contributed by Cygnus Solutions (a Red Hat company). 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22#include "defs.h" 23#include "mi-out.h" 24 25#include <vector> 26 27#include "interps.h" 28#include "ui-out.h" 29#include "utils.h" 30#include "gdbsupport/gdb-checked-static-cast.h" 31 32/* Mark beginning of a table. */ 33 34void 35mi_ui_out::do_table_begin (int nr_cols, int nr_rows, 36 const char *tblid) 37{ 38 open (tblid, ui_out_type_tuple); 39 do_field_signed (-1, -1, ui_left, "nr_rows", nr_rows); 40 do_field_signed (-1, -1, ui_left, "nr_cols", nr_cols); 41 open ("hdr", ui_out_type_list); 42} 43 44/* Mark beginning of a table body. */ 45 46void 47mi_ui_out::do_table_body () 48{ 49 /* close the table header line if there were any headers */ 50 close (ui_out_type_list); 51 open ("body", ui_out_type_list); 52} 53 54/* Mark end of a table. */ 55 56void 57mi_ui_out::do_table_end () 58{ 59 close (ui_out_type_list); /* body */ 60 close (ui_out_type_tuple); 61} 62 63/* Specify table header. */ 64 65void 66mi_ui_out::do_table_header (int width, ui_align alignment, 67 const std::string &col_name, 68 const std::string &col_hdr) 69{ 70 open (NULL, ui_out_type_tuple); 71 do_field_signed (0, 0, ui_center, "width", width); 72 do_field_signed (0, 0, ui_center, "alignment", alignment); 73 do_field_string (0, 0, ui_center, "col_name", col_name.c_str (), 74 ui_file_style ()); 75 do_field_string (0, width, alignment, "colhdr", col_hdr.c_str (), 76 ui_file_style ()); 77 close (ui_out_type_tuple); 78} 79 80/* Mark beginning of a list. */ 81 82void 83mi_ui_out::do_begin (ui_out_type type, const char *id) 84{ 85 open (id, type); 86} 87 88/* Mark end of a list. */ 89 90void 91mi_ui_out::do_end (ui_out_type type) 92{ 93 close (type); 94} 95 96/* Output an int field. */ 97 98void 99mi_ui_out::do_field_signed (int fldno, int width, ui_align alignment, 100 const char *fldname, LONGEST value) 101{ 102 do_field_string (fldno, width, alignment, fldname, plongest (value), 103 ui_file_style ()); 104} 105 106/* Output an unsigned field. */ 107 108void 109mi_ui_out::do_field_unsigned (int fldno, int width, ui_align alignment, 110 const char *fldname, ULONGEST value) 111{ 112 do_field_string (fldno, width, alignment, fldname, pulongest (value), 113 ui_file_style ()); 114} 115 116/* Used to omit a field. */ 117 118void 119mi_ui_out::do_field_skip (int fldno, int width, ui_align alignment, 120 const char *fldname) 121{ 122} 123 124/* Other specific mi_field_* end up here so alignment and field 125 separators are both handled by mi_field_string. */ 126 127void 128mi_ui_out::do_field_string (int fldno, int width, ui_align align, 129 const char *fldname, const char *string, 130 const ui_file_style &style) 131{ 132 ui_file *stream = m_streams.back (); 133 field_separator (); 134 135 if (fldname) 136 gdb_printf (stream, "%s=", fldname); 137 gdb_printf (stream, "\""); 138 if (string) 139 stream->putstr (string, '"'); 140 gdb_printf (stream, "\""); 141} 142 143void 144mi_ui_out::do_field_fmt (int fldno, int width, ui_align align, 145 const char *fldname, const ui_file_style &style, 146 const char *format, va_list args) 147{ 148 ui_file *stream = m_streams.back (); 149 field_separator (); 150 151 if (fldname) 152 gdb_printf (stream, "%s=\"", fldname); 153 else 154 gdb_puts ("\"", stream); 155 gdb_vprintf (stream, format, args); 156 gdb_puts ("\"", stream); 157} 158 159void 160mi_ui_out::do_spaces (int numspaces) 161{ 162} 163 164void 165mi_ui_out::do_text (const char *string) 166{ 167} 168 169void 170mi_ui_out::do_message (const ui_file_style &style, 171 const char *format, va_list args) 172{ 173} 174 175void 176mi_ui_out::do_wrap_hint (int indent) 177{ 178 m_streams.back ()->wrap_here (indent); 179} 180 181void 182mi_ui_out::do_flush () 183{ 184 185 gdb_flush (m_streams.back ()); 186} 187 188void 189mi_ui_out::do_redirect (ui_file *outstream) 190{ 191 if (outstream != NULL) 192 m_streams.push_back (outstream); 193 else 194 m_streams.pop_back (); 195} 196 197void 198mi_ui_out::field_separator () 199{ 200 if (m_suppress_field_separator) 201 m_suppress_field_separator = false; 202 else 203 gdb_putc (',', m_streams.back ()); 204} 205 206void 207mi_ui_out::open (const char *name, ui_out_type type) 208{ 209 ui_file *stream = m_streams.back (); 210 211 field_separator (); 212 m_suppress_field_separator = true; 213 214 if (name) 215 gdb_printf (stream, "%s=", name); 216 217 switch (type) 218 { 219 case ui_out_type_tuple: 220 gdb_putc ('{', stream); 221 break; 222 223 case ui_out_type_list: 224 gdb_putc ('[', stream); 225 break; 226 227 default: 228 internal_error (_("bad switch")); 229 } 230} 231 232void 233mi_ui_out::close (ui_out_type type) 234{ 235 ui_file *stream = m_streams.back (); 236 237 switch (type) 238 { 239 case ui_out_type_tuple: 240 gdb_putc ('}', stream); 241 break; 242 243 case ui_out_type_list: 244 gdb_putc (']', stream); 245 break; 246 247 default: 248 internal_error (_("bad switch")); 249 } 250 251 m_suppress_field_separator = false; 252} 253 254string_file * 255mi_ui_out::main_stream () 256{ 257 gdb_assert (m_streams.size () == 1); 258 259 return (string_file *) m_streams.back (); 260} 261 262/* Initialize a progress update to be displayed with 263 mi_ui_out::do_progress_notify. */ 264 265void 266mi_ui_out::do_progress_start () 267{ 268 m_progress_info.emplace_back (); 269} 270 271/* Indicate that a task described by MSG is in progress. */ 272 273void 274mi_ui_out::do_progress_notify (const std::string &msg, const char *unit, 275 double cur, double total) 276{ 277 mi_progress_info &info (m_progress_info.back ()); 278 279 if (info.state == progress_update::START) 280 { 281 gdb_printf ("%s...\n", msg.c_str ()); 282 info.state = progress_update::WORKING; 283 } 284} 285 286/* Remove the most recent progress update from the progress_info stack. */ 287 288void 289mi_ui_out::do_progress_end () 290{ 291 m_progress_info.pop_back (); 292} 293 294/* Clear the buffer. */ 295 296void 297mi_ui_out::rewind () 298{ 299 main_stream ()->clear (); 300} 301 302/* Dump the buffer onto the specified stream. */ 303 304void 305mi_ui_out::put (ui_file *where) 306{ 307 string_file *mi_stream = main_stream (); 308 309 where->write (mi_stream->data (), mi_stream->size ()); 310 mi_stream->clear (); 311} 312 313/* Return the current MI version. */ 314 315int 316mi_ui_out::version () 317{ 318 return m_mi_version; 319} 320 321/* Constructor for an `mi_out_data' object. */ 322 323mi_ui_out::mi_ui_out (int mi_version) 324: ui_out (make_flags (mi_version)), 325 m_suppress_field_separator (false), 326 m_suppress_output (false), 327 m_mi_version (mi_version) 328{ 329 string_file *stream = new string_file (); 330 m_streams.push_back (stream); 331} 332 333mi_ui_out::~mi_ui_out () 334{ 335} 336 337/* See mi/mi-out.h. */ 338 339mi_ui_out * 340mi_out_new (const char *mi_version) 341{ 342 if (streq (mi_version, INTERP_MI4) || streq (mi_version, INTERP_MI)) 343 return new mi_ui_out (4); 344 345 if (streq (mi_version, INTERP_MI3)) 346 return new mi_ui_out (3); 347 348 if (streq (mi_version, INTERP_MI2)) 349 return new mi_ui_out (2); 350 351 if (streq (mi_version, INTERP_MI1)) 352 return new mi_ui_out (1); 353 354 return nullptr; 355} 356 357/* Helper function to return the given UIOUT as an mi_ui_out. It is an error 358 to call this function with an ui_out that is not an MI. */ 359 360static mi_ui_out * 361as_mi_ui_out (ui_out *uiout) 362{ 363 return gdb::checked_static_cast<mi_ui_out *> (uiout); 364} 365 366int 367mi_version (ui_out *uiout) 368{ 369 return as_mi_ui_out (uiout)->version (); 370} 371 372void 373mi_out_put (ui_out *uiout, struct ui_file *stream) 374{ 375 return as_mi_ui_out (uiout)->put (stream); 376} 377 378void 379mi_out_rewind (ui_out *uiout) 380{ 381 return as_mi_ui_out (uiout)->rewind (); 382} 383