blob: c4c53662a825cadd7090434d54ce45d6e6b007b9 [file] [log] [blame]
Klement Sekera958b7502017-09-28 06:31:53 +02001#!/usr/bin/env python2
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02002
3import argparse
4import os
5import sys
6import logging
Klement Sekera2108c0c2018-08-24 11:43:20 +02007from vapi_json_parser import Field, Struct, Enum, Union, Message, JsonParser,\
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02008 SimpleType, StructType
9
10
11class CField(Field):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020012 def get_c_def(self):
13 if self.len is not None:
14 return "%s %s[%d]" % (self.type.get_c_name(), self.name, self.len)
15 else:
16 return "%s %s" % (self.type.get_c_name(), self.name)
17
18 def get_swap_to_be_code(self, struct, var):
19 if self.len is not None:
20 if self.len > 0:
Klement Sekeradc15be22017-06-12 06:49:33 +020021 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020022 " while(0);" % (
23 self.len,
24 self.type.get_swap_to_be_code(struct, "%s[i]" % var))
25 else:
26 if self.nelem_field.needs_byte_swap():
27 nelem_field = "%s(%s%s)" % (
28 self.nelem_field.type.get_swap_to_host_func_name(),
29 struct, self.nelem_field.name)
30 else:
31 nelem_field = "%s%s" % (struct, self.nelem_field.name)
32 return (
Klement Sekeradc15be22017-06-12 06:49:33 +020033 "do { unsigned i; for (i = 0; i < %s; ++i) { %s } }"
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020034 " while(0);" %
35 (nelem_field, self.type.get_swap_to_be_code(
36 struct, "%s[i]" % var)))
37 return self.type.get_swap_to_be_code(struct, "%s" % var)
38
39 def get_swap_to_host_code(self, struct, var):
40 if self.len is not None:
41 if self.len > 0:
Klement Sekeradc15be22017-06-12 06:49:33 +020042 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020043 " while(0);" % (
44 self.len,
45 self.type.get_swap_to_host_code(struct, "%s[i]" % var))
46 else:
47 # nelem_field already swapped to host here...
48 return (
Klement Sekeradc15be22017-06-12 06:49:33 +020049 "do { unsigned i; for (i = 0; i < %s%s; ++i) { %s } }"
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020050 " while(0);" %
51 (struct, self.nelem_field.name,
52 self.type.get_swap_to_host_code(
53 struct, "%s[i]" % var)))
54 return self.type.get_swap_to_host_code(struct, "%s" % var)
55
56 def needs_byte_swap(self):
57 return self.type.needs_byte_swap()
58
59
60class CStruct(Struct):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020061 def get_c_def(self):
62 return "\n".join([
Klement Sekera2108c0c2018-08-24 11:43:20 +020063 "typedef struct __attribute__((__packed__)) {\n%s;" % (
64 ";\n".join([" %s" % x.get_c_def()
65 for x in self.fields])),
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020066 "} %s;" % self.get_c_name()])
67
68
69class CSimpleType (SimpleType):
70
71 swap_to_be_dict = {
72 'i16': 'htobe16', 'u16': 'htobe16',
73 'i32': 'htobe32', 'u32': 'htobe32',
74 'i64': 'htobe64', 'u64': 'htobe64',
75 }
76
77 swap_to_host_dict = {
78 'i16': 'be16toh', 'u16': 'be16toh',
79 'i32': 'be32toh', 'u32': 'be32toh',
80 'i64': 'be64toh', 'u64': 'be64toh',
81 }
82
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020083 def get_c_name(self):
84 return self.name
85
86 def get_swap_to_be_func_name(self):
87 return self.swap_to_be_dict[self.name]
88
89 def get_swap_to_host_func_name(self):
90 return self.swap_to_host_dict[self.name]
91
Klement Sekera2108c0c2018-08-24 11:43:20 +020092 def get_swap_to_be_code(self, struct, var, cast=None):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020093 x = "%s%s" % (struct, var)
Klement Sekera2108c0c2018-08-24 11:43:20 +020094 return "%s = %s%s(%s);" % (x,
95 "(%s)" % cast if cast else "",
96 self.get_swap_to_be_func_name(), x)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020097
Klement Sekera2108c0c2018-08-24 11:43:20 +020098 def get_swap_to_host_code(self, struct, var, cast=None):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020099 x = "%s%s" % (struct, var)
Klement Sekera2108c0c2018-08-24 11:43:20 +0200100 return "%s = %s%s(%s);" % (x,
101 "(%s)" % cast if cast else "",
102 self.get_swap_to_host_func_name(), x)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200103
104 def needs_byte_swap(self):
105 try:
106 self.get_swap_to_host_func_name()
107 return True
108 except:
109 pass
110 return False
111
112
Klement Sekera2108c0c2018-08-24 11:43:20 +0200113class CEnum(Enum):
114 def get_c_name(self):
115 return "vapi_enum_%s" % self.name
116
117 def get_c_def(self):
118 return "typedef enum {\n%s\n} %s;" % (
119 "\n".join([" %s = %s," % (i, j) for i, j in self.value_pairs]),
120 self.get_c_name()
121 )
122
123 def needs_byte_swap(self):
124 return self.type.needs_byte_swap()
125
126 def get_swap_to_be_code(self, struct, var):
127 return self.type.get_swap_to_be_code(struct, var, self.get_c_name())
128
129 def get_swap_to_host_code(self, struct, var):
130 return self.type.get_swap_to_host_code(struct, var, self.get_c_name())
131
132
133class CUnion(Union):
134 def get_c_name(self):
135 return "vapi_union_%s" % self.name
136
137 def get_c_def(self):
138 return "typedef union {\n%s\n} %s;" % (
139 "\n".join([" %s %s;" % (i.get_c_name(), j)
140 for i, j in self.type_pairs]),
141 self.get_c_name()
142 )
143
144 def needs_byte_swap(self):
145 return False
146
147
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200148class CStructType (StructType, CStruct):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200149 def get_c_name(self):
150 return "vapi_type_%s" % self.name
151
152 def get_swap_to_be_func_name(self):
153 return "%s_hton" % self.get_c_name()
154
155 def get_swap_to_host_func_name(self):
156 return "%s_ntoh" % self.get_c_name()
157
158 def get_swap_to_be_func_decl(self):
159 return "void %s(%s *msg)" % (
160 self.get_swap_to_be_func_name(), self.get_c_name())
161
162 def get_swap_to_be_func_def(self):
163 return "%s\n{\n%s\n}" % (
164 self.get_swap_to_be_func_decl(),
165 "\n".join([
166 " %s" % p.get_swap_to_be_code("msg->", "%s" % p.name)
167 for p in self.fields if p.needs_byte_swap()]),
168 )
169
170 def get_swap_to_host_func_decl(self):
171 return "void %s(%s *msg)" % (
172 self.get_swap_to_host_func_name(), self.get_c_name())
173
174 def get_swap_to_host_func_def(self):
175 return "%s\n{\n%s\n}" % (
176 self.get_swap_to_host_func_decl(),
177 "\n".join([
178 " %s" % p.get_swap_to_host_code("msg->", "%s" % p.name)
179 for p in self.fields if p.needs_byte_swap()]),
180 )
181
182 def get_swap_to_be_code(self, struct, var):
183 return "%s(&%s%s);" % (self.get_swap_to_be_func_name(), struct, var)
184
185 def get_swap_to_host_code(self, struct, var):
186 return "%s(&%s%s);" % (self.get_swap_to_host_func_name(), struct, var)
187
188 def needs_byte_swap(self):
189 for f in self.fields:
190 if f.needs_byte_swap():
191 return True
192 return False
193
194
195class CMessage (Message):
Klement Sekera2108c0c2018-08-24 11:43:20 +0200196 def __init__(self, logger, definition, json_parser):
197 super(CMessage, self).__init__(logger, definition, json_parser)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200198 self.payload_members = [
199 " %s" % p.get_c_def()
200 for p in self.fields
201 if p.type != self.header
202 ]
203
204 def has_payload(self):
205 return len(self.payload_members) > 0
206
207 def get_msg_id_name(self):
208 return "vapi_msg_id_%s" % self.name
209
210 def get_c_name(self):
211 return "vapi_msg_%s" % self.name
212
213 def get_payload_struct_name(self):
214 return "vapi_payload_%s" % self.name
215
216 def get_alloc_func_vla_field_length_name(self, field):
217 return "%s_array_size" % field.name
218
219 def get_alloc_func_name(self):
220 return "vapi_alloc_%s" % self.name
221
Klement Sekeradc15be22017-06-12 06:49:33 +0200222 def get_alloc_vla_param_names(self):
223 return [self.get_alloc_func_vla_field_length_name(f)
224 for f in self.fields
225 if f.nelem_field is not None]
226
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200227 def get_alloc_func_decl(self):
228 return "%s* %s(struct vapi_ctx_s *ctx%s)" % (
229 self.get_c_name(),
230 self.get_alloc_func_name(),
Klement Sekeradc15be22017-06-12 06:49:33 +0200231 "".join([", size_t %s" % n for n in
232 self.get_alloc_vla_param_names()]))
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200233
234 def get_alloc_func_def(self):
235 extra = []
236 if self.header.has_field('client_index'):
237 extra.append(
238 " msg->header.client_index = vapi_get_client_index(ctx);")
239 if self.header.has_field('context'):
240 extra.append(" msg->header.context = 0;")
241 return "\n".join([
242 "%s" % self.get_alloc_func_decl(),
243 "{",
244 " %s *msg = NULL;" % self.get_c_name(),
245 " const size_t size = sizeof(%s)%s;" % (
246 self.get_c_name(),
247 "".join([
248 " + sizeof(msg->payload.%s[0]) * %s" % (
249 f.name,
250 self.get_alloc_func_vla_field_length_name(f))
251 for f in self.fields
252 if f.nelem_field is not None
253 ])),
Klement Sekeradc15be22017-06-12 06:49:33 +0200254 " /* cast here required to play nicely with C++ world ... */",
255 " msg = (%s*)vapi_msg_alloc(ctx, size);" % self.get_c_name(),
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200256 " if (!msg) {",
257 " return NULL;",
258 " }",
259 ] + extra + [
260 " msg->header._vl_msg_id = vapi_lookup_vl_msg_id(ctx, %s);" %
261 self.get_msg_id_name(),
262 "\n".join([" msg->payload.%s = %s;" % (
263 f.nelem_field.name,
264 self.get_alloc_func_vla_field_length_name(f))
265 for f in self.fields
266 if f.nelem_field is not None]),
267 " return msg;",
268 "}"])
269
270 def get_calc_msg_size_func_name(self):
271 return "vapi_calc_%s_msg_size" % self.name
272
273 def get_calc_msg_size_func_decl(self):
274 return "uword %s(%s *msg)" % (
275 self.get_calc_msg_size_func_name(),
276 self.get_c_name())
277
278 def get_calc_msg_size_func_def(self):
279 return "\n".join([
280 "%s" % self.get_calc_msg_size_func_decl(),
281 "{",
282 " return sizeof(*msg)%s;" %
283 "".join(["+ msg->payload.%s * sizeof(msg->payload.%s[0])" % (
284 f.nelem_field.name,
285 f.name)
286 for f in self.fields
287 if f.nelem_field is not None
288 ]),
289 "}",
290 ])
291
292 def get_c_def(self):
293 if self.has_payload():
294 return "\n".join([
295 "typedef struct __attribute__ ((__packed__)) {",
296 "%s; " %
297 ";\n".join(self.payload_members),
298 "} %s;" % self.get_payload_struct_name(),
299 "",
300 "typedef struct __attribute__ ((__packed__)) {",
301 (" %s %s;" % (self.header.get_c_name(),
302 self.fields[0].name)
303 if self.header is not None else ""),
304 " %s payload;" % self.get_payload_struct_name(),
305 "} %s;" % self.get_c_name(), ])
306 else:
307 return "\n".join([
308 "typedef struct __attribute__ ((__packed__)) {",
309 (" %s %s;" % (self.header.get_c_name(),
310 self.fields[0].name)
311 if self.header is not None else ""),
312 "} %s;" % self.get_c_name(), ])
313
314 def get_swap_payload_to_host_func_name(self):
315 return "%s_payload_ntoh" % self.get_c_name()
316
317 def get_swap_payload_to_be_func_name(self):
318 return "%s_payload_hton" % self.get_c_name()
319
320 def get_swap_payload_to_host_func_decl(self):
321 return "void %s(%s *payload)" % (
322 self.get_swap_payload_to_host_func_name(),
323 self.get_payload_struct_name())
324
325 def get_swap_payload_to_be_func_decl(self):
326 return "void %s(%s *payload)" % (
327 self.get_swap_payload_to_be_func_name(),
328 self.get_payload_struct_name())
329
330 def get_swap_payload_to_be_func_def(self):
331 return "%s\n{\n%s\n}" % (
332 self.get_swap_payload_to_be_func_decl(),
333 "\n".join([
334 " %s" % p.get_swap_to_be_code("payload->", "%s" % p.name)
335 for p in self.fields
336 if p.needs_byte_swap() and p.type != self.header]),
337 )
338
339 def get_swap_payload_to_host_func_def(self):
340 return "%s\n{\n%s\n}" % (
341 self.get_swap_payload_to_host_func_decl(),
342 "\n".join([
343 " %s" % p.get_swap_to_host_code("payload->", "%s" % p.name)
344 for p in self.fields
345 if p.needs_byte_swap() and p.type != self.header]),
346 )
347
348 def get_swap_to_host_func_name(self):
349 return "%s_ntoh" % self.get_c_name()
350
351 def get_swap_to_be_func_name(self):
352 return "%s_hton" % self.get_c_name()
353
354 def get_swap_to_host_func_decl(self):
355 return "void %s(%s *msg)" % (
356 self.get_swap_to_host_func_name(), self.get_c_name())
357
358 def get_swap_to_be_func_decl(self):
359 return "void %s(%s *msg)" % (
360 self.get_swap_to_be_func_name(), self.get_c_name())
361
362 def get_swap_to_be_func_def(self):
363 return "\n".join([
364 "%s" % self.get_swap_to_be_func_decl(),
365 "{",
366 (" VAPI_DBG(\"Swapping `%s'@%%p to big endian\", msg);" %
367 self.get_c_name()),
368 " %s(&msg->header);" % self.header.get_swap_to_be_func_name()
369 if self.header is not None else "",
370 " %s(&msg->payload);" % self.get_swap_payload_to_be_func_name()
371 if self.has_payload() else "",
372 "}",
373 ])
374
375 def get_swap_to_host_func_def(self):
376 return "\n".join([
377 "%s" % self.get_swap_to_host_func_decl(),
378 "{",
379 (" VAPI_DBG(\"Swapping `%s'@%%p to host byte order\", msg);" %
380 self.get_c_name()),
381 " %s(&msg->header);" % self.header.get_swap_to_host_func_name()
382 if self.header is not None else "",
383 " %s(&msg->payload);" % self.get_swap_payload_to_host_func_name()
384 if self.has_payload() else "",
385 "}",
386 ])
387
388 def get_op_func_name(self):
389 return "vapi_%s" % self.name
390
391 def get_op_func_decl(self):
392 if self.reply.has_payload():
393 return "vapi_error_e %s(%s)" % (
394 self.get_op_func_name(),
395 ",\n ".join([
396 'struct vapi_ctx_s *ctx',
397 '%s *msg' % self.get_c_name(),
398 'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
399 ' void *callback_ctx',
400 ' vapi_error_e rv',
401 ' bool is_last',
402 ' %s *reply)' %
403 self.reply.get_payload_struct_name(),
404 'void *callback_ctx',
405 ])
406 )
407 else:
408 return "vapi_error_e %s(%s)" % (
409 self.get_op_func_name(),
410 ",\n ".join([
411 'struct vapi_ctx_s *ctx',
412 '%s *msg' % self.get_c_name(),
413 'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
414 ' void *callback_ctx',
415 ' vapi_error_e rv',
416 ' bool is_last)',
417 'void *callback_ctx',
418 ])
419 )
420
421 def get_op_func_def(self):
422 return "\n".join([
423 "%s" % self.get_op_func_decl(),
424 "{",
425 " if (!msg || !callback) {",
426 " return VAPI_EINVAL;",
427 " }",
428 " if (vapi_is_nonblocking(ctx) && vapi_requests_full(ctx)) {",
429 " return VAPI_EAGAIN;",
430 " }",
431 " vapi_error_e rv;",
432 " if (VAPI_OK != (rv = vapi_producer_lock (ctx))) {",
433 " return rv;",
434 " }",
435 " u32 req_context = vapi_gen_req_context(ctx);",
436 " msg->header.context = req_context;",
437 " %s(msg);" % self.get_swap_to_be_func_name(),
438 (" if (VAPI_OK == (rv = vapi_send_with_control_ping "
439 "(ctx, msg, req_context))) {"
Klement Sekera2108c0c2018-08-24 11:43:20 +0200440 if self.reply_is_stream else
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200441 " if (VAPI_OK == (rv = vapi_send (ctx, msg))) {"
442 ),
443 (" vapi_store_request(ctx, req_context, %s, "
444 "(vapi_cb_t)callback, callback_ctx);" %
Klement Sekera2108c0c2018-08-24 11:43:20 +0200445 ("true" if self.reply_is_stream else "false")),
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200446 " if (VAPI_OK != vapi_producer_unlock (ctx)) {",
447 " abort (); /* this really shouldn't happen */",
448 " }",
449 " if (vapi_is_nonblocking(ctx)) {",
450 " rv = VAPI_OK;",
451 " } else {",
452 " rv = vapi_dispatch(ctx);",
453 " }",
454 " } else {",
455 " %s(msg);" % self.get_swap_to_host_func_name(),
456 " if (VAPI_OK != vapi_producer_unlock (ctx)) {",
457 " abort (); /* this really shouldn't happen */",
458 " }",
459 " }",
460 " return rv;",
461 "}",
462 "",
463 ])
464
465 def get_event_cb_func_decl(self):
Klement Sekera2108c0c2018-08-24 11:43:20 +0200466 if not self.is_reply and not self.is_event:
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200467 raise Exception(
Klement Sekeradc15be22017-06-12 06:49:33 +0200468 "Cannot register event callback for non-reply message")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200469 if self.has_payload():
470 return "\n".join([
471 "void vapi_set_%s_event_cb (" %
472 self.get_c_name(),
473 " struct vapi_ctx_s *ctx, ",
474 (" vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
475 "void *callback_ctx, %s *payload)," %
476 self.get_payload_struct_name()),
477 " void *callback_ctx)",
478 ])
479 else:
480 return "\n".join([
481 "void vapi_set_%s_event_cb (" %
482 self.get_c_name(),
483 " struct vapi_ctx_s *ctx, ",
484 " vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
485 "void *callback_ctx),",
486 " void *callback_ctx)",
487 ])
488
489 def get_event_cb_func_def(self):
Klement Sekera2108c0c2018-08-24 11:43:20 +0200490 if not self.is_reply and not self.is_event:
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200491 raise Exception(
492 "Cannot register event callback for non-reply function")
493 return "\n".join([
494 "%s" % self.get_event_cb_func_decl(),
495 "{",
496 (" vapi_set_event_cb(ctx, %s, (vapi_event_cb)callback, "
497 "callback_ctx);" %
498 self.get_msg_id_name()),
499 "}"])
500
501 def get_c_metadata_struct_name(self):
502 return "__vapi_metadata_%s" % self.name
503
504 def get_c_constructor(self):
505 has_context = False
506 if self.header is not None:
507 has_context = self.header.has_field('context')
508 return '\n'.join([
509 'static void __attribute__((constructor)) __vapi_constructor_%s()'
510 % self.name,
511 '{',
512 ' static const char name[] = "%s";' % self.name,
513 ' static const char name_with_crc[] = "%s_%s";'
514 % (self.name, self.crc[2:]),
515 ' static vapi_message_desc_t %s = {' %
516 self.get_c_metadata_struct_name(),
517 ' name,',
518 ' sizeof(name) - 1,',
519 ' name_with_crc,',
520 ' sizeof(name_with_crc) - 1,',
521 ' true,' if has_context else ' false,',
522 ' offsetof(%s, context),' % self.header.get_c_name()
523 if has_context else ' 0,',
524 (' offsetof(%s, payload),' % self.get_c_name())
Klement Sekeradab732a2018-07-04 13:43:46 +0200525 if self.has_payload() else ' VAPI_INVALID_MSG_ID,',
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200526 ' sizeof(%s),' % self.get_c_name(),
527 ' (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
528 ' (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
Klement Sekeradab732a2018-07-04 13:43:46 +0200529 ' VAPI_INVALID_MSG_ID,',
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200530 ' };',
531 '',
532 ' %s = vapi_register_msg(&%s);' %
533 (self.get_msg_id_name(), self.get_c_metadata_struct_name()),
534 ' VAPI_DBG("Assigned msg id %%d to %s", %s);' %
535 (self.name, self.get_msg_id_name()),
536 '}',
537 ])
538
539
540vapi_send_with_control_ping = """
541static inline vapi_error_e
542vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
543{
544 vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
545 if (!ping)
546 {
547 return VAPI_ENOMEM;
548 }
549 ping->header.context = context;
550 vapi_msg_control_ping_hton (ping);
551 return vapi_send2 (ctx, msg, ping);
552}
553"""
554
555
Klement Sekera1732e472018-08-28 17:23:18 +0200556def emit_definition(parser, json_file, emitted, o):
Klement Sekera2108c0c2018-08-24 11:43:20 +0200557 if o in emitted:
558 return
Klement Sekera2108c0c2018-08-24 11:43:20 +0200559 if o.name in ("msg_header1_t", "msg_header2_t"):
560 return
561 if hasattr(o, "depends"):
562 for x in o.depends:
Klement Sekera1732e472018-08-28 17:23:18 +0200563 emit_definition(parser, json_file, emitted, x)
Klement Sekera2108c0c2018-08-24 11:43:20 +0200564 if hasattr(o, "reply"):
Klement Sekera1732e472018-08-28 17:23:18 +0200565 emit_definition(parser, json_file, emitted, o.reply)
Klement Sekera2108c0c2018-08-24 11:43:20 +0200566 if hasattr(o, "get_c_def"):
567 if (o not in parser.enums_by_json[json_file] and
568 o not in parser.types_by_json[json_file] and
569 o not in parser.unions_by_json[json_file] and
570 o.name not in parser.messages_by_json[json_file]):
571 return
Klement Sekera2108c0c2018-08-24 11:43:20 +0200572 guard = "defined_%s" % o.get_c_name()
573 print("#ifndef %s" % guard)
574 print("#define %s" % guard)
575 print("%s" % o.get_c_def())
576 print("")
577 function_attrs = "static inline "
578 if o.name in parser.messages_by_json[json_file]:
Klement Sekera2108c0c2018-08-24 11:43:20 +0200579 if o.has_payload():
Klement Sekera2108c0c2018-08-24 11:43:20 +0200580 print("%s%s" % (function_attrs,
581 o.get_swap_payload_to_be_func_def()))
582 print("")
583 print("%s%s" % (function_attrs,
584 o.get_swap_payload_to_host_func_def()))
585 print("")
586 print("%s%s" % (function_attrs, o.get_swap_to_be_func_def()))
587 print("")
588 print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
589 print("")
590 print("%s%s" % (function_attrs, o.get_calc_msg_size_func_def()))
591 print("")
592 if not o.is_reply and not o.is_event:
593 print("%s%s" % (function_attrs, o.get_alloc_func_def()))
594 print("")
595 print("%s%s" % (function_attrs, o.get_op_func_def()))
596 print("")
597 print("%s" % o.get_c_constructor())
598 print("")
Klement Sekera1732e472018-08-28 17:23:18 +0200599 if o.is_reply or o.is_event:
Klement Sekera2108c0c2018-08-24 11:43:20 +0200600 print("%s%s;" % (function_attrs, o.get_event_cb_func_def()))
601 print("")
602 elif hasattr(o, "get_swap_to_be_func_def"):
603 print("%s%s" % (function_attrs, o.get_swap_to_be_func_def()))
604 print("")
605 print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
606 print("")
607 print("#endif")
608 emitted.append(o)
609
610
Klement Sekeradc15be22017-06-12 06:49:33 +0200611def gen_json_unified_header(parser, logger, j, io, name):
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200612 d, f = os.path.split(j)
Klement Sekeradc15be22017-06-12 06:49:33 +0200613 logger.info("Generating header `%s'" % name)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200614 orig_stdout = sys.stdout
615 sys.stdout = io
616 include_guard = "__included_%s" % (
617 j.replace(".", "_").replace("/", "_").replace("-", "_"))
618 print("#ifndef %s" % include_guard)
619 print("#define %s" % include_guard)
620 print("")
Klement Sekeradc15be22017-06-12 06:49:33 +0200621 print("#include <stdlib.h>")
622 print("#include <stddef.h>")
623 print("#include <arpa/inet.h>")
624 print("#include <vapi/vapi_internal.h>")
625 print("#include <vapi/vapi.h>")
626 print("#include <vapi/vapi_dbg.h>")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200627 print("")
Klement Sekeradc15be22017-06-12 06:49:33 +0200628 print("#ifdef __cplusplus")
629 print("extern \"C\" {")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200630 print("#endif")
Klement Sekeradc15be22017-06-12 06:49:33 +0200631 if name == "vpe.api.vapi.h":
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200632 print("")
633 print("static inline vapi_error_e vapi_send_with_control_ping "
634 "(vapi_ctx_t ctx, void * msg, u32 context);")
635 else:
Klement Sekeradc15be22017-06-12 06:49:33 +0200636 print("#include <vapi/vpe.api.vapi.h>")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200637 print("")
638 for m in parser.messages_by_json[j].values():
639 print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
640 print("")
641 print("#define DEFINE_VAPI_MSG_IDS_%s\\" %
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200642 f.replace(".", "_").replace("/", "_").replace("-", "_").upper())
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200643 print("\\\n".join([
644 " vapi_msg_id_t %s;" % m.get_msg_id_name()
645 for m in parser.messages_by_json[j].values()
646 ]))
647 print("")
648 print("")
Klement Sekera2108c0c2018-08-24 11:43:20 +0200649 emitted = []
650 for e in parser.enums_by_json[j]:
Klement Sekera1732e472018-08-28 17:23:18 +0200651 emit_definition(parser, j, emitted, e)
Klement Sekera2108c0c2018-08-24 11:43:20 +0200652 for u in parser.unions_by_json[j]:
Klement Sekera1732e472018-08-28 17:23:18 +0200653 emit_definition(parser, j, emitted, u)
Ole Troan52ca7562018-03-06 17:45:32 +0100654 for t in parser.types_by_json[j]:
Klement Sekera1732e472018-08-28 17:23:18 +0200655 emit_definition(parser, j, emitted, t)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200656 for m in parser.messages_by_json[j].values():
Klement Sekera1732e472018-08-28 17:23:18 +0200657 emit_definition(parser, j, emitted, m)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200658
659 print("")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200660
Klement Sekeradc15be22017-06-12 06:49:33 +0200661 if name == "vpe.api.vapi.h":
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200662 print("%s" % vapi_send_with_control_ping)
663 print("")
664
Klement Sekeradc15be22017-06-12 06:49:33 +0200665 print("#ifdef __cplusplus")
666 print("}")
667 print("#endif")
668 print("")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200669 print("#endif")
670 sys.stdout = orig_stdout
671
672
Klement Sekeradc15be22017-06-12 06:49:33 +0200673def json_to_c_header_name(json_name):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200674 if json_name.endswith(".json"):
675 return "%s.vapi.h" % os.path.splitext(json_name)[0]
676 raise Exception("Unexpected json name `%s'!" % json_name)
677
678
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200679def gen_c_unified_headers(parser, logger, prefix, remove_path):
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200680 if prefix == "" or prefix is None:
681 prefix = ""
682 else:
683 prefix = "%s/" % prefix
684 for j in parser.json_files:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200685 if remove_path:
686 d, f = os.path.split(j)
687 else:
688 f = j
689 with open('%s%s' % (prefix, json_to_c_header_name(f)), "w") as io:
Klement Sekeradc15be22017-06-12 06:49:33 +0200690 gen_json_unified_header(
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200691 parser, logger, j, io, json_to_c_header_name(f))
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200692
693
694if __name__ == '__main__':
695 try:
696 verbose = int(os.getenv("V", 0))
697 except:
698 verbose = 0
699
700 if verbose >= 2:
701 log_level = 10
702 elif verbose == 1:
703 log_level = 20
704 else:
705 log_level = 40
706
707 logging.basicConfig(stream=sys.stdout, level=log_level)
708 logger = logging.getLogger("VAPI C GEN")
709 logger.setLevel(log_level)
710
Klement Sekeradc15be22017-06-12 06:49:33 +0200711 argparser = argparse.ArgumentParser(description="VPP C API generator")
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200712 argparser.add_argument('files', metavar='api-file', action='append',
713 type=str, help='json api file'
714 '(may be specified multiple times)')
715 argparser.add_argument('--prefix', action='store', default=None,
716 help='path prefix')
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200717 argparser.add_argument('--remove-path', action='store_true',
718 help='remove path from filename')
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200719 args = argparser.parse_args()
720
721 jsonparser = JsonParser(logger, args.files,
722 simple_type_class=CSimpleType,
Klement Sekera2108c0c2018-08-24 11:43:20 +0200723 enum_class=CEnum,
724 union_class=CUnion,
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200725 struct_type_class=CStructType,
726 field_class=CField,
727 message_class=CMessage)
728
729 # not using the model of having separate generated header and code files
730 # with generated symbols present in shared library (per discussion with
731 # Damjan), to avoid symbol version issues in .so
732 # gen_c_headers_and_code(jsonparser, logger, args.prefix)
733
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200734 gen_c_unified_headers(jsonparser, logger, args.prefix, args.remove_path)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200735
736 for e in jsonparser.exceptions:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200737 logger.warning(e)