qapi-visit.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. #
  2. # QAPI visitor generator
  3. #
  4. # Copyright IBM, Corp. 2011
  5. # Copyright (C) 2014-2015 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. from ordereddict import OrderedDict
  15. from qapi import *
  16. import re
  17. import sys
  18. import os
  19. import getopt
  20. import errno
  21. implicit_structs = []
  22. def generate_visit_implicit_struct(type):
  23. global implicit_structs
  24. if type in implicit_structs:
  25. return ''
  26. implicit_structs.append(type)
  27. return mcgen('''
  28. static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
  29. {
  30. Error *err = NULL;
  31. visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
  32. if (!err) {
  33. visit_type_%(c_type)s_fields(m, obj, errp);
  34. visit_end_implicit_struct(m, &err);
  35. }
  36. error_propagate(errp, err);
  37. }
  38. ''',
  39. c_type=type_name(type))
  40. def generate_visit_struct_fields(name, members, base = None):
  41. substructs = []
  42. ret = ''
  43. if base:
  44. ret += generate_visit_implicit_struct(base)
  45. ret += mcgen('''
  46. static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
  47. {
  48. Error *err = NULL;
  49. ''',
  50. name=c_name(name))
  51. push_indent()
  52. if base:
  53. ret += mcgen('''
  54. visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
  55. if (err) {
  56. goto out;
  57. }
  58. ''',
  59. type=type_name(base), c_name=c_name('base'))
  60. for argname, argentry, optional in parse_args(members):
  61. if optional:
  62. ret += mcgen('''
  63. visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
  64. if (!err && (*obj)->has_%(c_name)s) {
  65. ''',
  66. c_name=c_name(argname), name=argname)
  67. push_indent()
  68. ret += mcgen('''
  69. visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
  70. ''',
  71. type=type_name(argentry), c_name=c_name(argname),
  72. name=argname)
  73. if optional:
  74. pop_indent()
  75. ret += mcgen('''
  76. }
  77. ''')
  78. ret += mcgen('''
  79. if (err) {
  80. goto out;
  81. }
  82. ''')
  83. pop_indent()
  84. if re.search('^ *goto out\\;', ret, re.MULTILINE):
  85. ret += mcgen('''
  86. out:
  87. ''')
  88. ret += mcgen('''
  89. error_propagate(errp, err);
  90. }
  91. ''')
  92. return ret
  93. def generate_visit_struct_body(name, members):
  94. ret = mcgen('''
  95. Error *err = NULL;
  96. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
  97. if (!err) {
  98. if (*obj) {
  99. visit_type_%(c_name)s_fields(m, obj, errp);
  100. }
  101. visit_end_struct(m, &err);
  102. }
  103. error_propagate(errp, err);
  104. ''',
  105. name=name, c_name=c_name(name))
  106. return ret
  107. def generate_visit_struct(expr):
  108. name = expr['struct']
  109. members = expr['data']
  110. base = expr.get('base')
  111. ret = generate_visit_struct_fields(name, members, base)
  112. ret += mcgen('''
  113. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  114. {
  115. ''',
  116. name=c_name(name))
  117. ret += generate_visit_struct_body(name, members)
  118. ret += mcgen('''
  119. }
  120. ''')
  121. return ret
  122. def generate_visit_list(name, members):
  123. return mcgen('''
  124. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
  125. {
  126. Error *err = NULL;
  127. GenericList *i, **prev;
  128. visit_start_list(m, name, &err);
  129. if (err) {
  130. goto out;
  131. }
  132. for (prev = (GenericList **)obj;
  133. !err && (i = visit_next_list(m, prev, &err)) != NULL;
  134. prev = &i) {
  135. %(name)sList *native_i = (%(name)sList *)i;
  136. visit_type_%(name)s(m, &native_i->value, NULL, &err);
  137. }
  138. error_propagate(errp, err);
  139. err = NULL;
  140. visit_end_list(m, &err);
  141. out:
  142. error_propagate(errp, err);
  143. }
  144. ''',
  145. name=type_name(name))
  146. def generate_visit_enum(name, members):
  147. return mcgen('''
  148. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
  149. {
  150. visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
  151. }
  152. ''',
  153. name=c_name(name))
  154. def generate_visit_alternate(name, members):
  155. ret = mcgen('''
  156. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  157. {
  158. Error *err = NULL;
  159. visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
  160. if (err) {
  161. goto out;
  162. }
  163. visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
  164. if (err) {
  165. goto out_end;
  166. }
  167. switch ((*obj)->kind) {
  168. ''',
  169. name=c_name(name))
  170. # For alternate, always use the default enum type automatically generated
  171. # as name + 'Kind'
  172. disc_type = c_name(name) + 'Kind'
  173. for key in members:
  174. assert (members[key] in builtin_types.keys()
  175. or find_struct(members[key])
  176. or find_union(members[key])
  177. or find_enum(members[key])), "Invalid alternate member"
  178. enum_full_value = c_enum_const(disc_type, key)
  179. ret += mcgen('''
  180. case %(enum_full_value)s:
  181. visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
  182. break;
  183. ''',
  184. enum_full_value = enum_full_value,
  185. c_type = type_name(members[key]),
  186. c_name = c_name(key))
  187. ret += mcgen('''
  188. default:
  189. abort();
  190. }
  191. out_end:
  192. error_propagate(errp, err);
  193. err = NULL;
  194. visit_end_implicit_struct(m, &err);
  195. out:
  196. error_propagate(errp, err);
  197. }
  198. ''')
  199. return ret
  200. def generate_visit_union(expr):
  201. name = expr['union']
  202. members = expr['data']
  203. base = expr.get('base')
  204. discriminator = expr.get('discriminator')
  205. enum_define = discriminator_find_enum_define(expr)
  206. if enum_define:
  207. # Use the enum type as discriminator
  208. ret = ""
  209. disc_type = c_name(enum_define['enum_name'])
  210. else:
  211. # There will always be a discriminator in the C switch code, by default
  212. # it is an enum type generated silently
  213. ret = generate_visit_enum(name + 'Kind', members.keys())
  214. disc_type = c_name(name) + 'Kind'
  215. if base:
  216. assert discriminator
  217. base_fields = find_struct(base)['data'].copy()
  218. del base_fields[discriminator]
  219. ret += generate_visit_struct_fields(name, base_fields)
  220. if discriminator:
  221. for key in members:
  222. ret += generate_visit_implicit_struct(members[key])
  223. ret += mcgen('''
  224. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  225. {
  226. Error *err = NULL;
  227. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
  228. if (err) {
  229. goto out;
  230. }
  231. if (*obj) {
  232. ''',
  233. name=c_name(name))
  234. if base:
  235. ret += mcgen('''
  236. visit_type_%(name)s_fields(m, obj, &err);
  237. if (err) {
  238. goto out_obj;
  239. }
  240. ''',
  241. name=c_name(name))
  242. if not discriminator:
  243. disc_key = "type"
  244. else:
  245. disc_key = discriminator
  246. ret += mcgen('''
  247. visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
  248. if (err) {
  249. goto out_obj;
  250. }
  251. if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
  252. goto out_obj;
  253. }
  254. switch ((*obj)->kind) {
  255. ''',
  256. disc_type = disc_type,
  257. disc_key = disc_key)
  258. for key in members:
  259. if not discriminator:
  260. fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
  261. else:
  262. fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
  263. enum_full_value = c_enum_const(disc_type, key)
  264. ret += mcgen('''
  265. case %(enum_full_value)s:
  266. ''' + fmt + '''
  267. break;
  268. ''',
  269. enum_full_value = enum_full_value,
  270. c_type=type_name(members[key]),
  271. c_name=c_name(key))
  272. ret += mcgen('''
  273. default:
  274. abort();
  275. }
  276. out_obj:
  277. error_propagate(errp, err);
  278. err = NULL;
  279. visit_end_union(m, !!(*obj)->data, &err);
  280. error_propagate(errp, err);
  281. err = NULL;
  282. }
  283. visit_end_struct(m, &err);
  284. out:
  285. error_propagate(errp, err);
  286. }
  287. ''')
  288. return ret
  289. def generate_declaration(name, members, builtin_type=False):
  290. ret = ""
  291. if not builtin_type:
  292. name = c_name(name)
  293. ret += mcgen('''
  294. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
  295. ''',
  296. name=name)
  297. ret += mcgen('''
  298. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  299. ''',
  300. name=name)
  301. return ret
  302. def generate_enum_declaration(name, members):
  303. ret = mcgen('''
  304. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  305. ''',
  306. name=c_name(name))
  307. return ret
  308. def generate_decl_enum(name, members):
  309. return mcgen('''
  310. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
  311. ''',
  312. name=c_name(name))
  313. try:
  314. opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
  315. ["source", "header", "builtins", "prefix=",
  316. "input-file=", "output-dir="])
  317. except getopt.GetoptError, err:
  318. print str(err)
  319. sys.exit(1)
  320. input_file = ""
  321. output_dir = ""
  322. prefix = ""
  323. c_file = 'qapi-visit.c'
  324. h_file = 'qapi-visit.h'
  325. do_c = False
  326. do_h = False
  327. do_builtins = False
  328. for o, a in opts:
  329. if o in ("-p", "--prefix"):
  330. prefix = a
  331. elif o in ("-i", "--input-file"):
  332. input_file = a
  333. elif o in ("-o", "--output-dir"):
  334. output_dir = a + "/"
  335. elif o in ("-c", "--source"):
  336. do_c = True
  337. elif o in ("-h", "--header"):
  338. do_h = True
  339. elif o in ("-b", "--builtins"):
  340. do_builtins = True
  341. if not do_c and not do_h:
  342. do_c = True
  343. do_h = True
  344. c_file = output_dir + prefix + c_file
  345. h_file = output_dir + prefix + h_file
  346. try:
  347. os.makedirs(output_dir)
  348. except os.error, e:
  349. if e.errno != errno.EEXIST:
  350. raise
  351. def maybe_open(really, name, opt):
  352. if really:
  353. return open(name, opt)
  354. else:
  355. import StringIO
  356. return StringIO.StringIO()
  357. fdef = maybe_open(do_c, c_file, 'w')
  358. fdecl = maybe_open(do_h, h_file, 'w')
  359. fdef.write(mcgen('''
  360. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  361. /*
  362. * schema-defined QAPI visitor functions
  363. *
  364. * Copyright IBM, Corp. 2011
  365. *
  366. * Authors:
  367. * Anthony Liguori <aliguori@us.ibm.com>
  368. *
  369. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  370. * See the COPYING.LIB file in the top-level directory.
  371. *
  372. */
  373. #include "qemu-common.h"
  374. #include "%(header)s"
  375. ''',
  376. header=basename(h_file)))
  377. fdecl.write(mcgen('''
  378. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  379. /*
  380. * schema-defined QAPI visitor functions
  381. *
  382. * Copyright IBM, Corp. 2011
  383. *
  384. * Authors:
  385. * Anthony Liguori <aliguori@us.ibm.com>
  386. *
  387. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  388. * See the COPYING.LIB file in the top-level directory.
  389. *
  390. */
  391. #ifndef %(guard)s
  392. #define %(guard)s
  393. #include "qapi/visitor.h"
  394. #include "%(prefix)sqapi-types.h"
  395. ''',
  396. prefix=prefix, guard=guardname(h_file)))
  397. exprs = parse_schema(input_file)
  398. # to avoid header dependency hell, we always generate declarations
  399. # for built-in types in our header files and simply guard them
  400. fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  401. for typename in builtin_types.keys():
  402. fdecl.write(generate_declaration(typename, None, builtin_type=True))
  403. fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  404. # ...this doesn't work for cases where we link in multiple objects that
  405. # have the functions defined, so we use -b option to provide control
  406. # over these cases
  407. if do_builtins:
  408. for typename in builtin_types.keys():
  409. fdef.write(generate_visit_list(typename, None))
  410. for expr in exprs:
  411. if expr.has_key('struct'):
  412. ret = generate_visit_struct(expr)
  413. ret += generate_visit_list(expr['struct'], expr['data'])
  414. fdef.write(ret)
  415. ret = generate_declaration(expr['struct'], expr['data'])
  416. fdecl.write(ret)
  417. elif expr.has_key('union'):
  418. ret = generate_visit_union(expr)
  419. ret += generate_visit_list(expr['union'], expr['data'])
  420. fdef.write(ret)
  421. enum_define = discriminator_find_enum_define(expr)
  422. ret = ""
  423. if not enum_define:
  424. ret = generate_decl_enum('%sKind' % expr['union'],
  425. expr['data'].keys())
  426. ret += generate_declaration(expr['union'], expr['data'])
  427. fdecl.write(ret)
  428. elif expr.has_key('alternate'):
  429. ret = generate_visit_alternate(expr['alternate'], expr['data'])
  430. ret += generate_visit_list(expr['alternate'], expr['data'])
  431. fdef.write(ret)
  432. ret = generate_decl_enum('%sKind' % expr['alternate'],
  433. expr['data'].keys())
  434. ret += generate_declaration(expr['alternate'], expr['data'])
  435. fdecl.write(ret)
  436. elif expr.has_key('enum'):
  437. ret = generate_visit_list(expr['enum'], expr['data'])
  438. ret += generate_visit_enum(expr['enum'], expr['data'])
  439. fdef.write(ret)
  440. ret = generate_decl_enum(expr['enum'], expr['data'])
  441. ret += generate_enum_declaration(expr['enum'], expr['data'])
  442. fdecl.write(ret)
  443. fdecl.write('''
  444. #endif
  445. ''')
  446. fdecl.flush()
  447. fdecl.close()
  448. fdef.flush()
  449. fdef.close()