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