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