lib: split real FC/field into single and double prec FC/field
[babeltrace.git] / src / plugins / text / details / write.c
index 3601d45ce9f698038dafa17a3fe71b1ed41dd70f..1eab46b24e09977f8a76eedc575d06464c2768ef 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "common/assert.h"
 #include "common/common.h"
+#include "common/uuid.h"
 #include "details.h"
 #include "write.h"
 #include "obj-lifetime-mgmt.h"
@@ -198,14 +199,15 @@ void write_compound_member_name(struct details_write_ctx *ctx, const char *name)
 }
 
 static inline
-void write_array_index(struct details_write_ctx *ctx, uint64_t index)
+void write_array_index(struct details_write_ctx *ctx, uint64_t index,
+               const char *color)
 {
        char buf[32];
 
        write_indent(ctx);
        format_uint(buf, index, 10);
        g_string_append_printf(ctx->str, "%s[%s]%s:",
-               color_fg_cyan(ctx), buf, color_reset(ctx));
+               color, buf, color_reset(ctx));
 }
 
 static inline
@@ -222,6 +224,14 @@ void write_prop_name(struct details_write_ctx *ctx, const char *prop_name)
                color_fg_magenta(ctx), prop_name, color_reset(ctx));
 }
 
+static inline
+void write_prop_name_line(struct details_write_ctx *ctx, const char *prop_name)
+{
+       write_indent(ctx);
+       g_string_append_printf(ctx->str, "%s%s%s:",
+               color_fg_magenta(ctx), prop_name, color_reset(ctx));
+}
+
 static inline
 void write_str_prop_value(struct details_write_ctx *ctx, const char *value)
 {
@@ -229,6 +239,14 @@ void write_str_prop_value(struct details_write_ctx *ctx, const char *value)
                color_bold(ctx), value, color_reset(ctx));
 }
 
+static inline
+void write_none_prop_value(struct details_write_ctx *ctx, const char *value)
+{
+       g_string_append_printf(ctx->str, "%s%s%s%s",
+               color_bold(ctx), color_fg_magenta(ctx),
+               value, color_reset(ctx));
+}
+
 static inline
 void write_uint_str_prop_value(struct details_write_ctx *ctx, const char *value)
 {
@@ -301,14 +319,11 @@ void write_int_str_prop_value(struct details_write_ctx *ctx, const char *value)
 }
 
 static inline
-void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
-               bt_bool prop_value)
+void write_bool_prop_value(struct details_write_ctx *ctx, bt_bool prop_value)
 {
        const char *str;
 
-       write_indent(ctx);
-       write_prop_name(ctx, prop_name);
-       g_string_append_printf(ctx->str, ": %s", color_bold(ctx));
+       g_string_append(ctx->str, color_bold(ctx));
 
        if (prop_value) {
                g_string_append(ctx->str, color_fg_green(ctx));
@@ -318,7 +333,18 @@ void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
                str = "No";
        }
 
-       g_string_append_printf(ctx->str, "%s%s\n", str, color_reset(ctx));
+       g_string_append_printf(ctx->str, "%s%s", str, color_reset(ctx));
+}
+
+static inline
+void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
+               bt_bool prop_value)
+{
+       write_indent(ctx);
+       write_prop_name(ctx, prop_name);
+       g_string_append(ctx->str, ": ");
+       write_bool_prop_value(ctx, prop_value);
+       write_nl(ctx);
 }
 
 static inline
@@ -329,27 +355,158 @@ void write_uuid_prop_line(struct details_write_ctx *ctx, const char *prop_name,
        write_indent(ctx);
        write_prop_name(ctx, prop_name);
        g_string_append_printf(ctx->str,
-               ": %s%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n",
+               ": %s" BT_UUID_FMT "%s\n",
                color_bold(ctx),
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15],
+               BT_UUID_FMT_VALUES(uuid),
                color_reset(ctx));
 }
 
+static
+gint compare_strings(const char **a, const char **b)
+{
+       return strcmp(*a, *b);
+}
+
+static
+bt_bool map_value_foreach_add_key_to_array(const char *key,
+               const bt_value *object, void *data)
+{
+       GPtrArray *keys = data;
+
+       BT_ASSERT(keys);
+       g_ptr_array_add(keys, (void *) key);
+       return BT_TRUE;
+}
+
+static
+void write_value(struct details_write_ctx *ctx, const bt_value *value,
+               const char *name)
+{
+       uint64_t i;
+       bt_value_type value_type = bt_value_get_type(value);
+       GPtrArray *keys = g_ptr_array_new();
+       char buf[64];
+
+       BT_ASSERT(keys);
+
+       /* Write field's name */
+       if (name) {
+               write_prop_name_line(ctx, name);
+       }
+
+       /* Write field's value */
+       switch (value_type) {
+       case BT_VALUE_TYPE_NULL:
+               write_sp(ctx);
+               write_none_prop_value(ctx, "Null");
+               break;
+       case BT_VALUE_TYPE_BOOL:
+               write_sp(ctx);
+               write_bool_prop_value(ctx, bt_value_bool_get(value));
+               break;
+       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
+               format_uint(buf, bt_value_integer_unsigned_get(value), 10);
+               write_sp(ctx);
+               write_uint_str_prop_value(ctx, buf);
+               break;
+       case BT_VALUE_TYPE_SIGNED_INTEGER:
+               format_int(buf, bt_value_integer_signed_get(value), 10);
+               write_sp(ctx);
+               write_int_str_prop_value(ctx, buf);
+               break;
+       case BT_VALUE_TYPE_REAL:
+               write_sp(ctx);
+               write_float_prop_value(ctx, bt_value_real_get(value));
+               break;
+       case BT_VALUE_TYPE_STRING:
+               write_sp(ctx);
+               write_str_prop_value(ctx, bt_value_string_get(value));
+               break;
+       case BT_VALUE_TYPE_ARRAY:
+       {
+               uint64_t length = bt_value_array_get_length(value);
+
+               if (length == 0) {
+                       write_sp(ctx);
+                       write_none_prop_value(ctx, "Empty");
+               } else {
+                       g_string_append(ctx->str, " Length ");
+                       write_uint_prop_value(ctx, length);
+                       g_string_append_c(ctx->str, ':');
+               }
+
+               incr_indent(ctx);
+
+               for (i = 0; i < length; i++) {
+                       const bt_value *elem_value =
+                               bt_value_array_borrow_element_by_index_const(
+                                       value, i);
+
+                       write_nl(ctx);
+                       write_array_index(ctx, i, color_fg_magenta(ctx));
+                       write_value(ctx, elem_value, NULL);
+               }
+
+               decr_indent(ctx);
+               break;
+       }
+       case BT_VALUE_TYPE_MAP:
+       {
+               bt_value_map_foreach_entry_const_status foreach_status =
+                       bt_value_map_foreach_entry_const(value,
+                               map_value_foreach_add_key_to_array, keys);
+
+               BT_ASSERT(foreach_status ==
+                       BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK);
+               g_ptr_array_sort(keys, (GCompareFunc) compare_strings);
+
+               if (keys->len > 0) {
+                       incr_indent(ctx);
+
+                       for (i = 0; i < keys->len; i++) {
+                               const char *key = keys->pdata[i];
+                               const bt_value *entry_value =
+                                       bt_value_map_borrow_entry_value_const(
+                                               value, key);
+
+                               write_nl(ctx);
+                               write_value(ctx, entry_value, key);
+                       }
+
+                       decr_indent(ctx);
+               } else {
+                       write_sp(ctx);
+                       write_none_prop_value(ctx, "Empty");
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       g_ptr_array_free(keys, TRUE);
+}
+
+static
+void write_user_attributes(struct details_write_ctx *ctx,
+               const bt_value *user_attrs, bool write_newline, bool *written)
+{
+       BT_ASSERT(user_attrs);
+
+       if (!bt_value_map_is_empty(user_attrs)) {
+               write_value(ctx, user_attrs, "User attributes");
+
+               if (write_newline) {
+                       write_nl(ctx);
+               }
+
+               if (written) {
+                       *written = true;
+               }
+       }
+}
+
 static
 void write_int_field_class_props(struct details_write_ctx *ctx,
                const bt_field_class *fc, bool close)
@@ -381,7 +538,7 @@ void write_int_field_class_props(struct details_write_ctx *ctx,
        }
 }
 
-struct enum_field_class_mapping_range {
+struct int_range {
        union {
                uint64_t u;
                int64_t i;
@@ -397,7 +554,7 @@ struct enum_field_class_mapping {
        /* Weak */
        const char *label;
 
-       /* Array of `struct enum_field_class_mapping_range` */
+       /* Array of `struct int_range` */
        GArray *ranges;
 };
 
@@ -409,9 +566,7 @@ gint compare_enum_field_class_mappings(struct enum_field_class_mapping **a,
 }
 
 static
-gint compare_enum_field_class_mapping_ranges_signed(
-               struct enum_field_class_mapping_range *a,
-               struct enum_field_class_mapping_range *b)
+gint compare_int_ranges_signed(struct int_range *a, struct int_range *b)
 {
 
        if (a->lower.i < b->lower.i) {
@@ -430,9 +585,7 @@ gint compare_enum_field_class_mapping_ranges_signed(
 }
 
 static
-gint compare_enum_field_class_mapping_ranges_unsigned(
-               struct enum_field_class_mapping_range *a,
-               struct enum_field_class_mapping_range *b)
+gint compare_int_ranges_unsigned(struct int_range *a, struct int_range *b)
 {
        if (a->lower.u < b->lower.u) {
                return -1;
@@ -449,6 +602,58 @@ gint compare_enum_field_class_mapping_ranges_unsigned(
        }
 }
 
+static
+GArray *range_set_to_int_ranges(const void *spec_range_set, bool is_signed)
+{
+       uint64_t i;
+       const bt_integer_range_set *range_set;
+       GArray *ranges = g_array_new(FALSE, TRUE, sizeof(struct int_range));
+
+       if (!ranges) {
+               goto end;
+       }
+
+       if (is_signed) {
+               range_set = bt_integer_range_set_signed_as_range_set_const(
+                       spec_range_set);
+       } else {
+               range_set = bt_integer_range_set_unsigned_as_range_set_const(
+                       spec_range_set);
+       }
+
+       for (i = 0; i < bt_integer_range_set_get_range_count(range_set); i++) {
+               struct int_range range;
+
+               if (is_signed) {
+                       const bt_integer_range_signed *orig_range =
+                               bt_integer_range_set_signed_borrow_range_by_index_const(
+                                       spec_range_set, i);
+
+                       range.lower.i = bt_integer_range_signed_get_lower(orig_range);
+                       range.upper.i = bt_integer_range_signed_get_upper(orig_range);
+               } else {
+                       const bt_integer_range_unsigned *orig_range =
+                               bt_integer_range_set_unsigned_borrow_range_by_index_const(
+                                       spec_range_set, i);
+
+                       range.lower.u = bt_integer_range_unsigned_get_lower(orig_range);
+                       range.upper.u = bt_integer_range_unsigned_get_upper(orig_range);
+               }
+
+               g_array_append_val(ranges, range);
+       }
+
+       if (is_signed) {
+               g_array_sort(ranges, (GCompareFunc) compare_int_ranges_signed);
+       } else {
+               g_array_sort(ranges,
+                       (GCompareFunc) compare_int_ranges_unsigned);
+       }
+
+end:
+       return ranges;
+}
+
 static
 void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping)
 {
@@ -461,8 +666,14 @@ void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping)
 }
 
 static
-void write_enum_field_class_mapping_range(struct details_write_ctx *ctx,
-               struct enum_field_class_mapping_range *range, bool is_signed)
+struct int_range *int_range_at(GArray *ranges, uint64_t index)
+{
+       return &g_array_index(ranges, struct int_range, index);
+}
+
+static
+void write_int_range(struct details_write_ctx *ctx,
+               struct int_range *range, bool is_signed)
 {
        g_string_append(ctx->str, "[");
 
@@ -472,12 +683,14 @@ void write_enum_field_class_mapping_range(struct details_write_ctx *ctx,
                write_int_prop_value(ctx, range->lower.u);
        }
 
-       g_string_append(ctx->str, ", ");
+       if (range->lower.u != range->upper.u) {
+               g_string_append(ctx->str, ", ");
 
-       if (is_signed) {
-               write_int_prop_value(ctx, range->upper.i);
-       } else {
-               write_int_prop_value(ctx, range->upper.u);
+               if (is_signed) {
+                       write_int_prop_value(ctx, range->upper.i);
+               } else {
+                       write_int_prop_value(ctx, range->upper.u);
+               }
        }
 
        g_string_append(ctx->str, "]");
@@ -503,95 +716,50 @@ void write_enum_field_class_mappings(struct details_write_ctx *ctx,
         */
        for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
                const void *fc_mapping;
+               const void *fc_range_set;
                struct enum_field_class_mapping *mapping = g_new0(
                        struct enum_field_class_mapping, 1);
 
                BT_ASSERT(mapping);
-               mapping->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct enum_field_class_mapping_range));
-               BT_ASSERT(mapping->ranges);
 
                if (is_signed) {
-                       fc_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
+                       fc_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
                                fc, i);
+                       fc_range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
+                               fc_mapping);
                } else {
-                       fc_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
+                       fc_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
                                fc, i);
+                       fc_range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
+                               fc_mapping);
                }
 
                mapping->label = bt_field_class_enumeration_mapping_get_label(
-                       bt_field_class_signed_enumeration_mapping_as_mapping_const(
+                       bt_field_class_enumeration_signed_mapping_as_mapping_const(
                                fc_mapping));
-
-               for (range_i = 0;
-                               range_i < bt_field_class_enumeration_mapping_get_range_count(
-                                       bt_field_class_signed_enumeration_mapping_as_mapping_const(fc_mapping));
-                               range_i++) {
-                       struct enum_field_class_mapping_range range;
-
-                       if (is_signed) {
-                               bt_field_class_signed_enumeration_mapping_get_range_by_index(
-                                       fc_mapping, range_i,
-                                       &range.lower.i, &range.upper.i);
-                       } else {
-                               bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
-                                       fc_mapping, range_i,
-                                       &range.lower.u, &range.upper.u);
-                       }
-
-                       g_array_append_val(mapping->ranges, range);
-               }
-
+               mapping->ranges = range_set_to_int_ranges(fc_range_set,
+                       is_signed);
+               BT_ASSERT(mapping->ranges);
                g_ptr_array_add(mappings, mapping);
        }
 
-       /* Sort mappings, and for each mapping, sort ranges */
+       /* Sort mappings (ranges are already sorted within mappings) */
        g_ptr_array_sort(mappings,
                (GCompareFunc) compare_enum_field_class_mappings);
 
-       for (i = 0; i < mappings->len; i++) {
-               struct enum_field_class_mapping *mapping = mappings->pdata[i];
-
-               if (is_signed) {
-                       g_array_sort(mapping->ranges,
-                               (GCompareFunc)
-                                       compare_enum_field_class_mapping_ranges_signed);
-               } else {
-                       g_array_sort(mapping->ranges,
-                               (GCompareFunc)
-                                       compare_enum_field_class_mapping_ranges_unsigned);
-               }
-       }
-
        /* Write mappings */
        for (i = 0; i < mappings->len; i++) {
                struct enum_field_class_mapping *mapping = mappings->pdata[i];
 
                write_nl(ctx);
-               write_compound_member_name(ctx, mapping->label);
-
-               if (mapping->ranges->len == 1) {
-                       /* Single one: write on same line */
-                       write_sp(ctx);
-                       write_enum_field_class_mapping_range(ctx,
-                               &g_array_index(mapping->ranges,
-                                       struct enum_field_class_mapping_range,
-                                       0), is_signed);
-                       continue;
-               }
-
-               incr_indent(ctx);
+               write_prop_name_line(ctx, mapping->label);
 
                for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
-                       write_nl(ctx);
-                       write_indent(ctx);
-                       write_enum_field_class_mapping_range(ctx,
-                               &g_array_index(mapping->ranges,
-                                       struct enum_field_class_mapping_range,
-                                       range_i), is_signed);
+                       write_sp(ctx);
+                       write_int_range(ctx,
+                               int_range_at(mapping->ranges, range_i),
+                               is_signed);
                }
-
-               decr_indent(ctx);
        }
 
        g_ptr_array_free(mappings, TRUE);
@@ -606,16 +774,16 @@ void write_field_path(struct details_write_ctx *ctx,
        g_string_append_c(ctx->str, '[');
 
        switch (bt_field_path_get_root_scope(field_path)) {
-       case BT_SCOPE_PACKET_CONTEXT:
+       case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
                write_str_prop_value(ctx, "Packet context");
                break;
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+       case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
                write_str_prop_value(ctx, "Event common context");
                break;
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+       case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
                write_str_prop_value(ctx, "Event specific context");
                break;
-       case BT_SCOPE_EVENT_PAYLOAD:
+       case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
                write_str_prop_value(ctx, "Event payload");
                break;
        default:
@@ -649,21 +817,108 @@ void write_field_path(struct details_write_ctx *ctx,
 }
 
 static
-void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
-               const char *name)
+void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc);
+
+static
+void write_variant_field_class_option(struct details_write_ctx *ctx,
+               const bt_field_class *fc, uint64_t index)
 {
-       uint64_t i;
-       const char *type;
        bt_field_class_type fc_type = bt_field_class_get_type(fc);
+       const bt_field_class_variant_option *option =
+               bt_field_class_variant_borrow_option_by_index_const(
+                       fc, index);
+       const void *orig_ranges = NULL;
+       GArray *int_ranges = NULL;
+       bool is_signed;
+       const bt_value *user_attrs =
+               bt_field_class_variant_option_borrow_user_attributes_const(
+                       option);
+       const bt_field_class *option_fc =
+               bt_field_class_variant_option_borrow_field_class_const(option);
 
-       /* Write field class's name */
-       if (name) {
-               write_compound_member_name(ctx, name);
+       write_nl(ctx);
+       write_compound_member_name(ctx,
+               bt_field_class_variant_option_get_name(option));
+
+       if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
+               const bt_field_class_variant_with_selector_unsigned_option *spec_opt =
+                       bt_field_class_variant_with_selector_unsigned_borrow_option_by_index_const(
+                               fc, index);
+
+               orig_ranges =
+                       bt_field_class_variant_with_selector_unsigned_option_borrow_ranges_const(
+                               spec_opt);
+               is_signed = false;
+       } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
+               const bt_field_class_variant_with_selector_signed_option *spec_opt =
+                       bt_field_class_variant_with_selector_signed_borrow_option_by_index_const(
+                               fc, index);
+
+               orig_ranges =
+                       bt_field_class_variant_with_selector_signed_option_borrow_ranges_const(
+                               spec_opt);
+               is_signed = true;
+       }
+
+       if (orig_ranges) {
+               uint64_t i;
+
+               int_ranges = range_set_to_int_ranges(orig_ranges, is_signed);
+               BT_ASSERT(int_ranges);
+
+               for (i = 0; i < int_ranges->len; i++) {
+                       struct int_range *range = int_range_at(int_ranges, i);
+
+                       write_sp(ctx);
+                       write_int_range(ctx, range, is_signed);
+               }
+
+               g_string_append(ctx->str, ": ");
+       } else {
+               write_sp(ctx);
+       }
+
+       if (bt_value_map_is_empty(user_attrs)) {
+               write_field_class(ctx, option_fc);
+       } else {
+               write_nl(ctx);
+               incr_indent(ctx);
+
+               /* Field class */
+               write_prop_name_line(ctx, "Field class");
                write_sp(ctx);
+               write_field_class(ctx, option_fc);
+               write_nl(ctx);
+
+               /* User attributes */
+               write_user_attributes(ctx, user_attrs,
+                       false, NULL);
+
+               decr_indent(ctx);
+       }
+
+       if (int_ranges) {
+               g_array_free(int_ranges, TRUE);
        }
+}
+
+static
+void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc)
+{
+       uint64_t i;
+       const char *type;
+       bt_field_class_type fc_type = bt_field_class_get_type(fc);
+       const bt_value *user_attrs;
+       bool wrote_user_attrs = false;
 
        /* Write field class's type */
        switch (fc_type) {
+       case BT_FIELD_CLASS_TYPE_BOOL:
+               type = "Boolean";
+               break;
+       case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
+               type = "Bit array";
+               break;
        case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
                type = "Unsigned integer";
                break;
@@ -676,8 +931,11 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
        case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
                type = "Signed enumeration";
                break;
-       case BT_FIELD_CLASS_TYPE_REAL:
-               type = "Real";
+       case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
+               type = "Single-precision real";
+               break;
+       case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
+               type = "Double-precision real";
                break;
        case BT_FIELD_CLASS_TYPE_STRING:
                type = "String";
@@ -691,8 +949,17 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
        case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
                type = "Dynamic array";
                break;
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               type = "Variant";
+       case BT_FIELD_CLASS_TYPE_OPTION:
+               type = "Option";
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
+               type = "Variant (no selector)";
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
+               type = "Variant (unsigned selector)";
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
+               type = "Variant (signed selector)";
                break;
        default:
                abort();
@@ -701,7 +968,7 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
        g_string_append_printf(ctx->str, "%s%s%s",
                color_fg_blue(ctx), type, color_reset(ctx));
 
-       /* Write field class's properties */
+       /* Write field class's single-line properties */
        switch (fc_type) {
        case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
        case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
@@ -720,24 +987,8 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
                write_uint_prop_value(ctx, mapping_count);
                g_string_append_printf(ctx->str, " mapping%s)",
                        plural(mapping_count));
-
-               if (mapping_count > 0) {
-                       g_string_append_c(ctx->str, ':');
-                       incr_indent(ctx);
-                       write_enum_field_class_mappings(ctx, fc);
-                       decr_indent(ctx);
-               }
-
                break;
        }
-       case BT_FIELD_CLASS_TYPE_REAL:
-               if (bt_field_class_real_is_single_precision(fc)) {
-                       g_string_append(ctx->str, " (Single precision)");
-               } else {
-                       g_string_append(ctx->str, " (Double precision)");
-               }
-
-               break;
        case BT_FIELD_CLASS_TYPE_STRUCTURE:
        {
                uint64_t member_count =
@@ -747,25 +998,6 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
                write_uint_prop_value(ctx, member_count);
                g_string_append_printf(ctx->str, " member%s)",
                        plural(member_count));
-
-               if (member_count > 0) {
-                       g_string_append_c(ctx->str, ':');
-                       incr_indent(ctx);
-
-                       for (i = 0; i < member_count; i++) {
-                               const bt_field_class_structure_member *member =
-                                       bt_field_class_structure_borrow_member_by_index_const(
-                                               fc, i);
-
-                               write_nl(ctx);
-                               write_field_class(ctx,
-                                       bt_field_class_structure_member_borrow_field_class_const(member),
-                                       bt_field_class_structure_member_get_name(member));
-                       }
-
-                       decr_indent(ctx);
-               }
-
                break;
        }
        case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
@@ -773,11 +1005,11 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
                if (fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
                        g_string_append(ctx->str, " (Length ");
                        write_uint_prop_value(ctx,
-                               bt_field_class_static_array_get_length(fc));
+                               bt_field_class_array_static_get_length(fc));
                        g_string_append_c(ctx->str, ')');
                } else {
                        const bt_field_path *length_field_path =
-                               bt_field_class_dynamic_array_borrow_length_field_path_const(
+                               bt_field_class_array_dynamic_borrow_length_field_path_const(
                                        fc);
 
                        if (length_field_path) {
@@ -787,50 +1019,200 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
                        }
                }
 
-               g_string_append_c(ctx->str, ':');
-               write_nl(ctx);
-               incr_indent(ctx);
-               write_field_class(ctx,
-                       bt_field_class_array_borrow_element_field_class_const(fc),
-                       "Element");
-               decr_indent(ctx);
                break;
-       case BT_FIELD_CLASS_TYPE_VARIANT:
+       case BT_FIELD_CLASS_TYPE_OPTION:
+       {
+               const bt_field_path *selector_field_path =
+                       bt_field_class_option_borrow_selector_field_path_const(fc);
+
+               if (selector_field_path) {
+                       g_string_append(ctx->str, " (Selector field path ");
+                       write_field_path(ctx, selector_field_path);
+                       g_string_append_c(ctx->str, ')');
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
        {
                uint64_t option_count =
                        bt_field_class_variant_get_option_count(fc);
-               const bt_field_path *sel_field_path =
-                       bt_field_class_variant_borrow_selector_field_path_const(
-                               fc);
+               const bt_field_path *sel_field_path = NULL;
+
+               if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR ||
+                               fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
+                       sel_field_path =
+                               bt_field_class_variant_with_selector_borrow_selector_field_path_const(
+                                       fc);
+                       BT_ASSERT(sel_field_path);
+               }
 
                g_string_append(ctx->str, " (");
                write_uint_prop_value(ctx, option_count);
-               g_string_append_printf(ctx->str, " option%s",
+               g_string_append_printf(ctx->str, " option%s",
                        plural(option_count));
 
                if (sel_field_path) {
-                       g_string_append(ctx->str, "Selector field path ");
+                       g_string_append(ctx->str, "Selector field path ");
                        write_field_path(ctx, sel_field_path);
                }
 
                g_string_append_c(ctx->str, ')');
+               break;
+       }
+       default:
+               break;
+       }
 
-               if (option_count > 0) {
-                       g_string_append_c(ctx->str, ':');
-                       incr_indent(ctx);
+       incr_indent(ctx);
+       user_attrs = bt_field_class_borrow_user_attributes_const(fc);
+       if (!bt_value_map_is_empty(user_attrs)) {
+               g_string_append(ctx->str, ":\n");
+               write_user_attributes(ctx, user_attrs, false, NULL);
+               wrote_user_attrs = true;
+       }
 
-                       for (i = 0; i < option_count; i++) {
-                               const bt_field_class_variant_option *option =
-                                       bt_field_class_variant_borrow_option_by_index_const(
+       /* Write field class's complex properties */
+       switch (fc_type) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+       {
+               uint64_t mapping_count =
+                       bt_field_class_enumeration_get_mapping_count(fc);
+
+               if (mapping_count > 0) {
+                       if (wrote_user_attrs) {
+                               write_nl(ctx);
+                               write_indent(ctx);
+                               write_prop_name(ctx, "Mappings");
+                               g_string_append_c(ctx->str, ':');
+                               incr_indent(ctx);
+                       } else {
+                               /* Each mapping starts with its own newline */
+                               g_string_append_c(ctx->str, ':');
+                       }
+
+                       write_enum_field_class_mappings(ctx, fc);
+
+                       if (wrote_user_attrs) {
+                               decr_indent(ctx);
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       {
+               uint64_t member_count =
+                       bt_field_class_structure_get_member_count(fc);
+
+               if (member_count > 0) {
+                       if (wrote_user_attrs) {
+                               write_nl(ctx);
+                               write_indent(ctx);
+                               write_prop_name(ctx, "Members");
+                               g_string_append_c(ctx->str, ':');
+                               incr_indent(ctx);
+                       } else {
+                               /* Each member starts with its own newline */
+                               g_string_append_c(ctx->str, ':');
+                       }
+
+                       for (i = 0; i < member_count; i++) {
+                               const bt_field_class_structure_member *member =
+                                       bt_field_class_structure_borrow_member_by_index_const(
                                                fc, i);
+                               const bt_value *user_attrs;
+                               const bt_field_class *member_fc =
+                                       bt_field_class_structure_member_borrow_field_class_const(member);
 
                                write_nl(ctx);
-                               write_field_class(ctx,
-                                       bt_field_class_variant_option_borrow_field_class_const(option),
-                                       bt_field_class_variant_option_get_name(option));
+                               write_compound_member_name(ctx,
+                                       bt_field_class_structure_member_get_name(member));
+                               user_attrs = bt_field_class_structure_member_borrow_user_attributes_const(
+                                       member);
+
+                               if (bt_value_map_is_empty(user_attrs)) {
+                                       write_sp(ctx);
+                                       write_field_class(ctx, member_fc);
+                               } else {
+                                       write_nl(ctx);
+                                       incr_indent(ctx);
+
+                                       /* Field class */
+                                       write_prop_name_line(ctx, "Field class");
+                                       write_sp(ctx);
+                                       write_field_class(ctx, member_fc);
+                                       write_nl(ctx);
+
+                                       /* User attributes */
+                                       write_user_attributes(ctx, user_attrs,
+                                               false, NULL);
+
+                                       decr_indent(ctx);
+                               }
                        }
 
-                       decr_indent(ctx);
+                       if (wrote_user_attrs) {
+                               decr_indent(ctx);
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               if (wrote_user_attrs) {
+                       write_nl(ctx);
+               } else {
+                       g_string_append(ctx->str, ":\n");
+               }
+
+               write_prop_name_line(ctx, "Element");
+               write_sp(ctx);
+               write_field_class(ctx,
+                       bt_field_class_array_borrow_element_field_class_const(fc));
+               break;
+       case BT_FIELD_CLASS_TYPE_OPTION:
+               if (wrote_user_attrs) {
+                       write_nl(ctx);
+               } else {
+                       g_string_append(ctx->str, ":\n");
+               }
+
+               write_prop_name_line(ctx, "Content");
+               write_sp(ctx);
+               write_field_class(ctx,
+                       bt_field_class_option_borrow_field_class_const(fc));
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
+       {
+               uint64_t option_count =
+                       bt_field_class_variant_get_option_count(fc);
+
+               if (option_count > 0) {
+                       if (wrote_user_attrs) {
+                               write_nl(ctx);
+                               write_indent(ctx);
+                               write_prop_name(ctx, "Options");
+                               g_string_append_c(ctx->str, ':');
+                               incr_indent(ctx);
+                       } else {
+                               /* Each option starts with its own newline */
+                               g_string_append_c(ctx->str, ':');
+                       }
+
+                       for (i = 0; i < option_count; i++) {
+                               write_variant_field_class_option(ctx, fc, i);
+                       }
+
+                       if (wrote_user_attrs) {
+                               decr_indent(ctx);
+                       }
                }
 
                break;
@@ -838,6 +1220,8 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc,
        default:
                break;
        }
+
+       decr_indent(ctx);
 }
 
 static
@@ -849,7 +1233,7 @@ void write_root_field_class(struct details_write_ctx *ctx, const char *name,
        write_indent(ctx);
        write_prop_name(ctx, name);
        g_string_append(ctx->str, ": ");
-       write_field_class(ctx, fc, NULL);
+       write_field_class(ctx, fc);
        write_nl(ctx);
 }
 
@@ -877,6 +1261,10 @@ void write_event_class(struct details_write_ctx *ctx, const bt_event_class *ec)
        /* Write properties */
        incr_indent(ctx);
 
+       /* Write user attributes */
+       write_user_attributes(ctx,
+               bt_event_class_borrow_user_attributes_const(ec), true, NULL);
+
        /* Write log level */
        if (bt_event_class_get_log_level(ec, &log_level) ==
                        BT_PROPERTY_AVAILABILITY_AVAILABLE) {
@@ -969,6 +1357,8 @@ void write_clock_class_prop_lines(struct details_write_ctx *ctx,
                write_str_prop_line(ctx, "Name", str);
        }
 
+       write_user_attributes(ctx,
+               bt_clock_class_borrow_user_attributes_const(cc), true, NULL);
        str = bt_clock_class_get_description(cc);
        if (str) {
                write_str_prop_line(ctx, "Description", str);
@@ -1037,25 +1427,42 @@ void write_stream_class(struct details_write_ctx *ctx,
        /* Write properties */
        incr_indent(ctx);
 
+       /* Write user attributes */
+       write_user_attributes(ctx,
+               bt_stream_class_borrow_user_attributes_const(sc), true, NULL);
+
        /* Write configuration */
        write_bool_prop_line(ctx,
-               "Packets have beginning default clock snapshot",
-               bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
-       write_bool_prop_line(ctx,
-               "Packets have end default clock snapshot",
-               bt_stream_class_packets_have_end_default_clock_snapshot(sc));
+               "Supports packets", bt_stream_class_supports_packets(sc));
+
+       if (bt_stream_class_supports_packets(sc)) {
+               write_bool_prop_line(ctx,
+                       "Packets have beginning default clock snapshot",
+                       bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
+               write_bool_prop_line(ctx,
+                       "Packets have end default clock snapshot",
+                       bt_stream_class_packets_have_end_default_clock_snapshot(sc));
+       }
+
        write_bool_prop_line(ctx,
                "Supports discarded events",
                bt_stream_class_supports_discarded_events(sc));
-       write_bool_prop_line(ctx,
-               "Discarded events have default clock snapshots",
-               bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
+
+       if (bt_stream_class_supports_discarded_events(sc)) {
+               write_bool_prop_line(ctx,
+                       "Discarded events have default clock snapshots",
+                       bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
+       }
+
        write_bool_prop_line(ctx,
                "Supports discarded packets",
                bt_stream_class_supports_discarded_packets(sc));
-       write_bool_prop_line(ctx,
-               "Discarded packets have default clock snapshots",
-               bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
+
+       if (bt_stream_class_supports_discarded_packets(sc)) {
+               write_bool_prop_line(ctx,
+                       "Discarded packets have default clock snapshots",
+                       bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
+       }
 
        /* Write default clock class */
        if (bt_stream_class_borrow_default_clock_class_const(sc)) {
@@ -1078,139 +1485,49 @@ void write_stream_class(struct details_write_ctx *ctx,
        if (fc) {
                write_root_field_class(ctx, "Event common context field class",
                        fc);
-       }
-
-       for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
-               g_ptr_array_add(event_classes,
-                       (gpointer) bt_stream_class_borrow_event_class_by_index_const(
-                               sc, i));
-       }
-
-       g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
-
-       for (i = 0; i < event_classes->len; i++) {
-               write_event_class(ctx, event_classes->pdata[i]);
-       }
-
-       decr_indent(ctx);
-       g_ptr_array_free(event_classes, TRUE);
-}
-
-static
-gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
-{
-       uint64_t id_a = bt_stream_class_get_id(*a);
-       uint64_t id_b = bt_stream_class_get_id(*b);
-
-       if (id_a < id_b) {
-               return -1;
-       } else if (id_a > id_b) {
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static
-gint compare_strings(const char **a, const char **b)
-{
-       return strcmp(*a, *b);
-}
-
-static
-void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
-{
-       GPtrArray *stream_classes = g_ptr_array_new();
-       GPtrArray *env_names = g_ptr_array_new();
-       uint64_t env_count;
-       uint64_t i;
-       bool printed_prop = false;
-
-       write_indent(ctx);
-       write_obj_type_name(ctx, "Trace class");
-
-       /* Write name */
-       if (ctx->details_comp->cfg.with_trace_class_name) {
-               const char *name = bt_trace_class_get_name(tc);
-
-               if (name) {
-                       g_string_append(ctx->str, " `");
-                       write_str_prop_value(ctx, name);
-                       g_string_append(ctx->str, "`");
-               }
-       }
-
-       /* Write properties */
-       incr_indent(ctx);
-
-       if (ctx->details_comp->cfg.with_uuid) {
-               bt_uuid uuid = bt_trace_class_get_uuid(tc);
-
-               if (uuid) {
-                       if (!printed_prop) {
-                               g_string_append(ctx->str, ":\n");
-                               printed_prop = true;
-                       }
-
-                       write_uuid_prop_line(ctx, "UUID", uuid);
-               }
-       }
-
-       /* Write environment */
-       env_count = bt_trace_class_get_environment_entry_count(tc);
-       if (env_count > 0) {
-               if (!printed_prop) {
-                       g_string_append(ctx->str, ":\n");
-                       printed_prop = true;
-               }
-
-               write_indent(ctx);
-               write_prop_name(ctx, "Environment");
-               g_string_append(ctx->str, " (");
-               write_uint_prop_value(ctx, env_count);
-               g_string_append_printf(ctx->str, " entr%s):",
-                       env_count == 1 ? "y" : "ies");
-               write_nl(ctx);
-               incr_indent(ctx);
+       }
 
-               for (i = 0; i < env_count; i++) {
-                       const char *name;
-                       const bt_value *value;
+       for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
+               g_ptr_array_add(event_classes,
+                       (gpointer) bt_stream_class_borrow_event_class_by_index_const(
+                               sc, i));
+       }
 
-                       bt_trace_class_borrow_environment_entry_by_index_const(
-                               tc, i, &name, &value);
-                       g_ptr_array_add(env_names, (gpointer) name);
-               }
+       g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
 
-               g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
+       for (i = 0; i < event_classes->len; i++) {
+               write_event_class(ctx, event_classes->pdata[i]);
+       }
 
-               for (i = 0; i < env_names->len; i++) {
-                       const char *name = env_names->pdata[i];
-                       const bt_value *value =
-                               bt_trace_class_borrow_environment_entry_value_by_name_const(
-                                       tc, name);
+       decr_indent(ctx);
+       g_ptr_array_free(event_classes, TRUE);
+}
 
-                       BT_ASSERT(value);
-                       write_compound_member_name(ctx, name);
-                       write_sp(ctx);
+static
+gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
+{
+       uint64_t id_a = bt_stream_class_get_id(*a);
+       uint64_t id_b = bt_stream_class_get_id(*b);
 
-                       if (bt_value_get_type(value) ==
-                                       BT_VALUE_TYPE_SIGNED_INTEGER) {
-                               write_int_prop_value(ctx,
-                                       bt_value_signed_integer_get(value));
-                       } else if (bt_value_get_type(value) ==
-                                       BT_VALUE_TYPE_STRING) {
-                               write_str_prop_value(ctx,
-                                       bt_value_string_get(value));
-                       } else {
-                               abort();
-                       }
+       if (id_a < id_b) {
+               return -1;
+       } else if (id_a > id_b) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
 
-                       write_nl(ctx);
-               }
+static
+void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
+{
+       GPtrArray *stream_classes = g_ptr_array_new();
+       uint64_t i;
+       bool printed_prop = false;
+
+       write_indent(ctx);
+       write_obj_type_name(ctx, "Trace class");
 
-               decr_indent(ctx);
-       }
 
        for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
                g_ptr_array_add(stream_classes,
@@ -1227,18 +1544,24 @@ void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
                }
        }
 
+       incr_indent(ctx);
+
+       /* Write user attributes */
+       write_user_attributes(ctx,
+               bt_trace_class_borrow_user_attributes_const(tc), true,
+               &printed_prop);
+
+       /* Write stream classes */
        for (i = 0; i < stream_classes->len; i++) {
                write_stream_class(ctx, stream_classes->pdata[i]);
        }
 
-       decr_indent(ctx);
-
        if (!printed_prop) {
                write_nl(ctx);
        }
 
+       decr_indent(ctx);
        g_ptr_array_free(stream_classes, TRUE);
-       g_ptr_array_free(env_names, TRUE);
 }
 
 static
@@ -1268,7 +1591,6 @@ int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
                 * rewrite `sc`.
                 */
                write_trace_class(ctx, tc);
-               write_nl(ctx);
 
                /*
                 * Mark this trace class as written, as well as all
@@ -1320,7 +1642,6 @@ int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
                 * classes, so we don't need to rewrite `ec`.
                 */
                write_stream_class(ctx, sc);
-               write_nl(ctx);
 
                /*
                 * Mark this stream class as written, as well as all its
@@ -1353,7 +1674,6 @@ int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
                }
 
                write_event_class(ctx, ec);
-               write_nl(ctx);
                details_did_write_meta_object(ctx, tc, ec);
                goto end;
        }
@@ -1385,7 +1705,7 @@ end:
 static
 void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
 {
-       bt_clock_snapshot_status status;
+       bt_clock_snapshot_get_ns_from_origin_status cs_status;
        int64_t ns_from_origin;
        char buf[32];
 
@@ -1398,8 +1718,8 @@ void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
                color_bold(ctx), color_fg_blue(ctx), buf,
                color_reset(ctx),
                ctx->details_comp->cfg.compact ? "" : " cycles");
-       status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
-       if (status == BT_CLOCK_SNAPSHOT_STATUS_OK) {
+       cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
+       if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
                format_int(buf, ns_from_origin, 10);
                g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
                        ctx->details_comp->cfg.compact ? "" : ",",
@@ -1474,6 +1794,16 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
 
        /* Write field's value */
        switch (fc_type) {
+       case BT_FIELD_CLASS_TYPE_BOOL:
+               write_sp(ctx);
+               write_bool_prop_value(ctx, bt_field_bool_get_value(field));
+               break;
+       case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
+               format_uint(buf, bt_field_bit_array_get_value_as_integer(field),
+                       16);
+               write_sp(ctx);
+               write_uint_str_prop_value(ctx, buf);
+               break;
        case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
        case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
        case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
@@ -1505,13 +1835,13 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
                if (fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
                                fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
                        format_uint(buf,
-                               bt_field_unsigned_integer_get_value(field),
+                               bt_field_integer_unsigned_get_value(field),
                                fmt_base);
                        write_sp(ctx);
                        write_uint_str_prop_value(ctx, buf);
                } else {
                        format_int(buf,
-                               bt_field_signed_integer_get_value(field),
+                               bt_field_integer_signed_get_value(field),
                                fmt_base);
                        write_sp(ctx);
                        write_int_str_prop_value(ctx, buf);
@@ -1519,9 +1849,13 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
 
                break;
        }
-       case BT_FIELD_CLASS_TYPE_REAL:
+       case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
+               write_sp(ctx);
+               write_float_prop_value(ctx, bt_field_real_single_precision_get_value(field));
+               break;
+       case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
                write_sp(ctx);
-               write_float_prop_value(ctx, bt_field_real_get_value(field));
+               write_float_prop_value(ctx, bt_field_real_double_precision_get_value(field));
                break;
        case BT_FIELD_CLASS_TYPE_STRING:
                write_sp(ctx);
@@ -1552,7 +1886,8 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
 
                        decr_indent(ctx);
                } else {
-                       g_string_append(ctx->str, " Empty");
+                       write_sp(ctx);
+                       write_none_prop_value(ctx, "Empty");
                }
 
                break;
@@ -1563,7 +1898,8 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
                uint64_t length = bt_field_array_get_length(field);
 
                if (length == 0) {
-                       g_string_append(ctx->str, " Empty");
+                       write_sp(ctx);
+                       write_none_prop_value(ctx, "Empty");
                } else {
                        g_string_append(ctx->str, " Length ");
                        write_uint_prop_value(ctx, length);
@@ -1578,14 +1914,30 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field,
                                        field, i);
 
                        write_nl(ctx);
-                       write_array_index(ctx, i);
+                       write_array_index(ctx, i, color_fg_cyan(ctx));
                        write_field(ctx, elem_field, NULL);
                }
 
                decr_indent(ctx);
                break;
        }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
+       case BT_FIELD_CLASS_TYPE_OPTION:
+       {
+               const bt_field *content_field =
+                       bt_field_option_borrow_field_const(field);
+
+               if (!content_field) {
+                       write_sp(ctx);
+                       write_none_prop_value(ctx, "None");
+               } else {
+                       write_field(ctx, content_field, NULL);
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
+       case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
                write_field(ctx,
                        bt_field_variant_borrow_selected_option_field_const(
                                field), NULL);
@@ -1626,6 +1978,18 @@ int write_event_message(struct details_write_ctx *ctx,
                goto end;
        }
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
+       if (ctx->str->len > 0) {
+               /*
+                * Output buffer contains metadata: separate blocks with
+                * newline.
+                */
+               write_nl(ctx);
+       }
+
        /* Write time */
        if (bt_stream_class_borrow_default_clock_class_const(sc)) {
                write_time(ctx,
@@ -1682,7 +2046,6 @@ int write_event_message(struct details_write_ctx *ctx,
        decr_indent(ctx);
 
 end:
-
        return ret;
 }
 
@@ -1716,10 +2079,11 @@ static
 void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
 {
        const char *name;
-       const bt_trace_class *tc = bt_trace_borrow_class_const(trace);
        GPtrArray *streams = g_ptr_array_new();
        uint64_t i;
        bool printed_prop = false;
+       GPtrArray *env_names = g_ptr_array_new();
+       uint64_t env_count;
 
        write_indent(ctx);
        write_obj_type_name(ctx, "Trace");
@@ -1737,29 +2101,74 @@ void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
        /* Write properties */
        incr_indent(ctx);
 
-       if (ctx->details_comp->cfg.with_trace_class_name) {
-               name = bt_trace_class_get_name(tc);
-               if (name) {
+       /* Write UUID */
+       if (ctx->details_comp->cfg.with_uuid) {
+               bt_uuid uuid = bt_trace_get_uuid(trace);
+
+               if (uuid) {
                        if (!printed_prop) {
                                g_string_append(ctx->str, ":\n");
                                printed_prop = true;
                        }
 
-                       write_str_prop_line(ctx, "Class name", name);
+                       write_uuid_prop_line(ctx, "UUID", uuid);
                }
        }
 
-       if (ctx->details_comp->cfg.with_uuid) {
-               bt_uuid uuid = bt_trace_class_get_uuid(tc);
+       /* Write environment */
+       env_count = bt_trace_get_environment_entry_count(trace);
+       if (env_count > 0) {
+               if (!printed_prop) {
+                       g_string_append(ctx->str, ":\n");
+                       printed_prop = true;
+               }
 
-               if (uuid) {
-                       if (!printed_prop) {
-                               g_string_append(ctx->str, ":\n");
-                               printed_prop = true;
+               write_indent(ctx);
+               write_prop_name(ctx, "Environment");
+               g_string_append(ctx->str, " (");
+               write_uint_prop_value(ctx, env_count);
+               g_string_append_printf(ctx->str, " entr%s):",
+                       env_count == 1 ? "y" : "ies");
+               write_nl(ctx);
+               incr_indent(ctx);
+
+               for (i = 0; i < env_count; i++) {
+                       const char *name;
+                       const bt_value *value;
+
+                       bt_trace_borrow_environment_entry_by_index_const(
+                               trace, i, &name, &value);
+                       g_ptr_array_add(env_names, (gpointer) name);
+               }
+
+               g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
+
+               for (i = 0; i < env_names->len; i++) {
+                       const char *name = env_names->pdata[i];
+                       const bt_value *value =
+                               bt_trace_borrow_environment_entry_value_by_name_const(
+                                       trace, name);
+
+                       BT_ASSERT(value);
+                       write_compound_member_name(ctx, name);
+                       write_sp(ctx);
+
+                       if (bt_value_get_type(value) ==
+                                       BT_VALUE_TYPE_SIGNED_INTEGER) {
+                               write_int_prop_value(ctx,
+                                       bt_value_integer_signed_get(value));
+                       } else if (bt_value_get_type(value) ==
+                                       BT_VALUE_TYPE_STRING) {
+                               write_str_prop_value(ctx,
+                                       bt_value_string_get(value));
+                       } else {
+                               abort();
                        }
 
-                       write_uuid_prop_line(ctx, "Class UUID", uuid);
+                       write_nl(ctx);
                }
+
+               decr_indent(ctx);
        }
 
        for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
@@ -1796,6 +2205,7 @@ void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
        }
 
        g_ptr_array_free(streams, TRUE);
+       g_ptr_array_free(env_names, TRUE);
 }
 
 static
@@ -1807,6 +2217,7 @@ int write_stream_beginning_message(struct details_write_ctx *ctx,
                bt_message_stream_beginning_borrow_stream_const(msg);
        const bt_trace *trace = bt_stream_borrow_trace_const(stream);
        const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
+       const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
        const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
        const char *name;
 
@@ -1815,6 +2226,31 @@ int write_stream_beginning_message(struct details_write_ctx *ctx,
                goto end;
        }
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
+       if (ctx->str->len > 0) {
+               /*
+                * Output buffer contains metadata: separate blocks with
+                * newline.
+                */
+               write_nl(ctx);
+       }
+
+       /* Write time */
+       if (cc) {
+               const bt_clock_snapshot *cs;
+               bt_message_stream_clock_snapshot_state cs_state =
+                       bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
+
+               if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       write_time(ctx, cs);
+               } else {
+                       write_time_str(ctx, "Unknown");
+               }
+       }
+
        /* Write follow tag for message */
        ret = write_message_follow_tag(ctx, stream);
        if (ret) {
@@ -1860,87 +2296,26 @@ int write_stream_end_message(struct details_write_ctx *ctx,
        int ret = 0;
        const bt_stream *stream =
                bt_message_stream_end_borrow_stream_const(msg);
+       const bt_stream_class *sc =
+               bt_stream_borrow_class_const(stream);
+       const bt_clock_class *cc =
+               bt_stream_class_borrow_default_clock_class_const(sc);
 
-       /* Write follow tag for message */
-       ret = write_message_follow_tag(ctx, stream);
-       if (ret) {
+       if (!ctx->details_comp->cfg.with_data) {
                goto end;
        }
 
-       /* Write stream properties */
-       write_obj_type_name(ctx, "Stream end\n");
-
-end:
-       return ret;
-}
-
-static
-int write_stream_activity_beginning_message(struct details_write_ctx *ctx,
-               const bt_message *msg)
-{
-       int ret = 0;
-       const bt_stream *stream =
-               bt_message_stream_activity_beginning_borrow_stream_const(msg);
-       bt_message_stream_activity_clock_snapshot_state cs_state;
-       const bt_clock_snapshot *cs = NULL;
-
        /* Write time */
-       cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-               msg, &cs);
-       switch (cs_state) {
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-               BT_ASSERT(cs);
-               write_time(ctx, cs);
-               break;
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-               write_time_str(ctx, "Unknown");
-               break;
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-               write_time_str(ctx, "-Infinity");
-               break;
-       default:
-               abort();
-       }
-
-       /* Write follow tag for message */
-       ret = write_message_follow_tag(ctx, stream);
-       if (ret) {
-               goto end;
-       }
-
-       write_obj_type_name(ctx, "Stream activity beginning");
-       write_nl(ctx);
-
-end:
-       return ret;
-}
-
-static
-int write_stream_activity_end_message(struct details_write_ctx *ctx,
-               const bt_message *msg)
-{
-       int ret = 0;
-       const bt_stream *stream =
-               bt_message_stream_activity_end_borrow_stream_const(msg);
-       bt_message_stream_activity_clock_snapshot_state cs_state;
-       const bt_clock_snapshot *cs = NULL;
+       if (cc) {
+               const bt_clock_snapshot *cs;
+               bt_message_stream_clock_snapshot_state cs_state =
+                       bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
 
-       /* Write time */
-       cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-               msg, &cs);
-       switch (cs_state) {
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-               BT_ASSERT(cs);
-               write_time(ctx, cs);
-               break;
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-               write_time_str(ctx, "Unknown");
-               break;
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-               write_time_str(ctx, "+Infinity");
-               break;
-       default:
-               abort();
+               if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       write_time(ctx, cs);
+               } else {
+                       write_time_str(ctx, "Unknown");
+               }
        }
 
        /* Write follow tag for message */
@@ -1949,8 +2324,8 @@ int write_stream_activity_end_message(struct details_write_ctx *ctx,
                goto end;
        }
 
-       write_obj_type_name(ctx, "Stream activity end");
-       write_nl(ctx);
+       /* Write stream properties */
+       write_obj_type_name(ctx, "Stream end\n");
 
 end:
        return ret;
@@ -1967,6 +2342,10 @@ int write_packet_beginning_message(struct details_write_ctx *ctx,
        const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
        const bt_field *field;
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
        /* Write time */
        if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
                write_time(ctx,
@@ -1988,15 +2367,16 @@ int write_packet_beginning_message(struct details_write_ctx *ctx,
        }
 
        /* Write field */
-       g_string_append(ctx->str, ":\n");
-       incr_indent(ctx);
        field = bt_packet_borrow_context_field_const(packet);
        if (field) {
+               g_string_append(ctx->str, ":\n");
+               incr_indent(ctx);
                write_root_field(ctx, "Context", field);
+               decr_indent(ctx);
+       } else {
+               write_nl(ctx);
        }
 
-       decr_indent(ctx);
-
 end:
        return ret;
 }
@@ -2043,6 +2423,7 @@ static
 int write_discarded_events_message(struct details_write_ctx *ctx,
                const bt_message *msg)
 {
+       int ret = 0;
        const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
                msg);
        const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
@@ -2050,6 +2431,10 @@ int write_discarded_events_message(struct details_write_ctx *ctx,
        const bt_clock_snapshot *end_cs = NULL;
        uint64_t count;
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
        if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
                beginning_cs =
                        bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
@@ -2064,14 +2449,18 @@ int write_discarded_events_message(struct details_write_ctx *ctx,
                count = UINT64_C(-1);
        }
 
-       return write_discarded_items_message(ctx, "events", stream,
+       ret = write_discarded_items_message(ctx, "events", stream,
                beginning_cs, end_cs, count);
+
+end:
+       return ret;
 }
 
 static
 int write_discarded_packets_message(struct details_write_ctx *ctx,
                const bt_message *msg)
 {
+       int ret = 0;
        const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
                msg);
        const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
@@ -2079,6 +2468,10 @@ int write_discarded_packets_message(struct details_write_ctx *ctx,
        const bt_clock_snapshot *end_cs = NULL;
        uint64_t count;
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
        if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
                beginning_cs =
                        bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
@@ -2093,8 +2486,11 @@ int write_discarded_packets_message(struct details_write_ctx *ctx,
                count = UINT64_C(-1);
        }
 
-       return write_discarded_items_message(ctx, "packets", stream,
+       ret = write_discarded_items_message(ctx, "packets", stream,
                beginning_cs, end_cs, count);
+
+end:
+       return ret;
 }
 
 static
@@ -2107,6 +2503,10 @@ int write_packet_end_message(struct details_write_ctx *ctx,
        const bt_stream *stream = bt_packet_borrow_stream_const(packet);
        const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
 
+       if (!ctx->details_comp->cfg.with_data) {
+               goto end;
+       }
+
        /* Write time */
        if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
                write_time(ctx,
@@ -2175,10 +2575,6 @@ int details_write_message(struct details_comp *details_comp,
        /* Reset output buffer */
        g_string_assign(details_comp->str, "");
 
-       if (details_comp->printed_something && !details_comp->cfg.compact) {
-               write_nl(&ctx);
-       }
-
        switch (bt_message_get_type(msg)) {
        case BT_MESSAGE_TYPE_EVENT:
                ret = write_event_message(&ctx, msg);
@@ -2198,12 +2594,6 @@ int details_write_message(struct details_comp *details_comp,
        case BT_MESSAGE_TYPE_PACKET_END:
                ret = write_packet_end_message(&ctx, msg);
                break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               ret = write_stream_activity_beginning_message(&ctx, msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               ret = write_stream_activity_end_message(&ctx, msg);
-               break;
        case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
                ret = write_discarded_events_message(&ctx, msg);
                break;
@@ -2214,5 +2604,17 @@ int details_write_message(struct details_comp *details_comp,
                abort();
        }
 
+       /*
+        * If this component printed at least one character so far, and
+        * we're not in compact mode, and there's something in the
+        * output buffer for this message, then prepend a newline to the
+        * output buffer to visually separate message blocks.
+        */
+       if (details_comp->printed_something && !details_comp->cfg.compact &&
+                       details_comp->str->len > 0) {
+               /* TODO: Optimize this */
+               g_string_prepend_c(details_comp->str, '\n');
+       }
+
        return ret;
 }
This page took 0.044222 seconds and 4 git commands to generate.