5 # types translated into "int"
6 simpletypes
= ["int", "gint", "guint", "gboolean", "size_t", "gssize", "time_t"]
8 # List "excluded" contains functions that shouldn't be exported via
9 # DBus. If you remove a function from this list, please make sure
10 # that it does not break "make" with the configure option
11 # "--enable-dbus" turned on.
14 # I don't remember why this function is excluded; something to do
15 # with the fact that it takes a (const) GList as a parameter.
16 "purple_presence_add_list",
18 # These functions are excluded because they involve value of the
19 # type PurpleConvPlacementFunc, which is a pointer to a function and
20 # (currently?) can't be translated into a DBus type. Normally,
21 # functions with untranslatable types are skipped, but this script
22 # assumes that all non-pointer type names beginning with "Purple"
23 # are enums, which is not true in this case.
24 "purple_conv_placement_add_fnc",
25 "purple_conv_placement_get_fnc",
26 "purple_conv_placement_get_current_func",
27 "purple_conv_placement_set_current_func",
29 # Similar to the above:
30 "purple_account_set_register_callback",
31 "purple_account_unregister",
32 "purple_connection_new_unregister",
34 # These functions are excluded because they involve setting arbitrary
35 # data via pointers for protocols and UIs. This just won't work.
36 "purple_blist_get_ui_data",
37 "purple_blist_set_ui_data",
38 "purple_blist_node_get_ui_data",
39 "purple_blist_node_set_ui_data",
40 "purple_buddy_get_protocol_data",
41 "purple_buddy_set_protocol_data",
43 # This is excluded because this script treats PurpleLogReadFlags*
44 # as pointer to a struct, instead of a pointer to an enum. This
45 # causes a compilation error. Someone should fix this script.
49 # This is a list of functions that return a GList* or GSList * whose elements
50 # are strings, not pointers to objects.
52 "purple_prefs_get_path_list",
53 "purple_prefs_get_string_list",
54 "purple_uri_list_extract_filenames",
55 "purple_uri_list_extract_uris",
56 "purple_prefs_get_children_names",
59 # This is a list of functions that return a GList* or GSList* that should
60 # not be freed. Ideally, this information should be obtained from the Doxygen
61 # documentation at some point.
63 "purple_account_get_status_types",
64 "purple_accounts_get_all",
65 "purple_account_option_get_list",
66 "purple_connections_get_all",
67 "purple_connections_get_connecting",
68 "purple_get_conversations",
71 "purple_conv_chat_get_users",
72 "purple_conv_chat_get_ignored",
73 "purple_mime_document_get_fields",
74 "purple_mime_document_get_parts",
75 "purple_mime_part_get_fields",
76 "purple_notify_user_info_get_entries",
77 "purple_request_fields_get_required",
78 "purple_request_field_list_get_selected",
79 "purple_request_field_list_get_items",
80 "purple_savedstatuses_get_all",
81 "purple_status_type_get_attrs",
82 "purple_presence_get_statuses",
83 "purple_conversation_get_message_history",
88 class MyException(Exception):
91 myexception
= MyException()
95 for word
in name
.split("_"):
96 newname
+= word
.capitalize()
100 def __init__(self
, type, name
):
104 def fromtokens(tokens
, parameternumber
= -1):
107 if (len(tokens
) == 1) or (tokens
[-1] == pointer
):
108 if parameternumber
>= 0:
109 return Parameter(tokens
, "param%i" % parameternumber
)
113 return Parameter(tokens
[:-1], tokens
[-1])
115 fromtokens
= staticmethod(fromtokens
)
118 def __init__(self
, functiontext
, paramtexts
):
119 self
.function
= Parameter
.fromtokens(functiontext
.split())
121 if self
.function
.name
in excluded
:
125 for i
in range(len(paramtexts
)):
126 self
.params
.append(Parameter
.fromtokens(paramtexts
[i
].split(), i
))
128 self
.call
= "%s(%s)" % (self
.function
.name
,
129 ", ".join(param
.name
for param
in self
.params
))
133 for param
in self
.params
:
134 self
.processinput(param
.type, param
.name
)
136 self
.processoutput(self
.function
.type, "RESULT")
140 def processinput(self
, type, name
):
143 if type[0] == "const":
147 if type[0] == "unsigned":
152 # simple types (int, gboolean, etc.) and enums
153 if (type[0] in simpletypes
) or ((type[0].startswith("Purple") and not type[0].endswith("Callback"))):
154 return self
.inputsimple(type, name
, unsigned
)
157 if (len(type) == 2) and (type[1] == pointer
):
159 if type[0] in ["char", "gchar"]:
161 return self
.inputstring(type, name
, unsigned
)
165 elif type[0] == "GHashTable":
166 return self
.inputhash(type, name
)
168 # known object types are transformed to integer handles
169 elif type[0].startswith("Purple") or type[0] == "xmlnode":
170 return self
.inputpurplestructure(type, name
)
172 # special case for *_get_data functions, be careful here...
173 elif (type[0] == "size_t" or type[0] == "gsize") and name
== "len":
174 return self
.inputgetdata(type, name
)
176 # unknown pointers are always replaced with NULL
178 return self
.inputpointer(type, name
)
183 def processoutput(self
, type, name
):
186 # the "void" type is simple ...
188 return self
.outputvoid(type, name
)
190 if type[0] == "const":
194 if type[0] == "unsigned":
199 if type == ["char", pointer
] or type == ["gchar", pointer
]:
200 return self
.outputstring(type, name
, const
)
202 # simple types (ints, booleans, enums, ...)
203 if (len(type) == 1) and \
204 ((type[0] in simpletypes
) or (type[0].startswith("Purple"))):
205 return self
.outputsimple(type, name
, unsigned
)
208 if (len(type) == 2) and (type[1] == pointer
):
211 if type[0].startswith("Purple"):
212 return self
.outputpurplestructure(type, name
)
214 if type[0] in ["GList", "GSList"]:
215 return self
.outputlist(type, name
)
217 # Special case for *_get_data functions
218 if type[0] == "gconstpointer":
219 return self
.outputgetdata(type, name
)
224 class ClientBinding (Binding
):
225 def __init__(self
, functiontext
, paramtexts
, knowntypes
, headersonly
):
226 Binding
.__init
__(self
, functiontext
, paramtexts
)
227 self
.knowntypes
= knowntypes
228 self
.headersonly
= headersonly
231 self
.inputparams
= []
232 self
.outputparams
= []
236 paramslist
= ", ".join(self
.paramshdr
)
237 if (paramslist
== "") :
239 print "%s %s(%s)" % (self
.functiontype
, self
.function
.name
,
248 for decl
in self
.decls
:
251 print 'dbus_g_proxy_call(purple_proxy, "%s", NULL,' % ctopascal(self
.function
.name
)
253 for type_name
in self
.inputparams
:
254 print "\t%s, %s, " % type_name
,
255 print "G_TYPE_INVALID,"
257 for type_name
in self
.outputparams
:
258 print "\t%s, &%s, " % type_name
,
259 print "G_TYPE_INVALID);"
261 for code
in self
.returncode
:
267 def definepurplestructure(self
, type):
268 if (self
.headersonly
) and (type[0] not in self
.knowntypes
):
269 print "struct _%s;" % type[0]
270 print "typedef struct _%s %s;" % (type[0], type[0])
271 self
.knowntypes
.append(type[0])
273 def inputsimple(self
, type, name
, us
):
274 self
.paramshdr
.append("%s %s" % (type[0], name
))
276 self
.inputparams
.append(("G_TYPE_UINT", name
))
278 self
.inputparams
.append(("G_TYPE_INT", name
))
280 def inputstring(self
, type, name
, us
):
282 self
.paramshdr
.append("const unsigned char *%s" % name
)
284 self
.paramshdr
.append("const char *%s" % name
)
285 self
.inputparams
.append(("G_TYPE_STRING", name
))
287 def inputpurplestructure(self
, type, name
):
288 self
.paramshdr
.append("const %s *%s" % (type[0], name
))
289 self
.inputparams
.append(("G_TYPE_INT", "GPOINTER_TO_INT(%s)" % name
))
290 self
.definepurplestructure(type)
292 def inputpointer(self
, type, name
):
294 self
.paramshdr
.append("const %s *%s" % (type[0], name
))
295 self
.inputparams
.append(("G_TYPE_INT", "0"))
297 def inputhash(self
, type, name
):
298 self
.paramshdr
.append("const GHashTable *%s" % name
)
299 self
.inputparams
.append(('dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)', name
))
301 def outputvoid(self
, type, name
):
302 self
.functiontype
= "void"
304 def outputstring(self
, type, name
, const
):
305 self
.functiontype
= "char*"
306 self
.decls
.append("char *%s = NULL;" % name
)
307 self
.outputparams
.append(("G_TYPE_STRING", name
))
308 # self.returncode.append("NULLIFY(%s);" % name)
309 self
.returncode
.append("return %s;" % name
);
311 def outputsimple(self
, type, name
, us
):
312 self
.functiontype
= type[0]
313 self
.decls
.append("%s %s = 0;" % (type[0], name
))
315 self
.outputparams
.append(("G_TYPE_UINT", name
))
317 self
.outputparams
.append(("G_TYPE_INT", name
))
318 self
.returncode
.append("return %s;" % name
);
320 # we could add "const" to the return type but this would probably
322 def outputpurplestructure(self
, type, name
):
324 self
.functiontype
= "%s*" % type[0]
325 self
.decls
.append("int %s = 0;" % name
)
326 self
.outputparams
.append(("G_TYPE_INT", "%s" % name
))
327 self
.returncode
.append("return (%s*) GINT_TO_POINTER(%s);" % (type[0], name
));
328 self
.definepurplestructure(type)
330 def outputlist(self
, type, name
):
331 self
.functiontype
= "%s*" % type[0]
332 self
.decls
.append("GArray *%s;" % name
)
333 self
.outputparams
.append(('dbus_g_type_get_collection("GArray", G_TYPE_INT)', name
))
334 self
.returncode
.append("return garray_int_to_%s(%s);" %
335 (type[0].lower(), name
));
337 # Special case for *_get_data functions, don't need client bindings,
338 # but do need the name so it doesn't crash
339 def inputgetdata(self
, type, name
):
341 def outputgetdata(self
, type, name
):
344 class ServerBinding (Binding
):
345 def __init__(self
, functiontext
, paramtexts
):
346 Binding
.__init
__(self
, functiontext
, paramtexts
)
353 self
.argfunc
= "dbus_message_get_args"
356 print "static DBusMessage*"
357 print "%s_DBUS(DBusMessage *message_DBUS, DBusError *error_DBUS) {" % \
360 print "\tDBusMessage *reply_DBUS;"
362 for decl
in self
.cdecls
:
365 print "\t%s(message_DBUS, error_DBUS," % self
.argfunc
,
366 for param
in self
.cparams
:
367 print "DBUS_TYPE_%s, &%s," % param
,
368 print "DBUS_TYPE_INVALID);"
370 print "\tCHECK_ERROR(error_DBUS);"
372 for code
in self
.ccode
:
375 print "\treply_DBUS = dbus_message_new_method_return (message_DBUS);"
377 print "\tdbus_message_append_args(reply_DBUS,",
378 for param
in self
.cparamsout
:
379 if type(param
) is str:
382 print "DBUS_TYPE_%s, &%s," % param
,
383 print "DBUS_TYPE_INVALID);"
385 for code
in self
.ccodeout
:
388 print "\treturn reply_DBUS;\n}\n"
391 def addstring(self
, *items
):
393 self
.dparams
+= item
+ r
"\0"
395 def addintype(self
, type, name
):
396 self
.addstring("in", type, name
)
398 def addouttype(self
, type, name
):
399 self
.addstring("out", type, name
)
404 def inputsimple(self
, type, name
, us
):
406 self
.cdecls
.append("\tdbus_uint32_t %s;" % name
)
407 self
.cparams
.append(("UINT32", name
))
408 self
.addintype("u", name
)
410 self
.cdecls
.append("\tdbus_int32_t %s;" % name
)
411 self
.cparams
.append(("INT32", name
))
412 self
.addintype("i", name
)
414 def inputstring(self
, type, name
, us
):
416 self
.cdecls
.append("\tconst unsigned char *%s;" % name
)
418 self
.cdecls
.append("\tconst char *%s;" % name
)
419 self
.cparams
.append(("STRING", name
))
420 self
.ccode
.append("\t%s = (%s && %s[0]) ? %s : NULL;" % (name
,name
,name
,name
))
421 self
.addintype("s", name
)
423 def inputhash(self
, type, name
):
424 self
.argfunc
= "purple_dbus_message_get_args"
425 self
.cdecls
.append("\tDBusMessageIter %s_ITER;" % name
)
426 self
.cdecls
.append("\tGHashTable *%s;" % name
)
427 self
.cparams
.append(("ARRAY", "%s_ITER" % name
))
428 self
.ccode
.append("\t%s = purple_dbus_iter_hash_table(&%s_ITER, error_DBUS);" \
430 self
.ccode
.append("\tCHECK_ERROR(error_DBUS);")
431 self
.ccodeout
.append("\tg_hash_table_destroy(%s);" % name
)
432 self
.addintype("a{ss}", name
)
434 def inputpurplestructure(self
, type, name
):
435 self
.cdecls
.append("\tdbus_int32_t %s_ID;" % name
)
436 self
.cdecls
.append("\t%s *%s;" % (type[0], name
))
437 self
.cparams
.append(("INT32", name
+ "_ID"))
438 self
.ccode
.append("\tPURPLE_DBUS_ID_TO_POINTER(%s, %s_ID, %s, error_DBUS);" % \
439 (name
, name
, type[0]))
440 self
.addintype("i", name
)
442 def inputpointer(self
, type, name
):
443 self
.cdecls
.append("\tdbus_int32_t %s_NULL;" % name
)
444 self
.cdecls
.append("\t%s *%s;" % (type[0], name
))
445 self
.cparams
.append(("INT32", name
+ "_NULL"))
446 self
.ccode
.append("\t%s = NULL;" % name
)
447 self
.addintype("i", name
)
451 def outputvoid(self
, type, name
):
452 self
.ccode
.append("\t%s;" % self
.call
) # just call the function
454 def outputstring(self
, type, name
, const
):
456 self
.cdecls
.append("\tconst char *%s;" % name
)
458 self
.cdecls
.append("\tchar *%s;" % name
)
459 self
.ccode
.append("\tif ((%s = %s) == NULL)" % (name
, self
.call
))
460 self
.ccode
.append("\t\t%s = \"\";" % (name
))
461 self
.cparamsout
.append(("STRING", name
))
462 self
.addouttype("s", name
)
464 self
.ccodeout
.append("\tg_free(%s);" % name
)
466 def outputsimple(self
, type, name
, us
):
468 self
.cdecls
.append("\tdbus_uint32_t %s;" % name
)
469 self
.cparamsout
.append(("UINT32", name
))
470 self
.addouttype("u", name
)
472 self
.cdecls
.append("\tdbus_int32_t %s;" % name
)
473 self
.cparamsout
.append(("INT32", name
))
474 self
.addouttype("i", name
)
475 self
.ccode
.append("\t%s = %s;" % (name
, self
.call
))
477 def outputpurplestructure(self
, type, name
):
478 self
.cdecls
.append("\tdbus_int32_t %s;" % name
)
479 self
.ccode
.append("\tPURPLE_DBUS_POINTER_TO_ID(%s, %s, error_DBUS);" % (name
, self
.call
))
480 self
.cparamsout
.append(("INT32", name
))
481 self
.addouttype("i", name
)
483 # GList*, GSList*, assume that list is a list of objects
484 # unless the function is in stringlists
485 def outputlist(self
, type, name
):
486 self
.cdecls
.append("\tdbus_int32_t %s_LEN;" % name
)
487 self
.ccodeout
.append("\tg_free(%s);" % name
)
489 self
.cdecls
.append("\t%s *list;" % type[0]);
491 if self
.function
.name
in stringlists
:
492 self
.cdecls
.append("\tchar **%s;" % name
)
493 self
.ccode
.append("\tlist = %s;" % self
.call
)
494 self
.ccode
.append("\t%s = (char **)purple_%s_to_array(list, FALSE, &%s_LEN);" % \
495 (name
, type[0], name
))
496 self
.cparamsout
.append("DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &%s, %s_LEN" \
498 if (not (self
.function
.name
in constlists
)):
499 type_name
= type[0].lower()[1:]
500 self
.ccodeout
.append("\tg_%s_foreach(list, (GFunc)g_free, NULL);" % type_name
)
501 self
.ccodeout
.append("\tg_%s_free(list);" % type_name
)
502 self
.addouttype("as", name
)
504 self
.cdecls
.append("\tdbus_int32_t *%s;" % name
)
505 self
.ccode
.append("\tlist = %s;" % self
.call
)
506 self
.ccode
.append("\t%s = purple_dbusify_%s(list, FALSE, &%s_LEN);" % \
507 (name
, type[0], name
))
508 if (not (self
.function
.name
in constlists
)):
509 self
.ccode
.append("\tg_%s_free(list);" % type[0].lower()[1:])
510 self
.cparamsout
.append("DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &%s, %s_LEN" \
512 self
.addouttype("ai", name
)
514 # Special case for *_get_data functions
515 def inputgetdata(self
, type, name
):
516 self
.cdecls
.append("\tsize_t %s = 0;" % name
)
518 def outputgetdata(self
, type, name
):
519 # This is a total hack, but self.call is set up before the parameters
520 # are processed, so we can't tell it to pass a parameter by reference.
521 self
.call
= "%s(%s)" % (self
.function
.name
,
522 ", ".join([(param
.name
, "&len")[param
.name
== "len"] for param
in self
.params
]))
524 self
.cdecls
.append("\tgconstpointer %s;" % name
)
525 self
.ccode
.append("\t%s = %s;" % (name
, self
.call
))
526 self
.cparamsout
.append("DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &%s, %s" \
528 self
.addouttype("ay", name
)
531 regexp
= r
"^(\w[^()]*)\(([^()]*)\)\s*;\s*$";
533 def __init__(self
, inputfile
, fprefix
):
534 self
.inputiter
= iter(inputfile
)
535 self
.functionregexp
= \
536 re
.compile("^%s(\w[^()]*)\(([^()]*)\)\s*;\s*$" % fprefix
)
537 self
.typeregexp
= re
.compile("^\w+\s*\*?\s*$")
542 print "/* Generated by %s. Do not edit! */" % sys
.argv
[0]
544 for line
in self
.inputiter
:
546 if len(words
) == 0: # empty line
548 if line
[0] == "#": # preprocessor directive
550 if words
[0] in ["typedef", "struct", "enum", "static"]:
553 # accumulate lines until the parentheses are balance or an
554 # empty line has been encountered
555 myline
= line
.strip()
556 while (myline
.count("(") > myline
.count(")")) or self
.typeregexp
.match(myline
):
557 newline
= self
.inputiter
.next().strip()
558 if len(newline
) == 0:
560 myline
+= " " + newline
562 # is this a function declaration?
563 thematch
= self
.functionregexp
.match(
564 myline
.replace("*", " " + pointer
+ " "))
569 functiontext
= thematch
.group(1)
570 paramstext
= thematch
.group(2).strip()
572 if (paramstext
== "void") or (paramstext
== ""):
575 paramtexts
= paramstext
.split(",")
578 self
.processfunction(functiontext
, paramtexts
)
580 # sys.stderr.write(myline + "\n")
583 # sys.stderr.write(myline + "\n")
588 class ServerBindingSet (BindingSet
):
589 def __init__(self
, inputfile
, fprefix
):
590 BindingSet
.__init
__(self
, inputfile
, fprefix
)
594 def processfunction(self
, functiontext
, paramtexts
):
595 binding
= ServerBinding(functiontext
, paramtexts
)
597 self
.functions
.append((binding
.function
.name
, binding
.dparams
))
600 print "static PurpleDBusBinding bindings_DBUS[] = { "
601 for function
, params
in self
.functions
:
602 print '{"%s", "%s", %s_DBUS},' % \
603 (ctopascal(function
), params
, function
)
605 print "{NULL, NULL, NULL}"
608 print "#define PURPLE_DBUS_REGISTER_BINDINGS(handle) purple_dbus_register_bindings(handle, bindings_DBUS)"
610 class ClientBindingSet (BindingSet
):
611 def __init__(self
, inputfile
, fprefix
, headersonly
):
612 BindingSet
.__init
__(self
, inputfile
, fprefix
)
615 self
.headersonly
= headersonly
617 def processfunction(self
, functiontext
, paramtexts
):
618 binding
= ClientBinding(functiontext
, paramtexts
, self
.knowntypes
, self
.headersonly
)
628 for arg
in sys
.argv
[1:]:
630 mylist
= arg
[2:].split("=",1)
633 options
[command
] = mylist
[1]
635 options
[command
] = None
637 if "export-only" in options
:
638 fprefix
= "DBUS_EXPORT\s+"
642 #sys.stderr.write("%s: Functions not exported:\n" % sys.argv[0])
644 if "client" in options
:
645 bindings
= ClientBindingSet(sys
.stdin
, fprefix
,
646 options
.has_key("headers"))
648 bindings
= ServerBindingSet(sys
.stdin
, fprefix
)