cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / plugins / text / details / write.c
CommitLineData
55478183 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
55478183 3 *
0235b0db 4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
55478183
PP
5 */
6
55478183 7#include <babeltrace2/babeltrace.h>
c4f23e30 8#include <stdbool.h>
350ad6c1
PP
9#include <stdio.h>
10#include <string.h>
55478183
PP
11
12#include "common/assert.h"
13#include "common/common.h"
6162e6b7 14#include "common/uuid.h"
55478183
PP
15#include "details.h"
16#include "write.h"
17#include "obj-lifetime-mgmt.h"
18#include "colors.h"
19
20static inline
21const char *plural(uint64_t value)
22{
23 return value == 1 ? "" : "s";
24}
25
26static inline
27void incr_indent_by(struct details_write_ctx *ctx, unsigned int value)
28{
98b15851 29 BT_ASSERT_DBG(ctx);
55478183
PP
30 ctx->indent_level += value;
31}
32
33static inline
34void incr_indent(struct details_write_ctx *ctx)
35{
36 incr_indent_by(ctx, 2);
37}
38
39static inline
40void decr_indent_by(struct details_write_ctx *ctx, unsigned int value)
41{
98b15851
PP
42 BT_ASSERT_DBG(ctx);
43 BT_ASSERT_DBG(ctx->indent_level >= value);
55478183
PP
44 ctx->indent_level -= value;
45}
46
47static inline
48void decr_indent(struct details_write_ctx *ctx)
49{
50 decr_indent_by(ctx, 2);
51}
52
53static inline
54void format_uint(char *buf, uint64_t value, unsigned int base)
55{
56 const char *spec = "%" PRIu64;
57 char *buf_start = buf;
58 unsigned int digits_per_group = 3;
59 char sep = ',';
60 bool sep_digits = true;
61
62 switch (base) {
63 case 2:
64 case 16:
65 /* TODO: Support binary format */
66 spec = "%" PRIx64;
67 strcpy(buf, "0x");
68 buf_start = buf + 2;
69 digits_per_group = 4;
70 sep = ':';
71 break;
72 case 8:
73 spec = "%" PRIo64;
74 strcpy(buf, "0");
75 buf_start = buf + 1;
76 sep = ':';
77 break;
78 case 10:
79 if (value <= 9999) {
80 /*
81 * Do not insert digit separators for numbers
82 * under 10,000 as it looks weird.
83 */
84 sep_digits = false;
85 }
86
87 break;
88 default:
498e7994 89 bt_common_abort();
55478183
PP
90 }
91
900eef73
SM
92#pragma GCC diagnostic push
93#pragma GCC diagnostic ignored "-Wformat-nonliteral"
55478183 94 sprintf(buf_start, spec, value);
900eef73 95#pragma GCC diagnostic pop
55478183
PP
96
97 if (sep_digits) {
98 bt_common_sep_digits(buf_start, digits_per_group, sep);
99 }
100}
101
102static inline
103void format_int(char *buf, int64_t value, unsigned int base)
104{
105 const char *spec = "%" PRIu64;
106 char *buf_start = buf;
107 unsigned int digits_per_group = 3;
108 char sep = ',';
109 bool sep_digits = true;
110 uint64_t abs_value = value < 0 ? (uint64_t) -value : (uint64_t) value;
111
112 if (value < 0) {
113 buf[0] = '-';
114 buf_start++;
115 }
116
117 switch (base) {
118 case 2:
119 case 16:
120 /* TODO: Support binary format */
121 spec = "%" PRIx64;
122 strcpy(buf_start, "0x");
123 buf_start += 2;
124 digits_per_group = 4;
125 sep = ':';
126 break;
127 case 8:
128 spec = "%" PRIo64;
129 strcpy(buf_start, "0");
130 buf_start++;
131 sep = ':';
132 break;
133 case 10:
134 if (value >= -9999 && value <= 9999) {
135 /*
136 * Do not insert digit separators for numbers
137 * over -10,000 and under 10,000 as it looks
138 * weird.
139 */
140 sep_digits = false;
141 }
142
143 break;
144 default:
498e7994 145 bt_common_abort();
55478183
PP
146 }
147
900eef73
SM
148#pragma GCC diagnostic push
149#pragma GCC diagnostic ignored "-Wformat-nonliteral"
55478183 150 sprintf(buf_start, spec, abs_value);
900eef73 151#pragma GCC diagnostic pop
55478183
PP
152
153 if (sep_digits) {
154 bt_common_sep_digits(buf_start, digits_per_group, sep);
155 }
156}
157
158static inline
159void write_nl(struct details_write_ctx *ctx)
160{
98b15851 161 BT_ASSERT_DBG(ctx);
55478183
PP
162 g_string_append_c(ctx->str, '\n');
163}
164
165static inline
166void write_sp(struct details_write_ctx *ctx)
167{
98b15851 168 BT_ASSERT_DBG(ctx);
55478183
PP
169 g_string_append_c(ctx->str, ' ');
170}
171
172static inline
173void write_indent(struct details_write_ctx *ctx)
174{
175 uint64_t i;
176
98b15851 177 BT_ASSERT_DBG(ctx);
55478183
PP
178
179 for (i = 0; i < ctx->indent_level; i++) {
180 write_sp(ctx);
181 }
182}
183
184static inline
185void write_compound_member_name(struct details_write_ctx *ctx, const char *name)
186{
187 write_indent(ctx);
188 g_string_append_printf(ctx->str, "%s%s%s:",
189 color_fg_cyan(ctx), name, color_reset(ctx));
190}
191
192static inline
48be9a91
PP
193void write_array_index(struct details_write_ctx *ctx, uint64_t index,
194 const char *color)
55478183
PP
195{
196 char buf[32];
197
198 write_indent(ctx);
199 format_uint(buf, index, 10);
200 g_string_append_printf(ctx->str, "%s[%s]%s:",
48be9a91 201 color, buf, color_reset(ctx));
55478183
PP
202}
203
204static inline
205void write_obj_type_name(struct details_write_ctx *ctx, const char *name)
206{
207 g_string_append_printf(ctx->str, "%s%s%s%s",
04609487
PP
208 color_bold(ctx), color_fg_bright_yellow(ctx), name,
209 color_reset(ctx));
55478183
PP
210}
211
212static inline
213void write_prop_name(struct details_write_ctx *ctx, const char *prop_name)
214{
215 g_string_append_printf(ctx->str, "%s%s%s",
216 color_fg_magenta(ctx), prop_name, color_reset(ctx));
217}
218
48be9a91
PP
219static inline
220void write_prop_name_line(struct details_write_ctx *ctx, const char *prop_name)
221{
222 write_indent(ctx);
223 g_string_append_printf(ctx->str, "%s%s%s:",
224 color_fg_magenta(ctx), prop_name, color_reset(ctx));
225}
226
55478183
PP
227static inline
228void write_str_prop_value(struct details_write_ctx *ctx, const char *value)
229{
230 g_string_append_printf(ctx->str, "%s%s%s",
231 color_bold(ctx), value, color_reset(ctx));
232}
233
25510d56
PP
234static inline
235void write_none_prop_value(struct details_write_ctx *ctx, const char *value)
236{
237 g_string_append_printf(ctx->str, "%s%s%s%s",
04609487 238 color_bold(ctx), color_fg_bright_magenta(ctx),
25510d56
PP
239 value, color_reset(ctx));
240}
241
55478183
PP
242static inline
243void write_uint_str_prop_value(struct details_write_ctx *ctx, const char *value)
244{
245 write_str_prop_value(ctx, value);
246}
247
248static inline
249void write_uint_prop_value(struct details_write_ctx *ctx, uint64_t value)
250{
251 char buf[32];
252
253 format_uint(buf, value, 10);
254 write_uint_str_prop_value(ctx, buf);
255}
256
257static inline
258void write_int_prop_value(struct details_write_ctx *ctx, int64_t value)
259{
260 char buf[32];
261
262 format_int(buf, value, 10);
263 write_uint_str_prop_value(ctx, buf);
264}
265
266static inline
267void write_float_prop_value(struct details_write_ctx *ctx, double value)
268{
269 g_string_append_printf(ctx->str, "%s%f%s",
270 color_bold(ctx), value, color_reset(ctx));
271}
272
273static inline
274void write_str_prop_line(struct details_write_ctx *ctx, const char *prop_name,
275 const char *prop_value)
276{
98b15851 277 BT_ASSERT_DBG(prop_value);
55478183
PP
278 write_indent(ctx);
279 write_prop_name(ctx, prop_name);
280 g_string_append(ctx->str, ": ");
281 write_str_prop_value(ctx, prop_value);
282 write_nl(ctx);
283}
284
285static inline
286void write_uint_prop_line(struct details_write_ctx *ctx, const char *prop_name,
287 uint64_t prop_value)
288{
289 write_indent(ctx);
290 write_prop_name(ctx, prop_name);
291 g_string_append(ctx->str, ": ");
292 write_uint_prop_value(ctx, prop_value);
293 write_nl(ctx);
294}
295
296static inline
297void write_int_prop_line(struct details_write_ctx *ctx, const char *prop_name,
298 int64_t prop_value)
299{
300 write_indent(ctx);
301 write_prop_name(ctx, prop_name);
302 g_string_append(ctx->str, ": ");
303 write_int_prop_value(ctx, prop_value);
304 write_nl(ctx);
305}
306
307static inline
308void write_int_str_prop_value(struct details_write_ctx *ctx, const char *value)
309{
310 write_str_prop_value(ctx, value);
311}
312
313static inline
dacaa55d 314void write_bool_prop_value(struct details_write_ctx *ctx, bt_bool prop_value)
55478183
PP
315{
316 const char *str;
317
dacaa55d 318 g_string_append(ctx->str, color_bold(ctx));
55478183
PP
319
320 if (prop_value) {
04609487 321 g_string_append(ctx->str, color_fg_bright_green(ctx));
55478183
PP
322 str = "Yes";
323 } else {
04609487 324 g_string_append(ctx->str, color_fg_bright_red(ctx));
55478183
PP
325 str = "No";
326 }
327
dacaa55d
PP
328 g_string_append_printf(ctx->str, "%s%s", str, color_reset(ctx));
329}
330
331static inline
332void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
333 bt_bool prop_value)
334{
335 write_indent(ctx);
336 write_prop_name(ctx, prop_name);
337 g_string_append(ctx->str, ": ");
338 write_bool_prop_value(ctx, prop_value);
339 write_nl(ctx);
55478183
PP
340}
341
342static inline
343void write_uuid_prop_line(struct details_write_ctx *ctx, const char *prop_name,
344 bt_uuid uuid)
345{
98b15851 346 BT_ASSERT_DBG(uuid);
55478183
PP
347 write_indent(ctx);
348 write_prop_name(ctx, prop_name);
349 g_string_append_printf(ctx->str,
6162e6b7 350 ": %s" BT_UUID_FMT "%s\n",
55478183 351 color_bold(ctx),
6162e6b7 352 BT_UUID_FMT_VALUES(uuid),
55478183
PP
353 color_reset(ctx));
354}
355
48be9a91
PP
356static
357gint compare_strings(const char **a, const char **b)
358{
359 return strcmp(*a, *b);
360}
361
362static
27c61ce8 363bt_value_map_foreach_entry_const_func_status map_value_foreach_add_key_to_array(
ecd7492f
MJ
364 const char *key,
365 const bt_value *object __attribute__((unused)),
366 void *data)
48be9a91
PP
367{
368 GPtrArray *keys = data;
369
98b15851 370 BT_ASSERT_DBG(keys);
48be9a91 371 g_ptr_array_add(keys, (void *) key);
27c61ce8 372 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
48be9a91
PP
373}
374
375static
376void write_value(struct details_write_ctx *ctx, const bt_value *value,
377 const char *name)
378{
379 uint64_t i;
380 bt_value_type value_type = bt_value_get_type(value);
381 GPtrArray *keys = g_ptr_array_new();
382 char buf[64];
383
98b15851 384 BT_ASSERT_DBG(keys);
48be9a91
PP
385
386 /* Write field's name */
387 if (name) {
388 write_prop_name_line(ctx, name);
389 }
390
391 /* Write field's value */
392 switch (value_type) {
393 case BT_VALUE_TYPE_NULL:
394 write_sp(ctx);
395 write_none_prop_value(ctx, "Null");
396 break;
397 case BT_VALUE_TYPE_BOOL:
398 write_sp(ctx);
399 write_bool_prop_value(ctx, bt_value_bool_get(value));
400 break;
401 case BT_VALUE_TYPE_UNSIGNED_INTEGER:
402 format_uint(buf, bt_value_integer_unsigned_get(value), 10);
403 write_sp(ctx);
404 write_uint_str_prop_value(ctx, buf);
405 break;
406 case BT_VALUE_TYPE_SIGNED_INTEGER:
407 format_int(buf, bt_value_integer_signed_get(value), 10);
408 write_sp(ctx);
409 write_int_str_prop_value(ctx, buf);
410 break;
411 case BT_VALUE_TYPE_REAL:
412 write_sp(ctx);
413 write_float_prop_value(ctx, bt_value_real_get(value));
414 break;
415 case BT_VALUE_TYPE_STRING:
35fbda93
PP
416 if (strlen(bt_value_string_get(value)) > 0) {
417 write_sp(ctx);
418 write_str_prop_value(ctx, bt_value_string_get(value));
419 }
420
48be9a91
PP
421 break;
422 case BT_VALUE_TYPE_ARRAY:
423 {
393729a6 424 uint64_t length = bt_value_array_get_length(value);
48be9a91
PP
425
426 if (length == 0) {
427 write_sp(ctx);
428 write_none_prop_value(ctx, "Empty");
429 } else {
430 g_string_append(ctx->str, " Length ");
431 write_uint_prop_value(ctx, length);
432 g_string_append_c(ctx->str, ':');
433 }
434
435 incr_indent(ctx);
436
437 for (i = 0; i < length; i++) {
438 const bt_value *elem_value =
439 bt_value_array_borrow_element_by_index_const(
440 value, i);
441
442 write_nl(ctx);
443 write_array_index(ctx, i, color_fg_magenta(ctx));
444 write_value(ctx, elem_value, NULL);
445 }
446
447 decr_indent(ctx);
448 break;
449 }
450 case BT_VALUE_TYPE_MAP:
451 {
452 bt_value_map_foreach_entry_const_status foreach_status =
453 bt_value_map_foreach_entry_const(value,
454 map_value_foreach_add_key_to_array, keys);
455
98b15851 456 BT_ASSERT_DBG(foreach_status ==
48be9a91
PP
457 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK);
458 g_ptr_array_sort(keys, (GCompareFunc) compare_strings);
459
460 if (keys->len > 0) {
461 incr_indent(ctx);
462
463 for (i = 0; i < keys->len; i++) {
464 const char *key = keys->pdata[i];
465 const bt_value *entry_value =
466 bt_value_map_borrow_entry_value_const(
467 value, key);
468
469 write_nl(ctx);
470 write_value(ctx, entry_value, key);
471 }
472
473 decr_indent(ctx);
474 } else {
475 write_sp(ctx);
476 write_none_prop_value(ctx, "Empty");
477 }
478
479 break;
480 }
481 default:
498e7994 482 bt_common_abort();
48be9a91
PP
483 }
484
485 g_ptr_array_free(keys, TRUE);
486}
487
488static
489void write_user_attributes(struct details_write_ctx *ctx,
490 const bt_value *user_attrs, bool write_newline, bool *written)
491{
98b15851 492 BT_ASSERT_DBG(user_attrs);
48be9a91
PP
493
494 if (!bt_value_map_is_empty(user_attrs)) {
495 write_value(ctx, user_attrs, "User attributes");
496
497 if (write_newline) {
498 write_nl(ctx);
499 }
500
501 if (written) {
502 *written = true;
503 }
504 }
505}
506
55478183
PP
507static
508void write_int_field_class_props(struct details_write_ctx *ctx,
509 const bt_field_class *fc, bool close)
510{
511 g_string_append_printf(ctx->str, "(%s%" PRIu64 "-bit%s, Base ",
512 color_bold(ctx),
513 bt_field_class_integer_get_field_value_range(fc),
514 color_reset(ctx));
515
516 switch (bt_field_class_integer_get_preferred_display_base(fc)) {
517 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
518 write_uint_prop_value(ctx, 2);
519 break;
520 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
521 write_uint_prop_value(ctx, 8);
522 break;
523 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
524 write_uint_prop_value(ctx, 10);
525 break;
526 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
527 write_uint_prop_value(ctx, 16);
528 break;
529 default:
498e7994 530 bt_common_abort();
55478183
PP
531 }
532
533 if (close) {
534 g_string_append(ctx->str, ")");
535 }
536}
537
45c51519 538struct int_range {
55478183
PP
539 union {
540 uint64_t u;
541 int64_t i;
542 } lower;
543
544 union {
545 uint64_t u;
546 int64_t i;
547 } upper;
548};
549
550struct enum_field_class_mapping {
551 /* Weak */
552 const char *label;
553
45c51519 554 /* Array of `struct int_range` */
55478183
PP
555 GArray *ranges;
556};
557
558static
559gint compare_enum_field_class_mappings(struct enum_field_class_mapping **a,
560 struct enum_field_class_mapping **b)
561{
562 return strcmp((*a)->label, (*b)->label);
563}
564
565static
45c51519 566gint compare_int_ranges_signed(struct int_range *a, struct int_range *b)
55478183
PP
567{
568
569 if (a->lower.i < b->lower.i) {
570 return -1;
571 } else if (a->lower.i > b->lower.i) {
572 return 1;
573 } else {
574 if (a->upper.i < b->upper.i) {
575 return -1;
576 } else if (a->upper.i > b->upper.i) {
577 return 1;
578 } else {
579 return 0;
580 }
581 }
582}
583
584static
45c51519 585gint compare_int_ranges_unsigned(struct int_range *a, struct int_range *b)
55478183
PP
586{
587 if (a->lower.u < b->lower.u) {
588 return -1;
589 } else if (a->lower.u > b->lower.u) {
590 return 1;
591 } else {
592 if (a->upper.u < b->upper.u) {
593 return -1;
594 } else if (a->upper.u > b->upper.u) {
595 return 1;
596 } else {
597 return 0;
598 }
599 }
600}
601
45c51519
PP
602static
603GArray *range_set_to_int_ranges(const void *spec_range_set, bool is_signed)
604{
605 uint64_t i;
606 const bt_integer_range_set *range_set;
607 GArray *ranges = g_array_new(FALSE, TRUE, sizeof(struct int_range));
608
609 if (!ranges) {
610 goto end;
611 }
612
613 if (is_signed) {
614 range_set = bt_integer_range_set_signed_as_range_set_const(
615 spec_range_set);
616 } else {
617 range_set = bt_integer_range_set_unsigned_as_range_set_const(
618 spec_range_set);
619 }
620
621 for (i = 0; i < bt_integer_range_set_get_range_count(range_set); i++) {
622 struct int_range range;
623
624 if (is_signed) {
625 const bt_integer_range_signed *orig_range =
626 bt_integer_range_set_signed_borrow_range_by_index_const(
627 spec_range_set, i);
628
629 range.lower.i = bt_integer_range_signed_get_lower(orig_range);
630 range.upper.i = bt_integer_range_signed_get_upper(orig_range);
631 } else {
632 const bt_integer_range_unsigned *orig_range =
633 bt_integer_range_set_unsigned_borrow_range_by_index_const(
634 spec_range_set, i);
635
636 range.lower.u = bt_integer_range_unsigned_get_lower(orig_range);
637 range.upper.u = bt_integer_range_unsigned_get_upper(orig_range);
638 }
639
640 g_array_append_val(ranges, range);
641 }
642
643 if (is_signed) {
644 g_array_sort(ranges, (GCompareFunc) compare_int_ranges_signed);
645 } else {
646 g_array_sort(ranges,
647 (GCompareFunc) compare_int_ranges_unsigned);
648 }
649
650end:
651 return ranges;
652}
653
55478183
PP
654static
655void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping)
656{
657 if (mapping->ranges) {
658 g_array_free(mapping->ranges, TRUE);
659 mapping->ranges = NULL;
660 }
661
662 g_free(mapping);
663}
664
665static
45c51519
PP
666struct int_range *int_range_at(GArray *ranges, uint64_t index)
667{
d50d46f3 668 return &bt_g_array_index(ranges, struct int_range, index);
45c51519
PP
669}
670
671static
672void write_int_range(struct details_write_ctx *ctx,
673 struct int_range *range, bool is_signed)
55478183
PP
674{
675 g_string_append(ctx->str, "[");
676
677 if (is_signed) {
678 write_int_prop_value(ctx, range->lower.i);
679 } else {
3feba3d8 680 write_uint_prop_value(ctx, range->lower.u);
55478183
PP
681 }
682
45c51519
PP
683 if (range->lower.u != range->upper.u) {
684 g_string_append(ctx->str, ", ");
55478183 685
45c51519
PP
686 if (is_signed) {
687 write_int_prop_value(ctx, range->upper.i);
688 } else {
3feba3d8 689 write_uint_prop_value(ctx, range->upper.u);
45c51519 690 }
55478183
PP
691 }
692
693 g_string_append(ctx->str, "]");
694}
695
696static
697void write_enum_field_class_mappings(struct details_write_ctx *ctx,
698 const bt_field_class *fc)
699{
700 GPtrArray *mappings;
701 uint64_t i;
702 uint64_t range_i;
703 bool is_signed = bt_field_class_get_type(fc) ==
704 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION;
705
706 mappings = g_ptr_array_new_with_free_func(
707 (GDestroyNotify) destroy_enum_field_class_mapping);
98b15851 708 BT_ASSERT_DBG(mappings);
55478183
PP
709
710 /*
711 * Copy field class's mappings to our own arrays and structures
712 * to sort them.
713 */
714 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
715 const void *fc_mapping;
45c51519 716 const void *fc_range_set;
55478183
PP
717 struct enum_field_class_mapping *mapping = g_new0(
718 struct enum_field_class_mapping, 1);
719
98b15851 720 BT_ASSERT_DBG(mapping);
55478183
PP
721
722 if (is_signed) {
9c08c816 723 fc_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
55478183 724 fc, i);
9c08c816 725 fc_range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
45c51519 726 fc_mapping);
55478183 727 } else {
9c08c816 728 fc_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
55478183 729 fc, i);
9c08c816 730 fc_range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
45c51519 731 fc_mapping);
55478183
PP
732 }
733
734 mapping->label = bt_field_class_enumeration_mapping_get_label(
9c08c816 735 bt_field_class_enumeration_signed_mapping_as_mapping_const(
55478183 736 fc_mapping));
45c51519
PP
737 mapping->ranges = range_set_to_int_ranges(fc_range_set,
738 is_signed);
98b15851 739 BT_ASSERT_DBG(mapping->ranges);
55478183
PP
740 g_ptr_array_add(mappings, mapping);
741 }
742
45c51519 743 /* Sort mappings (ranges are already sorted within mappings) */
55478183
PP
744 g_ptr_array_sort(mappings,
745 (GCompareFunc) compare_enum_field_class_mappings);
746
55478183
PP
747 /* Write mappings */
748 for (i = 0; i < mappings->len; i++) {
749 struct enum_field_class_mapping *mapping = mappings->pdata[i];
750
751 write_nl(ctx);
48be9a91 752 write_prop_name_line(ctx, mapping->label);
55478183 753
55478183 754 for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
45c51519
PP
755 write_sp(ctx);
756 write_int_range(ctx,
757 int_range_at(mapping->ranges, range_i),
758 is_signed);
55478183 759 }
55478183
PP
760 }
761
762 g_ptr_array_free(mappings, TRUE);
763}
764
765static
766void write_field_path(struct details_write_ctx *ctx,
767 const bt_field_path *field_path)
768{
769 uint64_t i;
770
771 g_string_append_c(ctx->str, '[');
772
773 switch (bt_field_path_get_root_scope(field_path)) {
e7ceb9df 774 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
55478183
PP
775 write_str_prop_value(ctx, "Packet context");
776 break;
e7ceb9df 777 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
55478183
PP
778 write_str_prop_value(ctx, "Event common context");
779 break;
e7ceb9df 780 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
55478183
PP
781 write_str_prop_value(ctx, "Event specific context");
782 break;
e7ceb9df 783 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
55478183
PP
784 write_str_prop_value(ctx, "Event payload");
785 break;
786 default:
498e7994 787 bt_common_abort();
55478183
PP
788 }
789
790 g_string_append(ctx->str, ": ");
791
792 for (i = 0; i < bt_field_path_get_item_count(field_path); i++) {
793 const bt_field_path_item *fp_item =
794 bt_field_path_borrow_item_by_index_const(field_path, i);
795
796 if (i != 0) {
797 g_string_append(ctx->str, ", ");
798 }
799
800 switch (bt_field_path_item_get_type(fp_item)) {
801 case BT_FIELD_PATH_ITEM_TYPE_INDEX:
802 write_uint_prop_value(ctx,
803 bt_field_path_item_index_get_index(fp_item));
804 break;
805 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
806 write_str_prop_value(ctx, "<current>");
807 break;
808 default:
498e7994 809 bt_common_abort();
55478183
PP
810 }
811 }
812
813 g_string_append_c(ctx->str, ']');
814}
815
816static
45c51519
PP
817void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc);
818
819static
820void write_variant_field_class_option(struct details_write_ctx *ctx,
821 const bt_field_class *fc, uint64_t index)
55478183 822{
55478183 823 bt_field_class_type fc_type = bt_field_class_get_type(fc);
45c51519
PP
824 const bt_field_class_variant_option *option =
825 bt_field_class_variant_borrow_option_by_index_const(
826 fc, index);
48be9a91 827 const void *orig_ranges = NULL;
45c51519
PP
828 GArray *int_ranges = NULL;
829 bool is_signed;
48be9a91
PP
830 const bt_value *user_attrs =
831 bt_field_class_variant_option_borrow_user_attributes_const(
832 option);
833 const bt_field_class *option_fc =
834 bt_field_class_variant_option_borrow_field_class_const(option);
55478183 835
45c51519
PP
836 write_nl(ctx);
837 write_compound_member_name(ctx,
838 bt_field_class_variant_option_get_name(option));
839
de821fe5
PP
840 if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
841 const bt_field_class_variant_with_selector_field_integer_unsigned_option *spec_opt =
842 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
45c51519
PP
843 fc, index);
844
845 orig_ranges =
de821fe5 846 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
45c51519
PP
847 spec_opt);
848 is_signed = false;
de821fe5
PP
849 } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
850 const bt_field_class_variant_with_selector_field_integer_signed_option *spec_opt =
851 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
45c51519
PP
852 fc, index);
853
854 orig_ranges =
de821fe5 855 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
45c51519
PP
856 spec_opt);
857 is_signed = true;
858 }
859
860 if (orig_ranges) {
861 uint64_t i;
862
863 int_ranges = range_set_to_int_ranges(orig_ranges, is_signed);
98b15851 864 BT_ASSERT_DBG(int_ranges);
45c51519
PP
865
866 for (i = 0; i < int_ranges->len; i++) {
867 struct int_range *range = int_range_at(int_ranges, i);
868
869 write_sp(ctx);
870 write_int_range(ctx, range, is_signed);
871 }
872
873 g_string_append(ctx->str, ": ");
874 } else {
55478183
PP
875 write_sp(ctx);
876 }
877
48be9a91
PP
878 if (bt_value_map_is_empty(user_attrs)) {
879 write_field_class(ctx, option_fc);
880 } else {
881 write_nl(ctx);
882 incr_indent(ctx);
45c51519 883
48be9a91
PP
884 /* Field class */
885 write_prop_name_line(ctx, "Field class");
886 write_sp(ctx);
887 write_field_class(ctx, option_fc);
888 write_nl(ctx);
45c51519 889
48be9a91
PP
890 /* User attributes */
891 write_user_attributes(ctx, user_attrs,
892 false, NULL);
45c51519 893
48be9a91 894 decr_indent(ctx);
45c51519
PP
895 }
896
48be9a91
PP
897 if (int_ranges) {
898 g_array_free(int_ranges, TRUE);
45c51519
PP
899 }
900}
901
902static
903void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc)
904{
905 uint64_t i;
906 const char *type;
907 bt_field_class_type fc_type = bt_field_class_get_type(fc);
48be9a91
PP
908 const bt_value *user_attrs;
909 bool wrote_user_attrs = false;
45c51519 910
55478183
PP
911 /* Write field class's type */
912 switch (fc_type) {
dacaa55d
PP
913 case BT_FIELD_CLASS_TYPE_BOOL:
914 type = "Boolean";
915 break;
9684703d
PP
916 case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
917 type = "Bit array";
918 break;
55478183
PP
919 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
920 type = "Unsigned integer";
921 break;
922 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
923 type = "Signed integer";
924 break;
925 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
926 type = "Unsigned enumeration";
927 break;
928 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
929 type = "Signed enumeration";
930 break;
fe4df857
FD
931 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
932 type = "Single-precision real";
933 break;
934 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
935 type = "Double-precision real";
55478183
PP
936 break;
937 case BT_FIELD_CLASS_TYPE_STRING:
938 type = "String";
939 break;
940 case BT_FIELD_CLASS_TYPE_STRUCTURE:
941 type = "Structure";
942 break;
943 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
944 type = "Static array";
945 break;
81b8fa44
PP
946 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
947 type = "Dynamic array (no length field)";
948 break;
949 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
950 type = "Dynamic array (with length field)";
55478183 951 break;
de821fe5 952 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD:
0aa006b7
PP
953 type = "Option (no selector)";
954 break;
de821fe5 955 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
0aa006b7
PP
956 type = "Option (boolean selector)";
957 break;
de821fe5 958 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
0aa006b7
PP
959 type = "Option (unsigned integer selector)";
960 break;
de821fe5 961 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
0aa006b7 962 type = "Option (signed integer selector)";
25510d56 963 break;
de821fe5 964 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
45c51519
PP
965 type = "Variant (no selector)";
966 break;
de821fe5 967 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
fabfe034 968 type = "Variant (unsigned integer selector)";
45c51519 969 break;
de821fe5 970 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
fabfe034 971 type = "Variant (signed integer selector)";
55478183
PP
972 break;
973 default:
498e7994 974 bt_common_abort();
55478183
PP
975 }
976
977 g_string_append_printf(ctx->str, "%s%s%s",
978 color_fg_blue(ctx), type, color_reset(ctx));
979
48be9a91 980 /* Write field class's single-line properties */
ebdb6693 981 if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
55478183
PP
982 uint64_t mapping_count =
983 bt_field_class_enumeration_get_mapping_count(fc);
984
985 write_sp(ctx);
986 write_int_field_class_props(ctx, fc, false);
987 g_string_append(ctx->str, ", ");
988 write_uint_prop_value(ctx, mapping_count);
989 g_string_append_printf(ctx->str, " mapping%s)",
990 plural(mapping_count));
ebdb6693
PP
991 } else if (bt_field_class_type_is(fc_type,
992 BT_FIELD_CLASS_TYPE_INTEGER)) {
993 write_sp(ctx);
994 write_int_field_class_props(ctx, fc, true);
995 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
55478183
PP
996 uint64_t member_count =
997 bt_field_class_structure_get_member_count(fc);
998
999 g_string_append(ctx->str, " (");
1000 write_uint_prop_value(ctx, member_count);
1001 g_string_append_printf(ctx->str, " member%s)",
1002 plural(member_count));
ebdb6693
PP
1003 } else if (fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
1004 g_string_append(ctx->str, " (Length ");
1005 write_uint_prop_value(ctx,
1006 bt_field_class_array_static_get_length(fc));
1007 g_string_append_c(ctx->str, ')');
1008 } else if (fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
1009 const bt_field_path *length_field_path =
1010 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1011 fc);
55478183 1012
ebdb6693
PP
1013 g_string_append(ctx->str, " (Length field path ");
1014 write_field_path(ctx, length_field_path);
1015 g_string_append_c(ctx->str, ')');
1016 } else if (bt_field_class_type_is(fc_type,
1017 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD)) {
25510d56 1018 const bt_field_path *selector_field_path =
de821fe5 1019 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
0aa006b7 1020 fc);
25510d56 1021
0aa006b7
PP
1022 g_string_append(ctx->str, " (Selector field path ");
1023 write_field_path(ctx, selector_field_path);
1024 g_string_append_c(ctx->str, ')');
ebdb6693
PP
1025 } else if (bt_field_class_type_is(fc_type,
1026 BT_FIELD_CLASS_TYPE_VARIANT)) {
48be9a91
PP
1027 uint64_t option_count =
1028 bt_field_class_variant_get_option_count(fc);
1029 const bt_field_path *sel_field_path = NULL;
1030
ebdb6693
PP
1031 if (bt_field_class_type_is(fc_type,
1032 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) {
48be9a91 1033 sel_field_path =
de821fe5 1034 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
48be9a91 1035 fc);
98b15851 1036 BT_ASSERT_DBG(sel_field_path);
48be9a91
PP
1037 }
1038
1039 g_string_append(ctx->str, " (");
1040 write_uint_prop_value(ctx, option_count);
1041 g_string_append_printf(ctx->str, " option%s",
1042 plural(option_count));
1043
1044 if (sel_field_path) {
1045 g_string_append(ctx->str, ", Selector field path ");
1046 write_field_path(ctx, sel_field_path);
1047 }
1048
1049 g_string_append_c(ctx->str, ')');
48be9a91
PP
1050 }
1051
1052 incr_indent(ctx);
1053 user_attrs = bt_field_class_borrow_user_attributes_const(fc);
1054 if (!bt_value_map_is_empty(user_attrs)) {
1055 g_string_append(ctx->str, ":\n");
1056 write_user_attributes(ctx, user_attrs, false, NULL);
1057 wrote_user_attrs = true;
1058 }
1059
1060 /* Write field class's complex properties */
ebdb6693 1061 if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
48be9a91
PP
1062 uint64_t mapping_count =
1063 bt_field_class_enumeration_get_mapping_count(fc);
1064
1065 if (mapping_count > 0) {
1066 if (wrote_user_attrs) {
1067 write_nl(ctx);
1068 write_indent(ctx);
1069 write_prop_name(ctx, "Mappings");
1070 g_string_append_c(ctx->str, ':');
1071 incr_indent(ctx);
1072 } else {
1073 /* Each mapping starts with its own newline */
1074 g_string_append_c(ctx->str, ':');
1075 }
1076
1077 write_enum_field_class_mappings(ctx, fc);
1078
1079 if (wrote_user_attrs) {
1080 decr_indent(ctx);
1081 }
1082 }
ebdb6693 1083 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
48be9a91
PP
1084 uint64_t member_count =
1085 bt_field_class_structure_get_member_count(fc);
1086
1087 if (member_count > 0) {
1088 if (wrote_user_attrs) {
1089 write_nl(ctx);
1090 write_indent(ctx);
1091 write_prop_name(ctx, "Members");
1092 g_string_append_c(ctx->str, ':');
1093 incr_indent(ctx);
1094 } else {
1095 /* Each member starts with its own newline */
1096 g_string_append_c(ctx->str, ':');
1097 }
1098
1099 for (i = 0; i < member_count; i++) {
1100 const bt_field_class_structure_member *member =
1101 bt_field_class_structure_borrow_member_by_index_const(
1102 fc, i);
50233236 1103 const bt_value *member_user_attrs;
48be9a91
PP
1104 const bt_field_class *member_fc =
1105 bt_field_class_structure_member_borrow_field_class_const(member);
1106
1107 write_nl(ctx);
1108 write_compound_member_name(ctx,
1109 bt_field_class_structure_member_get_name(member));
50233236 1110 member_user_attrs = bt_field_class_structure_member_borrow_user_attributes_const(
48be9a91
PP
1111 member);
1112
50233236 1113 if (bt_value_map_is_empty(member_user_attrs)) {
48be9a91
PP
1114 write_sp(ctx);
1115 write_field_class(ctx, member_fc);
1116 } else {
1117 write_nl(ctx);
1118 incr_indent(ctx);
1119
1120 /* Field class */
1121 write_prop_name_line(ctx, "Field class");
1122 write_sp(ctx);
1123 write_field_class(ctx, member_fc);
1124 write_nl(ctx);
1125
1126 /* User attributes */
50233236 1127 write_user_attributes(ctx, member_user_attrs,
48be9a91
PP
1128 false, NULL);
1129
1130 decr_indent(ctx);
1131 }
1132 }
1133
1134 if (wrote_user_attrs) {
1135 decr_indent(ctx);
1136 }
1137 }
ebdb6693 1138 } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
48be9a91
PP
1139 if (wrote_user_attrs) {
1140 write_nl(ctx);
1141 } else {
1142 g_string_append(ctx->str, ":\n");
1143 }
1144
1145 write_prop_name_line(ctx, "Element");
1146 write_sp(ctx);
1147 write_field_class(ctx,
1148 bt_field_class_array_borrow_element_field_class_const(fc));
ebdb6693
PP
1149 } else if (bt_field_class_type_is(fc_type,
1150 BT_FIELD_CLASS_TYPE_OPTION)) {
0aa006b7
PP
1151 const void *ranges = NULL;
1152 bool selector_is_signed = false;
1153
48be9a91
PP
1154 if (wrote_user_attrs) {
1155 write_nl(ctx);
1156 } else {
1157 g_string_append(ctx->str, ":\n");
1158 }
1159
de821fe5 1160 if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) {
0aa006b7 1161 write_bool_prop_line(ctx, "Selector is reversed",
de821fe5
PP
1162 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc));
1163 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
1164 ranges = bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc);
1165 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
1166 ranges = bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc);
0aa006b7
PP
1167 selector_is_signed = true;
1168 }
1169
1170 if (ranges) {
1171 GArray *sorted_ranges = range_set_to_int_ranges(
1172 ranges, selector_is_signed);
0aa006b7 1173
98b15851
PP
1174 BT_ASSERT_DBG(sorted_ranges);
1175 BT_ASSERT_DBG(sorted_ranges->len > 0);
0aa006b7
PP
1176 write_prop_name_line(ctx, "Selector ranges");
1177
1178 for (i = 0; i < sorted_ranges->len; i++) {
1179 write_sp(ctx);
1180 write_int_range(ctx,
1181 int_range_at(sorted_ranges, i),
1182 selector_is_signed);
1183 }
1184
1185 write_nl(ctx);
1186 g_array_free(sorted_ranges, TRUE);
1187 }
1188
48be9a91 1189 write_prop_name_line(ctx, "Content");
25510d56
PP
1190 write_sp(ctx);
1191 write_field_class(ctx,
1192 bt_field_class_option_borrow_field_class_const(fc));
ebdb6693
PP
1193 } else if (bt_field_class_type_is(fc_type,
1194 BT_FIELD_CLASS_TYPE_VARIANT)) {
48be9a91
PP
1195 uint64_t option_count =
1196 bt_field_class_variant_get_option_count(fc);
1197
1198 if (option_count > 0) {
1199 if (wrote_user_attrs) {
1200 write_nl(ctx);
1201 write_indent(ctx);
1202 write_prop_name(ctx, "Options");
1203 g_string_append_c(ctx->str, ':');
1204 incr_indent(ctx);
1205 } else {
1206 /* Each option starts with its own newline */
1207 g_string_append_c(ctx->str, ':');
1208 }
1209
1210 for (i = 0; i < option_count; i++) {
1211 write_variant_field_class_option(ctx, fc, i);
1212 }
1213
1214 if (wrote_user_attrs) {
1215 decr_indent(ctx);
1216 }
1217 }
55478183 1218 }
48be9a91
PP
1219
1220 decr_indent(ctx);
55478183
PP
1221}
1222
1223static
1224void write_root_field_class(struct details_write_ctx *ctx, const char *name,
1225 const bt_field_class *fc)
1226{
98b15851
PP
1227 BT_ASSERT_DBG(name);
1228 BT_ASSERT_DBG(fc);
55478183
PP
1229 write_indent(ctx);
1230 write_prop_name(ctx, name);
1231 g_string_append(ctx->str, ": ");
45c51519 1232 write_field_class(ctx, fc);
55478183
PP
1233 write_nl(ctx);
1234}
1235
1236static
1237void write_event_class(struct details_write_ctx *ctx, const bt_event_class *ec)
1238{
1239 const char *name = bt_event_class_get_name(ec);
1240 const char *emf_uri;
1241 const bt_field_class *fc;
1242 bt_event_class_log_level log_level;
1243
1244 write_indent(ctx);
1245 write_obj_type_name(ctx, "Event class");
1246
1247 /* Write name and ID */
1248 if (name) {
1249 g_string_append_printf(ctx->str, " `%s%s%s`",
1250 color_fg_green(ctx), name, color_reset(ctx));
1251 }
1252
1253 g_string_append(ctx->str, " (ID ");
1254 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1255 g_string_append(ctx->str, "):\n");
1256
1257 /* Write properties */
1258 incr_indent(ctx);
1259
48be9a91
PP
1260 /* Write user attributes */
1261 write_user_attributes(ctx,
1262 bt_event_class_borrow_user_attributes_const(ec), true, NULL);
1263
55478183
PP
1264 /* Write log level */
1265 if (bt_event_class_get_log_level(ec, &log_level) ==
1266 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
1267 const char *ll_str = NULL;
1268
1269 switch (log_level) {
1270 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
1271 ll_str = "Emergency";
1272 break;
1273 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
1274 ll_str = "Alert";
1275 break;
1276 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
1277 ll_str = "Critical";
1278 break;
1279 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
1280 ll_str = "Error";
1281 break;
1282 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
1283 ll_str = "Warning";
1284 break;
1285 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
1286 ll_str = "Notice";
1287 break;
1288 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
1289 ll_str = "Info";
1290 break;
1291 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
1292 ll_str = "Debug (system)";
1293 break;
1294 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
1295 ll_str = "Debug (program)";
1296 break;
1297 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
1298 ll_str = "Debug (process)";
1299 break;
1300 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
1301 ll_str = "Debug (module)";
1302 break;
1303 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
1304 ll_str = "Debug (unit)";
1305 break;
1306 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
1307 ll_str = "Debug (function)";
1308 break;
1309 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
1310 ll_str = "Debug (line)";
1311 break;
1312 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
1313 ll_str = "Debug";
1314 break;
1315 default:
498e7994 1316 bt_common_abort();
55478183
PP
1317 }
1318
1319 write_str_prop_line(ctx, "Log level", ll_str);
1320 }
1321
1322 /* Write EMF URI */
1323 emf_uri = bt_event_class_get_emf_uri(ec);
1324 if (emf_uri) {
1325 write_str_prop_line(ctx, "EMF URI", emf_uri);
1326 }
1327
1328 /* Write specific context field class */
1329 fc = bt_event_class_borrow_specific_context_field_class_const(ec);
1330 if (fc) {
1331 write_root_field_class(ctx, "Specific context field class", fc);
1332 }
1333
1334 /* Write payload field class */
1335 fc = bt_event_class_borrow_payload_field_class_const(ec);
1336 if (fc) {
1337 write_root_field_class(ctx, "Payload field class", fc);
1338 }
1339
1340 decr_indent(ctx);
1341}
1342
1343static
1344void write_clock_class_prop_lines(struct details_write_ctx *ctx,
1345 const bt_clock_class *cc)
1346{
1347 int64_t offset_seconds;
1348 uint64_t offset_cycles;
1349 const char *str;
1350
1351 str = bt_clock_class_get_name(cc);
1352 if (str) {
1353 write_str_prop_line(ctx, "Name", str);
1354 }
1355
48be9a91
PP
1356 write_user_attributes(ctx,
1357 bt_clock_class_borrow_user_attributes_const(cc), true, NULL);
55478183
PP
1358 str = bt_clock_class_get_description(cc);
1359 if (str) {
1360 write_str_prop_line(ctx, "Description", str);
1361 }
1362
1363 write_uint_prop_line(ctx, "Frequency (Hz)",
1364 bt_clock_class_get_frequency(cc));
1365 write_uint_prop_line(ctx, "Precision (cycles)",
1366 bt_clock_class_get_precision(cc));
1367 bt_clock_class_get_offset(cc, &offset_seconds, &offset_cycles);
1368 write_int_prop_line(ctx, "Offset (s)", offset_seconds);
1369 write_uint_prop_line(ctx, "Offset (cycles)", offset_cycles);
1370 write_bool_prop_line(ctx, "Origin is Unix epoch",
1371 bt_clock_class_origin_is_unix_epoch(cc));
1372
1373 if (ctx->details_comp->cfg.with_uuid) {
1374 bt_uuid uuid = bt_clock_class_get_uuid(cc);
1375
1376 if (uuid) {
1377 write_uuid_prop_line(ctx, "UUID", uuid);
1378 }
1379 }
1380}
1381
1382static
1383gint compare_event_classes(const bt_event_class **a, const bt_event_class **b)
1384{
1385 uint64_t id_a = bt_event_class_get_id(*a);
1386 uint64_t id_b = bt_event_class_get_id(*b);
1387
1388 if (id_a < id_b) {
1389 return -1;
1390 } else if (id_a > id_b) {
1391 return 1;
1392 } else {
1393 return 0;
1394 }
1395}
1396
1397static
1398void write_stream_class(struct details_write_ctx *ctx,
1399 const bt_stream_class *sc)
1400{
1401 const bt_field_class *fc;
1402 GPtrArray *event_classes = g_ptr_array_new();
1403 uint64_t i;
1404
1405 write_indent(ctx);
1406 write_obj_type_name(ctx, "Stream class");
1407
1408 /* Write name and ID */
1409 if (ctx->details_comp->cfg.with_stream_class_name) {
1410 const char *name = bt_stream_class_get_name(sc);
1411
1412 if (name) {
1413 g_string_append(ctx->str, " `");
1414 write_str_prop_value(ctx, name);
1415 g_string_append(ctx->str, "`");
1416 }
1417 }
1418
1419 g_string_append(ctx->str, " (ID ");
1420 write_uint_prop_value(ctx, bt_stream_class_get_id(sc));
1421 g_string_append(ctx->str, "):\n");
1422
1423 /* Write properties */
1424 incr_indent(ctx);
1425
48be9a91
PP
1426 /* Write user attributes */
1427 write_user_attributes(ctx,
1428 bt_stream_class_borrow_user_attributes_const(sc), true, NULL);
1429
55478183
PP
1430 /* Write configuration */
1431 write_bool_prop_line(ctx,
26fc5aed
PP
1432 "Supports packets", bt_stream_class_supports_packets(sc));
1433
1434 if (bt_stream_class_supports_packets(sc)) {
1435 write_bool_prop_line(ctx,
1436 "Packets have beginning default clock snapshot",
1437 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
1438 write_bool_prop_line(ctx,
1439 "Packets have end default clock snapshot",
1440 bt_stream_class_packets_have_end_default_clock_snapshot(sc));
1441 }
1442
55478183
PP
1443 write_bool_prop_line(ctx,
1444 "Supports discarded events",
1445 bt_stream_class_supports_discarded_events(sc));
a3c75374
PP
1446
1447 if (bt_stream_class_supports_discarded_events(sc)) {
1448 write_bool_prop_line(ctx,
1449 "Discarded events have default clock snapshots",
1450 bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
1451 }
1452
55478183
PP
1453 write_bool_prop_line(ctx,
1454 "Supports discarded packets",
1455 bt_stream_class_supports_discarded_packets(sc));
a3c75374
PP
1456
1457 if (bt_stream_class_supports_discarded_packets(sc)) {
1458 write_bool_prop_line(ctx,
1459 "Discarded packets have default clock snapshots",
1460 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
1461 }
55478183
PP
1462
1463 /* Write default clock class */
1464 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1465 write_indent(ctx);
1466 write_prop_name(ctx, "Default clock class");
1467 g_string_append_c(ctx->str, ':');
1468 write_nl(ctx);
1469 incr_indent(ctx);
1470 write_clock_class_prop_lines(ctx,
1471 bt_stream_class_borrow_default_clock_class_const(sc));
1472 decr_indent(ctx);
1473 }
1474
1475 fc = bt_stream_class_borrow_packet_context_field_class_const(sc);
1476 if (fc) {
1477 write_root_field_class(ctx, "Packet context field class", fc);
1478 }
1479
1480 fc = bt_stream_class_borrow_event_common_context_field_class_const(sc);
1481 if (fc) {
1482 write_root_field_class(ctx, "Event common context field class",
1483 fc);
1484 }
1485
1486 for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
1487 g_ptr_array_add(event_classes,
1488 (gpointer) bt_stream_class_borrow_event_class_by_index_const(
1489 sc, i));
1490 }
1491
1492 g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
1493
1494 for (i = 0; i < event_classes->len; i++) {
1495 write_event_class(ctx, event_classes->pdata[i]);
1496 }
1497
1498 decr_indent(ctx);
1499 g_ptr_array_free(event_classes, TRUE);
1500}
1501
1502static
1503gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
1504{
1505 uint64_t id_a = bt_stream_class_get_id(*a);
1506 uint64_t id_b = bt_stream_class_get_id(*b);
1507
1508 if (id_a < id_b) {
1509 return -1;
1510 } else if (id_a > id_b) {
1511 return 1;
1512 } else {
1513 return 0;
1514 }
1515}
1516
55478183
PP
1517static
1518void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
1519{
1520 GPtrArray *stream_classes = g_ptr_array_new();
55478183
PP
1521 uint64_t i;
1522 bool printed_prop = false;
1523
1524 write_indent(ctx);
1525 write_obj_type_name(ctx, "Trace class");
1526
48be9a91 1527
55478183
PP
1528 for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
1529 g_ptr_array_add(stream_classes,
1530 (gpointer) bt_trace_class_borrow_stream_class_by_index_const(
1531 tc, i));
1532 }
1533
1534 g_ptr_array_sort(stream_classes, (GCompareFunc) compare_stream_classes);
1535
1536 if (stream_classes->len > 0) {
1537 if (!printed_prop) {
1538 g_string_append(ctx->str, ":\n");
1539 printed_prop = true;
1540 }
1541 }
1542
335a2da5
PP
1543 incr_indent(ctx);
1544
48be9a91
PP
1545 /* Write user attributes */
1546 write_user_attributes(ctx,
1547 bt_trace_class_borrow_user_attributes_const(tc), true,
1548 &printed_prop);
1549
1550 /* Write stream classes */
55478183
PP
1551 for (i = 0; i < stream_classes->len; i++) {
1552 write_stream_class(ctx, stream_classes->pdata[i]);
1553 }
1554
55478183
PP
1555 if (!printed_prop) {
1556 write_nl(ctx);
1557 }
1558
335a2da5 1559 decr_indent(ctx);
55478183 1560 g_ptr_array_free(stream_classes, TRUE);
55478183
PP
1561}
1562
1563static
1564int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
1565 const bt_stream_class *sc, const bt_event_class *ec)
1566{
1567 int ret = 0;
1568
98b15851 1569 BT_ASSERT_DBG(tc);
55478183
PP
1570
1571 if (details_need_to_write_trace_class(ctx, tc)) {
1572 uint64_t sc_i;
1573
1574 if (ctx->details_comp->cfg.compact &&
1575 ctx->details_comp->printed_something) {
1576 /*
1577 * There are no empty line between messages in
1578 * compact mode, so write one here to decouple
1579 * the trace class from the next message.
1580 */
1581 write_nl(ctx);
1582 }
1583
1584 /*
1585 * write_trace_class() also writes all its stream
1586 * classes their event classes, so we don't need to
1587 * rewrite `sc`.
1588 */
1589 write_trace_class(ctx, tc);
55478183
PP
1590
1591 /*
1592 * Mark this trace class as written, as well as all
1593 * its stream classes and their event classes.
1594 */
1595 ret = details_did_write_trace_class(ctx, tc);
1596 if (ret) {
1597 goto end;
1598 }
1599
1600 for (sc_i = 0; sc_i < bt_trace_class_get_stream_class_count(tc);
1601 sc_i++) {
1602 uint64_t ec_i;
1603 const bt_stream_class *tc_sc =
1604 bt_trace_class_borrow_stream_class_by_index_const(
1605 tc, sc_i);
1606
1607 details_did_write_meta_object(ctx, tc, tc_sc);
1608
1609 for (ec_i = 0; ec_i <
1610 bt_stream_class_get_event_class_count(tc_sc);
1611 ec_i++) {
1612 details_did_write_meta_object(ctx, tc,
1613 bt_stream_class_borrow_event_class_by_index_const(
1614 tc_sc, ec_i));
1615 }
1616 }
1617
1618 goto end;
1619 }
1620
1621 if (sc && details_need_to_write_meta_object(ctx, tc, sc)) {
1622 uint64_t ec_i;
1623
98b15851 1624 BT_ASSERT_DBG(tc);
55478183
PP
1625
1626 if (ctx->details_comp->cfg.compact &&
1627 ctx->details_comp->printed_something) {
1628 /*
1629 * There are no empty line between messages in
1630 * compact mode, so write one here to decouple
1631 * the stream class from the next message.
1632 */
1633 write_nl(ctx);
1634 }
1635
1636 /*
1637 * write_stream_class() also writes all its event
1638 * classes, so we don't need to rewrite `ec`.
1639 */
1640 write_stream_class(ctx, sc);
55478183
PP
1641
1642 /*
1643 * Mark this stream class as written, as well as all its
1644 * event classes.
1645 */
1646 details_did_write_meta_object(ctx, tc, sc);
1647
1648 for (ec_i = 0; ec_i <
1649 bt_stream_class_get_event_class_count(sc);
1650 ec_i++) {
1651 details_did_write_meta_object(ctx, tc,
1652 bt_stream_class_borrow_event_class_by_index_const(
1653 sc, ec_i));
1654 }
1655
1656 goto end;
1657 }
1658
1659 if (ec && details_need_to_write_meta_object(ctx, tc, ec)) {
98b15851 1660 BT_ASSERT_DBG(sc);
55478183
PP
1661
1662 if (ctx->details_comp->cfg.compact &&
1663 ctx->details_comp->printed_something) {
1664 /*
1665 * There are no empty line between messages in
1666 * compact mode, so write one here to decouple
1667 * the event class from the next message.
1668 */
1669 write_nl(ctx);
1670 }
1671
1672 write_event_class(ctx, ec);
55478183
PP
1673 details_did_write_meta_object(ctx, tc, ec);
1674 goto end;
1675 }
1676
1677end:
1678 return ret;
1679}
1680
1681static
1682void write_time_str(struct details_write_ctx *ctx, const char *str)
1683{
1684 if (!ctx->details_comp->cfg.with_time) {
1685 goto end;
1686 }
1687
1688 g_string_append_printf(ctx->str, "[%s%s%s%s]",
04609487
PP
1689 color_bold(ctx), color_fg_bright_blue(ctx), str,
1690 color_reset(ctx));
55478183
PP
1691
1692 if (ctx->details_comp->cfg.compact) {
1693 write_sp(ctx);
1694 } else {
1695 write_nl(ctx);
1696 }
1697
1698end:
1699 return;
1700}
1701
1702static
1703void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
1704{
d24d5663 1705 bt_clock_snapshot_get_ns_from_origin_status cs_status;
55478183
PP
1706 int64_t ns_from_origin;
1707 char buf[32];
1708
1709 if (!ctx->details_comp->cfg.with_time) {
1710 goto end;
1711 }
1712
1713 format_uint(buf, bt_clock_snapshot_get_value(cs), 10);
1714 g_string_append_printf(ctx->str, "[%s%s%s%s%s",
04609487 1715 color_bold(ctx), color_fg_bright_blue(ctx), buf,
55478183
PP
1716 color_reset(ctx),
1717 ctx->details_comp->cfg.compact ? "" : " cycles");
d24d5663
PP
1718 cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
1719 if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
55478183
PP
1720 format_int(buf, ns_from_origin, 10);
1721 g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
1722 ctx->details_comp->cfg.compact ? "" : ",",
04609487 1723 color_bold(ctx), color_fg_bright_blue(ctx), buf,
55478183
PP
1724 color_reset(ctx),
1725 ctx->details_comp->cfg.compact ? "" : " ns from origin");
1726 }
1727
1728 g_string_append(ctx->str, "]");
1729
1730 if (ctx->details_comp->cfg.compact) {
1731 write_sp(ctx);
1732 } else {
1733 write_nl(ctx);
1734 }
1735
1736end:
1737 return;
1738}
1739
1740static
1741int write_message_follow_tag(struct details_write_ctx *ctx,
1742 const bt_stream *stream)
1743{
1744 int ret;
1745 uint64_t unique_trace_id;
1746 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1747 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1748
1749 ret = details_trace_unique_id(ctx, trace, &unique_trace_id);
1750 if (ret) {
1751 goto end;
1752 }
1753
1754 if (ctx->details_comp->cfg.compact) {
1755 g_string_append_printf(ctx->str,
04609487 1756 "%s{%s%s%" PRIu64 " %" PRIu64 " %" PRIu64 "%s%s}%s ",
55478183 1757 color_fg_cyan(ctx), color_bold(ctx),
04609487 1758 color_fg_bright_cyan(ctx),
55478183
PP
1759 unique_trace_id, bt_stream_class_get_id(sc),
1760 bt_stream_get_id(stream),
1761 color_reset(ctx), color_fg_cyan(ctx), color_reset(ctx));
1762 } else {
1763 g_string_append_printf(ctx->str,
04609487
PP
1764 "%s{Trace %s%s%" PRIu64 "%s%s, Stream class ID %s%s%" PRIu64 "%s%s, Stream ID %s%s%" PRIu64 "%s%s}%s\n",
1765 color_fg_cyan(ctx),
1766 color_bold(ctx), color_fg_bright_cyan(ctx),
1767 unique_trace_id, color_reset(ctx),
1768 color_fg_cyan(ctx),
1769 color_bold(ctx), color_fg_bright_cyan(ctx),
1770 bt_stream_class_get_id(sc), color_reset(ctx),
55478183 1771 color_fg_cyan(ctx),
04609487
PP
1772 color_bold(ctx), color_fg_bright_cyan(ctx),
1773 bt_stream_get_id(stream), color_reset(ctx),
1774 color_fg_cyan(ctx), color_reset(ctx));
55478183
PP
1775 }
1776
1777end:
1778 return ret;
1779}
1780
1781static
1782void write_field(struct details_write_ctx *ctx, const bt_field *field,
1783 const char *name)
1784{
1785 uint64_t i;
1786 bt_field_class_type fc_type = bt_field_get_class_type(field);
1787 const bt_field_class *fc;
1788 char buf[64];
1789
1790 /* Write field's name */
1791 if (name) {
1792 write_compound_member_name(ctx, name);
1793 }
1794
1795 /* Write field's value */
ebdb6693 1796 if (fc_type == BT_FIELD_CLASS_TYPE_BOOL) {
dacaa55d
PP
1797 write_sp(ctx);
1798 write_bool_prop_value(ctx, bt_field_bool_get_value(field));
ebdb6693 1799 } else if (fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) {
9684703d
PP
1800 format_uint(buf, bt_field_bit_array_get_value_as_integer(field),
1801 16);
1802 write_sp(ctx);
1803 write_uint_str_prop_value(ctx, buf);
ebdb6693
PP
1804 } else if (bt_field_class_type_is(fc_type,
1805 BT_FIELD_CLASS_TYPE_INTEGER)) {
55478183
PP
1806 unsigned int fmt_base;
1807 bt_field_class_integer_preferred_display_base base;
1808
1809 fc = bt_field_borrow_class_const(field);
1810 base = bt_field_class_integer_get_preferred_display_base(fc);
1811
1812 switch (base) {
1813 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
1814 fmt_base = 10;
1815 break;
1816 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
1817 fmt_base = 8;
1818 break;
1819 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
1820 fmt_base = 2;
1821 break;
1822 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
1823 fmt_base = 16;
1824 break;
1825 default:
498e7994 1826 bt_common_abort();
55478183
PP
1827 }
1828
ebdb6693
PP
1829 if (bt_field_class_type_is(fc_type,
1830 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) {
55478183 1831 format_uint(buf,
9c08c816 1832 bt_field_integer_unsigned_get_value(field),
55478183
PP
1833 fmt_base);
1834 write_sp(ctx);
1835 write_uint_str_prop_value(ctx, buf);
1836 } else {
1837 format_int(buf,
9c08c816 1838 bt_field_integer_signed_get_value(field),
55478183
PP
1839 fmt_base);
1840 write_sp(ctx);
1841 write_int_str_prop_value(ctx, buf);
1842 }
ebdb6693 1843 } else if (fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
fe4df857
FD
1844 write_sp(ctx);
1845 write_float_prop_value(ctx, bt_field_real_single_precision_get_value(field));
ebdb6693 1846 } else if (fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) {
55478183 1847 write_sp(ctx);
fe4df857 1848 write_float_prop_value(ctx, bt_field_real_double_precision_get_value(field));
ebdb6693 1849 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRING) {
55478183
PP
1850 write_sp(ctx);
1851 write_str_prop_value(ctx, bt_field_string_get_value(field));
ebdb6693 1852 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
55478183
PP
1853 uint64_t member_count;
1854
1855 fc = bt_field_borrow_class_const(field);
1856 member_count = bt_field_class_structure_get_member_count(fc);
1857
1858 if (member_count > 0) {
1859 incr_indent(ctx);
1860
1861 for (i = 0; i < member_count; i++) {
1862 const bt_field_class_structure_member *member =
1863 bt_field_class_structure_borrow_member_by_index_const(
1864 fc, i);
1865 const bt_field *member_field =
1866 bt_field_structure_borrow_member_field_by_index_const(
1867 field, i);
1868
1869 write_nl(ctx);
1870 write_field(ctx, member_field,
1871 bt_field_class_structure_member_get_name(member));
1872 }
1873
1874 decr_indent(ctx);
1875 } else {
8f512475
PP
1876 write_sp(ctx);
1877 write_none_prop_value(ctx, "Empty");
55478183 1878 }
ebdb6693 1879 } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
55478183
PP
1880 uint64_t length = bt_field_array_get_length(field);
1881
1882 if (length == 0) {
8f512475
PP
1883 write_sp(ctx);
1884 write_none_prop_value(ctx, "Empty");
55478183
PP
1885 } else {
1886 g_string_append(ctx->str, " Length ");
1887 write_uint_prop_value(ctx, length);
1888 g_string_append_c(ctx->str, ':');
1889 }
1890
1891 incr_indent(ctx);
1892
1893 for (i = 0; i < length; i++) {
1894 const bt_field *elem_field =
1895 bt_field_array_borrow_element_field_by_index_const(
1896 field, i);
1897
1898 write_nl(ctx);
48be9a91 1899 write_array_index(ctx, i, color_fg_cyan(ctx));
55478183
PP
1900 write_field(ctx, elem_field, NULL);
1901 }
1902
1903 decr_indent(ctx);
ebdb6693
PP
1904 } else if (bt_field_class_type_is(fc_type,
1905 BT_FIELD_CLASS_TYPE_OPTION)) {
25510d56
PP
1906 const bt_field *content_field =
1907 bt_field_option_borrow_field_const(field);
1908
1909 if (!content_field) {
1910 write_sp(ctx);
1911 write_none_prop_value(ctx, "None");
1912 } else {
1913 write_field(ctx, content_field, NULL);
1914 }
ebdb6693
PP
1915 } else if (bt_field_class_type_is(fc_type,
1916 BT_FIELD_CLASS_TYPE_VARIANT)) {
55478183
PP
1917 write_field(ctx,
1918 bt_field_variant_borrow_selected_option_field_const(
1919 field), NULL);
ebdb6693 1920 } else {
498e7994 1921 bt_common_abort();
55478183
PP
1922 }
1923}
1924
1925static
1926void write_root_field(struct details_write_ctx *ctx, const char *name,
1927 const bt_field *field)
1928{
98b15851
PP
1929 BT_ASSERT_DBG(name);
1930 BT_ASSERT_DBG(field);
55478183
PP
1931 write_indent(ctx);
1932 write_prop_name(ctx, name);
1933 g_string_append(ctx->str, ":");
1934 write_field(ctx, field, NULL);
1935 write_nl(ctx);
1936}
1937
1938static
1939int write_event_message(struct details_write_ctx *ctx,
1940 const bt_message *msg)
1941{
1942 int ret = 0;
1943 const bt_event *event = bt_message_event_borrow_event_const(msg);
1944 const bt_stream *stream = bt_event_borrow_stream_const(event);
1945 const bt_event_class *ec = bt_event_borrow_class_const(event);
1946 const bt_stream_class *sc = bt_event_class_borrow_stream_class_const(ec);
1947 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1948 const char *ec_name;
1949 const bt_field *field;
1950
1951 ret = try_write_meta(ctx, tc, sc, ec);
1952 if (ret) {
1953 goto end;
1954 }
1955
cc413248
PP
1956 if (!ctx->details_comp->cfg.with_data) {
1957 goto end;
1958 }
1959
1960 if (ctx->str->len > 0) {
1961 /*
1962 * Output buffer contains metadata: separate blocks with
1963 * newline.
1964 */
1965 write_nl(ctx);
1966 }
1967
55478183
PP
1968 /* Write time */
1969 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1970 write_time(ctx,
1971 bt_message_event_borrow_default_clock_snapshot_const(
1972 msg));
1973 }
1974
1975 /* Write follow tag for message */
1976 ret = write_message_follow_tag(ctx, stream);
1977 if (ret) {
1978 goto end;
1979 }
1980
1981 /* Write object's basic properties */
1982 write_obj_type_name(ctx, "Event");
1983 ec_name = bt_event_class_get_name(ec);
1984 if (ec_name) {
1985 g_string_append_printf(ctx->str, " `%s%s%s`",
1986 color_fg_green(ctx), ec_name, color_reset(ctx));
1987 }
1988
1989 g_string_append(ctx->str, " (");
1990
1991 if (!ctx->details_comp->cfg.compact) {
1992 g_string_append(ctx->str, "Class ID ");
1993 }
1994
1995 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1996 g_string_append(ctx->str, ")");
1997
1998 if (ctx->details_comp->cfg.compact) {
1999 write_nl(ctx);
2000 goto end;
2001 }
2002
2003 /* Write fields */
2004 g_string_append(ctx->str, ":\n");
2005 incr_indent(ctx);
2006 field = bt_event_borrow_common_context_field_const(event);
2007 if (field) {
2008 write_root_field(ctx, "Common context", field);
2009 }
2010
2011 field = bt_event_borrow_specific_context_field_const(event);
2012 if (field) {
2013 write_root_field(ctx, "Specific context", field);
2014 }
2015
2016 field = bt_event_borrow_payload_field_const(event);
2017 if (field) {
2018 write_root_field(ctx, "Payload", field);
2019 }
2020
2021 decr_indent(ctx);
2022
2023end:
55478183
PP
2024 return ret;
2025}
2026
2027static
2028gint compare_streams(const bt_stream **a, const bt_stream **b)
2029{
2030 uint64_t id_a = bt_stream_get_id(*a);
2031 uint64_t id_b = bt_stream_get_id(*b);
2032
2033 if (id_a < id_b) {
2034 return -1;
2035 } else if (id_a > id_b) {
2036 return 1;
2037 } else {
2038 const bt_stream_class *a_sc = bt_stream_borrow_class_const(*a);
2039 const bt_stream_class *b_sc = bt_stream_borrow_class_const(*b);
2040 uint64_t a_sc_id = bt_stream_class_get_id(a_sc);
2041 uint64_t b_sc_id = bt_stream_class_get_id(b_sc);
2042
2043 if (a_sc_id < b_sc_id) {
2044 return -1;
2045 } else if (a_sc_id > b_sc_id) {
2046 return 1;
2047 } else {
2048 return 0;
2049 }
2050 }
2051}
2052
2053static
2054void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
2055{
55478183
PP
2056 GPtrArray *streams = g_ptr_array_new();
2057 uint64_t i;
2058 bool printed_prop = false;
335a2da5
PP
2059 GPtrArray *env_names = g_ptr_array_new();
2060 uint64_t env_count;
55478183
PP
2061
2062 write_indent(ctx);
2063 write_obj_type_name(ctx, "Trace");
2064
2065 /* Write name */
2066 if (ctx->details_comp->cfg.with_trace_name) {
50233236 2067 const char *name = bt_trace_get_name(trace);
55478183
PP
2068 if (name) {
2069 g_string_append(ctx->str, " `");
2070 write_str_prop_value(ctx, name);
2071 g_string_append(ctx->str, "`");
2072 }
2073 }
2074
2075 /* Write properties */
2076 incr_indent(ctx);
2077
335a2da5
PP
2078 /* Write UUID */
2079 if (ctx->details_comp->cfg.with_uuid) {
2080 bt_uuid uuid = bt_trace_get_uuid(trace);
2081
2082 if (uuid) {
55478183
PP
2083 if (!printed_prop) {
2084 g_string_append(ctx->str, ":\n");
2085 printed_prop = true;
2086 }
2087
335a2da5 2088 write_uuid_prop_line(ctx, "UUID", uuid);
55478183
PP
2089 }
2090 }
2091
335a2da5
PP
2092 /* Write environment */
2093 env_count = bt_trace_get_environment_entry_count(trace);
2094 if (env_count > 0) {
2095 if (!printed_prop) {
2096 g_string_append(ctx->str, ":\n");
2097 printed_prop = true;
2098 }
55478183 2099
335a2da5
PP
2100 write_indent(ctx);
2101 write_prop_name(ctx, "Environment");
2102 g_string_append(ctx->str, " (");
2103 write_uint_prop_value(ctx, env_count);
2104 g_string_append_printf(ctx->str, " entr%s):",
2105 env_count == 1 ? "y" : "ies");
2106 write_nl(ctx);
2107 incr_indent(ctx);
2108
2109 for (i = 0; i < env_count; i++) {
2110 const char *name;
2111 const bt_value *value;
2112
2113 bt_trace_borrow_environment_entry_by_index_const(
2114 trace, i, &name, &value);
2115 g_ptr_array_add(env_names, (gpointer) name);
2116 }
2117
2118 g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
2119
2120 for (i = 0; i < env_names->len; i++) {
2121 const char *name = env_names->pdata[i];
2122 const bt_value *value =
2123 bt_trace_borrow_environment_entry_value_by_name_const(
2124 trace, name);
2125
98b15851 2126 BT_ASSERT_DBG(value);
335a2da5 2127 write_compound_member_name(ctx, name);
335a2da5
PP
2128
2129 if (bt_value_get_type(value) ==
2130 BT_VALUE_TYPE_SIGNED_INTEGER) {
35fbda93 2131 write_sp(ctx);
335a2da5 2132 write_int_prop_value(ctx,
9c08c816 2133 bt_value_integer_signed_get(value));
335a2da5
PP
2134 } else if (bt_value_get_type(value) ==
2135 BT_VALUE_TYPE_STRING) {
35fbda93
PP
2136 if (strlen(bt_value_string_get(value)) > 0) {
2137 write_sp(ctx);
2138 write_str_prop_value(ctx,
2139 bt_value_string_get(value));
2140 }
335a2da5 2141 } else {
498e7994 2142 bt_common_abort();
55478183
PP
2143 }
2144
335a2da5 2145 write_nl(ctx);
55478183 2146 }
335a2da5
PP
2147
2148 decr_indent(ctx);
55478183
PP
2149 }
2150
2151 for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
2152 g_ptr_array_add(streams,
2153 (gpointer) bt_trace_borrow_stream_by_index_const(
2154 trace, i));
2155 }
2156
2157 g_ptr_array_sort(streams, (GCompareFunc) compare_streams);
2158
2159 if (streams->len > 0 && !printed_prop) {
2160 g_string_append(ctx->str, ":\n");
2161 printed_prop = true;
2162 }
2163
2164 for (i = 0; i < streams->len; i++) {
2165 const bt_stream *stream = streams->pdata[i];
2166
2167 write_indent(ctx);
2168 write_obj_type_name(ctx, "Stream");
2169 g_string_append(ctx->str, " (ID ");
2170 write_uint_prop_value(ctx, bt_stream_get_id(stream));
2171 g_string_append(ctx->str, ", Class ID ");
2172 write_uint_prop_value(ctx, bt_stream_class_get_id(
2173 bt_stream_borrow_class_const(stream)));
2174 g_string_append(ctx->str, ")");
2175 write_nl(ctx);
2176 }
2177
2178 decr_indent(ctx);
2179
2180 if (!printed_prop) {
2181 write_nl(ctx);
2182 }
2183
2184 g_ptr_array_free(streams, TRUE);
335a2da5 2185 g_ptr_array_free(env_names, TRUE);
55478183
PP
2186}
2187
2188static
2189int write_stream_beginning_message(struct details_write_ctx *ctx,
2190 const bt_message *msg)
2191{
2192 int ret = 0;
2193 const bt_stream *stream =
2194 bt_message_stream_beginning_borrow_stream_const(msg);
2195 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
2196 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
188edac1 2197 const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
55478183
PP
2198 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
2199 const char *name;
2200
2201 ret = try_write_meta(ctx, tc, sc, NULL);
2202 if (ret) {
2203 goto end;
2204 }
2205
cc413248
PP
2206 if (!ctx->details_comp->cfg.with_data) {
2207 goto end;
2208 }
2209
2210 if (ctx->str->len > 0) {
2211 /*
2212 * Output buffer contains metadata: separate blocks with
2213 * newline.
2214 */
2215 write_nl(ctx);
2216 }
2217
188edac1
SM
2218 /* Write time */
2219 if (cc) {
2220 const bt_clock_snapshot *cs;
2221 bt_message_stream_clock_snapshot_state cs_state =
2222 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
2223
2224 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2225 write_time(ctx, cs);
2226 } else {
2227 write_time_str(ctx, "Unknown");
2228 }
2229 }
2230
55478183
PP
2231 /* Write follow tag for message */
2232 ret = write_message_follow_tag(ctx, stream);
2233 if (ret) {
2234 goto end;
2235 }
2236
2237 /* Write stream properties */
2238 write_obj_type_name(ctx, "Stream beginning");
2239
2240 if (ctx->details_comp->cfg.compact) {
2241 write_nl(ctx);
2242 goto end;
2243 }
2244
2245 g_string_append(ctx->str, ":\n");
2246 incr_indent(ctx);
2247
2248 if (ctx->details_comp->cfg.with_stream_name) {
2249 name = bt_stream_get_name(stream);
2250 if (name) {
2251 write_str_prop_line(ctx, "Name", name);
2252 }
2253 }
2254
2255 if (ctx->details_comp->cfg.with_stream_class_name) {
2256 name = bt_stream_class_get_name(sc);
2257 if (name) {
2258 write_str_prop_line(ctx, "Class name", name);
2259 }
2260 }
2261
2262 write_trace(ctx, trace);
2263 decr_indent(ctx);
2264
2265end:
2266 return ret;
2267}
2268
2269static
2270int write_stream_end_message(struct details_write_ctx *ctx,
2271 const bt_message *msg)
2272{
2273 int ret = 0;
2274 const bt_stream *stream =
2275 bt_message_stream_end_borrow_stream_const(msg);
188edac1
SM
2276 const bt_stream_class *sc =
2277 bt_stream_borrow_class_const(stream);
2278 const bt_clock_class *cc =
2279 bt_stream_class_borrow_default_clock_class_const(sc);
55478183 2280
cc413248
PP
2281 if (!ctx->details_comp->cfg.with_data) {
2282 goto end;
2283 }
2284
55478183 2285 /* Write time */
188edac1
SM
2286 if (cc) {
2287 const bt_clock_snapshot *cs;
2288 bt_message_stream_clock_snapshot_state cs_state =
2289 bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
55478183 2290
188edac1
SM
2291 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2292 write_time(ctx, cs);
2293 } else {
2294 write_time_str(ctx, "Unknown");
2295 }
55478183
PP
2296 }
2297
2298 /* Write follow tag for message */
2299 ret = write_message_follow_tag(ctx, stream);
2300 if (ret) {
2301 goto end;
2302 }
2303
188edac1
SM
2304 /* Write stream properties */
2305 write_obj_type_name(ctx, "Stream end\n");
55478183
PP
2306
2307end:
2308 return ret;
2309}
2310
2311static
2312int write_packet_beginning_message(struct details_write_ctx *ctx,
2313 const bt_message *msg)
2314{
2315 int ret = 0;
2316 const bt_packet *packet =
2317 bt_message_packet_beginning_borrow_packet_const(msg);
2318 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2319 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2320 const bt_field *field;
2321
cc413248
PP
2322 if (!ctx->details_comp->cfg.with_data) {
2323 goto end;
2324 }
2325
55478183
PP
2326 /* Write time */
2327 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
2328 write_time(ctx,
2329 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2330 msg));
2331 }
2332
2333 /* Write follow tag for message */
2334 ret = write_message_follow_tag(ctx, stream);
2335 if (ret) {
2336 goto end;
2337 }
2338
2339 write_obj_type_name(ctx, "Packet beginning");
2340
2341 if (ctx->details_comp->cfg.compact) {
2342 write_nl(ctx);
2343 goto end;
2344 }
2345
2346 /* Write field */
55478183
PP
2347 field = bt_packet_borrow_context_field_const(packet);
2348 if (field) {
340be5dd
PP
2349 g_string_append(ctx->str, ":\n");
2350 incr_indent(ctx);
55478183 2351 write_root_field(ctx, "Context", field);
340be5dd
PP
2352 decr_indent(ctx);
2353 } else {
2354 write_nl(ctx);
55478183
PP
2355 }
2356
55478183
PP
2357end:
2358 return ret;
2359}
2360
2361static
2362int write_discarded_items_message(struct details_write_ctx *ctx,
2363 const char *name, const bt_stream *stream,
2364 const bt_clock_snapshot *beginning_cs,
2365 const bt_clock_snapshot *end_cs, uint64_t count)
2366{
2367 int ret = 0;
2368
2369 /* Write times */
2370 if (beginning_cs) {
2371 write_time(ctx, beginning_cs);
98b15851 2372 BT_ASSERT_DBG(end_cs);
55478183
PP
2373 write_time(ctx, end_cs);
2374 }
2375
2376 /* Write follow tag for message */
2377 ret = write_message_follow_tag(ctx, stream);
2378 if (ret) {
2379 goto end;
2380 }
2381
2382 write_obj_type_name(ctx, "Discarded ");
2383 write_obj_type_name(ctx, name);
2384
2385 /* Write count */
2386 if (count == UINT64_C(-1)) {
2387 write_nl(ctx);
2388 goto end;
2389 }
2390
2391 g_string_append(ctx->str, " (");
2392 write_uint_prop_value(ctx, count);
2393 g_string_append_printf(ctx->str, " %s)\n", name);
2394
2395end:
2396 return ret;
2397}
2398
2399static
2400int write_discarded_events_message(struct details_write_ctx *ctx,
2401 const bt_message *msg)
2402{
cc413248 2403 int ret = 0;
55478183
PP
2404 const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
2405 msg);
2406 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2407 const bt_clock_snapshot *beginning_cs = NULL;
2408 const bt_clock_snapshot *end_cs = NULL;
2409 uint64_t count;
2410
cc413248
PP
2411 if (!ctx->details_comp->cfg.with_data) {
2412 goto end;
2413 }
2414
55478183
PP
2415 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
2416 beginning_cs =
2417 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2418 msg);
2419 end_cs =
2420 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2421 msg);
2422 }
2423
2424 if (bt_message_discarded_events_get_count(msg, &count) !=
2425 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2426 count = UINT64_C(-1);
2427 }
2428
cc413248 2429 ret = write_discarded_items_message(ctx, "events", stream,
55478183 2430 beginning_cs, end_cs, count);
cc413248
PP
2431
2432end:
2433 return ret;
55478183
PP
2434}
2435
2436static
2437int write_discarded_packets_message(struct details_write_ctx *ctx,
2438 const bt_message *msg)
2439{
cc413248 2440 int ret = 0;
55478183
PP
2441 const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
2442 msg);
2443 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2444 const bt_clock_snapshot *beginning_cs = NULL;
2445 const bt_clock_snapshot *end_cs = NULL;
2446 uint64_t count;
2447
cc413248
PP
2448 if (!ctx->details_comp->cfg.with_data) {
2449 goto end;
2450 }
2451
55478183
PP
2452 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
2453 beginning_cs =
2454 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2455 msg);
2456 end_cs =
2457 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2458 msg);
2459 }
2460
2461 if (bt_message_discarded_packets_get_count(msg, &count) !=
2462 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2463 count = UINT64_C(-1);
2464 }
2465
cc413248 2466 ret = write_discarded_items_message(ctx, "packets", stream,
55478183 2467 beginning_cs, end_cs, count);
cc413248
PP
2468
2469end:
2470 return ret;
55478183
PP
2471}
2472
2473static
2474int write_packet_end_message(struct details_write_ctx *ctx,
2475 const bt_message *msg)
2476{
2477 int ret = 0;
2478 const bt_packet *packet =
2479 bt_message_packet_end_borrow_packet_const(msg);
2480 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2481 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2482
cc413248
PP
2483 if (!ctx->details_comp->cfg.with_data) {
2484 goto end;
2485 }
2486
55478183
PP
2487 /* Write time */
2488 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
2489 write_time(ctx,
2490 bt_message_packet_end_borrow_default_clock_snapshot_const(
2491 msg));
2492 }
2493
2494 /* Write follow tag for message */
2495 ret = write_message_follow_tag(ctx, stream);
2496 if (ret) {
2497 goto end;
2498 }
2499
2500 write_obj_type_name(ctx, "Packet end");
2501 write_nl(ctx);
2502
2503end:
2504 return ret;
2505}
2506
2507static
2508int write_message_iterator_inactivity_message(struct details_write_ctx *ctx,
2509 const bt_message *msg)
2510{
2511 int ret = 0;
2512 const bt_clock_snapshot *cs =
60d02328 2513 bt_message_message_iterator_inactivity_borrow_clock_snapshot_const(
55478183
PP
2514 msg);
2515
2516 /* Write time */
2517 write_time(ctx, cs);
2518 write_obj_type_name(ctx, "Message iterator inactivity");
2519
2520 if (ctx->details_comp->cfg.compact) {
2521 write_nl(ctx);
2522 goto end;
2523 }
2524
2525 /* Write clock class properties */
2526 g_string_append(ctx->str, ":\n");
2527 incr_indent(ctx);
2528 write_indent(ctx);
2529 write_prop_name(ctx, "Clock class");
2530 g_string_append_c(ctx->str, ':');
2531 write_nl(ctx);
2532 incr_indent(ctx);
2533 write_clock_class_prop_lines(ctx,
2534 bt_clock_snapshot_borrow_clock_class_const(cs));
2535 decr_indent(ctx);
2536
2537end:
2538 return ret;
2539}
2540
55478183
PP
2541int details_write_message(struct details_comp *details_comp,
2542 const bt_message *msg)
2543{
2544 int ret = 0;
2545 struct details_write_ctx ctx = {
2546 .details_comp = details_comp,
2547 .str = details_comp->str,
2548 .indent_level = 0,
2549 };
2550
2551 /* Reset output buffer */
2552 g_string_assign(details_comp->str, "");
2553
55478183
PP
2554 switch (bt_message_get_type(msg)) {
2555 case BT_MESSAGE_TYPE_EVENT:
2556 ret = write_event_message(&ctx, msg);
2557 break;
2558 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
2559 ret = write_message_iterator_inactivity_message(&ctx, msg);
2560 break;
2561 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
2562 ret = write_stream_beginning_message(&ctx, msg);
2563 break;
2564 case BT_MESSAGE_TYPE_STREAM_END:
2565 ret = write_stream_end_message(&ctx, msg);
2566 break;
2567 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
2568 ret = write_packet_beginning_message(&ctx, msg);
2569 break;
2570 case BT_MESSAGE_TYPE_PACKET_END:
2571 ret = write_packet_end_message(&ctx, msg);
2572 break;
55478183
PP
2573 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
2574 ret = write_discarded_events_message(&ctx, msg);
2575 break;
2576 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
2577 ret = write_discarded_packets_message(&ctx, msg);
2578 break;
2579 default:
498e7994 2580 bt_common_abort();
55478183
PP
2581 }
2582
cc413248
PP
2583 /*
2584 * If this component printed at least one character so far, and
2585 * we're not in compact mode, and there's something in the
2586 * output buffer for this message, then prepend a newline to the
2587 * output buffer to visually separate message blocks.
2588 */
2589 if (details_comp->printed_something && !details_comp->cfg.compact &&
2590 details_comp->str->len > 0) {
2591 /* TODO: Optimize this */
2592 g_string_prepend_c(details_comp->str, '\n');
2593 }
2594
55478183
PP
2595 return ret;
2596}
This page took 0.21092 seconds and 4 git commands to generate.