1 # 2 # QAPI visitor generator 3 # 4 # Copyright IBM, Corp. 2011 5 # 6 # Authors: 7 # Anthony Liguori <aliguori (at] us.ibm.com> 8 # Michael Roth <mdroth (at] 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 13 from ordereddict import OrderedDict 14 from qapi import * 15 import sys 16 import os 17 import getopt 18 import errno 19 20 def 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 41 static 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(''' 50 visit_start_implicit_struct(m, obj ? (void**) &(*obj)->%(c_name)s : NULL, sizeof(%(type)s), &err); 51 if (!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(''' 64 visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err); 65 if (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(''' 75 visit_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 } 85 visit_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 97 def generate_visit_struct_body(field_prefix, name, members): 98 ret = mcgen(''' 99 if (!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(''' 110 Error **errp = &err; /* from outer scope */ 111 Error *err = NULL; 112 visit_start_struct(m, NULL, "", "%(name)s", 0, &err); 113 ''', 114 name=name) 115 else: 116 ret += mcgen(''' 117 Error *err = NULL; 118 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); 119 ''', 120 name=name) 121 122 ret += mcgen(''' 123 if (!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 142 def 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 152 void 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 166 def generate_visit_list(name, members): 167 return mcgen(''' 168 169 void 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 193 def generate_visit_enum(name, members): 194 return mcgen(''' 195 196 void 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 203 def generate_visit_anon_union(name, members): 204 ret = mcgen(''' 205 206 void 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 246 def 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 269 void 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 351 def generate_declaration(name, members, genlist=True, builtin_type=False): 352 ret = "" 353 if not builtin_type: 354 ret += mcgen(''' 355 356 void 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(''' 362 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); 363 ''', 364 name=name) 365 366 return ret 367 368 def generate_enum_declaration(name, members, genlist=True): 369 ret = "" 370 if genlist: 371 ret += mcgen(''' 372 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); 373 ''', 374 name=name) 375 376 return ret 377 378 def generate_decl_enum(name, members, genlist=True): 379 return mcgen(''' 380 381 void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp); 382 ''', 383 name=name) 384 385 try: 386 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", 387 ["source", "header", "builtins", "prefix=", 388 "output-dir="]) 389 except getopt.GetoptError, err: 390 print str(err) 391 sys.exit(1) 392 393 output_dir = "" 394 prefix = "" 395 c_file = 'qapi-visit.c' 396 h_file = 'qapi-visit.h' 397 398 do_c = False 399 do_h = False 400 do_builtins = False 401 402 for 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 414 if not do_c and not do_h: 415 do_c = True 416 do_h = True 417 418 c_file = output_dir + prefix + c_file 419 h_file = output_dir + prefix + h_file 420 421 try: 422 os.makedirs(output_dir) 423 except os.error, e: 424 if e.errno != errno.EEXIST: 425 raise 426 427 def maybe_open(really, name, opt): 428 if really: 429 return open(name, opt) 430 else: 431 import StringIO 432 return StringIO.StringIO() 433 434 fdef = maybe_open(do_c, c_file, 'w') 435 fdecl = maybe_open(do_h, h_file, 'w') 436 437 fdef.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 (at] 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 458 fdecl.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 (at] 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 483 exprs = 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 487 fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) 488 for typename in builtin_types: 489 fdecl.write(generate_declaration(typename, None, genlist=True, 490 builtin_type=True)) 491 fdecl.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 496 if 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 502 for 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 527 fdecl.write(''' 528 #endif 529 ''') 530 531 fdecl.flush() 532 fdecl.close() 533 534 fdef.flush() 535 fdef.close() 536