1 /* MI Command Set - output generating routines. 2 3 Copyright (C) 2000-2020 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 31 /* Mark beginning of a table. */ 32 33 void 34 mi_ui_out::do_table_begin (int nr_cols, int nr_rows, 35 const char *tblid) 36 { 37 open (tblid, ui_out_type_tuple); 38 do_field_signed (-1, -1, ui_left, "nr_rows", nr_rows); 39 do_field_signed (-1, -1, ui_left, "nr_cols", nr_cols); 40 open ("hdr", ui_out_type_list); 41 } 42 43 /* Mark beginning of a table body. */ 44 45 void 46 mi_ui_out::do_table_body () 47 { 48 /* close the table header line if there were any headers */ 49 close (ui_out_type_list); 50 open ("body", ui_out_type_list); 51 } 52 53 /* Mark end of a table. */ 54 55 void 56 mi_ui_out::do_table_end () 57 { 58 close (ui_out_type_list); /* body */ 59 close (ui_out_type_tuple); 60 } 61 62 /* Specify table header. */ 63 64 void 65 mi_ui_out::do_table_header (int width, ui_align alignment, 66 const std::string &col_name, 67 const std::string &col_hdr) 68 { 69 open (NULL, ui_out_type_tuple); 70 do_field_signed (0, 0, ui_center, "width", width); 71 do_field_signed (0, 0, ui_center, "alignment", alignment); 72 do_field_string (0, 0, ui_center, "col_name", col_name.c_str (), 73 ui_file_style ()); 74 do_field_string (0, width, alignment, "colhdr", col_hdr.c_str (), 75 ui_file_style ()); 76 close (ui_out_type_tuple); 77 } 78 79 /* Mark beginning of a list. */ 80 81 void 82 mi_ui_out::do_begin (ui_out_type type, const char *id) 83 { 84 open (id, type); 85 } 86 87 /* Mark end of a list. */ 88 89 void 90 mi_ui_out::do_end (ui_out_type type) 91 { 92 close (type); 93 } 94 95 /* Output an int field. */ 96 97 void 98 mi_ui_out::do_field_signed (int fldno, int width, ui_align alignment, 99 const char *fldname, LONGEST value) 100 { 101 do_field_string (fldno, width, alignment, fldname, plongest (value), 102 ui_file_style ()); 103 } 104 105 /* Output an unsigned field. */ 106 107 void 108 mi_ui_out::do_field_unsigned (int fldno, int width, ui_align alignment, 109 const char *fldname, ULONGEST value) 110 { 111 do_field_string (fldno, width, alignment, fldname, pulongest (value), 112 ui_file_style ()); 113 } 114 115 /* Used to omit a field. */ 116 117 void 118 mi_ui_out::do_field_skip (int fldno, int width, ui_align alignment, 119 const char *fldname) 120 { 121 } 122 123 /* Other specific mi_field_* end up here so alignment and field 124 separators are both handled by mi_field_string. */ 125 126 void 127 mi_ui_out::do_field_string (int fldno, int width, ui_align align, 128 const char *fldname, const char *string, 129 const ui_file_style &style) 130 { 131 ui_file *stream = m_streams.back (); 132 field_separator (); 133 134 if (fldname) 135 fprintf_unfiltered (stream, "%s=", fldname); 136 fprintf_unfiltered (stream, "\""); 137 if (string) 138 fputstr_unfiltered (string, '"', stream); 139 fprintf_unfiltered (stream, "\""); 140 } 141 142 void 143 mi_ui_out::do_field_fmt (int fldno, int width, ui_align align, 144 const char *fldname, const ui_file_style &style, 145 const char *format, va_list args) 146 { 147 ui_file *stream = m_streams.back (); 148 field_separator (); 149 150 if (fldname) 151 fprintf_unfiltered (stream, "%s=\"", fldname); 152 else 153 fputs_unfiltered ("\"", stream); 154 vfprintf_unfiltered (stream, format, args); 155 fputs_unfiltered ("\"", stream); 156 } 157 158 void 159 mi_ui_out::do_spaces (int numspaces) 160 { 161 } 162 163 void 164 mi_ui_out::do_text (const char *string) 165 { 166 } 167 168 void 169 mi_ui_out::do_message (const ui_file_style &style, 170 const char *format, va_list args) 171 { 172 } 173 174 void 175 mi_ui_out::do_wrap_hint (const char *identstring) 176 { 177 wrap_here (identstring); 178 } 179 180 void 181 mi_ui_out::do_flush () 182 { 183 184 gdb_flush (m_streams.back ()); 185 } 186 187 void 188 mi_ui_out::do_redirect (ui_file *outstream) 189 { 190 if (outstream != NULL) 191 m_streams.push_back (outstream); 192 else 193 m_streams.pop_back (); 194 } 195 196 void 197 mi_ui_out::field_separator () 198 { 199 if (m_suppress_field_separator) 200 m_suppress_field_separator = false; 201 else 202 fputc_unfiltered (',', m_streams.back ()); 203 } 204 205 void 206 mi_ui_out::open (const char *name, ui_out_type type) 207 { 208 ui_file *stream = m_streams.back (); 209 210 field_separator (); 211 m_suppress_field_separator = true; 212 213 if (name) 214 fprintf_unfiltered (stream, "%s=", name); 215 216 switch (type) 217 { 218 case ui_out_type_tuple: 219 fputc_unfiltered ('{', stream); 220 break; 221 222 case ui_out_type_list: 223 fputc_unfiltered ('[', stream); 224 break; 225 226 default: 227 internal_error (__FILE__, __LINE__, _("bad switch")); 228 } 229 } 230 231 void 232 mi_ui_out::close (ui_out_type type) 233 { 234 ui_file *stream = m_streams.back (); 235 236 switch (type) 237 { 238 case ui_out_type_tuple: 239 fputc_unfiltered ('}', stream); 240 break; 241 242 case ui_out_type_list: 243 fputc_unfiltered (']', stream); 244 break; 245 246 default: 247 internal_error (__FILE__, __LINE__, _("bad switch")); 248 } 249 250 m_suppress_field_separator = false; 251 } 252 253 string_file * 254 mi_ui_out::main_stream () 255 { 256 gdb_assert (m_streams.size () == 1); 257 258 return (string_file *) m_streams.back (); 259 } 260 261 /* Clear the buffer. */ 262 263 void 264 mi_ui_out::rewind () 265 { 266 main_stream ()->clear (); 267 } 268 269 /* Dump the buffer onto the specified stream. */ 270 271 void 272 mi_ui_out::put (ui_file *where) 273 { 274 string_file *mi_stream = main_stream (); 275 276 where->write (mi_stream->data (), mi_stream->size ()); 277 mi_stream->clear (); 278 } 279 280 /* Return the current MI version. */ 281 282 int 283 mi_ui_out::version () 284 { 285 return m_mi_version; 286 } 287 288 /* Constructor for an `mi_out_data' object. */ 289 290 mi_ui_out::mi_ui_out (int mi_version) 291 : ui_out (mi_version >= 3 292 ? fix_multi_location_breakpoint_output : (ui_out_flag) 0), 293 m_suppress_field_separator (false), 294 m_suppress_output (false), 295 m_mi_version (mi_version) 296 { 297 string_file *stream = new string_file (); 298 m_streams.push_back (stream); 299 } 300 301 mi_ui_out::~mi_ui_out () 302 { 303 } 304 305 /* See mi/mi-out.h. */ 306 307 mi_ui_out * 308 mi_out_new (const char *mi_version) 309 { 310 if (streq (mi_version, INTERP_MI3) || streq (mi_version, INTERP_MI)) 311 return new mi_ui_out (3); 312 313 if (streq (mi_version, INTERP_MI2)) 314 return new mi_ui_out (2); 315 316 if (streq (mi_version, INTERP_MI1)) 317 return new mi_ui_out (1); 318 319 return nullptr; 320 } 321 322 /* Helper function to return the given UIOUT as an mi_ui_out. It is an error 323 to call this function with an ui_out that is not an MI. */ 324 325 static mi_ui_out * 326 as_mi_ui_out (ui_out *uiout) 327 { 328 mi_ui_out *mi_uiout = dynamic_cast<mi_ui_out *> (uiout); 329 330 gdb_assert (mi_uiout != NULL); 331 332 return mi_uiout; 333 } 334 335 int 336 mi_version (ui_out *uiout) 337 { 338 return as_mi_ui_out (uiout)->version (); 339 } 340 341 void 342 mi_out_put (ui_out *uiout, struct ui_file *stream) 343 { 344 return as_mi_ui_out (uiout)->put (stream); 345 } 346 347 void 348 mi_out_rewind (ui_out *uiout) 349 { 350 return as_mi_ui_out (uiout)->rewind (); 351 } 352