blob: f0fb00831c34b76d36306a5d88a4da026c75a182 [file] [log] [blame]
Ole Troan9d420872017-10-12 13:06:35 +02001# C generation
2import datetime
3import os
Nirmoy Dasc9f40222018-06-28 10:18:43 +02004import time
Ole Troan9d420872017-10-12 13:06:35 +02005
Nirmoy Dasc9f40222018-06-28 10:18:43 +02006datestring = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
Ole Troan9d420872017-10-12 13:06:35 +02007input_filename = 'inputfil'
8top_boilerplate = '''\
9/*
10 * VLIB API definitions {datestring}
11 * Input file: {input_filename}
12 * Automatically generated: please edit the input file NOT this file!
13 */
14
15#if defined(vl_msg_id)||defined(vl_union_id) \\
16 || defined(vl_printfun) ||defined(vl_endianfun) \\
17 || defined(vl_api_version)||defined(vl_typedefs) \\
18 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
19 || defined(vl_api_version_tuple)
20/* ok, something was selected */
21#else
22#warning no content included from {input_filename}
23#endif
24
25#define VL_API_PACKED(x) x __attribute__ ((packed))
26'''
27
28bottom_boilerplate = '''\
29/****** API CRC (whole file) *****/
30
31#ifdef vl_api_version
32vl_api_version({input_filename}, {file_crc:#08x})
33
34#endif
35'''
36
37
38def msg_ids(s):
39 output = '''\
40
41/****** Message ID / handler enum ******/
42
43#ifdef vl_msg_id
44'''
45
Ole Troan2c2feab2018-04-24 00:02:37 -040046 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020047 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
48 (t.name.upper(), t.name)
49 output += "#endif"
50
51 return output
52
53
54def msg_names(s):
55 output = '''\
56
57/****** Message names ******/
58
59#ifdef vl_msg_name
60'''
61
Ole Troan2c2feab2018-04-24 00:02:37 -040062 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020063 dont_trace = 0 if t.dont_trace else 1
64 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
65 output += "#endif"
66
67 return output
68
69
70def msg_name_crc_list(s, suffix):
71 output = '''\
72
73/****** Message name, crc list ******/
74
75#ifdef vl_msg_name_crc_list
76'''
77 output += "#define foreach_vl_msg_name_crc_%s " % suffix
78
Ole Troan2c2feab2018-04-24 00:02:37 -040079 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020080 output += "\\\n_(VL_API_%s, %s, %08x) " % \
81 (t.name.upper(), t.name, t.crc)
82 output += "\n#endif"
83
84 return output
85
86
87def duplicate_wrapper_head(name):
Ole Troan02143df2018-11-30 08:34:11 +010088 s = "#ifndef _vl_api_defined_%s\n" % name
89 s += "#define _vl_api_defined_%s\n" % name
Ole Troan9d420872017-10-12 13:06:35 +020090 return s
91
92
93def duplicate_wrapper_tail():
94 return '#endif\n\n'
95
96
Ole Troan53fffa12018-11-13 12:36:56 +010097def typedefs(objs, aliases, filename):
Ole Troan9d420872017-10-12 13:06:35 +020098 name = filename.replace('.', '_')
99 output = '''\
100
101
102/****** Typedefs ******/
103
104#ifdef vl_typedefs
105#ifndef included_{module}
106#define included_{module}
107'''
108 output = output.format(module=name)
Ole Troan53fffa12018-11-13 12:36:56 +0100109
110 for k, v in aliases.items():
111 output += duplicate_wrapper_head(k)
112 if 'length' in v:
113 output += 'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length'])
114 else:
115 output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k)
116 output += duplicate_wrapper_tail()
117
Ole Troan2c2feab2018-04-24 00:02:37 -0400118 for o in objs:
119 tname = o.__class__.__name__
120 output += duplicate_wrapper_head(o.name)
121 if tname == 'Enum':
122 output += "typedef enum {\n"
123 for b in o.block:
124 output += " %s = %s,\n" % (b[0], b[1])
125 output += '} vl_api_%s_t;\n' % o.name
126 else:
127 if tname == 'Union':
128 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200129 else:
Ole Troan2c2feab2018-04-24 00:02:37 -0400130 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
131 for b in o.block:
132 if b.type == 'Field':
133 output += " %s %s;\n" % (b.fieldtype, b.fieldname)
134 elif b.type == 'Array':
135 if b.lengthfield:
136 output += " %s %s[0];\n" % (b.fieldtype, b.fieldname)
137 else:
138 output += " %s %s[%s];\n" % (b.fieldtype, b.fieldname,
139 b.length)
140 else:
141 raise ValueError("Error in processing array type %s" % b)
Ole Troan9d420872017-10-12 13:06:35 +0200142
Ole Troan2c2feab2018-04-24 00:02:37 -0400143 output += '}) vl_api_%s_t;\n' % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200144 output += duplicate_wrapper_tail()
145
146 output += "\n#endif"
147 output += "\n#endif\n\n"
148
149 return output
150
151
152format_strings = {'u8': '%u',
153 'i8': '%d',
154 'u16': '%u',
155 'i16': '%d',
156 'u32': '%u',
157 'i32': '%ld',
158 'u64': '%llu',
159 'i64': '%llu',
160 'f64': '%.2f', }
161
162
Ole Troan2c2feab2018-04-24 00:02:37 -0400163def printfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200164 output = '''\
165/****** Print functions *****/
166#ifdef vl_printfun
167
168#ifdef LP64
169#define _uword_fmt \"%lld\"
170#define _uword_cast (long long)
171#else
172#define _uword_fmt \"%ld\"
173#define _uword_cast long
174#endif
175
176'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400177 for t in objs:
178 if t.__class__.__name__ == 'Enum':
179 continue
Ole Troan9d420872017-10-12 13:06:35 +0200180 if t.manual_print:
181 output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name
182 continue
183 output += duplicate_wrapper_head(t.name + '_t_print')
184 output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \
185 (t.name, t.name)
186 output += "void *handle)\n{\n"
187 output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name
188
189 for o in t.block:
190 if o.type != 'Field':
191 continue
192 if o.fieldtype in format_strings:
193 output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \
194 (o.fieldname, format_strings[o.fieldtype],
195 o.fieldname)
196
197 output += ' return handle;\n'
198 output += '}\n\n'
199 output += duplicate_wrapper_tail()
200
201 output += "\n#endif /* vl_printfun */\n"
202
203 return output
204
205
206endian_strings = {
207 'u16': 'clib_net_to_host_u16',
208 'u32': 'clib_net_to_host_u32',
209 'u64': 'clib_net_to_host_u64',
210 'i16': 'clib_net_to_host_u16',
211 'i32': 'clib_net_to_host_u32',
212 'i64': 'clib_net_to_host_u64',
213}
214
215
Ole Troan2c2feab2018-04-24 00:02:37 -0400216def endianfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200217 output = '''\
218
219/****** Endian swap functions *****/\n\
220#ifdef vl_endianfun
221
222#undef clib_net_to_host_uword
223#ifdef LP64
224#define clib_net_to_host_uword clib_net_to_host_u64
225#else
226#define clib_net_to_host_uword clib_net_to_host_u32
227#endif
228
229'''
230
Ole Troan2c2feab2018-04-24 00:02:37 -0400231 for t in objs:
232 if t.__class__.__name__ == 'Enum':
233 continue
Ole Troan9d420872017-10-12 13:06:35 +0200234 if t.manual_endian:
235 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
236 continue
237 output += duplicate_wrapper_head(t.name + '_t_endian')
238 output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \
239 (t.name, t.name)
240 output += "\n{\n"
241
242 for o in t.block:
243 if o.type != 'Field':
244 continue
245 if o.fieldtype in endian_strings:
246 output += " a->%s = %s(a->%s);\n" % \
247 (o.fieldname, endian_strings[o.fieldtype], o.fieldname)
248 else:
249 output += " /* a->%s = a->%s (no-op) */\n" % \
250 (o.fieldname, o.fieldname)
251
252 output += '}\n\n'
253 output += duplicate_wrapper_tail()
254 output += "\n#endif /* vl_endianfun */\n\n"
255
256 return output
257
258
259def version_tuple(s, module):
260 output = '''\
261/****** Version tuple *****/
262
263#ifdef vl_api_version_tuple
264
265'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400266 if 'version' in s['Option']:
267 v = s['Option']['version']
Ole Troan9d420872017-10-12 13:06:35 +0200268 (major, minor, patch) = v.split('.')
269 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
270 (module, major, minor, patch)
271
272 output += "\n#endif /* vl_api_version_tuple */\n\n"
273
274 return output
275
276
277#
278# Plugin entry point
279#
280def run(input_filename, s, file_crc):
281 basename = os.path.basename(input_filename)
282 filename, file_extension = os.path.splitext(basename)
283 output = top_boilerplate.format(datestring=datestring,
284 input_filename=basename)
285 output += msg_ids(s)
286 output += msg_names(s)
287 output += msg_name_crc_list(s, filename)
Ole Troan53fffa12018-11-13 12:36:56 +0100288 output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension)
Ole Troan2c2feab2018-04-24 00:02:37 -0400289 output += printfun(s['types'] + s['Define'])
290 output += endianfun(s['types'] + s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +0200291 output += version_tuple(s, basename)
292 output += bottom_boilerplate.format(input_filename=basename,
293 file_crc=file_crc)
294
295 return output