]> git.0d.be Git - empathy.git/blob - tools/libtpcodegen.py
Update Simplified Chinese help 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
24 from string import ascii_letters, digits
25
26
27 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
28
29 _ASCII_ALNUM = ascii_letters + digits
30
31
32 def cmp_by_name(node1, node2):
33     return cmp(node1.getAttributeNode("name").nodeValue,
34                node2.getAttributeNode("name").nodeValue)
35
36
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.
40
41     The reversible encoding is as follows:
42
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
47     """
48     # '' -> '_'
49     if not identifier:
50         return '_'
51
52     # A bit of a fast path for strings which are already OK.
53     # We deliberately omit '_' because, for reversibility, that must also
54     # be escaped.
55     if (identifier.strip(_ASCII_ALNUM) == '' and
56         identifier[0] in ascii_letters):
57         return identifier
58
59     # The first character may not be a digit
60     if identifier[0] not in ascii_letters:
61         ret = ['_%02x' % ord(identifier[0])]
62     else:
63         ret = [identifier[0]]
64
65     # Subsequent characters may be digits or ASCII letters
66     for c in identifier[1:]:
67         if c in _ASCII_ALNUM:
68             ret.append(c)
69         else:
70             ret.append('_%02x' % ord(c))
71
72     return ''.join(ret)
73
74
75 def get_by_path(element, path):
76     branches = path.split('/')
77     branch = branches[0]
78
79     # Is the current branch an attribute, if so, return the attribute value
80     if branch[0] == '@':
81         return element.getAttribute(branch[1:])
82
83     # Find matching children for the branch
84     children = []
85     if branch == '..':
86         children.append(element.parentNode)
87     else:
88         for x in element.childNodes:
89             if x.localName == branch:
90                 children.append(x)
91
92     ret = []
93     # If this is not the last path element, recursively gather results from
94     # children
95     if len(branches) > 1:
96         for x in children:
97             add = get_by_path(x, '/'.join(branches[1:]))
98             if isinstance(add, list):
99                 ret += add
100             else:
101                 return add
102     else:
103         ret = children
104
105     return ret
106
107
108 def get_docstring(element):
109     docstring = None
110     for x in element.childNodes:
111         if x.namespaceURI == NS_TP and x.localName == 'docstring':
112             docstring = x
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/>', ''):
120             docstring = ''
121     return docstring
122
123 def get_deprecated(element):
124     text = []
125     for x in element.childNodes:
126         if hasattr(x, 'data'):
127             text.append(x.data.replace('\n', ' ').strip())
128         else:
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)
133
134 def get_descendant_text(element_or_elements):
135     if not element_or_elements:
136         return ''
137     if isinstance(element_or_elements, list):
138         return ''.join(map(get_descendant_text, element_or_elements))
139     parts = []
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))
145         else:
146             pass
147     return ''.join(parts)
148
149
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
153     (like Scratchbox).
154     """
155     def __init__(self, string):
156         self.remaining = string
157
158     def next(self):
159         if self.remaining == '':
160             raise StopIteration
161
162         signature = self.remaining
163         block_depth = 0
164         block_type = None
165         end = len(signature)
166
167         for marker in range(0, end):
168             cur_sig = signature[marker]
169
170             if cur_sig == 'a':
171                 pass
172             elif cur_sig == '{' or cur_sig == '(':
173                 if block_type == None:
174                     block_type = cur_sig
175
176                 if block_type == cur_sig:
177                     block_depth = block_depth + 1
178
179             elif cur_sig == '}':
180                 if block_type == '{':
181                     block_depth = block_depth - 1
182
183                 if block_depth == 0:
184                     end = marker
185                     break
186
187             elif cur_sig == ')':
188                 if block_type == '(':
189                     block_depth = block_depth - 1
190
191                 if block_depth == 0:
192                     end = marker
193                     break
194
195             else:
196                 if block_depth == 0:
197                     end = marker
198                     break
199
200         end = end + 1
201         self.remaining = signature[end:]
202         return Signature(signature[0:end])
203
204
205 class Signature(str):
206     """A string, iteration over which is by D-Bus single complete types
207     rather than characters.
208     """
209     def __iter__(self):
210         return _SignatureIter(self)
211
212
213 def xml_escape(s):
214     s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
215     return s.replace('<', '&lt;').replace('>', '&gt;')