lib: make bt_value_map_foreach_entry_{const_}func() return a status code
[babeltrace.git] / src / plugins / text / details / write.c
CommitLineData
55478183
PP
1/*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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
20 * SOFTWARE.
21 */
22
55478183 23#include <babeltrace2/babeltrace.h>
c4f23e30 24#include <stdbool.h>
350ad6c1
PP
25#include <stdio.h>
26#include <string.h>
55478183
PP
27
28#include "common/assert.h"
29#include "common/common.h"
6162e6b7 30#include "common/uuid.h"
55478183
PP
31#include "details.h"
32#include "write.h"
33#include "obj-lifetime-mgmt.h"
34#include "colors.h"
35
36static inline
37const char *plural(uint64_t value)
38{
39 return value == 1 ? "" : "s";
40}
41
42static inline
43void incr_indent_by(struct details_write_ctx *ctx, unsigned int value)
44{
98b15851 45 BT_ASSERT_DBG(ctx);
55478183
PP
46 ctx->indent_level += value;
47}
48
49static inline
50void incr_indent(struct details_write_ctx *ctx)
51{
52 incr_indent_by(ctx, 2);
53}
54
55static inline
56void decr_indent_by(struct details_write_ctx *ctx, unsigned int value)
57{
98b15851
PP
58 BT_ASSERT_DBG(ctx);
59 BT_ASSERT_DBG(ctx->indent_level >= value);
55478183
PP
60 ctx->indent_level -= value;
61}
62
63static inline
64void decr_indent(struct details_write_ctx *ctx)
65{
66 decr_indent_by(ctx, 2);
67}
68
69static inline
70void format_uint(char *buf, uint64_t value, unsigned int base)
71{
72 const char *spec = "%" PRIu64;
73 char *buf_start = buf;
74 unsigned int digits_per_group = 3;
75 char sep = ',';
76 bool sep_digits = true;
77
78 switch (base) {
79 case 2:
80 case 16:
81 /* TODO: Support binary format */
82 spec = "%" PRIx64;
83 strcpy(buf, "0x");
84 buf_start = buf + 2;
85 digits_per_group = 4;
86 sep = ':';
87 break;
88 case 8:
89 spec = "%" PRIo64;
90 strcpy(buf, "0");
91 buf_start = buf + 1;
92 sep = ':';
93 break;
94 case 10:
95 if (value <= 9999) {
96 /*
97 * Do not insert digit separators for numbers
98 * under 10,000 as it looks weird.
99 */
100 sep_digits = false;
101 }
102
103 break;
104 default:
498e7994 105 bt_common_abort();
55478183
PP
106 }
107
108 sprintf(buf_start, spec, value);
109
110 if (sep_digits) {
111 bt_common_sep_digits(buf_start, digits_per_group, sep);
112 }
113}
114
115static inline
116void format_int(char *buf, int64_t value, unsigned int base)
117{
118 const char *spec = "%" PRIu64;
119 char *buf_start = buf;
120 unsigned int digits_per_group = 3;
121 char sep = ',';
122 bool sep_digits = true;
123 uint64_t abs_value = value < 0 ? (uint64_t) -value : (uint64_t) value;
124
125 if (value < 0) {
126 buf[0] = '-';
127 buf_start++;
128 }
129
130 switch (base) {
131 case 2:
132 case 16:
133 /* TODO: Support binary format */
134 spec = "%" PRIx64;
135 strcpy(buf_start, "0x");
136 buf_start += 2;
137 digits_per_group = 4;
138 sep = ':';
139 break;
140 case 8:
141 spec = "%" PRIo64;
142 strcpy(buf_start, "0");
143 buf_start++;
144 sep = ':';
145 break;
146 case 10:
147 if (value >= -9999 && value <= 9999) {
148 /*
149 * Do not insert digit separators for numbers
150 * over -10,000 and under 10,000 as it looks
151 * weird.
152 */
153 sep_digits = false;
154 }
155
156 break;
157 default:
498e7994 158 bt_common_abort();
55478183
PP
159 }
160
161 sprintf(buf_start, spec, abs_value);
162
163 if (sep_digits) {
164 bt_common_sep_digits(buf_start, digits_per_group, sep);
165 }
166}
167
168static inline
169void write_nl(struct details_write_ctx *ctx)
170{
98b15851 171 BT_ASSERT_DBG(ctx);
55478183
PP
172 g_string_append_c(ctx->str, '\n');
173}
174
175static inline
176void write_sp(struct details_write_ctx *ctx)
177{
98b15851 178 BT_ASSERT_DBG(ctx);
55478183
PP
179 g_string_append_c(ctx->str, ' ');
180}
181
182static inline
183void write_indent(struct details_write_ctx *ctx)
184{
185 uint64_t i;
186
98b15851 187 BT_ASSERT_DBG(ctx);
55478183
PP
188
189 for (i = 0; i < ctx->indent_level; i++) {
190 write_sp(ctx);
191 }
192}
193
194static inline
195void write_compound_member_name(struct details_write_ctx *ctx, const char *name)
196{
197 write_indent(ctx);
198 g_string_append_printf(ctx->str, "%s%s%s:",
199 color_fg_cyan(ctx), name, color_reset(ctx));
200}
201
202static inline
48be9a91
PP
203void write_array_index(struct details_write_ctx *ctx, uint64_t index,
204 const char *color)
55478183
PP
205{
206 char buf[32];
207
208 write_indent(ctx);
209 format_uint(buf, index, 10);
210 g_string_append_printf(ctx->str, "%s[%s]%s:",
48be9a91 211 color, buf, color_reset(ctx));
55478183
PP
212}
213
214static inline
215void write_obj_type_name(struct details_write_ctx *ctx, const char *name)
216{
217 g_string_append_printf(ctx->str, "%s%s%s%s",
04609487
PP
218 color_bold(ctx), color_fg_bright_yellow(ctx), name,
219 color_reset(ctx));
55478183
PP
220}
221
222static inline
223void write_prop_name(struct details_write_ctx *ctx, const char *prop_name)
224{
225 g_string_append_printf(ctx->str, "%s%s%s",
226 color_fg_magenta(ctx), prop_name, color_reset(ctx));
227}
228
48be9a91
PP
229static inline
230void write_prop_name_line(struct details_write_ctx *ctx, const char *prop_name)
231{
232 write_indent(ctx);
233 g_string_append_printf(ctx->str, "%s%s%s:",
234 color_fg_magenta(ctx), prop_name, color_reset(ctx));
235}
236
55478183
PP
237static inline
238void write_str_prop_value(struct details_write_ctx *ctx, const char *value)
239{
240 g_string_append_printf(ctx->str, "%s%s%s",
241 color_bold(ctx), value, color_reset(ctx));
242}
243
25510d56
PP
244static inline
245void write_none_prop_value(struct details_write_ctx *ctx, const char *value)
246{
247 g_string_append_printf(ctx->str, "%s%s%s%s",
04609487 248 color_bold(ctx), color_fg_bright_magenta(ctx),
25510d56
PP
249 value, color_reset(ctx));
250}
251
55478183
PP
252static inline
253void write_uint_str_prop_value(struct details_write_ctx *ctx, const char *value)
254{
255 write_str_prop_value(ctx, value);
256}
257
258static inline
259void write_uint_prop_value(struct details_write_ctx *ctx, uint64_t value)
260{
261 char buf[32];
262
263 format_uint(buf, value, 10);
264 write_uint_str_prop_value(ctx, buf);
265}
266
267static inline
268void write_int_prop_value(struct details_write_ctx *ctx, int64_t value)
269{
270 char buf[32];
271
272 format_int(buf, value, 10);
273 write_uint_str_prop_value(ctx, buf);
274}
275
276static inline
277void write_float_prop_value(struct details_write_ctx *ctx, double value)
278{
279 g_string_append_printf(ctx->str, "%s%f%s",
280 color_bold(ctx), value, color_reset(ctx));
281}
282
283static inline
284void write_str_prop_line(struct details_write_ctx *ctx, const char *prop_name,
285 const char *prop_value)
286{
98b15851 287 BT_ASSERT_DBG(prop_value);
55478183
PP
288 write_indent(ctx);
289 write_prop_name(ctx, prop_name);
290 g_string_append(ctx->str, ": ");
291 write_str_prop_value(ctx, prop_value);
292 write_nl(ctx);
293}
294
295static inline
296void write_uint_prop_line(struct details_write_ctx *ctx, const char *prop_name,
297 uint64_t prop_value)
298{
299 write_indent(ctx);
300 write_prop_name(ctx, prop_name);
301 g_string_append(ctx->str, ": ");
302 write_uint_prop_value(ctx, prop_value);
303 write_nl(ctx);
304}
305
306static inline
307void write_int_prop_line(struct details_write_ctx *ctx, const char *prop_name,
308 int64_t prop_value)
309{
310 write_indent(ctx);
311 write_prop_name(ctx, prop_name);
312 g_string_append(ctx->str, ": ");
313 write_int_prop_value(ctx, prop_value);
314 write_nl(ctx);
315}
316
317static inline
318void write_int_str_prop_value(struct details_write_ctx *ctx, const char *value)
319{
320 write_str_prop_value(ctx, value);
321}
322
323static inline
dacaa55d 324void write_bool_prop_value(struct details_write_ctx *ctx, bt_bool prop_value)
55478183
PP
325{
326 const char *str;
327
dacaa55d 328 g_string_append(ctx->str, color_bold(ctx));
55478183
PP
329
330 if (prop_value) {
04609487 331 g_string_append(ctx->str, color_fg_bright_green(ctx));
55478183
PP
332 str = "Yes";
333 } else {
04609487 334 g_string_append(ctx->str, color_fg_bright_red(ctx));
55478183
PP
335 str = "No";
336 }
337
dacaa55d
PP
338 g_string_append_printf(ctx->str, "%s%s", str, color_reset(ctx));
339}
340
341static inline
342void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
343 bt_bool prop_value)
344{
345 write_indent(ctx);
346 write_prop_name(ctx, prop_name);
347 g_string_append(ctx->str, ": ");
348 write_bool_prop_value(ctx, prop_value);
349 write_nl(ctx);
55478183
PP
350}
351
352static inline
353void write_uuid_prop_line(struct details_write_ctx *ctx, const char *prop_name,
354 bt_uuid uuid)
355{
98b15851 356 BT_ASSERT_DBG(uuid);
55478183
PP
357 write_indent(ctx);
358 write_prop_name(ctx, prop_name);
359 g_string_append_printf(ctx->str,
6162e6b7 360 ": %s" BT_UUID_FMT "%s\n",
55478183 361 color_bold(ctx),
6162e6b7 362 BT_UUID_FMT_VALUES(uuid),
55478183
PP
363 color_reset(ctx));
364}
365
48be9a91
PP
366static
367gint compare_strings(const char **a, const char **b)
368{
369 return strcmp(*a, *b);
370}
371
372static
27c61ce8
PP
373bt_value_map_foreach_entry_const_func_status map_value_foreach_add_key_to_array(
374 const char *key, const bt_value *object, void *data)
48be9a91
PP
375{
376 GPtrArray *keys = data;
377
98b15851 378 BT_ASSERT_DBG(keys);
48be9a91 379 g_ptr_array_add(keys, (void *) key);
27c61ce8 380 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
48be9a91
PP
381}
382
383static
384void write_value(struct details_write_ctx *ctx, const bt_value *value,
385 const char *name)
386{
387 uint64_t i;
388 bt_value_type value_type = bt_value_get_type(value);
389 GPtrArray *keys = g_ptr_array_new();
390 char buf[64];
391
98b15851 392 BT_ASSERT_DBG(keys);
48be9a91
PP
393
394 /* Write field's name */
395 if (name) {
396 write_prop_name_line(ctx, name);
397 }
398
399 /* Write field's value */
400 switch (value_type) {
401 case BT_VALUE_TYPE_NULL:
402 write_sp(ctx);
403 write_none_prop_value(ctx, "Null");
404 break;
405 case BT_VALUE_TYPE_BOOL:
406 write_sp(ctx);
407 write_bool_prop_value(ctx, bt_value_bool_get(value));
408 break;
409 case BT_VALUE_TYPE_UNSIGNED_INTEGER:
410 format_uint(buf, bt_value_integer_unsigned_get(value), 10);
411 write_sp(ctx);
412 write_uint_str_prop_value(ctx, buf);
413 break;
414 case BT_VALUE_TYPE_SIGNED_INTEGER:
415 format_int(buf, bt_value_integer_signed_get(value), 10);
416 write_sp(ctx);
417 write_int_str_prop_value(ctx, buf);
418 break;
419 case BT_VALUE_TYPE_REAL:
420 write_sp(ctx);
421 write_float_prop_value(ctx, bt_value_real_get(value));
422 break;
423 case BT_VALUE_TYPE_STRING:
424 write_sp(ctx);
425 write_str_prop_value(ctx, bt_value_string_get(value));
426 break;
427 case BT_VALUE_TYPE_ARRAY:
428 {
393729a6 429 uint64_t length = bt_value_array_get_length(value);
48be9a91
PP
430
431 if (length == 0) {
432 write_sp(ctx);
433 write_none_prop_value(ctx, "Empty");
434 } else {
435 g_string_append(ctx->str, " Length ");
436 write_uint_prop_value(ctx, length);
437 g_string_append_c(ctx->str, ':');
438 }
439
440 incr_indent(ctx);
441
442 for (i = 0; i < length; i++) {
443 const bt_value *elem_value =
444 bt_value_array_borrow_element_by_index_const(
445 value, i);
446
447 write_nl(ctx);
448 write_array_index(ctx, i, color_fg_magenta(ctx));
449 write_value(ctx, elem_value, NULL);
450 }
451
452 decr_indent(ctx);
453 break;
454 }
455 case BT_VALUE_TYPE_MAP:
456 {
457 bt_value_map_foreach_entry_const_status foreach_status =
458 bt_value_map_foreach_entry_const(value,
459 map_value_foreach_add_key_to_array, keys);
460
98b15851 461 BT_ASSERT_DBG(foreach_status ==
48be9a91
PP
462 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK);
463 g_ptr_array_sort(keys, (GCompareFunc) compare_strings);
464
465 if (keys->len > 0) {
466 incr_indent(ctx);
467
468 for (i = 0; i < keys->len; i++) {
469 const char *key = keys->pdata[i];
470 const bt_value *entry_value =
471 bt_value_map_borrow_entry_value_const(
472 value, key);
473
474 write_nl(ctx);
475 write_value(ctx, entry_value, key);
476 }
477
478 decr_indent(ctx);
479 } else {
480 write_sp(ctx);
481 write_none_prop_value(ctx, "Empty");
482 }
483
484 break;
485 }
486 default:
498e7994 487 bt_common_abort();
48be9a91
PP
488 }
489
490 g_ptr_array_free(keys, TRUE);
491}
492
493static
494void write_user_attributes(struct details_write_ctx *ctx,
495 const bt_value *user_attrs, bool write_newline, bool *written)
496{
98b15851 497 BT_ASSERT_DBG(user_attrs);
48be9a91
PP
498
499 if (!bt_value_map_is_empty(user_attrs)) {
500 write_value(ctx, user_attrs, "User attributes");
501
502 if (write_newline) {
503 write_nl(ctx);
504 }
505
506 if (written) {
507 *written = true;
508 }
509 }
510}
511
55478183
PP
512static
513void write_int_field_class_props(struct details_write_ctx *ctx,
514 const bt_field_class *fc, bool close)
515{
516 g_string_append_printf(ctx->str, "(%s%" PRIu64 "-bit%s, Base ",
517 color_bold(ctx),
518 bt_field_class_integer_get_field_value_range(fc),
519 color_reset(ctx));
520
521 switch (bt_field_class_integer_get_preferred_display_base(fc)) {
522 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
523 write_uint_prop_value(ctx, 2);
524 break;
525 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
526 write_uint_prop_value(ctx, 8);
527 break;
528 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
529 write_uint_prop_value(ctx, 10);
530 break;
531 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
532 write_uint_prop_value(ctx, 16);
533 break;
534 default:
498e7994 535 bt_common_abort();
55478183
PP
536 }
537
538 if (close) {
539 g_string_append(ctx->str, ")");
540 }
541}
542
45c51519 543struct int_range {
55478183
PP
544 union {
545 uint64_t u;
546 int64_t i;
547 } lower;
548
549 union {
550 uint64_t u;
551 int64_t i;
552 } upper;
553};
554
555struct enum_field_class_mapping {
556 /* Weak */
557 const char *label;
558
45c51519 559 /* Array of `struct int_range` */
55478183
PP
560 GArray *ranges;
561};
562
563static
564gint compare_enum_field_class_mappings(struct enum_field_class_mapping **a,
565 struct enum_field_class_mapping **b)
566{
567 return strcmp((*a)->label, (*b)->label);
568}
569
570static
45c51519 571gint compare_int_ranges_signed(struct int_range *a, struct int_range *b)
55478183
PP
572{
573
574 if (a->lower.i < b->lower.i) {
575 return -1;
576 } else if (a->lower.i > b->lower.i) {
577 return 1;
578 } else {
579 if (a->upper.i < b->upper.i) {
580 return -1;
581 } else if (a->upper.i > b->upper.i) {
582 return 1;
583 } else {
584 return 0;
585 }
586 }
587}
588
589static
45c51519 590gint compare_int_ranges_unsigned(struct int_range *a, struct int_range *b)
55478183
PP
591{
592 if (a->lower.u < b->lower.u) {
593 return -1;
594 } else if (a->lower.u > b->lower.u) {
595 return 1;
596 } else {
597 if (a->upper.u < b->upper.u) {
598 return -1;
599 } else if (a->upper.u > b->upper.u) {
600 return 1;
601 } else {
602 return 0;
603 }
604 }
605}
606
45c51519
PP
607static
608GArray *range_set_to_int_ranges(const void *spec_range_set, bool is_signed)
609{
610 uint64_t i;
611 const bt_integer_range_set *range_set;
612 GArray *ranges = g_array_new(FALSE, TRUE, sizeof(struct int_range));
613
614 if (!ranges) {
615 goto end;
616 }
617
618 if (is_signed) {
619 range_set = bt_integer_range_set_signed_as_range_set_const(
620 spec_range_set);
621 } else {
622 range_set = bt_integer_range_set_unsigned_as_range_set_const(
623 spec_range_set);
624 }
625
626 for (i = 0; i < bt_integer_range_set_get_range_count(range_set); i++) {
627 struct int_range range;
628
629 if (is_signed) {
630 const bt_integer_range_signed *orig_range =
631 bt_integer_range_set_signed_borrow_range_by_index_const(
632 spec_range_set, i);
633
634 range.lower.i = bt_integer_range_signed_get_lower(orig_range);
635 range.upper.i = bt_integer_range_signed_get_upper(orig_range);
636 } else {
637 const bt_integer_range_unsigned *orig_range =
638 bt_integer_range_set_unsigned_borrow_range_by_index_const(
639 spec_range_set, i);
640
641 range.lower.u = bt_integer_range_unsigned_get_lower(orig_range);
642 range.upper.u = bt_integer_range_unsigned_get_upper(orig_range);
643 }
644
645 g_array_append_val(ranges, range);
646 }
647
648 if (is_signed) {
649 g_array_sort(ranges, (GCompareFunc) compare_int_ranges_signed);
650 } else {
651 g_array_sort(ranges,
652 (GCompareFunc) compare_int_ranges_unsigned);
653 }
654
655end:
656 return ranges;
657}
658
55478183
PP
659static
660void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping)
661{
662 if (mapping->ranges) {
663 g_array_free(mapping->ranges, TRUE);
664 mapping->ranges = NULL;
665 }
666
667 g_free(mapping);
668}
669
670static
45c51519
PP
671struct int_range *int_range_at(GArray *ranges, uint64_t index)
672{
673 return &g_array_index(ranges, struct int_range, index);
674}
675
676static
677void write_int_range(struct details_write_ctx *ctx,
678 struct int_range *range, bool is_signed)
55478183
PP
679{
680 g_string_append(ctx->str, "[");
681
682 if (is_signed) {
683 write_int_prop_value(ctx, range->lower.i);
684 } else {
685 write_int_prop_value(ctx, range->lower.u);
686 }
687
45c51519
PP
688 if (range->lower.u != range->upper.u) {
689 g_string_append(ctx->str, ", ");
55478183 690
45c51519
PP
691 if (is_signed) {
692 write_int_prop_value(ctx, range->upper.i);
693 } else {
694 write_int_prop_value(ctx, range->upper.u);
695 }
55478183
PP
696 }
697
698 g_string_append(ctx->str, "]");
699}
700
701static
702void write_enum_field_class_mappings(struct details_write_ctx *ctx,
703 const bt_field_class *fc)
704{
705 GPtrArray *mappings;
706 uint64_t i;
707 uint64_t range_i;
708 bool is_signed = bt_field_class_get_type(fc) ==
709 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION;
710
711 mappings = g_ptr_array_new_with_free_func(
712 (GDestroyNotify) destroy_enum_field_class_mapping);
98b15851 713 BT_ASSERT_DBG(mappings);
55478183
PP
714
715 /*
716 * Copy field class's mappings to our own arrays and structures
717 * to sort them.
718 */
719 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
720 const void *fc_mapping;
45c51519 721 const void *fc_range_set;
55478183
PP
722 struct enum_field_class_mapping *mapping = g_new0(
723 struct enum_field_class_mapping, 1);
724
98b15851 725 BT_ASSERT_DBG(mapping);
55478183
PP
726
727 if (is_signed) {
9c08c816 728 fc_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
55478183 729 fc, i);
9c08c816 730 fc_range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
45c51519 731 fc_mapping);
55478183 732 } else {
9c08c816 733 fc_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
55478183 734 fc, i);
9c08c816 735 fc_range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
45c51519 736 fc_mapping);
55478183
PP
737 }
738
739 mapping->label = bt_field_class_enumeration_mapping_get_label(
9c08c816 740 bt_field_class_enumeration_signed_mapping_as_mapping_const(
55478183 741 fc_mapping));
45c51519
PP
742 mapping->ranges = range_set_to_int_ranges(fc_range_set,
743 is_signed);
98b15851 744 BT_ASSERT_DBG(mapping->ranges);
55478183
PP
745 g_ptr_array_add(mappings, mapping);
746 }
747
45c51519 748 /* Sort mappings (ranges are already sorted within mappings) */
55478183
PP
749 g_ptr_array_sort(mappings,
750 (GCompareFunc) compare_enum_field_class_mappings);
751
55478183
PP
752 /* Write mappings */
753 for (i = 0; i < mappings->len; i++) {
754 struct enum_field_class_mapping *mapping = mappings->pdata[i];
755
756 write_nl(ctx);
48be9a91 757 write_prop_name_line(ctx, mapping->label);
55478183 758
55478183 759 for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
45c51519
PP
760 write_sp(ctx);
761 write_int_range(ctx,
762 int_range_at(mapping->ranges, range_i),
763 is_signed);
55478183 764 }
55478183
PP
765 }
766
767 g_ptr_array_free(mappings, TRUE);
768}
769
770static
771void write_field_path(struct details_write_ctx *ctx,
772 const bt_field_path *field_path)
773{
774 uint64_t i;
775
776 g_string_append_c(ctx->str, '[');
777
778 switch (bt_field_path_get_root_scope(field_path)) {
e7ceb9df 779 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
55478183
PP
780 write_str_prop_value(ctx, "Packet context");
781 break;
e7ceb9df 782 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
55478183
PP
783 write_str_prop_value(ctx, "Event common context");
784 break;
e7ceb9df 785 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
55478183
PP
786 write_str_prop_value(ctx, "Event specific context");
787 break;
e7ceb9df 788 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
55478183
PP
789 write_str_prop_value(ctx, "Event payload");
790 break;
791 default:
498e7994 792 bt_common_abort();
55478183
PP
793 }
794
795 g_string_append(ctx->str, ": ");
796
797 for (i = 0; i < bt_field_path_get_item_count(field_path); i++) {
798 const bt_field_path_item *fp_item =
799 bt_field_path_borrow_item_by_index_const(field_path, i);
800
801 if (i != 0) {
802 g_string_append(ctx->str, ", ");
803 }
804
805 switch (bt_field_path_item_get_type(fp_item)) {
806 case BT_FIELD_PATH_ITEM_TYPE_INDEX:
807 write_uint_prop_value(ctx,
808 bt_field_path_item_index_get_index(fp_item));
809 break;
810 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
811 write_str_prop_value(ctx, "<current>");
812 break;
813 default:
498e7994 814 bt_common_abort();
55478183
PP
815 }
816 }
817
818 g_string_append_c(ctx->str, ']');
819}
820
821static
45c51519
PP
822void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc);
823
824static
825void write_variant_field_class_option(struct details_write_ctx *ctx,
826 const bt_field_class *fc, uint64_t index)
55478183 827{
55478183 828 bt_field_class_type fc_type = bt_field_class_get_type(fc);
45c51519
PP
829 const bt_field_class_variant_option *option =
830 bt_field_class_variant_borrow_option_by_index_const(
831 fc, index);
48be9a91 832 const void *orig_ranges = NULL;
45c51519
PP
833 GArray *int_ranges = NULL;
834 bool is_signed;
48be9a91
PP
835 const bt_value *user_attrs =
836 bt_field_class_variant_option_borrow_user_attributes_const(
837 option);
838 const bt_field_class *option_fc =
839 bt_field_class_variant_option_borrow_field_class_const(option);
55478183 840
45c51519
PP
841 write_nl(ctx);
842 write_compound_member_name(ctx,
843 bt_field_class_variant_option_get_name(option));
844
de821fe5
PP
845 if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
846 const bt_field_class_variant_with_selector_field_integer_unsigned_option *spec_opt =
847 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
45c51519
PP
848 fc, index);
849
850 orig_ranges =
de821fe5 851 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
45c51519
PP
852 spec_opt);
853 is_signed = false;
de821fe5
PP
854 } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
855 const bt_field_class_variant_with_selector_field_integer_signed_option *spec_opt =
856 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
45c51519
PP
857 fc, index);
858
859 orig_ranges =
de821fe5 860 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
45c51519
PP
861 spec_opt);
862 is_signed = true;
863 }
864
865 if (orig_ranges) {
866 uint64_t i;
867
868 int_ranges = range_set_to_int_ranges(orig_ranges, is_signed);
98b15851 869 BT_ASSERT_DBG(int_ranges);
45c51519
PP
870
871 for (i = 0; i < int_ranges->len; i++) {
872 struct int_range *range = int_range_at(int_ranges, i);
873
874 write_sp(ctx);
875 write_int_range(ctx, range, is_signed);
876 }
877
878 g_string_append(ctx->str, ": ");
879 } else {
55478183
PP
880 write_sp(ctx);
881 }
882
48be9a91
PP
883 if (bt_value_map_is_empty(user_attrs)) {
884 write_field_class(ctx, option_fc);
885 } else {
886 write_nl(ctx);
887 incr_indent(ctx);
45c51519 888
48be9a91
PP
889 /* Field class */
890 write_prop_name_line(ctx, "Field class");
891 write_sp(ctx);
892 write_field_class(ctx, option_fc);
893 write_nl(ctx);
45c51519 894
48be9a91
PP
895 /* User attributes */
896 write_user_attributes(ctx, user_attrs,
897 false, NULL);
45c51519 898
48be9a91 899 decr_indent(ctx);
45c51519
PP
900 }
901
48be9a91
PP
902 if (int_ranges) {
903 g_array_free(int_ranges, TRUE);
45c51519
PP
904 }
905}
906
907static
908void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc)
909{
910 uint64_t i;
911 const char *type;
912 bt_field_class_type fc_type = bt_field_class_get_type(fc);
48be9a91
PP
913 const bt_value *user_attrs;
914 bool wrote_user_attrs = false;
45c51519 915
55478183
PP
916 /* Write field class's type */
917 switch (fc_type) {
dacaa55d
PP
918 case BT_FIELD_CLASS_TYPE_BOOL:
919 type = "Boolean";
920 break;
9684703d
PP
921 case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
922 type = "Bit array";
923 break;
55478183
PP
924 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
925 type = "Unsigned integer";
926 break;
927 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
928 type = "Signed integer";
929 break;
930 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
931 type = "Unsigned enumeration";
932 break;
933 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
934 type = "Signed enumeration";
935 break;
fe4df857
FD
936 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
937 type = "Single-precision real";
938 break;
939 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
940 type = "Double-precision real";
55478183
PP
941 break;
942 case BT_FIELD_CLASS_TYPE_STRING:
943 type = "String";
944 break;
945 case BT_FIELD_CLASS_TYPE_STRUCTURE:
946 type = "Structure";
947 break;
948 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
949 type = "Static array";
950 break;
81b8fa44
PP
951 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
952 type = "Dynamic array (no length field)";
953 break;
954 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
955 type = "Dynamic array (with length field)";
55478183 956 break;
de821fe5 957 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD:
0aa006b7
PP
958 type = "Option (no selector)";
959 break;
de821fe5 960 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
0aa006b7
PP
961 type = "Option (boolean selector)";
962 break;
de821fe5 963 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
0aa006b7
PP
964 type = "Option (unsigned integer selector)";
965 break;
de821fe5 966 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
0aa006b7 967 type = "Option (signed integer selector)";
25510d56 968 break;
de821fe5 969 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
45c51519
PP
970 type = "Variant (no selector)";
971 break;
de821fe5 972 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
fabfe034 973 type = "Variant (unsigned integer selector)";
45c51519 974 break;
de821fe5 975 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
fabfe034 976 type = "Variant (signed integer selector)";
55478183
PP
977 break;
978 default:
498e7994 979 bt_common_abort();
55478183
PP
980 }
981
982 g_string_append_printf(ctx->str, "%s%s%s",
983 color_fg_blue(ctx), type, color_reset(ctx));
984
48be9a91 985 /* Write field class's single-line properties */
ebdb6693 986 if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
55478183
PP
987 uint64_t mapping_count =
988 bt_field_class_enumeration_get_mapping_count(fc);
989
990 write_sp(ctx);
991 write_int_field_class_props(ctx, fc, false);
992 g_string_append(ctx->str, ", ");
993 write_uint_prop_value(ctx, mapping_count);
994 g_string_append_printf(ctx->str, " mapping%s)",
995 plural(mapping_count));
ebdb6693
PP
996 } else if (bt_field_class_type_is(fc_type,
997 BT_FIELD_CLASS_TYPE_INTEGER)) {
998 write_sp(ctx);
999 write_int_field_class_props(ctx, fc, true);
1000 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
55478183
PP
1001 uint64_t member_count =
1002 bt_field_class_structure_get_member_count(fc);
1003
1004 g_string_append(ctx->str, " (");
1005 write_uint_prop_value(ctx, member_count);
1006 g_string_append_printf(ctx->str, " member%s)",
1007 plural(member_count));
ebdb6693
PP
1008 } else if (fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
1009 g_string_append(ctx->str, " (Length ");
1010 write_uint_prop_value(ctx,
1011 bt_field_class_array_static_get_length(fc));
1012 g_string_append_c(ctx->str, ')');
1013 } else if (fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
1014 const bt_field_path *length_field_path =
1015 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1016 fc);
55478183 1017
ebdb6693
PP
1018 g_string_append(ctx->str, " (Length field path ");
1019 write_field_path(ctx, length_field_path);
1020 g_string_append_c(ctx->str, ')');
1021 } else if (bt_field_class_type_is(fc_type,
1022 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD)) {
25510d56 1023 const bt_field_path *selector_field_path =
de821fe5 1024 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
0aa006b7 1025 fc);
25510d56 1026
0aa006b7
PP
1027 g_string_append(ctx->str, " (Selector field path ");
1028 write_field_path(ctx, selector_field_path);
1029 g_string_append_c(ctx->str, ')');
ebdb6693
PP
1030 } else if (bt_field_class_type_is(fc_type,
1031 BT_FIELD_CLASS_TYPE_VARIANT)) {
48be9a91
PP
1032 uint64_t option_count =
1033 bt_field_class_variant_get_option_count(fc);
1034 const bt_field_path *sel_field_path = NULL;
1035
ebdb6693
PP
1036 if (bt_field_class_type_is(fc_type,
1037 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) {
48be9a91 1038 sel_field_path =
de821fe5 1039 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
48be9a91 1040 fc);
98b15851 1041 BT_ASSERT_DBG(sel_field_path);
48be9a91
PP
1042 }
1043
1044 g_string_append(ctx->str, " (");
1045 write_uint_prop_value(ctx, option_count);
1046 g_string_append_printf(ctx->str, " option%s",
1047 plural(option_count));
1048
1049 if (sel_field_path) {
1050 g_string_append(ctx->str, ", Selector field path ");
1051 write_field_path(ctx, sel_field_path);
1052 }
1053
1054 g_string_append_c(ctx->str, ')');
48be9a91
PP
1055 }
1056
1057 incr_indent(ctx);
1058 user_attrs = bt_field_class_borrow_user_attributes_const(fc);
1059 if (!bt_value_map_is_empty(user_attrs)) {
1060 g_string_append(ctx->str, ":\n");
1061 write_user_attributes(ctx, user_attrs, false, NULL);
1062 wrote_user_attrs = true;
1063 }
1064
1065 /* Write field class's complex properties */
ebdb6693 1066 if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
48be9a91
PP
1067 uint64_t mapping_count =
1068 bt_field_class_enumeration_get_mapping_count(fc);
1069
1070 if (mapping_count > 0) {
1071 if (wrote_user_attrs) {
1072 write_nl(ctx);
1073 write_indent(ctx);
1074 write_prop_name(ctx, "Mappings");
1075 g_string_append_c(ctx->str, ':');
1076 incr_indent(ctx);
1077 } else {
1078 /* Each mapping starts with its own newline */
1079 g_string_append_c(ctx->str, ':');
1080 }
1081
1082 write_enum_field_class_mappings(ctx, fc);
1083
1084 if (wrote_user_attrs) {
1085 decr_indent(ctx);
1086 }
1087 }
ebdb6693 1088 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
48be9a91
PP
1089 uint64_t member_count =
1090 bt_field_class_structure_get_member_count(fc);
1091
1092 if (member_count > 0) {
1093 if (wrote_user_attrs) {
1094 write_nl(ctx);
1095 write_indent(ctx);
1096 write_prop_name(ctx, "Members");
1097 g_string_append_c(ctx->str, ':');
1098 incr_indent(ctx);
1099 } else {
1100 /* Each member starts with its own newline */
1101 g_string_append_c(ctx->str, ':');
1102 }
1103
1104 for (i = 0; i < member_count; i++) {
1105 const bt_field_class_structure_member *member =
1106 bt_field_class_structure_borrow_member_by_index_const(
1107 fc, i);
50233236 1108 const bt_value *member_user_attrs;
48be9a91
PP
1109 const bt_field_class *member_fc =
1110 bt_field_class_structure_member_borrow_field_class_const(member);
1111
1112 write_nl(ctx);
1113 write_compound_member_name(ctx,
1114 bt_field_class_structure_member_get_name(member));
50233236 1115 member_user_attrs = bt_field_class_structure_member_borrow_user_attributes_const(
48be9a91
PP
1116 member);
1117
50233236 1118 if (bt_value_map_is_empty(member_user_attrs)) {
48be9a91
PP
1119 write_sp(ctx);
1120 write_field_class(ctx, member_fc);
1121 } else {
1122 write_nl(ctx);
1123 incr_indent(ctx);
1124
1125 /* Field class */
1126 write_prop_name_line(ctx, "Field class");
1127 write_sp(ctx);
1128 write_field_class(ctx, member_fc);
1129 write_nl(ctx);
1130
1131 /* User attributes */
50233236 1132 write_user_attributes(ctx, member_user_attrs,
48be9a91
PP
1133 false, NULL);
1134
1135 decr_indent(ctx);
1136 }
1137 }
1138
1139 if (wrote_user_attrs) {
1140 decr_indent(ctx);
1141 }
1142 }
ebdb6693 1143 } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
48be9a91
PP
1144 if (wrote_user_attrs) {
1145 write_nl(ctx);
1146 } else {
1147 g_string_append(ctx->str, ":\n");
1148 }
1149
1150 write_prop_name_line(ctx, "Element");
1151 write_sp(ctx);
1152 write_field_class(ctx,
1153 bt_field_class_array_borrow_element_field_class_const(fc));
ebdb6693
PP
1154 } else if (bt_field_class_type_is(fc_type,
1155 BT_FIELD_CLASS_TYPE_OPTION)) {
0aa006b7
PP
1156 const void *ranges = NULL;
1157 bool selector_is_signed = false;
1158
48be9a91
PP
1159 if (wrote_user_attrs) {
1160 write_nl(ctx);
1161 } else {
1162 g_string_append(ctx->str, ":\n");
1163 }
1164
de821fe5 1165 if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) {
0aa006b7 1166 write_bool_prop_line(ctx, "Selector is reversed",
de821fe5
PP
1167 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc));
1168 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
1169 ranges = bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc);
1170 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
1171 ranges = bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc);
0aa006b7
PP
1172 selector_is_signed = true;
1173 }
1174
1175 if (ranges) {
1176 GArray *sorted_ranges = range_set_to_int_ranges(
1177 ranges, selector_is_signed);
0aa006b7 1178
98b15851
PP
1179 BT_ASSERT_DBG(sorted_ranges);
1180 BT_ASSERT_DBG(sorted_ranges->len > 0);
0aa006b7
PP
1181 write_prop_name_line(ctx, "Selector ranges");
1182
1183 for (i = 0; i < sorted_ranges->len; i++) {
1184 write_sp(ctx);
1185 write_int_range(ctx,
1186 int_range_at(sorted_ranges, i),
1187 selector_is_signed);
1188 }
1189
1190 write_nl(ctx);
1191 g_array_free(sorted_ranges, TRUE);
1192 }
1193
48be9a91 1194 write_prop_name_line(ctx, "Content");
25510d56
PP
1195 write_sp(ctx);
1196 write_field_class(ctx,
1197 bt_field_class_option_borrow_field_class_const(fc));
ebdb6693
PP
1198 } else if (bt_field_class_type_is(fc_type,
1199 BT_FIELD_CLASS_TYPE_VARIANT)) {
48be9a91
PP
1200 uint64_t option_count =
1201 bt_field_class_variant_get_option_count(fc);
1202
1203 if (option_count > 0) {
1204 if (wrote_user_attrs) {
1205 write_nl(ctx);
1206 write_indent(ctx);
1207 write_prop_name(ctx, "Options");
1208 g_string_append_c(ctx->str, ':');
1209 incr_indent(ctx);
1210 } else {
1211 /* Each option starts with its own newline */
1212 g_string_append_c(ctx->str, ':');
1213 }
1214
1215 for (i = 0; i < option_count; i++) {
1216 write_variant_field_class_option(ctx, fc, i);
1217 }
1218
1219 if (wrote_user_attrs) {
1220 decr_indent(ctx);
1221 }
1222 }
55478183 1223 }
48be9a91
PP
1224
1225 decr_indent(ctx);
55478183
PP
1226}
1227
1228static
1229void write_root_field_class(struct details_write_ctx *ctx, const char *name,
1230 const bt_field_class *fc)
1231{
98b15851
PP
1232 BT_ASSERT_DBG(name);
1233 BT_ASSERT_DBG(fc);
55478183
PP
1234 write_indent(ctx);
1235 write_prop_name(ctx, name);
1236 g_string_append(ctx->str, ": ");
45c51519 1237 write_field_class(ctx, fc);
55478183
PP
1238 write_nl(ctx);
1239}
1240
1241static
1242void write_event_class(struct details_write_ctx *ctx, const bt_event_class *ec)
1243{
1244 const char *name = bt_event_class_get_name(ec);
1245 const char *emf_uri;
1246 const bt_field_class *fc;
1247 bt_event_class_log_level log_level;
1248
1249 write_indent(ctx);
1250 write_obj_type_name(ctx, "Event class");
1251
1252 /* Write name and ID */
1253 if (name) {
1254 g_string_append_printf(ctx->str, " `%s%s%s`",
1255 color_fg_green(ctx), name, color_reset(ctx));
1256 }
1257
1258 g_string_append(ctx->str, " (ID ");
1259 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1260 g_string_append(ctx->str, "):\n");
1261
1262 /* Write properties */
1263 incr_indent(ctx);
1264
48be9a91
PP
1265 /* Write user attributes */
1266 write_user_attributes(ctx,
1267 bt_event_class_borrow_user_attributes_const(ec), true, NULL);
1268
55478183
PP
1269 /* Write log level */
1270 if (bt_event_class_get_log_level(ec, &log_level) ==
1271 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
1272 const char *ll_str = NULL;
1273
1274 switch (log_level) {
1275 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
1276 ll_str = "Emergency";
1277 break;
1278 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
1279 ll_str = "Alert";
1280 break;
1281 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
1282 ll_str = "Critical";
1283 break;
1284 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
1285 ll_str = "Error";
1286 break;
1287 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
1288 ll_str = "Warning";
1289 break;
1290 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
1291 ll_str = "Notice";
1292 break;
1293 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
1294 ll_str = "Info";
1295 break;
1296 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
1297 ll_str = "Debug (system)";
1298 break;
1299 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
1300 ll_str = "Debug (program)";
1301 break;
1302 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
1303 ll_str = "Debug (process)";
1304 break;
1305 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
1306 ll_str = "Debug (module)";
1307 break;
1308 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
1309 ll_str = "Debug (unit)";
1310 break;
1311 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
1312 ll_str = "Debug (function)";
1313 break;
1314 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
1315 ll_str = "Debug (line)";
1316 break;
1317 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
1318 ll_str = "Debug";
1319 break;
1320 default:
498e7994 1321 bt_common_abort();
55478183
PP
1322 }
1323
1324 write_str_prop_line(ctx, "Log level", ll_str);
1325 }
1326
1327 /* Write EMF URI */
1328 emf_uri = bt_event_class_get_emf_uri(ec);
1329 if (emf_uri) {
1330 write_str_prop_line(ctx, "EMF URI", emf_uri);
1331 }
1332
1333 /* Write specific context field class */
1334 fc = bt_event_class_borrow_specific_context_field_class_const(ec);
1335 if (fc) {
1336 write_root_field_class(ctx, "Specific context field class", fc);
1337 }
1338
1339 /* Write payload field class */
1340 fc = bt_event_class_borrow_payload_field_class_const(ec);
1341 if (fc) {
1342 write_root_field_class(ctx, "Payload field class", fc);
1343 }
1344
1345 decr_indent(ctx);
1346}
1347
1348static
1349void write_clock_class_prop_lines(struct details_write_ctx *ctx,
1350 const bt_clock_class *cc)
1351{
1352 int64_t offset_seconds;
1353 uint64_t offset_cycles;
1354 const char *str;
1355
1356 str = bt_clock_class_get_name(cc);
1357 if (str) {
1358 write_str_prop_line(ctx, "Name", str);
1359 }
1360
48be9a91
PP
1361 write_user_attributes(ctx,
1362 bt_clock_class_borrow_user_attributes_const(cc), true, NULL);
55478183
PP
1363 str = bt_clock_class_get_description(cc);
1364 if (str) {
1365 write_str_prop_line(ctx, "Description", str);
1366 }
1367
1368 write_uint_prop_line(ctx, "Frequency (Hz)",
1369 bt_clock_class_get_frequency(cc));
1370 write_uint_prop_line(ctx, "Precision (cycles)",
1371 bt_clock_class_get_precision(cc));
1372 bt_clock_class_get_offset(cc, &offset_seconds, &offset_cycles);
1373 write_int_prop_line(ctx, "Offset (s)", offset_seconds);
1374 write_uint_prop_line(ctx, "Offset (cycles)", offset_cycles);
1375 write_bool_prop_line(ctx, "Origin is Unix epoch",
1376 bt_clock_class_origin_is_unix_epoch(cc));
1377
1378 if (ctx->details_comp->cfg.with_uuid) {
1379 bt_uuid uuid = bt_clock_class_get_uuid(cc);
1380
1381 if (uuid) {
1382 write_uuid_prop_line(ctx, "UUID", uuid);
1383 }
1384 }
1385}
1386
1387static
1388gint compare_event_classes(const bt_event_class **a, const bt_event_class **b)
1389{
1390 uint64_t id_a = bt_event_class_get_id(*a);
1391 uint64_t id_b = bt_event_class_get_id(*b);
1392
1393 if (id_a < id_b) {
1394 return -1;
1395 } else if (id_a > id_b) {
1396 return 1;
1397 } else {
1398 return 0;
1399 }
1400}
1401
1402static
1403void write_stream_class(struct details_write_ctx *ctx,
1404 const bt_stream_class *sc)
1405{
1406 const bt_field_class *fc;
1407 GPtrArray *event_classes = g_ptr_array_new();
1408 uint64_t i;
1409
1410 write_indent(ctx);
1411 write_obj_type_name(ctx, "Stream class");
1412
1413 /* Write name and ID */
1414 if (ctx->details_comp->cfg.with_stream_class_name) {
1415 const char *name = bt_stream_class_get_name(sc);
1416
1417 if (name) {
1418 g_string_append(ctx->str, " `");
1419 write_str_prop_value(ctx, name);
1420 g_string_append(ctx->str, "`");
1421 }
1422 }
1423
1424 g_string_append(ctx->str, " (ID ");
1425 write_uint_prop_value(ctx, bt_stream_class_get_id(sc));
1426 g_string_append(ctx->str, "):\n");
1427
1428 /* Write properties */
1429 incr_indent(ctx);
1430
48be9a91
PP
1431 /* Write user attributes */
1432 write_user_attributes(ctx,
1433 bt_stream_class_borrow_user_attributes_const(sc), true, NULL);
1434
55478183
PP
1435 /* Write configuration */
1436 write_bool_prop_line(ctx,
26fc5aed
PP
1437 "Supports packets", bt_stream_class_supports_packets(sc));
1438
1439 if (bt_stream_class_supports_packets(sc)) {
1440 write_bool_prop_line(ctx,
1441 "Packets have beginning default clock snapshot",
1442 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
1443 write_bool_prop_line(ctx,
1444 "Packets have end default clock snapshot",
1445 bt_stream_class_packets_have_end_default_clock_snapshot(sc));
1446 }
1447
55478183
PP
1448 write_bool_prop_line(ctx,
1449 "Supports discarded events",
1450 bt_stream_class_supports_discarded_events(sc));
a3c75374
PP
1451
1452 if (bt_stream_class_supports_discarded_events(sc)) {
1453 write_bool_prop_line(ctx,
1454 "Discarded events have default clock snapshots",
1455 bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
1456 }
1457
55478183
PP
1458 write_bool_prop_line(ctx,
1459 "Supports discarded packets",
1460 bt_stream_class_supports_discarded_packets(sc));
a3c75374
PP
1461
1462 if (bt_stream_class_supports_discarded_packets(sc)) {
1463 write_bool_prop_line(ctx,
1464 "Discarded packets have default clock snapshots",
1465 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
1466 }
55478183
PP
1467
1468 /* Write default clock class */
1469 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1470 write_indent(ctx);
1471 write_prop_name(ctx, "Default clock class");
1472 g_string_append_c(ctx->str, ':');
1473 write_nl(ctx);
1474 incr_indent(ctx);
1475 write_clock_class_prop_lines(ctx,
1476 bt_stream_class_borrow_default_clock_class_const(sc));
1477 decr_indent(ctx);
1478 }
1479
1480 fc = bt_stream_class_borrow_packet_context_field_class_const(sc);
1481 if (fc) {
1482 write_root_field_class(ctx, "Packet context field class", fc);
1483 }
1484
1485 fc = bt_stream_class_borrow_event_common_context_field_class_const(sc);
1486 if (fc) {
1487 write_root_field_class(ctx, "Event common context field class",
1488 fc);
1489 }
1490
1491 for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
1492 g_ptr_array_add(event_classes,
1493 (gpointer) bt_stream_class_borrow_event_class_by_index_const(
1494 sc, i));
1495 }
1496
1497 g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
1498
1499 for (i = 0; i < event_classes->len; i++) {
1500 write_event_class(ctx, event_classes->pdata[i]);
1501 }
1502
1503 decr_indent(ctx);
1504 g_ptr_array_free(event_classes, TRUE);
1505}
1506
1507static
1508gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
1509{
1510 uint64_t id_a = bt_stream_class_get_id(*a);
1511 uint64_t id_b = bt_stream_class_get_id(*b);
1512
1513 if (id_a < id_b) {
1514 return -1;
1515 } else if (id_a > id_b) {
1516 return 1;
1517 } else {
1518 return 0;
1519 }
1520}
1521
55478183
PP
1522static
1523void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
1524{
1525 GPtrArray *stream_classes = g_ptr_array_new();
55478183
PP
1526 uint64_t i;
1527 bool printed_prop = false;
1528
1529 write_indent(ctx);
1530 write_obj_type_name(ctx, "Trace class");
1531
48be9a91 1532
55478183
PP
1533 for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
1534 g_ptr_array_add(stream_classes,
1535 (gpointer) bt_trace_class_borrow_stream_class_by_index_const(
1536 tc, i));
1537 }
1538
1539 g_ptr_array_sort(stream_classes, (GCompareFunc) compare_stream_classes);
1540
1541 if (stream_classes->len > 0) {
1542 if (!printed_prop) {
1543 g_string_append(ctx->str, ":\n");
1544 printed_prop = true;
1545 }
1546 }
1547
335a2da5
PP
1548 incr_indent(ctx);
1549
48be9a91
PP
1550 /* Write user attributes */
1551 write_user_attributes(ctx,
1552 bt_trace_class_borrow_user_attributes_const(tc), true,
1553 &printed_prop);
1554
1555 /* Write stream classes */
55478183
PP
1556 for (i = 0; i < stream_classes->len; i++) {
1557 write_stream_class(ctx, stream_classes->pdata[i]);
1558 }
1559
55478183
PP
1560 if (!printed_prop) {
1561 write_nl(ctx);
1562 }
1563
335a2da5 1564 decr_indent(ctx);
55478183 1565 g_ptr_array_free(stream_classes, TRUE);
55478183
PP
1566}
1567
1568static
1569int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
1570 const bt_stream_class *sc, const bt_event_class *ec)
1571{
1572 int ret = 0;
1573
98b15851 1574 BT_ASSERT_DBG(tc);
55478183
PP
1575
1576 if (details_need_to_write_trace_class(ctx, tc)) {
1577 uint64_t sc_i;
1578
1579 if (ctx->details_comp->cfg.compact &&
1580 ctx->details_comp->printed_something) {
1581 /*
1582 * There are no empty line between messages in
1583 * compact mode, so write one here to decouple
1584 * the trace class from the next message.
1585 */
1586 write_nl(ctx);
1587 }
1588
1589 /*
1590 * write_trace_class() also writes all its stream
1591 * classes their event classes, so we don't need to
1592 * rewrite `sc`.
1593 */
1594 write_trace_class(ctx, tc);
55478183
PP
1595
1596 /*
1597 * Mark this trace class as written, as well as all
1598 * its stream classes and their event classes.
1599 */
1600 ret = details_did_write_trace_class(ctx, tc);
1601 if (ret) {
1602 goto end;
1603 }
1604
1605 for (sc_i = 0; sc_i < bt_trace_class_get_stream_class_count(tc);
1606 sc_i++) {
1607 uint64_t ec_i;
1608 const bt_stream_class *tc_sc =
1609 bt_trace_class_borrow_stream_class_by_index_const(
1610 tc, sc_i);
1611
1612 details_did_write_meta_object(ctx, tc, tc_sc);
1613
1614 for (ec_i = 0; ec_i <
1615 bt_stream_class_get_event_class_count(tc_sc);
1616 ec_i++) {
1617 details_did_write_meta_object(ctx, tc,
1618 bt_stream_class_borrow_event_class_by_index_const(
1619 tc_sc, ec_i));
1620 }
1621 }
1622
1623 goto end;
1624 }
1625
1626 if (sc && details_need_to_write_meta_object(ctx, tc, sc)) {
1627 uint64_t ec_i;
1628
98b15851 1629 BT_ASSERT_DBG(tc);
55478183
PP
1630
1631 if (ctx->details_comp->cfg.compact &&
1632 ctx->details_comp->printed_something) {
1633 /*
1634 * There are no empty line between messages in
1635 * compact mode, so write one here to decouple
1636 * the stream class from the next message.
1637 */
1638 write_nl(ctx);
1639 }
1640
1641 /*
1642 * write_stream_class() also writes all its event
1643 * classes, so we don't need to rewrite `ec`.
1644 */
1645 write_stream_class(ctx, sc);
55478183
PP
1646
1647 /*
1648 * Mark this stream class as written, as well as all its
1649 * event classes.
1650 */
1651 details_did_write_meta_object(ctx, tc, sc);
1652
1653 for (ec_i = 0; ec_i <
1654 bt_stream_class_get_event_class_count(sc);
1655 ec_i++) {
1656 details_did_write_meta_object(ctx, tc,
1657 bt_stream_class_borrow_event_class_by_index_const(
1658 sc, ec_i));
1659 }
1660
1661 goto end;
1662 }
1663
1664 if (ec && details_need_to_write_meta_object(ctx, tc, ec)) {
98b15851 1665 BT_ASSERT_DBG(sc);
55478183
PP
1666
1667 if (ctx->details_comp->cfg.compact &&
1668 ctx->details_comp->printed_something) {
1669 /*
1670 * There are no empty line between messages in
1671 * compact mode, so write one here to decouple
1672 * the event class from the next message.
1673 */
1674 write_nl(ctx);
1675 }
1676
1677 write_event_class(ctx, ec);
55478183
PP
1678 details_did_write_meta_object(ctx, tc, ec);
1679 goto end;
1680 }
1681
1682end:
1683 return ret;
1684}
1685
1686static
1687void write_time_str(struct details_write_ctx *ctx, const char *str)
1688{
1689 if (!ctx->details_comp->cfg.with_time) {
1690 goto end;
1691 }
1692
1693 g_string_append_printf(ctx->str, "[%s%s%s%s]",
04609487
PP
1694 color_bold(ctx), color_fg_bright_blue(ctx), str,
1695 color_reset(ctx));
55478183
PP
1696
1697 if (ctx->details_comp->cfg.compact) {
1698 write_sp(ctx);
1699 } else {
1700 write_nl(ctx);
1701 }
1702
1703end:
1704 return;
1705}
1706
1707static
1708void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
1709{
d24d5663 1710 bt_clock_snapshot_get_ns_from_origin_status cs_status;
55478183
PP
1711 int64_t ns_from_origin;
1712 char buf[32];
1713
1714 if (!ctx->details_comp->cfg.with_time) {
1715 goto end;
1716 }
1717
1718 format_uint(buf, bt_clock_snapshot_get_value(cs), 10);
1719 g_string_append_printf(ctx->str, "[%s%s%s%s%s",
04609487 1720 color_bold(ctx), color_fg_bright_blue(ctx), buf,
55478183
PP
1721 color_reset(ctx),
1722 ctx->details_comp->cfg.compact ? "" : " cycles");
d24d5663
PP
1723 cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
1724 if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
55478183
PP
1725 format_int(buf, ns_from_origin, 10);
1726 g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
1727 ctx->details_comp->cfg.compact ? "" : ",",
04609487 1728 color_bold(ctx), color_fg_bright_blue(ctx), buf,
55478183
PP
1729 color_reset(ctx),
1730 ctx->details_comp->cfg.compact ? "" : " ns from origin");
1731 }
1732
1733 g_string_append(ctx->str, "]");
1734
1735 if (ctx->details_comp->cfg.compact) {
1736 write_sp(ctx);
1737 } else {
1738 write_nl(ctx);
1739 }
1740
1741end:
1742 return;
1743}
1744
1745static
1746int write_message_follow_tag(struct details_write_ctx *ctx,
1747 const bt_stream *stream)
1748{
1749 int ret;
1750 uint64_t unique_trace_id;
1751 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1752 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1753
1754 ret = details_trace_unique_id(ctx, trace, &unique_trace_id);
1755 if (ret) {
1756 goto end;
1757 }
1758
1759 if (ctx->details_comp->cfg.compact) {
1760 g_string_append_printf(ctx->str,
04609487 1761 "%s{%s%s%" PRIu64 " %" PRIu64 " %" PRIu64 "%s%s}%s ",
55478183 1762 color_fg_cyan(ctx), color_bold(ctx),
04609487 1763 color_fg_bright_cyan(ctx),
55478183
PP
1764 unique_trace_id, bt_stream_class_get_id(sc),
1765 bt_stream_get_id(stream),
1766 color_reset(ctx), color_fg_cyan(ctx), color_reset(ctx));
1767 } else {
1768 g_string_append_printf(ctx->str,
04609487
PP
1769 "%s{Trace %s%s%" PRIu64 "%s%s, Stream class ID %s%s%" PRIu64 "%s%s, Stream ID %s%s%" PRIu64 "%s%s}%s\n",
1770 color_fg_cyan(ctx),
1771 color_bold(ctx), color_fg_bright_cyan(ctx),
1772 unique_trace_id, color_reset(ctx),
1773 color_fg_cyan(ctx),
1774 color_bold(ctx), color_fg_bright_cyan(ctx),
1775 bt_stream_class_get_id(sc), color_reset(ctx),
55478183 1776 color_fg_cyan(ctx),
04609487
PP
1777 color_bold(ctx), color_fg_bright_cyan(ctx),
1778 bt_stream_get_id(stream), color_reset(ctx),
1779 color_fg_cyan(ctx), color_reset(ctx));
55478183
PP
1780 }
1781
1782end:
1783 return ret;
1784}
1785
1786static
1787void write_field(struct details_write_ctx *ctx, const bt_field *field,
1788 const char *name)
1789{
1790 uint64_t i;
1791 bt_field_class_type fc_type = bt_field_get_class_type(field);
1792 const bt_field_class *fc;
1793 char buf[64];
1794
1795 /* Write field's name */
1796 if (name) {
1797 write_compound_member_name(ctx, name);
1798 }
1799
1800 /* Write field's value */
ebdb6693 1801 if (fc_type == BT_FIELD_CLASS_TYPE_BOOL) {
dacaa55d
PP
1802 write_sp(ctx);
1803 write_bool_prop_value(ctx, bt_field_bool_get_value(field));
ebdb6693 1804 } else if (fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) {
9684703d
PP
1805 format_uint(buf, bt_field_bit_array_get_value_as_integer(field),
1806 16);
1807 write_sp(ctx);
1808 write_uint_str_prop_value(ctx, buf);
ebdb6693
PP
1809 } else if (bt_field_class_type_is(fc_type,
1810 BT_FIELD_CLASS_TYPE_INTEGER)) {
55478183
PP
1811 unsigned int fmt_base;
1812 bt_field_class_integer_preferred_display_base base;
1813
1814 fc = bt_field_borrow_class_const(field);
1815 base = bt_field_class_integer_get_preferred_display_base(fc);
1816
1817 switch (base) {
1818 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
1819 fmt_base = 10;
1820 break;
1821 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
1822 fmt_base = 8;
1823 break;
1824 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
1825 fmt_base = 2;
1826 break;
1827 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
1828 fmt_base = 16;
1829 break;
1830 default:
498e7994 1831 bt_common_abort();
55478183
PP
1832 }
1833
ebdb6693
PP
1834 if (bt_field_class_type_is(fc_type,
1835 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) {
55478183 1836 format_uint(buf,
9c08c816 1837 bt_field_integer_unsigned_get_value(field),
55478183
PP
1838 fmt_base);
1839 write_sp(ctx);
1840 write_uint_str_prop_value(ctx, buf);
1841 } else {
1842 format_int(buf,
9c08c816 1843 bt_field_integer_signed_get_value(field),
55478183
PP
1844 fmt_base);
1845 write_sp(ctx);
1846 write_int_str_prop_value(ctx, buf);
1847 }
ebdb6693 1848 } else if (fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
fe4df857
FD
1849 write_sp(ctx);
1850 write_float_prop_value(ctx, bt_field_real_single_precision_get_value(field));
ebdb6693 1851 } else if (fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) {
55478183 1852 write_sp(ctx);
fe4df857 1853 write_float_prop_value(ctx, bt_field_real_double_precision_get_value(field));
ebdb6693 1854 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRING) {
55478183
PP
1855 write_sp(ctx);
1856 write_str_prop_value(ctx, bt_field_string_get_value(field));
ebdb6693 1857 } else if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
55478183
PP
1858 uint64_t member_count;
1859
1860 fc = bt_field_borrow_class_const(field);
1861 member_count = bt_field_class_structure_get_member_count(fc);
1862
1863 if (member_count > 0) {
1864 incr_indent(ctx);
1865
1866 for (i = 0; i < member_count; i++) {
1867 const bt_field_class_structure_member *member =
1868 bt_field_class_structure_borrow_member_by_index_const(
1869 fc, i);
1870 const bt_field *member_field =
1871 bt_field_structure_borrow_member_field_by_index_const(
1872 field, i);
1873
1874 write_nl(ctx);
1875 write_field(ctx, member_field,
1876 bt_field_class_structure_member_get_name(member));
1877 }
1878
1879 decr_indent(ctx);
1880 } else {
8f512475
PP
1881 write_sp(ctx);
1882 write_none_prop_value(ctx, "Empty");
55478183 1883 }
ebdb6693 1884 } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
55478183
PP
1885 uint64_t length = bt_field_array_get_length(field);
1886
1887 if (length == 0) {
8f512475
PP
1888 write_sp(ctx);
1889 write_none_prop_value(ctx, "Empty");
55478183
PP
1890 } else {
1891 g_string_append(ctx->str, " Length ");
1892 write_uint_prop_value(ctx, length);
1893 g_string_append_c(ctx->str, ':');
1894 }
1895
1896 incr_indent(ctx);
1897
1898 for (i = 0; i < length; i++) {
1899 const bt_field *elem_field =
1900 bt_field_array_borrow_element_field_by_index_const(
1901 field, i);
1902
1903 write_nl(ctx);
48be9a91 1904 write_array_index(ctx, i, color_fg_cyan(ctx));
55478183
PP
1905 write_field(ctx, elem_field, NULL);
1906 }
1907
1908 decr_indent(ctx);
ebdb6693
PP
1909 } else if (bt_field_class_type_is(fc_type,
1910 BT_FIELD_CLASS_TYPE_OPTION)) {
25510d56
PP
1911 const bt_field *content_field =
1912 bt_field_option_borrow_field_const(field);
1913
1914 if (!content_field) {
1915 write_sp(ctx);
1916 write_none_prop_value(ctx, "None");
1917 } else {
1918 write_field(ctx, content_field, NULL);
1919 }
ebdb6693
PP
1920 } else if (bt_field_class_type_is(fc_type,
1921 BT_FIELD_CLASS_TYPE_VARIANT)) {
55478183
PP
1922 write_field(ctx,
1923 bt_field_variant_borrow_selected_option_field_const(
1924 field), NULL);
ebdb6693 1925 } else {
498e7994 1926 bt_common_abort();
55478183
PP
1927 }
1928}
1929
1930static
1931void write_root_field(struct details_write_ctx *ctx, const char *name,
1932 const bt_field *field)
1933{
98b15851
PP
1934 BT_ASSERT_DBG(name);
1935 BT_ASSERT_DBG(field);
55478183
PP
1936 write_indent(ctx);
1937 write_prop_name(ctx, name);
1938 g_string_append(ctx->str, ":");
1939 write_field(ctx, field, NULL);
1940 write_nl(ctx);
1941}
1942
1943static
1944int write_event_message(struct details_write_ctx *ctx,
1945 const bt_message *msg)
1946{
1947 int ret = 0;
1948 const bt_event *event = bt_message_event_borrow_event_const(msg);
1949 const bt_stream *stream = bt_event_borrow_stream_const(event);
1950 const bt_event_class *ec = bt_event_borrow_class_const(event);
1951 const bt_stream_class *sc = bt_event_class_borrow_stream_class_const(ec);
1952 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1953 const char *ec_name;
1954 const bt_field *field;
1955
1956 ret = try_write_meta(ctx, tc, sc, ec);
1957 if (ret) {
1958 goto end;
1959 }
1960
cc413248
PP
1961 if (!ctx->details_comp->cfg.with_data) {
1962 goto end;
1963 }
1964
1965 if (ctx->str->len > 0) {
1966 /*
1967 * Output buffer contains metadata: separate blocks with
1968 * newline.
1969 */
1970 write_nl(ctx);
1971 }
1972
55478183
PP
1973 /* Write time */
1974 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1975 write_time(ctx,
1976 bt_message_event_borrow_default_clock_snapshot_const(
1977 msg));
1978 }
1979
1980 /* Write follow tag for message */
1981 ret = write_message_follow_tag(ctx, stream);
1982 if (ret) {
1983 goto end;
1984 }
1985
1986 /* Write object's basic properties */
1987 write_obj_type_name(ctx, "Event");
1988 ec_name = bt_event_class_get_name(ec);
1989 if (ec_name) {
1990 g_string_append_printf(ctx->str, " `%s%s%s`",
1991 color_fg_green(ctx), ec_name, color_reset(ctx));
1992 }
1993
1994 g_string_append(ctx->str, " (");
1995
1996 if (!ctx->details_comp->cfg.compact) {
1997 g_string_append(ctx->str, "Class ID ");
1998 }
1999
2000 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
2001 g_string_append(ctx->str, ")");
2002
2003 if (ctx->details_comp->cfg.compact) {
2004 write_nl(ctx);
2005 goto end;
2006 }
2007
2008 /* Write fields */
2009 g_string_append(ctx->str, ":\n");
2010 incr_indent(ctx);
2011 field = bt_event_borrow_common_context_field_const(event);
2012 if (field) {
2013 write_root_field(ctx, "Common context", field);
2014 }
2015
2016 field = bt_event_borrow_specific_context_field_const(event);
2017 if (field) {
2018 write_root_field(ctx, "Specific context", field);
2019 }
2020
2021 field = bt_event_borrow_payload_field_const(event);
2022 if (field) {
2023 write_root_field(ctx, "Payload", field);
2024 }
2025
2026 decr_indent(ctx);
2027
2028end:
55478183
PP
2029 return ret;
2030}
2031
2032static
2033gint compare_streams(const bt_stream **a, const bt_stream **b)
2034{
2035 uint64_t id_a = bt_stream_get_id(*a);
2036 uint64_t id_b = bt_stream_get_id(*b);
2037
2038 if (id_a < id_b) {
2039 return -1;
2040 } else if (id_a > id_b) {
2041 return 1;
2042 } else {
2043 const bt_stream_class *a_sc = bt_stream_borrow_class_const(*a);
2044 const bt_stream_class *b_sc = bt_stream_borrow_class_const(*b);
2045 uint64_t a_sc_id = bt_stream_class_get_id(a_sc);
2046 uint64_t b_sc_id = bt_stream_class_get_id(b_sc);
2047
2048 if (a_sc_id < b_sc_id) {
2049 return -1;
2050 } else if (a_sc_id > b_sc_id) {
2051 return 1;
2052 } else {
2053 return 0;
2054 }
2055 }
2056}
2057
2058static
2059void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
2060{
55478183
PP
2061 GPtrArray *streams = g_ptr_array_new();
2062 uint64_t i;
2063 bool printed_prop = false;
335a2da5
PP
2064 GPtrArray *env_names = g_ptr_array_new();
2065 uint64_t env_count;
55478183
PP
2066
2067 write_indent(ctx);
2068 write_obj_type_name(ctx, "Trace");
2069
2070 /* Write name */
2071 if (ctx->details_comp->cfg.with_trace_name) {
50233236 2072 const char *name = bt_trace_get_name(trace);
55478183
PP
2073 if (name) {
2074 g_string_append(ctx->str, " `");
2075 write_str_prop_value(ctx, name);
2076 g_string_append(ctx->str, "`");
2077 }
2078 }
2079
2080 /* Write properties */
2081 incr_indent(ctx);
2082
335a2da5
PP
2083 /* Write UUID */
2084 if (ctx->details_comp->cfg.with_uuid) {
2085 bt_uuid uuid = bt_trace_get_uuid(trace);
2086
2087 if (uuid) {
55478183
PP
2088 if (!printed_prop) {
2089 g_string_append(ctx->str, ":\n");
2090 printed_prop = true;
2091 }
2092
335a2da5 2093 write_uuid_prop_line(ctx, "UUID", uuid);
55478183
PP
2094 }
2095 }
2096
335a2da5
PP
2097 /* Write environment */
2098 env_count = bt_trace_get_environment_entry_count(trace);
2099 if (env_count > 0) {
2100 if (!printed_prop) {
2101 g_string_append(ctx->str, ":\n");
2102 printed_prop = true;
2103 }
55478183 2104
335a2da5
PP
2105 write_indent(ctx);
2106 write_prop_name(ctx, "Environment");
2107 g_string_append(ctx->str, " (");
2108 write_uint_prop_value(ctx, env_count);
2109 g_string_append_printf(ctx->str, " entr%s):",
2110 env_count == 1 ? "y" : "ies");
2111 write_nl(ctx);
2112 incr_indent(ctx);
2113
2114 for (i = 0; i < env_count; i++) {
2115 const char *name;
2116 const bt_value *value;
2117
2118 bt_trace_borrow_environment_entry_by_index_const(
2119 trace, i, &name, &value);
2120 g_ptr_array_add(env_names, (gpointer) name);
2121 }
2122
2123 g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
2124
2125 for (i = 0; i < env_names->len; i++) {
2126 const char *name = env_names->pdata[i];
2127 const bt_value *value =
2128 bt_trace_borrow_environment_entry_value_by_name_const(
2129 trace, name);
2130
98b15851 2131 BT_ASSERT_DBG(value);
335a2da5
PP
2132 write_compound_member_name(ctx, name);
2133 write_sp(ctx);
2134
2135 if (bt_value_get_type(value) ==
2136 BT_VALUE_TYPE_SIGNED_INTEGER) {
2137 write_int_prop_value(ctx,
9c08c816 2138 bt_value_integer_signed_get(value));
335a2da5
PP
2139 } else if (bt_value_get_type(value) ==
2140 BT_VALUE_TYPE_STRING) {
2141 write_str_prop_value(ctx,
2142 bt_value_string_get(value));
2143 } else {
498e7994 2144 bt_common_abort();
55478183
PP
2145 }
2146
335a2da5 2147 write_nl(ctx);
55478183 2148 }
335a2da5
PP
2149
2150 decr_indent(ctx);
55478183
PP
2151 }
2152
2153 for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
2154 g_ptr_array_add(streams,
2155 (gpointer) bt_trace_borrow_stream_by_index_const(
2156 trace, i));
2157 }
2158
2159 g_ptr_array_sort(streams, (GCompareFunc) compare_streams);
2160
2161 if (streams->len > 0 && !printed_prop) {
2162 g_string_append(ctx->str, ":\n");
2163 printed_prop = true;
2164 }
2165
2166 for (i = 0; i < streams->len; i++) {
2167 const bt_stream *stream = streams->pdata[i];
2168
2169 write_indent(ctx);
2170 write_obj_type_name(ctx, "Stream");
2171 g_string_append(ctx->str, " (ID ");
2172 write_uint_prop_value(ctx, bt_stream_get_id(stream));
2173 g_string_append(ctx->str, ", Class ID ");
2174 write_uint_prop_value(ctx, bt_stream_class_get_id(
2175 bt_stream_borrow_class_const(stream)));
2176 g_string_append(ctx->str, ")");
2177 write_nl(ctx);
2178 }
2179
2180 decr_indent(ctx);
2181
2182 if (!printed_prop) {
2183 write_nl(ctx);
2184 }
2185
2186 g_ptr_array_free(streams, TRUE);
335a2da5 2187 g_ptr_array_free(env_names, TRUE);
55478183
PP
2188}
2189
2190static
2191int write_stream_beginning_message(struct details_write_ctx *ctx,
2192 const bt_message *msg)
2193{
2194 int ret = 0;
2195 const bt_stream *stream =
2196 bt_message_stream_beginning_borrow_stream_const(msg);
2197 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
2198 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
188edac1 2199 const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
55478183
PP
2200 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
2201 const char *name;
2202
2203 ret = try_write_meta(ctx, tc, sc, NULL);
2204 if (ret) {
2205 goto end;
2206 }
2207
cc413248
PP
2208 if (!ctx->details_comp->cfg.with_data) {
2209 goto end;
2210 }
2211
2212 if (ctx->str->len > 0) {
2213 /*
2214 * Output buffer contains metadata: separate blocks with
2215 * newline.
2216 */
2217 write_nl(ctx);
2218 }
2219
188edac1
SM
2220 /* Write time */
2221 if (cc) {
2222 const bt_clock_snapshot *cs;
2223 bt_message_stream_clock_snapshot_state cs_state =
2224 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
2225
2226 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2227 write_time(ctx, cs);
2228 } else {
2229 write_time_str(ctx, "Unknown");
2230 }
2231 }
2232
55478183
PP
2233 /* Write follow tag for message */
2234 ret = write_message_follow_tag(ctx, stream);
2235 if (ret) {
2236 goto end;
2237 }
2238
2239 /* Write stream properties */
2240 write_obj_type_name(ctx, "Stream beginning");
2241
2242 if (ctx->details_comp->cfg.compact) {
2243 write_nl(ctx);
2244 goto end;
2245 }
2246
2247 g_string_append(ctx->str, ":\n");
2248 incr_indent(ctx);
2249
2250 if (ctx->details_comp->cfg.with_stream_name) {
2251 name = bt_stream_get_name(stream);
2252 if (name) {
2253 write_str_prop_line(ctx, "Name", name);
2254 }
2255 }
2256
2257 if (ctx->details_comp->cfg.with_stream_class_name) {
2258 name = bt_stream_class_get_name(sc);
2259 if (name) {
2260 write_str_prop_line(ctx, "Class name", name);
2261 }
2262 }
2263
2264 write_trace(ctx, trace);
2265 decr_indent(ctx);
2266
2267end:
2268 return ret;
2269}
2270
2271static
2272int write_stream_end_message(struct details_write_ctx *ctx,
2273 const bt_message *msg)
2274{
2275 int ret = 0;
2276 const bt_stream *stream =
2277 bt_message_stream_end_borrow_stream_const(msg);
188edac1
SM
2278 const bt_stream_class *sc =
2279 bt_stream_borrow_class_const(stream);
2280 const bt_clock_class *cc =
2281 bt_stream_class_borrow_default_clock_class_const(sc);
55478183 2282
cc413248
PP
2283 if (!ctx->details_comp->cfg.with_data) {
2284 goto end;
2285 }
2286
55478183 2287 /* Write time */
188edac1
SM
2288 if (cc) {
2289 const bt_clock_snapshot *cs;
2290 bt_message_stream_clock_snapshot_state cs_state =
2291 bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
55478183 2292
188edac1
SM
2293 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2294 write_time(ctx, cs);
2295 } else {
2296 write_time_str(ctx, "Unknown");
2297 }
55478183
PP
2298 }
2299
2300 /* Write follow tag for message */
2301 ret = write_message_follow_tag(ctx, stream);
2302 if (ret) {
2303 goto end;
2304 }
2305
188edac1
SM
2306 /* Write stream properties */
2307 write_obj_type_name(ctx, "Stream end\n");
55478183
PP
2308
2309end:
2310 return ret;
2311}
2312
2313static
2314int write_packet_beginning_message(struct details_write_ctx *ctx,
2315 const bt_message *msg)
2316{
2317 int ret = 0;
2318 const bt_packet *packet =
2319 bt_message_packet_beginning_borrow_packet_const(msg);
2320 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2321 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2322 const bt_field *field;
2323
cc413248
PP
2324 if (!ctx->details_comp->cfg.with_data) {
2325 goto end;
2326 }
2327
55478183
PP
2328 /* Write time */
2329 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
2330 write_time(ctx,
2331 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2332 msg));
2333 }
2334
2335 /* Write follow tag for message */
2336 ret = write_message_follow_tag(ctx, stream);
2337 if (ret) {
2338 goto end;
2339 }
2340
2341 write_obj_type_name(ctx, "Packet beginning");
2342
2343 if (ctx->details_comp->cfg.compact) {
2344 write_nl(ctx);
2345 goto end;
2346 }
2347
2348 /* Write field */
55478183
PP
2349 field = bt_packet_borrow_context_field_const(packet);
2350 if (field) {
340be5dd
PP
2351 g_string_append(ctx->str, ":\n");
2352 incr_indent(ctx);
55478183 2353 write_root_field(ctx, "Context", field);
340be5dd
PP
2354 decr_indent(ctx);
2355 } else {
2356 write_nl(ctx);
55478183
PP
2357 }
2358
55478183
PP
2359end:
2360 return ret;
2361}
2362
2363static
2364int write_discarded_items_message(struct details_write_ctx *ctx,
2365 const char *name, const bt_stream *stream,
2366 const bt_clock_snapshot *beginning_cs,
2367 const bt_clock_snapshot *end_cs, uint64_t count)
2368{
2369 int ret = 0;
2370
2371 /* Write times */
2372 if (beginning_cs) {
2373 write_time(ctx, beginning_cs);
98b15851 2374 BT_ASSERT_DBG(end_cs);
55478183
PP
2375 write_time(ctx, end_cs);
2376 }
2377
2378 /* Write follow tag for message */
2379 ret = write_message_follow_tag(ctx, stream);
2380 if (ret) {
2381 goto end;
2382 }
2383
2384 write_obj_type_name(ctx, "Discarded ");
2385 write_obj_type_name(ctx, name);
2386
2387 /* Write count */
2388 if (count == UINT64_C(-1)) {
2389 write_nl(ctx);
2390 goto end;
2391 }
2392
2393 g_string_append(ctx->str, " (");
2394 write_uint_prop_value(ctx, count);
2395 g_string_append_printf(ctx->str, " %s)\n", name);
2396
2397end:
2398 return ret;
2399}
2400
2401static
2402int write_discarded_events_message(struct details_write_ctx *ctx,
2403 const bt_message *msg)
2404{
cc413248 2405 int ret = 0;
55478183
PP
2406 const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
2407 msg);
2408 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2409 const bt_clock_snapshot *beginning_cs = NULL;
2410 const bt_clock_snapshot *end_cs = NULL;
2411 uint64_t count;
2412
cc413248
PP
2413 if (!ctx->details_comp->cfg.with_data) {
2414 goto end;
2415 }
2416
55478183
PP
2417 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
2418 beginning_cs =
2419 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2420 msg);
2421 end_cs =
2422 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2423 msg);
2424 }
2425
2426 if (bt_message_discarded_events_get_count(msg, &count) !=
2427 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2428 count = UINT64_C(-1);
2429 }
2430
cc413248 2431 ret = write_discarded_items_message(ctx, "events", stream,
55478183 2432 beginning_cs, end_cs, count);
cc413248
PP
2433
2434end:
2435 return ret;
55478183
PP
2436}
2437
2438static
2439int write_discarded_packets_message(struct details_write_ctx *ctx,
2440 const bt_message *msg)
2441{
cc413248 2442 int ret = 0;
55478183
PP
2443 const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
2444 msg);
2445 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2446 const bt_clock_snapshot *beginning_cs = NULL;
2447 const bt_clock_snapshot *end_cs = NULL;
2448 uint64_t count;
2449
cc413248
PP
2450 if (!ctx->details_comp->cfg.with_data) {
2451 goto end;
2452 }
2453
55478183
PP
2454 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
2455 beginning_cs =
2456 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2457 msg);
2458 end_cs =
2459 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2460 msg);
2461 }
2462
2463 if (bt_message_discarded_packets_get_count(msg, &count) !=
2464 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2465 count = UINT64_C(-1);
2466 }
2467
cc413248 2468 ret = write_discarded_items_message(ctx, "packets", stream,
55478183 2469 beginning_cs, end_cs, count);
cc413248
PP
2470
2471end:
2472 return ret;
55478183
PP
2473}
2474
2475static
2476int write_packet_end_message(struct details_write_ctx *ctx,
2477 const bt_message *msg)
2478{
2479 int ret = 0;
2480 const bt_packet *packet =
2481 bt_message_packet_end_borrow_packet_const(msg);
2482 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2483 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2484
cc413248
PP
2485 if (!ctx->details_comp->cfg.with_data) {
2486 goto end;
2487 }
2488
55478183
PP
2489 /* Write time */
2490 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
2491 write_time(ctx,
2492 bt_message_packet_end_borrow_default_clock_snapshot_const(
2493 msg));
2494 }
2495
2496 /* Write follow tag for message */
2497 ret = write_message_follow_tag(ctx, stream);
2498 if (ret) {
2499 goto end;
2500 }
2501
2502 write_obj_type_name(ctx, "Packet end");
2503 write_nl(ctx);
2504
2505end:
2506 return ret;
2507}
2508
2509static
2510int write_message_iterator_inactivity_message(struct details_write_ctx *ctx,
2511 const bt_message *msg)
2512{
2513 int ret = 0;
2514 const bt_clock_snapshot *cs =
2515 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
2516 msg);
2517
2518 /* Write time */
2519 write_time(ctx, cs);
2520 write_obj_type_name(ctx, "Message iterator inactivity");
2521
2522 if (ctx->details_comp->cfg.compact) {
2523 write_nl(ctx);
2524 goto end;
2525 }
2526
2527 /* Write clock class properties */
2528 g_string_append(ctx->str, ":\n");
2529 incr_indent(ctx);
2530 write_indent(ctx);
2531 write_prop_name(ctx, "Clock class");
2532 g_string_append_c(ctx->str, ':');
2533 write_nl(ctx);
2534 incr_indent(ctx);
2535 write_clock_class_prop_lines(ctx,
2536 bt_clock_snapshot_borrow_clock_class_const(cs));
2537 decr_indent(ctx);
2538
2539end:
2540 return ret;
2541}
2542
2543BT_HIDDEN
2544int details_write_message(struct details_comp *details_comp,
2545 const bt_message *msg)
2546{
2547 int ret = 0;
2548 struct details_write_ctx ctx = {
2549 .details_comp = details_comp,
2550 .str = details_comp->str,
2551 .indent_level = 0,
2552 };
2553
2554 /* Reset output buffer */
2555 g_string_assign(details_comp->str, "");
2556
55478183
PP
2557 switch (bt_message_get_type(msg)) {
2558 case BT_MESSAGE_TYPE_EVENT:
2559 ret = write_event_message(&ctx, msg);
2560 break;
2561 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
2562 ret = write_message_iterator_inactivity_message(&ctx, msg);
2563 break;
2564 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
2565 ret = write_stream_beginning_message(&ctx, msg);
2566 break;
2567 case BT_MESSAGE_TYPE_STREAM_END:
2568 ret = write_stream_end_message(&ctx, msg);
2569 break;
2570 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
2571 ret = write_packet_beginning_message(&ctx, msg);
2572 break;
2573 case BT_MESSAGE_TYPE_PACKET_END:
2574 ret = write_packet_end_message(&ctx, msg);
2575 break;
55478183
PP
2576 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
2577 ret = write_discarded_events_message(&ctx, msg);
2578 break;
2579 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
2580 ret = write_discarded_packets_message(&ctx, msg);
2581 break;
2582 default:
498e7994 2583 bt_common_abort();
55478183
PP
2584 }
2585
cc413248
PP
2586 /*
2587 * If this component printed at least one character so far, and
2588 * we're not in compact mode, and there's something in the
2589 * output buffer for this message, then prepend a newline to the
2590 * output buffer to visually separate message blocks.
2591 */
2592 if (details_comp->printed_something && !details_comp->cfg.compact &&
2593 details_comp->str->len > 0) {
2594 /* TODO: Optimize this */
2595 g_string_prepend_c(details_comp->str, '\n');
2596 }
2597
55478183
PP
2598 return ret;
2599}
This page took 0.156703 seconds and 4 git commands to generate.