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
35 ###############################################################################
37 '''Class to generate functions converting from VPP binary API to JSON.'''
39 noprint_fields = {'_vl_msg_id': None,
42 is_number = {'u8': None,
53 def __init__(self, module, types, defines, imported_types, stream):
56 self.defines = defines
58 self.types_hash = {'vl_api_'+d.name+'_t':
59 d for d in types + imported_types}
60 self.defines_hash = {d.name: d for d in defines}
63 '''Output the top boilerplate.'''
64 write = self.stream.write
65 write('#ifndef included_{}_api_tojson_h\n'.format(self.module))
66 write('#define included_{}_api_tojson_h\n'.format(self.module))
67 write('#include <vppinfra/cJSON.h>\n\n')
68 write('#include <vat2/jsonconvert.h>\n\n')
71 '''Output the bottom boilerplate.'''
72 write = self.stream.write
75 def get_json_func(self, t):
76 '''Given the type, returns the function to use to create a
80 vt = self.types_hash[t]
81 if vt.type == 'Using' and 'length' not in vt.alias:
82 vt_type = vt.alias['type']
86 if t in self.is_number or vt_type in self.is_number:
87 return 'cJSON_AddNumberToObject', '', False
89 return 'cJSON_AddBoolToObject', '', False
91 # Lookup type name check if it's enum
93 return '{t}_tojson'.format(t=t), '', True
94 return '{t}_tojson'.format(t=t), '&', True
96 def get_json_array_func(self, t):
97 '''Given a type returns the function to create a cJSON object
99 if t in self.is_number:
100 return 'cJSON_CreateNumber', ''
102 return 'cJSON_CreateBool', ''
103 return '{t}_tojson'.format(t=t), '&'
105 def print_string(self, o):
106 '''Create cJSON object from vl_api_string_t'''
107 write = self.stream.write
109 write(' vl_api_string_cJSON_AddToObject(o, "{n}", &a->{n});\n'
110 .format(n=o.fieldname))
113 write(' cJSON_AddStringToObject(o, "{n}", (char *)a->{n});\n'
114 .format(n=o.fieldname))
116 def print_field(self, o):
117 '''Called for every field in a typedef or define.'''
118 write = self.stream.write
119 if o.fieldname in self.noprint_fields:
122 f, p, newobj = self.get_json_func(o.fieldtype)
125 write(' cJSON_AddItemToObject(o, "{n}", {f}({p}a->{n}));\n'
126 .format(f=f, p=p, n=o.fieldname))
128 write(' {f}(o, "{n}", {p}a->{n});\n'
129 .format(f=f, p=p, n=o.fieldname))
131 _dispatch['Field'] = print_field
133 def print_array(self, o):
134 '''Converts a VPP API array to cJSON array.'''
135 write = self.stream.write
140 cJSON *array = cJSON_AddArrayToObject(o, "{n}");
141 for (i = 0; i < {lfield}; i++) {{
142 cJSON_AddItemToArray(array, {f}({p}a->{n}[i]));
147 if o.fieldtype == 'string':
151 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
152 if o.fieldtype == 'u8':
154 # What is length field doing here?
155 write(' u8 *s = format(0, "0x%U", format_hex_bytes, '
156 '&a->{n}, {lfield});\n'
157 .format(n=o.fieldname, lfield=lfield))
158 write(' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'
159 .format(n=o.fieldname))
160 write(' vec_free(s);\n')
164 f, p = self.get_json_array_func(o.fieldtype)
165 write(forloop.format(lfield=lfield,
171 _dispatch['Array'] = print_array
173 def print_enum(self, o):
174 '''Create cJSON object (string) for VPP API enum'''
175 write = self.stream.write
176 write('static inline cJSON *vl_api_{name}_t_tojson '
177 '(vl_api_{name}_t a) {{\n'.format(name=o.name))
179 write(" switch(a) {\n")
181 write(" case %s:\n" % b[1])
182 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
183 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
185 write(' return 0;\n')
188 _dispatch['Enum'] = print_enum
190 def print_typedef(self, o):
191 '''Create cJSON (dictionary) object from VPP API typedef'''
192 write = self.stream.write
193 write('static inline cJSON *vl_api_{name}_t_tojson '
194 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
195 write(' cJSON *o = cJSON_CreateObject();\n')
198 self._dispatch[t.type](self, t)
200 write(' return o;\n')
203 def print_define(self, o):
204 '''Create cJSON (dictionary) object from VPP API define'''
205 write = self.stream.write
206 write('static inline cJSON *vl_api_{name}_t_tojson '
207 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
208 write(' cJSON *o = cJSON_CreateObject();\n')
209 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'
213 self._dispatch[t.type](self, t)
215 write(' return o;\n')
218 def print_using(self, o):
219 '''Create cJSON (dictionary) object from VPP API aliased type'''
223 write = self.stream.write
224 write('static inline cJSON *vl_api_{name}_t_tojson '
225 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
227 write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'
229 write(' cJSON *o = cJSON_CreateString((char *)s);\n')
230 write(' vec_free(s);\n')
231 write(' return o;\n')
234 _dispatch['Typedef'] = print_typedef
235 _dispatch['Define'] = print_define
236 _dispatch['Using'] = print_using
237 _dispatch['Union'] = print_typedef
239 def generate_function(self, t):
240 '''Main entry point'''
241 write = self.stream.write
243 write('/* Manual print {} */\n'.format(t.name))
245 self._dispatch[t.type](self, t)
247 def generate_types(self):
248 '''Main entry point'''
250 self.generate_function(t)
252 def generate_defines(self):
253 '''Main entry point'''
254 for t in self.defines:
255 self.generate_function(t)
260 Parse JSON objects into VPP API binary message structures.
263 noprint_fields = {'_vl_msg_id': None,
264 'client_index': None,
266 is_number = {'u8': None,
277 def __init__(self, module, types, defines, imported_types, stream):
280 self.defines = defines
282 self.types_hash = {'vl_api_'+d.name+'_t':
283 d for d in types + imported_types}
284 self.defines_hash = {d.name: d for d in defines}
287 '''Output the top boilerplate.'''
288 write = self.stream.write
289 write('#ifndef included_{}_api_fromjson_h\n'.format(self.module))
290 write('#define included_{}_api_fromjson_h\n'.format(self.module))
291 write('#include <vppinfra/cJSON.h>\n\n')
292 write('#include <vat2/jsonconvert.h>\n\n')
294 def is_base_type(self, t):
295 '''Check if a type is one of the VPP API base types'''
296 if t in self.is_number:
303 '''Output the bottom boilerplate.'''
304 write = self.stream.write
307 def print_string(self, o, toplevel=False):
308 '''Convert JSON string to vl_api_string_t'''
309 write = self.stream.write
311 msgvar = "a" if toplevel else "mp"
312 msgsize = "l" if toplevel else "*len"
315 write(' char *p = cJSON_GetStringValue(item);\n')
316 write(' size_t plen = strlen(p);\n')
317 write(' {msgvar} = realloc({msgvar}, {msgsize} + plen);\n'
318 .format(msgvar=msgvar, msgsize=msgsize))
319 write(' vl_api_c_string_to_api_string(p, (void *){msgvar} + '
320 '{msgsize} - sizeof(vl_api_string_t));\n'
321 .format(msgvar=msgvar, msgsize=msgsize))
322 write(' {msgsize} += plen;\n'.format(msgsize=msgsize))
324 write(' strncpy_s((char *)a->{n}, sizeof(a->{n}), '
325 'cJSON_GetStringValue(item), sizeof(a->{n}) - 1);\n'
326 .format(n=o.fieldname))
328 def print_field(self, o, toplevel=False):
329 '''Called for every field in a typedef or define.'''
330 write = self.stream.write
331 write(' // start field {}\n'.format(o.fieldname))
332 if o.fieldname in self.noprint_fields:
334 is_bt = self.is_base_type(o.fieldtype)
335 t = 'vl_api_{}'.format(o.fieldtype) if is_bt else o.fieldtype
337 msgvar = "a" if toplevel else "mp"
338 msgsize = "&l" if toplevel else "len"
341 write(' vl_api_{t}_fromjson(item, &a->{n});\n'
342 .format(t=o.fieldtype, n=o.fieldname))
344 write(' {msgvar} = {t}_fromjson({msgvar}, '
345 '{msgsize}, item, &a->{n});\n'
346 .format(t=t, n=o.fieldname, msgvar=msgvar, msgsize=msgsize))
347 write(' if (!{msgvar}) return 0;\n'.format(msgvar=msgvar))
349 write(' // end field {}\n'.format(o.fieldname))
351 _dispatch['Field'] = print_field
353 def print_array(self, o, toplevel=False):
354 '''Convert JSON array to VPP API array'''
355 write = self.stream.write
360 cJSON *array = cJSON_GetObjectItem(o, "{n}");
361 int size = cJSON_GetArraySize(array);
362 if (size != {lfield}) return 0;
363 for (i = 0; i < size; i++) {{
364 cJSON *e = cJSON_GetArrayItem(array, i);
372 cJSON *array = cJSON_GetObjectItem(o, "{n}");
373 int size = cJSON_GetArraySize(array);
375 {msgvar} = realloc({msgvar}, {msgsize} + sizeof({t}) * size);
376 {t} *d = (void *){msgvar} + {msgsize};
377 {msgsize} += sizeof({t}) * size;
378 for (i = 0; i < size; i++) {{
379 cJSON *e = cJSON_GetArrayItem(array, i);
385 if o.fieldtype == 'string':
386 self.print_string(o, toplevel)
389 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
390 msgvar = "a" if toplevel else "mp"
391 msgsize = "l" if toplevel else "*len"
393 if o.fieldtype == 'u8':
395 write(' s = u8string_fromjson(o, "{}");\n'
396 .format(o.fieldname))
397 write(' if (!s) return 0;\n')
398 write(' {} = vec_len(s);\n'.format(lfield))
400 write(' {msgvar} = realloc({msgvar}, {msgsize} + '
401 'vec_len(s));\n'.format(msgvar=msgvar, msgsize=msgsize))
402 write(' memcpy((void *){msgvar} + {msgsize}, s, '
403 'vec_len(s));\n'.format(msgvar=msgvar, msgsize=msgsize))
404 write(' {msgsize} += vec_len(s);\n'.format(msgsize=msgsize))
406 write(' vec_free(s);\n')
408 write(' u8string_fromjson2(o, "{n}", a->{n});\n'
409 .format(n=o.fieldname))
412 is_bt = self.is_base_type(o.fieldtype)
416 call = ('vl_api_{t}_fromjson(e, &d[i]);'
417 .format(t=o.fieldtype))
419 call = ('{t}_fromjson({msgvar}, len, e, &d[i]); '
420 .format(t=o.fieldtype, msgvar=msgvar))
421 write(forloop_vla.format(lfield=lfield,
429 call = ('vl_api_{t}_fromjson(e, &a->{n}[i]);'
430 .format(t=t, n=o.fieldname))
432 call = ('a = {}_fromjson({}, len, e, &a->{}[i]);'
433 .format(t, msgvar, o.fieldname))
434 write(forloop.format(lfield=lfield,
441 _dispatch['Array'] = print_array
443 def print_enum(self, o):
444 '''Convert to JSON enum(string) to VPP API enum (int)'''
445 write = self.stream.write
446 write('static inline void *vl_api_{n}_t_fromjson '
447 '(void *mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n'
449 write(' char *p = cJSON_GetStringValue(o);\n')
451 write(' if (strcmp(p, "{}") == 0) {{*a = {}; return mp;}}\n'
453 write(' return 0;\n')
456 _dispatch['Enum'] = print_enum
458 def print_typedef(self, o):
459 '''Convert from JSON object to VPP API binary representation'''
460 write = self.stream.write
462 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
463 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
464 .format(name=o.name))
465 write(' cJSON *item __attribute__ ((unused));\n')
466 write(' u8 *s __attribute__ ((unused));\n')
468 if t.type == 'Field' and t.is_lengthfield:
470 write(' item = cJSON_GetObjectItem(o, "{}");\n'
471 .format(t.fieldname))
472 write(' if (!item) return 0;\n')
474 self._dispatch[t.type](self, t)
476 write(' return mp;\n')
479 def print_union(self, o):
480 '''Convert JSON object to VPP API binary union'''
481 write = self.stream.write
483 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
484 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
485 .format(name=o.name))
486 write(' cJSON *item __attribute__ ((unused));\n')
487 write(' u8 *s __attribute__ ((unused));\n')
489 if t.type == 'Field' and t.is_lengthfield:
491 write(' item = cJSON_GetObjectItem(o, "{}");\n'
492 .format(t.fieldname))
493 write(' if (item) {\n')
494 self._dispatch[t.type](self, t)
496 write(' return mp;\n')
499 def print_define(self, o):
500 '''Convert JSON object to VPP API message'''
501 write = self.stream.write
502 write('static inline vl_api_{name}_t *vl_api_{name}_t_fromjson '
503 '(cJSON *o, int *len) {{\n'.format(name=o.name))
504 write(' cJSON *item __attribute__ ((unused));\n')
505 write(' u8 *s __attribute__ ((unused));\n')
506 write(' int l = sizeof(vl_api_{}_t);\n'.format(o.name))
507 write(' vl_api_{}_t *a = malloc(l);\n'.format(o.name))
510 if t.fieldname in self.noprint_fields:
512 if t.type == 'Field' and t.is_lengthfield:
514 write(' // processing {}: {} {}\n'
515 .format(o.name, t.fieldtype, t.fieldname))
517 write(' item = cJSON_GetObjectItem(o, "{}");\n'
518 .format(t.fieldname))
519 write(' if (!item) return 0;\n')
520 self._dispatch[t.type](self, t, toplevel=True)
524 write(' *len = l;\n')
525 write(' return a;\n')
528 def print_using(self, o):
529 '''Convert JSON field to VPP type alias'''
530 write = self.stream.write
536 write('static inline void *vl_api_{name}_t_fromjson (void *mp, '
537 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
538 .format(name=o.name))
539 if 'length' in o.alias:
540 if t.fieldtype != 'u8':
541 raise ValueError("Error in processing type {} for {}"
542 .format(t.fieldtype, o.name))
543 write(' vl_api_u8_string_fromjson(o, (u8 *)a, {});\n'
544 .format(o.alias['length']))
546 write(' vl_api_{t}_fromjson(o, ({t} *)a);\n'
547 .format(t=t.fieldtype))
549 write(' return mp;\n')
552 _dispatch['Typedef'] = print_typedef
553 _dispatch['Define'] = print_define
554 _dispatch['Using'] = print_using
555 _dispatch['Union'] = print_union
557 def generate_function(self, t):
558 '''Main entry point'''
559 write = self.stream.write
561 write('/* Manual print {} */\n'.format(t.name))
563 self._dispatch[t.type](self, t)
565 def generate_types(self):
566 '''Main entry point'''
568 self.generate_function(t)
570 def generate_defines(self):
571 '''Main entry point'''
572 for t in self.defines:
573 self.generate_function(t)
576 def generate_tojson(s, modulename, stream):
577 '''Generate all functions to convert from API to JSON'''
580 write('/* Imported API files */\n')
581 for i in s['Import']:
582 f = i.filename.replace('plugins/', '')
583 write('#include <{}_tojson.h>\n'.format(f))
585 pp = ToJSON(modulename, s['types'], s['Define'], s['imported']['types'],
589 pp.generate_defines()
594 def generate_fromjson(s, modulename, stream):
595 '''Generate all functions to convert from JSON to API'''
597 write('/* Imported API files */\n')
598 for i in s['Import']:
599 f = i.filename.replace('plugins/', '')
600 write('#include <{}_fromjson.h>\n'.format(f))
602 pp = FromJSON(modulename, s['types'], s['Define'], s['imported']['types'],
606 pp.generate_defines()
611 ###############################################################################
614 DATESTRING = datetime.datetime.utcfromtimestamp(
615 int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
616 TOP_BOILERPLATE = '''\
618 * VLIB API definitions {datestring}
619 * Input file: {input_filename}
620 * Automatically generated: please edit the input file NOT this file!
624 #if defined(vl_msg_id)||defined(vl_union_id) \\
625 || defined(vl_printfun) ||defined(vl_endianfun) \\
626 || defined(vl_api_version)||defined(vl_typedefs) \\
627 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
628 || defined(vl_api_version_tuple)
629 /* ok, something was selected */
631 #warning no content included from {input_filename}
634 #define VL_API_PACKED(x) x __attribute__ ((packed))
637 BOTTOM_BOILERPLATE = '''\
638 /****** API CRC (whole file) *****/
640 #ifdef vl_api_version
641 vl_api_version({input_filename}, {file_crc:#08x})
648 '''Generate macro to map API message id to handler'''
651 /****** Message ID / handler enum ******/
656 for t in s['Define']:
657 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
658 (t.name.upper(), t.name)
665 '''Generate calls to name mapping macro'''
668 /****** Message names ******/
673 for t in s['Define']:
674 dont_trace = 0 if t.dont_trace else 1
675 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
681 def msg_name_crc_list(s, suffix):
682 '''Generate list of names to CRC mappings'''
685 /****** Message name, crc list ******/
687 #ifdef vl_msg_name_crc_list
689 output += "#define foreach_vl_msg_name_crc_%s " % suffix
691 for t in s['Define']:
692 output += "\\\n_(VL_API_%s, %s, %08x) " % \
693 (t.name.upper(), t.name, t.crc)
699 def api2c(fieldtype):
700 '''Map between API type names and internal VPP type names'''
701 mappingtable = {'string': 'vl_api_string_t', }
702 if fieldtype in mappingtable:
703 return mappingtable[fieldtype]
707 def typedefs(filename):
708 '''Include in the main files to the types file'''
711 /****** Typedefs ******/
714 #include "{include}.api_types.h"
716 '''.format(include=filename)
720 FORMAT_STRINGS = {'u8': '%u',
733 '''Functions for pretty printing VPP API messages'''
735 noprint_fields = {'_vl_msg_id': None,
736 'client_index': None,
739 def __init__(self, stream):
743 def print_string(o, stream):
744 '''Pretty print a vl_api_string_t'''
747 write(' if (vl_api_string_len(&a->{f}) > 0) {{\n'
748 .format(f=o.fieldname))
749 write(' s = format(s, "\\n%U{f}: %U", '
750 'format_white_space, indent, '
751 'vl_api_format_string, (&a->{f}));\n'.format(f=o.fieldname))
753 write(' s = format(s, "\\n%U{f}:", '
754 'format_white_space, indent);\n'.format(f=o.fieldname))
757 write(' s = format(s, "\\n%U{f}: %s", '
758 'format_white_space, indent, a->{f});\n'
759 .format(f=o.fieldname))
761 def print_field(self, o, stream):
762 '''Pretty print API field'''
764 if o.fieldname in self.noprint_fields:
766 if o.fieldtype in FORMAT_STRINGS:
767 f = FORMAT_STRINGS[o.fieldtype]
768 write(' s = format(s, "\\n%U{n}: {f}", '
769 'format_white_space, indent, a->{n});\n'
770 .format(n=o.fieldname, f=f))
772 write(' s = format(s, "\\n%U{n}: %U", '
773 'format_white_space, indent, '
774 'format_{t}, &a->{n}, indent);\n'
775 .format(n=o.fieldname, t=o.fieldtype))
777 _dispatch['Field'] = print_field
779 def print_array(self, o, stream):
780 '''Pretty print API array'''
784 for (i = 0; i < {lfield}; i++) {{
785 s = format(s, "\\n%U{n}: %U",
786 format_white_space, indent, format_{t}, &a->{n}[i], indent);
790 forloop_format = '''\
791 for (i = 0; i < {lfield}; i++) {{
792 s = format(s, "\\n%U{n}: {t}",
793 format_white_space, indent, a->{n}[i]);
797 if o.fieldtype == 'string':
798 self.print_string(o, stream)
801 if o.fieldtype == 'u8':
803 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
804 'indent, format_hex_bytes, a->{n}, a->{lfield});\n'
805 .format(n=o.fieldname, lfield=o.lengthfield))
807 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
808 'indent, format_hex_bytes, a, {lfield});\n'
809 .format(n=o.fieldname, lfield=o.length))
812 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
813 if o.fieldtype in FORMAT_STRINGS:
814 write(forloop_format.format(lfield=lfield,
815 t=FORMAT_STRINGS[o.fieldtype],
818 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname))
820 _dispatch['Array'] = print_array
823 def print_alias(k, v, stream):
824 '''Pretty print type alias'''
826 if ('length' in v.alias and v.alias['length'] and
827 v.alias['type'] == 'u8'):
828 write(' return format(s, "%U", format_hex_bytes, a, {});\n'
829 .format(v.alias['length']))
830 elif v.alias['type'] in FORMAT_STRINGS:
831 write(' return format(s, "{}", *a);\n'
832 .format(FORMAT_STRINGS[v.alias['type']]))
834 write(' return format(s, "{} (print not implemented)");\n'
838 def print_enum(o, stream):
839 '''Pretty print API enum'''
841 write(" switch(*a) {\n")
843 write(" case %s:\n" % b[1])
844 write(' return format(s, "{}");\n'.format(b[0]))
847 _dispatch['Enum'] = print_enum
849 def print_obj(self, o, stream):
853 if o.type in self._dispatch:
854 self._dispatch[o.type](self, o, stream)
856 write(' s = format(s, "\\n{} {} {} (print not implemented");\n'
857 .format(o.type, o.fieldtype, o.fieldname))
860 def printfun(objs, stream, modulename):
861 '''Main entry point for pretty print function generation'''
865 /****** Print functions *****/
867 #ifndef included_{module}_printfun
868 #define included_{module}_printfun
871 #define _uword_fmt \"%lld\"
872 #define _uword_cast (long long)
874 #define _uword_fmt \"%ld\"
875 #define _uword_cast long
881 static inline void *vl_api_{name}_t_print (vl_api_{name}_t *a, void *handle)
884 u32 indent __attribute__((unused)) = 2;
885 int i __attribute__((unused));
888 h = h.format(module=modulename)
891 pp = Printfun(stream)
894 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
896 write(signature.format(name=t.name))
897 write(' /* Message definition: vl_api_{}_t: */\n'.format(t.name))
898 write(" s = format(s, \"vl_api_%s_t:\");\n" % t.name)
900 pp.print_obj(o, stream)
901 write(' vec_add1(s, 0);\n')
902 write(' vl_print (handle, (char *)s);\n')
903 write(' vec_free (s);\n')
904 write(' return handle;\n')
908 write("\n#endif /* vl_printfun */\n")
913 def printfun_types(objs, stream, modulename):
914 '''Pretty print API types'''
916 pp = Printfun(stream)
919 /****** Print functions *****/
921 #ifndef included_{module}_printfun_types
922 #define included_{module}_printfun_types
925 h = h.format(module=modulename)
929 static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
931 vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
932 u32 indent __attribute__((unused)) = va_arg (*args, u32);
933 int i __attribute__((unused));
938 if t.__class__.__name__ == 'Enum':
939 write(signature.format(name=t.name))
940 pp.print_enum(t.block, stream)
941 write(' return s;\n')
946 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
949 if t.__class__.__name__ == 'Using':
950 write(signature.format(name=t.name))
951 pp.print_alias(t.name, t, stream)
955 write(signature.format(name=t.name))
957 pp.print_obj(o, stream)
959 write(' return s;\n')
963 write("\n#endif /* vl_printfun_types */\n")
966 def generate_imports(imports):
967 '''Add #include matching the API import statements'''
968 output = '/* Imported API files */\n'
969 output += '#ifndef vl_api_version\n'
972 s = i.filename.replace('plugins/', '')
973 output += '#include <{}.h>\n'.format(s)
979 'u16': 'clib_net_to_host_u16',
980 'u32': 'clib_net_to_host_u32',
981 'u64': 'clib_net_to_host_u64',
982 'i16': 'clib_net_to_host_i16',
983 'i32': 'clib_net_to_host_i32',
984 'i64': 'clib_net_to_host_i64',
985 'f64': 'clib_net_to_host_f64',
989 def endianfun_array(o):
990 '''Generate endian functions for arrays'''
992 for (i = 0; i < {length}; i++) {{
993 a->{name}[i] = {format}(a->{name}[i]);
997 forloop_format = '''\
998 for (i = 0; i < {length}; i++) {{
999 {type}_endian(&a->{name}[i]);
1004 if o.fieldtype == 'u8' or o.fieldtype == 'string':
1005 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1007 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
1008 if o.fieldtype in ENDIAN_STRINGS:
1010 .format(length=lfield,
1011 format=ENDIAN_STRINGS[o.fieldtype],
1014 output += (forloop_format
1015 .format(length=lfield, type=o.fieldtype,
1020 NO_ENDIAN_CONVERSION = {'client_index': None}
1023 def endianfun_obj(o):
1024 '''Generate endian conversion function for type'''
1026 if o.type == 'Array':
1027 return endianfun_array(o)
1028 if o.type != 'Field':
1029 output += (' s = format(s, "\\n{} {} {} (print not implemented");\n'
1030 .format(o.type, o.fieldtype, o.fieldname))
1032 if o.fieldname in NO_ENDIAN_CONVERSION:
1033 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1035 if o.fieldtype in ENDIAN_STRINGS:
1036 output += (' a->{name} = {format}(a->{name});\n'
1037 .format(name=o.fieldname,
1038 format=ENDIAN_STRINGS[o.fieldtype]))
1039 elif o.fieldtype.startswith('vl_api_'):
1040 output += (' {type}_endian(&a->{name});\n'
1041 .format(type=o.fieldtype, name=o.fieldname))
1043 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1048 def endianfun(objs, modulename):
1049 '''Main entry point for endian function generation'''
1052 /****** Endian swap functions *****/\n\
1054 #ifndef included_{module}_endianfun
1055 #define included_{module}_endianfun
1057 #undef clib_net_to_host_uword
1059 #define clib_net_to_host_uword clib_net_to_host_u64
1061 #define clib_net_to_host_uword clib_net_to_host_u32
1065 output = output.format(module=modulename)
1068 static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
1070 int i __attribute__((unused));
1074 if t.__class__.__name__ == 'Enum':
1075 output += signature.format(name=t.name)
1076 if t.enumtype in ENDIAN_STRINGS:
1077 output += (' *a = {}(*a);\n'
1078 .format(ENDIAN_STRINGS[t.enumtype]))
1080 output += (' /* a->{name} = a->{name} (no-op) */\n'
1081 .format(name=t.name))
1087 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1090 if t.__class__.__name__ == 'Using':
1091 output += signature.format(name=t.name)
1092 if ('length' in t.alias and t.alias['length'] and
1093 t.alias['type'] == 'u8'):
1094 output += (' /* a->{name} = a->{name} (no-op) */\n'
1095 .format(name=t.name))
1096 elif t.alias['type'] in FORMAT_STRINGS:
1097 output += (' *a = {}(*a);\n'
1098 .format(ENDIAN_STRINGS[t.alias['type']]))
1100 output += ' /* Not Implemented yet {} */'.format(t.name)
1104 output += signature.format(name=t.name)
1107 output += endianfun_obj(o)
1110 output += "\n#endif"
1111 output += "\n#endif /* vl_endianfun */\n\n"
1116 def version_tuple(s, module):
1117 '''Generate semantic version string'''
1119 /****** Version tuple *****/
1121 #ifdef vl_api_version_tuple
1124 if 'version' in s['Option']:
1125 v = s['Option']['version']
1126 (major, minor, patch) = v.split('.')
1127 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
1128 (module, major, minor, patch)
1130 output += "\n#endif /* vl_api_version_tuple */\n\n"
1135 def generate_include_enum(s, module, stream):
1136 '''Generate <name>.api_enum.h'''
1137 write = stream.write
1140 write('typedef enum {\n')
1141 for t in s['Define']:
1142 write(' VL_API_{},\n'.format(t.name.upper()))
1143 write(' VL_MSG_{}_LAST\n'.format(module.upper()))
1144 write('}} vl_api_{}_enum_t;\n'.format(module))
1147 def generate_include_counters(s, stream):
1148 '''Include file for the counter data model types.'''
1149 write = stream.write
1152 csetname = counters.name
1153 write('typedef enum {\n')
1154 for c in counters.block:
1155 write(' {}_ERROR_{},\n'
1156 .format(csetname.upper(), c['name'].upper()))
1157 write(' {}_N_ERROR\n'.format(csetname.upper()))
1158 write('}} vl_counter_{}_enum_t;\n'.format(csetname))
1160 write('extern vl_counter_t {}_error_counters[];\n'.format(csetname))
1163 def generate_include_types(s, module, stream):
1164 '''Generate separate API _types file.'''
1165 write = stream.write
1167 write('#ifndef included_{module}_api_types_h\n'.format(module=module))
1168 write('#define included_{module}_api_types_h\n'.format(module=module))
1170 if 'version' in s['Option']:
1171 v = s['Option']['version']
1172 (major, minor, patch) = v.split('.')
1173 write('#define VL_API_{m}_API_VERSION_MAJOR {v}\n'
1174 .format(m=module.upper(), v=major))
1175 write('#define VL_API_{m}_API_VERSION_MINOR {v}\n'
1176 .format(m=module.upper(), v=minor))
1177 write('#define VL_API_{m}_API_VERSION_PATCH {v}\n'
1178 .format(m=module.upper(), v=patch))
1181 write('/* Imported API files */\n')
1182 for i in s['Import']:
1183 filename = i.filename.replace('plugins/', '')
1184 write('#include <{}_types.h>\n'.format(filename))
1186 for o in s['types'] + s['Define']:
1187 tname = o.__class__.__name__
1188 if tname == 'Using':
1189 if 'length' in o.alias:
1190 write('typedef %s vl_api_%s_t[%s];\n' %
1191 (o.alias['type'], o.name, o.alias['length']))
1193 write('typedef %s vl_api_%s_t;\n' % (o.alias['type'], o.name))
1194 elif tname == 'Enum':
1195 if o.enumtype == 'u32':
1196 write("typedef enum {\n")
1198 write("typedef enum __attribute__((packed)) {\n")
1201 write(" %s = %s,\n" % (b[0], b[1]))
1202 write('} vl_api_%s_t;\n' % o.name)
1203 if o.enumtype != 'u32':
1204 size1 = 'sizeof(vl_api_%s_t)' % o.name
1205 size2 = 'sizeof(%s)' % o.enumtype
1206 err_str = 'size of API enum %s is wrong' % o.name
1207 write('STATIC_ASSERT(%s == %s, "%s");\n'
1208 % (size1, size2, err_str))
1210 if tname == 'Union':
1211 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n"
1214 write(("typedef struct __attribute__ ((packed)) _vl_api_%s {\n")
1217 if b.type == 'Option':
1219 if b.type == 'Field':
1220 write(" %s %s;\n" % (api2c(b.fieldtype),
1222 elif b.type == 'Array':
1224 write(" %s %s[0];\n" % (api2c(b.fieldtype),
1227 # Fixed length strings decay to nul terminated u8
1228 if b.fieldtype == 'string':
1231 .format(api2c(b.fieldtype),
1234 write(' u8 {}[{}];\n'
1235 .format(b.fieldname, b.length))
1237 write(" %s %s[%s];\n" %
1238 (api2c(b.fieldtype), b.fieldname,
1241 raise ValueError("Error in processing type {} for {}"
1244 write('} vl_api_%s_t;\n' % o.name)
1246 for t in s['Define']:
1247 write('#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'
1248 .format(n=t.name, ID=t.name.upper(), crc=t.crc))
1253 def generate_c_boilerplate(services, defines, counters, file_crc,
1255 '''VPP side plugin.'''
1256 write = stream.write
1257 define_hash = {d.name: d for d in defines}
1260 #define vl_endianfun /* define message structures */
1261 #include "{module}.api.h"
1264 /* instantiate all the print functions we know about */
1265 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1267 #include "{module}.api.h"
1272 write(hdr.format(module=module))
1273 write('static u16\n')
1274 write('setup_message_id_table (void) {\n')
1275 write(' api_main_t *am = my_api_main;\n')
1276 write(' vl_msg_api_msg_config_t c;\n')
1277 write(' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1278 'VL_MSG_{m}_LAST);\n'
1279 .format(module, crc=file_crc, m=module.upper()))
1282 write(' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1283 ' VL_API_{ID} + msg_id_base);\n'
1284 .format(n=d.name, ID=d.name.upper(), crc=d.crc))
1286 d = define_hash[s.caller]
1287 write(' c = (vl_msg_api_msg_config_t) '
1288 ' {{.id = VL_API_{ID} + msg_id_base,\n'
1290 ' .handler = vl_api_{n}_t_handler,\n'
1291 ' .cleanup = vl_noop_handler,\n'
1292 ' .endian = vl_api_{n}_t_endian,\n'
1293 ' .print = vl_api_{n}_t_print,\n'
1294 ' .is_autoendian = 0}};\n'
1295 .format(n=s.caller, ID=s.caller.upper()))
1296 write(' vl_msg_api_config (&c);\n')
1298 d = define_hash[s.reply]
1299 write(' c = (vl_msg_api_msg_config_t) '
1300 '{{.id = VL_API_{ID} + msg_id_base,\n'
1303 ' .cleanup = vl_noop_handler,\n'
1304 ' .endian = vl_api_{n}_t_endian,\n'
1305 ' .print = vl_api_{n}_t_print,\n'
1306 ' .is_autoendian = 0}};\n'
1307 .format(n=s.reply, ID=s.reply.upper()))
1308 write(' vl_msg_api_config (&c);\n')
1312 write(' return msg_id_base;\n')
1315 severity = {'error': 'VL_COUNTER_SEVERITY_ERROR',
1316 'info': 'VL_COUNTER_SEVERITY_INFO',
1317 'warn': 'VL_COUNTER_SEVERITY_WARN'}
1319 for cnt in counters:
1321 write('vl_counter_t {}_error_counters[] = {{\n'.format(csetname))
1324 write(' .name = "{}",\n'.format(c['name']))
1325 write(' .desc = "{}",\n'.format(c['description']))
1326 write(' .severity = {},\n'.format(severity[c['severity']]))
1331 def generate_c_test_boilerplate(services, defines, file_crc, module, plugin,
1333 '''Generate code for legacy style VAT. To be deleted.'''
1334 write = stream.write
1336 define_hash = {d.name: d for d in defines}
1339 #define vl_endianfun /* define message structures */
1340 #include "{module}.api.h"
1343 /* instantiate all the print functions we know about */
1344 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1346 #include "{module}.api.h"
1351 write(hdr.format(module=module))
1354 d = define_hash[s.reply]
1359 ' * Manual definition requested for: \n'
1360 ' * vl_api_{n}_t_handler()\n'
1364 if not define_hash[s.caller].autoreply:
1365 write('/* Generation not supported (vl_api_{n}_t_handler()) */\n'
1368 write('#ifndef VL_API_{n}_T_HANDLER\n'.format(n=s.reply.upper()))
1369 write('static void\n')
1370 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'
1372 write(' vat_main_t * vam = {}_test_main.vat_main;\n'.format(module))
1373 write(' i32 retval = ntohl(mp->retval);\n')
1374 write(' if (vam->async_mode) {\n')
1375 write(' vam->async_errors += (retval < 0);\n')
1376 write(' } else {\n')
1377 write(' vam->retval = retval;\n')
1378 write(' vam->result_ready = 1;\n')
1384 if define_hash[e].manual_print:
1386 write('static void\n')
1387 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'.format(n=e))
1388 write(' vl_print(0, "{n} event called:");\n'.format(n=e))
1389 write(' vl_api_{n}_t_print(mp, 0);\n'.format(n=e))
1392 write('static void\n')
1393 write('setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n')
1395 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1397 ' vl_api_{n}_t_handler, '
1398 ' vl_noop_handler,\n'
1399 ' vl_api_{n}_t_endian, '
1400 ' vl_api_{n}_t_print,\n'
1401 ' sizeof(vl_api_{n}_t), 1);\n'
1402 .format(n=s.reply, ID=s.reply.upper()))
1403 write(' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'
1404 .format(n=s.caller))
1406 write(' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'
1408 help=define_hash[s.caller].options['vat_help']))
1414 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1416 ' vl_api_{n}_t_handler, '
1417 ' vl_noop_handler,\n'
1418 ' vl_api_{n}_t_endian, '
1419 ' vl_api_{n}_t_print,\n'
1420 ' sizeof(vl_api_{n}_t), 1);\n'
1421 .format(n=e, ID=e.upper()))
1425 write('clib_error_t * vat_plugin_register (vat_main_t *vam)\n')
1427 write('clib_error_t * vat_{}_plugin_register (vat_main_t *vam)\n'
1430 write(' {n}_test_main_t * mainp = &{n}_test_main;\n'.format(n=module))
1431 write(' mainp->vat_main = vam;\n')
1432 write(' mainp->msg_id_base = vl_client_get_first_plugin_msg_id '
1433 ' ("{n}_{crc:08x}");\n'
1434 .format(n=module, crc=file_crc))
1435 write(' if (mainp->msg_id_base == (u16) ~0)\n')
1436 write(' return clib_error_return (0, "{} plugin not loaded...");\n'
1438 write(' setup_message_id_table (vam, mainp->msg_id_base);\n')
1439 write('#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n')
1440 write(' VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n')
1442 write(' return 0;\n')
1447 '''Check if a method is generated already.'''
1448 def _f(module, d, processed, *args):
1449 if d.name in processed:
1451 processed[d.name] = True
1452 return func(module, d, *args)
1456 def c_test_api_service(s, dump, stream):
1457 '''Generate JSON code for a service.'''
1458 write = stream.write
1460 req_reply_template = '''\
1467 mp = vl_api_{n}_t_fromjson(o, &len);
1469 fprintf(stderr, "Failed converting JSON to API\\n");
1473 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1474 vl_api_{n}_t_endian(mp);
1475 vac_write((char *)mp, len);
1481 vac_read(&p, &l, 5); // XXX: Fix timeout
1482 // XXX Will fail in case of event received. Do loop
1483 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1484 fprintf(stderr, "Mismatched reply\\n");
1487 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1488 vl_api_{r}_t_endian(rmp);
1489 return vl_api_{r}_t_tojson(rmp);
1493 dump_details_template = '''\
1497 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1500 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1502 fprintf(stderr, "Failed converting JSON to API\\n");
1505 mp->_vl_msg_id = msg_id;
1506 vl_api_{n}_t_endian(mp);
1507 vac_write((char *)mp, len);
1510 vat2_control_ping(123); // FIX CONTEXT
1511 cJSON *reply = cJSON_CreateArray();
1513 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1514 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1520 vac_read(&p, &l, 5); // XXX: Fix timeout
1522 /* Message can be one of [_details, control_ping_reply
1523 * or unrelated event]
1525 u16 reply_msg_id = ntohs(*((u16 *)p));
1526 if (reply_msg_id == ping_reply_msg_id) {{
1530 if (reply_msg_id == details_msg_id) {{
1531 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1532 vl_api_{r}_t_endian(rmp);
1533 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1540 gets_details_reply_template = '''\
1544 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1547 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1549 fprintf(stderr, "Failed converting JSON to API\\n");
1552 mp->_vl_msg_id = msg_id;
1554 vl_api_{n}_t_endian(mp);
1555 vac_write((char *)mp, len);
1558 cJSON *reply = cJSON_CreateArray();
1560 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1561 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1567 vac_read(&p, &l, 5); // XXX: Fix timeout
1569 /* Message can be one of [_details, control_ping_reply
1570 * or unrelated event]
1572 u16 msg_id = ntohs(*((u16 *)p));
1573 if (msg_id == reply_msg_id) {{
1574 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1575 vl_api_{r}_t_endian(rmp);
1576 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1580 if (msg_id == details_msg_id) {{
1581 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
1582 vl_api_{d}_t_endian(rmp);
1583 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1592 if s.stream_message:
1593 write(gets_details_reply_template
1594 .format(n=s.caller, r=s.reply, N=s.caller.upper(),
1595 R=s.reply.upper(), d=s.stream_message,
1596 D=s.stream_message.upper()))
1598 write(dump_details_template.format(n=s.caller, r=s.reply,
1602 write(req_reply_template.format(n=s.caller, r=s.reply,
1607 def generate_c_test2_boilerplate(services, defines, module, stream):
1608 '''Generate code for VAT2 plugin.'''
1609 write = stream.write
1611 define_hash = {d.name: d for d in defines}
1615 #include <vlibapi/api.h>
1616 #include <vlibmemory/api.h>
1617 #include <vppinfra/error.h>
1618 #include <vnet/ip/ip_format_fns.h>
1619 #include <vnet/ethernet/ethernet_format_fns.h>
1621 #define vl_typedefs /* define message structures */
1622 #include <vpp/api/vpe_all_api_h.h>
1625 #include "{module}.api_enum.h"
1626 #include "{module}.api_types.h"
1628 #define vl_endianfun /* define message structures */
1629 #include "{module}.api.h"
1632 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1634 #include "{module}.api.h"
1637 #include "{module}.api_tojson.h"
1638 #include "{module}.api_fromjson.h"
1639 #include <vpp-api/client/vppapiclient.h>
1641 #include <vat2/vat2_helpers.h>
1645 write(hdr.format(module=module))
1648 if s.reply not in define_hash:
1650 c_test_api_service(s, s.stream, stream)
1652 write('void vat2_register_function(char *, cJSON * (*)(cJSON *));\n')
1653 # write('__attribute__((constructor))')
1654 write('clib_error_t *\n')
1655 write('vat2_register_plugin (void) {\n')
1657 write(' vat2_register_function("{n}", api_{n});\n'
1658 .format(n=s.caller))
1659 write(' return 0;\n')
1664 # Plugin entry point
1666 def run(args, apifilename, s):
1667 '''Main plugin entry point.'''
1670 if not args.outputdir:
1671 sys.stderr.write('Missing --outputdir argument')
1674 basename = os.path.basename(apifilename)
1675 filename, _ = os.path.splitext(basename)
1676 modulename = filename.replace('.', '_')
1677 filename_enum = os.path.join(args.outputdir + '/' + basename + '_enum.h')
1678 filename_types = os.path.join(args.outputdir + '/' + basename + '_types.h')
1679 filename_c = os.path.join(args.outputdir + '/' + basename + '.c')
1680 filename_c_test = os.path.join(args.outputdir + '/' + basename + '_test.c')
1681 filename_c_test2 = (os.path.join(args.outputdir + '/' + basename +
1683 filename_c_tojson = (os.path.join(args.outputdir +
1684 '/' + basename + '_tojson.h'))
1685 filename_c_fromjson = (os.path.join(args.outputdir + '/' +
1686 basename + '_fromjson.h'))
1688 # Generate separate types file
1690 generate_include_types(s, modulename, st)
1691 with open(filename_types, 'w') as fd:
1693 shutil.copyfileobj(st, fd)
1696 # Generate separate enum file
1698 st.write('#ifndef included_{}_api_enum_h\n'.format(modulename))
1699 st.write('#define included_{}_api_enum_h\n'.format(modulename))
1700 generate_include_enum(s, modulename, st)
1701 generate_include_counters(s['Counters'], st)
1702 st.write('#endif\n')
1703 with open(filename_enum, 'w') as fd:
1705 shutil.copyfileobj(st, fd)
1708 # Generate separate C file
1710 generate_c_boilerplate(s['Service'], s['Define'], s['Counters'],
1711 s['file_crc'], modulename, st)
1712 with open(filename_c, 'w') as fd:
1714 shutil.copyfileobj(st, fd)
1717 # Generate separate C test file
1719 plugin = bool('plugin' in apifilename)
1720 generate_c_test_boilerplate(s['Service'], s['Define'],
1722 modulename, plugin, st)
1723 with open(filename_c_test, 'w') as fd:
1725 shutil.copyfileobj(st, fd)
1728 # Fully autogenerated VATv2 C test file
1730 generate_c_test2_boilerplate(s['Service'], s['Define'],
1732 with open(filename_c_test2, 'w') as fd:
1734 shutil.copyfileobj(st, fd)
1737 # Generate separate JSON file
1739 generate_tojson(s, modulename, st)
1740 with open(filename_c_tojson, 'w') as fd:
1742 shutil.copyfileobj(st, fd)
1745 generate_fromjson(s, modulename, st)
1746 with open(filename_c_fromjson, 'w') as fd:
1748 shutil.copyfileobj(st, fd)
1751 output = TOP_BOILERPLATE.format(datestring=DATESTRING,
1752 input_filename=basename)
1753 output += generate_imports(s['Import'])
1754 output += msg_ids(s)
1755 output += msg_names(s)
1756 output += msg_name_crc_list(s, filename)
1757 output += typedefs(modulename)
1758 printfun_types(s['types'], stream, modulename)
1759 printfun(s['Define'], stream, modulename)
1760 output += stream.getvalue()
1762 output += endianfun(s['types'] + s['Define'], modulename)
1763 output += version_tuple(s, basename)
1764 output += BOTTOM_BOILERPLATE.format(input_filename=basename,
1765 file_crc=s['file_crc'])