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