1# 2# QAPI visitor generator 3# 4# Copyright IBM, Corp. 2011 5# Copyright (C) 2014 Red Hat, Inc. 6# 7# Authors: 8# Anthony Liguori <aliguori@us.ibm.com> 9# Michael Roth <mdroth@linux.vnet.ibm.com> 10# Markus Armbruster <armbru@redhat.com> 11# 12# This work is licensed under the terms of the GNU GPL, version 2. 13# See the COPYING file in the top-level directory. 14 15from ordereddict import OrderedDict 16from qapi import * 17import re 18import sys 19import os 20import getopt 21import errno 22 23implicit_structs = [] 24 25def generate_visit_implicit_struct(type): 26 global implicit_structs 27 if type in implicit_structs: 28 return '' 29 implicit_structs.append(type) 30 return mcgen(''' 31 32static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) 33{ 34 Error *err = NULL; 35 36 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); 37 if (!err) { 38 visit_type_%(c_type)s_fields(m, obj, errp); 39 visit_end_implicit_struct(m, &err); 40 } 41 error_propagate(errp, err); 42} 43''', 44 c_type=type_name(type)) 45 46def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None): 47 substructs = [] 48 ret = '' 49 if not fn_prefix: 50 full_name = name 51 else: 52 full_name = "%s_%s" % (name, fn_prefix) 53 54 for argname, argentry, optional, structured in parse_args(members): 55 if structured: 56 if not fn_prefix: 57 nested_fn_prefix = argname 58 else: 59 nested_fn_prefix = "%s_%s" % (fn_prefix, argname) 60 61 nested_field_prefix = "%s%s." % (field_prefix, argname) 62 ret += generate_visit_struct_fields(name, nested_field_prefix, 63 nested_fn_prefix, argentry) 64 ret += mcgen(''' 65 66static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp) 67{ 68''', 69 name=name, full_name=full_name, c_name=c_var(argname)) 70 ret += generate_visit_struct_body(full_name, argname, argentry) 71 ret += mcgen(''' 72} 73''') 74 75 if base: 76 ret += generate_visit_implicit_struct(base) 77 78 ret += mcgen(''' 79 80static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s **obj, Error **errp) 81{ 82 Error *err = NULL; 83''', 84 name=name, full_name=full_name) 85 push_indent() 86 87 if base: 88 ret += mcgen(''' 89visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); 90if (err) { 91 goto out; 92} 93''', 94 c_prefix=c_var(field_prefix), 95 type=type_name(base), c_name=c_var('base')) 96 97 for argname, argentry, optional, structured in parse_args(members): 98 if optional: 99 ret += mcgen(''' 100visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); 101if (!err && (*obj)->%(prefix)shas_%(c_name)s) { 102''', 103 c_prefix=c_var(field_prefix), prefix=field_prefix, 104 c_name=c_var(argname), name=argname) 105 push_indent() 106 107 if structured: 108 ret += mcgen(''' 109visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err); 110''', 111 full_name=full_name, c_name=c_var(argname)) 112 else: 113 ret += mcgen(''' 114visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); 115''', 116 c_prefix=c_var(field_prefix), prefix=field_prefix, 117 type=type_name(argentry), c_name=c_var(argname), 118 name=argname) 119 120 if optional: 121 pop_indent() 122 ret += mcgen(''' 123} 124''') 125 ret += mcgen(''' 126if (err) { 127 goto out; 128} 129''') 130 131 pop_indent() 132 if re.search('^ *goto out\\;', ret, re.MULTILINE): 133 ret += mcgen(''' 134 135out: 136''') 137 ret += mcgen(''' 138 error_propagate(errp, err); 139} 140''') 141 return ret 142 143 144def generate_visit_struct_body(field_prefix, name, members): 145 ret = mcgen(''' 146 Error *err = NULL; 147 148''') 149 150 if not field_prefix: 151 full_name = name 152 else: 153 full_name = "%s_%s" % (field_prefix, name) 154 155 if len(field_prefix): 156 ret += mcgen(''' 157 visit_start_struct(m, NULL, "", "%(name)s", 0, &err); 158''', 159 name=name) 160 else: 161 ret += mcgen(''' 162 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); 163''', 164 name=name) 165 166 ret += mcgen(''' 167 if (!err) { 168 if (*obj) { 169 visit_type_%(name)s_fields(m, obj, errp); 170 } 171 visit_end_struct(m, &err); 172 } 173 error_propagate(errp, err); 174''', 175 name=full_name) 176 177 return ret 178 179def generate_visit_struct(expr): 180 181 name = expr['type'] 182 members = expr['data'] 183 base = expr.get('base') 184 185 ret = generate_visit_struct_fields(name, "", "", members, base) 186 187 ret += mcgen(''' 188 189void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) 190{ 191''', 192 name=name) 193 194 ret += generate_visit_struct_body("", name, members) 195 196 ret += mcgen(''' 197} 198''') 199 return ret 200 201def generate_visit_list(name, members): 202 return mcgen(''' 203 204void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp) 205{ 206 Error *err = NULL; 207 GenericList *i, **prev; 208 209 visit_start_list(m, name, &err); 210 if (err) { 211 goto out; 212 } 213 214 for (prev = (GenericList **)obj; 215 !err && (i = visit_next_list(m, prev, &err)) != NULL; 216 prev = &i) { 217 %(name)sList *native_i = (%(name)sList *)i; 218 visit_type_%(name)s(m, &native_i->value, NULL, &err); 219 } 220 221 error_propagate(errp, err); 222 err = NULL; 223 visit_end_list(m, &err); 224out: 225 error_propagate(errp, err); 226} 227''', 228 name=name) 229 230def generate_visit_enum(name, members): 231 return mcgen(''' 232 233void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp) 234{ 235 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); 236} 237''', 238 name=name) 239 240def generate_visit_anon_union(name, members): 241 ret = mcgen(''' 242 243void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) 244{ 245 Error *err = NULL; 246 247 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); 248 if (err) { 249 goto out; 250 } 251 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); 252 if (err) { 253 goto out_end; 254 } 255 switch ((*obj)->kind) { 256''', 257 name=name) 258 259 # For anon union, always use the default enum type automatically generated 260 # as "'%sKind' % (name)" 261 disc_type = '%sKind' % (name) 262 263 for key in members: 264 assert (members[key] in builtin_types 265 or find_struct(members[key]) 266 or find_union(members[key]) 267 or find_enum(members[key])), "Invalid anonymous union member" 268 269 enum_full_value = generate_enum_full_value(disc_type, key) 270 ret += mcgen(''' 271 case %(enum_full_value)s: 272 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); 273 break; 274''', 275 enum_full_value = enum_full_value, 276 c_type = type_name(members[key]), 277 c_name = c_fun(key)) 278 279 ret += mcgen(''' 280 default: 281 abort(); 282 } 283out_end: 284 error_propagate(errp, err); 285 err = NULL; 286 visit_end_implicit_struct(m, &err); 287out: 288 error_propagate(errp, err); 289} 290''') 291 292 return ret 293 294 295def generate_visit_union(expr): 296 297 name = expr['union'] 298 members = expr['data'] 299 300 base = expr.get('base') 301 discriminator = expr.get('discriminator') 302 303 if discriminator == {}: 304 assert not base 305 return generate_visit_anon_union(name, members) 306 307 enum_define = discriminator_find_enum_define(expr) 308 if enum_define: 309 # Use the enum type as discriminator 310 ret = "" 311 disc_type = enum_define['enum_name'] 312 else: 313 # There will always be a discriminator in the C switch code, by default it 314 # is an enum type generated silently as "'%sKind' % (name)" 315 ret = generate_visit_enum('%sKind' % name, members.keys()) 316 disc_type = '%sKind' % (name) 317 318 if base: 319 base_fields = find_struct(base)['data'] 320 if discriminator: 321 base_fields = base_fields.copy() 322 del base_fields[discriminator] 323 ret += generate_visit_struct_fields(name, "", "", base_fields) 324 325 if discriminator: 326 for key in members: 327 ret += generate_visit_implicit_struct(members[key]) 328 329 ret += mcgen(''' 330 331void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) 332{ 333 Error *err = NULL; 334 335 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); 336 if (err) { 337 goto out; 338 } 339 if (*obj) { 340''', 341 name=name) 342 343 if base: 344 ret += mcgen(''' 345 visit_type_%(name)s_fields(m, obj, &err); 346 if (err) { 347 goto out_obj; 348 } 349''', 350 name=name) 351 352 if not discriminator: 353 disc_key = "type" 354 else: 355 disc_key = discriminator 356 ret += mcgen(''' 357 visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); 358 if (err) { 359 goto out_obj; 360 } 361 if (!visit_start_union(m, !!(*obj)->data, &err) || err) { 362 goto out_obj; 363 } 364 switch ((*obj)->kind) { 365''', 366 disc_type = disc_type, 367 disc_key = disc_key) 368 369 for key in members: 370 if not discriminator: 371 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' 372 else: 373 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' 374 375 enum_full_value = generate_enum_full_value(disc_type, key) 376 ret += mcgen(''' 377 case %(enum_full_value)s: 378 ''' + fmt + ''' 379 break; 380''', 381 enum_full_value = enum_full_value, 382 c_type=type_name(members[key]), 383 c_name=c_fun(key)) 384 385 ret += mcgen(''' 386 default: 387 abort(); 388 } 389out_obj: 390 error_propagate(errp, err); 391 err = NULL; 392 visit_end_union(m, !!(*obj)->data, &err); 393 error_propagate(errp, err); 394 err = NULL; 395 } 396 visit_end_struct(m, &err); 397out: 398 error_propagate(errp, err); 399} 400''') 401 402 return ret 403 404def generate_declaration(name, members, genlist=True, builtin_type=False): 405 ret = "" 406 if not builtin_type: 407 ret += mcgen(''' 408 409void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp); 410''', 411 name=name) 412 413 if genlist: 414 ret += mcgen(''' 415void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); 416''', 417 name=name) 418 419 return ret 420 421def generate_enum_declaration(name, members, genlist=True): 422 ret = "" 423 if genlist: 424 ret += mcgen(''' 425void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); 426''', 427 name=name) 428 429 return ret 430 431def generate_decl_enum(name, members, genlist=True): 432 return mcgen(''' 433 434void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp); 435''', 436 name=name) 437 438try: 439 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", 440 ["source", "header", "builtins", "prefix=", 441 "input-file=", "output-dir="]) 442except getopt.GetoptError, err: 443 print str(err) 444 sys.exit(1) 445 446input_file = "" 447output_dir = "" 448prefix = "" 449c_file = 'qapi-visit.c' 450h_file = 'qapi-visit.h' 451 452do_c = False 453do_h = False 454do_builtins = False 455 456for o, a in opts: 457 if o in ("-p", "--prefix"): 458 prefix = a 459 elif o in ("-i", "--input-file"): 460 input_file = a 461 elif o in ("-o", "--output-dir"): 462 output_dir = a + "/" 463 elif o in ("-c", "--source"): 464 do_c = True 465 elif o in ("-h", "--header"): 466 do_h = True 467 elif o in ("-b", "--builtins"): 468 do_builtins = True 469 470if not do_c and not do_h: 471 do_c = True 472 do_h = True 473 474c_file = output_dir + prefix + c_file 475h_file = output_dir + prefix + h_file 476 477try: 478 os.makedirs(output_dir) 479except os.error, e: 480 if e.errno != errno.EEXIST: 481 raise 482 483def maybe_open(really, name, opt): 484 if really: 485 return open(name, opt) 486 else: 487 import StringIO 488 return StringIO.StringIO() 489 490fdef = maybe_open(do_c, c_file, 'w') 491fdecl = maybe_open(do_h, h_file, 'w') 492 493fdef.write(mcgen(''' 494/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ 495 496/* 497 * schema-defined QAPI visitor functions 498 * 499 * Copyright IBM, Corp. 2011 500 * 501 * Authors: 502 * Anthony Liguori <aliguori@us.ibm.com> 503 * 504 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 505 * See the COPYING.LIB file in the top-level directory. 506 * 507 */ 508 509#include "qemu-common.h" 510#include "%(header)s" 511''', 512 header=basename(h_file))) 513 514fdecl.write(mcgen(''' 515/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ 516 517/* 518 * schema-defined QAPI visitor functions 519 * 520 * Copyright IBM, Corp. 2011 521 * 522 * Authors: 523 * Anthony Liguori <aliguori@us.ibm.com> 524 * 525 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 526 * See the COPYING.LIB file in the top-level directory. 527 * 528 */ 529 530#ifndef %(guard)s 531#define %(guard)s 532 533#include "qapi/visitor.h" 534#include "%(prefix)sqapi-types.h" 535 536''', 537 prefix=prefix, guard=guardname(h_file))) 538 539exprs = parse_schema(input_file) 540 541# to avoid header dependency hell, we always generate declarations 542# for built-in types in our header files and simply guard them 543fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) 544for typename in builtin_types: 545 fdecl.write(generate_declaration(typename, None, genlist=True, 546 builtin_type=True)) 547fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) 548 549# ...this doesn't work for cases where we link in multiple objects that 550# have the functions defined, so we use -b option to provide control 551# over these cases 552if do_builtins: 553 for typename in builtin_types: 554 fdef.write(generate_visit_list(typename, None)) 555 556for expr in exprs: 557 if expr.has_key('type'): 558 ret = generate_visit_struct(expr) 559 ret += generate_visit_list(expr['type'], expr['data']) 560 fdef.write(ret) 561 562 ret = generate_declaration(expr['type'], expr['data']) 563 fdecl.write(ret) 564 elif expr.has_key('union'): 565 ret = generate_visit_union(expr) 566 ret += generate_visit_list(expr['union'], expr['data']) 567 fdef.write(ret) 568 569 enum_define = discriminator_find_enum_define(expr) 570 ret = "" 571 if not enum_define: 572 ret = generate_decl_enum('%sKind' % expr['union'], 573 expr['data'].keys()) 574 ret += generate_declaration(expr['union'], expr['data']) 575 fdecl.write(ret) 576 elif expr.has_key('enum'): 577 ret = generate_visit_list(expr['enum'], expr['data']) 578 ret += generate_visit_enum(expr['enum'], expr['data']) 579 fdef.write(ret) 580 581 ret = generate_decl_enum(expr['enum'], expr['data']) 582 ret += generate_enum_declaration(expr['enum'], expr['data']) 583 fdecl.write(ret) 584 585fdecl.write(''' 586#endif 587''') 588 589fdecl.flush() 590fdecl.close() 591 592fdef.flush() 593fdef.close() 594