blob: c9e543f486ba1086e643ddb0a4455126ccfc47db [file] [log] [blame]
Ole Troan9d420872017-10-12 13:06:35 +02001# C generation
2import datetime
3import os
4
5datestring = datetime.datetime.now()
6input_filename = 'inputfil'
7top_boilerplate = '''\
8/*
9 * VLIB API definitions {datestring}
10 * Input file: {input_filename}
11 * Automatically generated: please edit the input file NOT this file!
12 */
13
14#if defined(vl_msg_id)||defined(vl_union_id) \\
15 || defined(vl_printfun) ||defined(vl_endianfun) \\
16 || defined(vl_api_version)||defined(vl_typedefs) \\
17 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
18 || defined(vl_api_version_tuple)
19/* ok, something was selected */
20#else
21#warning no content included from {input_filename}
22#endif
23
24#define VL_API_PACKED(x) x __attribute__ ((packed))
25'''
26
27bottom_boilerplate = '''\
28/****** API CRC (whole file) *****/
29
30#ifdef vl_api_version
31vl_api_version({input_filename}, {file_crc:#08x})
32
33#endif
34'''
35
36
37def msg_ids(s):
38 output = '''\
39
40/****** Message ID / handler enum ******/
41
42#ifdef vl_msg_id
43'''
44
Ole Troan2c2feab2018-04-24 00:02:37 -040045 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020046 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
47 (t.name.upper(), t.name)
48 output += "#endif"
49
50 return output
51
52
53def msg_names(s):
54 output = '''\
55
56/****** Message names ******/
57
58#ifdef vl_msg_name
59'''
60
Ole Troan2c2feab2018-04-24 00:02:37 -040061 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020062 dont_trace = 0 if t.dont_trace else 1
63 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
64 output += "#endif"
65
66 return output
67
68
69def msg_name_crc_list(s, suffix):
70 output = '''\
71
72/****** Message name, crc list ******/
73
74#ifdef vl_msg_name_crc_list
75'''
76 output += "#define foreach_vl_msg_name_crc_%s " % suffix
77
Ole Troan2c2feab2018-04-24 00:02:37 -040078 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +020079 output += "\\\n_(VL_API_%s, %s, %08x) " % \
80 (t.name.upper(), t.name, t.crc)
81 output += "\n#endif"
82
83 return output
84
85
86def duplicate_wrapper_head(name):
87 s = "#ifndef defined_%s\n" % name
88 s += "#define defined_%s\n" % name
89 return s
90
91
92def duplicate_wrapper_tail():
93 return '#endif\n\n'
94
95
Ole Troan2c2feab2018-04-24 00:02:37 -040096def typedefs(objs, filename):
Ole Troan9d420872017-10-12 13:06:35 +020097 name = filename.replace('.', '_')
98 output = '''\
99
100
101/****** Typedefs ******/
102
103#ifdef vl_typedefs
104#ifndef included_{module}
105#define included_{module}
106'''
107 output = output.format(module=name)
Ole Troan2c2feab2018-04-24 00:02:37 -0400108 for o in objs:
109 tname = o.__class__.__name__
110 output += duplicate_wrapper_head(o.name)
111 if tname == 'Enum':
112 output += "typedef enum {\n"
113 for b in o.block:
114 output += " %s = %s,\n" % (b[0], b[1])
115 output += '} vl_api_%s_t;\n' % o.name
116 else:
117 if tname == 'Union':
118 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200119 else:
Ole Troan2c2feab2018-04-24 00:02:37 -0400120 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
121 for b in o.block:
122 if b.type == 'Field':
123 output += " %s %s;\n" % (b.fieldtype, b.fieldname)
124 elif b.type == 'Array':
125 if b.lengthfield:
126 output += " %s %s[0];\n" % (b.fieldtype, b.fieldname)
127 else:
128 output += " %s %s[%s];\n" % (b.fieldtype, b.fieldname,
129 b.length)
130 else:
131 raise ValueError("Error in processing array type %s" % b)
Ole Troan9d420872017-10-12 13:06:35 +0200132
Ole Troan2c2feab2018-04-24 00:02:37 -0400133 output += '}) vl_api_%s_t;\n' % o.name
Ole Troan9d420872017-10-12 13:06:35 +0200134 output += duplicate_wrapper_tail()
135
136 output += "\n#endif"
137 output += "\n#endif\n\n"
138
139 return output
140
141
142format_strings = {'u8': '%u',
143 'i8': '%d',
144 'u16': '%u',
145 'i16': '%d',
146 'u32': '%u',
147 'i32': '%ld',
148 'u64': '%llu',
149 'i64': '%llu',
150 'f64': '%.2f', }
151
152
Ole Troan2c2feab2018-04-24 00:02:37 -0400153def printfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200154 output = '''\
155/****** Print functions *****/
156#ifdef vl_printfun
157
158#ifdef LP64
159#define _uword_fmt \"%lld\"
160#define _uword_cast (long long)
161#else
162#define _uword_fmt \"%ld\"
163#define _uword_cast long
164#endif
165
166'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400167 for t in objs:
168 if t.__class__.__name__ == 'Enum':
169 continue
Ole Troan9d420872017-10-12 13:06:35 +0200170 if t.manual_print:
171 output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name
172 continue
173 output += duplicate_wrapper_head(t.name + '_t_print')
174 output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \
175 (t.name, t.name)
176 output += "void *handle)\n{\n"
177 output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name
178
179 for o in t.block:
180 if o.type != 'Field':
181 continue
182 if o.fieldtype in format_strings:
183 output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \
184 (o.fieldname, format_strings[o.fieldtype],
185 o.fieldname)
186
187 output += ' return handle;\n'
188 output += '}\n\n'
189 output += duplicate_wrapper_tail()
190
191 output += "\n#endif /* vl_printfun */\n"
192
193 return output
194
195
196endian_strings = {
197 'u16': 'clib_net_to_host_u16',
198 'u32': 'clib_net_to_host_u32',
199 'u64': 'clib_net_to_host_u64',
200 'i16': 'clib_net_to_host_u16',
201 'i32': 'clib_net_to_host_u32',
202 'i64': 'clib_net_to_host_u64',
203}
204
205
Ole Troan2c2feab2018-04-24 00:02:37 -0400206def endianfun(objs):
Ole Troan9d420872017-10-12 13:06:35 +0200207 output = '''\
208
209/****** Endian swap functions *****/\n\
210#ifdef vl_endianfun
211
212#undef clib_net_to_host_uword
213#ifdef LP64
214#define clib_net_to_host_uword clib_net_to_host_u64
215#else
216#define clib_net_to_host_uword clib_net_to_host_u32
217#endif
218
219'''
220
Ole Troan2c2feab2018-04-24 00:02:37 -0400221 for t in objs:
222 if t.__class__.__name__ == 'Enum':
223 continue
Ole Troan9d420872017-10-12 13:06:35 +0200224 if t.manual_endian:
225 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
226 continue
227 output += duplicate_wrapper_head(t.name + '_t_endian')
228 output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \
229 (t.name, t.name)
230 output += "\n{\n"
231
232 for o in t.block:
233 if o.type != 'Field':
234 continue
235 if o.fieldtype in endian_strings:
236 output += " a->%s = %s(a->%s);\n" % \
237 (o.fieldname, endian_strings[o.fieldtype], o.fieldname)
238 else:
239 output += " /* a->%s = a->%s (no-op) */\n" % \
240 (o.fieldname, o.fieldname)
241
242 output += '}\n\n'
243 output += duplicate_wrapper_tail()
244 output += "\n#endif /* vl_endianfun */\n\n"
245
246 return output
247
248
249def version_tuple(s, module):
250 output = '''\
251/****** Version tuple *****/
252
253#ifdef vl_api_version_tuple
254
255'''
Ole Troan2c2feab2018-04-24 00:02:37 -0400256 if 'version' in s['Option']:
257 v = s['Option']['version']
Ole Troan9d420872017-10-12 13:06:35 +0200258 (major, minor, patch) = v.split('.')
259 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
260 (module, major, minor, patch)
261
262 output += "\n#endif /* vl_api_version_tuple */\n\n"
263
264 return output
265
266
267#
268# Plugin entry point
269#
270def run(input_filename, s, file_crc):
271 basename = os.path.basename(input_filename)
272 filename, file_extension = os.path.splitext(basename)
273 output = top_boilerplate.format(datestring=datestring,
274 input_filename=basename)
275 output += msg_ids(s)
276 output += msg_names(s)
277 output += msg_name_crc_list(s, filename)
Ole Troan2c2feab2018-04-24 00:02:37 -0400278 output += typedefs(s['types'] + s['Define'], filename + file_extension)
279 output += printfun(s['types'] + s['Define'])
280 output += endianfun(s['types'] + s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +0200281 output += version_tuple(s, basename)
282 output += bottom_boilerplate.format(input_filename=basename,
283 file_crc=file_crc)
284
285 return output