1 # -*- coding: utf-8 -*-
5 # Copyright (c) 2018-2019 Red Hat Inc.
8 # Markus Armbruster <armbru@redhat.com>
9 # Marc-André Lureau <marcandre.lureau@redhat.com>
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
):
157 """A 'with' statement context manager to wrap with start_if()/end_if()
159 *args: any number of QAPIGenCCode
163 with ifcontext(ifcond, self._genh, self._genc):
164 modify self._genh and self._genc ...
166 Is equivalent to calling::
168 self._genh.start_if(ifcond)
169 self._genc.start_if(ifcond)
170 modify self._genh and self._genc ...
181 class QAPIGenDoc(QAPIGen
):
184 return (super()._top
()
185 + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
188 class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor
):
190 def __init__(self
, prefix
, what
, blurb
, pydoc
):
191 self
._prefix
= prefix
193 self
._genc
= QAPIGenC(self
._prefix
+ self
._what
+ '.c',
195 self
._genh
= QAPIGenH(self
._prefix
+ self
._what
+ '.h',
198 def write(self
, output_dir
):
199 self
._genc
.write(output_dir
)
200 self
._genh
.write(output_dir
)
203 class QAPISchemaModularCVisitor(QAPISchemaVisitor
):
205 def __init__(self
, prefix
, what
, user_blurb
, builtin_blurb
, pydoc
):
206 self
._prefix
= prefix
208 self
._user
_blurb
= user_blurb
209 self
._builtin
_blurb
= builtin_blurb
214 self
._main
_module
= None
217 def _is_user_module(name
):
218 return name
and not name
.startswith('./')
221 def _is_builtin_module(name
):
224 def _module_dirname(self
, what
, name
):
225 if self
._is
_user
_module
(name
):
226 return os
.path
.dirname(name
)
229 def _module_basename(self
, what
, name
):
230 ret
= '' if self
._is
_builtin
_module
(name
) else self
._prefix
231 if self
._is
_user
_module
(name
):
232 basename
= os
.path
.basename(name
)
234 if name
!= self
._main
_module
:
235 ret
+= '-' + os
.path
.splitext(basename
)[0]
237 name
= name
[2:] if name
else 'builtin'
238 ret
+= re
.sub(r
'-', '-' + name
+ '-', what
)
241 def _module_filename(self
, what
, name
):
242 return os
.path
.join(self
._module
_dirname
(what
, name
),
243 self
._module
_basename
(what
, name
))
245 def _add_module(self
, name
, blurb
):
246 basename
= self
._module
_filename
(self
._what
, name
)
247 genc
= QAPIGenC(basename
+ '.c', blurb
, self
._pydoc
)
248 genh
= QAPIGenH(basename
+ '.h', blurb
, self
._pydoc
)
249 self
._module
[name
] = (genc
, genh
)
250 self
._genc
, self
._genh
= self
._module
[name
]
252 def _add_user_module(self
, name
, blurb
):
253 assert self
._is
_user
_module
(name
)
254 if self
._main
_module
is None:
255 self
._main
_module
= name
256 self
._add
_module
(name
, blurb
)
258 def _add_system_module(self
, name
, blurb
):
259 self
._add
_module
(name
and './' + name
, blurb
)
261 def write(self
, output_dir
, opt_builtins
=False):
262 for name
in self
._module
:
263 if self
._is
_builtin
_module
(name
) and not opt_builtins
:
265 (genc
, genh
) = self
._module
[name
]
266 genc
.write(output_dir
)
267 genh
.write(output_dir
)
269 def _begin_system_module(self
, name
):
272 def _begin_user_module(self
, name
):
275 def visit_module(self
, name
):
277 if self
._builtin
_blurb
:
278 self
._add
_system
_module
(None, self
._builtin
_blurb
)
279 self
._begin
_system
_module
(name
)
281 # The built-in module has not been created. No code may
286 self
._add
_user
_module
(name
, self
._user
_blurb
)
287 self
._begin
_user
_module
(name
)
289 def visit_include(self
, name
, info
):
290 relname
= os
.path
.relpath(self
._module
_filename
(self
._what
, name
),
291 os
.path
.dirname(self
._genh
.fname
))
292 self
._genh
.preamble_add(mcgen('''
293 #include "%(relname)s.h"