2 # Copyright (c) 2020 Cisco and/or its affiliates.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 # Provide two classes FromJSON and TOJSON that converts between JSON and VPP's
22 This module creates C code for core VPP, VPP plugins and client side VAT and
30 from io import StringIO
33 process_imports = False
36 ###############################################################################
38 '''Class to generate functions converting from VPP binary API to JSON.'''
40 noprint_fields = {'_vl_msg_id': None,
43 is_number = {'u8': None,
54 def __init__(self, module, types, defines, imported_types, stream):
57 self.defines = defines
59 self.types_hash = {'vl_api_'+d.name+'_t':
60 d for d in types + imported_types}
61 self.defines_hash = {d.name: d for d in defines}
64 '''Output the top boilerplate.'''
65 write = self.stream.write
66 write('#ifndef included_{}_api_tojson_h\n'.format(self.module))
67 write('#define included_{}_api_tojson_h\n'.format(self.module))
68 write('#include <vppinfra/cJSON.h>\n\n')
69 write('#include <vat2/jsonconvert.h>\n\n')
72 '''Output the bottom boilerplate.'''
73 write = self.stream.write
76 def get_json_func(self, t):
77 '''Given the type, returns the function to use to create a
81 vt = self.types_hash[t]
82 if vt.type == 'Using' and 'length' not in vt.alias:
83 vt_type = vt.alias['type']
87 if t in self.is_number or vt_type in self.is_number:
88 return 'cJSON_AddNumberToObject', '', False
90 return 'cJSON_AddBoolToObject', '', False
92 # Lookup type name check if it's enum
94 return '{t}_tojson'.format(t=t), '', True
95 return '{t}_tojson'.format(t=t), '&', True
97 def get_json_array_func(self, t):
98 '''Given a type returns the function to create a cJSON object
100 if t in self.is_number:
101 return 'cJSON_CreateNumber', ''
103 return 'cJSON_CreateBool', ''
104 return '{t}_tojson'.format(t=t), '&'
106 def print_string(self, o):
107 '''Create cJSON object from vl_api_string_t'''
108 write = self.stream.write
110 write(' vl_api_string_cJSON_AddToObject(o, "{n}", &a->{n});\n'
111 .format(n=o.fieldname))
114 write(' cJSON_AddStringToObject(o, "{n}", (char *)a->{n});\n'
115 .format(n=o.fieldname))
117 def print_field(self, o):
118 '''Called for every field in a typedef or define.'''
119 write = self.stream.write
120 if o.fieldname in self.noprint_fields:
123 f, p, newobj = self.get_json_func(o.fieldtype)
126 write(' cJSON_AddItemToObject(o, "{n}", {f}({p}a->{n}));\n'
127 .format(f=f, p=p, n=o.fieldname))
129 write(' {f}(o, "{n}", {p}a->{n});\n'
130 .format(f=f, p=p, n=o.fieldname))
132 _dispatch['Field'] = print_field
134 def print_array(self, o):
135 '''Converts a VPP API array to cJSON array.'''
136 write = self.stream.write
141 cJSON *array = cJSON_AddArrayToObject(o, "{n}");
142 for (i = 0; i < {lfield}; i++) {{
143 cJSON_AddItemToArray(array, {f}({p}a->{n}[i]));
148 if o.fieldtype == 'string':
152 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
153 if o.fieldtype == 'u8':
155 # What is length field doing here?
156 write(' u8 *s = format(0, "0x%U", format_hex_bytes, '
157 '&a->{n}, {lfield});\n'
158 .format(n=o.fieldname, lfield=lfield))
159 write(' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'
160 .format(n=o.fieldname))
161 write(' vec_free(s);\n')
165 f, p = self.get_json_array_func(o.fieldtype)
166 write(forloop.format(lfield=lfield,
172 _dispatch['Array'] = print_array
174 def print_enum(self, o):
175 '''Create cJSON object (string) for VPP API enum'''
176 write = self.stream.write
177 write('static inline cJSON *vl_api_{name}_t_tojson '
178 '(vl_api_{name}_t a) {{\n'.format(name=o.name))
180 write(" switch(a) {\n")
182 write(" case %s:\n" % b[1])
183 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
184 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
186 write(' return 0;\n')
189 _dispatch['Enum'] = print_enum
191 def print_typedef(self, o):
192 '''Create cJSON (dictionary) object from VPP API typedef'''
193 write = self.stream.write
194 write('static inline cJSON *vl_api_{name}_t_tojson '
195 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
196 write(' cJSON *o = cJSON_CreateObject();\n')
199 self._dispatch[t.type](self, t)
201 write(' return o;\n')
204 def print_define(self, o):
205 '''Create cJSON (dictionary) object from VPP API define'''
206 write = self.stream.write
207 write('static inline cJSON *vl_api_{name}_t_tojson '
208 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
209 write(' cJSON *o = cJSON_CreateObject();\n')
210 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'
214 self._dispatch[t.type](self, t)
216 write(' return o;\n')
219 def print_using(self, o):
220 '''Create cJSON (dictionary) object from VPP API aliased type'''
224 write = self.stream.write
225 write('static inline cJSON *vl_api_{name}_t_tojson '
226 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
228 write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'
230 write(' cJSON *o = cJSON_CreateString((char *)s);\n')
231 write(' vec_free(s);\n')
232 write(' return o;\n')
235 _dispatch['Typedef'] = print_typedef
236 _dispatch['Define'] = print_define
237 _dispatch['Using'] = print_using
238 _dispatch['Union'] = print_typedef
240 def generate_function(self, t):
241 '''Main entry point'''
242 write = self.stream.write
244 write('/* Manual print {} */\n'.format(t.name))
246 self._dispatch[t.type](self, t)
248 def generate_types(self):
249 '''Main entry point'''
251 self.generate_function(t)
253 def generate_defines(self):
254 '''Main entry point'''
255 for t in self.defines:
256 self.generate_function(t)
261 Parse JSON objects into VPP API binary message structures.
264 noprint_fields = {'_vl_msg_id': None,
265 'client_index': None,
267 is_number = {'u8': None,
278 def __init__(self, module, types, defines, imported_types, stream):
281 self.defines = defines
283 self.types_hash = {'vl_api_'+d.name+'_t':
284 d for d in types + imported_types}
285 self.defines_hash = {d.name: d for d in defines}
288 '''Output the top boilerplate.'''
289 write = self.stream.write
290 write('#ifndef included_{}_api_fromjson_h\n'.format(self.module))
291 write('#define included_{}_api_fromjson_h\n'.format(self.module))
292 write('#include <vppinfra/cJSON.h>\n\n')
293 write('#include <vat2/jsonconvert.h>\n\n')
295 def is_base_type(self, t):
296 '''Check if a type is one of the VPP API base types'''
297 if t in self.is_number:
304 '''Output the bottom boilerplate.'''
305 write = self.stream.write
308 def print_string(self, o, toplevel=False):
309 '''Convert JSON string to vl_api_string_t'''
310 write = self.stream.write
312 msgvar = "a" if toplevel else "mp"
313 msgsize = "l" if toplevel else "*len"
316 write(' char *p = cJSON_GetStringValue(item);\n')
317 write(' size_t plen = strlen(p);\n')
318 write(' {msgvar} = realloc({msgvar}, {msgsize} + plen);\n'
319 .format(msgvar=msgvar, msgsize=msgsize))
320 write(' vl_api_c_string_to_api_string(p, (void *){msgvar} + '
321 '{msgsize} - sizeof(vl_api_string_t));\n'
322 .format(msgvar=msgvar, msgsize=msgsize))
323 write(' {msgsize} += plen;\n'.format(msgsize=msgsize))
325 write(' strncpy_s((char *)a->{n}, sizeof(a->{n}), '
326 'cJSON_GetStringValue(item), sizeof(a->{n}) - 1);\n'
327 .format(n=o.fieldname))
329 def print_field(self, o, toplevel=False):
330 '''Called for every field in a typedef or define.'''
331 write = self.stream.write
332 write(' // start field {}\n'.format(o.fieldname))
333 if o.fieldname in self.noprint_fields:
335 is_bt = self.is_base_type(o.fieldtype)
336 t = 'vl_api_{}'.format(o.fieldtype) if is_bt else o.fieldtype
338 msgvar = "a" if toplevel else "mp"
339 msgsize = "&l" if toplevel else "len"
342 write(' vl_api_{t}_fromjson(item, &a->{n});\n'
343 .format(t=o.fieldtype, n=o.fieldname))
345 write(' {msgvar} = {t}_fromjson({msgvar}, '
346 '{msgsize}, item, &a->{n});\n'
347 .format(t=t, n=o.fieldname, msgvar=msgvar, msgsize=msgsize))
348 write(' if (!{msgvar}) return 0;\n'.format(msgvar=msgvar))
350 write(' // end field {}\n'.format(o.fieldname))
352 _dispatch['Field'] = print_field
354 def print_array(self, o, toplevel=False):
355 '''Convert JSON array to VPP API array'''
356 write = self.stream.write
361 cJSON *array = cJSON_GetObjectItem(o, "{n}");
362 int size = cJSON_GetArraySize(array);
363 if (size != {lfield}) return 0;
364 for (i = 0; i < size; i++) {{
365 cJSON *e = cJSON_GetArrayItem(array, i);
373 cJSON *array = cJSON_GetObjectItem(o, "{n}");
374 int size = cJSON_GetArraySize(array);
376 {msgvar} = realloc({msgvar}, {msgsize} + sizeof({t}) * size);
377 {t} *d = (void *){msgvar} + {msgsize};
378 {msgsize} += sizeof({t}) * size;
379 for (i = 0; i < size; i++) {{
380 cJSON *e = cJSON_GetArrayItem(array, i);
386 if o.fieldtype == 'string':
387 self.print_string(o, toplevel)
390 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
391 msgvar = "a" if toplevel else "mp"
392 msgsize = "l" if toplevel else "*len"
394 if o.fieldtype == 'u8':
396 write(' s = u8string_fromjson(o, "{}");\n'
397 .format(o.fieldname))
398 write(' if (!s) return 0;\n')
399 write(' {} = vec_len(s);\n'.format(lfield))
401 write(' {msgvar} = realloc({msgvar}, {msgsize} + '
402 'vec_len(s));\n'.format(msgvar=msgvar, msgsize=msgsize))
403 write(' memcpy((void *){msgvar} + {msgsize}, s, '
404 'vec_len(s));\n'.format(msgvar=msgvar, msgsize=msgsize))
405 write(' {msgsize} += vec_len(s);\n'.format(msgsize=msgsize))
407 write(' vec_free(s);\n')
409 write(' u8string_fromjson2(o, "{n}", a->{n});\n'
410 .format(n=o.fieldname))
413 is_bt = self.is_base_type(o.fieldtype)
417 call = ('vl_api_{t}_fromjson(e, &d[i]);'
418 .format(t=o.fieldtype))
420 call = ('{t}_fromjson({msgvar}, len, e, &d[i]); '
421 .format(t=o.fieldtype, msgvar=msgvar))
422 write(forloop_vla.format(lfield=lfield,
430 call = ('vl_api_{t}_fromjson(e, &a->{n}[i]);'
431 .format(t=t, n=o.fieldname))
433 call = ('a = {}_fromjson({}, len, e, &a->{}[i]);'
434 .format(t, msgvar, o.fieldname))
435 write(forloop.format(lfield=lfield,
442 _dispatch['Array'] = print_array
444 def print_enum(self, o):
445 '''Convert to JSON enum(string) to VPP API enum (int)'''
446 write = self.stream.write
447 write('static inline void *vl_api_{n}_t_fromjson '
448 '(void *mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n'
450 write(' char *p = cJSON_GetStringValue(o);\n')
452 write(' if (strcmp(p, "{}") == 0) {{*a = {}; return mp;}}\n'
454 write(' return 0;\n')
457 _dispatch['Enum'] = print_enum
459 def print_typedef(self, o):
460 '''Convert from JSON object to VPP API binary representation'''
461 write = self.stream.write
463 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
464 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
465 .format(name=o.name))
466 write(' cJSON *item __attribute__ ((unused));\n')
467 write(' u8 *s __attribute__ ((unused));\n')
469 if t.type == 'Field' and t.is_lengthfield:
471 write(' item = cJSON_GetObjectItem(o, "{}");\n'
472 .format(t.fieldname))
473 write(' if (!item) return 0;\n')
475 self._dispatch[t.type](self, t)
477 write(' return mp;\n')
480 def print_union(self, o):
481 '''Convert JSON object to VPP API binary union'''
482 write = self.stream.write
484 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
485 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
486 .format(name=o.name))
487 write(' cJSON *item __attribute__ ((unused));\n')
488 write(' u8 *s __attribute__ ((unused));\n')
490 if t.type == 'Field' and t.is_lengthfield:
492 write(' item = cJSON_GetObjectItem(o, "{}");\n'
493 .format(t.fieldname))
494 write(' if (item) {\n')
495 self._dispatch[t.type](self, t)
497 write(' return mp;\n')
500 def print_define(self, o):
501 '''Convert JSON object to VPP API message'''
502 write = self.stream.write
503 write('static inline vl_api_{name}_t *vl_api_{name}_t_fromjson '
504 '(cJSON *o, int *len) {{\n'.format(name=o.name))
505 write(' cJSON *item __attribute__ ((unused));\n')
506 write(' u8 *s __attribute__ ((unused));\n')
507 write(' int l = sizeof(vl_api_{}_t);\n'.format(o.name))
508 write(' vl_api_{}_t *a = malloc(l);\n'.format(o.name))
511 if t.fieldname in self.noprint_fields:
513 if t.type == 'Field' and t.is_lengthfield:
515 write(' // processing {}: {} {}\n'
516 .format(o.name, t.fieldtype, t.fieldname))
518 write(' item = cJSON_GetObjectItem(o, "{}");\n'
519 .format(t.fieldname))
520 write(' if (!item) return 0;\n')
521 self._dispatch[t.type](self, t, toplevel=True)
525 write(' *len = l;\n')
526 write(' return a;\n')
529 def print_using(self, o):
530 '''Convert JSON field to VPP type alias'''
531 write = self.stream.write
537 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
538 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
539 .format(name=o.name))
540 if 'length' in o.alias:
541 if t.fieldtype != 'u8':
542 raise ValueError("Error in processing type {} for {}"
543 .format(t.fieldtype, o.name))
544 write(' vl_api_u8_string_fromjson(o, (u8 *)a, {});\n'
545 .format(o.alias['length']))
547 write(' vl_api_{t}_fromjson(o, ({t} *)a);\n'
548 .format(t=t.fieldtype))
550 write(' return mp;\n')
553 _dispatch['Typedef'] = print_typedef
554 _dispatch['Define'] = print_define
555 _dispatch['Using'] = print_using
556 _dispatch['Union'] = print_union
558 def generate_function(self, t):
559 '''Main entry point'''
560 write = self.stream.write
562 write('/* Manual print {} */\n'.format(t.name))
564 self._dispatch[t.type](self, t)
566 def generate_types(self):
567 '''Main entry point'''
569 self.generate_function(t)
571 def generate_defines(self):
572 '''Main entry point'''
573 for t in self.defines:
574 self.generate_function(t)
577 def generate_tojson(s, modulename, stream):
578 '''Generate all functions to convert from API to JSON'''
581 write('/* Imported API files */\n')
582 for i in s['Import']:
583 f = i.filename.replace('plugins/', '')
584 write('#include <{}_tojson.h>\n'.format(f))
586 pp = ToJSON(modulename, s['types'], s['Define'], s['imported']['types'],
590 pp.generate_defines()
595 def generate_fromjson(s, modulename, stream):
596 '''Generate all functions to convert from JSON to API'''
598 write('/* Imported API files */\n')
599 for i in s['Import']:
600 f = i.filename.replace('plugins/', '')
601 write('#include <{}_fromjson.h>\n'.format(f))
603 pp = FromJSON(modulename, s['types'], s['Define'], s['imported']['types'],
607 pp.generate_defines()
612 ###############################################################################
615 DATESTRING = datetime.datetime.utcfromtimestamp(
616 int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
617 TOP_BOILERPLATE = '''\
619 * VLIB API definitions {datestring}
620 * Input file: {input_filename}
621 * Automatically generated: please edit the input file NOT this file!
625 #if defined(vl_msg_id)||defined(vl_union_id) \\
626 || defined(vl_printfun) ||defined(vl_endianfun) \\
627 || defined(vl_api_version)||defined(vl_typedefs) \\
628 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
629 || defined(vl_api_version_tuple)
630 /* ok, something was selected */
632 #warning no content included from {input_filename}
635 #define VL_API_PACKED(x) x __attribute__ ((packed))
638 BOTTOM_BOILERPLATE = '''\
639 /****** API CRC (whole file) *****/
641 #ifdef vl_api_version
642 vl_api_version({input_filename}, {file_crc:#08x})
649 '''Generate macro to map API message id to handler'''
652 /****** Message ID / handler enum ******/
657 for t in s['Define']:
658 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
659 (t.name.upper(), t.name)
666 '''Generate calls to name mapping macro'''
669 /****** Message names ******/
674 for t in s['Define']:
675 dont_trace = 0 if t.dont_trace else 1
676 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
682 def msg_name_crc_list(s, suffix):
683 '''Generate list of names to CRC mappings'''
686 /****** Message name, crc list ******/
688 #ifdef vl_msg_name_crc_list
690 output += "#define foreach_vl_msg_name_crc_%s " % suffix
692 for t in s['Define']:
693 output += "\\\n_(VL_API_%s, %s, %08x) " % \
694 (t.name.upper(), t.name, t.crc)
700 def api2c(fieldtype):
701 '''Map between API type names and internal VPP type names'''
702 mappingtable = {'string': 'vl_api_string_t', }
703 if fieldtype in mappingtable:
704 return mappingtable[fieldtype]
708 def typedefs(filename):
709 '''Include in the main files to the types file'''
712 /****** Typedefs ******/
715 #include "{include}.api_types.h"
717 '''.format(include=filename)
721 FORMAT_STRINGS = {'u8': '%u',
734 '''Functions for pretty printing VPP API messages'''
736 noprint_fields = {'_vl_msg_id': None,
737 'client_index': None,
740 def __init__(self, stream):
744 def print_string(o, stream):
745 '''Pretty print a vl_api_string_t'''
748 write(' if (vl_api_string_len(&a->{f}) > 0) {{\n'
749 .format(f=o.fieldname))
750 write(' s = format(s, "\\n%U{f}: %U", '
751 'format_white_space, indent, '
752 'vl_api_format_string, (&a->{f}));\n'.format(f=o.fieldname))
754 write(' s = format(s, "\\n%U{f}:", '
755 'format_white_space, indent);\n'.format(f=o.fieldname))
758 write(' s = format(s, "\\n%U{f}: %s", '
759 'format_white_space, indent, a->{f});\n'
760 .format(f=o.fieldname))
762 def print_field(self, o, stream):
763 '''Pretty print API field'''
765 if o.fieldname in self.noprint_fields:
767 if o.fieldtype in FORMAT_STRINGS:
768 f = FORMAT_STRINGS[o.fieldtype]
769 write(' s = format(s, "\\n%U{n}: {f}", '
770 'format_white_space, indent, a->{n});\n'
771 .format(n=o.fieldname, f=f))
773 write(' s = format(s, "\\n%U{n}: %U", '
774 'format_white_space, indent, '
775 'format_{t}, &a->{n}, indent);\n'
776 .format(n=o.fieldname, t=o.fieldtype))
778 _dispatch['Field'] = print_field
780 def print_array(self, o, stream):
781 '''Pretty print API array'''
785 for (i = 0; i < {lfield}; i++) {{
786 s = format(s, "\\n%U{n}: %U",
787 format_white_space, indent, format_{t}, &a->{n}[i], indent);
791 forloop_format = '''\
792 for (i = 0; i < {lfield}; i++) {{
793 s = format(s, "\\n%U{n}: {t}",
794 format_white_space, indent, a->{n}[i]);
798 if o.fieldtype == 'string':
799 self.print_string(o, stream)
802 if o.fieldtype == 'u8':
804 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
805 'indent, format_hex_bytes, a->{n}, a->{lfield});\n'
806 .format(n=o.fieldname, lfield=o.lengthfield))
808 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
809 'indent, format_hex_bytes, a, {lfield});\n'
810 .format(n=o.fieldname, lfield=o.length))
813 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
814 if o.fieldtype in FORMAT_STRINGS:
815 write(forloop_format.format(lfield=lfield,
816 t=FORMAT_STRINGS[o.fieldtype],
819 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname))
821 _dispatch['Array'] = print_array
824 def print_alias(k, v, stream):
825 '''Pretty print type alias'''
827 if ('length' in v.alias and v.alias['length'] and
828 v.alias['type'] == 'u8'):
829 write(' return format(s, "%U", format_hex_bytes, a, {});\n'
830 .format(v.alias['length']))
831 elif v.alias['type'] in FORMAT_STRINGS:
832 write(' return format(s, "{}", *a);\n'
833 .format(FORMAT_STRINGS[v.alias['type']]))
835 write(' return format(s, "{} (print not implemented)");\n'
839 def print_enum(o, stream):
840 '''Pretty print API enum'''
842 write(" switch(*a) {\n")
844 write(" case %s:\n" % b[1])
845 write(' return format(s, "{}");\n'.format(b[0]))
848 _dispatch['Enum'] = print_enum
850 def print_obj(self, o, stream):
854 if o.type in self._dispatch:
855 self._dispatch[o.type](self, o, stream)
857 write(' s = format(s, "\\n{} {} {} (print not implemented");\n'
858 .format(o.type, o.fieldtype, o.fieldname))
861 def printfun(objs, stream, modulename):
862 '''Main entry point for pretty print function generation'''
866 /****** Print functions *****/
868 #ifndef included_{module}_printfun
869 #define included_{module}_printfun
872 #define _uword_fmt \"%lld\"
873 #define _uword_cast (long long)
875 #define _uword_fmt \"%ld\"
876 #define _uword_cast long
882 static inline void *vl_api_{name}_t_print (vl_api_{name}_t *a, void *handle)
885 u32 indent __attribute__((unused)) = 2;
886 int i __attribute__((unused));
889 h = h.format(module=modulename)
892 pp = Printfun(stream)
895 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
897 write(signature.format(name=t.name))
898 write(' /* Message definition: vl_api_{}_t: */\n'.format(t.name))
899 write(" s = format(s, \"vl_api_%s_t:\");\n" % t.name)
901 pp.print_obj(o, stream)
902 write(' vec_add1(s, 0);\n')
903 write(' vl_print (handle, (char *)s);\n')
904 write(' vec_free (s);\n')
905 write(' return handle;\n')
909 write("\n#endif /* vl_printfun */\n")
914 def printfun_types(objs, stream, modulename):
915 '''Pretty print API types'''
917 pp = Printfun(stream)
920 /****** Print functions *****/
922 #ifndef included_{module}_printfun_types
923 #define included_{module}_printfun_types
926 h = h.format(module=modulename)
930 static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
932 vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
933 u32 indent __attribute__((unused)) = va_arg (*args, u32);
934 int i __attribute__((unused));
939 if t.__class__.__name__ == 'Enum':
940 write(signature.format(name=t.name))
941 pp.print_enum(t.block, stream)
942 write(' return s;\n')
947 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
950 if t.__class__.__name__ == 'Using':
951 write(signature.format(name=t.name))
952 pp.print_alias(t.name, t, stream)
956 write(signature.format(name=t.name))
958 pp.print_obj(o, stream)
960 write(' return s;\n')
964 write("\n#endif /* vl_printfun_types */\n")
967 def generate_imports(imports):
968 '''Add #include matching the API import statements'''
969 output = '/* Imported API files */\n'
970 output += '#ifndef vl_api_version\n'
973 s = i.filename.replace('plugins/', '')
974 output += '#include <{}.h>\n'.format(s)
980 'u16': 'clib_net_to_host_u16',
981 'u32': 'clib_net_to_host_u32',
982 'u64': 'clib_net_to_host_u64',
983 'i16': 'clib_net_to_host_i16',
984 'i32': 'clib_net_to_host_i32',
985 'i64': 'clib_net_to_host_i64',
986 'f64': 'clib_net_to_host_f64',
990 def endianfun_array(o):
991 '''Generate endian functions for arrays'''
993 for (i = 0; i < {length}; i++) {{
994 a->{name}[i] = {format}(a->{name}[i]);
998 forloop_format = '''\
999 for (i = 0; i < {length}; i++) {{
1000 {type}_endian(&a->{name}[i]);
1005 if o.fieldtype == 'u8' or o.fieldtype == 'string':
1006 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1008 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
1009 if o.fieldtype in ENDIAN_STRINGS:
1011 .format(length=lfield,
1012 format=ENDIAN_STRINGS[o.fieldtype],
1015 output += (forloop_format
1016 .format(length=lfield, type=o.fieldtype,
1021 NO_ENDIAN_CONVERSION = {'client_index': None}
1024 def endianfun_obj(o):
1025 '''Generate endian conversion function for type'''
1027 if o.type == 'Array':
1028 return endianfun_array(o)
1029 if o.type != 'Field':
1030 output += (' s = format(s, "\\n{} {} {} (print not implemented");\n'
1031 .format(o.type, o.fieldtype, o.fieldname))
1033 if o.fieldname in NO_ENDIAN_CONVERSION:
1034 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1036 if o.fieldtype in ENDIAN_STRINGS:
1037 output += (' a->{name} = {format}(a->{name});\n'
1038 .format(name=o.fieldname,
1039 format=ENDIAN_STRINGS[o.fieldtype]))
1040 elif o.fieldtype.startswith('vl_api_'):
1041 output += (' {type}_endian(&a->{name});\n'
1042 .format(type=o.fieldtype, name=o.fieldname))
1044 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1049 def endianfun(objs, modulename):
1050 '''Main entry point for endian function generation'''
1053 /****** Endian swap functions *****/\n\
1055 #ifndef included_{module}_endianfun
1056 #define included_{module}_endianfun
1058 #undef clib_net_to_host_uword
1060 #define clib_net_to_host_uword clib_net_to_host_u64
1062 #define clib_net_to_host_uword clib_net_to_host_u32
1066 output = output.format(module=modulename)
1069 static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
1071 int i __attribute__((unused));
1075 if t.__class__.__name__ == 'Enum':
1076 output += signature.format(name=t.name)
1077 if t.enumtype in ENDIAN_STRINGS:
1078 output += (' *a = {}(*a);\n'
1079 .format(ENDIAN_STRINGS[t.enumtype]))
1081 output += (' /* a->{name} = a->{name} (no-op) */\n'
1082 .format(name=t.name))
1088 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1091 if t.__class__.__name__ == 'Using':
1092 output += signature.format(name=t.name)
1093 if ('length' in t.alias and t.alias['length'] and
1094 t.alias['type'] == 'u8'):
1095 output += (' /* a->{name} = a->{name} (no-op) */\n'
1096 .format(name=t.name))
1097 elif t.alias['type'] in FORMAT_STRINGS:
1098 output += (' *a = {}(*a);\n'
1099 .format(ENDIAN_STRINGS[t.alias['type']]))
1101 output += ' /* Not Implemented yet {} */'.format(t.name)
1105 output += signature.format(name=t.name)
1108 output += endianfun_obj(o)
1111 output += "\n#endif"
1112 output += "\n#endif /* vl_endianfun */\n\n"
1117 def version_tuple(s, module):
1118 '''Generate semantic version string'''
1120 /****** Version tuple *****/
1122 #ifdef vl_api_version_tuple
1125 if 'version' in s['Option']:
1126 v = s['Option']['version']
1127 (major, minor, patch) = v.split('.')
1128 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
1129 (module, major, minor, patch)
1131 output += "\n#endif /* vl_api_version_tuple */\n\n"
1136 def generate_include_enum(s, module, stream):
1137 '''Generate <name>.api_enum.h'''
1138 write = stream.write
1141 write('typedef enum {\n')
1142 for t in s['Define']:
1143 write(' VL_API_{},\n'.format(t.name.upper()))
1144 write(' VL_MSG_{}_LAST\n'.format(module.upper()))
1145 write('}} vl_api_{}_enum_t;\n'.format(module))
1148 def generate_include_counters(s, stream):
1149 '''Include file for the counter data model types.'''
1150 write = stream.write
1153 csetname = counters.name
1154 write('typedef enum {\n')
1155 for c in counters.block:
1156 write(' {}_ERROR_{},\n'
1157 .format(csetname.upper(), c['name'].upper()))
1158 write(' {}_N_ERROR\n'.format(csetname.upper()))
1159 write('}} vl_counter_{}_enum_t;\n'.format(csetname))
1161 write('extern vl_counter_t {}_error_counters[];\n'.format(csetname))
1164 def generate_include_types(s, module, stream):
1165 '''Generate separate API _types file.'''
1166 write = stream.write
1168 write('#ifndef included_{module}_api_types_h\n'.format(module=module))
1169 write('#define included_{module}_api_types_h\n'.format(module=module))
1171 if 'version' in s['Option']:
1172 v = s['Option']['version']
1173 (major, minor, patch) = v.split('.')
1174 write('#define VL_API_{m}_API_VERSION_MAJOR {v}\n'
1175 .format(m=module.upper(), v=major))
1176 write('#define VL_API_{m}_API_VERSION_MINOR {v}\n'
1177 .format(m=module.upper(), v=minor))
1178 write('#define VL_API_{m}_API_VERSION_PATCH {v}\n'
1179 .format(m=module.upper(), v=patch))
1182 write('/* Imported API files */\n')
1183 for i in s['Import']:
1184 filename = i.filename.replace('plugins/', '')
1185 write('#include <{}_types.h>\n'.format(filename))
1187 for o in s['types'] + s['Define']:
1188 tname = o.__class__.__name__
1189 if tname == 'Using':
1190 if 'length' in o.alias:
1191 write('typedef %s vl_api_%s_t[%s];\n' %
1192 (o.alias['type'], o.name, o.alias['length']))
1194 write('typedef %s vl_api_%s_t;\n' % (o.alias['type'], o.name))
1195 elif tname == 'Enum':
1196 if o.enumtype == 'u32':
1197 write("typedef enum {\n")
1199 write("typedef enum __attribute__((packed)) {\n")
1202 write(" %s = %s,\n" % (b[0], b[1]))
1203 write('} vl_api_%s_t;\n' % o.name)
1204 if o.enumtype != 'u32':
1205 size1 = 'sizeof(vl_api_%s_t)' % o.name
1206 size2 = 'sizeof(%s)' % o.enumtype
1207 err_str = 'size of API enum %s is wrong' % o.name
1208 write('STATIC_ASSERT(%s == %s, "%s");\n'
1209 % (size1, size2, err_str))
1211 if tname == 'Union':
1212 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n"
1215 write(("typedef struct __attribute__ ((packed)) _vl_api_%s {\n")
1218 if b.type == 'Option':
1220 if b.type == 'Field':
1221 write(" %s %s;\n" % (api2c(b.fieldtype),
1223 elif b.type == 'Array':
1225 write(" %s %s[0];\n" % (api2c(b.fieldtype),
1228 # Fixed length strings decay to nul terminated u8
1229 if b.fieldtype == 'string':
1232 .format(api2c(b.fieldtype),
1235 write(' u8 {}[{}];\n'
1236 .format(b.fieldname, b.length))
1238 write(" %s %s[%s];\n" %
1239 (api2c(b.fieldtype), b.fieldname,
1242 raise ValueError("Error in processing type {} for {}"
1245 write('} vl_api_%s_t;\n' % o.name)
1247 for t in s['Define']:
1248 write('#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'
1249 .format(n=t.name, ID=t.name.upper(), crc=t.crc))
1254 def generate_c_boilerplate(services, defines, counters, file_crc,
1256 '''VPP side plugin.'''
1257 write = stream.write
1258 define_hash = {d.name: d for d in defines}
1261 #define vl_endianfun /* define message structures */
1262 #include "{module}.api.h"
1265 /* instantiate all the print functions we know about */
1266 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1268 #include "{module}.api.h"
1273 write(hdr.format(module=module))
1274 write('static u16\n')
1275 write('setup_message_id_table (void) {\n')
1276 write(' api_main_t *am = my_api_main;\n')
1277 write(' vl_msg_api_msg_config_t c;\n')
1278 write(' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1279 'VL_MSG_{m}_LAST);\n'
1280 .format(module, crc=file_crc, m=module.upper()))
1283 write(' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1284 ' VL_API_{ID} + msg_id_base);\n'
1285 .format(n=d.name, ID=d.name.upper(), crc=d.crc))
1287 d = define_hash[s.caller]
1288 write(' c = (vl_msg_api_msg_config_t) '
1289 ' {{.id = VL_API_{ID} + msg_id_base,\n'
1291 ' .handler = vl_api_{n}_t_handler,\n'
1292 ' .cleanup = vl_noop_handler,\n'
1293 ' .endian = vl_api_{n}_t_endian,\n'
1294 ' .print = vl_api_{n}_t_print,\n'
1295 ' .is_autoendian = 0}};\n'
1296 .format(n=s.caller, ID=s.caller.upper()))
1297 write(' vl_msg_api_config (&c);\n')
1299 d = define_hash[s.reply]
1300 write(' c = (vl_msg_api_msg_config_t) '
1301 '{{.id = VL_API_{ID} + msg_id_base,\n'
1304 ' .cleanup = vl_noop_handler,\n'
1305 ' .endian = vl_api_{n}_t_endian,\n'
1306 ' .print = vl_api_{n}_t_print,\n'
1307 ' .is_autoendian = 0}};\n'
1308 .format(n=s.reply, ID=s.reply.upper()))
1309 write(' vl_msg_api_config (&c);\n')
1313 write(' return msg_id_base;\n')
1316 severity = {'error': 'VL_COUNTER_SEVERITY_ERROR',
1317 'info': 'VL_COUNTER_SEVERITY_INFO',
1318 'warn': 'VL_COUNTER_SEVERITY_WARN'}
1320 for cnt in counters:
1322 write('vl_counter_t {}_error_counters[] = {{\n'.format(csetname))
1325 write(' .name = "{}",\n'.format(c['name']))
1326 write(' .desc = "{}",\n'.format(c['description']))
1327 write(' .severity = {},\n'.format(severity[c['severity']]))
1332 def generate_c_test_boilerplate(services, defines, file_crc, module, plugin,
1334 '''Generate code for legacy style VAT. To be deleted.'''
1335 write = stream.write
1337 define_hash = {d.name: d for d in defines}
1340 #define vl_endianfun /* define message structures */
1341 #include "{module}.api.h"
1344 /* instantiate all the print functions we know about */
1345 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1347 #include "{module}.api.h"
1352 write(hdr.format(module=module))
1355 d = define_hash[s.reply]
1360 ' * Manual definition requested for: \n'
1361 ' * vl_api_{n}_t_handler()\n'
1365 if not define_hash[s.caller].autoreply:
1366 write('/* Generation not supported (vl_api_{n}_t_handler()) */\n'
1369 write('#ifndef VL_API_{n}_T_HANDLER\n'.format(n=s.reply.upper()))
1370 write('static void\n')
1371 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'
1373 write(' vat_main_t * vam = {}_test_main.vat_main;\n'.format(module))
1374 write(' i32 retval = ntohl(mp->retval);\n')
1375 write(' if (vam->async_mode) {\n')
1376 write(' vam->async_errors += (retval < 0);\n')
1377 write(' } else {\n')
1378 write(' vam->retval = retval;\n')
1379 write(' vam->result_ready = 1;\n')
1385 if define_hash[e].manual_print:
1387 write('static void\n')
1388 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'.format(n=e))
1389 write(' vl_print(0, "{n} event called:");\n'.format(n=e))
1390 write(' vl_api_{n}_t_print(mp, 0);\n'.format(n=e))
1393 write('static void\n')
1394 write('setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n')
1396 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1398 ' vl_api_{n}_t_handler, '
1399 ' vl_noop_handler,\n'
1400 ' vl_api_{n}_t_endian, '
1401 ' vl_api_{n}_t_print,\n'
1402 ' sizeof(vl_api_{n}_t), 1);\n'
1403 .format(n=s.reply, ID=s.reply.upper()))
1404 write(' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'
1405 .format(n=s.caller))
1407 write(' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'
1409 help=define_hash[s.caller].options['vat_help']))
1415 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1417 ' vl_api_{n}_t_handler, '
1418 ' vl_noop_handler,\n'
1419 ' vl_api_{n}_t_endian, '
1420 ' vl_api_{n}_t_print,\n'
1421 ' sizeof(vl_api_{n}_t), 1);\n'
1422 .format(n=e, ID=e.upper()))
1426 write('clib_error_t * vat_plugin_register (vat_main_t *vam)\n')
1428 write('clib_error_t * vat_{}_plugin_register (vat_main_t *vam)\n'
1431 write(' {n}_test_main_t * mainp = &{n}_test_main;\n'.format(n=module))
1432 write(' mainp->vat_main = vam;\n')
1433 write(' mainp->msg_id_base = vl_client_get_first_plugin_msg_id '
1434 ' ("{n}_{crc:08x}");\n'
1435 .format(n=module, crc=file_crc))
1436 write(' if (mainp->msg_id_base == (u16) ~0)\n')
1437 write(' return clib_error_return (0, "{} plugin not loaded...");\n'
1439 write(' setup_message_id_table (vam, mainp->msg_id_base);\n')
1440 write('#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n')
1441 write(' VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n')
1443 write(' return 0;\n')
1448 '''Check if a method is generated already.'''
1449 def _f(module, d, processed, *args):
1450 if d.name in processed:
1452 processed[d.name] = True
1453 return func(module, d, *args)
1457 def c_test_api_service(s, dump, stream):
1458 '''Generate JSON code for a service.'''
1459 write = stream.write
1461 req_reply_template = '''\
1468 mp = vl_api_{n}_t_fromjson(o, &len);
1470 fprintf(stderr, "Failed converting JSON to API\\n");
1474 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1475 vl_api_{n}_t_endian(mp);
1476 vac_write((char *)mp, len);
1482 vac_read(&p, &l, 5); // XXX: Fix timeout
1483 // XXX Will fail in case of event received. Do loop
1484 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1485 fprintf(stderr, "Mismatched reply\\n");
1488 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1489 vl_api_{r}_t_endian(rmp);
1490 return vl_api_{r}_t_tojson(rmp);
1494 dump_details_template = '''\
1498 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1501 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1503 fprintf(stderr, "Failed converting JSON to API\\n");
1506 mp->_vl_msg_id = msg_id;
1507 vl_api_{n}_t_endian(mp);
1508 vac_write((char *)mp, len);
1511 vat2_control_ping(123); // FIX CONTEXT
1512 cJSON *reply = cJSON_CreateArray();
1514 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1515 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1521 vac_read(&p, &l, 5); // XXX: Fix timeout
1523 /* Message can be one of [_details, control_ping_reply
1524 * or unrelated event]
1526 u16 reply_msg_id = ntohs(*((u16 *)p));
1527 if (reply_msg_id == ping_reply_msg_id) {{
1531 if (reply_msg_id == details_msg_id) {{
1532 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1533 vl_api_{r}_t_endian(rmp);
1534 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1541 gets_details_reply_template = '''\
1545 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1548 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1550 fprintf(stderr, "Failed converting JSON to API\\n");
1553 mp->_vl_msg_id = msg_id;
1555 vl_api_{n}_t_endian(mp);
1556 vac_write((char *)mp, len);
1559 cJSON *reply = cJSON_CreateArray();
1561 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1562 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1568 vac_read(&p, &l, 5); // XXX: Fix timeout
1570 /* Message can be one of [_details, control_ping_reply
1571 * or unrelated event]
1573 u16 msg_id = ntohs(*((u16 *)p));
1574 if (msg_id == reply_msg_id) {{
1575 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1576 vl_api_{r}_t_endian(rmp);
1577 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1581 if (msg_id == details_msg_id) {{
1582 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
1583 vl_api_{d}_t_endian(rmp);
1584 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1593 if s.stream_message:
1594 write(gets_details_reply_template
1595 .format(n=s.caller, r=s.reply, N=s.caller.upper(),
1596 R=s.reply.upper(), d=s.stream_message,
1597 D=s.stream_message.upper()))
1599 write(dump_details_template.format(n=s.caller, r=s.reply,
1603 write(req_reply_template.format(n=s.caller, r=s.reply,
1608 def generate_c_test2_boilerplate(services, defines, module, stream):
1609 '''Generate code for VAT2 plugin.'''
1610 write = stream.write
1612 define_hash = {d.name: d for d in defines}
1616 #include <vlibapi/api.h>
1617 #include <vlibmemory/api.h>
1618 #include <vppinfra/error.h>
1619 #include <vnet/ip/ip_format_fns.h>
1620 #include <vnet/ethernet/ethernet_format_fns.h>
1622 #define vl_typedefs /* define message structures */
1623 #include <vpp/api/vpe_all_api_h.h>
1626 #include "{module}.api_enum.h"
1627 #include "{module}.api_types.h"
1629 #define vl_endianfun /* define message structures */
1630 #include "{module}.api.h"
1633 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1635 #include "{module}.api.h"
1638 #include "{module}.api_tojson.h"
1639 #include "{module}.api_fromjson.h"
1640 #include <vpp-api/client/vppapiclient.h>
1642 #include <vat2/vat2_helpers.h>
1646 write(hdr.format(module=module))
1649 if s.reply not in define_hash:
1651 c_test_api_service(s, s.stream, stream)
1653 write('void vat2_register_function(char *, cJSON * (*)(cJSON *));\n')
1654 # write('__attribute__((constructor))')
1655 write('clib_error_t *\n')
1656 write('vat2_register_plugin (void) {\n')
1658 write(' vat2_register_function("{n}", api_{n});\n'
1659 .format(n=s.caller))
1660 write(' return 0;\n')
1665 # Plugin entry point
1667 def run(args, apifilename, s):
1668 '''Main plugin entry point.'''
1671 if not args.outputdir:
1672 sys.stderr.write('Missing --outputdir argument')
1675 basename = os.path.basename(apifilename)
1676 filename, _ = os.path.splitext(basename)
1677 modulename = filename.replace('.', '_')
1678 filename_enum = os.path.join(args.outputdir + '/' + basename + '_enum.h')
1679 filename_types = os.path.join(args.outputdir + '/' + basename + '_types.h')
1680 filename_c = os.path.join(args.outputdir + '/' + basename + '.c')
1681 filename_c_test = os.path.join(args.outputdir + '/' + basename + '_test.c')
1682 filename_c_test2 = (os.path.join(args.outputdir + '/' + basename +
1684 filename_c_tojson = (os.path.join(args.outputdir +
1685 '/' + basename + '_tojson.h'))
1686 filename_c_fromjson = (os.path.join(args.outputdir + '/' +
1687 basename + '_fromjson.h'))
1689 # Generate separate types file
1691 generate_include_types(s, modulename, st)
1692 with open(filename_types, 'w') as fd:
1694 shutil.copyfileobj(st, fd)
1697 # Generate separate enum file
1699 st.write('#ifndef included_{}_api_enum_h\n'.format(modulename))
1700 st.write('#define included_{}_api_enum_h\n'.format(modulename))
1701 generate_include_enum(s, modulename, st)
1702 generate_include_counters(s['Counters'], st)
1703 st.write('#endif\n')
1704 with open(filename_enum, 'w') as fd:
1706 shutil.copyfileobj(st, fd)
1709 # Generate separate C file
1711 generate_c_boilerplate(s['Service'], s['Define'], s['Counters'],
1712 s['file_crc'], modulename, st)
1713 with open(filename_c, 'w') as fd:
1715 shutil.copyfileobj(st, fd)
1718 # Generate separate C test file
1720 plugin = bool('plugin' in apifilename)
1721 generate_c_test_boilerplate(s['Service'], s['Define'],
1723 modulename, plugin, st)
1724 with open(filename_c_test, 'w') as fd:
1726 shutil.copyfileobj(st, fd)
1729 # Fully autogenerated VATv2 C test file
1731 generate_c_test2_boilerplate(s['Service'], s['Define'],
1733 with open(filename_c_test2, 'w') as fd:
1735 shutil.copyfileobj(st, fd)
1738 # Generate separate JSON file
1740 generate_tojson(s, modulename, st)
1741 with open(filename_c_tojson, 'w') as fd:
1743 shutil.copyfileobj(st, fd)
1746 generate_fromjson(s, modulename, st)
1747 with open(filename_c_fromjson, 'w') as fd:
1749 shutil.copyfileobj(st, fd)
1752 output = TOP_BOILERPLATE.format(datestring=DATESTRING,
1753 input_filename=basename)
1754 output += generate_imports(s['Import'])
1755 output += msg_ids(s)
1756 output += msg_names(s)
1757 output += msg_name_crc_list(s, filename)
1758 output += typedefs(modulename)
1759 printfun_types(s['types'], stream, modulename)
1760 printfun(s['Define'], stream, modulename)
1761 output += stream.getvalue()
1763 output += endianfun(s['types'] + s['Define'], modulename)
1764 output += version_tuple(s, basename)
1765 output += BOTTOM_BOILERPLATE.format(input_filename=basename,
1766 file_crc=s['file_crc'])