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