blob: 6c4ca356f3a2210e356f69010dfff942e4d2f53f [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
16#if defined(vl_msg_id)||defined(vl_union_id) \\
17 || defined(vl_printfun) ||defined(vl_endianfun) \\
18 || defined(vl_api_version)||defined(vl_typedefs) \\
19 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
20 || defined(vl_api_version_tuple)
21/* ok, something was selected */
22#else
23#warning no content included from {input_filename}
24#endif
25
26#define VL_API_PACKED(x) x __attribute__ ((packed))
27'''
28
29bottom_boilerplate = '''\
30/****** API CRC (whole file) *****/
31
32#ifdef vl_api_version
33vl_api_version({input_filename}, {file_crc:#08x})
34
35#endif
36'''
37
38
39def msg_ids(s):
40 output = '''\
41
42/****** Message ID / handler enum ******/
43
44#ifdef vl_msg_id
45'''
46
Ole Troan2c2feab2018-04-24 00:02:37 -040047 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020048 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
49 (t.name.upper(), t.name)
50 output += "#endif"
51
52 return output
53
54
55def msg_names(s):
56 output = '''\
57
58/****** Message names ******/
59
60#ifdef vl_msg_name
61'''
62
Ole Troan2c2feab2018-04-24 00:02:37 -040063 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020064 dont_trace = 0 if t.dont_trace else 1
65 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
66 output += "#endif"
67
68 return output
69
70
71def msg_name_crc_list(s, suffix):
72 output = '''\
73
74/****** Message name, crc list ******/
75
76#ifdef vl_msg_name_crc_list
77'''
78 output += "#define foreach_vl_msg_name_crc_%s " % suffix
79
Ole Troan2c2feab2018-04-24 00:02:37 -040080 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020081 output += "\\\n_(VL_API_%s, %s, %08x) " % \
82 (t.name.upper(), t.name, t.crc)
83 output += "\n#endif"
84
85 return output
86
87
88def duplicate_wrapper_head(name):
Ole Troan02143df2018-11-30 08:34:11 +010089 s = "#ifndef _vl_api_defined_%s\n" % name
90 s += "#define _vl_api_defined_%s\n" % name
Ole Troan9d420872017-10-12 13:06:35 +020091 return s
92
93
94def duplicate_wrapper_tail():
95 return '#endif\n\n'
96
97
Ole Troan413f4a52018-11-28 11:36:05 +010098def api2c(fieldtype):
99 mappingtable = {'string': 'vl_api_string_t', }
100 if fieldtype in mappingtable:
101 return mappingtable[fieldtype]
102 return fieldtype
103
104
Ole Troan53fffa12018-11-13 12:36:56 +0100105def typedefs(objs, aliases, filename):
Ole Troan9d420872017-10-12 13:06:35 +0200106 name = filename.replace('.', '_')
107 output = '''\
108
109
110/****** Typedefs ******/
111
112#ifdef vl_typedefs
113#ifndef included_{module}
114#define included_{module}
115'''
116 output = output.format(module=name)
Ole Troan53fffa12018-11-13 12:36:56 +0100117
118 for k, v in aliases.items():
119 output += duplicate_wrapper_head(k)
120 if 'length' in v:
121 output += 'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length'])
122 else:
123 output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k)
124 output += duplicate_wrapper_tail()
125
Ole Troan2c2feab2018-04-24 00:02:37 -0400126 for o in objs:
127 tname = o.__class__.__name__
128 output += duplicate_wrapper_head(o.name)
129 if tname == 'Enum':
Andrew Yourtchenko5c4b9f12019-03-19 14:52:29 +0100130 if o.enumtype == 'u32':
131 output += "typedef enum {\n"
132 else:
133 output += "typedef enum __attribute__((__packed__)) {\n"
134
Ole Troan2c2feab2018-04-24 00:02:37 -0400135 for b in o.block:
136 output += " %s = %s,\n" % (b[0], b[1])
137 output += '} vl_api_%s_t;\n' % o.name
Andrew Yourtchenko5c4b9f12019-03-19 14:52:29 +0100138 if o.enumtype != 'u32':
139 size1 = 'sizeof(vl_api_%s_t)' % o.name
140 size2 = 'sizeof(%s)' % o.enumtype
141 err_str = 'size of API enum %s is wrong' % o.name
142 output += 'STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str)
Ole Troan2c2feab2018-04-24 00:02:37 -0400143 else:
144 if tname == 'Union':
145 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200146 else:
Ole Troan2c2feab2018-04-24 00:02:37 -0400147 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
148 for b in o.block:
149 if b.type == 'Field':
Ole Troan413f4a52018-11-28 11:36:05 +0100150 output += " %s %s;\n" % (api2c(b.fieldtype), b.fieldname)
Ole Troan2c2feab2018-04-24 00:02:37 -0400151 elif b.type == 'Array':
152 if b.lengthfield:
Ole Troan413f4a52018-11-28 11:36:05 +0100153 output += " %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname)
Ole Troan2c2feab2018-04-24 00:02:37 -0400154 else:
Ole Troan413f4a52018-11-28 11:36:05 +0100155 output += " %s %s[%s];\n" % (api2c(b.fieldtype), b.fieldname,
Ole Troan2c2feab2018-04-24 00:02:37 -0400156 b.length)
157 else:
158 raise ValueError("Error in processing array type %s" % b)
Ole Troan9d420872017-10-12 13:06:35 +0200159
Ole Troan2c2feab2018-04-24 00:02:37 -0400160 output += '}) vl_api_%s_t;\n' % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200161 output += duplicate_wrapper_tail()
162
163 output += "\n#endif"
164 output += "\n#endif\n\n"
165
166 return output
167
168
169format_strings = {'u8': '%u',
170 'i8': '%d',
171 'u16': '%u',
172 'i16': '%d',
173 'u32': '%u',
174 'i32': '%ld',
175 'u64': '%llu',
176 'i64': '%llu',
177 'f64': '%.2f', }
178
179
Ole Troan2c2feab2018-04-24 00:02:37 -0400180def printfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200181 output = '''\
182/****** Print functions *****/
183#ifdef vl_printfun
184
185#ifdef LP64
186#define _uword_fmt \"%lld\"
187#define _uword_cast (long long)
188#else
189#define _uword_fmt \"%ld\"
190#define _uword_cast long
191#endif
192
193'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400194 for t in objs:
195 if t.__class__.__name__ == 'Enum':
196 continue
Ole Troan9d420872017-10-12 13:06:35 +0200197 if t.manual_print:
198 output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name
199 continue
200 output += duplicate_wrapper_head(t.name + '_t_print')
201 output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \
202 (t.name, t.name)
203 output += "void *handle)\n{\n"
204 output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name
205
206 for o in t.block:
207 if o.type != 'Field':
208 continue
209 if o.fieldtype in format_strings:
210 output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \
211 (o.fieldname, format_strings[o.fieldtype],
212 o.fieldname)
213
214 output += ' return handle;\n'
215 output += '}\n\n'
216 output += duplicate_wrapper_tail()
217
218 output += "\n#endif /* vl_printfun */\n"
219
220 return output
221
222
223endian_strings = {
224 'u16': 'clib_net_to_host_u16',
225 'u32': 'clib_net_to_host_u32',
226 'u64': 'clib_net_to_host_u64',
227 'i16': 'clib_net_to_host_u16',
228 'i32': 'clib_net_to_host_u32',
229 'i64': 'clib_net_to_host_u64',
230}
231
232
Ole Troan2c2feab2018-04-24 00:02:37 -0400233def endianfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200234 output = '''\
235
236/****** Endian swap functions *****/\n\
237#ifdef vl_endianfun
238
239#undef clib_net_to_host_uword
240#ifdef LP64
241#define clib_net_to_host_uword clib_net_to_host_u64
242#else
243#define clib_net_to_host_uword clib_net_to_host_u32
244#endif
245
246'''
247
Ole Troan2c2feab2018-04-24 00:02:37 -0400248 for t in objs:
249 if t.__class__.__name__ == 'Enum':
250 continue
Ole Troan9d420872017-10-12 13:06:35 +0200251 if t.manual_endian:
252 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
253 continue
254 output += duplicate_wrapper_head(t.name + '_t_endian')
255 output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \
256 (t.name, t.name)
257 output += "\n{\n"
258
259 for o in t.block:
260 if o.type != 'Field':
261 continue
262 if o.fieldtype in endian_strings:
263 output += " a->%s = %s(a->%s);\n" % \
264 (o.fieldname, endian_strings[o.fieldtype], o.fieldname)
265 else:
266 output += " /* a->%s = a->%s (no-op) */\n" % \
267 (o.fieldname, o.fieldname)
268
269 output += '}\n\n'
270 output += duplicate_wrapper_tail()
271 output += "\n#endif /* vl_endianfun */\n\n"
272
273 return output
274
275
276def version_tuple(s, module):
277 output = '''\
278/****** Version tuple *****/
279
280#ifdef vl_api_version_tuple
281
282'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400283 if 'version' in s['Option']:
284 v = s['Option']['version']
Ole Troan9d420872017-10-12 13:06:35 +0200285 (major, minor, patch) = v.split('.')
286 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
287 (module, major, minor, patch)
288
289 output += "\n#endif /* vl_api_version_tuple */\n\n"
290
291 return output
292
293
294#
295# Plugin entry point
296#
297def run(input_filename, s, file_crc):
298 basename = os.path.basename(input_filename)
299 filename, file_extension = os.path.splitext(basename)
300 output = top_boilerplate.format(datestring=datestring,
301 input_filename=basename)
302 output += msg_ids(s)
303 output += msg_names(s)
304 output += msg_name_crc_list(s, filename)
Ole Troan53fffa12018-11-13 12:36:56 +0100305 output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension)
Ole Troan2c2feab2018-04-24 00:02:37 -0400306 output += printfun(s['types'] + s['Define'])
307 output += endianfun(s['types'] + s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +0200308 output += version_tuple(s, basename)
309 output += bottom_boilerplate.format(input_filename=basename,
310 file_crc=file_crc)
311
312 return output