Commit | Line | Data |
---|---|---|
8b93c638 | 1 | /* Output generating routines for GDB. |
349c5d5f | 2 | |
42a4f53d | 3 | Copyright (C) 1999-2019 Free Software Foundation, Inc. |
349c5d5f | 4 | |
8b93c638 JM |
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 | |
a9762ec7 | 12 | the Free Software Foundation; either version 3 of the License, or |
8b93c638 JM |
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 | |
a9762ec7 | 21 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
8b93c638 JM |
22 | |
23 | #include "defs.h" | |
8b93c638 JM |
24 | #include "expression.h" /* For language.h */ |
25 | #include "language.h" | |
26 | #include "ui-out.h" | |
e43b10e1 TT |
27 | #include "gdbsupport/format.h" |
28 | #include "cli/cli-style.h" | |
284782de | 29 | #include "diagnostics.h" |
8b93c638 | 30 | |
56df3084 SM |
31 | #include <vector> |
32 | #include <memory> | |
95a23284 | 33 | #include <string> |
56df3084 | 34 | |
ffdbe864 YQ |
35 | namespace { |
36 | ||
37e20dd6 | 37 | /* A header of a ui_out_table. */ |
8b93c638 | 38 | |
37e20dd6 SM |
39 | class ui_out_hdr |
40 | { | |
41 | public: | |
42 | ||
43 | explicit ui_out_hdr (int number, int min_width, ui_align alignment, | |
44 | const std::string &name, const std::string &header) | |
45 | : m_number (number), | |
46 | m_min_width (min_width), | |
47 | m_alignment (alignment), | |
48 | m_name (name), | |
49 | m_header (header) | |
8b93c638 | 50 | { |
37e20dd6 SM |
51 | } |
52 | ||
53 | int number () const | |
54 | { | |
55 | return m_number; | |
56 | } | |
57 | ||
58 | int min_width () const | |
59 | { | |
60 | return m_min_width; | |
61 | } | |
62 | ||
63 | ui_align alignment () const | |
64 | { | |
65 | return m_alignment; | |
66 | } | |
67 | ||
68 | const std::string &header () const | |
69 | { | |
70 | return m_header; | |
71 | } | |
72 | ||
73 | const std::string &name () const | |
74 | { | |
75 | return m_name; | |
76 | } | |
77 | ||
78 | private: | |
79 | ||
80 | /* The number of the table column this header represents, 1-based. */ | |
81 | int m_number; | |
82 | ||
83 | /* Minimal column width in characters. May or may not be applicable, | |
84 | depending on the actual implementation of ui_out. */ | |
85 | int m_min_width; | |
86 | ||
87 | /* Alignment of the content in the column. May or may not be applicable, | |
88 | depending on the actual implementation of ui_out. */ | |
89 | ui_align m_alignment; | |
90 | ||
91 | /* Internal column name, used to internally refer to the column. */ | |
92 | std::string m_name; | |
93 | ||
94 | /* Printed header text of the column. */ | |
95 | std::string m_header; | |
96 | }; | |
8b93c638 | 97 | |
ffdbe864 YQ |
98 | } // namespace |
99 | ||
909c0aa5 SM |
100 | /* A level of nesting (either a list or a tuple) in a ui_out output. */ |
101 | ||
102 | class ui_out_level | |
103 | { | |
104 | public: | |
105 | ||
106 | explicit ui_out_level (ui_out_type type) | |
107 | : m_type (type), | |
108 | m_field_count (0) | |
80f49b30 | 109 | { |
909c0aa5 SM |
110 | } |
111 | ||
112 | ui_out_type type () const | |
113 | { | |
114 | return m_type; | |
115 | } | |
116 | ||
117 | int field_count () const | |
118 | { | |
119 | return m_field_count; | |
120 | } | |
121 | ||
122 | void inc_field_count () | |
123 | { | |
124 | m_field_count++; | |
125 | } | |
126 | ||
127 | private: | |
128 | ||
129 | /* The type of this level. */ | |
130 | ui_out_type m_type; | |
131 | ||
132 | /* Count each field; the first element is for non-list fields. */ | |
133 | int m_field_count; | |
134 | }; | |
80f49b30 | 135 | |
bafdd3b3 AC |
136 | /* Tables are special. Maintain a separate structure that tracks |
137 | their state. At present an output can only contain a single table | |
138 | but that restriction might eventually be lifted. */ | |
139 | ||
36d18bc5 | 140 | class ui_out_table |
bafdd3b3 | 141 | { |
36d18bc5 SM |
142 | public: |
143 | ||
144 | /* States (steps) of a table generation. */ | |
145 | ||
146 | enum class state | |
147 | { | |
148 | /* We are generating the table headers. */ | |
149 | HEADERS, | |
150 | ||
151 | /* We are generating the table body. */ | |
152 | BODY, | |
153 | }; | |
154 | ||
155 | explicit ui_out_table (int entry_level, int nr_cols, const std::string &id) | |
156 | : m_state (state::HEADERS), | |
157 | m_entry_level (entry_level), | |
158 | m_nr_cols (nr_cols), | |
159 | m_id (id) | |
160 | { | |
161 | } | |
162 | ||
163 | /* Start building the body of the table. */ | |
164 | ||
165 | void start_body (); | |
166 | ||
167 | /* Add a new header to the table. */ | |
168 | ||
169 | void append_header (int width, ui_align alignment, | |
170 | const std::string &col_name, const std::string &col_hdr); | |
bafdd3b3 | 171 | |
36d18bc5 SM |
172 | void start_row (); |
173 | ||
174 | /* Extract the format information for the next header and advance | |
175 | the header iterator. Return false if there was no next header. */ | |
176 | ||
177 | bool get_next_header (int *colno, int *width, ui_align *alignment, | |
178 | const char **col_hdr); | |
179 | ||
180 | bool query_field (int colno, int *width, int *alignment, | |
181 | const char **col_name) const; | |
182 | ||
183 | state current_state () const; | |
184 | ||
185 | int entry_level () const; | |
186 | ||
187 | private: | |
188 | ||
189 | state m_state; | |
bafdd3b3 | 190 | |
a6c47c14 AC |
191 | /* The level at which each entry of the table is to be found. A row |
192 | (a tuple) is made up of entries. Consequently ENTRY_LEVEL is one | |
193 | above that of the table. */ | |
36d18bc5 | 194 | int m_entry_level; |
a6c47c14 | 195 | |
bafdd3b3 | 196 | /* Number of table columns (as specified in the table_begin call). */ |
36d18bc5 | 197 | int m_nr_cols; |
bafdd3b3 AC |
198 | |
199 | /* String identifying the table (as specified in the table_begin | |
200 | call). */ | |
36d18bc5 | 201 | std::string m_id; |
bafdd3b3 | 202 | |
78afa7f8 | 203 | /* Pointers to the column headers. */ |
36d18bc5 | 204 | std::vector<std::unique_ptr<ui_out_hdr>> m_headers; |
bafdd3b3 | 205 | |
78afa7f8 | 206 | /* Iterator over the headers vector, used when printing successive fields. */ |
36d18bc5 | 207 | std::vector<std::unique_ptr<ui_out_hdr>>::const_iterator m_headers_iterator; |
bafdd3b3 AC |
208 | }; |
209 | ||
36d18bc5 SM |
210 | /* See ui-out.h. */ |
211 | ||
212 | void ui_out_table::start_body () | |
213 | { | |
214 | if (m_state != state::HEADERS) | |
215 | internal_error (__FILE__, __LINE__, | |
216 | _("extra table_body call not allowed; there must be only " | |
217 | "one table_body after a table_begin and before a " | |
218 | "table_end.")); | |
219 | ||
220 | /* Check if the number of defined headers matches the number of expected | |
221 | columns. */ | |
222 | if (m_headers.size () != m_nr_cols) | |
223 | internal_error (__FILE__, __LINE__, | |
224 | _("number of headers differ from number of table " | |
225 | "columns.")); | |
226 | ||
227 | m_state = state::BODY; | |
228 | m_headers_iterator = m_headers.begin (); | |
229 | } | |
230 | ||
231 | /* See ui-out.h. */ | |
232 | ||
233 | void ui_out_table::append_header (int width, ui_align alignment, | |
234 | const std::string &col_name, | |
235 | const std::string &col_hdr) | |
236 | { | |
237 | if (m_state != state::HEADERS) | |
238 | internal_error (__FILE__, __LINE__, | |
239 | _("table header must be specified after table_begin and " | |
240 | "before table_body.")); | |
241 | ||
242 | std::unique_ptr<ui_out_hdr> header (new ui_out_hdr (m_headers.size () + 1, | |
243 | width, alignment, | |
244 | col_name, col_hdr)); | |
245 | ||
246 | m_headers.push_back (std::move (header)); | |
247 | } | |
248 | ||
249 | /* See ui-out.h. */ | |
250 | ||
251 | void ui_out_table::start_row () | |
252 | { | |
253 | m_headers_iterator = m_headers.begin (); | |
254 | } | |
255 | ||
256 | /* See ui-out.h. */ | |
257 | ||
258 | bool ui_out_table::get_next_header (int *colno, int *width, ui_align *alignment, | |
259 | const char **col_hdr) | |
260 | { | |
261 | /* There may be no headers at all or we may have used all columns. */ | |
262 | if (m_headers_iterator == m_headers.end ()) | |
263 | return false; | |
264 | ||
265 | ui_out_hdr *hdr = m_headers_iterator->get (); | |
266 | ||
267 | *colno = hdr->number (); | |
268 | *width = hdr->min_width (); | |
269 | *alignment = hdr->alignment (); | |
270 | *col_hdr = hdr->header ().c_str (); | |
271 | ||
272 | /* Advance the header pointer to the next entry. */ | |
273 | m_headers_iterator++; | |
274 | ||
275 | return true; | |
276 | } | |
277 | ||
278 | /* See ui-out.h. */ | |
279 | ||
280 | bool ui_out_table::query_field (int colno, int *width, int *alignment, | |
281 | const char **col_name) const | |
282 | { | |
283 | /* Column numbers are 1-based, so convert to 0-based index. */ | |
284 | int index = colno - 1; | |
285 | ||
286 | if (index >= 0 && index < m_headers.size ()) | |
287 | { | |
288 | ui_out_hdr *hdr = m_headers[index].get (); | |
289 | ||
290 | gdb_assert (colno == hdr->number ()); | |
291 | ||
292 | *width = hdr->min_width (); | |
293 | *alignment = hdr->alignment (); | |
294 | *col_name = hdr->name ().c_str (); | |
295 | ||
296 | return true; | |
297 | } | |
298 | else | |
299 | return false; | |
300 | } | |
301 | ||
302 | /* See ui-out.h. */ | |
303 | ||
304 | ui_out_table::state ui_out_table::current_state () const | |
305 | { | |
306 | return m_state; | |
307 | } | |
308 | ||
309 | /* See ui-out.h. */ | |
310 | ||
311 | int ui_out_table::entry_level () const | |
312 | { | |
313 | return m_entry_level; | |
314 | } | |
bafdd3b3 | 315 | |
112e8700 SM |
316 | int |
317 | ui_out::level () const | |
318 | { | |
319 | return m_levels.size (); | |
320 | } | |
8b93c638 | 321 | |
581e13c1 | 322 | /* The current (inner most) level. */ |
112e8700 SM |
323 | |
324 | ui_out_level * | |
325 | ui_out::current_level () const | |
80f49b30 | 326 | { |
112e8700 | 327 | return m_levels.back ().get (); |
80f49b30 AC |
328 | } |
329 | ||
33b2fac6 | 330 | /* Create a new level, of TYPE. */ |
112e8700 SM |
331 | void |
332 | ui_out::push_level (ui_out_type type) | |
80f49b30 | 333 | { |
909c0aa5 | 334 | std::unique_ptr<ui_out_level> level (new ui_out_level (type)); |
56df3084 | 335 | |
112e8700 | 336 | m_levels.push_back (std::move (level)); |
80f49b30 AC |
337 | } |
338 | ||
33b2fac6 SM |
339 | /* Discard the current level. TYPE is the type of the level being |
340 | discarded. */ | |
112e8700 SM |
341 | void |
342 | ui_out::pop_level (ui_out_type type) | |
80f49b30 | 343 | { |
581e13c1 | 344 | /* We had better not underflow the buffer. */ |
112e8700 SM |
345 | gdb_assert (m_levels.size () > 0); |
346 | gdb_assert (current_level ()->type () == type); | |
347 | ||
348 | m_levels.pop_back (); | |
349 | } | |
8b93c638 | 350 | |
581e13c1 | 351 | /* Mark beginning of a table. */ |
8b93c638 | 352 | |
112e8700 SM |
353 | void |
354 | ui_out::table_begin (int nr_cols, int nr_rows, const std::string &tblid) | |
8b93c638 | 355 | { |
112e8700 | 356 | if (m_table_up != nullptr) |
8e65ff28 | 357 | internal_error (__FILE__, __LINE__, |
e2e0b3e5 AC |
358 | _("tables cannot be nested; table_begin found before \ |
359 | previous table_end.")); | |
8b93c638 | 360 | |
112e8700 | 361 | m_table_up.reset (new ui_out_table (level () + 1, nr_cols, tblid)); |
95a23284 | 362 | |
112e8700 | 363 | do_table_begin (nr_cols, nr_rows, tblid.c_str ()); |
8b93c638 JM |
364 | } |
365 | ||
366 | void | |
112e8700 SM |
367 | ui_out::table_header (int width, ui_align alignment, |
368 | const std::string &col_name, const std::string &col_hdr) | |
8b93c638 | 369 | { |
112e8700 | 370 | if (m_table_up == nullptr) |
8e65ff28 | 371 | internal_error (__FILE__, __LINE__, |
112e8700 SM |
372 | _("table_header outside a table is not valid; it must be \ |
373 | after a table_begin and before a table_body.")); | |
77a179e7 | 374 | |
112e8700 | 375 | m_table_up->append_header (width, alignment, col_name, col_hdr); |
8b93c638 | 376 | |
112e8700 | 377 | do_table_header (width, alignment, col_name, col_hdr); |
8b93c638 JM |
378 | } |
379 | ||
112e8700 SM |
380 | void |
381 | ui_out::table_body () | |
8b93c638 | 382 | { |
112e8700 | 383 | if (m_table_up == nullptr) |
8e65ff28 | 384 | internal_error (__FILE__, __LINE__, |
112e8700 SM |
385 | _("table_body outside a table is not valid; it must be " |
386 | "after a table_begin and before a table_end.")); | |
8b93c638 | 387 | |
112e8700 | 388 | m_table_up->start_body (); |
36d18bc5 | 389 | |
112e8700 | 390 | do_table_body (); |
8b93c638 JM |
391 | } |
392 | ||
393 | void | |
112e8700 | 394 | ui_out::table_end () |
8b93c638 | 395 | { |
112e8700 | 396 | if (m_table_up == nullptr) |
8e65ff28 | 397 | internal_error (__FILE__, __LINE__, |
112e8700 | 398 | _("misplaced table_end or missing table_begin.")); |
8b93c638 | 399 | |
112e8700 | 400 | do_table_end (); |
8b93c638 | 401 | |
112e8700 | 402 | m_table_up = nullptr; |
8b93c638 JM |
403 | } |
404 | ||
405 | void | |
112e8700 | 406 | ui_out::begin (ui_out_type type, const char *id) |
8b93c638 | 407 | { |
a6c47c14 AC |
408 | /* Be careful to verify the ``field'' before the new tuple/list is |
409 | pushed onto the stack. That way the containing list/table/row is | |
410 | verified and not the newly created tuple/list. This verification | |
411 | is needed (at least) for the case where a table row entry | |
412 | contains either a tuple/list. For that case bookkeeping such as | |
413 | updating the column count or advancing to the next heading still | |
414 | needs to be performed. */ | |
415 | { | |
416 | int fldno; | |
417 | int width; | |
112e8700 | 418 | ui_align align; |
5d502164 | 419 | |
112e8700 | 420 | verify_field (&fldno, &width, &align); |
a6c47c14 AC |
421 | } |
422 | ||
112e8700 | 423 | push_level (type); |
a6c47c14 AC |
424 | |
425 | /* If the push puts us at the same level as a table row entry, we've | |
426 | got a new table row. Put the header pointer back to the start. */ | |
112e8700 SM |
427 | if (m_table_up != nullptr |
428 | && m_table_up->current_state () == ui_out_table::state::BODY | |
429 | && m_table_up->entry_level () == level ()) | |
430 | m_table_up->start_row (); | |
a6c47c14 | 431 | |
112e8700 | 432 | do_begin (type, id); |
631ec795 AC |
433 | } |
434 | ||
631ec795 | 435 | void |
112e8700 | 436 | ui_out::end (ui_out_type type) |
631ec795 | 437 | { |
112e8700 | 438 | pop_level (type); |
5d502164 | 439 | |
112e8700 | 440 | do_end (type); |
8b93c638 JM |
441 | } |
442 | ||
8b93c638 | 443 | void |
381befee | 444 | ui_out::field_signed (const char *fldname, LONGEST value) |
8b93c638 JM |
445 | { |
446 | int fldno; | |
447 | int width; | |
112e8700 | 448 | ui_align align; |
8b93c638 | 449 | |
112e8700 | 450 | verify_field (&fldno, &width, &align); |
8b93c638 | 451 | |
381befee | 452 | do_field_signed (fldno, width, align, fldname, value); |
8b93c638 JM |
453 | } |
454 | ||
52c6a6ac | 455 | void |
381befee TT |
456 | ui_out::field_fmt_signed (int input_width, ui_align input_align, |
457 | const char *fldname, LONGEST value) | |
52c6a6ac JJ |
458 | { |
459 | int fldno; | |
460 | int width; | |
112e8700 | 461 | ui_align align; |
52c6a6ac | 462 | |
112e8700 | 463 | verify_field (&fldno, &width, &align); |
52c6a6ac | 464 | |
381befee | 465 | do_field_signed (fldno, input_width, input_align, fldname, value); |
52c6a6ac JJ |
466 | } |
467 | ||
1f77b012 TT |
468 | /* See ui-out.h. */ |
469 | ||
470 | void | |
471 | ui_out::field_unsigned (const char *fldname, ULONGEST value) | |
472 | { | |
473 | int fldno; | |
474 | int width; | |
475 | ui_align align; | |
476 | ||
477 | verify_field (&fldno, &width, &align); | |
478 | ||
479 | do_field_unsigned (fldno, width, align, fldname, value); | |
480 | } | |
481 | ||
15230f37 TJB |
482 | /* Documented in ui-out.h. */ |
483 | ||
8b93c638 | 484 | void |
112e8700 SM |
485 | ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch, |
486 | CORE_ADDR address) | |
8b93c638 | 487 | { |
35fb8261 | 488 | field_string (fldname, print_core_address (gdbarch, address), |
e43b10e1 | 489 | address_style.style ()); |
8b93c638 JM |
490 | } |
491 | ||
492 | void | |
cbe56571 | 493 | ui_out::field_stream (const char *fldname, string_file &stream, |
e43b10e1 | 494 | const ui_file_style &style) |
8b93c638 | 495 | { |
d7e74731 | 496 | if (!stream.empty ()) |
cbe56571 | 497 | field_string (fldname, stream.c_str (), style); |
8b93c638 | 498 | else |
112e8700 | 499 | field_skip (fldname); |
d7e74731 | 500 | stream.clear (); |
8b93c638 JM |
501 | } |
502 | ||
581e13c1 | 503 | /* Used to omit a field. */ |
8b93c638 JM |
504 | |
505 | void | |
112e8700 | 506 | ui_out::field_skip (const char *fldname) |
8b93c638 JM |
507 | { |
508 | int fldno; | |
509 | int width; | |
112e8700 | 510 | ui_align align; |
8b93c638 | 511 | |
112e8700 | 512 | verify_field (&fldno, &width, &align); |
8b93c638 | 513 | |
112e8700 | 514 | do_field_skip (fldno, width, align, fldname); |
8b93c638 JM |
515 | } |
516 | ||
517 | void | |
cbe56571 | 518 | ui_out::field_string (const char *fldname, const char *string, |
e43b10e1 | 519 | const ui_file_style &style) |
8b93c638 JM |
520 | { |
521 | int fldno; | |
522 | int width; | |
112e8700 | 523 | ui_align align; |
8b93c638 | 524 | |
112e8700 | 525 | verify_field (&fldno, &width, &align); |
8b93c638 | 526 | |
cbe56571 | 527 | do_field_string (fldno, width, align, fldname, string, style); |
8b93c638 JM |
528 | } |
529 | ||
6fb16ce6 SM |
530 | void |
531 | ui_out::field_string (const char *fldname, const std::string &string) | |
532 | { | |
533 | field_string (fldname, string.c_str ()); | |
534 | } | |
535 | ||
8b93c638 JM |
536 | /* VARARGS */ |
537 | void | |
112e8700 | 538 | ui_out::field_fmt (const char *fldname, const char *format, ...) |
8b93c638 JM |
539 | { |
540 | va_list args; | |
541 | int fldno; | |
542 | int width; | |
112e8700 | 543 | ui_align align; |
8b93c638 | 544 | |
112e8700 | 545 | verify_field (&fldno, &width, &align); |
8b93c638 JM |
546 | |
547 | va_start (args, format); | |
548 | ||
7f6aba03 TT |
549 | do_field_fmt (fldno, width, align, fldname, ui_file_style (), format, args); |
550 | ||
551 | va_end (args); | |
552 | } | |
553 | ||
554 | void | |
555 | ui_out::field_fmt (const char *fldname, const ui_file_style &style, | |
556 | const char *format, ...) | |
557 | { | |
558 | va_list args; | |
559 | int fldno; | |
560 | int width; | |
561 | ui_align align; | |
562 | ||
563 | verify_field (&fldno, &width, &align); | |
564 | ||
565 | va_start (args, format); | |
566 | ||
567 | do_field_fmt (fldno, width, align, fldname, style, format, args); | |
8b93c638 JM |
568 | |
569 | va_end (args); | |
570 | } | |
571 | ||
572 | void | |
112e8700 | 573 | ui_out::spaces (int numspaces) |
8b93c638 | 574 | { |
112e8700 | 575 | do_spaces (numspaces); |
8b93c638 JM |
576 | } |
577 | ||
578 | void | |
112e8700 | 579 | ui_out::text (const char *string) |
8b93c638 | 580 | { |
112e8700 | 581 | do_text (string); |
8b93c638 JM |
582 | } |
583 | ||
584 | void | |
2a3c1174 PA |
585 | ui_out::call_do_message (const ui_file_style &style, const char *format, |
586 | ...) | |
8b93c638 JM |
587 | { |
588 | va_list args; | |
589 | ||
590 | va_start (args, format); | |
284782de SM |
591 | |
592 | /* Since call_do_message is only used as a helper of vmessage, silence the | |
593 | warning here once instead of at all call sites in vmessage, if we were | |
594 | to put a "format" attribute on call_do_message. */ | |
595 | DIAGNOSTIC_PUSH | |
596 | DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL | |
2a3c1174 | 597 | do_message (style, format, args); |
284782de SM |
598 | DIAGNOSTIC_POP |
599 | ||
2a3c1174 PA |
600 | va_end (args); |
601 | } | |
602 | ||
603 | void | |
604 | ui_out::vmessage (const ui_file_style &in_style, const char *format, | |
605 | va_list args) | |
606 | { | |
607 | format_pieces fpieces (&format, true); | |
608 | ||
609 | ui_file_style style = in_style; | |
610 | ||
611 | for (auto &&piece : fpieces) | |
612 | { | |
613 | const char *current_substring = piece.string; | |
614 | ||
615 | gdb_assert (piece.n_int_args >= 0 && piece.n_int_args <= 2); | |
616 | int intvals[2] = { 0, 0 }; | |
617 | for (int i = 0; i < piece.n_int_args; ++i) | |
618 | intvals[i] = va_arg (args, int); | |
619 | ||
620 | /* The only ones we support for now. */ | |
621 | gdb_assert (piece.n_int_args == 0 | |
622 | || piece.argclass == string_arg | |
623 | || piece.argclass == int_arg | |
624 | || piece.argclass == long_arg); | |
625 | ||
626 | switch (piece.argclass) | |
627 | { | |
628 | case string_arg: | |
629 | { | |
630 | const char *str = va_arg (args, const char *); | |
631 | switch (piece.n_int_args) | |
632 | { | |
633 | case 0: | |
634 | call_do_message (style, current_substring, str); | |
635 | break; | |
636 | case 1: | |
637 | call_do_message (style, current_substring, intvals[0], str); | |
638 | break; | |
639 | case 2: | |
640 | call_do_message (style, current_substring, | |
641 | intvals[0], intvals[1], str); | |
642 | break; | |
643 | } | |
644 | } | |
645 | break; | |
646 | case wide_string_arg: | |
647 | gdb_assert_not_reached (_("wide_string_arg not supported in vmessage")); | |
648 | break; | |
649 | case wide_char_arg: | |
650 | gdb_assert_not_reached (_("wide_char_arg not supported in vmessage")); | |
651 | break; | |
652 | case long_long_arg: | |
653 | call_do_message (style, current_substring, va_arg (args, long long)); | |
654 | break; | |
655 | case int_arg: | |
656 | { | |
657 | int val = va_arg (args, int); | |
658 | switch (piece.n_int_args) | |
659 | { | |
660 | case 0: | |
661 | call_do_message (style, current_substring, val); | |
662 | break; | |
663 | case 1: | |
664 | call_do_message (style, current_substring, intvals[0], val); | |
665 | break; | |
666 | case 2: | |
667 | call_do_message (style, current_substring, | |
668 | intvals[0], intvals[1], val); | |
669 | break; | |
670 | } | |
671 | } | |
672 | break; | |
673 | case long_arg: | |
674 | { | |
675 | long val = va_arg (args, long); | |
676 | switch (piece.n_int_args) | |
677 | { | |
678 | case 0: | |
679 | call_do_message (style, current_substring, val); | |
680 | break; | |
681 | case 1: | |
682 | call_do_message (style, current_substring, intvals[0], val); | |
683 | break; | |
684 | case 2: | |
685 | call_do_message (style, current_substring, | |
686 | intvals[0], intvals[1], val); | |
687 | break; | |
688 | } | |
689 | } | |
690 | break; | |
e06f3d6e AB |
691 | case size_t_arg: |
692 | { | |
693 | size_t val = va_arg (args, size_t); | |
694 | switch (piece.n_int_args) | |
695 | { | |
696 | case 0: | |
697 | call_do_message (style, current_substring, val); | |
698 | break; | |
699 | case 1: | |
700 | call_do_message (style, current_substring, intvals[0], val); | |
701 | break; | |
702 | case 2: | |
703 | call_do_message (style, current_substring, | |
704 | intvals[0], intvals[1], val); | |
705 | break; | |
706 | } | |
707 | } | |
708 | break; | |
2a3c1174 PA |
709 | case double_arg: |
710 | call_do_message (style, current_substring, va_arg (args, double)); | |
711 | break; | |
712 | case long_double_arg: | |
713 | gdb_assert_not_reached (_("long_double_arg not supported in vmessage")); | |
714 | break; | |
715 | case dec32float_arg: | |
716 | gdb_assert_not_reached (_("dec32float_arg not supported in vmessage")); | |
717 | break; | |
718 | case dec64float_arg: | |
719 | gdb_assert_not_reached (_("dec64float_arg not supported in vmessage")); | |
720 | break; | |
721 | case dec128float_arg: | |
722 | gdb_assert_not_reached (_("dec128float_arg not supported in vmessage")); | |
723 | break; | |
724 | case ptr_arg: | |
725 | switch (current_substring[2]) | |
726 | { | |
727 | case 'F': | |
728 | { | |
729 | gdb_assert (!test_flags (disallow_ui_out_field)); | |
730 | base_field_s *bf = va_arg (args, base_field_s *); | |
731 | switch (bf->kind) | |
732 | { | |
28ce7b07 | 733 | case field_kind::FIELD_SIGNED: |
2a3c1174 PA |
734 | { |
735 | auto *f = (signed_field_s *) bf; | |
736 | field_signed (f->name, f->val); | |
737 | } | |
738 | break; | |
28ce7b07 | 739 | case field_kind::FIELD_STRING: |
2a3c1174 PA |
740 | { |
741 | auto *f = (string_field_s *) bf; | |
742 | field_string (f->name, f->str); | |
743 | } | |
744 | break; | |
745 | } | |
746 | } | |
747 | break; | |
748 | case 's': | |
749 | { | |
750 | styled_string_s *ss = va_arg (args, styled_string_s *); | |
751 | call_do_message (ss->style, "%s", ss->str); | |
752 | } | |
753 | break; | |
754 | case '[': | |
755 | style = *va_arg (args, const ui_file_style *); | |
756 | break; | |
757 | case ']': | |
758 | { | |
759 | void *arg = va_arg (args, void *); | |
760 | gdb_assert (arg == nullptr); | |
761 | ||
762 | style = {}; | |
763 | } | |
764 | break; | |
765 | default: | |
766 | call_do_message (style, current_substring, va_arg (args, void *)); | |
767 | break; | |
768 | } | |
769 | break; | |
770 | case literal_piece: | |
771 | /* Print a portion of the format string that has no | |
772 | directives. Note that this will not include any ordinary | |
773 | %-specs, but it might include "%%". That is why we use | |
774 | call_do_message here. Also, we pass a dummy argument | |
775 | because some platforms have modified GCC to include | |
776 | -Wformat-security by default, which will warn here if | |
777 | there is no argument. */ | |
778 | call_do_message (style, current_substring, 0); | |
779 | break; | |
780 | default: | |
781 | internal_error (__FILE__, __LINE__, | |
782 | _("failed internal consistency check")); | |
783 | } | |
784 | } | |
785 | } | |
786 | ||
787 | void | |
788 | ui_out::message (const char *format, ...) | |
789 | { | |
790 | va_list args; | |
791 | va_start (args, format); | |
792 | ||
793 | vmessage (ui_file_style (), format, args); | |
794 | ||
8b93c638 JM |
795 | va_end (args); |
796 | } | |
797 | ||
8b93c638 | 798 | void |
112e8700 | 799 | ui_out::wrap_hint (const char *identstring) |
8b93c638 | 800 | { |
112e8700 | 801 | do_wrap_hint (identstring); |
8b93c638 JM |
802 | } |
803 | ||
804 | void | |
112e8700 | 805 | ui_out::flush () |
8b93c638 | 806 | { |
112e8700 | 807 | do_flush (); |
8b93c638 JM |
808 | } |
809 | ||
7becfd03 | 810 | void |
112e8700 | 811 | ui_out::redirect (ui_file *outstream) |
0fac0b41 | 812 | { |
7becfd03 | 813 | do_redirect (outstream); |
0fac0b41 DJ |
814 | } |
815 | ||
581e13c1 | 816 | /* Test the flags against the mask given. */ |
112e8700 SM |
817 | ui_out_flags |
818 | ui_out::test_flags (ui_out_flags mask) | |
8b93c638 | 819 | { |
112e8700 | 820 | return m_flags & mask; |
8b93c638 JM |
821 | } |
822 | ||
112e8700 | 823 | bool |
4904c3c6 | 824 | ui_out::is_mi_like_p () const |
8b93c638 | 825 | { |
112e8700 | 826 | return do_is_mi_like_p (); |
0fac0b41 DJ |
827 | } |
828 | ||
a6c47c14 AC |
829 | /* Verify that the field/tuple/list is correctly positioned. Return |
830 | the field number and corresponding alignment (if | |
831 | available/applicable). */ | |
8b93c638 | 832 | |
112e8700 SM |
833 | void |
834 | ui_out::verify_field (int *fldno, int *width, ui_align *align) | |
8b93c638 | 835 | { |
112e8700 | 836 | ui_out_level *current = current_level (); |
c5209615 | 837 | const char *text; |
a6c47c14 | 838 | |
112e8700 SM |
839 | if (m_table_up != nullptr |
840 | && m_table_up->current_state () != ui_out_table::state::BODY) | |
8b93c638 | 841 | { |
77a179e7 SM |
842 | internal_error (__FILE__, __LINE__, |
843 | _("table_body missing; table fields must be \ | |
e2e0b3e5 | 844 | specified after table_body and inside a list.")); |
8b93c638 | 845 | } |
8b93c638 | 846 | |
909c0aa5 | 847 | current->inc_field_count (); |
8b93c638 | 848 | |
112e8700 SM |
849 | if (m_table_up != nullptr |
850 | && m_table_up->current_state () == ui_out_table::state::BODY | |
851 | && m_table_up->entry_level () == level () | |
852 | && m_table_up->get_next_header (fldno, width, align, &text)) | |
8b93c638 | 853 | { |
909c0aa5 | 854 | if (*fldno != current->field_count ()) |
8e65ff28 | 855 | internal_error (__FILE__, __LINE__, |
e2e0b3e5 | 856 | _("ui-out internal error in handling headers.")); |
8b93c638 JM |
857 | } |
858 | else | |
859 | { | |
860 | *width = 0; | |
861 | *align = ui_noalign; | |
909c0aa5 | 862 | *fldno = current->field_count (); |
8b93c638 JM |
863 | } |
864 | } | |
865 | ||
170b53b2 | 866 | /* Access table field parameters. */ |
112e8700 SM |
867 | |
868 | bool | |
869 | ui_out::query_table_field (int colno, int *width, int *alignment, | |
870 | const char **col_name) | |
170b53b2 | 871 | { |
112e8700 SM |
872 | if (m_table_up == nullptr) |
873 | return false; | |
170b53b2 | 874 | |
112e8700 | 875 | return m_table_up->query_field (colno, width, alignment, col_name); |
170b53b2 UW |
876 | } |
877 | ||
112e8700 | 878 | /* The constructor. */ |
8b93c638 | 879 | |
112e8700 SM |
880 | ui_out::ui_out (ui_out_flags flags) |
881 | : m_flags (flags) | |
8b93c638 | 882 | { |
33b2fac6 | 883 | /* Create the ui-out level #1, the default level. */ |
112e8700 SM |
884 | push_level (ui_out_type_tuple); |
885 | } | |
54eb231c | 886 | |
112e8700 SM |
887 | ui_out::~ui_out () |
888 | { | |
8b93c638 | 889 | } |