2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 #include <babeltrace2/babeltrace.h>
28 #include "common/assert.h"
29 #include "common/common.h"
30 #include "common/uuid.h"
33 #include "obj-lifetime-mgmt.h"
37 const char *plural(uint64_t value
)
39 return value
== 1 ? "" : "s";
43 void incr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
46 ctx
->indent_level
+= value
;
50 void incr_indent(struct details_write_ctx
*ctx
)
52 incr_indent_by(ctx
, 2);
56 void decr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
59 BT_ASSERT_DBG(ctx
->indent_level
>= value
);
60 ctx
->indent_level
-= value
;
64 void decr_indent(struct details_write_ctx
*ctx
)
66 decr_indent_by(ctx
, 2);
70 void format_uint(char *buf
, uint64_t value
, unsigned int base
)
72 const char *spec
= "%" PRIu64
;
73 char *buf_start
= buf
;
74 unsigned int digits_per_group
= 3;
76 bool sep_digits
= true;
81 /* TODO: Support binary format */
97 * Do not insert digit separators for numbers
98 * under 10,000 as it looks weird.
108 sprintf(buf_start
, spec
, value
);
111 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
116 void format_int(char *buf
, int64_t value
, unsigned int base
)
118 const char *spec
= "%" PRIu64
;
119 char *buf_start
= buf
;
120 unsigned int digits_per_group
= 3;
122 bool sep_digits
= true;
123 uint64_t abs_value
= value
< 0 ? (uint64_t) -value
: (uint64_t) value
;
133 /* TODO: Support binary format */
135 strcpy(buf_start
, "0x");
137 digits_per_group
= 4;
142 strcpy(buf_start
, "0");
147 if (value
>= -9999 && value
<= 9999) {
149 * Do not insert digit separators for numbers
150 * over -10,000 and under 10,000 as it looks
161 sprintf(buf_start
, spec
, abs_value
);
164 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
169 void write_nl(struct details_write_ctx
*ctx
)
172 g_string_append_c(ctx
->str
, '\n');
176 void write_sp(struct details_write_ctx
*ctx
)
179 g_string_append_c(ctx
->str
, ' ');
183 void write_indent(struct details_write_ctx
*ctx
)
189 for (i
= 0; i
< ctx
->indent_level
; i
++) {
195 void write_compound_member_name(struct details_write_ctx
*ctx
, const char *name
)
198 g_string_append_printf(ctx
->str
, "%s%s%s:",
199 color_fg_cyan(ctx
), name
, color_reset(ctx
));
203 void write_array_index(struct details_write_ctx
*ctx
, uint64_t index
,
209 format_uint(buf
, index
, 10);
210 g_string_append_printf(ctx
->str
, "%s[%s]%s:",
211 color
, buf
, color_reset(ctx
));
215 void write_obj_type_name(struct details_write_ctx
*ctx
, const char *name
)
217 g_string_append_printf(ctx
->str
, "%s%s%s%s",
218 color_fg_yellow(ctx
), color_bold(ctx
), name
, color_reset(ctx
));
222 void write_prop_name(struct details_write_ctx
*ctx
, const char *prop_name
)
224 g_string_append_printf(ctx
->str
, "%s%s%s",
225 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
229 void write_prop_name_line(struct details_write_ctx
*ctx
, const char *prop_name
)
232 g_string_append_printf(ctx
->str
, "%s%s%s:",
233 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
237 void write_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
239 g_string_append_printf(ctx
->str
, "%s%s%s",
240 color_bold(ctx
), value
, color_reset(ctx
));
244 void write_none_prop_value(struct details_write_ctx
*ctx
, const char *value
)
246 g_string_append_printf(ctx
->str
, "%s%s%s%s",
247 color_bold(ctx
), color_fg_magenta(ctx
),
248 value
, color_reset(ctx
));
252 void write_uint_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
254 write_str_prop_value(ctx
, value
);
258 void write_uint_prop_value(struct details_write_ctx
*ctx
, uint64_t value
)
262 format_uint(buf
, value
, 10);
263 write_uint_str_prop_value(ctx
, buf
);
267 void write_int_prop_value(struct details_write_ctx
*ctx
, int64_t value
)
271 format_int(buf
, value
, 10);
272 write_uint_str_prop_value(ctx
, buf
);
276 void write_float_prop_value(struct details_write_ctx
*ctx
, double value
)
278 g_string_append_printf(ctx
->str
, "%s%f%s",
279 color_bold(ctx
), value
, color_reset(ctx
));
283 void write_str_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
284 const char *prop_value
)
286 BT_ASSERT_DBG(prop_value
);
288 write_prop_name(ctx
, prop_name
);
289 g_string_append(ctx
->str
, ": ");
290 write_str_prop_value(ctx
, prop_value
);
295 void write_uint_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
299 write_prop_name(ctx
, prop_name
);
300 g_string_append(ctx
->str
, ": ");
301 write_uint_prop_value(ctx
, prop_value
);
306 void write_int_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
310 write_prop_name(ctx
, prop_name
);
311 g_string_append(ctx
->str
, ": ");
312 write_int_prop_value(ctx
, prop_value
);
317 void write_int_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
319 write_str_prop_value(ctx
, value
);
323 void write_bool_prop_value(struct details_write_ctx
*ctx
, bt_bool prop_value
)
327 g_string_append(ctx
->str
, color_bold(ctx
));
330 g_string_append(ctx
->str
, color_fg_green(ctx
));
333 g_string_append(ctx
->str
, color_fg_red(ctx
));
337 g_string_append_printf(ctx
->str
, "%s%s", str
, color_reset(ctx
));
341 void write_bool_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
345 write_prop_name(ctx
, prop_name
);
346 g_string_append(ctx
->str
, ": ");
347 write_bool_prop_value(ctx
, prop_value
);
352 void write_uuid_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
357 write_prop_name(ctx
, prop_name
);
358 g_string_append_printf(ctx
->str
,
359 ": %s" BT_UUID_FMT
"%s\n",
361 BT_UUID_FMT_VALUES(uuid
),
366 gint
compare_strings(const char **a
, const char **b
)
368 return strcmp(*a
, *b
);
372 bt_bool
map_value_foreach_add_key_to_array(const char *key
,
373 const bt_value
*object
, void *data
)
375 GPtrArray
*keys
= data
;
378 g_ptr_array_add(keys
, (void *) key
);
383 void write_value(struct details_write_ctx
*ctx
, const bt_value
*value
,
387 bt_value_type value_type
= bt_value_get_type(value
);
388 GPtrArray
*keys
= g_ptr_array_new();
393 /* Write field's name */
395 write_prop_name_line(ctx
, name
);
398 /* Write field's value */
399 switch (value_type
) {
400 case BT_VALUE_TYPE_NULL
:
402 write_none_prop_value(ctx
, "Null");
404 case BT_VALUE_TYPE_BOOL
:
406 write_bool_prop_value(ctx
, bt_value_bool_get(value
));
408 case BT_VALUE_TYPE_UNSIGNED_INTEGER
:
409 format_uint(buf
, bt_value_integer_unsigned_get(value
), 10);
411 write_uint_str_prop_value(ctx
, buf
);
413 case BT_VALUE_TYPE_SIGNED_INTEGER
:
414 format_int(buf
, bt_value_integer_signed_get(value
), 10);
416 write_int_str_prop_value(ctx
, buf
);
418 case BT_VALUE_TYPE_REAL
:
420 write_float_prop_value(ctx
, bt_value_real_get(value
));
422 case BT_VALUE_TYPE_STRING
:
424 write_str_prop_value(ctx
, bt_value_string_get(value
));
426 case BT_VALUE_TYPE_ARRAY
:
428 uint64_t length
= bt_value_array_get_length(value
);
432 write_none_prop_value(ctx
, "Empty");
434 g_string_append(ctx
->str
, " Length ");
435 write_uint_prop_value(ctx
, length
);
436 g_string_append_c(ctx
->str
, ':');
441 for (i
= 0; i
< length
; i
++) {
442 const bt_value
*elem_value
=
443 bt_value_array_borrow_element_by_index_const(
447 write_array_index(ctx
, i
, color_fg_magenta(ctx
));
448 write_value(ctx
, elem_value
, NULL
);
454 case BT_VALUE_TYPE_MAP
:
456 bt_value_map_foreach_entry_const_status foreach_status
=
457 bt_value_map_foreach_entry_const(value
,
458 map_value_foreach_add_key_to_array
, keys
);
460 BT_ASSERT_DBG(foreach_status
==
461 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK
);
462 g_ptr_array_sort(keys
, (GCompareFunc
) compare_strings
);
467 for (i
= 0; i
< keys
->len
; i
++) {
468 const char *key
= keys
->pdata
[i
];
469 const bt_value
*entry_value
=
470 bt_value_map_borrow_entry_value_const(
474 write_value(ctx
, entry_value
, key
);
480 write_none_prop_value(ctx
, "Empty");
489 g_ptr_array_free(keys
, TRUE
);
493 void write_user_attributes(struct details_write_ctx
*ctx
,
494 const bt_value
*user_attrs
, bool write_newline
, bool *written
)
496 BT_ASSERT_DBG(user_attrs
);
498 if (!bt_value_map_is_empty(user_attrs
)) {
499 write_value(ctx
, user_attrs
, "User attributes");
512 void write_int_field_class_props(struct details_write_ctx
*ctx
,
513 const bt_field_class
*fc
, bool close
)
515 g_string_append_printf(ctx
->str
, "(%s%" PRIu64
"-bit%s, Base ",
517 bt_field_class_integer_get_field_value_range(fc
),
520 switch (bt_field_class_integer_get_preferred_display_base(fc
)) {
521 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
522 write_uint_prop_value(ctx
, 2);
524 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
525 write_uint_prop_value(ctx
, 8);
527 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
528 write_uint_prop_value(ctx
, 10);
530 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
531 write_uint_prop_value(ctx
, 16);
538 g_string_append(ctx
->str
, ")");
554 struct enum_field_class_mapping
{
558 /* Array of `struct int_range` */
563 gint
compare_enum_field_class_mappings(struct enum_field_class_mapping
**a
,
564 struct enum_field_class_mapping
**b
)
566 return strcmp((*a
)->label
, (*b
)->label
);
570 gint
compare_int_ranges_signed(struct int_range
*a
, struct int_range
*b
)
573 if (a
->lower
.i
< b
->lower
.i
) {
575 } else if (a
->lower
.i
> b
->lower
.i
) {
578 if (a
->upper
.i
< b
->upper
.i
) {
580 } else if (a
->upper
.i
> b
->upper
.i
) {
589 gint
compare_int_ranges_unsigned(struct int_range
*a
, struct int_range
*b
)
591 if (a
->lower
.u
< b
->lower
.u
) {
593 } else if (a
->lower
.u
> b
->lower
.u
) {
596 if (a
->upper
.u
< b
->upper
.u
) {
598 } else if (a
->upper
.u
> b
->upper
.u
) {
607 GArray
*range_set_to_int_ranges(const void *spec_range_set
, bool is_signed
)
610 const bt_integer_range_set
*range_set
;
611 GArray
*ranges
= g_array_new(FALSE
, TRUE
, sizeof(struct int_range
));
618 range_set
= bt_integer_range_set_signed_as_range_set_const(
621 range_set
= bt_integer_range_set_unsigned_as_range_set_const(
625 for (i
= 0; i
< bt_integer_range_set_get_range_count(range_set
); i
++) {
626 struct int_range range
;
629 const bt_integer_range_signed
*orig_range
=
630 bt_integer_range_set_signed_borrow_range_by_index_const(
633 range
.lower
.i
= bt_integer_range_signed_get_lower(orig_range
);
634 range
.upper
.i
= bt_integer_range_signed_get_upper(orig_range
);
636 const bt_integer_range_unsigned
*orig_range
=
637 bt_integer_range_set_unsigned_borrow_range_by_index_const(
640 range
.lower
.u
= bt_integer_range_unsigned_get_lower(orig_range
);
641 range
.upper
.u
= bt_integer_range_unsigned_get_upper(orig_range
);
644 g_array_append_val(ranges
, range
);
648 g_array_sort(ranges
, (GCompareFunc
) compare_int_ranges_signed
);
651 (GCompareFunc
) compare_int_ranges_unsigned
);
659 void destroy_enum_field_class_mapping(struct enum_field_class_mapping
*mapping
)
661 if (mapping
->ranges
) {
662 g_array_free(mapping
->ranges
, TRUE
);
663 mapping
->ranges
= NULL
;
670 struct int_range
*int_range_at(GArray
*ranges
, uint64_t index
)
672 return &g_array_index(ranges
, struct int_range
, index
);
676 void write_int_range(struct details_write_ctx
*ctx
,
677 struct int_range
*range
, bool is_signed
)
679 g_string_append(ctx
->str
, "[");
682 write_int_prop_value(ctx
, range
->lower
.i
);
684 write_int_prop_value(ctx
, range
->lower
.u
);
687 if (range
->lower
.u
!= range
->upper
.u
) {
688 g_string_append(ctx
->str
, ", ");
691 write_int_prop_value(ctx
, range
->upper
.i
);
693 write_int_prop_value(ctx
, range
->upper
.u
);
697 g_string_append(ctx
->str
, "]");
701 void write_enum_field_class_mappings(struct details_write_ctx
*ctx
,
702 const bt_field_class
*fc
)
707 bool is_signed
= bt_field_class_get_type(fc
) ==
708 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
;
710 mappings
= g_ptr_array_new_with_free_func(
711 (GDestroyNotify
) destroy_enum_field_class_mapping
);
712 BT_ASSERT_DBG(mappings
);
715 * Copy field class's mappings to our own arrays and structures
718 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(fc
); i
++) {
719 const void *fc_mapping
;
720 const void *fc_range_set
;
721 struct enum_field_class_mapping
*mapping
= g_new0(
722 struct enum_field_class_mapping
, 1);
724 BT_ASSERT_DBG(mapping
);
727 fc_mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
729 fc_range_set
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
732 fc_mapping
= bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
734 fc_range_set
= bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
738 mapping
->label
= bt_field_class_enumeration_mapping_get_label(
739 bt_field_class_enumeration_signed_mapping_as_mapping_const(
741 mapping
->ranges
= range_set_to_int_ranges(fc_range_set
,
743 BT_ASSERT_DBG(mapping
->ranges
);
744 g_ptr_array_add(mappings
, mapping
);
747 /* Sort mappings (ranges are already sorted within mappings) */
748 g_ptr_array_sort(mappings
,
749 (GCompareFunc
) compare_enum_field_class_mappings
);
752 for (i
= 0; i
< mappings
->len
; i
++) {
753 struct enum_field_class_mapping
*mapping
= mappings
->pdata
[i
];
756 write_prop_name_line(ctx
, mapping
->label
);
758 for (range_i
= 0; range_i
< mapping
->ranges
->len
; range_i
++) {
761 int_range_at(mapping
->ranges
, range_i
),
766 g_ptr_array_free(mappings
, TRUE
);
770 void write_field_path(struct details_write_ctx
*ctx
,
771 const bt_field_path
*field_path
)
775 g_string_append_c(ctx
->str
, '[');
777 switch (bt_field_path_get_root_scope(field_path
)) {
778 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
779 write_str_prop_value(ctx
, "Packet context");
781 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
782 write_str_prop_value(ctx
, "Event common context");
784 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
785 write_str_prop_value(ctx
, "Event specific context");
787 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
788 write_str_prop_value(ctx
, "Event payload");
794 g_string_append(ctx
->str
, ": ");
796 for (i
= 0; i
< bt_field_path_get_item_count(field_path
); i
++) {
797 const bt_field_path_item
*fp_item
=
798 bt_field_path_borrow_item_by_index_const(field_path
, i
);
801 g_string_append(ctx
->str
, ", ");
804 switch (bt_field_path_item_get_type(fp_item
)) {
805 case BT_FIELD_PATH_ITEM_TYPE_INDEX
:
806 write_uint_prop_value(ctx
,
807 bt_field_path_item_index_get_index(fp_item
));
809 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
:
810 write_str_prop_value(ctx
, "<current>");
817 g_string_append_c(ctx
->str
, ']');
821 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
);
824 void write_variant_field_class_option(struct details_write_ctx
*ctx
,
825 const bt_field_class
*fc
, uint64_t index
)
827 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
828 const bt_field_class_variant_option
*option
=
829 bt_field_class_variant_borrow_option_by_index_const(
831 const void *orig_ranges
= NULL
;
832 GArray
*int_ranges
= NULL
;
834 const bt_value
*user_attrs
=
835 bt_field_class_variant_option_borrow_user_attributes_const(
837 const bt_field_class
*option_fc
=
838 bt_field_class_variant_option_borrow_field_class_const(option
);
841 write_compound_member_name(ctx
,
842 bt_field_class_variant_option_get_name(option
));
844 if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
845 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*spec_opt
=
846 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
850 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
853 } else if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
854 const bt_field_class_variant_with_selector_field_integer_signed_option
*spec_opt
=
855 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
859 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
867 int_ranges
= range_set_to_int_ranges(orig_ranges
, is_signed
);
868 BT_ASSERT_DBG(int_ranges
);
870 for (i
= 0; i
< int_ranges
->len
; i
++) {
871 struct int_range
*range
= int_range_at(int_ranges
, i
);
874 write_int_range(ctx
, range
, is_signed
);
877 g_string_append(ctx
->str
, ": ");
882 if (bt_value_map_is_empty(user_attrs
)) {
883 write_field_class(ctx
, option_fc
);
889 write_prop_name_line(ctx
, "Field class");
891 write_field_class(ctx
, option_fc
);
894 /* User attributes */
895 write_user_attributes(ctx
, user_attrs
,
902 g_array_free(int_ranges
, TRUE
);
907 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
)
911 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
912 const bt_value
*user_attrs
;
913 bool wrote_user_attrs
= false;
915 /* Write field class's type */
917 case BT_FIELD_CLASS_TYPE_BOOL
:
920 case BT_FIELD_CLASS_TYPE_BIT_ARRAY
:
923 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
924 type
= "Unsigned integer";
926 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
927 type
= "Signed integer";
929 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
930 type
= "Unsigned enumeration";
932 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
933 type
= "Signed enumeration";
935 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
:
936 type
= "Single-precision real";
938 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
:
939 type
= "Double-precision real";
941 case BT_FIELD_CLASS_TYPE_STRING
:
944 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
947 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
948 type
= "Static array";
950 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
951 type
= "Dynamic array (no length field)";
953 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
954 type
= "Dynamic array (with length field)";
956 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD
:
957 type
= "Option (no selector)";
959 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
:
960 type
= "Option (boolean selector)";
962 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
963 type
= "Option (unsigned integer selector)";
965 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
966 type
= "Option (signed integer selector)";
968 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
:
969 type
= "Variant (no selector)";
971 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
972 type
= "Variant (unsigned integer selector)";
974 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
975 type
= "Variant (signed integer selector)";
981 g_string_append_printf(ctx
->str
, "%s%s%s",
982 color_fg_blue(ctx
), type
, color_reset(ctx
));
984 /* Write field class's single-line properties */
985 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
986 uint64_t mapping_count
=
987 bt_field_class_enumeration_get_mapping_count(fc
);
990 write_int_field_class_props(ctx
, fc
, false);
991 g_string_append(ctx
->str
, ", ");
992 write_uint_prop_value(ctx
, mapping_count
);
993 g_string_append_printf(ctx
->str
, " mapping%s)",
994 plural(mapping_count
));
995 } else if (bt_field_class_type_is(fc_type
,
996 BT_FIELD_CLASS_TYPE_INTEGER
)) {
998 write_int_field_class_props(ctx
, fc
, true);
999 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1000 uint64_t member_count
=
1001 bt_field_class_structure_get_member_count(fc
);
1003 g_string_append(ctx
->str
, " (");
1004 write_uint_prop_value(ctx
, member_count
);
1005 g_string_append_printf(ctx
->str
, " member%s)",
1006 plural(member_count
));
1007 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
1008 g_string_append(ctx
->str
, " (Length ");
1009 write_uint_prop_value(ctx
,
1010 bt_field_class_array_static_get_length(fc
));
1011 g_string_append_c(ctx
->str
, ')');
1012 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
1013 const bt_field_path
*length_field_path
=
1014 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1017 g_string_append(ctx
->str
, " (Length field path ");
1018 write_field_path(ctx
, length_field_path
);
1019 g_string_append_c(ctx
->str
, ')');
1020 } else if (bt_field_class_type_is(fc_type
,
1021 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
1022 const bt_field_path
*selector_field_path
=
1023 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
1026 g_string_append(ctx
->str
, " (Selector field path ");
1027 write_field_path(ctx
, selector_field_path
);
1028 g_string_append_c(ctx
->str
, ')');
1029 } else if (bt_field_class_type_is(fc_type
,
1030 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1031 uint64_t option_count
=
1032 bt_field_class_variant_get_option_count(fc
);
1033 const bt_field_path
*sel_field_path
= NULL
;
1035 if (bt_field_class_type_is(fc_type
,
1036 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
1038 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1040 BT_ASSERT_DBG(sel_field_path
);
1043 g_string_append(ctx
->str
, " (");
1044 write_uint_prop_value(ctx
, option_count
);
1045 g_string_append_printf(ctx
->str
, " option%s",
1046 plural(option_count
));
1048 if (sel_field_path
) {
1049 g_string_append(ctx
->str
, ", Selector field path ");
1050 write_field_path(ctx
, sel_field_path
);
1053 g_string_append_c(ctx
->str
, ')');
1057 user_attrs
= bt_field_class_borrow_user_attributes_const(fc
);
1058 if (!bt_value_map_is_empty(user_attrs
)) {
1059 g_string_append(ctx
->str
, ":\n");
1060 write_user_attributes(ctx
, user_attrs
, false, NULL
);
1061 wrote_user_attrs
= true;
1064 /* Write field class's complex properties */
1065 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
1066 uint64_t mapping_count
=
1067 bt_field_class_enumeration_get_mapping_count(fc
);
1069 if (mapping_count
> 0) {
1070 if (wrote_user_attrs
) {
1073 write_prop_name(ctx
, "Mappings");
1074 g_string_append_c(ctx
->str
, ':');
1077 /* Each mapping starts with its own newline */
1078 g_string_append_c(ctx
->str
, ':');
1081 write_enum_field_class_mappings(ctx
, fc
);
1083 if (wrote_user_attrs
) {
1087 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1088 uint64_t member_count
=
1089 bt_field_class_structure_get_member_count(fc
);
1091 if (member_count
> 0) {
1092 if (wrote_user_attrs
) {
1095 write_prop_name(ctx
, "Members");
1096 g_string_append_c(ctx
->str
, ':');
1099 /* Each member starts with its own newline */
1100 g_string_append_c(ctx
->str
, ':');
1103 for (i
= 0; i
< member_count
; i
++) {
1104 const bt_field_class_structure_member
*member
=
1105 bt_field_class_structure_borrow_member_by_index_const(
1107 const bt_value
*member_user_attrs
;
1108 const bt_field_class
*member_fc
=
1109 bt_field_class_structure_member_borrow_field_class_const(member
);
1112 write_compound_member_name(ctx
,
1113 bt_field_class_structure_member_get_name(member
));
1114 member_user_attrs
= bt_field_class_structure_member_borrow_user_attributes_const(
1117 if (bt_value_map_is_empty(member_user_attrs
)) {
1119 write_field_class(ctx
, member_fc
);
1125 write_prop_name_line(ctx
, "Field class");
1127 write_field_class(ctx
, member_fc
);
1130 /* User attributes */
1131 write_user_attributes(ctx
, member_user_attrs
,
1138 if (wrote_user_attrs
) {
1142 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1143 if (wrote_user_attrs
) {
1146 g_string_append(ctx
->str
, ":\n");
1149 write_prop_name_line(ctx
, "Element");
1151 write_field_class(ctx
,
1152 bt_field_class_array_borrow_element_field_class_const(fc
));
1153 } else if (bt_field_class_type_is(fc_type
,
1154 BT_FIELD_CLASS_TYPE_OPTION
)) {
1155 const void *ranges
= NULL
;
1156 bool selector_is_signed
= false;
1158 if (wrote_user_attrs
) {
1161 g_string_append(ctx
->str
, ":\n");
1164 if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
) {
1165 write_bool_prop_line(ctx
, "Selector is reversed",
1166 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc
));
1167 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
1168 ranges
= bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc
);
1169 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
1170 ranges
= bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc
);
1171 selector_is_signed
= true;
1175 GArray
*sorted_ranges
= range_set_to_int_ranges(
1176 ranges
, selector_is_signed
);
1178 BT_ASSERT_DBG(sorted_ranges
);
1179 BT_ASSERT_DBG(sorted_ranges
->len
> 0);
1180 write_prop_name_line(ctx
, "Selector ranges");
1182 for (i
= 0; i
< sorted_ranges
->len
; i
++) {
1184 write_int_range(ctx
,
1185 int_range_at(sorted_ranges
, i
),
1186 selector_is_signed
);
1190 g_array_free(sorted_ranges
, TRUE
);
1193 write_prop_name_line(ctx
, "Content");
1195 write_field_class(ctx
,
1196 bt_field_class_option_borrow_field_class_const(fc
));
1197 } else if (bt_field_class_type_is(fc_type
,
1198 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1199 uint64_t option_count
=
1200 bt_field_class_variant_get_option_count(fc
);
1202 if (option_count
> 0) {
1203 if (wrote_user_attrs
) {
1206 write_prop_name(ctx
, "Options");
1207 g_string_append_c(ctx
->str
, ':');
1210 /* Each option starts with its own newline */
1211 g_string_append_c(ctx
->str
, ':');
1214 for (i
= 0; i
< option_count
; i
++) {
1215 write_variant_field_class_option(ctx
, fc
, i
);
1218 if (wrote_user_attrs
) {
1228 void write_root_field_class(struct details_write_ctx
*ctx
, const char *name
,
1229 const bt_field_class
*fc
)
1231 BT_ASSERT_DBG(name
);
1234 write_prop_name(ctx
, name
);
1235 g_string_append(ctx
->str
, ": ");
1236 write_field_class(ctx
, fc
);
1241 void write_event_class(struct details_write_ctx
*ctx
, const bt_event_class
*ec
)
1243 const char *name
= bt_event_class_get_name(ec
);
1244 const char *emf_uri
;
1245 const bt_field_class
*fc
;
1246 bt_event_class_log_level log_level
;
1249 write_obj_type_name(ctx
, "Event class");
1251 /* Write name and ID */
1253 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1254 color_fg_green(ctx
), name
, color_reset(ctx
));
1257 g_string_append(ctx
->str
, " (ID ");
1258 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1259 g_string_append(ctx
->str
, "):\n");
1261 /* Write properties */
1264 /* Write user attributes */
1265 write_user_attributes(ctx
,
1266 bt_event_class_borrow_user_attributes_const(ec
), true, NULL
);
1268 /* Write log level */
1269 if (bt_event_class_get_log_level(ec
, &log_level
) ==
1270 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
1271 const char *ll_str
= NULL
;
1273 switch (log_level
) {
1274 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY
:
1275 ll_str
= "Emergency";
1277 case BT_EVENT_CLASS_LOG_LEVEL_ALERT
:
1280 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL
:
1281 ll_str
= "Critical";
1283 case BT_EVENT_CLASS_LOG_LEVEL_ERROR
:
1286 case BT_EVENT_CLASS_LOG_LEVEL_WARNING
:
1289 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE
:
1292 case BT_EVENT_CLASS_LOG_LEVEL_INFO
:
1295 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
:
1296 ll_str
= "Debug (system)";
1298 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
:
1299 ll_str
= "Debug (program)";
1301 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
:
1302 ll_str
= "Debug (process)";
1304 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
:
1305 ll_str
= "Debug (module)";
1307 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
:
1308 ll_str
= "Debug (unit)";
1310 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
:
1311 ll_str
= "Debug (function)";
1313 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
:
1314 ll_str
= "Debug (line)";
1316 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG
:
1323 write_str_prop_line(ctx
, "Log level", ll_str
);
1327 emf_uri
= bt_event_class_get_emf_uri(ec
);
1329 write_str_prop_line(ctx
, "EMF URI", emf_uri
);
1332 /* Write specific context field class */
1333 fc
= bt_event_class_borrow_specific_context_field_class_const(ec
);
1335 write_root_field_class(ctx
, "Specific context field class", fc
);
1338 /* Write payload field class */
1339 fc
= bt_event_class_borrow_payload_field_class_const(ec
);
1341 write_root_field_class(ctx
, "Payload field class", fc
);
1348 void write_clock_class_prop_lines(struct details_write_ctx
*ctx
,
1349 const bt_clock_class
*cc
)
1351 int64_t offset_seconds
;
1352 uint64_t offset_cycles
;
1355 str
= bt_clock_class_get_name(cc
);
1357 write_str_prop_line(ctx
, "Name", str
);
1360 write_user_attributes(ctx
,
1361 bt_clock_class_borrow_user_attributes_const(cc
), true, NULL
);
1362 str
= bt_clock_class_get_description(cc
);
1364 write_str_prop_line(ctx
, "Description", str
);
1367 write_uint_prop_line(ctx
, "Frequency (Hz)",
1368 bt_clock_class_get_frequency(cc
));
1369 write_uint_prop_line(ctx
, "Precision (cycles)",
1370 bt_clock_class_get_precision(cc
));
1371 bt_clock_class_get_offset(cc
, &offset_seconds
, &offset_cycles
);
1372 write_int_prop_line(ctx
, "Offset (s)", offset_seconds
);
1373 write_uint_prop_line(ctx
, "Offset (cycles)", offset_cycles
);
1374 write_bool_prop_line(ctx
, "Origin is Unix epoch",
1375 bt_clock_class_origin_is_unix_epoch(cc
));
1377 if (ctx
->details_comp
->cfg
.with_uuid
) {
1378 bt_uuid uuid
= bt_clock_class_get_uuid(cc
);
1381 write_uuid_prop_line(ctx
, "UUID", uuid
);
1387 gint
compare_event_classes(const bt_event_class
**a
, const bt_event_class
**b
)
1389 uint64_t id_a
= bt_event_class_get_id(*a
);
1390 uint64_t id_b
= bt_event_class_get_id(*b
);
1394 } else if (id_a
> id_b
) {
1402 void write_stream_class(struct details_write_ctx
*ctx
,
1403 const bt_stream_class
*sc
)
1405 const bt_field_class
*fc
;
1406 GPtrArray
*event_classes
= g_ptr_array_new();
1410 write_obj_type_name(ctx
, "Stream class");
1412 /* Write name and ID */
1413 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
1414 const char *name
= bt_stream_class_get_name(sc
);
1417 g_string_append(ctx
->str
, " `");
1418 write_str_prop_value(ctx
, name
);
1419 g_string_append(ctx
->str
, "`");
1423 g_string_append(ctx
->str
, " (ID ");
1424 write_uint_prop_value(ctx
, bt_stream_class_get_id(sc
));
1425 g_string_append(ctx
->str
, "):\n");
1427 /* Write properties */
1430 /* Write user attributes */
1431 write_user_attributes(ctx
,
1432 bt_stream_class_borrow_user_attributes_const(sc
), true, NULL
);
1434 /* Write configuration */
1435 write_bool_prop_line(ctx
,
1436 "Supports packets", bt_stream_class_supports_packets(sc
));
1438 if (bt_stream_class_supports_packets(sc
)) {
1439 write_bool_prop_line(ctx
,
1440 "Packets have beginning default clock snapshot",
1441 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
));
1442 write_bool_prop_line(ctx
,
1443 "Packets have end default clock snapshot",
1444 bt_stream_class_packets_have_end_default_clock_snapshot(sc
));
1447 write_bool_prop_line(ctx
,
1448 "Supports discarded events",
1449 bt_stream_class_supports_discarded_events(sc
));
1451 if (bt_stream_class_supports_discarded_events(sc
)) {
1452 write_bool_prop_line(ctx
,
1453 "Discarded events have default clock snapshots",
1454 bt_stream_class_discarded_events_have_default_clock_snapshots(sc
));
1457 write_bool_prop_line(ctx
,
1458 "Supports discarded packets",
1459 bt_stream_class_supports_discarded_packets(sc
));
1461 if (bt_stream_class_supports_discarded_packets(sc
)) {
1462 write_bool_prop_line(ctx
,
1463 "Discarded packets have default clock snapshots",
1464 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
));
1467 /* Write default clock class */
1468 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1470 write_prop_name(ctx
, "Default clock class");
1471 g_string_append_c(ctx
->str
, ':');
1474 write_clock_class_prop_lines(ctx
,
1475 bt_stream_class_borrow_default_clock_class_const(sc
));
1479 fc
= bt_stream_class_borrow_packet_context_field_class_const(sc
);
1481 write_root_field_class(ctx
, "Packet context field class", fc
);
1484 fc
= bt_stream_class_borrow_event_common_context_field_class_const(sc
);
1486 write_root_field_class(ctx
, "Event common context field class",
1490 for (i
= 0; i
< bt_stream_class_get_event_class_count(sc
); i
++) {
1491 g_ptr_array_add(event_classes
,
1492 (gpointer
) bt_stream_class_borrow_event_class_by_index_const(
1496 g_ptr_array_sort(event_classes
, (GCompareFunc
) compare_event_classes
);
1498 for (i
= 0; i
< event_classes
->len
; i
++) {
1499 write_event_class(ctx
, event_classes
->pdata
[i
]);
1503 g_ptr_array_free(event_classes
, TRUE
);
1507 gint
compare_stream_classes(const bt_stream_class
**a
, const bt_stream_class
**b
)
1509 uint64_t id_a
= bt_stream_class_get_id(*a
);
1510 uint64_t id_b
= bt_stream_class_get_id(*b
);
1514 } else if (id_a
> id_b
) {
1522 void write_trace_class(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
)
1524 GPtrArray
*stream_classes
= g_ptr_array_new();
1526 bool printed_prop
= false;
1529 write_obj_type_name(ctx
, "Trace class");
1532 for (i
= 0; i
< bt_trace_class_get_stream_class_count(tc
); i
++) {
1533 g_ptr_array_add(stream_classes
,
1534 (gpointer
) bt_trace_class_borrow_stream_class_by_index_const(
1538 g_ptr_array_sort(stream_classes
, (GCompareFunc
) compare_stream_classes
);
1540 if (stream_classes
->len
> 0) {
1541 if (!printed_prop
) {
1542 g_string_append(ctx
->str
, ":\n");
1543 printed_prop
= true;
1549 /* Write user attributes */
1550 write_user_attributes(ctx
,
1551 bt_trace_class_borrow_user_attributes_const(tc
), true,
1554 /* Write stream classes */
1555 for (i
= 0; i
< stream_classes
->len
; i
++) {
1556 write_stream_class(ctx
, stream_classes
->pdata
[i
]);
1559 if (!printed_prop
) {
1564 g_ptr_array_free(stream_classes
, TRUE
);
1568 int try_write_meta(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
,
1569 const bt_stream_class
*sc
, const bt_event_class
*ec
)
1575 if (details_need_to_write_trace_class(ctx
, tc
)) {
1578 if (ctx
->details_comp
->cfg
.compact
&&
1579 ctx
->details_comp
->printed_something
) {
1581 * There are no empty line between messages in
1582 * compact mode, so write one here to decouple
1583 * the trace class from the next message.
1589 * write_trace_class() also writes all its stream
1590 * classes their event classes, so we don't need to
1593 write_trace_class(ctx
, tc
);
1596 * Mark this trace class as written, as well as all
1597 * its stream classes and their event classes.
1599 ret
= details_did_write_trace_class(ctx
, tc
);
1604 for (sc_i
= 0; sc_i
< bt_trace_class_get_stream_class_count(tc
);
1607 const bt_stream_class
*tc_sc
=
1608 bt_trace_class_borrow_stream_class_by_index_const(
1611 details_did_write_meta_object(ctx
, tc
, tc_sc
);
1613 for (ec_i
= 0; ec_i
<
1614 bt_stream_class_get_event_class_count(tc_sc
);
1616 details_did_write_meta_object(ctx
, tc
,
1617 bt_stream_class_borrow_event_class_by_index_const(
1625 if (sc
&& details_need_to_write_meta_object(ctx
, tc
, sc
)) {
1630 if (ctx
->details_comp
->cfg
.compact
&&
1631 ctx
->details_comp
->printed_something
) {
1633 * There are no empty line between messages in
1634 * compact mode, so write one here to decouple
1635 * the stream class from the next message.
1641 * write_stream_class() also writes all its event
1642 * classes, so we don't need to rewrite `ec`.
1644 write_stream_class(ctx
, sc
);
1647 * Mark this stream class as written, as well as all its
1650 details_did_write_meta_object(ctx
, tc
, sc
);
1652 for (ec_i
= 0; ec_i
<
1653 bt_stream_class_get_event_class_count(sc
);
1655 details_did_write_meta_object(ctx
, tc
,
1656 bt_stream_class_borrow_event_class_by_index_const(
1663 if (ec
&& details_need_to_write_meta_object(ctx
, tc
, ec
)) {
1666 if (ctx
->details_comp
->cfg
.compact
&&
1667 ctx
->details_comp
->printed_something
) {
1669 * There are no empty line between messages in
1670 * compact mode, so write one here to decouple
1671 * the event class from the next message.
1676 write_event_class(ctx
, ec
);
1677 details_did_write_meta_object(ctx
, tc
, ec
);
1686 void write_time_str(struct details_write_ctx
*ctx
, const char *str
)
1688 if (!ctx
->details_comp
->cfg
.with_time
) {
1692 g_string_append_printf(ctx
->str
, "[%s%s%s%s]",
1693 color_bold(ctx
), color_fg_blue(ctx
), str
, color_reset(ctx
));
1695 if (ctx
->details_comp
->cfg
.compact
) {
1706 void write_time(struct details_write_ctx
*ctx
, const bt_clock_snapshot
*cs
)
1708 bt_clock_snapshot_get_ns_from_origin_status cs_status
;
1709 int64_t ns_from_origin
;
1712 if (!ctx
->details_comp
->cfg
.with_time
) {
1716 format_uint(buf
, bt_clock_snapshot_get_value(cs
), 10);
1717 g_string_append_printf(ctx
->str
, "[%s%s%s%s%s",
1718 color_bold(ctx
), color_fg_blue(ctx
), buf
,
1720 ctx
->details_comp
->cfg
.compact
? "" : " cycles");
1721 cs_status
= bt_clock_snapshot_get_ns_from_origin(cs
, &ns_from_origin
);
1722 if (cs_status
== BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK
) {
1723 format_int(buf
, ns_from_origin
, 10);
1724 g_string_append_printf(ctx
->str
, "%s %s%s%s%s%s",
1725 ctx
->details_comp
->cfg
.compact
? "" : ",",
1726 color_bold(ctx
), color_fg_blue(ctx
), buf
,
1728 ctx
->details_comp
->cfg
.compact
? "" : " ns from origin");
1731 g_string_append(ctx
->str
, "]");
1733 if (ctx
->details_comp
->cfg
.compact
) {
1744 int write_message_follow_tag(struct details_write_ctx
*ctx
,
1745 const bt_stream
*stream
)
1748 uint64_t unique_trace_id
;
1749 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
1750 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
1752 ret
= details_trace_unique_id(ctx
, trace
, &unique_trace_id
);
1757 if (ctx
->details_comp
->cfg
.compact
) {
1758 g_string_append_printf(ctx
->str
,
1759 "%s{%s%" PRIu64
" %" PRIu64
" %" PRIu64
"%s%s}%s ",
1760 color_fg_cyan(ctx
), color_bold(ctx
),
1761 unique_trace_id
, bt_stream_class_get_id(sc
),
1762 bt_stream_get_id(stream
),
1763 color_reset(ctx
), color_fg_cyan(ctx
), color_reset(ctx
));
1765 g_string_append_printf(ctx
->str
,
1766 "%s{Trace %s%" PRIu64
"%s%s, Stream class ID %s%" PRIu64
"%s%s, Stream ID %s%" PRIu64
"%s%s}%s\n",
1768 color_bold(ctx
), unique_trace_id
,
1769 color_reset(ctx
), color_fg_cyan(ctx
),
1770 color_bold(ctx
), bt_stream_class_get_id(sc
),
1771 color_reset(ctx
), color_fg_cyan(ctx
),
1772 color_bold(ctx
), bt_stream_get_id(stream
),
1773 color_reset(ctx
), color_fg_cyan(ctx
),
1782 void write_field(struct details_write_ctx
*ctx
, const bt_field
*field
,
1786 bt_field_class_type fc_type
= bt_field_get_class_type(field
);
1787 const bt_field_class
*fc
;
1790 /* Write field's name */
1792 write_compound_member_name(ctx
, name
);
1795 /* Write field's value */
1796 if (fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1798 write_bool_prop_value(ctx
, bt_field_bool_get_value(field
));
1799 } else if (fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1800 format_uint(buf
, bt_field_bit_array_get_value_as_integer(field
),
1803 write_uint_str_prop_value(ctx
, buf
);
1804 } else if (bt_field_class_type_is(fc_type
,
1805 BT_FIELD_CLASS_TYPE_INTEGER
)) {
1806 unsigned int fmt_base
;
1807 bt_field_class_integer_preferred_display_base base
;
1809 fc
= bt_field_borrow_class_const(field
);
1810 base
= bt_field_class_integer_get_preferred_display_base(fc
);
1813 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
1816 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
1819 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
1822 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
1829 if (bt_field_class_type_is(fc_type
,
1830 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
)) {
1832 bt_field_integer_unsigned_get_value(field
),
1835 write_uint_str_prop_value(ctx
, buf
);
1838 bt_field_integer_signed_get_value(field
),
1841 write_int_str_prop_value(ctx
, buf
);
1843 } else if (fc_type
== BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
) {
1845 write_float_prop_value(ctx
, bt_field_real_single_precision_get_value(field
));
1846 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
) {
1848 write_float_prop_value(ctx
, bt_field_real_double_precision_get_value(field
));
1849 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1851 write_str_prop_value(ctx
, bt_field_string_get_value(field
));
1852 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1853 uint64_t member_count
;
1855 fc
= bt_field_borrow_class_const(field
);
1856 member_count
= bt_field_class_structure_get_member_count(fc
);
1858 if (member_count
> 0) {
1861 for (i
= 0; i
< member_count
; i
++) {
1862 const bt_field_class_structure_member
*member
=
1863 bt_field_class_structure_borrow_member_by_index_const(
1865 const bt_field
*member_field
=
1866 bt_field_structure_borrow_member_field_by_index_const(
1870 write_field(ctx
, member_field
,
1871 bt_field_class_structure_member_get_name(member
));
1877 write_none_prop_value(ctx
, "Empty");
1879 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1880 uint64_t length
= bt_field_array_get_length(field
);
1884 write_none_prop_value(ctx
, "Empty");
1886 g_string_append(ctx
->str
, " Length ");
1887 write_uint_prop_value(ctx
, length
);
1888 g_string_append_c(ctx
->str
, ':');
1893 for (i
= 0; i
< length
; i
++) {
1894 const bt_field
*elem_field
=
1895 bt_field_array_borrow_element_field_by_index_const(
1899 write_array_index(ctx
, i
, color_fg_cyan(ctx
));
1900 write_field(ctx
, elem_field
, NULL
);
1904 } else if (bt_field_class_type_is(fc_type
,
1905 BT_FIELD_CLASS_TYPE_OPTION
)) {
1906 const bt_field
*content_field
=
1907 bt_field_option_borrow_field_const(field
);
1909 if (!content_field
) {
1911 write_none_prop_value(ctx
, "None");
1913 write_field(ctx
, content_field
, NULL
);
1915 } else if (bt_field_class_type_is(fc_type
,
1916 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1918 bt_field_variant_borrow_selected_option_field_const(
1926 void write_root_field(struct details_write_ctx
*ctx
, const char *name
,
1927 const bt_field
*field
)
1929 BT_ASSERT_DBG(name
);
1930 BT_ASSERT_DBG(field
);
1932 write_prop_name(ctx
, name
);
1933 g_string_append(ctx
->str
, ":");
1934 write_field(ctx
, field
, NULL
);
1939 int write_event_message(struct details_write_ctx
*ctx
,
1940 const bt_message
*msg
)
1943 const bt_event
*event
= bt_message_event_borrow_event_const(msg
);
1944 const bt_stream
*stream
= bt_event_borrow_stream_const(event
);
1945 const bt_event_class
*ec
= bt_event_borrow_class_const(event
);
1946 const bt_stream_class
*sc
= bt_event_class_borrow_stream_class_const(ec
);
1947 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
1948 const char *ec_name
;
1949 const bt_field
*field
;
1951 ret
= try_write_meta(ctx
, tc
, sc
, ec
);
1956 if (!ctx
->details_comp
->cfg
.with_data
) {
1960 if (ctx
->str
->len
> 0) {
1962 * Output buffer contains metadata: separate blocks with
1969 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1971 bt_message_event_borrow_default_clock_snapshot_const(
1975 /* Write follow tag for message */
1976 ret
= write_message_follow_tag(ctx
, stream
);
1981 /* Write object's basic properties */
1982 write_obj_type_name(ctx
, "Event");
1983 ec_name
= bt_event_class_get_name(ec
);
1985 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1986 color_fg_green(ctx
), ec_name
, color_reset(ctx
));
1989 g_string_append(ctx
->str
, " (");
1991 if (!ctx
->details_comp
->cfg
.compact
) {
1992 g_string_append(ctx
->str
, "Class ID ");
1995 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1996 g_string_append(ctx
->str
, ")");
1998 if (ctx
->details_comp
->cfg
.compact
) {
2004 g_string_append(ctx
->str
, ":\n");
2006 field
= bt_event_borrow_common_context_field_const(event
);
2008 write_root_field(ctx
, "Common context", field
);
2011 field
= bt_event_borrow_specific_context_field_const(event
);
2013 write_root_field(ctx
, "Specific context", field
);
2016 field
= bt_event_borrow_payload_field_const(event
);
2018 write_root_field(ctx
, "Payload", field
);
2028 gint
compare_streams(const bt_stream
**a
, const bt_stream
**b
)
2030 uint64_t id_a
= bt_stream_get_id(*a
);
2031 uint64_t id_b
= bt_stream_get_id(*b
);
2035 } else if (id_a
> id_b
) {
2038 const bt_stream_class
*a_sc
= bt_stream_borrow_class_const(*a
);
2039 const bt_stream_class
*b_sc
= bt_stream_borrow_class_const(*b
);
2040 uint64_t a_sc_id
= bt_stream_class_get_id(a_sc
);
2041 uint64_t b_sc_id
= bt_stream_class_get_id(b_sc
);
2043 if (a_sc_id
< b_sc_id
) {
2045 } else if (a_sc_id
> b_sc_id
) {
2054 void write_trace(struct details_write_ctx
*ctx
, const bt_trace
*trace
)
2056 GPtrArray
*streams
= g_ptr_array_new();
2058 bool printed_prop
= false;
2059 GPtrArray
*env_names
= g_ptr_array_new();
2063 write_obj_type_name(ctx
, "Trace");
2066 if (ctx
->details_comp
->cfg
.with_trace_name
) {
2067 const char *name
= bt_trace_get_name(trace
);
2069 g_string_append(ctx
->str
, " `");
2070 write_str_prop_value(ctx
, name
);
2071 g_string_append(ctx
->str
, "`");
2075 /* Write properties */
2079 if (ctx
->details_comp
->cfg
.with_uuid
) {
2080 bt_uuid uuid
= bt_trace_get_uuid(trace
);
2083 if (!printed_prop
) {
2084 g_string_append(ctx
->str
, ":\n");
2085 printed_prop
= true;
2088 write_uuid_prop_line(ctx
, "UUID", uuid
);
2092 /* Write environment */
2093 env_count
= bt_trace_get_environment_entry_count(trace
);
2094 if (env_count
> 0) {
2095 if (!printed_prop
) {
2096 g_string_append(ctx
->str
, ":\n");
2097 printed_prop
= true;
2101 write_prop_name(ctx
, "Environment");
2102 g_string_append(ctx
->str
, " (");
2103 write_uint_prop_value(ctx
, env_count
);
2104 g_string_append_printf(ctx
->str
, " entr%s):",
2105 env_count
== 1 ? "y" : "ies");
2109 for (i
= 0; i
< env_count
; i
++) {
2111 const bt_value
*value
;
2113 bt_trace_borrow_environment_entry_by_index_const(
2114 trace
, i
, &name
, &value
);
2115 g_ptr_array_add(env_names
, (gpointer
) name
);
2118 g_ptr_array_sort(env_names
, (GCompareFunc
) compare_strings
);
2120 for (i
= 0; i
< env_names
->len
; i
++) {
2121 const char *name
= env_names
->pdata
[i
];
2122 const bt_value
*value
=
2123 bt_trace_borrow_environment_entry_value_by_name_const(
2126 BT_ASSERT_DBG(value
);
2127 write_compound_member_name(ctx
, name
);
2130 if (bt_value_get_type(value
) ==
2131 BT_VALUE_TYPE_SIGNED_INTEGER
) {
2132 write_int_prop_value(ctx
,
2133 bt_value_integer_signed_get(value
));
2134 } else if (bt_value_get_type(value
) ==
2135 BT_VALUE_TYPE_STRING
) {
2136 write_str_prop_value(ctx
,
2137 bt_value_string_get(value
));
2148 for (i
= 0; i
< bt_trace_get_stream_count(trace
); i
++) {
2149 g_ptr_array_add(streams
,
2150 (gpointer
) bt_trace_borrow_stream_by_index_const(
2154 g_ptr_array_sort(streams
, (GCompareFunc
) compare_streams
);
2156 if (streams
->len
> 0 && !printed_prop
) {
2157 g_string_append(ctx
->str
, ":\n");
2158 printed_prop
= true;
2161 for (i
= 0; i
< streams
->len
; i
++) {
2162 const bt_stream
*stream
= streams
->pdata
[i
];
2165 write_obj_type_name(ctx
, "Stream");
2166 g_string_append(ctx
->str
, " (ID ");
2167 write_uint_prop_value(ctx
, bt_stream_get_id(stream
));
2168 g_string_append(ctx
->str
, ", Class ID ");
2169 write_uint_prop_value(ctx
, bt_stream_class_get_id(
2170 bt_stream_borrow_class_const(stream
)));
2171 g_string_append(ctx
->str
, ")");
2177 if (!printed_prop
) {
2181 g_ptr_array_free(streams
, TRUE
);
2182 g_ptr_array_free(env_names
, TRUE
);
2186 int write_stream_beginning_message(struct details_write_ctx
*ctx
,
2187 const bt_message
*msg
)
2190 const bt_stream
*stream
=
2191 bt_message_stream_beginning_borrow_stream_const(msg
);
2192 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
2193 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2194 const bt_clock_class
*cc
= bt_stream_class_borrow_default_clock_class_const(sc
);
2195 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
2198 ret
= try_write_meta(ctx
, tc
, sc
, NULL
);
2203 if (!ctx
->details_comp
->cfg
.with_data
) {
2207 if (ctx
->str
->len
> 0) {
2209 * Output buffer contains metadata: separate blocks with
2217 const bt_clock_snapshot
*cs
;
2218 bt_message_stream_clock_snapshot_state cs_state
=
2219 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg
, &cs
);
2221 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2222 write_time(ctx
, cs
);
2224 write_time_str(ctx
, "Unknown");
2228 /* Write follow tag for message */
2229 ret
= write_message_follow_tag(ctx
, stream
);
2234 /* Write stream properties */
2235 write_obj_type_name(ctx
, "Stream beginning");
2237 if (ctx
->details_comp
->cfg
.compact
) {
2242 g_string_append(ctx
->str
, ":\n");
2245 if (ctx
->details_comp
->cfg
.with_stream_name
) {
2246 name
= bt_stream_get_name(stream
);
2248 write_str_prop_line(ctx
, "Name", name
);
2252 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
2253 name
= bt_stream_class_get_name(sc
);
2255 write_str_prop_line(ctx
, "Class name", name
);
2259 write_trace(ctx
, trace
);
2267 int write_stream_end_message(struct details_write_ctx
*ctx
,
2268 const bt_message
*msg
)
2271 const bt_stream
*stream
=
2272 bt_message_stream_end_borrow_stream_const(msg
);
2273 const bt_stream_class
*sc
=
2274 bt_stream_borrow_class_const(stream
);
2275 const bt_clock_class
*cc
=
2276 bt_stream_class_borrow_default_clock_class_const(sc
);
2278 if (!ctx
->details_comp
->cfg
.with_data
) {
2284 const bt_clock_snapshot
*cs
;
2285 bt_message_stream_clock_snapshot_state cs_state
=
2286 bt_message_stream_end_borrow_default_clock_snapshot_const(msg
, &cs
);
2288 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2289 write_time(ctx
, cs
);
2291 write_time_str(ctx
, "Unknown");
2295 /* Write follow tag for message */
2296 ret
= write_message_follow_tag(ctx
, stream
);
2301 /* Write stream properties */
2302 write_obj_type_name(ctx
, "Stream end\n");
2309 int write_packet_beginning_message(struct details_write_ctx
*ctx
,
2310 const bt_message
*msg
)
2313 const bt_packet
*packet
=
2314 bt_message_packet_beginning_borrow_packet_const(msg
);
2315 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2316 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2317 const bt_field
*field
;
2319 if (!ctx
->details_comp
->cfg
.with_data
) {
2324 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
)) {
2326 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2330 /* Write follow tag for message */
2331 ret
= write_message_follow_tag(ctx
, stream
);
2336 write_obj_type_name(ctx
, "Packet beginning");
2338 if (ctx
->details_comp
->cfg
.compact
) {
2344 field
= bt_packet_borrow_context_field_const(packet
);
2346 g_string_append(ctx
->str
, ":\n");
2348 write_root_field(ctx
, "Context", field
);
2359 int write_discarded_items_message(struct details_write_ctx
*ctx
,
2360 const char *name
, const bt_stream
*stream
,
2361 const bt_clock_snapshot
*beginning_cs
,
2362 const bt_clock_snapshot
*end_cs
, uint64_t count
)
2368 write_time(ctx
, beginning_cs
);
2369 BT_ASSERT_DBG(end_cs
);
2370 write_time(ctx
, end_cs
);
2373 /* Write follow tag for message */
2374 ret
= write_message_follow_tag(ctx
, stream
);
2379 write_obj_type_name(ctx
, "Discarded ");
2380 write_obj_type_name(ctx
, name
);
2383 if (count
== UINT64_C(-1)) {
2388 g_string_append(ctx
->str
, " (");
2389 write_uint_prop_value(ctx
, count
);
2390 g_string_append_printf(ctx
->str
, " %s)\n", name
);
2397 int write_discarded_events_message(struct details_write_ctx
*ctx
,
2398 const bt_message
*msg
)
2401 const bt_stream
*stream
= bt_message_discarded_events_borrow_stream_const(
2403 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2404 const bt_clock_snapshot
*beginning_cs
= NULL
;
2405 const bt_clock_snapshot
*end_cs
= NULL
;
2408 if (!ctx
->details_comp
->cfg
.with_data
) {
2412 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc
)) {
2414 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2417 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2421 if (bt_message_discarded_events_get_count(msg
, &count
) !=
2422 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2423 count
= UINT64_C(-1);
2426 ret
= write_discarded_items_message(ctx
, "events", stream
,
2427 beginning_cs
, end_cs
, count
);
2434 int write_discarded_packets_message(struct details_write_ctx
*ctx
,
2435 const bt_message
*msg
)
2438 const bt_stream
*stream
= bt_message_discarded_packets_borrow_stream_const(
2440 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2441 const bt_clock_snapshot
*beginning_cs
= NULL
;
2442 const bt_clock_snapshot
*end_cs
= NULL
;
2445 if (!ctx
->details_comp
->cfg
.with_data
) {
2449 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
)) {
2451 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2454 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2458 if (bt_message_discarded_packets_get_count(msg
, &count
) !=
2459 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2460 count
= UINT64_C(-1);
2463 ret
= write_discarded_items_message(ctx
, "packets", stream
,
2464 beginning_cs
, end_cs
, count
);
2471 int write_packet_end_message(struct details_write_ctx
*ctx
,
2472 const bt_message
*msg
)
2475 const bt_packet
*packet
=
2476 bt_message_packet_end_borrow_packet_const(msg
);
2477 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2478 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2480 if (!ctx
->details_comp
->cfg
.with_data
) {
2485 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc
)) {
2487 bt_message_packet_end_borrow_default_clock_snapshot_const(
2491 /* Write follow tag for message */
2492 ret
= write_message_follow_tag(ctx
, stream
);
2497 write_obj_type_name(ctx
, "Packet end");
2505 int write_message_iterator_inactivity_message(struct details_write_ctx
*ctx
,
2506 const bt_message
*msg
)
2509 const bt_clock_snapshot
*cs
=
2510 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
2514 write_time(ctx
, cs
);
2515 write_obj_type_name(ctx
, "Message iterator inactivity");
2517 if (ctx
->details_comp
->cfg
.compact
) {
2522 /* Write clock class properties */
2523 g_string_append(ctx
->str
, ":\n");
2526 write_prop_name(ctx
, "Clock class");
2527 g_string_append_c(ctx
->str
, ':');
2530 write_clock_class_prop_lines(ctx
,
2531 bt_clock_snapshot_borrow_clock_class_const(cs
));
2539 int details_write_message(struct details_comp
*details_comp
,
2540 const bt_message
*msg
)
2543 struct details_write_ctx ctx
= {
2544 .details_comp
= details_comp
,
2545 .str
= details_comp
->str
,
2549 /* Reset output buffer */
2550 g_string_assign(details_comp
->str
, "");
2552 switch (bt_message_get_type(msg
)) {
2553 case BT_MESSAGE_TYPE_EVENT
:
2554 ret
= write_event_message(&ctx
, msg
);
2556 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY
:
2557 ret
= write_message_iterator_inactivity_message(&ctx
, msg
);
2559 case BT_MESSAGE_TYPE_STREAM_BEGINNING
:
2560 ret
= write_stream_beginning_message(&ctx
, msg
);
2562 case BT_MESSAGE_TYPE_STREAM_END
:
2563 ret
= write_stream_end_message(&ctx
, msg
);
2565 case BT_MESSAGE_TYPE_PACKET_BEGINNING
:
2566 ret
= write_packet_beginning_message(&ctx
, msg
);
2568 case BT_MESSAGE_TYPE_PACKET_END
:
2569 ret
= write_packet_end_message(&ctx
, msg
);
2571 case BT_MESSAGE_TYPE_DISCARDED_EVENTS
:
2572 ret
= write_discarded_events_message(&ctx
, msg
);
2574 case BT_MESSAGE_TYPE_DISCARDED_PACKETS
:
2575 ret
= write_discarded_packets_message(&ctx
, msg
);
2582 * If this component printed at least one character so far, and
2583 * we're not in compact mode, and there's something in the
2584 * output buffer for this message, then prepend a newline to the
2585 * output buffer to visually separate message blocks.
2587 if (details_comp
->printed_something
&& !details_comp
->cfg
.compact
&&
2588 details_comp
->str
->len
> 0) {
2589 /* TODO: Optimize this */
2590 g_string_prepend_c(details_comp
->str
, '\n');