We should display the avatar/preview when call is disconnected
[empathy-mirror.git] / tools / libtpcodegen.py
blob6391f1a48e5de6ee649433946c9d96fc3f5b967e
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
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 camelcase_to_lower(s):
33 out ="";
34 out += s[0].lower()
35 last_upper=False
36 if s[0].isupper():
37 last_upper=True
38 for i in range(1,len(s)):
39 if s[i].isupper():
40 if last_upper:
41 if (i+1) < len(s) and s[i+1].islower():
42 out += "_" + s[i].lower()
43 else:
44 out += s[i].lower()
45 else:
46 out += "_" + s[i].lower()
47 last_upper=True
48 else:
49 out += s[i]
50 last_upper=False
51 return out
54 def camelcase_to_upper(s):
55 return camelcase_to_lower(s).upper()
58 def cmp_by_name(node1, node2):
59 return cmp(node1.getAttributeNode("name").nodeValue,
60 node2.getAttributeNode("name").nodeValue)
63 def escape_as_identifier(identifier):
64 """Escape the given string to be a valid D-Bus object path or service
65 name component, using a reversible encoding to ensure uniqueness.
67 The reversible encoding is as follows:
69 * The empty string becomes '_'
70 * Otherwise, each non-alphanumeric character is replaced by '_' plus
71 two lower-case hex digits; the same replacement is carried out on
72 the first character, if it's a digit
73 """
74 # '' -> '_'
75 if not identifier:
76 return '_'
78 # A bit of a fast path for strings which are already OK.
79 # We deliberately omit '_' because, for reversibility, that must also
80 # be escaped.
81 if (identifier.strip(_ASCII_ALNUM) == '' and
82 identifier[0] in ascii_letters):
83 return identifier
85 # The first character may not be a digit
86 if identifier[0] not in ascii_letters:
87 ret = ['_%02x' % ord(identifier[0])]
88 else:
89 ret = [identifier[0]]
91 # Subsequent characters may be digits or ASCII letters
92 for c in identifier[1:]:
93 if c in _ASCII_ALNUM:
94 ret.append(c)
95 else:
96 ret.append('_%02x' % ord(c))
98 return ''.join(ret)
101 def get_by_path(element, path):
102 branches = path.split('/')
103 branch = branches[0]
105 # Is the current branch an attribute, if so, return the attribute value
106 if branch[0] == '@':
107 return element.getAttribute(branch[1:])
109 # Find matching children for the branch
110 children = []
111 if branch == '..':
112 children.append(element.parentNode)
113 else:
114 for x in element.childNodes:
115 if x.localName == branch:
116 children.append(x)
118 ret = []
119 # If this is not the last path element, recursively gather results from
120 # children
121 if len(branches) > 1:
122 for x in children:
123 add = get_by_path(x, '/'.join(branches[1:]))
124 if isinstance(add, list):
125 ret += add
126 else:
127 return add
128 else:
129 ret = children
131 return ret
134 def get_docstring(element):
135 docstring = None
136 for x in element.childNodes:
137 if x.namespaceURI == NS_TP and x.localName == 'docstring':
138 docstring = x
139 if docstring is not None:
140 docstring = docstring.toxml().replace('\n', ' ').strip()
141 if docstring.startswith('<tp:docstring>'):
142 docstring = docstring[14:].lstrip()
143 if docstring.endswith('</tp:docstring>'):
144 docstring = docstring[:-15].rstrip()
145 if docstring in ('<tp:docstring/>', ''):
146 docstring = ''
147 return docstring
150 def get_descendant_text(element_or_elements):
151 if not element_or_elements:
152 return ''
153 if isinstance(element_or_elements, list):
154 return ''.join(map(get_descendant_text, element_or_elements))
155 parts = []
156 for x in element_or_elements.childNodes:
157 if x.nodeType == x.TEXT_NODE:
158 parts.append(x.nodeValue)
159 elif x.nodeType == x.ELEMENT_NODE:
160 parts.append(get_descendant_text(x))
161 else:
162 pass
163 return ''.join(parts)
166 class _SignatureIter:
167 """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
168 can run genginterface in a limited environment with only Python
169 (like Scratchbox).
171 def __init__(self, string):
172 self.remaining = string
174 def next(self):
175 if self.remaining == '':
176 raise StopIteration
178 signature = self.remaining
179 block_depth = 0
180 block_type = None
181 end = len(signature)
183 for marker in range(0, end):
184 cur_sig = signature[marker]
186 if cur_sig == 'a':
187 pass
188 elif cur_sig == '{' or cur_sig == '(':
189 if block_type == None:
190 block_type = cur_sig
192 if block_type == cur_sig:
193 block_depth = block_depth + 1
195 elif cur_sig == '}':
196 if block_type == '{':
197 block_depth = block_depth - 1
199 if block_depth == 0:
200 end = marker
201 break
203 elif cur_sig == ')':
204 if block_type == '(':
205 block_depth = block_depth - 1
207 if block_depth == 0:
208 end = marker
209 break
211 else:
212 if block_depth == 0:
213 end = marker
214 break
216 end = end + 1
217 self.remaining = signature[end:]
218 return Signature(signature[0:end])
221 class Signature(str):
222 """A string, iteration over which is by D-Bus single complete types
223 rather than characters.
225 def __iter__(self):
226 return _SignatureIter(self)
229 def xml_escape(s):
230 s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
231 return s.replace('<', '&lt;').replace('>', '&gt;')