2
0

qapi-event.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. #
  2. # QAPI event generator
  3. #
  4. # Copyright (c) 2014 Wenchao Xia
  5. #
  6. # Authors:
  7. # Wenchao Xia <wenchaoqemu@gmail.com>
  8. #
  9. # This work is licensed under the terms of the GNU GPL, version 2.
  10. # See the COPYING file in the top-level directory.
  11. from ordereddict import OrderedDict
  12. from qapi import *
  13. import sys
  14. import os
  15. import getopt
  16. import errno
  17. def _generate_event_api_name(event_name, params):
  18. api_name = "void qapi_event_send_%s(" % c_fun(event_name).lower();
  19. l = len(api_name)
  20. if params:
  21. for argname, argentry, optional, structured in parse_args(params):
  22. if optional:
  23. api_name += "bool has_%s,\n" % c_var(argname)
  24. api_name += "".ljust(l)
  25. if argentry == "str":
  26. api_name += "const "
  27. api_name += "%s %s,\n" % (c_type(argentry), c_var(argname))
  28. api_name += "".ljust(l)
  29. api_name += "Error **errp)"
  30. return api_name;
  31. # Following are the core functions that generate C APIs to emit event.
  32. def generate_event_declaration(api_name):
  33. return mcgen('''
  34. %(api_name)s;
  35. ''',
  36. api_name = api_name)
  37. def generate_event_implement(api_name, event_name, params):
  38. # step 1: declare any variables
  39. ret = mcgen("""
  40. %(api_name)s
  41. {
  42. QDict *qmp;
  43. Error *local_err = NULL;
  44. QMPEventFuncEmit emit;
  45. """,
  46. api_name = api_name)
  47. if params:
  48. ret += mcgen("""
  49. QmpOutputVisitor *qov;
  50. Visitor *v;
  51. QObject *obj;
  52. """)
  53. # step 2: check emit function, create a dict
  54. ret += mcgen("""
  55. emit = qmp_event_get_func_emit();
  56. if (!emit) {
  57. return;
  58. }
  59. qmp = qmp_event_build_dict("%(event_name)s");
  60. """,
  61. event_name = event_name)
  62. # step 3: visit the params if params != None
  63. if params:
  64. ret += mcgen("""
  65. qov = qmp_output_visitor_new();
  66. g_assert(qov);
  67. v = qmp_output_get_visitor(qov);
  68. g_assert(v);
  69. /* Fake visit, as if all members are under a structure */
  70. visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
  71. if (local_err) {
  72. goto clean;
  73. }
  74. """,
  75. event_name = event_name)
  76. for argname, argentry, optional, structured in parse_args(params):
  77. if optional:
  78. ret += mcgen("""
  79. if (has_%(var)s) {
  80. """,
  81. var = c_var(argname))
  82. push_indent()
  83. if argentry == "str":
  84. var_type = "(char **)"
  85. else:
  86. var_type = ""
  87. ret += mcgen("""
  88. visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
  89. if (local_err) {
  90. goto clean;
  91. }
  92. """,
  93. var_type = var_type,
  94. var = c_var(argname),
  95. type = type_name(argentry),
  96. name = argname)
  97. if optional:
  98. pop_indent()
  99. ret += mcgen("""
  100. }
  101. """)
  102. ret += mcgen("""
  103. visit_end_struct(v, &local_err);
  104. if (local_err) {
  105. goto clean;
  106. }
  107. obj = qmp_output_get_qobject(qov);
  108. g_assert(obj != NULL);
  109. qdict_put_obj(qmp, "data", obj);
  110. """)
  111. # step 4: call qmp event api
  112. ret += mcgen("""
  113. emit(%(event_enum_value)s, qmp, &local_err);
  114. """,
  115. event_enum_value = event_enum_value)
  116. # step 5: clean up
  117. if params:
  118. ret += mcgen("""
  119. clean:
  120. qmp_output_visitor_cleanup(qov);
  121. """)
  122. ret += mcgen("""
  123. error_propagate(errp, local_err);
  124. QDECREF(qmp);
  125. }
  126. """)
  127. return ret
  128. # Following are the functions that generate an enum type for all defined
  129. # events, similar to qapi-types.py. Here we already have enum name and
  130. # values which were generated before and recorded in event_enum_*. It also
  131. # works around the issue that "import qapi-types" can't work.
  132. def generate_event_enum_decl(event_enum_name, event_enum_values):
  133. lookup_decl = mcgen('''
  134. extern const char *%(event_enum_name)s_lookup[];
  135. ''',
  136. event_enum_name = event_enum_name)
  137. enum_decl = mcgen('''
  138. typedef enum %(event_enum_name)s
  139. {
  140. ''',
  141. event_enum_name = event_enum_name)
  142. # append automatically generated _MAX value
  143. enum_max_value = generate_enum_full_value(event_enum_name, "MAX")
  144. enum_values = event_enum_values + [ enum_max_value ]
  145. i = 0
  146. for value in enum_values:
  147. enum_decl += mcgen('''
  148. %(value)s = %(i)d,
  149. ''',
  150. value = value,
  151. i = i)
  152. i += 1
  153. enum_decl += mcgen('''
  154. } %(event_enum_name)s;
  155. ''',
  156. event_enum_name = event_enum_name)
  157. return lookup_decl + enum_decl
  158. def generate_event_enum_lookup(event_enum_name, event_enum_strings):
  159. ret = mcgen('''
  160. const char *%(event_enum_name)s_lookup[] = {
  161. ''',
  162. event_enum_name = event_enum_name)
  163. i = 0
  164. for string in event_enum_strings:
  165. ret += mcgen('''
  166. "%(string)s",
  167. ''',
  168. string = string)
  169. ret += mcgen('''
  170. NULL,
  171. };
  172. ''')
  173. return ret
  174. # Start the real job
  175. try:
  176. opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
  177. ["source", "header", "builtins", "prefix=",
  178. "input-file=", "output-dir="])
  179. except getopt.GetoptError, err:
  180. print str(err)
  181. sys.exit(1)
  182. input_file = ""
  183. output_dir = ""
  184. prefix = ""
  185. c_file = 'qapi-event.c'
  186. h_file = 'qapi-event.h'
  187. do_c = False
  188. do_h = False
  189. do_builtins = False
  190. for o, a in opts:
  191. if o in ("-p", "--prefix"):
  192. prefix = a
  193. elif o in ("-i", "--input-file"):
  194. input_file = a
  195. elif o in ("-o", "--output-dir"):
  196. output_dir = a + "/"
  197. elif o in ("-c", "--source"):
  198. do_c = True
  199. elif o in ("-h", "--header"):
  200. do_h = True
  201. elif o in ("-b", "--builtins"):
  202. do_builtins = True
  203. if not do_c and not do_h:
  204. do_c = True
  205. do_h = True
  206. c_file = output_dir + prefix + c_file
  207. h_file = output_dir + prefix + h_file
  208. try:
  209. os.makedirs(output_dir)
  210. except os.error, e:
  211. if e.errno != errno.EEXIST:
  212. raise
  213. def maybe_open(really, name, opt):
  214. if really:
  215. return open(name, opt)
  216. else:
  217. import StringIO
  218. return StringIO.StringIO()
  219. fdef = maybe_open(do_c, c_file, 'w')
  220. fdecl = maybe_open(do_h, h_file, 'w')
  221. fdef.write(mcgen('''
  222. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  223. /*
  224. * schema-defined QAPI event functions
  225. *
  226. * Copyright (c) 2014 Wenchao Xia
  227. *
  228. * Authors:
  229. * Wenchao Xia <wenchaoqemu@gmail.com>
  230. *
  231. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  232. * See the COPYING.LIB file in the top-level directory.
  233. *
  234. */
  235. #include "qemu-common.h"
  236. #include "%(header)s"
  237. #include "%(prefix)sqapi-visit.h"
  238. #include "qapi/qmp-output-visitor.h"
  239. #include "qapi/qmp-event.h"
  240. ''',
  241. prefix=prefix, header=basename(h_file)))
  242. fdecl.write(mcgen('''
  243. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  244. /*
  245. * schema-defined QAPI event functions
  246. *
  247. * Copyright (c) 2014 Wenchao Xia
  248. *
  249. * Authors:
  250. * Wenchao Xia <wenchaoqemu@gmail.com>
  251. *
  252. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  253. * See the COPYING.LIB file in the top-level directory.
  254. *
  255. */
  256. #ifndef %(guard)s
  257. #define %(guard)s
  258. #include "qapi/error.h"
  259. #include "qapi/qmp/qdict.h"
  260. #include "%(prefix)sqapi-types.h"
  261. ''',
  262. prefix=prefix, guard=guardname(h_file)))
  263. exprs = parse_schema(input_file)
  264. event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
  265. event_enum_values = []
  266. event_enum_strings = []
  267. for expr in exprs:
  268. if expr.has_key('event'):
  269. event_name = expr['event']
  270. params = expr.get('data')
  271. if params and len(params) == 0:
  272. params = None
  273. api_name = _generate_event_api_name(event_name, params)
  274. ret = generate_event_declaration(api_name)
  275. fdecl.write(ret)
  276. # We need an enum value per event
  277. event_enum_value = generate_enum_full_value(event_enum_name,
  278. event_name)
  279. ret = generate_event_implement(api_name, event_name, params)
  280. fdef.write(ret)
  281. # Record it, and generate enum later
  282. event_enum_values.append(event_enum_value)
  283. event_enum_strings.append(event_name)
  284. ret = generate_event_enum_decl(event_enum_name, event_enum_values)
  285. fdecl.write(ret)
  286. ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
  287. fdef.write(ret)
  288. fdecl.write('''
  289. #endif
  290. ''')
  291. fdecl.flush()
  292. fdecl.close()
  293. fdef.flush()
  294. fdef.close()