1 /* Output generating routines for GDB. 2 3 Copyright (C) 1999-2019 Free Software Foundation, Inc. 4 5 Contributed by Cygnus Solutions. 6 Written by Fernando Nasser for Cygnus. 7 8 This file is part of GDB. 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 22 23 #include "defs.h" 24 #include "expression.h" /* For language.h */ 25 #include "language.h" 26 #include "ui-out.h" 27 28 #include <vector> 29 #include <memory> 30 #include <string> 31 32 namespace { 33 34 /* A header of a ui_out_table. */ 35 36 class ui_out_hdr 37 { 38 public: 39 40 explicit ui_out_hdr (int number, int min_width, ui_align alignment, 41 const std::string &name, const std::string &header) 42 : m_number (number), 43 m_min_width (min_width), 44 m_alignment (alignment), 45 m_name (name), 46 m_header (header) 47 { 48 } 49 50 int number () const 51 { 52 return m_number; 53 } 54 55 int min_width () const 56 { 57 return m_min_width; 58 } 59 60 ui_align alignment () const 61 { 62 return m_alignment; 63 } 64 65 const std::string &header () const 66 { 67 return m_header; 68 } 69 70 const std::string &name () const 71 { 72 return m_name; 73 } 74 75 private: 76 77 /* The number of the table column this header represents, 1-based. */ 78 int m_number; 79 80 /* Minimal column width in characters. May or may not be applicable, 81 depending on the actual implementation of ui_out. */ 82 int m_min_width; 83 84 /* Alignment of the content in the column. May or may not be applicable, 85 depending on the actual implementation of ui_out. */ 86 ui_align m_alignment; 87 88 /* Internal column name, used to internally refer to the column. */ 89 std::string m_name; 90 91 /* Printed header text of the column. */ 92 std::string m_header; 93 }; 94 95 } // namespace 96 97 /* A level of nesting (either a list or a tuple) in a ui_out output. */ 98 99 class ui_out_level 100 { 101 public: 102 103 explicit ui_out_level (ui_out_type type) 104 : m_type (type), 105 m_field_count (0) 106 { 107 } 108 109 ui_out_type type () const 110 { 111 return m_type; 112 } 113 114 int field_count () const 115 { 116 return m_field_count; 117 } 118 119 void inc_field_count () 120 { 121 m_field_count++; 122 } 123 124 private: 125 126 /* The type of this level. */ 127 ui_out_type m_type; 128 129 /* Count each field; the first element is for non-list fields. */ 130 int m_field_count; 131 }; 132 133 /* Tables are special. Maintain a separate structure that tracks 134 their state. At present an output can only contain a single table 135 but that restriction might eventually be lifted. */ 136 137 class ui_out_table 138 { 139 public: 140 141 /* States (steps) of a table generation. */ 142 143 enum class state 144 { 145 /* We are generating the table headers. */ 146 HEADERS, 147 148 /* We are generating the table body. */ 149 BODY, 150 }; 151 152 explicit ui_out_table (int entry_level, int nr_cols, const std::string &id) 153 : m_state (state::HEADERS), 154 m_entry_level (entry_level), 155 m_nr_cols (nr_cols), 156 m_id (id) 157 { 158 } 159 160 /* Start building the body of the table. */ 161 162 void start_body (); 163 164 /* Add a new header to the table. */ 165 166 void append_header (int width, ui_align alignment, 167 const std::string &col_name, const std::string &col_hdr); 168 169 void start_row (); 170 171 /* Extract the format information for the next header and advance 172 the header iterator. Return false if there was no next header. */ 173 174 bool get_next_header (int *colno, int *width, ui_align *alignment, 175 const char **col_hdr); 176 177 bool query_field (int colno, int *width, int *alignment, 178 const char **col_name) const; 179 180 state current_state () const; 181 182 int entry_level () const; 183 184 private: 185 186 state m_state; 187 188 /* The level at which each entry of the table is to be found. A row 189 (a tuple) is made up of entries. Consequently ENTRY_LEVEL is one 190 above that of the table. */ 191 int m_entry_level; 192 193 /* Number of table columns (as specified in the table_begin call). */ 194 int m_nr_cols; 195 196 /* String identifying the table (as specified in the table_begin 197 call). */ 198 std::string m_id; 199 200 /* Pointers to the column headers. */ 201 std::vector<std::unique_ptr<ui_out_hdr>> m_headers; 202 203 /* Iterator over the headers vector, used when printing successive fields. */ 204 std::vector<std::unique_ptr<ui_out_hdr>>::const_iterator m_headers_iterator; 205 }; 206 207 /* See ui-out.h. */ 208 209 void ui_out_table::start_body () 210 { 211 if (m_state != state::HEADERS) 212 internal_error (__FILE__, __LINE__, 213 _("extra table_body call not allowed; there must be only " 214 "one table_body after a table_begin and before a " 215 "table_end.")); 216 217 /* Check if the number of defined headers matches the number of expected 218 columns. */ 219 if (m_headers.size () != m_nr_cols) 220 internal_error (__FILE__, __LINE__, 221 _("number of headers differ from number of table " 222 "columns.")); 223 224 m_state = state::BODY; 225 m_headers_iterator = m_headers.begin (); 226 } 227 228 /* See ui-out.h. */ 229 230 void ui_out_table::append_header (int width, ui_align alignment, 231 const std::string &col_name, 232 const std::string &col_hdr) 233 { 234 if (m_state != state::HEADERS) 235 internal_error (__FILE__, __LINE__, 236 _("table header must be specified after table_begin and " 237 "before table_body.")); 238 239 std::unique_ptr<ui_out_hdr> header (new ui_out_hdr (m_headers.size () + 1, 240 width, alignment, 241 col_name, col_hdr)); 242 243 m_headers.push_back (std::move (header)); 244 } 245 246 /* See ui-out.h. */ 247 248 void ui_out_table::start_row () 249 { 250 m_headers_iterator = m_headers.begin (); 251 } 252 253 /* See ui-out.h. */ 254 255 bool ui_out_table::get_next_header (int *colno, int *width, ui_align *alignment, 256 const char **col_hdr) 257 { 258 /* There may be no headers at all or we may have used all columns. */ 259 if (m_headers_iterator == m_headers.end ()) 260 return false; 261 262 ui_out_hdr *hdr = m_headers_iterator->get (); 263 264 *colno = hdr->number (); 265 *width = hdr->min_width (); 266 *alignment = hdr->alignment (); 267 *col_hdr = hdr->header ().c_str (); 268 269 /* Advance the header pointer to the next entry. */ 270 m_headers_iterator++; 271 272 return true; 273 } 274 275 /* See ui-out.h. */ 276 277 bool ui_out_table::query_field (int colno, int *width, int *alignment, 278 const char **col_name) const 279 { 280 /* Column numbers are 1-based, so convert to 0-based index. */ 281 int index = colno - 1; 282 283 if (index >= 0 && index < m_headers.size ()) 284 { 285 ui_out_hdr *hdr = m_headers[index].get (); 286 287 gdb_assert (colno == hdr->number ()); 288 289 *width = hdr->min_width (); 290 *alignment = hdr->alignment (); 291 *col_name = hdr->name ().c_str (); 292 293 return true; 294 } 295 else 296 return false; 297 } 298 299 /* See ui-out.h. */ 300 301 ui_out_table::state ui_out_table::current_state () const 302 { 303 return m_state; 304 } 305 306 /* See ui-out.h. */ 307 308 int ui_out_table::entry_level () const 309 { 310 return m_entry_level; 311 } 312 313 int 314 ui_out::level () const 315 { 316 return m_levels.size (); 317 } 318 319 /* The current (inner most) level. */ 320 321 ui_out_level * 322 ui_out::current_level () const 323 { 324 return m_levels.back ().get (); 325 } 326 327 /* Create a new level, of TYPE. */ 328 void 329 ui_out::push_level (ui_out_type type) 330 { 331 std::unique_ptr<ui_out_level> level (new ui_out_level (type)); 332 333 m_levels.push_back (std::move (level)); 334 } 335 336 /* Discard the current level. TYPE is the type of the level being 337 discarded. */ 338 void 339 ui_out::pop_level (ui_out_type type) 340 { 341 /* We had better not underflow the buffer. */ 342 gdb_assert (m_levels.size () > 0); 343 gdb_assert (current_level ()->type () == type); 344 345 m_levels.pop_back (); 346 } 347 348 /* Mark beginning of a table. */ 349 350 void 351 ui_out::table_begin (int nr_cols, int nr_rows, const std::string &tblid) 352 { 353 if (m_table_up != nullptr) 354 internal_error (__FILE__, __LINE__, 355 _("tables cannot be nested; table_begin found before \ 356 previous table_end.")); 357 358 m_table_up.reset (new ui_out_table (level () + 1, nr_cols, tblid)); 359 360 do_table_begin (nr_cols, nr_rows, tblid.c_str ()); 361 } 362 363 void 364 ui_out::table_header (int width, ui_align alignment, 365 const std::string &col_name, const std::string &col_hdr) 366 { 367 if (m_table_up == nullptr) 368 internal_error (__FILE__, __LINE__, 369 _("table_header outside a table is not valid; it must be \ 370 after a table_begin and before a table_body.")); 371 372 m_table_up->append_header (width, alignment, col_name, col_hdr); 373 374 do_table_header (width, alignment, col_name, col_hdr); 375 } 376 377 void 378 ui_out::table_body () 379 { 380 if (m_table_up == nullptr) 381 internal_error (__FILE__, __LINE__, 382 _("table_body outside a table is not valid; it must be " 383 "after a table_begin and before a table_end.")); 384 385 m_table_up->start_body (); 386 387 do_table_body (); 388 } 389 390 void 391 ui_out::table_end () 392 { 393 if (m_table_up == nullptr) 394 internal_error (__FILE__, __LINE__, 395 _("misplaced table_end or missing table_begin.")); 396 397 do_table_end (); 398 399 m_table_up = nullptr; 400 } 401 402 void 403 ui_out::begin (ui_out_type type, const char *id) 404 { 405 /* Be careful to verify the ``field'' before the new tuple/list is 406 pushed onto the stack. That way the containing list/table/row is 407 verified and not the newly created tuple/list. This verification 408 is needed (at least) for the case where a table row entry 409 contains either a tuple/list. For that case bookkeeping such as 410 updating the column count or advancing to the next heading still 411 needs to be performed. */ 412 { 413 int fldno; 414 int width; 415 ui_align align; 416 417 verify_field (&fldno, &width, &align); 418 } 419 420 push_level (type); 421 422 /* If the push puts us at the same level as a table row entry, we've 423 got a new table row. Put the header pointer back to the start. */ 424 if (m_table_up != nullptr 425 && m_table_up->current_state () == ui_out_table::state::BODY 426 && m_table_up->entry_level () == level ()) 427 m_table_up->start_row (); 428 429 do_begin (type, id); 430 } 431 432 void 433 ui_out::end (ui_out_type type) 434 { 435 pop_level (type); 436 437 do_end (type); 438 } 439 440 void 441 ui_out::field_int (const char *fldname, int value) 442 { 443 int fldno; 444 int width; 445 ui_align align; 446 447 verify_field (&fldno, &width, &align); 448 449 do_field_int (fldno, width, align, fldname, value); 450 } 451 452 void 453 ui_out::field_fmt_int (int input_width, ui_align input_align, 454 const char *fldname, int value) 455 { 456 int fldno; 457 int width; 458 ui_align align; 459 460 verify_field (&fldno, &width, &align); 461 462 do_field_int (fldno, input_width, input_align, fldname, value); 463 } 464 465 /* Documented in ui-out.h. */ 466 467 void 468 ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch, 469 CORE_ADDR address) 470 { 471 field_string (fldname, print_core_address (gdbarch, address), 472 ui_out_style_kind::ADDRESS); 473 } 474 475 void 476 ui_out::field_stream (const char *fldname, string_file &stream, 477 ui_out_style_kind style) 478 { 479 if (!stream.empty ()) 480 field_string (fldname, stream.c_str (), style); 481 else 482 field_skip (fldname); 483 stream.clear (); 484 } 485 486 /* Used to omit a field. */ 487 488 void 489 ui_out::field_skip (const char *fldname) 490 { 491 int fldno; 492 int width; 493 ui_align align; 494 495 verify_field (&fldno, &width, &align); 496 497 do_field_skip (fldno, width, align, fldname); 498 } 499 500 void 501 ui_out::field_string (const char *fldname, const char *string, 502 ui_out_style_kind style) 503 { 504 int fldno; 505 int width; 506 ui_align align; 507 508 verify_field (&fldno, &width, &align); 509 510 do_field_string (fldno, width, align, fldname, string, style); 511 } 512 513 void 514 ui_out::field_string (const char *fldname, const std::string &string) 515 { 516 field_string (fldname, string.c_str ()); 517 } 518 519 /* VARARGS */ 520 void 521 ui_out::field_fmt (const char *fldname, const char *format, ...) 522 { 523 va_list args; 524 int fldno; 525 int width; 526 ui_align align; 527 528 verify_field (&fldno, &width, &align); 529 530 va_start (args, format); 531 532 do_field_fmt (fldno, width, align, fldname, format, args); 533 534 va_end (args); 535 } 536 537 void 538 ui_out::spaces (int numspaces) 539 { 540 do_spaces (numspaces); 541 } 542 543 void 544 ui_out::text (const char *string) 545 { 546 do_text (string); 547 } 548 549 void 550 ui_out::message (const char *format, ...) 551 { 552 va_list args; 553 554 va_start (args, format); 555 do_message (format, args); 556 va_end (args); 557 } 558 559 void 560 ui_out::wrap_hint (const char *identstring) 561 { 562 do_wrap_hint (identstring); 563 } 564 565 void 566 ui_out::flush () 567 { 568 do_flush (); 569 } 570 571 void 572 ui_out::redirect (ui_file *outstream) 573 { 574 do_redirect (outstream); 575 } 576 577 /* Test the flags against the mask given. */ 578 ui_out_flags 579 ui_out::test_flags (ui_out_flags mask) 580 { 581 return m_flags & mask; 582 } 583 584 bool 585 ui_out::is_mi_like_p () const 586 { 587 return do_is_mi_like_p (); 588 } 589 590 /* Verify that the field/tuple/list is correctly positioned. Return 591 the field number and corresponding alignment (if 592 available/applicable). */ 593 594 void 595 ui_out::verify_field (int *fldno, int *width, ui_align *align) 596 { 597 ui_out_level *current = current_level (); 598 const char *text; 599 600 if (m_table_up != nullptr 601 && m_table_up->current_state () != ui_out_table::state::BODY) 602 { 603 internal_error (__FILE__, __LINE__, 604 _("table_body missing; table fields must be \ 605 specified after table_body and inside a list.")); 606 } 607 608 current->inc_field_count (); 609 610 if (m_table_up != nullptr 611 && m_table_up->current_state () == ui_out_table::state::BODY 612 && m_table_up->entry_level () == level () 613 && m_table_up->get_next_header (fldno, width, align, &text)) 614 { 615 if (*fldno != current->field_count ()) 616 internal_error (__FILE__, __LINE__, 617 _("ui-out internal error in handling headers.")); 618 } 619 else 620 { 621 *width = 0; 622 *align = ui_noalign; 623 *fldno = current->field_count (); 624 } 625 } 626 627 /* Access table field parameters. */ 628 629 bool 630 ui_out::query_table_field (int colno, int *width, int *alignment, 631 const char **col_name) 632 { 633 if (m_table_up == nullptr) 634 return false; 635 636 return m_table_up->query_field (colno, width, alignment, col_name); 637 } 638 639 /* The constructor. */ 640 641 ui_out::ui_out (ui_out_flags flags) 642 : m_flags (flags) 643 { 644 /* Create the ui-out level #1, the default level. */ 645 push_level (ui_out_type_tuple); 646 } 647 648 ui_out::~ui_out () 649 { 650 } 651