1 /* Output generating routines for GDB CLI. 2 3 Copyright (C) 1999-2013 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 "ui-out.h" 25 #include "cli-out.h" 26 #include "gdb_string.h" 27 #include "gdb_assert.h" 28 #include "vec.h" 29 30 typedef struct cli_ui_out_data cli_out_data; 31 32 33 /* Prototypes for local functions */ 34 35 static void cli_text (struct ui_out *uiout, const char *string); 36 37 static void field_separator (void); 38 39 static void out_field_fmt (struct ui_out *uiout, int fldno, 40 const char *fldname, 41 const char *format,...) ATTRIBUTE_PRINTF (4, 5); 42 43 /* These are the CLI output functions */ 44 45 /* Mark beginning of a table */ 46 47 static void 48 cli_table_begin (struct ui_out *uiout, int nbrofcols, 49 int nr_rows, 50 const char *tblid) 51 { 52 cli_out_data *data = ui_out_data (uiout); 53 54 if (nr_rows == 0) 55 data->suppress_output = 1; 56 else 57 /* Only the table suppresses the output and, fortunately, a table 58 is not a recursive data structure. */ 59 gdb_assert (data->suppress_output == 0); 60 } 61 62 /* Mark beginning of a table body */ 63 64 static void 65 cli_table_body (struct ui_out *uiout) 66 { 67 cli_out_data *data = ui_out_data (uiout); 68 69 if (data->suppress_output) 70 return; 71 /* first, close the table header line */ 72 cli_text (uiout, "\n"); 73 } 74 75 /* Mark end of a table */ 76 77 static void 78 cli_table_end (struct ui_out *uiout) 79 { 80 cli_out_data *data = ui_out_data (uiout); 81 82 data->suppress_output = 0; 83 } 84 85 /* Specify table header */ 86 87 static void 88 cli_table_header (struct ui_out *uiout, int width, enum ui_align alignment, 89 const char *col_name, 90 const char *colhdr) 91 { 92 cli_out_data *data = ui_out_data (uiout); 93 94 if (data->suppress_output) 95 return; 96 97 /* Always go through the function pointer (virtual function call). 98 We may have been extended. */ 99 uo_field_string (uiout, 0, width, alignment, 0, colhdr); 100 } 101 102 /* Mark beginning of a list */ 103 104 static void 105 cli_begin (struct ui_out *uiout, 106 enum ui_out_type type, 107 int level, 108 const char *id) 109 { 110 cli_out_data *data = ui_out_data (uiout); 111 112 if (data->suppress_output) 113 return; 114 } 115 116 /* Mark end of a list */ 117 118 static void 119 cli_end (struct ui_out *uiout, 120 enum ui_out_type type, 121 int level) 122 { 123 cli_out_data *data = ui_out_data (uiout); 124 125 if (data->suppress_output) 126 return; 127 } 128 129 /* output an int field */ 130 131 static void 132 cli_field_int (struct ui_out *uiout, int fldno, int width, 133 enum ui_align alignment, 134 const char *fldname, int value) 135 { 136 char buffer[20]; /* FIXME: how many chars long a %d can become? */ 137 cli_out_data *data = ui_out_data (uiout); 138 139 if (data->suppress_output) 140 return; 141 xsnprintf (buffer, sizeof (buffer), "%d", value); 142 143 /* Always go through the function pointer (virtual function call). 144 We may have been extended. */ 145 uo_field_string (uiout, fldno, width, alignment, fldname, buffer); 146 } 147 148 /* used to ommit a field */ 149 150 static void 151 cli_field_skip (struct ui_out *uiout, int fldno, int width, 152 enum ui_align alignment, 153 const char *fldname) 154 { 155 cli_out_data *data = ui_out_data (uiout); 156 157 if (data->suppress_output) 158 return; 159 160 /* Always go through the function pointer (virtual function call). 161 We may have been extended. */ 162 uo_field_string (uiout, fldno, width, alignment, fldname, ""); 163 } 164 165 /* other specific cli_field_* end up here so alignment and field 166 separators are both handled by cli_field_string */ 167 168 static void 169 cli_field_string (struct ui_out *uiout, 170 int fldno, 171 int width, 172 enum ui_align align, 173 const char *fldname, 174 const char *string) 175 { 176 int before = 0; 177 int after = 0; 178 cli_out_data *data = ui_out_data (uiout); 179 180 if (data->suppress_output) 181 return; 182 183 if ((align != ui_noalign) && string) 184 { 185 before = width - strlen (string); 186 if (before <= 0) 187 before = 0; 188 else 189 { 190 if (align == ui_right) 191 after = 0; 192 else if (align == ui_left) 193 { 194 after = before; 195 before = 0; 196 } 197 else 198 /* ui_center */ 199 { 200 after = before / 2; 201 before -= after; 202 } 203 } 204 } 205 206 if (before) 207 ui_out_spaces (uiout, before); 208 if (string) 209 out_field_fmt (uiout, fldno, fldname, "%s", string); 210 if (after) 211 ui_out_spaces (uiout, after); 212 213 if (align != ui_noalign) 214 field_separator (); 215 } 216 217 /* This is the only field function that does not align. */ 218 219 static void ATTRIBUTE_PRINTF (6, 0) 220 cli_field_fmt (struct ui_out *uiout, int fldno, 221 int width, enum ui_align align, 222 const char *fldname, 223 const char *format, 224 va_list args) 225 { 226 cli_out_data *data = ui_out_data (uiout); 227 struct ui_file *stream; 228 229 if (data->suppress_output) 230 return; 231 232 stream = VEC_last (ui_filep, data->streams); 233 vfprintf_filtered (stream, format, args); 234 235 if (align != ui_noalign) 236 field_separator (); 237 } 238 239 static void 240 cli_spaces (struct ui_out *uiout, int numspaces) 241 { 242 cli_out_data *data = ui_out_data (uiout); 243 struct ui_file *stream; 244 245 if (data->suppress_output) 246 return; 247 248 stream = VEC_last (ui_filep, data->streams); 249 print_spaces_filtered (numspaces, stream); 250 } 251 252 static void 253 cli_text (struct ui_out *uiout, const char *string) 254 { 255 cli_out_data *data = ui_out_data (uiout); 256 struct ui_file *stream; 257 258 if (data->suppress_output) 259 return; 260 261 stream = VEC_last (ui_filep, data->streams); 262 fputs_filtered (string, stream); 263 } 264 265 static void ATTRIBUTE_PRINTF (3, 0) 266 cli_message (struct ui_out *uiout, int verbosity, 267 const char *format, va_list args) 268 { 269 cli_out_data *data = ui_out_data (uiout); 270 271 if (data->suppress_output) 272 return; 273 274 if (ui_out_get_verblvl (uiout) >= verbosity) 275 { 276 struct ui_file *stream = VEC_last (ui_filep, data->streams); 277 278 vfprintf_unfiltered (stream, format, args); 279 } 280 } 281 282 static void 283 cli_wrap_hint (struct ui_out *uiout, char *identstring) 284 { 285 cli_out_data *data = ui_out_data (uiout); 286 287 if (data->suppress_output) 288 return; 289 wrap_here (identstring); 290 } 291 292 static void 293 cli_flush (struct ui_out *uiout) 294 { 295 cli_out_data *data = ui_out_data (uiout); 296 struct ui_file *stream = VEC_last (ui_filep, data->streams); 297 298 gdb_flush (stream); 299 } 300 301 /* OUTSTREAM as non-NULL will push OUTSTREAM on the stack of output streams 302 and make it therefore active. OUTSTREAM as NULL will pop the last pushed 303 output stream; it is an internal error if it does not exist. */ 304 305 static int 306 cli_redirect (struct ui_out *uiout, struct ui_file *outstream) 307 { 308 cli_out_data *data = ui_out_data (uiout); 309 310 if (outstream != NULL) 311 VEC_safe_push (ui_filep, data->streams, outstream); 312 else 313 VEC_pop (ui_filep, data->streams); 314 315 return 0; 316 } 317 318 /* local functions */ 319 320 /* Like cli_field_fmt, but takes a variable number of args 321 and makes a va_list and does not insert a separator. */ 322 323 /* VARARGS */ 324 static void 325 out_field_fmt (struct ui_out *uiout, int fldno, 326 const char *fldname, 327 const char *format,...) 328 { 329 cli_out_data *data = ui_out_data (uiout); 330 struct ui_file *stream = VEC_last (ui_filep, data->streams); 331 va_list args; 332 333 va_start (args, format); 334 vfprintf_filtered (stream, format, args); 335 336 va_end (args); 337 } 338 339 /* Access to ui_out format private members. */ 340 341 static void 342 field_separator (void) 343 { 344 cli_out_data *data = ui_out_data (current_uiout); 345 struct ui_file *stream = VEC_last (ui_filep, data->streams); 346 347 fputc_filtered (' ', stream); 348 } 349 350 /* This is the CLI ui-out implementation functions vector */ 351 352 /* FIXME: This can be initialized dynamically after default is set to 353 handle initial output in main.c */ 354 355 struct ui_out_impl cli_ui_out_impl = 356 { 357 cli_table_begin, 358 cli_table_body, 359 cli_table_end, 360 cli_table_header, 361 cli_begin, 362 cli_end, 363 cli_field_int, 364 cli_field_skip, 365 cli_field_string, 366 cli_field_fmt, 367 cli_spaces, 368 cli_text, 369 cli_message, 370 cli_wrap_hint, 371 cli_flush, 372 cli_redirect, 373 0, 374 0, /* Does not need MI hacks (i.e. needs CLI hacks). */ 375 }; 376 377 /* Constructor for a `cli_out_data' object. */ 378 379 void 380 cli_out_data_ctor (cli_out_data *self, struct ui_file *stream) 381 { 382 gdb_assert (stream != NULL); 383 384 self->streams = NULL; 385 VEC_safe_push (ui_filep, self->streams, stream); 386 387 self->suppress_output = 0; 388 } 389 390 /* Initialize private members at startup. */ 391 392 struct ui_out * 393 cli_out_new (struct ui_file *stream) 394 { 395 int flags = ui_source_list; 396 cli_out_data *data = XMALLOC (cli_out_data); 397 398 cli_out_data_ctor (data, stream); 399 return ui_out_new (&cli_ui_out_impl, data, flags); 400 } 401 402 struct ui_file * 403 cli_out_set_stream (struct ui_out *uiout, struct ui_file *stream) 404 { 405 cli_out_data *data = ui_out_data (uiout); 406 struct ui_file *old; 407 408 old = VEC_pop (ui_filep, data->streams); 409 VEC_quick_push (ui_filep, data->streams, stream); 410 411 return old; 412 } 413