]> git.0d.be Git - empathy.git/blob - tools/libtpcodegen.py
Updated Swedish translation
[empathy.git] / tools / libtpcodegen.py
1 """Library code for language-independent D-Bus-related code generation.
2
3 The master copy of this library is in the telepathy-glib repository -
4 please make any changes there.
5 """
6
7 # Copyright (C) 2006-2008 Collabora Limited
8 #
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.
13 #
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.
18 #
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
22
23 import os
24 import sys
25 from string import ascii_letters, digits
26
27
28 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
29
30 _ASCII_ALNUM = ascii_letters + digits
31
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')
45
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
55
56     open(filename + '.tmp', 'wb').write(contents)
57     os.rename(filename + '.tmp', filename)
58
59 def cmp_by_name(node1, node2):
60     return cmp(node1.getAttributeNode("name").nodeValue,
61                node2.getAttributeNode("name").nodeValue)
62
63 def key_by_name(node):
64     return node.getAttributeNode("name").nodeValue
65
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.
69
70     The reversible encoding is as follows:
71
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 '_'
80
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
87
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]]
93
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))
100
101     return ''.join(ret)
102
103
104 def get_by_path(element, path):
105     branches = path.split('/')
106     branch = branches[0]
107
108     # Is the current branch an attribute, if so, return the attribute value
109     if branch[0] == '@':
110         return element.getAttribute(branch[1:])
111
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)
120
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
133
134     return ret
135
136
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
151
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)
162
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)
177
178
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).
183     """
184     def __init__(self, string):
185         self.remaining = string
186
187     def next(self):
188         return self.__next__()
189
190     def __next__(self):
191         if self.remaining == '':
192             raise StopIteration
193
194         signature = self.remaining
195         block_depth = 0
196         block_type = None
197         end = len(signature)
198
199         for marker in range(0, end):
200             cur_sig = signature[marker]
201
202             if cur_sig == 'a':
203                 pass
204             elif cur_sig == '{' or cur_sig == '(':
205                 if block_type == None:
206                     block_type = cur_sig
207
208                 if block_type == cur_sig:
209                     block_depth = block_depth + 1
210
211             elif cur_sig == '}':
212                 if block_type == '{':
213                     block_depth = block_depth - 1
214
215                 if block_depth == 0:
216                     end = marker
217                     break
218
219             elif cur_sig == ')':
220                 if block_type == '(':
221                     block_depth = block_depth - 1
222
223                 if block_depth == 0:
224                     end = marker
225                     break
226
227             else:
228                 if block_depth == 0:
229                     end = marker
230                     break
231
232         end = end + 1
233         self.remaining = signature[end:]
234         return Signature(signature[0:end])
235
236
237 class Signature(str):
238     """A string, iteration over which is by D-Bus single complete types
239     rather than characters.
240     """
241     def __iter__(self):
242         return _SignatureIter(self)
243
244
245 def xml_escape(s):
246     s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
247     return s.replace('<', '&lt;').replace('>', '&gt;')