lib: rename option/var. "selector" to "selector field"
[babeltrace.git] / src / plugins / text / details / write.c
CommitLineData
a0bcd369
PP
1/*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
a0bcd369 23#include <babeltrace2/babeltrace.h>
b03487ab
PP
24#include <stdio.h>
25#include <string.h>
a0bcd369
PP
26
27#include "common/assert.h"
28#include "common/common.h"
d126826c 29#include "common/uuid.h"
a0bcd369
PP
30#include "details.h"
31#include "write.h"
32#include "obj-lifetime-mgmt.h"
33#include "colors.h"
34
35static inline
36const char *plural(uint64_t value)
37{
38 return value == 1 ? "" : "s";
39}
40
41static inline
42void incr_indent_by(struct details_write_ctx *ctx, unsigned int value)
43{
44 BT_ASSERT(ctx);
45 ctx->indent_level += value;
46}
47
48static inline
49void incr_indent(struct details_write_ctx *ctx)
50{
51 incr_indent_by(ctx, 2);
52}
53
54static inline
55void decr_indent_by(struct details_write_ctx *ctx, unsigned int value)
56{
57 BT_ASSERT(ctx);
58 BT_ASSERT(ctx->indent_level >= value);
59 ctx->indent_level -= value;
60}
61
62static inline
63void decr_indent(struct details_write_ctx *ctx)
64{
65 decr_indent_by(ctx, 2);
66}
67
68static inline
69void format_uint(char *buf, uint64_t value, unsigned int base)
70{
71 const char *spec = "%" PRIu64;
72 char *buf_start = buf;
73 unsigned int digits_per_group = 3;
74 char sep = ',';
75 bool sep_digits = true;
76
77 switch (base) {
78 case 2:
79 case 16:
80 /* TODO: Support binary format */
81 spec = "%" PRIx64;
82 strcpy(buf, "0x");
83 buf_start = buf + 2;
84 digits_per_group = 4;
85 sep = ':';
86 break;
87 case 8:
88 spec = "%" PRIo64;
89 strcpy(buf, "0");
90 buf_start = buf + 1;
91 sep = ':';
92 break;
93 case 10:
94 if (value <= 9999) {
95 /*
96 * Do not insert digit separators for numbers
97 * under 10,000 as it looks weird.
98 */
99 sep_digits = false;
100 }
101
102 break;
103 default:
104 abort();
105 }
106
107 sprintf(buf_start, spec, value);
108
109 if (sep_digits) {
110 bt_common_sep_digits(buf_start, digits_per_group, sep);
111 }
112}
113
114static inline
115void format_int(char *buf, int64_t value, unsigned int base)
116{
117 const char *spec = "%" PRIu64;
118 char *buf_start = buf;
119 unsigned int digits_per_group = 3;
120 char sep = ',';
121 bool sep_digits = true;
122 uint64_t abs_value = value < 0 ? (uint64_t) -value : (uint64_t) value;
123
124 if (value < 0) {
125 buf[0] = '-';
126 buf_start++;
127 }
128
129 switch (base) {
130 case 2:
131 case 16:
132 /* TODO: Support binary format */
133 spec = "%" PRIx64;
134 strcpy(buf_start, "0x");
135 buf_start += 2;
136 digits_per_group = 4;
137 sep = ':';
138 break;
139 case 8:
140 spec = "%" PRIo64;
141 strcpy(buf_start, "0");
142 buf_start++;
143 sep = ':';
144 break;
145 case 10:
146 if (value >= -9999 && value <= 9999) {
147 /*
148 * Do not insert digit separators for numbers
149 * over -10,000 and under 10,000 as it looks
150 * weird.
151 */
152 sep_digits = false;
153 }
154
155 break;
156 default:
157 abort();
158 }
159
160 sprintf(buf_start, spec, abs_value);
161
162 if (sep_digits) {
163 bt_common_sep_digits(buf_start, digits_per_group, sep);
164 }
165}
166
167static inline
168void write_nl(struct details_write_ctx *ctx)
169{
170 BT_ASSERT(ctx);
171 g_string_append_c(ctx->str, '\n');
172}
173
174static inline
175void write_sp(struct details_write_ctx *ctx)
176{
177 BT_ASSERT(ctx);
178 g_string_append_c(ctx->str, ' ');
179}
180
181static inline
182void write_indent(struct details_write_ctx *ctx)
183{
184 uint64_t i;
185
186 BT_ASSERT(ctx);
187
188 for (i = 0; i < ctx->indent_level; i++) {
189 write_sp(ctx);
190 }
191}
192
193static inline
194void write_compound_member_name(struct details_write_ctx *ctx, const char *name)
195{
196 write_indent(ctx);
197 g_string_append_printf(ctx->str, "%s%s%s:",
198 color_fg_cyan(ctx), name, color_reset(ctx));
199}
200
201static inline
7753db0d
PP
202void write_array_index(struct details_write_ctx *ctx, uint64_t index,
203 const char *color)
a0bcd369
PP
204{
205 char buf[32];
206
207 write_indent(ctx);
208 format_uint(buf, index, 10);
209 g_string_append_printf(ctx->str, "%s[%s]%s:",
7753db0d 210 color, buf, color_reset(ctx));
a0bcd369
PP
211}
212
213static inline
214void write_obj_type_name(struct details_write_ctx *ctx, const char *name)
215{
216 g_string_append_printf(ctx->str, "%s%s%s%s",
217 color_fg_yellow(ctx), color_bold(ctx), name, color_reset(ctx));
218}
219
220static inline
221void write_prop_name(struct details_write_ctx *ctx, const char *prop_name)
222{
223 g_string_append_printf(ctx->str, "%s%s%s",
224 color_fg_magenta(ctx), prop_name, color_reset(ctx));
225}
226
7753db0d
PP
227static inline
228void write_prop_name_line(struct details_write_ctx *ctx, const char *prop_name)
229{
230 write_indent(ctx);
231 g_string_append_printf(ctx->str, "%s%s%s:",
232 color_fg_magenta(ctx), prop_name, color_reset(ctx));
233}
234
a0bcd369
PP
235static inline
236void write_str_prop_value(struct details_write_ctx *ctx, const char *value)
237{
238 g_string_append_printf(ctx->str, "%s%s%s",
239 color_bold(ctx), value, color_reset(ctx));
240}
241
1bca9d21
PP
242static inline
243void write_none_prop_value(struct details_write_ctx *ctx, const char *value)
244{
245 g_string_append_printf(ctx->str, "%s%s%s%s",
246 color_bold(ctx), color_fg_magenta(ctx),
247 value, color_reset(ctx));
248}
249
a0bcd369
PP
250static inline
251void write_uint_str_prop_value(struct details_write_ctx *ctx, const char *value)
252{
253 write_str_prop_value(ctx, value);
254}
255
256static inline
257void write_uint_prop_value(struct details_write_ctx *ctx, uint64_t value)
258{
259 char buf[32];
260
261 format_uint(buf, value, 10);
262 write_uint_str_prop_value(ctx, buf);
263}
264
265static inline
266void write_int_prop_value(struct details_write_ctx *ctx, int64_t value)
267{
268 char buf[32];
269
270 format_int(buf, value, 10);
271 write_uint_str_prop_value(ctx, buf);
272}
273
274static inline
275void write_float_prop_value(struct details_write_ctx *ctx, double value)
276{
277 g_string_append_printf(ctx->str, "%s%f%s",
278 color_bold(ctx), value, color_reset(ctx));
279}
280
281static inline
282void write_str_prop_line(struct details_write_ctx *ctx, const char *prop_name,
283 const char *prop_value)
284{
285 BT_ASSERT(prop_value);
286 write_indent(ctx);
287 write_prop_name(ctx, prop_name);
288 g_string_append(ctx->str, ": ");
289 write_str_prop_value(ctx, prop_value);
290 write_nl(ctx);
291}
292
293static inline
294void write_uint_prop_line(struct details_write_ctx *ctx, const char *prop_name,
295 uint64_t prop_value)
296{
297 write_indent(ctx);
298 write_prop_name(ctx, prop_name);
299 g_string_append(ctx->str, ": ");
300 write_uint_prop_value(ctx, prop_value);
301 write_nl(ctx);
302}
303
304static inline
305void write_int_prop_line(struct details_write_ctx *ctx, const char *prop_name,
306 int64_t prop_value)
307{
308 write_indent(ctx);
309 write_prop_name(ctx, prop_name);
310 g_string_append(ctx->str, ": ");
311 write_int_prop_value(ctx, prop_value);
312 write_nl(ctx);
313}
314
315static inline
316void write_int_str_prop_value(struct details_write_ctx *ctx, const char *value)
317{
318 write_str_prop_value(ctx, value);
319}
320
321static inline
9edadc81 322void write_bool_prop_value(struct details_write_ctx *ctx, bt_bool prop_value)
a0bcd369
PP
323{
324 const char *str;
325
9edadc81 326 g_string_append(ctx->str, color_bold(ctx));
a0bcd369
PP
327
328 if (prop_value) {
329 g_string_append(ctx->str, color_fg_green(ctx));
330 str = "Yes";
331 } else {
332 g_string_append(ctx->str, color_fg_red(ctx));
333 str = "No";
334 }
335
9edadc81
PP
336 g_string_append_printf(ctx->str, "%s%s", str, color_reset(ctx));
337}
338
339static inline
340void write_bool_prop_line(struct details_write_ctx *ctx, const char *prop_name,
341 bt_bool prop_value)
342{
343 write_indent(ctx);
344 write_prop_name(ctx, prop_name);
345 g_string_append(ctx->str, ": ");
346 write_bool_prop_value(ctx, prop_value);
347 write_nl(ctx);
a0bcd369
PP
348}
349
350static inline
351void write_uuid_prop_line(struct details_write_ctx *ctx, const char *prop_name,
352 bt_uuid uuid)
353{
354 BT_ASSERT(uuid);
355 write_indent(ctx);
356 write_prop_name(ctx, prop_name);
357 g_string_append_printf(ctx->str,
d126826c 358 ": %s" BT_UUID_FMT "%s\n",
a0bcd369 359 color_bold(ctx),
d126826c 360 BT_UUID_FMT_VALUES(uuid),
a0bcd369
PP
361 color_reset(ctx));
362}
363
7753db0d
PP
364static
365gint compare_strings(const char **a, const char **b)
366{
367 return strcmp(*a, *b);
368}
369
370static
371bt_bool map_value_foreach_add_key_to_array(const char *key,
372 const bt_value *object, void *data)
373{
374 GPtrArray *keys = data;
375
376 BT_ASSERT(keys);
377 g_ptr_array_add(keys, (void *) key);
378 return BT_TRUE;
379}
380
381static
382void write_value(struct details_write_ctx *ctx, const bt_value *value,
383 const char *name)
384{
385 uint64_t i;
386 bt_value_type value_type = bt_value_get_type(value);
387 GPtrArray *keys = g_ptr_array_new();
388 char buf[64];
389
390 BT_ASSERT(keys);
391
392 /* Write field's name */
393 if (name) {
394 write_prop_name_line(ctx, name);
395 }
396
397 /* Write field's value */
398 switch (value_type) {
399 case BT_VALUE_TYPE_NULL:
400 write_sp(ctx);
401 write_none_prop_value(ctx, "Null");
402 break;
403 case BT_VALUE_TYPE_BOOL:
404 write_sp(ctx);
405 write_bool_prop_value(ctx, bt_value_bool_get(value));
406 break;
407 case BT_VALUE_TYPE_UNSIGNED_INTEGER:
408 format_uint(buf, bt_value_integer_unsigned_get(value), 10);
409 write_sp(ctx);
410 write_uint_str_prop_value(ctx, buf);
411 break;
412 case BT_VALUE_TYPE_SIGNED_INTEGER:
413 format_int(buf, bt_value_integer_signed_get(value), 10);
414 write_sp(ctx);
415 write_int_str_prop_value(ctx, buf);
416 break;
417 case BT_VALUE_TYPE_REAL:
418 write_sp(ctx);
419 write_float_prop_value(ctx, bt_value_real_get(value));
420 break;
421 case BT_VALUE_TYPE_STRING:
422 write_sp(ctx);
423 write_str_prop_value(ctx, bt_value_string_get(value));
424 break;
425 case BT_VALUE_TYPE_ARRAY:
426 {
1270d0e9 427 uint64_t length = bt_value_array_get_length(value);
7753db0d
PP
428
429 if (length == 0) {
430 write_sp(ctx);
431 write_none_prop_value(ctx, "Empty");
432 } else {
433 g_string_append(ctx->str, " Length ");
434 write_uint_prop_value(ctx, length);
435 g_string_append_c(ctx->str, ':');
436 }
437
438 incr_indent(ctx);
439
440 for (i = 0; i < length; i++) {
441 const bt_value *elem_value =
442 bt_value_array_borrow_element_by_index_const(
443 value, i);
444
445 write_nl(ctx);
446 write_array_index(ctx, i, color_fg_magenta(ctx));
447 write_value(ctx, elem_value, NULL);
448 }
449
450 decr_indent(ctx);
451 break;
452 }
453 case BT_VALUE_TYPE_MAP:
454 {
455 bt_value_map_foreach_entry_const_status foreach_status =
456 bt_value_map_foreach_entry_const(value,
457 map_value_foreach_add_key_to_array, keys);
458
459 BT_ASSERT(foreach_status ==
460 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK);
461 g_ptr_array_sort(keys, (GCompareFunc) compare_strings);
462
463 if (keys->len > 0) {
464 incr_indent(ctx);
465
466 for (i = 0; i < keys->len; i++) {
467 const char *key = keys->pdata[i];
468 const bt_value *entry_value =
469 bt_value_map_borrow_entry_value_const(
470 value, key);
471
472 write_nl(ctx);
473 write_value(ctx, entry_value, key);
474 }
475
476 decr_indent(ctx);
477 } else {
478 write_sp(ctx);
479 write_none_prop_value(ctx, "Empty");
480 }
481
482 break;
483 }
484 default:
485 abort();
486 }
487
488 g_ptr_array_free(keys, TRUE);
489}
490
491static
492void write_user_attributes(struct details_write_ctx *ctx,
493 const bt_value *user_attrs, bool write_newline, bool *written)
494{
495 BT_ASSERT(user_attrs);
496
497 if (!bt_value_map_is_empty(user_attrs)) {
498 write_value(ctx, user_attrs, "User attributes");
499
500 if (write_newline) {
501 write_nl(ctx);
502 }
503
504 if (written) {
505 *written = true;
506 }
507 }
508}
509
a0bcd369
PP
510static
511void write_int_field_class_props(struct details_write_ctx *ctx,
512 const bt_field_class *fc, bool close)
513{
514 g_string_append_printf(ctx->str, "(%s%" PRIu64 "-bit%s, Base ",
515 color_bold(ctx),
516 bt_field_class_integer_get_field_value_range(fc),
517 color_reset(ctx));
518
519 switch (bt_field_class_integer_get_preferred_display_base(fc)) {
520 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
521 write_uint_prop_value(ctx, 2);
522 break;
523 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
524 write_uint_prop_value(ctx, 8);
525 break;
526 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
527 write_uint_prop_value(ctx, 10);
528 break;
529 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
530 write_uint_prop_value(ctx, 16);
531 break;
532 default:
533 abort();
534 }
535
536 if (close) {
537 g_string_append(ctx->str, ")");
538 }
539}
540
02b61fe0 541struct int_range {
a0bcd369
PP
542 union {
543 uint64_t u;
544 int64_t i;
545 } lower;
546
547 union {
548 uint64_t u;
549 int64_t i;
550 } upper;
551};
552
553struct enum_field_class_mapping {
554 /* Weak */
555 const char *label;
556
02b61fe0 557 /* Array of `struct int_range` */
a0bcd369
PP
558 GArray *ranges;
559};
560
561static
562gint compare_enum_field_class_mappings(struct enum_field_class_mapping **a,
563 struct enum_field_class_mapping **b)
564{
565 return strcmp((*a)->label, (*b)->label);
566}
567
568static
02b61fe0 569gint compare_int_ranges_signed(struct int_range *a, struct int_range *b)
a0bcd369
PP
570{
571
572 if (a->lower.i < b->lower.i) {
573 return -1;
574 } else if (a->lower.i > b->lower.i) {
575 return 1;
576 } else {
577 if (a->upper.i < b->upper.i) {
578 return -1;
579 } else if (a->upper.i > b->upper.i) {
580 return 1;
581 } else {
582 return 0;
583 }
584 }
585}
586
587static
02b61fe0 588gint compare_int_ranges_unsigned(struct int_range *a, struct int_range *b)
a0bcd369
PP
589{
590 if (a->lower.u < b->lower.u) {
591 return -1;
592 } else if (a->lower.u > b->lower.u) {
593 return 1;
594 } else {
595 if (a->upper.u < b->upper.u) {
596 return -1;
597 } else if (a->upper.u > b->upper.u) {
598 return 1;
599 } else {
600 return 0;
601 }
602 }
603}
604
02b61fe0
PP
605static
606GArray *range_set_to_int_ranges(const void *spec_range_set, bool is_signed)
607{
608 uint64_t i;
609 const bt_integer_range_set *range_set;
610 GArray *ranges = g_array_new(FALSE, TRUE, sizeof(struct int_range));
611
612 if (!ranges) {
613 goto end;
614 }
615
616 if (is_signed) {
617 range_set = bt_integer_range_set_signed_as_range_set_const(
618 spec_range_set);
619 } else {
620 range_set = bt_integer_range_set_unsigned_as_range_set_const(
621 spec_range_set);
622 }
623
624 for (i = 0; i < bt_integer_range_set_get_range_count(range_set); i++) {
625 struct int_range range;
626
627 if (is_signed) {
628 const bt_integer_range_signed *orig_range =
629 bt_integer_range_set_signed_borrow_range_by_index_const(
630 spec_range_set, i);
631
632 range.lower.i = bt_integer_range_signed_get_lower(orig_range);
633 range.upper.i = bt_integer_range_signed_get_upper(orig_range);
634 } else {
635 const bt_integer_range_unsigned *orig_range =
636 bt_integer_range_set_unsigned_borrow_range_by_index_const(
637 spec_range_set, i);
638
639 range.lower.u = bt_integer_range_unsigned_get_lower(orig_range);
640 range.upper.u = bt_integer_range_unsigned_get_upper(orig_range);
641 }
642
643 g_array_append_val(ranges, range);
644 }
645
646 if (is_signed) {
647 g_array_sort(ranges, (GCompareFunc) compare_int_ranges_signed);
648 } else {
649 g_array_sort(ranges,
650 (GCompareFunc) compare_int_ranges_unsigned);
651 }
652
653end:
654 return ranges;
655}
656
a0bcd369
PP
657static
658void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping)
659{
660 if (mapping->ranges) {
661 g_array_free(mapping->ranges, TRUE);
662 mapping->ranges = NULL;
663 }
664
665 g_free(mapping);
666}
667
668static
02b61fe0
PP
669struct int_range *int_range_at(GArray *ranges, uint64_t index)
670{
671 return &g_array_index(ranges, struct int_range, index);
672}
673
674static
675void write_int_range(struct details_write_ctx *ctx,
676 struct int_range *range, bool is_signed)
a0bcd369
PP
677{
678 g_string_append(ctx->str, "[");
679
680 if (is_signed) {
681 write_int_prop_value(ctx, range->lower.i);
682 } else {
683 write_int_prop_value(ctx, range->lower.u);
684 }
685
02b61fe0
PP
686 if (range->lower.u != range->upper.u) {
687 g_string_append(ctx->str, ", ");
a0bcd369 688
02b61fe0
PP
689 if (is_signed) {
690 write_int_prop_value(ctx, range->upper.i);
691 } else {
692 write_int_prop_value(ctx, range->upper.u);
693 }
a0bcd369
PP
694 }
695
696 g_string_append(ctx->str, "]");
697}
698
699static
700void write_enum_field_class_mappings(struct details_write_ctx *ctx,
701 const bt_field_class *fc)
702{
703 GPtrArray *mappings;
704 uint64_t i;
705 uint64_t range_i;
706 bool is_signed = bt_field_class_get_type(fc) ==
707 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION;
708
709 mappings = g_ptr_array_new_with_free_func(
710 (GDestroyNotify) destroy_enum_field_class_mapping);
711 BT_ASSERT(mappings);
712
713 /*
714 * Copy field class's mappings to our own arrays and structures
715 * to sort them.
716 */
717 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
718 const void *fc_mapping;
02b61fe0 719 const void *fc_range_set;
a0bcd369
PP
720 struct enum_field_class_mapping *mapping = g_new0(
721 struct enum_field_class_mapping, 1);
722
723 BT_ASSERT(mapping);
a0bcd369
PP
724
725 if (is_signed) {
60bbfc7c 726 fc_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
a0bcd369 727 fc, i);
60bbfc7c 728 fc_range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
02b61fe0 729 fc_mapping);
a0bcd369 730 } else {
60bbfc7c 731 fc_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
a0bcd369 732 fc, i);
60bbfc7c 733 fc_range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
02b61fe0 734 fc_mapping);
a0bcd369
PP
735 }
736
737 mapping->label = bt_field_class_enumeration_mapping_get_label(
60bbfc7c 738 bt_field_class_enumeration_signed_mapping_as_mapping_const(
a0bcd369 739 fc_mapping));
02b61fe0
PP
740 mapping->ranges = range_set_to_int_ranges(fc_range_set,
741 is_signed);
742 BT_ASSERT(mapping->ranges);
a0bcd369
PP
743 g_ptr_array_add(mappings, mapping);
744 }
745
02b61fe0 746 /* Sort mappings (ranges are already sorted within mappings) */
a0bcd369
PP
747 g_ptr_array_sort(mappings,
748 (GCompareFunc) compare_enum_field_class_mappings);
749
a0bcd369
PP
750 /* Write mappings */
751 for (i = 0; i < mappings->len; i++) {
752 struct enum_field_class_mapping *mapping = mappings->pdata[i];
753
754 write_nl(ctx);
7753db0d 755 write_prop_name_line(ctx, mapping->label);
a0bcd369 756
a0bcd369 757 for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
02b61fe0
PP
758 write_sp(ctx);
759 write_int_range(ctx,
760 int_range_at(mapping->ranges, range_i),
761 is_signed);
a0bcd369 762 }
a0bcd369
PP
763 }
764
765 g_ptr_array_free(mappings, TRUE);
766}
767
768static
769void write_field_path(struct details_write_ctx *ctx,
770 const bt_field_path *field_path)
771{
772 uint64_t i;
773
774 g_string_append_c(ctx->str, '[');
775
776 switch (bt_field_path_get_root_scope(field_path)) {
056995e5 777 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
a0bcd369
PP
778 write_str_prop_value(ctx, "Packet context");
779 break;
056995e5 780 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
a0bcd369
PP
781 write_str_prop_value(ctx, "Event common context");
782 break;
056995e5 783 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
a0bcd369
PP
784 write_str_prop_value(ctx, "Event specific context");
785 break;
056995e5 786 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
a0bcd369
PP
787 write_str_prop_value(ctx, "Event payload");
788 break;
789 default:
790 abort();
791 }
792
793 g_string_append(ctx->str, ": ");
794
795 for (i = 0; i < bt_field_path_get_item_count(field_path); i++) {
796 const bt_field_path_item *fp_item =
797 bt_field_path_borrow_item_by_index_const(field_path, i);
798
799 if (i != 0) {
800 g_string_append(ctx->str, ", ");
801 }
802
803 switch (bt_field_path_item_get_type(fp_item)) {
804 case BT_FIELD_PATH_ITEM_TYPE_INDEX:
805 write_uint_prop_value(ctx,
806 bt_field_path_item_index_get_index(fp_item));
807 break;
808 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
809 write_str_prop_value(ctx, "<current>");
810 break;
811 default:
812 abort();
813 }
814 }
815
816 g_string_append_c(ctx->str, ']');
817}
818
819static
02b61fe0
PP
820void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc);
821
822static
823void write_variant_field_class_option(struct details_write_ctx *ctx,
824 const bt_field_class *fc, uint64_t index)
a0bcd369 825{
a0bcd369 826 bt_field_class_type fc_type = bt_field_class_get_type(fc);
02b61fe0
PP
827 const bt_field_class_variant_option *option =
828 bt_field_class_variant_borrow_option_by_index_const(
829 fc, index);
7753db0d 830 const void *orig_ranges = NULL;
02b61fe0
PP
831 GArray *int_ranges = NULL;
832 bool is_signed;
7753db0d
PP
833 const bt_value *user_attrs =
834 bt_field_class_variant_option_borrow_user_attributes_const(
835 option);
836 const bt_field_class *option_fc =
837 bt_field_class_variant_option_borrow_field_class_const(option);
a0bcd369 838
02b61fe0
PP
839 write_nl(ctx);
840 write_compound_member_name(ctx,
841 bt_field_class_variant_option_get_name(option));
842
8bc207af
PP
843 if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
844 const bt_field_class_variant_with_selector_field_integer_unsigned_option *spec_opt =
845 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
02b61fe0
PP
846 fc, index);
847
848 orig_ranges =
8bc207af 849 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
02b61fe0
PP
850 spec_opt);
851 is_signed = false;
8bc207af
PP
852 } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
853 const bt_field_class_variant_with_selector_field_integer_signed_option *spec_opt =
854 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
02b61fe0
PP
855 fc, index);
856
857 orig_ranges =
8bc207af 858 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
02b61fe0
PP
859 spec_opt);
860 is_signed = true;
861 }
862
863 if (orig_ranges) {
864 uint64_t i;
865
866 int_ranges = range_set_to_int_ranges(orig_ranges, is_signed);
867 BT_ASSERT(int_ranges);
868
869 for (i = 0; i < int_ranges->len; i++) {
870 struct int_range *range = int_range_at(int_ranges, i);
871
872 write_sp(ctx);
873 write_int_range(ctx, range, is_signed);
874 }
875
876 g_string_append(ctx->str, ": ");
877 } else {
a0bcd369
PP
878 write_sp(ctx);
879 }
880
7753db0d
PP
881 if (bt_value_map_is_empty(user_attrs)) {
882 write_field_class(ctx, option_fc);
883 } else {
884 write_nl(ctx);
885 incr_indent(ctx);
02b61fe0 886
7753db0d
PP
887 /* Field class */
888 write_prop_name_line(ctx, "Field class");
889 write_sp(ctx);
890 write_field_class(ctx, option_fc);
891 write_nl(ctx);
02b61fe0 892
7753db0d
PP
893 /* User attributes */
894 write_user_attributes(ctx, user_attrs,
895 false, NULL);
02b61fe0 896
7753db0d 897 decr_indent(ctx);
02b61fe0
PP
898 }
899
7753db0d
PP
900 if (int_ranges) {
901 g_array_free(int_ranges, TRUE);
02b61fe0
PP
902 }
903}
904
905static
906void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc)
907{
908 uint64_t i;
909 const char *type;
910 bt_field_class_type fc_type = bt_field_class_get_type(fc);
7753db0d
PP
911 const bt_value *user_attrs;
912 bool wrote_user_attrs = false;
02b61fe0 913
a0bcd369
PP
914 /* Write field class's type */
915 switch (fc_type) {
9edadc81
PP
916 case BT_FIELD_CLASS_TYPE_BOOL:
917 type = "Boolean";
918 break;
635615fb
PP
919 case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
920 type = "Bit array";
921 break;
a0bcd369
PP
922 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
923 type = "Unsigned integer";
924 break;
925 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
926 type = "Signed integer";
927 break;
928 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
929 type = "Unsigned enumeration";
930 break;
931 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
932 type = "Signed enumeration";
933 break;
76276a81
FD
934 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
935 type = "Single-precision real";
936 break;
937 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
938 type = "Double-precision real";
a0bcd369
PP
939 break;
940 case BT_FIELD_CLASS_TYPE_STRING:
941 type = "String";
942 break;
943 case BT_FIELD_CLASS_TYPE_STRUCTURE:
944 type = "Structure";
945 break;
946 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
947 type = "Static array";
948 break;
b8ddb4f0
PP
949 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
950 type = "Dynamic array (no length field)";
951 break;
952 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
953 type = "Dynamic array (with length field)";
a0bcd369 954 break;
8bc207af 955 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD:
467673c1
PP
956 type = "Option (no selector)";
957 break;
8bc207af 958 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
467673c1
PP
959 type = "Option (boolean selector)";
960 break;
8bc207af 961 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
467673c1
PP
962 type = "Option (unsigned integer selector)";
963 break;
8bc207af 964 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
467673c1 965 type = "Option (signed integer selector)";
1bca9d21 966 break;
8bc207af 967 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
02b61fe0
PP
968 type = "Variant (no selector)";
969 break;
8bc207af 970 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
0822832b 971 type = "Variant (unsigned integer selector)";
02b61fe0 972 break;
8bc207af 973 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
0822832b 974 type = "Variant (signed integer selector)";
a0bcd369
PP
975 break;
976 default:
977 abort();
978 }
979
980 g_string_append_printf(ctx->str, "%s%s%s",
981 color_fg_blue(ctx), type, color_reset(ctx));
982
7753db0d 983 /* Write field class's single-line properties */
a0bcd369
PP
984 switch (fc_type) {
985 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
986 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
987 write_sp(ctx);
988 write_int_field_class_props(ctx, fc, true);
989 break;
990 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
991 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
992 {
993 uint64_t mapping_count =
994 bt_field_class_enumeration_get_mapping_count(fc);
995
996 write_sp(ctx);
997 write_int_field_class_props(ctx, fc, false);
998 g_string_append(ctx->str, ", ");
999 write_uint_prop_value(ctx, mapping_count);
1000 g_string_append_printf(ctx->str, " mapping%s)",
1001 plural(mapping_count));
a0bcd369
PP
1002 break;
1003 }
a0bcd369
PP
1004 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1005 {
1006 uint64_t member_count =
1007 bt_field_class_structure_get_member_count(fc);
1008
1009 g_string_append(ctx->str, " (");
1010 write_uint_prop_value(ctx, member_count);
1011 g_string_append_printf(ctx->str, " member%s)",
1012 plural(member_count));
a0bcd369
PP
1013 break;
1014 }
1015 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
b8ddb4f0
PP
1016 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
1017 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
a0bcd369
PP
1018 if (fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
1019 g_string_append(ctx->str, " (Length ");
1020 write_uint_prop_value(ctx,
60bbfc7c 1021 bt_field_class_array_static_get_length(fc));
a0bcd369 1022 g_string_append_c(ctx->str, ')');
b8ddb4f0 1023 } else if (fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
a0bcd369 1024 const bt_field_path *length_field_path =
b8ddb4f0 1025 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
a0bcd369
PP
1026 fc);
1027
b8ddb4f0
PP
1028 g_string_append(ctx->str, " (Length field path ");
1029 write_field_path(ctx, length_field_path);
1030 g_string_append_c(ctx->str, ')');
a0bcd369
PP
1031 }
1032
a0bcd369 1033 break;
8bc207af
PP
1034 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
1035 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1036 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
1bca9d21
PP
1037 {
1038 const bt_field_path *selector_field_path =
8bc207af 1039 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
467673c1 1040 fc);
1bca9d21 1041
467673c1
PP
1042 g_string_append(ctx->str, " (Selector field path ");
1043 write_field_path(ctx, selector_field_path);
1044 g_string_append_c(ctx->str, ')');
7753db0d
PP
1045 break;
1046 }
8bc207af
PP
1047 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
1048 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1049 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
7753db0d
PP
1050 {
1051 uint64_t option_count =
1052 bt_field_class_variant_get_option_count(fc);
1053 const bt_field_path *sel_field_path = NULL;
1054
8bc207af
PP
1055 if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD ||
1056 fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
7753db0d 1057 sel_field_path =
8bc207af 1058 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
7753db0d
PP
1059 fc);
1060 BT_ASSERT(sel_field_path);
1061 }
1062
1063 g_string_append(ctx->str, " (");
1064 write_uint_prop_value(ctx, option_count);
1065 g_string_append_printf(ctx->str, " option%s",
1066 plural(option_count));
1067
1068 if (sel_field_path) {
1069 g_string_append(ctx->str, ", Selector field path ");
1070 write_field_path(ctx, sel_field_path);
1071 }
1072
1073 g_string_append_c(ctx->str, ')');
1074 break;
1075 }
1076 default:
1077 break;
1078 }
1079
1080 incr_indent(ctx);
1081 user_attrs = bt_field_class_borrow_user_attributes_const(fc);
1082 if (!bt_value_map_is_empty(user_attrs)) {
1083 g_string_append(ctx->str, ":\n");
1084 write_user_attributes(ctx, user_attrs, false, NULL);
1085 wrote_user_attrs = true;
1086 }
1087
1088 /* Write field class's complex properties */
1089 switch (fc_type) {
1090 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1091 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1092 {
1093 uint64_t mapping_count =
1094 bt_field_class_enumeration_get_mapping_count(fc);
1095
1096 if (mapping_count > 0) {
1097 if (wrote_user_attrs) {
1098 write_nl(ctx);
1099 write_indent(ctx);
1100 write_prop_name(ctx, "Mappings");
1101 g_string_append_c(ctx->str, ':');
1102 incr_indent(ctx);
1103 } else {
1104 /* Each mapping starts with its own newline */
1105 g_string_append_c(ctx->str, ':');
1106 }
1107
1108 write_enum_field_class_mappings(ctx, fc);
1109
1110 if (wrote_user_attrs) {
1111 decr_indent(ctx);
1112 }
1113 }
1114
1115 break;
1116 }
1117 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1118 {
1119 uint64_t member_count =
1120 bt_field_class_structure_get_member_count(fc);
1121
1122 if (member_count > 0) {
1123 if (wrote_user_attrs) {
1124 write_nl(ctx);
1125 write_indent(ctx);
1126 write_prop_name(ctx, "Members");
1127 g_string_append_c(ctx->str, ':');
1128 incr_indent(ctx);
1129 } else {
1130 /* Each member starts with its own newline */
1131 g_string_append_c(ctx->str, ':');
1132 }
1133
1134 for (i = 0; i < member_count; i++) {
1135 const bt_field_class_structure_member *member =
1136 bt_field_class_structure_borrow_member_by_index_const(
1137 fc, i);
1138 const bt_value *user_attrs;
1139 const bt_field_class *member_fc =
1140 bt_field_class_structure_member_borrow_field_class_const(member);
1141
1142 write_nl(ctx);
1143 write_compound_member_name(ctx,
1144 bt_field_class_structure_member_get_name(member));
1145 user_attrs = bt_field_class_structure_member_borrow_user_attributes_const(
1146 member);
1147
1148 if (bt_value_map_is_empty(user_attrs)) {
1149 write_sp(ctx);
1150 write_field_class(ctx, member_fc);
1151 } else {
1152 write_nl(ctx);
1153 incr_indent(ctx);
1154
1155 /* Field class */
1156 write_prop_name_line(ctx, "Field class");
1157 write_sp(ctx);
1158 write_field_class(ctx, member_fc);
1159 write_nl(ctx);
1160
1161 /* User attributes */
1162 write_user_attributes(ctx, user_attrs,
1163 false, NULL);
1164
1165 decr_indent(ctx);
1166 }
1167 }
1168
1169 if (wrote_user_attrs) {
1170 decr_indent(ctx);
1171 }
1172 }
1173
1174 break;
1175 }
1176 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
b8ddb4f0
PP
1177 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
1178 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
7753db0d
PP
1179 if (wrote_user_attrs) {
1180 write_nl(ctx);
1181 } else {
1182 g_string_append(ctx->str, ":\n");
1183 }
1184
1185 write_prop_name_line(ctx, "Element");
1186 write_sp(ctx);
1187 write_field_class(ctx,
1188 bt_field_class_array_borrow_element_field_class_const(fc));
1189 break;
8bc207af
PP
1190 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD:
1191 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
1192 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1193 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
467673c1
PP
1194 {
1195 const void *ranges = NULL;
1196 bool selector_is_signed = false;
1197
7753db0d
PP
1198 if (wrote_user_attrs) {
1199 write_nl(ctx);
1200 } else {
1201 g_string_append(ctx->str, ":\n");
1202 }
1203
8bc207af 1204 if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) {
467673c1 1205 write_bool_prop_line(ctx, "Selector is reversed",
8bc207af
PP
1206 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc));
1207 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
1208 ranges = bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc);
1209 } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD) {
1210 ranges = bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc);
467673c1
PP
1211 selector_is_signed = true;
1212 }
1213
1214 if (ranges) {
1215 GArray *sorted_ranges = range_set_to_int_ranges(
1216 ranges, selector_is_signed);
1217 uint64_t i;
1218
1219 BT_ASSERT(sorted_ranges);
1220 BT_ASSERT(sorted_ranges->len > 0);
1221 write_prop_name_line(ctx, "Selector ranges");
1222
1223 for (i = 0; i < sorted_ranges->len; i++) {
1224 write_sp(ctx);
1225 write_int_range(ctx,
1226 int_range_at(sorted_ranges, i),
1227 selector_is_signed);
1228 }
1229
1230 write_nl(ctx);
1231 g_array_free(sorted_ranges, TRUE);
1232 }
1233
7753db0d 1234 write_prop_name_line(ctx, "Content");
1bca9d21
PP
1235 write_sp(ctx);
1236 write_field_class(ctx,
1237 bt_field_class_option_borrow_field_class_const(fc));
1bca9d21 1238 break;
467673c1 1239 }
8bc207af
PP
1240 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
1241 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1242 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
7753db0d
PP
1243 {
1244 uint64_t option_count =
1245 bt_field_class_variant_get_option_count(fc);
1246
1247 if (option_count > 0) {
1248 if (wrote_user_attrs) {
1249 write_nl(ctx);
1250 write_indent(ctx);
1251 write_prop_name(ctx, "Options");
1252 g_string_append_c(ctx->str, ':');
1253 incr_indent(ctx);
1254 } else {
1255 /* Each option starts with its own newline */
1256 g_string_append_c(ctx->str, ':');
1257 }
1258
1259 for (i = 0; i < option_count; i++) {
1260 write_variant_field_class_option(ctx, fc, i);
1261 }
1262
1263 if (wrote_user_attrs) {
1264 decr_indent(ctx);
1265 }
1266 }
1267
a0bcd369 1268 break;
7753db0d 1269 }
a0bcd369
PP
1270 default:
1271 break;
1272 }
7753db0d
PP
1273
1274 decr_indent(ctx);
a0bcd369
PP
1275}
1276
1277static
1278void write_root_field_class(struct details_write_ctx *ctx, const char *name,
1279 const bt_field_class *fc)
1280{
1281 BT_ASSERT(name);
1282 BT_ASSERT(fc);
1283 write_indent(ctx);
1284 write_prop_name(ctx, name);
1285 g_string_append(ctx->str, ": ");
02b61fe0 1286 write_field_class(ctx, fc);
a0bcd369
PP
1287 write_nl(ctx);
1288}
1289
1290static
1291void write_event_class(struct details_write_ctx *ctx, const bt_event_class *ec)
1292{
1293 const char *name = bt_event_class_get_name(ec);
1294 const char *emf_uri;
1295 const bt_field_class *fc;
1296 bt_event_class_log_level log_level;
1297
1298 write_indent(ctx);
1299 write_obj_type_name(ctx, "Event class");
1300
1301 /* Write name and ID */
1302 if (name) {
1303 g_string_append_printf(ctx->str, " `%s%s%s`",
1304 color_fg_green(ctx), name, color_reset(ctx));
1305 }
1306
1307 g_string_append(ctx->str, " (ID ");
1308 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
1309 g_string_append(ctx->str, "):\n");
1310
1311 /* Write properties */
1312 incr_indent(ctx);
1313
7753db0d
PP
1314 /* Write user attributes */
1315 write_user_attributes(ctx,
1316 bt_event_class_borrow_user_attributes_const(ec), true, NULL);
1317
a0bcd369
PP
1318 /* Write log level */
1319 if (bt_event_class_get_log_level(ec, &log_level) ==
1320 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
1321 const char *ll_str = NULL;
1322
1323 switch (log_level) {
1324 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
1325 ll_str = "Emergency";
1326 break;
1327 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
1328 ll_str = "Alert";
1329 break;
1330 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
1331 ll_str = "Critical";
1332 break;
1333 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
1334 ll_str = "Error";
1335 break;
1336 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
1337 ll_str = "Warning";
1338 break;
1339 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
1340 ll_str = "Notice";
1341 break;
1342 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
1343 ll_str = "Info";
1344 break;
1345 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
1346 ll_str = "Debug (system)";
1347 break;
1348 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
1349 ll_str = "Debug (program)";
1350 break;
1351 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
1352 ll_str = "Debug (process)";
1353 break;
1354 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
1355 ll_str = "Debug (module)";
1356 break;
1357 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
1358 ll_str = "Debug (unit)";
1359 break;
1360 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
1361 ll_str = "Debug (function)";
1362 break;
1363 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
1364 ll_str = "Debug (line)";
1365 break;
1366 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
1367 ll_str = "Debug";
1368 break;
1369 default:
1370 abort();
1371 }
1372
1373 write_str_prop_line(ctx, "Log level", ll_str);
1374 }
1375
1376 /* Write EMF URI */
1377 emf_uri = bt_event_class_get_emf_uri(ec);
1378 if (emf_uri) {
1379 write_str_prop_line(ctx, "EMF URI", emf_uri);
1380 }
1381
1382 /* Write specific context field class */
1383 fc = bt_event_class_borrow_specific_context_field_class_const(ec);
1384 if (fc) {
1385 write_root_field_class(ctx, "Specific context field class", fc);
1386 }
1387
1388 /* Write payload field class */
1389 fc = bt_event_class_borrow_payload_field_class_const(ec);
1390 if (fc) {
1391 write_root_field_class(ctx, "Payload field class", fc);
1392 }
1393
1394 decr_indent(ctx);
1395}
1396
1397static
1398void write_clock_class_prop_lines(struct details_write_ctx *ctx,
1399 const bt_clock_class *cc)
1400{
1401 int64_t offset_seconds;
1402 uint64_t offset_cycles;
1403 const char *str;
1404
1405 str = bt_clock_class_get_name(cc);
1406 if (str) {
1407 write_str_prop_line(ctx, "Name", str);
1408 }
1409
7753db0d
PP
1410 write_user_attributes(ctx,
1411 bt_clock_class_borrow_user_attributes_const(cc), true, NULL);
a0bcd369
PP
1412 str = bt_clock_class_get_description(cc);
1413 if (str) {
1414 write_str_prop_line(ctx, "Description", str);
1415 }
1416
1417 write_uint_prop_line(ctx, "Frequency (Hz)",
1418 bt_clock_class_get_frequency(cc));
1419 write_uint_prop_line(ctx, "Precision (cycles)",
1420 bt_clock_class_get_precision(cc));
1421 bt_clock_class_get_offset(cc, &offset_seconds, &offset_cycles);
1422 write_int_prop_line(ctx, "Offset (s)", offset_seconds);
1423 write_uint_prop_line(ctx, "Offset (cycles)", offset_cycles);
1424 write_bool_prop_line(ctx, "Origin is Unix epoch",
1425 bt_clock_class_origin_is_unix_epoch(cc));
1426
1427 if (ctx->details_comp->cfg.with_uuid) {
1428 bt_uuid uuid = bt_clock_class_get_uuid(cc);
1429
1430 if (uuid) {
1431 write_uuid_prop_line(ctx, "UUID", uuid);
1432 }
1433 }
1434}
1435
1436static
1437gint compare_event_classes(const bt_event_class **a, const bt_event_class **b)
1438{
1439 uint64_t id_a = bt_event_class_get_id(*a);
1440 uint64_t id_b = bt_event_class_get_id(*b);
1441
1442 if (id_a < id_b) {
1443 return -1;
1444 } else if (id_a > id_b) {
1445 return 1;
1446 } else {
1447 return 0;
1448 }
1449}
1450
1451static
1452void write_stream_class(struct details_write_ctx *ctx,
1453 const bt_stream_class *sc)
1454{
1455 const bt_field_class *fc;
1456 GPtrArray *event_classes = g_ptr_array_new();
1457 uint64_t i;
1458
1459 write_indent(ctx);
1460 write_obj_type_name(ctx, "Stream class");
1461
1462 /* Write name and ID */
1463 if (ctx->details_comp->cfg.with_stream_class_name) {
1464 const char *name = bt_stream_class_get_name(sc);
1465
1466 if (name) {
1467 g_string_append(ctx->str, " `");
1468 write_str_prop_value(ctx, name);
1469 g_string_append(ctx->str, "`");
1470 }
1471 }
1472
1473 g_string_append(ctx->str, " (ID ");
1474 write_uint_prop_value(ctx, bt_stream_class_get_id(sc));
1475 g_string_append(ctx->str, "):\n");
1476
1477 /* Write properties */
1478 incr_indent(ctx);
1479
7753db0d
PP
1480 /* Write user attributes */
1481 write_user_attributes(ctx,
1482 bt_stream_class_borrow_user_attributes_const(sc), true, NULL);
1483
a0bcd369
PP
1484 /* Write configuration */
1485 write_bool_prop_line(ctx,
37a93d41
PP
1486 "Supports packets", bt_stream_class_supports_packets(sc));
1487
1488 if (bt_stream_class_supports_packets(sc)) {
1489 write_bool_prop_line(ctx,
1490 "Packets have beginning default clock snapshot",
1491 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc));
1492 write_bool_prop_line(ctx,
1493 "Packets have end default clock snapshot",
1494 bt_stream_class_packets_have_end_default_clock_snapshot(sc));
1495 }
1496
a0bcd369
PP
1497 write_bool_prop_line(ctx,
1498 "Supports discarded events",
1499 bt_stream_class_supports_discarded_events(sc));
74f62477
PP
1500
1501 if (bt_stream_class_supports_discarded_events(sc)) {
1502 write_bool_prop_line(ctx,
1503 "Discarded events have default clock snapshots",
1504 bt_stream_class_discarded_events_have_default_clock_snapshots(sc));
1505 }
1506
a0bcd369
PP
1507 write_bool_prop_line(ctx,
1508 "Supports discarded packets",
1509 bt_stream_class_supports_discarded_packets(sc));
74f62477
PP
1510
1511 if (bt_stream_class_supports_discarded_packets(sc)) {
1512 write_bool_prop_line(ctx,
1513 "Discarded packets have default clock snapshots",
1514 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc));
1515 }
a0bcd369
PP
1516
1517 /* Write default clock class */
1518 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
1519 write_indent(ctx);
1520 write_prop_name(ctx, "Default clock class");
1521 g_string_append_c(ctx->str, ':');
1522 write_nl(ctx);
1523 incr_indent(ctx);
1524 write_clock_class_prop_lines(ctx,
1525 bt_stream_class_borrow_default_clock_class_const(sc));
1526 decr_indent(ctx);
1527 }
1528
1529 fc = bt_stream_class_borrow_packet_context_field_class_const(sc);
1530 if (fc) {
1531 write_root_field_class(ctx, "Packet context field class", fc);
1532 }
1533
1534 fc = bt_stream_class_borrow_event_common_context_field_class_const(sc);
1535 if (fc) {
1536 write_root_field_class(ctx, "Event common context field class",
1537 fc);
1538 }
1539
1540 for (i = 0; i < bt_stream_class_get_event_class_count(sc); i++) {
1541 g_ptr_array_add(event_classes,
1542 (gpointer) bt_stream_class_borrow_event_class_by_index_const(
1543 sc, i));
1544 }
1545
1546 g_ptr_array_sort(event_classes, (GCompareFunc) compare_event_classes);
1547
1548 for (i = 0; i < event_classes->len; i++) {
1549 write_event_class(ctx, event_classes->pdata[i]);
1550 }
1551
1552 decr_indent(ctx);
1553 g_ptr_array_free(event_classes, TRUE);
1554}
1555
1556static
1557gint compare_stream_classes(const bt_stream_class **a, const bt_stream_class **b)
1558{
1559 uint64_t id_a = bt_stream_class_get_id(*a);
1560 uint64_t id_b = bt_stream_class_get_id(*b);
1561
1562 if (id_a < id_b) {
1563 return -1;
1564 } else if (id_a > id_b) {
1565 return 1;
1566 } else {
1567 return 0;
1568 }
1569}
1570
a0bcd369
PP
1571static
1572void write_trace_class(struct details_write_ctx *ctx, const bt_trace_class *tc)
1573{
1574 GPtrArray *stream_classes = g_ptr_array_new();
a0bcd369
PP
1575 uint64_t i;
1576 bool printed_prop = false;
1577
1578 write_indent(ctx);
1579 write_obj_type_name(ctx, "Trace class");
1580
7753db0d 1581
a0bcd369
PP
1582 for (i = 0; i < bt_trace_class_get_stream_class_count(tc); i++) {
1583 g_ptr_array_add(stream_classes,
1584 (gpointer) bt_trace_class_borrow_stream_class_by_index_const(
1585 tc, i));
1586 }
1587
1588 g_ptr_array_sort(stream_classes, (GCompareFunc) compare_stream_classes);
1589
1590 if (stream_classes->len > 0) {
1591 if (!printed_prop) {
1592 g_string_append(ctx->str, ":\n");
1593 printed_prop = true;
1594 }
1595 }
1596
cd03c43c
PP
1597 incr_indent(ctx);
1598
7753db0d
PP
1599 /* Write user attributes */
1600 write_user_attributes(ctx,
1601 bt_trace_class_borrow_user_attributes_const(tc), true,
1602 &printed_prop);
1603
1604 /* Write stream classes */
a0bcd369
PP
1605 for (i = 0; i < stream_classes->len; i++) {
1606 write_stream_class(ctx, stream_classes->pdata[i]);
1607 }
1608
a0bcd369
PP
1609 if (!printed_prop) {
1610 write_nl(ctx);
1611 }
1612
cd03c43c 1613 decr_indent(ctx);
a0bcd369 1614 g_ptr_array_free(stream_classes, TRUE);
a0bcd369
PP
1615}
1616
1617static
1618int try_write_meta(struct details_write_ctx *ctx, const bt_trace_class *tc,
1619 const bt_stream_class *sc, const bt_event_class *ec)
1620{
1621 int ret = 0;
1622
1623 BT_ASSERT(tc);
1624
1625 if (details_need_to_write_trace_class(ctx, tc)) {
1626 uint64_t sc_i;
1627
1628 if (ctx->details_comp->cfg.compact &&
1629 ctx->details_comp->printed_something) {
1630 /*
1631 * There are no empty line between messages in
1632 * compact mode, so write one here to decouple
1633 * the trace class from the next message.
1634 */
1635 write_nl(ctx);
1636 }
1637
1638 /*
1639 * write_trace_class() also writes all its stream
1640 * classes their event classes, so we don't need to
1641 * rewrite `sc`.
1642 */
1643 write_trace_class(ctx, tc);
a0bcd369
PP
1644
1645 /*
1646 * Mark this trace class as written, as well as all
1647 * its stream classes and their event classes.
1648 */
1649 ret = details_did_write_trace_class(ctx, tc);
1650 if (ret) {
1651 goto end;
1652 }
1653
1654 for (sc_i = 0; sc_i < bt_trace_class_get_stream_class_count(tc);
1655 sc_i++) {
1656 uint64_t ec_i;
1657 const bt_stream_class *tc_sc =
1658 bt_trace_class_borrow_stream_class_by_index_const(
1659 tc, sc_i);
1660
1661 details_did_write_meta_object(ctx, tc, tc_sc);
1662
1663 for (ec_i = 0; ec_i <
1664 bt_stream_class_get_event_class_count(tc_sc);
1665 ec_i++) {
1666 details_did_write_meta_object(ctx, tc,
1667 bt_stream_class_borrow_event_class_by_index_const(
1668 tc_sc, ec_i));
1669 }
1670 }
1671
1672 goto end;
1673 }
1674
1675 if (sc && details_need_to_write_meta_object(ctx, tc, sc)) {
1676 uint64_t ec_i;
1677
1678 BT_ASSERT(tc);
1679
1680 if (ctx->details_comp->cfg.compact &&
1681 ctx->details_comp->printed_something) {
1682 /*
1683 * There are no empty line between messages in
1684 * compact mode, so write one here to decouple
1685 * the stream class from the next message.
1686 */
1687 write_nl(ctx);
1688 }
1689
1690 /*
1691 * write_stream_class() also writes all its event
1692 * classes, so we don't need to rewrite `ec`.
1693 */
1694 write_stream_class(ctx, sc);
a0bcd369
PP
1695
1696 /*
1697 * Mark this stream class as written, as well as all its
1698 * event classes.
1699 */
1700 details_did_write_meta_object(ctx, tc, sc);
1701
1702 for (ec_i = 0; ec_i <
1703 bt_stream_class_get_event_class_count(sc);
1704 ec_i++) {
1705 details_did_write_meta_object(ctx, tc,
1706 bt_stream_class_borrow_event_class_by_index_const(
1707 sc, ec_i));
1708 }
1709
1710 goto end;
1711 }
1712
1713 if (ec && details_need_to_write_meta_object(ctx, tc, ec)) {
1714 BT_ASSERT(sc);
1715
1716 if (ctx->details_comp->cfg.compact &&
1717 ctx->details_comp->printed_something) {
1718 /*
1719 * There are no empty line between messages in
1720 * compact mode, so write one here to decouple
1721 * the event class from the next message.
1722 */
1723 write_nl(ctx);
1724 }
1725
1726 write_event_class(ctx, ec);
a0bcd369
PP
1727 details_did_write_meta_object(ctx, tc, ec);
1728 goto end;
1729 }
1730
1731end:
1732 return ret;
1733}
1734
1735static
1736void write_time_str(struct details_write_ctx *ctx, const char *str)
1737{
1738 if (!ctx->details_comp->cfg.with_time) {
1739 goto end;
1740 }
1741
1742 g_string_append_printf(ctx->str, "[%s%s%s%s]",
1743 color_bold(ctx), color_fg_blue(ctx), str, color_reset(ctx));
1744
1745 if (ctx->details_comp->cfg.compact) {
1746 write_sp(ctx);
1747 } else {
1748 write_nl(ctx);
1749 }
1750
1751end:
1752 return;
1753}
1754
1755static
1756void write_time(struct details_write_ctx *ctx, const bt_clock_snapshot *cs)
1757{
fb25b9e3 1758 bt_clock_snapshot_get_ns_from_origin_status cs_status;
a0bcd369
PP
1759 int64_t ns_from_origin;
1760 char buf[32];
1761
1762 if (!ctx->details_comp->cfg.with_time) {
1763 goto end;
1764 }
1765
1766 format_uint(buf, bt_clock_snapshot_get_value(cs), 10);
1767 g_string_append_printf(ctx->str, "[%s%s%s%s%s",
1768 color_bold(ctx), color_fg_blue(ctx), buf,
1769 color_reset(ctx),
1770 ctx->details_comp->cfg.compact ? "" : " cycles");
fb25b9e3
PP
1771 cs_status = bt_clock_snapshot_get_ns_from_origin(cs, &ns_from_origin);
1772 if (cs_status == BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK) {
a0bcd369
PP
1773 format_int(buf, ns_from_origin, 10);
1774 g_string_append_printf(ctx->str, "%s %s%s%s%s%s",
1775 ctx->details_comp->cfg.compact ? "" : ",",
1776 color_bold(ctx), color_fg_blue(ctx), buf,
1777 color_reset(ctx),
1778 ctx->details_comp->cfg.compact ? "" : " ns from origin");
1779 }
1780
1781 g_string_append(ctx->str, "]");
1782
1783 if (ctx->details_comp->cfg.compact) {
1784 write_sp(ctx);
1785 } else {
1786 write_nl(ctx);
1787 }
1788
1789end:
1790 return;
1791}
1792
1793static
1794int write_message_follow_tag(struct details_write_ctx *ctx,
1795 const bt_stream *stream)
1796{
1797 int ret;
1798 uint64_t unique_trace_id;
1799 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
1800 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
1801
1802 ret = details_trace_unique_id(ctx, trace, &unique_trace_id);
1803 if (ret) {
1804 goto end;
1805 }
1806
1807 if (ctx->details_comp->cfg.compact) {
1808 g_string_append_printf(ctx->str,
1809 "%s{%s%" PRIu64 " %" PRIu64 " %" PRIu64 "%s%s}%s ",
1810 color_fg_cyan(ctx), color_bold(ctx),
1811 unique_trace_id, bt_stream_class_get_id(sc),
1812 bt_stream_get_id(stream),
1813 color_reset(ctx), color_fg_cyan(ctx), color_reset(ctx));
1814 } else {
1815 g_string_append_printf(ctx->str,
1816 "%s{Trace %s%" PRIu64 "%s%s, Stream class ID %s%" PRIu64 "%s%s, Stream ID %s%" PRIu64 "%s%s}%s\n",
1817 color_fg_cyan(ctx),
1818 color_bold(ctx), unique_trace_id,
1819 color_reset(ctx), color_fg_cyan(ctx),
1820 color_bold(ctx), bt_stream_class_get_id(sc),
1821 color_reset(ctx), color_fg_cyan(ctx),
1822 color_bold(ctx), bt_stream_get_id(stream),
1823 color_reset(ctx), color_fg_cyan(ctx),
1824 color_reset(ctx));
1825 }
1826
1827end:
1828 return ret;
1829}
1830
1831static
1832void write_field(struct details_write_ctx *ctx, const bt_field *field,
1833 const char *name)
1834{
1835 uint64_t i;
1836 bt_field_class_type fc_type = bt_field_get_class_type(field);
1837 const bt_field_class *fc;
1838 char buf[64];
1839
1840 /* Write field's name */
1841 if (name) {
1842 write_compound_member_name(ctx, name);
1843 }
1844
1845 /* Write field's value */
1846 switch (fc_type) {
9edadc81
PP
1847 case BT_FIELD_CLASS_TYPE_BOOL:
1848 write_sp(ctx);
1849 write_bool_prop_value(ctx, bt_field_bool_get_value(field));
1850 break;
635615fb
PP
1851 case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
1852 format_uint(buf, bt_field_bit_array_get_value_as_integer(field),
1853 16);
1854 write_sp(ctx);
1855 write_uint_str_prop_value(ctx, buf);
1856 break;
a0bcd369
PP
1857 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1858 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1859 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1860 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1861 {
1862 unsigned int fmt_base;
1863 bt_field_class_integer_preferred_display_base base;
1864
1865 fc = bt_field_borrow_class_const(field);
1866 base = bt_field_class_integer_get_preferred_display_base(fc);
1867
1868 switch (base) {
1869 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
1870 fmt_base = 10;
1871 break;
1872 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
1873 fmt_base = 8;
1874 break;
1875 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
1876 fmt_base = 2;
1877 break;
1878 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
1879 fmt_base = 16;
1880 break;
1881 default:
1882 abort();
1883 }
1884
1885 if (fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
1886 fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
1887 format_uint(buf,
60bbfc7c 1888 bt_field_integer_unsigned_get_value(field),
a0bcd369
PP
1889 fmt_base);
1890 write_sp(ctx);
1891 write_uint_str_prop_value(ctx, buf);
1892 } else {
1893 format_int(buf,
60bbfc7c 1894 bt_field_integer_signed_get_value(field),
a0bcd369
PP
1895 fmt_base);
1896 write_sp(ctx);
1897 write_int_str_prop_value(ctx, buf);
1898 }
1899
1900 break;
1901 }
76276a81
FD
1902 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
1903 write_sp(ctx);
1904 write_float_prop_value(ctx, bt_field_real_single_precision_get_value(field));
1905 break;
1906 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
a0bcd369 1907 write_sp(ctx);
76276a81 1908 write_float_prop_value(ctx, bt_field_real_double_precision_get_value(field));
a0bcd369
PP
1909 break;
1910 case BT_FIELD_CLASS_TYPE_STRING:
1911 write_sp(ctx);
1912 write_str_prop_value(ctx, bt_field_string_get_value(field));
1913 break;
1914 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1915 {
1916 uint64_t member_count;
1917
1918 fc = bt_field_borrow_class_const(field);
1919 member_count = bt_field_class_structure_get_member_count(fc);
1920
1921 if (member_count > 0) {
1922 incr_indent(ctx);
1923
1924 for (i = 0; i < member_count; i++) {
1925 const bt_field_class_structure_member *member =
1926 bt_field_class_structure_borrow_member_by_index_const(
1927 fc, i);
1928 const bt_field *member_field =
1929 bt_field_structure_borrow_member_field_by_index_const(
1930 field, i);
1931
1932 write_nl(ctx);
1933 write_field(ctx, member_field,
1934 bt_field_class_structure_member_get_name(member));
1935 }
1936
1937 decr_indent(ctx);
1938 } else {
423fc6f7
PP
1939 write_sp(ctx);
1940 write_none_prop_value(ctx, "Empty");
a0bcd369
PP
1941 }
1942
1943 break;
1944 }
1945 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
b8ddb4f0
PP
1946 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
1947 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
a0bcd369
PP
1948 {
1949 uint64_t length = bt_field_array_get_length(field);
1950
1951 if (length == 0) {
423fc6f7
PP
1952 write_sp(ctx);
1953 write_none_prop_value(ctx, "Empty");
a0bcd369
PP
1954 } else {
1955 g_string_append(ctx->str, " Length ");
1956 write_uint_prop_value(ctx, length);
1957 g_string_append_c(ctx->str, ':');
1958 }
1959
1960 incr_indent(ctx);
1961
1962 for (i = 0; i < length; i++) {
1963 const bt_field *elem_field =
1964 bt_field_array_borrow_element_field_by_index_const(
1965 field, i);
1966
1967 write_nl(ctx);
7753db0d 1968 write_array_index(ctx, i, color_fg_cyan(ctx));
a0bcd369
PP
1969 write_field(ctx, elem_field, NULL);
1970 }
1971
1972 decr_indent(ctx);
1973 break;
1974 }
8bc207af
PP
1975 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD:
1976 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD:
1977 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1978 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
1bca9d21
PP
1979 {
1980 const bt_field *content_field =
1981 bt_field_option_borrow_field_const(field);
1982
1983 if (!content_field) {
1984 write_sp(ctx);
1985 write_none_prop_value(ctx, "None");
1986 } else {
1987 write_field(ctx, content_field, NULL);
1988 }
1989
1990 break;
1991 }
8bc207af
PP
1992 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD:
1993 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD:
1994 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD:
a0bcd369
PP
1995 write_field(ctx,
1996 bt_field_variant_borrow_selected_option_field_const(
1997 field), NULL);
1998 break;
1999 default:
2000 abort();
2001 }
2002}
2003
2004static
2005void write_root_field(struct details_write_ctx *ctx, const char *name,
2006 const bt_field *field)
2007{
2008 BT_ASSERT(name);
2009 BT_ASSERT(field);
2010 write_indent(ctx);
2011 write_prop_name(ctx, name);
2012 g_string_append(ctx->str, ":");
2013 write_field(ctx, field, NULL);
2014 write_nl(ctx);
2015}
2016
2017static
2018int write_event_message(struct details_write_ctx *ctx,
2019 const bt_message *msg)
2020{
2021 int ret = 0;
2022 const bt_event *event = bt_message_event_borrow_event_const(msg);
2023 const bt_stream *stream = bt_event_borrow_stream_const(event);
2024 const bt_event_class *ec = bt_event_borrow_class_const(event);
2025 const bt_stream_class *sc = bt_event_class_borrow_stream_class_const(ec);
2026 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
2027 const char *ec_name;
2028 const bt_field *field;
2029
2030 ret = try_write_meta(ctx, tc, sc, ec);
2031 if (ret) {
2032 goto end;
2033 }
2034
08ef09ae
PP
2035 if (!ctx->details_comp->cfg.with_data) {
2036 goto end;
2037 }
2038
2039 if (ctx->str->len > 0) {
2040 /*
2041 * Output buffer contains metadata: separate blocks with
2042 * newline.
2043 */
2044 write_nl(ctx);
2045 }
2046
a0bcd369
PP
2047 /* Write time */
2048 if (bt_stream_class_borrow_default_clock_class_const(sc)) {
2049 write_time(ctx,
2050 bt_message_event_borrow_default_clock_snapshot_const(
2051 msg));
2052 }
2053
2054 /* Write follow tag for message */
2055 ret = write_message_follow_tag(ctx, stream);
2056 if (ret) {
2057 goto end;
2058 }
2059
2060 /* Write object's basic properties */
2061 write_obj_type_name(ctx, "Event");
2062 ec_name = bt_event_class_get_name(ec);
2063 if (ec_name) {
2064 g_string_append_printf(ctx->str, " `%s%s%s`",
2065 color_fg_green(ctx), ec_name, color_reset(ctx));
2066 }
2067
2068 g_string_append(ctx->str, " (");
2069
2070 if (!ctx->details_comp->cfg.compact) {
2071 g_string_append(ctx->str, "Class ID ");
2072 }
2073
2074 write_uint_prop_value(ctx, bt_event_class_get_id(ec));
2075 g_string_append(ctx->str, ")");
2076
2077 if (ctx->details_comp->cfg.compact) {
2078 write_nl(ctx);
2079 goto end;
2080 }
2081
2082 /* Write fields */
2083 g_string_append(ctx->str, ":\n");
2084 incr_indent(ctx);
2085 field = bt_event_borrow_common_context_field_const(event);
2086 if (field) {
2087 write_root_field(ctx, "Common context", field);
2088 }
2089
2090 field = bt_event_borrow_specific_context_field_const(event);
2091 if (field) {
2092 write_root_field(ctx, "Specific context", field);
2093 }
2094
2095 field = bt_event_borrow_payload_field_const(event);
2096 if (field) {
2097 write_root_field(ctx, "Payload", field);
2098 }
2099
2100 decr_indent(ctx);
2101
2102end:
a0bcd369
PP
2103 return ret;
2104}
2105
2106static
2107gint compare_streams(const bt_stream **a, const bt_stream **b)
2108{
2109 uint64_t id_a = bt_stream_get_id(*a);
2110 uint64_t id_b = bt_stream_get_id(*b);
2111
2112 if (id_a < id_b) {
2113 return -1;
2114 } else if (id_a > id_b) {
2115 return 1;
2116 } else {
2117 const bt_stream_class *a_sc = bt_stream_borrow_class_const(*a);
2118 const bt_stream_class *b_sc = bt_stream_borrow_class_const(*b);
2119 uint64_t a_sc_id = bt_stream_class_get_id(a_sc);
2120 uint64_t b_sc_id = bt_stream_class_get_id(b_sc);
2121
2122 if (a_sc_id < b_sc_id) {
2123 return -1;
2124 } else if (a_sc_id > b_sc_id) {
2125 return 1;
2126 } else {
2127 return 0;
2128 }
2129 }
2130}
2131
2132static
2133void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
2134{
2135 const char *name;
a0bcd369
PP
2136 GPtrArray *streams = g_ptr_array_new();
2137 uint64_t i;
2138 bool printed_prop = false;
cd03c43c
PP
2139 GPtrArray *env_names = g_ptr_array_new();
2140 uint64_t env_count;
a0bcd369
PP
2141
2142 write_indent(ctx);
2143 write_obj_type_name(ctx, "Trace");
2144
2145 /* Write name */
2146 if (ctx->details_comp->cfg.with_trace_name) {
2147 name = bt_trace_get_name(trace);
2148 if (name) {
2149 g_string_append(ctx->str, " `");
2150 write_str_prop_value(ctx, name);
2151 g_string_append(ctx->str, "`");
2152 }
2153 }
2154
2155 /* Write properties */
2156 incr_indent(ctx);
2157
cd03c43c
PP
2158 /* Write UUID */
2159 if (ctx->details_comp->cfg.with_uuid) {
2160 bt_uuid uuid = bt_trace_get_uuid(trace);
2161
2162 if (uuid) {
a0bcd369
PP
2163 if (!printed_prop) {
2164 g_string_append(ctx->str, ":\n");
2165 printed_prop = true;
2166 }
2167
cd03c43c 2168 write_uuid_prop_line(ctx, "UUID", uuid);
a0bcd369
PP
2169 }
2170 }
2171
cd03c43c
PP
2172 /* Write environment */
2173 env_count = bt_trace_get_environment_entry_count(trace);
2174 if (env_count > 0) {
2175 if (!printed_prop) {
2176 g_string_append(ctx->str, ":\n");
2177 printed_prop = true;
2178 }
a0bcd369 2179
cd03c43c
PP
2180 write_indent(ctx);
2181 write_prop_name(ctx, "Environment");
2182 g_string_append(ctx->str, " (");
2183 write_uint_prop_value(ctx, env_count);
2184 g_string_append_printf(ctx->str, " entr%s):",
2185 env_count == 1 ? "y" : "ies");
2186 write_nl(ctx);
2187 incr_indent(ctx);
2188
2189 for (i = 0; i < env_count; i++) {
2190 const char *name;
2191 const bt_value *value;
2192
2193 bt_trace_borrow_environment_entry_by_index_const(
2194 trace, i, &name, &value);
2195 g_ptr_array_add(env_names, (gpointer) name);
2196 }
2197
2198 g_ptr_array_sort(env_names, (GCompareFunc) compare_strings);
2199
2200 for (i = 0; i < env_names->len; i++) {
2201 const char *name = env_names->pdata[i];
2202 const bt_value *value =
2203 bt_trace_borrow_environment_entry_value_by_name_const(
2204 trace, name);
2205
2206 BT_ASSERT(value);
2207 write_compound_member_name(ctx, name);
2208 write_sp(ctx);
2209
2210 if (bt_value_get_type(value) ==
2211 BT_VALUE_TYPE_SIGNED_INTEGER) {
2212 write_int_prop_value(ctx,
60bbfc7c 2213 bt_value_integer_signed_get(value));
cd03c43c
PP
2214 } else if (bt_value_get_type(value) ==
2215 BT_VALUE_TYPE_STRING) {
2216 write_str_prop_value(ctx,
2217 bt_value_string_get(value));
2218 } else {
2219 abort();
a0bcd369
PP
2220 }
2221
cd03c43c 2222 write_nl(ctx);
a0bcd369 2223 }
cd03c43c
PP
2224
2225 decr_indent(ctx);
a0bcd369
PP
2226 }
2227
2228 for (i = 0; i < bt_trace_get_stream_count(trace); i++) {
2229 g_ptr_array_add(streams,
2230 (gpointer) bt_trace_borrow_stream_by_index_const(
2231 trace, i));
2232 }
2233
2234 g_ptr_array_sort(streams, (GCompareFunc) compare_streams);
2235
2236 if (streams->len > 0 && !printed_prop) {
2237 g_string_append(ctx->str, ":\n");
2238 printed_prop = true;
2239 }
2240
2241 for (i = 0; i < streams->len; i++) {
2242 const bt_stream *stream = streams->pdata[i];
2243
2244 write_indent(ctx);
2245 write_obj_type_name(ctx, "Stream");
2246 g_string_append(ctx->str, " (ID ");
2247 write_uint_prop_value(ctx, bt_stream_get_id(stream));
2248 g_string_append(ctx->str, ", Class ID ");
2249 write_uint_prop_value(ctx, bt_stream_class_get_id(
2250 bt_stream_borrow_class_const(stream)));
2251 g_string_append(ctx->str, ")");
2252 write_nl(ctx);
2253 }
2254
2255 decr_indent(ctx);
2256
2257 if (!printed_prop) {
2258 write_nl(ctx);
2259 }
2260
2261 g_ptr_array_free(streams, TRUE);
cd03c43c 2262 g_ptr_array_free(env_names, TRUE);
a0bcd369
PP
2263}
2264
2265static
2266int write_stream_beginning_message(struct details_write_ctx *ctx,
2267 const bt_message *msg)
2268{
2269 int ret = 0;
2270 const bt_stream *stream =
2271 bt_message_stream_beginning_borrow_stream_const(msg);
2272 const bt_trace *trace = bt_stream_borrow_trace_const(stream);
2273 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
b7cbc799 2274 const bt_clock_class *cc = bt_stream_class_borrow_default_clock_class_const(sc);
a0bcd369
PP
2275 const bt_trace_class *tc = bt_stream_class_borrow_trace_class_const(sc);
2276 const char *name;
2277
2278 ret = try_write_meta(ctx, tc, sc, NULL);
2279 if (ret) {
2280 goto end;
2281 }
2282
08ef09ae
PP
2283 if (!ctx->details_comp->cfg.with_data) {
2284 goto end;
2285 }
2286
2287 if (ctx->str->len > 0) {
2288 /*
2289 * Output buffer contains metadata: separate blocks with
2290 * newline.
2291 */
2292 write_nl(ctx);
2293 }
2294
b7cbc799
SM
2295 /* Write time */
2296 if (cc) {
2297 const bt_clock_snapshot *cs;
2298 bt_message_stream_clock_snapshot_state cs_state =
2299 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg, &cs);
2300
2301 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2302 write_time(ctx, cs);
2303 } else {
2304 write_time_str(ctx, "Unknown");
2305 }
2306 }
2307
a0bcd369
PP
2308 /* Write follow tag for message */
2309 ret = write_message_follow_tag(ctx, stream);
2310 if (ret) {
2311 goto end;
2312 }
2313
2314 /* Write stream properties */
2315 write_obj_type_name(ctx, "Stream beginning");
2316
2317 if (ctx->details_comp->cfg.compact) {
2318 write_nl(ctx);
2319 goto end;
2320 }
2321
2322 g_string_append(ctx->str, ":\n");
2323 incr_indent(ctx);
2324
2325 if (ctx->details_comp->cfg.with_stream_name) {
2326 name = bt_stream_get_name(stream);
2327 if (name) {
2328 write_str_prop_line(ctx, "Name", name);
2329 }
2330 }
2331
2332 if (ctx->details_comp->cfg.with_stream_class_name) {
2333 name = bt_stream_class_get_name(sc);
2334 if (name) {
2335 write_str_prop_line(ctx, "Class name", name);
2336 }
2337 }
2338
2339 write_trace(ctx, trace);
2340 decr_indent(ctx);
2341
2342end:
2343 return ret;
2344}
2345
2346static
2347int write_stream_end_message(struct details_write_ctx *ctx,
2348 const bt_message *msg)
2349{
2350 int ret = 0;
2351 const bt_stream *stream =
2352 bt_message_stream_end_borrow_stream_const(msg);
b7cbc799
SM
2353 const bt_stream_class *sc =
2354 bt_stream_borrow_class_const(stream);
2355 const bt_clock_class *cc =
2356 bt_stream_class_borrow_default_clock_class_const(sc);
a0bcd369 2357
08ef09ae
PP
2358 if (!ctx->details_comp->cfg.with_data) {
2359 goto end;
2360 }
2361
a0bcd369 2362 /* Write time */
b7cbc799
SM
2363 if (cc) {
2364 const bt_clock_snapshot *cs;
2365 bt_message_stream_clock_snapshot_state cs_state =
2366 bt_message_stream_end_borrow_default_clock_snapshot_const(msg, &cs);
a0bcd369 2367
b7cbc799
SM
2368 if (cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
2369 write_time(ctx, cs);
2370 } else {
2371 write_time_str(ctx, "Unknown");
2372 }
a0bcd369
PP
2373 }
2374
2375 /* Write follow tag for message */
2376 ret = write_message_follow_tag(ctx, stream);
2377 if (ret) {
2378 goto end;
2379 }
2380
b7cbc799
SM
2381 /* Write stream properties */
2382 write_obj_type_name(ctx, "Stream end\n");
a0bcd369
PP
2383
2384end:
2385 return ret;
2386}
2387
2388static
2389int write_packet_beginning_message(struct details_write_ctx *ctx,
2390 const bt_message *msg)
2391{
2392 int ret = 0;
2393 const bt_packet *packet =
2394 bt_message_packet_beginning_borrow_packet_const(msg);
2395 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2396 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2397 const bt_field *field;
2398
08ef09ae
PP
2399 if (!ctx->details_comp->cfg.with_data) {
2400 goto end;
2401 }
2402
a0bcd369
PP
2403 /* Write time */
2404 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc)) {
2405 write_time(ctx,
2406 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2407 msg));
2408 }
2409
2410 /* Write follow tag for message */
2411 ret = write_message_follow_tag(ctx, stream);
2412 if (ret) {
2413 goto end;
2414 }
2415
2416 write_obj_type_name(ctx, "Packet beginning");
2417
2418 if (ctx->details_comp->cfg.compact) {
2419 write_nl(ctx);
2420 goto end;
2421 }
2422
2423 /* Write field */
a0bcd369
PP
2424 field = bt_packet_borrow_context_field_const(packet);
2425 if (field) {
b9c58eba
PP
2426 g_string_append(ctx->str, ":\n");
2427 incr_indent(ctx);
a0bcd369 2428 write_root_field(ctx, "Context", field);
b9c58eba
PP
2429 decr_indent(ctx);
2430 } else {
2431 write_nl(ctx);
a0bcd369
PP
2432 }
2433
a0bcd369
PP
2434end:
2435 return ret;
2436}
2437
2438static
2439int write_discarded_items_message(struct details_write_ctx *ctx,
2440 const char *name, const bt_stream *stream,
2441 const bt_clock_snapshot *beginning_cs,
2442 const bt_clock_snapshot *end_cs, uint64_t count)
2443{
2444 int ret = 0;
2445
2446 /* Write times */
2447 if (beginning_cs) {
2448 write_time(ctx, beginning_cs);
2449 BT_ASSERT(end_cs);
2450 write_time(ctx, end_cs);
2451 }
2452
2453 /* Write follow tag for message */
2454 ret = write_message_follow_tag(ctx, stream);
2455 if (ret) {
2456 goto end;
2457 }
2458
2459 write_obj_type_name(ctx, "Discarded ");
2460 write_obj_type_name(ctx, name);
2461
2462 /* Write count */
2463 if (count == UINT64_C(-1)) {
2464 write_nl(ctx);
2465 goto end;
2466 }
2467
2468 g_string_append(ctx->str, " (");
2469 write_uint_prop_value(ctx, count);
2470 g_string_append_printf(ctx->str, " %s)\n", name);
2471
2472end:
2473 return ret;
2474}
2475
2476static
2477int write_discarded_events_message(struct details_write_ctx *ctx,
2478 const bt_message *msg)
2479{
08ef09ae 2480 int ret = 0;
a0bcd369
PP
2481 const bt_stream *stream = bt_message_discarded_events_borrow_stream_const(
2482 msg);
2483 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2484 const bt_clock_snapshot *beginning_cs = NULL;
2485 const bt_clock_snapshot *end_cs = NULL;
2486 uint64_t count;
2487
08ef09ae
PP
2488 if (!ctx->details_comp->cfg.with_data) {
2489 goto end;
2490 }
2491
a0bcd369
PP
2492 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
2493 beginning_cs =
2494 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2495 msg);
2496 end_cs =
2497 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2498 msg);
2499 }
2500
2501 if (bt_message_discarded_events_get_count(msg, &count) !=
2502 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2503 count = UINT64_C(-1);
2504 }
2505
08ef09ae 2506 ret = write_discarded_items_message(ctx, "events", stream,
a0bcd369 2507 beginning_cs, end_cs, count);
08ef09ae
PP
2508
2509end:
2510 return ret;
a0bcd369
PP
2511}
2512
2513static
2514int write_discarded_packets_message(struct details_write_ctx *ctx,
2515 const bt_message *msg)
2516{
08ef09ae 2517 int ret = 0;
a0bcd369
PP
2518 const bt_stream *stream = bt_message_discarded_packets_borrow_stream_const(
2519 msg);
2520 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2521 const bt_clock_snapshot *beginning_cs = NULL;
2522 const bt_clock_snapshot *end_cs = NULL;
2523 uint64_t count;
2524
08ef09ae
PP
2525 if (!ctx->details_comp->cfg.with_data) {
2526 goto end;
2527 }
2528
a0bcd369
PP
2529 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
2530 beginning_cs =
2531 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2532 msg);
2533 end_cs =
2534 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2535 msg);
2536 }
2537
2538 if (bt_message_discarded_packets_get_count(msg, &count) !=
2539 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
2540 count = UINT64_C(-1);
2541 }
2542
08ef09ae 2543 ret = write_discarded_items_message(ctx, "packets", stream,
a0bcd369 2544 beginning_cs, end_cs, count);
08ef09ae
PP
2545
2546end:
2547 return ret;
a0bcd369
PP
2548}
2549
2550static
2551int write_packet_end_message(struct details_write_ctx *ctx,
2552 const bt_message *msg)
2553{
2554 int ret = 0;
2555 const bt_packet *packet =
2556 bt_message_packet_end_borrow_packet_const(msg);
2557 const bt_stream *stream = bt_packet_borrow_stream_const(packet);
2558 const bt_stream_class *sc = bt_stream_borrow_class_const(stream);
2559
08ef09ae
PP
2560 if (!ctx->details_comp->cfg.with_data) {
2561 goto end;
2562 }
2563
a0bcd369
PP
2564 /* Write time */
2565 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc)) {
2566 write_time(ctx,
2567 bt_message_packet_end_borrow_default_clock_snapshot_const(
2568 msg));
2569 }
2570
2571 /* Write follow tag for message */
2572 ret = write_message_follow_tag(ctx, stream);
2573 if (ret) {
2574 goto end;
2575 }
2576
2577 write_obj_type_name(ctx, "Packet end");
2578 write_nl(ctx);
2579
2580end:
2581 return ret;
2582}
2583
2584static
2585int write_message_iterator_inactivity_message(struct details_write_ctx *ctx,
2586 const bt_message *msg)
2587{
2588 int ret = 0;
2589 const bt_clock_snapshot *cs =
2590 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
2591 msg);
2592
2593 /* Write time */
2594 write_time(ctx, cs);
2595 write_obj_type_name(ctx, "Message iterator inactivity");
2596
2597 if (ctx->details_comp->cfg.compact) {
2598 write_nl(ctx);
2599 goto end;
2600 }
2601
2602 /* Write clock class properties */
2603 g_string_append(ctx->str, ":\n");
2604 incr_indent(ctx);
2605 write_indent(ctx);
2606 write_prop_name(ctx, "Clock class");
2607 g_string_append_c(ctx->str, ':');
2608 write_nl(ctx);
2609 incr_indent(ctx);
2610 write_clock_class_prop_lines(ctx,
2611 bt_clock_snapshot_borrow_clock_class_const(cs));
2612 decr_indent(ctx);
2613
2614end:
2615 return ret;
2616}
2617
2618BT_HIDDEN
2619int details_write_message(struct details_comp *details_comp,
2620 const bt_message *msg)
2621{
2622 int ret = 0;
2623 struct details_write_ctx ctx = {
2624 .details_comp = details_comp,
2625 .str = details_comp->str,
2626 .indent_level = 0,
2627 };
2628
2629 /* Reset output buffer */
2630 g_string_assign(details_comp->str, "");
2631
a0bcd369
PP
2632 switch (bt_message_get_type(msg)) {
2633 case BT_MESSAGE_TYPE_EVENT:
2634 ret = write_event_message(&ctx, msg);
2635 break;
2636 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
2637 ret = write_message_iterator_inactivity_message(&ctx, msg);
2638 break;
2639 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
2640 ret = write_stream_beginning_message(&ctx, msg);
2641 break;
2642 case BT_MESSAGE_TYPE_STREAM_END:
2643 ret = write_stream_end_message(&ctx, msg);
2644 break;
2645 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
2646 ret = write_packet_beginning_message(&ctx, msg);
2647 break;
2648 case BT_MESSAGE_TYPE_PACKET_END:
2649 ret = write_packet_end_message(&ctx, msg);
2650 break;
a0bcd369
PP
2651 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
2652 ret = write_discarded_events_message(&ctx, msg);
2653 break;
2654 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
2655 ret = write_discarded_packets_message(&ctx, msg);
2656 break;
2657 default:
2658 abort();
2659 }
2660
08ef09ae
PP
2661 /*
2662 * If this component printed at least one character so far, and
2663 * we're not in compact mode, and there's something in the
2664 * output buffer for this message, then prepend a newline to the
2665 * output buffer to visually separate message blocks.
2666 */
2667 if (details_comp->printed_something && !details_comp->cfg.compact &&
2668 details_comp->str->len > 0) {
2669 /* TODO: Optimize this */
2670 g_string_prepend_c(details_comp->str, '\n');
2671 }
2672
a0bcd369
PP
2673 return ret;
2674}
This page took 0.141271 seconds and 4 git commands to generate.