]> git.0d.be Git - empathy.git/blob - tools/glib-client-gen.py
tp-chat: prepare CONNECTED on the TpConnection first
[empathy.git] / tools / glib-client-gen.py
1 #!/usr/bin/python
2
3 # glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool"
4 #
5 # Generate GLib client wrappers from the Telepathy specification.
6 # The master copy of this program is in the telepathy-glib repository -
7 # please make any changes there.
8 #
9 # Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
10 #
11 # This library is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU Lesser General Public
13 # License as published by the Free Software Foundation; either
14 # version 2.1 of the License, or (at your option) any later version.
15 #
16 # This library is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 # Lesser General Public License for more details.
20 #
21 # You should have received a copy of the GNU Lesser General Public
22 # License along with this library; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24
25 import sys
26 import os.path
27 import xml.dom.minidom
28 from getopt import gnu_getopt
29
30 from libtpcodegen import file_set_contents
31 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
32         get_docstring, xml_escape, get_deprecated
33
34
35 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
36
37 class Generator(object):
38
39     def __init__(self, dom, prefix, basename, opts):
40         self.dom = dom
41         self.__header = []
42         self.__body = []
43         self.__docs = []
44
45         self.prefix_lc = prefix.lower()
46         self.prefix_uc = prefix.upper()
47         self.prefix_mc = prefix.replace('_', '')
48         self.basename = basename
49         self.group = opts.get('--group', None)
50         self.iface_quark_prefix = opts.get('--iface-quark-prefix', None)
51         self.tp_proxy_api = tuple(map(int,
52                 opts.get('--tp-proxy-api', '0').split('.')))
53         self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *'
54         self.proxy_arg = opts.get('--subclass', 'void') + ' *'
55         self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY')
56         self.proxy_doc = ('A #%s or subclass'
57             % opts.get('--subclass', 'TpProxy'))
58         if self.proxy_arg == 'void *':
59             self.proxy_arg = 'gpointer '
60
61         self.reentrant_symbols = set()
62         try:
63             filename = opts['--generate-reentrant']
64             with open(filename, 'r') as f:
65                 for line in f.readlines():
66                     self.reentrant_symbols.add(line.strip())
67         except KeyError:
68             pass
69
70         self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
71         self.deprecation_attribute = opts.get('--deprecation-attribute',
72                 'G_GNUC_DEPRECATED')
73
74         self.guard = opts.get('--guard', None)
75
76     def h(self, s):
77         if isinstance(s, unicode):
78             s = s.encode('utf-8')
79         self.__header.append(s)
80
81     def b(self, s):
82         if isinstance(s, unicode):
83             s = s.encode('utf-8')
84         self.__body.append(s)
85
86     def d(self, s):
87         if isinstance(s, unicode):
88             s = s.encode('utf-8')
89         self.__docs.append(s)
90
91     def get_iface_quark(self):
92         assert self.iface_dbus is not None
93         assert self.iface_uc is not None
94         if self.iface_quark_prefix is None:
95             return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
96         else:
97             return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
98
99     def do_signal(self, iface, signal):
100         iface_lc = iface.lower()
101
102         member = signal.getAttribute('name')
103         member_lc = signal.getAttribute('tp:name-for-bindings')
104         if member != member_lc.replace('_', ''):
105             raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
106                     'not match' % (member, member_lc))
107         member_lc = member_lc.lower()
108         member_uc = member_lc.upper()
109
110         arg_count = 0
111         args = []
112         out_args = []
113
114         for arg in signal.getElementsByTagName('arg'):
115             name = arg.getAttribute('name')
116             type = arg.getAttribute('type')
117             tp_type = arg.getAttribute('tp:type')
118
119             if not name:
120                 name = 'arg%u' % arg_count
121                 arg_count += 1
122             else:
123                 name = 'arg_%s' % name
124
125             info = type_to_gtype(type)
126             args.append((name, info, tp_type, arg))
127
128         callback_name = ('%s_%s_signal_callback_%s'
129                          % (self.prefix_lc, iface_lc, member_lc))
130         collect_name = ('_%s_%s_collect_args_of_%s'
131                         % (self.prefix_lc, iface_lc, member_lc))
132         invoke_name = ('_%s_%s_invoke_callback_for_%s'
133                        % (self.prefix_lc, iface_lc, member_lc))
134
135         # Example:
136         #
137         # typedef void (*tp_cli_connection_signal_callback_new_channel)
138         #   (TpConnection *proxy, const gchar *arg_object_path,
139         #   const gchar *arg_channel_type, guint arg_handle_type,
140         #   guint arg_handle, gboolean arg_suppress_handler,
141         #   gpointer user_data, GObject *weak_object);
142
143         self.d('/**')
144         self.d(' * %s:' % callback_name)
145         self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
146                % (self.prefix_lc, iface_lc, member_lc))
147         self.d(' *  was called')
148
149         for arg in args:
150             name, info, tp_type, elt = arg
151             ctype, gtype, marshaller, pointer = info
152
153             docs = get_docstring(elt) or '(Undocumented)'
154
155             if ctype == 'guint ' and tp_type != '':
156                 docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
157
158             self.d(' * @%s: %s' % (name, xml_escape(docs)))
159
160         self.d(' * @user_data: User-supplied data')
161         self.d(' * @weak_object: User-supplied weakly referenced object')
162         self.d(' *')
163         self.d(' * Represents the signature of a callback for the signal %s.'
164                % member)
165         self.d(' */')
166         self.d('')
167
168         self.h('typedef void (*%s) (%sproxy,'
169                % (callback_name, self.proxy_cls))
170
171         for arg in args:
172             name, info, tp_type, elt = arg
173             ctype, gtype, marshaller, pointer = info
174
175             const = pointer and 'const ' or ''
176
177             self.h('    %s%s%s,' % (const, ctype, name))
178
179         self.h('    gpointer user_data, GObject *weak_object);')
180
181         if args:
182             self.b('static void')
183             self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
184
185             for arg in args:
186                 name, info, tp_type, elt = arg
187                 ctype, gtype, marshaller, pointer = info
188
189                 const = pointer and 'const ' or ''
190
191                 self.b('    %s%s%s,' % (const, ctype, name))
192
193             self.b('    TpProxySignalConnection *sc)')
194             self.b('{')
195             self.b('  GValueArray *args = g_value_array_new (%d);' % len(args))
196             self.b('  GValue blank = { 0 };')
197             self.b('  guint i;')
198             self.b('')
199             self.b('  g_value_init (&blank, G_TYPE_INT);')
200             self.b('')
201             self.b('  for (i = 0; i < %d; i++)' % len(args))
202             self.b('    g_value_array_append (args, &blank);')
203             self.b('')
204
205             for i, arg in enumerate(args):
206                 name, info, tp_type, elt = arg
207                 ctype, gtype, marshaller, pointer = info
208
209                 self.b('  g_value_unset (args->values + %d);' % i)
210                 self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))
211
212                 if gtype == 'G_TYPE_STRING':
213                     self.b('  g_value_set_string (args->values + %d, %s);'
214                            % (i, name))
215                 elif marshaller == 'BOXED':
216                     self.b('  g_value_set_boxed (args->values + %d, %s);'
217                            % (i, name))
218                 elif gtype == 'G_TYPE_UCHAR':
219                     self.b('  g_value_set_uchar (args->values + %d, %s);'
220                            % (i, name))
221                 elif gtype == 'G_TYPE_BOOLEAN':
222                     self.b('  g_value_set_boolean (args->values + %d, %s);'
223                            % (i, name))
224                 elif gtype == 'G_TYPE_INT':
225                     self.b('  g_value_set_int (args->values + %d, %s);'
226                            % (i, name))
227                 elif gtype == 'G_TYPE_UINT':
228                     self.b('  g_value_set_uint (args->values + %d, %s);'
229                            % (i, name))
230                 elif gtype == 'G_TYPE_INT64':
231                     self.b('  g_value_set_int (args->values + %d, %s);'
232                            % (i, name))
233                 elif gtype == 'G_TYPE_UINT64':
234                     self.b('  g_value_set_uint64 (args->values + %d, %s);'
235                            % (i, name))
236                 elif gtype == 'G_TYPE_DOUBLE':
237                     self.b('  g_value_set_double (args->values + %d, %s);'
238                            % (i, name))
239                 else:
240                     assert False, ("Don't know how to put %s in a GValue"
241                                    % gtype)
242                 self.b('')
243
244             self.b('  tp_proxy_signal_connection_v0_take_results (sc, args);')
245             self.b('}')
246
247         self.b('static void')
248         self.b('%s (TpProxy *tpproxy,' % invoke_name)
249         self.b('    GError *error G_GNUC_UNUSED,')
250         self.b('    GValueArray *args,')
251         self.b('    GCallback generic_callback,')
252         self.b('    gpointer user_data,')
253         self.b('    GObject *weak_object)')
254         self.b('{')
255         self.b('  %s callback =' % callback_name)
256         self.b('      (%s) generic_callback;' % callback_name)
257         self.b('')
258         self.b('  if (callback != NULL)')
259         self.b('    callback (g_object_ref (tpproxy),')
260
261         # FIXME: factor out into a function
262         for i, arg in enumerate(args):
263             name, info, tp_type, elt = arg
264             ctype, gtype, marshaller, pointer = info
265
266             if marshaller == 'BOXED':
267                 self.b('      g_value_get_boxed (args->values + %d),' % i)
268             elif gtype == 'G_TYPE_STRING':
269                 self.b('      g_value_get_string (args->values + %d),' % i)
270             elif gtype == 'G_TYPE_UCHAR':
271                 self.b('      g_value_get_uchar (args->values + %d),' % i)
272             elif gtype == 'G_TYPE_BOOLEAN':
273                 self.b('      g_value_get_boolean (args->values + %d),' % i)
274             elif gtype == 'G_TYPE_UINT':
275                 self.b('      g_value_get_uint (args->values + %d),' % i)
276             elif gtype == 'G_TYPE_INT':
277                 self.b('      g_value_get_int (args->values + %d),' % i)
278             elif gtype == 'G_TYPE_UINT64':
279                 self.b('      g_value_get_uint64 (args->values + %d),' % i)
280             elif gtype == 'G_TYPE_INT64':
281                 self.b('      g_value_get_int64 (args->values + %d),' % i)
282             elif gtype == 'G_TYPE_DOUBLE':
283                 self.b('      g_value_get_double (args->values + %d),' % i)
284             else:
285                 assert False, "Don't know how to get %s from a GValue" % gtype
286
287         self.b('      user_data,')
288         self.b('      weak_object);')
289         self.b('')
290
291         if len(args) > 0:
292             self.b('  g_value_array_free (args);')
293         else:
294             self.b('  if (args != NULL)')
295             self.b('    g_value_array_free (args);')
296             self.b('')
297
298         self.b('  g_object_unref (tpproxy);')
299         self.b('}')
300
301         # Example:
302         #
303         # TpProxySignalConnection *
304         #   tp_cli_connection_connect_to_new_channel
305         #   (TpConnection *proxy,
306         #   tp_cli_connection_signal_callback_new_channel callback,
307         #   gpointer user_data,
308         #   GDestroyNotify destroy);
309         #
310         # destroy is invoked when the signal becomes disconnected. This
311         # is either because the signal has been disconnected explicitly
312         # by the user, because the TpProxy has become invalid and
313         # emitted the 'invalidated' signal, or because the weakly referenced
314         # object has gone away.
315
316         self.d('/**')
317         self.d(' * %s_%s_connect_to_%s:'
318                % (self.prefix_lc, iface_lc, member_lc))
319         self.d(' * @proxy: %s' % self.proxy_doc)
320         self.d(' * @callback: Callback to be called when the signal is')
321         self.d(' *   received')
322         self.d(' * @user_data: User-supplied data for the callback')
323         self.d(' * @destroy: Destructor for the user-supplied data, which')
324         self.d(' *   will be called when this signal is disconnected, or')
325         self.d(' *   before this function returns %NULL')
326         self.d(' * @weak_object: A #GObject which will be weakly referenced; ')
327         self.d(' *   if it is destroyed, this callback will automatically be')
328         self.d(' *   disconnected')
329         self.d(' * @error: If not %NULL, used to raise an error if %NULL is')
330         self.d(' *   returned')
331         self.d(' *')
332         self.d(' * Connect a handler to the signal %s.' % member)
333         self.d(' *')
334         self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
335         self.d(' *')
336         self.d(' * Returns: a #TpProxySignalConnection containing all of the')
337         self.d(' * above, which can be used to disconnect the signal; or')
338         self.d(' * %NULL if the proxy does not have the desired interface')
339         self.d(' * or has become invalid.')
340         self.d(' */')
341         self.d('')
342
343         self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
344                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
345         self.h('    %s callback,' % callback_name)
346         self.h('    gpointer user_data,')
347         self.h('    GDestroyNotify destroy,')
348         self.h('    GObject *weak_object,')
349         self.h('    GError **error);')
350         self.h('')
351
352         self.b('TpProxySignalConnection *')
353         self.b('%s_%s_connect_to_%s (%sproxy,'
354                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
355         self.b('    %s callback,' % callback_name)
356         self.b('    gpointer user_data,')
357         self.b('    GDestroyNotify destroy,')
358         self.b('    GObject *weak_object,')
359         self.b('    GError **error)')
360         self.b('{')
361         self.b('  GType expected_types[%d] = {' % (len(args) + 1))
362
363         for arg in args:
364             name, info, tp_type, elt = arg
365             ctype, gtype, marshaller, pointer = info
366
367             self.b('      %s,' % gtype)
368
369         self.b('      G_TYPE_INVALID };')
370         self.b('')
371         self.b('  g_return_val_if_fail (%s (proxy), NULL);'
372                % self.proxy_assert)
373         self.b('  g_return_val_if_fail (callback != NULL, NULL);')
374         self.b('')
375         self.b('  return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
376         self.b('      %s, \"%s\",' % (self.get_iface_quark(), member))
377         self.b('      expected_types,')
378
379         if args:
380             self.b('      G_CALLBACK (%s),' % collect_name)
381         else:
382             self.b('      NULL, /* no args => no collector function */')
383
384         self.b('      %s,' % invoke_name)
385         self.b('      G_CALLBACK (callback), user_data, destroy,')
386         self.b('      weak_object, error);')
387         self.b('}')
388         self.b('')
389
390     def do_method(self, iface, method):
391         iface_lc = iface.lower()
392
393         member = method.getAttribute('name')
394         member_lc = method.getAttribute('tp:name-for-bindings')
395         if member != member_lc.replace('_', ''):
396             raise AssertionError('Method %s tp:name-for-bindings (%s) does '
397                     'not match' % (member, member_lc))
398         member_lc = member_lc.lower()
399         member_uc = member_lc.upper()
400
401         in_count = 0
402         ret_count = 0
403         in_args = []
404         out_args = []
405
406         for arg in method.getElementsByTagName('arg'):
407             name = arg.getAttribute('name')
408             direction = arg.getAttribute('direction')
409             type = arg.getAttribute('type')
410             tp_type = arg.getAttribute('tp:type')
411
412             if direction != 'out':
413                 if not name:
414                     name = 'in%u' % in_count
415                     in_count += 1
416                 else:
417                     name = 'in_%s' % name
418             else:
419                 if not name:
420                     name = 'out%u' % ret_count
421                     ret_count += 1
422                 else:
423                     name = 'out_%s' % name
424
425             info = type_to_gtype(type)
426             if direction != 'out':
427                 in_args.append((name, info, tp_type, arg))
428             else:
429                 out_args.append((name, info, tp_type, arg))
430
431         # Async reply callback type
432
433         # Example:
434         # void (*tp_cli_properties_interface_callback_for_get_properties)
435         #   (TpProxy *proxy,
436         #       const GPtrArray *out0,
437         #       const GError *error,
438         #       gpointer user_data,
439         #       GObject *weak_object);
440
441         self.d('/**')
442         self.d(' * %s_%s_callback_for_%s:'
443                % (self.prefix_lc, iface_lc, member_lc))
444         self.d(' * @proxy: the proxy on which the call was made')
445
446         for arg in out_args:
447             name, info, tp_type, elt = arg
448             ctype, gtype, marshaller, pointer = info
449
450             docs = xml_escape(get_docstring(elt) or '(Undocumented)')
451
452             if ctype == 'guint ' and tp_type != '':
453                 docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
454
455             self.d(' * @%s: Used to return an \'out\' argument if @error is '
456                    '%%NULL: %s'
457                    % (name, docs))
458
459         self.d(' * @error: %NULL on success, or an error on failure')
460         self.d(' * @user_data: user-supplied data')
461         self.d(' * @weak_object: user-supplied object')
462         self.d(' *')
463         self.d(' * Signature of the callback called when a %s method call'
464                % member)
465         self.d(' * succeeds or fails.')
466
467         deprecated = method.getElementsByTagName('tp:deprecated')
468         if deprecated:
469             d = deprecated[0]
470             self.d(' *')
471             self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
472
473         self.d(' */')
474         self.d('')
475
476         callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
477                                                    member_lc)
478
479         self.h('typedef void (*%s) (%sproxy,'
480                % (callback_name, self.proxy_cls))
481
482         for arg in out_args:
483             name, info, tp_type, elt = arg
484             ctype, gtype, marshaller, pointer = info
485             const = pointer and 'const ' or ''
486
487             self.h('    %s%s%s,' % (const, ctype, name))
488
489         self.h('    const GError *error, gpointer user_data,')
490         self.h('    GObject *weak_object);')
491         self.h('')
492
493         # Async callback implementation
494
495         invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
496                                                          iface_lc,
497                                                          member_lc)
498
499         collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
500                                                            iface_lc,
501                                                            member_lc)
502
503         # The callback called by dbus-glib; this ends the call and collects
504         # the results into a GValueArray.
505         self.b('static void')
506         self.b('%s (DBusGProxy *proxy,' % collect_callback)
507         self.b('    DBusGProxyCall *call,')
508         self.b('    gpointer user_data)')
509         self.b('{')
510         self.b('  GError *error = NULL;')
511
512         if len(out_args) > 0:
513             self.b('  GValueArray *args;')
514             self.b('  GValue blank = { 0 };')
515             self.b('  guint i;')
516
517             for arg in out_args:
518                 name, info, tp_type, elt = arg
519                 ctype, gtype, marshaller, pointer = info
520
521                 # "We handle variants specially; the caller is expected to
522                 # have already allocated storage for them". Thanks,
523                 # dbus-glib...
524                 if gtype == 'G_TYPE_VALUE':
525                     self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
526                 else:
527                     self.b('  %s%s;' % (ctype, name))
528
529         self.b('')
530         self.b('  dbus_g_proxy_end_call (proxy, call, &error,')
531
532         for arg in out_args:
533             name, info, tp_type, elt = arg
534             ctype, gtype, marshaller, pointer = info
535
536             if gtype == 'G_TYPE_VALUE':
537                 self.b('      %s, %s,' % (gtype, name))
538             else:
539                 self.b('      %s, &%s,' % (gtype, name))
540
541         self.b('      G_TYPE_INVALID);')
542
543         if len(out_args) == 0:
544             self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
545                    'NULL);')
546         else:
547             self.b('')
548             self.b('  if (error != NULL)')
549             self.b('    {')
550             self.b('      tp_proxy_pending_call_v0_take_results (user_data, error,')
551             self.b('          NULL);')
552
553             for arg in out_args:
554                 name, info, tp_type, elt = arg
555                 ctype, gtype, marshaller, pointer = info
556                 if gtype == 'G_TYPE_VALUE':
557                     self.b('      g_free (%s);' % name)
558
559             self.b('      return;')
560             self.b('    }')
561             self.b('')
562             self.b('  args = g_value_array_new (%d);' % len(out_args))
563             self.b('  g_value_init (&blank, G_TYPE_INT);')
564             self.b('')
565             self.b('  for (i = 0; i < %d; i++)' % len(out_args))
566             self.b('    g_value_array_append (args, &blank);')
567
568             for i, arg in enumerate(out_args):
569                 name, info, tp_type, elt = arg
570                 ctype, gtype, marshaller, pointer = info
571
572                 self.b('')
573                 self.b('  g_value_unset (args->values + %d);' % i)
574                 self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))
575
576                 if gtype == 'G_TYPE_STRING':
577                     self.b('  g_value_take_string (args->values + %d, %s);'
578                            % (i, name))
579                 elif marshaller == 'BOXED':
580                     self.b('  g_value_take_boxed (args->values + %d, %s);'
581                             % (i, name))
582                 elif gtype == 'G_TYPE_UCHAR':
583                     self.b('  g_value_set_uchar (args->values + %d, %s);'
584                             % (i, name))
585                 elif gtype == 'G_TYPE_BOOLEAN':
586                     self.b('  g_value_set_boolean (args->values + %d, %s);'
587                             % (i, name))
588                 elif gtype == 'G_TYPE_INT':
589                     self.b('  g_value_set_int (args->values + %d, %s);'
590                             % (i, name))
591                 elif gtype == 'G_TYPE_UINT':
592                     self.b('  g_value_set_uint (args->values + %d, %s);'
593                             % (i, name))
594                 elif gtype == 'G_TYPE_INT64':
595                     self.b('  g_value_set_int (args->values + %d, %s);'
596                             % (i, name))
597                 elif gtype == 'G_TYPE_UINT64':
598                     self.b('  g_value_set_uint (args->values + %d, %s);'
599                             % (i, name))
600                 elif gtype == 'G_TYPE_DOUBLE':
601                     self.b('  g_value_set_double (args->values + %d, %s);'
602                             % (i, name))
603                 else:
604                     assert False, ("Don't know how to put %s in a GValue"
605                                    % gtype)
606
607             self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
608                    'NULL, args);')
609
610         self.b('}')
611
612         self.b('static void')
613         self.b('%s (TpProxy *self,' % invoke_callback)
614         self.b('    GError *error,')
615         self.b('    GValueArray *args,')
616         self.b('    GCallback generic_callback,')
617         self.b('    gpointer user_data,')
618         self.b('    GObject *weak_object)')
619         self.b('{')
620         self.b('  %s callback = (%s) generic_callback;'
621                % (callback_name, callback_name))
622         self.b('')
623         self.b('  if (error != NULL)')
624         self.b('    {')
625         self.b('      callback ((%s) self,' % self.proxy_cls)
626
627         for arg in out_args:
628             name, info, tp_type, elt = arg
629             ctype, gtype, marshaller, pointer = info
630
631             if marshaller == 'BOXED' or pointer:
632                 self.b('          NULL,')
633             elif gtype == 'G_TYPE_DOUBLE':
634                 self.b('          0.0,')
635             else:
636                 self.b('          0,')
637
638         self.b('          error, user_data, weak_object);')
639         self.b('      g_error_free (error);')
640         self.b('      return;')
641         self.b('    }')
642
643         self.b('  callback ((%s) self,' % self.proxy_cls)
644
645         # FIXME: factor out into a function
646         for i, arg in enumerate(out_args):
647             name, info, tp_type, elt = arg
648             ctype, gtype, marshaller, pointer = info
649
650             if marshaller == 'BOXED':
651                 self.b('      g_value_get_boxed (args->values + %d),' % i)
652             elif gtype == 'G_TYPE_STRING':
653                 self.b('      g_value_get_string (args->values + %d),' % i)
654             elif gtype == 'G_TYPE_UCHAR':
655                 self.b('      g_value_get_uchar (args->values + %d),' % i)
656             elif gtype == 'G_TYPE_BOOLEAN':
657                 self.b('      g_value_get_boolean (args->values + %d),' % i)
658             elif gtype == 'G_TYPE_UINT':
659                 self.b('      g_value_get_uint (args->values + %d),' % i)
660             elif gtype == 'G_TYPE_INT':
661                 self.b('      g_value_get_int (args->values + %d),' % i)
662             elif gtype == 'G_TYPE_UINT64':
663                 self.b('      g_value_get_uint64 (args->values + %d),' % i)
664             elif gtype == 'G_TYPE_INT64':
665                 self.b('      g_value_get_int64 (args->values + %d),' % i)
666             elif gtype == 'G_TYPE_DOUBLE':
667                 self.b('      g_value_get_double (args->values + %d),' % i)
668             else:
669                 assert False, "Don't know how to get %s from a GValue" % gtype
670
671         self.b('      error, user_data, weak_object);')
672         self.b('')
673
674         if len(out_args) > 0:
675             self.b('  g_value_array_free (args);')
676         else:
677             self.b('  if (args != NULL)')
678             self.b('    g_value_array_free (args);')
679
680         self.b('}')
681         self.b('')
682
683         # Async stub
684
685         # Example:
686         # TpProxyPendingCall *
687         #   tp_cli_properties_interface_call_get_properties
688         #   (gpointer proxy,
689         #   gint timeout_ms,
690         #   const GArray *in_properties,
691         #   tp_cli_properties_interface_callback_for_get_properties callback,
692         #   gpointer user_data,
693         #   GDestroyNotify *destructor);
694
695         self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
696                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
697         self.h('    gint timeout_ms,')
698
699         self.d('/**')
700         self.d(' * %s_%s_call_%s:'
701                % (self.prefix_lc, iface_lc, member_lc))
702         self.d(' * @proxy: the #TpProxy')
703         self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
704         self.d(' *   default')
705
706         for arg in in_args:
707             name, info, tp_type, elt = arg
708             ctype, gtype, marshaller, pointer = info
709
710             docs = xml_escape(get_docstring(elt) or '(Undocumented)')
711
712             if ctype == 'guint ' and tp_type != '':
713                 docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
714
715             self.d(' * @%s: Used to pass an \'in\' argument: %s'
716                    % (name, docs))
717
718         self.d(' * @callback: called when the method call succeeds or fails;')
719         self.d(' *   may be %NULL to make a "fire and forget" call with no ')
720         self.d(' *   reply tracking')
721         self.d(' * @user_data: user-supplied data passed to the callback;')
722         self.d(' *   must be %NULL if @callback is %NULL')
723         self.d(' * @destroy: called with the user_data as argument, after the')
724         self.d(' *   call has succeeded, failed or been cancelled;')
725         self.d(' *   must be %NULL if @callback is %NULL')
726         self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
727         self.d(' *   weakly referenced; if it is destroyed, this call ')
728         self.d(' *   will automatically be cancelled. Must be %NULL if ')
729         self.d(' *   @callback is %NULL')
730         self.d(' *')
731         self.d(' * Start a %s method call.' % member)
732         self.d(' *')
733         self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
734         self.d(' *')
735         self.d(' * Returns: a #TpProxyPendingCall representing the call in')
736         self.d(' *  progress. It is borrowed from the object, and will become')
737         self.d(' *  invalid when the callback is called, the call is')
738         self.d(' *  cancelled or the #TpProxy becomes invalid.')
739
740         deprecated = method.getElementsByTagName('tp:deprecated')
741         if deprecated:
742             d = deprecated[0]
743             self.d(' *')
744             self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
745
746         self.d(' */')
747         self.d('')
748
749         self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
750                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
751         self.b('    gint timeout_ms,')
752
753         for arg in in_args:
754             name, info, tp_type, elt = arg
755             ctype, gtype, marshaller, pointer = info
756
757             const = pointer and 'const ' or ''
758
759             self.h('    %s%s%s,' % (const, ctype, name))
760             self.b('    %s%s%s,' % (const, ctype, name))
761
762         self.h('    %s callback,' % callback_name)
763         self.h('    gpointer user_data,')
764         self.h('    GDestroyNotify destroy,')
765         self.h('    GObject *weak_object);')
766         self.h('')
767
768         self.b('    %s callback,' % callback_name)
769         self.b('    gpointer user_data,')
770         self.b('    GDestroyNotify destroy,')
771         self.b('    GObject *weak_object)')
772         self.b('{')
773         self.b('  GError *error = NULL;')
774         self.b('  GQuark interface = %s;' % self.get_iface_quark())
775         self.b('  DBusGProxy *iface;')
776         self.b('')
777         self.b('  g_return_val_if_fail (%s (proxy), NULL);'
778                % self.proxy_assert)
779         self.b('  g_return_val_if_fail (callback != NULL || '
780                'user_data == NULL, NULL);')
781         self.b('  g_return_val_if_fail (callback != NULL || '
782                'destroy == NULL, NULL);')
783         self.b('  g_return_val_if_fail (callback != NULL || '
784                'weak_object == NULL, NULL);')
785         self.b('')
786         self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
787         self.b('  iface = tp_proxy_borrow_interface_by_id (')
788         self.b('      (TpProxy *) proxy,')
789         self.b('      interface, &error);')
790         self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')
791         self.b('')
792         self.b('  if (iface == NULL)')
793         self.b('    {')
794         self.b('      if (callback != NULL)')
795         self.b('        callback (proxy,')
796
797         for arg in out_args:
798             name, info, tp_type, elt = arg
799             ctype, gtype, marshaller, pointer = info
800
801             if pointer:
802                 self.b('            NULL,')
803             else:
804                 self.b('            0,')
805
806         self.b('            error, user_data, weak_object);')
807         self.b('')
808         self.b('      if (destroy != NULL)')
809         self.b('        destroy (user_data);')
810         self.b('')
811         self.b('      g_error_free (error);')
812         self.b('      return NULL;')
813         self.b('    }')
814         self.b('')
815         self.b('  if (callback == NULL)')
816         self.b('    {')
817         self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)
818
819         for arg in in_args:
820             name, info, tp_type, elt = arg
821             ctype, gtype, marshaller, pointer = info
822
823             const = pointer and 'const ' or ''
824
825             self.b('          %s, %s,' % (gtype, name))
826
827         self.b('          G_TYPE_INVALID);')
828         self.b('      return NULL;')
829         self.b('    }')
830         self.b('  else')
831         self.b('    {')
832         self.b('      TpProxyPendingCall *data;')
833         self.b('')
834         self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
835         self.b('          interface, "%s", iface,' % member)
836         self.b('          %s,' % invoke_callback)
837         self.b('          G_CALLBACK (callback), user_data, destroy,')
838         self.b('          weak_object, FALSE);')
839         self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
840         self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
841         self.b('              "%s",' % member)
842         self.b('              %s,' % collect_callback)
843         self.b('              data,')
844         self.b('              tp_proxy_pending_call_v0_completed,')
845         self.b('              timeout_ms,')
846
847         for arg in in_args:
848             name, info, tp_type, elt = arg
849             ctype, gtype, marshaller, pointer = info
850
851             const = pointer and 'const ' or ''
852
853             self.b('              %s, %s,' % (gtype, name))
854
855         self.b('              G_TYPE_INVALID));')
856         self.b('')
857         self.b('      return data;')
858         self.b('    }')
859         self.b('}')
860         self.b('')
861
862         self.do_method_reentrant(method, iface_lc, member, member_lc,
863                                  in_args, out_args, collect_callback)
864
865         # leave a gap for the end of the method
866         self.d('')
867         self.b('')
868         self.h('')
869
870     def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
871             out_args, collect_callback):
872         # Reentrant blocking calls
873         # Example:
874         # gboolean tp_cli_properties_interface_run_get_properties
875         #   (gpointer proxy,
876         #       gint timeout_ms,
877         #       const GArray *in_properties,
878         #       GPtrArray **out0,
879         #       GError **error,
880         #       GMainLoop **loop);
881
882         run_method_name = '%s_%s_run_%s' % (self.prefix_lc, iface_lc, member_lc)
883         if run_method_name not in self.reentrant_symbols:
884             return
885
886         self.b('typedef struct {')
887         self.b('    GMainLoop *loop;')
888         self.b('    GError **error;')
889
890         for arg in out_args:
891             name, info, tp_type, elt = arg
892             ctype, gtype, marshaller, pointer = info
893
894             self.b('    %s*%s;' % (ctype, name))
895
896         self.b('    unsigned success:1;')
897         self.b('    unsigned completed:1;')
898         self.b('} _%s_%s_run_state_%s;'
899                % (self.prefix_lc, iface_lc, member_lc))
900
901         reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
902                                                          iface_lc,
903                                                          member_lc)
904
905         self.b('static void')
906         self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
907         self.b('    GError *error,')
908         self.b('    GValueArray *args,')
909         self.b('    GCallback unused G_GNUC_UNUSED,')
910         self.b('    gpointer user_data G_GNUC_UNUSED,')
911         self.b('    GObject *unused2 G_GNUC_UNUSED)')
912         self.b('{')
913         self.b('  _%s_%s_run_state_%s *state = user_data;'
914                % (self.prefix_lc, iface_lc, member_lc))
915         self.b('')
916         self.b('  state->success = (error == NULL);')
917         self.b('  state->completed = TRUE;')
918         self.b('  g_main_loop_quit (state->loop);')
919         self.b('')
920         self.b('  if (error != NULL)')
921         self.b('    {')
922         self.b('      if (state->error != NULL)')
923         self.b('        *state->error = error;')
924         self.b('      else')
925         self.b('        g_error_free (error);')
926         self.b('')
927         self.b('      return;')
928         self.b('    }')
929         self.b('')
930
931         for i, arg in enumerate(out_args):
932             name, info, tp_type, elt = arg
933             ctype, gtype, marshaller, pointer = info
934
935             self.b('  if (state->%s != NULL)' % name)
936             if marshaller == 'BOXED':
937                 self.b('    *state->%s = g_value_dup_boxed ('
938                        'args->values + %d);' % (name, i))
939             elif marshaller == 'STRING':
940                 self.b('    *state->%s = g_value_dup_string '
941                        '(args->values + %d);' % (name, i))
942             elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
943                     'INT64', 'UINT64', 'DOUBLE'):
944                 self.b('    *state->%s = g_value_get_%s (args->values + %d);'
945                        % (name, marshaller.lower(), i))
946             else:
947                 assert False, "Don't know how to copy %s" % gtype
948
949             self.b('')
950
951         if len(out_args) > 0:
952             self.b('  g_value_array_free (args);')
953         else:
954             self.b('  if (args != NULL)')
955             self.b('    g_value_array_free (args);')
956
957         self.b('}')
958         self.b('')
959
960         if self.deprecate_reentrant:
961             self.h('#ifndef %s' % self.deprecate_reentrant)
962
963         self.h('gboolean %s (%sproxy,'
964                % (run_method_name, self.proxy_arg))
965         self.h('    gint timeout_ms,')
966
967         self.d('/**')
968         self.d(' * %s:' % run_method_name)
969         self.d(' * @proxy: %s' % self.proxy_doc)
970         self.d(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
971
972         for arg in in_args:
973             name, info, tp_type, elt = arg
974             ctype, gtype, marshaller, pointer = info
975
976             docs = xml_escape(get_docstring(elt) or '(Undocumented)')
977
978             if ctype == 'guint ' and tp_type != '':
979                 docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
980
981             self.d(' * @%s: Used to pass an \'in\' argument: %s'
982                    % (name, docs))
983
984         for arg in out_args:
985             name, info, tp_type, elt = arg
986             ctype, gtype, marshaller, pointer = info
987
988             self.d(' * @%s: Used to return an \'out\' argument if %%TRUE is '
989                    'returned: %s'
990                    % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
991
992         self.d(' * @error: If not %NULL, used to return errors if %FALSE ')
993         self.d(' *  is returned')
994         self.d(' * @loop: If not %NULL, set before re-entering ')
995         self.d(' *  the main loop, to point to a #GMainLoop ')
996         self.d(' *  which can be used to cancel this call with ')
997         self.d(' *  g_main_loop_quit(), causing a return of ')
998         self.d(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
999         self.d(' *')
1000         self.d(' * Call the method %s and run the main loop' % member)
1001         self.d(' * until it returns. Before calling this method, you must')
1002         self.d(' * add a reference to any borrowed objects you need to keep,')
1003         self.d(' * and generally ensure that everything is in a consistent')
1004         self.d(' * state.')
1005         self.d(' *')
1006         self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
1007         self.d(' *')
1008         self.d(' * Returns: TRUE on success, FALSE and sets @error on error')
1009
1010         deprecated = method.getElementsByTagName('tp:deprecated')
1011         if deprecated:
1012             d = deprecated[0]
1013             self.d(' *')
1014             self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
1015
1016         self.d(' */')
1017         self.d('')
1018
1019         self.b('gboolean\n%s (%sproxy,'
1020                % (run_method_name, self.proxy_arg))
1021         self.b('    gint timeout_ms,')
1022
1023         for arg in in_args:
1024             name, info, tp_type, elt = arg
1025             ctype, gtype, marshaller, pointer = info
1026
1027             const = pointer and 'const ' or ''
1028
1029             self.h('    %s%s%s,' % (const, ctype, name))
1030             self.b('    %s%s%s,' % (const, ctype, name))
1031
1032         for arg in out_args:
1033             name, info, tp_type, elt = arg
1034             ctype, gtype, marshaller, pointer = info
1035
1036             self.h('    %s*%s,' % (ctype, name))
1037             self.b('    %s*%s,' % (ctype, name))
1038
1039         self.h('    GError **error,')
1040
1041         if self.deprecate_reentrant:
1042             self.h('    GMainLoop **loop) %s;' % self.deprecation_attribute)
1043             self.h('#endif /* not %s */' % self.deprecate_reentrant)
1044         else:
1045             self.h('    GMainLoop **loop);')
1046
1047         self.h('')
1048
1049         self.b('    GError **error,')
1050         self.b('    GMainLoop **loop)')
1051         self.b('{')
1052         self.b('  DBusGProxy *iface;')
1053         self.b('  GQuark interface = %s;' % self.get_iface_quark())
1054         self.b('  TpProxyPendingCall *pc;')
1055         self.b('  _%s_%s_run_state_%s state = {'
1056                % (self.prefix_lc, iface_lc, member_lc))
1057         self.b('      NULL /* loop */, error,')
1058
1059         for arg in out_args:
1060             name, info, tp_type, elt = arg
1061
1062             self.b('    %s,' % name)
1063
1064         self.b('      FALSE /* completed */, FALSE /* success */ };')
1065         self.b('')
1066         self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
1067                % self.proxy_assert)
1068         self.b('')
1069         self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
1070         self.b('  iface = tp_proxy_borrow_interface_by_id')
1071         self.b('       ((TpProxy *) proxy, interface, error);')
1072         self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')
1073         self.b('')
1074         self.b('  if (iface == NULL)')
1075         self.b('    return FALSE;')
1076         self.b('')
1077         self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
1078         self.b('')
1079         self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
1080         self.b('      interface, "%s", iface,' % member)
1081         self.b('      %s,' % reentrant_invoke)
1082         self.b('      NULL, &state, NULL, NULL, TRUE);')
1083         self.b('')
1084         self.b('  if (loop != NULL)')
1085         self.b('    *loop = state.loop;')
1086         self.b('')
1087         self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
1088         self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
1089         self.b('          "%s",' % member)
1090         self.b('          %s,' % collect_callback)
1091         self.b('          pc,')
1092         self.b('          tp_proxy_pending_call_v0_completed,')
1093         self.b('          timeout_ms,')
1094
1095         for arg in in_args:
1096             name, info, tp_type, elt = arg
1097             ctype, gtype, marshaller, pointer = info
1098
1099             const = pointer and 'const ' or ''
1100
1101             self.b('              %s, %s,' % (gtype, name))
1102
1103         self.b('          G_TYPE_INVALID));')
1104         self.b('')
1105         self.b('  if (!state.completed)')
1106         self.b('    g_main_loop_run (state.loop);')
1107         self.b('')
1108         self.b('  if (!state.completed)')
1109         self.b('    tp_proxy_pending_call_cancel (pc);')
1110         self.b('')
1111         self.b('  if (loop != NULL)')
1112         self.b('    *loop = NULL;')
1113         self.b('')
1114         self.b('  g_main_loop_unref (state.loop);')
1115         self.b('')
1116         self.b('  return state.success;')
1117         self.b('}')
1118         self.b('')
1119
1120     def do_signal_add(self, signal):
1121         marshaller_items = []
1122         gtypes = []
1123
1124         for i in signal.getElementsByTagName('arg'):
1125             name = i.getAttribute('name')
1126             type = i.getAttribute('type')
1127             info = type_to_gtype(type)
1128             # type, GType, STRING, is a pointer
1129             gtypes.append(info[1])
1130
1131         self.b('  dbus_g_proxy_add_signal (proxy, "%s",'
1132                % signal.getAttribute('name'))
1133         for gtype in gtypes:
1134             self.b('      %s,' % gtype)
1135         self.b('      G_TYPE_INVALID);')
1136
1137     def do_interface(self, node):
1138         ifaces = node.getElementsByTagName('interface')
1139         assert len(ifaces) == 1
1140         iface = ifaces[0]
1141         name = node.getAttribute('name').replace('/', '')
1142
1143         self.iface = name
1144         self.iface_lc = name.lower()
1145         self.iface_uc = name.upper()
1146         self.iface_mc = name.replace('_', '')
1147         self.iface_dbus = iface.getAttribute('name')
1148
1149         signals = node.getElementsByTagName('signal')
1150         methods = node.getElementsByTagName('method')
1151
1152         if signals:
1153             self.b('static inline void')
1154             self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1155                     % (self.prefix_lc, name.lower()))
1156             self.b('{')
1157
1158             if self.tp_proxy_api >= (0, 7, 6):
1159                 self.b('  if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1160                        '(proxy))')
1161                 self.b('    return;')
1162
1163             for signal in signals:
1164                 self.do_signal_add(signal)
1165
1166             self.b('}')
1167             self.b('')
1168             self.b('')
1169
1170         for signal in signals:
1171             self.do_signal(name, signal)
1172
1173         for method in methods:
1174             self.do_method(name, method)
1175
1176         self.iface_dbus = None
1177
1178     def __call__(self):
1179
1180         if self.guard is not None:
1181             self.h('#ifndef %s' % self.guard)
1182             self.h('#define %s' % self.guard)
1183             self.h('')
1184
1185         self.h('G_BEGIN_DECLS')
1186         self.h('')
1187
1188         self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
1189         self.b(' * confused by seeing function definitions, so mark it as: */')
1190         self.b('/*<private_header>*/')
1191         self.b('')
1192
1193         nodes = self.dom.getElementsByTagName('node')
1194         nodes.sort(cmp_by_name)
1195
1196         for node in nodes:
1197             self.do_interface(node)
1198
1199         if self.group is not None:
1200
1201             self.b('/*')
1202             self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
1203             self.b(' * @self: the #TpProxy')
1204             self.b(' * @quark: a quark whose string value is the interface')
1205             self.b(' *   name whose signals should be added')
1206             self.b(' * @proxy: the D-Bus proxy to which to add the signals')
1207             self.b(' * @unused: not used for anything')
1208             self.b(' *')
1209             self.b(' * Tell dbus-glib that @proxy has the signatures of all')
1210             self.b(' * signals on the given interface, if it\'s one we')
1211             self.b(' * support.')
1212             self.b(' *')
1213             self.b(' * This function should be used as a signal handler for')
1214             self.b(' * #TpProxy::interface-added.')
1215             self.b(' */')
1216             self.b('static void')
1217             self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
1218                     % (self.prefix_lc, self.group))
1219             self.b('    guint quark,')
1220             self.b('    DBusGProxy *proxy,')
1221             self.b('    gpointer unused G_GNUC_UNUSED)')
1222
1223             self.b('{')
1224
1225             for node in nodes:
1226                 iface = node.getElementsByTagName('interface')[0]
1227                 self.iface_dbus = iface.getAttribute('name')
1228                 signals = node.getElementsByTagName('signal')
1229                 if not signals:
1230                     continue
1231                 name = node.getAttribute('name').replace('/', '').lower()
1232                 self.iface_uc = name.upper()
1233                 self.b('  if (quark == %s)' % self.get_iface_quark())
1234                 self.b('    %s_add_signals_for_%s (proxy);'
1235                        % (self.prefix_lc, name))
1236
1237             self.b('}')
1238             self.b('')
1239
1240         self.h('G_END_DECLS')
1241         self.h('')
1242
1243         if self.guard is not None:
1244             self.h('#endif /* defined (%s) */' % self.guard)
1245             self.h('')
1246
1247         file_set_contents(self.basename + '.h', '\n'.join(self.__header))
1248         file_set_contents(self.basename + '-body.h', '\n'.join(self.__body))
1249         file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs))
1250
1251 def types_to_gtypes(types):
1252     return [type_to_gtype(t)[1] for t in types]
1253
1254
1255 if __name__ == '__main__':
1256     options, argv = gnu_getopt(sys.argv[1:], '',
1257                                ['group=', 'subclass=', 'subclass-assert=',
1258                                 'iface-quark-prefix=', 'tp-proxy-api=',
1259                                 'generate-reentrant=', 'deprecate-reentrant=',
1260                                 'deprecation-attribute=', 'guard='])
1261
1262     opts = {}
1263
1264     for option, value in options:
1265         opts[option] = value
1266
1267     dom = xml.dom.minidom.parse(argv[0])
1268
1269     Generator(dom, argv[1], argv[2], opts)()