Mercurial > pidgin
annotate libgaim/dbus-analyze-functions.py @ 14600:d44c87d17b19
[gaim-migrate @ 17327]
Fall back to using internal libgadu if an external one is not found
committer: Tailor Script <tailor@pidgin.im>
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Wed, 20 Sep 2006 11:42:26 +0000 |
parents | 9c884b84afb9 |
children | 74b69a11830c |
rev | line source |
---|---|
14192 | 1 import re |
2 import string | |
3 import sys | |
4 | |
5 | |
6 # types translated into "int" | |
7 simpletypes = ["int", "gint", "guint", "gboolean"] | |
8 | |
9 # List "excluded" contains functions that shouldn't be exported via | |
10 # DBus. If you remove a function from this list, please make sure | |
11 # that it does not break "make" with the configure option | |
12 # "--enable-dbus" turned on. | |
13 | |
14 excluded = [\ | |
15 # I don't remember why this function is excluded; something to do | |
16 # with the fact that it takes a (const) GList as a parameter. | |
17 "gaim_presence_add_list", | |
18 | |
19 # These functions are excluded because they involve value of the | |
20 # type GaimConvPlacementFunc, which is a pointer to a function and | |
21 # (currently?) can't be translated into a DBus type. Normally, | |
22 # functions with untranslatable types are skipped, but this script | |
23 # assumes that all non-pointer type names beginning with "Gaim" | |
24 # are enums, which is not true in this case. | |
25 "gaim_conv_placement_add_fnc", | |
26 "gaim_conv_placement_get_fnc", | |
27 "gaim_conv_placement_get_current_func", | |
28 "gaim_conv_placement_set_current_func", | |
29 | |
30 # This is excluded because this script treats GaimLogReadFlags* | |
31 # as pointer to a struct, instead of a pointer to an enum. This | |
32 # causes a compilation error. Someone should fix this script. | |
33 "gaim_log_read", | |
34 ] | |
35 | |
36 # This is a list of functions that return a GList* whose elements are | |
37 # string, not pointers to objects. Don't put any functions here, it | |
38 # won't work. | |
39 stringlists = [] | |
40 | |
41 pointer = "#pointer#" | |
42 myexception = "My Exception" | |
43 | |
44 def ctopascal(name): | |
45 newname = "" | |
46 for word in name.split("_"): | |
47 newname += word.capitalize() | |
48 return newname | |
49 | |
50 class Parameter: | |
51 def __init__(self, type, name): | |
52 self.name = name | |
53 self.type = type | |
54 | |
55 def fromtokens(tokens, parameternumber = -1): | |
56 if len(tokens) == 0: | |
57 raise myexception | |
58 if (len(tokens) == 1) or (tokens[-1] == pointer): | |
59 if parameternumber >= 0: | |
60 return Parameter(tokens, "param%i" % parameternumber) | |
61 else: | |
62 raise myexception | |
63 else: | |
64 return Parameter(tokens[:-1], tokens[-1]) | |
65 | |
66 fromtokens = staticmethod(fromtokens) | |
67 | |
68 class Binding: | |
69 def __init__(self, functiontext, paramtexts): | |
70 self.function = Parameter.fromtokens(functiontext.split()) | |
71 | |
72 if self.function.name in excluded: | |
73 raise myexception | |
74 | |
75 self.params = [] | |
76 for i in range(len(paramtexts)): | |
77 self.params.append(Parameter.fromtokens(paramtexts[i].split(), i)) | |
78 | |
79 self.call = "%s(%s)" % (self.function.name, | |
80 ", ".join([param.name for param in self.params])) | |
81 | |
82 | |
83 def process(self): | |
84 for param in self.params: | |
85 self.processinput(param.type, param.name) | |
86 | |
87 self.processoutput(self.function.type, "RESULT") | |
88 self.flush() | |
89 | |
90 | |
91 def processinput(self, type, name): | |
92 const = False | |
93 if type[0] == "const": | |
94 type = type[1:] | |
95 const = True | |
96 | |
97 if len(type) == 1: | |
98 # simple types (int, gboolean, etc.) and enums | |
99 if (type[0] in simpletypes) or (type[0].startswith("Gaim")): | |
100 return self.inputsimple(type, name) | |
101 | |
102 | |
103 # va_list, replace by NULL | |
104 if type[0] == "va_list": | |
105 return self.inputvalist(type, name) | |
106 | |
107 # pointers ... | |
108 if (len(type) == 2) and (type[1] == pointer): | |
109 # strings | |
110 if type[0] == "char": | |
111 if const: | |
112 return self.inputstring(type, name) | |
113 else: | |
114 raise myexception | |
115 | |
116 elif type[0] == "GHashTable": | |
117 return self.inputhash(type, name) | |
118 | |
119 # known object types are transformed to integer handles | |
14352
9c884b84afb9
[gaim-migrate @ 17058]
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
14192
diff
changeset
|
120 elif type[0].startswith("Gaim") or type[0] == "xmlnode": |
14192 | 121 return self.inputgaimstructure(type, name) |
122 | |
123 # unknown pointers are always replaced with NULL | |
124 else: | |
125 return self.inputpointer(type, name) | |
126 return | |
127 | |
128 raise myexception | |
129 | |
130 | |
131 def processoutput(self, type, name): | |
132 # the "void" type is simple ... | |
133 if type == ["void"]: | |
134 return self.outputvoid(type, name) | |
135 | |
136 const = False | |
137 if type[0] == "const": | |
138 type = type[1:] | |
139 const = True | |
140 | |
141 # a string | |
142 if type == ["char", pointer]: | |
143 return self.outputstring(type, name, const) | |
144 | |
145 # simple types (ints, booleans, enums, ...) | |
146 if (len(type) == 1) and \ | |
147 ((type[0] in simpletypes) or (type[0].startswith("Gaim"))): | |
148 return self.outputsimple(type, name) | |
149 | |
150 # pointers ... | |
151 if (len(type) == 2) and (type[1] == pointer): | |
152 | |
153 # handles | |
154 if type[0].startswith("Gaim"): | |
155 return self.outputgaimstructure(type, name) | |
156 | |
157 if type[0] in ["GList", "GSList"]: | |
158 return self.outputlist(type, name) | |
159 | |
160 raise myexception | |
161 | |
162 | |
163 class ClientBinding (Binding): | |
164 def __init__(self, functiontext, paramtexts, knowntypes, headersonly): | |
165 Binding.__init__(self, functiontext, paramtexts) | |
166 self.knowntypes = knowntypes | |
167 self.headersonly = headersonly | |
168 self.paramshdr = [] | |
169 self.decls = [] | |
170 self.inputparams = [] | |
171 self.outputparams = [] | |
172 self.returncode = [] | |
173 | |
174 def flush(self): | |
175 print "%s %s(%s)" % (self.functiontype, self.function.name, | |
176 ", ".join(self.paramshdr)), | |
177 | |
178 if self.headersonly: | |
179 print ";" | |
180 return | |
181 | |
182 print "{" | |
183 | |
184 for decl in self.decls: | |
185 print decl | |
186 | |
187 print 'dbus_g_proxy_call(gaim_proxy, "%s", NULL,' % ctopascal(self.function.name) | |
188 | |
189 for type_name in self.inputparams: | |
190 print "\t%s, %s, " % type_name, | |
191 print "G_TYPE_INVALID," | |
192 | |
193 for type_name in self.outputparams: | |
194 print "\t%s, &%s, " % type_name, | |
195 print "G_TYPE_INVALID);" | |
196 | |
197 for code in self.returncode: | |
198 print code | |
199 | |
200 print "}\n" | |
201 | |
202 | |
203 def definegaimstructure(self, type): | |
204 if (self.headersonly) and (type[0] not in self.knowntypes): | |
205 print "struct _%s;" % type[0] | |
206 print "typedef struct _%s %s;" % (type[0], type[0]) | |
207 self.knowntypes.append(type[0]) | |
208 | |
209 def inputsimple(self, type, name): | |
210 self.paramshdr.append("%s %s" % (type[0], name)) | |
211 self.inputparams.append(("G_TYPE_INT", name)) | |
212 | |
213 def inputvalist(self, type, name): | |
214 self.paramshdr.append("va_list %s_NULL" % name) | |
215 | |
216 def inputstring(self, type, name): | |
217 self.paramshdr.append("const char *%s" % name) | |
218 self.inputparams.append(("G_TYPE_STRING", name)) | |
219 | |
220 def inputgaimstructure(self, type, name): | |
221 self.paramshdr.append("const %s *%s" % (type[0], name)) | |
222 self.inputparams.append(("G_TYPE_INT", "GPOINTER_TO_INT(%s)" % name)) | |
223 self.definegaimstructure(type) | |
224 | |
225 def inputpointer(self, type, name): | |
226 name += "_NULL" | |
227 self.paramshdr.append("const %s *%s" % (type[0], name)) | |
228 self.inputparams.append(("G_TYPE_INT", "0")) | |
229 | |
230 def inputhash(self, type, name): | |
231 self.paramshdr.append("const GHashTable *%s" % name) | |
232 self.inputparams.append(('dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)', name)) | |
233 | |
234 def outputvoid(self, type, name): | |
235 self.functiontype = "void" | |
236 | |
237 def outputstring(self, type, name, const): | |
238 self.functiontype = "char*" | |
239 self.decls.append("char *%s = NULL;" % name) | |
240 self.outputparams.append(("G_TYPE_STRING", name)) | |
241 # self.returncode.append("NULLIFY(%s);" % name) | |
242 self.returncode.append("return %s;" % name); | |
243 | |
244 def outputsimple(self, type, name): | |
245 self.functiontype = type[0] | |
246 self.decls.append("%s %s = 0;" % (type[0], name)) | |
247 self.outputparams.append(("G_TYPE_INT", name)) | |
248 self.returncode.append("return %s;" % name); | |
249 | |
250 # we could add "const" to the return type but this would probably | |
251 # be a nuisance | |
252 def outputgaimstructure(self, type, name): | |
253 name = name + "_ID" | |
254 self.functiontype = "%s*" % type[0] | |
255 self.decls.append("int %s = 0;" % name) | |
256 self.outputparams.append(("G_TYPE_INT", "%s" % name)) | |
257 self.returncode.append("return (%s*) GINT_TO_POINTER(%s);" % (type[0], name)); | |
258 self.definegaimstructure(type) | |
259 | |
260 def outputlist(self, type, name): | |
261 self.functiontype = "%s*" % type[0] | |
262 self.decls.append("GArray *%s;" % name) | |
263 self.outputparams.append(('dbus_g_type_get_collection("GArray", G_TYPE_INT)', name)) | |
264 self.returncode.append("return garray_int_to_%s(%s);" % | |
265 (type[0].lower(), name)); | |
266 | |
267 | |
268 class ServerBinding (Binding): | |
269 def __init__(self, functiontext, paramtexts): | |
270 Binding.__init__(self, functiontext, paramtexts) | |
271 self.dparams = "" | |
272 self.cparams = [] | |
273 self.cdecls = [] | |
274 self.ccode = [] | |
275 self.cparamsout = [] | |
276 self.ccodeout = [] | |
277 self.argfunc = "dbus_message_get_args" | |
278 | |
279 def flush(self): | |
280 print "static DBusMessage*" | |
281 print "%s_DBUS(DBusMessage *message_DBUS, DBusError *error_DBUS) {" % \ | |
282 self.function.name | |
283 | |
284 print "\tDBusMessage *reply_DBUS;" | |
285 | |
286 for decl in self.cdecls: | |
287 print decl | |
288 | |
289 print "\t%s(message_DBUS, error_DBUS, " % self.argfunc, | |
290 for param in self.cparams: | |
291 print "DBUS_TYPE_%s, &%s," % param, | |
292 print "DBUS_TYPE_INVALID);" | |
293 | |
294 print "\tCHECK_ERROR(error_DBUS);" | |
295 | |
296 for code in self.ccode: | |
297 print code | |
298 | |
299 print "\treply_DBUS = dbus_message_new_method_return (message_DBUS);" | |
300 | |
301 print "\tdbus_message_append_args(reply_DBUS, ", | |
302 for param in self.cparamsout: | |
303 if type(param) is str: | |
304 print "%s, " % param | |
305 else: | |
306 print "DBUS_TYPE_%s, &%s, " % param, | |
307 print "DBUS_TYPE_INVALID);" | |
308 | |
309 for code in self.ccodeout: | |
310 print code | |
311 | |
312 print "\treturn reply_DBUS;\n}\n" | |
313 | |
314 | |
315 def addstring(self, *items): | |
316 for item in items: | |
317 self.dparams += item + r"\0" | |
318 | |
319 def addintype(self, type, name): | |
320 self.addstring("in", type, name) | |
321 | |
322 def addouttype(self, type, name): | |
323 self.addstring("out", type, name) | |
324 | |
325 | |
326 # input parameters | |
327 | |
328 def inputsimple(self, type, name): | |
329 self.cdecls.append("\tdbus_int32_t %s;" % name) | |
330 self.cparams.append(("INT32", name)) | |
331 self.addintype("i", name) | |
332 | |
333 def inputvalist(self, type, name): | |
334 self.cdecls.append("\tvoid * %s;" % name); | |
335 self.ccode.append("\t%s = NULL;" % name); | |
336 | |
337 def inputstring(self, type, name): | |
338 self.cdecls.append("\tconst char *%s;" % name) | |
339 self.cparams.append(("STRING", name)) | |
340 self.ccode .append("\tNULLIFY(%s);" % name) | |
341 self.addintype("s", name) | |
342 | |
343 def inputhash(self, type, name): | |
344 self.argfunc = "gaim_dbus_message_get_args" | |
345 self.cdecls.append("\tDBusMessageIter %s_ITER;" % name) | |
346 self.cdecls.append("\tGHashTable *%s;" % name) | |
347 self.cparams.append(("ARRAY", "%s_ITER" % name)) | |
348 self.ccode.append("\t%s = gaim_dbus_iter_hash_table(&%s_ITER, error_DBUS);" \ | |
349 % (name, name)) | |
350 self.ccode.append("\tCHECK_ERROR(error_DBUS);") | |
351 self.ccodeout.append("\tg_hash_table_destroy(%s);" % name) | |
352 self.addintype("a{ss}", name) | |
353 | |
354 def inputgaimstructure(self, type, name): | |
355 self.cdecls.append("\tdbus_int32_t %s_ID;" % name) | |
356 self.cdecls.append("\t%s *%s;" % (type[0], name)) | |
357 self.cparams.append(("INT32", name + "_ID")) | |
358 self.ccode.append("\tGAIM_DBUS_ID_TO_POINTER(%s, %s_ID, %s, error_DBUS);" % \ | |
359 (name, name, type[0])) | |
360 self.addintype("i", name) | |
361 | |
362 def inputpointer(self, type, name): | |
363 self.cdecls.append("\tdbus_int32_t %s_NULL;" % name) | |
364 self.cdecls .append("\t%s *%s;" % (type[0], name)) | |
365 self.cparams.append(("INT32", name + "_NULL")) | |
366 self.ccode .append("\t%s = NULL;" % name) | |
367 self.addintype("i", name) | |
368 | |
369 # output parameters | |
370 | |
371 def outputvoid(self, type, name): | |
372 self.ccode.append("\t%s;" % self.call) # just call the function | |
373 | |
374 def outputstring(self, type, name, const): | |
375 self.cdecls.append("\tconst char *%s;" % name) | |
376 self.ccode.append("\t%s = null_to_empty(%s);" % (name, self.call)) | |
377 self.cparamsout.append(("STRING", name)) | |
378 self.addouttype("s", name) | |
379 if not const: | |
380 self.ccodeout.append("\tg_free(%s);" % name) | |
381 | |
382 def outputsimple(self, type, name): | |
383 self.cdecls.append("\tdbus_int32_t %s;" % name) | |
384 self.ccode.append("\t%s = %s;" % (name, self.call)) | |
385 self.cparamsout.append(("INT32", name)) | |
386 self.addouttype("i", name) | |
387 | |
388 def outputgaimstructure(self, type, name): | |
389 self.cdecls.append("\tdbus_int32_t %s;" % name) | |
390 self.ccode .append("\tGAIM_DBUS_POINTER_TO_ID(%s, %s, error_DBUS);" % (name, self.call)) | |
391 self.cparamsout.append(("INT32", name)) | |
392 self.addouttype("i", name) | |
393 | |
394 # GList*, GSList*, assume that list is a list of objects | |
395 | |
396 # fixme: at the moment, we do NOT free the memory occupied by | |
397 # the list, we should free it if the list has NOT been declared const | |
398 | |
399 # fixme: we assume that this is a list of objects, not a list | |
400 # of strings | |
401 | |
402 def outputlist(self, type, name): | |
403 self.cdecls.append("\tdbus_int32_t %s_LEN;" % name) | |
404 self.ccodeout.append("\tg_free(%s);" % name) | |
405 | |
406 if self.function.name in stringlists: | |
407 self.cdecls.append("\tchar **%s;" % name) | |
408 self.ccode.append("\t%s = gaim_%s_to_array(%s, FALSE, &%s_LEN);" % \ | |
409 (name, type[0], self.call, name)) | |
410 self.cparamsout.append("\tDBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &%s, %s_LEN" \ | |
411 % (name, name)) | |
412 self.addouttype("as", name) | |
413 else: | |
414 self.cdecls.append("\tdbus_int32_t *%s;" % name) | |
415 self.ccode.append("\t%s = gaim_dbusify_%s(%s, FALSE, &%s_LEN);" % \ | |
416 (name, type[0], self.call, name)) | |
417 self.cparamsout.append("\tDBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &%s, %s_LEN" \ | |
418 % (name, name)) | |
419 self.addouttype("ai", name) | |
420 | |
421 | |
422 class BindingSet: | |
423 regexp = r"^(\w[^()]*)\(([^()]*)\)\s*;\s*$"; | |
424 | |
425 def __init__(self, inputfile, fprefix): | |
426 self.inputiter = iter(inputfile) | |
427 self.functionregexp = \ | |
428 re.compile("^%s(\w[^()]*)\(([^()]*)\)\s*;\s*$" % fprefix) | |
429 | |
430 | |
431 | |
432 def process(self): | |
433 print "/* Generated by %s. Do not edit! */" % sys.argv[0] | |
434 | |
435 for line in self.inputiter: | |
436 words = line.split() | |
437 if len(words) == 0: # empty line | |
438 continue | |
439 if line[0] == "#": # preprocessor directive | |
440 continue | |
441 if words[0] in ["typedef", "struct", "enum", "static"]: | |
442 continue | |
443 | |
444 # accumulate lines until the parentheses are balance or an | |
445 # empty line has been encountered | |
446 myline = line.strip() | |
447 while myline.count("(") > myline.count(")"): | |
448 newline = self.inputiter.next().strip() | |
449 if len(newline) == 0: | |
450 break | |
451 myline += " " + newline | |
452 | |
453 # is this a function declaration? | |
454 thematch = self.functionregexp.match( | |
455 myline.replace("*", " " + pointer + " ")) | |
456 | |
457 if thematch is None: | |
458 continue | |
459 | |
460 functiontext = thematch.group(1) | |
461 paramstext = thematch.group(2).strip() | |
462 | |
463 if (paramstext == "void") or (paramstext == ""): | |
464 paramtexts = [] | |
465 else: | |
466 paramtexts = paramstext.split(",") | |
467 | |
468 try: | |
469 self.processfunction(functiontext, paramtexts) | |
470 except myexception: | |
471 sys.stderr.write(myline + "\n") | |
472 except: | |
473 sys.stderr.write(myline + "\n") | |
474 raise | |
475 | |
476 self.flush() | |
477 | |
478 class ServerBindingSet (BindingSet): | |
479 def __init__(self, inputfile, fprefix): | |
480 BindingSet.__init__(self, inputfile, fprefix) | |
481 self.functions = [] | |
482 | |
483 | |
484 def processfunction(self, functiontext, paramtexts): | |
485 binding = ServerBinding(functiontext, paramtexts) | |
486 binding.process() | |
487 self.functions.append((binding.function.name, binding.dparams)) | |
488 | |
489 def flush(self): | |
490 print "static GaimDBusBinding bindings_DBUS[] = { " | |
491 for function, params in self.functions: | |
492 print '{"%s", "%s", %s_DBUS},' % \ | |
493 (ctopascal(function), params, function) | |
494 | |
495 print "{NULL, NULL, NULL}" | |
496 print "};" | |
497 | |
498 print "#define GAIM_DBUS_REGISTER_BINDINGS(handle) gaim_dbus_register_bindings(handle, bindings_DBUS)" | |
499 | |
500 class ClientBindingSet (BindingSet): | |
501 def __init__(self, inputfile, fprefix, headersonly): | |
502 BindingSet.__init__(self, inputfile, fprefix) | |
503 self.functions = [] | |
504 self.knowntypes = [] | |
505 self.headersonly = headersonly | |
506 | |
507 def processfunction(self, functiontext, paramtexts): | |
508 binding = ClientBinding(functiontext, paramtexts, self.knowntypes, self.headersonly) | |
509 binding.process() | |
510 | |
511 def flush(self): | |
512 pass | |
513 | |
514 # Main program | |
515 | |
516 options = {} | |
517 | |
518 for arg in sys.argv[1:]: | |
519 if arg[0:2] == "--": | |
520 mylist = arg[2:].split("=",1) | |
521 command = mylist[0] | |
522 if len(mylist) > 1: | |
523 options[command] = mylist[1] | |
524 else: | |
525 options[command] = None | |
526 | |
527 if "export-only" in options: | |
528 fprefix = "DBUS_EXPORT\s+" | |
529 else: | |
530 fprefix = "" | |
531 | |
532 sys.stderr.write("%s: Functions not exported:\n" % sys.argv[0]) | |
533 | |
534 if "client" in options: | |
535 bindings = ClientBindingSet(sys.stdin, fprefix, | |
536 options.has_key("headers")) | |
537 else: | |
538 bindings = ServerBindingSet(sys.stdin, fprefix) | |
539 bindings.process() | |
540 | |
541 | |
542 | |
543 |