2 * SPDX-License-Identifier: MIT
4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
7 #include <babeltrace2/babeltrace.h>
12 #include "common/assert.h"
13 #include "common/common.h"
14 #include "common/uuid.h"
17 #include "obj-lifetime-mgmt.h"
21 const char *plural(uint64_t value
)
23 return value
== 1 ? "" : "s";
27 void incr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
30 ctx
->indent_level
+= value
;
34 void incr_indent(struct details_write_ctx
*ctx
)
36 incr_indent_by(ctx
, 2);
40 void decr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
43 BT_ASSERT_DBG(ctx
->indent_level
>= value
);
44 ctx
->indent_level
-= value
;
48 void decr_indent(struct details_write_ctx
*ctx
)
50 decr_indent_by(ctx
, 2);
54 void format_uint(char *buf
, uint64_t value
, unsigned int base
)
56 const char *spec
= "%" PRIu64
;
57 char *buf_start
= buf
;
58 unsigned int digits_per_group
= 3;
60 bool sep_digits
= true;
65 /* TODO: Support binary format */
81 * Do not insert digit separators for numbers
82 * under 10,000 as it looks weird.
92 #pragma GCC diagnostic push
93 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
94 sprintf(buf_start
, spec
, value
);
95 #pragma GCC diagnostic pop
98 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
103 void format_int(char *buf
, int64_t value
, unsigned int base
)
105 const char *spec
= "%" PRIu64
;
106 char *buf_start
= buf
;
107 unsigned int digits_per_group
= 3;
109 bool sep_digits
= true;
110 uint64_t abs_value
= value
< 0 ? (uint64_t) -value
: (uint64_t) value
;
120 /* TODO: Support binary format */
122 strcpy(buf_start
, "0x");
124 digits_per_group
= 4;
129 strcpy(buf_start
, "0");
134 if (value
>= -9999 && value
<= 9999) {
136 * Do not insert digit separators for numbers
137 * over -10,000 and under 10,000 as it looks
148 #pragma GCC diagnostic push
149 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
150 sprintf(buf_start
, spec
, abs_value
);
151 #pragma GCC diagnostic pop
154 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
159 void write_nl(struct details_write_ctx
*ctx
)
162 g_string_append_c(ctx
->str
, '\n');
166 void write_sp(struct details_write_ctx
*ctx
)
169 g_string_append_c(ctx
->str
, ' ');
173 void write_indent(struct details_write_ctx
*ctx
)
179 for (i
= 0; i
< ctx
->indent_level
; i
++) {
185 void write_compound_member_name(struct details_write_ctx
*ctx
, const char *name
)
188 g_string_append_printf(ctx
->str
, "%s%s%s:",
189 color_fg_cyan(ctx
), name
, color_reset(ctx
));
193 void write_array_index(struct details_write_ctx
*ctx
, uint64_t index
,
199 format_uint(buf
, index
, 10);
200 g_string_append_printf(ctx
->str
, "%s[%s]%s:",
201 color
, buf
, color_reset(ctx
));
205 void write_obj_type_name(struct details_write_ctx
*ctx
, const char *name
)
207 g_string_append_printf(ctx
->str
, "%s%s%s%s",
208 color_bold(ctx
), color_fg_bright_yellow(ctx
), name
,
213 void write_prop_name(struct details_write_ctx
*ctx
, const char *prop_name
)
215 g_string_append_printf(ctx
->str
, "%s%s%s",
216 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
220 void write_prop_name_line(struct details_write_ctx
*ctx
, const char *prop_name
)
223 g_string_append_printf(ctx
->str
, "%s%s%s:",
224 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
228 void write_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
230 g_string_append_printf(ctx
->str
, "%s%s%s",
231 color_bold(ctx
), value
, color_reset(ctx
));
235 void write_none_prop_value(struct details_write_ctx
*ctx
, const char *value
)
237 g_string_append_printf(ctx
->str
, "%s%s%s%s",
238 color_bold(ctx
), color_fg_bright_magenta(ctx
),
239 value
, color_reset(ctx
));
243 void write_uint_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
245 write_str_prop_value(ctx
, value
);
249 void write_uint_prop_value(struct details_write_ctx
*ctx
, uint64_t value
)
253 format_uint(buf
, value
, 10);
254 write_uint_str_prop_value(ctx
, buf
);
258 void write_int_prop_value(struct details_write_ctx
*ctx
, int64_t value
)
262 format_int(buf
, value
, 10);
263 write_uint_str_prop_value(ctx
, buf
);
267 void write_float_prop_value(struct details_write_ctx
*ctx
, double value
)
269 g_string_append_printf(ctx
->str
, "%s%f%s",
270 color_bold(ctx
), value
, color_reset(ctx
));
274 void write_str_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
275 const char *prop_value
)
277 BT_ASSERT_DBG(prop_value
);
279 write_prop_name(ctx
, prop_name
);
280 g_string_append(ctx
->str
, ": ");
281 write_str_prop_value(ctx
, prop_value
);
286 void write_uint_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
290 write_prop_name(ctx
, prop_name
);
291 g_string_append(ctx
->str
, ": ");
292 write_uint_prop_value(ctx
, prop_value
);
297 void write_int_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
301 write_prop_name(ctx
, prop_name
);
302 g_string_append(ctx
->str
, ": ");
303 write_int_prop_value(ctx
, prop_value
);
308 void write_int_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
310 write_str_prop_value(ctx
, value
);
314 void write_bool_prop_value(struct details_write_ctx
*ctx
, bt_bool prop_value
)
318 g_string_append(ctx
->str
, color_bold(ctx
));
321 g_string_append(ctx
->str
, color_fg_bright_green(ctx
));
324 g_string_append(ctx
->str
, color_fg_bright_red(ctx
));
328 g_string_append_printf(ctx
->str
, "%s%s", str
, color_reset(ctx
));
332 void write_bool_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
336 write_prop_name(ctx
, prop_name
);
337 g_string_append(ctx
->str
, ": ");
338 write_bool_prop_value(ctx
, prop_value
);
343 void write_uuid_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
348 write_prop_name(ctx
, prop_name
);
349 g_string_append_printf(ctx
->str
,
350 ": %s" BT_UUID_FMT
"%s\n",
352 BT_UUID_FMT_VALUES(uuid
),
357 gint
compare_strings(const char **a
, const char **b
)
359 return strcmp(*a
, *b
);
363 bt_value_map_foreach_entry_const_func_status
map_value_foreach_add_key_to_array(
365 const bt_value
*object
__attribute__((unused
)),
368 GPtrArray
*keys
= data
;
371 g_ptr_array_add(keys
, (void *) key
);
372 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK
;
376 void write_value(struct details_write_ctx
*ctx
, const bt_value
*value
,
380 bt_value_type value_type
= bt_value_get_type(value
);
381 GPtrArray
*keys
= g_ptr_array_new();
386 /* Write field's name */
388 write_prop_name_line(ctx
, name
);
391 /* Write field's value */
392 switch (value_type
) {
393 case BT_VALUE_TYPE_NULL
:
395 write_none_prop_value(ctx
, "Null");
397 case BT_VALUE_TYPE_BOOL
:
399 write_bool_prop_value(ctx
, bt_value_bool_get(value
));
401 case BT_VALUE_TYPE_UNSIGNED_INTEGER
:
402 format_uint(buf
, bt_value_integer_unsigned_get(value
), 10);
404 write_uint_str_prop_value(ctx
, buf
);
406 case BT_VALUE_TYPE_SIGNED_INTEGER
:
407 format_int(buf
, bt_value_integer_signed_get(value
), 10);
409 write_int_str_prop_value(ctx
, buf
);
411 case BT_VALUE_TYPE_REAL
:
413 write_float_prop_value(ctx
, bt_value_real_get(value
));
415 case BT_VALUE_TYPE_STRING
:
417 write_str_prop_value(ctx
, bt_value_string_get(value
));
419 case BT_VALUE_TYPE_ARRAY
:
421 uint64_t length
= bt_value_array_get_length(value
);
425 write_none_prop_value(ctx
, "Empty");
427 g_string_append(ctx
->str
, " Length ");
428 write_uint_prop_value(ctx
, length
);
429 g_string_append_c(ctx
->str
, ':');
434 for (i
= 0; i
< length
; i
++) {
435 const bt_value
*elem_value
=
436 bt_value_array_borrow_element_by_index_const(
440 write_array_index(ctx
, i
, color_fg_magenta(ctx
));
441 write_value(ctx
, elem_value
, NULL
);
447 case BT_VALUE_TYPE_MAP
:
449 bt_value_map_foreach_entry_const_status foreach_status
=
450 bt_value_map_foreach_entry_const(value
,
451 map_value_foreach_add_key_to_array
, keys
);
453 BT_ASSERT_DBG(foreach_status
==
454 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK
);
455 g_ptr_array_sort(keys
, (GCompareFunc
) compare_strings
);
460 for (i
= 0; i
< keys
->len
; i
++) {
461 const char *key
= keys
->pdata
[i
];
462 const bt_value
*entry_value
=
463 bt_value_map_borrow_entry_value_const(
467 write_value(ctx
, entry_value
, key
);
473 write_none_prop_value(ctx
, "Empty");
482 g_ptr_array_free(keys
, TRUE
);
486 void write_user_attributes(struct details_write_ctx
*ctx
,
487 const bt_value
*user_attrs
, bool write_newline
, bool *written
)
489 BT_ASSERT_DBG(user_attrs
);
491 if (!bt_value_map_is_empty(user_attrs
)) {
492 write_value(ctx
, user_attrs
, "User attributes");
505 void write_int_field_class_props(struct details_write_ctx
*ctx
,
506 const bt_field_class
*fc
, bool close
)
508 g_string_append_printf(ctx
->str
, "(%s%" PRIu64
"-bit%s, Base ",
510 bt_field_class_integer_get_field_value_range(fc
),
513 switch (bt_field_class_integer_get_preferred_display_base(fc
)) {
514 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
515 write_uint_prop_value(ctx
, 2);
517 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
518 write_uint_prop_value(ctx
, 8);
520 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
521 write_uint_prop_value(ctx
, 10);
523 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
524 write_uint_prop_value(ctx
, 16);
531 g_string_append(ctx
->str
, ")");
547 struct enum_field_class_mapping
{
551 /* Array of `struct int_range` */
556 gint
compare_enum_field_class_mappings(struct enum_field_class_mapping
**a
,
557 struct enum_field_class_mapping
**b
)
559 return strcmp((*a
)->label
, (*b
)->label
);
563 gint
compare_int_ranges_signed(struct int_range
*a
, struct int_range
*b
)
566 if (a
->lower
.i
< b
->lower
.i
) {
568 } else if (a
->lower
.i
> b
->lower
.i
) {
571 if (a
->upper
.i
< b
->upper
.i
) {
573 } else if (a
->upper
.i
> b
->upper
.i
) {
582 gint
compare_int_ranges_unsigned(struct int_range
*a
, struct int_range
*b
)
584 if (a
->lower
.u
< b
->lower
.u
) {
586 } else if (a
->lower
.u
> b
->lower
.u
) {
589 if (a
->upper
.u
< b
->upper
.u
) {
591 } else if (a
->upper
.u
> b
->upper
.u
) {
600 GArray
*range_set_to_int_ranges(const void *spec_range_set
, bool is_signed
)
603 const bt_integer_range_set
*range_set
;
604 GArray
*ranges
= g_array_new(FALSE
, TRUE
, sizeof(struct int_range
));
611 range_set
= bt_integer_range_set_signed_as_range_set_const(
614 range_set
= bt_integer_range_set_unsigned_as_range_set_const(
618 for (i
= 0; i
< bt_integer_range_set_get_range_count(range_set
); i
++) {
619 struct int_range range
;
622 const bt_integer_range_signed
*orig_range
=
623 bt_integer_range_set_signed_borrow_range_by_index_const(
626 range
.lower
.i
= bt_integer_range_signed_get_lower(orig_range
);
627 range
.upper
.i
= bt_integer_range_signed_get_upper(orig_range
);
629 const bt_integer_range_unsigned
*orig_range
=
630 bt_integer_range_set_unsigned_borrow_range_by_index_const(
633 range
.lower
.u
= bt_integer_range_unsigned_get_lower(orig_range
);
634 range
.upper
.u
= bt_integer_range_unsigned_get_upper(orig_range
);
637 g_array_append_val(ranges
, range
);
641 g_array_sort(ranges
, (GCompareFunc
) compare_int_ranges_signed
);
644 (GCompareFunc
) compare_int_ranges_unsigned
);
652 void destroy_enum_field_class_mapping(struct enum_field_class_mapping
*mapping
)
654 if (mapping
->ranges
) {
655 g_array_free(mapping
->ranges
, TRUE
);
656 mapping
->ranges
= NULL
;
663 struct int_range
*int_range_at(GArray
*ranges
, uint64_t index
)
665 return &bt_g_array_index(ranges
, struct int_range
, index
);
669 void write_int_range(struct details_write_ctx
*ctx
,
670 struct int_range
*range
, bool is_signed
)
672 g_string_append(ctx
->str
, "[");
675 write_int_prop_value(ctx
, range
->lower
.i
);
677 write_uint_prop_value(ctx
, range
->lower
.u
);
680 if (range
->lower
.u
!= range
->upper
.u
) {
681 g_string_append(ctx
->str
, ", ");
684 write_int_prop_value(ctx
, range
->upper
.i
);
686 write_uint_prop_value(ctx
, range
->upper
.u
);
690 g_string_append(ctx
->str
, "]");
694 void write_enum_field_class_mappings(struct details_write_ctx
*ctx
,
695 const bt_field_class
*fc
)
700 bool is_signed
= bt_field_class_get_type(fc
) ==
701 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
;
703 mappings
= g_ptr_array_new_with_free_func(
704 (GDestroyNotify
) destroy_enum_field_class_mapping
);
705 BT_ASSERT_DBG(mappings
);
708 * Copy field class's mappings to our own arrays and structures
711 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(fc
); i
++) {
712 const void *fc_mapping
;
713 const void *fc_range_set
;
714 struct enum_field_class_mapping
*mapping
= g_new0(
715 struct enum_field_class_mapping
, 1);
717 BT_ASSERT_DBG(mapping
);
720 fc_mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
722 fc_range_set
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
725 fc_mapping
= bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
727 fc_range_set
= bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
731 mapping
->label
= bt_field_class_enumeration_mapping_get_label(
732 bt_field_class_enumeration_signed_mapping_as_mapping_const(
734 mapping
->ranges
= range_set_to_int_ranges(fc_range_set
,
736 BT_ASSERT_DBG(mapping
->ranges
);
737 g_ptr_array_add(mappings
, mapping
);
740 /* Sort mappings (ranges are already sorted within mappings) */
741 g_ptr_array_sort(mappings
,
742 (GCompareFunc
) compare_enum_field_class_mappings
);
745 for (i
= 0; i
< mappings
->len
; i
++) {
746 struct enum_field_class_mapping
*mapping
= mappings
->pdata
[i
];
749 write_prop_name_line(ctx
, mapping
->label
);
751 for (range_i
= 0; range_i
< mapping
->ranges
->len
; range_i
++) {
754 int_range_at(mapping
->ranges
, range_i
),
759 g_ptr_array_free(mappings
, TRUE
);
763 void write_field_path(struct details_write_ctx
*ctx
,
764 const bt_field_path
*field_path
)
768 g_string_append_c(ctx
->str
, '[');
770 switch (bt_field_path_get_root_scope(field_path
)) {
771 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
772 write_str_prop_value(ctx
, "Packet context");
774 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
775 write_str_prop_value(ctx
, "Event common context");
777 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
778 write_str_prop_value(ctx
, "Event specific context");
780 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
781 write_str_prop_value(ctx
, "Event payload");
787 g_string_append(ctx
->str
, ": ");
789 for (i
= 0; i
< bt_field_path_get_item_count(field_path
); i
++) {
790 const bt_field_path_item
*fp_item
=
791 bt_field_path_borrow_item_by_index_const(field_path
, i
);
794 g_string_append(ctx
->str
, ", ");
797 switch (bt_field_path_item_get_type(fp_item
)) {
798 case BT_FIELD_PATH_ITEM_TYPE_INDEX
:
799 write_uint_prop_value(ctx
,
800 bt_field_path_item_index_get_index(fp_item
));
802 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
:
803 write_str_prop_value(ctx
, "<current>");
810 g_string_append_c(ctx
->str
, ']');
814 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
);
817 void write_variant_field_class_option(struct details_write_ctx
*ctx
,
818 const bt_field_class
*fc
, uint64_t index
)
820 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
821 const bt_field_class_variant_option
*option
=
822 bt_field_class_variant_borrow_option_by_index_const(
824 const void *orig_ranges
= NULL
;
825 GArray
*int_ranges
= NULL
;
827 const bt_value
*user_attrs
=
828 bt_field_class_variant_option_borrow_user_attributes_const(
830 const bt_field_class
*option_fc
=
831 bt_field_class_variant_option_borrow_field_class_const(option
);
834 write_compound_member_name(ctx
,
835 bt_field_class_variant_option_get_name(option
));
837 if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
838 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*spec_opt
=
839 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
843 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
846 } else if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
847 const bt_field_class_variant_with_selector_field_integer_signed_option
*spec_opt
=
848 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
852 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
860 int_ranges
= range_set_to_int_ranges(orig_ranges
, is_signed
);
861 BT_ASSERT_DBG(int_ranges
);
863 for (i
= 0; i
< int_ranges
->len
; i
++) {
864 struct int_range
*range
= int_range_at(int_ranges
, i
);
867 write_int_range(ctx
, range
, is_signed
);
870 g_string_append(ctx
->str
, ": ");
875 if (bt_value_map_is_empty(user_attrs
)) {
876 write_field_class(ctx
, option_fc
);
882 write_prop_name_line(ctx
, "Field class");
884 write_field_class(ctx
, option_fc
);
887 /* User attributes */
888 write_user_attributes(ctx
, user_attrs
,
895 g_array_free(int_ranges
, TRUE
);
900 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
)
904 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
905 const bt_value
*user_attrs
;
906 bool wrote_user_attrs
= false;
908 /* Write field class's type */
910 case BT_FIELD_CLASS_TYPE_BOOL
:
913 case BT_FIELD_CLASS_TYPE_BIT_ARRAY
:
916 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
917 type
= "Unsigned integer";
919 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
920 type
= "Signed integer";
922 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
923 type
= "Unsigned enumeration";
925 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
926 type
= "Signed enumeration";
928 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
:
929 type
= "Single-precision real";
931 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
:
932 type
= "Double-precision real";
934 case BT_FIELD_CLASS_TYPE_STRING
:
937 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
940 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
941 type
= "Static array";
943 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
944 type
= "Dynamic array (no length field)";
946 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
947 type
= "Dynamic array (with length field)";
949 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD
:
950 type
= "Option (no selector)";
952 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
:
953 type
= "Option (boolean selector)";
955 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
956 type
= "Option (unsigned integer selector)";
958 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
959 type
= "Option (signed integer selector)";
961 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
:
962 type
= "Variant (no selector)";
964 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
965 type
= "Variant (unsigned integer selector)";
967 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
968 type
= "Variant (signed integer selector)";
974 g_string_append_printf(ctx
->str
, "%s%s%s",
975 color_fg_blue(ctx
), type
, color_reset(ctx
));
977 /* Write field class's single-line properties */
978 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
979 uint64_t mapping_count
=
980 bt_field_class_enumeration_get_mapping_count(fc
);
983 write_int_field_class_props(ctx
, fc
, false);
984 g_string_append(ctx
->str
, ", ");
985 write_uint_prop_value(ctx
, mapping_count
);
986 g_string_append_printf(ctx
->str
, " mapping%s)",
987 plural(mapping_count
));
988 } else if (bt_field_class_type_is(fc_type
,
989 BT_FIELD_CLASS_TYPE_INTEGER
)) {
991 write_int_field_class_props(ctx
, fc
, true);
992 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
993 uint64_t member_count
=
994 bt_field_class_structure_get_member_count(fc
);
996 g_string_append(ctx
->str
, " (");
997 write_uint_prop_value(ctx
, member_count
);
998 g_string_append_printf(ctx
->str
, " member%s)",
999 plural(member_count
));
1000 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
1001 g_string_append(ctx
->str
, " (Length ");
1002 write_uint_prop_value(ctx
,
1003 bt_field_class_array_static_get_length(fc
));
1004 g_string_append_c(ctx
->str
, ')');
1005 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
1006 const bt_field_path
*length_field_path
=
1007 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1010 g_string_append(ctx
->str
, " (Length field path ");
1011 write_field_path(ctx
, length_field_path
);
1012 g_string_append_c(ctx
->str
, ')');
1013 } else if (bt_field_class_type_is(fc_type
,
1014 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
1015 const bt_field_path
*selector_field_path
=
1016 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
1019 g_string_append(ctx
->str
, " (Selector field path ");
1020 write_field_path(ctx
, selector_field_path
);
1021 g_string_append_c(ctx
->str
, ')');
1022 } else if (bt_field_class_type_is(fc_type
,
1023 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1024 uint64_t option_count
=
1025 bt_field_class_variant_get_option_count(fc
);
1026 const bt_field_path
*sel_field_path
= NULL
;
1028 if (bt_field_class_type_is(fc_type
,
1029 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
1031 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1033 BT_ASSERT_DBG(sel_field_path
);
1036 g_string_append(ctx
->str
, " (");
1037 write_uint_prop_value(ctx
, option_count
);
1038 g_string_append_printf(ctx
->str
, " option%s",
1039 plural(option_count
));
1041 if (sel_field_path
) {
1042 g_string_append(ctx
->str
, ", Selector field path ");
1043 write_field_path(ctx
, sel_field_path
);
1046 g_string_append_c(ctx
->str
, ')');
1050 user_attrs
= bt_field_class_borrow_user_attributes_const(fc
);
1051 if (!bt_value_map_is_empty(user_attrs
)) {
1052 g_string_append(ctx
->str
, ":\n");
1053 write_user_attributes(ctx
, user_attrs
, false, NULL
);
1054 wrote_user_attrs
= true;
1057 /* Write field class's complex properties */
1058 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
1059 uint64_t mapping_count
=
1060 bt_field_class_enumeration_get_mapping_count(fc
);
1062 if (mapping_count
> 0) {
1063 if (wrote_user_attrs
) {
1066 write_prop_name(ctx
, "Mappings");
1067 g_string_append_c(ctx
->str
, ':');
1070 /* Each mapping starts with its own newline */
1071 g_string_append_c(ctx
->str
, ':');
1074 write_enum_field_class_mappings(ctx
, fc
);
1076 if (wrote_user_attrs
) {
1080 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1081 uint64_t member_count
=
1082 bt_field_class_structure_get_member_count(fc
);
1084 if (member_count
> 0) {
1085 if (wrote_user_attrs
) {
1088 write_prop_name(ctx
, "Members");
1089 g_string_append_c(ctx
->str
, ':');
1092 /* Each member starts with its own newline */
1093 g_string_append_c(ctx
->str
, ':');
1096 for (i
= 0; i
< member_count
; i
++) {
1097 const bt_field_class_structure_member
*member
=
1098 bt_field_class_structure_borrow_member_by_index_const(
1100 const bt_value
*member_user_attrs
;
1101 const bt_field_class
*member_fc
=
1102 bt_field_class_structure_member_borrow_field_class_const(member
);
1105 write_compound_member_name(ctx
,
1106 bt_field_class_structure_member_get_name(member
));
1107 member_user_attrs
= bt_field_class_structure_member_borrow_user_attributes_const(
1110 if (bt_value_map_is_empty(member_user_attrs
)) {
1112 write_field_class(ctx
, member_fc
);
1118 write_prop_name_line(ctx
, "Field class");
1120 write_field_class(ctx
, member_fc
);
1123 /* User attributes */
1124 write_user_attributes(ctx
, member_user_attrs
,
1131 if (wrote_user_attrs
) {
1135 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1136 if (wrote_user_attrs
) {
1139 g_string_append(ctx
->str
, ":\n");
1142 write_prop_name_line(ctx
, "Element");
1144 write_field_class(ctx
,
1145 bt_field_class_array_borrow_element_field_class_const(fc
));
1146 } else if (bt_field_class_type_is(fc_type
,
1147 BT_FIELD_CLASS_TYPE_OPTION
)) {
1148 const void *ranges
= NULL
;
1149 bool selector_is_signed
= false;
1151 if (wrote_user_attrs
) {
1154 g_string_append(ctx
->str
, ":\n");
1157 if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
) {
1158 write_bool_prop_line(ctx
, "Selector is reversed",
1159 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc
));
1160 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
1161 ranges
= bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc
);
1162 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
1163 ranges
= bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc
);
1164 selector_is_signed
= true;
1168 GArray
*sorted_ranges
= range_set_to_int_ranges(
1169 ranges
, selector_is_signed
);
1171 BT_ASSERT_DBG(sorted_ranges
);
1172 BT_ASSERT_DBG(sorted_ranges
->len
> 0);
1173 write_prop_name_line(ctx
, "Selector ranges");
1175 for (i
= 0; i
< sorted_ranges
->len
; i
++) {
1177 write_int_range(ctx
,
1178 int_range_at(sorted_ranges
, i
),
1179 selector_is_signed
);
1183 g_array_free(sorted_ranges
, TRUE
);
1186 write_prop_name_line(ctx
, "Content");
1188 write_field_class(ctx
,
1189 bt_field_class_option_borrow_field_class_const(fc
));
1190 } else if (bt_field_class_type_is(fc_type
,
1191 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1192 uint64_t option_count
=
1193 bt_field_class_variant_get_option_count(fc
);
1195 if (option_count
> 0) {
1196 if (wrote_user_attrs
) {
1199 write_prop_name(ctx
, "Options");
1200 g_string_append_c(ctx
->str
, ':');
1203 /* Each option starts with its own newline */
1204 g_string_append_c(ctx
->str
, ':');
1207 for (i
= 0; i
< option_count
; i
++) {
1208 write_variant_field_class_option(ctx
, fc
, i
);
1211 if (wrote_user_attrs
) {
1221 void write_root_field_class(struct details_write_ctx
*ctx
, const char *name
,
1222 const bt_field_class
*fc
)
1224 BT_ASSERT_DBG(name
);
1227 write_prop_name(ctx
, name
);
1228 g_string_append(ctx
->str
, ": ");
1229 write_field_class(ctx
, fc
);
1234 void write_event_class(struct details_write_ctx
*ctx
, const bt_event_class
*ec
)
1236 const char *name
= bt_event_class_get_name(ec
);
1237 const char *emf_uri
;
1238 const bt_field_class
*fc
;
1239 bt_event_class_log_level log_level
;
1242 write_obj_type_name(ctx
, "Event class");
1244 /* Write name and ID */
1246 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1247 color_fg_green(ctx
), name
, color_reset(ctx
));
1250 g_string_append(ctx
->str
, " (ID ");
1251 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1252 g_string_append(ctx
->str
, "):\n");
1254 /* Write properties */
1257 /* Write user attributes */
1258 write_user_attributes(ctx
,
1259 bt_event_class_borrow_user_attributes_const(ec
), true, NULL
);
1261 /* Write log level */
1262 if (bt_event_class_get_log_level(ec
, &log_level
) ==
1263 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
1264 const char *ll_str
= NULL
;
1266 switch (log_level
) {
1267 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY
:
1268 ll_str
= "Emergency";
1270 case BT_EVENT_CLASS_LOG_LEVEL_ALERT
:
1273 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL
:
1274 ll_str
= "Critical";
1276 case BT_EVENT_CLASS_LOG_LEVEL_ERROR
:
1279 case BT_EVENT_CLASS_LOG_LEVEL_WARNING
:
1282 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE
:
1285 case BT_EVENT_CLASS_LOG_LEVEL_INFO
:
1288 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
:
1289 ll_str
= "Debug (system)";
1291 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
:
1292 ll_str
= "Debug (program)";
1294 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
:
1295 ll_str
= "Debug (process)";
1297 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
:
1298 ll_str
= "Debug (module)";
1300 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
:
1301 ll_str
= "Debug (unit)";
1303 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
:
1304 ll_str
= "Debug (function)";
1306 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
:
1307 ll_str
= "Debug (line)";
1309 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG
:
1316 write_str_prop_line(ctx
, "Log level", ll_str
);
1320 emf_uri
= bt_event_class_get_emf_uri(ec
);
1322 write_str_prop_line(ctx
, "EMF URI", emf_uri
);
1325 /* Write specific context field class */
1326 fc
= bt_event_class_borrow_specific_context_field_class_const(ec
);
1328 write_root_field_class(ctx
, "Specific context field class", fc
);
1331 /* Write payload field class */
1332 fc
= bt_event_class_borrow_payload_field_class_const(ec
);
1334 write_root_field_class(ctx
, "Payload field class", fc
);
1341 void write_clock_class_prop_lines(struct details_write_ctx
*ctx
,
1342 const bt_clock_class
*cc
)
1344 int64_t offset_seconds
;
1345 uint64_t offset_cycles
;
1348 str
= bt_clock_class_get_name(cc
);
1350 write_str_prop_line(ctx
, "Name", str
);
1353 write_user_attributes(ctx
,
1354 bt_clock_class_borrow_user_attributes_const(cc
), true, NULL
);
1355 str
= bt_clock_class_get_description(cc
);
1357 write_str_prop_line(ctx
, "Description", str
);
1360 write_uint_prop_line(ctx
, "Frequency (Hz)",
1361 bt_clock_class_get_frequency(cc
));
1362 write_uint_prop_line(ctx
, "Precision (cycles)",
1363 bt_clock_class_get_precision(cc
));
1364 bt_clock_class_get_offset(cc
, &offset_seconds
, &offset_cycles
);
1365 write_int_prop_line(ctx
, "Offset (s)", offset_seconds
);
1366 write_uint_prop_line(ctx
, "Offset (cycles)", offset_cycles
);
1367 write_bool_prop_line(ctx
, "Origin is Unix epoch",
1368 bt_clock_class_origin_is_unix_epoch(cc
));
1370 if (ctx
->details_comp
->cfg
.with_uuid
) {
1371 bt_uuid uuid
= bt_clock_class_get_uuid(cc
);
1374 write_uuid_prop_line(ctx
, "UUID", uuid
);
1380 gint
compare_event_classes(const bt_event_class
**a
, const bt_event_class
**b
)
1382 uint64_t id_a
= bt_event_class_get_id(*a
);
1383 uint64_t id_b
= bt_event_class_get_id(*b
);
1387 } else if (id_a
> id_b
) {
1395 void write_stream_class(struct details_write_ctx
*ctx
,
1396 const bt_stream_class
*sc
)
1398 const bt_field_class
*fc
;
1399 GPtrArray
*event_classes
= g_ptr_array_new();
1403 write_obj_type_name(ctx
, "Stream class");
1405 /* Write name and ID */
1406 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
1407 const char *name
= bt_stream_class_get_name(sc
);
1410 g_string_append(ctx
->str
, " `");
1411 write_str_prop_value(ctx
, name
);
1412 g_string_append(ctx
->str
, "`");
1416 g_string_append(ctx
->str
, " (ID ");
1417 write_uint_prop_value(ctx
, bt_stream_class_get_id(sc
));
1418 g_string_append(ctx
->str
, "):\n");
1420 /* Write properties */
1423 /* Write user attributes */
1424 write_user_attributes(ctx
,
1425 bt_stream_class_borrow_user_attributes_const(sc
), true, NULL
);
1427 /* Write configuration */
1428 write_bool_prop_line(ctx
,
1429 "Supports packets", bt_stream_class_supports_packets(sc
));
1431 if (bt_stream_class_supports_packets(sc
)) {
1432 write_bool_prop_line(ctx
,
1433 "Packets have beginning default clock snapshot",
1434 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
));
1435 write_bool_prop_line(ctx
,
1436 "Packets have end default clock snapshot",
1437 bt_stream_class_packets_have_end_default_clock_snapshot(sc
));
1440 write_bool_prop_line(ctx
,
1441 "Supports discarded events",
1442 bt_stream_class_supports_discarded_events(sc
));
1444 if (bt_stream_class_supports_discarded_events(sc
)) {
1445 write_bool_prop_line(ctx
,
1446 "Discarded events have default clock snapshots",
1447 bt_stream_class_discarded_events_have_default_clock_snapshots(sc
));
1450 write_bool_prop_line(ctx
,
1451 "Supports discarded packets",
1452 bt_stream_class_supports_discarded_packets(sc
));
1454 if (bt_stream_class_supports_discarded_packets(sc
)) {
1455 write_bool_prop_line(ctx
,
1456 "Discarded packets have default clock snapshots",
1457 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
));
1460 /* Write default clock class */
1461 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1463 write_prop_name(ctx
, "Default clock class");
1464 g_string_append_c(ctx
->str
, ':');
1467 write_clock_class_prop_lines(ctx
,
1468 bt_stream_class_borrow_default_clock_class_const(sc
));
1472 fc
= bt_stream_class_borrow_packet_context_field_class_const(sc
);
1474 write_root_field_class(ctx
, "Packet context field class", fc
);
1477 fc
= bt_stream_class_borrow_event_common_context_field_class_const(sc
);
1479 write_root_field_class(ctx
, "Event common context field class",
1483 for (i
= 0; i
< bt_stream_class_get_event_class_count(sc
); i
++) {
1484 g_ptr_array_add(event_classes
,
1485 (gpointer
) bt_stream_class_borrow_event_class_by_index_const(
1489 g_ptr_array_sort(event_classes
, (GCompareFunc
) compare_event_classes
);
1491 for (i
= 0; i
< event_classes
->len
; i
++) {
1492 write_event_class(ctx
, event_classes
->pdata
[i
]);
1496 g_ptr_array_free(event_classes
, TRUE
);
1500 gint
compare_stream_classes(const bt_stream_class
**a
, const bt_stream_class
**b
)
1502 uint64_t id_a
= bt_stream_class_get_id(*a
);
1503 uint64_t id_b
= bt_stream_class_get_id(*b
);
1507 } else if (id_a
> id_b
) {
1515 void write_trace_class(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
)
1517 GPtrArray
*stream_classes
= g_ptr_array_new();
1519 bool printed_prop
= false;
1522 write_obj_type_name(ctx
, "Trace class");
1525 for (i
= 0; i
< bt_trace_class_get_stream_class_count(tc
); i
++) {
1526 g_ptr_array_add(stream_classes
,
1527 (gpointer
) bt_trace_class_borrow_stream_class_by_index_const(
1531 g_ptr_array_sort(stream_classes
, (GCompareFunc
) compare_stream_classes
);
1533 if (stream_classes
->len
> 0) {
1534 if (!printed_prop
) {
1535 g_string_append(ctx
->str
, ":\n");
1536 printed_prop
= true;
1542 /* Write user attributes */
1543 write_user_attributes(ctx
,
1544 bt_trace_class_borrow_user_attributes_const(tc
), true,
1547 /* Write stream classes */
1548 for (i
= 0; i
< stream_classes
->len
; i
++) {
1549 write_stream_class(ctx
, stream_classes
->pdata
[i
]);
1552 if (!printed_prop
) {
1557 g_ptr_array_free(stream_classes
, TRUE
);
1561 int try_write_meta(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
,
1562 const bt_stream_class
*sc
, const bt_event_class
*ec
)
1568 if (details_need_to_write_trace_class(ctx
, tc
)) {
1571 if (ctx
->details_comp
->cfg
.compact
&&
1572 ctx
->details_comp
->printed_something
) {
1574 * There are no empty line between messages in
1575 * compact mode, so write one here to decouple
1576 * the trace class from the next message.
1582 * write_trace_class() also writes all its stream
1583 * classes their event classes, so we don't need to
1586 write_trace_class(ctx
, tc
);
1589 * Mark this trace class as written, as well as all
1590 * its stream classes and their event classes.
1592 ret
= details_did_write_trace_class(ctx
, tc
);
1597 for (sc_i
= 0; sc_i
< bt_trace_class_get_stream_class_count(tc
);
1600 const bt_stream_class
*tc_sc
=
1601 bt_trace_class_borrow_stream_class_by_index_const(
1604 details_did_write_meta_object(ctx
, tc
, tc_sc
);
1606 for (ec_i
= 0; ec_i
<
1607 bt_stream_class_get_event_class_count(tc_sc
);
1609 details_did_write_meta_object(ctx
, tc
,
1610 bt_stream_class_borrow_event_class_by_index_const(
1618 if (sc
&& details_need_to_write_meta_object(ctx
, tc
, sc
)) {
1623 if (ctx
->details_comp
->cfg
.compact
&&
1624 ctx
->details_comp
->printed_something
) {
1626 * There are no empty line between messages in
1627 * compact mode, so write one here to decouple
1628 * the stream class from the next message.
1634 * write_stream_class() also writes all its event
1635 * classes, so we don't need to rewrite `ec`.
1637 write_stream_class(ctx
, sc
);
1640 * Mark this stream class as written, as well as all its
1643 details_did_write_meta_object(ctx
, tc
, sc
);
1645 for (ec_i
= 0; ec_i
<
1646 bt_stream_class_get_event_class_count(sc
);
1648 details_did_write_meta_object(ctx
, tc
,
1649 bt_stream_class_borrow_event_class_by_index_const(
1656 if (ec
&& details_need_to_write_meta_object(ctx
, tc
, ec
)) {
1659 if (ctx
->details_comp
->cfg
.compact
&&
1660 ctx
->details_comp
->printed_something
) {
1662 * There are no empty line between messages in
1663 * compact mode, so write one here to decouple
1664 * the event class from the next message.
1669 write_event_class(ctx
, ec
);
1670 details_did_write_meta_object(ctx
, tc
, ec
);
1679 void write_time_str(struct details_write_ctx
*ctx
, const char *str
)
1681 if (!ctx
->details_comp
->cfg
.with_time
) {
1685 g_string_append_printf(ctx
->str
, "[%s%s%s%s]",
1686 color_bold(ctx
), color_fg_bright_blue(ctx
), str
,
1689 if (ctx
->details_comp
->cfg
.compact
) {
1700 void write_time(struct details_write_ctx
*ctx
, const bt_clock_snapshot
*cs
)
1702 bt_clock_snapshot_get_ns_from_origin_status cs_status
;
1703 int64_t ns_from_origin
;
1706 if (!ctx
->details_comp
->cfg
.with_time
) {
1710 format_uint(buf
, bt_clock_snapshot_get_value(cs
), 10);
1711 g_string_append_printf(ctx
->str
, "[%s%s%s%s%s",
1712 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1714 ctx
->details_comp
->cfg
.compact
? "" : " cycles");
1715 cs_status
= bt_clock_snapshot_get_ns_from_origin(cs
, &ns_from_origin
);
1716 if (cs_status
== BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK
) {
1717 format_int(buf
, ns_from_origin
, 10);
1718 g_string_append_printf(ctx
->str
, "%s %s%s%s%s%s",
1719 ctx
->details_comp
->cfg
.compact
? "" : ",",
1720 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1722 ctx
->details_comp
->cfg
.compact
? "" : " ns from origin");
1725 g_string_append(ctx
->str
, "]");
1727 if (ctx
->details_comp
->cfg
.compact
) {
1738 int write_message_follow_tag(struct details_write_ctx
*ctx
,
1739 const bt_stream
*stream
)
1742 uint64_t unique_trace_id
;
1743 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
1744 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
1746 ret
= details_trace_unique_id(ctx
, trace
, &unique_trace_id
);
1751 if (ctx
->details_comp
->cfg
.compact
) {
1752 g_string_append_printf(ctx
->str
,
1753 "%s{%s%s%" PRIu64
" %" PRIu64
" %" PRIu64
"%s%s}%s ",
1754 color_fg_cyan(ctx
), color_bold(ctx
),
1755 color_fg_bright_cyan(ctx
),
1756 unique_trace_id
, bt_stream_class_get_id(sc
),
1757 bt_stream_get_id(stream
),
1758 color_reset(ctx
), color_fg_cyan(ctx
), color_reset(ctx
));
1760 g_string_append_printf(ctx
->str
,
1761 "%s{Trace %s%s%" PRIu64
"%s%s, Stream class ID %s%s%" PRIu64
"%s%s, Stream ID %s%s%" PRIu64
"%s%s}%s\n",
1763 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1764 unique_trace_id
, color_reset(ctx
),
1766 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1767 bt_stream_class_get_id(sc
), color_reset(ctx
),
1769 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1770 bt_stream_get_id(stream
), color_reset(ctx
),
1771 color_fg_cyan(ctx
), color_reset(ctx
));
1779 void write_field(struct details_write_ctx
*ctx
, const bt_field
*field
,
1783 bt_field_class_type fc_type
= bt_field_get_class_type(field
);
1784 const bt_field_class
*fc
;
1787 /* Write field's name */
1789 write_compound_member_name(ctx
, name
);
1792 /* Write field's value */
1793 if (fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1795 write_bool_prop_value(ctx
, bt_field_bool_get_value(field
));
1796 } else if (fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1797 format_uint(buf
, bt_field_bit_array_get_value_as_integer(field
),
1800 write_uint_str_prop_value(ctx
, buf
);
1801 } else if (bt_field_class_type_is(fc_type
,
1802 BT_FIELD_CLASS_TYPE_INTEGER
)) {
1803 unsigned int fmt_base
;
1804 bt_field_class_integer_preferred_display_base base
;
1806 fc
= bt_field_borrow_class_const(field
);
1807 base
= bt_field_class_integer_get_preferred_display_base(fc
);
1810 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
1813 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
1816 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
1819 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
1826 if (bt_field_class_type_is(fc_type
,
1827 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
)) {
1829 bt_field_integer_unsigned_get_value(field
),
1832 write_uint_str_prop_value(ctx
, buf
);
1835 bt_field_integer_signed_get_value(field
),
1838 write_int_str_prop_value(ctx
, buf
);
1840 } else if (fc_type
== BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
) {
1842 write_float_prop_value(ctx
, bt_field_real_single_precision_get_value(field
));
1843 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
) {
1845 write_float_prop_value(ctx
, bt_field_real_double_precision_get_value(field
));
1846 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1848 write_str_prop_value(ctx
, bt_field_string_get_value(field
));
1849 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1850 uint64_t member_count
;
1852 fc
= bt_field_borrow_class_const(field
);
1853 member_count
= bt_field_class_structure_get_member_count(fc
);
1855 if (member_count
> 0) {
1858 for (i
= 0; i
< member_count
; i
++) {
1859 const bt_field_class_structure_member
*member
=
1860 bt_field_class_structure_borrow_member_by_index_const(
1862 const bt_field
*member_field
=
1863 bt_field_structure_borrow_member_field_by_index_const(
1867 write_field(ctx
, member_field
,
1868 bt_field_class_structure_member_get_name(member
));
1874 write_none_prop_value(ctx
, "Empty");
1876 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1877 uint64_t length
= bt_field_array_get_length(field
);
1881 write_none_prop_value(ctx
, "Empty");
1883 g_string_append(ctx
->str
, " Length ");
1884 write_uint_prop_value(ctx
, length
);
1885 g_string_append_c(ctx
->str
, ':');
1890 for (i
= 0; i
< length
; i
++) {
1891 const bt_field
*elem_field
=
1892 bt_field_array_borrow_element_field_by_index_const(
1896 write_array_index(ctx
, i
, color_fg_cyan(ctx
));
1897 write_field(ctx
, elem_field
, NULL
);
1901 } else if (bt_field_class_type_is(fc_type
,
1902 BT_FIELD_CLASS_TYPE_OPTION
)) {
1903 const bt_field
*content_field
=
1904 bt_field_option_borrow_field_const(field
);
1906 if (!content_field
) {
1908 write_none_prop_value(ctx
, "None");
1910 write_field(ctx
, content_field
, NULL
);
1912 } else if (bt_field_class_type_is(fc_type
,
1913 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1915 bt_field_variant_borrow_selected_option_field_const(
1923 void write_root_field(struct details_write_ctx
*ctx
, const char *name
,
1924 const bt_field
*field
)
1926 BT_ASSERT_DBG(name
);
1927 BT_ASSERT_DBG(field
);
1929 write_prop_name(ctx
, name
);
1930 g_string_append(ctx
->str
, ":");
1931 write_field(ctx
, field
, NULL
);
1936 int write_event_message(struct details_write_ctx
*ctx
,
1937 const bt_message
*msg
)
1940 const bt_event
*event
= bt_message_event_borrow_event_const(msg
);
1941 const bt_stream
*stream
= bt_event_borrow_stream_const(event
);
1942 const bt_event_class
*ec
= bt_event_borrow_class_const(event
);
1943 const bt_stream_class
*sc
= bt_event_class_borrow_stream_class_const(ec
);
1944 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
1945 const char *ec_name
;
1946 const bt_field
*field
;
1948 ret
= try_write_meta(ctx
, tc
, sc
, ec
);
1953 if (!ctx
->details_comp
->cfg
.with_data
) {
1957 if (ctx
->str
->len
> 0) {
1959 * Output buffer contains metadata: separate blocks with
1966 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1968 bt_message_event_borrow_default_clock_snapshot_const(
1972 /* Write follow tag for message */
1973 ret
= write_message_follow_tag(ctx
, stream
);
1978 /* Write object's basic properties */
1979 write_obj_type_name(ctx
, "Event");
1980 ec_name
= bt_event_class_get_name(ec
);
1982 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1983 color_fg_green(ctx
), ec_name
, color_reset(ctx
));
1986 g_string_append(ctx
->str
, " (");
1988 if (!ctx
->details_comp
->cfg
.compact
) {
1989 g_string_append(ctx
->str
, "Class ID ");
1992 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1993 g_string_append(ctx
->str
, ")");
1995 if (ctx
->details_comp
->cfg
.compact
) {
2001 g_string_append(ctx
->str
, ":\n");
2003 field
= bt_event_borrow_common_context_field_const(event
);
2005 write_root_field(ctx
, "Common context", field
);
2008 field
= bt_event_borrow_specific_context_field_const(event
);
2010 write_root_field(ctx
, "Specific context", field
);
2013 field
= bt_event_borrow_payload_field_const(event
);
2015 write_root_field(ctx
, "Payload", field
);
2025 gint
compare_streams(const bt_stream
**a
, const bt_stream
**b
)
2027 uint64_t id_a
= bt_stream_get_id(*a
);
2028 uint64_t id_b
= bt_stream_get_id(*b
);
2032 } else if (id_a
> id_b
) {
2035 const bt_stream_class
*a_sc
= bt_stream_borrow_class_const(*a
);
2036 const bt_stream_class
*b_sc
= bt_stream_borrow_class_const(*b
);
2037 uint64_t a_sc_id
= bt_stream_class_get_id(a_sc
);
2038 uint64_t b_sc_id
= bt_stream_class_get_id(b_sc
);
2040 if (a_sc_id
< b_sc_id
) {
2042 } else if (a_sc_id
> b_sc_id
) {
2051 void write_trace(struct details_write_ctx
*ctx
, const bt_trace
*trace
)
2053 GPtrArray
*streams
= g_ptr_array_new();
2055 bool printed_prop
= false;
2056 GPtrArray
*env_names
= g_ptr_array_new();
2060 write_obj_type_name(ctx
, "Trace");
2063 if (ctx
->details_comp
->cfg
.with_trace_name
) {
2064 const char *name
= bt_trace_get_name(trace
);
2066 g_string_append(ctx
->str
, " `");
2067 write_str_prop_value(ctx
, name
);
2068 g_string_append(ctx
->str
, "`");
2072 /* Write properties */
2076 if (ctx
->details_comp
->cfg
.with_uuid
) {
2077 bt_uuid uuid
= bt_trace_get_uuid(trace
);
2080 if (!printed_prop
) {
2081 g_string_append(ctx
->str
, ":\n");
2082 printed_prop
= true;
2085 write_uuid_prop_line(ctx
, "UUID", uuid
);
2089 /* Write environment */
2090 env_count
= bt_trace_get_environment_entry_count(trace
);
2091 if (env_count
> 0) {
2092 if (!printed_prop
) {
2093 g_string_append(ctx
->str
, ":\n");
2094 printed_prop
= true;
2098 write_prop_name(ctx
, "Environment");
2099 g_string_append(ctx
->str
, " (");
2100 write_uint_prop_value(ctx
, env_count
);
2101 g_string_append_printf(ctx
->str
, " entr%s):",
2102 env_count
== 1 ? "y" : "ies");
2106 for (i
= 0; i
< env_count
; i
++) {
2108 const bt_value
*value
;
2110 bt_trace_borrow_environment_entry_by_index_const(
2111 trace
, i
, &name
, &value
);
2112 g_ptr_array_add(env_names
, (gpointer
) name
);
2115 g_ptr_array_sort(env_names
, (GCompareFunc
) compare_strings
);
2117 for (i
= 0; i
< env_names
->len
; i
++) {
2118 const char *name
= env_names
->pdata
[i
];
2119 const bt_value
*value
=
2120 bt_trace_borrow_environment_entry_value_by_name_const(
2123 BT_ASSERT_DBG(value
);
2124 write_compound_member_name(ctx
, name
);
2127 if (bt_value_get_type(value
) ==
2128 BT_VALUE_TYPE_SIGNED_INTEGER
) {
2129 write_int_prop_value(ctx
,
2130 bt_value_integer_signed_get(value
));
2131 } else if (bt_value_get_type(value
) ==
2132 BT_VALUE_TYPE_STRING
) {
2133 write_str_prop_value(ctx
,
2134 bt_value_string_get(value
));
2145 for (i
= 0; i
< bt_trace_get_stream_count(trace
); i
++) {
2146 g_ptr_array_add(streams
,
2147 (gpointer
) bt_trace_borrow_stream_by_index_const(
2151 g_ptr_array_sort(streams
, (GCompareFunc
) compare_streams
);
2153 if (streams
->len
> 0 && !printed_prop
) {
2154 g_string_append(ctx
->str
, ":\n");
2155 printed_prop
= true;
2158 for (i
= 0; i
< streams
->len
; i
++) {
2159 const bt_stream
*stream
= streams
->pdata
[i
];
2162 write_obj_type_name(ctx
, "Stream");
2163 g_string_append(ctx
->str
, " (ID ");
2164 write_uint_prop_value(ctx
, bt_stream_get_id(stream
));
2165 g_string_append(ctx
->str
, ", Class ID ");
2166 write_uint_prop_value(ctx
, bt_stream_class_get_id(
2167 bt_stream_borrow_class_const(stream
)));
2168 g_string_append(ctx
->str
, ")");
2174 if (!printed_prop
) {
2178 g_ptr_array_free(streams
, TRUE
);
2179 g_ptr_array_free(env_names
, TRUE
);
2183 int write_stream_beginning_message(struct details_write_ctx
*ctx
,
2184 const bt_message
*msg
)
2187 const bt_stream
*stream
=
2188 bt_message_stream_beginning_borrow_stream_const(msg
);
2189 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
2190 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2191 const bt_clock_class
*cc
= bt_stream_class_borrow_default_clock_class_const(sc
);
2192 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
2195 ret
= try_write_meta(ctx
, tc
, sc
, NULL
);
2200 if (!ctx
->details_comp
->cfg
.with_data
) {
2204 if (ctx
->str
->len
> 0) {
2206 * Output buffer contains metadata: separate blocks with
2214 const bt_clock_snapshot
*cs
;
2215 bt_message_stream_clock_snapshot_state cs_state
=
2216 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg
, &cs
);
2218 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2219 write_time(ctx
, cs
);
2221 write_time_str(ctx
, "Unknown");
2225 /* Write follow tag for message */
2226 ret
= write_message_follow_tag(ctx
, stream
);
2231 /* Write stream properties */
2232 write_obj_type_name(ctx
, "Stream beginning");
2234 if (ctx
->details_comp
->cfg
.compact
) {
2239 g_string_append(ctx
->str
, ":\n");
2242 if (ctx
->details_comp
->cfg
.with_stream_name
) {
2243 name
= bt_stream_get_name(stream
);
2245 write_str_prop_line(ctx
, "Name", name
);
2249 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
2250 name
= bt_stream_class_get_name(sc
);
2252 write_str_prop_line(ctx
, "Class name", name
);
2256 write_trace(ctx
, trace
);
2264 int write_stream_end_message(struct details_write_ctx
*ctx
,
2265 const bt_message
*msg
)
2268 const bt_stream
*stream
=
2269 bt_message_stream_end_borrow_stream_const(msg
);
2270 const bt_stream_class
*sc
=
2271 bt_stream_borrow_class_const(stream
);
2272 const bt_clock_class
*cc
=
2273 bt_stream_class_borrow_default_clock_class_const(sc
);
2275 if (!ctx
->details_comp
->cfg
.with_data
) {
2281 const bt_clock_snapshot
*cs
;
2282 bt_message_stream_clock_snapshot_state cs_state
=
2283 bt_message_stream_end_borrow_default_clock_snapshot_const(msg
, &cs
);
2285 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2286 write_time(ctx
, cs
);
2288 write_time_str(ctx
, "Unknown");
2292 /* Write follow tag for message */
2293 ret
= write_message_follow_tag(ctx
, stream
);
2298 /* Write stream properties */
2299 write_obj_type_name(ctx
, "Stream end\n");
2306 int write_packet_beginning_message(struct details_write_ctx
*ctx
,
2307 const bt_message
*msg
)
2310 const bt_packet
*packet
=
2311 bt_message_packet_beginning_borrow_packet_const(msg
);
2312 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2313 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2314 const bt_field
*field
;
2316 if (!ctx
->details_comp
->cfg
.with_data
) {
2321 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
)) {
2323 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2327 /* Write follow tag for message */
2328 ret
= write_message_follow_tag(ctx
, stream
);
2333 write_obj_type_name(ctx
, "Packet beginning");
2335 if (ctx
->details_comp
->cfg
.compact
) {
2341 field
= bt_packet_borrow_context_field_const(packet
);
2343 g_string_append(ctx
->str
, ":\n");
2345 write_root_field(ctx
, "Context", field
);
2356 int write_discarded_items_message(struct details_write_ctx
*ctx
,
2357 const char *name
, const bt_stream
*stream
,
2358 const bt_clock_snapshot
*beginning_cs
,
2359 const bt_clock_snapshot
*end_cs
, uint64_t count
)
2365 write_time(ctx
, beginning_cs
);
2366 BT_ASSERT_DBG(end_cs
);
2367 write_time(ctx
, end_cs
);
2370 /* Write follow tag for message */
2371 ret
= write_message_follow_tag(ctx
, stream
);
2376 write_obj_type_name(ctx
, "Discarded ");
2377 write_obj_type_name(ctx
, name
);
2380 if (count
== UINT64_C(-1)) {
2385 g_string_append(ctx
->str
, " (");
2386 write_uint_prop_value(ctx
, count
);
2387 g_string_append_printf(ctx
->str
, " %s)\n", name
);
2394 int write_discarded_events_message(struct details_write_ctx
*ctx
,
2395 const bt_message
*msg
)
2398 const bt_stream
*stream
= bt_message_discarded_events_borrow_stream_const(
2400 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2401 const bt_clock_snapshot
*beginning_cs
= NULL
;
2402 const bt_clock_snapshot
*end_cs
= NULL
;
2405 if (!ctx
->details_comp
->cfg
.with_data
) {
2409 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc
)) {
2411 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2414 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2418 if (bt_message_discarded_events_get_count(msg
, &count
) !=
2419 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2420 count
= UINT64_C(-1);
2423 ret
= write_discarded_items_message(ctx
, "events", stream
,
2424 beginning_cs
, end_cs
, count
);
2431 int write_discarded_packets_message(struct details_write_ctx
*ctx
,
2432 const bt_message
*msg
)
2435 const bt_stream
*stream
= bt_message_discarded_packets_borrow_stream_const(
2437 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2438 const bt_clock_snapshot
*beginning_cs
= NULL
;
2439 const bt_clock_snapshot
*end_cs
= NULL
;
2442 if (!ctx
->details_comp
->cfg
.with_data
) {
2446 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
)) {
2448 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2451 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2455 if (bt_message_discarded_packets_get_count(msg
, &count
) !=
2456 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2457 count
= UINT64_C(-1);
2460 ret
= write_discarded_items_message(ctx
, "packets", stream
,
2461 beginning_cs
, end_cs
, count
);
2468 int write_packet_end_message(struct details_write_ctx
*ctx
,
2469 const bt_message
*msg
)
2472 const bt_packet
*packet
=
2473 bt_message_packet_end_borrow_packet_const(msg
);
2474 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2475 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2477 if (!ctx
->details_comp
->cfg
.with_data
) {
2482 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc
)) {
2484 bt_message_packet_end_borrow_default_clock_snapshot_const(
2488 /* Write follow tag for message */
2489 ret
= write_message_follow_tag(ctx
, stream
);
2494 write_obj_type_name(ctx
, "Packet end");
2502 int write_message_iterator_inactivity_message(struct details_write_ctx
*ctx
,
2503 const bt_message
*msg
)
2506 const bt_clock_snapshot
*cs
=
2507 bt_message_message_iterator_inactivity_borrow_clock_snapshot_const(
2511 write_time(ctx
, cs
);
2512 write_obj_type_name(ctx
, "Message iterator inactivity");
2514 if (ctx
->details_comp
->cfg
.compact
) {
2519 /* Write clock class properties */
2520 g_string_append(ctx
->str
, ":\n");
2523 write_prop_name(ctx
, "Clock class");
2524 g_string_append_c(ctx
->str
, ':');
2527 write_clock_class_prop_lines(ctx
,
2528 bt_clock_snapshot_borrow_clock_class_const(cs
));
2535 int details_write_message(struct details_comp
*details_comp
,
2536 const bt_message
*msg
)
2539 struct details_write_ctx ctx
= {
2540 .details_comp
= details_comp
,
2541 .str
= details_comp
->str
,
2545 /* Reset output buffer */
2546 g_string_assign(details_comp
->str
, "");
2548 switch (bt_message_get_type(msg
)) {
2549 case BT_MESSAGE_TYPE_EVENT
:
2550 ret
= write_event_message(&ctx
, msg
);
2552 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY
:
2553 ret
= write_message_iterator_inactivity_message(&ctx
, msg
);
2555 case BT_MESSAGE_TYPE_STREAM_BEGINNING
:
2556 ret
= write_stream_beginning_message(&ctx
, msg
);
2558 case BT_MESSAGE_TYPE_STREAM_END
:
2559 ret
= write_stream_end_message(&ctx
, msg
);
2561 case BT_MESSAGE_TYPE_PACKET_BEGINNING
:
2562 ret
= write_packet_beginning_message(&ctx
, msg
);
2564 case BT_MESSAGE_TYPE_PACKET_END
:
2565 ret
= write_packet_end_message(&ctx
, msg
);
2567 case BT_MESSAGE_TYPE_DISCARDED_EVENTS
:
2568 ret
= write_discarded_events_message(&ctx
, msg
);
2570 case BT_MESSAGE_TYPE_DISCARDED_PACKETS
:
2571 ret
= write_discarded_packets_message(&ctx
, msg
);
2578 * If this component printed at least one character so far, and
2579 * we're not in compact mode, and there's something in the
2580 * output buffer for this message, then prepend a newline to the
2581 * output buffer to visually separate message blocks.
2583 if (details_comp
->printed_something
&& !details_comp
->cfg
.compact
&&
2584 details_comp
->str
->len
> 0) {
2585 /* TODO: Optimize this */
2586 g_string_prepend_c(details_comp
->str
, '\n');