1 # -*- coding: utf-8 -*-
5 # Copyright (c) 2018-2019 Red Hat Inc.
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
19 from contextlib import contextmanager
21 from qapi.common import *
22 from qapi.schema import QAPISchemaVisitor
25 class QAPIGen(object):
27 def __init__(self, fname):
32 def preamble_add(self, text):
33 self._preamble += text
38 def get_content(self):
39 return self._top() + self._preamble + self._body + self._bottom()
47 def write(self, output_dir):
48 pathname = os.path.join(output_dir, self.fname)
49 dir = os.path.dirname(pathname)
54 if e.errno != errno.EEXIST:
56 fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
57 if sys.version_info[0] >= 3:
58 f = open(fd, 'r+', encoding='utf-8')
60 f = os.fdopen(fd, 'r+')
61 text = self.get_content()
62 oldtext = f.read(len(text) + 1)
70 def _wrap_ifcond(ifcond, before, after):
72 return after # suppress empty #if ... #endif
74 assert after.startswith(before)
76 added = after[len(before):]
82 out += gen_endif(ifcond)
86 class QAPIGenCCode(QAPIGen):
88 def __init__(self, fname):
89 QAPIGen.__init__(self, fname)
92 def start_if(self, ifcond):
93 assert self._start_if is None
94 self._start_if = (ifcond, self._body, self._preamble)
101 def _wrap_ifcond(self):
102 self._body = _wrap_ifcond(self._start_if[0],
103 self._start_if[1], self._body)
104 self._preamble = _wrap_ifcond(self._start_if[0],
105 self._start_if[2], self._preamble)
107 def get_content(self):
108 assert self._start_if is None
109 return QAPIGen.get_content(self)
112 class QAPIGenC(QAPIGenCCode):
114 def __init__(self, fname, blurb, pydoc):
115 QAPIGenCCode.__init__(self, fname)
117 self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
122 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
129 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
130 * See the COPYING.LIB file in the top-level directory.
134 blurb=self._blurb, copyright=self._copyright)
139 /* Dummy declaration to prevent empty .o file */
140 char qapi_dummy_%(name)s;
142 name=c_fname(self.fname))
145 class QAPIGenH(QAPIGenC):
148 return QAPIGenC._top(self) + guardstart(self.fname)
151 return guardend(self.fname)
155 def ifcontext(ifcond, *args):
156 """A 'with' statement context manager to wrap with start_if()/end_if()
158 *args: any number of QAPIGenCCode
162 with ifcontext(ifcond, self._genh, self._genc):
163 modify self._genh and self._genc ...
165 Is equivalent to calling::
167 self._genh.start_if(ifcond)
168 self._genc.start_if(ifcond)
169 modify self._genh and self._genc ...
180 class QAPIGenDoc(QAPIGen):
183 return (QAPIGen._top(self)
184 + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
187 class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
189 def __init__(self, prefix, what, blurb, pydoc):
190 self._prefix = prefix
192 self._genc = QAPIGenC(self._prefix + self._what + '.c',
194 self._genh = QAPIGenH(self._prefix + self._what + '.h',
197 def write(self, output_dir):
198 self._genc.write(output_dir)
199 self._genh.write(output_dir)
202 class QAPISchemaModularCVisitor(QAPISchemaVisitor):
204 def __init__(self, prefix, what, user_blurb, builtin_blurb, pydoc):
205 self._prefix = prefix
207 self._user_blurb = user_blurb
208 self._builtin_blurb = builtin_blurb
213 self._main_module = None
216 def _is_user_module(name):
217 return name and not name.startswith('./')
220 def _is_builtin_module(name):
223 def _module_dirname(self, what, name):
224 if self._is_user_module(name):
225 return os.path.dirname(name)
228 def _module_basename(self, what, name):
229 ret = '' if self._is_builtin_module(name) else self._prefix
230 if self._is_user_module(name):
231 basename = os.path.basename(name)
233 if name != self._main_module:
234 ret += '-' + os.path.splitext(basename)[0]
236 name = name[2:] if name else 'builtin'
237 ret += re.sub(r'-', '-' + name + '-', what)
240 def _module_filename(self, what, name):
241 return os.path.join(self._module_dirname(what, name),
242 self._module_basename(what, name))
244 def _add_module(self, name, blurb):
245 basename = self._module_filename(self._what, name)
246 genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
247 genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
248 self._module[name] = (genc, genh)
249 self._genc, self._genh = self._module[name]
251 def _add_user_module(self, name, blurb):
252 assert self._is_user_module(name)
253 if self._main_module is None:
254 self._main_module = name
255 self._add_module(name, blurb)
257 def _add_system_module(self, name, blurb):
258 self._add_module(name and './' + name, blurb)
260 def write(self, output_dir, opt_builtins=False):
261 for name in self._module:
262 if self._is_builtin_module(name) and not opt_builtins:
264 (genc, genh) = self._module[name]
265 genc.write(output_dir)
266 genh.write(output_dir)
268 def _begin_user_module(self, name):
271 def visit_module(self, name):
273 if self._builtin_blurb:
274 self._add_system_module(None, self._builtin_blurb)
275 self._begin_system_module(name)
277 # The built-in module has not been created. No code may
282 self._add_user_module(name, self._user_blurb)
283 self._begin_user_module(name)
285 def visit_include(self, name, info):
286 relname = os.path.relpath(self._module_filename(self._what, name),
287 os.path.dirname(self._genh.fname))
288 self._genh.preamble_add(mcgen('''
289 #include "%(relname)s.h"