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