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