1 # The MIT License (MIT)
3 # Copyright (c) 2014 Philippe Proulx <philippe.proulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 from termcolor
import cprint
, colored
32 def _perror(msg
, exit_code
=1):
33 cprint('Error: {}'.format(msg
), 'red', attrs
=['bold'], file=sys
.stderr
)
38 cprint(':: {}'.format(msg
), 'blue', attrs
=['bold'], file=sys
.stderr
)
42 ap
= argparse
.ArgumentParser()
44 ap
.add_argument('-O', '--output', metavar
='OUTPUT', action
='store',
46 help='output directory of C files')
47 ap
.add_argument('-p', '--prefix', metavar
='PREFIX', action
='store',
49 help='custom prefix for C function and structure names')
50 ap
.add_argument('-s', '--static-inline', action
='store_true',
51 help='generate static inline C functions')
52 ap
.add_argument('-c', '--manual-clock', action
='store_true',
53 help='do not use a clock callback: pass clock value to tracing functions')
54 ap
.add_argument('metadata', metavar
='METADATA', action
='store',
55 help='CTF metadata input file')
58 args
= ap
.parse_args()
60 # validate output directory
61 if not os
.path
.isdir(args
.output
):
62 _perror('"{}" is not an existing directory'.format(args
.output
))
65 if not re
.match(r
'^[a-zA-Z_][a-zA-Z0-9_]*$', args
.prefix
):
66 _perror('"{}" is not a valid C identifier'.format(args
.prefix
))
68 # validate that metadata file exists
69 if not os
.path
.isfile(args
.metadata
):
70 _perror('"{}" is not an existing file'.format(args
.metadata
))
75 # TODO: prettify this function
76 def _validate_struct(struct
):
77 # just in case we call this with the wrong type
78 if type(struct
) is not pytsdl
.tsdl
.Struct
:
79 raise RuntimeError('expecting a struct')
81 # make sure inner structures are at least byte-aligned
82 if _get_obj_alignment(struct
) < 8:
83 raise RuntimeError('inner struct must be at least byte-aligned')
86 for name
, ftype
in struct
.fields
.items():
87 if type(ftype
) is pytsdl
.tsdl
.Sequence
:
88 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(name
))
89 elif type(ftype
) is pytsdl
.tsdl
.Array
:
90 # we need to check every element type until we find a terminal one
92 element
= ftype
.element
95 if type(element
) is pytsdl
.tsdl
.Sequence
:
96 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(name
))
97 elif type(element
) is pytsdl
.tsdl
.Variant
:
98 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(name
))
99 elif type(element
) is pytsdl
.tsdl
.String
:
100 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(name
))
101 elif type(element
) is pytsdl
.tsdl
.Struct
:
102 _validate_struct(element
)
103 elif type(element
) is pytsdl
.tsdl
.Integer
:
104 if _get_integer_size(element
) > 64:
105 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name
))
106 elif type(element
) is pytsdl
.tsdl
.FloatingPoint
:
107 if _get_floating_point_size(element
) > 64:
108 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name
))
109 elif type(element
) is pytsdl
.tsdl
.Enum
:
110 if _get_enum_size(element
) > 64:
111 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name
))
113 if type(element
) is pytsdl
.tsdl
.Array
:
114 # still an array, continue
115 element
= element
.element
117 # found the terminal element
119 elif type(ftype
) is pytsdl
.tsdl
.Variant
:
120 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name
))
121 elif type(ftype
) is pytsdl
.tsdl
.String
:
122 raise RuntimeError('field "{}" is a string (not allowed here)'.format(name
))
123 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
124 _validate_struct(ftype
)
125 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
126 if _get_integer_size(ftype
) > 64:
127 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name
))
128 elif type(ftype
) is pytsdl
.tsdl
.FloatingPoint
:
129 if _get_floating_point_size(ftype
) > 64:
130 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name
))
131 elif type(ftype
) is pytsdl
.tsdl
.Enum
:
132 if _get_enum_size(ftype
) > 64:
133 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name
))
136 def _validate_context_field(struct
):
137 if type(struct
) is not pytsdl
.tsdl
.Struct
:
138 raise RuntimeError('expecting a struct')
140 for name
, ftype
in struct
.fields
.items():
141 if type(ftype
) is pytsdl
.tsdl
.Variant
:
142 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name
))
143 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
144 # validate inner structure against barectf constraints
145 _validate_struct(ftype
)
148 def _validate_integer(integer
, size
=None, align
=None, signed
=None):
149 if type(integer
) is not pytsdl
.tsdl
.Integer
:
150 raise RuntimeError('expected integer')
153 if integer
.size
!= size
:
154 raise RuntimeError('expected {}-bit integer'.format(size
))
156 if align
is not None:
157 if integer
.align
!= align
:
158 raise RuntimeError('expected integer with {}-bit alignment'.format(align
))
160 if signed
is not None:
161 if integer
.signed
!= signed
:
162 raise RuntimeError('expected {} integer'.format('signed' if signed
else 'unsigned'))
165 def _validate_packet_header(packet_header
):
167 _validate_struct(packet_header
)
168 except RuntimeError as e
:
169 _perror('packet header: {}'.format(e
))
171 # magic must be the first field
172 if 'magic' in packet_header
.fields
:
173 if list(packet_header
.fields
.keys())[0] != 'magic':
174 _perror('packet header: "magic" must be the first field')
176 _perror('packet header: missing "magic" field')
178 # magic must be a 32-bit unsigned integer, 32-bit aligned
180 _validate_integer(packet_header
['magic'], 32, 32, False)
181 except RuntimeError as e
:
182 _perror('packet header: "magic": {}'.format(e
))
184 # mandatory stream_id
185 if 'stream_id' not in packet_header
.fields
:
186 _perror('packet header: missing "stream_id" field')
188 # stream_id must be an unsigned integer
190 _validate_integer(packet_header
['stream_id'], signed
=False)
191 except RuntimeError as e
:
192 _perror('packet header: "stream_id": {}'.format(e
))
195 def _dot_name_to_str(name
):
196 return '.'.join(name
)
199 def _compare_integers(int1
, int2
):
200 if type(int1
) is not pytsdl
.tsdl
.Integer
:
203 if type(int2
) is not pytsdl
.tsdl
.Integer
:
206 size
= int1
.size
== int2
.size
207 align
= int1
.align
== int2
.align
208 cmap
= int1
.map == int2
.map
209 base
= int1
.base
== int2
.base
210 encoding
= int1
.encoding
== int2
.encoding
211 signed
= int1
.signed
== int2
.signed
212 comps
= (size
, align
, cmap
, base
, encoding
, signed
)
214 # True means 1 for sum()
215 return sum(comps
) == len(comps
)
218 def _validate_packet_context(doc
, stream
):
219 packet_context
= stream
.packet_context
223 _validate_struct(packet_context
)
224 except RuntimeError as e
:
225 _perror('stream {}: packet context: {}'.format(sid
, e
))
227 fields
= packet_context
.fields
229 # if timestamp_begin exists, timestamp_end must exist
230 if 'timestamp_begin' in fields
or 'timestamp_end' in fields
:
231 if 'timestamp_begin' not in fields
or 'timestamp_end' not in fields
:
232 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid
))
234 # timestamp_begin and timestamp_end must have the same integer
235 # as the event header's timestamp field (should exist by now)
236 timestamp
= stream
.event_header
['timestamp']
238 if not _compare_integers(fields
['timestamp_begin'], timestamp
):
239 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid
))
241 if not _compare_integers(fields
['timestamp_end'], timestamp
):
242 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid
))
244 # content_size must exist and be an unsigned integer
245 if 'content_size' not in fields
:
246 _perror('stream {}: packet context: missing "content_size" field'.format(sid
))
249 _validate_integer(fields
['content_size'], 32, 32, False)
252 _validate_integer(fields
['content_size'], 64, 64, False)
254 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
256 # packet_size must exist and be an unsigned integer
257 if 'packet_size' not in fields
:
258 _perror('stream {}: packet context: missing "packet_size" field'.format(sid
))
261 _validate_integer(fields
['packet_size'], 32, 32, False)
264 _validate_integer(fields
['packet_size'], 64, 64, False)
266 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
268 # if cpu_id exists, must be an unsigned integer
269 if 'cpu_id' in fields
:
271 _validate_integer(fields
['cpu_id'], signed
=False)
272 except RuntimeError as e
:
273 _perror('stream {}: packet context: "cpu_id": {}'.format(sid
, e
))
276 def _validate_event_header(doc
, stream
):
277 event_header
= stream
.event_header
281 _validate_struct(event_header
)
282 except RuntimeError as e
:
283 _perror('stream {}: event header: {}'.format(sid
, e
))
285 fields
= event_header
.fields
287 # id must exist and be an unsigned integer
288 if 'id' not in fields
:
289 _perror('stream {}: event header: missing "id" field'.format(sid
))
292 _validate_integer(fields
['id'], signed
=False)
293 except RuntimeError as e
:
294 _perror('stream {}: "id": {}'.format(sid
, format(e
)))
297 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
298 if 'timestamp' not in fields
:
299 _perror('stream {}: event header: missing "timestamp" field'.format(sid
))
302 _validate_integer(fields
['timestamp'], signed
=False)
303 except RuntimeError as e
:
304 _perror('stream {}: "timestamp": {}'.format(sid
, format(e
)))
307 def _validate_stream_event_context(doc
, stream
):
308 stream_event_context
= stream
.event_context
311 if stream_event_context
is None:
315 _validate_context_field(stream_event_context
)
316 except RuntimeError as e
:
317 _perror('stream {}: event context: {}'.format(sid
, e
))
320 def _validate_all_scopes(doc
):
322 _validate_packet_header(doc
.trace
.packet_header
)
325 for stream_id
, stream
in doc
.streams
.items():
326 _validate_event_header(doc
, stream
)
327 _validate_packet_context(doc
, stream
)
328 _validate_stream_event_context(doc
, stream
)
331 def _validate_metadata(doc
):
332 _validate_all_scopes(doc
)
342 def _get_alignment(at
, align
):
343 return (at
+ align
- 1) & -align
346 def _offset_vars_tree_to_vars(offset_vars_tree
, prefix
='',
347 offset_vars
=collections
.OrderedDict()):
348 for name
, offset
in offset_vars_tree
.items():
349 varname
= '{}_{}'.format(prefix
, name
)
351 if isinstance(offset
, dict):
352 _offset_vars_tree_to_vars(offset
, varname
, offset_vars
)
354 offset_vars
[varname
] = offset
359 # returns the size of a struct with _static size_
360 def _get_struct_size(struct
, offset_vars_tree
=collections
.OrderedDict(),
364 for fname
, ftype
in struct
.fields
.items():
365 field_alignment
= _get_obj_alignment(ftype
)
366 offset
= _get_alignment(offset
, field_alignment
)
368 if type(ftype
) is pytsdl
.tsdl
.Struct
:
369 offset_vars_tree
[fname
] = collections
.OrderedDict()
370 sz
= _get_struct_size(ftype
, offset_vars_tree
[fname
],
371 base_offset
+ offset
)
373 # only integers may act as sequence lengths
374 if type(ftype
) is pytsdl
.tsdl
.Integer
:
375 offset_vars_tree
[fname
] = base_offset
+ offset
377 sz
= _get_obj_size(ftype
)
384 def _get_array_size(array
):
385 element
= array
.element
387 # effective size of one element includes its alignment after its size
388 size
= _get_obj_size(element
)
389 align
= _get_obj_alignment(element
)
391 return _get_alignment(size
, align
) * array
.length
394 def _get_enum_size(enum
):
395 return _get_obj_size(enum
.integer
)
398 def _get_floating_point_size(floating_point
):
399 return floating_point
.exp_dig
+ floating_point
.mant_dig
402 def _get_integer_size(integer
):
407 pytsdl
.tsdl
.Struct
: _get_struct_size
,
408 pytsdl
.tsdl
.Integer
: _get_integer_size
,
409 pytsdl
.tsdl
.Enum
: _get_enum_size
,
410 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_size
,
411 pytsdl
.tsdl
.Array
: _get_array_size
,
415 def _get_obj_size(obj
):
416 return _obj_size_cb
[type(obj
)](obj
)
419 def _get_struct_alignment(struct
):
420 if struct
.align
is not None:
425 for fname
, ftype
in struct
.fields
.items():
426 cur_align
= max(_get_obj_alignment(ftype
), cur_align
)
431 def _get_integer_alignment(integer
):
435 def _get_floating_point_alignment(floating_point
):
436 return floating_point
.align
439 def _get_enum_alignment(enum
):
440 return _get_obj_alignment(enum
.integer
)
443 def _get_string_alignment(string
):
446 def _get_array_alignment(array
):
447 return _get_obj_alignment(array
.element
)
450 def _get_sequence_alignment(sequence
):
451 return _get_obj_alignment(sequence
.element
)
454 _obj_alignment_cb
= {
455 pytsdl
.tsdl
.Struct
: _get_struct_alignment
,
456 pytsdl
.tsdl
.Integer
: _get_integer_alignment
,
457 pytsdl
.tsdl
.Enum
: _get_enum_alignment
,
458 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_alignment
,
459 pytsdl
.tsdl
.Array
: _get_array_alignment
,
460 pytsdl
.tsdl
.Sequence
: _get_sequence_alignment
,
461 pytsdl
.tsdl
.String
: _get_string_alignment
,
465 def _get_obj_alignment(obj
):
466 return _obj_alignment_cb
[type(obj
)](obj
)
470 _CTX_BUF
= 'ctx->buf'
471 _CTX_BUF_SIZE
= 'ctx->buf_size'
472 _CTX_BUF_AT
= '{}[{} >> 3]'.format(_CTX_BUF
, _CTX_AT
)
473 _CTX_BUF_AT_ADDR
= '&{}'.format(_CTX_BUF_AT
)
474 _ALIGN_OFFSET
= 'ALIGN_OFFSET'
475 _CHECK_OFFSET_OVERFLOW_FMT
= \
476 'CHECK_OFFSET_OVERFLOW({}, {}, {{}});'.format(_CTX_AT
, _CTX_BUF_SIZE
)
479 def _field_name_to_param_name(fname
):
480 return 'param_{}'.format(fname
)
483 def _get_integer_param_type(integer
):
484 signed
= 'u' if not integer
.signed
else ''
486 if integer
.size
== 8:
488 elif integer
.size
== 16:
490 elif integer
.size
== 32:
492 elif integer
.size
== 64:
495 # if the integer is signed and of uncommon size, the sign bit is
496 # at a custom position anyway so we use a 64-bit unsigned
502 if integer
.size
< 16:
504 elif integer
.size
< 32:
506 elif integer
.size
< 64:
511 return '{}int{}_t'.format(signed
, sz
)
514 def _get_enum_param_type(enum
):
515 return _get_obj_param_type(enum
.integer
)
518 def _get_floating_point_param_type(fp
):
519 if fp
.exp_dig
== 8 and fp
.mant_dig
== 24 and fp
.align
== 32:
521 elif fp
.exp_dig
== 11 and fp
.mant_dig
== 53 and fp
.align
== 64:
527 _obj_param_type_cb
= {
528 pytsdl
.tsdl
.Struct
: lambda obj
: 'const void*',
529 pytsdl
.tsdl
.Integer
: _get_integer_param_type
,
530 pytsdl
.tsdl
.Enum
: _get_enum_param_type
,
531 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_param_type
,
532 pytsdl
.tsdl
.Array
: lambda obj
: 'const void*',
533 pytsdl
.tsdl
.Sequence
: lambda obj
: 'const void*',
534 pytsdl
.tsdl
.String
: lambda obj
: 'const char*',
538 def _get_obj_param_type(obj
):
539 return _obj_param_type_cb
[type(obj
)](obj
)
550 def _get_check_offset_overflow_cline(size
):
551 return _CLine(_CHECK_OFFSET_OVERFLOW_FMT
.format(size
))
554 def _write_field_struct(doc
, fname
, struct
):
555 size
= _get_struct_size(struct
)
556 size_bytes
= _get_alignment(size
, 8) // 8
558 dst
= _CTX_BUF_AT_ADDR
559 src
= _field_name_to_param_name(fname
)
562 # memcpy() is safe since barectf requires inner structures
564 _get_check_offset_overflow_cline(size
),
565 _CLine('memcpy({}, {}, {});'.format(dst
, src
, size_bytes
)),
566 _CLine('{} += {};'.format(_CTX_AT
, size
)),
571 pytsdl
.tsdl
.ByteOrder
.BE
: 'be',
572 pytsdl
.tsdl
.ByteOrder
.LE
: 'le',
576 def _write_field_integer(doc
, fname
, integer
):
577 bo
= _bo_suffixes_map
[integer
.byte_order
]
579 t
= _get_obj_param_type(integer
)
581 length
= _get_obj_size(integer
)
582 value
= _field_name_to_param_name(fname
)
583 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
586 _get_check_offset_overflow_cline(length
),
587 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, value
)),
588 _CLine('{} += {};'.format(_CTX_AT
, length
))
592 def _write_field_enum(doc
, fname
, enum
):
593 return _write_field_obj(doc
, fname
, enum
.integer
)
596 def _write_field_floating_point(doc
, fname
, floating_point
):
597 bo
= _bo_suffixes_map
[floating_point
.byte_order
]
599 t
= _get_obj_param_type(floating_point
)
601 length
= _get_obj_size(floating_point
)
602 value
= _field_name_to_param_name(fname
)
603 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
606 _get_check_offset_overflow_cline(length
),
607 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, value
)),
608 _CLine('{} += {};'.format(_CTX_AT
, length
))
612 def _write_field_array(doc
, fname
, array
):
615 # array index variable declaration
616 iv
= 'ia_{}'.format(fname
)
617 lines
.append(_CLine('uint32_t {};'.format(iv
)))
619 # for loop using array's static length
620 line
= 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv
=iv
, l
=array
.length
)
621 lines
.append(_CLine(line
))
623 # for loop statements
624 for_block
= _CBlock()
626 # align bit index before writing to the buffer
627 element_align
= _get_obj_alignment(array
.element
)
628 line
= '{}({}, {});'.format(_ALIGN_OFFSET
, _CTX_AT
, element_align
)
629 for_block
.append(_CLine(line
))
631 # write element to the buffer
632 for_block
+= _write_field_obj(doc
, fname
, array
.element
)
633 lines
.append(for_block
)
636 lines
.append(_CLine('}'))
641 def _write_field_sequence(doc
, fname
, sequence
):
643 _CLine('would write sequence here;'),
647 def _write_field_string(doc
, fname
, string
):
650 # source pointer (function parameter)
651 src
= _field_name_to_param_name(fname
)
653 # string index variable declaration
654 iv
= 'is_{}'.format(fname
)
655 lines
.append(_CLine('uint32_t {};'.format(iv
)))
657 # for loop; loop until the end of the source string is reached
658 fmt
= "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
659 lines
.append(_CLine(fmt
.format(iv
=iv
, src
=src
, ctxat
=_CTX_AT
)))
661 # for loop statements
662 for_block
= _CBlock()
664 # check offset overflow
665 for_block
.append(_get_check_offset_overflow_cline(8))
667 # write byte to the buffer
668 line
= '{} = {}[{}]'.format(_CTX_BUF_AT
, src
, iv
)
669 for_block
.append(_CLine(line
))
672 lines
.append(for_block
)
673 lines
.append(_CLine('}'))
675 # write NULL character to the buffer
676 lines
.append(_CLine("{} = '\\0';".format(_CTX_BUF_AT
)))
677 lines
.append(_CLine('{} += 8;'.format(_CTX_AT
)))
682 _write_field_obj_cb
= {
683 pytsdl
.tsdl
.Struct
: _write_field_struct
,
684 pytsdl
.tsdl
.Integer
: _write_field_integer
,
685 pytsdl
.tsdl
.Enum
: _write_field_enum
,
686 pytsdl
.tsdl
.FloatingPoint
: _write_field_floating_point
,
687 pytsdl
.tsdl
.Array
: _write_field_array
,
688 pytsdl
.tsdl
.Sequence
: _write_field_sequence
,
689 pytsdl
.tsdl
.String
: _write_field_string
,
693 def _write_field_obj(doc
, fname
, ftype
):
694 return _write_field_obj_cb
[type(ftype
)](doc
, fname
, ftype
)
697 def _struct_to_clines(doc
, struct
):
700 for fname
, ftype
in struct
.fields
.items():
702 pname
= _field_name_to_param_name(fname
)
703 align
= _get_obj_alignment(ftype
)
705 # align bit index before writing to the buffer
706 line
= '{}({}, {});'.format(_ALIGN_OFFSET
, _CTX_AT
, align
)
709 # write offset variables
710 if type(ftype
) is pytsdl
.tsdl
.Struct
:
711 offset_vars_tree
= collections
.OrderedDict()
712 _get_struct_size(ftype
, offset_vars_tree
)
713 offset_vars
= _offset_vars_tree_to_vars(offset_vars_tree
)
715 # as many offset as there are child fields because a future
716 # sequence could refer to any of those fields
717 for lname
, offset
in offset_vars
.items():
718 fmt
= 'uint32_t off_{}_{} = {} + {};'
719 line
= fmt
.format(fname
, lname
, _CTX_AT
, offset
);
720 lines
.append(_CLine(line
))
721 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
722 # offset of this simple field is the current bit index
723 line
= 'uint32_t off_{} = {};'.format(fname
, _CTX_AT
)
724 lines
.append(_CLine(line
))
726 lines
+= _write_field_obj(doc
, fname
, ftype
)
727 line_groups
.append(lines
)
732 output_lines
= line_groups
[0]
734 for lines
in line_groups
[1:]:
735 output_lines
.append('')
736 output_lines
+= lines
741 def _cblock_to_source_lines(cblock
, indent
=1):
743 indentstr
= '\t' * indent
746 if type(line
) is _CBlock
:
747 src
+= _cblock_to_source_lines(line
, indent
+ 1)
749 src
.append(indentstr
+ line
)
754 def _cblock_to_source(cblock
, indent
=1):
755 lines
= _cblock_to_source_lines(cblock
, indent
)
757 return '\n'.join(lines
)
760 def gen_barectf(metadata
, output
, prefix
, static_inline
, manual_clock
):
761 # open CTF metadata file
763 with
open(metadata
) as f
:
766 _perror('cannot open/read CTF metadata file "{}"'.format(metadata
))
769 parser
= pytsdl
.parser
.Parser()
772 doc
= parser
.parse(tsdl
)
773 except pytsdl
.parser
.ParseError
as e
:
774 _perror('parse error: {}'.format(e
))
776 # validate CTF metadata against barectf constraints
777 _validate_metadata(doc
)
781 clines
= _struct_to_clines(doc
, doc
.streams
[0].get_event(0).fields
)
782 print(_cblock_to_source(_CBlock(clines
)))
787 gen_barectf(args
.metadata
, args
.output
, args
.prefix
, args
.static_inline
,