Fix coverity warnings in VOM and VAPI
[vpp.git] / src / vpp-api / vapi / vapi_c_gen.py
1 #!/usr/bin/env python2
2
3 import argparse
4 import os
5 import sys
6 import logging
7 from vapi_json_parser import Field, Struct, Message, JsonParser,\
8     SimpleType, StructType
9
10
11 class CField(Field):
12     def __init__(
13             self,
14             field_name,
15             field_type,
16             array_len=None,
17             nelem_field=None):
18         super(CField, self).__init__(
19             field_name, field_type, array_len, nelem_field)
20
21     def get_c_def(self):
22         if self.len is not None:
23             return "%s %s[%d]" % (self.type.get_c_name(), self.name, self.len)
24         else:
25             return "%s %s" % (self.type.get_c_name(), self.name)
26
27     def get_swap_to_be_code(self, struct, var):
28         if self.len is not None:
29             if self.len > 0:
30                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
31                     " while(0);" % (
32                         self.len,
33                         self.type.get_swap_to_be_code(struct, "%s[i]" % var))
34             else:
35                 if self.nelem_field.needs_byte_swap():
36                     nelem_field = "%s(%s%s)" % (
37                         self.nelem_field.type.get_swap_to_host_func_name(),
38                         struct, self.nelem_field.name)
39                 else:
40                     nelem_field = "%s%s" % (struct, self.nelem_field.name)
41                 return (
42                     "do { unsigned i; for (i = 0; i < %s; ++i) { %s } }"
43                     " while(0);" %
44                     (nelem_field, self.type.get_swap_to_be_code(
45                         struct, "%s[i]" % var)))
46         return self.type.get_swap_to_be_code(struct, "%s" % var)
47
48     def get_swap_to_host_code(self, struct, var):
49         if self.len is not None:
50             if self.len > 0:
51                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
52                     " while(0);" % (
53                         self.len,
54                         self.type.get_swap_to_host_code(struct, "%s[i]" % var))
55             else:
56                 # nelem_field already swapped to host here...
57                 return (
58                     "do { unsigned i; for (i = 0; i < %s%s; ++i) { %s } }"
59                     " while(0);" %
60                     (struct, self.nelem_field.name,
61                      self.type.get_swap_to_host_code(
62                          struct, "%s[i]" % var)))
63         return self.type.get_swap_to_host_code(struct, "%s" % var)
64
65     def needs_byte_swap(self):
66         return self.type.needs_byte_swap()
67
68
69 class CStruct(Struct):
70     def __init__(self, name, fields):
71         super(CStruct, self).__init__(name, fields)
72
73     def get_c_def(self):
74         return "\n".join([
75             "typedef struct __attribute__((__packed__)) {",
76             "%s;" % ";\n".join(["  %s" % x.get_c_def()
77                                 for x in self.fields]),
78             "} %s;" % self.get_c_name()])
79
80
81 class CSimpleType (SimpleType):
82
83     swap_to_be_dict = {
84         'i16': 'htobe16', 'u16': 'htobe16',
85         'i32': 'htobe32', 'u32': 'htobe32',
86         'i64': 'htobe64', 'u64': 'htobe64',
87     }
88
89     swap_to_host_dict = {
90         'i16': 'be16toh', 'u16': 'be16toh',
91         'i32': 'be32toh', 'u32': 'be32toh',
92         'i64': 'be64toh', 'u64': 'be64toh',
93     }
94
95     def __init__(self, name):
96         super(CSimpleType, self).__init__(name)
97
98     def get_c_name(self):
99         return self.name
100
101     def get_swap_to_be_func_name(self):
102         return self.swap_to_be_dict[self.name]
103
104     def get_swap_to_host_func_name(self):
105         return self.swap_to_host_dict[self.name]
106
107     def get_swap_to_be_code(self, struct, var):
108         x = "%s%s" % (struct, var)
109         return "%s = %s(%s);" % (x, self.get_swap_to_be_func_name(), x)
110
111     def get_swap_to_host_code(self, struct, var):
112         x = "%s%s" % (struct, var)
113         return "%s = %s(%s);" % (x, self.get_swap_to_host_func_name(), x)
114
115     def needs_byte_swap(self):
116         try:
117             self.get_swap_to_host_func_name()
118             return True
119         except:
120             pass
121         return False
122
123
124 class CStructType (StructType, CStruct):
125     def __init__(self, definition, typedict, field_class):
126         super(CStructType, self).__init__(definition, typedict, field_class)
127
128     def get_c_name(self):
129         return "vapi_type_%s" % self.name
130
131     def get_swap_to_be_func_name(self):
132         return "%s_hton" % self.get_c_name()
133
134     def get_swap_to_host_func_name(self):
135         return "%s_ntoh" % self.get_c_name()
136
137     def get_swap_to_be_func_decl(self):
138         return "void %s(%s *msg)" % (
139             self.get_swap_to_be_func_name(), self.get_c_name())
140
141     def get_swap_to_be_func_def(self):
142         return "%s\n{\n%s\n}" % (
143             self.get_swap_to_be_func_decl(),
144             "\n".join([
145                 "  %s" % p.get_swap_to_be_code("msg->", "%s" % p.name)
146                 for p in self.fields if p.needs_byte_swap()]),
147         )
148
149     def get_swap_to_host_func_decl(self):
150         return "void %s(%s *msg)" % (
151             self.get_swap_to_host_func_name(), self.get_c_name())
152
153     def get_swap_to_host_func_def(self):
154         return "%s\n{\n%s\n}" % (
155             self.get_swap_to_host_func_decl(),
156             "\n".join([
157                 "  %s" % p.get_swap_to_host_code("msg->", "%s" % p.name)
158                 for p in self.fields if p.needs_byte_swap()]),
159         )
160
161     def get_swap_to_be_code(self, struct, var):
162         return "%s(&%s%s);" % (self.get_swap_to_be_func_name(), struct, var)
163
164     def get_swap_to_host_code(self, struct, var):
165         return "%s(&%s%s);" % (self.get_swap_to_host_func_name(), struct, var)
166
167     def needs_byte_swap(self):
168         for f in self.fields:
169             if f.needs_byte_swap():
170                 return True
171         return False
172
173
174 class CMessage (Message):
175     def __init__(self, logger, definition, typedict,
176                  struct_type_class, simple_type_class, field_class):
177         super(CMessage, self).__init__(logger, definition, typedict,
178                                        struct_type_class, simple_type_class,
179                                        field_class)
180         self.payload_members = [
181             "  %s" % p.get_c_def()
182             for p in self.fields
183             if p.type != self.header
184         ]
185
186     def has_payload(self):
187         return len(self.payload_members) > 0
188
189     def get_msg_id_name(self):
190         return "vapi_msg_id_%s" % self.name
191
192     def get_c_name(self):
193         return "vapi_msg_%s" % self.name
194
195     def get_payload_struct_name(self):
196         return "vapi_payload_%s" % self.name
197
198     def get_alloc_func_vla_field_length_name(self, field):
199         return "%s_array_size" % field.name
200
201     def get_alloc_func_name(self):
202         return "vapi_alloc_%s" % self.name
203
204     def get_alloc_vla_param_names(self):
205         return [self.get_alloc_func_vla_field_length_name(f)
206                 for f in self.fields
207                 if f.nelem_field is not None]
208
209     def get_alloc_func_decl(self):
210         return "%s* %s(struct vapi_ctx_s *ctx%s)" % (
211             self.get_c_name(),
212             self.get_alloc_func_name(),
213             "".join([", size_t %s" % n for n in
214                      self.get_alloc_vla_param_names()]))
215
216     def get_alloc_func_def(self):
217         extra = []
218         if self.header.has_field('client_index'):
219             extra.append(
220                 "  msg->header.client_index = vapi_get_client_index(ctx);")
221         if self.header.has_field('context'):
222             extra.append("  msg->header.context = 0;")
223         return "\n".join([
224             "%s" % self.get_alloc_func_decl(),
225             "{",
226             "  %s *msg = NULL;" % self.get_c_name(),
227             "  const size_t size = sizeof(%s)%s;" % (
228                 self.get_c_name(),
229                 "".join([
230                     " + sizeof(msg->payload.%s[0]) * %s" % (
231                         f.name,
232                         self.get_alloc_func_vla_field_length_name(f))
233                     for f in self.fields
234                     if f.nelem_field is not None
235                 ])),
236             "  /* cast here required to play nicely with C++ world ... */",
237             "  msg = (%s*)vapi_msg_alloc(ctx, size);" % self.get_c_name(),
238             "  if (!msg) {",
239             "    return NULL;",
240             "  }",
241         ] + extra + [
242             "  msg->header._vl_msg_id = vapi_lookup_vl_msg_id(ctx, %s);" %
243             self.get_msg_id_name(),
244             "\n".join(["  msg->payload.%s = %s;" % (
245                 f.nelem_field.name,
246                 self.get_alloc_func_vla_field_length_name(f))
247                 for f in self.fields
248                 if f.nelem_field is not None]),
249             "  return msg;",
250             "}"])
251
252     def get_calc_msg_size_func_name(self):
253         return "vapi_calc_%s_msg_size" % self.name
254
255     def get_calc_msg_size_func_decl(self):
256         return "uword %s(%s *msg)" % (
257             self.get_calc_msg_size_func_name(),
258             self.get_c_name())
259
260     def get_calc_msg_size_func_def(self):
261         return "\n".join([
262             "%s" % self.get_calc_msg_size_func_decl(),
263             "{",
264             "  return sizeof(*msg)%s;" %
265             "".join(["+ msg->payload.%s * sizeof(msg->payload.%s[0])" % (
266                     f.nelem_field.name,
267                     f.name)
268                 for f in self.fields
269                 if f.nelem_field is not None
270             ]),
271             "}",
272         ])
273
274     def get_c_def(self):
275         if self.has_payload():
276             return "\n".join([
277                 "typedef struct __attribute__ ((__packed__)) {",
278                 "%s; " %
279                 ";\n".join(self.payload_members),
280                 "} %s;" % self.get_payload_struct_name(),
281                 "",
282                 "typedef struct __attribute__ ((__packed__)) {",
283                 ("  %s %s;" % (self.header.get_c_name(),
284                                self.fields[0].name)
285                     if self.header is not None else ""),
286                 "  %s payload;" % self.get_payload_struct_name(),
287                 "} %s;" % self.get_c_name(), ])
288         else:
289             return "\n".join([
290                 "typedef struct __attribute__ ((__packed__)) {",
291                 ("  %s %s;" % (self.header.get_c_name(),
292                                self.fields[0].name)
293                     if self.header is not None else ""),
294                 "} %s;" % self.get_c_name(), ])
295
296     def get_swap_payload_to_host_func_name(self):
297         return "%s_payload_ntoh" % self.get_c_name()
298
299     def get_swap_payload_to_be_func_name(self):
300         return "%s_payload_hton" % self.get_c_name()
301
302     def get_swap_payload_to_host_func_decl(self):
303         return "void %s(%s *payload)" % (
304             self.get_swap_payload_to_host_func_name(),
305             self.get_payload_struct_name())
306
307     def get_swap_payload_to_be_func_decl(self):
308         return "void %s(%s *payload)" % (
309             self.get_swap_payload_to_be_func_name(),
310             self.get_payload_struct_name())
311
312     def get_swap_payload_to_be_func_def(self):
313         return "%s\n{\n%s\n}" % (
314             self.get_swap_payload_to_be_func_decl(),
315             "\n".join([
316                 "  %s" % p.get_swap_to_be_code("payload->", "%s" % p.name)
317                 for p in self.fields
318                 if p.needs_byte_swap() and p.type != self.header]),
319         )
320
321     def get_swap_payload_to_host_func_def(self):
322         return "%s\n{\n%s\n}" % (
323             self.get_swap_payload_to_host_func_decl(),
324             "\n".join([
325                 "  %s" % p.get_swap_to_host_code("payload->", "%s" % p.name)
326                 for p in self.fields
327                 if p.needs_byte_swap() and p.type != self.header]),
328         )
329
330     def get_swap_to_host_func_name(self):
331         return "%s_ntoh" % self.get_c_name()
332
333     def get_swap_to_be_func_name(self):
334         return "%s_hton" % self.get_c_name()
335
336     def get_swap_to_host_func_decl(self):
337         return "void %s(%s *msg)" % (
338             self.get_swap_to_host_func_name(), self.get_c_name())
339
340     def get_swap_to_be_func_decl(self):
341         return "void %s(%s *msg)" % (
342             self.get_swap_to_be_func_name(), self.get_c_name())
343
344     def get_swap_to_be_func_def(self):
345         return "\n".join([
346             "%s" % self.get_swap_to_be_func_decl(),
347             "{",
348             ("  VAPI_DBG(\"Swapping `%s'@%%p to big endian\", msg);" %
349                 self.get_c_name()),
350             "  %s(&msg->header);" % self.header.get_swap_to_be_func_name()
351             if self.header is not None else "",
352             "  %s(&msg->payload);" % self.get_swap_payload_to_be_func_name()
353             if self.has_payload() else "",
354             "}",
355         ])
356
357     def get_swap_to_host_func_def(self):
358         return "\n".join([
359             "%s" % self.get_swap_to_host_func_decl(),
360             "{",
361             ("  VAPI_DBG(\"Swapping `%s'@%%p to host byte order\", msg);" %
362                 self.get_c_name()),
363             "  %s(&msg->header);" % self.header.get_swap_to_host_func_name()
364             if self.header is not None else "",
365             "  %s(&msg->payload);" % self.get_swap_payload_to_host_func_name()
366             if self.has_payload() else "",
367             "}",
368         ])
369
370     def get_op_func_name(self):
371         return "vapi_%s" % self.name
372
373     def get_op_func_decl(self):
374         if self.reply.has_payload():
375             return "vapi_error_e %s(%s)" % (
376                 self.get_op_func_name(),
377                 ",\n  ".join([
378                     'struct vapi_ctx_s *ctx',
379                     '%s *msg' % self.get_c_name(),
380                     'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
381                     '                         void *callback_ctx',
382                     '                         vapi_error_e rv',
383                     '                         bool is_last',
384                     '                         %s *reply)' %
385                     self.reply.get_payload_struct_name(),
386                     'void *callback_ctx',
387                 ])
388             )
389         else:
390             return "vapi_error_e %s(%s)" % (
391                 self.get_op_func_name(),
392                 ",\n  ".join([
393                     'struct vapi_ctx_s *ctx',
394                     '%s *msg' % self.get_c_name(),
395                     'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
396                     '                         void *callback_ctx',
397                     '                         vapi_error_e rv',
398                     '                         bool is_last)',
399                     'void *callback_ctx',
400                 ])
401             )
402
403     def get_op_func_def(self):
404         return "\n".join([
405             "%s" % self.get_op_func_decl(),
406             "{",
407             "  if (!msg || !callback) {",
408             "    return VAPI_EINVAL;",
409             "  }",
410             "  if (vapi_is_nonblocking(ctx) && vapi_requests_full(ctx)) {",
411             "    return VAPI_EAGAIN;",
412             "  }",
413             "  vapi_error_e rv;",
414             "  if (VAPI_OK != (rv = vapi_producer_lock (ctx))) {",
415             "    return rv;",
416             "  }",
417             "  u32 req_context = vapi_gen_req_context(ctx);",
418             "  msg->header.context = req_context;",
419             "  %s(msg);" % self.get_swap_to_be_func_name(),
420             ("  if (VAPI_OK == (rv = vapi_send_with_control_ping "
421                 "(ctx, msg, req_context))) {"
422                 if self.is_dump() else
423                 "  if (VAPI_OK == (rv = vapi_send (ctx, msg))) {"
424              ),
425             ("    vapi_store_request(ctx, req_context, %s, "
426              "(vapi_cb_t)callback, callback_ctx);" %
427              ("true" if self.is_dump() else "false")),
428             "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
429             "      abort (); /* this really shouldn't happen */",
430             "    }",
431             "    if (vapi_is_nonblocking(ctx)) {",
432             "      rv = VAPI_OK;",
433             "    } else {",
434             "      rv = vapi_dispatch(ctx);",
435             "    }",
436             "  } else {",
437             "    %s(msg);" % self.get_swap_to_host_func_name(),
438             "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
439             "      abort (); /* this really shouldn't happen */",
440             "    }",
441             "  }",
442             "  return rv;",
443             "}",
444             "",
445         ])
446
447     def get_event_cb_func_decl(self):
448         if not self.is_reply():
449             raise Exception(
450                 "Cannot register event callback for non-reply message")
451         if self.has_payload():
452             return "\n".join([
453                 "void vapi_set_%s_event_cb (" %
454                 self.get_c_name(),
455                 "  struct vapi_ctx_s *ctx, ",
456                 ("  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
457                  "void *callback_ctx, %s *payload)," %
458                  self.get_payload_struct_name()),
459                 "  void *callback_ctx)",
460             ])
461         else:
462             return "\n".join([
463                 "void vapi_set_%s_event_cb (" %
464                 self.get_c_name(),
465                 "  struct vapi_ctx_s *ctx, ",
466                 "  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
467                 "void *callback_ctx),",
468                 "  void *callback_ctx)",
469             ])
470
471     def get_event_cb_func_def(self):
472         if not self.is_reply():
473             raise Exception(
474                 "Cannot register event callback for non-reply function")
475         return "\n".join([
476             "%s" % self.get_event_cb_func_decl(),
477             "{",
478             ("  vapi_set_event_cb(ctx, %s, (vapi_event_cb)callback, "
479              "callback_ctx);" %
480              self.get_msg_id_name()),
481             "}"])
482
483     def get_c_metadata_struct_name(self):
484         return "__vapi_metadata_%s" % self.name
485
486     def get_c_constructor(self):
487         has_context = False
488         if self.header is not None:
489             has_context = self.header.has_field('context')
490         return '\n'.join([
491             'static void __attribute__((constructor)) __vapi_constructor_%s()'
492             % self.name,
493             '{',
494             '  static const char name[] = "%s";' % self.name,
495             '  static const char name_with_crc[] = "%s_%s";'
496             % (self.name, self.crc[2:]),
497             '  static vapi_message_desc_t %s = {' %
498             self.get_c_metadata_struct_name(),
499             '    name,',
500             '    sizeof(name) - 1,',
501             '    name_with_crc,',
502             '    sizeof(name_with_crc) - 1,',
503             '    true,' if has_context else '    false,',
504             '    offsetof(%s, context),' % self.header.get_c_name()
505             if has_context else '    0,',
506             ('    offsetof(%s, payload),' % self.get_c_name())
507             if self.has_payload() else '    INVALID_MSG_ID,',
508             '    sizeof(%s),' % self.get_c_name(),
509             '    (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
510             '    (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
511             '    INVALID_MSG_ID,',
512             '  };',
513             '',
514             '  %s = vapi_register_msg(&%s);' %
515             (self.get_msg_id_name(), self.get_c_metadata_struct_name()),
516             '  VAPI_DBG("Assigned msg id %%d to %s", %s);' %
517             (self.name, self.get_msg_id_name()),
518             '}',
519         ])
520
521
522 vapi_send_with_control_ping = """
523 static inline vapi_error_e
524 vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
525 {
526   vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
527   if (!ping)
528     {
529       return VAPI_ENOMEM;
530     }
531   ping->header.context = context;
532   vapi_msg_control_ping_hton (ping);
533   return vapi_send2 (ctx, msg, ping);
534 }
535 """
536
537
538 def gen_json_unified_header(parser, logger, j, io, name):
539     logger.info("Generating header `%s'" % name)
540     orig_stdout = sys.stdout
541     sys.stdout = io
542     include_guard = "__included_%s" % (
543         j.replace(".", "_").replace("/", "_").replace("-", "_"))
544     print("#ifndef %s" % include_guard)
545     print("#define %s" % include_guard)
546     print("")
547     print("#include <stdlib.h>")
548     print("#include <stddef.h>")
549     print("#include <arpa/inet.h>")
550     print("#include <vapi/vapi_internal.h>")
551     print("#include <vapi/vapi.h>")
552     print("#include <vapi/vapi_dbg.h>")
553     print("")
554     print("#ifdef __cplusplus")
555     print("extern \"C\" {")
556     print("#endif")
557     if name == "vpe.api.vapi.h":
558         print("")
559         print("static inline vapi_error_e vapi_send_with_control_ping "
560               "(vapi_ctx_t ctx, void * msg, u32 context);")
561     else:
562         print("#include <vapi/vpe.api.vapi.h>")
563     print("")
564     for m in parser.messages_by_json[j].values():
565         print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
566     print("")
567     print("#define DEFINE_VAPI_MSG_IDS_%s\\" %
568           j.replace(".", "_").replace("/", "_").replace("-", "_").upper())
569     print("\\\n".join([
570         "  vapi_msg_id_t %s;" % m.get_msg_id_name()
571         for m in parser.messages_by_json[j].values()
572     ]))
573     print("")
574     print("")
575     for t in parser.types_by_json[j].values():
576         try:
577             print("%s" % t.get_c_def())
578             print("")
579         except:
580             pass
581     for m in parser.messages_by_json[j].values():
582         print("%s" % m.get_c_def())
583         print("")
584
585     print("")
586     function_attrs = "static inline "
587     for t in parser.types_by_json[j].values():
588         print("%s%s" % (function_attrs, t.get_swap_to_be_func_def()))
589         print("")
590         print("%s%s" % (function_attrs, t.get_swap_to_host_func_def()))
591         print("")
592     for m in parser.messages_by_json[j].values():
593         if m.has_payload():
594             print("%s%s" % (function_attrs,
595                             m.get_swap_payload_to_be_func_def()))
596             print("")
597             print("%s%s" % (function_attrs,
598                             m.get_swap_payload_to_host_func_def()))
599             print("")
600         print("%s%s" % (function_attrs, m.get_calc_msg_size_func_def()))
601         print("")
602         print("%s%s" % (function_attrs, m.get_swap_to_be_func_def()))
603         print("")
604         print("%s%s" % (function_attrs, m.get_swap_to_host_func_def()))
605         print("")
606     for m in parser.messages_by_json[j].values():
607         if m.is_reply():
608             continue
609         print("%s%s" % (function_attrs, m.get_alloc_func_def()))
610         print("")
611         print("%s%s" % (function_attrs, m.get_op_func_def()))
612         print("")
613     print("")
614     for m in parser.messages_by_json[j].values():
615         print("%s" % m.get_c_constructor())
616         print("")
617     print("")
618     for m in parser.messages_by_json[j].values():
619         if not m.is_reply():
620             continue
621         print("%s%s;" % (function_attrs, m.get_event_cb_func_def()))
622         print("")
623     print("")
624
625     if name == "vpe.api.vapi.h":
626         print("%s" % vapi_send_with_control_ping)
627         print("")
628
629     print("#ifdef __cplusplus")
630     print("}")
631     print("#endif")
632     print("")
633     print("#endif")
634     sys.stdout = orig_stdout
635
636
637 def json_to_c_header_name(json_name):
638     if json_name.endswith(".json"):
639         return "%s.vapi.h" % os.path.splitext(json_name)[0]
640     raise Exception("Unexpected json name `%s'!" % json_name)
641
642
643 def gen_c_unified_headers(parser, logger, prefix):
644     if prefix == "" or prefix is None:
645         prefix = ""
646     else:
647         prefix = "%s/" % prefix
648     for j in parser.json_files:
649         with open('%s%s' % (prefix, json_to_c_header_name(j)), "w") as io:
650             gen_json_unified_header(
651                 parser, logger, j, io, json_to_c_header_name(j))
652
653
654 if __name__ == '__main__':
655     try:
656         verbose = int(os.getenv("V", 0))
657     except:
658         verbose = 0
659
660     if verbose >= 2:
661         log_level = 10
662     elif verbose == 1:
663         log_level = 20
664     else:
665         log_level = 40
666
667     logging.basicConfig(stream=sys.stdout, level=log_level)
668     logger = logging.getLogger("VAPI C GEN")
669     logger.setLevel(log_level)
670
671     argparser = argparse.ArgumentParser(description="VPP C API generator")
672     argparser.add_argument('files', metavar='api-file', action='append',
673                            type=str, help='json api file'
674                            '(may be specified multiple times)')
675     argparser.add_argument('--prefix', action='store', default=None,
676                            help='path prefix')
677     args = argparser.parse_args()
678
679     jsonparser = JsonParser(logger, args.files,
680                             simple_type_class=CSimpleType,
681                             struct_type_class=CStructType,
682                             field_class=CField,
683                             message_class=CMessage)
684
685     # not using the model of having separate generated header and code files
686     # with generated symbols present in shared library (per discussion with
687     # Damjan), to avoid symbol version issues in .so
688     # gen_c_headers_and_code(jsonparser, logger, args.prefix)
689
690     gen_c_unified_headers(jsonparser, logger, args.prefix)
691
692     for e in jsonparser.exceptions:
693         logger.error(e)