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