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