1 """Library code for language-independent D-Bus-related code generation.
3 The master copy of this library is in the telepathy-glib repository -
4 please make any changes there.
7 # Copyright (C) 2006-2008 Collabora Limited
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 from string import ascii_letters, digits
27 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
29 _ASCII_ALNUM = ascii_letters + digits
32 def cmp_by_name(node1, node2):
33 return cmp(node1.getAttributeNode("name").nodeValue,
34 node2.getAttributeNode("name").nodeValue)
37 def escape_as_identifier(identifier):
38 """Escape the given string to be a valid D-Bus object path or service
39 name component, using a reversible encoding to ensure uniqueness.
41 The reversible encoding is as follows:
43 * The empty string becomes '_'
44 * Otherwise, each non-alphanumeric character is replaced by '_' plus
45 two lower-case hex digits; the same replacement is carried out on
46 the first character, if it's a digit
52 # A bit of a fast path for strings which are already OK.
53 # We deliberately omit '_' because, for reversibility, that must also
55 if (identifier.strip(_ASCII_ALNUM) == '' and
56 identifier[0] in ascii_letters):
59 # The first character may not be a digit
60 if identifier[0] not in ascii_letters:
61 ret = ['_%02x' % ord(identifier[0])]
65 # Subsequent characters may be digits or ASCII letters
66 for c in identifier[1:]:
70 ret.append('_%02x' % ord(c))
75 def get_by_path(element, path):
76 branches = path.split('/')
79 # Is the current branch an attribute, if so, return the attribute value
81 return element.getAttribute(branch[1:])
83 # Find matching children for the branch
86 children.append(element.parentNode)
88 for x in element.childNodes:
89 if x.localName == branch:
93 # If this is not the last path element, recursively gather results from
97 add = get_by_path(x, '/'.join(branches[1:]))
98 if isinstance(add, list):
108 def get_docstring(element):
110 for x in element.childNodes:
111 if x.namespaceURI == NS_TP and x.localName == 'docstring':
113 if docstring is not None:
114 docstring = docstring.toxml().replace('\n', ' ').strip()
115 if docstring.startswith('<tp:docstring>'):
116 docstring = docstring[14:].lstrip()
117 if docstring.endswith('</tp:docstring>'):
118 docstring = docstring[:-15].rstrip()
119 if docstring in ('<tp:docstring/>', ''):
123 def get_deprecated(element):
125 for x in element.childNodes:
126 if hasattr(x, 'data'):
127 text.append(x.data.replace('\n', ' ').strip())
129 # This caters for tp:dbus-ref elements, but little else.
130 if x.childNodes and hasattr(x.childNodes[0], 'data'):
131 text.append(x.childNodes[0].data.replace('\n', ' ').strip())
132 return ' '.join(text)
134 def get_descendant_text(element_or_elements):
135 if not element_or_elements:
137 if isinstance(element_or_elements, list):
138 return ''.join(map(get_descendant_text, element_or_elements))
140 for x in element_or_elements.childNodes:
141 if x.nodeType == x.TEXT_NODE:
142 parts.append(x.nodeValue)
143 elif x.nodeType == x.ELEMENT_NODE:
144 parts.append(get_descendant_text(x))
147 return ''.join(parts)
150 class _SignatureIter:
151 """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
152 can run genginterface in a limited environment with only Python
155 def __init__(self, string):
156 self.remaining = string
159 if self.remaining == '':
162 signature = self.remaining
167 for marker in range(0, end):
168 cur_sig = signature[marker]
172 elif cur_sig == '{' or cur_sig == '(':
173 if block_type == None:
176 if block_type == cur_sig:
177 block_depth = block_depth + 1
180 if block_type == '{':
181 block_depth = block_depth - 1
188 if block_type == '(':
189 block_depth = block_depth - 1
201 self.remaining = signature[end:]
202 return Signature(signature[0:end])
205 class Signature(str):
206 """A string, iteration over which is by D-Bus single complete types
207 rather than characters.
210 return _SignatureIter(self)
214 s = s.replace('&', '&').replace("'", ''').replace('"', '"')
215 return s.replace('<', '<').replace('>', '>')