Reuse previously allocated string when setting value
[babeltrace.git] / formats / ctf / ir / event-fields.c
1 /*
2 * event-fields.c
3 *
4 * Babeltrace CTF Writer
5 *
6 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <babeltrace/ctf-writer/event-fields.h>
30 #include <babeltrace/ctf-ir/event-fields-internal.h>
31 #include <babeltrace/ctf-ir/event-types-internal.h>
32 #include <babeltrace/compiler.h>
33
34 #define PACKET_LEN_INCREMENT (getpagesize() * 8 * CHAR_BIT)
35
36 static
37 struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *);
38 static
39 struct bt_ctf_field *bt_ctf_field_enumeration_create(
40 struct bt_ctf_field_type *);
41 static
42 struct bt_ctf_field *bt_ctf_field_floating_point_create(
43 struct bt_ctf_field_type *);
44 static
45 struct bt_ctf_field *bt_ctf_field_structure_create(
46 struct bt_ctf_field_type *);
47 static
48 struct bt_ctf_field *bt_ctf_field_variant_create(
49 struct bt_ctf_field_type *);
50 static
51 struct bt_ctf_field *bt_ctf_field_array_create(
52 struct bt_ctf_field_type *);
53 static
54 struct bt_ctf_field *bt_ctf_field_sequence_create(
55 struct bt_ctf_field_type *);
56 static
57 struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *);
58
59 static
60 void bt_ctf_field_destroy(struct bt_ctf_ref *);
61 static
62 void bt_ctf_field_integer_destroy(struct bt_ctf_field *);
63 static
64 void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *);
65 static
66 void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *);
67 static
68 void bt_ctf_field_structure_destroy(struct bt_ctf_field *);
69 static
70 void bt_ctf_field_variant_destroy(struct bt_ctf_field *);
71 static
72 void bt_ctf_field_array_destroy(struct bt_ctf_field *);
73 static
74 void bt_ctf_field_sequence_destroy(struct bt_ctf_field *);
75 static
76 void bt_ctf_field_string_destroy(struct bt_ctf_field *);
77
78 static
79 int bt_ctf_field_generic_validate(struct bt_ctf_field *field);
80 static
81 int bt_ctf_field_structure_validate(struct bt_ctf_field *field);
82 static
83 int bt_ctf_field_variant_validate(struct bt_ctf_field *field);
84 static
85 int bt_ctf_field_enumeration_validate(struct bt_ctf_field *field);
86 static
87 int bt_ctf_field_array_validate(struct bt_ctf_field *field);
88 static
89 int bt_ctf_field_sequence_validate(struct bt_ctf_field *field);
90
91 static
92 int bt_ctf_field_integer_serialize(struct bt_ctf_field *,
93 struct ctf_stream_pos *);
94 static
95 int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *,
96 struct ctf_stream_pos *);
97 static
98 int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *,
99 struct ctf_stream_pos *);
100 static
101 int bt_ctf_field_structure_serialize(struct bt_ctf_field *,
102 struct ctf_stream_pos *);
103 static
104 int bt_ctf_field_variant_serialize(struct bt_ctf_field *,
105 struct ctf_stream_pos *);
106 static
107 int bt_ctf_field_array_serialize(struct bt_ctf_field *,
108 struct ctf_stream_pos *);
109 static
110 int bt_ctf_field_sequence_serialize(struct bt_ctf_field *,
111 struct ctf_stream_pos *);
112 static
113 int bt_ctf_field_string_serialize(struct bt_ctf_field *,
114 struct ctf_stream_pos *);
115
116 static
117 int increase_packet_size(struct ctf_stream_pos *pos);
118
119 static
120 struct bt_ctf_field *(*field_create_funcs[])(
121 struct bt_ctf_field_type *) = {
122 [CTF_TYPE_INTEGER] = bt_ctf_field_integer_create,
123 [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_create,
124 [CTF_TYPE_FLOAT] =
125 bt_ctf_field_floating_point_create,
126 [CTF_TYPE_STRUCT] = bt_ctf_field_structure_create,
127 [CTF_TYPE_VARIANT] = bt_ctf_field_variant_create,
128 [CTF_TYPE_ARRAY] = bt_ctf_field_array_create,
129 [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_create,
130 [CTF_TYPE_STRING] = bt_ctf_field_string_create,
131 };
132
133 static
134 void (*field_destroy_funcs[])(struct bt_ctf_field *) = {
135 [CTF_TYPE_INTEGER] = bt_ctf_field_integer_destroy,
136 [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_destroy,
137 [CTF_TYPE_FLOAT] =
138 bt_ctf_field_floating_point_destroy,
139 [CTF_TYPE_STRUCT] = bt_ctf_field_structure_destroy,
140 [CTF_TYPE_VARIANT] = bt_ctf_field_variant_destroy,
141 [CTF_TYPE_ARRAY] = bt_ctf_field_array_destroy,
142 [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_destroy,
143 [CTF_TYPE_STRING] = bt_ctf_field_string_destroy,
144 };
145
146 static
147 int (*field_validate_funcs[])(struct bt_ctf_field *) = {
148 [CTF_TYPE_INTEGER] = bt_ctf_field_generic_validate,
149 [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_validate,
150 [CTF_TYPE_FLOAT] = bt_ctf_field_generic_validate,
151 [CTF_TYPE_STRUCT] = bt_ctf_field_structure_validate,
152 [CTF_TYPE_VARIANT] = bt_ctf_field_variant_validate,
153 [CTF_TYPE_ARRAY] = bt_ctf_field_array_validate,
154 [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_validate,
155 [CTF_TYPE_STRING] = bt_ctf_field_generic_validate,
156 };
157
158 static
159 int (*field_serialize_funcs[])(struct bt_ctf_field *,
160 struct ctf_stream_pos *) = {
161 [CTF_TYPE_INTEGER] = bt_ctf_field_integer_serialize,
162 [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_serialize,
163 [CTF_TYPE_FLOAT] =
164 bt_ctf_field_floating_point_serialize,
165 [CTF_TYPE_STRUCT] = bt_ctf_field_structure_serialize,
166 [CTF_TYPE_VARIANT] = bt_ctf_field_variant_serialize,
167 [CTF_TYPE_ARRAY] = bt_ctf_field_array_serialize,
168 [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_serialize,
169 [CTF_TYPE_STRING] = bt_ctf_field_string_serialize,
170 };
171
172 struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type)
173 {
174 struct bt_ctf_field *field = NULL;
175 enum ctf_type_id type_id;
176
177 if (!type) {
178 goto error;
179 }
180
181 type_id = bt_ctf_field_type_get_type_id(type);
182 if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES ||
183 bt_ctf_field_type_validate(type)) {
184 goto error;
185 }
186
187 field = field_create_funcs[type_id](type);
188 if (!field) {
189 goto error;
190 }
191
192 /* The type's declaration can't change after this point */
193 bt_ctf_field_type_freeze(type);
194 bt_ctf_field_type_get(type);
195 bt_ctf_ref_init(&field->ref_count);
196 field->type = type;
197 error:
198 return field;
199 }
200
201 void bt_ctf_field_get(struct bt_ctf_field *field)
202 {
203 if (field) {
204 bt_ctf_ref_get(&field->ref_count);
205 }
206 }
207
208 void bt_ctf_field_put(struct bt_ctf_field *field)
209 {
210 if (field) {
211 bt_ctf_ref_put(&field->ref_count, bt_ctf_field_destroy);
212 }
213 }
214
215 struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field)
216 {
217 struct bt_ctf_field_type *ret = NULL;
218
219 if (!field) {
220 goto end;
221 }
222
223 ret = field->type;
224 bt_ctf_field_type_get(ret);
225 end:
226 return ret;
227 }
228
229 struct bt_ctf_field *bt_ctf_field_sequence_get_length(
230 struct bt_ctf_field *field)
231 {
232 struct bt_ctf_field *ret = NULL;
233 struct bt_ctf_field_sequence *sequence;
234
235 if (!field) {
236 goto end;
237 }
238
239 if (bt_ctf_field_type_get_type_id(field->type) !=
240 CTF_TYPE_SEQUENCE) {
241 goto end;
242 }
243
244 sequence = container_of(field, struct bt_ctf_field_sequence, parent);
245 ret = sequence->length;
246 bt_ctf_field_get(ret);
247 end:
248 return ret;
249 }
250
251 int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
252 struct bt_ctf_field *length_field)
253 {
254 int ret = 0;
255 struct bt_ctf_field_type_integer *length_type;
256 struct bt_ctf_field_integer *length;
257 struct bt_ctf_field_sequence *sequence;
258 uint64_t sequence_length;
259
260 if (!field || !length_field) {
261 ret = -1;
262 goto end;
263 }
264 if (bt_ctf_field_type_get_type_id(length_field->type) !=
265 CTF_TYPE_INTEGER) {
266 ret = -1;
267 goto end;
268 }
269
270 length_type = container_of(length_field->type,
271 struct bt_ctf_field_type_integer, parent);
272 /* The length field must be unsigned */
273 if (length_type->declaration.signedness) {
274 ret = -1;
275 goto end;
276 }
277
278 length = container_of(length_field, struct bt_ctf_field_integer,
279 parent);
280 sequence_length = length->definition.value._unsigned;
281 sequence = container_of(field, struct bt_ctf_field_sequence, parent);
282 if (sequence->elements) {
283 g_ptr_array_free(sequence->elements, TRUE);
284 bt_ctf_field_put(sequence->length);
285 }
286
287 sequence->elements = g_ptr_array_sized_new((size_t)sequence_length);
288 if (!sequence->elements) {
289 ret = -1;
290 goto end;
291 }
292
293 g_ptr_array_set_free_func(sequence->elements,
294 (GDestroyNotify)bt_ctf_field_put);
295 g_ptr_array_set_size(sequence->elements, (size_t)sequence_length);
296 bt_ctf_field_get(length_field);
297 sequence->length = length_field;
298 end:
299 return ret;
300 }
301
302 struct bt_ctf_field *bt_ctf_field_structure_get_field(
303 struct bt_ctf_field *field, const char *name)
304 {
305 struct bt_ctf_field *new_field = NULL;
306 GQuark field_quark;
307 struct bt_ctf_field_structure *structure;
308 struct bt_ctf_field_type *field_type = NULL;
309 size_t index;
310
311 if (!field || !name ||
312 bt_ctf_field_type_get_type_id(field->type) !=
313 CTF_TYPE_STRUCT) {
314 goto error;
315 }
316
317 field_quark = g_quark_from_string(name);
318 structure = container_of(field, struct bt_ctf_field_structure, parent);
319 field_type =
320 bt_ctf_field_type_structure_get_field_type_by_name(field->type,
321 name);
322 if (!g_hash_table_lookup_extended(structure->field_name_to_index,
323 GUINT_TO_POINTER(field_quark), NULL, (gpointer *)&index)) {
324 goto error;
325 }
326
327 if (structure->fields->pdata[index]) {
328 new_field = structure->fields->pdata[index];
329 goto end;
330 }
331
332 new_field = bt_ctf_field_create(field_type);
333 if (!new_field) {
334 goto error;
335 }
336
337 structure->fields->pdata[index] = new_field;
338 end:
339 bt_ctf_field_get(new_field);
340 error:
341 if (field_type) {
342 bt_ctf_field_type_put(field_type);
343 }
344 return new_field;
345 }
346
347 struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
348 struct bt_ctf_field *field, size_t index)
349 {
350 int ret;
351 const char *field_name;
352 struct bt_ctf_field_structure *structure;
353 struct bt_ctf_field_type *structure_type;
354 struct bt_ctf_field_type *field_type = NULL;
355 struct bt_ctf_field *ret_field = NULL;
356
357 if (!field ||
358 bt_ctf_field_type_get_type_id(field->type) != CTF_TYPE_STRUCT) {
359 goto end;
360 }
361
362 structure = container_of(field, struct bt_ctf_field_structure, parent);
363 if (index >= structure->fields->len) {
364 goto error;
365 }
366
367 ret_field = structure->fields->pdata[index];
368 if (ret_field) {
369 goto end;
370 }
371
372 /* Field has not been instanciated yet, create it */
373 structure_type = bt_ctf_field_get_type(field);
374 if (!structure_type) {
375 goto error;
376 }
377
378 ret = bt_ctf_field_type_structure_get_field(structure_type,
379 &field_name, &field_type, index);
380 bt_ctf_field_type_put(structure_type);
381 if (ret) {
382 goto error;
383 }
384
385 ret_field = bt_ctf_field_create(field_type);
386 if (!ret_field) {
387 goto error;
388 }
389
390 structure->fields->pdata[index] = ret_field;
391 end:
392 bt_ctf_field_get(ret_field);
393 error:
394 if (field_type) {
395 bt_ctf_field_type_put(field_type);
396 }
397 return ret_field;
398 }
399
400 BT_HIDDEN
401 int bt_ctf_field_structure_set_field(struct bt_ctf_field *field,
402 const char *name, struct bt_ctf_field *value)
403 {
404 int ret = 0;
405 GQuark field_quark;
406 struct bt_ctf_field_structure *structure;
407 struct bt_ctf_field_type *expected_field_type = NULL;
408 size_t index;
409
410 if (!field || !name || !value ||
411 bt_ctf_field_type_get_type_id(field->type) !=
412 CTF_TYPE_STRUCT) {
413 ret = -1;
414 goto end;
415 }
416
417 field_quark = g_quark_from_string(name);
418 structure = container_of(field, struct bt_ctf_field_structure, parent);
419 expected_field_type =
420 bt_ctf_field_type_structure_get_field_type_by_name(field->type,
421 name);
422 if (expected_field_type != value->type) {
423 ret = -1;
424 goto end;
425 }
426
427 if (!g_hash_table_lookup_extended(structure->field_name_to_index,
428 GUINT_TO_POINTER(field_quark), NULL, (gpointer *) &index)) {
429 goto end;
430 }
431
432 if (structure->fields->pdata[index]) {
433 bt_ctf_field_put(structure->fields->pdata[index]);
434 }
435
436 structure->fields->pdata[index] = value;
437 bt_ctf_field_get(value);
438 end:
439 if (expected_field_type) {
440 bt_ctf_field_type_put(expected_field_type);
441 }
442 return ret;
443 }
444
445 struct bt_ctf_field *bt_ctf_field_array_get_field(struct bt_ctf_field *field,
446 uint64_t index)
447 {
448 struct bt_ctf_field *new_field = NULL;
449 struct bt_ctf_field_type *field_type = NULL;
450 struct bt_ctf_field_array *array;
451
452 if (!field || bt_ctf_field_type_get_type_id(field->type) !=
453 CTF_TYPE_ARRAY) {
454 goto end;
455 }
456
457 array = container_of(field, struct bt_ctf_field_array, parent);
458 if (index >= array->elements->len) {
459 goto end;
460 }
461
462 field_type = bt_ctf_field_type_array_get_element_type(field->type);
463 if (array->elements->pdata[(size_t)index]) {
464 new_field = array->elements->pdata[(size_t)index];
465 goto end;
466 }
467
468 new_field = bt_ctf_field_create(field_type);
469 bt_ctf_field_get(new_field);
470 array->elements->pdata[(size_t)index] = new_field;
471 end:
472 if (field_type) {
473 bt_ctf_field_type_put(field_type);
474 }
475 return new_field;
476 }
477
478 struct bt_ctf_field *bt_ctf_field_sequence_get_field(struct bt_ctf_field *field,
479 uint64_t index)
480 {
481 struct bt_ctf_field *new_field = NULL;
482 struct bt_ctf_field_type *field_type = NULL;
483 struct bt_ctf_field_sequence *sequence;
484
485 if (!field || bt_ctf_field_type_get_type_id(field->type) !=
486 CTF_TYPE_SEQUENCE) {
487 goto end;
488 }
489
490 sequence = container_of(field, struct bt_ctf_field_sequence, parent);
491 if (!sequence->elements || sequence->elements->len <= index) {
492 goto end;
493 }
494
495 field_type = bt_ctf_field_type_sequence_get_element_type(field->type);
496 if (sequence->elements->pdata[(size_t)index]) {
497 new_field = sequence->elements->pdata[(size_t)index];
498 goto end;
499 }
500
501 new_field = bt_ctf_field_create(field_type);
502 bt_ctf_field_get(new_field);
503 sequence->elements->pdata[(size_t)index] = new_field;
504 end:
505 if (field_type) {
506 bt_ctf_field_type_put(field_type);
507 }
508 return new_field;
509 }
510
511 struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
512 struct bt_ctf_field *tag_field)
513 {
514 struct bt_ctf_field *new_field = NULL;
515 struct bt_ctf_field_variant *variant;
516 struct bt_ctf_field_type_variant *variant_type;
517 struct bt_ctf_field_type *field_type;
518 struct bt_ctf_field *tag_enum = NULL;
519 struct bt_ctf_field_integer *tag_enum_integer;
520 int64_t tag_enum_value;
521
522 if (!field || !tag_field ||
523 bt_ctf_field_type_get_type_id(field->type) !=
524 CTF_TYPE_VARIANT ||
525 bt_ctf_field_type_get_type_id(tag_field->type) !=
526 CTF_TYPE_ENUM) {
527 goto end;
528 }
529
530 variant = container_of(field, struct bt_ctf_field_variant, parent);
531 variant_type = container_of(field->type,
532 struct bt_ctf_field_type_variant, parent);
533 tag_enum = bt_ctf_field_enumeration_get_container(tag_field);
534 if (!tag_enum) {
535 goto end;
536 }
537
538 tag_enum_integer = container_of(tag_enum, struct bt_ctf_field_integer,
539 parent);
540
541 if (!bt_ctf_field_validate(variant->tag)) {
542 goto end;
543 }
544
545 tag_enum_value = tag_enum_integer->definition.value._signed;
546 field_type = bt_ctf_field_type_variant_get_field_type_signed(
547 variant_type, tag_enum_value);
548 if (!field_type) {
549 goto end;
550 }
551
552 new_field = bt_ctf_field_create(field_type);
553 if (!new_field) {
554 goto end;
555 }
556
557 bt_ctf_field_put(variant->tag);
558 bt_ctf_field_put(variant->payload);
559 bt_ctf_field_get(new_field);
560 bt_ctf_field_get(tag_field);
561 variant->tag = tag_field;
562 variant->payload = new_field;
563 end:
564 bt_ctf_field_put(tag_enum);
565 return new_field;
566 }
567
568 struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
569 struct bt_ctf_field *field)
570 {
571 struct bt_ctf_field *container = NULL;
572 struct bt_ctf_field_enumeration *enumeration;
573
574 if (!field || bt_ctf_field_type_get_type_id(field->type) !=
575 CTF_TYPE_ENUM) {
576 goto end;
577 }
578
579 enumeration = container_of(field, struct bt_ctf_field_enumeration,
580 parent);
581 if (!enumeration->payload) {
582 struct bt_ctf_field_type_enumeration *enumeration_type =
583 container_of(field->type,
584 struct bt_ctf_field_type_enumeration, parent);
585 enumeration->payload =
586 bt_ctf_field_create(enumeration_type->container);
587 }
588
589 container = enumeration->payload;
590 bt_ctf_field_get(container);
591 end:
592 return container;
593 }
594
595 const char *bt_ctf_field_enumeration_get_mapping_name(
596 struct bt_ctf_field *field)
597 {
598 int ret;
599 const char *name = NULL;
600 struct bt_ctf_field *container = NULL;
601 struct bt_ctf_field_type *container_type = NULL;
602 struct bt_ctf_field_type_integer *integer_type = NULL;
603 struct bt_ctf_field_type_enumeration *enumeration_type = NULL;
604
605 container = bt_ctf_field_enumeration_get_container(field);
606 if (!container) {
607 goto end;
608 }
609
610 container_type = bt_ctf_field_get_type(container);
611 if (!container_type) {
612 goto error_put_container;
613 }
614
615 integer_type = container_of(container_type,
616 struct bt_ctf_field_type_integer, parent);
617 enumeration_type = container_of(field->type,
618 struct bt_ctf_field_type_enumeration, parent);
619
620 if (!integer_type->declaration.signedness) {
621 uint64_t value;
622 ret = bt_ctf_field_unsigned_integer_get_value(container,
623 &value);
624 if (ret) {
625 goto error_put_container_type;
626 }
627
628 name = bt_ctf_field_type_enumeration_get_mapping_name_unsigned(
629 enumeration_type, value);
630 } else {
631 int64_t value;
632 ret = bt_ctf_field_signed_integer_get_value(container,
633 &value);
634 if (ret) {
635 goto error_put_container_type;
636 }
637
638 name = bt_ctf_field_type_enumeration_get_mapping_name_signed(
639 enumeration_type, value);
640 }
641
642 error_put_container_type:
643 bt_ctf_field_type_put(container_type);
644 error_put_container:
645 bt_ctf_field_put(container);
646 end:
647 return name;
648 }
649
650 int bt_ctf_field_signed_integer_get_value(struct bt_ctf_field *field,
651 int64_t *value)
652 {
653 int ret = 0;
654 struct bt_ctf_field_integer *integer;
655 struct bt_ctf_field_type_integer *integer_type;
656
657 if (!field || !value || !field->payload_set ||
658 bt_ctf_field_type_get_type_id(field->type) !=
659 CTF_TYPE_INTEGER) {
660 ret = -1;
661 goto end;
662 }
663
664 integer_type = container_of(field->type,
665 struct bt_ctf_field_type_integer, parent);
666 if (!integer_type->declaration.signedness) {
667 ret = -1;
668 goto end;
669 }
670
671 integer = container_of(field,
672 struct bt_ctf_field_integer, parent);
673 *value = integer->definition.value._signed;
674 end:
675 return ret;
676 }
677
678 int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *field,
679 int64_t value)
680 {
681 int ret = 0;
682 struct bt_ctf_field_integer *integer;
683 struct bt_ctf_field_type_integer *integer_type;
684 unsigned int size;
685 int64_t min_value, max_value;
686
687 if (!field ||
688 bt_ctf_field_type_get_type_id(field->type) !=
689 CTF_TYPE_INTEGER) {
690 ret = -1;
691 goto end;
692 }
693
694 integer = container_of(field, struct bt_ctf_field_integer, parent);
695 integer_type = container_of(field->type,
696 struct bt_ctf_field_type_integer, parent);
697 if (!integer_type->declaration.signedness) {
698 ret = -1;
699 goto end;
700 }
701
702 size = integer_type->declaration.len;
703 min_value = -((int64_t)1 << (size - 1));
704 max_value = ((int64_t)1 << (size - 1)) - 1;
705 if (value < min_value || value > max_value) {
706 ret = -1;
707 goto end;
708 }
709
710 integer->definition.value._signed = value;
711 integer->parent.payload_set = 1;
712 end:
713 return ret;
714 }
715
716 int bt_ctf_field_unsigned_integer_get_value(struct bt_ctf_field *field,
717 uint64_t *value)
718 {
719 int ret = 0;
720 struct bt_ctf_field_integer *integer;
721 struct bt_ctf_field_type_integer *integer_type;
722
723 if (!field || !value || !field->payload_set ||
724 bt_ctf_field_type_get_type_id(field->type) !=
725 CTF_TYPE_INTEGER) {
726 ret = -1;
727 goto end;
728 }
729
730 integer_type = container_of(field->type,
731 struct bt_ctf_field_type_integer, parent);
732 if (integer_type->declaration.signedness) {
733 ret = -1;
734 goto end;
735 }
736
737 integer = container_of(field,
738 struct bt_ctf_field_integer, parent);
739 *value = integer->definition.value._unsigned;
740 end:
741 return ret;
742 }
743
744 int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *field,
745 uint64_t value)
746 {
747 int ret = 0;
748 struct bt_ctf_field_integer *integer;
749 struct bt_ctf_field_type_integer *integer_type;
750 unsigned int size;
751 uint64_t max_value;
752
753 if (!field ||
754 bt_ctf_field_type_get_type_id(field->type) !=
755 CTF_TYPE_INTEGER) {
756 ret = -1;
757 goto end;
758 }
759
760 integer = container_of(field, struct bt_ctf_field_integer, parent);
761 integer_type = container_of(field->type,
762 struct bt_ctf_field_type_integer, parent);
763 if (integer_type->declaration.signedness) {
764 ret = -1;
765 goto end;
766 }
767
768 size = integer_type->declaration.len;
769 max_value = (size == 64) ? UINT64_MAX : ((uint64_t)1 << size) - 1;
770 if (value > max_value) {
771 ret = -1;
772 goto end;
773 }
774
775 integer->definition.value._unsigned = value;
776 integer->parent.payload_set = 1;
777 end:
778 return ret;
779 }
780
781 int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
782 double *value)
783 {
784 int ret = 0;
785 struct bt_ctf_field_floating_point *floating_point;
786
787 if (!field || !value || !field->payload_set ||
788 bt_ctf_field_type_get_type_id(field->type) !=
789 CTF_TYPE_FLOAT) {
790 ret = -1;
791 goto end;
792 }
793
794 floating_point = container_of(field,
795 struct bt_ctf_field_floating_point, parent);
796 *value = floating_point->definition.value;
797 end:
798 return ret;
799 }
800
801 int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field,
802 double value)
803 {
804 int ret = 0;
805 struct bt_ctf_field_floating_point *floating_point;
806
807 if (!field ||
808 bt_ctf_field_type_get_type_id(field->type) !=
809 CTF_TYPE_FLOAT) {
810 ret = -1;
811 goto end;
812 }
813 floating_point = container_of(field, struct bt_ctf_field_floating_point,
814 parent);
815 floating_point->definition.value = value;
816 floating_point->parent.payload_set = 1;
817 end:
818 return ret;
819 }
820
821 const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field)
822 {
823 const char *ret = NULL;
824 struct bt_ctf_field_string *string;
825
826 if (!field || !field->payload_set ||
827 bt_ctf_field_type_get_type_id(field->type) !=
828 CTF_TYPE_STRING) {
829 goto end;
830 }
831
832 string = container_of(field,
833 struct bt_ctf_field_string, parent);
834 ret = string->payload->str;
835 end:
836 return ret;
837 }
838
839 int bt_ctf_field_string_set_value(struct bt_ctf_field *field,
840 const char *value)
841 {
842 int ret = 0;
843 struct bt_ctf_field_string *string;
844
845 if (!field || !value ||
846 bt_ctf_field_type_get_type_id(field->type) !=
847 CTF_TYPE_STRING) {
848 ret = -1;
849 goto end;
850 }
851
852 string = container_of(field, struct bt_ctf_field_string, parent);
853 if (string->payload) {
854 g_string_assign(string->payload, value);
855 } else {
856 string->payload = g_string_new(value);
857 }
858
859 string->parent.payload_set = 1;
860 end:
861 return ret;
862 }
863
864 BT_HIDDEN
865 int bt_ctf_field_validate(struct bt_ctf_field *field)
866 {
867 int ret = 0;
868 enum ctf_type_id type_id;
869
870 if (!field) {
871 ret = -1;
872 goto end;
873 }
874
875 type_id = bt_ctf_field_type_get_type_id(field->type);
876 if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) {
877 ret = -1;
878 goto end;
879 }
880
881 ret = field_validate_funcs[type_id](field);
882 end:
883 return ret;
884 }
885
886 BT_HIDDEN
887 int bt_ctf_field_serialize(struct bt_ctf_field *field,
888 struct ctf_stream_pos *pos)
889 {
890 int ret = 0;
891 enum ctf_type_id type_id;
892
893 if (!field || !pos) {
894 ret = -1;
895 goto end;
896 }
897
898 type_id = bt_ctf_field_type_get_type_id(field->type);
899 if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) {
900 ret = -1;
901 goto end;
902 }
903
904 ret = field_serialize_funcs[type_id](field, pos);
905 end:
906 return ret;
907 }
908
909 static
910 struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
911 {
912 struct bt_ctf_field_type_integer *integer_type = container_of(type,
913 struct bt_ctf_field_type_integer, parent);
914 struct bt_ctf_field_integer *integer = g_new0(
915 struct bt_ctf_field_integer, 1);
916
917 if (integer) {
918 integer->definition.declaration = &integer_type->declaration;
919 }
920
921 return integer ? &integer->parent : NULL;
922 }
923
924 static
925 struct bt_ctf_field *bt_ctf_field_enumeration_create(
926 struct bt_ctf_field_type *type)
927 {
928 struct bt_ctf_field_enumeration *enumeration = g_new0(
929 struct bt_ctf_field_enumeration, 1);
930
931 return enumeration ? &enumeration->parent : NULL;
932 }
933
934 static
935 struct bt_ctf_field *bt_ctf_field_floating_point_create(
936 struct bt_ctf_field_type *type)
937 {
938 struct bt_ctf_field_floating_point *floating_point;
939 struct bt_ctf_field_type_floating_point *floating_point_type;
940
941 floating_point = g_new0(struct bt_ctf_field_floating_point, 1);
942 if (!floating_point) {
943 goto end;
944 }
945
946 floating_point_type = container_of(type,
947 struct bt_ctf_field_type_floating_point, parent);
948 floating_point->definition.declaration = container_of(
949 type->declaration, struct declaration_float, p);
950
951
952 floating_point->definition.sign = &floating_point->sign;
953 floating_point->sign.declaration = &floating_point_type->sign;
954 floating_point->definition.sign->p.declaration =
955 &floating_point_type->sign.p;
956
957 floating_point->definition.mantissa = &floating_point->mantissa;
958 floating_point->mantissa.declaration = &floating_point_type->mantissa;
959 floating_point->definition.mantissa->p.declaration =
960 &floating_point_type->mantissa.p;
961
962 floating_point->definition.exp = &floating_point->exp;
963 floating_point->exp.declaration = &floating_point_type->exp;
964 floating_point->definition.exp->p.declaration =
965 &floating_point_type->exp.p;
966
967 end:
968 return floating_point ? &floating_point->parent : NULL;
969 }
970
971 static
972 struct bt_ctf_field *bt_ctf_field_structure_create(
973 struct bt_ctf_field_type *type)
974 {
975 struct bt_ctf_field_type_structure *structure_type = container_of(type,
976 struct bt_ctf_field_type_structure, parent);
977 struct bt_ctf_field_structure *structure = g_new0(
978 struct bt_ctf_field_structure, 1);
979 struct bt_ctf_field *field = NULL;
980
981 if (!structure || !structure_type->fields->len) {
982 goto end;
983 }
984
985 structure->field_name_to_index = structure_type->field_name_to_index;
986 structure->fields = g_ptr_array_new_with_free_func(
987 (GDestroyNotify)bt_ctf_field_put);
988 g_ptr_array_set_size(structure->fields,
989 g_hash_table_size(structure->field_name_to_index));
990 field = &structure->parent;
991 end:
992 return field;
993 }
994
995 static
996 struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
997 {
998 struct bt_ctf_field_variant *variant = g_new0(
999 struct bt_ctf_field_variant, 1);
1000 return variant ? &variant->parent : NULL;
1001 }
1002
1003 static
1004 struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
1005 {
1006 struct bt_ctf_field_array *array = g_new0(struct bt_ctf_field_array, 1);
1007 struct bt_ctf_field_type_array *array_type;
1008 unsigned int array_length;
1009
1010 if (!array || !type) {
1011 goto error;
1012 }
1013
1014 array_type = container_of(type, struct bt_ctf_field_type_array, parent);
1015 array_length = array_type->length;
1016 array->elements = g_ptr_array_sized_new(array_length);
1017 if (!array->elements) {
1018 goto error;
1019 }
1020
1021 g_ptr_array_set_free_func(array->elements,
1022 (GDestroyNotify)bt_ctf_field_put);
1023 g_ptr_array_set_size(array->elements, array_length);
1024 return &array->parent;
1025 error:
1026 g_free(array);
1027 return NULL;
1028 }
1029
1030 static
1031 struct bt_ctf_field *bt_ctf_field_sequence_create(
1032 struct bt_ctf_field_type *type)
1033 {
1034 struct bt_ctf_field_sequence *sequence = g_new0(
1035 struct bt_ctf_field_sequence, 1);
1036 return sequence ? &sequence->parent : NULL;
1037 }
1038
1039 static
1040 struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
1041 {
1042 struct bt_ctf_field_string *string = g_new0(
1043 struct bt_ctf_field_string, 1);
1044 return string ? &string->parent : NULL;
1045 }
1046
1047 static
1048 void bt_ctf_field_destroy(struct bt_ctf_ref *ref)
1049 {
1050 struct bt_ctf_field *field;
1051 struct bt_ctf_field_type *type;
1052 enum ctf_type_id type_id;
1053
1054 if (!ref) {
1055 return;
1056 }
1057
1058 field = container_of(ref, struct bt_ctf_field, ref_count);
1059 type = field->type;
1060 type_id = bt_ctf_field_type_get_type_id(type);
1061 if (type_id <= CTF_TYPE_UNKNOWN ||
1062 type_id >= NR_CTF_TYPES) {
1063 return;
1064 }
1065
1066 field_destroy_funcs[type_id](field);
1067 if (type) {
1068 bt_ctf_field_type_put(type);
1069 }
1070 }
1071
1072 static
1073 void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
1074 {
1075 struct bt_ctf_field_integer *integer;
1076
1077 if (!field) {
1078 return;
1079 }
1080
1081 integer = container_of(field, struct bt_ctf_field_integer, parent);
1082 g_free(integer);
1083 }
1084
1085 static
1086 void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *field)
1087 {
1088 struct bt_ctf_field_enumeration *enumeration;
1089
1090 if (!field) {
1091 return;
1092 }
1093
1094 enumeration = container_of(field, struct bt_ctf_field_enumeration,
1095 parent);
1096 bt_ctf_field_put(enumeration->payload);
1097 g_free(enumeration);
1098 }
1099
1100 static
1101 void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
1102 {
1103 struct bt_ctf_field_floating_point *floating_point;
1104
1105 if (!field) {
1106 return;
1107 }
1108
1109 floating_point = container_of(field, struct bt_ctf_field_floating_point,
1110 parent);
1111 g_free(floating_point);
1112 }
1113
1114 static
1115 void bt_ctf_field_structure_destroy(struct bt_ctf_field *field)
1116 {
1117 struct bt_ctf_field_structure *structure;
1118
1119 if (!field) {
1120 return;
1121 }
1122
1123 structure = container_of(field, struct bt_ctf_field_structure, parent);
1124 g_ptr_array_free(structure->fields, TRUE);
1125 g_free(structure);
1126 }
1127
1128 static
1129 void bt_ctf_field_variant_destroy(struct bt_ctf_field *field)
1130 {
1131 struct bt_ctf_field_variant *variant;
1132
1133 if (!field) {
1134 return;
1135 }
1136
1137 variant = container_of(field, struct bt_ctf_field_variant, parent);
1138 bt_ctf_field_put(variant->tag);
1139 bt_ctf_field_put(variant->payload);
1140 g_free(variant);
1141 }
1142
1143 static
1144 void bt_ctf_field_array_destroy(struct bt_ctf_field *field)
1145 {
1146 struct bt_ctf_field_array *array;
1147
1148 if (!field) {
1149 return;
1150 }
1151
1152 array = container_of(field, struct bt_ctf_field_array, parent);
1153 g_ptr_array_free(array->elements, TRUE);
1154 g_free(array);
1155 }
1156
1157 static
1158 void bt_ctf_field_sequence_destroy(struct bt_ctf_field *field)
1159 {
1160 struct bt_ctf_field_sequence *sequence;
1161
1162 if (!field) {
1163 return;
1164 }
1165
1166 sequence = container_of(field, struct bt_ctf_field_sequence, parent);
1167 g_ptr_array_free(sequence->elements, TRUE);
1168 bt_ctf_field_put(sequence->length);
1169 g_free(sequence);
1170 }
1171
1172 static
1173 void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
1174 {
1175 struct bt_ctf_field_string *string;
1176 if (!field) {
1177 return;
1178 }
1179
1180 string = container_of(field, struct bt_ctf_field_string, parent);
1181 g_string_free(string->payload, TRUE);
1182 g_free(string);
1183 }
1184
1185 static
1186 int bt_ctf_field_generic_validate(struct bt_ctf_field *field)
1187 {
1188 return (field && field->payload_set) ? 0 : -1;
1189 }
1190
1191 static
1192 int bt_ctf_field_enumeration_validate(struct bt_ctf_field *field)
1193 {
1194 int ret;
1195 struct bt_ctf_field_enumeration *enumeration;
1196
1197 if (!field) {
1198 ret = -1;
1199 goto end;
1200 }
1201
1202 enumeration = container_of(field, struct bt_ctf_field_enumeration,
1203 parent);
1204 if (!enumeration->payload) {
1205 ret = -1;
1206 goto end;
1207 }
1208
1209 ret = bt_ctf_field_validate(enumeration->payload);
1210 end:
1211 return ret;
1212 }
1213
1214 static
1215 int bt_ctf_field_structure_validate(struct bt_ctf_field *field)
1216 {
1217 size_t i;
1218 int ret = 0;
1219 struct bt_ctf_field_structure *structure;
1220
1221 if (!field) {
1222 ret = -1;
1223 goto end;
1224 }
1225
1226 structure = container_of(field, struct bt_ctf_field_structure, parent);
1227 for (i = 0; i < structure->fields->len; i++) {
1228 ret = bt_ctf_field_validate(structure->fields->pdata[i]);
1229 if (ret) {
1230 goto end;
1231 }
1232 }
1233 end:
1234 return ret;
1235 }
1236
1237 static
1238 int bt_ctf_field_variant_validate(struct bt_ctf_field *field)
1239 {
1240 int ret = 0;
1241 struct bt_ctf_field_variant *variant;
1242
1243 if (!field) {
1244 ret = -1;
1245 goto end;
1246 }
1247
1248 variant = container_of(field, struct bt_ctf_field_variant, parent);
1249 ret = bt_ctf_field_validate(variant->payload);
1250 end:
1251 return ret;
1252 }
1253
1254 static
1255 int bt_ctf_field_array_validate(struct bt_ctf_field *field)
1256 {
1257 size_t i;
1258 int ret = 0;
1259 struct bt_ctf_field_array *array;
1260
1261 if (!field) {
1262 ret = -1;
1263 goto end;
1264 }
1265
1266 array = container_of(field, struct bt_ctf_field_array, parent);
1267 for (i = 0; i < array->elements->len; i++) {
1268 ret = bt_ctf_field_validate(array->elements->pdata[i]);
1269 if (ret) {
1270 goto end;
1271 }
1272 }
1273 end:
1274 return ret;
1275 }
1276
1277 static
1278 int bt_ctf_field_sequence_validate(struct bt_ctf_field *field)
1279 {
1280 size_t i;
1281 int ret = 0;
1282 struct bt_ctf_field_sequence *sequence;
1283
1284 if (!field) {
1285 ret = -1;
1286 goto end;
1287 }
1288
1289 sequence = container_of(field, struct bt_ctf_field_sequence, parent);
1290 for (i = 0; i < sequence->elements->len; i++) {
1291 ret = bt_ctf_field_validate(sequence->elements->pdata[i]);
1292 if (ret) {
1293 goto end;
1294 }
1295 }
1296 end:
1297 return ret;
1298 }
1299
1300 static
1301 int bt_ctf_field_integer_serialize(struct bt_ctf_field *field,
1302 struct ctf_stream_pos *pos)
1303 {
1304 int ret = 0;
1305 struct bt_ctf_field_integer *integer = container_of(field,
1306 struct bt_ctf_field_integer, parent);
1307
1308 retry:
1309 ret = ctf_integer_write(&pos->parent, &integer->definition.p);
1310 if (ret == -EFAULT) {
1311 /*
1312 * The field is too large to fit in the current packet's
1313 * remaining space. Bump the packet size and retry.
1314 */
1315 ret = increase_packet_size(pos);
1316 if (ret) {
1317 goto end;
1318 }
1319 goto retry;
1320 }
1321 end:
1322 return ret;
1323 }
1324
1325 static
1326 int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *field,
1327 struct ctf_stream_pos *pos)
1328 {
1329 struct bt_ctf_field_enumeration *enumeration = container_of(
1330 field, struct bt_ctf_field_enumeration, parent);
1331
1332 return bt_ctf_field_serialize(enumeration->payload, pos);
1333 }
1334
1335 static
1336 int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *field,
1337 struct ctf_stream_pos *pos)
1338 {
1339 int ret = 0;
1340 struct bt_ctf_field_floating_point *floating_point = container_of(field,
1341 struct bt_ctf_field_floating_point, parent);
1342
1343 retry:
1344 ret = ctf_float_write(&pos->parent, &floating_point->definition.p);
1345 if (ret == -EFAULT) {
1346 /*
1347 * The field is too large to fit in the current packet's
1348 * remaining space. Bump the packet size and retry.
1349 */
1350 ret = increase_packet_size(pos);
1351 if (ret) {
1352 goto end;
1353 }
1354 goto retry;
1355 }
1356 end:
1357 return ret;
1358 }
1359
1360 static
1361 int bt_ctf_field_structure_serialize(struct bt_ctf_field *field,
1362 struct ctf_stream_pos *pos)
1363 {
1364 size_t i;
1365 int ret = 0;
1366 struct bt_ctf_field_structure *structure = container_of(
1367 field, struct bt_ctf_field_structure, parent);
1368
1369 while (!ctf_pos_access_ok(pos,
1370 offset_align(pos->offset,
1371 field->type->declaration->alignment))) {
1372 ret = increase_packet_size(pos);
1373 if (ret) {
1374 goto end;
1375 }
1376 }
1377
1378 if (!ctf_align_pos(pos, field->type->declaration->alignment)) {
1379 ret = -1;
1380 goto end;
1381 }
1382
1383 for (i = 0; i < structure->fields->len; i++) {
1384 struct bt_ctf_field *field = g_ptr_array_index(
1385 structure->fields, i);
1386
1387 ret = bt_ctf_field_serialize(field, pos);
1388 if (ret) {
1389 break;
1390 }
1391 }
1392 end:
1393 return ret;
1394 }
1395
1396 static
1397 int bt_ctf_field_variant_serialize(struct bt_ctf_field *field,
1398 struct ctf_stream_pos *pos)
1399 {
1400 struct bt_ctf_field_variant *variant = container_of(
1401 field, struct bt_ctf_field_variant, parent);
1402
1403 return bt_ctf_field_serialize(variant->payload, pos);
1404 }
1405
1406 static
1407 int bt_ctf_field_array_serialize(struct bt_ctf_field *field,
1408 struct ctf_stream_pos *pos)
1409 {
1410 size_t i;
1411 int ret = 0;
1412 struct bt_ctf_field_array *array = container_of(
1413 field, struct bt_ctf_field_array, parent);
1414
1415 for (i = 0; i < array->elements->len; i++) {
1416 ret = bt_ctf_field_serialize(
1417 g_ptr_array_index(array->elements, i), pos);
1418 if (ret) {
1419 goto end;
1420 }
1421 }
1422 end:
1423 return ret;
1424 }
1425
1426 static
1427 int bt_ctf_field_sequence_serialize(struct bt_ctf_field *field,
1428 struct ctf_stream_pos *pos)
1429 {
1430 size_t i;
1431 int ret = 0;
1432 struct bt_ctf_field_sequence *sequence = container_of(
1433 field, struct bt_ctf_field_sequence, parent);
1434
1435 for (i = 0; i < sequence->elements->len; i++) {
1436 ret = bt_ctf_field_serialize(
1437 g_ptr_array_index(sequence->elements, i), pos);
1438 if (ret) {
1439 goto end;
1440 }
1441 }
1442 end:
1443 return ret;
1444 }
1445
1446 static
1447 int bt_ctf_field_string_serialize(struct bt_ctf_field *field,
1448 struct ctf_stream_pos *pos)
1449 {
1450 size_t i;
1451 int ret = 0;
1452 struct bt_ctf_field_string *string = container_of(field,
1453 struct bt_ctf_field_string, parent);
1454 struct bt_ctf_field_type *character_type =
1455 get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
1456 struct bt_ctf_field *character = bt_ctf_field_create(character_type);
1457
1458 for (i = 0; i < string->payload->len + 1; i++) {
1459 ret = bt_ctf_field_unsigned_integer_set_value(character,
1460 (uint64_t) string->payload->str[i]);
1461 if (ret) {
1462 goto end;
1463 }
1464
1465 ret = bt_ctf_field_integer_serialize(character, pos);
1466 if (ret) {
1467 goto end;
1468 }
1469 }
1470 end:
1471 bt_ctf_field_put(character);
1472 bt_ctf_field_type_put(character_type);
1473 return ret;
1474 }
1475
1476 static
1477 int increase_packet_size(struct ctf_stream_pos *pos)
1478 {
1479 int ret;
1480
1481 assert(pos);
1482 ret = munmap_align(pos->base_mma);
1483 if (ret) {
1484 goto end;
1485 }
1486
1487 pos->packet_size += PACKET_LEN_INCREMENT;
1488 ret = posix_fallocate(pos->fd, pos->mmap_offset,
1489 pos->packet_size / CHAR_BIT);
1490 if (ret) {
1491 goto end;
1492 }
1493
1494 pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot,
1495 pos->flags, pos->fd, pos->mmap_offset);
1496 if (pos->base_mma == MAP_FAILED) {
1497 ret = -1;
1498 }
1499 end:
1500 return ret;
1501 }
This page took 0.057604 seconds and 5 git commands to generate.