+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_DBG(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_DBG(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_DBG(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_DBG(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;
+ }
+ }
+}
+