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 sprintf(buf_start
, spec
, value
);
95 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
100 void format_int(char *buf
, int64_t value
, unsigned int base
)
102 const char *spec
= "%" PRIu64
;
103 char *buf_start
= buf
;
104 unsigned int digits_per_group
= 3;
106 bool sep_digits
= true;
107 uint64_t abs_value
= value
< 0 ? (uint64_t) -value
: (uint64_t) value
;
117 /* TODO: Support binary format */
119 strcpy(buf_start
, "0x");
121 digits_per_group
= 4;
126 strcpy(buf_start
, "0");
131 if (value
>= -9999 && value
<= 9999) {
133 * Do not insert digit separators for numbers
134 * over -10,000 and under 10,000 as it looks
145 sprintf(buf_start
, spec
, abs_value
);
148 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
153 void write_nl(struct details_write_ctx
*ctx
)
156 g_string_append_c(ctx
->str
, '\n');
160 void write_sp(struct details_write_ctx
*ctx
)
163 g_string_append_c(ctx
->str
, ' ');
167 void write_indent(struct details_write_ctx
*ctx
)
173 for (i
= 0; i
< ctx
->indent_level
; i
++) {
179 void write_compound_member_name(struct details_write_ctx
*ctx
, const char *name
)
182 g_string_append_printf(ctx
->str
, "%s%s%s:",
183 color_fg_cyan(ctx
), name
, color_reset(ctx
));
187 void write_array_index(struct details_write_ctx
*ctx
, uint64_t index
,
193 format_uint(buf
, index
, 10);
194 g_string_append_printf(ctx
->str
, "%s[%s]%s:",
195 color
, buf
, color_reset(ctx
));
199 void write_obj_type_name(struct details_write_ctx
*ctx
, const char *name
)
201 g_string_append_printf(ctx
->str
, "%s%s%s%s",
202 color_bold(ctx
), color_fg_bright_yellow(ctx
), name
,
207 void write_prop_name(struct details_write_ctx
*ctx
, const char *prop_name
)
209 g_string_append_printf(ctx
->str
, "%s%s%s",
210 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
214 void write_prop_name_line(struct details_write_ctx
*ctx
, const char *prop_name
)
217 g_string_append_printf(ctx
->str
, "%s%s%s:",
218 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
222 void write_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
224 g_string_append_printf(ctx
->str
, "%s%s%s",
225 color_bold(ctx
), value
, color_reset(ctx
));
229 void write_none_prop_value(struct details_write_ctx
*ctx
, const char *value
)
231 g_string_append_printf(ctx
->str
, "%s%s%s%s",
232 color_bold(ctx
), color_fg_bright_magenta(ctx
),
233 value
, color_reset(ctx
));
237 void write_uint_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
239 write_str_prop_value(ctx
, value
);
243 void write_uint_prop_value(struct details_write_ctx
*ctx
, uint64_t value
)
247 format_uint(buf
, value
, 10);
248 write_uint_str_prop_value(ctx
, buf
);
252 void write_int_prop_value(struct details_write_ctx
*ctx
, int64_t value
)
256 format_int(buf
, value
, 10);
257 write_uint_str_prop_value(ctx
, buf
);
261 void write_float_prop_value(struct details_write_ctx
*ctx
, double value
)
263 g_string_append_printf(ctx
->str
, "%s%f%s",
264 color_bold(ctx
), value
, color_reset(ctx
));
268 void write_str_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
269 const char *prop_value
)
271 BT_ASSERT_DBG(prop_value
);
273 write_prop_name(ctx
, prop_name
);
274 g_string_append(ctx
->str
, ": ");
275 write_str_prop_value(ctx
, prop_value
);
280 void write_uint_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
284 write_prop_name(ctx
, prop_name
);
285 g_string_append(ctx
->str
, ": ");
286 write_uint_prop_value(ctx
, prop_value
);
291 void write_int_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
295 write_prop_name(ctx
, prop_name
);
296 g_string_append(ctx
->str
, ": ");
297 write_int_prop_value(ctx
, prop_value
);
302 void write_int_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
304 write_str_prop_value(ctx
, value
);
308 void write_bool_prop_value(struct details_write_ctx
*ctx
, bt_bool prop_value
)
312 g_string_append(ctx
->str
, color_bold(ctx
));
315 g_string_append(ctx
->str
, color_fg_bright_green(ctx
));
318 g_string_append(ctx
->str
, color_fg_bright_red(ctx
));
322 g_string_append_printf(ctx
->str
, "%s%s", str
, color_reset(ctx
));
326 void write_bool_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
330 write_prop_name(ctx
, prop_name
);
331 g_string_append(ctx
->str
, ": ");
332 write_bool_prop_value(ctx
, prop_value
);
337 void write_uuid_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
342 write_prop_name(ctx
, prop_name
);
343 g_string_append_printf(ctx
->str
,
344 ": %s" BT_UUID_FMT
"%s\n",
346 BT_UUID_FMT_VALUES(uuid
),
351 gint
compare_strings(const char **a
, const char **b
)
353 return strcmp(*a
, *b
);
357 bt_value_map_foreach_entry_const_func_status
map_value_foreach_add_key_to_array(
358 const char *key
, const bt_value
*object
, void *data
)
360 GPtrArray
*keys
= data
;
363 g_ptr_array_add(keys
, (void *) key
);
364 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK
;
368 void write_value(struct details_write_ctx
*ctx
, const bt_value
*value
,
372 bt_value_type value_type
= bt_value_get_type(value
);
373 GPtrArray
*keys
= g_ptr_array_new();
378 /* Write field's name */
380 write_prop_name_line(ctx
, name
);
383 /* Write field's value */
384 switch (value_type
) {
385 case BT_VALUE_TYPE_NULL
:
387 write_none_prop_value(ctx
, "Null");
389 case BT_VALUE_TYPE_BOOL
:
391 write_bool_prop_value(ctx
, bt_value_bool_get(value
));
393 case BT_VALUE_TYPE_UNSIGNED_INTEGER
:
394 format_uint(buf
, bt_value_integer_unsigned_get(value
), 10);
396 write_uint_str_prop_value(ctx
, buf
);
398 case BT_VALUE_TYPE_SIGNED_INTEGER
:
399 format_int(buf
, bt_value_integer_signed_get(value
), 10);
401 write_int_str_prop_value(ctx
, buf
);
403 case BT_VALUE_TYPE_REAL
:
405 write_float_prop_value(ctx
, bt_value_real_get(value
));
407 case BT_VALUE_TYPE_STRING
:
409 write_str_prop_value(ctx
, bt_value_string_get(value
));
411 case BT_VALUE_TYPE_ARRAY
:
413 uint64_t length
= bt_value_array_get_length(value
);
417 write_none_prop_value(ctx
, "Empty");
419 g_string_append(ctx
->str
, " Length ");
420 write_uint_prop_value(ctx
, length
);
421 g_string_append_c(ctx
->str
, ':');
426 for (i
= 0; i
< length
; i
++) {
427 const bt_value
*elem_value
=
428 bt_value_array_borrow_element_by_index_const(
432 write_array_index(ctx
, i
, color_fg_magenta(ctx
));
433 write_value(ctx
, elem_value
, NULL
);
439 case BT_VALUE_TYPE_MAP
:
441 bt_value_map_foreach_entry_const_status foreach_status
=
442 bt_value_map_foreach_entry_const(value
,
443 map_value_foreach_add_key_to_array
, keys
);
445 BT_ASSERT_DBG(foreach_status
==
446 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK
);
447 g_ptr_array_sort(keys
, (GCompareFunc
) compare_strings
);
452 for (i
= 0; i
< keys
->len
; i
++) {
453 const char *key
= keys
->pdata
[i
];
454 const bt_value
*entry_value
=
455 bt_value_map_borrow_entry_value_const(
459 write_value(ctx
, entry_value
, key
);
465 write_none_prop_value(ctx
, "Empty");
474 g_ptr_array_free(keys
, TRUE
);
478 void write_user_attributes(struct details_write_ctx
*ctx
,
479 const bt_value
*user_attrs
, bool write_newline
, bool *written
)
481 BT_ASSERT_DBG(user_attrs
);
483 if (!bt_value_map_is_empty(user_attrs
)) {
484 write_value(ctx
, user_attrs
, "User attributes");
497 void write_int_field_class_props(struct details_write_ctx
*ctx
,
498 const bt_field_class
*fc
, bool close
)
500 g_string_append_printf(ctx
->str
, "(%s%" PRIu64
"-bit%s, Base ",
502 bt_field_class_integer_get_field_value_range(fc
),
505 switch (bt_field_class_integer_get_preferred_display_base(fc
)) {
506 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
507 write_uint_prop_value(ctx
, 2);
509 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
510 write_uint_prop_value(ctx
, 8);
512 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
513 write_uint_prop_value(ctx
, 10);
515 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
516 write_uint_prop_value(ctx
, 16);
523 g_string_append(ctx
->str
, ")");
539 struct enum_field_class_mapping
{
543 /* Array of `struct int_range` */
548 gint
compare_enum_field_class_mappings(struct enum_field_class_mapping
**a
,
549 struct enum_field_class_mapping
**b
)
551 return strcmp((*a
)->label
, (*b
)->label
);
555 gint
compare_int_ranges_signed(struct int_range
*a
, struct int_range
*b
)
558 if (a
->lower
.i
< b
->lower
.i
) {
560 } else if (a
->lower
.i
> b
->lower
.i
) {
563 if (a
->upper
.i
< b
->upper
.i
) {
565 } else if (a
->upper
.i
> b
->upper
.i
) {
574 gint
compare_int_ranges_unsigned(struct int_range
*a
, struct int_range
*b
)
576 if (a
->lower
.u
< b
->lower
.u
) {
578 } else if (a
->lower
.u
> b
->lower
.u
) {
581 if (a
->upper
.u
< b
->upper
.u
) {
583 } else if (a
->upper
.u
> b
->upper
.u
) {
592 GArray
*range_set_to_int_ranges(const void *spec_range_set
, bool is_signed
)
595 const bt_integer_range_set
*range_set
;
596 GArray
*ranges
= g_array_new(FALSE
, TRUE
, sizeof(struct int_range
));
603 range_set
= bt_integer_range_set_signed_as_range_set_const(
606 range_set
= bt_integer_range_set_unsigned_as_range_set_const(
610 for (i
= 0; i
< bt_integer_range_set_get_range_count(range_set
); i
++) {
611 struct int_range range
;
614 const bt_integer_range_signed
*orig_range
=
615 bt_integer_range_set_signed_borrow_range_by_index_const(
618 range
.lower
.i
= bt_integer_range_signed_get_lower(orig_range
);
619 range
.upper
.i
= bt_integer_range_signed_get_upper(orig_range
);
621 const bt_integer_range_unsigned
*orig_range
=
622 bt_integer_range_set_unsigned_borrow_range_by_index_const(
625 range
.lower
.u
= bt_integer_range_unsigned_get_lower(orig_range
);
626 range
.upper
.u
= bt_integer_range_unsigned_get_upper(orig_range
);
629 g_array_append_val(ranges
, range
);
633 g_array_sort(ranges
, (GCompareFunc
) compare_int_ranges_signed
);
636 (GCompareFunc
) compare_int_ranges_unsigned
);
644 void destroy_enum_field_class_mapping(struct enum_field_class_mapping
*mapping
)
646 if (mapping
->ranges
) {
647 g_array_free(mapping
->ranges
, TRUE
);
648 mapping
->ranges
= NULL
;
655 struct int_range
*int_range_at(GArray
*ranges
, uint64_t index
)
657 return &g_array_index(ranges
, struct int_range
, index
);
661 void write_int_range(struct details_write_ctx
*ctx
,
662 struct int_range
*range
, bool is_signed
)
664 g_string_append(ctx
->str
, "[");
667 write_int_prop_value(ctx
, range
->lower
.i
);
669 write_int_prop_value(ctx
, range
->lower
.u
);
672 if (range
->lower
.u
!= range
->upper
.u
) {
673 g_string_append(ctx
->str
, ", ");
676 write_int_prop_value(ctx
, range
->upper
.i
);
678 write_int_prop_value(ctx
, range
->upper
.u
);
682 g_string_append(ctx
->str
, "]");
686 void write_enum_field_class_mappings(struct details_write_ctx
*ctx
,
687 const bt_field_class
*fc
)
692 bool is_signed
= bt_field_class_get_type(fc
) ==
693 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
;
695 mappings
= g_ptr_array_new_with_free_func(
696 (GDestroyNotify
) destroy_enum_field_class_mapping
);
697 BT_ASSERT_DBG(mappings
);
700 * Copy field class's mappings to our own arrays and structures
703 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(fc
); i
++) {
704 const void *fc_mapping
;
705 const void *fc_range_set
;
706 struct enum_field_class_mapping
*mapping
= g_new0(
707 struct enum_field_class_mapping
, 1);
709 BT_ASSERT_DBG(mapping
);
712 fc_mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
714 fc_range_set
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
717 fc_mapping
= bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
719 fc_range_set
= bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
723 mapping
->label
= bt_field_class_enumeration_mapping_get_label(
724 bt_field_class_enumeration_signed_mapping_as_mapping_const(
726 mapping
->ranges
= range_set_to_int_ranges(fc_range_set
,
728 BT_ASSERT_DBG(mapping
->ranges
);
729 g_ptr_array_add(mappings
, mapping
);
732 /* Sort mappings (ranges are already sorted within mappings) */
733 g_ptr_array_sort(mappings
,
734 (GCompareFunc
) compare_enum_field_class_mappings
);
737 for (i
= 0; i
< mappings
->len
; i
++) {
738 struct enum_field_class_mapping
*mapping
= mappings
->pdata
[i
];
741 write_prop_name_line(ctx
, mapping
->label
);
743 for (range_i
= 0; range_i
< mapping
->ranges
->len
; range_i
++) {
746 int_range_at(mapping
->ranges
, range_i
),
751 g_ptr_array_free(mappings
, TRUE
);
755 void write_field_path(struct details_write_ctx
*ctx
,
756 const bt_field_path
*field_path
)
760 g_string_append_c(ctx
->str
, '[');
762 switch (bt_field_path_get_root_scope(field_path
)) {
763 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
764 write_str_prop_value(ctx
, "Packet context");
766 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
767 write_str_prop_value(ctx
, "Event common context");
769 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
770 write_str_prop_value(ctx
, "Event specific context");
772 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
773 write_str_prop_value(ctx
, "Event payload");
779 g_string_append(ctx
->str
, ": ");
781 for (i
= 0; i
< bt_field_path_get_item_count(field_path
); i
++) {
782 const bt_field_path_item
*fp_item
=
783 bt_field_path_borrow_item_by_index_const(field_path
, i
);
786 g_string_append(ctx
->str
, ", ");
789 switch (bt_field_path_item_get_type(fp_item
)) {
790 case BT_FIELD_PATH_ITEM_TYPE_INDEX
:
791 write_uint_prop_value(ctx
,
792 bt_field_path_item_index_get_index(fp_item
));
794 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
:
795 write_str_prop_value(ctx
, "<current>");
802 g_string_append_c(ctx
->str
, ']');
806 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
);
809 void write_variant_field_class_option(struct details_write_ctx
*ctx
,
810 const bt_field_class
*fc
, uint64_t index
)
812 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
813 const bt_field_class_variant_option
*option
=
814 bt_field_class_variant_borrow_option_by_index_const(
816 const void *orig_ranges
= NULL
;
817 GArray
*int_ranges
= NULL
;
819 const bt_value
*user_attrs
=
820 bt_field_class_variant_option_borrow_user_attributes_const(
822 const bt_field_class
*option_fc
=
823 bt_field_class_variant_option_borrow_field_class_const(option
);
826 write_compound_member_name(ctx
,
827 bt_field_class_variant_option_get_name(option
));
829 if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
830 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*spec_opt
=
831 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
835 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
838 } else if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
839 const bt_field_class_variant_with_selector_field_integer_signed_option
*spec_opt
=
840 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
844 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
852 int_ranges
= range_set_to_int_ranges(orig_ranges
, is_signed
);
853 BT_ASSERT_DBG(int_ranges
);
855 for (i
= 0; i
< int_ranges
->len
; i
++) {
856 struct int_range
*range
= int_range_at(int_ranges
, i
);
859 write_int_range(ctx
, range
, is_signed
);
862 g_string_append(ctx
->str
, ": ");
867 if (bt_value_map_is_empty(user_attrs
)) {
868 write_field_class(ctx
, option_fc
);
874 write_prop_name_line(ctx
, "Field class");
876 write_field_class(ctx
, option_fc
);
879 /* User attributes */
880 write_user_attributes(ctx
, user_attrs
,
887 g_array_free(int_ranges
, TRUE
);
892 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
)
896 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
897 const bt_value
*user_attrs
;
898 bool wrote_user_attrs
= false;
900 /* Write field class's type */
902 case BT_FIELD_CLASS_TYPE_BOOL
:
905 case BT_FIELD_CLASS_TYPE_BIT_ARRAY
:
908 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
909 type
= "Unsigned integer";
911 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
912 type
= "Signed integer";
914 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
915 type
= "Unsigned enumeration";
917 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
918 type
= "Signed enumeration";
920 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
:
921 type
= "Single-precision real";
923 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
:
924 type
= "Double-precision real";
926 case BT_FIELD_CLASS_TYPE_STRING
:
929 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
932 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
933 type
= "Static array";
935 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
936 type
= "Dynamic array (no length field)";
938 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
939 type
= "Dynamic array (with length field)";
941 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD
:
942 type
= "Option (no selector)";
944 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
:
945 type
= "Option (boolean selector)";
947 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
948 type
= "Option (unsigned integer selector)";
950 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
951 type
= "Option (signed integer selector)";
953 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
:
954 type
= "Variant (no selector)";
956 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
957 type
= "Variant (unsigned integer selector)";
959 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
960 type
= "Variant (signed integer selector)";
966 g_string_append_printf(ctx
->str
, "%s%s%s",
967 color_fg_blue(ctx
), type
, color_reset(ctx
));
969 /* Write field class's single-line properties */
970 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
971 uint64_t mapping_count
=
972 bt_field_class_enumeration_get_mapping_count(fc
);
975 write_int_field_class_props(ctx
, fc
, false);
976 g_string_append(ctx
->str
, ", ");
977 write_uint_prop_value(ctx
, mapping_count
);
978 g_string_append_printf(ctx
->str
, " mapping%s)",
979 plural(mapping_count
));
980 } else if (bt_field_class_type_is(fc_type
,
981 BT_FIELD_CLASS_TYPE_INTEGER
)) {
983 write_int_field_class_props(ctx
, fc
, true);
984 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
985 uint64_t member_count
=
986 bt_field_class_structure_get_member_count(fc
);
988 g_string_append(ctx
->str
, " (");
989 write_uint_prop_value(ctx
, member_count
);
990 g_string_append_printf(ctx
->str
, " member%s)",
991 plural(member_count
));
992 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
993 g_string_append(ctx
->str
, " (Length ");
994 write_uint_prop_value(ctx
,
995 bt_field_class_array_static_get_length(fc
));
996 g_string_append_c(ctx
->str
, ')');
997 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
998 const bt_field_path
*length_field_path
=
999 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1002 g_string_append(ctx
->str
, " (Length field path ");
1003 write_field_path(ctx
, length_field_path
);
1004 g_string_append_c(ctx
->str
, ')');
1005 } else if (bt_field_class_type_is(fc_type
,
1006 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
1007 const bt_field_path
*selector_field_path
=
1008 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
1011 g_string_append(ctx
->str
, " (Selector field path ");
1012 write_field_path(ctx
, selector_field_path
);
1013 g_string_append_c(ctx
->str
, ')');
1014 } else if (bt_field_class_type_is(fc_type
,
1015 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1016 uint64_t option_count
=
1017 bt_field_class_variant_get_option_count(fc
);
1018 const bt_field_path
*sel_field_path
= NULL
;
1020 if (bt_field_class_type_is(fc_type
,
1021 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
1023 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1025 BT_ASSERT_DBG(sel_field_path
);
1028 g_string_append(ctx
->str
, " (");
1029 write_uint_prop_value(ctx
, option_count
);
1030 g_string_append_printf(ctx
->str
, " option%s",
1031 plural(option_count
));
1033 if (sel_field_path
) {
1034 g_string_append(ctx
->str
, ", Selector field path ");
1035 write_field_path(ctx
, sel_field_path
);
1038 g_string_append_c(ctx
->str
, ')');
1042 user_attrs
= bt_field_class_borrow_user_attributes_const(fc
);
1043 if (!bt_value_map_is_empty(user_attrs
)) {
1044 g_string_append(ctx
->str
, ":\n");
1045 write_user_attributes(ctx
, user_attrs
, false, NULL
);
1046 wrote_user_attrs
= true;
1049 /* Write field class's complex properties */
1050 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
1051 uint64_t mapping_count
=
1052 bt_field_class_enumeration_get_mapping_count(fc
);
1054 if (mapping_count
> 0) {
1055 if (wrote_user_attrs
) {
1058 write_prop_name(ctx
, "Mappings");
1059 g_string_append_c(ctx
->str
, ':');
1062 /* Each mapping starts with its own newline */
1063 g_string_append_c(ctx
->str
, ':');
1066 write_enum_field_class_mappings(ctx
, fc
);
1068 if (wrote_user_attrs
) {
1072 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1073 uint64_t member_count
=
1074 bt_field_class_structure_get_member_count(fc
);
1076 if (member_count
> 0) {
1077 if (wrote_user_attrs
) {
1080 write_prop_name(ctx
, "Members");
1081 g_string_append_c(ctx
->str
, ':');
1084 /* Each member starts with its own newline */
1085 g_string_append_c(ctx
->str
, ':');
1088 for (i
= 0; i
< member_count
; i
++) {
1089 const bt_field_class_structure_member
*member
=
1090 bt_field_class_structure_borrow_member_by_index_const(
1092 const bt_value
*member_user_attrs
;
1093 const bt_field_class
*member_fc
=
1094 bt_field_class_structure_member_borrow_field_class_const(member
);
1097 write_compound_member_name(ctx
,
1098 bt_field_class_structure_member_get_name(member
));
1099 member_user_attrs
= bt_field_class_structure_member_borrow_user_attributes_const(
1102 if (bt_value_map_is_empty(member_user_attrs
)) {
1104 write_field_class(ctx
, member_fc
);
1110 write_prop_name_line(ctx
, "Field class");
1112 write_field_class(ctx
, member_fc
);
1115 /* User attributes */
1116 write_user_attributes(ctx
, member_user_attrs
,
1123 if (wrote_user_attrs
) {
1127 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1128 if (wrote_user_attrs
) {
1131 g_string_append(ctx
->str
, ":\n");
1134 write_prop_name_line(ctx
, "Element");
1136 write_field_class(ctx
,
1137 bt_field_class_array_borrow_element_field_class_const(fc
));
1138 } else if (bt_field_class_type_is(fc_type
,
1139 BT_FIELD_CLASS_TYPE_OPTION
)) {
1140 const void *ranges
= NULL
;
1141 bool selector_is_signed
= false;
1143 if (wrote_user_attrs
) {
1146 g_string_append(ctx
->str
, ":\n");
1149 if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
) {
1150 write_bool_prop_line(ctx
, "Selector is reversed",
1151 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc
));
1152 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
1153 ranges
= bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc
);
1154 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
1155 ranges
= bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc
);
1156 selector_is_signed
= true;
1160 GArray
*sorted_ranges
= range_set_to_int_ranges(
1161 ranges
, selector_is_signed
);
1163 BT_ASSERT_DBG(sorted_ranges
);
1164 BT_ASSERT_DBG(sorted_ranges
->len
> 0);
1165 write_prop_name_line(ctx
, "Selector ranges");
1167 for (i
= 0; i
< sorted_ranges
->len
; i
++) {
1169 write_int_range(ctx
,
1170 int_range_at(sorted_ranges
, i
),
1171 selector_is_signed
);
1175 g_array_free(sorted_ranges
, TRUE
);
1178 write_prop_name_line(ctx
, "Content");
1180 write_field_class(ctx
,
1181 bt_field_class_option_borrow_field_class_const(fc
));
1182 } else if (bt_field_class_type_is(fc_type
,
1183 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1184 uint64_t option_count
=
1185 bt_field_class_variant_get_option_count(fc
);
1187 if (option_count
> 0) {
1188 if (wrote_user_attrs
) {
1191 write_prop_name(ctx
, "Options");
1192 g_string_append_c(ctx
->str
, ':');
1195 /* Each option starts with its own newline */
1196 g_string_append_c(ctx
->str
, ':');
1199 for (i
= 0; i
< option_count
; i
++) {
1200 write_variant_field_class_option(ctx
, fc
, i
);
1203 if (wrote_user_attrs
) {
1213 void write_root_field_class(struct details_write_ctx
*ctx
, const char *name
,
1214 const bt_field_class
*fc
)
1216 BT_ASSERT_DBG(name
);
1219 write_prop_name(ctx
, name
);
1220 g_string_append(ctx
->str
, ": ");
1221 write_field_class(ctx
, fc
);
1226 void write_event_class(struct details_write_ctx
*ctx
, const bt_event_class
*ec
)
1228 const char *name
= bt_event_class_get_name(ec
);
1229 const char *emf_uri
;
1230 const bt_field_class
*fc
;
1231 bt_event_class_log_level log_level
;
1234 write_obj_type_name(ctx
, "Event class");
1236 /* Write name and ID */
1238 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1239 color_fg_green(ctx
), name
, color_reset(ctx
));
1242 g_string_append(ctx
->str
, " (ID ");
1243 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1244 g_string_append(ctx
->str
, "):\n");
1246 /* Write properties */
1249 /* Write user attributes */
1250 write_user_attributes(ctx
,
1251 bt_event_class_borrow_user_attributes_const(ec
), true, NULL
);
1253 /* Write log level */
1254 if (bt_event_class_get_log_level(ec
, &log_level
) ==
1255 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
1256 const char *ll_str
= NULL
;
1258 switch (log_level
) {
1259 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY
:
1260 ll_str
= "Emergency";
1262 case BT_EVENT_CLASS_LOG_LEVEL_ALERT
:
1265 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL
:
1266 ll_str
= "Critical";
1268 case BT_EVENT_CLASS_LOG_LEVEL_ERROR
:
1271 case BT_EVENT_CLASS_LOG_LEVEL_WARNING
:
1274 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE
:
1277 case BT_EVENT_CLASS_LOG_LEVEL_INFO
:
1280 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
:
1281 ll_str
= "Debug (system)";
1283 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
:
1284 ll_str
= "Debug (program)";
1286 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
:
1287 ll_str
= "Debug (process)";
1289 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
:
1290 ll_str
= "Debug (module)";
1292 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
:
1293 ll_str
= "Debug (unit)";
1295 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
:
1296 ll_str
= "Debug (function)";
1298 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
:
1299 ll_str
= "Debug (line)";
1301 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG
:
1308 write_str_prop_line(ctx
, "Log level", ll_str
);
1312 emf_uri
= bt_event_class_get_emf_uri(ec
);
1314 write_str_prop_line(ctx
, "EMF URI", emf_uri
);
1317 /* Write specific context field class */
1318 fc
= bt_event_class_borrow_specific_context_field_class_const(ec
);
1320 write_root_field_class(ctx
, "Specific context field class", fc
);
1323 /* Write payload field class */
1324 fc
= bt_event_class_borrow_payload_field_class_const(ec
);
1326 write_root_field_class(ctx
, "Payload field class", fc
);
1333 void write_clock_class_prop_lines(struct details_write_ctx
*ctx
,
1334 const bt_clock_class
*cc
)
1336 int64_t offset_seconds
;
1337 uint64_t offset_cycles
;
1340 str
= bt_clock_class_get_name(cc
);
1342 write_str_prop_line(ctx
, "Name", str
);
1345 write_user_attributes(ctx
,
1346 bt_clock_class_borrow_user_attributes_const(cc
), true, NULL
);
1347 str
= bt_clock_class_get_description(cc
);
1349 write_str_prop_line(ctx
, "Description", str
);
1352 write_uint_prop_line(ctx
, "Frequency (Hz)",
1353 bt_clock_class_get_frequency(cc
));
1354 write_uint_prop_line(ctx
, "Precision (cycles)",
1355 bt_clock_class_get_precision(cc
));
1356 bt_clock_class_get_offset(cc
, &offset_seconds
, &offset_cycles
);
1357 write_int_prop_line(ctx
, "Offset (s)", offset_seconds
);
1358 write_uint_prop_line(ctx
, "Offset (cycles)", offset_cycles
);
1359 write_bool_prop_line(ctx
, "Origin is Unix epoch",
1360 bt_clock_class_origin_is_unix_epoch(cc
));
1362 if (ctx
->details_comp
->cfg
.with_uuid
) {
1363 bt_uuid uuid
= bt_clock_class_get_uuid(cc
);
1366 write_uuid_prop_line(ctx
, "UUID", uuid
);
1372 gint
compare_event_classes(const bt_event_class
**a
, const bt_event_class
**b
)
1374 uint64_t id_a
= bt_event_class_get_id(*a
);
1375 uint64_t id_b
= bt_event_class_get_id(*b
);
1379 } else if (id_a
> id_b
) {
1387 void write_stream_class(struct details_write_ctx
*ctx
,
1388 const bt_stream_class
*sc
)
1390 const bt_field_class
*fc
;
1391 GPtrArray
*event_classes
= g_ptr_array_new();
1395 write_obj_type_name(ctx
, "Stream class");
1397 /* Write name and ID */
1398 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
1399 const char *name
= bt_stream_class_get_name(sc
);
1402 g_string_append(ctx
->str
, " `");
1403 write_str_prop_value(ctx
, name
);
1404 g_string_append(ctx
->str
, "`");
1408 g_string_append(ctx
->str
, " (ID ");
1409 write_uint_prop_value(ctx
, bt_stream_class_get_id(sc
));
1410 g_string_append(ctx
->str
, "):\n");
1412 /* Write properties */
1415 /* Write user attributes */
1416 write_user_attributes(ctx
,
1417 bt_stream_class_borrow_user_attributes_const(sc
), true, NULL
);
1419 /* Write configuration */
1420 write_bool_prop_line(ctx
,
1421 "Supports packets", bt_stream_class_supports_packets(sc
));
1423 if (bt_stream_class_supports_packets(sc
)) {
1424 write_bool_prop_line(ctx
,
1425 "Packets have beginning default clock snapshot",
1426 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
));
1427 write_bool_prop_line(ctx
,
1428 "Packets have end default clock snapshot",
1429 bt_stream_class_packets_have_end_default_clock_snapshot(sc
));
1432 write_bool_prop_line(ctx
,
1433 "Supports discarded events",
1434 bt_stream_class_supports_discarded_events(sc
));
1436 if (bt_stream_class_supports_discarded_events(sc
)) {
1437 write_bool_prop_line(ctx
,
1438 "Discarded events have default clock snapshots",
1439 bt_stream_class_discarded_events_have_default_clock_snapshots(sc
));
1442 write_bool_prop_line(ctx
,
1443 "Supports discarded packets",
1444 bt_stream_class_supports_discarded_packets(sc
));
1446 if (bt_stream_class_supports_discarded_packets(sc
)) {
1447 write_bool_prop_line(ctx
,
1448 "Discarded packets have default clock snapshots",
1449 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
));
1452 /* Write default clock class */
1453 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1455 write_prop_name(ctx
, "Default clock class");
1456 g_string_append_c(ctx
->str
, ':');
1459 write_clock_class_prop_lines(ctx
,
1460 bt_stream_class_borrow_default_clock_class_const(sc
));
1464 fc
= bt_stream_class_borrow_packet_context_field_class_const(sc
);
1466 write_root_field_class(ctx
, "Packet context field class", fc
);
1469 fc
= bt_stream_class_borrow_event_common_context_field_class_const(sc
);
1471 write_root_field_class(ctx
, "Event common context field class",
1475 for (i
= 0; i
< bt_stream_class_get_event_class_count(sc
); i
++) {
1476 g_ptr_array_add(event_classes
,
1477 (gpointer
) bt_stream_class_borrow_event_class_by_index_const(
1481 g_ptr_array_sort(event_classes
, (GCompareFunc
) compare_event_classes
);
1483 for (i
= 0; i
< event_classes
->len
; i
++) {
1484 write_event_class(ctx
, event_classes
->pdata
[i
]);
1488 g_ptr_array_free(event_classes
, TRUE
);
1492 gint
compare_stream_classes(const bt_stream_class
**a
, const bt_stream_class
**b
)
1494 uint64_t id_a
= bt_stream_class_get_id(*a
);
1495 uint64_t id_b
= bt_stream_class_get_id(*b
);
1499 } else if (id_a
> id_b
) {
1507 void write_trace_class(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
)
1509 GPtrArray
*stream_classes
= g_ptr_array_new();
1511 bool printed_prop
= false;
1514 write_obj_type_name(ctx
, "Trace class");
1517 for (i
= 0; i
< bt_trace_class_get_stream_class_count(tc
); i
++) {
1518 g_ptr_array_add(stream_classes
,
1519 (gpointer
) bt_trace_class_borrow_stream_class_by_index_const(
1523 g_ptr_array_sort(stream_classes
, (GCompareFunc
) compare_stream_classes
);
1525 if (stream_classes
->len
> 0) {
1526 if (!printed_prop
) {
1527 g_string_append(ctx
->str
, ":\n");
1528 printed_prop
= true;
1534 /* Write user attributes */
1535 write_user_attributes(ctx
,
1536 bt_trace_class_borrow_user_attributes_const(tc
), true,
1539 /* Write stream classes */
1540 for (i
= 0; i
< stream_classes
->len
; i
++) {
1541 write_stream_class(ctx
, stream_classes
->pdata
[i
]);
1544 if (!printed_prop
) {
1549 g_ptr_array_free(stream_classes
, TRUE
);
1553 int try_write_meta(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
,
1554 const bt_stream_class
*sc
, const bt_event_class
*ec
)
1560 if (details_need_to_write_trace_class(ctx
, tc
)) {
1563 if (ctx
->details_comp
->cfg
.compact
&&
1564 ctx
->details_comp
->printed_something
) {
1566 * There are no empty line between messages in
1567 * compact mode, so write one here to decouple
1568 * the trace class from the next message.
1574 * write_trace_class() also writes all its stream
1575 * classes their event classes, so we don't need to
1578 write_trace_class(ctx
, tc
);
1581 * Mark this trace class as written, as well as all
1582 * its stream classes and their event classes.
1584 ret
= details_did_write_trace_class(ctx
, tc
);
1589 for (sc_i
= 0; sc_i
< bt_trace_class_get_stream_class_count(tc
);
1592 const bt_stream_class
*tc_sc
=
1593 bt_trace_class_borrow_stream_class_by_index_const(
1596 details_did_write_meta_object(ctx
, tc
, tc_sc
);
1598 for (ec_i
= 0; ec_i
<
1599 bt_stream_class_get_event_class_count(tc_sc
);
1601 details_did_write_meta_object(ctx
, tc
,
1602 bt_stream_class_borrow_event_class_by_index_const(
1610 if (sc
&& details_need_to_write_meta_object(ctx
, tc
, sc
)) {
1615 if (ctx
->details_comp
->cfg
.compact
&&
1616 ctx
->details_comp
->printed_something
) {
1618 * There are no empty line between messages in
1619 * compact mode, so write one here to decouple
1620 * the stream class from the next message.
1626 * write_stream_class() also writes all its event
1627 * classes, so we don't need to rewrite `ec`.
1629 write_stream_class(ctx
, sc
);
1632 * Mark this stream class as written, as well as all its
1635 details_did_write_meta_object(ctx
, tc
, sc
);
1637 for (ec_i
= 0; ec_i
<
1638 bt_stream_class_get_event_class_count(sc
);
1640 details_did_write_meta_object(ctx
, tc
,
1641 bt_stream_class_borrow_event_class_by_index_const(
1648 if (ec
&& details_need_to_write_meta_object(ctx
, tc
, ec
)) {
1651 if (ctx
->details_comp
->cfg
.compact
&&
1652 ctx
->details_comp
->printed_something
) {
1654 * There are no empty line between messages in
1655 * compact mode, so write one here to decouple
1656 * the event class from the next message.
1661 write_event_class(ctx
, ec
);
1662 details_did_write_meta_object(ctx
, tc
, ec
);
1671 void write_time_str(struct details_write_ctx
*ctx
, const char *str
)
1673 if (!ctx
->details_comp
->cfg
.with_time
) {
1677 g_string_append_printf(ctx
->str
, "[%s%s%s%s]",
1678 color_bold(ctx
), color_fg_bright_blue(ctx
), str
,
1681 if (ctx
->details_comp
->cfg
.compact
) {
1692 void write_time(struct details_write_ctx
*ctx
, const bt_clock_snapshot
*cs
)
1694 bt_clock_snapshot_get_ns_from_origin_status cs_status
;
1695 int64_t ns_from_origin
;
1698 if (!ctx
->details_comp
->cfg
.with_time
) {
1702 format_uint(buf
, bt_clock_snapshot_get_value(cs
), 10);
1703 g_string_append_printf(ctx
->str
, "[%s%s%s%s%s",
1704 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1706 ctx
->details_comp
->cfg
.compact
? "" : " cycles");
1707 cs_status
= bt_clock_snapshot_get_ns_from_origin(cs
, &ns_from_origin
);
1708 if (cs_status
== BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK
) {
1709 format_int(buf
, ns_from_origin
, 10);
1710 g_string_append_printf(ctx
->str
, "%s %s%s%s%s%s",
1711 ctx
->details_comp
->cfg
.compact
? "" : ",",
1712 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1714 ctx
->details_comp
->cfg
.compact
? "" : " ns from origin");
1717 g_string_append(ctx
->str
, "]");
1719 if (ctx
->details_comp
->cfg
.compact
) {
1730 int write_message_follow_tag(struct details_write_ctx
*ctx
,
1731 const bt_stream
*stream
)
1734 uint64_t unique_trace_id
;
1735 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
1736 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
1738 ret
= details_trace_unique_id(ctx
, trace
, &unique_trace_id
);
1743 if (ctx
->details_comp
->cfg
.compact
) {
1744 g_string_append_printf(ctx
->str
,
1745 "%s{%s%s%" PRIu64
" %" PRIu64
" %" PRIu64
"%s%s}%s ",
1746 color_fg_cyan(ctx
), color_bold(ctx
),
1747 color_fg_bright_cyan(ctx
),
1748 unique_trace_id
, bt_stream_class_get_id(sc
),
1749 bt_stream_get_id(stream
),
1750 color_reset(ctx
), color_fg_cyan(ctx
), color_reset(ctx
));
1752 g_string_append_printf(ctx
->str
,
1753 "%s{Trace %s%s%" PRIu64
"%s%s, Stream class ID %s%s%" PRIu64
"%s%s, Stream ID %s%s%" PRIu64
"%s%s}%s\n",
1755 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1756 unique_trace_id
, color_reset(ctx
),
1758 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1759 bt_stream_class_get_id(sc
), color_reset(ctx
),
1761 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1762 bt_stream_get_id(stream
), color_reset(ctx
),
1763 color_fg_cyan(ctx
), color_reset(ctx
));
1771 void write_field(struct details_write_ctx
*ctx
, const bt_field
*field
,
1775 bt_field_class_type fc_type
= bt_field_get_class_type(field
);
1776 const bt_field_class
*fc
;
1779 /* Write field's name */
1781 write_compound_member_name(ctx
, name
);
1784 /* Write field's value */
1785 if (fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1787 write_bool_prop_value(ctx
, bt_field_bool_get_value(field
));
1788 } else if (fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1789 format_uint(buf
, bt_field_bit_array_get_value_as_integer(field
),
1792 write_uint_str_prop_value(ctx
, buf
);
1793 } else if (bt_field_class_type_is(fc_type
,
1794 BT_FIELD_CLASS_TYPE_INTEGER
)) {
1795 unsigned int fmt_base
;
1796 bt_field_class_integer_preferred_display_base base
;
1798 fc
= bt_field_borrow_class_const(field
);
1799 base
= bt_field_class_integer_get_preferred_display_base(fc
);
1802 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
1805 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
1808 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
1811 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
1818 if (bt_field_class_type_is(fc_type
,
1819 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
)) {
1821 bt_field_integer_unsigned_get_value(field
),
1824 write_uint_str_prop_value(ctx
, buf
);
1827 bt_field_integer_signed_get_value(field
),
1830 write_int_str_prop_value(ctx
, buf
);
1832 } else if (fc_type
== BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
) {
1834 write_float_prop_value(ctx
, bt_field_real_single_precision_get_value(field
));
1835 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
) {
1837 write_float_prop_value(ctx
, bt_field_real_double_precision_get_value(field
));
1838 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1840 write_str_prop_value(ctx
, bt_field_string_get_value(field
));
1841 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1842 uint64_t member_count
;
1844 fc
= bt_field_borrow_class_const(field
);
1845 member_count
= bt_field_class_structure_get_member_count(fc
);
1847 if (member_count
> 0) {
1850 for (i
= 0; i
< member_count
; i
++) {
1851 const bt_field_class_structure_member
*member
=
1852 bt_field_class_structure_borrow_member_by_index_const(
1854 const bt_field
*member_field
=
1855 bt_field_structure_borrow_member_field_by_index_const(
1859 write_field(ctx
, member_field
,
1860 bt_field_class_structure_member_get_name(member
));
1866 write_none_prop_value(ctx
, "Empty");
1868 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1869 uint64_t length
= bt_field_array_get_length(field
);
1873 write_none_prop_value(ctx
, "Empty");
1875 g_string_append(ctx
->str
, " Length ");
1876 write_uint_prop_value(ctx
, length
);
1877 g_string_append_c(ctx
->str
, ':');
1882 for (i
= 0; i
< length
; i
++) {
1883 const bt_field
*elem_field
=
1884 bt_field_array_borrow_element_field_by_index_const(
1888 write_array_index(ctx
, i
, color_fg_cyan(ctx
));
1889 write_field(ctx
, elem_field
, NULL
);
1893 } else if (bt_field_class_type_is(fc_type
,
1894 BT_FIELD_CLASS_TYPE_OPTION
)) {
1895 const bt_field
*content_field
=
1896 bt_field_option_borrow_field_const(field
);
1898 if (!content_field
) {
1900 write_none_prop_value(ctx
, "None");
1902 write_field(ctx
, content_field
, NULL
);
1904 } else if (bt_field_class_type_is(fc_type
,
1905 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1907 bt_field_variant_borrow_selected_option_field_const(
1915 void write_root_field(struct details_write_ctx
*ctx
, const char *name
,
1916 const bt_field
*field
)
1918 BT_ASSERT_DBG(name
);
1919 BT_ASSERT_DBG(field
);
1921 write_prop_name(ctx
, name
);
1922 g_string_append(ctx
->str
, ":");
1923 write_field(ctx
, field
, NULL
);
1928 int write_event_message(struct details_write_ctx
*ctx
,
1929 const bt_message
*msg
)
1932 const bt_event
*event
= bt_message_event_borrow_event_const(msg
);
1933 const bt_stream
*stream
= bt_event_borrow_stream_const(event
);
1934 const bt_event_class
*ec
= bt_event_borrow_class_const(event
);
1935 const bt_stream_class
*sc
= bt_event_class_borrow_stream_class_const(ec
);
1936 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
1937 const char *ec_name
;
1938 const bt_field
*field
;
1940 ret
= try_write_meta(ctx
, tc
, sc
, ec
);
1945 if (!ctx
->details_comp
->cfg
.with_data
) {
1949 if (ctx
->str
->len
> 0) {
1951 * Output buffer contains metadata: separate blocks with
1958 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1960 bt_message_event_borrow_default_clock_snapshot_const(
1964 /* Write follow tag for message */
1965 ret
= write_message_follow_tag(ctx
, stream
);
1970 /* Write object's basic properties */
1971 write_obj_type_name(ctx
, "Event");
1972 ec_name
= bt_event_class_get_name(ec
);
1974 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1975 color_fg_green(ctx
), ec_name
, color_reset(ctx
));
1978 g_string_append(ctx
->str
, " (");
1980 if (!ctx
->details_comp
->cfg
.compact
) {
1981 g_string_append(ctx
->str
, "Class ID ");
1984 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1985 g_string_append(ctx
->str
, ")");
1987 if (ctx
->details_comp
->cfg
.compact
) {
1993 g_string_append(ctx
->str
, ":\n");
1995 field
= bt_event_borrow_common_context_field_const(event
);
1997 write_root_field(ctx
, "Common context", field
);
2000 field
= bt_event_borrow_specific_context_field_const(event
);
2002 write_root_field(ctx
, "Specific context", field
);
2005 field
= bt_event_borrow_payload_field_const(event
);
2007 write_root_field(ctx
, "Payload", field
);
2017 gint
compare_streams(const bt_stream
**a
, const bt_stream
**b
)
2019 uint64_t id_a
= bt_stream_get_id(*a
);
2020 uint64_t id_b
= bt_stream_get_id(*b
);
2024 } else if (id_a
> id_b
) {
2027 const bt_stream_class
*a_sc
= bt_stream_borrow_class_const(*a
);
2028 const bt_stream_class
*b_sc
= bt_stream_borrow_class_const(*b
);
2029 uint64_t a_sc_id
= bt_stream_class_get_id(a_sc
);
2030 uint64_t b_sc_id
= bt_stream_class_get_id(b_sc
);
2032 if (a_sc_id
< b_sc_id
) {
2034 } else if (a_sc_id
> b_sc_id
) {
2043 void write_trace(struct details_write_ctx
*ctx
, const bt_trace
*trace
)
2045 GPtrArray
*streams
= g_ptr_array_new();
2047 bool printed_prop
= false;
2048 GPtrArray
*env_names
= g_ptr_array_new();
2052 write_obj_type_name(ctx
, "Trace");
2055 if (ctx
->details_comp
->cfg
.with_trace_name
) {
2056 const char *name
= bt_trace_get_name(trace
);
2058 g_string_append(ctx
->str
, " `");
2059 write_str_prop_value(ctx
, name
);
2060 g_string_append(ctx
->str
, "`");
2064 /* Write properties */
2068 if (ctx
->details_comp
->cfg
.with_uuid
) {
2069 bt_uuid uuid
= bt_trace_get_uuid(trace
);
2072 if (!printed_prop
) {
2073 g_string_append(ctx
->str
, ":\n");
2074 printed_prop
= true;
2077 write_uuid_prop_line(ctx
, "UUID", uuid
);
2081 /* Write environment */
2082 env_count
= bt_trace_get_environment_entry_count(trace
);
2083 if (env_count
> 0) {
2084 if (!printed_prop
) {
2085 g_string_append(ctx
->str
, ":\n");
2086 printed_prop
= true;
2090 write_prop_name(ctx
, "Environment");
2091 g_string_append(ctx
->str
, " (");
2092 write_uint_prop_value(ctx
, env_count
);
2093 g_string_append_printf(ctx
->str
, " entr%s):",
2094 env_count
== 1 ? "y" : "ies");
2098 for (i
= 0; i
< env_count
; i
++) {
2100 const bt_value
*value
;
2102 bt_trace_borrow_environment_entry_by_index_const(
2103 trace
, i
, &name
, &value
);
2104 g_ptr_array_add(env_names
, (gpointer
) name
);
2107 g_ptr_array_sort(env_names
, (GCompareFunc
) compare_strings
);
2109 for (i
= 0; i
< env_names
->len
; i
++) {
2110 const char *name
= env_names
->pdata
[i
];
2111 const bt_value
*value
=
2112 bt_trace_borrow_environment_entry_value_by_name_const(
2115 BT_ASSERT_DBG(value
);
2116 write_compound_member_name(ctx
, name
);
2119 if (bt_value_get_type(value
) ==
2120 BT_VALUE_TYPE_SIGNED_INTEGER
) {
2121 write_int_prop_value(ctx
,
2122 bt_value_integer_signed_get(value
));
2123 } else if (bt_value_get_type(value
) ==
2124 BT_VALUE_TYPE_STRING
) {
2125 write_str_prop_value(ctx
,
2126 bt_value_string_get(value
));
2137 for (i
= 0; i
< bt_trace_get_stream_count(trace
); i
++) {
2138 g_ptr_array_add(streams
,
2139 (gpointer
) bt_trace_borrow_stream_by_index_const(
2143 g_ptr_array_sort(streams
, (GCompareFunc
) compare_streams
);
2145 if (streams
->len
> 0 && !printed_prop
) {
2146 g_string_append(ctx
->str
, ":\n");
2147 printed_prop
= true;
2150 for (i
= 0; i
< streams
->len
; i
++) {
2151 const bt_stream
*stream
= streams
->pdata
[i
];
2154 write_obj_type_name(ctx
, "Stream");
2155 g_string_append(ctx
->str
, " (ID ");
2156 write_uint_prop_value(ctx
, bt_stream_get_id(stream
));
2157 g_string_append(ctx
->str
, ", Class ID ");
2158 write_uint_prop_value(ctx
, bt_stream_class_get_id(
2159 bt_stream_borrow_class_const(stream
)));
2160 g_string_append(ctx
->str
, ")");
2166 if (!printed_prop
) {
2170 g_ptr_array_free(streams
, TRUE
);
2171 g_ptr_array_free(env_names
, TRUE
);
2175 int write_stream_beginning_message(struct details_write_ctx
*ctx
,
2176 const bt_message
*msg
)
2179 const bt_stream
*stream
=
2180 bt_message_stream_beginning_borrow_stream_const(msg
);
2181 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
2182 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2183 const bt_clock_class
*cc
= bt_stream_class_borrow_default_clock_class_const(sc
);
2184 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
2187 ret
= try_write_meta(ctx
, tc
, sc
, NULL
);
2192 if (!ctx
->details_comp
->cfg
.with_data
) {
2196 if (ctx
->str
->len
> 0) {
2198 * Output buffer contains metadata: separate blocks with
2206 const bt_clock_snapshot
*cs
;
2207 bt_message_stream_clock_snapshot_state cs_state
=
2208 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg
, &cs
);
2210 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2211 write_time(ctx
, cs
);
2213 write_time_str(ctx
, "Unknown");
2217 /* Write follow tag for message */
2218 ret
= write_message_follow_tag(ctx
, stream
);
2223 /* Write stream properties */
2224 write_obj_type_name(ctx
, "Stream beginning");
2226 if (ctx
->details_comp
->cfg
.compact
) {
2231 g_string_append(ctx
->str
, ":\n");
2234 if (ctx
->details_comp
->cfg
.with_stream_name
) {
2235 name
= bt_stream_get_name(stream
);
2237 write_str_prop_line(ctx
, "Name", name
);
2241 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
2242 name
= bt_stream_class_get_name(sc
);
2244 write_str_prop_line(ctx
, "Class name", name
);
2248 write_trace(ctx
, trace
);
2256 int write_stream_end_message(struct details_write_ctx
*ctx
,
2257 const bt_message
*msg
)
2260 const bt_stream
*stream
=
2261 bt_message_stream_end_borrow_stream_const(msg
);
2262 const bt_stream_class
*sc
=
2263 bt_stream_borrow_class_const(stream
);
2264 const bt_clock_class
*cc
=
2265 bt_stream_class_borrow_default_clock_class_const(sc
);
2267 if (!ctx
->details_comp
->cfg
.with_data
) {
2273 const bt_clock_snapshot
*cs
;
2274 bt_message_stream_clock_snapshot_state cs_state
=
2275 bt_message_stream_end_borrow_default_clock_snapshot_const(msg
, &cs
);
2277 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2278 write_time(ctx
, cs
);
2280 write_time_str(ctx
, "Unknown");
2284 /* Write follow tag for message */
2285 ret
= write_message_follow_tag(ctx
, stream
);
2290 /* Write stream properties */
2291 write_obj_type_name(ctx
, "Stream end\n");
2298 int write_packet_beginning_message(struct details_write_ctx
*ctx
,
2299 const bt_message
*msg
)
2302 const bt_packet
*packet
=
2303 bt_message_packet_beginning_borrow_packet_const(msg
);
2304 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2305 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2306 const bt_field
*field
;
2308 if (!ctx
->details_comp
->cfg
.with_data
) {
2313 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
)) {
2315 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2319 /* Write follow tag for message */
2320 ret
= write_message_follow_tag(ctx
, stream
);
2325 write_obj_type_name(ctx
, "Packet beginning");
2327 if (ctx
->details_comp
->cfg
.compact
) {
2333 field
= bt_packet_borrow_context_field_const(packet
);
2335 g_string_append(ctx
->str
, ":\n");
2337 write_root_field(ctx
, "Context", field
);
2348 int write_discarded_items_message(struct details_write_ctx
*ctx
,
2349 const char *name
, const bt_stream
*stream
,
2350 const bt_clock_snapshot
*beginning_cs
,
2351 const bt_clock_snapshot
*end_cs
, uint64_t count
)
2357 write_time(ctx
, beginning_cs
);
2358 BT_ASSERT_DBG(end_cs
);
2359 write_time(ctx
, end_cs
);
2362 /* Write follow tag for message */
2363 ret
= write_message_follow_tag(ctx
, stream
);
2368 write_obj_type_name(ctx
, "Discarded ");
2369 write_obj_type_name(ctx
, name
);
2372 if (count
== UINT64_C(-1)) {
2377 g_string_append(ctx
->str
, " (");
2378 write_uint_prop_value(ctx
, count
);
2379 g_string_append_printf(ctx
->str
, " %s)\n", name
);
2386 int write_discarded_events_message(struct details_write_ctx
*ctx
,
2387 const bt_message
*msg
)
2390 const bt_stream
*stream
= bt_message_discarded_events_borrow_stream_const(
2392 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2393 const bt_clock_snapshot
*beginning_cs
= NULL
;
2394 const bt_clock_snapshot
*end_cs
= NULL
;
2397 if (!ctx
->details_comp
->cfg
.with_data
) {
2401 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc
)) {
2403 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2406 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2410 if (bt_message_discarded_events_get_count(msg
, &count
) !=
2411 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2412 count
= UINT64_C(-1);
2415 ret
= write_discarded_items_message(ctx
, "events", stream
,
2416 beginning_cs
, end_cs
, count
);
2423 int write_discarded_packets_message(struct details_write_ctx
*ctx
,
2424 const bt_message
*msg
)
2427 const bt_stream
*stream
= bt_message_discarded_packets_borrow_stream_const(
2429 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2430 const bt_clock_snapshot
*beginning_cs
= NULL
;
2431 const bt_clock_snapshot
*end_cs
= NULL
;
2434 if (!ctx
->details_comp
->cfg
.with_data
) {
2438 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
)) {
2440 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2443 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2447 if (bt_message_discarded_packets_get_count(msg
, &count
) !=
2448 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2449 count
= UINT64_C(-1);
2452 ret
= write_discarded_items_message(ctx
, "packets", stream
,
2453 beginning_cs
, end_cs
, count
);
2460 int write_packet_end_message(struct details_write_ctx
*ctx
,
2461 const bt_message
*msg
)
2464 const bt_packet
*packet
=
2465 bt_message_packet_end_borrow_packet_const(msg
);
2466 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2467 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2469 if (!ctx
->details_comp
->cfg
.with_data
) {
2474 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc
)) {
2476 bt_message_packet_end_borrow_default_clock_snapshot_const(
2480 /* Write follow tag for message */
2481 ret
= write_message_follow_tag(ctx
, stream
);
2486 write_obj_type_name(ctx
, "Packet end");
2494 int write_message_iterator_inactivity_message(struct details_write_ctx
*ctx
,
2495 const bt_message
*msg
)
2498 const bt_clock_snapshot
*cs
=
2499 bt_message_message_iterator_inactivity_borrow_clock_snapshot_const(
2503 write_time(ctx
, cs
);
2504 write_obj_type_name(ctx
, "Message iterator inactivity");
2506 if (ctx
->details_comp
->cfg
.compact
) {
2511 /* Write clock class properties */
2512 g_string_append(ctx
->str
, ":\n");
2515 write_prop_name(ctx
, "Clock class");
2516 g_string_append_c(ctx
->str
, ':');
2519 write_clock_class_prop_lines(ctx
,
2520 bt_clock_snapshot_borrow_clock_class_const(cs
));
2528 int details_write_message(struct details_comp
*details_comp
,
2529 const bt_message
*msg
)
2532 struct details_write_ctx ctx
= {
2533 .details_comp
= details_comp
,
2534 .str
= details_comp
->str
,
2538 /* Reset output buffer */
2539 g_string_assign(details_comp
->str
, "");
2541 switch (bt_message_get_type(msg
)) {
2542 case BT_MESSAGE_TYPE_EVENT
:
2543 ret
= write_event_message(&ctx
, msg
);
2545 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY
:
2546 ret
= write_message_iterator_inactivity_message(&ctx
, msg
);
2548 case BT_MESSAGE_TYPE_STREAM_BEGINNING
:
2549 ret
= write_stream_beginning_message(&ctx
, msg
);
2551 case BT_MESSAGE_TYPE_STREAM_END
:
2552 ret
= write_stream_end_message(&ctx
, msg
);
2554 case BT_MESSAGE_TYPE_PACKET_BEGINNING
:
2555 ret
= write_packet_beginning_message(&ctx
, msg
);
2557 case BT_MESSAGE_TYPE_PACKET_END
:
2558 ret
= write_packet_end_message(&ctx
, msg
);
2560 case BT_MESSAGE_TYPE_DISCARDED_EVENTS
:
2561 ret
= write_discarded_events_message(&ctx
, msg
);
2563 case BT_MESSAGE_TYPE_DISCARDED_PACKETS
:
2564 ret
= write_discarded_packets_message(&ctx
, msg
);
2571 * If this component printed at least one character so far, and
2572 * we're not in compact mode, and there's something in the
2573 * output buffer for this message, then prepend a newline to the
2574 * output buffer to visually separate message blocks.
2576 if (details_comp
->printed_something
&& !details_comp
->cfg
.compact
&&
2577 details_comp
->str
->len
> 0) {
2578 /* TODO: Optimize this */
2579 g_string_prepend_c(details_comp
->str
, '\n');