1# Copyright (C) 2014-2016 Intel Corporation.   All Rights Reserved.
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the "Software"),
5# to deal in the Software without restriction, including without limitation
6# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7# and/or sell copies of the Software, and to permit persons to whom the
8# Software is furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice (including the next
11# paragraph) shall be included in all copies or substantial portions of the
12# Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20# IN THE SOFTWARE.
21
22# Python source
23from __future__ import print_function
24import os
25import sys
26import re
27import argparse
28from mako.template import Template
29from mako.exceptions import RichTraceback
30
31def write_template_to_string(template_filename, **kwargs):
32    try:
33        template = Template(filename=template_filename)
34        # Split + Join fixes line-endings for whatever platform you are using
35        return '\n'.join(template.render(**kwargs).splitlines())
36    except:
37        traceback = RichTraceback()
38        for (filename, lineno, function, line) in traceback.traceback:
39            print("File %s, line %s, in %s" % (filename, lineno, function))
40            print(line, "\n")
41        print("%s: %s" % (str(traceback.error.__class__.__name__), traceback.error))
42
43def write_template_to_file(template_filename, output_filename, **kwargs):
44    with open(output_filename, "w") as outfile:
45        print(write_template_to_string(template_filename, **kwargs), file=outfile)
46
47def parse_event_fields(lines, idx, event_dict):
48    field_names = []
49    field_types = []
50    end_of_event = False
51
52    num_fields = 0
53
54    # record all fields in event definition.
55    # note: we don't check if there's a leading brace.
56    while not end_of_event and idx < len(lines):
57        line = lines[idx].rstrip()
58        idx += 1
59
60        field = re.match(r"(\s*)(\w+)(\s*)(\w+)", line)
61
62        if field:
63            field_types.append(field.group(2))
64            field_names.append(field.group(4))
65            num_fields += 1
66
67        end_of_event = re.match(r"(\s*)};", line)
68
69    event_dict['field_types'] = field_types
70    event_dict['field_names'] = field_names
71    event_dict['num_fields'] = num_fields
72
73    return idx
74
75def parse_enums(lines, idx, event_dict):
76    enum_names = []
77    end_of_enum = False
78
79    # record all enum values in enumeration
80    # note: we don't check if there's a leading brace.
81    while not end_of_enum and idx < len(lines):
82        line = lines[idx].rstrip()
83        idx += 1
84
85        preprocessor = re.search(r"#if|#endif", line)
86
87        if not preprocessor:
88            enum = re.match(r"(\s*)(\w+)(\s*)", line)
89
90            if enum:
91                enum_names.append(line)
92
93            end_of_enum = re.match(r"(\s*)};", line)
94
95    event_dict['names'] = enum_names
96    return idx
97
98def parse_protos(filename):
99    protos = {}
100
101    with open(filename, 'r') as f:
102        lines=f.readlines()
103
104        idx = 0
105
106        protos['events'] = {}       # event dictionary containing events with their fields
107        protos['event_names'] = []  # needed to keep events in order parsed. dict is not ordered.
108        protos['enums'] = {}
109        protos['enum_names'] = []
110
111        eventId = 0
112        raw_text = []
113        while idx < len(lines):
114            line = lines[idx].rstrip()
115            idx += 1
116
117            # search for event definitions.
118            match = re.match(r"(\s*)event(\s*)(\w+)", line)
119
120            if match:
121                eventId += 1
122                event_name = match.group(3)
123                protos['event_names'].append(event_name)
124
125                protos['events'][event_name] = {}
126                protos['events'][event_name]['event_id'] = eventId
127                idx = parse_event_fields(lines, idx, protos['events'][event_name])
128
129            # search for enums.
130            match = re.match(r"(\s*)enum(\s*)(\w+)", line)
131
132            if match:
133                enum_name = match.group(3)
134                protos['enum_names'].append(enum_name)
135
136                protos['enums'][enum_name] = {}
137                idx = parse_enums(lines, idx, protos['enums'][enum_name])
138
139    return protos
140
141def main():
142
143    # Parse args...
144    parser = argparse.ArgumentParser()
145    parser.add_argument("--proto", "-p", help="Path to proto file", required=True)
146    parser.add_argument("--output", "-o", help="Output filename (i.e. event.h)", required=True)
147    parser.add_argument("--gen_event_h", "-geh", help="Generate event header", action="store_true", default=False)
148    parser.add_argument("--gen_event_cpp", "-gec", help="Generate event cpp", action="store_true", default=False)
149    parser.add_argument("--gen_eventhandler_h", "-gehh", help="Generate eventhandler header", action="store_true", default=False)
150    parser.add_argument("--gen_eventhandlerfile_h", "-gehf", help="Generate eventhandler header for writing to files", action="store_true", default=False)
151    args = parser.parse_args()
152
153    proto_filename = args.proto
154
155    (output_dir, output_filename) = os.path.split(args.output)
156
157    if not output_dir:
158        output_dir = "."
159
160    #print("output_dir = %s" % output_dir, file=sys.stderr)
161    #print("output_filename = %s" % output_filename, file=sys.stderr)
162
163    if not os.path.exists(proto_filename):
164        print("Error: Could not find proto file %s" % proto_filename, file=sys.stderr)
165        return 1
166
167    protos = parse_protos(proto_filename)
168
169    # Generate event header
170    if args.gen_event_h:
171        curdir = os.path.dirname(os.path.abspath(__file__))
172        template_file = os.sep.join([curdir, 'templates', 'ar_event_h.template'])
173        output_fullpath = os.sep.join([output_dir, output_filename])
174
175        write_template_to_file(template_file, output_fullpath,
176                filename=output_filename,
177                protos=protos)
178
179    # Generate event implementation
180    if args.gen_event_cpp:
181        curdir = os.path.dirname(os.path.abspath(__file__))
182        template_file = os.sep.join([curdir, 'templates', 'ar_event_cpp.template'])
183        output_fullpath = os.sep.join([output_dir, output_filename])
184
185        write_template_to_file(template_file, output_fullpath,
186                filename=output_filename,
187                protos=protos)
188
189    # Generate event handler header
190    if args.gen_eventhandler_h:
191        curdir = os.path.dirname(os.path.abspath(__file__))
192        template_file = os.sep.join([curdir, 'templates', 'ar_eventhandler_h.template'])
193        output_fullpath = os.sep.join([output_dir, output_filename])
194
195        write_template_to_file(template_file, output_fullpath,
196                filename=output_filename,
197                event_header="gen_ar_event.h",   # todo: fix this!
198                protos=protos)
199
200    # Generate event handler header
201    if args.gen_eventhandlerfile_h:
202        curdir = os.path.dirname(os.path.abspath(__file__))
203        template_file = os.sep.join([curdir, 'templates', 'ar_eventhandlerfile_h.template'])
204        output_fullpath = os.sep.join([output_dir, output_filename])
205
206        write_template_to_file(template_file, output_fullpath,
207                filename=output_filename,
208                event_header="gen_ar_eventhandler.h",   # todo: fix this!
209                protos=protos)
210
211    return 0
212
213if __name__ == '__main__':
214    sys.exit(main())
215
216