1 # 2 # QAPI types generator 3 # 4 # Copyright IBM, Corp. 2011 5 # 6 # Authors: 7 # Anthony Liguori <aliguori (at] us.ibm.com> 8 # 9 # This work is licensed under the terms of the GNU GPLv2. 10 # See the COPYING.LIB file in the top-level directory. 11 12 from ordereddict import OrderedDict 13 from qapi import * 14 import sys 15 import os 16 import getopt 17 import errno 18 19 def generate_fwd_struct(name, members, builtin_type=False): 20 if builtin_type: 21 return mcgen(''' 22 23 typedef struct %(name)sList 24 { 25 union { 26 %(type)s value; 27 uint64_t padding; 28 }; 29 struct %(name)sList *next; 30 } %(name)sList; 31 ''', 32 type=c_type(name), 33 name=name) 34 35 return mcgen(''' 36 37 typedef struct %(name)s %(name)s; 38 39 typedef struct %(name)sList 40 { 41 union { 42 %(name)s *value; 43 uint64_t padding; 44 }; 45 struct %(name)sList *next; 46 } %(name)sList; 47 ''', 48 name=name) 49 50 def generate_fwd_enum_struct(name, members): 51 return mcgen(''' 52 typedef struct %(name)sList 53 { 54 union { 55 %(name)s value; 56 uint64_t padding; 57 }; 58 struct %(name)sList *next; 59 } %(name)sList; 60 ''', 61 name=name) 62 63 def generate_struct_fields(members): 64 ret = '' 65 66 for argname, argentry, optional, structured in parse_args(members): 67 if optional: 68 ret += mcgen(''' 69 bool has_%(c_name)s; 70 ''', 71 c_name=c_var(argname)) 72 if structured: 73 push_indent() 74 ret += generate_struct({ "field": argname, "data": argentry}) 75 pop_indent() 76 else: 77 ret += mcgen(''' 78 %(c_type)s %(c_name)s; 79 ''', 80 c_type=c_type(argentry), c_name=c_var(argname)) 81 82 return ret 83 84 def generate_struct(expr): 85 86 structname = expr.get('type', "") 87 fieldname = expr.get('field', "") 88 members = expr['data'] 89 base = expr.get('base') 90 91 ret = mcgen(''' 92 struct %(name)s 93 { 94 ''', 95 name=structname) 96 97 if base: 98 ret += generate_struct_fields({'base': base}) 99 100 ret += generate_struct_fields(members) 101 102 if len(fieldname): 103 fieldname = " " + fieldname 104 ret += mcgen(''' 105 }%(field)s; 106 ''', 107 field=fieldname) 108 109 return ret 110 111 def generate_enum_lookup(name, values): 112 ret = mcgen(''' 113 const char *%(name)s_lookup[] = { 114 ''', 115 name=name) 116 i = 0 117 for value in values: 118 ret += mcgen(''' 119 "%(value)s", 120 ''', 121 value=value) 122 123 ret += mcgen(''' 124 NULL, 125 }; 126 127 ''') 128 return ret 129 130 def generate_enum_name(name): 131 if name.isupper(): 132 return c_fun(name, False) 133 new_name = '' 134 for c in c_fun(name, False): 135 if c.isupper(): 136 new_name += '_' 137 new_name += c 138 return new_name.lstrip('_').upper() 139 140 def generate_enum(name, values): 141 lookup_decl = mcgen(''' 142 extern const char *%(name)s_lookup[]; 143 ''', 144 name=name) 145 146 enum_decl = mcgen(''' 147 typedef enum %(name)s 148 { 149 ''', 150 name=name) 151 152 # append automatically generated _MAX value 153 enum_values = values + [ 'MAX' ] 154 155 i = 0 156 for value in enum_values: 157 enum_decl += mcgen(''' 158 %(abbrev)s_%(value)s = %(i)d, 159 ''', 160 abbrev=de_camel_case(name).upper(), 161 value=generate_enum_name(value), 162 i=i) 163 i += 1 164 165 enum_decl += mcgen(''' 166 } %(name)s; 167 ''', 168 name=name) 169 170 return lookup_decl + enum_decl 171 172 def generate_anon_union_qtypes(expr): 173 174 name = expr['union'] 175 members = expr['data'] 176 177 ret = mcgen(''' 178 const int %(name)s_qtypes[QTYPE_MAX] = { 179 ''', 180 name=name) 181 182 for key in members: 183 qapi_type = members[key] 184 if builtin_type_qtypes.has_key(qapi_type): 185 qtype = builtin_type_qtypes[qapi_type] 186 elif find_struct(qapi_type): 187 qtype = "QTYPE_QDICT" 188 elif find_union(qapi_type): 189 qtype = "QTYPE_QDICT" 190 else: 191 assert False, "Invalid anonymous union member" 192 193 ret += mcgen(''' 194 [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, 195 ''', 196 qtype = qtype, 197 abbrev = de_camel_case(name).upper(), 198 enum = c_fun(de_camel_case(key),False).upper()) 199 200 ret += mcgen(''' 201 }; 202 ''') 203 return ret 204 205 206 def generate_union(expr): 207 208 name = expr['union'] 209 typeinfo = expr['data'] 210 211 base = expr.get('base') 212 discriminator = expr.get('discriminator') 213 214 ret = mcgen(''' 215 struct %(name)s 216 { 217 %(name)sKind kind; 218 union { 219 void *data; 220 ''', 221 name=name) 222 223 for key in typeinfo: 224 ret += mcgen(''' 225 %(c_type)s %(c_name)s; 226 ''', 227 c_type=c_type(typeinfo[key]), 228 c_name=c_fun(key)) 229 230 ret += mcgen(''' 231 }; 232 ''') 233 234 if base: 235 base_fields = find_struct(base)['data'] 236 if discriminator: 237 base_fields = base_fields.copy() 238 del base_fields[discriminator] 239 ret += generate_struct_fields(base_fields) 240 else: 241 assert not discriminator 242 243 ret += mcgen(''' 244 }; 245 ''') 246 if discriminator == {}: 247 ret += mcgen(''' 248 extern const int %(name)s_qtypes[]; 249 ''', 250 name=name) 251 252 253 return ret 254 255 def generate_type_cleanup_decl(name): 256 ret = mcgen(''' 257 void qapi_free_%(type)s(%(c_type)s obj); 258 ''', 259 c_type=c_type(name),type=name) 260 return ret 261 262 def generate_type_cleanup(name): 263 ret = mcgen(''' 264 265 void qapi_free_%(type)s(%(c_type)s obj) 266 { 267 QapiDeallocVisitor *md; 268 Visitor *v; 269 270 if (!obj) { 271 return; 272 } 273 274 md = qapi_dealloc_visitor_new(); 275 v = qapi_dealloc_get_visitor(md); 276 visit_type_%(type)s(v, &obj, NULL, NULL); 277 qapi_dealloc_visitor_cleanup(md); 278 } 279 ''', 280 c_type=c_type(name),type=name) 281 return ret 282 283 284 try: 285 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", 286 ["source", "header", "builtins", 287 "prefix=", "output-dir="]) 288 except getopt.GetoptError, err: 289 print str(err) 290 sys.exit(1) 291 292 output_dir = "" 293 prefix = "" 294 c_file = 'qapi-types.c' 295 h_file = 'qapi-types.h' 296 297 do_c = False 298 do_h = False 299 do_builtins = False 300 301 for o, a in opts: 302 if o in ("-p", "--prefix"): 303 prefix = a 304 elif o in ("-o", "--output-dir"): 305 output_dir = a + "/" 306 elif o in ("-c", "--source"): 307 do_c = True 308 elif o in ("-h", "--header"): 309 do_h = True 310 elif o in ("-b", "--builtins"): 311 do_builtins = True 312 313 if not do_c and not do_h: 314 do_c = True 315 do_h = True 316 317 c_file = output_dir + prefix + c_file 318 h_file = output_dir + prefix + h_file 319 320 try: 321 os.makedirs(output_dir) 322 except os.error, e: 323 if e.errno != errno.EEXIST: 324 raise 325 326 def maybe_open(really, name, opt): 327 if really: 328 return open(name, opt) 329 else: 330 import StringIO 331 return StringIO.StringIO() 332 333 fdef = maybe_open(do_c, c_file, 'w') 334 fdecl = maybe_open(do_h, h_file, 'w') 335 336 fdef.write(mcgen(''' 337 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */ 338 339 /* 340 * deallocation functions for schema-defined QAPI types 341 * 342 * Copyright IBM, Corp. 2011 343 * 344 * Authors: 345 * Anthony Liguori <aliguori (at] us.ibm.com> 346 * Michael Roth <mdroth (at] linux.vnet.ibm.com> 347 * 348 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 349 * See the COPYING.LIB file in the top-level directory. 350 * 351 */ 352 353 #include "qapi/dealloc-visitor.h" 354 #include "%(prefix)sqapi-types.h" 355 #include "%(prefix)sqapi-visit.h" 356 357 ''', prefix=prefix)) 358 359 fdecl.write(mcgen(''' 360 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */ 361 362 /* 363 * schema-defined QAPI types 364 * 365 * Copyright IBM, Corp. 2011 366 * 367 * Authors: 368 * Anthony Liguori <aliguori (at] us.ibm.com> 369 * 370 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 371 * See the COPYING.LIB file in the top-level directory. 372 * 373 */ 374 375 #ifndef %(guard)s 376 #define %(guard)s 377 378 #include <stdbool.h> 379 #include <stdint.h> 380 381 ''', 382 guard=guardname(h_file))) 383 384 exprs = parse_schema(sys.stdin) 385 exprs = filter(lambda expr: not expr.has_key('gen'), exprs) 386 387 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL")) 388 for typename in builtin_types: 389 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True)) 390 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL")) 391 392 for expr in exprs: 393 ret = "\n" 394 if expr.has_key('type'): 395 ret += generate_fwd_struct(expr['type'], expr['data']) 396 elif expr.has_key('enum'): 397 ret += generate_enum(expr['enum'], expr['data']) + "\n" 398 ret += generate_fwd_enum_struct(expr['enum'], expr['data']) 399 fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) 400 elif expr.has_key('union'): 401 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" 402 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) 403 fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) 404 if expr.get('discriminator') == {}: 405 fdef.write(generate_anon_union_qtypes(expr)) 406 else: 407 continue 408 fdecl.write(ret) 409 410 # to avoid header dependency hell, we always generate declarations 411 # for built-in types in our header files and simply guard them 412 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL")) 413 for typename in builtin_types: 414 fdecl.write(generate_type_cleanup_decl(typename + "List")) 415 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL")) 416 417 # ...this doesn't work for cases where we link in multiple objects that 418 # have the functions defined, so we use -b option to provide control 419 # over these cases 420 if do_builtins: 421 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF")) 422 for typename in builtin_types: 423 fdef.write(generate_type_cleanup(typename + "List")) 424 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF")) 425 426 for expr in exprs: 427 ret = "\n" 428 if expr.has_key('type'): 429 ret += generate_struct(expr) + "\n" 430 ret += generate_type_cleanup_decl(expr['type'] + "List") 431 fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n") 432 ret += generate_type_cleanup_decl(expr['type']) 433 fdef.write(generate_type_cleanup(expr['type']) + "\n") 434 elif expr.has_key('union'): 435 ret += generate_union(expr) 436 ret += generate_type_cleanup_decl(expr['union'] + "List") 437 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n") 438 ret += generate_type_cleanup_decl(expr['union']) 439 fdef.write(generate_type_cleanup(expr['union']) + "\n") 440 elif expr.has_key('enum'): 441 ret += generate_type_cleanup_decl(expr['enum'] + "List") 442 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n") 443 else: 444 continue 445 fdecl.write(ret) 446 447 fdecl.write(''' 448 #endif 449 ''') 450 451 fdecl.flush() 452 fdecl.close() 453 454 fdef.flush() 455 fdef.close() 456