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