_CCodeGenerator.generate_c_src(): use Jinja 2 templates
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 28 Aug 2020 22:00:56 +0000 (18:00 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 3 Sep 2020 14:07:20 +0000 (10:07 -0400)
This patch makes _CCodeGenerator.generate_c_src() use Jinja 2 templates
instead of a generic code generator.

The purpose of switching to Jinja 2 templates is to make such templates
more readable than Python code, to make them reusable, and to assign
different concerns to different templates.

As such a change is hard to make incrementally, this patch changes many
parts of the tree at once. More specifically, the impacted parts are:

`gen.py`:
    * _CCodeGenerator.generate_c_src() now creates _all_ the operations
      (which used to be named "serialization actions"; more about this
      below) for all the root field types and passes this to the
      `barectf.c.j2` template at rendering time.

      _CCodeGenerator.generate_c_src() doesn't use anything from
      `barectf.codegen` or `barectf.templates`.

    * What used to be named `_SerializationActions` is now named
      `_OpsBuilder`.

      An `_OpsBuilder` object does pretty much the same job as what a
      `_SerializationActions` object previously did: when you call its
      append_root_ft() method, it iterates the members of the structure
      field type recursively to append corresponding operations to
      itself. You can then get its current list of operations with its
      `ops` property.

    * An operation is either "align" (`_AlignOp`) or "write"
      (`_WriteOp`).

      Each of those operations can occur in two different contexts:
      serialization or size computation. Therefore, each operation
      contains two `barectf.template._Template` objects: one for the
      serialization function and one for the size computation function.
      You can render both templates using the serialize_str() and
      size_str() methods (to which you can pass more rendering context).

      Although most operations use the same generic templates, the
      serialization template of some "write" operations can be custom.
      This is how special fields are handled, like the packet header's
      magic number or the event header's time.

      In `barectf/templates/c`, template files are named as such:

      +--------------------+------------------------+-------------------+
      | Operation/Function | Serialization          | Size              |
      +====================+========================+===================+
      | Align              | `serialize-align-*.j2` | `size-align-*.j2` |
      | Write              | `serialize-write-*.j2` | `size-write-*.j2` |
      +--------------------+------------------------+-------------------+

    * An operation contains all the names you need to craft a source
      variable name (to be joined with `_`).

      This is why root field type prefixes (`_RootFtPrefixes`) don't
      contain a trailing underscore anymore.

      The topmost name of an operation `o` is `o.top_name`; templates
      mostly use this property for C comments.

`template.py`:
`codegen.py`:
    Both files are removed as they're no longer needed by the project.

`templates/c`:
    `barectf.c.j2`:
        New template which generates the whole `barectf.c` file (given
        the file name prefix is `barectf`).

        This template generates, in this order:

        * The licence header.
        * Utility C macros.
        * Internal data structures.
        * Public barectf context access funtions.
        * Internal functions.
        * Public barectf context initialization function.
        * For each stream type:
          * Public packet opening function.
          * Public packet closing function.
          * Internal event header serialization function.
          * Internal event common context serialization function.
          * For each event type:
            * Internal serialization function.
          * For each event type:
            * Internal size computation function.
          * For each event type:
            * Public tracing function.

    `barectf.c-macros.j2`:
        Macros to be used by the `barectf.c.j2` template:

        * open_close_func_preamble()
        * ft_call_params()

    `common.j2`:
        New trace_func_name() and op_src() macros.

    `align-statements-comment.j2`:
        C comment for any alignment statement.

    `serialize-align-statements.j2`:
        Alignment statements for serialization functions.

    `serialize-write-*statements.j2`:
        Writing statements for serialization functions.

    `serialize-write-statements-comment.j2`:
        C comment for generic writing statements (for serialization
        functions).

    `size-align-statements.j2`:
        Alignment statements for size computation functions.

    `size-write-*-statements.j2`:
        Writing statements for size computation functions.

    Also, to make templates simpler, I standardized the following C
    variable names:

    `ctx`:
        Generic barectf context.

    `sctx`:
        Stream-type-specific barectf context.

    `vctx`:
        `ctx` as a `void` pointer.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
52 files changed:
barectf/codegen.py [deleted file]
barectf/gen.py
barectf/templates.py [deleted file]
barectf/templates/barectf.h.j2 [deleted file]
barectf/templates/bitfield.h.j2 [deleted file]
barectf/templates/c-close-func-proto.j2 [deleted file]
barectf/templates/c-common.j2 [deleted file]
barectf/templates/c-ctx-init-func-proto.j2 [deleted file]
barectf/templates/c-open-func-proto.j2 [deleted file]
barectf/templates/c-trace-func-proto.j2 [deleted file]
barectf/templates/c/align-statements-comment.j2 [new file with mode: 0644]
barectf/templates/c/barectf.c-macros.j2 [new file with mode: 0644]
barectf/templates/c/barectf.c.j2 [new file with mode: 0644]
barectf/templates/c/barectf.h.j2 [new file with mode: 0644]
barectf/templates/c/bitfield.h.j2 [new file with mode: 0644]
barectf/templates/c/close-func-proto.j2 [new file with mode: 0644]
barectf/templates/c/common.j2 [new file with mode: 0644]
barectf/templates/c/ctx-init-func-proto.j2 [new file with mode: 0644]
barectf/templates/c/func-proto-params.j2 [new file with mode: 0644]
barectf/templates/c/open-func-proto.j2 [new file with mode: 0644]
barectf/templates/c/serialize-align-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-bit-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-ev-type-id-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-int-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-magic-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-packet-size-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-real-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-saved-int-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-skip-save-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-statements-comment.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-stream-type-id-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-string-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-time-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-uuid-statements.j2 [new file with mode: 0644]
barectf/templates/c/size-align-statements.j2 [new file with mode: 0644]
barectf/templates/c/size-write-bit-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/size-write-string-statements.j2 [new file with mode: 0644]
barectf/templates/c/trace-func-proto.j2 [new file with mode: 0644]
barectf/templates/metadata-enum-ft.j2 [deleted file]
barectf/templates/metadata-int-ft.j2 [deleted file]
barectf/templates/metadata-real-ft.j2 [deleted file]
barectf/templates/metadata-str-ft.j2 [deleted file]
barectf/templates/metadata-struct-ft.j2 [deleted file]
barectf/templates/metadata.j2 [deleted file]
barectf/templates/metadata/enum-ft.j2 [new file with mode: 0644]
barectf/templates/metadata/int-ft.j2 [new file with mode: 0644]
barectf/templates/metadata/metadata.j2 [new file with mode: 0644]
barectf/templates/metadata/real-ft.j2 [new file with mode: 0644]
barectf/templates/metadata/str-ft.j2 [new file with mode: 0644]
barectf/templates/metadata/struct-ft.j2 [new file with mode: 0644]
barectf/tsdl182gen.py
doc/examples/linux-fs-simple/config.yaml

diff --git a/barectf/codegen.py b/barectf/codegen.py
deleted file mode 100644 (file)
index 3a54ea3..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-class _CodeGenerator:
-    def __init__(self, indent_string):
-        self._indent_string = indent_string
-        self.reset()
-
-    @property
-    def code(self):
-        return '\n'.join(self._lines)
-
-    def reset(self):
-        self._lines = []
-        self._indent = 0
-        self._glue = False
-
-    def add_line(self, line):
-        if self._glue:
-            self.append_to_last_line(line)
-            self._glue = False
-            return
-
-        indent_string = self._get_indent_string()
-        self._lines.append(indent_string + str(line))
-
-    def add_lines(self, lines):
-        if type(lines) is str:
-            lines = lines.split('\n')
-
-        for line in lines:
-            self.add_line(line)
-
-    def add_glue(self):
-        self._glue = True
-
-    def append_to_last_line(self, s):
-        if self._lines:
-            self._lines[-1] += str(s)
-
-    def add_empty_line(self):
-        self._lines.append('')
-
-    def add_cc_line(self, comment):
-        self.add_line('/* {} */'.format(comment))
-
-    def append_cc_to_last_line(self, comment, with_space=True):
-        if with_space:
-            sp = ' '
-        else:
-            sp = ''
-
-        self.append_to_last_line('{}/* {} */'.format(sp, comment))
-
-    def indent(self):
-        self._indent += 1
-
-    def unindent(self):
-        self._indent = max(self._indent - 1, 0)
-
-    def _get_indent_string(self):
-        return self._indent_string * self._indent
index 4745f54ad8f00804c6c05d95fdb7f02218f4edcd..2fbc00881970bba48aedfd3ff3db0d869d48d595 100644 (file)
 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 import barectf.tsdl182gen as barectf_tsdl182gen
-import barectf.templates as barectf_templates
 import barectf.template as barectf_template
-import barectf.codegen as barectf_codegen
 import barectf.config as barectf_config
 import barectf.version as barectf_version
 import itertools
 import datetime
+import collections
 import copy
 
 
+# A file generated by a `CodeGenerator` object.
+#
+# A generated file has a name (influenced by the configuration's
+# file name prefix option) and contents.
 class _GeneratedFile:
     def __init__(self, name, contents):
         self._name = name
@@ -46,6 +49,12 @@ class _GeneratedFile:
         return self._contents
 
 
+# A barectf code generator.
+#
+# Build a code generator with a barectf configuration.
+#
+# A code generator can generate the TSDL `metadata` file and C source
+# and header files.
 class CodeGenerator:
     def __init__(self, configuration):
         self._config = configuration
@@ -90,16 +99,31 @@ class CodeGenerator:
         return self._metadata_stream
 
 
-def _align(v, align):
-    return (v + (align - 1)) & -align
+# A tuple containing serialization and size computation function
+# templates for a given operation.
+_OpTemplates = collections.namedtuple('_OpTemplates', ['serialize', 'size'])
 
 
-class _SerializationAction:
-    def __init__(self, offset_in_byte, ft, names):
+# Base class of any operation within source code.
+#
+# Any operation has:
+#
+# * An offset at which to start to write within the current byte.
+#
+# * A field type.
+#
+# * A list of names which, when joined with `_`, form the generic C
+#   source variable name.
+#
+# * Serialization and size computation templates to generate the
+#   operation's source code for those functions.
+class _Op:
+    def __init__(self, offset_in_byte, ft, names, templates):
         assert(offset_in_byte >= 0 and offset_in_byte < 8)
         self._offset_in_byte = offset_in_byte
         self._ft = ft
-        self._names = copy.deepcopy(names)
+        self._names = copy.copy(names)
+        self._templates = templates
 
     @property
     def offset_in_byte(self):
@@ -113,10 +137,25 @@ class _SerializationAction:
     def names(self):
         return self._names
 
+    @property
+    def top_name(self):
+        return self._names[-1]
 
-class _AlignSerializationAction(_SerializationAction):
-    def __init__(self, offset_in_byte, ft, names, value):
-        super().__init__(offset_in_byte, ft, names)
+    def _render_template(self, templ, **kwargs):
+        return templ.render(op=self, root_ft_prefixes=_RootFtPrefixes,
+                            root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, **kwargs)
+
+    def serialize_str(self, **kwargs):
+        return self._render_template(self._templates.serialize, **kwargs)
+
+    def size_str(self, **kwargs):
+        return self._render_template(self._templates.size, **kwargs)
+
+
+# An "align" operation.
+class _AlignOp(_Op):
+    def __init__(self, offset_in_byte, ft, names, templates, value):
+        super().__init__(offset_in_byte, ft, names, templates)
         self._value = value
 
     @property
@@ -124,52 +163,130 @@ class _AlignSerializationAction(_SerializationAction):
         return self._value
 
 
-class _SerializeSerializationAction(_SerializationAction):
+# A "write" operation.
+class _WriteOp(_Op):
     pass
 
 
-class _SerializationActions:
-    def __init__(self):
-        self.reset()
-
-    def reset(self):
+# A builder of a chain of operations.
+#
+# Such a builder is closely connected to a `_CCodeGenerator` object
+# using it to find generic templates.
+#
+# Call append_root_ft() to make an operation builder append operations
+# to itself for each member, recursively, of the structure field type.
+#
+# Get an operation builder's operations with its `ops` property.
+class _OpsBuilder:
+    def __init__(self, cg):
         self._last_alignment = None
         self._last_bit_array_size = None
-        self._actions = []
+        self._ops = []
         self._names = []
         self._offset_in_byte = 0
+        self._cg = cg
 
-    def append_root_scope_ft(self, ft, name):
+    @property
+    def ops(self):
+        return self._ops
+
+    # Creates and appends the operations for the members, recursively,
+    # of the root structure field type `ft` named `name`.
+    #
+    # `spec_serialize_write_templates` is a mapping of first level
+    # member names to specialized serialization "write" templates.
+    def append_root_ft(self, ft, name, spec_serialize_write_templates=None):
         if ft is None:
             return
 
-        assert(type(ft) is barectf_config.StructureFieldType)
-        self._names = [name]
-        self._append_ft(ft)
+        if spec_serialize_write_templates is None:
+            spec_serialize_write_templates = {}
+
+        assert type(ft) is barectf_config.StructureFieldType
+        assert len(self._names) == 0
+        self._append_ft(ft, name, spec_serialize_write_templates)
+
+    # Creates and appends the operations of a given field type `ft`
+    # named `name`.
+    #
+    # See append_root_ft() for `spec_serialize_write_templates`.
+    def _append_ft(self, ft, name, spec_serialize_write_templates):
+        def top_name():
+            return self._names[-1]
+
+        # Appends a "write" operation for the field type `ft`.
+        #
+        # This function considers `spec_serialize_write_templates` to
+        # override generic templates.
+        def append_write_op(ft):
+            assert type(ft) is not barectf_config.StructureFieldType
+            offset_in_byte = self._offset_in_byte
+
+            if isinstance(ft, barectf_config._BitArrayFieldType):
+                self._offset_in_byte += ft.size
+                self._offset_in_byte %= 8
+
+            serialize_write_templ = None
+
+            if len(self._names) == 2:
+                serialize_write_templ = spec_serialize_write_templates.get(top_name())
+
+            if serialize_write_templ is None:
+                if isinstance(ft, barectf_config._IntegerFieldType):
+                    serialize_write_templ = self._cg._serialize_write_int_statements_templ
+                elif type(ft) is barectf_config.RealFieldType:
+                    serialize_write_templ = self._cg._serialize_write_real_statements_templ
+                else:
+                    assert type(ft) is barectf_config.StringFieldType
+                    serialize_write_templ = self._cg._serialize_write_string_statements_templ
+
+            size_write_templ = None
 
-    @property
-    def actions(self):
-        return self._actions
+            if isinstance(ft, barectf_config._BitArrayFieldType):
+                size_write_templ = self._cg._size_write_bit_array_statements_templ
+            elif type(ft) is barectf_config.StringFieldType:
+                size_write_templ = self._cg._size_write_string_statements_templ
+
+            self._ops.append(_WriteOp(offset_in_byte, ft, self._names,
+                                      _OpTemplates(serialize_write_templ, size_write_templ)))
+
+        # Creates and appends an "align" operation for the field type
+        # `ft` if needed.
+        #
+        # This function updates the builder's state.
+        def try_append_align_op(alignment, do_align, ft):
+            def align(v, alignment):
+                return (v + (alignment - 1)) & -alignment
+
+            offset_in_byte = self._offset_in_byte
+            self._offset_in_byte = align(self._offset_in_byte, alignment) % 8
+
+            if do_align and alignment > 1:
+                self._ops.append(_AlignOp(offset_in_byte, ft, self._names,
+                                          _OpTemplates(self._cg._serialize_align_statements_templ,
+                                                       self._cg._size_align_statements_templ),
+                                          alignment))
 
-    def align(self, alignment):
-        do_align = self._must_align(alignment)
-        self._last_alignment = alignment
-        self._last_bit_array_size = alignment
-        self._try_append_align_action(alignment, do_align)
+        # Returns whether or not, considering the alignment requirement
+        # `align_req` and the builder's current state, we must create
+        # and append an "align" operation.
+        def must_align(align_req):
+            return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0
 
-    def _must_align(self, align_req):
-        return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0
+        # push field type's name to the builder's name stack initially
+        self._names.append(name)
 
-    def _append_ft(self, ft):
         if isinstance(ft, (barectf_config.StringFieldType, barectf_config._ArrayFieldType)):
-            assert(type(ft) is barectf_config.StringFieldType or self._names[-1] == 'uuid')
-            do_align = self._must_align(8)
+            assert type(ft) is barectf_config.StringFieldType or top_name() == 'uuid'
+
+            # strings and arrays are always byte-aligned
+            do_align = must_align(8)
             self._last_alignment = 8
             self._last_bit_array_size = 8
-            self._try_append_align_action(8, do_align, ft)
-            self._append_serialize_action(ft)
+            try_append_align_op(8, do_align, ft)
+            append_write_op(ft)
         else:
-            do_align = self._must_align(ft.alignment)
+            do_align = must_align(ft.alignment)
             self._last_alignment = ft.alignment
 
             if type(ft) is barectf_config.StructureFieldType:
@@ -177,89 +294,167 @@ class _SerializationActions:
             else:
                 self._last_bit_array_size = ft.size
 
-            self._try_append_align_action(ft.alignment, do_align, ft)
+            try_append_align_op(ft.alignment, do_align, ft)
 
             if type(ft) is barectf_config.StructureFieldType:
                 for member_name, member in ft.members.items():
-                    self._names.append(member_name)
-                    self._append_ft(member.field_type)
-                    del self._names[-1]
+                    self._append_ft(member.field_type, member_name, spec_serialize_write_templates)
             else:
-                self._append_serialize_action(ft)
+                append_write_op(ft)
+
+        # exiting for this field type: pop its name
+        del self._names[-1]
 
-    def _try_append_align_action(self, alignment, do_align, ft=None):
-        offset_in_byte = self._offset_in_byte
-        self._offset_in_byte = _align(self._offset_in_byte, alignment) % 8
 
-        if do_align and alignment > 1:
-            self._actions.append(_AlignSerializationAction(offset_in_byte, ft, self._names,
-                                                           alignment))
+# The operations for an event.
+#
+# The available operations are:
+#
+# * Specific context operations.
+# * Payload operations.
+class _EventOps:
+    def __init__(self, spec_ctx_ops, payload_ops):
+        self._spec_ctx_ops = copy.copy(spec_ctx_ops)
+        self._payload_ops = copy.copy(payload_ops)
 
-    def _append_serialize_action(self, ft):
-        assert(type(ft) is not barectf_config.StructureFieldType)
-        offset_in_byte = self._offset_in_byte
+    @property
+    def spec_ctx_ops(self):
+        return self._spec_ctx_ops
 
-        if isinstance(ft, barectf_config._BitArrayFieldType):
-            self._offset_in_byte += ft.size
-            self._offset_in_byte %= 8
+    @property
+    def payload_ops(self):
+        return self._payload_ops
 
-        self._actions.append(_SerializeSerializationAction(offset_in_byte, ft, self._names))
 
+# The operations for a stream.
+#
+# The available operations are:
+#
+# * Packet header operations.
+# * Packet context operations.
+# * Event header operations.
+# * Event common context operations.
+# * Event operations (`_EventOps`).
+class _StreamOps:
+    def __init__(self, pkt_header_ops, pkt_ctx_ops, ev_header_ops,
+                 ev_common_ctx_ops, ev_ops):
+        self._pkt_header_ops = copy.copy(pkt_header_ops)
+        self._pkt_ctx_ops = copy.copy(pkt_ctx_ops)
+        self._ev_header_ops = copy.copy(ev_header_ops)
+        self._ev_common_ctx_ops = copy.copy(ev_common_ctx_ops)
+        self._ev_ops = copy.copy(ev_ops)
 
+    @property
+    def pkt_header_ops(self):
+        return self._pkt_header_ops
+
+    @property
+    def pkt_ctx_ops(self):
+        return self._pkt_ctx_ops
+
+    @property
+    def ev_header_ops(self):
+        return self._ev_header_ops
+
+    @property
+    def ev_common_ctx_ops(self):
+        return self._ev_common_ctx_ops
+
+    @property
+    def ev_ops(self):
+        return self._ev_ops
+
+
+# The C variable name prefixes for the six kinds of root field types.
 class _RootFtPrefixes:
-    TPH = 'tph_'
-    SPC = 'spc_'
-    SEH = 'seh_'
-    SEC = 'sec_'
-    EC = 'ec_'
-    EP = 'ep_'
-
-
-_ROOT_FT_PREFIX_TO_NAME = {
-    _RootFtPrefixes.TPH: 'trace packet header',
-    _RootFtPrefixes.SPC: 'stream packet context',
-    _RootFtPrefixes.SEH: 'stream event header',
-    _RootFtPrefixes.SEC: 'stream event context',
-    _RootFtPrefixes.EC: 'event context',
-    _RootFtPrefixes.EP: 'event payload',
+    TPH = 'tph'
+    SPC = 'spc'
+    SEH = 'seh'
+    SEC = 'sec'
+    EC = 'ec'
+    EP = 'ep'
+
+
+# The human-readable names of the `_RootFtPrefixes` members.
+_ROOT_FT_PREFIX_NAMES = {
+    _RootFtPrefixes.TPH: 'packet header',
+    _RootFtPrefixes.SPC: 'packet context',
+    _RootFtPrefixes.SEH: 'event header',
+    _RootFtPrefixes.SEC: 'event common context',
+    _RootFtPrefixes.EC: 'specific context',
+    _RootFtPrefixes.EP: 'payload',
 }
 
 
+# A named function parameter for a given field type.
+_FtParam = collections.namedtuple('_FtParam', ['ft', 'name'])
+
+
+# A C code generator.
+#
+# Such a code generator can generate:
+#
+# * The bitfield header (generate_bitfield_header()).
+# * The public header (generate_header()).
+# * The source code (generate_c_src()).
 class _CCodeGenerator:
     def __init__(self, cfg):
         self._cfg = cfg
-        code_gen_opts = cfg.options.code_generation_options
-        self._iden_prefix = code_gen_opts.identifier_prefix
-        self._cg = barectf_codegen._CodeGenerator('\t')
-        self._saved_serialization_actions = {}
-
-    @property
-    def _template_filters(self):
-        return {
-            'ft_c_type': self._get_ft_c_type,
+        self._iden_prefix = cfg.options.code_generation_options.identifier_prefix
+        self._saved_serialization_ops = {}
+        self._templ_filters = {
+            'ft_c_type': self._ft_c_type,
+            'open_func_params_str': self._open_func_params_str,
+            'trace_func_params_str': self._trace_func_params_str,
+            'serialize_ev_common_ctx_func_params_str': self._serialize_ev_common_ctx_func_params_str,
         }
-
+        self._func_proto_params_templ = self._create_template('func-proto-params.j2')
+        self._serialize_align_statements_templ = self._create_template('serialize-align-statements.j2')
+        self._serialize_write_int_statements_templ = self._create_template('serialize-write-int-statements.j2')
+        self._serialize_write_real_statements_templ = self._create_template('serialize-write-real-statements.j2')
+        self._serialize_write_string_statements_templ = self._create_template('serialize-write-string-statements.j2')
+        self._serialize_write_magic_statements_templ = self._create_template('serialize-write-magic-statements.j2')
+        self._serialize_write_uuid_statements_templ = self._create_template('serialize-write-uuid-statements.j2')
+        self._serialize_write_stream_type_id_statements_templ = self._create_template('serialize-write-stream-type-id-statements.j2')
+        self._serialize_write_time_statements_templ = self._create_template('serialize-write-time-statements.j2')
+        self._serialize_write_packet_size_statements_templ = self._create_template('serialize-write-packet-size-statements.j2')
+        self._serialize_write_skip_save_statements_templ = self._create_template('serialize-write-skip-save-statements.j2')
+        self._serialize_write_ev_type_id_statements_templ = self._create_template('serialize-write-ev-type-id-statements.j2')
+        self._size_align_statements_templ = self._create_template('size-align-statements.j2')
+        self._size_write_bit_array_statements_templ = self._create_template('size-write-bit-array-statements.j2')
+        self._size_write_string_statements_templ = self._create_template('size-write-string-statements.j2')
+
+    # Creates and returns a template named `name` which is a file
+    # template if `is_file_template` is `True`.
+    #
+    # `name` is the file name, including the `.j2` extension, within the
+    # `c` directory.
+    #
+    # Such a template has the filters custom filters
+    # `self._templ_filters`.
+    def _create_template_base(self, name: str, is_file_template: bool):
+        return barectf_template._Template(f'c/{name}', is_file_template, self._cfg,
+                                          self._templ_filters)
+
+    # Creates and returns a non-file template named `name`.
+    #
+    # See _create_template_base() for `name`.
     def _create_template(self, name: str) -> barectf_template._Template:
-        return barectf_template._Template(name, False, self._cfg, self._template_filters)
+        return self._create_template_base(name, False)
 
+    # Creates and returns a file template named `name`.
+    #
+    # See _create_template_base() for `name`.
     def _create_file_template(self, name: str) -> barectf_template._Template:
-        return barectf_template._Template(name, True, self._cfg, self._template_filters)
+        return self._create_template_base(name, True)
 
+    # Trace type of this code generator's barectf configuration.
     @property
     def _trace_type(self):
         return self._cfg.trace.type
 
-    def _clk_type_c_type(self, clk_type):
-        return self._cfg.options.code_generation_options.clock_type_c_types[clk_type]
-
-    def generate_bitfield_header(self):
-        return self._create_file_template('bitfield.h.j2').render()
-
-    def _generate_func_init_proto(self):
-        tmpl = barectf_templates._FUNC_INIT_PROTO
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
-
-    def _get_ft_c_type(self, ft):
+    # Returns the C type for the field type `ft`.
+    def _ft_c_type(self, ft):
         if isinstance(ft, barectf_config._IntegerFieldType):
             sign_prefix = 'u' if isinstance(ft, barectf_config.UnsignedIntegerFieldType) else ''
 
@@ -270,7 +465,7 @@ class _CCodeGenerator:
             elif ft.size <= 32:
                 sz = 32
             else:
-                assert ft.size == 64
+                assert ft.size <= 64
                 sz = 64
 
             return f'{sign_prefix}int{sz}_t'
@@ -285,38 +480,35 @@ class _CCodeGenerator:
             assert type(ft) is barectf_config.StringFieldType
             return 'const char *'
 
-    def _generate_ft_c_type(self, ft):
-        c_type = self._get_ft_c_type(ft)
-        self._cg.append_to_last_line(c_type)
-
-    def _generate_proto_param(self, ft, name):
-        self._generate_ft_c_type(ft)
-        self._cg.append_to_last_line(' ')
-        self._cg.append_to_last_line(name)
+    # Returns the function prototype parameters for the members of the
+    # root structure field type `root_ft`.
+    #
+    # Each parameter has the prefix `name_prefix` followed with `_`.
+    #
+    # Members of which the name is in `exclude_set` are excluded.
+    def _proto_params_str(self, root_ft, name_prefix, exclude_set=None):
+        if root_ft is None:
+            return
 
-    def _generate_proto_params(self, ft, name_prefix, exclude_set=None):
         if exclude_set is None:
             exclude_set = set()
 
-        self._cg.indent()
+        params = []
 
-        for member_name, member in ft.members.items():
+        for member_name, member in root_ft.members.items():
             if member_name in exclude_set:
                 continue
 
-            self._cg.append_to_last_line(',')
-            self._cg.add_line('')
-            self._generate_proto_param(member.field_type, name_prefix + member_name)
-
-        self._cg.unindent()
+            params.append(_FtParam(member.field_type, member_name))
 
-    def _generate_func_open_proto(self, stream_type):
-        tmpl = barectf_templates._FUNC_OPEN_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
+        return self._func_proto_params_templ.render(params=params, prefix=name_prefix)
 
-        if self._trace_type._pkt_header_ft is not None:
-            self._generate_proto_params(self._trace_type._pkt_header_ft, _RootFtPrefixes.TPH,
-                                        {'magic', 'stream_id', 'uuid'})
+    # Returns the packet opening function prototype parameters for the
+    # stream type `stream_type`.
+    def _open_func_params_str(self, stream_type):
+        parts = []
+        parts.append(self._proto_params_str(self._trace_type._pkt_header_ft, _RootFtPrefixes.TPH,
+                                            {'magic', 'stream_id', 'uuid'}))
 
         exclude_set = {
             'timestamp_begin',
@@ -325,611 +517,148 @@ class _CCodeGenerator:
             'content_size',
             'events_discarded',
         }
-        self._generate_proto_params(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC, exclude_set)
-        tmpl = barectf_templates._FUNC_OPEN_PROTO_END
-        self._cg.add_lines(tmpl)
+        parts.append(self._proto_params_str(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC,
+                                            exclude_set))
+        return ''.join(parts)
 
-    def _generate_func_close_proto(self, stream_type):
-        tmpl = barectf_templates._FUNC_CLOSE_PROTO
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
+    # Returns the tracing function prototype parameters for the stream
+    # and event types `stream_ev_types`.
+    def _trace_func_params_str(self, stream_ev_types):
+        stream_type = stream_ev_types[0]
+        ev_type = stream_ev_types[1]
+        parts = []
 
-    def _generate_func_trace_proto_params(self, stream_type, ev_type):
         if stream_type._ev_header_ft is not None:
-            self._generate_proto_params(stream_type._ev_header_ft,
-                                        _RootFtPrefixes.SEH, {'id', 'timestamp'})
+            parts.append(self._proto_params_str(stream_type._ev_header_ft, _RootFtPrefixes.SEH,
+                                                {'id', 'timestamp'}))
 
         if stream_type.event_common_context_field_type is not None:
-            self._generate_proto_params(stream_type.event_common_context_field_type,
-                                        _RootFtPrefixes.SEC)
+            parts.append(self._proto_params_str(stream_type.event_common_context_field_type,
+                                                _RootFtPrefixes.SEC))
 
         if ev_type.specific_context_field_type is not None:
-            self._generate_proto_params(ev_type.specific_context_field_type, _RootFtPrefixes.EC)
+            parts.append(self._proto_params_str(ev_type.specific_context_field_type,
+                                                _RootFtPrefixes.EC))
 
         if ev_type.payload_field_type is not None:
-            self._generate_proto_params(ev_type.payload_field_type, _RootFtPrefixes.EP)
-
-    def _generate_func_trace_proto(self, stream_type, ev_type):
-        tmpl = barectf_templates._FUNC_TRACE_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
-                                       evname=ev_type.name))
-        self._generate_func_trace_proto_params(stream_type, ev_type)
-        tmpl = barectf_templates._FUNC_TRACE_PROTO_END
-        self._cg.add_lines(tmpl)
-
-    def generate_header(self):
-        return self._create_file_template('barectf.h.j2').render(root_ft_prefixes=_RootFtPrefixes)
+            parts.append(self._proto_params_str(ev_type.payload_field_type, _RootFtPrefixes.EP))
 
-    def _get_call_event_param_list_from_struct_ft(self, ft, prefix, exclude_set=None):
-        if exclude_set is None:
-            exclude_set = set()
+        return ''.join(parts)
 
-        lst = ''
+    # Returns the event header serialization function prototype
+    # parameters for the stream type `stream_type`.
+    def _serialize_ev_common_ctx_func_params_str(self, stream_type):
+        return self._proto_params_str(stream_type.event_common_context_field_type,
+                                      _RootFtPrefixes.SEC);
 
-        for member_name in ft.members:
-            if member_name in exclude_set:
-                continue
-
-            lst += f', {prefix}{member_name}'
-
-        return lst
-
-    def _get_call_event_param_list(self, stream_type, ev_type):
-        lst = ''
-
-        if stream_type._ev_header_ft is not None:
-            lst += self._get_call_event_param_list_from_struct_ft(stream_type._ev_header_ft,
-                                                                  _RootFtPrefixes.SEH, {'id', 'timestamp'})
-
-        if stream_type.event_common_context_field_type is not None:
-            lst += self._get_call_event_param_list_from_struct_ft(stream_type.event_common_context_field_type,
-                                                                  _RootFtPrefixes.SEC)
-
-        if ev_type.specific_context_field_type is not None:
-            lst += self._get_call_event_param_list_from_struct_ft(ev_type.specific_context_field_type,
-                                                                  _RootFtPrefixes.EC)
-
-        if ev_type.payload_field_type is not None:
-            lst += self._get_call_event_param_list_from_struct_ft(ev_type.payload_field_type,
-                                                                  _RootFtPrefixes.EP)
-
-        return lst
-
-    def _generate_align(self, at, align):
-        self._cg.add_line(f'_ALIGN({at}, {align});')
-
-    def _generate_incr_pos(self, var, value):
-        self._cg.add_line(f'{var} += {value};')
-
-    def _generate_incr_pos_bytes(self, var, value):
-        self._generate_incr_pos(var, f'_BYTES_TO_BITS({value})')
-
-    def _generate_func_get_event_size_proto(self, stream_type, ev_type):
-        tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
-                                       evname=ev_type.name))
-        self._generate_func_trace_proto_params(stream_type, ev_type)
-        tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_PROTO_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_get_event_size(self, stream_type, ev_type):
-        self._generate_func_get_event_size_proto(stream_type, ev_type)
-        tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_BODY_BEGIN
-        lines = tmpl.format(prefix=self._iden_prefix)
-        self._cg.add_lines(lines)
-        self._cg.add_empty_line()
-        self._cg.indent()
-        ser_actions = _SerializationActions()
-        ser_actions.append_root_scope_ft(stream_type._ev_header_ft, _RootFtPrefixes.SEH)
-        ser_actions.append_root_scope_ft(stream_type.event_common_context_field_type,
-                                         _RootFtPrefixes.SEC)
-        ser_actions.append_root_scope_ft(ev_type.specific_context_field_type, _RootFtPrefixes.EC)
-        ser_actions.append_root_scope_ft(ev_type.payload_field_type, _RootFtPrefixes.EP)
-
-        for action in ser_actions.actions:
-            if type(action) is _AlignSerializationAction:
-                if action.names:
-                    if len(action.names) == 1:
-                        line = f'align {_ROOT_FT_PREFIX_TO_NAME[action.names[0]]} structure'
-                    else:
-                        line = f'align field `{action.names[-1]}` ({_ROOT_FT_PREFIX_TO_NAME[action.names[0]]})'
-
-                    self._cg.add_cc_line(line)
-
-                self._generate_align('at', action.value)
-                self._cg.add_empty_line()
-            else:
-                assert type(action) is _SerializeSerializationAction
-                assert(len(action.names) >= 2)
-                line = f'add size of field `{action.names[-1]}` ({_ROOT_FT_PREFIX_TO_NAME[action.names[0]]})'
-                self._cg.add_cc_line(line)
-
-                if type(action.ft) is barectf_config.StringFieldType:
-                    param = ''.join(action.names)
-                    self._generate_incr_pos_bytes('at', f'strlen({param}) + 1')
-                else:
-                    self._generate_incr_pos('at', action.ft.size)
-
-                self._cg.add_empty_line()
-
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_BODY_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_serialize_event_proto(self, stream_type, ev_type):
-        tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
-                                       evname=ev_type.name))
-        self._generate_func_trace_proto_params(stream_type, ev_type)
-        tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_PROTO_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_serialize_from_action(self, var, ctx, action):
-        def gen_bitfield_write(c_type, var, ctx, action):
-            ptr = f'&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'
-            start = action.offset_in_byte
-            suffix = 'le' if action.ft.byte_order is barectf_config.ByteOrder.LITTLE_ENDIAN else 'be'
-            func = f'{self._iden_prefix}bt_bitfield_write_{suffix}'
-            call = f'{func}({ptr}, uint8_t, {start}, {action.ft.size}, {c_type}, ({c_type}) {var});'
-            self._cg.add_line(call)
-
-        def gen_serialize_int(var, ctx, action):
-            c_type = self._get_ft_c_type(action.ft)
-            gen_bitfield_write(c_type, var, ctx, action)
-            self._generate_incr_pos(f'{ctx}->at', action.ft.size)
-
-        def gen_serialize_real(var, ctx, action):
-            c_type = self._get_ft_c_type(action.ft)
-            flt_dbl = False
-
-            if c_type == 'float' or c_type == 'double':
-                flt_dbl = True
-
-                if c_type == 'float':
-                    union_name = 'f2u'
-                    int_c_type = 'uint32_t'
-                else:
-                    assert c_type == 'double'
-                    union_name = 'd2u'
-                    int_c_type = 'uint64_t'
-
-                # union for reading the bytes of the floating point number
-                self._cg.add_empty_line()
-                self._cg.add_line('{')
-                self._cg.indent()
-                self._cg.add_line(f'union {union_name} {union_name};')
-                self._cg.add_empty_line()
-                self._cg.add_line(f'{union_name}.f = {var};')
-                bf_var = f'{union_name}.u'
-            else:
-                bf_var = f'({c_type}) {var}'
-                int_c_type = c_type
-
-            gen_bitfield_write(int_c_type, bf_var, ctx, action)
-
-            if flt_dbl:
-                self._cg.unindent()
-                self._cg.add_line('}')
-                self._cg.add_empty_line()
-
-            self._generate_incr_pos(f'{ctx}->at', action.ft.size)
-
-        def gen_serialize_string(var, ctx, action):
-            self._cg.add_lines(f'_write_cstring({ctx}, {var});')
-
-        if isinstance(action.ft, barectf_config._IntegerFieldType):
-            return gen_serialize_int(var, ctx, action)
-        elif type(action.ft) is barectf_config.RealFieldType:
-            return gen_serialize_real(var, ctx, action)
-        else:
-            assert type(action.ft) is barectf_config.StringFieldType
-            return gen_serialize_string(var, ctx, action)
-
-    def _generate_serialize_statements_from_actions(self, prefix, action_iter, spec_src=None):
-        for action in action_iter:
-            if type(action) is _AlignSerializationAction:
-                if action.names:
-                    if len(action.names) == 1:
-                        line = f'align {_ROOT_FT_PREFIX_TO_NAME[action.names[0]]} structure'
-                    else:
-                        line = f'align field `{action.names[-1]}` ({_ROOT_FT_PREFIX_TO_NAME[action.names[0]]})'
-
-                    self._cg.add_cc_line(line)
-
-                self._generate_align('ctx->at', action.value)
-                self._cg.add_empty_line()
-            else:
-                assert type(action) is _SerializeSerializationAction
-                assert(len(action.names) >= 2)
-                member_name = action.names[-1]
-                line = f'serialize field `{member_name}` ({_ROOT_FT_PREFIX_TO_NAME[action.names[0]]})'
-                self._cg.add_cc_line(line)
-                src = prefix + member_name
-
-                if spec_src is not None and member_name in spec_src:
-                    src = spec_src[member_name]
-
-                self._generate_serialize_from_action(src, 'ctx', action)
-                self._cg.add_empty_line()
-
-    def _generate_func_serialize_event(self, stream_type, ev_type, orig_ser_actions):
-        self._generate_func_serialize_event_proto(stream_type, ev_type)
-        tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_BODY_BEGIN
-        lines = tmpl.format(prefix=self._iden_prefix)
-        self._cg.add_lines(lines)
-        self._cg.indent()
-        self._cg.add_empty_line()
-
-        if stream_type._ev_header_ft is not None:
-            params = self._get_call_event_param_list_from_struct_ft(stream_type._ev_header_ft,
-                                                                    _RootFtPrefixes.SEH,
-                                                                    {'timestamp', 'id'})
-            self._cg.add_cc_line('stream event header')
-            line = f'_serialize_stream_event_header_{stream_type.name}(ctx, {ev_type.id}{params});'
-            self._cg.add_line(line)
-            self._cg.add_empty_line()
-
-        if stream_type.event_common_context_field_type is not None:
-            params = self._get_call_event_param_list_from_struct_ft(stream_type.event_common_context_field_type,
-                                                                    _RootFtPrefixes.SEC)
-            self._cg.add_cc_line('stream event context')
-            line = f'_serialize_stream_event_context_{stream_type.name}(ctx{params});'
-            self._cg.add_line(line)
-            self._cg.add_empty_line()
-
-        if ev_type.specific_context_field_type is not None or ev_type.payload_field_type is not None:
-            ser_actions = copy.deepcopy(orig_ser_actions)
-
-        if ev_type.specific_context_field_type is not None:
-            ser_action_index = len(ser_actions.actions)
-            ser_actions.append_root_scope_ft(ev_type.specific_context_field_type, _RootFtPrefixes.EC)
-            ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
-            self._generate_serialize_statements_from_actions(_RootFtPrefixes.EC, ser_action_iter)
-
-        if ev_type.payload_field_type is not None:
-            ser_action_index = len(ser_actions.actions)
-            ser_actions.append_root_scope_ft(ev_type.payload_field_type, _RootFtPrefixes.EP)
-            ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
-            self._generate_serialize_statements_from_actions(_RootFtPrefixes.EP, ser_action_iter)
-
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_BODY_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_serialize_event_header_proto(self, stream_type):
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
-
-        if stream_type._ev_header_ft is not None:
-            self._generate_proto_params(stream_type._ev_header_ft, _RootFtPrefixes.SEH,
-                                        {'id', 'timestamp'})
-
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_serialize_event_common_context_proto(self, stream_type):
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_BEGIN
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
-
-        if stream_type.event_common_context_field_type is not None:
-            self._generate_proto_params(stream_type.event_common_context_field_type, _RootFtPrefixes.SEC)
-
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_serialize_event_header(self, stream_type, ser_action_iter):
-        self._generate_func_serialize_event_header_proto(stream_type)
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_BEGIN
-        lines = tmpl.format(prefix=self._iden_prefix, sname=stream_type.name)
-        self._cg.add_lines(lines)
-        self._cg.indent()
-
-        if stream_type.default_clock_type is not None:
-            line = f'struct {self._iden_prefix}{stream_type.name}_ctx *s_ctx = FROM_VOID_PTR(struct {self._iden_prefix}{stream_type.name}_ctx, vctx);'
-            self._cg.add_line(line)
-            line = f'const {self._clk_type_c_type(stream_type.default_clock_type)} ts = s_ctx->cur_last_event_ts;'
-            self._cg.add_line(line)
-
-        self._cg.add_empty_line()
-
-        if stream_type._ev_header_ft is not None:
-            spec_src = {}
-            member_name = 'id'
-            member = stream_type._ev_header_ft.members.get(member_name)
-
-            if member is not None:
-                spec_src[member_name] = f'({self._get_ft_c_type(member.field_type)}) event_id'
-
-            member_name = 'timestamp'
-            member = stream_type._ev_header_ft.members.get(member_name)
-
-            if member is not None:
-                spec_src[member_name] = f'({self._get_ft_c_type(member.field_type)}) ts'
-
-            self._generate_serialize_statements_from_actions(_RootFtPrefixes.SEH, ser_action_iter,
-                                                             spec_src)
-
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_serialize_event_common_context(self, stream_type, ser_action_iter):
-        self._generate_func_serialize_event_common_context_proto(stream_type)
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_BEGIN
-        lines = tmpl.format(prefix=self._iden_prefix)
-        self._cg.add_lines(lines)
-        self._cg.indent()
-
-        if stream_type.event_common_context_field_type is not None:
-            self._generate_serialize_statements_from_actions(_RootFtPrefixes.SEC, ser_action_iter)
-
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END
-        self._cg.add_lines(tmpl)
+    # Generates the bitfield header file contents.
+    def generate_bitfield_header(self):
+        return self._create_file_template('bitfield.h.j2').render()
 
-    def _generate_func_trace(self, stream_type, ev_type):
-        self._generate_func_trace_proto(stream_type, ev_type)
-        params = self._get_call_event_param_list(stream_type, ev_type)
-        def_clk_type = stream_type.default_clock_type
+    # Generates the public header file contents.
+    def generate_header(self):
+        return self._create_file_template('barectf.h.j2').render(root_ft_prefixes=_RootFtPrefixes)
 
-        if def_clk_type is not None:
-            save_ts_line = f'ctx->cur_last_event_ts = ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
-        else:
-            save_ts_line = '/* (no clock) */'
-
-        tmpl = barectf_templates._FUNC_TRACE_BODY
-        self._cg.add_lines(tmpl.format(sname=stream_type.name, evname=ev_type.name, params=params,
-                                       save_ts=save_ts_line))
-
-    def _generate_func_init(self):
-        self._generate_func_init_proto()
-        tmpl = barectf_templates._FUNC_INIT_BODY
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
-
-    def _generate_member_name_cc_line(self, member_name):
-        self._cg.add_cc_line(f'`{member_name}` field')
-
-    def _save_serialization_action(self, name, action):
-        self._saved_serialization_actions[name] = action
-
-    def _get_open_close_ts_line(self, stream_type):
-        def_clk_type = stream_type.default_clock_type
-
-        if def_clk_type is None:
-            return ''
-
-        c_type = self._clk_type_c_type(def_clk_type)
-        return f'\tconst {c_type} ts = ctx->parent.use_cur_last_event_ts ? ctx->cur_last_event_ts : ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
-
-    def _generate_func_open(self, stream_type):
-        def generate_save_offset(name, action):
-            self._cg.add_line(f'ctx->off_spc_{name} = ctx->parent.at;')
-            self._save_serialization_action(name, action)
-
-        self._generate_func_open_proto(stream_type)
-        tmpl = barectf_templates._FUNC_OPEN_BODY_BEGIN
-        pkt_ctx_ft = stream_type._pkt_ctx_ft
-        ts_line = self._get_open_close_ts_line(stream_type)
-        lines = tmpl.format(ts=ts_line)
-        self._cg.add_lines(lines)
-        self._cg.indent()
-        self._cg.add_cc_line('do not open a packet that is already open')
-        self._cg.add_line('if (ctx->parent.packet_is_open) {')
-        self._cg.indent()
-        self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
-        self._cg.add_line('return;')
-        self._cg.unindent()
-        self._cg.add_line('}')
-        self._cg.add_empty_line()
-        self._cg.add_line('ctx->parent.at = 0;')
-        pkt_header_ft = self._trace_type._pkt_header_ft
-        ser_actions = _SerializationActions()
-
-        if pkt_header_ft is not None:
-            self._cg.add_empty_line()
-            self._cg.add_cc_line('trace packet header')
-            self._cg.add_line('{')
-            self._cg.indent()
-            ser_actions.append_root_scope_ft(pkt_header_ft, _RootFtPrefixes.TPH)
-
-            for action in ser_actions.actions:
-                if type(action) is _AlignSerializationAction:
-                    if action.names:
-                        if len(action.names) == 1:
-                            line = 'align trace packet header structure'
-                        else:
-                            line = f'align field `{action.names[-1]}`'
-
-                        self._cg.add_cc_line(line)
-
-                    self._generate_align('ctx->parent.at', action.value)
-                    self._cg.add_empty_line()
-                else:
-                    assert type(action) is _SerializeSerializationAction
-                    assert(len(action.names) >= 2)
-                    member_name = action.names[-1]
-                    line = f'serialize field `{member_name}`'
-                    self._cg.add_cc_line(line)
-                    src = _RootFtPrefixes.TPH + member_name
-
-                    if member_name == 'magic':
-                        src = '0xc1fc1fc1UL'
-                    elif member_name == 'stream_id':
-                        src = f'({self._get_ft_c_type(action.ft)}) {stream_type.id}'
-                    elif member_name == 'uuid':
-                        self._cg.add_line('{')
-                        self._cg.indent()
-                        self._cg.add_line('static uint8_t uuid[] = {')
-                        self._cg.indent()
-
-                        for b in self._trace_type.uuid.bytes:
-                            self._cg.add_line(f'{b},')
-
-                        self._cg.unindent()
-                        self._cg.add_line('};')
-                        self._cg.add_empty_line()
-                        self._generate_align('ctx->parent.at', 8)
-                        line = 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
-                        self._cg.add_line(line)
-                        self._generate_incr_pos_bytes('ctx->parent.at', 16)
-                        self._cg.unindent()
-                        self._cg.add_line('}')
-                        self._cg.add_empty_line()
-                        continue
-
-                    self._generate_serialize_from_action(src, '(&ctx->parent)', action)
-                    self._cg.add_empty_line()
-
-            self._cg.unindent()
-            self._cg.add_lines('}')
-
-        spc_action_index = len(ser_actions.actions)
-        self._cg.add_empty_line()
-        self._cg.add_cc_line('stream packet context')
-        self._cg.add_line('{')
-        self._cg.indent()
-        ser_actions.append_root_scope_ft(pkt_ctx_ft, _RootFtPrefixes.SPC)
-
-        for action in itertools.islice(ser_actions.actions, spc_action_index, None):
-            if type(action) is _AlignSerializationAction:
-                if action.names:
-                    if len(action.names) == 1:
-                        line = 'align stream packet context structure'
-                    else:
-                        line = f'align field `{action.names[-1]}`'
-
-                    self._cg.add_cc_line(line)
-
-                self._generate_align('ctx->parent.at', action.value)
-                self._cg.add_empty_line()
-            else:
-                assert type(action) is _SerializeSerializationAction
-                assert(len(action.names) >= 2)
-                member_name = action.names[-1]
-                line = f'serialize field `{member_name}`'
-                self._cg.add_cc_line(line)
-                src = _RootFtPrefixes.SPC + member_name
-                skip_int = False
-
-                if member_name == 'timestamp_begin':
-                    src = f'({self._get_ft_c_type(action.ft)}) ts'
-                elif member_name in {'timestamp_end', 'content_size', 'events_discarded'}:
-                    skip_int = True
-                elif member_name == 'packet_size':
-                    src = f'({self._get_ft_c_type(action.ft)}) ctx->parent.packet_size'
-
-                if skip_int:
-                    generate_save_offset(member_name, action)
-                    self._generate_incr_pos('ctx->parent.at', action.ft.size)
-                else:
-                    self._generate_serialize_from_action(src, '(&ctx->parent)', action)
-
-                self._cg.add_empty_line()
-
-        self._cg.unindent()
-        self._cg.add_lines('}')
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_OPEN_BODY_END
-        self._cg.add_lines(tmpl)
-
-    def _generate_func_close(self, stream_type):
-        def generate_goto_offset(name):
-            self._cg.add_line(f'ctx->parent.at = ctx->off_spc_{name};')
-
-        self._generate_func_close_proto(stream_type)
-        tmpl = barectf_templates._FUNC_CLOSE_BODY_BEGIN
-        pkt_ctx_ft = stream_type._pkt_ctx_ft
-        ts_line = self._get_open_close_ts_line(stream_type)
-        lines = tmpl.format(ts=ts_line)
-        self._cg.add_lines(lines)
-        self._cg.indent()
-        self._cg.add_cc_line('do not close a packet that is not open')
-        self._cg.add_line('if (!ctx->parent.packet_is_open) {')
-        self._cg.indent()
-        self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
-        self._cg.add_line('return;')
-        self._cg.unindent()
-        self._cg.add_line('}')
-        self._cg.add_empty_line()
-        self._cg.add_cc_line('save content size')
-        self._cg.add_line('ctx->parent.content_size = ctx->parent.at;')
-        member_name = 'timestamp_end'
-        member = pkt_ctx_ft.members.get(member_name)
-
-        if member is not None:
-            self._cg.add_empty_line()
-            self._generate_member_name_cc_line(member_name)
-            generate_goto_offset(member_name)
-            action = self._saved_serialization_actions[member_name]
-            c_type = self._get_ft_c_type(member.field_type)
-            self._generate_serialize_from_action(f'({c_type}) ts', '(&ctx->parent)', action)
-
-        member_name = 'content_size'
-        member = pkt_ctx_ft.members.get(member_name)
-
-        if member is not None:
-            self._cg.add_empty_line()
-            self._generate_member_name_cc_line(member_name)
-            generate_goto_offset(member_name)
-            action = self._saved_serialization_actions[member_name]
-            c_type = self._get_ft_c_type(member.field_type)
-            self._generate_serialize_from_action(f'({c_type}) ctx->parent.content_size',
-                                                 '(&ctx->parent)', action)
-
-        member_name = 'events_discarded'
-        member = pkt_ctx_ft.members.get(member_name)
-
-        if member is not None:
-            self._cg.add_empty_line()
-            self._generate_member_name_cc_line(member_name)
-            generate_goto_offset(member_name)
-            action = self._saved_serialization_actions[member_name]
-            c_type = self._get_ft_c_type(member.field_type)
-            self._generate_serialize_from_action(f'({c_type}) ctx->parent.events_discarded',
-                                                 '(&ctx->parent)', action)
-
-        self._cg.unindent()
-        tmpl = barectf_templates._FUNC_CLOSE_BODY_END
-        self._cg.add_lines(tmpl)
-
-    def generate_c_src(self, header_name, bitfield_header_name):
-        self._cg.reset()
-        dt = datetime.datetime.now().isoformat()
-        tmpl = barectf_templates._C_SRC
-        self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, header_filename=header_name,
-                                       bitfield_header_filename=bitfield_header_name,
-                                       version=barectf_version.__version__, date=dt))
-        self._cg.add_empty_line()
-
-        # initialization function
-        self._generate_func_init()
-        self._cg.add_empty_line()
-
-        for stream_type in self._trace_type.stream_types:
-            self._generate_func_open(stream_type)
-            self._cg.add_empty_line()
-            self._generate_func_close(stream_type)
-            self._cg.add_empty_line()
-            ser_actions = _SerializationActions()
-
-            if stream_type._ev_header_ft is not None:
-                ser_actions.append_root_scope_ft(stream_type._ev_header_ft, _RootFtPrefixes.SEH)
-                self._generate_func_serialize_event_header(stream_type, iter(ser_actions.actions))
-                self._cg.add_empty_line()
-
-            if stream_type.event_common_context_field_type is not None:
-                ser_action_index = len(ser_actions.actions)
-                ser_actions.append_root_scope_ft(stream_type.event_common_context_field_type,
-                                                 _RootFtPrefixes.SEC)
-                ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
-                self._generate_func_serialize_event_common_context(stream_type, ser_action_iter)
-                self._cg.add_empty_line()
-
-            for ev_type in stream_type.event_types:
-                self._generate_func_get_event_size(stream_type, ev_type)
-                self._cg.add_empty_line()
-                self._generate_func_serialize_event(stream_type, ev_type, ser_actions)
-                self._cg.add_empty_line()
-                self._generate_func_trace(stream_type, ev_type)
-                self._cg.add_empty_line()
-
-        return self._cg.code
+    # Generates the source code file contents.
+    def generate_c_src(self, header_file_name, bitfield_header_file_name):
+        # Creates and returns the operations for all the stream and for
+        # all their events.
+        def create_stream_ops():
+            stream_ser_ops = {}
+
+            for stream_type in self._trace_type.stream_types:
+                pkt_header_ser_ops = []
+                builder = _OpsBuilder(self)
+                pkt_header_ft = self._trace_type._pkt_header_ft
+
+                # packet header serialization operations
+                if pkt_header_ft is not None:
+                    spec_serialize_write_templates = {
+                        'magic': self._serialize_write_magic_statements_templ,
+                        'uuid': self._serialize_write_uuid_statements_templ,
+                        'stream_id': self._serialize_write_stream_type_id_statements_templ,
+                    }
+                    builder.append_root_ft(pkt_header_ft, _RootFtPrefixes.TPH,
+                                           spec_serialize_write_templates)
+                    pkt_header_ser_ops = copy.copy(builder.ops)
+
+                # packet context serialization operations
+                first_op_index = len(builder.ops)
+                spec_serialize_write_templates = {
+                    'timestamp_begin': self._serialize_write_time_statements_templ,
+                    'packet_size': self._serialize_write_packet_size_statements_templ,
+                    'timestamp_end': self._serialize_write_skip_save_statements_templ,
+                    'events_discarded': self._serialize_write_skip_save_statements_templ,
+                    'content_size': self._serialize_write_skip_save_statements_templ,
+                }
+                builder.append_root_ft(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC,
+                                       spec_serialize_write_templates)
+                pkt_ctx_ser_ops = copy.copy(builder.ops[first_op_index:])
+
+                # event header serialization operations
+                builder = _OpsBuilder(self)
+                ev_header_ser_ops = []
+
+                if stream_type._ev_header_ft is not None:
+                    spec_serialize_write_templates = {
+                        'timestamp': self._serialize_write_time_statements_templ,
+                        'id': self._serialize_write_ev_type_id_statements_templ,
+                    }
+                    builder.append_root_ft(stream_type._ev_header_ft, _RootFtPrefixes.SEH,
+                                           spec_serialize_write_templates)
+                    ev_header_ser_ops = copy.copy(builder.ops)
+
+                # event common context serialization operations
+                ev_common_ctx_ser_ops = []
+
+                if stream_type.event_common_context_field_type is not None:
+                    first_op_index = len(builder.ops)
+                    builder.append_root_ft(stream_type.event_common_context_field_type,
+                                           _RootFtPrefixes.SEC)
+                    ev_common_ctx_ser_ops = copy.copy(builder.ops[first_op_index:])
+
+                # serialization operations specific to each event type
+                ev_ser_ops = {}
+
+                for ev_type in stream_type.event_types:
+                    ev_builder = copy.copy(builder)
+
+                    # specific context serialization operations
+                    spec_ctx_ser_ops = []
+
+                    if ev_type.specific_context_field_type is not None:
+                        first_op_index = len(ev_builder.ops)
+                        ev_builder.append_root_ft(ev_type.specific_context_field_type,
+                                                  _RootFtPrefixes.EC)
+                        spec_ctx_ser_ops = copy.copy(ev_builder.ops[first_op_index:])
+
+                    # payload serialization operations
+                    payload_ser_ops = []
+
+                    if ev_type.payload_field_type is not None:
+                        first_op_index = len(ev_builder.ops)
+                        ev_builder.append_root_ft(ev_type.payload_field_type, _RootFtPrefixes.EP)
+                        payload_ser_ops = copy.copy(ev_builder.ops[first_op_index:])
+
+                    ev_ser_ops[ev_type] = _EventOps(spec_ctx_ser_ops, payload_ser_ops)
+
+                stream_ser_ops[stream_type] = _StreamOps(pkt_header_ser_ops, pkt_ctx_ser_ops,
+                                                         ev_header_ser_ops, ev_common_ctx_ser_ops,
+                                                         ev_ser_ops)
+
+            return stream_ser_ops
+
+        # Returns the "write" operation for the packet context member
+        # named `member_name` within the stream type `stream_type`.
+        def stream_op_pkt_ctx_op(stream_type, member_name):
+            for op in stream_ops[stream_type].pkt_ctx_ops:
+                if op.top_name == member_name and type(op) is _WriteOp:
+                    return op
+
+        stream_ops = create_stream_ops()
+        return self._create_file_template('barectf.c.j2').render(header_file_name=header_file_name,
+                                                                 bitfield_header_file_name=bitfield_header_file_name,
+                                                                 root_ft_prefixes=_RootFtPrefixes,
+                                                                 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES,
+                                                                 stream_ops=stream_ops,
+                                                                 stream_op_pkt_ctx_op=stream_op_pkt_ctx_op)
diff --git a/barectf/templates.py b/barectf/templates.py
deleted file mode 100644 (file)
index 047b7b4..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-_FUNC_INIT_PROTO = '''/* initialize context */
-void {prefix}init(
-       void *vctx,
-       uint8_t *buf,
-       uint32_t buf_size,
-       struct {prefix}platform_callbacks cbs,
-       void *data
-)'''
-
-
-_FUNC_INIT_BODY = '''{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);
-       ctx->cbs = cbs;
-       ctx->data = data;
-       ctx->buf = buf;
-       ctx->packet_size = _BYTES_TO_BITS(buf_size);
-       ctx->at = 0;
-       ctx->events_discarded = 0;
-       ctx->packet_is_open = 0;
-       ctx->in_tracing_section = 0;
-       ctx->is_tracing_enabled = 1;
-       ctx->use_cur_last_event_ts = 0;
-}}'''
-
-
-_FUNC_OPEN_PROTO_BEGIN = '''/* open packet for stream `{sname}` */
-void {prefix}{sname}_open_packet(
-       struct {prefix}{sname}_ctx *ctx'''
-
-
-_FUNC_OPEN_PROTO_END = ')'
-
-
-_FUNC_OPEN_BODY_BEGIN = '''{{
-{ts}
-       const int saved_in_tracing_section = ctx->parent.in_tracing_section;
-
-       /*
-        * This function is either called by a tracing function, or
-        * directly by the platform.
-        *
-        * If it's called by a tracing function, then
-        * ctx->parent.in_tracing_section is 1, so it's safe to open
-        * the packet here (alter the packet), even if tracing was
-        * disabled in the meantime because we're already in a tracing
-        * section (which finishes at the end of the tracing function
-        * call).
-        *
-        * If it's called directly by the platform, then if tracing is
-        * disabled, we don't want to alter the packet, and return
-        * immediately.
-        */
-       if (!ctx->parent.is_tracing_enabled && !saved_in_tracing_section) {{
-               ctx->parent.in_tracing_section = 0;
-               return;
-       }}
-
-       /* we can modify the packet */
-       ctx->parent.in_tracing_section = 1;
-'''
-
-
-_FUNC_OPEN_BODY_END = '''
-       /* save content beginning's offset */
-       ctx->parent.off_content = ctx->parent.at;
-
-       /* mark current packet as open */
-       ctx->parent.packet_is_open = 1;
-
-       /* not tracing anymore */
-       ctx->parent.in_tracing_section = saved_in_tracing_section;
-}'''
-
-
-_FUNC_CLOSE_PROTO = '''/* close packet for stream `{sname}` */
-void {prefix}{sname}_close_packet(struct {prefix}{sname}_ctx *ctx)'''
-
-
-_FUNC_CLOSE_BODY_BEGIN = '''{{
-{ts}
-       const int saved_in_tracing_section = ctx->parent.in_tracing_section;
-
-       /*
-        * This function is either called by a tracing function, or
-        * directly by the platform.
-        *
-        * If it's called by a tracing function, then
-        * ctx->parent.in_tracing_section is 1, so it's safe to close
-        * the packet here (alter the packet), even if tracing was
-        * disabled in the meantime, because we're already in a tracing
-        * section (which finishes at the end of the tracing function
-        * call).
-        *
-        * If it's called directly by the platform, then if tracing is
-        * disabled, we don't want to alter the packet, and return
-        * immediately.
-        */
-       if (!ctx->parent.is_tracing_enabled && !saved_in_tracing_section) {{
-               ctx->parent.in_tracing_section = 0;
-               return;
-       }}
-
-       /* we can modify the packet */
-       ctx->parent.in_tracing_section = 1;
-'''
-
-
-_FUNC_CLOSE_BODY_END = '''
-       /* go back to end of packet */
-       ctx->parent.at = ctx->parent.packet_size;
-
-       /* mark packet as closed */
-       ctx->parent.packet_is_open = 0;
-
-       /* not tracing anymore */
-       ctx->parent.in_tracing_section = saved_in_tracing_section;
-}'''
-
-
-_FUNC_TRACE_PROTO_BEGIN = '''/* trace (stream `{sname}`, event `{evname}`) */
-void {prefix}{sname}_trace_{evname}(
-       struct {prefix}{sname}_ctx *ctx'''
-
-
-_FUNC_TRACE_PROTO_END = ')'
-
-
-_FUNC_TRACE_BODY = '''{{
-       uint32_t ev_size;
-
-       /* save timestamp */
-       {save_ts}
-
-       if (!ctx->parent.is_tracing_enabled) {{
-               return;
-       }}
-
-       /* we can modify the packet */
-       ctx->parent.in_tracing_section = 1;
-
-       /* get event size */
-       ev_size = _get_event_size_{sname}_{evname}(TO_VOID_PTR(ctx){params});
-
-       /* do we have enough space to serialize? */
-       if (!_reserve_event_space(TO_VOID_PTR(ctx), ev_size)) {{
-               /* no: forget this */
-               ctx->parent.in_tracing_section = 0;
-               return;
-       }}
-
-       /* serialize event */
-       _serialize_event_{sname}_{evname}(TO_VOID_PTR(ctx){params});
-
-       /* commit event */
-       _commit_event(TO_VOID_PTR(ctx));
-
-       /* not tracing anymore */
-       ctx->parent.in_tracing_section = 0;
-}}'''
-
-
-_FUNC_GET_EVENT_SIZE_PROTO_BEGIN = '''static uint32_t _get_event_size_{sname}_{evname}(
-       void *vctx'''
-
-
-_FUNC_GET_EVENT_SIZE_PROTO_END = ')'
-
-
-_FUNC_GET_EVENT_SIZE_BODY_BEGIN = '''{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);
-       uint32_t at = ctx->at;'''
-
-
-_FUNC_GET_EVENT_SIZE_BODY_END = '''    return at - ctx->at;
-}'''
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_BEGIN = '''static void _serialize_stream_event_header_{sname}(
-       void *vctx,
-       uint32_t event_id'''
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END = ')'
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_BEGIN = '''{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);'''
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END = '}'
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_BEGIN = '''static void _serialize_stream_event_context_{sname}(
-       void *vctx'''
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END = ')'
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_BEGIN = '''{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);'''
-
-
-_FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END = '}'
-
-
-_FUNC_SERIALIZE_EVENT_PROTO_BEGIN = '''static void _serialize_event_{sname}_{evname}(
-       void *vctx'''
-
-
-_FUNC_SERIALIZE_EVENT_PROTO_END = ')'
-
-
-_FUNC_SERIALIZE_EVENT_BODY_BEGIN = '''{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);'''
-
-
-_FUNC_SERIALIZE_EVENT_BODY_END = '}'
-
-
-_C_SRC = '''/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- *
- * The following C code was generated by barectf {version}
- * on {date}.
- *
- * For more details, see <http://barectf.org>.
- */
-
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-
-#include "{header_filename}"
-#include "{bitfield_header_filename}"
-
-#define _ALIGN(_at, _align)                                    \\
-       do {{                                                   \\
-               (_at) = ((_at) + ((_align) - 1)) & -(_align);   \\
-       }} while (0)
-
-#ifdef __cplusplus
-# define TO_VOID_PTR(_value)           static_cast<void *>(_value)
-# define FROM_VOID_PTR(_type, _value)  static_cast<_type *>(_value)
-#else
-# define TO_VOID_PTR(_value)           ((void *) (_value))
-# define FROM_VOID_PTR(_type, _value)  ((_type *) (_value))
-#endif
-
-#define _BITS_TO_BYTES(_x)     ((_x) >> 3)
-#define _BYTES_TO_BITS(_x)     ((_x) << 3)
-
-union f2u {{
-       float f;
-       uint32_t u;
-}};
-
-union d2u {{
-       double f;
-       uint64_t u;
-}};
-
-uint32_t {prefix}packet_size(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->packet_size;
-}}
-
-int {prefix}packet_is_full(void *ctx)
-{{
-       struct {prefix}ctx *cctx = FROM_VOID_PTR(struct {prefix}ctx, ctx);
-
-       return cctx->at == cctx->packet_size;
-}}
-
-int {prefix}packet_is_empty(void *ctx)
-{{
-       struct {prefix}ctx *cctx = FROM_VOID_PTR(struct {prefix}ctx, ctx);
-
-       return cctx->at <= cctx->off_content;
-}}
-
-uint32_t {prefix}packet_events_discarded(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->events_discarded;
-}}
-
-uint8_t *{prefix}packet_buf(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->buf;
-}}
-
-uint32_t {prefix}packet_buf_size(void *ctx)
-{{
-       struct {prefix}ctx *cctx = FROM_VOID_PTR(struct {prefix}ctx, ctx);
-
-       return _BITS_TO_BYTES(cctx->packet_size);
-}}
-
-void {prefix}packet_set_buf(void *ctx, uint8_t *buf, uint32_t buf_size)
-{{
-       struct {prefix}ctx *cctx = FROM_VOID_PTR(struct {prefix}ctx, ctx);
-
-       cctx->buf = buf;
-       cctx->packet_size = _BYTES_TO_BITS(buf_size);
-}}
-
-int {prefix}packet_is_open(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->packet_is_open;
-}}
-
-int {prefix}is_in_tracing_section(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->in_tracing_section;
-}}
-
-volatile const int *{prefix}is_in_tracing_section_ptr(void *ctx)
-{{
-       return &FROM_VOID_PTR(struct {prefix}ctx, ctx)->in_tracing_section;
-}}
-
-int {prefix}is_tracing_enabled(void *ctx)
-{{
-       return FROM_VOID_PTR(struct {prefix}ctx, ctx)->is_tracing_enabled;
-}}
-
-void {prefix}enable_tracing(void *ctx, int enable)
-{{
-       FROM_VOID_PTR(struct {prefix}ctx, ctx)->is_tracing_enabled = enable;
-}}
-
-static
-void _write_cstring(struct {prefix}ctx *ctx, const char *src)
-{{
-       uint32_t sz = strlen(src) + 1;
-
-       memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], src, sz);
-       ctx->at += _BYTES_TO_BITS(sz);
-}}
-
-static
-int _reserve_event_space(void *vctx, uint32_t ev_size)
-{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);
-
-       /* event _cannot_ fit? */
-       if (ev_size > (ctx->packet_size - ctx->off_content)) {{
-               ctx->events_discarded++;
-
-               return 0;
-       }}
-
-       /* packet is full? */
-       if ({prefix}packet_is_full(ctx)) {{
-               /* yes: is back-end full? */
-               if (ctx->cbs.is_backend_full(ctx->data)) {{
-                       /* yes: discard event */
-                       ctx->events_discarded++;
-
-                       return 0;
-               }}
-
-               /* back-end is not full: open new packet */
-               ctx->use_cur_last_event_ts = 1;
-               ctx->cbs.open_packet(ctx->data);
-               ctx->use_cur_last_event_ts = 0;
-       }}
-
-       /* event fits the current packet? */
-       if (ev_size > (ctx->packet_size - ctx->at)) {{
-               /* no: close packet now */
-               ctx->use_cur_last_event_ts = 1;
-               ctx->cbs.close_packet(ctx->data);
-               ctx->use_cur_last_event_ts = 0;
-
-               /* is back-end full? */
-               if (ctx->cbs.is_backend_full(ctx->data)) {{
-                       /* yes: discard event */
-                       ctx->events_discarded++;
-
-                       return 0;
-               }}
-
-               /* back-end is not full: open new packet */
-               ctx->use_cur_last_event_ts = 1;
-               ctx->cbs.open_packet(ctx->data);
-               ctx->use_cur_last_event_ts = 0;
-               assert(ev_size <= (ctx->packet_size - ctx->at));
-       }}
-
-       return 1;
-}}
-
-static
-void _commit_event(void *vctx)
-{{
-       struct {prefix}ctx *ctx = FROM_VOID_PTR(struct {prefix}ctx, vctx);
-
-       /* is packet full? */
-       if ({prefix}packet_is_full(ctx)) {{
-               /* yes: close it now */
-               ctx->cbs.close_packet(ctx->data);
-       }}
-}}'''
diff --git a/barectf/templates/barectf.h.j2 b/barectf/templates/barectf.h.j2
deleted file mode 100644 (file)
index f19b74d..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-{% import 'common.j2' as common %}
-{% import 'c-common.j2' as c_common %}
-{% set prefix = common.prefix %}
-{% set ucprefix = common.ucprefix %}
-{% set trace_type = cfg.trace.type %}
-{% set cg_opts = cfg.options.code_generation_options %}
-{% set def_stream_type = cg_opts.default_stream_type %}
-{% set header_opts = cg_opts.header_options %}
-#ifndef _{{ ucprefix }}H
-#define _{{ ucprefix }}H
-
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- *
- * The following C code was generated by barectf v{{ barectf_version.__version__ }}
- * on {{ common.gen_date }}.
- *
- * For more details, see <https://barectf.org/>.
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-{% if header_opts.identifier_prefix_definition %}
-#define _BARECTF_PREFIX {{ prefix }}
-{% endif %}
-{% if def_stream_type and header_opts.default_stream_type_name_definition %}
-#define _BARECTF_DEFAULT_STREAM {{ def_stream_type.name }}
-{% endif %}
-{% if def_stream_type %}
-
-{% for ev_type in def_stream_type.event_types | sort %}
-#define {{ prefix }}trace_{{ ev_type.name }} {{ c_common.trace_func_name(def_stream_type, ev_type) }}
-{% endfor %}
-{% endif %}
-
-struct {{ prefix }}ctx;
-
-uint32_t {{ prefix }}packet_size(void *ctx);
-int {{ prefix }}packet_is_full(void *ctx);
-int {{ prefix }}packet_is_empty(void *ctx);
-uint32_t {{ prefix }}packet_events_discarded(void *ctx);
-uint8_t *{{ prefix }}packet_buf(void *ctx);
-void {{ prefix }}packet_set_buf(void *ctx, uint8_t *buf, uint32_t buf_size);
-uint32_t {{ prefix }}packet_buf_size(void *ctx);
-int {{ prefix }}packet_is_open(void *ctx);
-int {{ prefix }}is_in_tracing_section(void *ctx);
-volatile const int *{{ prefix }}is_in_tracing_section_ptr(void *ctx);
-int {{ prefix }}is_tracing_enabled(void *ctx);
-void {{ prefix }}enable_tracing(void *ctx, int enable);
-
-/* barectf platform callbacks */
-struct {{ prefix }}platform_callbacks {
-{% set clk_types = trace_type.clock_types %}
-{% if clk_types %}
-       /* clock callbacks */
-{% for clk_type in clk_types | sort %}
-       {{ cg_opts.clock_type_c_types[clk_type] }} (*{{ clk_type.name }}_clock_get_value)(void *);
-{% endfor %}
-
-{% endif %}
-       /* is back-end full? */
-       int (*is_backend_full)(void *);
-
-       /* open packet */
-       void (*open_packet)(void *);
-
-       /* close packet */
-       void (*close_packet)(void *);
-};
-
-/* common barectf context */
-struct {{ prefix }}ctx {
-       /* platform callbacks */
-       struct {{ prefix }}platform_callbacks cbs;
-
-       /* platform data (passed to callbacks) */
-       void *data;
-
-       /* output buffer (will contain a CTF binary packet) */
-       uint8_t *buf;
-
-       /* packet's total size (bits) */
-       uint32_t packet_size;
-
-       /* packet's content size (bits) */
-       uint32_t content_size;
-
-       /* current position from beginning of packet (bits) */
-       uint32_t at;
-
-       /* size of packet header + context fields (content offset) */
-       uint32_t off_content;
-
-       /* discarded event counter */
-       uint32_t events_discarded;
-
-       /* current packet is open? */
-       int packet_is_open;
-
-       /* in tracing code? */
-       volatile int in_tracing_section;
-
-       /* tracing is enabled? */
-       volatile int is_tracing_enabled;
-
-       /* use current/last event time when opening/closing packets */
-       int use_cur_last_event_ts;
-};
-
-{% for stream_type in trace_type.stream_types | sort %}
-/* context for stream type `{{ stream_type.name }}` */
-struct {{ prefix }}{{ stream_type.name }}_ctx {
-       /* parent */
-       struct {{ prefix }}ctx parent;
-
-       /* config-specific members follow */
-{% if trace_type._pkt_header_ft %}
-{% for member_name in trace_type._pkt_header_ft.members %}
-       uint32_t off_tph_{{ member_name }};
-{% endfor %}
-{% endif %}
-{% for member_name in stream_type._pkt_ctx_ft.members %}
-       uint32_t off_spc_{{ member_name }};
-{% endfor %}
-{% if stream_type.default_clock_type %}
-       {{ cg_opts.clock_type_c_types[stream_type.default_clock_type] }} cur_last_event_ts;
-{% endif %}
-};
-
-{% endfor %}
-{% include 'c-ctx-init-func-proto.j2' %};
-
-{% for stream_type in trace_type.stream_types | sort %}
-{% include 'c-open-func-proto.j2' %};
-
-{% include 'c-close-func-proto.j2' %};
-{% for ev_type in stream_type.event_types | sort %}
-
-{% include 'c-trace-func-proto.j2' %};
-{% endfor %}
-{% endfor %}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _{{ ucprefix }}H */
diff --git a/barectf/templates/bitfield.h.j2 b/barectf/templates/bitfield.h.j2
deleted file mode 100644 (file)
index 51ea797..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-{% import 'common.j2' as common %}
-{% set prefix = common.prefix %}
-{% set ucprefix = common.ucprefix %}
-#ifndef _{{ ucprefix }}BITFIELD_H
-#define _{{ ucprefix }}BITFIELD_H
-
-/*
- * BabelTrace
- *
- * Bitfields read/write functions.
- *
- * Copyright (c) 2010-2020 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <limits.h>
-
-#ifdef __cplusplus
-# define {{ ucprefix }}CAST_PTR(_type, _value) \
-       static_cast<_type>(static_cast<void *>(_value))
-#else
-# define {{ ucprefix }}CAST_PTR(_type, _value) ((void *) (_value))
-#endif
-
-{% set def_bo = cfg.trace.type.default_byte_order %}
-{% set def_bo_str = 'LITTLE_ENDIAN' if def_bo == barectf_config.ByteOrder.LITTLE_ENDIAN else 'BIG_ENDIAN' %}
-#define {{ ucprefix }}BYTE_ORDER {{ def_bo_str }}
-
-
-/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
-#define _{{ prefix }}bt_piecewise_rshift(_vtype, _v, _shift) \
-do {                                                                   \
-       unsigned long ___shift = (_shift);                              \
-       unsigned long sb = (___shift) / (sizeof(_v) * CHAR_BIT - 1);    \
-       unsigned long final = (___shift) % (sizeof(_v) * CHAR_BIT - 1); \
-                                                                       \
-       for (; sb; sb--)                                                \
-               _v >>= sizeof(_v) * CHAR_BIT - 1;                       \
-       _v >>= final;                                                   \
-} while (0)
-
-/*
- * {{ prefix }}bt_bitfield_write - write integer to a bitfield in native endianness
- *
- * Save integer to the bitfield, which starts at the "start" bit, has "len"
- * bits.
- * The inside of a bitfield is from high bits to low bits.
- * Uses native endianness.
- * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
- * For signed "v", sign-extend v if bitfield is larger than v.
- *
- * On little endian, bytes are placed from the less significant to the most
- * significant. Also, consecutive bitfields are placed from lower bits to higher
- * bits.
- *
- * On big endian, bytes are places from most significant to less significant.
- * Also, consecutive bitfields are placed from higher to lower bits.
- */
-
-#define _{{ prefix }}bt_bitfield_write_le(_ptr, type, _start, _length, _vtype, _v) \
-do {                                                                   \
-       _vtype __v = (_v);                                              \
-       type *__ptr = {{ ucprefix }}CAST_PTR(type *, _ptr);                     \
-       unsigned long __start = (_start), __length = (_length);         \
-       type mask, cmask;                                               \
-       unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */     \
-       unsigned long start_unit, end_unit, this_unit;                  \
-       unsigned long end, cshift; /* cshift is "complement shift" */   \
-                                                                       \
-       if (!__length)                                                  \
-               break;                                                  \
-                                                                       \
-       end = __start + __length;                                       \
-       start_unit = __start / ts;                                      \
-       end_unit = (end + (ts - 1)) / ts;                               \
-                                                                       \
-       /* Trim v high bits */                                          \
-       if (__length < sizeof(__v) * CHAR_BIT)                          \
-               __v &= ~((~(_vtype) 0) << __length);                    \
-                                                                       \
-       /* We can now append v with a simple "or", shift it piece-wise */ \
-       this_unit = start_unit;                                         \
-       if (start_unit == end_unit - 1) {                               \
-               mask = ~((~(type) 0) << (__start % ts));                \
-               if (end % ts)                                           \
-                       mask |= (~(type) 0) << (end % ts);              \
-               cmask = (type) __v << (__start % ts);                   \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-               break;                                                  \
-       }                                                               \
-       if (__start % ts) {                                             \
-               cshift = __start % ts;                                  \
-               mask = ~((~(type) 0) << cshift);                        \
-               cmask = (type) __v << cshift;                           \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts - cshift); \
-               __start += ts - cshift;                                 \
-               this_unit++;                                            \
-       }                                                               \
-       for (; this_unit < end_unit - 1; this_unit++) {                 \
-               __ptr[this_unit] = (type) __v;                          \
-               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts);              \
-               __start += ts;                                          \
-       }                                                               \
-       if (end % ts) {                                                 \
-               mask = (~(type) 0) << (end % ts);                       \
-               cmask = (type) __v;                                     \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-       } else                                                          \
-               __ptr[this_unit] = (type) __v;                          \
-} while (0)
-
-#define _{{ prefix }}bt_bitfield_write_be(_ptr, type, _start, _length, _vtype, _v) \
-do {                                                                   \
-       _vtype __v = (_v);                                              \
-       type *__ptr = {{ ucprefix }}CAST_PTR(type *, _ptr);                     \
-       unsigned long __start = (_start), __length = (_length);         \
-       type mask, cmask;                                               \
-       unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */     \
-       unsigned long start_unit, end_unit, this_unit;                  \
-       unsigned long end, cshift; /* cshift is "complement shift" */   \
-                                                                       \
-       if (!__length)                                                  \
-               break;                                                  \
-                                                                       \
-       end = __start + __length;                                       \
-       start_unit = __start / ts;                                      \
-       end_unit = (end + (ts - 1)) / ts;                               \
-                                                                       \
-       /* Trim v high bits */                                          \
-       if (__length < sizeof(__v) * CHAR_BIT)                          \
-               __v &= ~((~(_vtype) 0) << __length);                    \
-                                                                       \
-       /* We can now append v with a simple "or", shift it piece-wise */ \
-       this_unit = end_unit - 1;                                       \
-       if (start_unit == end_unit - 1) {                               \
-               mask = ~((~(type) 0) << ((ts - (end % ts)) % ts));      \
-               if (__start % ts)                                       \
-                       mask |= (~((type) 0)) << (ts - (__start % ts)); \
-               cmask = (type) __v << ((ts - (end % ts)) % ts);         \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-               break;                                                  \
-       }                                                               \
-       if (end % ts) {                                                 \
-               cshift = end % ts;                                      \
-               mask = ~((~(type) 0) << (ts - cshift));                 \
-               cmask = (type) __v << (ts - cshift);                    \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, cshift);  \
-               end -= cshift;                                          \
-               this_unit--;                                            \
-       }                                                               \
-       for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
-               __ptr[this_unit] = (type) __v;                          \
-               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts);              \
-               end -= ts;                                              \
-       }                                                               \
-       if (__start % ts) {                                             \
-               mask = (~(type) 0) << (ts - (__start % ts));            \
-               cmask = (type) __v;                                     \
-               cmask &= ~mask;                                         \
-               __ptr[this_unit] &= mask;                               \
-               __ptr[this_unit] |= cmask;                              \
-       } else                                                          \
-               __ptr[this_unit] = (type) __v;                          \
-} while (0)
-
-/*
- * {{ prefix }}bt_bitfield_write_le - write integer to a bitfield in little endian
- * {{ prefix }}bt_bitfield_write_be - write integer to a bitfield in big endian
- */
-
-#if ({{ ucprefix }}BYTE_ORDER == LITTLE_ENDIAN)
-
-#define {{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v) \
-       _{{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v)
-
-#define {{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v) \
-       _{{ prefix }}bt_bitfield_write_be(ptr, unsigned char, _start, _length, _vtype, _v)
-
-#elif ({{ ucprefix }}BYTE_ORDER == BIG_ENDIAN)
-
-#define {{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v) \
-       _{{ prefix }}bt_bitfield_write_le(ptr, unsigned char, _start, _length, _vtype, _v)
-
-#define {{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v) \
-       _{{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v)
-
-#else /* ({{ ucprefix }}BYTE_ORDER == PDP_ENDIAN) */
-
-#error "Byte order not supported"
-
-#endif
-
-#endif /* _{{ ucprefix }}BITFIELD_H */
diff --git a/barectf/templates/c-close-func-proto.j2 b/barectf/templates/c-close-func-proto.j2
deleted file mode 100644 (file)
index 848ad86..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* close packet for stream type `{{ stream_type.name }}` */
-void {{ prefix }}{{ stream_type.name }}_close_packet(struct {{ prefix }}{{ stream_type.name }}_ctx *ctx)
diff --git a/barectf/templates/c-common.j2 b/barectf/templates/c-common.j2
deleted file mode 100644 (file)
index 9f79229..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-{#
- # Common variables and macros (for C templates).
- #}
-
-{% import 'common.j2' as common %}
-
-{#
- # Generates the name of a tracing function for the stream type
- # `stream_type` and the event type `ev_type`.
- #}
-{% macro trace_func_name(stream_type, ev_type) -%}
-{{ common.prefix }}{{ stream_type.name }}_trace_{{ ev_type.name }}
-{%- endmacro %}
-
-{#
- # Generates the name of a single function parameter named `name` for
- # the field type `ft`.
- #}
-{% macro func_param(name, ft) -%}
-{{ ft | ft_c_type }} {{ name }}
-{%- endmacro %}
-
-{#
- # Generates a list of parameters for the members of a given structure
- # field type `struct_ft`.
- #
- # Each parameter has the prefix `name_prefix` and starts with an
- # immediate comma followed with a newline and a tab. For example:
- #
- #     ,
- #             const char * msg,
- #             uint32_t msg_id
- #
- # This macro does not generate a parameter line for a member name which
- # is part of `exclude_list`.
- #}
-{% macro func_params(struct_ft, name_prefix, exclude_list) -%}
-{% for name, member in struct_ft.members.items() if name not in exclude_list -%}
-,
-       {{ func_param(name_prefix + name, member.field_type) }}
-{%- endfor %}
-{%- endmacro %}
diff --git a/barectf/templates/c-ctx-init-func-proto.j2 b/barectf/templates/c-ctx-init-func-proto.j2
deleted file mode 100644 (file)
index 225e2f1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* initialize context */
-void {{ prefix }}init(
-    void *vctx,
-    uint8_t *buf,
-    uint32_t buf_size,
-    struct {{ prefix }}platform_callbacks cbs,
-    void *data)
diff --git a/barectf/templates/c-open-func-proto.j2 b/barectf/templates/c-open-func-proto.j2
deleted file mode 100644 (file)
index 630707f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{% set pkt_header_exclude_list = ['magic', 'stream_id', 'uuid'] %}
-{% set pkt_ctx_exclude_list = [
-       'timestamp_begin',
-       'timestamp_end',
-       'packet_size',
-       'content_size',
-       'events_discarded'
-] %}
-/* open packet for stream type `{{ stream_type.name }}` */
-void {{ prefix }}{{ stream_type.name }}_open_packet(
-       struct {{ prefix }}{{ stream_type.name }}_ctx *ctx
-       {%- if trace_type._pkt_header_ft -%}
-               {{ c_common.func_params(trace_type._pkt_header_ft,
-                       root_ft_prefixes.TPH, pkt_header_exclude_list) }}
-       {%- endif -%}
-    {{ c_common.func_params(stream_type._pkt_ctx_ft, root_ft_prefixes.SPC, pkt_ctx_exclude_list) }})
diff --git a/barectf/templates/c-trace-func-proto.j2 b/barectf/templates/c-trace-func-proto.j2
deleted file mode 100644 (file)
index b1bc696..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{% set ev_header_exclude_list = ['id', 'timestamp'] %}
-/* trace (stream type `{{ stream_type.name }}`, event type `{{ ev_type.name }}`) */
-void {{ prefix }}{{ stream_type.name }}_trace_{{ ev_type.name }}(
-       struct {{ prefix }}{{ stream_type.name }}_ctx *ctx
-       {%- if stream_type._ev_header_ft -%}
-               {{ c_common.func_params(stream_type._ev_header_ft,
-                       root_ft_prefixes.SEH, ev_header_exclude_list) }}
-       {%- endif -%}
-       {%- if stream_type.event_common_context_field_type -%}
-               {{ c_common.func_params(stream_type.event_common_context_field_type,
-                       root_ft_prefixes.SEC, []) }}
-       {%- endif -%}
-       {%- if ev_type.specific_context_field_type -%}
-               {{ c_common.func_params(ev_type.specific_context_field_type, root_ft_prefixes.EC, []) }}
-       {%- endif -%}
-       {%- if ev_type.payload_field_type -%}
-               {{ c_common.func_params(ev_type.payload_field_type, root_ft_prefixes.EP, []) }}
-       {%- endif -%})
diff --git a/barectf/templates/c/align-statements-comment.j2 b/barectf/templates/c/align-statements-comment.j2
new file mode 100644 (file)
index 0000000..1288321
--- /dev/null
@@ -0,0 +1,7 @@
+{% if op.names %}
+       {% if op.names | length == 1 %}
+/* align for {{ root_ft_prefix_names[op.top_name] }} structure */
+       {%- else %}
+/* align for `{{ op.top_name }}` field */
+       {%- endif %}
+{% endif %}
diff --git a/barectf/templates/c/barectf.c-macros.j2 b/barectf/templates/c/barectf.c-macros.j2
new file mode 100644 (file)
index 0000000..b189e75
--- /dev/null
@@ -0,0 +1,39 @@
+{% import 'common.j2' as common %}
+
+{% set prefix = common.prefix %}
+{% set ucprefix = common.ucprefix %}
+{% set cg_opts = cfg.options.code_generation_options %}
+
+{#
+ # Generates the preamble of the packet opening/closing functions for
+ # the stream type `stream_type`.
+ #}
+{% macro open_close_func_preamble(stream_type) %}
+struct {{ prefix }}ctx *ctx = &sctx->parent;
+{% if stream_type.default_clock_type %}
+const {{ cg_opts.clock_type_c_types[stream_type.default_clock_type] }} ts = ctx->use_cur_last_event_ts ?
+       sctx->cur_last_event_ts :
+       ctx->cbs.{{ stream_type.default_clock_type.name }}_clock_get_value(ctx->data);
+{% endif %}
+const int saved_in_tracing_section = ctx->in_tracing_section;
+{%- endmacro %}
+
+{#
+ # Generates a list of function call parameters for the members of
+ # the structure field type `ft`.
+ #
+ # Each parameter has the prefix `param_prefix`.
+ #
+ # The list always starts with a comma (if there's at least one member).
+ #
+ # Example:
+ #
+ #     , sec_peer_id, sec_addr, ep_msg_id, ep_msg
+ #}
+{% macro ft_call_params(param_prefix, ft) %}
+{% if ft %}
+       {% for member_name in ft.members %}
+, {{ param_prefix }}_{{ member_name }}
+       {%- endfor %}
+{% endif %}
+{% endmacro %}
diff --git a/barectf/templates/c/barectf.c.j2 b/barectf/templates/c/barectf.c.j2
new file mode 100644 (file)
index 0000000..2d35c92
--- /dev/null
@@ -0,0 +1,554 @@
+{% import 'common.j2' as common %}
+{% import 'c/common.j2' as c_common %}
+{% import 'c/barectf.c-macros.j2' as macros %}
+{% set prefix = common.prefix %}
+{% set ucprefix = common.ucprefix %}
+{% set ctx_struct_name = c_common.ctx_struct_name %}
+{% set cg_opts = cfg.options.code_generation_options %}
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ *
+ * The following C code was generated by barectf v{{ barectf_version.__version__ }}
+ * on {{ common.gen_date }}.
+ *
+ * For more details, see <https://barectf.org/>.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "{{ header_file_name }}"
+#include "{{ bitfield_header_file_name }}"
+
+#define _ALIGN(_at, _align)                                    \
+       do {                                                    \
+               (_at) = ((_at) + ((_align) - 1)) & -(_align);   \
+       } while (0)
+
+#ifdef __cplusplus
+# define _TO_VOID_PTR(_value)          static_cast<void *>(_value)
+# define _FROM_VOID_PTR(_type, _value) static_cast<_type *>(_value)
+#else
+# define _TO_VOID_PTR(_value)          ((void *) (_value))
+# define _FROM_VOID_PTR(_type, _value) ((_type *) (_value))
+#endif
+
+#define _BITS_TO_BYTES(_x)     ((_x) >> 3)
+#define _BYTES_TO_BITS(_x)     ((_x) << 3)
+
+union _f2u {
+       float f;
+       uint32_t u;
+};
+
+union _d2u {
+       double f;
+       uint64_t u;
+};
+
+uint32_t {{ prefix }}packet_size(void *ctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, ctx)->packet_size;
+}
+
+int {{ prefix }}packet_is_full(void *vctx)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       return ctx->at == ctx->packet_size;
+}
+
+int {{ prefix }}packet_is_empty(void *vctx)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       return ctx->at <= ctx->off_content;
+}
+
+uint32_t {{ prefix }}packet_events_discarded(void *vctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->events_discarded;
+}
+
+uint8_t *{{ prefix }}packet_buf(void *vctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->buf;
+}
+
+uint32_t {{ prefix }}packet_buf_size(void *vctx)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       return _BITS_TO_BYTES(ctx->packet_size);
+}
+
+void {{ prefix }}packet_set_buf(void *vctx, uint8_t *buf, uint32_t buf_size)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       ctx->buf = buf;
+       ctx->packet_size = _BYTES_TO_BITS(buf_size);
+}
+
+int {{ prefix }}packet_is_open(void *vctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->packet_is_open;
+}
+
+int {{ prefix }}is_in_tracing_section(void *vctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
+}
+
+volatile const int *{{ prefix }}is_in_tracing_section_ptr(void *vctx)
+{
+       return &_FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
+}
+
+int {{ prefix }}is_tracing_enabled(void *vctx)
+{
+       return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled;
+}
+
+void {{ prefix }}enable_tracing(void *vctx, int enable)
+{
+       _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled = enable;
+}
+
+static
+void _write_c_str(struct {{ ctx_struct_name }} *ctx, const char *src)
+{
+       uint32_t sz = strlen(src) + 1;
+
+       memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], src, sz);
+       ctx->at += _BYTES_TO_BITS(sz);
+}
+
+static
+int _reserve_ev_space(void *vctx, uint32_t ev_size)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       /* event _cannot_ fit? */
+       if (ev_size > (ctx->packet_size - ctx->off_content)) {
+               ctx->events_discarded++;
+               return 0;
+       }
+
+       /* packet is full? */
+       if ({{ prefix }}packet_is_full(ctx)) {
+               /* yes: is back-end full? */
+               if (ctx->cbs.is_backend_full(ctx->data)) {
+                       /* yes: discard event */
+                       ctx->events_discarded++;
+                       return 0;
+               }
+
+               /* back-end is not full: open new packet */
+               ctx->use_cur_last_event_ts = 1;
+               ctx->cbs.open_packet(ctx->data);
+               ctx->use_cur_last_event_ts = 0;
+       }
+
+       /* event fits the current packet? */
+       if (ev_size > (ctx->packet_size - ctx->at)) {
+               /* no: close packet now */
+               ctx->use_cur_last_event_ts = 1;
+               ctx->cbs.close_packet(ctx->data);
+               ctx->use_cur_last_event_ts = 0;
+
+               /* is back-end full? */
+               if (ctx->cbs.is_backend_full(ctx->data)) {
+                       /* yes: discard event */
+                       ctx->events_discarded++;
+                       return 0;
+               }
+
+               /* back-end is not full: open new packet */
+               ctx->use_cur_last_event_ts = 1;
+               ctx->cbs.open_packet(ctx->data);
+               ctx->use_cur_last_event_ts = 0;
+               assert(ev_size <= (ctx->packet_size - ctx->at));
+       }
+
+       return 1;
+}
+
+static
+void _commit_ev(void *vctx)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       /* is packet full? */
+       if ({{ prefix }}packet_is_full(ctx)) {
+               /* yes: close it now */
+               ctx->cbs.close_packet(ctx->data);
+       }
+}
+
+{% include 'c/ctx-init-func-proto.j2' %}
+
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+       ctx->cbs = cbs;
+       ctx->data = data;
+       ctx->buf = buf;
+       ctx->packet_size = _BYTES_TO_BITS(buf_size);
+       ctx->at = 0;
+       ctx->events_discarded = 0;
+       ctx->packet_is_open = 0;
+       ctx->in_tracing_section = 0;
+       ctx->is_tracing_enabled = 1;
+       ctx->use_cur_last_event_ts = 0;
+}
+
+{% for stream_type in cfg.trace.type.stream_types | sort %}
+       {% set def_clk_type = stream_type.default_clock_type %}
+       {% set sctx_name %}{{ prefix }}{{ stream_type.name }}{% endset %}
+       {% set this_stream_ops = stream_ops[stream_type] %}
+       {% include 'c/open-func-proto.j2' %}
+
+{
+       {{ macros.open_close_func_preamble(stream_type) | indent_tab }}
+
+       /*
+        * This function is either called by a tracing function, or
+        * directly by the platform.
+        *
+        * If it's called by a tracing function, then
+        * `ctx->in_tracing_section` is 1, so it's safe to open
+        * the packet here (alter the packet), even if tracing was
+        * disabled in the meantime because we're already in a tracing
+        * section (which finishes at the end of the tracing function
+        * call).
+        *
+        * If it's called directly by the platform, then if tracing is
+        * disabled, we don't want to alter the packet, and return
+        * immediately.
+        */
+       if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
+               ctx->in_tracing_section = 0;
+               return;
+       }
+
+       /* we can alter the packet */
+       ctx->in_tracing_section = 1;
+
+       /* do not open a packet that is already open */
+       if (ctx->packet_is_open) {
+               ctx->in_tracing_section = saved_in_tracing_section;
+               return;
+       }
+
+       ctx->at = 0;
+       {% set pkt_header_ops = this_stream_ops.pkt_header_ops %}
+       {% if pkt_header_ops %}
+
+       /* serialize packet header */
+       {
+               {% for op in pkt_header_ops %}
+               {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }}
+
+               {% endfor %}
+       }
+       {% endif %}
+
+       /* serialize packet context */
+       {
+       {% for op in this_stream_ops.pkt_ctx_ops %}
+               {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }}
+
+       {% endfor %}
+       }
+
+       /* save content beginning's offset */
+       ctx->off_content = ctx->at;
+
+       /* mark current packet as open */
+       ctx->packet_is_open = 1;
+
+       /* not tracing anymore */
+       ctx->in_tracing_section = saved_in_tracing_section;
+}
+
+       {% include 'c/close-func-proto.j2' %}
+
+{
+       {{ macros.open_close_func_preamble(stream_type) | indent_tab }}
+
+       /*
+        * This function is either called by a tracing function, or
+        * directly by the platform.
+        *
+        * If it's called by a tracing function, then
+        * `ctx->in_tracing_section` is 1, so it's safe to close
+        * the packet here (alter the packet), even if tracing was
+        * disabled in the meantime, because we're already in a tracing
+        * section (which finishes at the end of the tracing function
+        * call).
+        *
+        * If it's called directly by the platform, then if tracing is
+        * disabled, we don't want to alter the packet, and return
+        * immediately.
+        */
+       if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
+               ctx->in_tracing_section = 0;
+               return;
+       }
+
+       /* we can alter the packet */
+       ctx->in_tracing_section = 1;
+
+       /* do not close a packet that is not open */
+       if (!ctx->packet_is_open) {
+               ctx->in_tracing_section = saved_in_tracing_section;
+               return;
+       }
+
+       /* save content size */
+       ctx->content_size = ctx->at;
+       {% if 'timestamp_end' in stream_type._pkt_ctx_ft.members %}
+               {% set op = stream_op_pkt_ctx_op(stream_type, 'timestamp_end') %}
+
+       /* go back to `timestamp_end` field offset */
+       ctx->at = sctx->off_{{ c_common.op_src(op) }};
+
+               {% set src = 'ts' %}
+               {% filter indent_tab(indent_first=True) %}
+                       {% include 'c/serialize-write-saved-int-statements.j2' %}
+
+               {% endfilter %}
+       {% endif %}
+       {% if 'content_size' in stream_type._pkt_ctx_ft.members %}
+               {% set op = stream_op_pkt_ctx_op(stream_type, 'content_size') %}
+
+       /* go back to `content_size` field offset */
+       ctx->at = sctx->off_{{ c_common.op_src(op) }};
+
+               {% set src = 'ctx->content_size' %}
+               {% filter indent_tab(indent_first=True) %}
+                       {% include 'c/serialize-write-saved-int-statements.j2' %}
+
+               {% endfilter %}
+       {% endif %}
+       {% if 'events_discarded' in stream_type._pkt_ctx_ft.members %}
+               {% set op = stream_op_pkt_ctx_op(stream_type, 'events_discarded') %}
+
+       /* go back to `events_discarded` field offset */
+       ctx->at = sctx->off_{{ c_common.op_src(op) }};
+
+               {% set src = 'ctx->events_discarded' %}
+               {% filter indent_tab(indent_first=True) %}
+                       {% include 'c/serialize-write-saved-int-statements.j2' %}
+
+               {% endfilter %}
+       {% endif %}
+
+       /* go back to end of packet */
+       ctx->at = ctx->packet_size;
+
+       /* mark packet as closed */
+       ctx->packet_is_open = 0;
+
+       /* not tracing anymore */
+       ctx->in_tracing_section = saved_in_tracing_section;
+}
+       {% if stream_type._ev_header_ft %}
+
+static void _serialize_ev_header_{{ stream_type.name }}(void *vctx,
+       uint32_t ev_type_id)
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+               {% if def_clk_type %}
+       struct {{ sctx_name }}_ctx *sctx = _FROM_VOID_PTR(struct {{ sctx_name }}_ctx, vctx);
+       const {{ cg_opts.clock_type_c_types[def_clk_type] }} ts = sctx->cur_last_event_ts;
+               {% endif %}
+
+       /* serialize event header */
+       {
+               {% for op in this_stream_ops.ev_header_ops %}
+               {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }}
+
+               {% endfor %}
+       }
+}
+       {% endif %}
+       {% if stream_type.event_common_context_field_type %}
+
+static void _serialize_ev_common_ctx_{{ stream_type.name }}(void *vctx{{ stream_type | serialize_ev_common_ctx_func_params_str }})
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+
+       /* serialize event common context */
+       {
+               {% for op in this_stream_ops.ev_common_ctx_ops %}
+               {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }}
+
+               {% endfor %}
+       }
+}
+       {% endif %}
+       {# internal serialization functions #}
+       {% for ev_type in stream_type.event_types | sort %}
+
+static void _serialize_ev_{{ stream_type.name }}_{{ ev_type.name }}(void *vctx{{ (stream_type, ev_type) | trace_func_params_str }})
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+               {% if stream_type._ev_header_ft %}
+
+       /* serialize header */
+       _serialize_ev_header_{{ stream_type.name }}(ctx, {{ ev_type.id }});
+               {% endif %}
+               {% if stream_type.event_common_context_field_type %}
+
+       /* serialize common context */
+                       {% set params = macros.ft_call_params(root_ft_prefixes.SEC, stream_type.event_common_context_field_type) %}
+       _serialize_ev_common_ctx_{{ stream_type.name }}(ctx{{ params }});
+               {% endif %}
+               {% set this_ev_ops = this_stream_ops.ev_ops[ev_type] %}
+               {% if this_ev_ops.spec_ctx_ops %}
+
+       /* serialize specific context */
+       {
+                       {% for op in this_ev_ops.spec_ctx_ops %}
+               {{ op.serialize_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+               {% if this_ev_ops.payload_ops %}
+
+       /* serialize payload */
+       {
+                       {% for op in this_ev_ops.payload_ops %}
+               {{ op.serialize_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+}
+       {% endfor %}
+       {# internal size functions #}
+       {% for ev_type in stream_type.event_types | sort %}
+               {% set this_ev_ops = this_stream_ops.ev_ops[ev_type] %}
+
+static uint32_t _ev_size_{{ stream_type.name }}_{{ ev_type.name }}(void *vctx{{ (stream_type, ev_type) | trace_func_params_str }})
+{
+       struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
+       uint32_t at = ctx->at;
+               {% if this_stream_ops.ev_header_ops %}
+
+       /* add header size */
+       {
+                       {% for op in this_stream_ops.ev_header_ops %}
+               {{ op.size_str(stream_type=stream_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+               {% if this_stream_ops.ev_common_ctx_ops %}
+
+       /* add common context size */
+       {
+                       {% for op in this_stream_ops.ev_common_ctx_ops %}
+               {{ op.size_str(stream_type=stream_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+               {% if this_ev_ops.spec_ctx_ops %}
+
+       /* add specific context size */
+       {
+                       {% for op in this_ev_ops.spec_ctx_ops %}
+               {{ op.size_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+               {% if this_ev_ops.payload_ops %}
+
+       /* add payload size */
+       {
+                       {% for op in this_ev_ops.payload_ops %}
+               {{ op.size_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }}
+
+                       {% endfor %}
+       }
+               {% endif %}
+
+       return at - ctx->at;
+}
+       {% endfor %}
+       {# public tracing functions #}
+       {% for ev_type in stream_type.event_types | sort %}
+
+               {% include 'c/trace-func-proto.j2' %}
+
+{
+       struct {{ ctx_struct_name }} *ctx = &sctx->parent;
+       uint32_t ev_size;
+
+               {% if def_clk_type %}
+       /* save time */
+       sctx->cur_last_event_ts = ctx->cbs.{{ def_clk_type.name }}_clock_get_value(ctx->data);
+
+               {% endif %}
+
+       if (!ctx->is_tracing_enabled) {
+               return;
+       }
+
+       /* we can alter the packet */
+       ctx->in_tracing_section = 1;
+
+       /* compute event size */
+               {% set ev_common_ctx_params = macros.ft_call_params(root_ft_prefixes.SEC, stream_type.event_common_context_field_type) %}
+               {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.EC, ev_type.specific_context_field_type) %}
+               {% set payload_params = macros.ft_call_params(root_ft_prefixes.EP, ev_type.payload_field_type) %}
+               {% set params %}{{ ev_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %}
+       ev_size = _ev_size_{{ stream_type.name }}_{{ ev_type.name }}(_TO_VOID_PTR(ctx){{ params }});
+
+       /* do we have enough space to serialize? */
+       if (!_reserve_ev_space(_TO_VOID_PTR(ctx), ev_size)) {
+               /* no: forget this */
+               ctx->in_tracing_section = 0;
+               return;
+       }
+
+       /* serialize event */
+       _serialize_ev_{{ stream_type.name }}_{{ ev_type.name }}(_TO_VOID_PTR(ctx){{ params }});
+
+       /* commit event */
+       _commit_ev(_TO_VOID_PTR(ctx));
+
+       /* not tracing anymore */
+       ctx->in_tracing_section = 0;
+}
+       {% endfor %}
+{% endfor %}
diff --git a/barectf/templates/c/barectf.h.j2 b/barectf/templates/c/barectf.h.j2
new file mode 100644 (file)
index 0000000..c2b7bbb
--- /dev/null
@@ -0,0 +1,175 @@
+{% import 'common.j2' as common %}
+{% import 'c/common.j2' as c_common %}
+{% set prefix = common.prefix %}
+{% set ucprefix = common.ucprefix %}
+{% set trace_type = cfg.trace.type %}
+{% set cg_opts = cfg.options.code_generation_options %}
+{% set def_stream_type = cg_opts.default_stream_type %}
+{% set header_opts = cg_opts.header_options %}
+#ifndef _{{ ucprefix }}H
+#define _{{ ucprefix }}H
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ *
+ * The following C code was generated by barectf v{{ barectf_version.__version__ }}
+ * on {{ common.gen_date }}.
+ *
+ * For more details, see <https://barectf.org/>.
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+{% if header_opts.identifier_prefix_definition %}
+#define _BARECTF_PREFIX {{ prefix }}
+{% endif %}
+{% if def_stream_type and header_opts.default_stream_type_name_definition %}
+#define _BARECTF_DEFAULT_STREAM {{ def_stream_type.name }}
+{% endif %}
+{% if def_stream_type %}
+
+       {% for ev_type in def_stream_type.event_types | sort %}
+#define {{ prefix }}trace_{{ ev_type.name }} {{ c_common.trace_func_name(def_stream_type, ev_type) }}
+       {% endfor %}
+{% endif %}
+
+struct {{ prefix }}ctx;
+
+uint32_t {{ prefix }}packet_size(void *ctx);
+int {{ prefix }}packet_is_full(void *ctx);
+int {{ prefix }}packet_is_empty(void *ctx);
+uint32_t {{ prefix }}packet_events_discarded(void *ctx);
+uint8_t *{{ prefix }}packet_buf(void *ctx);
+void {{ prefix }}packet_set_buf(void *ctx, uint8_t *buf, uint32_t buf_size);
+uint32_t {{ prefix }}packet_buf_size(void *ctx);
+int {{ prefix }}packet_is_open(void *ctx);
+int {{ prefix }}is_in_tracing_section(void *ctx);
+volatile const int *{{ prefix }}is_in_tracing_section_ptr(void *ctx);
+int {{ prefix }}is_tracing_enabled(void *ctx);
+void {{ prefix }}enable_tracing(void *ctx, int enable);
+
+/* barectf platform callbacks */
+struct {{ prefix }}platform_callbacks {
+{% set clk_types = trace_type.clock_types %}
+{% if clk_types %}
+       /* clock callbacks */
+       {% for clk_type in clk_types | sort %}
+       {{ cg_opts.clock_type_c_types[clk_type] }} (*{{ clk_type.name }}_clock_get_value)(void *);
+       {% endfor %}
+
+{% endif %}
+       /* is back-end full? */
+       int (*is_backend_full)(void *);
+
+       /* open packet */
+       void (*open_packet)(void *);
+
+       /* close packet */
+       void (*close_packet)(void *);
+};
+
+/* common barectf context */
+struct {{ prefix }}ctx {
+       /* platform callbacks */
+       struct {{ prefix }}platform_callbacks cbs;
+
+       /* platform data (passed to callbacks) */
+       void *data;
+
+       /* output buffer (will contain a CTF binary packet) */
+       uint8_t *buf;
+
+       /* packet's total size (bits) */
+       uint32_t packet_size;
+
+       /* packet's content size (bits) */
+       uint32_t content_size;
+
+       /* current position from beginning of packet (bits) */
+       uint32_t at;
+
+       /* size of packet header + context fields (content offset) */
+       uint32_t off_content;
+
+       /* discarded event counter */
+       uint32_t events_discarded;
+
+       /* current packet is open? */
+       int packet_is_open;
+
+       /* in tracing code? */
+       volatile int in_tracing_section;
+
+       /* tracing is enabled? */
+       volatile int is_tracing_enabled;
+
+       /* use current/last event time when opening/closing packets */
+       int use_cur_last_event_ts;
+};
+
+{% for stream_type in trace_type.stream_types | sort %}
+/* context for stream type `{{ stream_type.name }}` */
+struct {{ prefix }}{{ stream_type.name }}_ctx {
+       /* parent */
+       struct {{ prefix }}ctx parent;
+
+       /* config-specific members follow */
+       {% if trace_type._pkt_header_ft %}
+               {% for member_name in trace_type._pkt_header_ft.members %}
+       uint32_t off_tph_{{ member_name }};
+               {% endfor %}
+       {% endif %}
+       {% for member_name in stream_type._pkt_ctx_ft.members %}
+       uint32_t off_spc_{{ member_name }};
+       {% endfor %}
+       {% if stream_type.default_clock_type %}
+       {{ cg_opts.clock_type_c_types[stream_type.default_clock_type] }} cur_last_event_ts;
+       {% endif %}
+};
+
+{% endfor %}
+{% include 'c/ctx-init-func-proto.j2' %};
+
+{% for stream_type in trace_type.stream_types | sort %}
+       {% include 'c/open-func-proto.j2' %};
+
+       {% include 'c/close-func-proto.j2' %};
+       {% for ev_type in stream_type.event_types | sort %}
+
+               {% include 'c/trace-func-proto.j2' %};
+       {% endfor %}
+{% endfor %}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _{{ ucprefix }}H */
diff --git a/barectf/templates/c/bitfield.h.j2 b/barectf/templates/c/bitfield.h.j2
new file mode 100644 (file)
index 0000000..51ea797
--- /dev/null
@@ -0,0 +1,224 @@
+{% import 'common.j2' as common %}
+{% set prefix = common.prefix %}
+{% set ucprefix = common.ucprefix %}
+#ifndef _{{ ucprefix }}BITFIELD_H
+#define _{{ ucprefix }}BITFIELD_H
+
+/*
+ * BabelTrace
+ *
+ * Bitfields read/write functions.
+ *
+ * Copyright (c) 2010-2020 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <limits.h>
+
+#ifdef __cplusplus
+# define {{ ucprefix }}CAST_PTR(_type, _value) \
+       static_cast<_type>(static_cast<void *>(_value))
+#else
+# define {{ ucprefix }}CAST_PTR(_type, _value) ((void *) (_value))
+#endif
+
+{% set def_bo = cfg.trace.type.default_byte_order %}
+{% set def_bo_str = 'LITTLE_ENDIAN' if def_bo == barectf_config.ByteOrder.LITTLE_ENDIAN else 'BIG_ENDIAN' %}
+#define {{ ucprefix }}BYTE_ORDER {{ def_bo_str }}
+
+
+/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
+#define _{{ prefix }}bt_piecewise_rshift(_vtype, _v, _shift) \
+do {                                                                   \
+       unsigned long ___shift = (_shift);                              \
+       unsigned long sb = (___shift) / (sizeof(_v) * CHAR_BIT - 1);    \
+       unsigned long final = (___shift) % (sizeof(_v) * CHAR_BIT - 1); \
+                                                                       \
+       for (; sb; sb--)                                                \
+               _v >>= sizeof(_v) * CHAR_BIT - 1;                       \
+       _v >>= final;                                                   \
+} while (0)
+
+/*
+ * {{ prefix }}bt_bitfield_write - write integer to a bitfield in native endianness
+ *
+ * Save integer to the bitfield, which starts at the "start" bit, has "len"
+ * bits.
+ * The inside of a bitfield is from high bits to low bits.
+ * Uses native endianness.
+ * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
+ * For signed "v", sign-extend v if bitfield is larger than v.
+ *
+ * On little endian, bytes are placed from the less significant to the most
+ * significant. Also, consecutive bitfields are placed from lower bits to higher
+ * bits.
+ *
+ * On big endian, bytes are places from most significant to less significant.
+ * Also, consecutive bitfields are placed from higher to lower bits.
+ */
+
+#define _{{ prefix }}bt_bitfield_write_le(_ptr, type, _start, _length, _vtype, _v) \
+do {                                                                   \
+       _vtype __v = (_v);                                              \
+       type *__ptr = {{ ucprefix }}CAST_PTR(type *, _ptr);                     \
+       unsigned long __start = (_start), __length = (_length);         \
+       type mask, cmask;                                               \
+       unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */     \
+       unsigned long start_unit, end_unit, this_unit;                  \
+       unsigned long end, cshift; /* cshift is "complement shift" */   \
+                                                                       \
+       if (!__length)                                                  \
+               break;                                                  \
+                                                                       \
+       end = __start + __length;                                       \
+       start_unit = __start / ts;                                      \
+       end_unit = (end + (ts - 1)) / ts;                               \
+                                                                       \
+       /* Trim v high bits */                                          \
+       if (__length < sizeof(__v) * CHAR_BIT)                          \
+               __v &= ~((~(_vtype) 0) << __length);                    \
+                                                                       \
+       /* We can now append v with a simple "or", shift it piece-wise */ \
+       this_unit = start_unit;                                         \
+       if (start_unit == end_unit - 1) {                               \
+               mask = ~((~(type) 0) << (__start % ts));                \
+               if (end % ts)                                           \
+                       mask |= (~(type) 0) << (end % ts);              \
+               cmask = (type) __v << (__start % ts);                   \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+               break;                                                  \
+       }                                                               \
+       if (__start % ts) {                                             \
+               cshift = __start % ts;                                  \
+               mask = ~((~(type) 0) << cshift);                        \
+               cmask = (type) __v << cshift;                           \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts - cshift); \
+               __start += ts - cshift;                                 \
+               this_unit++;                                            \
+       }                                                               \
+       for (; this_unit < end_unit - 1; this_unit++) {                 \
+               __ptr[this_unit] = (type) __v;                          \
+               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts);              \
+               __start += ts;                                          \
+       }                                                               \
+       if (end % ts) {                                                 \
+               mask = (~(type) 0) << (end % ts);                       \
+               cmask = (type) __v;                                     \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+       } else                                                          \
+               __ptr[this_unit] = (type) __v;                          \
+} while (0)
+
+#define _{{ prefix }}bt_bitfield_write_be(_ptr, type, _start, _length, _vtype, _v) \
+do {                                                                   \
+       _vtype __v = (_v);                                              \
+       type *__ptr = {{ ucprefix }}CAST_PTR(type *, _ptr);                     \
+       unsigned long __start = (_start), __length = (_length);         \
+       type mask, cmask;                                               \
+       unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */     \
+       unsigned long start_unit, end_unit, this_unit;                  \
+       unsigned long end, cshift; /* cshift is "complement shift" */   \
+                                                                       \
+       if (!__length)                                                  \
+               break;                                                  \
+                                                                       \
+       end = __start + __length;                                       \
+       start_unit = __start / ts;                                      \
+       end_unit = (end + (ts - 1)) / ts;                               \
+                                                                       \
+       /* Trim v high bits */                                          \
+       if (__length < sizeof(__v) * CHAR_BIT)                          \
+               __v &= ~((~(_vtype) 0) << __length);                    \
+                                                                       \
+       /* We can now append v with a simple "or", shift it piece-wise */ \
+       this_unit = end_unit - 1;                                       \
+       if (start_unit == end_unit - 1) {                               \
+               mask = ~((~(type) 0) << ((ts - (end % ts)) % ts));      \
+               if (__start % ts)                                       \
+                       mask |= (~((type) 0)) << (ts - (__start % ts)); \
+               cmask = (type) __v << ((ts - (end % ts)) % ts);         \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+               break;                                                  \
+       }                                                               \
+       if (end % ts) {                                                 \
+               cshift = end % ts;                                      \
+               mask = ~((~(type) 0) << (ts - cshift));                 \
+               cmask = (type) __v << (ts - cshift);                    \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, cshift);  \
+               end -= cshift;                                          \
+               this_unit--;                                            \
+       }                                                               \
+       for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
+               __ptr[this_unit] = (type) __v;                          \
+               _{{ prefix }}bt_piecewise_rshift(_vtype, __v, ts);              \
+               end -= ts;                                              \
+       }                                                               \
+       if (__start % ts) {                                             \
+               mask = (~(type) 0) << (ts - (__start % ts));            \
+               cmask = (type) __v;                                     \
+               cmask &= ~mask;                                         \
+               __ptr[this_unit] &= mask;                               \
+               __ptr[this_unit] |= cmask;                              \
+       } else                                                          \
+               __ptr[this_unit] = (type) __v;                          \
+} while (0)
+
+/*
+ * {{ prefix }}bt_bitfield_write_le - write integer to a bitfield in little endian
+ * {{ prefix }}bt_bitfield_write_be - write integer to a bitfield in big endian
+ */
+
+#if ({{ ucprefix }}BYTE_ORDER == LITTLE_ENDIAN)
+
+#define {{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v) \
+       _{{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v)
+
+#define {{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v) \
+       _{{ prefix }}bt_bitfield_write_be(ptr, unsigned char, _start, _length, _vtype, _v)
+
+#elif ({{ ucprefix }}BYTE_ORDER == BIG_ENDIAN)
+
+#define {{ prefix }}bt_bitfield_write_le(ptr, type, _start, _length, _vtype, _v) \
+       _{{ prefix }}bt_bitfield_write_le(ptr, unsigned char, _start, _length, _vtype, _v)
+
+#define {{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v) \
+       _{{ prefix }}bt_bitfield_write_be(ptr, type, _start, _length, _vtype, _v)
+
+#else /* ({{ ucprefix }}BYTE_ORDER == PDP_ENDIAN) */
+
+#error "Byte order not supported"
+
+#endif
+
+#endif /* _{{ ucprefix }}BITFIELD_H */
diff --git a/barectf/templates/c/close-func-proto.j2 b/barectf/templates/c/close-func-proto.j2
new file mode 100644 (file)
index 0000000..9ee497a
--- /dev/null
@@ -0,0 +1,3 @@
+{% import 'common.j2' as common %}
+/* close packet for stream type `{{ stream_type.name }}` */
+void {{ common.prefix }}{{ stream_type.name }}_close_packet(struct {{ common.prefix }}{{ stream_type.name }}_ctx *sctx)
diff --git a/barectf/templates/c/common.j2 b/barectf/templates/c/common.j2
new file mode 100644 (file)
index 0000000..10f064e
--- /dev/null
@@ -0,0 +1,32 @@
+{#
+ # Common variables and macros (for C templates).
+ #}
+
+{% import 'common.j2' as common %}
+
+{# generic barectf context structure name #}
+{% set ctx_struct_name %}{{ common.prefix }}ctx{% endset %}
+
+{#
+ # Generates the name of a tracing function for the stream type
+ # `stream_type` and the event type `ev_type`.
+ #
+ # Example:
+ #
+ #     barectf_my_stream_trace_my_event
+ #}
+{% macro trace_func_name(stream_type, ev_type) %}
+{{ common.prefix }}{{ stream_type.name }}_trace_{{ ev_type.name }}
+{%- endmacro %}
+
+{#
+ # Generates the name of a source variable from the names of the
+ # operation `op`.
+ #
+ # Example:
+ #
+ #     ep_msg_id
+ #}
+{% macro op_src(op) %}
+{{ op.names | join('_') }}
+{%- endmacro %}
diff --git a/barectf/templates/c/ctx-init-func-proto.j2 b/barectf/templates/c/ctx-init-func-proto.j2
new file mode 100644 (file)
index 0000000..87082bc
--- /dev/null
@@ -0,0 +1,5 @@
+{% import 'common.j2' as common %}
+/* initialize context */
+void {{ common.prefix }}init(void *vctx,
+       uint8_t *buf, uint32_t buf_size,
+       struct {{ common.prefix }}platform_callbacks cbs, void *data)
diff --git a/barectf/templates/c/func-proto-params.j2 b/barectf/templates/c/func-proto-params.j2
new file mode 100644 (file)
index 0000000..af1ad4b
--- /dev/null
@@ -0,0 +1,4 @@
+{% for param in params %}
+    {% set c_type = param.ft | ft_c_type %},
+       {{ c_type }}{{ ' ' if not c_type.endswith('*') }}{{ prefix }}_{{ param.name }}
+{%- endfor %}
diff --git a/barectf/templates/c/open-func-proto.j2 b/barectf/templates/c/open-func-proto.j2
new file mode 100644 (file)
index 0000000..05fda9a
--- /dev/null
@@ -0,0 +1,4 @@
+{% import 'common.j2' as common %}
+/* open packet for stream type `{{ stream_type.name }}` */
+void {{ common.prefix }}{{ stream_type.name }}_open_packet(
+       struct {{ common.prefix }}{{ stream_type.name }}_ctx *sctx{{ stream_type | open_func_params_str }})
diff --git a/barectf/templates/c/serialize-align-statements.j2 b/barectf/templates/c/serialize-align-statements.j2
new file mode 100644 (file)
index 0000000..9f812cc
--- /dev/null
@@ -0,0 +1,3 @@
+{% include 'c/align-statements-comment.j2' %}
+
+_ALIGN(ctx->at, {{ op.value }});
diff --git a/barectf/templates/c/serialize-write-bit-array-statements.j2 b/barectf/templates/c/serialize-write-bit-array-statements.j2
new file mode 100644 (file)
index 0000000..6562e58
--- /dev/null
@@ -0,0 +1,6 @@
+{% import 'common.j2' as common %}
+{% set bo = 'le' if op.ft.byte_order == barectf_config.ByteOrder.LITTLE_ENDIAN else 'be' %}
+{{ common.prefix }}bt_bitfield_write_{{ bo }}(&ctx->buf[_BITS_TO_BYTES(ctx->at)],
+       uint8_t, {{ op.offset_in_byte }}, {{ op.ft.size }}, {{ c_type }},
+       ({{ c_type }}) {{ src }});
+ctx->at += {{ op.ft.size }};
diff --git a/barectf/templates/c/serialize-write-ev-type-id-statements.j2 b/barectf/templates/c/serialize-write-ev-type-id-statements.j2
new file mode 100644 (file)
index 0000000..2266335
--- /dev/null
@@ -0,0 +1,4 @@
+{% set c_type = op.ft | ft_c_type %}
+{% set src = 'ev_type_id' %}
+/* write event type ID field */
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-int-statements.j2 b/barectf/templates/c/serialize-write-int-statements.j2
new file mode 100644 (file)
index 0000000..98701a6
--- /dev/null
@@ -0,0 +1,6 @@
+{% import 'c/common.j2' as c_common %}
+{% set c_type = op.ft | ft_c_type %}
+{% set src = c_common.op_src(op) %}
+{% include 'c/serialize-write-statements-comment.j2' %}
+
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-magic-statements.j2 b/barectf/templates/c/serialize-write-magic-statements.j2
new file mode 100644 (file)
index 0000000..581eaa5
--- /dev/null
@@ -0,0 +1,4 @@
+{% set c_type = op.ft | ft_c_type %}
+{% set src = '0xc1fc1fc1UL' %}
+/* write magic number field */
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-packet-size-statements.j2 b/barectf/templates/c/serialize-write-packet-size-statements.j2
new file mode 100644 (file)
index 0000000..63894f5
--- /dev/null
@@ -0,0 +1,4 @@
+{% set c_type = op.ft | ft_c_type %}
+{% set src = 'ctx->packet_size' %}
+/* write packet total size field */
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-real-statements.j2 b/barectf/templates/c/serialize-write-real-statements.j2
new file mode 100644 (file)
index 0000000..30fd9d4
--- /dev/null
@@ -0,0 +1,15 @@
+{% import 'c/common.j2' as c_common %}
+{% set union_name = 'f2u' if op.ft.size == 32 else 'd2u' %}
+{% set c_type = 'uint32_t' if op.ft.size == 32 else 'uint64_t' %}
+{% set src %}{{ union_name }}.u{% endset %}
+{% include 'c/serialize-write-statements-comment.j2' %}
+
+{
+       union _{{ union_name }} {{ union_name }};
+
+       {{ union_name }}.f = {{ c_common.op_src(op) }};
+{% filter indent_tab(indent_first=True) %}
+       {% include 'c/serialize-write-bit-array-statements.j2' %}
+
+{% endfilter %}
+}
diff --git a/barectf/templates/c/serialize-write-saved-int-statements.j2 b/barectf/templates/c/serialize-write-saved-int-statements.j2
new file mode 100644 (file)
index 0000000..e0afd43
--- /dev/null
@@ -0,0 +1,5 @@
+{% import 'c/common.j2' as c_common %}
+{% set c_type = op.ft | ft_c_type %}
+{% include 'c/serialize-write-statements-comment.j2' %}
+
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-skip-save-statements.j2 b/barectf/templates/c/serialize-write-skip-save-statements.j2
new file mode 100644 (file)
index 0000000..0071533
--- /dev/null
@@ -0,0 +1,4 @@
+{% import 'c/common.j2' as c_common %}
+/* do not write `{{ op.top_name }}` field; save its offset */
+sctx->off_{{ c_common.op_src(op) }} = ctx->at;
+ctx->at += {{ op.ft.size }};
diff --git a/barectf/templates/c/serialize-write-statements-comment.j2 b/barectf/templates/c/serialize-write-statements-comment.j2
new file mode 100644 (file)
index 0000000..9a0a4e3
--- /dev/null
@@ -0,0 +1 @@
+/* write `{{ op.top_name }}` field */
diff --git a/barectf/templates/c/serialize-write-stream-type-id-statements.j2 b/barectf/templates/c/serialize-write-stream-type-id-statements.j2
new file mode 100644 (file)
index 0000000..f3732b2
--- /dev/null
@@ -0,0 +1,4 @@
+{% set c_type = op.ft | ft_c_type %}
+{% set src = stream_type.id %}
+/* write stream type ID field */
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-string-statements.j2 b/barectf/templates/c/serialize-write-string-statements.j2
new file mode 100644 (file)
index 0000000..1da8d67
--- /dev/null
@@ -0,0 +1,4 @@
+{% import 'c/common.j2' as c_common %}
+{% include 'c/serialize-write-statements-comment.j2' %}
+
+_write_c_str(ctx, {{ c_common.op_src(op) }});
diff --git a/barectf/templates/c/serialize-write-time-statements.j2 b/barectf/templates/c/serialize-write-time-statements.j2
new file mode 100644 (file)
index 0000000..004640f
--- /dev/null
@@ -0,0 +1,4 @@
+{% set c_type = op.ft | ft_c_type %}
+{% set src = 'ts' %}
+/* write {{ 'beginning ' if op.top_name == 'timestamp_begin' }}time field */
+{% include 'c/serialize-write-bit-array-statements.j2' %}
diff --git a/barectf/templates/c/serialize-write-uuid-statements.j2 b/barectf/templates/c/serialize-write-uuid-statements.j2
new file mode 100644 (file)
index 0000000..26d09fc
--- /dev/null
@@ -0,0 +1,12 @@
+/* write UUID */
+{
+       static uint8_t uuid[] = {
+{% for row in cfg.trace.type.uuid.bytes | batch(4) %}
+               {{ row | join(', ') }},
+{% endfor %}
+       };
+
+       _ALIGN(ctx->at, 8);
+       memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], uuid, 16);
+       ctx->at += _BYTES_TO_BITS(16);
+}
diff --git a/barectf/templates/c/size-align-statements.j2 b/barectf/templates/c/size-align-statements.j2
new file mode 100644 (file)
index 0000000..102b714
--- /dev/null
@@ -0,0 +1,3 @@
+{% include 'c/align-statements-comment.j2' %}
+
+_ALIGN(at, {{ op.value }});
diff --git a/barectf/templates/c/size-write-bit-array-statements.j2 b/barectf/templates/c/size-write-bit-array-statements.j2
new file mode 100644 (file)
index 0000000..9f189a2
--- /dev/null
@@ -0,0 +1,2 @@
+/* add `{{ op.top_name }}` bit array field's size */
+at += {{ op.ft.size }};
diff --git a/barectf/templates/c/size-write-string-statements.j2 b/barectf/templates/c/size-write-string-statements.j2
new file mode 100644 (file)
index 0000000..2c47fbe
--- /dev/null
@@ -0,0 +1,3 @@
+{% import 'c/common.j2' as c_common %}
+/* add `{{ op.top_name }}` string field's size */
+at += _BYTES_TO_BITS(strlen({{ c_common.op_src(op) }}) + 1);
diff --git a/barectf/templates/c/trace-func-proto.j2 b/barectf/templates/c/trace-func-proto.j2
new file mode 100644 (file)
index 0000000..e3e6ba8
--- /dev/null
@@ -0,0 +1,3 @@
+{% import 'common.j2' as common %}
+/* trace (stream type `{{ stream_type.name }}`, event type `{{ ev_type.name }}`) */
+void {{ common.prefix }}{{ stream_type.name }}_trace_{{ ev_type.name }}(struct {{ common.prefix }}{{ stream_type.name }}_ctx *sctx{{ (stream_type, ev_type) | trace_func_params_str }})
diff --git a/barectf/templates/metadata-enum-ft.j2 b/barectf/templates/metadata-enum-ft.j2
deleted file mode 100644 (file)
index 1dc2783..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-enum : {{ ft | int_ft_str }} {
-{% for label, mapping in ft.mappings.items() %}
-{% for rg in mapping.ranges %}
-       {% if rg.lower == rg.upper %}
-               {% set rg_str = rg.lower %}
-       {% else %}
-               {% set rg_str %}{{ rg.lower }} ... {{ rg.upper }}{% endset %}
-       {% endif %}
-       "{{ label | escape_dq }}" = {{ rg_str }},
-{% endfor %}
-{% endfor %}
-}
diff --git a/barectf/templates/metadata-int-ft.j2 b/barectf/templates/metadata-int-ft.j2
deleted file mode 100644 (file)
index 50e6513..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-integer {
-       signed = {{ 'true' if is_signed else 'false' }};
-       size = {{ ft.size }};
-       align = {{ ft.alignment }};
-       byte_order = {{ ft.byte_order | bo_str }};
-       base = {{ ft.preferred_display_base | disp_base_int }};
-       {% if ft._mapped_clk_type_name %}
-       map = clock.{{ ft._mapped_clk_type_name }}.value;
-       {% endif %}
-}
diff --git a/barectf/templates/metadata-real-ft.j2 b/barectf/templates/metadata-real-ft.j2
deleted file mode 100644 (file)
index d70fbfd..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-floating_point {
-       mant_dig = {{ 24 if ft.size == 32 else 53 }};
-       exp_dig = {{ 8 if ft.size == 32 else 11 }};
-       align = {{ ft.alignment }};
-       byte_order = {{ ft.byte_order | bo_str }};
-}
diff --git a/barectf/templates/metadata-str-ft.j2 b/barectf/templates/metadata-str-ft.j2
deleted file mode 100644 (file)
index 6de8a2b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-string {
-       encoding = UTF8;
-}
diff --git a/barectf/templates/metadata-struct-ft.j2 b/barectf/templates/metadata-struct-ft.j2
deleted file mode 100644 (file)
index 7c30035..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-struct {
-{% for name, member in ft.members.items() %}
-{#
- # `chain` is a list of static array field types terminated with a
- # non-array field type (the most nested).
- #}
-{% set chain = ft_chain(member.field_type) %}
-       {{ chain[-1] | ft_str | indent_tab }} {{ name }}
-       {%- for array_ft in chain[:-1] %}[{{ array_ft.length }}]{% endfor %};
-{% endfor %}
-} align({{ ft.minimum_alignment }})
diff --git a/barectf/templates/metadata.j2 b/barectf/templates/metadata.j2
deleted file mode 100644 (file)
index f3abe74..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-{% import 'common.j2' as common %}
-/* CTF 1.8 */
-
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- *
- * The following TSDL code was generated by barectf v{{ barectf_version.__version__ }}
- * on {{ common.gen_date }}.
- *
- * For more details, see <https://barectf.org/>.
- */
-{#
- # Generates a root field type string named `name` for the field type
- # `rft` with all the lines except the first one indented with a single
- # tab.
- #}
-{% macro root_ft(name, rft) -%}
-{{ name }} := {{ rft | ft_str | indent_tab }};
-{%- endmacro %}
-
-trace {
-       major = 1;
-       minor = 8;
-       byte_order = {{ cfg.trace.type.default_byte_order | bo_str }};
-       {% if cfg.trace.type.uuid %}
-       uuid = "{{ cfg.trace.type.uuid }}";
-       {% endif %}
-       {% if cfg.trace.type._pkt_header_ft %}
-       {{ root_ft('packet.header', cfg.trace.type._pkt_header_ft) }}
-       {% endif %}
-};
-
-env {
-{% for name, value in cfg.trace.environment.items() %}
-       {{ name }} = {{ value if value is number else '"{}"'.format(value | escape_dq) }};
-{% endfor %}
-};
-
-{# all clock types (stream types's default clock types) #}
-{% for clk_type in cfg.trace.type.clock_types | sort %}
-clock {
-       name = {{ clk_type.name }};
-       {% if clk_type.description %}
-       description = "{{ clk_type.description | escape_dq }}";
-       {% endif %}
-       {% if clk_type.uuid %}
-       uuid = "{{ clk_type.uuid }}";
-       {% endif %}
-       freq = {{ clk_type.frequency }};
-       precision = {{ clk_type.precision }};
-       offset_s = {{ clk_type.offset.seconds }};
-       offset = {{ clk_type.offset.cycles }};
-       absolute = {{ 'true' if clk_type.origin_is_unix_epoch else 'false' }};
-};
-
-{% endfor %}
-{# stream types and their event types #}
-{%- for stream_type in cfg.trace.type.stream_types | sort %}
-/* Stream type `{{ stream_type.name }}` */
-stream {
-       id = {{ stream_type.id }};
-       {{ root_ft('packet.context', stream_type._pkt_ctx_ft) }}
-       {% if stream_type._ev_header_ft %}
-       {{ root_ft('event.header', stream_type._ev_header_ft) }}
-       {% endif %}
-       {% if stream_type.event_common_context_field_type %}
-       {{ root_ft('event.context', stream_type.event_common_context_field_type) }}
-       {% endif %}
-};
-
-{# stream type's event types #}
-{% for ev_type in stream_type.event_types | sort %}
-event {
-       id = {{ ev_type.id }};
-       stream_id = {{ stream_type.id }};
-       name = "{{ ev_type.name }}";
-       {% if ev_type.log_level %}
-       loglevel = {{ ev_type.log_level }};
-       {% endif %}
-       {% if ev_type.specific_context_field_type %}
-       {{ root_ft('context', ev_type.specific_context_field_type) }}
-       {% endif %}
-       {% if ev_type.payload_field_type %}
-       {{ root_ft('fields', ev_type.payload_field_type) }}
-       {% endif %}
-};
-
-{% endfor %}
-{% endfor %}
diff --git a/barectf/templates/metadata/enum-ft.j2 b/barectf/templates/metadata/enum-ft.j2
new file mode 100644 (file)
index 0000000..1dc2783
--- /dev/null
@@ -0,0 +1,12 @@
+enum : {{ ft | int_ft_str }} {
+{% for label, mapping in ft.mappings.items() %}
+{% for rg in mapping.ranges %}
+       {% if rg.lower == rg.upper %}
+               {% set rg_str = rg.lower %}
+       {% else %}
+               {% set rg_str %}{{ rg.lower }} ... {{ rg.upper }}{% endset %}
+       {% endif %}
+       "{{ label | escape_dq }}" = {{ rg_str }},
+{% endfor %}
+{% endfor %}
+}
diff --git a/barectf/templates/metadata/int-ft.j2 b/barectf/templates/metadata/int-ft.j2
new file mode 100644 (file)
index 0000000..50e6513
--- /dev/null
@@ -0,0 +1,10 @@
+integer {
+       signed = {{ 'true' if is_signed else 'false' }};
+       size = {{ ft.size }};
+       align = {{ ft.alignment }};
+       byte_order = {{ ft.byte_order | bo_str }};
+       base = {{ ft.preferred_display_base | disp_base_int }};
+       {% if ft._mapped_clk_type_name %}
+       map = clock.{{ ft._mapped_clk_type_name }}.value;
+       {% endif %}
+}
diff --git a/barectf/templates/metadata/metadata.j2 b/barectf/templates/metadata/metadata.j2
new file mode 100644 (file)
index 0000000..068f4c2
--- /dev/null
@@ -0,0 +1,111 @@
+{% import 'common.j2' as common %}
+/* CTF 1.8 */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ *
+ * The following TSDL code was generated by barectf v{{ barectf_version.__version__ }}
+ * on {{ common.gen_date }}.
+ *
+ * For more details, see <https://barectf.org/>.
+ */
+{#
+ # Generates a root field type string named `name` for the field type
+ # `rft` with all the lines except the first one indented with a single
+ # tab.
+ #}
+{% macro root_ft(name, rft) -%}
+{{ name }} := {{ rft | ft_str | indent_tab }};
+{%- endmacro %}
+
+trace {
+       major = 1;
+       minor = 8;
+       byte_order = {{ cfg.trace.type.default_byte_order | bo_str }};
+{% if cfg.trace.type.uuid %}
+       uuid = "{{ cfg.trace.type.uuid }}";
+{% endif %}
+{% if cfg.trace.type._pkt_header_ft %}
+       {{ root_ft('packet.header', cfg.trace.type._pkt_header_ft) }}
+{% endif %}
+};
+
+env {
+{% for name, value in cfg.trace.environment.items() %}
+       {{ name }} = {{ value if value is number else '"{}"'.format(value | escape_dq) }};
+{% endfor %}
+};
+
+{# all clock types (stream types's default clock types) #}
+{% for clk_type in cfg.trace.type.clock_types | sort %}
+clock {
+       name = {{ clk_type.name }};
+       {% if clk_type.description %}
+       description = "{{ clk_type.description | escape_dq }}";
+       {% endif %}
+       {% if clk_type.uuid %}
+       uuid = "{{ clk_type.uuid }}";
+       {% endif %}
+       freq = {{ clk_type.frequency }};
+       precision = {{ clk_type.precision }};
+       offset_s = {{ clk_type.offset.seconds }};
+       offset = {{ clk_type.offset.cycles }};
+       absolute = {{ 'true' if clk_type.origin_is_unix_epoch else 'false' }};
+};
+
+{% endfor %}
+{# stream types and their event types #}
+{%- for stream_type in cfg.trace.type.stream_types | sort %}
+/* Stream type `{{ stream_type.name }}` */
+stream {
+       id = {{ stream_type.id }};
+       {{ root_ft('packet.context', stream_type._pkt_ctx_ft) }}
+       {% if stream_type._ev_header_ft %}
+       {{ root_ft('event.header', stream_type._ev_header_ft) }}
+       {% endif %}
+       {% if stream_type.event_common_context_field_type %}
+       {{ root_ft('event.context', stream_type.event_common_context_field_type) }}
+       {% endif %}
+};
+
+       {# stream type's event types #}
+       {% for ev_type in stream_type.event_types | sort %}
+event {
+       id = {{ ev_type.id }};
+       stream_id = {{ stream_type.id }};
+       name = "{{ ev_type.name }}";
+               {% if ev_type.log_level %}
+       loglevel = {{ ev_type.log_level }};
+               {% endif %}
+               {% if ev_type.specific_context_field_type %}
+       {{ root_ft('context', ev_type.specific_context_field_type) }}
+               {% endif %}
+               {% if ev_type.payload_field_type %}
+       {{ root_ft('fields', ev_type.payload_field_type) }}
+               {% endif %}
+};
+
+       {% endfor %}
+{% endfor %}
diff --git a/barectf/templates/metadata/real-ft.j2 b/barectf/templates/metadata/real-ft.j2
new file mode 100644 (file)
index 0000000..d70fbfd
--- /dev/null
@@ -0,0 +1,6 @@
+floating_point {
+       mant_dig = {{ 24 if ft.size == 32 else 53 }};
+       exp_dig = {{ 8 if ft.size == 32 else 11 }};
+       align = {{ ft.alignment }};
+       byte_order = {{ ft.byte_order | bo_str }};
+}
diff --git a/barectf/templates/metadata/str-ft.j2 b/barectf/templates/metadata/str-ft.j2
new file mode 100644 (file)
index 0000000..6de8a2b
--- /dev/null
@@ -0,0 +1,3 @@
+string {
+       encoding = UTF8;
+}
diff --git a/barectf/templates/metadata/struct-ft.j2 b/barectf/templates/metadata/struct-ft.j2
new file mode 100644 (file)
index 0000000..7c30035
--- /dev/null
@@ -0,0 +1,11 @@
+struct {
+{% for name, member in ft.members.items() %}
+{#
+ # `chain` is a list of static array field types terminated with a
+ # non-array field type (the most nested).
+ #}
+{% set chain = ft_chain(member.field_type) %}
+       {{ chain[-1] | ft_str | indent_tab }} {{ name }}
+       {%- for array_ft in chain[:-1] %}[{{ array_ft.length }}]{% endfor %};
+{% endfor %}
+} align({{ ft.minimum_alignment }})
index c11dac27869381eb8fd304ab910210380c81f7ac..39fd64f8494e858a79d4b3dc233b587ace5f22fe 100644 (file)
@@ -100,15 +100,15 @@ _TEMPL_FILTERS = {
 
 def _create_template(name: str, is_file_template: bool = False,
                      cfg: Optional[barectf_config.Configuration] = None) -> barectf_template._Template:
-    return barectf_template._Template(name, is_file_template, cfg,
+    return barectf_template._Template(f'metadata/{name}', is_file_template, cfg,
                                       typing.cast(barectf_template._Filters, _TEMPL_FILTERS))
 
 
-_ENUM_FT_TEMPL = _create_template('metadata-enum-ft.j2')
-_INT_FT_TEMPL = _create_template('metadata-int-ft.j2')
-_REAL_FT_TEMPL = _create_template('metadata-real-ft.j2')
-_STR_FT_TEMPL = _create_template('metadata-str-ft.j2')
-_STRUCT_FT_TEMPL = _create_template('metadata-struct-ft.j2')
+_ENUM_FT_TEMPL = _create_template('enum-ft.j2')
+_INT_FT_TEMPL = _create_template('int-ft.j2')
+_REAL_FT_TEMPL = _create_template('real-ft.j2')
+_STR_FT_TEMPL = _create_template('str-ft.j2')
+_STRUCT_FT_TEMPL = _create_template('struct-ft.j2')
 
 
 def _from_config(cfg: barectf_config.Configuration) -> str:
index 7e7e2cbf483ace0bdedfe98761ceb7b97525dc26..9d81b3d017ba971bfacc25d0979252f4f9105eff 100644 (file)
@@ -66,6 +66,7 @@ metadata:
           packet_size: uint32
           content_size: uint32
           events_discarded: uint32
+          salut: string
       event-header-type:
         class: struct
         fields:
This page took 0.120797 seconds and 4 git commands to generate.