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.
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
, blurb
, pydoc
):
205 self
._prefix
= prefix
212 self
._main
_module
= None
215 def _is_user_module(name
):
216 return name
and not name
.startswith('./')
219 def _is_builtin_module(name
):
222 def _module_dirname(self
, what
, name
):
223 if self
._is
_user
_module
(name
):
224 return os
.path
.dirname(name
)
227 def _module_basename(self
, what
, name
):
228 ret
= '' if self
._is
_builtin
_module
(name
) else self
._prefix
229 if self
._is
_user
_module
(name
):
230 basename
= os
.path
.basename(name
)
232 if name
!= self
._main
_module
:
233 ret
+= '-' + os
.path
.splitext(basename
)[0]
235 name
= name
[2:] if name
else 'builtin'
236 ret
+= re
.sub(r
'-', '-' + name
+ '-', what
)
239 def _module_filename(self
, what
, name
):
240 return os
.path
.join(self
._module
_dirname
(what
, name
),
241 self
._module
_basename
(what
, name
))
243 def _add_module(self
, name
, blurb
):
244 basename
= self
._module
_filename
(self
._what
, name
)
245 genc
= QAPIGenC(basename
+ '.c', blurb
, self
._pydoc
)
246 genh
= QAPIGenH(basename
+ '.h', blurb
, self
._pydoc
)
247 self
._module
[name
] = (genc
, genh
)
248 self
._set
_module
(name
)
250 def _add_user_module(self
, name
, blurb
):
251 assert self
._is
_user
_module
(name
)
252 if self
._main
_module
is None:
253 self
._main
_module
= name
254 self
._add
_module
(name
, blurb
)
256 def _add_system_module(self
, name
, blurb
):
257 self
._add
_module
(name
and './' + name
, blurb
)
259 def _set_module(self
, name
):
260 self
._genc
, self
._genh
= self
._module
[name
]
262 def write(self
, output_dir
, opt_builtins
=False):
263 for name
in self
._module
:
264 if self
._is
_builtin
_module
(name
) and not opt_builtins
:
266 (genc
, genh
) = self
._module
[name
]
267 genc
.write(output_dir
)
268 genh
.write(output_dir
)
270 def _begin_user_module(self
, name
):
273 def visit_module(self
, name
):
274 if name
in self
._module
:
275 self
._set
_module
(name
)
276 elif self
._is
_builtin
_module
(name
):
277 # The built-in module has not been created. No code may
282 self
._add
_user
_module
(name
, self
._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"