mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
e3f80b9254
This is a reimplementation of commit
4aba03562b
from Will Thompson, but
conditional on the caller passing `--glib-min-version 2.64` to
`gdbus-codegen` to explicitly opt-in to the new behaviour.
From the commit message for that commit:
Previously, if a method was not annotated with org.gtk.GDBus.C.UnixFD
then the generated code would never contain GUnixFDList parameters, even
if the method has 'h' (file descriptor) parameters. However, in this
case, the generated code is essentially useless: the method cannot be
called or handled except in degenerate cases where the file descriptors
are missing or ignored.
Check the argument types for 'h', and if present, generate code as if
org.gtk.GDBus.C.UnixFD annotation were specified.
Includes a unit test too.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1726
297 lines
13 KiB
Python
297 lines
13 KiB
Python
# -*- Mode: Python -*-
|
|
|
|
# GDBus - GLib D-Bus Library
|
|
#
|
|
# Copyright (C) 2008-2011 Red Hat, Inc.
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General
|
|
# Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# Author: David Zeuthen <davidz@redhat.com>
|
|
|
|
import sys
|
|
import xml.parsers.expat
|
|
|
|
from . import dbustypes
|
|
from .utils import print_error
|
|
|
|
class DBusXMLParser:
|
|
STATE_TOP = 'top'
|
|
STATE_NODE = 'node'
|
|
STATE_INTERFACE = 'interface'
|
|
STATE_METHOD = 'method'
|
|
STATE_SIGNAL = 'signal'
|
|
STATE_PROPERTY = 'property'
|
|
STATE_ARG = 'arg'
|
|
STATE_ANNOTATION = 'annotation'
|
|
STATE_IGNORED = 'ignored'
|
|
|
|
def __init__(self, xml_data, h_type_implies_unix_fd=True):
|
|
self._parser = xml.parsers.expat.ParserCreate()
|
|
self._parser.CommentHandler = self.handle_comment
|
|
self._parser.CharacterDataHandler = self.handle_char_data
|
|
self._parser.StartElementHandler = self.handle_start_element
|
|
self._parser.EndElementHandler = self.handle_end_element
|
|
|
|
self.parsed_interfaces = []
|
|
self._cur_object = None
|
|
|
|
self.state = DBusXMLParser.STATE_TOP
|
|
self.state_stack = []
|
|
self._cur_object = None
|
|
self._cur_object_stack = []
|
|
|
|
self.doc_comment_last_symbol = ''
|
|
|
|
self._h_type_implies_unix_fd = h_type_implies_unix_fd
|
|
|
|
self._parser.Parse(xml_data)
|
|
|
|
COMMENT_STATE_BEGIN = 'begin'
|
|
COMMENT_STATE_PARAMS = 'params'
|
|
COMMENT_STATE_BODY = 'body'
|
|
COMMENT_STATE_SKIP = 'skip'
|
|
def handle_comment(self, data):
|
|
comment_state = DBusXMLParser.COMMENT_STATE_BEGIN;
|
|
lines = data.split('\n')
|
|
symbol = ''
|
|
body = ''
|
|
in_para = False
|
|
params = {}
|
|
for line in lines:
|
|
orig_line = line
|
|
line = line.lstrip()
|
|
if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
|
|
if len(line) > 0:
|
|
colon_index = line.find(': ')
|
|
if colon_index == -1:
|
|
if line.endswith(':'):
|
|
symbol = line[0:len(line)-1]
|
|
comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
|
|
else:
|
|
comment_state = DBusXMLParser.COMMENT_STATE_SKIP
|
|
else:
|
|
symbol = line[0:colon_index]
|
|
rest_of_line = line[colon_index+2:].strip()
|
|
if len(rest_of_line) > 0:
|
|
body += '<para>' + rest_of_line + '</para>'
|
|
comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
|
|
elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
|
|
if line.startswith('@'):
|
|
colon_index = line.find(': ')
|
|
if colon_index == -1:
|
|
comment_state = DBusXMLParser.COMMENT_STATE_BODY
|
|
if not in_para:
|
|
body += '<para>'
|
|
in_para = True
|
|
body += orig_line + '\n'
|
|
else:
|
|
param = line[1:colon_index]
|
|
docs = line[colon_index + 2:]
|
|
params[param] = docs
|
|
else:
|
|
comment_state = DBusXMLParser.COMMENT_STATE_BODY
|
|
if len(line) > 0:
|
|
if not in_para:
|
|
body += '<para>'
|
|
in_para = True
|
|
body += orig_line + '\n'
|
|
elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
|
|
if len(line) > 0:
|
|
if not in_para:
|
|
body += '<para>'
|
|
in_para = True
|
|
body += orig_line + '\n'
|
|
else:
|
|
if in_para:
|
|
body += '</para>'
|
|
in_para = False
|
|
if in_para:
|
|
body += '</para>'
|
|
|
|
if symbol != '':
|
|
self.doc_comment_last_symbol = symbol
|
|
self.doc_comment_params = params
|
|
self.doc_comment_body = body
|
|
|
|
def handle_char_data(self, data):
|
|
#print 'char_data=%s'%data
|
|
pass
|
|
|
|
def handle_start_element(self, name, attrs):
|
|
old_state = self.state
|
|
old_cur_object = self._cur_object
|
|
if self.state == DBusXMLParser.STATE_IGNORED:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
elif self.state == DBusXMLParser.STATE_TOP:
|
|
if name == DBusXMLParser.STATE_NODE:
|
|
self.state = DBusXMLParser.STATE_NODE
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
elif self.state == DBusXMLParser.STATE_NODE:
|
|
if name == DBusXMLParser.STATE_INTERFACE:
|
|
self.state = DBusXMLParser.STATE_INTERFACE
|
|
iface = dbustypes.Interface(attrs['name'])
|
|
self._cur_object = iface
|
|
self.parsed_interfaces.append(iface)
|
|
elif name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
# assign docs, if any
|
|
if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
|
|
self._cur_object.doc_string = self.doc_comment_body
|
|
if 'short_description' in self.doc_comment_params:
|
|
short_description = self.doc_comment_params['short_description']
|
|
self._cur_object.doc_string_brief = short_description
|
|
if 'since' in self.doc_comment_params:
|
|
self._cur_object.since = \
|
|
self.doc_comment_params['since'].strip()
|
|
|
|
elif self.state == DBusXMLParser.STATE_INTERFACE:
|
|
if name == DBusXMLParser.STATE_METHOD:
|
|
self.state = DBusXMLParser.STATE_METHOD
|
|
method = dbustypes.Method(attrs['name'],
|
|
h_type_implies_unix_fd=self._h_type_implies_unix_fd)
|
|
self._cur_object.methods.append(method)
|
|
self._cur_object = method
|
|
elif name == DBusXMLParser.STATE_SIGNAL:
|
|
self.state = DBusXMLParser.STATE_SIGNAL
|
|
signal = dbustypes.Signal(attrs['name'])
|
|
self._cur_object.signals.append(signal)
|
|
self._cur_object = signal
|
|
elif name == DBusXMLParser.STATE_PROPERTY:
|
|
self.state = DBusXMLParser.STATE_PROPERTY
|
|
prop = dbustypes.Property(attrs['name'], attrs['type'], attrs['access'])
|
|
self._cur_object.properties.append(prop)
|
|
self._cur_object = prop
|
|
elif name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
# assign docs, if any
|
|
if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
|
|
self._cur_object.doc_string = self.doc_comment_body
|
|
if 'since' in self.doc_comment_params:
|
|
self._cur_object.since = \
|
|
self.doc_comment_params['since'].strip()
|
|
|
|
elif self.state == DBusXMLParser.STATE_METHOD:
|
|
if name == DBusXMLParser.STATE_ARG:
|
|
self.state = DBusXMLParser.STATE_ARG
|
|
arg_name = None
|
|
if 'name' in attrs:
|
|
arg_name = attrs['name']
|
|
arg = dbustypes.Arg(arg_name, attrs['type'])
|
|
direction = attrs.get('direction', 'in')
|
|
if direction == 'in':
|
|
self._cur_object.in_args.append(arg)
|
|
elif direction == 'out':
|
|
self._cur_object.out_args.append(arg)
|
|
else:
|
|
print_error('Invalid direction "{}"'.format(direction))
|
|
self._cur_object = arg
|
|
elif name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
# assign docs, if any
|
|
if self.doc_comment_last_symbol == old_cur_object.name:
|
|
if 'name' in attrs and attrs['name'] in self.doc_comment_params:
|
|
doc_string = self.doc_comment_params[attrs['name']]
|
|
if doc_string != None:
|
|
self._cur_object.doc_string = doc_string
|
|
if 'since' in self.doc_comment_params:
|
|
self._cur_object.since = \
|
|
self.doc_comment_params['since'].strip()
|
|
|
|
elif self.state == DBusXMLParser.STATE_SIGNAL:
|
|
if name == DBusXMLParser.STATE_ARG:
|
|
self.state = DBusXMLParser.STATE_ARG
|
|
arg_name = None
|
|
if 'name' in attrs:
|
|
arg_name = attrs['name']
|
|
arg = dbustypes.Arg(arg_name, attrs['type'])
|
|
self._cur_object.args.append(arg)
|
|
self._cur_object = arg
|
|
elif name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
# assign docs, if any
|
|
if self.doc_comment_last_symbol == old_cur_object.name:
|
|
if 'name' in attrs and attrs['name'] in self.doc_comment_params:
|
|
doc_string = self.doc_comment_params[attrs['name']]
|
|
if doc_string != None:
|
|
self._cur_object.doc_string = doc_string
|
|
if 'since' in self.doc_comment_params:
|
|
self._cur_object.since = \
|
|
self.doc_comment_params['since'].strip()
|
|
|
|
elif self.state == DBusXMLParser.STATE_PROPERTY:
|
|
if name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
elif self.state == DBusXMLParser.STATE_ARG:
|
|
if name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
elif self.state == DBusXMLParser.STATE_ANNOTATION:
|
|
if name == DBusXMLParser.STATE_ANNOTATION:
|
|
self.state = DBusXMLParser.STATE_ANNOTATION
|
|
anno = dbustypes.Annotation(attrs['name'], attrs['value'])
|
|
self._cur_object.annotations.append(anno)
|
|
self._cur_object = anno
|
|
else:
|
|
self.state = DBusXMLParser.STATE_IGNORED
|
|
|
|
else:
|
|
print_error('Unhandled state "{}" while entering element with name "{}"'.format(self.state, name))
|
|
|
|
self.state_stack.append(old_state)
|
|
self._cur_object_stack.append(old_cur_object)
|
|
|
|
def handle_end_element(self, name):
|
|
self.state = self.state_stack.pop()
|
|
self._cur_object = self._cur_object_stack.pop()
|
|
|
|
def parse_dbus_xml(xml_data, h_type_implies_unix_fd):
|
|
parser = DBusXMLParser(xml_data, h_type_implies_unix_fd)
|
|
return parser.parsed_interfaces
|