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