57254008d9bcc6907ca8823146c4cdc6448d65df
[platform/upstream/glib.git] / gio / gdbus-2.0 / codegen / codegen_main.py
1 # -*- Mode: Python -*-
2
3 # GDBus - GLib D-Bus Library
4 #
5 # Copyright (C) 2008-2011 Red Hat, Inc.
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2 of the License, or (at your option) any later version.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General
18 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #
20 # Author: David Zeuthen <davidz@redhat.com>
21
22 import sys
23 import optparse
24 from os import path
25
26 from . import config
27 from . import utils
28 from . import dbustypes
29 from . import parser
30 from . import codegen
31 from . import codegen_docbook
32
33 def find_arg(arg_list, arg_name):
34     for a in arg_list:
35         if a.name == arg_name:
36             return a
37     return None
38
39 def find_method(iface, method):
40     for m in iface.methods:
41         if m.name == method:
42             return m
43     return None
44
45 def find_signal(iface, signal):
46     for m in iface.signals:
47         if m.name == signal:
48             return m
49     return None
50
51 def find_prop(iface, prop):
52     for m in iface.properties:
53         if m.name == prop:
54             return m
55     return None
56
57 def apply_annotation(iface_list, iface, method, signal, prop, arg, key, value):
58     iface_obj = None
59     for i in iface_list:
60         if i.name == iface:
61             iface_obj = i
62             break
63
64     if iface_obj == None:
65         raise RuntimeError('No interface %s'%iface)
66
67     target_obj = None
68
69     if method:
70         method_obj = find_method(iface_obj, method)
71         if method_obj == None:
72             raise RuntimeError('No method %s on interface %s'%(method, iface))
73         if arg:
74             arg_obj = find_arg(method_obj.in_args, arg)
75             if (arg_obj == None):
76                 arg_obj = find_arg(method_obj.out_args, arg)
77                 if (arg_obj == None):
78                     raise RuntimeError('No arg %s on method %s on interface %s'%(arg, method, iface))
79             target_obj = arg_obj
80         else:
81             target_obj = method_obj
82     elif signal:
83         signal_obj = find_signal(iface_obj, signal)
84         if signal_obj == None:
85             raise RuntimeError('No signal %s on interface %s'%(signal, iface))
86         if arg:
87             arg_obj = find_arg(signal_obj.args, arg)
88             if (arg_obj == None):
89                 raise RuntimeError('No arg %s on signal %s on interface %s'%(arg, signal, iface))
90             target_obj = arg_obj
91         else:
92             target_obj = signal_obj
93     elif prop:
94         prop_obj = find_prop(iface_obj, prop)
95         if prop_obj == None:
96             raise RuntimeError('No property %s on interface %s'%(prop, iface))
97         target_obj = prop_obj
98     else:
99         target_obj = iface_obj
100     target_obj.annotations.insert(0, dbustypes.Annotation(key, value))
101
102
103 def apply_annotations(iface_list, annotation_list):
104     # apply annotations given on the command line
105     for (what, key, value) in annotation_list:
106         pos = what.find('::')
107         if pos != -1:
108             # signal
109             iface = what[0:pos];
110             signal = what[pos + 2:]
111             pos = signal.find('[')
112             if pos != -1:
113                 arg = signal[pos + 1:]
114                 signal = signal[0:pos]
115                 pos = arg.find(']')
116                 arg = arg[0:pos]
117                 apply_annotation(iface_list, iface, None, signal, None, arg, key, value)
118             else:
119                 apply_annotation(iface_list, iface, None, signal, None, None, key, value)
120         else:
121             pos = what.find(':')
122             if pos != -1:
123                 # property
124                 iface = what[0:pos];
125                 prop = what[pos + 1:]
126                 apply_annotation(iface_list, iface, None, None, prop, None, key, value)
127             else:
128                 pos = what.find('()')
129                 if pos != -1:
130                     # method
131                     combined = what[0:pos]
132                     pos = combined.rfind('.')
133                     iface = combined[0:pos]
134                     method = combined[pos + 1:]
135                     pos = what.find('[')
136                     if pos != -1:
137                         arg = what[pos + 1:]
138                         pos = arg.find(']')
139                         arg = arg[0:pos]
140                         apply_annotation(iface_list, iface, method, None, None, arg, key, value)
141                     else:
142                         apply_annotation(iface_list, iface, method, None, None, None, key, value)
143                 else:
144                     # must be an interface
145                     iface = what
146                     apply_annotation(iface_list, iface, None, None, None, None, key, value)
147
148 def codegen_main():
149     arg_parser = optparse.OptionParser('%prog [options]')
150     arg_parser.add_option('', '--xml-files', metavar='FILE', action='append',
151                           help='D-Bus introspection XML file')
152     arg_parser.add_option('', '--interface-prefix', metavar='PREFIX', default='',
153                             help='String to strip from D-Bus interface names for code and docs')
154     arg_parser.add_option('', '--c-namespace', metavar='NAMESPACE', default='',
155                             help='The namespace to use for generated C code')
156     arg_parser.add_option('', '--c-generate-object-manager', action='store_true',
157                             help='Generate a GDBusObjectManagerClient subclass when generating C code')
158     arg_parser.add_option('', '--generate-c-code', metavar='OUTFILES',
159                           help='Generate C code in OUTFILES.[ch]')
160     arg_parser.add_option('', '--c-generate-autocleanup', type='choice', choices=['none', 'objects', 'all'], default='objects',
161                              help='Generate autocleanup support')
162     arg_parser.add_option('', '--generate-docbook', metavar='OUTFILES',
163                           help='Generate Docbook in OUTFILES-org.Project.IFace.xml')
164     arg_parser.add_option('', '--annotate', nargs=3, action='append', metavar='WHAT KEY VALUE',
165                           help='Add annotation (may be used several times)')
166     arg_parser.add_option('', '--output-directory', metavar='OUTDIR', default='',
167                           help='Location to output generated files')
168     (opts, args) = arg_parser.parse_args();
169
170     all_ifaces = []
171     for fname in args:
172         f = open(fname, 'rb')
173         xml_data = f.read()
174         f.close()
175         parsed_ifaces = parser.parse_dbus_xml(xml_data)
176         all_ifaces.extend(parsed_ifaces)
177
178     if opts.annotate != None:
179         apply_annotations(all_ifaces, opts.annotate)
180
181     for i in all_ifaces:
182         i.post_process(opts.interface_prefix, opts.c_namespace)
183
184     docbook = opts.generate_docbook
185     docbook_gen = codegen_docbook.DocbookCodeGenerator(all_ifaces, docbook);
186     if docbook:
187         ret = docbook_gen.generate()
188
189     c_code = opts.generate_c_code
190     if c_code:
191         outdir = opts.output_directory
192         header_name = c_code + '.h'
193         h = open(path.join(outdir, header_name), 'w')
194         c = open(path.join(outdir, c_code + '.c'), 'w')
195         gen = codegen.CodeGenerator(all_ifaces,
196                                     opts.c_namespace,
197                                     opts.interface_prefix,
198                                     opts.c_generate_object_manager,
199                                     opts.c_generate_autocleanup,
200                                     docbook_gen,
201                                     h, c,
202                                     header_name)
203         ret = gen.generate()
204         h.close()
205         c.close()
206
207     sys.exit(0)
208
209 if __name__ == "__main__":
210     codegen_main()