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