Merge tag 'qemu-macppc-20230206' of https://github.com/mcayland/qemu into staging
[qemu.git] / docs / sphinx / dbusparser.py
blob024553eae7b580bf7417978fc20b97044d4c2e7d
1 # Based from "GDBus - GLib D-Bus Library":
3 # Copyright (C) 2008-2011 Red Hat, Inc.
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General
16 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 # Author: David Zeuthen <davidz@redhat.com>
20 import xml.parsers.expat
23 class Annotation:
24 def __init__(self, key, value):
25 self.key = key
26 self.value = value
27 self.annotations = []
28 self.since = ""
31 class Arg:
32 def __init__(self, name, signature):
33 self.name = name
34 self.signature = signature
35 self.annotations = []
36 self.doc_string = ""
37 self.since = ""
40 class Method:
41 def __init__(self, name, h_type_implies_unix_fd=True):
42 self.name = name
43 self.h_type_implies_unix_fd = h_type_implies_unix_fd
44 self.in_args = []
45 self.out_args = []
46 self.annotations = []
47 self.doc_string = ""
48 self.since = ""
49 self.deprecated = False
50 self.unix_fd = False
53 class Signal:
54 def __init__(self, name):
55 self.name = name
56 self.args = []
57 self.annotations = []
58 self.doc_string = ""
59 self.since = ""
60 self.deprecated = False
63 class Property:
64 def __init__(self, name, signature, access):
65 self.name = name
66 self.signature = signature
67 self.access = access
68 self.annotations = []
69 self.arg = Arg("value", self.signature)
70 self.arg.annotations = self.annotations
71 self.readable = False
72 self.writable = False
73 if self.access == "readwrite":
74 self.readable = True
75 self.writable = True
76 elif self.access == "read":
77 self.readable = True
78 elif self.access == "write":
79 self.writable = True
80 else:
81 raise ValueError('Invalid access type "{}"'.format(self.access))
82 self.doc_string = ""
83 self.since = ""
84 self.deprecated = False
85 self.emits_changed_signal = True
88 class Interface:
89 def __init__(self, name):
90 self.name = name
91 self.methods = []
92 self.signals = []
93 self.properties = []
94 self.annotations = []
95 self.doc_string = ""
96 self.doc_string_brief = ""
97 self.since = ""
98 self.deprecated = False
101 class DBusXMLParser:
102 STATE_TOP = "top"
103 STATE_NODE = "node"
104 STATE_INTERFACE = "interface"
105 STATE_METHOD = "method"
106 STATE_SIGNAL = "signal"
107 STATE_PROPERTY = "property"
108 STATE_ARG = "arg"
109 STATE_ANNOTATION = "annotation"
110 STATE_IGNORED = "ignored"
112 def __init__(self, xml_data, h_type_implies_unix_fd=True):
113 self._parser = xml.parsers.expat.ParserCreate()
114 self._parser.CommentHandler = self.handle_comment
115 self._parser.CharacterDataHandler = self.handle_char_data
116 self._parser.StartElementHandler = self.handle_start_element
117 self._parser.EndElementHandler = self.handle_end_element
119 self.parsed_interfaces = []
120 self._cur_object = None
122 self.state = DBusXMLParser.STATE_TOP
123 self.state_stack = []
124 self._cur_object = None
125 self._cur_object_stack = []
127 self.doc_comment_last_symbol = ""
129 self._h_type_implies_unix_fd = h_type_implies_unix_fd
131 self._parser.Parse(xml_data)
133 COMMENT_STATE_BEGIN = "begin"
134 COMMENT_STATE_PARAMS = "params"
135 COMMENT_STATE_BODY = "body"
136 COMMENT_STATE_SKIP = "skip"
138 def handle_comment(self, data):
139 comment_state = DBusXMLParser.COMMENT_STATE_BEGIN
140 lines = data.split("\n")
141 symbol = ""
142 body = ""
143 in_para = False
144 params = {}
145 for line in lines:
146 orig_line = line
147 line = line.lstrip()
148 if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
149 if len(line) > 0:
150 colon_index = line.find(": ")
151 if colon_index == -1:
152 if line.endswith(":"):
153 symbol = line[0 : len(line) - 1]
154 comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
155 else:
156 comment_state = DBusXMLParser.COMMENT_STATE_SKIP
157 else:
158 symbol = line[0:colon_index]
159 rest_of_line = line[colon_index + 2 :].strip()
160 if len(rest_of_line) > 0:
161 body += rest_of_line + "\n"
162 comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
163 elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
164 if line.startswith("@"):
165 colon_index = line.find(": ")
166 if colon_index == -1:
167 comment_state = DBusXMLParser.COMMENT_STATE_BODY
168 if not in_para:
169 in_para = True
170 body += orig_line + "\n"
171 else:
172 param = line[1:colon_index]
173 docs = line[colon_index + 2 :]
174 params[param] = docs
175 else:
176 comment_state = DBusXMLParser.COMMENT_STATE_BODY
177 if len(line) > 0:
178 if not in_para:
179 in_para = True
180 body += orig_line + "\n"
181 elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
182 if len(line) > 0:
183 if not in_para:
184 in_para = True
185 body += orig_line + "\n"
186 else:
187 if in_para:
188 body += "\n"
189 in_para = False
190 if in_para:
191 body += "\n"
193 if symbol != "":
194 self.doc_comment_last_symbol = symbol
195 self.doc_comment_params = params
196 self.doc_comment_body = body
198 def handle_char_data(self, data):
199 # print 'char_data=%s'%data
200 pass
202 def handle_start_element(self, name, attrs):
203 old_state = self.state
204 old_cur_object = self._cur_object
205 if self.state == DBusXMLParser.STATE_IGNORED:
206 self.state = DBusXMLParser.STATE_IGNORED
207 elif self.state == DBusXMLParser.STATE_TOP:
208 if name == DBusXMLParser.STATE_NODE:
209 self.state = DBusXMLParser.STATE_NODE
210 else:
211 self.state = DBusXMLParser.STATE_IGNORED
212 elif self.state == DBusXMLParser.STATE_NODE:
213 if name == DBusXMLParser.STATE_INTERFACE:
214 self.state = DBusXMLParser.STATE_INTERFACE
215 iface = Interface(attrs["name"])
216 self._cur_object = iface
217 self.parsed_interfaces.append(iface)
218 elif name == DBusXMLParser.STATE_ANNOTATION:
219 self.state = DBusXMLParser.STATE_ANNOTATION
220 anno = Annotation(attrs["name"], attrs["value"])
221 self._cur_object.annotations.append(anno)
222 self._cur_object = anno
223 else:
224 self.state = DBusXMLParser.STATE_IGNORED
226 # assign docs, if any
227 if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
228 self._cur_object.doc_string = self.doc_comment_body
229 if "short_description" in self.doc_comment_params:
230 short_description = self.doc_comment_params["short_description"]
231 self._cur_object.doc_string_brief = short_description
232 if "since" in self.doc_comment_params:
233 self._cur_object.since = self.doc_comment_params["since"].strip()
235 elif self.state == DBusXMLParser.STATE_INTERFACE:
236 if name == DBusXMLParser.STATE_METHOD:
237 self.state = DBusXMLParser.STATE_METHOD
238 method = Method(
239 attrs["name"], h_type_implies_unix_fd=self._h_type_implies_unix_fd
241 self._cur_object.methods.append(method)
242 self._cur_object = method
243 elif name == DBusXMLParser.STATE_SIGNAL:
244 self.state = DBusXMLParser.STATE_SIGNAL
245 signal = Signal(attrs["name"])
246 self._cur_object.signals.append(signal)
247 self._cur_object = signal
248 elif name == DBusXMLParser.STATE_PROPERTY:
249 self.state = DBusXMLParser.STATE_PROPERTY
250 prop = Property(attrs["name"], attrs["type"], attrs["access"])
251 self._cur_object.properties.append(prop)
252 self._cur_object = prop
253 elif name == DBusXMLParser.STATE_ANNOTATION:
254 self.state = DBusXMLParser.STATE_ANNOTATION
255 anno = Annotation(attrs["name"], attrs["value"])
256 self._cur_object.annotations.append(anno)
257 self._cur_object = anno
258 else:
259 self.state = DBusXMLParser.STATE_IGNORED
261 # assign docs, if any
262 if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
263 self._cur_object.doc_string = self.doc_comment_body
264 if "since" in self.doc_comment_params:
265 self._cur_object.since = self.doc_comment_params["since"].strip()
267 elif self.state == DBusXMLParser.STATE_METHOD:
268 if name == DBusXMLParser.STATE_ARG:
269 self.state = DBusXMLParser.STATE_ARG
270 arg_name = None
271 if "name" in attrs:
272 arg_name = attrs["name"]
273 arg = Arg(arg_name, attrs["type"])
274 direction = attrs.get("direction", "in")
275 if direction == "in":
276 self._cur_object.in_args.append(arg)
277 elif direction == "out":
278 self._cur_object.out_args.append(arg)
279 else:
280 raise ValueError('Invalid direction "{}"'.format(direction))
281 self._cur_object = arg
282 elif name == DBusXMLParser.STATE_ANNOTATION:
283 self.state = DBusXMLParser.STATE_ANNOTATION
284 anno = Annotation(attrs["name"], attrs["value"])
285 self._cur_object.annotations.append(anno)
286 self._cur_object = anno
287 else:
288 self.state = DBusXMLParser.STATE_IGNORED
290 # assign docs, if any
291 if self.doc_comment_last_symbol == old_cur_object.name:
292 if "name" in attrs and attrs["name"] in self.doc_comment_params:
293 doc_string = self.doc_comment_params[attrs["name"]]
294 if doc_string is not None:
295 self._cur_object.doc_string = doc_string
296 if "since" in self.doc_comment_params:
297 self._cur_object.since = self.doc_comment_params[
298 "since"
299 ].strip()
301 elif self.state == DBusXMLParser.STATE_SIGNAL:
302 if name == DBusXMLParser.STATE_ARG:
303 self.state = DBusXMLParser.STATE_ARG
304 arg_name = None
305 if "name" in attrs:
306 arg_name = attrs["name"]
307 arg = Arg(arg_name, attrs["type"])
308 self._cur_object.args.append(arg)
309 self._cur_object = arg
310 elif name == DBusXMLParser.STATE_ANNOTATION:
311 self.state = DBusXMLParser.STATE_ANNOTATION
312 anno = Annotation(attrs["name"], attrs["value"])
313 self._cur_object.annotations.append(anno)
314 self._cur_object = anno
315 else:
316 self.state = DBusXMLParser.STATE_IGNORED
318 # assign docs, if any
319 if self.doc_comment_last_symbol == old_cur_object.name:
320 if "name" in attrs and attrs["name"] in self.doc_comment_params:
321 doc_string = self.doc_comment_params[attrs["name"]]
322 if doc_string is not None:
323 self._cur_object.doc_string = doc_string
324 if "since" in self.doc_comment_params:
325 self._cur_object.since = self.doc_comment_params[
326 "since"
327 ].strip()
329 elif self.state == DBusXMLParser.STATE_PROPERTY:
330 if name == DBusXMLParser.STATE_ANNOTATION:
331 self.state = DBusXMLParser.STATE_ANNOTATION
332 anno = Annotation(attrs["name"], attrs["value"])
333 self._cur_object.annotations.append(anno)
334 self._cur_object = anno
335 else:
336 self.state = DBusXMLParser.STATE_IGNORED
338 elif self.state == DBusXMLParser.STATE_ARG:
339 if name == DBusXMLParser.STATE_ANNOTATION:
340 self.state = DBusXMLParser.STATE_ANNOTATION
341 anno = Annotation(attrs["name"], attrs["value"])
342 self._cur_object.annotations.append(anno)
343 self._cur_object = anno
344 else:
345 self.state = DBusXMLParser.STATE_IGNORED
347 elif self.state == DBusXMLParser.STATE_ANNOTATION:
348 if name == DBusXMLParser.STATE_ANNOTATION:
349 self.state = DBusXMLParser.STATE_ANNOTATION
350 anno = Annotation(attrs["name"], attrs["value"])
351 self._cur_object.annotations.append(anno)
352 self._cur_object = anno
353 else:
354 self.state = DBusXMLParser.STATE_IGNORED
356 else:
357 raise ValueError(
358 'Unhandled state "{}" while entering element with name "{}"'.format(
359 self.state, name
363 self.state_stack.append(old_state)
364 self._cur_object_stack.append(old_cur_object)
366 def handle_end_element(self, name):
367 self.state = self.state_stack.pop()
368 self._cur_object = self._cur_object_stack.pop()
371 def parse_dbus_xml(xml_data):
372 parser = DBusXMLParser(xml_data, True)
373 return parser.parsed_interfaces