sink.text.details: print option 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_UNSIGNED_INTEGER:
784 type = "Unsigned integer";
785 break;
786 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
787 type = "Signed integer";
788 break;
789 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
790 type = "Unsigned enumeration";
791 break;
792 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
793 type = "Signed enumeration";
794 break;
795 case BT_FIELD_CLASS_TYPE_REAL:
796 type = "Real";
797 break;
798 case BT_FIELD_CLASS_TYPE_STRING:
799 type = "String";
800 break;
801 case BT_FIELD_CLASS_TYPE_STRUCTURE:
802 type = "Structure";
803 break;
804 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
805 type = "Static array";
806 break;
807 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
808 type = "Dynamic array";
809 break;
810 case BT_FIELD_CLASS_TYPE_OPTION:
811 type = "Option";
812 break;
813 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
814 type = "Variant (no selector)";
815 break;
816 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
817 type = "Variant (unsigned selector)";
818 break;
819 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
820 type = "Variant (signed selector)";
821 break;
822 default:
823 abort();
824 }
825
826 g_string_append_printf(ctx->str, "%s%s%s",
827 color_fg_blue(ctx), type, color_reset(ctx));
828
829 /* Write field class's properties */
830 switch (fc_type) {
831 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
832 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
833 write_sp(ctx);
834 write_int_field_class_props(ctx, fc, true);
835 break;
836 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
837 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
838 {
839 uint64_t mapping_count =
840 bt_field_class_enumeration_get_mapping_count(fc);
841
842 write_sp(ctx);
843 write_int_field_class_props(ctx, fc, false);
844 g_string_append(ctx->str, ", ");
845 write_uint_prop_value(ctx, mapping_count);
846 g_string_append_printf(ctx->str, " mapping%s)",
847 plural(mapping_count));
848
849 if (mapping_count > 0) {
850 g_string_append_c(ctx->str, ':');
851 incr_indent(ctx);
852 write_enum_field_class_mappings(ctx, fc);
853 decr_indent(ctx);
854 }
855
856 break;
857 }
858 case BT_FIELD_CLASS_TYPE_REAL:
859 if (bt_field_class_real_is_single_precision(fc)) {
860 g_string_append(ctx->str, " (Single precision)");
861 } else {
862 g_string_append(ctx->str, " (Double precision)");
863 }
864
865 break;
866 case BT_FIELD_CLASS_TYPE_STRUCTURE:
867 {
868 uint64_t member_count =
869 bt_field_class_structure_get_member_count(fc);
870
871 g_string_append(ctx->str, " (");
872 write_uint_prop_value(ctx, member_count);
873 g_string_append_printf(ctx->str, " member%s)",
874 plural(member_count));
875
876 if (member_count > 0) {
877 g_string_append_c(ctx->str, ':');
878 incr_indent(ctx);
879
880 for (i = 0; i < member_count; i++) {
881 const bt_field_class_structure_member *member =
882 bt_field_class_structure_borrow_member_by_index_const(
883 fc, i);
884
885 write_nl(ctx);
886 write_compound_member_name(ctx,
887 bt_field_class_structure_member_get_name(member));
888 write_sp(ctx);
889 write_field_class(ctx,
890 bt_field_class_structure_member_borrow_field_class_const(member));
891 }
892
893 decr_indent(ctx);
894 }
895
896 break;
897 }
898 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
899 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
900 if (fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
901 g_string_append(ctx->str, " (Length ");
902 write_uint_prop_value(ctx,
903 bt_field_class_array_static_get_length(fc));
904 g_string_append_c(ctx->str, ')');
905 } else {
906 const bt_field_path *length_field_path =
907 bt_field_class_array_dynamic_borrow_length_field_path_const(
908 fc);
909
910 if (length_field_path) {
911 g_string_append(ctx->str, " (Length field path ");
912 write_field_path(ctx, length_field_path);
913 g_string_append_c(ctx->str, ')');
914 }
915 }
916
917 g_string_append_c(ctx->str, ':');
918 write_nl(ctx);
919 incr_indent(ctx);
920 write_compound_member_name(ctx, "Element");
921 write_sp(ctx);
922 write_field_class(ctx,
923 bt_field_class_array_borrow_element_field_class_const(fc));
924 decr_indent(ctx);
925 break;
926 case BT_FIELD_CLASS_TYPE_OPTION:
927 {
928 const bt_field_path *selector_field_path =
929 bt_field_class_option_borrow_selector_field_path_const(fc);
930
931 if (selector_field_path) {
932 g_string_append(ctx->str, " (Selector field path ");
933 write_field_path(ctx, selector_field_path);
934 g_string_append_c(ctx->str, ')');
935 }
936
937 g_string_append_c(ctx->str, ':');
938 write_nl(ctx);
939 incr_indent(ctx);
940 write_compound_member_name(ctx, "Content");
941 write_sp(ctx);
942 write_field_class(ctx,
943 bt_field_class_option_borrow_field_class_const(fc));
944 decr_indent(ctx);
945 break;
946 }
947 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
948 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
949 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
950 write_variant_field_class(ctx, fc);
951 break;
952 default:
953 break;
954 }
955 }
956
957 static
958 void write_root_field_class(struct details_write_ctx *ctx, const char *name,
959 const bt_field_class *fc)
960 {
961 BT_ASSERT(name);
962 BT_ASSERT(fc);
963 write_indent(ctx);
964 write_prop_name(ctx, name);
965 g_string_append(ctx->str, ": ");
966 write_field_class(ctx, fc);
967 write_nl(ctx);
968 }
969
970 static
971 void write_event_class(struct details_write_ctx *ctx, const bt_event_class *ec)
972 {
973 const char *name = bt_event_class_get_name(ec);
974 const char *emf_uri;
975 const bt_field_class *fc;
976 bt_event_class_log_level log_level;
977
978 write_indent(ctx);
979 write_obj_type_name(ctx, "Event class");
980
981 /* Write name and ID */
982 if (name) {
983 g_string_append_printf(ctx->str, " `%s%s%s`",
984 color_fg_green(ctx), name, color_reset(ctx));
985 }
986
987 g_string_append(ctx->str, " (ID ");
988 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
989 g_string_append(ctx->str, "):\n");
990
991 /* Write properties */
992 incr_indent(ctx);
993
994 /* Write log level */
995 if (bt_event_class_get_log_level(ec, &log_level) ==
996 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
997 const char *ll_str = NULL;
998
999 switch (log_level) {
1000 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
1001 ll_str = "Emergency";
1002 break;
1003 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
1004 ll_str = "Alert";
1005 break;
1006 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
1007 ll_str = "Critical";
1008 break;
1009 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
1010 ll_str = "Error";
1011 break;
1012 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
1013 ll_str = "Warning";
1014 break;
1015 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
1016 ll_str = "Notice";
1017 break;
1018 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
1019 ll_str = "Info";
1020 break;
1021 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
1022 ll_str = "Debug (system)";
1023 break;
1024 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
1025 ll_str = "Debug (program)";
1026 break;
1027 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
1028 ll_str = "Debug (process)";
1029 break;
1030 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
1031 ll_str = "Debug (module)";
1032 break;
1033 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
1034 ll_str = "Debug (unit)";
1035 break;
1036 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
1037 ll_str = "Debug (function)";
1038 break;
1039 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
1040 ll_str = "Debug (line)";
1041 break;
1042 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
1043 ll_str = "Debug";
1044 break;
1045 default:
1046 abort();
1047 }
1048
1049 write_str_prop_line(ctx, "Log level", ll_str);
1050 }
1051
1052 /* Write EMF URI */
1053 emf_uri = bt_event_class_get_emf_uri(ec);
1054 if (emf_uri) {
1055 write_str_prop_line(ctx, "EMF URI", emf_uri);
1056 }
1057
1058 /* Write specific context field class */
1059 fc = bt_event_class_borrow_specific_context_field_class_const(ec);
1060 if (fc) {
1061 write_root_field_class(ctx, "Specific context field class", fc);
1062 }
1063
1064 /* Write payload field class */
1065 fc = bt_event_class_borrow_payload_field_class_const(ec);
1066 if (fc) {
1067 write_root_field_class(ctx, "Payload field class", fc);
1068 }
1069
1070 decr_indent(ctx);
1071 }
1072
1073 static
1074 void write_clock_class_prop_lines(struct details_write_ctx *ctx,
1075 const bt_clock_class *cc)
1076 {
1077 int64_t offset_seconds;
1078 uint64_t offset_cycles;
1079 const char *str;
1080
1081 str = bt_clock_class_get_name(cc);
1082 if (str) {
1083 write_str_prop_line(ctx, "Name", str);
1084 }
1085
1086 str = bt_clock_class_get_description(cc);
1087 if (str) {
1088 write_str_prop_line(ctx, "Description", str);
1089 }
1090
1091 write_uint_prop_line(ctx, "Frequency (Hz)",
1092 bt_clock_class_get_frequency(cc));
1093 write_uint_prop_line(ctx, "Precision (cycles)",
1094 bt_clock_class_get_precision(cc));
1095 bt_clock_class_get_offset(cc, &offset_seconds, &offset_cycles);
1096 write_int_prop_line(ctx, "Offset (s)", offset_seconds);
1097 write_uint_prop_line(ctx, "Offset (cycles)", offset_cycles);
1098 write_bool_prop_line(ctx, "Origin is Unix epoch",
1099 bt_clock_class_origin_is_unix_epoch(cc));
1100
1101 if (ctx->details_comp->cfg.with_uuid) {
1102 bt_uuid uuid = bt_clock_class_get_uuid(cc);
1103
1104 if (uuid) {
1105 write_uuid_prop_line(ctx, "UUID", uuid);
1106 }
1107 }
1108 }
1109
1110 static
1111 gint compare_event_classes(const bt_event_class **a, const bt_event_class **b)
1112 {
1113 uint64_t id_a = bt_event_class_get_id(*a);
1114 uint64_t id_b = bt_event_class_get_id(*b);
1115
1116 if (id_a < id_b) {
1117 return -1;
1118 } else if (id_a > id_b) {
1119 return 1;
1120 } else {
1121 return 0;
1122 }
1123 }
1124
1125 static
1126 void write_stream_class(struct details_write_ctx *ctx,
1127 const bt_stream_class *sc)
1128 {
1129 const bt_field_class *fc;
1130 GPtrArray *event_classes = g_ptr_array_new();
1131 uint64_t i;
1132
1133 write_indent(ctx);
1134 write_obj_type_name(ctx, "Stream class");
1135
1136 /* Write name and ID */
1137 if (ctx->details_comp->cfg.with_stream_class_name) {
1138 const char *name = bt_stream_class_get_name(sc);
1139
1140 if (name) {
1141 g_string_append(ctx->str, " `");
1142 write_str_prop_value(ctx, name);
1143 g_string_append(ctx->str, "`");
1144 }
1145 }
1146
1147 g_string_append(ctx->str, " (ID ");
1148 write_uint_prop_value(ctx, bt_stream_class_get_id(sc));
1149 g_string_append(ctx->str, "):\n");
1150
1151 /* Write properties */
1152 incr_indent(ctx);
1153
1154 /* Write configuration */
1155 write_bool_prop_line(ctx,
1156 "Supports packets", bt_stream_class_supports_packets(sc));
1157
1158 if (bt_stream_class_supports_packets(sc)) {
1159 write_bool_prop_line(ctx,
1160 "Packets have beginning default clock snapshot",
1161 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
1162 write_bool_prop_line(ctx,
1163 "Packets have end default clock snapshot",
1164 bt_stream_class_packets_have_end_default_clock_snapshot(sc));
1165 }
1166
1167 write_bool_prop_line(ctx,
1168 "Supports discarded events",
1169 bt_stream_class_supports_discarded_events(sc));
1170
1171 if (bt_stream_class_supports_discarded_events(sc)) {
1172 write_bool_prop_line(ctx,
1173 "Discarded events have default clock snapshots",
1174 bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
1175 }
1176
1177 write_bool_prop_line(ctx,
1178 "Supports discarded packets",
1179 bt_stream_class_supports_discarded_packets(sc));
1180
1181 if (bt_stream_class_supports_discarded_packets(sc)) {
1182 write_bool_prop_line(ctx,
1183 "Discarded packets have default clock snapshots",
1184 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
1185 }
1186
1187 /* Write default clock class */
1188 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1189 write_indent(ctx);
1190 write_prop_name(ctx, "Default clock class");
1191 g_string_append_c(ctx->str, ':');
1192 write_nl(ctx);
1193 incr_indent(ctx);
1194 write_clock_class_prop_lines(ctx,
1195 bt_stream_class_borrow_default_clock_class_const(sc));
1196 decr_indent(ctx);
1197 }
1198
1199 fc = bt_stream_class_borrow_packet_context_field_class_const(sc);
1200 if (fc) {
1201 write_root_field_class(ctx, "Packet context field class", fc);
1202 }
1203
1204 fc = bt_stream_class_borrow_event_common_context_field_class_const(sc);
1205 if (fc) {
1206 write_root_field_class(ctx, "Event common context field class",
1207 fc);
1208 }
1209
1210 for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
1211 g_ptr_array_add(event_classes,
1212 (gpointer) bt_stream_class_borrow_event_class_by_index_const(
1213 sc, i));
1214 }
1215
1216 g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
1217
1218 for (i = 0; i < event_classes->len; i++) {
1219 write_event_class(ctx, event_classes->pdata[i]);
1220 }
1221
1222 decr_indent(ctx);
1223 g_ptr_array_free(event_classes, TRUE);
1224 }
1225
1226 static
1227 gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
1228 {
1229 uint64_t id_a = bt_stream_class_get_id(*a);
1230 uint64_t id_b = bt_stream_class_get_id(*b);
1231
1232 if (id_a < id_b) {
1233 return -1;
1234 } else if (id_a > id_b) {
1235 return 1;
1236 } else {
1237 return 0;
1238 }
1239 }
1240
1241 static
1242 gint compare_strings(const char **a, const char **b)
1243 {
1244 return strcmp(*a, *b);
1245 }
1246
1247 static
1248 void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
1249 {
1250 GPtrArray *stream_classes = g_ptr_array_new();
1251 uint64_t i;
1252 bool printed_prop = false;
1253
1254 write_indent(ctx);
1255 write_obj_type_name(ctx, "Trace class");
1256
1257 for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
1258 g_ptr_array_add(stream_classes,
1259 (gpointer) bt_trace_class_borrow_stream_class_by_index_const(
1260 tc, i));
1261 }
1262
1263 g_ptr_array_sort(stream_classes, (GCompareFunc) compare_stream_classes);
1264
1265 if (stream_classes->len > 0) {
1266 if (!printed_prop) {
1267 g_string_append(ctx->str, ":\n");
1268 printed_prop = true;
1269 }
1270 }
1271
1272 incr_indent(ctx);
1273
1274 for (i = 0; i < stream_classes->len; i++) {
1275 write_stream_class(ctx, stream_classes->pdata[i]);
1276 }
1277
1278 if (!printed_prop) {
1279 write_nl(ctx);
1280 }
1281
1282 decr_indent(ctx);
1283 g_ptr_array_free(stream_classes, TRUE);
1284 }
1285
1286 static
1287 int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
1288 const bt_stream_class *sc, const bt_event_class *ec)
1289 {
1290 int ret = 0;
1291
1292 BT_ASSERT(tc);
1293
1294 if (details_need_to_write_trace_class(ctx, tc)) {
1295 uint64_t sc_i;
1296
1297 if (ctx->details_comp->cfg.compact &&
1298 ctx->details_comp->printed_something) {
1299 /*
1300 * There are no empty line between messages in
1301 * compact mode, so write one here to decouple
1302 * the trace class from the next message.
1303 */
1304 write_nl(ctx);
1305 }
1306
1307 /*
1308 * write_trace_class() also writes all its stream
1309 * classes their event classes, so we don't need to
1310 * rewrite `sc`.
1311 */
1312 write_trace_class(ctx, tc);
1313 write_nl(ctx);
1314
1315 /*
1316 * Mark this trace class as written, as well as all
1317 * its stream classes and their event classes.
1318 */
1319 ret = details_did_write_trace_class(ctx, tc);
1320 if (ret) {
1321 goto end;
1322 }
1323
1324 for (sc_i = 0; sc_i < bt_trace_class_get_stream_class_count(tc);
1325 sc_i++) {
1326 uint64_t ec_i;
1327 const bt_stream_class *tc_sc =
1328 bt_trace_class_borrow_stream_class_by_index_const(
1329 tc, sc_i);
1330
1331 details_did_write_meta_object(ctx, tc, tc_sc);
1332
1333 for (ec_i = 0; ec_i <
1334 bt_stream_class_get_event_class_count(tc_sc);
1335 ec_i++) {
1336 details_did_write_meta_object(ctx, tc,
1337 bt_stream_class_borrow_event_class_by_index_const(
1338 tc_sc, ec_i));
1339 }
1340 }
1341
1342 goto end;
1343 }
1344
1345 if (sc && details_need_to_write_meta_object(ctx, tc, sc)) {
1346 uint64_t ec_i;
1347
1348 BT_ASSERT(tc);
1349
1350 if (ctx->details_comp->cfg.compact &&
1351 ctx->details_comp->printed_something) {
1352 /*
1353 * There are no empty line between messages in
1354 * compact mode, so write one here to decouple
1355 * the stream class from the next message.
1356 */
1357 write_nl(ctx);
1358 }
1359
1360 /*
1361 * write_stream_class() also writes all its event
1362 * classes, so we don't need to rewrite `ec`.
1363 */
1364 write_stream_class(ctx, sc);
1365 write_nl(ctx);
1366
1367 /*
1368 * Mark this stream class as written, as well as all its
1369 * event classes.
1370 */
1371 details_did_write_meta_object(ctx, tc, sc);
1372
1373 for (ec_i = 0; ec_i <
1374 bt_stream_class_get_event_class_count(sc);
1375 ec_i++) {
1376 details_did_write_meta_object(ctx, tc,
1377 bt_stream_class_borrow_event_class_by_index_const(
1378 sc, ec_i));
1379 }
1380
1381 goto end;
1382 }
1383
1384 if (ec && details_need_to_write_meta_object(ctx, tc, ec)) {
1385 BT_ASSERT(sc);
1386
1387 if (ctx->details_comp->cfg.compact &&
1388 ctx->details_comp->printed_something) {
1389 /*
1390 * There are no empty line between messages in
1391 * compact mode, so write one here to decouple
1392 * the event class from the next message.
1393 */
1394 write_nl(ctx);
1395 }
1396
1397 write_event_class(ctx, ec);
1398 write_nl(ctx);
1399 details_did_write_meta_object(ctx, tc, ec);
1400 goto end;
1401 }
1402
1403 end:
1404 return ret;
1405 }
1406
1407 static
1408 void write_time_str(struct details_write_ctx *ctx, const char *str)
1409 {
1410 if (!ctx->details_comp->cfg.with_time) {
1411 goto end;
1412 }
1413
1414 g_string_append_printf(ctx->str, "[%s%s%s%s]",
1415 color_bold(ctx), color_fg_blue(ctx), str, color_reset(ctx));
1416
1417 if (ctx->details_comp->cfg.compact) {
1418 write_sp(ctx);
1419 } else {
1420 write_nl(ctx);
1421 }
1422
1423 end:
1424 return;
1425 }
1426
1427 static
1428 void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
1429 {
1430 bt_clock_snapshot_get_ns_from_origin_status cs_status;
1431 int64_t ns_from_origin;
1432 char buf[32];
1433
1434 if (!ctx->details_comp->cfg.with_time) {
1435 goto end;
1436 }
1437
1438 format_uint(buf, bt_clock_snapshot_get_value(cs), 10);
1439 g_string_append_printf(ctx->str, "[%s%s%s%s%s",
1440 color_bold(ctx), color_fg_blue(ctx), buf,
1441 color_reset(ctx),
1442 ctx->details_comp->cfg.compact ? "" : " cycles");
1443 cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
1444 if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
1445 format_int(buf, ns_from_origin, 10);
1446 g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
1447 ctx->details_comp->cfg.compact ? "" : ",",
1448 color_bold(ctx), color_fg_blue(ctx), buf,
1449 color_reset(ctx),
1450 ctx->details_comp->cfg.compact ? "" : " ns from origin");
1451 }
1452
1453 g_string_append(ctx->str, "]");
1454
1455 if (ctx->details_comp->cfg.compact) {
1456 write_sp(ctx);
1457 } else {
1458 write_nl(ctx);
1459 }
1460
1461 end:
1462 return;
1463 }
1464
1465 static
1466 int write_message_follow_tag(struct details_write_ctx *ctx,
1467 const bt_stream *stream)
1468 {
1469 int ret;
1470 uint64_t unique_trace_id;
1471 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1472 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1473
1474 ret = details_trace_unique_id(ctx, trace, &unique_trace_id);
1475 if (ret) {
1476 goto end;
1477 }
1478
1479 if (ctx->details_comp->cfg.compact) {
1480 g_string_append_printf(ctx->str,
1481 "%s{%s%" PRIu64 " %" PRIu64 " %" PRIu64 "%s%s}%s ",
1482 color_fg_cyan(ctx), color_bold(ctx),
1483 unique_trace_id, bt_stream_class_get_id(sc),
1484 bt_stream_get_id(stream),
1485 color_reset(ctx), color_fg_cyan(ctx), color_reset(ctx));
1486 } else {
1487 g_string_append_printf(ctx->str,
1488 "%s{Trace %s%" PRIu64 "%s%s, Stream class ID %s%" PRIu64 "%s%s, Stream ID %s%" PRIu64 "%s%s}%s\n",
1489 color_fg_cyan(ctx),
1490 color_bold(ctx), unique_trace_id,
1491 color_reset(ctx), color_fg_cyan(ctx),
1492 color_bold(ctx), bt_stream_class_get_id(sc),
1493 color_reset(ctx), color_fg_cyan(ctx),
1494 color_bold(ctx), bt_stream_get_id(stream),
1495 color_reset(ctx), color_fg_cyan(ctx),
1496 color_reset(ctx));
1497 }
1498
1499 end:
1500 return ret;
1501 }
1502
1503 static
1504 void write_field(struct details_write_ctx *ctx, const bt_field *field,
1505 const char *name)
1506 {
1507 uint64_t i;
1508 bt_field_class_type fc_type = bt_field_get_class_type(field);
1509 const bt_field_class *fc;
1510 char buf[64];
1511
1512 /* Write field's name */
1513 if (name) {
1514 write_compound_member_name(ctx, name);
1515 }
1516
1517 /* Write field's value */
1518 switch (fc_type) {
1519 case BT_FIELD_CLASS_TYPE_BOOL:
1520 write_sp(ctx);
1521 write_bool_prop_value(ctx, bt_field_bool_get_value(field));
1522 break;
1523 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1524 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1525 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1526 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1527 {
1528 unsigned int fmt_base;
1529 bt_field_class_integer_preferred_display_base base;
1530
1531 fc = bt_field_borrow_class_const(field);
1532 base = bt_field_class_integer_get_preferred_display_base(fc);
1533
1534 switch (base) {
1535 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
1536 fmt_base = 10;
1537 break;
1538 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
1539 fmt_base = 8;
1540 break;
1541 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
1542 fmt_base = 2;
1543 break;
1544 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
1545 fmt_base = 16;
1546 break;
1547 default:
1548 abort();
1549 }
1550
1551 if (fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
1552 fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
1553 format_uint(buf,
1554 bt_field_integer_unsigned_get_value(field),
1555 fmt_base);
1556 write_sp(ctx);
1557 write_uint_str_prop_value(ctx, buf);
1558 } else {
1559 format_int(buf,
1560 bt_field_integer_signed_get_value(field),
1561 fmt_base);
1562 write_sp(ctx);
1563 write_int_str_prop_value(ctx, buf);
1564 }
1565
1566 break;
1567 }
1568 case BT_FIELD_CLASS_TYPE_REAL:
1569 write_sp(ctx);
1570 write_float_prop_value(ctx, bt_field_real_get_value(field));
1571 break;
1572 case BT_FIELD_CLASS_TYPE_STRING:
1573 write_sp(ctx);
1574 write_str_prop_value(ctx, bt_field_string_get_value(field));
1575 break;
1576 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1577 {
1578 uint64_t member_count;
1579
1580 fc = bt_field_borrow_class_const(field);
1581 member_count = bt_field_class_structure_get_member_count(fc);
1582
1583 if (member_count > 0) {
1584 incr_indent(ctx);
1585
1586 for (i = 0; i < member_count; i++) {
1587 const bt_field_class_structure_member *member =
1588 bt_field_class_structure_borrow_member_by_index_const(
1589 fc, i);
1590 const bt_field *member_field =
1591 bt_field_structure_borrow_member_field_by_index_const(
1592 field, i);
1593
1594 write_nl(ctx);
1595 write_field(ctx, member_field,
1596 bt_field_class_structure_member_get_name(member));
1597 }
1598
1599 decr_indent(ctx);
1600 } else {
1601 g_string_append(ctx->str, " Empty");
1602 }
1603
1604 break;
1605 }
1606 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1607 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1608 {
1609 uint64_t length = bt_field_array_get_length(field);
1610
1611 if (length == 0) {
1612 g_string_append(ctx->str, " Empty");
1613 } else {
1614 g_string_append(ctx->str, " Length ");
1615 write_uint_prop_value(ctx, length);
1616 g_string_append_c(ctx->str, ':');
1617 }
1618
1619 incr_indent(ctx);
1620
1621 for (i = 0; i < length; i++) {
1622 const bt_field *elem_field =
1623 bt_field_array_borrow_element_field_by_index_const(
1624 field, i);
1625
1626 write_nl(ctx);
1627 write_array_index(ctx, i);
1628 write_field(ctx, elem_field, NULL);
1629 }
1630
1631 decr_indent(ctx);
1632 break;
1633 }
1634 case BT_FIELD_CLASS_TYPE_OPTION:
1635 {
1636 const bt_field *content_field =
1637 bt_field_option_borrow_field_const(field);
1638
1639 if (!content_field) {
1640 write_sp(ctx);
1641 write_none_prop_value(ctx, "None");
1642 } else {
1643 write_field(ctx, content_field, NULL);
1644 }
1645
1646 break;
1647 }
1648 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1649 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1650 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
1651 write_field(ctx,
1652 bt_field_variant_borrow_selected_option_field_const(
1653 field), NULL);
1654 break;
1655 default:
1656 abort();
1657 }
1658 }
1659
1660 static
1661 void write_root_field(struct details_write_ctx *ctx, const char *name,
1662 const bt_field *field)
1663 {
1664 BT_ASSERT(name);
1665 BT_ASSERT(field);
1666 write_indent(ctx);
1667 write_prop_name(ctx, name);
1668 g_string_append(ctx->str, ":");
1669 write_field(ctx, field, NULL);
1670 write_nl(ctx);
1671 }
1672
1673 static
1674 int write_event_message(struct details_write_ctx *ctx,
1675 const bt_message *msg)
1676 {
1677 int ret = 0;
1678 const bt_event *event = bt_message_event_borrow_event_const(msg);
1679 const bt_stream *stream = bt_event_borrow_stream_const(event);
1680 const bt_event_class *ec = bt_event_borrow_class_const(event);
1681 const bt_stream_class *sc = bt_event_class_borrow_stream_class_const(ec);
1682 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1683 const char *ec_name;
1684 const bt_field *field;
1685
1686 ret = try_write_meta(ctx, tc, sc, ec);
1687 if (ret) {
1688 goto end;
1689 }
1690
1691 /* Write time */
1692 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1693 write_time(ctx,
1694 bt_message_event_borrow_default_clock_snapshot_const(
1695 msg));
1696 }
1697
1698 /* Write follow tag for message */
1699 ret = write_message_follow_tag(ctx, stream);
1700 if (ret) {
1701 goto end;
1702 }
1703
1704 /* Write object's basic properties */
1705 write_obj_type_name(ctx, "Event");
1706 ec_name = bt_event_class_get_name(ec);
1707 if (ec_name) {
1708 g_string_append_printf(ctx->str, " `%s%s%s`",
1709 color_fg_green(ctx), ec_name, color_reset(ctx));
1710 }
1711
1712 g_string_append(ctx->str, " (");
1713
1714 if (!ctx->details_comp->cfg.compact) {
1715 g_string_append(ctx->str, "Class ID ");
1716 }
1717
1718 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1719 g_string_append(ctx->str, ")");
1720
1721 if (ctx->details_comp->cfg.compact) {
1722 write_nl(ctx);
1723 goto end;
1724 }
1725
1726 /* Write fields */
1727 g_string_append(ctx->str, ":\n");
1728 incr_indent(ctx);
1729 field = bt_event_borrow_common_context_field_const(event);
1730 if (field) {
1731 write_root_field(ctx, "Common context", field);
1732 }
1733
1734 field = bt_event_borrow_specific_context_field_const(event);
1735 if (field) {
1736 write_root_field(ctx, "Specific context", field);
1737 }
1738
1739 field = bt_event_borrow_payload_field_const(event);
1740 if (field) {
1741 write_root_field(ctx, "Payload", field);
1742 }
1743
1744 decr_indent(ctx);
1745
1746 end:
1747
1748 return ret;
1749 }
1750
1751 static
1752 gint compare_streams(const bt_stream **a, const bt_stream **b)
1753 {
1754 uint64_t id_a = bt_stream_get_id(*a);
1755 uint64_t id_b = bt_stream_get_id(*b);
1756
1757 if (id_a < id_b) {
1758 return -1;
1759 } else if (id_a > id_b) {
1760 return 1;
1761 } else {
1762 const bt_stream_class *a_sc = bt_stream_borrow_class_const(*a);
1763 const bt_stream_class *b_sc = bt_stream_borrow_class_const(*b);
1764 uint64_t a_sc_id = bt_stream_class_get_id(a_sc);
1765 uint64_t b_sc_id = bt_stream_class_get_id(b_sc);
1766
1767 if (a_sc_id < b_sc_id) {
1768 return -1;
1769 } else if (a_sc_id > b_sc_id) {
1770 return 1;
1771 } else {
1772 return 0;
1773 }
1774 }
1775 }
1776
1777 static
1778 void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
1779 {
1780 const char *name;
1781 GPtrArray *streams = g_ptr_array_new();
1782 uint64_t i;
1783 bool printed_prop = false;
1784 GPtrArray *env_names = g_ptr_array_new();
1785 uint64_t env_count;
1786
1787 write_indent(ctx);
1788 write_obj_type_name(ctx, "Trace");
1789
1790 /* Write name */
1791 if (ctx->details_comp->cfg.with_trace_name) {
1792 name = bt_trace_get_name(trace);
1793 if (name) {
1794 g_string_append(ctx->str, " `");
1795 write_str_prop_value(ctx, name);
1796 g_string_append(ctx->str, "`");
1797 }
1798 }
1799
1800 /* Write properties */
1801 incr_indent(ctx);
1802
1803 /* Write UUID */
1804 if (ctx->details_comp->cfg.with_uuid) {
1805 bt_uuid uuid = bt_trace_get_uuid(trace);
1806
1807 if (uuid) {
1808 if (!printed_prop) {
1809 g_string_append(ctx->str, ":\n");
1810 printed_prop = true;
1811 }
1812
1813 write_uuid_prop_line(ctx, "UUID", uuid);
1814 }
1815 }
1816
1817 /* Write environment */
1818 env_count = bt_trace_get_environment_entry_count(trace);
1819 if (env_count > 0) {
1820 if (!printed_prop) {
1821 g_string_append(ctx->str, ":\n");
1822 printed_prop = true;
1823 }
1824
1825 write_indent(ctx);
1826 write_prop_name(ctx, "Environment");
1827 g_string_append(ctx->str, " (");
1828 write_uint_prop_value(ctx, env_count);
1829 g_string_append_printf(ctx->str, " entr%s):",
1830 env_count == 1 ? "y" : "ies");
1831 write_nl(ctx);
1832 incr_indent(ctx);
1833
1834 for (i = 0; i < env_count; i++) {
1835 const char *name;
1836 const bt_value *value;
1837
1838 bt_trace_borrow_environment_entry_by_index_const(
1839 trace, i, &name, &value);
1840 g_ptr_array_add(env_names, (gpointer) name);
1841 }
1842
1843 g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
1844
1845 for (i = 0; i < env_names->len; i++) {
1846 const char *name = env_names->pdata[i];
1847 const bt_value *value =
1848 bt_trace_borrow_environment_entry_value_by_name_const(
1849 trace, name);
1850
1851 BT_ASSERT(value);
1852 write_compound_member_name(ctx, name);
1853 write_sp(ctx);
1854
1855 if (bt_value_get_type(value) ==
1856 BT_VALUE_TYPE_SIGNED_INTEGER) {
1857 write_int_prop_value(ctx,
1858 bt_value_integer_signed_get(value));
1859 } else if (bt_value_get_type(value) ==
1860 BT_VALUE_TYPE_STRING) {
1861 write_str_prop_value(ctx,
1862 bt_value_string_get(value));
1863 } else {
1864 abort();
1865 }
1866
1867 write_nl(ctx);
1868 }
1869
1870 decr_indent(ctx);
1871 }
1872
1873 for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
1874 g_ptr_array_add(streams,
1875 (gpointer) bt_trace_borrow_stream_by_index_const(
1876 trace, i));
1877 }
1878
1879 g_ptr_array_sort(streams, (GCompareFunc) compare_streams);
1880
1881 if (streams->len > 0 && !printed_prop) {
1882 g_string_append(ctx->str, ":\n");
1883 printed_prop = true;
1884 }
1885
1886 for (i = 0; i < streams->len; i++) {
1887 const bt_stream *stream = streams->pdata[i];
1888
1889 write_indent(ctx);
1890 write_obj_type_name(ctx, "Stream");
1891 g_string_append(ctx->str, " (ID ");
1892 write_uint_prop_value(ctx, bt_stream_get_id(stream));
1893 g_string_append(ctx->str, ", Class ID ");
1894 write_uint_prop_value(ctx, bt_stream_class_get_id(
1895 bt_stream_borrow_class_const(stream)));
1896 g_string_append(ctx->str, ")");
1897 write_nl(ctx);
1898 }
1899
1900 decr_indent(ctx);
1901
1902 if (!printed_prop) {
1903 write_nl(ctx);
1904 }
1905
1906 g_ptr_array_free(streams, TRUE);
1907 g_ptr_array_free(env_names, TRUE);
1908 }
1909
1910 static
1911 int write_stream_beginning_message(struct details_write_ctx *ctx,
1912 const bt_message *msg)
1913 {
1914 int ret = 0;
1915 const bt_stream *stream =
1916 bt_message_stream_beginning_borrow_stream_const(msg);
1917 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1918 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1919 const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
1920 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1921 const char *name;
1922
1923 ret = try_write_meta(ctx, tc, sc, NULL);
1924 if (ret) {
1925 goto end;
1926 }
1927
1928 /* Write time */
1929 if (cc) {
1930 const bt_clock_snapshot *cs;
1931 bt_message_stream_clock_snapshot_state cs_state =
1932 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
1933
1934 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1935 write_time(ctx, cs);
1936 } else {
1937 write_time_str(ctx, "Unknown");
1938 }
1939 }
1940
1941 /* Write follow tag for message */
1942 ret = write_message_follow_tag(ctx, stream);
1943 if (ret) {
1944 goto end;
1945 }
1946
1947 /* Write stream properties */
1948 write_obj_type_name(ctx, "Stream beginning");
1949
1950 if (ctx->details_comp->cfg.compact) {
1951 write_nl(ctx);
1952 goto end;
1953 }
1954
1955 g_string_append(ctx->str, ":\n");
1956 incr_indent(ctx);
1957
1958 if (ctx->details_comp->cfg.with_stream_name) {
1959 name = bt_stream_get_name(stream);
1960 if (name) {
1961 write_str_prop_line(ctx, "Name", name);
1962 }
1963 }
1964
1965 if (ctx->details_comp->cfg.with_stream_class_name) {
1966 name = bt_stream_class_get_name(sc);
1967 if (name) {
1968 write_str_prop_line(ctx, "Class name", name);
1969 }
1970 }
1971
1972 write_trace(ctx, trace);
1973 decr_indent(ctx);
1974
1975 end:
1976 return ret;
1977 }
1978
1979 static
1980 int write_stream_end_message(struct details_write_ctx *ctx,
1981 const bt_message *msg)
1982 {
1983 int ret = 0;
1984 const bt_stream *stream =
1985 bt_message_stream_end_borrow_stream_const(msg);
1986 const bt_stream_class *sc =
1987 bt_stream_borrow_class_const(stream);
1988 const bt_clock_class *cc =
1989 bt_stream_class_borrow_default_clock_class_const(sc);
1990
1991 /* Write time */
1992 if (cc) {
1993 const bt_clock_snapshot *cs;
1994 bt_message_stream_clock_snapshot_state cs_state =
1995 bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
1996
1997 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1998 write_time(ctx, cs);
1999 } else {
2000 write_time_str(ctx, "Unknown");
2001 }
2002 }
2003
2004 /* Write follow tag for message */
2005 ret = write_message_follow_tag(ctx, stream);
2006 if (ret) {
2007 goto end;
2008 }
2009
2010 /* Write stream properties */
2011 write_obj_type_name(ctx, "Stream end\n");
2012
2013 end:
2014 return ret;
2015 }
2016
2017 static
2018 int write_packet_beginning_message(struct details_write_ctx *ctx,
2019 const bt_message *msg)
2020 {
2021 int ret = 0;
2022 const bt_packet *packet =
2023 bt_message_packet_beginning_borrow_packet_const(msg);
2024 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2025 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2026 const bt_field *field;
2027
2028 /* Write time */
2029 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
2030 write_time(ctx,
2031 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2032 msg));
2033 }
2034
2035 /* Write follow tag for message */
2036 ret = write_message_follow_tag(ctx, stream);
2037 if (ret) {
2038 goto end;
2039 }
2040
2041 write_obj_type_name(ctx, "Packet beginning");
2042
2043 if (ctx->details_comp->cfg.compact) {
2044 write_nl(ctx);
2045 goto end;
2046 }
2047
2048 /* Write field */
2049 g_string_append(ctx->str, ":\n");
2050 incr_indent(ctx);
2051 field = bt_packet_borrow_context_field_const(packet);
2052 if (field) {
2053 write_root_field(ctx, "Context", field);
2054 }
2055
2056 decr_indent(ctx);
2057
2058 end:
2059 return ret;
2060 }
2061
2062 static
2063 int write_discarded_items_message(struct details_write_ctx *ctx,
2064 const char *name, const bt_stream *stream,
2065 const bt_clock_snapshot *beginning_cs,
2066 const bt_clock_snapshot *end_cs, uint64_t count)
2067 {
2068 int ret = 0;
2069
2070 /* Write times */
2071 if (beginning_cs) {
2072 write_time(ctx, beginning_cs);
2073 BT_ASSERT(end_cs);
2074 write_time(ctx, end_cs);
2075 }
2076
2077 /* Write follow tag for message */
2078 ret = write_message_follow_tag(ctx, stream);
2079 if (ret) {
2080 goto end;
2081 }
2082
2083 write_obj_type_name(ctx, "Discarded ");
2084 write_obj_type_name(ctx, name);
2085
2086 /* Write count */
2087 if (count == UINT64_C(-1)) {
2088 write_nl(ctx);
2089 goto end;
2090 }
2091
2092 g_string_append(ctx->str, " (");
2093 write_uint_prop_value(ctx, count);
2094 g_string_append_printf(ctx->str, " %s)\n", name);
2095
2096 end:
2097 return ret;
2098 }
2099
2100 static
2101 int write_discarded_events_message(struct details_write_ctx *ctx,
2102 const bt_message *msg)
2103 {
2104 const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
2105 msg);
2106 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2107 const bt_clock_snapshot *beginning_cs = NULL;
2108 const bt_clock_snapshot *end_cs = NULL;
2109 uint64_t count;
2110
2111 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
2112 beginning_cs =
2113 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2114 msg);
2115 end_cs =
2116 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2117 msg);
2118 }
2119
2120 if (bt_message_discarded_events_get_count(msg, &count) !=
2121 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2122 count = UINT64_C(-1);
2123 }
2124
2125 return write_discarded_items_message(ctx, "events", stream,
2126 beginning_cs, end_cs, count);
2127 }
2128
2129 static
2130 int write_discarded_packets_message(struct details_write_ctx *ctx,
2131 const bt_message *msg)
2132 {
2133 const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
2134 msg);
2135 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2136 const bt_clock_snapshot *beginning_cs = NULL;
2137 const bt_clock_snapshot *end_cs = NULL;
2138 uint64_t count;
2139
2140 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
2141 beginning_cs =
2142 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2143 msg);
2144 end_cs =
2145 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2146 msg);
2147 }
2148
2149 if (bt_message_discarded_packets_get_count(msg, &count) !=
2150 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2151 count = UINT64_C(-1);
2152 }
2153
2154 return write_discarded_items_message(ctx, "packets", stream,
2155 beginning_cs, end_cs, count);
2156 }
2157
2158 static
2159 int write_packet_end_message(struct details_write_ctx *ctx,
2160 const bt_message *msg)
2161 {
2162 int ret = 0;
2163 const bt_packet *packet =
2164 bt_message_packet_end_borrow_packet_const(msg);
2165 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2166 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2167
2168 /* Write time */
2169 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
2170 write_time(ctx,
2171 bt_message_packet_end_borrow_default_clock_snapshot_const(
2172 msg));
2173 }
2174
2175 /* Write follow tag for message */
2176 ret = write_message_follow_tag(ctx, stream);
2177 if (ret) {
2178 goto end;
2179 }
2180
2181 write_obj_type_name(ctx, "Packet end");
2182 write_nl(ctx);
2183
2184 end:
2185 return ret;
2186 }
2187
2188 static
2189 int write_message_iterator_inactivity_message(struct details_write_ctx *ctx,
2190 const bt_message *msg)
2191 {
2192 int ret = 0;
2193 const bt_clock_snapshot *cs =
2194 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
2195 msg);
2196
2197 /* Write time */
2198 write_time(ctx, cs);
2199 write_obj_type_name(ctx, "Message iterator inactivity");
2200
2201 if (ctx->details_comp->cfg.compact) {
2202 write_nl(ctx);
2203 goto end;
2204 }
2205
2206 /* Write clock class properties */
2207 g_string_append(ctx->str, ":\n");
2208 incr_indent(ctx);
2209 write_indent(ctx);
2210 write_prop_name(ctx, "Clock class");
2211 g_string_append_c(ctx->str, ':');
2212 write_nl(ctx);
2213 incr_indent(ctx);
2214 write_clock_class_prop_lines(ctx,
2215 bt_clock_snapshot_borrow_clock_class_const(cs));
2216 decr_indent(ctx);
2217
2218 end:
2219 return ret;
2220 }
2221
2222 BT_HIDDEN
2223 int details_write_message(struct details_comp *details_comp,
2224 const bt_message *msg)
2225 {
2226 int ret = 0;
2227 struct details_write_ctx ctx = {
2228 .details_comp = details_comp,
2229 .str = details_comp->str,
2230 .indent_level = 0,
2231 };
2232
2233 /* Reset output buffer */
2234 g_string_assign(details_comp->str, "");
2235
2236 if (details_comp->printed_something && !details_comp->cfg.compact) {
2237 write_nl(&ctx);
2238 }
2239
2240 switch (bt_message_get_type(msg)) {
2241 case BT_MESSAGE_TYPE_EVENT:
2242 ret = write_event_message(&ctx, msg);
2243 break;
2244 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
2245 ret = write_message_iterator_inactivity_message(&ctx, msg);
2246 break;
2247 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
2248 ret = write_stream_beginning_message(&ctx, msg);
2249 break;
2250 case BT_MESSAGE_TYPE_STREAM_END:
2251 ret = write_stream_end_message(&ctx, msg);
2252 break;
2253 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
2254 ret = write_packet_beginning_message(&ctx, msg);
2255 break;
2256 case BT_MESSAGE_TYPE_PACKET_END:
2257 ret = write_packet_end_message(&ctx, msg);
2258 break;
2259 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
2260 ret = write_discarded_events_message(&ctx, msg);
2261 break;
2262 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
2263 ret = write_discarded_packets_message(&ctx, msg);
2264 break;
2265 default:
2266 abort();
2267 }
2268
2269 return ret;
2270 }
This page took 0.108307 seconds and 5 git commands to generate.