| 1 | /* Output generating routines for GDB. |
| 2 | |
| 3 | Copyright (C) 1999-2020 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 | #ifndef UI_OUT_H |
| 24 | #define UI_OUT_H 1 |
| 25 | |
| 26 | #include <vector> |
| 27 | |
| 28 | #include "gdbsupport/enum-flags.h" |
| 29 | #include "ui-style.h" |
| 30 | |
| 31 | class ui_out_level; |
| 32 | class ui_out_table; |
| 33 | struct ui_file; |
| 34 | |
| 35 | /* the current ui_out */ |
| 36 | |
| 37 | /* FIXME: This should not be a global but something passed down from main.c |
| 38 | or top.c. */ |
| 39 | extern struct ui_out **current_ui_current_uiout_ptr (void); |
| 40 | #define current_uiout (*current_ui_current_uiout_ptr ()) |
| 41 | |
| 42 | /* alignment enum */ |
| 43 | enum ui_align |
| 44 | { |
| 45 | ui_left = -1, |
| 46 | ui_center, |
| 47 | ui_right, |
| 48 | ui_noalign |
| 49 | }; |
| 50 | |
| 51 | /* flags enum */ |
| 52 | enum ui_out_flag |
| 53 | { |
| 54 | ui_source_list = (1 << 0), |
| 55 | fix_multi_location_breakpoint_output = (1 << 1), |
| 56 | /* For CLI output, this flag is set if unfiltered output is desired. |
| 57 | This should only be used by low-level formatting functions. */ |
| 58 | unfiltered_output = (1 << 2), |
| 59 | /* This indicates that %pF should be disallowed in a printf format |
| 60 | string. */ |
| 61 | disallow_ui_out_field = (1 << 3) |
| 62 | }; |
| 63 | |
| 64 | DEF_ENUM_FLAGS_TYPE (ui_out_flag, ui_out_flags); |
| 65 | |
| 66 | /* Prototypes for ui-out API. */ |
| 67 | |
| 68 | /* A result is a recursive data structure consisting of lists and |
| 69 | tuples. */ |
| 70 | |
| 71 | enum ui_out_type |
| 72 | { |
| 73 | ui_out_type_tuple, |
| 74 | ui_out_type_list |
| 75 | }; |
| 76 | |
| 77 | /* The possible kinds of fields. */ |
| 78 | enum class field_kind |
| 79 | { |
| 80 | /* "FIELD_STRING" needs a funny name to avoid clashes with tokens |
| 81 | named "STRING". See PR build/25250. FIELD_SIGNED is given a |
| 82 | similar name for consistency. */ |
| 83 | FIELD_SIGNED, |
| 84 | FIELD_STRING, |
| 85 | }; |
| 86 | |
| 87 | /* The base type of all fields that can be emitted using %pF. */ |
| 88 | |
| 89 | struct base_field_s |
| 90 | { |
| 91 | const char *name; |
| 92 | field_kind kind; |
| 93 | }; |
| 94 | |
| 95 | /* A signed integer field, to be passed to %pF in format strings. */ |
| 96 | |
| 97 | struct signed_field_s : base_field_s |
| 98 | { |
| 99 | LONGEST val; |
| 100 | }; |
| 101 | |
| 102 | /* Construct a temporary signed_field_s on the caller's stack and |
| 103 | return a pointer to the constructed object. We use this because |
| 104 | it's not possible to pass a reference via va_args. */ |
| 105 | |
| 106 | static inline signed_field_s * |
| 107 | signed_field (const char *name, LONGEST val, |
| 108 | signed_field_s &&tmp = {}) |
| 109 | { |
| 110 | tmp.name = name; |
| 111 | tmp.kind = field_kind::FIELD_SIGNED; |
| 112 | tmp.val = val; |
| 113 | return &tmp; |
| 114 | } |
| 115 | |
| 116 | /* A string field, to be passed to %pF in format strings. */ |
| 117 | |
| 118 | struct string_field_s : base_field_s |
| 119 | { |
| 120 | const char *str; |
| 121 | }; |
| 122 | |
| 123 | /* Construct a temporary string_field_s on the caller's stack and |
| 124 | return a pointer to the constructed object. We use this because |
| 125 | it's not possible to pass a reference via va_args. */ |
| 126 | |
| 127 | static inline string_field_s * |
| 128 | string_field (const char *name, const char *str, |
| 129 | string_field_s &&tmp = {}) |
| 130 | { |
| 131 | tmp.name = name; |
| 132 | tmp.kind = field_kind::FIELD_STRING; |
| 133 | tmp.str = str; |
| 134 | return &tmp; |
| 135 | } |
| 136 | |
| 137 | /* A styled string. */ |
| 138 | |
| 139 | struct styled_string_s |
| 140 | { |
| 141 | /* The style. */ |
| 142 | ui_file_style style; |
| 143 | |
| 144 | /* The string. */ |
| 145 | const char *str; |
| 146 | }; |
| 147 | |
| 148 | /* Construct a temporary styled_string_s on the caller's stack and |
| 149 | return a pointer to the constructed object. We use this because |
| 150 | it's not possible to pass a reference via va_args. */ |
| 151 | |
| 152 | static inline styled_string_s * |
| 153 | styled_string (const ui_file_style &style, const char *str, |
| 154 | styled_string_s &&tmp = {}) |
| 155 | { |
| 156 | tmp.style = style; |
| 157 | tmp.str = str; |
| 158 | return &tmp; |
| 159 | } |
| 160 | |
| 161 | class ui_out |
| 162 | { |
| 163 | public: |
| 164 | |
| 165 | explicit ui_out (ui_out_flags flags = 0); |
| 166 | virtual ~ui_out (); |
| 167 | |
| 168 | void push_level (ui_out_type type); |
| 169 | void pop_level (ui_out_type type); |
| 170 | |
| 171 | /* A table can be considered a special tuple/list combination with the |
| 172 | implied structure: ``table = { hdr = { header, ... } , body = [ { |
| 173 | field, ... }, ... ] }''. If NR_ROWS is negative then there is at |
| 174 | least one row. */ |
| 175 | |
| 176 | void table_begin (int nr_cols, int nr_rows, const std::string &tblid); |
| 177 | void table_header (int width, ui_align align, const std::string &col_name, |
| 178 | const std::string &col_hdr); |
| 179 | void table_body (); |
| 180 | void table_end (); |
| 181 | |
| 182 | void begin (ui_out_type type, const char *id); |
| 183 | void end (ui_out_type type); |
| 184 | |
| 185 | void field_signed (const char *fldname, LONGEST value); |
| 186 | void field_fmt_signed (int width, ui_align align, const char *fldname, |
| 187 | LONGEST value); |
| 188 | /* Like field_signed, but print an unsigned value. */ |
| 189 | void field_unsigned (const char *fldname, ULONGEST value); |
| 190 | void field_core_addr (const char *fldname, struct gdbarch *gdbarch, |
| 191 | CORE_ADDR address); |
| 192 | void field_string (const char *fldname, const char *string, |
| 193 | const ui_file_style &style = ui_file_style ()); |
| 194 | void field_string (const char *fldname, const std::string &string); |
| 195 | void field_stream (const char *fldname, string_file &stream, |
| 196 | const ui_file_style &style = ui_file_style ()); |
| 197 | void field_skip (const char *fldname); |
| 198 | void field_fmt (const char *fldname, const char *format, ...) |
| 199 | ATTRIBUTE_PRINTF (3, 4); |
| 200 | void field_fmt (const char *fldname, const ui_file_style &style, |
| 201 | const char *format, ...) |
| 202 | ATTRIBUTE_PRINTF (4, 5); |
| 203 | |
| 204 | void spaces (int numspaces); |
| 205 | void text (const char *string); |
| 206 | |
| 207 | /* Output a printf-style formatted string. In addition to the usual |
| 208 | printf format specs, this supports a few GDB-specific |
| 209 | formatters: |
| 210 | |
| 211 | - '%pF' - output a field. |
| 212 | |
| 213 | The argument is a field, wrapped in any of the base_field_s |
| 214 | subclasses. signed_field for integer fields, string_field for |
| 215 | string fields. This is preferred over separate |
| 216 | uiout->field_signed(), uiout_>field_string() etc. calls when |
| 217 | the formatted message is translatable. E.g.: |
| 218 | |
| 219 | uiout->message (_("\nWatchpoint %pF deleted because the program has " |
| 220 | "left the block in\n" |
| 221 | "which its expression is valid.\n"), |
| 222 | signed_field ("wpnum", b->number)); |
| 223 | |
| 224 | - '%p[' - output the following text in a specified style. |
| 225 | '%p]' - output the following text in the default style. |
| 226 | |
| 227 | The argument to '%p[' is a ui_file_style pointer. The argument |
| 228 | to '%p]' must be nullptr. |
| 229 | |
| 230 | This is useful when you want to output some portion of a string |
| 231 | literal in some style. E.g.: |
| 232 | |
| 233 | uiout->message (_(" %p[<repeats %u times>%p]"), |
| 234 | metadata_style.style ().ptr (), |
| 235 | reps, repeats, nullptr); |
| 236 | |
| 237 | - '%ps' - output a styled string. |
| 238 | |
| 239 | The argument is the result of a call to styled_string. This is |
| 240 | useful when you want to output some runtime-generated string in |
| 241 | some style. E.g.: |
| 242 | |
| 243 | uiout->message (_("this is a target address %ps.\n"), |
| 244 | styled_string (address_style.style (), |
| 245 | paddress (gdbarch, pc))); |
| 246 | |
| 247 | Note that these all "abuse" the %p printf format spec, in order |
| 248 | to be compatible with GCC's printf format checking. This is OK |
| 249 | because code in GDB that wants to print a host address should use |
| 250 | host_address_to_string instead of %p. */ |
| 251 | void message (const char *format, ...) ATTRIBUTE_PRINTF (2, 3); |
| 252 | void vmessage (const ui_file_style &in_style, |
| 253 | const char *format, va_list args) ATTRIBUTE_PRINTF (3, 0); |
| 254 | |
| 255 | void wrap_hint (const char *identstring); |
| 256 | |
| 257 | void flush (); |
| 258 | |
| 259 | /* Redirect the output of a ui_out object temporarily. */ |
| 260 | void redirect (ui_file *outstream); |
| 261 | |
| 262 | ui_out_flags test_flags (ui_out_flags mask); |
| 263 | |
| 264 | /* HACK: Code in GDB is currently checking to see the type of ui_out |
| 265 | builder when determining which output to produce. This function is |
| 266 | a hack to encapsulate that test. Once GDB manages to separate the |
| 267 | CLI/MI from the core of GDB the problem should just go away .... */ |
| 268 | |
| 269 | bool is_mi_like_p () const; |
| 270 | |
| 271 | bool query_table_field (int colno, int *width, int *alignment, |
| 272 | const char **col_name); |
| 273 | |
| 274 | /* Return true if this stream is prepared to handle style |
| 275 | escapes. */ |
| 276 | virtual bool can_emit_style_escape () const = 0; |
| 277 | |
| 278 | protected: |
| 279 | |
| 280 | virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) |
| 281 | = 0; |
| 282 | virtual void do_table_body () = 0; |
| 283 | virtual void do_table_end () = 0; |
| 284 | virtual void do_table_header (int width, ui_align align, |
| 285 | const std::string &col_name, |
| 286 | const std::string &col_hdr) = 0; |
| 287 | |
| 288 | virtual void do_begin (ui_out_type type, const char *id) = 0; |
| 289 | virtual void do_end (ui_out_type type) = 0; |
| 290 | virtual void do_field_signed (int fldno, int width, ui_align align, |
| 291 | const char *fldname, LONGEST value) = 0; |
| 292 | virtual void do_field_unsigned (int fldno, int width, ui_align align, |
| 293 | const char *fldname, ULONGEST value) = 0; |
| 294 | virtual void do_field_skip (int fldno, int width, ui_align align, |
| 295 | const char *fldname) = 0; |
| 296 | virtual void do_field_string (int fldno, int width, ui_align align, |
| 297 | const char *fldname, const char *string, |
| 298 | const ui_file_style &style) = 0; |
| 299 | virtual void do_field_fmt (int fldno, int width, ui_align align, |
| 300 | const char *fldname, const ui_file_style &style, |
| 301 | const char *format, va_list args) |
| 302 | ATTRIBUTE_PRINTF (7, 0) = 0; |
| 303 | virtual void do_spaces (int numspaces) = 0; |
| 304 | virtual void do_text (const char *string) = 0; |
| 305 | virtual void do_message (const ui_file_style &style, |
| 306 | const char *format, va_list args) |
| 307 | ATTRIBUTE_PRINTF (3,0) = 0; |
| 308 | virtual void do_wrap_hint (const char *identstring) = 0; |
| 309 | virtual void do_flush () = 0; |
| 310 | virtual void do_redirect (struct ui_file *outstream) = 0; |
| 311 | |
| 312 | /* Set as not MI-like by default. It is overridden in subclasses if |
| 313 | necessary. */ |
| 314 | |
| 315 | virtual bool do_is_mi_like_p () const |
| 316 | { return false; } |
| 317 | |
| 318 | private: |
| 319 | void call_do_message (const ui_file_style &style, const char *format, |
| 320 | ...); |
| 321 | |
| 322 | ui_out_flags m_flags; |
| 323 | |
| 324 | /* Vector to store and track the ui-out levels. */ |
| 325 | std::vector<std::unique_ptr<ui_out_level>> m_levels; |
| 326 | |
| 327 | /* A table, if any. At present only a single table is supported. */ |
| 328 | std::unique_ptr<ui_out_table> m_table_up; |
| 329 | |
| 330 | void verify_field (int *fldno, int *width, ui_align *align); |
| 331 | |
| 332 | int level () const; |
| 333 | ui_out_level *current_level () const; |
| 334 | }; |
| 335 | |
| 336 | /* Start a new tuple or list on construction, and end it on |
| 337 | destruction. Normally this is used via the typedefs |
| 338 | ui_out_emit_tuple and ui_out_emit_list. */ |
| 339 | template<ui_out_type Type> |
| 340 | class ui_out_emit_type |
| 341 | { |
| 342 | public: |
| 343 | |
| 344 | ui_out_emit_type (struct ui_out *uiout, const char *id) |
| 345 | : m_uiout (uiout) |
| 346 | { |
| 347 | uiout->begin (Type, id); |
| 348 | } |
| 349 | |
| 350 | ~ui_out_emit_type () |
| 351 | { |
| 352 | m_uiout->end (Type); |
| 353 | } |
| 354 | |
| 355 | DISABLE_COPY_AND_ASSIGN (ui_out_emit_type<Type>); |
| 356 | |
| 357 | private: |
| 358 | |
| 359 | struct ui_out *m_uiout; |
| 360 | }; |
| 361 | |
| 362 | typedef ui_out_emit_type<ui_out_type_tuple> ui_out_emit_tuple; |
| 363 | typedef ui_out_emit_type<ui_out_type_list> ui_out_emit_list; |
| 364 | |
| 365 | /* Start a new table on construction, and end the table on |
| 366 | destruction. */ |
| 367 | class ui_out_emit_table |
| 368 | { |
| 369 | public: |
| 370 | |
| 371 | ui_out_emit_table (struct ui_out *uiout, int nr_cols, int nr_rows, |
| 372 | const char *tblid) |
| 373 | : m_uiout (uiout) |
| 374 | { |
| 375 | m_uiout->table_begin (nr_cols, nr_rows, tblid); |
| 376 | } |
| 377 | |
| 378 | ~ui_out_emit_table () |
| 379 | { |
| 380 | m_uiout->table_end (); |
| 381 | } |
| 382 | |
| 383 | ui_out_emit_table (const ui_out_emit_table &) = delete; |
| 384 | ui_out_emit_table &operator= (const ui_out_emit_table &) = delete; |
| 385 | |
| 386 | private: |
| 387 | |
| 388 | struct ui_out *m_uiout; |
| 389 | }; |
| 390 | |
| 391 | /* On destruction, pop the last redirection by calling the uiout's |
| 392 | redirect method with a NULL parameter. */ |
| 393 | class ui_out_redirect_pop |
| 394 | { |
| 395 | public: |
| 396 | |
| 397 | ui_out_redirect_pop (ui_out *uiout) |
| 398 | : m_uiout (uiout) |
| 399 | { |
| 400 | } |
| 401 | |
| 402 | ~ui_out_redirect_pop () |
| 403 | { |
| 404 | m_uiout->redirect (NULL); |
| 405 | } |
| 406 | |
| 407 | ui_out_redirect_pop (const ui_out_redirect_pop &) = delete; |
| 408 | ui_out_redirect_pop &operator= (const ui_out_redirect_pop &) = delete; |
| 409 | |
| 410 | private: |
| 411 | struct ui_out *m_uiout; |
| 412 | }; |
| 413 | |
| 414 | #endif /* UI_OUT_H */ |