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 34 void 35 mi_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 46 void 47 mi_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 56 void 57 mi_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 65 void 66 mi_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 82 void 83 mi_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 90 void 91 mi_ui_out::do_end (ui_out_type type) 92 { 93 close (type); 94 } 95 96 /* Output an int field. */ 97 98 void 99 mi_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 108 void 109 mi_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 118 void 119 mi_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 127 void 128 mi_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 143 void 144 mi_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 159 void 160 mi_ui_out::do_spaces (int numspaces) 161 { 162 } 163 164 void 165 mi_ui_out::do_text (const char *string) 166 { 167 } 168 169 void 170 mi_ui_out::do_message (const ui_file_style &style, 171 const char *format, va_list args) 172 { 173 } 174 175 void 176 mi_ui_out::do_wrap_hint (int indent) 177 { 178 m_streams.back ()->wrap_here (indent); 179 } 180 181 void 182 mi_ui_out::do_flush () 183 { 184 185 gdb_flush (m_streams.back ()); 186 } 187 188 void 189 mi_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 197 void 198 mi_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 206 void 207 mi_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 232 void 233 mi_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 254 string_file * 255 mi_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 265 void 266 mi_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 273 void 274 mi_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 288 void 289 mi_ui_out::do_progress_end () 290 { 291 m_progress_info.pop_back (); 292 } 293 294 /* Clear the buffer. */ 295 296 void 297 mi_ui_out::rewind () 298 { 299 main_stream ()->clear (); 300 } 301 302 /* Dump the buffer onto the specified stream. */ 303 304 void 305 mi_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 315 int 316 mi_ui_out::version () 317 { 318 return m_mi_version; 319 } 320 321 /* Constructor for an `mi_out_data' object. */ 322 323 mi_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 333 mi_ui_out::~mi_ui_out () 334 { 335 } 336 337 /* See mi/mi-out.h. */ 338 339 mi_ui_out * 340 mi_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 360 static mi_ui_out * 361 as_mi_ui_out (ui_out *uiout) 362 { 363 return gdb::checked_static_cast<mi_ui_out *> (uiout); 364 } 365 366 int 367 mi_version (ui_out *uiout) 368 { 369 return as_mi_ui_out (uiout)->version (); 370 } 371 372 void 373 mi_out_put (ui_out *uiout, struct ui_file *stream) 374 { 375 return as_mi_ui_out (uiout)->put (stream); 376 } 377 378 void 379 mi_out_rewind (ui_out *uiout) 380 { 381 return as_mi_ui_out (uiout)->rewind (); 382 } 383