|
Packit |
79f644 |
"""Library code for language-independent D-Bus-related code generation.
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
The master copy of this library is in the telepathy-glib repository -
|
|
Packit |
79f644 |
please make any changes there.
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# Copyright (C) 2006-2008 Collabora Limited
|
|
Packit |
79f644 |
#
|
|
Packit |
79f644 |
# This library is free software; you can redistribute it and/or
|
|
Packit |
79f644 |
# modify it under the terms of the GNU Lesser General Public
|
|
Packit |
79f644 |
# License as published by the Free Software Foundation; either
|
|
Packit |
79f644 |
# version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
79f644 |
#
|
|
Packit |
79f644 |
# This library is distributed in the hope that it will be useful,
|
|
Packit |
79f644 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
79f644 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
79f644 |
# Lesser General Public License for more details.
|
|
Packit |
79f644 |
#
|
|
Packit |
79f644 |
# You should have received a copy of the GNU Lesser General Public
|
|
Packit |
79f644 |
# License along with this library; if not, write to the Free Software
|
|
Packit |
79f644 |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
import os
|
|
Packit |
79f644 |
import sys
|
|
Packit |
79f644 |
from string import ascii_letters, digits
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
_ASCII_ALNUM = ascii_letters + digits
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
if sys.version_info[0] >= 3:
|
|
Packit |
79f644 |
def u(s):
|
|
Packit |
79f644 |
"""Return s, which must be a str literal with no non-ASCII characters.
|
|
Packit |
79f644 |
This is like a more restricted form of the Python 2 u'' syntax.
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
return s.encode('ascii').decode('ascii')
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
def u(s):
|
|
Packit |
79f644 |
"""Return a Unicode version of s, which must be a str literal
|
|
Packit |
79f644 |
(a bytestring) in which each byte is an ASCII character.
|
|
Packit |
79f644 |
This is like a more restricted form of the u'' syntax.
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
return s.decode('ascii')
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def file_set_contents(filename, contents):
|
|
Packit |
79f644 |
try:
|
|
Packit |
79f644 |
os.remove(filename)
|
|
Packit |
79f644 |
except OSError:
|
|
Packit |
79f644 |
pass
|
|
Packit |
79f644 |
try:
|
|
Packit |
79f644 |
os.remove(filename + '.tmp')
|
|
Packit |
79f644 |
except OSError:
|
|
Packit |
79f644 |
pass
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
open(filename + '.tmp', 'wb').write(contents)
|
|
Packit |
79f644 |
os.rename(filename + '.tmp', filename)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def cmp_by_name(node1, node2):
|
|
Packit |
79f644 |
return cmp(node1.getAttributeNode("name").nodeValue,
|
|
Packit |
79f644 |
node2.getAttributeNode("name").nodeValue)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def key_by_name(node):
|
|
Packit |
79f644 |
return node.getAttributeNode("name").nodeValue
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def escape_as_identifier(identifier):
|
|
Packit |
79f644 |
"""Escape the given string to be a valid D-Bus object path or service
|
|
Packit |
79f644 |
name component, using a reversible encoding to ensure uniqueness.
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
The reversible encoding is as follows:
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
* The empty string becomes '_'
|
|
Packit |
79f644 |
* Otherwise, each non-alphanumeric character is replaced by '_' plus
|
|
Packit |
79f644 |
two lower-case hex digits; the same replacement is carried out on
|
|
Packit |
79f644 |
the first character, if it's a digit
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
# '' -> '_'
|
|
Packit |
79f644 |
if not identifier:
|
|
Packit |
79f644 |
return '_'
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# A bit of a fast path for strings which are already OK.
|
|
Packit |
79f644 |
# We deliberately omit '_' because, for reversibility, that must also
|
|
Packit |
79f644 |
# be escaped.
|
|
Packit |
79f644 |
if (identifier.strip(_ASCII_ALNUM) == '' and
|
|
Packit |
79f644 |
identifier[0] in ascii_letters):
|
|
Packit |
79f644 |
return identifier
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# The first character may not be a digit
|
|
Packit |
79f644 |
if identifier[0] not in ascii_letters:
|
|
Packit |
79f644 |
ret = ['_%02x' % ord(identifier[0])]
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
ret = [identifier[0]]
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# Subsequent characters may be digits or ASCII letters
|
|
Packit |
79f644 |
for c in identifier[1:]:
|
|
Packit |
79f644 |
if c in _ASCII_ALNUM:
|
|
Packit |
79f644 |
ret.append(c)
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
ret.append('_%02x' % ord(c))
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
return ''.join(ret)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def get_by_path(element, path):
|
|
Packit |
79f644 |
branches = path.split('/')
|
|
Packit |
79f644 |
branch = branches[0]
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# Is the current branch an attribute, if so, return the attribute value
|
|
Packit |
79f644 |
if branch[0] == '@':
|
|
Packit |
79f644 |
return element.getAttribute(branch[1:])
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
# Find matching children for the branch
|
|
Packit |
79f644 |
children = []
|
|
Packit |
79f644 |
if branch == '..':
|
|
Packit |
79f644 |
children.append(element.parentNode)
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
for x in element.childNodes:
|
|
Packit |
79f644 |
if x.localName == branch:
|
|
Packit |
79f644 |
children.append(x)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
ret = []
|
|
Packit |
79f644 |
# If this is not the last path element, recursively gather results from
|
|
Packit |
79f644 |
# children
|
|
Packit |
79f644 |
if len(branches) > 1:
|
|
Packit |
79f644 |
for x in children:
|
|
Packit |
79f644 |
add = get_by_path(x, '/'.join(branches[1:]))
|
|
Packit |
79f644 |
if isinstance(add, list):
|
|
Packit |
79f644 |
ret += add
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
return add
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
ret = children
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
return ret
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def get_docstring(element):
|
|
Packit |
79f644 |
docstring = None
|
|
Packit |
79f644 |
for x in element.childNodes:
|
|
Packit |
79f644 |
if x.namespaceURI == NS_TP and x.localName == 'docstring':
|
|
Packit |
79f644 |
docstring = x
|
|
Packit |
79f644 |
if docstring is not None:
|
|
Packit |
79f644 |
docstring = docstring.toxml().replace('\n', ' ').strip()
|
|
Packit |
79f644 |
if docstring.startswith('<tp:docstring>'):
|
|
Packit |
79f644 |
docstring = docstring[14:].lstrip()
|
|
Packit |
79f644 |
if docstring.endswith('</tp:docstring>'):
|
|
Packit |
79f644 |
docstring = docstring[:-15].rstrip()
|
|
Packit |
79f644 |
if docstring in ('<tp:docstring/>', ''):
|
|
Packit |
79f644 |
docstring = ''
|
|
Packit |
79f644 |
return docstring
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def get_deprecated(element):
|
|
Packit |
79f644 |
text = []
|
|
Packit |
79f644 |
for x in element.childNodes:
|
|
Packit |
79f644 |
if hasattr(x, 'data'):
|
|
Packit |
79f644 |
text.append(x.data.replace('\n', ' ').strip())
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
# This caters for tp:dbus-ref elements, but little else.
|
|
Packit |
79f644 |
if x.childNodes and hasattr(x.childNodes[0], 'data'):
|
|
Packit |
79f644 |
text.append(x.childNodes[0].data.replace('\n', ' ').strip())
|
|
Packit |
79f644 |
return ' '.join(text)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def get_descendant_text(element_or_elements):
|
|
Packit |
79f644 |
if not element_or_elements:
|
|
Packit |
79f644 |
return ''
|
|
Packit |
79f644 |
if isinstance(element_or_elements, list):
|
|
Packit |
79f644 |
return ''.join(map(get_descendant_text, element_or_elements))
|
|
Packit |
79f644 |
parts = []
|
|
Packit |
79f644 |
for x in element_or_elements.childNodes:
|
|
Packit |
79f644 |
if x.nodeType == x.TEXT_NODE:
|
|
Packit |
79f644 |
parts.append(x.nodeValue)
|
|
Packit |
79f644 |
elif x.nodeType == x.ELEMENT_NODE:
|
|
Packit |
79f644 |
parts.append(get_descendant_text(x))
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
pass
|
|
Packit |
79f644 |
return ''.join(parts)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
class _SignatureIter:
|
|
Packit |
79f644 |
"""Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
|
|
Packit |
79f644 |
can run genginterface in a limited environment with only Python
|
|
Packit |
79f644 |
(like Scratchbox).
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
def __init__(self, string):
|
|
Packit |
79f644 |
self.remaining = string
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def next(self):
|
|
Packit |
79f644 |
return self.__next__()
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def __next__(self):
|
|
Packit |
79f644 |
if self.remaining == '':
|
|
Packit |
79f644 |
raise StopIteration
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
signature = self.remaining
|
|
Packit |
79f644 |
block_depth = 0
|
|
Packit |
79f644 |
block_type = None
|
|
Packit |
79f644 |
end = len(signature)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
for marker in range(0, end):
|
|
Packit |
79f644 |
cur_sig = signature[marker]
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
if cur_sig == 'a':
|
|
Packit |
79f644 |
pass
|
|
Packit |
79f644 |
elif cur_sig == '{' or cur_sig == '(':
|
|
Packit |
79f644 |
if block_type == None:
|
|
Packit |
79f644 |
block_type = cur_sig
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
if block_type == cur_sig:
|
|
Packit |
79f644 |
block_depth = block_depth + 1
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
elif cur_sig == '}':
|
|
Packit |
79f644 |
if block_type == '{':
|
|
Packit |
79f644 |
block_depth = block_depth - 1
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
if block_depth == 0:
|
|
Packit |
79f644 |
end = marker
|
|
Packit |
79f644 |
break
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
elif cur_sig == ')':
|
|
Packit |
79f644 |
if block_type == '(':
|
|
Packit |
79f644 |
block_depth = block_depth - 1
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
if block_depth == 0:
|
|
Packit |
79f644 |
end = marker
|
|
Packit |
79f644 |
break
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
else:
|
|
Packit |
79f644 |
if block_depth == 0:
|
|
Packit |
79f644 |
end = marker
|
|
Packit |
79f644 |
break
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
end = end + 1
|
|
Packit |
79f644 |
self.remaining = signature[end:]
|
|
Packit |
79f644 |
return Signature(signature[0:end])
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
class Signature(str):
|
|
Packit |
79f644 |
"""A string, iteration over which is by D-Bus single complete types
|
|
Packit |
79f644 |
rather than characters.
|
|
Packit |
79f644 |
"""
|
|
Packit |
79f644 |
def __iter__(self):
|
|
Packit |
79f644 |
return _SignatureIter(self)
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
|
|
Packit |
79f644 |
def xml_escape(s):
|
|
Packit |
79f644 |
s = s.replace('&', '&').replace("'", ''').replace('"', '"')
|
|
Packit |
79f644 |
return s.replace('<', '<').replace('>', '>')
|