]> git.0d.be Git - empathy.git/blob - tools/glib-ginterface-gen.py
Updated Polish translation
[empathy.git] / tools / glib-ginterface-gen.py
1 #!/usr/bin/python
2
3 # glib-ginterface-gen.py: service-side interface generator
4 #
5 # Generate dbus-glib 0.x service GInterfaces 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, 2007 Collabora Limited
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
29 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
30         camelcase_to_lower, NS_TP, dbus_gutils_wincaps_to_uscore, \
31         signal_to_marshal_name, method_to_glue_marshal_name
32
33
34 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
35
36 class Generator(object):
37
38     def __init__(self, dom, prefix, basename, signal_marshal_prefix,
39                  headers, end_headers, not_implemented_func,
40                  allow_havoc):
41         self.dom = dom
42         self.__header = []
43         self.__body = []
44
45         assert prefix.endswith('_')
46         assert not signal_marshal_prefix.endswith('_')
47
48         # The main_prefix, sub_prefix thing is to get:
49         # FOO_ -> (FOO_, _)
50         # FOO_SVC_ -> (FOO_, _SVC_)
51         # but
52         # FOO_BAR/ -> (FOO_BAR_, _)
53         # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
54
55         if '/' in prefix:
56             main_prefix, sub_prefix = prefix.upper().split('/', 1)
57             prefix = prefix.replace('/', '_')
58         else:
59             main_prefix, sub_prefix = prefix.upper().split('_', 1)
60
61         self.MAIN_PREFIX_ = main_prefix + '_'
62         self._SUB_PREFIX_ = '_' + sub_prefix
63
64         self.Prefix_ = prefix
65         self.Prefix = prefix.replace('_', '')
66         self.prefix_ = prefix.lower()
67         self.PREFIX_ = prefix.upper()
68
69         self.signal_marshal_prefix = signal_marshal_prefix
70         self.headers = headers
71         self.end_headers = end_headers
72         self.not_implemented_func = not_implemented_func
73         self.allow_havoc = allow_havoc
74
75     def h(self, s):
76         self.__header.append(s)
77
78     def b(self, s):
79         self.__body.append(s)
80
81     def do_node(self, node):
82         node_name = node.getAttribute('name').replace('/', '')
83         node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
84         node_name_lc = self.node_name_lc = node_name.lower()
85         node_name_uc = self.node_name_uc = node_name.upper()
86
87         interfaces = node.getElementsByTagName('interface')
88         assert len(interfaces) == 1, interfaces
89         interface = interfaces[0]
90         self.iface_name = interface.getAttribute('name')
91
92         tmp = interface.getAttribute('tp:implement-service')
93         if tmp == "no":
94             return
95
96         tmp = interface.getAttribute('tp:causes-havoc')
97         if tmp and not self.allow_havoc:
98             raise AssertionError('%s is %s' % (self.iface_name, tmp))
99
100         self.b('static const DBusGObjectInfo _%s%s_object_info;'
101                % (self.prefix_, node_name_lc))
102         self.b('')
103
104         methods = interface.getElementsByTagName('method')
105         signals = interface.getElementsByTagName('signal')
106         properties = interface.getElementsByTagName('property')
107         # Don't put properties in dbus-glib glue
108         glue_properties = []
109
110         self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
111         self.b('    GTypeInterface parent_class;')
112         for method in methods:
113             self.b('    %s %s;' % self.get_method_impl_names(method))
114         self.b('};')
115         self.b('')
116
117         if signals:
118             self.b('enum {')
119             for signal in signals:
120                 self.b('    %s,' % self.get_signal_const_entry(signal))
121             self.b('    N_%s_SIGNALS' % node_name_uc)
122             self.b('};')
123             self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
124                    % (node_name_lc, node_name_uc))
125             self.b('')
126
127         self.b('static void %s%s_base_init (gpointer klass);'
128                % (self.prefix_, node_name_lc))
129         self.b('')
130
131         self.b('GType')
132         self.b('%s%s_get_type (void)'
133                % (self.prefix_, node_name_lc))
134         self.b('{')
135         self.b('  static GType type = 0;')
136         self.b('')
137         self.b('  if (G_UNLIKELY (type == 0))')
138         self.b('    {')
139         self.b('      static const GTypeInfo info = {')
140         self.b('        sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
141         self.b('        %s%s_base_init, /* base_init */'
142                % (self.prefix_, node_name_lc))
143         self.b('        NULL, /* base_finalize */')
144         self.b('        NULL, /* class_init */')
145         self.b('        NULL, /* class_finalize */')
146         self.b('        NULL, /* class_data */')
147         self.b('        0,')
148         self.b('        0, /* n_preallocs */')
149         self.b('        NULL /* instance_init */')
150         self.b('      };')
151         self.b('')
152         self.b('      type = g_type_register_static (G_TYPE_INTERFACE,')
153         self.b('          "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
154         self.b('    }')
155         self.b('')
156         self.b('  return type;')
157         self.b('}')
158         self.b('')
159
160         self.h('/**')
161         self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
162         self.h(' *')
163         self.h(' * Dummy typedef representing any implementation of this '
164                'interface.')
165         self.h(' */')
166         self.h('typedef struct _%s%s %s%s;'
167                % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
168         self.h('')
169         self.h('/**')
170         self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed))
171         self.h(' *')
172         self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
173         self.h(' */')
174         self.h('typedef struct _%s%sClass %s%sClass;'
175                % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
176         self.h('')
177         self.h('GType %s%s_get_type (void);'
178                % (self.prefix_, node_name_lc))
179
180         gtype = self.current_gtype = \
181                 self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
182         classname = self.Prefix + node_name_mixed
183
184         self.h('#define %s \\\n  (%s%s_get_type ())'
185                % (gtype, self.prefix_, node_name_lc))
186         self.h('#define %s%s(obj) \\\n'
187                '  (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
188                % (self.PREFIX_, node_name_uc, gtype, classname))
189         self.h('#define %sIS%s%s(obj) \\\n'
190                '  (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
191                % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
192         self.h('#define %s%s_GET_CLASS(obj) \\\n'
193                '  (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
194                % (self.PREFIX_, node_name_uc, gtype, classname))
195         self.h('')
196         self.h('')
197
198         base_init_code = []
199
200         for method in methods:
201             self.do_method(method)
202
203         for signal in signals:
204             base_init_code.extend(self.do_signal(signal))
205
206         self.b('static inline void')
207         self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
208                % (self.prefix_, node_name_lc))
209         self.b('{')
210         self.b('  static TpDBusPropertiesMixinPropInfo properties[%d] = {'
211                % (len(properties) + 1))
212
213         for m in properties:
214             access = m.getAttribute('access')
215             assert access in ('read', 'write', 'readwrite')
216
217             if access == 'read':
218                 flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
219             elif access == 'write':
220                 flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
221             else:
222                 flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
223                          'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
224
225             self.b('      { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
226                    % (flags, m.getAttribute('type'), m.getAttribute('name')))
227
228         self.b('      { 0, 0, NULL, 0, NULL, NULL }')
229         self.b('  };')
230         self.b('  static TpDBusPropertiesMixinIfaceInfo interface =')
231         self.b('      { 0, properties, NULL, NULL };')
232         self.b('')
233         self.b('  interface.dbus_interface = g_quark_from_static_string '
234                '("%s");' % self.iface_name)
235
236         for i, m in enumerate(properties):
237             self.b('  properties[%d].name = g_quark_from_static_string ("%s");'
238                    % (i, m.getAttribute('name')))
239             self.b('  properties[%d].type = %s;'
240                    % (i, type_to_gtype(m.getAttribute('type'))[1]))
241
242         self.b('  tp_svc_interface_set_dbus_properties_info (%s, &interface);'
243                % self.current_gtype)
244
245         self.b('')
246         for s in base_init_code:
247             self.b(s)
248         self.b('  dbus_g_object_type_install_info (%s%s_get_type (),'
249                % (self.prefix_, node_name_lc))
250         self.b('      &_%s%s_object_info);'
251                % (self.prefix_, node_name_lc))
252         self.b('}')
253
254         self.b('static void')
255         self.b('%s%s_base_init (gpointer klass)'
256                % (self.prefix_, node_name_lc))
257         self.b('{')
258         self.b('  static gboolean initialized = FALSE;')
259         self.b('')
260         self.b('  if (!initialized)')
261         self.b('    {')
262         self.b('      initialized = TRUE;')
263         self.b('      %s%s_base_init_once (klass);'
264                % (self.prefix_, node_name_lc))
265         self.b('    }')
266         # insert anything we need to do per implementation here
267         self.b('}')
268
269         self.h('')
270
271         self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
272                % (self.prefix_, node_name_lc))
273
274         method_blob, offsets = self.get_method_glue(methods)
275
276         for method, offset in zip(methods, offsets):
277             self.do_method_glue(method, offset)
278
279         self.b('};')
280         self.b('')
281
282         self.b('static const DBusGObjectInfo _%s%s_object_info = {'
283                % (self.prefix_, node_name_lc))
284         self.b('  0,')  # version
285         self.b('  _%s%s_methods,' % (self.prefix_, node_name_lc))
286         self.b('  %d,' % len(methods))
287         self.b('"' + method_blob.replace('\0', '\\0') + '",')
288         self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",')
289         self.b('"' +
290                self.get_property_glue(glue_properties).replace('\0', '\\0') +
291                '",')
292         self.b('};')
293         self.b('')
294
295         self.node_name_mixed = None
296         self.node_name_lc = None
297         self.node_name_uc = None
298
299     def get_method_glue(self, methods):
300         info = []
301         offsets = []
302
303         for method in methods:
304             offsets.append(len(''.join(info)))
305
306             info.append(self.iface_name + '\0')
307             info.append(method.getAttribute('name') + '\0')
308
309             info.append('A\0')    # async
310
311             counter = 0
312             for arg in method.getElementsByTagName('arg'):
313                 out = arg.getAttribute('direction') == 'out'
314
315                 name = arg.getAttribute('name')
316                 if not name:
317                     assert out
318                     name = 'arg%u' % counter
319                 counter += 1
320
321                 info.append(name + '\0')
322
323                 if out:
324                     info.append('O\0')
325                 else:
326                     info.append('I\0')
327
328                 if out:
329                     info.append('F\0')    # not const
330                     info.append('N\0')    # not error or return
331                 info.append(arg.getAttribute('type') + '\0')
332
333             info.append('\0')
334
335         return ''.join(info) + '\0', offsets
336
337     def do_method_glue(self, method, offset):
338         lc_name = camelcase_to_lower(method.getAttribute('name'))
339
340         marshaller = method_to_glue_marshal_name(method,
341                 self.signal_marshal_prefix)
342         wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
343
344         self.b("  { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
345
346     def get_signal_glue(self, signals):
347         info = []
348
349         for signal in signals:
350             info.append(self.iface_name)
351             info.append(signal.getAttribute('name'))
352
353         return '\0'.join(info) + '\0\0'
354
355     # the implementation can be the same
356     get_property_glue = get_signal_glue
357
358     def get_method_impl_names(self, method):
359         dbus_method_name = method.getAttribute('name')
360         class_member_name = camelcase_to_lower(dbus_method_name)
361         stub_name = (self.prefix_ + self.node_name_lc + '_' +
362                      class_member_name)
363         return (stub_name + '_impl', class_member_name)
364
365     def do_method(self, method):
366         assert self.node_name_mixed is not None
367
368         in_class = []
369
370         # Examples refer to Thing.DoStuff (su) -> ii
371
372         # DoStuff
373         dbus_method_name = method.getAttribute('name')
374         # do_stuff
375         class_member_name = camelcase_to_lower(dbus_method_name)
376         # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
377         #   DBusGMethodInvocation *);
378         stub_name = (self.prefix_ + self.node_name_lc + '_' +
379                      class_member_name)
380         # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
381         #   const char *, guint, DBusGMethodInvocation);
382         impl_name = stub_name + '_impl'
383         # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
384         #   gint, gint);
385         ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
386                     class_member_name)
387
388         # Gather arguments
389         in_args = []
390         out_args = []
391         for i in method.getElementsByTagName('arg'):
392             name = i.getAttribute('name')
393             direction = i.getAttribute('direction') or 'in'
394             dtype = i.getAttribute('type')
395
396             assert direction in ('in', 'out')
397
398             if name:
399                 name = direction + '_' + name
400             elif direction == 'in':
401                 name = direction + str(len(in_args))
402             else:
403                 name = direction + str(len(out_args))
404
405             ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
406
407             if pointer:
408                 ctype = 'const ' + ctype
409
410             struct = (ctype, name)
411
412             if direction == 'in':
413                 in_args.append(struct)
414             else:
415                 out_args.append(struct)
416
417         # Implementation type declaration (in header, docs in body)
418         self.b('/**')
419         self.b(' * %s:' % impl_name)
420         self.b(' * @self: The object implementing this interface')
421         for (ctype, name) in in_args:
422             self.b(' * @%s: %s (FIXME, generate documentation)'
423                    % (name, ctype))
424         self.b(' * @context: Used to return values or throw an error')
425         self.b(' *')
426         self.b(' * The signature of an implementation of the D-Bus method')
427         self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
428         self.b(' */')
429         self.h('typedef void (*%s) (%s%s *self,'
430           % (impl_name, self.Prefix, self.node_name_mixed))
431         for (ctype, name) in in_args:
432             self.h('    %s%s,' % (ctype, name))
433         self.h('    DBusGMethodInvocation *context);')
434
435         # Class member (in class definition)
436         in_class.append('    %s %s;' % (impl_name, class_member_name))
437
438         # Stub definition (in body only - it's static)
439         self.b('static void')
440         self.b('%s (%s%s *self,'
441            % (stub_name, self.Prefix, self.node_name_mixed))
442         for (ctype, name) in in_args:
443             self.b('    %s%s,' % (ctype, name))
444         self.b('    DBusGMethodInvocation *context)')
445         self.b('{')
446         self.b('  %s impl = (%s%s_GET_CLASS (self)->%s);'
447           % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
448         self.b('')
449         self.b('  if (impl != NULL)')
450         tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
451         self.b('    {')
452         self.b('      (impl) (%s);' % ',\n        '.join(tmp))
453         self.b('    }')
454         self.b('  else')
455         self.b('    {')
456         if self.not_implemented_func:
457             self.b('      %s (context);' % self.not_implemented_func)
458         else:
459             self.b('      GError e = { DBUS_GERROR, ')
460             self.b('           DBUS_GERROR_UNKNOWN_METHOD,')
461             self.b('           "Method not implemented" };')
462             self.b('')
463             self.b('      dbus_g_method_return_error (context, &e);')
464         self.b('    }')
465         self.b('}')
466         self.b('')
467
468         # Implementation registration (in both header and body)
469         self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
470                % (self.prefix_, self.node_name_lc, class_member_name,
471                   self.Prefix, self.node_name_mixed, impl_name))
472
473         self.b('/**')
474         self.b(' * %s%s_implement_%s:'
475                % (self.prefix_, self.node_name_lc, class_member_name))
476         self.b(' * @klass: A class whose instances implement this interface')
477         self.b(' * @impl: A callback used to implement the %s D-Bus method'
478                % dbus_method_name)
479         self.b(' *')
480         self.b(' * Register an implementation for the %s method in the vtable'
481                % dbus_method_name)
482         self.b(' * of an implementation of this interface. To be called from')
483         self.b(' * the interface init function.')
484         self.b(' */')
485         self.b('void')
486         self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
487                % (self.prefix_, self.node_name_lc, class_member_name,
488                   self.Prefix, self.node_name_mixed, impl_name))
489         self.b('{')
490         self.b('  klass->%s = impl;' % class_member_name)
491         self.b('}')
492         self.b('')
493
494         # Return convenience function (static inline, in header)
495         self.h('/**')
496         self.h(' * %s:' % ret_name)
497         self.h(' * @context: The D-Bus method invocation context')
498         for (ctype, name) in out_args:
499             self.h(' * @%s: %s (FIXME, generate documentation)'
500                    % (name, ctype))
501         self.h(' *')
502         self.h(' * Return successfully by calling dbus_g_method_return().')
503         self.h(' * This inline function exists only to provide type-safety.')
504         self.h(' */')
505         tmp = (['DBusGMethodInvocation *context'] +
506                [ctype + name for (ctype, name) in out_args])
507         self.h('static inline')
508         self.h('/* this comment is to stop gtkdoc realising this is static */')
509         self.h(('void %s (' % ret_name) + (',\n    '.join(tmp)) + ');')
510         self.h('static inline void')
511         self.h(('%s (' % ret_name) + (',\n    '.join(tmp)) + ')')
512         self.h('{')
513         tmp = ['context'] + [name for (ctype, name) in out_args]
514         self.h('  dbus_g_method_return (' + ',\n      '.join(tmp) + ');')
515         self.h('}')
516         self.h('')
517
518         return in_class
519
520     def get_signal_const_entry(self, signal):
521         assert self.node_name_uc is not None
522         return ('SIGNAL_%s_%s'
523                 % (self.node_name_uc, signal.getAttribute('name')))
524
525     def do_signal(self, signal):
526         assert self.node_name_mixed is not None
527
528         in_base_init = []
529
530         # for signal: Thing::StuffHappened (s, u)
531         # we want to emit:
532         # void tp_svc_thing_emit_stuff_happened (gpointer instance,
533         #    const char *arg0, guint arg1);
534
535         dbus_name = signal.getAttribute('name')
536         stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
537                      camelcase_to_lower(dbus_name))
538         const_name = self.get_signal_const_entry(signal)
539
540         # Gather arguments
541         args = []
542         for i in signal.getElementsByTagName('arg'):
543             name = i.getAttribute('name')
544             dtype = i.getAttribute('type')
545             tp_type = i.getAttribute('tp:type')
546
547             if name:
548                 name = 'arg_' + name
549             else:
550                 name = 'arg' + str(len(args))
551
552             ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
553
554             if pointer:
555                 ctype = 'const ' + ctype
556
557             struct = (ctype, name, gtype)
558             args.append(struct)
559
560         tmp = (['gpointer instance'] +
561                [ctype + name for (ctype, name, gtype) in args])
562
563         self.h(('void %s (' % stub_name) + (',\n    '.join(tmp)) + ');')
564
565         # FIXME: emit docs
566
567         self.b('/**')
568         self.b(' * %s:' % stub_name)
569         self.b(' * @instance: The object implementing this interface')
570         for (ctype, name, gtype) in args:
571             self.b(' * @%s: %s (FIXME, generate documentation)'
572                    % (name, ctype))
573         self.b(' *')
574         self.b(' * Type-safe wrapper around g_signal_emit to emit the')
575         self.b(' * %s signal on interface %s.'
576                % (dbus_name, self.iface_name))
577         self.b(' */')
578
579         self.b('void')
580         self.b(('%s (' % stub_name) + (',\n    '.join(tmp)) + ')')
581         self.b('{')
582         self.b('  g_assert (instance != NULL);')
583         self.b('  g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
584                % (self.current_gtype))
585         tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
586                 '0'] + [name for (ctype, name, gtype) in args])
587         self.b('  g_signal_emit (' + ',\n      '.join(tmp) + ');')
588         self.b('}')
589         self.b('')
590
591         signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_',
592                 '-')
593         in_base_init.append('  /**')
594         in_base_init.append('   * %s%s::%s:'
595                 % (self.Prefix, self.node_name_mixed, signal_name))
596         for (ctype, name, gtype) in args:
597             in_base_init.append('   * @%s: %s (FIXME, generate documentation)'
598                    % (name, ctype))
599         in_base_init.append('   *')
600         in_base_init.append('   * The %s D-Bus signal is emitted whenever '
601                 'this GObject signal is.' % dbus_name)
602         in_base_init.append('   */')
603         in_base_init.append('  %s_signals[%s] ='
604                             % (self.node_name_lc, const_name))
605         in_base_init.append('  g_signal_new ("%s",' % signal_name)
606         in_base_init.append('      G_OBJECT_CLASS_TYPE (klass),')
607         in_base_init.append('      G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
608         in_base_init.append('      0,')
609         in_base_init.append('      NULL, NULL,')
610         in_base_init.append('      %s,'
611                 % signal_to_marshal_name(signal, self.signal_marshal_prefix))
612         in_base_init.append('      G_TYPE_NONE,')
613         tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
614         in_base_init.append('      %s);' % ',\n      '.join(tmp))
615         in_base_init.append('')
616
617         return in_base_init
618
619     def __call__(self):
620         self.h('#include <glib-object.h>')
621         self.h('#include <dbus/dbus-glib.h>')
622         self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
623         self.h('')
624         self.h('G_BEGIN_DECLS')
625         self.h('')
626
627         self.b('#include "%s.h"' % basename)
628         self.b('')
629         for header in self.headers:
630             self.b('#include %s' % header)
631         self.b('')
632
633         nodes = self.dom.getElementsByTagName('node')
634         nodes.sort(cmp_by_name)
635
636         for node in nodes:
637             self.do_node(node)
638
639         self.h('')
640         self.h('G_END_DECLS')
641
642         self.b('')
643         for header in self.end_headers:
644             self.b('#include %s' % header)
645
646         self.h('')
647         self.b('')
648         open(basename + '.h', 'w').write('\n'.join(self.__header))
649         open(basename + '.c', 'w').write('\n'.join(self.__body))
650
651
652 def cmdline_error():
653     print """\
654 usage:
655     gen-ginterface [OPTIONS] xmlfile Prefix_
656 options:
657     --include='<header.h>' (may be repeated)
658     --include='"header.h"' (ditto)
659     --include-end='"header.h"' (ditto)
660         Include extra headers in the generated .c file
661     --signal-marshal-prefix='prefix'
662         Use the given prefix on generated signal marshallers (default is
663         prefix.lower()).
664     --filename='BASENAME'
665         Set the basename for the output files (default is prefix.lower()
666         + 'ginterfaces')
667     --not-implemented-func='symbol'
668         Set action when methods not implemented in the interface vtable are
669         called. symbol must have signature
670             void symbol (DBusGMethodInvocation *context)
671         and return some sort of "not implemented" error via
672             dbus_g_method_return_error (context, ...)
673 """
674     sys.exit(1)
675
676
677 if __name__ == '__main__':
678     from getopt import gnu_getopt
679
680     options, argv = gnu_getopt(sys.argv[1:], '',
681                                ['filename=', 'signal-marshal-prefix=',
682                                 'include=', 'include-end=',
683                                 'allow-unstable',
684                                 'not-implemented-func='])
685
686     try:
687         prefix = argv[1]
688     except IndexError:
689         cmdline_error()
690
691     basename = prefix.lower() + 'ginterfaces'
692     signal_marshal_prefix = prefix.lower().rstrip('_')
693     headers = []
694     end_headers = []
695     not_implemented_func = ''
696     allow_havoc = False
697
698     for option, value in options:
699         if option == '--filename':
700             basename = value
701         elif option == '--signal-marshal-prefix':
702             signal_marshal_prefix = value
703         elif option == '--include':
704             if value[0] not in '<"':
705                 value = '"%s"' % value
706             headers.append(value)
707         elif option == '--include-end':
708             if value[0] not in '<"':
709                 value = '"%s"' % value
710             end_headers.append(value)
711         elif option == '--not-implemented-func':
712             not_implemented_func = value
713         elif option == '--allow-unstable':
714             allow_havoc = True
715
716     try:
717         dom = xml.dom.minidom.parse(argv[0])
718     except IndexError:
719         cmdline_error()
720
721     Generator(dom, prefix, basename, signal_marshal_prefix, headers,
722               end_headers, not_implemented_func, allow_havoc)()