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