1 """Library code for GLib/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, 2007 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):
38 for i in range(1,len(s)):
41 if (i+1) < len(s) and s[i+1].islower():
42 out += "_" + s[i].lower()
46 out += "_" + s[i].lower()
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 dbus_gutils_wincaps_to_uscore(s):
64 """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
65 which gets sequences of capital letters wrong in the same way.
66 (e.g. in Telepathy, SendDTMF -> send_dt_mf)
70 if c >= 'A' and c <= 'Z':
72 if length > 0 and (length < 2 or ret[length-2] != '_'):
80 def escape_as_identifier(identifier):
81 """Escape the given string to be a valid D-Bus object path or service
82 name component, using a reversible encoding to ensure uniqueness.
84 The reversible encoding is as follows:
86 * The empty string becomes '_'
87 * Otherwise, each non-alphanumeric character is replaced by '_' plus
88 two lower-case hex digits; the same replacement is carried out on
89 the first character, if it's a digit
95 # A bit of a fast path for strings which are already OK.
96 # We deliberately omit '_' because, for reversibility, that must also
98 if (identifier.strip(_ASCII_ALNUM) == '' and
99 identifier[0] in ascii_letters):
102 # The first character may not be a digit
103 if identifier[0] not in ascii_letters:
104 ret = ['_%02x' % ord(identifier[0])]
106 ret = [identifier[0]]
108 # Subsequent characters may be digits or ASCII letters
109 for c in identifier[1:]:
110 if c in _ASCII_ALNUM:
113 ret.append('_%02x' % ord(c))
118 def get_docstring(element):
120 for x in element.childNodes:
121 if x.namespaceURI == NS_TP and x.localName == 'docstring':
123 if docstring is not None:
124 docstring = docstring.toxml().replace('\n', ' ').strip()
125 if docstring.startswith('<tp:docstring>'):
126 docstring = docstring[14:].lstrip()
127 if docstring.endswith('</tp:docstring>'):
128 docstring = docstring[:-15].rstrip()
129 if docstring in ('<tp:docstring/>', ''):
134 def signal_to_marshal_type(signal):
136 return a list of strings indicating the marshalling type for this signal.
140 for i in signal.getElementsByTagName("arg"):
141 name =i.getAttribute("name")
142 type = i.getAttribute("type")
143 mtype.append(type_to_gtype(type)[2])
148 _glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT',
149 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT',
150 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT',
154 def signal_to_marshal_name(signal, prefix):
156 mtype = signal_to_marshal_type(signal)
158 name = '_'.join(mtype)
162 if name in _glib_marshallers:
163 return 'g_cclosure_marshal_VOID__' + name
165 return prefix + '_marshal_VOID__' + name
168 def method_to_glue_marshal_name(method, prefix):
171 for i in method.getElementsByTagName("arg"):
172 if i.getAttribute("direction") != "out":
173 type = i.getAttribute("type")
174 mtype.append(type_to_gtype(type)[2])
176 mtype.append('POINTER')
178 name = '_'.join(mtype)
180 if name in _glib_marshallers:
181 return 'g_cclosure_marshal_VOID__' + name
183 return prefix + '_marshal_VOID__' + name
186 class _SignatureIter:
187 """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
188 can run genginterface in a limited environment with only Python
191 def __init__(self, string):
192 self.remaining = string
195 if self.remaining == '':
198 signature = self.remaining
203 for marker in range(0, end):
204 cur_sig = signature[marker]
208 elif cur_sig == '{' or cur_sig == '(':
209 if block_type == None:
212 if block_type == cur_sig:
213 block_depth = block_depth + 1
216 if block_type == '{':
217 block_depth = block_depth - 1
224 if block_type == '(':
225 block_depth = block_depth - 1
237 self.remaining = signature[end:]
238 return Signature(signature[0:end])
241 class Signature(str):
242 """A string, iteration over which is by D-Bus single complete types
243 rather than characters.
246 return _SignatureIter(self)
249 def type_to_gtype(s):
251 return ("guchar ", "G_TYPE_UCHAR","UCHAR", False)
252 elif s == 'b': #boolean
253 return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False)
254 elif s == 'n': #int16
255 return ("gint ", "G_TYPE_INT","INT", False)
256 elif s == 'q': #uint16
257 return ("guint ", "G_TYPE_UINT","UINT", False)
258 elif s == 'i': #int32
259 return ("gint ", "G_TYPE_INT","INT", False)
260 elif s == 'u': #uint32
261 return ("guint ", "G_TYPE_UINT","UINT", False)
262 elif s == 'x': #int64
263 return ("gint64 ", "G_TYPE_INT64","INT64", False)
264 elif s == 't': #uint64
265 return ("guint64 ", "G_TYPE_UINT64","UINT64", False)
266 elif s == 'd': #double
267 return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False)
268 elif s == 's': #string
269 return ("gchar *", "G_TYPE_STRING", "STRING", True)
270 elif s == 'g': #signature - FIXME
271 return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True)
272 elif s == 'o': #object path
273 return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True)
274 elif s == 'v': #variant
275 return ("GValue *", "G_TYPE_VALUE", "BOXED", True)
276 elif s == 'as': #array of strings
277 return ("gchar **", "G_TYPE_STRV", "BOXED", True)
278 elif s == 'ay': #byte array
280 "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED",
282 elif s == 'au': #uint array
283 return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True)
284 elif s == 'ai': #int array
285 return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True)
286 elif s == 'ax': #int64 array
287 return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True)
288 elif s == 'at': #uint64 array
289 return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True)
290 elif s == 'ad': #double array
291 return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True)
292 elif s == 'ab': #boolean array
293 return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True)
294 elif s == 'ao': #object path array
295 return ("GArray *", "DBUS_TYPE_G_OBJECT_ARRAY", "BOXED", True)
296 elif s == 'a{ss}': #hash table of string to string
297 return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False)
298 elif s[:2] == 'a{': #some arbitrary hash tables
299 if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'):
300 raise Exception, "can't index a hashtable off non-basic type " + s
301 first = type_to_gtype(s[2])
302 second = type_to_gtype(s[3:-1])
303 return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False)
304 elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse
305 gtype = type_to_gtype(s[1:])[1]
306 return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True)
307 elif s[:1] == '(': #struct
308 gtype = "(dbus_g_type_get_struct (\"GValueArray\", "
309 for subsig in Signature(s[1:-1]):
310 gtype = gtype + type_to_gtype(subsig)[1] + ", "
311 gtype = gtype + "G_TYPE_INVALID))"
312 return ("GValueArray *", gtype, "BOXED", True)
314 # we just don't know ..
315 raise Exception, "don't know the GType for " + s
319 s = s.replace('&', '&').replace("'", ''').replace('"', '"')
320 return s.replace('<', '<').replace('>', '>')