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