Replace libuuid with internal implementation
[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,
1028 "Packets have beginning default clock snapshot",
1029 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
1030 write_bool_prop_line(ctx,
1031 "Packets have end default clock snapshot",
1032 bt_stream_class_packets_have_end_default_clock_snapshot(sc));
1033 write_bool_prop_line(ctx,
1034 "Supports discarded events",
1035 bt_stream_class_supports_discarded_events(sc));
1036 write_bool_prop_line(ctx,
1037 "Discarded events have default clock snapshots",
1038 bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
1039 write_bool_prop_line(ctx,
1040 "Supports discarded packets",
1041 bt_stream_class_supports_discarded_packets(sc));
1042 write_bool_prop_line(ctx,
1043 "Discarded packets have default clock snapshots",
1044 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
1045
1046 /* Write default clock class */
1047 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1048 write_indent(ctx);
1049 write_prop_name(ctx, "Default clock class");
1050 g_string_append_c(ctx->str, ':');
1051 write_nl(ctx);
1052 incr_indent(ctx);
1053 write_clock_class_prop_lines(ctx,
1054 bt_stream_class_borrow_default_clock_class_const(sc));
1055 decr_indent(ctx);
1056 }
1057
1058 fc = bt_stream_class_borrow_packet_context_field_class_const(sc);
1059 if (fc) {
1060 write_root_field_class(ctx, "Packet context field class", fc);
1061 }
1062
1063 fc = bt_stream_class_borrow_event_common_context_field_class_const(sc);
1064 if (fc) {
1065 write_root_field_class(ctx, "Event common context field class",
1066 fc);
1067 }
1068
1069 for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
1070 g_ptr_array_add(event_classes,
1071 (gpointer) bt_stream_class_borrow_event_class_by_index_const(
1072 sc, i));
1073 }
1074
1075 g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
1076
1077 for (i = 0; i < event_classes->len; i++) {
1078 write_event_class(ctx, event_classes->pdata[i]);
1079 }
1080
1081 decr_indent(ctx);
1082 g_ptr_array_free(event_classes, TRUE);
1083}
1084
1085static
1086gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
1087{
1088 uint64_t id_a = bt_stream_class_get_id(*a);
1089 uint64_t id_b = bt_stream_class_get_id(*b);
1090
1091 if (id_a < id_b) {
1092 return -1;
1093 } else if (id_a > id_b) {
1094 return 1;
1095 } else {
1096 return 0;
1097 }
1098}
1099
1100static
1101gint compare_strings(const char **a, const char **b)
1102{
1103 return strcmp(*a, *b);
1104}
1105
1106static
1107void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
1108{
1109 GPtrArray *stream_classes = g_ptr_array_new();
55478183
PP
1110 uint64_t i;
1111 bool printed_prop = false;
1112
1113 write_indent(ctx);
1114 write_obj_type_name(ctx, "Trace class");
1115
55478183
PP
1116 for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
1117 g_ptr_array_add(stream_classes,
1118 (gpointer) bt_trace_class_borrow_stream_class_by_index_const(
1119 tc, i));
1120 }
1121
1122 g_ptr_array_sort(stream_classes, (GCompareFunc) compare_stream_classes);
1123
1124 if (stream_classes->len > 0) {
1125 if (!printed_prop) {
1126 g_string_append(ctx->str, ":\n");
1127 printed_prop = true;
1128 }
1129 }
1130
335a2da5
PP
1131 incr_indent(ctx);
1132
55478183
PP
1133 for (i = 0; i < stream_classes->len; i++) {
1134 write_stream_class(ctx, stream_classes->pdata[i]);
1135 }
1136
55478183
PP
1137 if (!printed_prop) {
1138 write_nl(ctx);
1139 }
1140
335a2da5 1141 decr_indent(ctx);
55478183 1142 g_ptr_array_free(stream_classes, TRUE);
55478183
PP
1143}
1144
1145static
1146int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
1147 const bt_stream_class *sc, const bt_event_class *ec)
1148{
1149 int ret = 0;
1150
1151 BT_ASSERT(tc);
1152
1153 if (details_need_to_write_trace_class(ctx, tc)) {
1154 uint64_t sc_i;
1155
1156 if (ctx->details_comp->cfg.compact &&
1157 ctx->details_comp->printed_something) {
1158 /*
1159 * There are no empty line between messages in
1160 * compact mode, so write one here to decouple
1161 * the trace class from the next message.
1162 */
1163 write_nl(ctx);
1164 }
1165
1166 /*
1167 * write_trace_class() also writes all its stream
1168 * classes their event classes, so we don't need to
1169 * rewrite `sc`.
1170 */
1171 write_trace_class(ctx, tc);
1172 write_nl(ctx);
1173
1174 /*
1175 * Mark this trace class as written, as well as all
1176 * its stream classes and their event classes.
1177 */
1178 ret = details_did_write_trace_class(ctx, tc);
1179 if (ret) {
1180 goto end;
1181 }
1182
1183 for (sc_i = 0; sc_i < bt_trace_class_get_stream_class_count(tc);
1184 sc_i++) {
1185 uint64_t ec_i;
1186 const bt_stream_class *tc_sc =
1187 bt_trace_class_borrow_stream_class_by_index_const(
1188 tc, sc_i);
1189
1190 details_did_write_meta_object(ctx, tc, tc_sc);
1191
1192 for (ec_i = 0; ec_i <
1193 bt_stream_class_get_event_class_count(tc_sc);
1194 ec_i++) {
1195 details_did_write_meta_object(ctx, tc,
1196 bt_stream_class_borrow_event_class_by_index_const(
1197 tc_sc, ec_i));
1198 }
1199 }
1200
1201 goto end;
1202 }
1203
1204 if (sc && details_need_to_write_meta_object(ctx, tc, sc)) {
1205 uint64_t ec_i;
1206
1207 BT_ASSERT(tc);
1208
1209 if (ctx->details_comp->cfg.compact &&
1210 ctx->details_comp->printed_something) {
1211 /*
1212 * There are no empty line between messages in
1213 * compact mode, so write one here to decouple
1214 * the stream class from the next message.
1215 */
1216 write_nl(ctx);
1217 }
1218
1219 /*
1220 * write_stream_class() also writes all its event
1221 * classes, so we don't need to rewrite `ec`.
1222 */
1223 write_stream_class(ctx, sc);
1224 write_nl(ctx);
1225
1226 /*
1227 * Mark this stream class as written, as well as all its
1228 * event classes.
1229 */
1230 details_did_write_meta_object(ctx, tc, sc);
1231
1232 for (ec_i = 0; ec_i <
1233 bt_stream_class_get_event_class_count(sc);
1234 ec_i++) {
1235 details_did_write_meta_object(ctx, tc,
1236 bt_stream_class_borrow_event_class_by_index_const(
1237 sc, ec_i));
1238 }
1239
1240 goto end;
1241 }
1242
1243 if (ec && details_need_to_write_meta_object(ctx, tc, ec)) {
1244 BT_ASSERT(sc);
1245
1246 if (ctx->details_comp->cfg.compact &&
1247 ctx->details_comp->printed_something) {
1248 /*
1249 * There are no empty line between messages in
1250 * compact mode, so write one here to decouple
1251 * the event class from the next message.
1252 */
1253 write_nl(ctx);
1254 }
1255
1256 write_event_class(ctx, ec);
1257 write_nl(ctx);
1258 details_did_write_meta_object(ctx, tc, ec);
1259 goto end;
1260 }
1261
1262end:
1263 return ret;
1264}
1265
1266static
1267void write_time_str(struct details_write_ctx *ctx, const char *str)
1268{
1269 if (!ctx->details_comp->cfg.with_time) {
1270 goto end;
1271 }
1272
1273 g_string_append_printf(ctx->str, "[%s%s%s%s]",
1274 color_bold(ctx), color_fg_blue(ctx), str, color_reset(ctx));
1275
1276 if (ctx->details_comp->cfg.compact) {
1277 write_sp(ctx);
1278 } else {
1279 write_nl(ctx);
1280 }
1281
1282end:
1283 return;
1284}
1285
1286static
1287void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
1288{
d24d5663 1289 bt_clock_snapshot_get_ns_from_origin_status cs_status;
55478183
PP
1290 int64_t ns_from_origin;
1291 char buf[32];
1292
1293 if (!ctx->details_comp->cfg.with_time) {
1294 goto end;
1295 }
1296
1297 format_uint(buf, bt_clock_snapshot_get_value(cs), 10);
1298 g_string_append_printf(ctx->str, "[%s%s%s%s%s",
1299 color_bold(ctx), color_fg_blue(ctx), buf,
1300 color_reset(ctx),
1301 ctx->details_comp->cfg.compact ? "" : " cycles");
d24d5663
PP
1302 cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
1303 if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
55478183
PP
1304 format_int(buf, ns_from_origin, 10);
1305 g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
1306 ctx->details_comp->cfg.compact ? "" : ",",
1307 color_bold(ctx), color_fg_blue(ctx), buf,
1308 color_reset(ctx),
1309 ctx->details_comp->cfg.compact ? "" : " ns from origin");
1310 }
1311
1312 g_string_append(ctx->str, "]");
1313
1314 if (ctx->details_comp->cfg.compact) {
1315 write_sp(ctx);
1316 } else {
1317 write_nl(ctx);
1318 }
1319
1320end:
1321 return;
1322}
1323
1324static
1325int write_message_follow_tag(struct details_write_ctx *ctx,
1326 const bt_stream *stream)
1327{
1328 int ret;
1329 uint64_t unique_trace_id;
1330 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1331 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1332
1333 ret = details_trace_unique_id(ctx, trace, &unique_trace_id);
1334 if (ret) {
1335 goto end;
1336 }
1337
1338 if (ctx->details_comp->cfg.compact) {
1339 g_string_append_printf(ctx->str,
1340 "%s{%s%" PRIu64 " %" PRIu64 " %" PRIu64 "%s%s}%s ",
1341 color_fg_cyan(ctx), color_bold(ctx),
1342 unique_trace_id, bt_stream_class_get_id(sc),
1343 bt_stream_get_id(stream),
1344 color_reset(ctx), color_fg_cyan(ctx), color_reset(ctx));
1345 } else {
1346 g_string_append_printf(ctx->str,
1347 "%s{Trace %s%" PRIu64 "%s%s, Stream class ID %s%" PRIu64 "%s%s, Stream ID %s%" PRIu64 "%s%s}%s\n",
1348 color_fg_cyan(ctx),
1349 color_bold(ctx), unique_trace_id,
1350 color_reset(ctx), color_fg_cyan(ctx),
1351 color_bold(ctx), bt_stream_class_get_id(sc),
1352 color_reset(ctx), color_fg_cyan(ctx),
1353 color_bold(ctx), bt_stream_get_id(stream),
1354 color_reset(ctx), color_fg_cyan(ctx),
1355 color_reset(ctx));
1356 }
1357
1358end:
1359 return ret;
1360}
1361
1362static
1363void write_field(struct details_write_ctx *ctx, const bt_field *field,
1364 const char *name)
1365{
1366 uint64_t i;
1367 bt_field_class_type fc_type = bt_field_get_class_type(field);
1368 const bt_field_class *fc;
1369 char buf[64];
1370
1371 /* Write field's name */
1372 if (name) {
1373 write_compound_member_name(ctx, name);
1374 }
1375
1376 /* Write field's value */
1377 switch (fc_type) {
1378 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1379 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1380 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1381 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1382 {
1383 unsigned int fmt_base;
1384 bt_field_class_integer_preferred_display_base base;
1385
1386 fc = bt_field_borrow_class_const(field);
1387 base = bt_field_class_integer_get_preferred_display_base(fc);
1388
1389 switch (base) {
1390 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
1391 fmt_base = 10;
1392 break;
1393 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
1394 fmt_base = 8;
1395 break;
1396 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
1397 fmt_base = 2;
1398 break;
1399 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
1400 fmt_base = 16;
1401 break;
1402 default:
1403 abort();
1404 }
1405
1406 if (fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
1407 fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
1408 format_uint(buf,
1409 bt_field_unsigned_integer_get_value(field),
1410 fmt_base);
1411 write_sp(ctx);
1412 write_uint_str_prop_value(ctx, buf);
1413 } else {
1414 format_int(buf,
1415 bt_field_signed_integer_get_value(field),
1416 fmt_base);
1417 write_sp(ctx);
1418 write_int_str_prop_value(ctx, buf);
1419 }
1420
1421 break;
1422 }
1423 case BT_FIELD_CLASS_TYPE_REAL:
1424 write_sp(ctx);
1425 write_float_prop_value(ctx, bt_field_real_get_value(field));
1426 break;
1427 case BT_FIELD_CLASS_TYPE_STRING:
1428 write_sp(ctx);
1429 write_str_prop_value(ctx, bt_field_string_get_value(field));
1430 break;
1431 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1432 {
1433 uint64_t member_count;
1434
1435 fc = bt_field_borrow_class_const(field);
1436 member_count = bt_field_class_structure_get_member_count(fc);
1437
1438 if (member_count > 0) {
1439 incr_indent(ctx);
1440
1441 for (i = 0; i < member_count; i++) {
1442 const bt_field_class_structure_member *member =
1443 bt_field_class_structure_borrow_member_by_index_const(
1444 fc, i);
1445 const bt_field *member_field =
1446 bt_field_structure_borrow_member_field_by_index_const(
1447 field, i);
1448
1449 write_nl(ctx);
1450 write_field(ctx, member_field,
1451 bt_field_class_structure_member_get_name(member));
1452 }
1453
1454 decr_indent(ctx);
1455 } else {
1456 g_string_append(ctx->str, " Empty");
1457 }
1458
1459 break;
1460 }
1461 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1462 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1463 {
1464 uint64_t length = bt_field_array_get_length(field);
1465
1466 if (length == 0) {
1467 g_string_append(ctx->str, " Empty");
1468 } else {
1469 g_string_append(ctx->str, " Length ");
1470 write_uint_prop_value(ctx, length);
1471 g_string_append_c(ctx->str, ':');
1472 }
1473
1474 incr_indent(ctx);
1475
1476 for (i = 0; i < length; i++) {
1477 const bt_field *elem_field =
1478 bt_field_array_borrow_element_field_by_index_const(
1479 field, i);
1480
1481 write_nl(ctx);
1482 write_array_index(ctx, i);
1483 write_field(ctx, elem_field, NULL);
1484 }
1485
1486 decr_indent(ctx);
1487 break;
1488 }
1489 case BT_FIELD_CLASS_TYPE_VARIANT:
1490 write_field(ctx,
1491 bt_field_variant_borrow_selected_option_field_const(
1492 field), NULL);
1493 break;
1494 default:
1495 abort();
1496 }
1497}
1498
1499static
1500void write_root_field(struct details_write_ctx *ctx, const char *name,
1501 const bt_field *field)
1502{
1503 BT_ASSERT(name);
1504 BT_ASSERT(field);
1505 write_indent(ctx);
1506 write_prop_name(ctx, name);
1507 g_string_append(ctx->str, ":");
1508 write_field(ctx, field, NULL);
1509 write_nl(ctx);
1510}
1511
1512static
1513int write_event_message(struct details_write_ctx *ctx,
1514 const bt_message *msg)
1515{
1516 int ret = 0;
1517 const bt_event *event = bt_message_event_borrow_event_const(msg);
1518 const bt_stream *stream = bt_event_borrow_stream_const(event);
1519 const bt_event_class *ec = bt_event_borrow_class_const(event);
1520 const bt_stream_class *sc = bt_event_class_borrow_stream_class_const(ec);
1521 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1522 const char *ec_name;
1523 const bt_field *field;
1524
1525 ret = try_write_meta(ctx, tc, sc, ec);
1526 if (ret) {
1527 goto end;
1528 }
1529
1530 /* Write time */
1531 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1532 write_time(ctx,
1533 bt_message_event_borrow_default_clock_snapshot_const(
1534 msg));
1535 }
1536
1537 /* Write follow tag for message */
1538 ret = write_message_follow_tag(ctx, stream);
1539 if (ret) {
1540 goto end;
1541 }
1542
1543 /* Write object's basic properties */
1544 write_obj_type_name(ctx, "Event");
1545 ec_name = bt_event_class_get_name(ec);
1546 if (ec_name) {
1547 g_string_append_printf(ctx->str, " `%s%s%s`",
1548 color_fg_green(ctx), ec_name, color_reset(ctx));
1549 }
1550
1551 g_string_append(ctx->str, " (");
1552
1553 if (!ctx->details_comp->cfg.compact) {
1554 g_string_append(ctx->str, "Class ID ");
1555 }
1556
1557 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1558 g_string_append(ctx->str, ")");
1559
1560 if (ctx->details_comp->cfg.compact) {
1561 write_nl(ctx);
1562 goto end;
1563 }
1564
1565 /* Write fields */
1566 g_string_append(ctx->str, ":\n");
1567 incr_indent(ctx);
1568 field = bt_event_borrow_common_context_field_const(event);
1569 if (field) {
1570 write_root_field(ctx, "Common context", field);
1571 }
1572
1573 field = bt_event_borrow_specific_context_field_const(event);
1574 if (field) {
1575 write_root_field(ctx, "Specific context", field);
1576 }
1577
1578 field = bt_event_borrow_payload_field_const(event);
1579 if (field) {
1580 write_root_field(ctx, "Payload", field);
1581 }
1582
1583 decr_indent(ctx);
1584
1585end:
1586
1587 return ret;
1588}
1589
1590static
1591gint compare_streams(const bt_stream **a, const bt_stream **b)
1592{
1593 uint64_t id_a = bt_stream_get_id(*a);
1594 uint64_t id_b = bt_stream_get_id(*b);
1595
1596 if (id_a < id_b) {
1597 return -1;
1598 } else if (id_a > id_b) {
1599 return 1;
1600 } else {
1601 const bt_stream_class *a_sc = bt_stream_borrow_class_const(*a);
1602 const bt_stream_class *b_sc = bt_stream_borrow_class_const(*b);
1603 uint64_t a_sc_id = bt_stream_class_get_id(a_sc);
1604 uint64_t b_sc_id = bt_stream_class_get_id(b_sc);
1605
1606 if (a_sc_id < b_sc_id) {
1607 return -1;
1608 } else if (a_sc_id > b_sc_id) {
1609 return 1;
1610 } else {
1611 return 0;
1612 }
1613 }
1614}
1615
1616static
1617void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
1618{
1619 const char *name;
55478183
PP
1620 GPtrArray *streams = g_ptr_array_new();
1621 uint64_t i;
1622 bool printed_prop = false;
335a2da5
PP
1623 GPtrArray *env_names = g_ptr_array_new();
1624 uint64_t env_count;
55478183
PP
1625
1626 write_indent(ctx);
1627 write_obj_type_name(ctx, "Trace");
1628
1629 /* Write name */
1630 if (ctx->details_comp->cfg.with_trace_name) {
1631 name = bt_trace_get_name(trace);
1632 if (name) {
1633 g_string_append(ctx->str, " `");
1634 write_str_prop_value(ctx, name);
1635 g_string_append(ctx->str, "`");
1636 }
1637 }
1638
1639 /* Write properties */
1640 incr_indent(ctx);
1641
335a2da5
PP
1642 /* Write UUID */
1643 if (ctx->details_comp->cfg.with_uuid) {
1644 bt_uuid uuid = bt_trace_get_uuid(trace);
1645
1646 if (uuid) {
55478183
PP
1647 if (!printed_prop) {
1648 g_string_append(ctx->str, ":\n");
1649 printed_prop = true;
1650 }
1651
335a2da5 1652 write_uuid_prop_line(ctx, "UUID", uuid);
55478183
PP
1653 }
1654 }
1655
335a2da5
PP
1656 /* Write environment */
1657 env_count = bt_trace_get_environment_entry_count(trace);
1658 if (env_count > 0) {
1659 if (!printed_prop) {
1660 g_string_append(ctx->str, ":\n");
1661 printed_prop = true;
1662 }
55478183 1663
335a2da5
PP
1664 write_indent(ctx);
1665 write_prop_name(ctx, "Environment");
1666 g_string_append(ctx->str, " (");
1667 write_uint_prop_value(ctx, env_count);
1668 g_string_append_printf(ctx->str, " entr%s):",
1669 env_count == 1 ? "y" : "ies");
1670 write_nl(ctx);
1671 incr_indent(ctx);
1672
1673 for (i = 0; i < env_count; i++) {
1674 const char *name;
1675 const bt_value *value;
1676
1677 bt_trace_borrow_environment_entry_by_index_const(
1678 trace, i, &name, &value);
1679 g_ptr_array_add(env_names, (gpointer) name);
1680 }
1681
1682 g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
1683
1684 for (i = 0; i < env_names->len; i++) {
1685 const char *name = env_names->pdata[i];
1686 const bt_value *value =
1687 bt_trace_borrow_environment_entry_value_by_name_const(
1688 trace, name);
1689
1690 BT_ASSERT(value);
1691 write_compound_member_name(ctx, name);
1692 write_sp(ctx);
1693
1694 if (bt_value_get_type(value) ==
1695 BT_VALUE_TYPE_SIGNED_INTEGER) {
1696 write_int_prop_value(ctx,
1697 bt_value_signed_integer_get(value));
1698 } else if (bt_value_get_type(value) ==
1699 BT_VALUE_TYPE_STRING) {
1700 write_str_prop_value(ctx,
1701 bt_value_string_get(value));
1702 } else {
1703 abort();
55478183
PP
1704 }
1705
335a2da5 1706 write_nl(ctx);
55478183 1707 }
335a2da5
PP
1708
1709 decr_indent(ctx);
55478183
PP
1710 }
1711
1712 for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
1713 g_ptr_array_add(streams,
1714 (gpointer) bt_trace_borrow_stream_by_index_const(
1715 trace, i));
1716 }
1717
1718 g_ptr_array_sort(streams, (GCompareFunc) compare_streams);
1719
1720 if (streams->len > 0 && !printed_prop) {
1721 g_string_append(ctx->str, ":\n");
1722 printed_prop = true;
1723 }
1724
1725 for (i = 0; i < streams->len; i++) {
1726 const bt_stream *stream = streams->pdata[i];
1727
1728 write_indent(ctx);
1729 write_obj_type_name(ctx, "Stream");
1730 g_string_append(ctx->str, " (ID ");
1731 write_uint_prop_value(ctx, bt_stream_get_id(stream));
1732 g_string_append(ctx->str, ", Class ID ");
1733 write_uint_prop_value(ctx, bt_stream_class_get_id(
1734 bt_stream_borrow_class_const(stream)));
1735 g_string_append(ctx->str, ")");
1736 write_nl(ctx);
1737 }
1738
1739 decr_indent(ctx);
1740
1741 if (!printed_prop) {
1742 write_nl(ctx);
1743 }
1744
1745 g_ptr_array_free(streams, TRUE);
335a2da5 1746 g_ptr_array_free(env_names, TRUE);
55478183
PP
1747}
1748
1749static
1750int write_stream_beginning_message(struct details_write_ctx *ctx,
1751 const bt_message *msg)
1752{
1753 int ret = 0;
1754 const bt_stream *stream =
1755 bt_message_stream_beginning_borrow_stream_const(msg);
1756 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1757 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
188edac1 1758 const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
55478183
PP
1759 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
1760 const char *name;
1761
1762 ret = try_write_meta(ctx, tc, sc, NULL);
1763 if (ret) {
1764 goto end;
1765 }
1766
188edac1
SM
1767 /* Write time */
1768 if (cc) {
1769 const bt_clock_snapshot *cs;
1770 bt_message_stream_clock_snapshot_state cs_state =
1771 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
1772
1773 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1774 write_time(ctx, cs);
1775 } else {
1776 write_time_str(ctx, "Unknown");
1777 }
1778 }
1779
55478183
PP
1780 /* Write follow tag for message */
1781 ret = write_message_follow_tag(ctx, stream);
1782 if (ret) {
1783 goto end;
1784 }
1785
1786 /* Write stream properties */
1787 write_obj_type_name(ctx, "Stream beginning");
1788
1789 if (ctx->details_comp->cfg.compact) {
1790 write_nl(ctx);
1791 goto end;
1792 }
1793
1794 g_string_append(ctx->str, ":\n");
1795 incr_indent(ctx);
1796
1797 if (ctx->details_comp->cfg.with_stream_name) {
1798 name = bt_stream_get_name(stream);
1799 if (name) {
1800 write_str_prop_line(ctx, "Name", name);
1801 }
1802 }
1803
1804 if (ctx->details_comp->cfg.with_stream_class_name) {
1805 name = bt_stream_class_get_name(sc);
1806 if (name) {
1807 write_str_prop_line(ctx, "Class name", name);
1808 }
1809 }
1810
1811 write_trace(ctx, trace);
1812 decr_indent(ctx);
1813
1814end:
1815 return ret;
1816}
1817
1818static
1819int write_stream_end_message(struct details_write_ctx *ctx,
1820 const bt_message *msg)
1821{
1822 int ret = 0;
1823 const bt_stream *stream =
1824 bt_message_stream_end_borrow_stream_const(msg);
188edac1
SM
1825 const bt_stream_class *sc =
1826 bt_stream_borrow_class_const(stream);
1827 const bt_clock_class *cc =
1828 bt_stream_class_borrow_default_clock_class_const(sc);
55478183
PP
1829
1830 /* Write time */
188edac1
SM
1831 if (cc) {
1832 const bt_clock_snapshot *cs;
1833 bt_message_stream_clock_snapshot_state cs_state =
1834 bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
55478183 1835
188edac1
SM
1836 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1837 write_time(ctx, cs);
1838 } else {
1839 write_time_str(ctx, "Unknown");
1840 }
55478183
PP
1841 }
1842
1843 /* Write follow tag for message */
1844 ret = write_message_follow_tag(ctx, stream);
1845 if (ret) {
1846 goto end;
1847 }
1848
188edac1
SM
1849 /* Write stream properties */
1850 write_obj_type_name(ctx, "Stream end\n");
55478183
PP
1851
1852end:
1853 return ret;
1854}
1855
1856static
1857int write_packet_beginning_message(struct details_write_ctx *ctx,
1858 const bt_message *msg)
1859{
1860 int ret = 0;
1861 const bt_packet *packet =
1862 bt_message_packet_beginning_borrow_packet_const(msg);
1863 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
1864 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1865 const bt_field *field;
1866
1867 /* Write time */
1868 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
1869 write_time(ctx,
1870 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
1871 msg));
1872 }
1873
1874 /* Write follow tag for message */
1875 ret = write_message_follow_tag(ctx, stream);
1876 if (ret) {
1877 goto end;
1878 }
1879
1880 write_obj_type_name(ctx, "Packet beginning");
1881
1882 if (ctx->details_comp->cfg.compact) {
1883 write_nl(ctx);
1884 goto end;
1885 }
1886
1887 /* Write field */
1888 g_string_append(ctx->str, ":\n");
1889 incr_indent(ctx);
1890 field = bt_packet_borrow_context_field_const(packet);
1891 if (field) {
1892 write_root_field(ctx, "Context", field);
1893 }
1894
1895 decr_indent(ctx);
1896
1897end:
1898 return ret;
1899}
1900
1901static
1902int write_discarded_items_message(struct details_write_ctx *ctx,
1903 const char *name, const bt_stream *stream,
1904 const bt_clock_snapshot *beginning_cs,
1905 const bt_clock_snapshot *end_cs, uint64_t count)
1906{
1907 int ret = 0;
1908
1909 /* Write times */
1910 if (beginning_cs) {
1911 write_time(ctx, beginning_cs);
1912 BT_ASSERT(end_cs);
1913 write_time(ctx, end_cs);
1914 }
1915
1916 /* Write follow tag for message */
1917 ret = write_message_follow_tag(ctx, stream);
1918 if (ret) {
1919 goto end;
1920 }
1921
1922 write_obj_type_name(ctx, "Discarded ");
1923 write_obj_type_name(ctx, name);
1924
1925 /* Write count */
1926 if (count == UINT64_C(-1)) {
1927 write_nl(ctx);
1928 goto end;
1929 }
1930
1931 g_string_append(ctx->str, " (");
1932 write_uint_prop_value(ctx, count);
1933 g_string_append_printf(ctx->str, " %s)\n", name);
1934
1935end:
1936 return ret;
1937}
1938
1939static
1940int write_discarded_events_message(struct details_write_ctx *ctx,
1941 const bt_message *msg)
1942{
1943 const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
1944 msg);
1945 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1946 const bt_clock_snapshot *beginning_cs = NULL;
1947 const bt_clock_snapshot *end_cs = NULL;
1948 uint64_t count;
1949
1950 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
1951 beginning_cs =
1952 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
1953 msg);
1954 end_cs =
1955 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
1956 msg);
1957 }
1958
1959 if (bt_message_discarded_events_get_count(msg, &count) !=
1960 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
1961 count = UINT64_C(-1);
1962 }
1963
1964 return write_discarded_items_message(ctx, "events", stream,
1965 beginning_cs, end_cs, count);
1966}
1967
1968static
1969int write_discarded_packets_message(struct details_write_ctx *ctx,
1970 const bt_message *msg)
1971{
1972 const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
1973 msg);
1974 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1975 const bt_clock_snapshot *beginning_cs = NULL;
1976 const bt_clock_snapshot *end_cs = NULL;
1977 uint64_t count;
1978
1979 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
1980 beginning_cs =
1981 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
1982 msg);
1983 end_cs =
1984 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
1985 msg);
1986 }
1987
1988 if (bt_message_discarded_packets_get_count(msg, &count) !=
1989 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
1990 count = UINT64_C(-1);
1991 }
1992
1993 return write_discarded_items_message(ctx, "packets", stream,
1994 beginning_cs, end_cs, count);
1995}
1996
1997static
1998int write_packet_end_message(struct details_write_ctx *ctx,
1999 const bt_message *msg)
2000{
2001 int ret = 0;
2002 const bt_packet *packet =
2003 bt_message_packet_end_borrow_packet_const(msg);
2004 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2005 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2006
2007 /* Write time */
2008 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
2009 write_time(ctx,
2010 bt_message_packet_end_borrow_default_clock_snapshot_const(
2011 msg));
2012 }
2013
2014 /* Write follow tag for message */
2015 ret = write_message_follow_tag(ctx, stream);
2016 if (ret) {
2017 goto end;
2018 }
2019
2020 write_obj_type_name(ctx, "Packet end");
2021 write_nl(ctx);
2022
2023end:
2024 return ret;
2025}
2026
2027static
2028int write_message_iterator_inactivity_message(struct details_write_ctx *ctx,
2029 const bt_message *msg)
2030{
2031 int ret = 0;
2032 const bt_clock_snapshot *cs =
2033 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
2034 msg);
2035
2036 /* Write time */
2037 write_time(ctx, cs);
2038 write_obj_type_name(ctx, "Message iterator inactivity");
2039
2040 if (ctx->details_comp->cfg.compact) {
2041 write_nl(ctx);
2042 goto end;
2043 }
2044
2045 /* Write clock class properties */
2046 g_string_append(ctx->str, ":\n");
2047 incr_indent(ctx);
2048 write_indent(ctx);
2049 write_prop_name(ctx, "Clock class");
2050 g_string_append_c(ctx->str, ':');
2051 write_nl(ctx);
2052 incr_indent(ctx);
2053 write_clock_class_prop_lines(ctx,
2054 bt_clock_snapshot_borrow_clock_class_const(cs));
2055 decr_indent(ctx);
2056
2057end:
2058 return ret;
2059}
2060
2061BT_HIDDEN
2062int details_write_message(struct details_comp *details_comp,
2063 const bt_message *msg)
2064{
2065 int ret = 0;
2066 struct details_write_ctx ctx = {
2067 .details_comp = details_comp,
2068 .str = details_comp->str,
2069 .indent_level = 0,
2070 };
2071
2072 /* Reset output buffer */
2073 g_string_assign(details_comp->str, "");
2074
2075 if (details_comp->printed_something && !details_comp->cfg.compact) {
2076 write_nl(&ctx);
2077 }
2078
2079 switch (bt_message_get_type(msg)) {
2080 case BT_MESSAGE_TYPE_EVENT:
2081 ret = write_event_message(&ctx, msg);
2082 break;
2083 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
2084 ret = write_message_iterator_inactivity_message(&ctx, msg);
2085 break;
2086 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
2087 ret = write_stream_beginning_message(&ctx, msg);
2088 break;
2089 case BT_MESSAGE_TYPE_STREAM_END:
2090 ret = write_stream_end_message(&ctx, msg);
2091 break;
2092 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
2093 ret = write_packet_beginning_message(&ctx, msg);
2094 break;
2095 case BT_MESSAGE_TYPE_PACKET_END:
2096 ret = write_packet_end_message(&ctx, msg);
2097 break;
55478183
PP
2098 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
2099 ret = write_discarded_events_message(&ctx, msg);
2100 break;
2101 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
2102 ret = write_discarded_packets_message(&ctx, msg);
2103 break;
2104 default:
2105 abort();
2106 }
2107
2108 return ret;
2109}
This page took 0.134252 seconds and 4 git commands to generate.