blob: c1bc11d4a120ef0c6f92e02b00dbed92b93060c5 [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
Ole Troan413f4a52018-11-28 11:36:05 +01006datestring = datetime.datetime.utcfromtimestamp(
7 int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
Ole Troan9d420872017-10-12 13:06:35 +02008input_filename = 'inputfil'
9top_boilerplate = '''\
10/*
11 * VLIB API definitions {datestring}
12 * Input file: {input_filename}
13 * Automatically generated: please edit the input file NOT this file!
14 */
15
Ole Troan288e0932019-05-29 12:30:05 +020016#include <stdbool.h>
Ole Troan9d420872017-10-12 13:06:35 +020017#if defined(vl_msg_id)||defined(vl_union_id) \\
18 || defined(vl_printfun) ||defined(vl_endianfun) \\
19 || defined(vl_api_version)||defined(vl_typedefs) \\
20 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
21 || defined(vl_api_version_tuple)
22/* ok, something was selected */
23#else
24#warning no content included from {input_filename}
25#endif
26
27#define VL_API_PACKED(x) x __attribute__ ((packed))
28'''
29
30bottom_boilerplate = '''\
31/****** API CRC (whole file) *****/
32
33#ifdef vl_api_version
34vl_api_version({input_filename}, {file_crc:#08x})
35
36#endif
37'''
38
39
40def msg_ids(s):
41 output = '''\
42
43/****** Message ID / handler enum ******/
44
45#ifdef vl_msg_id
46'''
47
Ole Troan2c2feab2018-04-24 00:02:37 -040048 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020049 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
50 (t.name.upper(), t.name)
51 output += "#endif"
52
53 return output
54
55
56def msg_names(s):
57 output = '''\
58
59/****** Message names ******/
60
61#ifdef vl_msg_name
62'''
63
Ole Troan2c2feab2018-04-24 00:02:37 -040064 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020065 dont_trace = 0 if t.dont_trace else 1
66 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
67 output += "#endif"
68
69 return output
70
71
72def msg_name_crc_list(s, suffix):
73 output = '''\
74
75/****** Message name, crc list ******/
76
77#ifdef vl_msg_name_crc_list
78'''
79 output += "#define foreach_vl_msg_name_crc_%s " % suffix
80
Ole Troan2c2feab2018-04-24 00:02:37 -040081 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020082 output += "\\\n_(VL_API_%s, %s, %08x) " % \
83 (t.name.upper(), t.name, t.crc)
84 output += "\n#endif"
85
86 return output
87
88
89def duplicate_wrapper_head(name):
Ole Troan02143df2018-11-30 08:34:11 +010090 s = "#ifndef _vl_api_defined_%s\n" % name
91 s += "#define _vl_api_defined_%s\n" % name
Ole Troan9d420872017-10-12 13:06:35 +020092 return s
93
94
95def duplicate_wrapper_tail():
96 return '#endif\n\n'
97
98
Ole Troan413f4a52018-11-28 11:36:05 +010099def api2c(fieldtype):
100 mappingtable = {'string': 'vl_api_string_t', }
101 if fieldtype in mappingtable:
102 return mappingtable[fieldtype]
103 return fieldtype
104
105
Ole Troan53fffa12018-11-13 12:36:56 +0100106def typedefs(objs, aliases, filename):
Ole Troan9d420872017-10-12 13:06:35 +0200107 name = filename.replace('.', '_')
108 output = '''\
109
110
111/****** Typedefs ******/
112
113#ifdef vl_typedefs
114#ifndef included_{module}
115#define included_{module}
116'''
117 output = output.format(module=name)
Ole Troan53fffa12018-11-13 12:36:56 +0100118
119 for k, v in aliases.items():
120 output += duplicate_wrapper_head(k)
121 if 'length' in v:
122 output += 'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length'])
123 else:
124 output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k)
125 output += duplicate_wrapper_tail()
126
Ole Troan2c2feab2018-04-24 00:02:37 -0400127 for o in objs:
128 tname = o.__class__.__name__
129 output += duplicate_wrapper_head(o.name)
130 if tname == 'Enum':
Andrew Yourtchenko5c4b9f12019-03-19 14:52:29 +0100131 if o.enumtype == 'u32':
132 output += "typedef enum {\n"
133 else:
134 output += "typedef enum __attribute__((__packed__)) {\n"
135
Ole Troan2c2feab2018-04-24 00:02:37 -0400136 for b in o.block:
137 output += " %s = %s,\n" % (b[0], b[1])
138 output += '} vl_api_%s_t;\n' % o.name
Andrew Yourtchenko5c4b9f12019-03-19 14:52:29 +0100139 if o.enumtype != 'u32':
140 size1 = 'sizeof(vl_api_%s_t)' % o.name
141 size2 = 'sizeof(%s)' % o.enumtype
142 err_str = 'size of API enum %s is wrong' % o.name
143 output += 'STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str)
Ole Troan2c2feab2018-04-24 00:02:37 -0400144 else:
145 if tname == 'Union':
146 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200147 else:
Ole Troan2c2feab2018-04-24 00:02:37 -0400148 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
149 for b in o.block:
150 if b.type == 'Field':
Ole Troan413f4a52018-11-28 11:36:05 +0100151 output += " %s %s;\n" % (api2c(b.fieldtype), b.fieldname)
Ole Troan2c2feab2018-04-24 00:02:37 -0400152 elif b.type == 'Array':
153 if b.lengthfield:
Ole Troan413f4a52018-11-28 11:36:05 +0100154 output += " %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname)
Ole Troan2c2feab2018-04-24 00:02:37 -0400155 else:
Ole Troane5ff5a32019-08-23 22:55:18 +0200156 # Fixed length strings decay to nul terminated u8
157 if b.fieldtype == 'string':
158 if b.modern_vla:
159 output += ' {} {};\n'.format(api2c(b.fieldtype), b.fieldname)
160 else:
161 output += ' u8 {}[{}];\n'.format(b.fieldname, b.length)
162 else:
163 output += " %s %s[%s];\n" % (api2c(b.fieldtype), b.fieldname,
164 b.length)
Ole Troan2c2feab2018-04-24 00:02:37 -0400165 else:
166 raise ValueError("Error in processing array type %s" % b)
Ole Troan9d420872017-10-12 13:06:35 +0200167
Ole Troan2c2feab2018-04-24 00:02:37 -0400168 output += '}) vl_api_%s_t;\n' % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200169 output += duplicate_wrapper_tail()
170
171 output += "\n#endif"
172 output += "\n#endif\n\n"
173
174 return output
175
176
177format_strings = {'u8': '%u',
178 'i8': '%d',
179 'u16': '%u',
180 'i16': '%d',
181 'u32': '%u',
182 'i32': '%ld',
183 'u64': '%llu',
184 'i64': '%llu',
185 'f64': '%.2f', }
186
187
Ole Troan2c2feab2018-04-24 00:02:37 -0400188def printfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200189 output = '''\
190/****** Print functions *****/
191#ifdef vl_printfun
192
193#ifdef LP64
194#define _uword_fmt \"%lld\"
195#define _uword_cast (long long)
196#else
197#define _uword_fmt \"%ld\"
198#define _uword_cast long
199#endif
200
201'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400202 for t in objs:
203 if t.__class__.__name__ == 'Enum':
204 continue
Ole Troan9d420872017-10-12 13:06:35 +0200205 if t.manual_print:
206 output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name
207 continue
208 output += duplicate_wrapper_head(t.name + '_t_print')
209 output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \
210 (t.name, t.name)
211 output += "void *handle)\n{\n"
212 output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name
213
214 for o in t.block:
215 if o.type != 'Field':
216 continue
217 if o.fieldtype in format_strings:
218 output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \
219 (o.fieldname, format_strings[o.fieldtype],
220 o.fieldname)
221
222 output += ' return handle;\n'
223 output += '}\n\n'
224 output += duplicate_wrapper_tail()
225
226 output += "\n#endif /* vl_printfun */\n"
227
228 return output
229
230
231endian_strings = {
232 'u16': 'clib_net_to_host_u16',
233 'u32': 'clib_net_to_host_u32',
234 'u64': 'clib_net_to_host_u64',
235 'i16': 'clib_net_to_host_u16',
236 'i32': 'clib_net_to_host_u32',
237 'i64': 'clib_net_to_host_u64',
Paul Vinciguerra07f87542019-07-30 18:24:41 -0400238 'f64': 'clib_net_to_host_u64',
Ole Troan9d420872017-10-12 13:06:35 +0200239}
240
241
Ole Troan2c2feab2018-04-24 00:02:37 -0400242def endianfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200243 output = '''\
244
245/****** Endian swap functions *****/\n\
246#ifdef vl_endianfun
247
248#undef clib_net_to_host_uword
249#ifdef LP64
250#define clib_net_to_host_uword clib_net_to_host_u64
251#else
252#define clib_net_to_host_uword clib_net_to_host_u32
253#endif
254
255'''
256
Ole Troan2c2feab2018-04-24 00:02:37 -0400257 for t in objs:
258 if t.__class__.__name__ == 'Enum':
259 continue
Ole Troan9d420872017-10-12 13:06:35 +0200260 if t.manual_endian:
261 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
262 continue
263 output += duplicate_wrapper_head(t.name + '_t_endian')
264 output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \
265 (t.name, t.name)
266 output += "\n{\n"
267
268 for o in t.block:
269 if o.type != 'Field':
270 continue
271 if o.fieldtype in endian_strings:
272 output += " a->%s = %s(a->%s);\n" % \
273 (o.fieldname, endian_strings[o.fieldtype], o.fieldname)
274 else:
275 output += " /* a->%s = a->%s (no-op) */\n" % \
276 (o.fieldname, o.fieldname)
277
278 output += '}\n\n'
279 output += duplicate_wrapper_tail()
280 output += "\n#endif /* vl_endianfun */\n\n"
281
282 return output
283
284
285def version_tuple(s, module):
286 output = '''\
287/****** Version tuple *****/
288
289#ifdef vl_api_version_tuple
290
291'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400292 if 'version' in s['Option']:
293 v = s['Option']['version']
Ole Troan9d420872017-10-12 13:06:35 +0200294 (major, minor, patch) = v.split('.')
295 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
296 (module, major, minor, patch)
297
298 output += "\n#endif /* vl_api_version_tuple */\n\n"
299
300 return output
301
302
303#
304# Plugin entry point
305#
Ole Troan8dbfb432019-04-24 14:31:18 +0200306def run(input_filename, s):
Ole Troan9d420872017-10-12 13:06:35 +0200307 basename = os.path.basename(input_filename)
308 filename, file_extension = os.path.splitext(basename)
309 output = top_boilerplate.format(datestring=datestring,
310 input_filename=basename)
311 output += msg_ids(s)
312 output += msg_names(s)
313 output += msg_name_crc_list(s, filename)
Ole Troan53fffa12018-11-13 12:36:56 +0100314 output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension)
Ole Troan2c2feab2018-04-24 00:02:37 -0400315 output += printfun(s['types'] + s['Define'])
316 output += endianfun(s['types'] + s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +0200317 output += version_tuple(s, basename)
318 output += bottom_boilerplate.format(input_filename=basename,
Ole Troan8dbfb432019-04-24 14:31:18 +0200319 file_crc=s['file_crc'])
Ole Troan9d420872017-10-12 13:06:35 +0200320
321 return output