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