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.
18 from contextlib import contextmanager
20 from qapi.common import *
21 from qapi.schema import QAPISchemaVisitor
26 def __init__(self, fname):
31 def preamble_add(self, text):
32 self._preamble += text
37 def get_content(self):
38 return self._top() + self._preamble + self._body + self._bottom()
46 def write(self, output_dir):
47 # Include paths starting with ../ are used to reuse modules of the main
48 # schema in specialised schemas. Don't overwrite the files that are
49 # already generated for the main schema.
50 if self.fname.startswith('../'):
52 pathname = os.path.join(output_dir, self.fname)
53 odir = os.path.dirname(pathname)
58 if e.errno != errno.EEXIST:
60 fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
61 f = open(fd, 'r+', encoding='utf-8')
62 text = self.get_content()
63 oldtext = f.read(len(text) + 1)
71 def _wrap_ifcond(ifcond, before, after):
73 return after # suppress empty #if ... #endif
75 assert after.startswith(before)
77 added = after[len(before):]
83 out += gen_endif(ifcond)
87 class QAPIGenCCode(QAPIGen):
89 def __init__(self, fname):
90 super().__init__(fname)
93 def start_if(self, ifcond):
94 assert self._start_if is None
95 self._start_if = (ifcond, self._body, self._preamble)
100 self._start_if = None
102 def _wrap_ifcond(self):
103 self._body = _wrap_ifcond(self._start_if[0],
104 self._start_if[1], self._body)
105 self._preamble = _wrap_ifcond(self._start_if[0],
106 self._start_if[2], self._preamble)
108 def get_content(self):
109 assert self._start_if is None
110 return super().get_content()
113 class QAPIGenC(QAPIGenCCode):
115 def __init__(self, fname, blurb, pydoc):
116 super().__init__(fname)
118 self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
123 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
130 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
131 * See the COPYING.LIB file in the top-level directory.
135 blurb=self._blurb, copyright=self._copyright)
140 /* Dummy declaration to prevent empty .o file */
141 char qapi_dummy_%(name)s;
143 name=c_fname(self.fname))
146 class QAPIGenH(QAPIGenC):
149 return super()._top() + guardstart(self.fname)
152 return guardend(self.fname)
156 def ifcontext(ifcond, *args):
158 A with-statement context manager that wraps with `start_if()` / `end_if()`.
160 :param ifcond: A list of conditionals, passed to `start_if()`.
161 :param args: any number of `QAPIGenCCode`.
165 with ifcontext(ifcond, self._genh, self._genc):
166 modify self._genh and self._genc ...
168 Is equivalent to calling::
170 self._genh.start_if(ifcond)
171 self._genc.start_if(ifcond)
172 modify self._genh and self._genc ...
183 class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
185 def __init__(self, prefix, what, blurb, pydoc):
186 self._prefix = prefix
188 self._genc = QAPIGenC(self._prefix + self._what + '.c',
190 self._genh = QAPIGenH(self._prefix + self._what + '.h',
193 def write(self, output_dir):
194 self._genc.write(output_dir)
195 self._genh.write(output_dir)
198 class QAPISchemaModularCVisitor(QAPISchemaVisitor):
200 def __init__(self, prefix, what, user_blurb, builtin_blurb, pydoc):
201 self._prefix = prefix
203 self._user_blurb = user_blurb
204 self._builtin_blurb = builtin_blurb
209 self._main_module = None
212 def _is_user_module(name):
213 return name and not name.startswith('./')
216 def _is_builtin_module(name):
219 def _module_dirname(self, what, name):
220 if self._is_user_module(name):
221 return os.path.dirname(name)
224 def _module_basename(self, what, name):
225 ret = '' if self._is_builtin_module(name) else self._prefix
226 if self._is_user_module(name):
227 basename = os.path.basename(name)
229 if name != self._main_module:
230 ret += '-' + os.path.splitext(basename)[0]
232 name = name[2:] if name else 'builtin'
233 ret += re.sub(r'-', '-' + name + '-', what)
236 def _module_filename(self, what, name):
237 return os.path.join(self._module_dirname(what, name),
238 self._module_basename(what, name))
240 def _add_module(self, name, blurb):
241 basename = self._module_filename(self._what, name)
242 genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
243 genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
244 self._module[name] = (genc, genh)
245 self._genc, self._genh = self._module[name]
247 def _add_user_module(self, name, blurb):
248 assert self._is_user_module(name)
249 if self._main_module is None:
250 self._main_module = name
251 self._add_module(name, blurb)
253 def _add_system_module(self, name, blurb):
254 self._add_module(name and './' + name, blurb)
256 def write(self, output_dir, opt_builtins=False):
257 for name in self._module:
258 if self._is_builtin_module(name) and not opt_builtins:
260 (genc, genh) = self._module[name]
261 genc.write(output_dir)
262 genh.write(output_dir)
264 def _begin_system_module(self, name):
267 def _begin_user_module(self, name):
270 def visit_module(self, name):
272 if self._builtin_blurb:
273 self._add_system_module(None, self._builtin_blurb)
274 self._begin_system_module(name)
276 # The built-in module has not been created. No code may
281 self._add_user_module(name, self._user_blurb)
282 self._begin_user_module(name)
284 def visit_include(self, name, info):
285 relname = os.path.relpath(self._module_filename(self._what, name),
286 os.path.dirname(self._genh.fname))
287 self._genh.preamble_add(mcgen('''
288 #include "%(relname)s.h"