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(
364 const char *key
, const bt_value
*object
, void *data
)
366 GPtrArray
*keys
= data
;
369 g_ptr_array_add(keys
, (void *) key
);
370 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK
;
374 void write_value(struct details_write_ctx
*ctx
, const bt_value
*value
,
378 bt_value_type value_type
= bt_value_get_type(value
);
379 GPtrArray
*keys
= g_ptr_array_new();
384 /* Write field's name */
386 write_prop_name_line(ctx
, name
);
389 /* Write field's value */
390 switch (value_type
) {
391 case BT_VALUE_TYPE_NULL
:
393 write_none_prop_value(ctx
, "Null");
395 case BT_VALUE_TYPE_BOOL
:
397 write_bool_prop_value(ctx
, bt_value_bool_get(value
));
399 case BT_VALUE_TYPE_UNSIGNED_INTEGER
:
400 format_uint(buf
, bt_value_integer_unsigned_get(value
), 10);
402 write_uint_str_prop_value(ctx
, buf
);
404 case BT_VALUE_TYPE_SIGNED_INTEGER
:
405 format_int(buf
, bt_value_integer_signed_get(value
), 10);
407 write_int_str_prop_value(ctx
, buf
);
409 case BT_VALUE_TYPE_REAL
:
411 write_float_prop_value(ctx
, bt_value_real_get(value
));
413 case BT_VALUE_TYPE_STRING
:
415 write_str_prop_value(ctx
, bt_value_string_get(value
));
417 case BT_VALUE_TYPE_ARRAY
:
419 uint64_t length
= bt_value_array_get_length(value
);
423 write_none_prop_value(ctx
, "Empty");
425 g_string_append(ctx
->str
, " Length ");
426 write_uint_prop_value(ctx
, length
);
427 g_string_append_c(ctx
->str
, ':');
432 for (i
= 0; i
< length
; i
++) {
433 const bt_value
*elem_value
=
434 bt_value_array_borrow_element_by_index_const(
438 write_array_index(ctx
, i
, color_fg_magenta(ctx
));
439 write_value(ctx
, elem_value
, NULL
);
445 case BT_VALUE_TYPE_MAP
:
447 bt_value_map_foreach_entry_const_status foreach_status
=
448 bt_value_map_foreach_entry_const(value
,
449 map_value_foreach_add_key_to_array
, keys
);
451 BT_ASSERT_DBG(foreach_status
==
452 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK
);
453 g_ptr_array_sort(keys
, (GCompareFunc
) compare_strings
);
458 for (i
= 0; i
< keys
->len
; i
++) {
459 const char *key
= keys
->pdata
[i
];
460 const bt_value
*entry_value
=
461 bt_value_map_borrow_entry_value_const(
465 write_value(ctx
, entry_value
, key
);
471 write_none_prop_value(ctx
, "Empty");
480 g_ptr_array_free(keys
, TRUE
);
484 void write_user_attributes(struct details_write_ctx
*ctx
,
485 const bt_value
*user_attrs
, bool write_newline
, bool *written
)
487 BT_ASSERT_DBG(user_attrs
);
489 if (!bt_value_map_is_empty(user_attrs
)) {
490 write_value(ctx
, user_attrs
, "User attributes");
503 void write_int_field_class_props(struct details_write_ctx
*ctx
,
504 const bt_field_class
*fc
, bool close
)
506 g_string_append_printf(ctx
->str
, "(%s%" PRIu64
"-bit%s, Base ",
508 bt_field_class_integer_get_field_value_range(fc
),
511 switch (bt_field_class_integer_get_preferred_display_base(fc
)) {
512 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
513 write_uint_prop_value(ctx
, 2);
515 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
516 write_uint_prop_value(ctx
, 8);
518 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
519 write_uint_prop_value(ctx
, 10);
521 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
522 write_uint_prop_value(ctx
, 16);
529 g_string_append(ctx
->str
, ")");
545 struct enum_field_class_mapping
{
549 /* Array of `struct int_range` */
554 gint
compare_enum_field_class_mappings(struct enum_field_class_mapping
**a
,
555 struct enum_field_class_mapping
**b
)
557 return strcmp((*a
)->label
, (*b
)->label
);
561 gint
compare_int_ranges_signed(struct int_range
*a
, struct int_range
*b
)
564 if (a
->lower
.i
< b
->lower
.i
) {
566 } else if (a
->lower
.i
> b
->lower
.i
) {
569 if (a
->upper
.i
< b
->upper
.i
) {
571 } else if (a
->upper
.i
> b
->upper
.i
) {
580 gint
compare_int_ranges_unsigned(struct int_range
*a
, struct int_range
*b
)
582 if (a
->lower
.u
< b
->lower
.u
) {
584 } else if (a
->lower
.u
> b
->lower
.u
) {
587 if (a
->upper
.u
< b
->upper
.u
) {
589 } else if (a
->upper
.u
> b
->upper
.u
) {
598 GArray
*range_set_to_int_ranges(const void *spec_range_set
, bool is_signed
)
601 const bt_integer_range_set
*range_set
;
602 GArray
*ranges
= g_array_new(FALSE
, TRUE
, sizeof(struct int_range
));
609 range_set
= bt_integer_range_set_signed_as_range_set_const(
612 range_set
= bt_integer_range_set_unsigned_as_range_set_const(
616 for (i
= 0; i
< bt_integer_range_set_get_range_count(range_set
); i
++) {
617 struct int_range range
;
620 const bt_integer_range_signed
*orig_range
=
621 bt_integer_range_set_signed_borrow_range_by_index_const(
624 range
.lower
.i
= bt_integer_range_signed_get_lower(orig_range
);
625 range
.upper
.i
= bt_integer_range_signed_get_upper(orig_range
);
627 const bt_integer_range_unsigned
*orig_range
=
628 bt_integer_range_set_unsigned_borrow_range_by_index_const(
631 range
.lower
.u
= bt_integer_range_unsigned_get_lower(orig_range
);
632 range
.upper
.u
= bt_integer_range_unsigned_get_upper(orig_range
);
635 g_array_append_val(ranges
, range
);
639 g_array_sort(ranges
, (GCompareFunc
) compare_int_ranges_signed
);
642 (GCompareFunc
) compare_int_ranges_unsigned
);
650 void destroy_enum_field_class_mapping(struct enum_field_class_mapping
*mapping
)
652 if (mapping
->ranges
) {
653 g_array_free(mapping
->ranges
, TRUE
);
654 mapping
->ranges
= NULL
;
661 struct int_range
*int_range_at(GArray
*ranges
, uint64_t index
)
663 return &g_array_index(ranges
, struct int_range
, index
);
667 void write_int_range(struct details_write_ctx
*ctx
,
668 struct int_range
*range
, bool is_signed
)
670 g_string_append(ctx
->str
, "[");
673 write_int_prop_value(ctx
, range
->lower
.i
);
675 write_uint_prop_value(ctx
, range
->lower
.u
);
678 if (range
->lower
.u
!= range
->upper
.u
) {
679 g_string_append(ctx
->str
, ", ");
682 write_int_prop_value(ctx
, range
->upper
.i
);
684 write_uint_prop_value(ctx
, range
->upper
.u
);
688 g_string_append(ctx
->str
, "]");
692 void write_enum_field_class_mappings(struct details_write_ctx
*ctx
,
693 const bt_field_class
*fc
)
698 bool is_signed
= bt_field_class_get_type(fc
) ==
699 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
;
701 mappings
= g_ptr_array_new_with_free_func(
702 (GDestroyNotify
) destroy_enum_field_class_mapping
);
703 BT_ASSERT_DBG(mappings
);
706 * Copy field class's mappings to our own arrays and structures
709 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(fc
); i
++) {
710 const void *fc_mapping
;
711 const void *fc_range_set
;
712 struct enum_field_class_mapping
*mapping
= g_new0(
713 struct enum_field_class_mapping
, 1);
715 BT_ASSERT_DBG(mapping
);
718 fc_mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
720 fc_range_set
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
723 fc_mapping
= bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
725 fc_range_set
= bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
729 mapping
->label
= bt_field_class_enumeration_mapping_get_label(
730 bt_field_class_enumeration_signed_mapping_as_mapping_const(
732 mapping
->ranges
= range_set_to_int_ranges(fc_range_set
,
734 BT_ASSERT_DBG(mapping
->ranges
);
735 g_ptr_array_add(mappings
, mapping
);
738 /* Sort mappings (ranges are already sorted within mappings) */
739 g_ptr_array_sort(mappings
,
740 (GCompareFunc
) compare_enum_field_class_mappings
);
743 for (i
= 0; i
< mappings
->len
; i
++) {
744 struct enum_field_class_mapping
*mapping
= mappings
->pdata
[i
];
747 write_prop_name_line(ctx
, mapping
->label
);
749 for (range_i
= 0; range_i
< mapping
->ranges
->len
; range_i
++) {
752 int_range_at(mapping
->ranges
, range_i
),
757 g_ptr_array_free(mappings
, TRUE
);
761 void write_field_path(struct details_write_ctx
*ctx
,
762 const bt_field_path
*field_path
)
766 g_string_append_c(ctx
->str
, '[');
768 switch (bt_field_path_get_root_scope(field_path
)) {
769 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
770 write_str_prop_value(ctx
, "Packet context");
772 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
773 write_str_prop_value(ctx
, "Event common context");
775 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
776 write_str_prop_value(ctx
, "Event specific context");
778 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
779 write_str_prop_value(ctx
, "Event payload");
785 g_string_append(ctx
->str
, ": ");
787 for (i
= 0; i
< bt_field_path_get_item_count(field_path
); i
++) {
788 const bt_field_path_item
*fp_item
=
789 bt_field_path_borrow_item_by_index_const(field_path
, i
);
792 g_string_append(ctx
->str
, ", ");
795 switch (bt_field_path_item_get_type(fp_item
)) {
796 case BT_FIELD_PATH_ITEM_TYPE_INDEX
:
797 write_uint_prop_value(ctx
,
798 bt_field_path_item_index_get_index(fp_item
));
800 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
:
801 write_str_prop_value(ctx
, "<current>");
808 g_string_append_c(ctx
->str
, ']');
812 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
);
815 void write_variant_field_class_option(struct details_write_ctx
*ctx
,
816 const bt_field_class
*fc
, uint64_t index
)
818 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
819 const bt_field_class_variant_option
*option
=
820 bt_field_class_variant_borrow_option_by_index_const(
822 const void *orig_ranges
= NULL
;
823 GArray
*int_ranges
= NULL
;
825 const bt_value
*user_attrs
=
826 bt_field_class_variant_option_borrow_user_attributes_const(
828 const bt_field_class
*option_fc
=
829 bt_field_class_variant_option_borrow_field_class_const(option
);
832 write_compound_member_name(ctx
,
833 bt_field_class_variant_option_get_name(option
));
835 if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
836 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*spec_opt
=
837 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
841 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
844 } else if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
845 const bt_field_class_variant_with_selector_field_integer_signed_option
*spec_opt
=
846 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
850 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
858 int_ranges
= range_set_to_int_ranges(orig_ranges
, is_signed
);
859 BT_ASSERT_DBG(int_ranges
);
861 for (i
= 0; i
< int_ranges
->len
; i
++) {
862 struct int_range
*range
= int_range_at(int_ranges
, i
);
865 write_int_range(ctx
, range
, is_signed
);
868 g_string_append(ctx
->str
, ": ");
873 if (bt_value_map_is_empty(user_attrs
)) {
874 write_field_class(ctx
, option_fc
);
880 write_prop_name_line(ctx
, "Field class");
882 write_field_class(ctx
, option_fc
);
885 /* User attributes */
886 write_user_attributes(ctx
, user_attrs
,
893 g_array_free(int_ranges
, TRUE
);
898 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
)
902 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
903 const bt_value
*user_attrs
;
904 bool wrote_user_attrs
= false;
906 /* Write field class's type */
908 case BT_FIELD_CLASS_TYPE_BOOL
:
911 case BT_FIELD_CLASS_TYPE_BIT_ARRAY
:
914 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
915 type
= "Unsigned integer";
917 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
918 type
= "Signed integer";
920 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
921 type
= "Unsigned enumeration";
923 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
924 type
= "Signed enumeration";
926 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
:
927 type
= "Single-precision real";
929 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
:
930 type
= "Double-precision real";
932 case BT_FIELD_CLASS_TYPE_STRING
:
935 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
938 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
939 type
= "Static array";
941 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
942 type
= "Dynamic array (no length field)";
944 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
945 type
= "Dynamic array (with length field)";
947 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD
:
948 type
= "Option (no selector)";
950 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
:
951 type
= "Option (boolean selector)";
953 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
954 type
= "Option (unsigned integer selector)";
956 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
957 type
= "Option (signed integer selector)";
959 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
:
960 type
= "Variant (no selector)";
962 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
963 type
= "Variant (unsigned integer selector)";
965 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
966 type
= "Variant (signed integer selector)";
972 g_string_append_printf(ctx
->str
, "%s%s%s",
973 color_fg_blue(ctx
), type
, color_reset(ctx
));
975 /* Write field class's single-line properties */
976 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
977 uint64_t mapping_count
=
978 bt_field_class_enumeration_get_mapping_count(fc
);
981 write_int_field_class_props(ctx
, fc
, false);
982 g_string_append(ctx
->str
, ", ");
983 write_uint_prop_value(ctx
, mapping_count
);
984 g_string_append_printf(ctx
->str
, " mapping%s)",
985 plural(mapping_count
));
986 } else if (bt_field_class_type_is(fc_type
,
987 BT_FIELD_CLASS_TYPE_INTEGER
)) {
989 write_int_field_class_props(ctx
, fc
, true);
990 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
991 uint64_t member_count
=
992 bt_field_class_structure_get_member_count(fc
);
994 g_string_append(ctx
->str
, " (");
995 write_uint_prop_value(ctx
, member_count
);
996 g_string_append_printf(ctx
->str
, " member%s)",
997 plural(member_count
));
998 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
999 g_string_append(ctx
->str
, " (Length ");
1000 write_uint_prop_value(ctx
,
1001 bt_field_class_array_static_get_length(fc
));
1002 g_string_append_c(ctx
->str
, ')');
1003 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
1004 const bt_field_path
*length_field_path
=
1005 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1008 g_string_append(ctx
->str
, " (Length field path ");
1009 write_field_path(ctx
, length_field_path
);
1010 g_string_append_c(ctx
->str
, ')');
1011 } else if (bt_field_class_type_is(fc_type
,
1012 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
1013 const bt_field_path
*selector_field_path
=
1014 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
1017 g_string_append(ctx
->str
, " (Selector field path ");
1018 write_field_path(ctx
, selector_field_path
);
1019 g_string_append_c(ctx
->str
, ')');
1020 } else if (bt_field_class_type_is(fc_type
,
1021 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1022 uint64_t option_count
=
1023 bt_field_class_variant_get_option_count(fc
);
1024 const bt_field_path
*sel_field_path
= NULL
;
1026 if (bt_field_class_type_is(fc_type
,
1027 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
1029 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1031 BT_ASSERT_DBG(sel_field_path
);
1034 g_string_append(ctx
->str
, " (");
1035 write_uint_prop_value(ctx
, option_count
);
1036 g_string_append_printf(ctx
->str
, " option%s",
1037 plural(option_count
));
1039 if (sel_field_path
) {
1040 g_string_append(ctx
->str
, ", Selector field path ");
1041 write_field_path(ctx
, sel_field_path
);
1044 g_string_append_c(ctx
->str
, ')');
1048 user_attrs
= bt_field_class_borrow_user_attributes_const(fc
);
1049 if (!bt_value_map_is_empty(user_attrs
)) {
1050 g_string_append(ctx
->str
, ":\n");
1051 write_user_attributes(ctx
, user_attrs
, false, NULL
);
1052 wrote_user_attrs
= true;
1055 /* Write field class's complex properties */
1056 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
1057 uint64_t mapping_count
=
1058 bt_field_class_enumeration_get_mapping_count(fc
);
1060 if (mapping_count
> 0) {
1061 if (wrote_user_attrs
) {
1064 write_prop_name(ctx
, "Mappings");
1065 g_string_append_c(ctx
->str
, ':');
1068 /* Each mapping starts with its own newline */
1069 g_string_append_c(ctx
->str
, ':');
1072 write_enum_field_class_mappings(ctx
, fc
);
1074 if (wrote_user_attrs
) {
1078 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1079 uint64_t member_count
=
1080 bt_field_class_structure_get_member_count(fc
);
1082 if (member_count
> 0) {
1083 if (wrote_user_attrs
) {
1086 write_prop_name(ctx
, "Members");
1087 g_string_append_c(ctx
->str
, ':');
1090 /* Each member starts with its own newline */
1091 g_string_append_c(ctx
->str
, ':');
1094 for (i
= 0; i
< member_count
; i
++) {
1095 const bt_field_class_structure_member
*member
=
1096 bt_field_class_structure_borrow_member_by_index_const(
1098 const bt_value
*member_user_attrs
;
1099 const bt_field_class
*member_fc
=
1100 bt_field_class_structure_member_borrow_field_class_const(member
);
1103 write_compound_member_name(ctx
,
1104 bt_field_class_structure_member_get_name(member
));
1105 member_user_attrs
= bt_field_class_structure_member_borrow_user_attributes_const(
1108 if (bt_value_map_is_empty(member_user_attrs
)) {
1110 write_field_class(ctx
, member_fc
);
1116 write_prop_name_line(ctx
, "Field class");
1118 write_field_class(ctx
, member_fc
);
1121 /* User attributes */
1122 write_user_attributes(ctx
, member_user_attrs
,
1129 if (wrote_user_attrs
) {
1133 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1134 if (wrote_user_attrs
) {
1137 g_string_append(ctx
->str
, ":\n");
1140 write_prop_name_line(ctx
, "Element");
1142 write_field_class(ctx
,
1143 bt_field_class_array_borrow_element_field_class_const(fc
));
1144 } else if (bt_field_class_type_is(fc_type
,
1145 BT_FIELD_CLASS_TYPE_OPTION
)) {
1146 const void *ranges
= NULL
;
1147 bool selector_is_signed
= false;
1149 if (wrote_user_attrs
) {
1152 g_string_append(ctx
->str
, ":\n");
1155 if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
) {
1156 write_bool_prop_line(ctx
, "Selector is reversed",
1157 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc
));
1158 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
1159 ranges
= bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc
);
1160 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
1161 ranges
= bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc
);
1162 selector_is_signed
= true;
1166 GArray
*sorted_ranges
= range_set_to_int_ranges(
1167 ranges
, selector_is_signed
);
1169 BT_ASSERT_DBG(sorted_ranges
);
1170 BT_ASSERT_DBG(sorted_ranges
->len
> 0);
1171 write_prop_name_line(ctx
, "Selector ranges");
1173 for (i
= 0; i
< sorted_ranges
->len
; i
++) {
1175 write_int_range(ctx
,
1176 int_range_at(sorted_ranges
, i
),
1177 selector_is_signed
);
1181 g_array_free(sorted_ranges
, TRUE
);
1184 write_prop_name_line(ctx
, "Content");
1186 write_field_class(ctx
,
1187 bt_field_class_option_borrow_field_class_const(fc
));
1188 } else if (bt_field_class_type_is(fc_type
,
1189 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1190 uint64_t option_count
=
1191 bt_field_class_variant_get_option_count(fc
);
1193 if (option_count
> 0) {
1194 if (wrote_user_attrs
) {
1197 write_prop_name(ctx
, "Options");
1198 g_string_append_c(ctx
->str
, ':');
1201 /* Each option starts with its own newline */
1202 g_string_append_c(ctx
->str
, ':');
1205 for (i
= 0; i
< option_count
; i
++) {
1206 write_variant_field_class_option(ctx
, fc
, i
);
1209 if (wrote_user_attrs
) {
1219 void write_root_field_class(struct details_write_ctx
*ctx
, const char *name
,
1220 const bt_field_class
*fc
)
1222 BT_ASSERT_DBG(name
);
1225 write_prop_name(ctx
, name
);
1226 g_string_append(ctx
->str
, ": ");
1227 write_field_class(ctx
, fc
);
1232 void write_event_class(struct details_write_ctx
*ctx
, const bt_event_class
*ec
)
1234 const char *name
= bt_event_class_get_name(ec
);
1235 const char *emf_uri
;
1236 const bt_field_class
*fc
;
1237 bt_event_class_log_level log_level
;
1240 write_obj_type_name(ctx
, "Event class");
1242 /* Write name and ID */
1244 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1245 color_fg_green(ctx
), name
, color_reset(ctx
));
1248 g_string_append(ctx
->str
, " (ID ");
1249 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1250 g_string_append(ctx
->str
, "):\n");
1252 /* Write properties */
1255 /* Write user attributes */
1256 write_user_attributes(ctx
,
1257 bt_event_class_borrow_user_attributes_const(ec
), true, NULL
);
1259 /* Write log level */
1260 if (bt_event_class_get_log_level(ec
, &log_level
) ==
1261 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
1262 const char *ll_str
= NULL
;
1264 switch (log_level
) {
1265 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY
:
1266 ll_str
= "Emergency";
1268 case BT_EVENT_CLASS_LOG_LEVEL_ALERT
:
1271 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL
:
1272 ll_str
= "Critical";
1274 case BT_EVENT_CLASS_LOG_LEVEL_ERROR
:
1277 case BT_EVENT_CLASS_LOG_LEVEL_WARNING
:
1280 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE
:
1283 case BT_EVENT_CLASS_LOG_LEVEL_INFO
:
1286 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
:
1287 ll_str
= "Debug (system)";
1289 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
:
1290 ll_str
= "Debug (program)";
1292 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
:
1293 ll_str
= "Debug (process)";
1295 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
:
1296 ll_str
= "Debug (module)";
1298 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
:
1299 ll_str
= "Debug (unit)";
1301 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
:
1302 ll_str
= "Debug (function)";
1304 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
:
1305 ll_str
= "Debug (line)";
1307 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG
:
1314 write_str_prop_line(ctx
, "Log level", ll_str
);
1318 emf_uri
= bt_event_class_get_emf_uri(ec
);
1320 write_str_prop_line(ctx
, "EMF URI", emf_uri
);
1323 /* Write specific context field class */
1324 fc
= bt_event_class_borrow_specific_context_field_class_const(ec
);
1326 write_root_field_class(ctx
, "Specific context field class", fc
);
1329 /* Write payload field class */
1330 fc
= bt_event_class_borrow_payload_field_class_const(ec
);
1332 write_root_field_class(ctx
, "Payload field class", fc
);
1339 void write_clock_class_prop_lines(struct details_write_ctx
*ctx
,
1340 const bt_clock_class
*cc
)
1342 int64_t offset_seconds
;
1343 uint64_t offset_cycles
;
1346 str
= bt_clock_class_get_name(cc
);
1348 write_str_prop_line(ctx
, "Name", str
);
1351 write_user_attributes(ctx
,
1352 bt_clock_class_borrow_user_attributes_const(cc
), true, NULL
);
1353 str
= bt_clock_class_get_description(cc
);
1355 write_str_prop_line(ctx
, "Description", str
);
1358 write_uint_prop_line(ctx
, "Frequency (Hz)",
1359 bt_clock_class_get_frequency(cc
));
1360 write_uint_prop_line(ctx
, "Precision (cycles)",
1361 bt_clock_class_get_precision(cc
));
1362 bt_clock_class_get_offset(cc
, &offset_seconds
, &offset_cycles
);
1363 write_int_prop_line(ctx
, "Offset (s)", offset_seconds
);
1364 write_uint_prop_line(ctx
, "Offset (cycles)", offset_cycles
);
1365 write_bool_prop_line(ctx
, "Origin is Unix epoch",
1366 bt_clock_class_origin_is_unix_epoch(cc
));
1368 if (ctx
->details_comp
->cfg
.with_uuid
) {
1369 bt_uuid uuid
= bt_clock_class_get_uuid(cc
);
1372 write_uuid_prop_line(ctx
, "UUID", uuid
);
1378 gint
compare_event_classes(const bt_event_class
**a
, const bt_event_class
**b
)
1380 uint64_t id_a
= bt_event_class_get_id(*a
);
1381 uint64_t id_b
= bt_event_class_get_id(*b
);
1385 } else if (id_a
> id_b
) {
1393 void write_stream_class(struct details_write_ctx
*ctx
,
1394 const bt_stream_class
*sc
)
1396 const bt_field_class
*fc
;
1397 GPtrArray
*event_classes
= g_ptr_array_new();
1401 write_obj_type_name(ctx
, "Stream class");
1403 /* Write name and ID */
1404 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
1405 const char *name
= bt_stream_class_get_name(sc
);
1408 g_string_append(ctx
->str
, " `");
1409 write_str_prop_value(ctx
, name
);
1410 g_string_append(ctx
->str
, "`");
1414 g_string_append(ctx
->str
, " (ID ");
1415 write_uint_prop_value(ctx
, bt_stream_class_get_id(sc
));
1416 g_string_append(ctx
->str
, "):\n");
1418 /* Write properties */
1421 /* Write user attributes */
1422 write_user_attributes(ctx
,
1423 bt_stream_class_borrow_user_attributes_const(sc
), true, NULL
);
1425 /* Write configuration */
1426 write_bool_prop_line(ctx
,
1427 "Supports packets", bt_stream_class_supports_packets(sc
));
1429 if (bt_stream_class_supports_packets(sc
)) {
1430 write_bool_prop_line(ctx
,
1431 "Packets have beginning default clock snapshot",
1432 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
));
1433 write_bool_prop_line(ctx
,
1434 "Packets have end default clock snapshot",
1435 bt_stream_class_packets_have_end_default_clock_snapshot(sc
));
1438 write_bool_prop_line(ctx
,
1439 "Supports discarded events",
1440 bt_stream_class_supports_discarded_events(sc
));
1442 if (bt_stream_class_supports_discarded_events(sc
)) {
1443 write_bool_prop_line(ctx
,
1444 "Discarded events have default clock snapshots",
1445 bt_stream_class_discarded_events_have_default_clock_snapshots(sc
));
1448 write_bool_prop_line(ctx
,
1449 "Supports discarded packets",
1450 bt_stream_class_supports_discarded_packets(sc
));
1452 if (bt_stream_class_supports_discarded_packets(sc
)) {
1453 write_bool_prop_line(ctx
,
1454 "Discarded packets have default clock snapshots",
1455 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
));
1458 /* Write default clock class */
1459 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1461 write_prop_name(ctx
, "Default clock class");
1462 g_string_append_c(ctx
->str
, ':');
1465 write_clock_class_prop_lines(ctx
,
1466 bt_stream_class_borrow_default_clock_class_const(sc
));
1470 fc
= bt_stream_class_borrow_packet_context_field_class_const(sc
);
1472 write_root_field_class(ctx
, "Packet context field class", fc
);
1475 fc
= bt_stream_class_borrow_event_common_context_field_class_const(sc
);
1477 write_root_field_class(ctx
, "Event common context field class",
1481 for (i
= 0; i
< bt_stream_class_get_event_class_count(sc
); i
++) {
1482 g_ptr_array_add(event_classes
,
1483 (gpointer
) bt_stream_class_borrow_event_class_by_index_const(
1487 g_ptr_array_sort(event_classes
, (GCompareFunc
) compare_event_classes
);
1489 for (i
= 0; i
< event_classes
->len
; i
++) {
1490 write_event_class(ctx
, event_classes
->pdata
[i
]);
1494 g_ptr_array_free(event_classes
, TRUE
);
1498 gint
compare_stream_classes(const bt_stream_class
**a
, const bt_stream_class
**b
)
1500 uint64_t id_a
= bt_stream_class_get_id(*a
);
1501 uint64_t id_b
= bt_stream_class_get_id(*b
);
1505 } else if (id_a
> id_b
) {
1513 void write_trace_class(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
)
1515 GPtrArray
*stream_classes
= g_ptr_array_new();
1517 bool printed_prop
= false;
1520 write_obj_type_name(ctx
, "Trace class");
1523 for (i
= 0; i
< bt_trace_class_get_stream_class_count(tc
); i
++) {
1524 g_ptr_array_add(stream_classes
,
1525 (gpointer
) bt_trace_class_borrow_stream_class_by_index_const(
1529 g_ptr_array_sort(stream_classes
, (GCompareFunc
) compare_stream_classes
);
1531 if (stream_classes
->len
> 0) {
1532 if (!printed_prop
) {
1533 g_string_append(ctx
->str
, ":\n");
1534 printed_prop
= true;
1540 /* Write user attributes */
1541 write_user_attributes(ctx
,
1542 bt_trace_class_borrow_user_attributes_const(tc
), true,
1545 /* Write stream classes */
1546 for (i
= 0; i
< stream_classes
->len
; i
++) {
1547 write_stream_class(ctx
, stream_classes
->pdata
[i
]);
1550 if (!printed_prop
) {
1555 g_ptr_array_free(stream_classes
, TRUE
);
1559 int try_write_meta(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
,
1560 const bt_stream_class
*sc
, const bt_event_class
*ec
)
1566 if (details_need_to_write_trace_class(ctx
, tc
)) {
1569 if (ctx
->details_comp
->cfg
.compact
&&
1570 ctx
->details_comp
->printed_something
) {
1572 * There are no empty line between messages in
1573 * compact mode, so write one here to decouple
1574 * the trace class from the next message.
1580 * write_trace_class() also writes all its stream
1581 * classes their event classes, so we don't need to
1584 write_trace_class(ctx
, tc
);
1587 * Mark this trace class as written, as well as all
1588 * its stream classes and their event classes.
1590 ret
= details_did_write_trace_class(ctx
, tc
);
1595 for (sc_i
= 0; sc_i
< bt_trace_class_get_stream_class_count(tc
);
1598 const bt_stream_class
*tc_sc
=
1599 bt_trace_class_borrow_stream_class_by_index_const(
1602 details_did_write_meta_object(ctx
, tc
, tc_sc
);
1604 for (ec_i
= 0; ec_i
<
1605 bt_stream_class_get_event_class_count(tc_sc
);
1607 details_did_write_meta_object(ctx
, tc
,
1608 bt_stream_class_borrow_event_class_by_index_const(
1616 if (sc
&& details_need_to_write_meta_object(ctx
, tc
, sc
)) {
1621 if (ctx
->details_comp
->cfg
.compact
&&
1622 ctx
->details_comp
->printed_something
) {
1624 * There are no empty line between messages in
1625 * compact mode, so write one here to decouple
1626 * the stream class from the next message.
1632 * write_stream_class() also writes all its event
1633 * classes, so we don't need to rewrite `ec`.
1635 write_stream_class(ctx
, sc
);
1638 * Mark this stream class as written, as well as all its
1641 details_did_write_meta_object(ctx
, tc
, sc
);
1643 for (ec_i
= 0; ec_i
<
1644 bt_stream_class_get_event_class_count(sc
);
1646 details_did_write_meta_object(ctx
, tc
,
1647 bt_stream_class_borrow_event_class_by_index_const(
1654 if (ec
&& details_need_to_write_meta_object(ctx
, tc
, ec
)) {
1657 if (ctx
->details_comp
->cfg
.compact
&&
1658 ctx
->details_comp
->printed_something
) {
1660 * There are no empty line between messages in
1661 * compact mode, so write one here to decouple
1662 * the event class from the next message.
1667 write_event_class(ctx
, ec
);
1668 details_did_write_meta_object(ctx
, tc
, ec
);
1677 void write_time_str(struct details_write_ctx
*ctx
, const char *str
)
1679 if (!ctx
->details_comp
->cfg
.with_time
) {
1683 g_string_append_printf(ctx
->str
, "[%s%s%s%s]",
1684 color_bold(ctx
), color_fg_bright_blue(ctx
), str
,
1687 if (ctx
->details_comp
->cfg
.compact
) {
1698 void write_time(struct details_write_ctx
*ctx
, const bt_clock_snapshot
*cs
)
1700 bt_clock_snapshot_get_ns_from_origin_status cs_status
;
1701 int64_t ns_from_origin
;
1704 if (!ctx
->details_comp
->cfg
.with_time
) {
1708 format_uint(buf
, bt_clock_snapshot_get_value(cs
), 10);
1709 g_string_append_printf(ctx
->str
, "[%s%s%s%s%s",
1710 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1712 ctx
->details_comp
->cfg
.compact
? "" : " cycles");
1713 cs_status
= bt_clock_snapshot_get_ns_from_origin(cs
, &ns_from_origin
);
1714 if (cs_status
== BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK
) {
1715 format_int(buf
, ns_from_origin
, 10);
1716 g_string_append_printf(ctx
->str
, "%s %s%s%s%s%s",
1717 ctx
->details_comp
->cfg
.compact
? "" : ",",
1718 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1720 ctx
->details_comp
->cfg
.compact
? "" : " ns from origin");
1723 g_string_append(ctx
->str
, "]");
1725 if (ctx
->details_comp
->cfg
.compact
) {
1736 int write_message_follow_tag(struct details_write_ctx
*ctx
,
1737 const bt_stream
*stream
)
1740 uint64_t unique_trace_id
;
1741 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
1742 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
1744 ret
= details_trace_unique_id(ctx
, trace
, &unique_trace_id
);
1749 if (ctx
->details_comp
->cfg
.compact
) {
1750 g_string_append_printf(ctx
->str
,
1751 "%s{%s%s%" PRIu64
" %" PRIu64
" %" PRIu64
"%s%s}%s ",
1752 color_fg_cyan(ctx
), color_bold(ctx
),
1753 color_fg_bright_cyan(ctx
),
1754 unique_trace_id
, bt_stream_class_get_id(sc
),
1755 bt_stream_get_id(stream
),
1756 color_reset(ctx
), color_fg_cyan(ctx
), color_reset(ctx
));
1758 g_string_append_printf(ctx
->str
,
1759 "%s{Trace %s%s%" PRIu64
"%s%s, Stream class ID %s%s%" PRIu64
"%s%s, Stream ID %s%s%" PRIu64
"%s%s}%s\n",
1761 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1762 unique_trace_id
, color_reset(ctx
),
1764 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1765 bt_stream_class_get_id(sc
), color_reset(ctx
),
1767 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1768 bt_stream_get_id(stream
), color_reset(ctx
),
1769 color_fg_cyan(ctx
), color_reset(ctx
));
1777 void write_field(struct details_write_ctx
*ctx
, const bt_field
*field
,
1781 bt_field_class_type fc_type
= bt_field_get_class_type(field
);
1782 const bt_field_class
*fc
;
1785 /* Write field's name */
1787 write_compound_member_name(ctx
, name
);
1790 /* Write field's value */
1791 if (fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1793 write_bool_prop_value(ctx
, bt_field_bool_get_value(field
));
1794 } else if (fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1795 format_uint(buf
, bt_field_bit_array_get_value_as_integer(field
),
1798 write_uint_str_prop_value(ctx
, buf
);
1799 } else if (bt_field_class_type_is(fc_type
,
1800 BT_FIELD_CLASS_TYPE_INTEGER
)) {
1801 unsigned int fmt_base
;
1802 bt_field_class_integer_preferred_display_base base
;
1804 fc
= bt_field_borrow_class_const(field
);
1805 base
= bt_field_class_integer_get_preferred_display_base(fc
);
1808 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
1811 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
1814 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
1817 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
1824 if (bt_field_class_type_is(fc_type
,
1825 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
)) {
1827 bt_field_integer_unsigned_get_value(field
),
1830 write_uint_str_prop_value(ctx
, buf
);
1833 bt_field_integer_signed_get_value(field
),
1836 write_int_str_prop_value(ctx
, buf
);
1838 } else if (fc_type
== BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
) {
1840 write_float_prop_value(ctx
, bt_field_real_single_precision_get_value(field
));
1841 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
) {
1843 write_float_prop_value(ctx
, bt_field_real_double_precision_get_value(field
));
1844 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1846 write_str_prop_value(ctx
, bt_field_string_get_value(field
));
1847 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1848 uint64_t member_count
;
1850 fc
= bt_field_borrow_class_const(field
);
1851 member_count
= bt_field_class_structure_get_member_count(fc
);
1853 if (member_count
> 0) {
1856 for (i
= 0; i
< member_count
; i
++) {
1857 const bt_field_class_structure_member
*member
=
1858 bt_field_class_structure_borrow_member_by_index_const(
1860 const bt_field
*member_field
=
1861 bt_field_structure_borrow_member_field_by_index_const(
1865 write_field(ctx
, member_field
,
1866 bt_field_class_structure_member_get_name(member
));
1872 write_none_prop_value(ctx
, "Empty");
1874 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1875 uint64_t length
= bt_field_array_get_length(field
);
1879 write_none_prop_value(ctx
, "Empty");
1881 g_string_append(ctx
->str
, " Length ");
1882 write_uint_prop_value(ctx
, length
);
1883 g_string_append_c(ctx
->str
, ':');
1888 for (i
= 0; i
< length
; i
++) {
1889 const bt_field
*elem_field
=
1890 bt_field_array_borrow_element_field_by_index_const(
1894 write_array_index(ctx
, i
, color_fg_cyan(ctx
));
1895 write_field(ctx
, elem_field
, NULL
);
1899 } else if (bt_field_class_type_is(fc_type
,
1900 BT_FIELD_CLASS_TYPE_OPTION
)) {
1901 const bt_field
*content_field
=
1902 bt_field_option_borrow_field_const(field
);
1904 if (!content_field
) {
1906 write_none_prop_value(ctx
, "None");
1908 write_field(ctx
, content_field
, NULL
);
1910 } else if (bt_field_class_type_is(fc_type
,
1911 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1913 bt_field_variant_borrow_selected_option_field_const(
1921 void write_root_field(struct details_write_ctx
*ctx
, const char *name
,
1922 const bt_field
*field
)
1924 BT_ASSERT_DBG(name
);
1925 BT_ASSERT_DBG(field
);
1927 write_prop_name(ctx
, name
);
1928 g_string_append(ctx
->str
, ":");
1929 write_field(ctx
, field
, NULL
);
1934 int write_event_message(struct details_write_ctx
*ctx
,
1935 const bt_message
*msg
)
1938 const bt_event
*event
= bt_message_event_borrow_event_const(msg
);
1939 const bt_stream
*stream
= bt_event_borrow_stream_const(event
);
1940 const bt_event_class
*ec
= bt_event_borrow_class_const(event
);
1941 const bt_stream_class
*sc
= bt_event_class_borrow_stream_class_const(ec
);
1942 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
1943 const char *ec_name
;
1944 const bt_field
*field
;
1946 ret
= try_write_meta(ctx
, tc
, sc
, ec
);
1951 if (!ctx
->details_comp
->cfg
.with_data
) {
1955 if (ctx
->str
->len
> 0) {
1957 * Output buffer contains metadata: separate blocks with
1964 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1966 bt_message_event_borrow_default_clock_snapshot_const(
1970 /* Write follow tag for message */
1971 ret
= write_message_follow_tag(ctx
, stream
);
1976 /* Write object's basic properties */
1977 write_obj_type_name(ctx
, "Event");
1978 ec_name
= bt_event_class_get_name(ec
);
1980 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1981 color_fg_green(ctx
), ec_name
, color_reset(ctx
));
1984 g_string_append(ctx
->str
, " (");
1986 if (!ctx
->details_comp
->cfg
.compact
) {
1987 g_string_append(ctx
->str
, "Class ID ");
1990 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1991 g_string_append(ctx
->str
, ")");
1993 if (ctx
->details_comp
->cfg
.compact
) {
1999 g_string_append(ctx
->str
, ":\n");
2001 field
= bt_event_borrow_common_context_field_const(event
);
2003 write_root_field(ctx
, "Common context", field
);
2006 field
= bt_event_borrow_specific_context_field_const(event
);
2008 write_root_field(ctx
, "Specific context", field
);
2011 field
= bt_event_borrow_payload_field_const(event
);
2013 write_root_field(ctx
, "Payload", field
);
2023 gint
compare_streams(const bt_stream
**a
, const bt_stream
**b
)
2025 uint64_t id_a
= bt_stream_get_id(*a
);
2026 uint64_t id_b
= bt_stream_get_id(*b
);
2030 } else if (id_a
> id_b
) {
2033 const bt_stream_class
*a_sc
= bt_stream_borrow_class_const(*a
);
2034 const bt_stream_class
*b_sc
= bt_stream_borrow_class_const(*b
);
2035 uint64_t a_sc_id
= bt_stream_class_get_id(a_sc
);
2036 uint64_t b_sc_id
= bt_stream_class_get_id(b_sc
);
2038 if (a_sc_id
< b_sc_id
) {
2040 } else if (a_sc_id
> b_sc_id
) {
2049 void write_trace(struct details_write_ctx
*ctx
, const bt_trace
*trace
)
2051 GPtrArray
*streams
= g_ptr_array_new();
2053 bool printed_prop
= false;
2054 GPtrArray
*env_names
= g_ptr_array_new();
2058 write_obj_type_name(ctx
, "Trace");
2061 if (ctx
->details_comp
->cfg
.with_trace_name
) {
2062 const char *name
= bt_trace_get_name(trace
);
2064 g_string_append(ctx
->str
, " `");
2065 write_str_prop_value(ctx
, name
);
2066 g_string_append(ctx
->str
, "`");
2070 /* Write properties */
2074 if (ctx
->details_comp
->cfg
.with_uuid
) {
2075 bt_uuid uuid
= bt_trace_get_uuid(trace
);
2078 if (!printed_prop
) {
2079 g_string_append(ctx
->str
, ":\n");
2080 printed_prop
= true;
2083 write_uuid_prop_line(ctx
, "UUID", uuid
);
2087 /* Write environment */
2088 env_count
= bt_trace_get_environment_entry_count(trace
);
2089 if (env_count
> 0) {
2090 if (!printed_prop
) {
2091 g_string_append(ctx
->str
, ":\n");
2092 printed_prop
= true;
2096 write_prop_name(ctx
, "Environment");
2097 g_string_append(ctx
->str
, " (");
2098 write_uint_prop_value(ctx
, env_count
);
2099 g_string_append_printf(ctx
->str
, " entr%s):",
2100 env_count
== 1 ? "y" : "ies");
2104 for (i
= 0; i
< env_count
; i
++) {
2106 const bt_value
*value
;
2108 bt_trace_borrow_environment_entry_by_index_const(
2109 trace
, i
, &name
, &value
);
2110 g_ptr_array_add(env_names
, (gpointer
) name
);
2113 g_ptr_array_sort(env_names
, (GCompareFunc
) compare_strings
);
2115 for (i
= 0; i
< env_names
->len
; i
++) {
2116 const char *name
= env_names
->pdata
[i
];
2117 const bt_value
*value
=
2118 bt_trace_borrow_environment_entry_value_by_name_const(
2121 BT_ASSERT_DBG(value
);
2122 write_compound_member_name(ctx
, name
);
2125 if (bt_value_get_type(value
) ==
2126 BT_VALUE_TYPE_SIGNED_INTEGER
) {
2127 write_int_prop_value(ctx
,
2128 bt_value_integer_signed_get(value
));
2129 } else if (bt_value_get_type(value
) ==
2130 BT_VALUE_TYPE_STRING
) {
2131 write_str_prop_value(ctx
,
2132 bt_value_string_get(value
));
2143 for (i
= 0; i
< bt_trace_get_stream_count(trace
); i
++) {
2144 g_ptr_array_add(streams
,
2145 (gpointer
) bt_trace_borrow_stream_by_index_const(
2149 g_ptr_array_sort(streams
, (GCompareFunc
) compare_streams
);
2151 if (streams
->len
> 0 && !printed_prop
) {
2152 g_string_append(ctx
->str
, ":\n");
2153 printed_prop
= true;
2156 for (i
= 0; i
< streams
->len
; i
++) {
2157 const bt_stream
*stream
= streams
->pdata
[i
];
2160 write_obj_type_name(ctx
, "Stream");
2161 g_string_append(ctx
->str
, " (ID ");
2162 write_uint_prop_value(ctx
, bt_stream_get_id(stream
));
2163 g_string_append(ctx
->str
, ", Class ID ");
2164 write_uint_prop_value(ctx
, bt_stream_class_get_id(
2165 bt_stream_borrow_class_const(stream
)));
2166 g_string_append(ctx
->str
, ")");
2172 if (!printed_prop
) {
2176 g_ptr_array_free(streams
, TRUE
);
2177 g_ptr_array_free(env_names
, TRUE
);
2181 int write_stream_beginning_message(struct details_write_ctx
*ctx
,
2182 const bt_message
*msg
)
2185 const bt_stream
*stream
=
2186 bt_message_stream_beginning_borrow_stream_const(msg
);
2187 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
2188 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2189 const bt_clock_class
*cc
= bt_stream_class_borrow_default_clock_class_const(sc
);
2190 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
2193 ret
= try_write_meta(ctx
, tc
, sc
, NULL
);
2198 if (!ctx
->details_comp
->cfg
.with_data
) {
2202 if (ctx
->str
->len
> 0) {
2204 * Output buffer contains metadata: separate blocks with
2212 const bt_clock_snapshot
*cs
;
2213 bt_message_stream_clock_snapshot_state cs_state
=
2214 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg
, &cs
);
2216 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2217 write_time(ctx
, cs
);
2219 write_time_str(ctx
, "Unknown");
2223 /* Write follow tag for message */
2224 ret
= write_message_follow_tag(ctx
, stream
);
2229 /* Write stream properties */
2230 write_obj_type_name(ctx
, "Stream beginning");
2232 if (ctx
->details_comp
->cfg
.compact
) {
2237 g_string_append(ctx
->str
, ":\n");
2240 if (ctx
->details_comp
->cfg
.with_stream_name
) {
2241 name
= bt_stream_get_name(stream
);
2243 write_str_prop_line(ctx
, "Name", name
);
2247 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
2248 name
= bt_stream_class_get_name(sc
);
2250 write_str_prop_line(ctx
, "Class name", name
);
2254 write_trace(ctx
, trace
);
2262 int write_stream_end_message(struct details_write_ctx
*ctx
,
2263 const bt_message
*msg
)
2266 const bt_stream
*stream
=
2267 bt_message_stream_end_borrow_stream_const(msg
);
2268 const bt_stream_class
*sc
=
2269 bt_stream_borrow_class_const(stream
);
2270 const bt_clock_class
*cc
=
2271 bt_stream_class_borrow_default_clock_class_const(sc
);
2273 if (!ctx
->details_comp
->cfg
.with_data
) {
2279 const bt_clock_snapshot
*cs
;
2280 bt_message_stream_clock_snapshot_state cs_state
=
2281 bt_message_stream_end_borrow_default_clock_snapshot_const(msg
, &cs
);
2283 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2284 write_time(ctx
, cs
);
2286 write_time_str(ctx
, "Unknown");
2290 /* Write follow tag for message */
2291 ret
= write_message_follow_tag(ctx
, stream
);
2296 /* Write stream properties */
2297 write_obj_type_name(ctx
, "Stream end\n");
2304 int write_packet_beginning_message(struct details_write_ctx
*ctx
,
2305 const bt_message
*msg
)
2308 const bt_packet
*packet
=
2309 bt_message_packet_beginning_borrow_packet_const(msg
);
2310 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2311 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2312 const bt_field
*field
;
2314 if (!ctx
->details_comp
->cfg
.with_data
) {
2319 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
)) {
2321 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2325 /* Write follow tag for message */
2326 ret
= write_message_follow_tag(ctx
, stream
);
2331 write_obj_type_name(ctx
, "Packet beginning");
2333 if (ctx
->details_comp
->cfg
.compact
) {
2339 field
= bt_packet_borrow_context_field_const(packet
);
2341 g_string_append(ctx
->str
, ":\n");
2343 write_root_field(ctx
, "Context", field
);
2354 int write_discarded_items_message(struct details_write_ctx
*ctx
,
2355 const char *name
, const bt_stream
*stream
,
2356 const bt_clock_snapshot
*beginning_cs
,
2357 const bt_clock_snapshot
*end_cs
, uint64_t count
)
2363 write_time(ctx
, beginning_cs
);
2364 BT_ASSERT_DBG(end_cs
);
2365 write_time(ctx
, end_cs
);
2368 /* Write follow tag for message */
2369 ret
= write_message_follow_tag(ctx
, stream
);
2374 write_obj_type_name(ctx
, "Discarded ");
2375 write_obj_type_name(ctx
, name
);
2378 if (count
== UINT64_C(-1)) {
2383 g_string_append(ctx
->str
, " (");
2384 write_uint_prop_value(ctx
, count
);
2385 g_string_append_printf(ctx
->str
, " %s)\n", name
);
2392 int write_discarded_events_message(struct details_write_ctx
*ctx
,
2393 const bt_message
*msg
)
2396 const bt_stream
*stream
= bt_message_discarded_events_borrow_stream_const(
2398 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2399 const bt_clock_snapshot
*beginning_cs
= NULL
;
2400 const bt_clock_snapshot
*end_cs
= NULL
;
2403 if (!ctx
->details_comp
->cfg
.with_data
) {
2407 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc
)) {
2409 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2412 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2416 if (bt_message_discarded_events_get_count(msg
, &count
) !=
2417 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2418 count
= UINT64_C(-1);
2421 ret
= write_discarded_items_message(ctx
, "events", stream
,
2422 beginning_cs
, end_cs
, count
);
2429 int write_discarded_packets_message(struct details_write_ctx
*ctx
,
2430 const bt_message
*msg
)
2433 const bt_stream
*stream
= bt_message_discarded_packets_borrow_stream_const(
2435 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2436 const bt_clock_snapshot
*beginning_cs
= NULL
;
2437 const bt_clock_snapshot
*end_cs
= NULL
;
2440 if (!ctx
->details_comp
->cfg
.with_data
) {
2444 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
)) {
2446 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2449 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2453 if (bt_message_discarded_packets_get_count(msg
, &count
) !=
2454 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2455 count
= UINT64_C(-1);
2458 ret
= write_discarded_items_message(ctx
, "packets", stream
,
2459 beginning_cs
, end_cs
, count
);
2466 int write_packet_end_message(struct details_write_ctx
*ctx
,
2467 const bt_message
*msg
)
2470 const bt_packet
*packet
=
2471 bt_message_packet_end_borrow_packet_const(msg
);
2472 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2473 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2475 if (!ctx
->details_comp
->cfg
.with_data
) {
2480 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc
)) {
2482 bt_message_packet_end_borrow_default_clock_snapshot_const(
2486 /* Write follow tag for message */
2487 ret
= write_message_follow_tag(ctx
, stream
);
2492 write_obj_type_name(ctx
, "Packet end");
2500 int write_message_iterator_inactivity_message(struct details_write_ctx
*ctx
,
2501 const bt_message
*msg
)
2504 const bt_clock_snapshot
*cs
=
2505 bt_message_message_iterator_inactivity_borrow_clock_snapshot_const(
2509 write_time(ctx
, cs
);
2510 write_obj_type_name(ctx
, "Message iterator inactivity");
2512 if (ctx
->details_comp
->cfg
.compact
) {
2517 /* Write clock class properties */
2518 g_string_append(ctx
->str
, ":\n");
2521 write_prop_name(ctx
, "Clock class");
2522 g_string_append_c(ctx
->str
, ':');
2525 write_clock_class_prop_lines(ctx
,
2526 bt_clock_snapshot_borrow_clock_class_const(cs
));
2533 int details_write_message(struct details_comp
*details_comp
,
2534 const bt_message
*msg
)
2537 struct details_write_ctx ctx
= {
2538 .details_comp
= details_comp
,
2539 .str
= details_comp
->str
,
2543 /* Reset output buffer */
2544 g_string_assign(details_comp
->str
, "");
2546 switch (bt_message_get_type(msg
)) {
2547 case BT_MESSAGE_TYPE_EVENT
:
2548 ret
= write_event_message(&ctx
, msg
);
2550 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY
:
2551 ret
= write_message_iterator_inactivity_message(&ctx
, msg
);
2553 case BT_MESSAGE_TYPE_STREAM_BEGINNING
:
2554 ret
= write_stream_beginning_message(&ctx
, msg
);
2556 case BT_MESSAGE_TYPE_STREAM_END
:
2557 ret
= write_stream_end_message(&ctx
, msg
);
2559 case BT_MESSAGE_TYPE_PACKET_BEGINNING
:
2560 ret
= write_packet_beginning_message(&ctx
, msg
);
2562 case BT_MESSAGE_TYPE_PACKET_END
:
2563 ret
= write_packet_end_message(&ctx
, msg
);
2565 case BT_MESSAGE_TYPE_DISCARDED_EVENTS
:
2566 ret
= write_discarded_events_message(&ctx
, msg
);
2568 case BT_MESSAGE_TYPE_DISCARDED_PACKETS
:
2569 ret
= write_discarded_packets_message(&ctx
, msg
);
2576 * If this component printed at least one character so far, and
2577 * we're not in compact mode, and there's something in the
2578 * output buffer for this message, then prepend a newline to the
2579 * output buffer to visually separate message blocks.
2581 if (details_comp
->printed_something
&& !details_comp
->cfg
.compact
&&
2582 details_comp
->str
->len
> 0) {
2583 /* TODO: Optimize this */
2584 g_string_prepend_c(details_comp
->str
, '\n');