Updated Indonesian translation
[empathy-mirror.git] / tools / libtpcodegen.py
blob99de66340d780e05a0fd887c11df65eff0050423
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.
5 """
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
23 import os
24 import sys
25 from string import ascii_letters, digits
28 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
30 _ASCII_ALNUM = ascii_letters + digits
32 if sys.version_info[0] >= 3:
33 def u(s):
34 """Return s, which must be a str literal with no non-ASCII characters.
35 This is like a more restricted form of the Python 2 u'' syntax.
36 """
37 return s.encode('ascii').decode('ascii')
38 else:
39 def u(s):
40 """Return a Unicode version of s, which must be a str literal
41 (a bytestring) in which each byte is an ASCII character.
42 This is like a more restricted form of the u'' syntax.
43 """
44 return s.decode('ascii')
46 def file_set_contents(filename, contents):
47 try:
48 os.remove(filename)
49 except OSError:
50 pass
51 try:
52 os.remove(filename + '.tmp')
53 except OSError:
54 pass
56 open(filename + '.tmp', 'wb').write(contents)
57 os.rename(filename + '.tmp', filename)
59 def cmp_by_name(node1, node2):
60 return cmp(node1.getAttributeNode("name").nodeValue,
61 node2.getAttributeNode("name").nodeValue)
63 def key_by_name(node):
64 return node.getAttributeNode("name").nodeValue
66 def escape_as_identifier(identifier):
67 """Escape the given string to be a valid D-Bus object path or service
68 name component, using a reversible encoding to ensure uniqueness.
70 The reversible encoding is as follows:
72 * The empty string becomes '_'
73 * Otherwise, each non-alphanumeric character is replaced by '_' plus
74 two lower-case hex digits; the same replacement is carried out on
75 the first character, if it's a digit
76 """
77 # '' -> '_'
78 if not identifier:
79 return '_'
81 # A bit of a fast path for strings which are already OK.
82 # We deliberately omit '_' because, for reversibility, that must also
83 # be escaped.
84 if (identifier.strip(_ASCII_ALNUM) == '' and
85 identifier[0] in ascii_letters):
86 return identifier
88 # The first character may not be a digit
89 if identifier[0] not in ascii_letters:
90 ret = ['_%02x' % ord(identifier[0])]
91 else:
92 ret = [identifier[0]]
94 # Subsequent characters may be digits or ASCII letters
95 for c in identifier[1:]:
96 if c in _ASCII_ALNUM:
97 ret.append(c)
98 else:
99 ret.append('_%02x' % ord(c))
101 return ''.join(ret)
104 def get_by_path(element, path):
105 branches = path.split('/')
106 branch = branches[0]
108 # Is the current branch an attribute, if so, return the attribute value
109 if branch[0] == '@':
110 return element.getAttribute(branch[1:])
112 # Find matching children for the branch
113 children = []
114 if branch == '..':
115 children.append(element.parentNode)
116 else:
117 for x in element.childNodes:
118 if x.localName == branch:
119 children.append(x)
121 ret = []
122 # If this is not the last path element, recursively gather results from
123 # children
124 if len(branches) > 1:
125 for x in children:
126 add = get_by_path(x, '/'.join(branches[1:]))
127 if isinstance(add, list):
128 ret += add
129 else:
130 return add
131 else:
132 ret = children
134 return ret
137 def get_docstring(element):
138 docstring = None
139 for x in element.childNodes:
140 if x.namespaceURI == NS_TP and x.localName == 'docstring':
141 docstring = x
142 if docstring is not None:
143 docstring = docstring.toxml().replace('\n', ' ').strip()
144 if docstring.startswith('<tp:docstring>'):
145 docstring = docstring[14:].lstrip()
146 if docstring.endswith('</tp:docstring>'):
147 docstring = docstring[:-15].rstrip()
148 if docstring in ('<tp:docstring/>', ''):
149 docstring = ''
150 return docstring
152 def get_deprecated(element):
153 text = []
154 for x in element.childNodes:
155 if hasattr(x, 'data'):
156 text.append(x.data.replace('\n', ' ').strip())
157 else:
158 # This caters for tp:dbus-ref elements, but little else.
159 if x.childNodes and hasattr(x.childNodes[0], 'data'):
160 text.append(x.childNodes[0].data.replace('\n', ' ').strip())
161 return ' '.join(text)
163 def get_descendant_text(element_or_elements):
164 if not element_or_elements:
165 return ''
166 if isinstance(element_or_elements, list):
167 return ''.join(map(get_descendant_text, element_or_elements))
168 parts = []
169 for x in element_or_elements.childNodes:
170 if x.nodeType == x.TEXT_NODE:
171 parts.append(x.nodeValue)
172 elif x.nodeType == x.ELEMENT_NODE:
173 parts.append(get_descendant_text(x))
174 else:
175 pass
176 return ''.join(parts)
179 class _SignatureIter:
180 """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
181 can run genginterface in a limited environment with only Python
182 (like Scratchbox).
184 def __init__(self, string):
185 self.remaining = string
187 def next(self):
188 return self.__next__()
190 def __next__(self):
191 if self.remaining == '':
192 raise StopIteration
194 signature = self.remaining
195 block_depth = 0
196 block_type = None
197 end = len(signature)
199 for marker in range(0, end):
200 cur_sig = signature[marker]
202 if cur_sig == 'a':
203 pass
204 elif cur_sig == '{' or cur_sig == '(':
205 if block_type == None:
206 block_type = cur_sig
208 if block_type == cur_sig:
209 block_depth = block_depth + 1
211 elif cur_sig == '}':
212 if block_type == '{':
213 block_depth = block_depth - 1
215 if block_depth == 0:
216 end = marker
217 break
219 elif cur_sig == ')':
220 if block_type == '(':
221 block_depth = block_depth - 1
223 if block_depth == 0:
224 end = marker
225 break
227 else:
228 if block_depth == 0:
229 end = marker
230 break
232 end = end + 1
233 self.remaining = signature[end:]
234 return Signature(signature[0:end])
237 class Signature(str):
238 """A string, iteration over which is by D-Bus single complete types
239 rather than characters.
241 def __iter__(self):
242 return _SignatureIter(self)
245 def xml_escape(s):
246 s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
247 return s.replace('<', '&lt;').replace('>', '&gt;')