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