diag_sand_prt.h (53332B)
1 2 /** 3 * \file diag_sand_prt.h 4 * 5 * Set of macros and routines to print beautified tabular output. Main purpose to provide 6 * standard output format for all tabular data in bcm shell 7 */ 8 /* 9 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 10 * 11 * Copyright 2007-2020 Broadcom Inc. All rights reserved. 12 */ 13 14 #ifndef DIAG_SAND_PRT_H 15 #define DIAG_SAND_PRT_H 16 17 #include <shared/utilex/utilex_rhlist.h> 18 #include <shared/utilex/utilex_str.h> 19 #include <shared/shrextend/shrextend_debug.h> 20 #include <appl/diag/sand/diag_sand_utils.h> 21 #include <appl/diag/sand/diag_sand_framework.h> 22 23 #define PRT_COLUMN_WIDTH (RHNAME_MAX_SIZE + 1) 24 #define PRT_COLUMN_WIDTH_BIG (16 * RHNAME_MAX_SIZE + 1) 25 #define PRT_TITLE_WIDTH (2*RHSTRING_MAX_SIZE + 1) 26 #define PRT_COLUMN_MAX_NUM 256 27 #define PRT_TITLE_ID PRT_COLUMN_MAX_NUM 28 #define PRT_MAX_SHIFT_NUM 5 29 30 typedef struct 31 { 32 uint32 width; 33 char format[RHKEYWORD_MAX_SIZE]; 34 char *next_ptr; 35 /** 36 * sample_str - first non empty string in column, if all cells in the column will be either identical or empty 37 * column will be shown in info instead of actual column when option columns="nosame" was choosen 38 */ 39 char *sample_str; 40 } prt_format_t; 41 42 /** 43 * In order to have proper XML output, each column should be assigned XML role 44 */ 45 typedef enum 46 { 47 /** 48 * No XML output assign, column will be skipped 49 */ 50 PRT_XML_NONE, 51 /** 52 * Column will be child, parent node should be figured out either through calculation or explicit input 53 */ 54 PRT_XML_CHILD, 55 /** 56 * Column will be attribute, node which attribute it will be should be either calculated or provided explicitly 57 */ 58 PRT_XML_ATTRIBUTE 59 } PRT_XML_TYPE; 60 61 /** 62 * Flex Type - allows PRT to split either cells or headers according to different criteria into multiple rows, 63 */ 64 typedef enum 65 { 66 /* 67 * No flexibility 68 */ 69 PRT_FLEX_NONE, 70 /* 71 * Split ASCII string using space, tab, point, comma or underscore (' ', '.', ',', '_', '\t') 72 * '\n' wil always move to the next line 73 */ 74 PRT_FLEX_ASCII, 75 /* 76 * Split ASCII string using space, tab, point, comma or underscore (' ', '.', ',', '_', '\t') 77 * '\n' will always move to the next line 78 * Difference from previous is that no shrink is performed on the string 79 */ 80 PRT_FLEX_ASCII_ORIG, 81 /* 82 * Split the string directly into portions of RHNAME_MAX_SIZE characters 83 */ 84 PRT_FLEX_BINARY 85 } PRT_FLEX_TYPE; 86 87 #define PRT_COLUMN_FLAG_SHOW 0x01 88 #define PRT_COLUMN_FLAG_FILTER 0x02 89 90 typedef struct 91 { 92 /** 93 * Column name - used in table header or as XML node name 94 * Established only by COLUMN_ADD 95 */ 96 char name[PRT_COLUMN_WIDTH]; 97 /** 98 * Misc flags - Does not influence XML output 99 * PRT_COLUMN_FLAG_SHOW - if this flag is TRUE show column in screen table 100 * PRT_COLUMN_FLAG_FILTER - If this flag is TRUE use cell from this column in content filtering 101 */ 102 int flags; 103 /** 104 * Flag marking whether string should be split as binary, ASCII or none 105 * Established only by COLUMN_ADD 106 */ 107 PRT_FLEX_TYPE flex_type; 108 /** 109 * Maximum size for strings in this column 110 * Established only by COLUMN_ADD 111 */ 112 int max_width; 113 /** 114 * Cell offset in the row 115 * Established only by COLUMN_ADD 116 */ 117 int cell_offset; 118 void *node[PRT_MAX_SHIFT_NUM]; 119 int cur_shift_id; 120 PRT_XML_TYPE type; 121 char *parent_name; 122 int parent_id; 123 int depth; 124 int align; 125 } prt_column_t; 126 127 typedef struct 128 { 129 /* 130 * Entry used to be queued on info_list 131 */ 132 rhentry_t entry; 133 /* 134 * Allow info length be the same as title one 135 */ 136 char content[PRT_TITLE_WIDTH]; 137 } prt_info_t; 138 139 typedef struct 140 { 141 /* 142 * Assigned once when we now the sum of all column widths by the first row added 143 */ 144 rhlist_t *list; 145 /* 146 * Unit id 147 */ 148 int unit; 149 /* 150 * Modified by PRT_COLUMN_ADD, first PRT_ROW_ADD blocks the option for column changes 151 */ 152 int col_num; 153 /* 154 * Sum of the all column max widths, modified only by PRT_COLUMN_ADD 155 */ 156 int row_width; 157 /** 158 * Desirable display width, set around in PRT_TITLE_SET or left undefined which prompts 64 character per column 159 */ 160 int display_width; 161 /* 162 * Separate place for title to allow bigger string 163 */ 164 char title[PRT_TITLE_WIDTH]; 165 /* 166 * Contain per column info - keep + 1 - it is for title node 167 */ 168 prt_column_t *columns[PRT_COLUMN_MAX_NUM + 1]; 169 /* 170 * Dynamic parameter - used to keep current entry 171 */ 172 void *row_cur; 173 /* 174 * Dynamic parameter - current column in the row 175 */ 176 int col_cur; 177 /* 178 * Per table information list 179 */ 180 rhlist_t *info_list; 181 } prt_control_t; 182 183 /** 184 * \brief Get the width of the terminal to best output fit 185 * \par DIRECT OUTPUT 186 * \retval - terminal width 187 */ 188 int diag_sand_prt_width( 189 void); 190 191 /** 192 * \brief Print number of identical characters 193 * \par DIRECT INPUT 194 * \param num [in] number of characters to print 195 * \param ch [in] character to print 196 * \par DIRECT OUTPUT 197 * \retval - terminal width 198 */ 199 void diag_sand_prt_char( 200 int num, 201 char ch); 202 203 /** 204 * \brief Actual output of prepared data either to display or XML file 205 * \param prt_ctr [in/out] pointer to the control list of table print 206 * \param sand_control [in] pointer to control block of shell command. NULL means that command was invocated by framework 207 * \param prt_filename [in] explicit XML filename to write the table to 208 * \remark 209 * OUTPUT: printing or formatted output to the standard output/XML File 210 */ 211 shr_error_e diag_sand_prt( 212 prt_control_t * prt_ctr, 213 sh_sand_control_t * sand_control, 214 char *prt_filename); 215 216 /** 217 * \brief Actual output of prepared data to display (multiple tables) 218 * \param prt_ctr [in/out] pointer to the control list of tables to print 219 * \param sand_control [in] pointer to control block of shell command. NULL means that command was invocated by framework 220 * \param table_count [in] Table count. 221 * \remark 222 * OUTPUT: printing or formatted output to the standard output. 223 */ 224 shr_error_e diag_sand_prt_multiple( 225 prt_control_t ** prt_ctr, 226 sh_sand_control_t * sand_control, 227 uint32 table_count); 228 229 /** 230 * \brief Add new column to the table 231 * \param prt_ctr [in/out] - pointer to the control list of table print 232 * \param flag [in] - mark different properties of column 233 * \param width [in] - column width 234 * \param prt_column_p [out] - pointer to column pointer 235 * \remark 236 * Should not be used outside the diag_sand_prt MACROs 237 */ 238 shr_error_e diag_sand_prt_column_add( 239 prt_control_t * prt_ctr, 240 int flag, 241 int width, 242 prt_column_t ** prt_column_p); 243 244 /** 245 * \brief Sanitize XML gold result file - like remove timestamp and may be other things to consider 246 * \param unit [in] - device id 247 * \param flags [in] - flags used for gold result path. 248 * \param command [in] - command string for the file to be sanitized 249 * \param filename [in] - filename build for this command 250 * \remark 251 * should be kept as internal routine 252 */ 253 shr_error_e diag_sand_prt_gold_sanitize( 254 int unit, 255 int flags, 256 char *command, 257 char *filename); 258 259 /* 260 * Modes for list entries 261 */ 262 typedef enum 263 { 264 /** 265 * No separation line 266 */ 267 PRT_ROW_SEP_NONE, 268 /** 269 * Underscore(__________) line after the row 270 */ 271 PRT_ROW_SEP_UNDERSCORE, 272 /** 273 * Underscore(__________) line before the row 274 */ 275 PRT_ROW_SEP_UNDERSCORE_BEFORE, 276 /** 277 * Equal(==========) line after the row 278 */ 279 PRT_ROW_SEP_EQUAL, 280 /** 281 * Equal(==========) line before the row 282 */ 283 PRT_ROW_SEP_EQUAL_BEFORE, 284 285 } PRT_ROW_SEP_MODE; 286 287 /* 288 * Internal Facilities for pretty print not to be used outside this include file 289 * { 290 */ 291 #define _PRT_FORMAT(mc_ptr, mc_length, mc_format,...) { \ 292 sal_snprintf(mc_ptr, mc_length, mc_format "%s", __VA_ARGS__); \ 293 } 294 #define PRT_FORMAT(mc_ptr, mc_length,...) { \ 295 _PRT_FORMAT(mc_ptr, mc_length, __VA_ARGS__, ""); \ 296 } 297 298 #define PRT_COLUMN_ITERATOR(k_mc, prt_column_mc, prt_ctr_mc) \ 299 for (k_mc = 0, prt_column_mc = prt_ctr->columns[0]; k_mc < prt_ctr_mc->col_num; \ 300 k_mc++, prt_column_mc = prt_ctr->columns[k_mc]) \ 301 if(prt_column_mc->flags & PRT_COLUMN_FLAG_SHOW) 302 303 #define PRT_FILTER_COLUMN_ITERATOR(k_mc, prt_column_mc, prt_ctr_mc) \ 304 for (k_mc = 0, prt_column_mc = prt_ctr->columns[0]; k_mc < prt_ctr_mc->col_num; \ 305 k_mc++, prt_column_mc = prt_ctr->columns[k_mc]) \ 306 if(prt_column_mc->flags & PRT_COLUMN_FLAG_FILTER) 307 308 #define PRT_HIDDEN_COLUMN_ITERATOR(k_mc, prt_column_mc, prt_ctr_mc) \ 309 for (k_mc = 0, prt_column_mc = prt_ctr->columns[0]; k_mc < prt_ctr_mc->col_num; \ 310 k_mc++, prt_column_mc = prt_ctr->columns[k_mc]) \ 311 if(!(prt_column_mc->flags & PRT_COLUMN_FLAG_SHOW)) 312 313 #define PRT_ALL_COLUMN_ITERATOR(k_mc, prt_column_mc, prt_ctr_mc) \ 314 for (k_mc = 0, prt_column_mc = prt_ctr->columns[0]; k_mc < prt_ctr_mc->col_num; \ 315 k_mc++, prt_column_mc = prt_ctr->columns[k_mc]) 316 317 /** 318 * \brief Free control structure allocated by _SET_TITLE 319 * \param [in] prt_ctr_mc - pointer to the control structure 320 * \remark 321 * Should be always used at the end(usually after exit: label) of routine using pretty printing to catch all errors 322 */ 323 #define _PRT_FREE(prt_ctr_mc) \ 324 if(prt_ctr_mc != NULL) \ 325 { \ 326 int i_col; \ 327 for(i_col = 0; i_col < prt_ctr_mc->col_num; i_col++) \ 328 { \ 329 if(prt_ctr_mc->columns[i_col] != NULL) \ 330 sal_free(prt_ctr_mc->columns[i_col]); \ 331 } \ 332 if(prt_ctr_mc->columns[PRT_TITLE_ID] != NULL) \ 333 sal_free(prt_ctr_mc->columns[PRT_TITLE_ID]); \ 334 if(prt_ctr_mc->list != NULL) \ 335 utilex_rhlist_free_all(prt_ctr_mc->list); \ 336 if(prt_ctr_mc->info_list != NULL) \ 337 utilex_rhlist_free_all(prt_ctr_mc->info_list); \ 338 sal_free(prt_ctr_mc); \ 339 prt_ctr_mc = NULL; \ 340 } 341 342 /** 343 * \brief Actual printing of prepared data to be used only in the context of shell framework 344 * \param prt_ctr_mc [in] - pointer to the control structure 345 * \remark 346 * Requires presence of sand_control, which is implicitly provided by the shell command invocation parameters, and 347 * should be transfered to underlying routines in the case of PRT usage down stack 348 * Frees the list 349 */ 350 #define _PRT_COMMITX(prt_ctr_mc) { \ 351 SHR_CLI_EXIT_IF_ERR(diag_sand_prt(prt_ctr_mc, sand_control, NULL), ""); \ 352 _PRT_FREE(prt_ctr_mc); \ 353 } 354 355 /** 356 * \brief Actual printing of prepared data, like PRT_COMMITX, but with on option to use explicit XML output file name 357 * \par DIRECT INPUT 358 * \param [in] prt_ctr_mc - pointer to the control structure 359 * \param [in] filename_str - XML file to be used for data export, if NULL the one from sand_control may be used 360 * \par INDIRECT INPUT: prt_ctr_mc - control structure that provides all the info on the table 361 * sand_control - control structure that provides all command related info 362 * \par INDIRECT OUTPUT: printing or formatted output to the standard output 363 * \remark automatically frees the list 364 */ 365 #define _PRT_COMMITF(prt_ctr_mc, filename_str) { \ 366 SHR_CLI_EXIT_IF_ERR(diag_sand_prt(prt_ctr_mc, sand_control, filename_str), ""); \ 367 _PRT_FREE(prt_ctr_mc); \ 368 } 369 370 /** 371 * \brief Same as PRT_COMMITX, the difference being to be used when no shell framework sand_control is now available 372 * \param [in] prt_ctr_mc - pointer to the control structure 373 * \par INDIRECT OUTPUT: printing or formatted output to the standard output 374 * \remark automatically frees the list 375 */ 376 #define _PRT_COMMIT(prt_ctr_mc) \ 377 { \ 378 SHR_CLI_EXIT_IF_ERR(diag_sand_prt(prt_ctr_mc, NULL, NULL), ""); \ 379 _PRT_FREE(prt_ctr_mc); \ 380 } 381 382 /** 383 * \brief Same as PRT_COMMITX, the difference being to be is that it is printing several tables as one. 384 * \param prt_ctr_mc [in] - pointer to the control structure 385 * \param mc_num [in] - number of tables to print. 386 * \remark 387 * Requires presence of sand_control, which is implicitly provided by the shell command invocation parameters, and 388 * should be transfered to underlying routines in the case of PRT usage down stack 389 * Does NOT frees the list, as we may want to print part of the set separately 390 */ 391 #define _PRT_COMMITX_COMBINE(prt_ctr_mc, mc_num) \ 392 { \ 393 SHR_CLI_EXIT_IF_ERR(diag_sand_prt_multiple(prt_ctr_mc, sand_control, mc_num), ""); \ 394 } 395 396 /** 397 * \brief Verifies validity if row/column position 398 * \param [in] prt_ctr_mc - pointer to the control structure 399 */ 400 #define _PRT_CELL_VERIFY(prt_ctr_mc) \ 401 if(prt_ctr_mc->row_cur == NULL) \ 402 { \ 403 SHR_CLI_EXIT(_SHR_E_INTERNAL, "First row for the table was not allocated\n"); \ 404 } \ 405 if(prt_ctr_mc->col_cur >= prt_ctr_mc->col_num) \ 406 { \ 407 SHR_CLI_EXIT(_SHR_E_INTERNAL, "Cell setting column:%d number of columns:%d\n", \ 408 prt_ctr_mc->col_cur + 1, prt_ctr_mc->col_num); \ 409 } \ 410 if(prt_ctr_mc->columns[prt_ctr_mc->col_cur] == NULL) \ 411 { \ 412 SHR_CLI_EXIT(_SHR_E_INTERNAL, "Column:%d was not allocated\n", prt_ctr_mc->col_cur); \ 413 } 414 415 /** 416 * \brief Fill cell with formatted data 417 * \param prt_ctr_mc [in] - pointer to the control structure 418 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 419 */ 420 #define _PRT_CELL_SET(prt_ctr_mc, ...) \ 421 { \ 422 char *prt_row_offset; \ 423 prt_column_t *prt_column_mc; \ 424 _PRT_CELL_VERIFY(prt_ctr_mc) \ 425 prt_column_mc = prt_ctr_mc->columns[prt_ctr_mc->col_cur]; \ 426 prt_row_offset = (char *)prt_ctr_mc->row_cur + sizeof(rhentry_t) + prt_column_mc->cell_offset; \ 427 PRT_FORMAT(prt_row_offset, prt_column_mc->max_width, __VA_ARGS__); \ 428 if (prt_column_mc->flex_type == PRT_FLEX_ASCII) \ 429 { \ 430 utilex_str_shrink(prt_row_offset); \ 431 } \ 432 prt_row_offset[prt_column_mc->max_width - 1] = 0; \ 433 prt_ctr_mc->col_cur++; \ 434 } 435 436 /** 437 * \brief Fill cell with formatted data 438 * \par DIRECT INPUT variadic variables 439 * \param [in] prt_ctr_mc - pointer to the control structure 440 * \param [in] prt_n - number of shift in the cell, each shift is 2 spaces 441 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 442 */ 443 #define _PRT_CELL_SET_SHIFT(prt_ctr_mc, prt_n, ...) \ 444 { \ 445 char *prt_row_offset; \ 446 prt_column_t *prt_column_mc; \ 447 _PRT_CELL_VERIFY(prt_ctr_mc) \ 448 prt_column_mc = prt_ctr_mc->columns[prt_ctr_mc->col_cur]; \ 449 prt_row_offset = (char *)prt_ctr_mc->row_cur + sizeof(rhentry_t) + prt_column_mc->cell_offset; \ 450 { \ 451 int shift_num = prt_n; \ 452 while(shift_num--) \ 453 { \ 454 PRT_FORMAT(prt_row_offset + strlen(prt_row_offset), prt_column_mc->max_width, " "); \ 455 } \ 456 } \ 457 PRT_FORMAT(prt_row_offset + strlen(prt_row_offset), prt_column_mc->max_width, __VA_ARGS__); \ 458 prt_row_offset[prt_column_mc->max_width - 1] = 0; \ 459 prt_ctr_mc->col_cur++; \ 460 } 461 462 /** 463 * \brief When filling table allows to skip cell 464 * \par DIRECT INPUT 465 * \param [in] prt_ctr_mc - pointer to the control structure 466 * \param [in] mc_skip_num - number of cells to be skipped 467 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 468 */ 469 #define _PRT_CELL_SKIP(prt_ctr_mc, mc_skip_num) \ 470 { \ 471 _PRT_CELL_VERIFY(prt_ctr_mc) \ 472 prt_ctr_mc->col_cur += mc_skip_num; \ 473 } 474 475 /** 476 * \brief Add Info Line after the title and before actual table starts 477 * \par DIRECT INPUT variadic variables 478 * \param [in] prt_ctr_mc - pointer to the control structure 479 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 480 * \remark MACRO limits the size to RHNAME_MAX_SIZE 481 */ 482 #define _PRT_INFO_ADD(prt_ctr_mc, ...) \ 483 { \ 484 rhhandle_t entry; \ 485 if(prt_ctr_mc == NULL) \ 486 { \ 487 SHR_CLI_EXIT(_SHR_E_INTERNAL, "Title was not defined\n"); \ 488 } \ 489 if(prt_ctr_mc->info_list == NULL) \ 490 { \ 491 if((prt_ctr_mc->info_list = utilex_rhlist_create("prt_print", sizeof(prt_info_t), 0)) == NULL) \ 492 { \ 493 SHR_CLI_EXIT(_SHR_E_MEMORY,"info_list create %s", "failed\n"); \ 494 } \ 495 } \ 496 if(utilex_rhlist_entry_add_tail(prt_ctr_mc->info_list, NULL, RHID_TO_BE_GENERATED, &entry) == _SHR_E_MEMORY) \ 497 { \ 498 SHR_CLI_EXIT(_SHR_E_MEMORY,"add entry to info_list %s", "failed\n"); \ 499 } \ 500 ((rhentry_t *)entry)->mode = PRT_ROW_SEP_NONE; \ 501 PRT_FORMAT(((prt_info_t *)entry)->content, PRT_TITLE_WIDTH - 1, __VA_ARGS__); \ 502 } 503 504 /** 505 * \brief Set separator for the last info - how it will be separated from previous line 506 * \param [in] prt_ctr_mc - pointer to the control structure 507 * \par DIRECT INPUT 508 * \param [in] mc_mode Type of separator from previous line. See PRT_ROW_SEP_MODE 509 */ 510 #define _PRT_INFO_SET_MODE(prt_ctr_mc, mc_mode) \ 511 { \ 512 rhentry_t *entry; \ 513 if((entry = utilex_rhlist_entry_get_last(prt_ctr_mc->info_list)) == NULL) \ 514 { \ 515 SHR_CLI_EXIT(_SHR_E_MEMORY,"Setting info mode while no info added\n"); \ 516 } \ 517 else \ 518 { \ 519 entry->mode = mc_mode; \ 520 } \ 521 } 522 523 /** 524 * \brief Low Level Add column routine 525 * \par DIRECT INPUT variadic variables 526 * \param [in] prt_ctr_mc - pointer to the control structure 527 * \param [in] flag - points to the FLEX type of the column to be created, either BINARY or ASCII, see PRT_FLEX_TYPE 528 * \param [in] width - maximum width for cell in the column 529 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 530 * \remark MACRO verifies the number of column does not exceed MAX 531 */ 532 #define _PRT_COLUMN_ADD(prt_ctr_mc, flag, width, ...) \ 533 { \ 534 prt_column_t *prt_column; \ 535 SHR_CLI_EXIT_IF_ERR(diag_sand_prt_column_add(prt_ctr_mc, flag, width, &prt_column),""); \ 536 PRT_FORMAT(prt_column->name, prt_column->max_width, __VA_ARGS__); \ 537 } 538 539 #define _PRT_COLUMN_ALIGN(prt_ctr_mc) \ 540 if((prt_ctr_mc->col_num == 0) || (prt_ctr_mc->columns[prt_ctr_mc->col_num - 1] == NULL)) \ 541 { \ 542 SHR_CLI_EXIT(_SHR_E_MEMORY, "Align for non-allocated column\n"); \ 543 } \ 544 prt_ctr_mc->columns[prt_ctr_mc->col_num - 1]->align = TRUE 545 546 /** 547 * \brief Add column 548 * \par DIRECT INPUT variadic variables 549 * \param [in] prt_ctr_mc - pointer to the control structure 550 * \param [in] prt_type - type of XML node to be created, may be either PRT_XML_CHILD, PRT_XML_ATTRUBUTE or PRT_XML_NONE 551 * \param [in] prt_parent_id - id for parent XML node 552 * \par DIRECT OUTPUT 553 * \param [out] prt_my_id_ptr - pointer for id of this column 554 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 555 * \remark MACRO verifies the number of column does not exceed MAX 556 */ 557 #define _PRT_COLUMN_ADDX(prt_ctr_mc, prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 558 { \ 559 _PRT_COLUMN_ADD(prt_ctr_mc, PRT_FLEX_NONE, PRT_COLUMN_WIDTH, __VA_ARGS__) \ 560 { \ 561 int *loc_my_id_ptr = prt_my_id_ptr; \ 562 prt_ctr_mc->columns[prt_ctr_mc->col_num - 1]->type = prt_type; \ 563 prt_ctr_mc->columns[prt_ctr_mc->col_num - 1]->parent_id = prt_parent_id; \ 564 if(loc_my_id_ptr != NULL) \ 565 *loc_my_id_ptr = prt_ctr_mc->col_num - 1; \ 566 } \ 567 } 568 569 /** 570 * \brief Add column 571 * \par DIRECT INPUT variadic variables 572 * \param [in] prt_ctr_mc - pointer to the control structure 573 * \param [in] flag - points to the FLEX type of the column to be created, either BINARY or ASCII, see PRT_FLEX_TYPE 574 * \param [in] prt_type - type of XML node to be created, may be either PRT_XML_CHILD, PRT_XML_ATTRUBUTE or PRT_XML_NONE 575 * \param [in] prt_parent_id - id for parent XML node 576 * \par DIRECT OUTPUT 577 * \param [out] prt_my_id_ptr - pointer for id of this column 578 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 579 * \remark MACRO verifies the number of column does not exceed MAX 580 */ 581 #define _PRT_COLUMN_ADDX_FLEX(prt_ctr_mc, flag, prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 582 { \ 583 _PRT_COLUMN_ADD(prt_ctr_mc, flag, PRT_COLUMN_WIDTH_BIG, __VA_ARGS__) \ 584 { \ 585 int *loc_my_id_ptr = prt_my_id_ptr; \ 586 prt_ctr_mc->columns[prt_ctr_mc->col_num - 1]->type = prt_type; \ 587 prt_ctr_mc->columns[prt_ctr_mc->col_num - 1]->parent_id = prt_parent_id; \ 588 if(loc_my_id_ptr != NULL) \ 589 *loc_my_id_ptr = prt_ctr_mc->col_num - 1; \ 590 } \ 591 } 592 593 /** 594 * \brief Set Title String for tabular output, it may appear as most upper string on display and top XML node 595 * \par DIRECT INPUT variadic variables 596 * \param [in] prt_ctr_mc - pointer to the control structure 597 * \par INDIRECT OUTPUT 598 * prt_ctr_mc->columns[PRT_TITLE_ID] - title prt column is updated 599 */ 600 #define _PRT_TITLE_SET(prt_ctr_mc, ...) \ 601 { \ 602 if(prt_ctr_mc != NULL) \ 603 { \ 604 SHR_CLI_EXIT(_SHR_E_INTERNAL, "Title may be defined only once\n"); \ 605 } \ 606 if((prt_ctr_mc = sal_alloc(sizeof(prt_control_t), "prt_control")) == NULL) \ 607 { \ 608 SHR_CLI_EXIT(_SHR_E_MEMORY, "No memory for PRT table\n"); \ 609 } \ 610 sal_memset(prt_ctr_mc, 0, sizeof(prt_control_t)); \ 611 if((prt_ctr_mc->columns[PRT_TITLE_ID] = sal_alloc(sizeof(*(prt_ctr_mc->columns[PRT_TITLE_ID])), "prt_title")) == NULL) \ 612 { \ 613 SHR_CLI_EXIT(_SHR_E_MEMORY, "No memory for PRT title\n"); \ 614 } \ 615 sal_memset(prt_ctr_mc->columns[PRT_TITLE_ID], 0, sizeof(*(prt_ctr_mc->columns[PRT_TITLE_ID])) ); \ 616 prt_ctr_mc->unit = unit; \ 617 prt_ctr_mc->columns[PRT_TITLE_ID]->depth = 1; \ 618 PRT_FORMAT(prt_ctr_mc->title, PRT_TITLE_WIDTH, __VA_ARGS__); \ 619 PRT_FORMAT(prt_ctr_mc->columns[PRT_TITLE_ID]->name, PRT_COLUMN_WIDTH, __VA_ARGS__); \ 620 } 621 622 /** 623 * \brief Check if the print title is set. 624 * \param [in] prt_ctr_mc - pointer to the control structure 625 * \par DIRECT OUTPUT 626 * \retval - return 1 if the title is already set, 0 if it is not. 627 */ 628 #define _PRT_TITLE_IS_SET(prt_ctr_mc) ((prt_ctr_mc != NULL) ? 1 : 0) 629 630 /** 631 * \brief Return the total number of columns in the table Used to derive number of columns in the table 632 * \param [in] prt_ctr_mc - pointer to the control structure 633 * \par DIRECT OUTPUT 634 * \retval - number of columns 635 */ 636 #define _PRT_COLUMN_NUM(prt_ctr_mc) prt_ctr_mc->col_num 637 638 /** 639 * \brief Add new row in the table 640 * \par DIRECT INPUT 641 * \param [in] prt_ctr_mc - pointer to the control structure 642 * \param [in] mc_mode Points to the type of separator from previous line. See PRT_ROW_SEP_MODE 643 * \par INDIRECT INPUT prt_list - pointer to the list of rows, that this one will be added to 644 * prt_row_offset - current place in the row to be written (cell pointer) 645 * prt_row_start - pointer to the beginning of row 646 * \par INDIRECT OUTPUT prt_list - new row will be added to this list 647 * prt_row_start - pointer to the beginning of new row 648 * prt_row_offset - set to the beginning of new row skipping control info 649 * \remark First row filled followed by ROW_COLUMN_SET is considered of being header one 650 */ 651 #define _PRT_ROW_ADD(prt_ctr_mc, mc_mode) \ 652 { \ 653 prt_ctr_mc->col_cur = 0; \ 654 if(prt_ctr_mc->list == NULL) \ 655 { \ 656 if((prt_ctr_mc->list = utilex_rhlist_create("prt_print", sizeof(rhentry_t) + prt_ctr_mc->row_width, 0)) == NULL) \ 657 { \ 658 SHR_CLI_EXIT(_SHR_E_MEMORY,"prt_list create %s", "failed\n"); \ 659 } \ 660 } \ 661 if(utilex_rhlist_entry_add_tail(prt_ctr_mc->list, NULL, RHID_TO_BE_GENERATED, &(prt_ctr_mc->row_cur)) == _SHR_E_MEMORY) \ 662 { \ 663 SHR_CLI_EXIT(_SHR_E_MEMORY,"add entry to prt_list %s", "failed\n"); \ 664 } \ 665 ((rhentry_t *)(prt_ctr_mc->row_cur))->mode = mc_mode; \ 666 } 667 668 /** 669 * \brief Delete Last Row in the table 670 * \par DIRECT INPUT 671 * \param [in] prt_ctr_mc - pointer to the control structure 672 * \remark Last Roe will be deleted, used when in process of PRT we decide to skip certain row 673 */ 674 #define _PRT_ROW_DELETE(prt_ctr_mc) \ 675 { \ 676 prt_ctr_mc->col_cur = 0; \ 677 if(prt_ctr_mc->list != NULL) \ 678 { \ 679 rhhandle_t *rhentry = utilex_rhlist_entry_get_last(prt_ctr_mc->list); \ 680 utilex_rhlist_entry_del_free(prt_ctr_mc->list, rhentry); \ 681 } \ 682 } 683 684 /** 685 * \brief Return number of rows in the table 686 * \param [in] prt_ctr_mc - pointer to the control structure 687 */ 688 #define _PRT_ROW_NUM(prt_ctr_mc) ((prt_ctr_mc->list != NULL) ? RHLNUM(prt_ctr_mc->list) : 0) 689 690 /** 691 * \brief Set mode for the last row 692 * \param [in] prt_ctr_mc - pointer to the control structure 693 * \par DIRECT INPUT 694 * \param [in] mc_mode Type of separator from previous line. See PRT_ROW_SEP_MODE 695 */ 696 #define _PRT_ROW_SET_MODE(prt_ctr_mc, mc_mode) \ 697 { \ 698 if(prt_ctr_mc->row_cur == NULL) \ 699 { /* If there are no rows yet - add one to assign mode to */ \ 700 _PRT_ROW_ADD(prt_ctr_mc, mc_mode); \ 701 } \ 702 else \ 703 { \ 704 ((rhentry_t *)(prt_ctr_mc->row_cur))->mode = mc_mode; \ 705 } \ 706 } 707 /* 708 * End of internal pretty printing facilities 709 * } 710 */ 711 712 /* 713 * Below MACROs are for external usage when only 1 table is required 714 * { 715 */ 716 /** 717 * \brief 718 * 1. Declares pointer to control structure used by pretty printing 719 * 2. Invocation should be before any code start 720 * 3. Pointer declared here may be passed down the line in order to have an ability to add cells to the table over 721 * multiple routines 722 * 4. The requirement is to invoke PRT_TITLE_SET, PRT_COMMIT and PRT_FREE only from the routine with PRT_INIT_VARS 723 */ 724 #define PRT_INIT_VARS prt_control_t *prt_ctr = NULL 725 726 /** 727 * \brief 728 * 1. Should be set once per table 729 * 2. Accepts regular printf format 730 * \par DIRECT INPUT variadic variables 731 */ 732 #define PRT_TITLE_SET(...) _PRT_TITLE_SET(prt_ctr, __VA_ARGS__) 733 #define PRT_TITLE_IS_SET _PRT_TITLE_IS_SET(prt_ctr) 734 /** 735 * \brief Add Info 736 * \par DIRECT INPUT variadic variables 737 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 738 * \remark 739 * 1. MACRO limits the size to RHNAME_MAX_SIZE - 1 740 * 2. In XML output all infos will be added to special node at the beginning of the file 741 */ 742 #define PRT_INFO_ADD(...) _PRT_INFO_ADD(prt_ctr, __VA_ARGS__) 743 744 /** 745 * \brief Set mode for the last row 746 * \par DIRECT INPUT 747 * \param [in] mc_mode Type of separator from previous line. See PRT_ROW_SEP_MODE 748 * \remark 749 * Used when the mode could be figured only after it is filled, e.g. when we understand the the row we printed is the 750 * last for certain logic 751 */ 752 #define PRT_INFO_SET_MODE(mc_mode) _PRT_INFO_SET_MODE(prt_ctr, mc_mode) 753 754 /** 755 * \brief Add column to the table with text provided in regular printf format 756 * \par DIRECT INPUT variadic variables 757 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 758 * \remark 759 * MACRO verifies the number of column does not exceed MAX 760 */ 761 #define PRT_COLUMN_ADD(...) _PRT_COLUMN_ADD(prt_ctr, PRT_FLEX_NONE, PRT_COLUMN_WIDTH, __VA_ARGS__) 762 763 /** 764 * \brief 765 * 1. Allows to have cells with size over RHNAME_MAX_SIZE, where cell content is split over multiple rows in the 766 * same column up to PRT_COLUMN_WIDTH_BIG - 1 767 * 2. When column header is bigger than max cell size in the column it will be split over the multiple rows inside 768 * header line 769 * \par DIRECT INPUT variadic variables 770 * \param [in] flag - points to the FLEX type of the column to be created, either BINARY or ASCII, see PRT_FLEX_TYPE 771 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 772 * \remark 773 * 1. MACRO verifies the number of column does not exceed MAX 774 * 2. Use binary for long numbers presentation 775 * 3. Use ASCII for string output 776 */ 777 #define PRT_COLUMN_ADD_FLEX(flag, ...) _PRT_COLUMN_ADD(prt_ctr, flag, PRT_COLUMN_WIDTH_BIG, __VA_ARGS__) 778 779 /** 780 * \brief Add column with specific instructions on XML location 781 * \par DIRECT INPUT variadic variables 782 * \param [in] prt_type - type of XML node to be created, may be either PRT_XML_CHILD, PRT_XML_ATTRUBUTE or PRT_XML_NONE 783 * \param [in] prt_parent_id - id for parent XML node 784 * \param [out] prt_my_id_ptr - pointer for id of this column 785 * \par INDIRECT INPUT prt_ctr_mc - Control structure containing information on table to be printed 786 * \remark 787 * 1. Used in the cases where automatic XML placement does not work, so you need to state explicitly which type do 788 * you want this column to be. See PRT_XML_TYPE for options 789 * 2. MACRO verifies the number of column does not exceed MAX 790 */ 791 #define PRT_COLUMN_ADDX(prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 792 _PRT_COLUMN_ADDX(prt_ctr, prt_type, prt_parent_id, prt_my_id_ptr, __VA_ARGS__) 793 /** 794 * \brief 795 * Combination of PRT_COLUMN_ADDX with flexibility option, see above 796 * \param [in] flag - points to the FLEX type of the column to be created, either BINARY or ASCII, see PRT_FLEX_TYPE 797 * \param [in] prt_type - type of XML node to be created, may be either PRT_XML_CHILD, PRT_XML_ATTRUBUTE or PRT_XML_NONE 798 * \param [in] prt_parent_id - id for parent XML node 799 * \param [out] prt_my_id_ptr - pointer for id of this column 800 */ 801 #define PRT_COLUMN_ADDX_FLEX(flag, prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 802 _PRT_COLUMN_ADDX_FLEX(prt_ctr, flag, prt_type, prt_parent_id, prt_my_id_ptr, __VA_ARGS__) 803 804 /** 805 * \brief 806 * Aligns current column content to the right. By default all columns are aligned to the left 807 * Should be called right after COLUMN_ADD 808 */ 809 #define PRT_COLUMN_ALIGN _PRT_COLUMN_ALIGN(prt_ctr) 810 811 /** 812 * \brief 813 * Returns current column number, is useful to calculate how many columns should be skipped when dealing with table, 814 * where number an order of columns is parameter dependent 815 */ 816 #define PRT_COLUMN_NUM _PRT_COLUMN_NUM(prt_ctr) 817 818 /** 819 * \brief Set mode for the last row 820 * \par DIRECT INPUT 821 * \param [in] mc_mode Type of separator from previous line. See PRT_ROW_SEP_MODE 822 * \remark 823 * Used when the mode could be figured only after it is filled, e.g. when we understand the the row we printed is the 824 * last for certain logic 825 */ 826 #define PRT_ROW_SET_MODE(mc_mode) _PRT_ROW_SET_MODE(prt_ctr, mc_mode) 827 828 /** 829 * \brief Add new row in the table 830 * \par DIRECT INPUT 831 * \param [in] mc_mode Points to the type of separator from previous line. See PRT_ROW_SEP_MODE 832 * \par INDIRECT INPUT prt_list - pointer to the list of rows, that this one will be added to 833 * prt_row_offset - current place in the row to be written (cell pointer) 834 * prt_row_start - pointer to the beginning of row 835 * \par INDIRECT OUTPUT prt_list - new row will be added to this list 836 * prt_row_start - pointer to the beginning of new row 837 * prt_row_offset - set to the beginning of new row skipping control info 838 * \remark First row filled followed by ROW_COLUMN_SET is considered of being header one 839 */ 840 #define PRT_ROW_ADD(mc_mode) _PRT_ROW_ADD(prt_ctr, mc_mode) 841 842 /** 843 * \brief Add new row in the table 844 * \remark Last row in the table to be deleted due to lack of interest in its content 845 */ 846 #define PRT_ROW_DELETE() _PRT_ROW_DELETE(prt_ctr) 847 848 /** 849 * \brief 850 * Returns current row number, is useful to figure out if there were rows at all and how many of them 851 */ 852 #define PRT_ROW_NUM() _PRT_ROW_NUM(prt_ctr) 853 854 /** 855 * \brief Fill cell with formatted data 856 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 857 * \remark 858 * 1. Maximum size of regular cell is PRT_COLUMN_WIDTH - 1 859 * 2. In the case of flexible column size may be up to PRT_COLUMN_WIDTH_BIG - 1 860 * 3. So cell with length between these 2 values will be split either accordingly - see PRT_COLUMN_ADD_FLEX 861 */ 862 #define PRT_CELL_SET(...) _PRT_CELL_SET(prt_ctr, __VA_ARGS__) 863 /** 864 * \brief same as PRT_CELL_SET with only difference being shift inside the cell for indentation purposes 865 * \param [in] prt_n - number of shift in the cell, each shift is 2 spaces 866 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 867 * \remark 868 * Used when we don't want to add additional column, but rather indent certain places in the same column 869 */ 870 #define PRT_CELL_SET_SHIFT(prt_n, ...) _PRT_CELL_SET_SHIFT(prt_ctr, prt_n, __VA_ARGS__) 871 872 /** 873 * \brief When filling table allows to skip cell 874 * \param [in] mc_skip_num - number of cells to be skipped 875 * \par INDIRECT OUTPUT prt_ctr_mc->col_cur is updated, so to reflect that cell was filled 876 * \remark 877 * No need to do SKIP at the end of ROW, anyway new row will start from column 878 */ 879 #define PRT_CELL_SKIP(mc_skip_num) _PRT_CELL_SKIP(prt_ctr, mc_skip_num) 880 881 /** 882 * \brief Actual printing of prepared data, may be used inside or outside framework 883 * \remark 884 * Does not support XML output, see PRT_COMMITF for XML output outside framework 885 */ 886 #define PRT_COMMIT _PRT_COMMIT(prt_ctr) 887 888 /** 889 * \brief Actual printing of prepared data to be used only in the context of shell framework 890 * \remark 891 * Requires presence of sand_control, which is implicitly provided by the shell command invocation parameters, and 892 * should be transfered to underlying routines in the case of PRT usage down stack. 893 * This macro allows to transfer implicitly cli options to PRT - e.g XML file output 894 * Frees the list 895 */ 896 #define PRT_COMMITX _PRT_COMMITX(prt_ctr) 897 898 /** 899 * \brief Actual printing of prepared data to be used, when outside shell framework XML file output may be requested 900 * \param [in] filename_str - XML file to be used for data export, if NULL the one from sand_control may be used 901 * \remark 902 * Requires presence of sand_control, which is implicitly provided by the shell command invocation parameters, and 903 * should be transfered to underlying routines in the case of PRT usage down stack. 904 * This macro allows to transfer implicitly cli options to PRT - e.g XML file output 905 * Frees the list 906 */ 907 #define PRT_COMMITF(filename_str) _PRT_COMMITF(prt_ctr, filename_str) 908 909 /** 910 * \brief Free control structure allocated by SET_TITLE 911 * \remark 912 * Should be always used at the end(usually after exit: label) of routine using pretty printing to catch all errors 913 */ 914 #define PRT_FREE _PRT_FREE(prt_ctr) 915 /* 916 * End of facilities for external usage when only 1 table is required 917 * } 918 */ 919 920 /* 921 * Below MACROs are for external usage when only Simultaneous Multiple Table are required 922 * All MACROs below will have _PL (plural) as a mark for this purpose 923 * All MACROS are exactly the same as regular ones with the only difference being additional parameter of table id 924 * { 925 */ 926 /** 927 * \brief Declares pointer to control structure used by pretty printing 928 * \param [in] mc_num - number of tables required for simultaneous filling 929 */ 930 #define PRT_INIT_VARS_PL(mc_num) prt_control_t *prt_ctr[mc_num] = {NULL} 931 932 /** 933 * All MACROS are exactly the same as regular ones with the only difference being additional parameter of table mc_id 934 * See one table macros for description 935 */ 936 #define PRT_TITLE_SET_PL(mc_id, ...) _PRT_TITLE_SET(prt_ctr[mc_id], __VA_ARGS__) 937 #define PRT_INFO_ADD_PL(mc_id, ...) _PRT_INFO_ADD(prt_ctr[mc_id], __VA_ARGS__) 938 #define PRT_COLUMN_ADD_PL(mc_id, ...) \ 939 _PRT_COLUMN_ADD(prt_ctr[mc_id], PRT_FLEX_NONE, PRT_COLUMN_WIDTH, __VA_ARGS__) 940 #define PRT_COLUMN_ADD_FLEX_PL(mc_id, flag, ...) \ 941 _PRT_COLUMN_ADD(prt_ctr[mc_id], flag, PRT_COLUMN_WIDTH_BIG, __VA_ARGS__) 942 #define PRT_COLUMN_ADDX_PL(mc_id, prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 943 _PRT_COLUMN_ADDX(prt_ctr[mc_id], prt_type, prt_parent_id, prt_my_id_ptr, __VA_ARGS__) 944 #define PRT_COLUMN_ADDX_FLEX_PL(mc_id, flag, prt_type, prt_parent_id, prt_my_id_ptr, ...) \ 945 _PRT_COLUMN_ADDX_FLEX(prt_ctr[mc_id], flag, prt_type, prt_parent_id, prt_my_id_ptr, __VA_ARGS__) 946 #define PRT_COLUMN_NUM_PL(mc_id) _PRT_COLUMN_NUM(prt_ctr[mc_id]) 947 #define PRT_ROW_SET_MODE_PL(mc_id, mc_mode) _PRT_ROW_SET_MODE(prt_ctr[mc_id], mc_mode) 948 #define PRT_ROW_ADD_PL(mc_id, mc_mode) _PRT_ROW_ADD(prt_ctr[mc_id], mc_mode) 949 #define PRT_ROW_NUM_PL(mc_id) _PRT_ROW_NUM(prt_ctr[mc_id]) 950 #define PRT_CELL_SET_PL(mc_id, ...) _PRT_CELL_SET(prt_ctr[mc_id], __VA_ARGS__) 951 #define PRT_CELL_SET_SHIFT_PL(mc_id, prt_n, ...) _PRT_CELL_SET_SHIFT(prt_ctr[mc_id], prt_n, __VA_ARGS__) 952 #define PRT_CELL_SKIP_PL(mc_id, mc_skip_num) _PRT_CELL_SKIP(prt_ctr[mc_id], mc_skip_num) 953 #define PRT_COMMIT_PL(mc_id) _PRT_COMMIT(prt_ctr[mc_id]) 954 #define PRT_COMMITX_PL(mc_id) _PRT_COMMITX(prt_ctr[mc_id]) 955 #define PRT_COMMITF_PL(mc_id, filename_str) _PRT_COMMITF(prt_ctr[mc_id], filename_str) 956 #define PRT_FREE_PL(mc_id) _PRT_FREE(prt_ctr[mc_id]) 957 958 #define PRT_COMMITX_COMBINE_PL(mc_num) _PRT_COMMITX_COMBINE(prt_ctr, mc_num) 959 /* 960 * End of facilities for external usage for multiple tables 961 * } 962 */ 963 964 #endif /* DIAG_SAND_PRT_H */