4 # GDBus - GLib D-Bus Library
6 # Copyright (C) 2008-2011 Red Hat, Inc.
7 # Copyright (C) 2018 Iñigo Martínez <inigomartinez@gmail.com>
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General
20 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 # Author: David Zeuthen <davidz@redhat.com>
29 from . import dbustypes
32 from . import codegen_docbook
33 from .utils
import print_error
, print_warning
35 def find_arg(arg_list
, arg_name
):
37 if a
.name
== arg_name
:
41 def find_method(iface
, method
):
42 for m
in iface
.methods
:
47 def find_signal(iface
, signal
):
48 for m
in iface
.signals
:
53 def find_prop(iface
, prop
):
54 for m
in iface
.properties
:
59 def apply_annotation(iface_list
, iface
, method
, signal
, prop
, arg
, key
, value
):
67 print_error('No interface "{}"'.format(iface
))
72 method_obj
= find_method(iface_obj
, method
)
73 if method_obj
is None:
74 print_error('No method "{}" on interface "{}"'.format(method
, iface
))
76 arg_obj
= find_arg(method_obj
.in_args
, arg
)
78 arg_obj
= find_arg(method_obj
.out_args
, arg
)
80 print_error('No arg "{}" on method "{}" on interface "{}"'.format(arg
, method
, iface
))
83 target_obj
= method_obj
85 signal_obj
= find_signal(iface_obj
, signal
)
86 if signal_obj
is None:
87 print_error('No signal "{}" on interface "{}"'.format(signal
, iface
))
89 arg_obj
= find_arg(signal_obj
.args
, arg
)
91 print_error('No arg "{}" on signal "{}" on interface "{}"'.format(arg
, signal
, iface
))
94 target_obj
= signal_obj
96 prop_obj
= find_prop(iface_obj
, prop
)
98 print_error('No property "{}" on interface "{}"'.format(prop
, iface
))
101 target_obj
= iface_obj
102 target_obj
.annotations
.insert(0, dbustypes
.Annotation(key
, value
))
105 def apply_annotations(iface_list
, annotation_list
):
106 # apply annotations given on the command line
107 for (what
, key
, value
) in annotation_list
:
108 pos
= what
.find('::')
112 signal
= what
[pos
+ 2:]
113 pos
= signal
.find('[')
115 arg
= signal
[pos
+ 1:]
116 signal
= signal
[0:pos
]
119 apply_annotation(iface_list
, iface
, None, signal
, None, arg
, key
, value
)
121 apply_annotation(iface_list
, iface
, None, signal
, None, None, key
, value
)
127 prop
= what
[pos
+ 1:]
128 apply_annotation(iface_list
, iface
, None, None, prop
, None, key
, value
)
130 pos
= what
.find('()')
133 combined
= what
[0:pos
]
134 pos
= combined
.rfind('.')
135 iface
= combined
[0:pos
]
136 method
= combined
[pos
+ 1:]
142 apply_annotation(iface_list
, iface
, method
, None, None, arg
, key
, value
)
144 apply_annotation(iface_list
, iface
, method
, None, None, None, key
, value
)
146 # must be an interface
148 apply_annotation(iface_list
, iface
, None, None, None, None, key
, value
)
151 arg_parser
= argparse
.ArgumentParser(description
='D-Bus code and documentation generator')
152 arg_parser
.add_argument('files', metavar
='FILE', nargs
='*',
153 help='D-Bus introspection XML file')
154 arg_parser
.add_argument('--xml-files', metavar
='FILE', action
='append', default
=[],
155 help=argparse
.SUPPRESS
)
156 arg_parser
.add_argument('--interface-prefix', metavar
='PREFIX', default
='',
157 help='String to strip from D-Bus interface names for code and docs')
158 arg_parser
.add_argument('--c-namespace', metavar
='NAMESPACE', default
='',
159 help='The namespace to use for generated C code')
160 arg_parser
.add_argument('--c-generate-object-manager', action
='store_true',
161 help='Generate a GDBusObjectManagerClient subclass when generating C code')
162 arg_parser
.add_argument('--c-generate-autocleanup', choices
=['none', 'objects', 'all'], default
='objects',
163 help='Generate autocleanup support')
164 arg_parser
.add_argument('--generate-docbook', metavar
='OUTFILES',
165 help='Generate Docbook in OUTFILES-org.Project.IFace.xml')
166 arg_parser
.add_argument('--pragma-once', action
='store_true',
167 help='Use "pragma once" as the inclusion guard')
168 arg_parser
.add_argument('--annotate', nargs
=3, action
='append', metavar
='WHAT KEY VALUE',
169 help='Add annotation (may be used several times)')
171 group
= arg_parser
.add_mutually_exclusive_group()
172 group
.add_argument('--generate-c-code', metavar
='OUTFILES',
173 help='Generate C code in OUTFILES.[ch]')
174 group
.add_argument('--header', action
='store_true',
175 help='Generate C headers')
176 group
.add_argument('--body', action
='store_true',
177 help='Generate C code')
178 group
.add_argument('--interface-info-header', action
='store_true',
179 help='Generate GDBusInterfaceInfo C header')
180 group
.add_argument('--interface-info-body', action
='store_true',
181 help='Generate GDBusInterfaceInfo C code')
183 group
= arg_parser
.add_mutually_exclusive_group()
184 group
.add_argument('--output', metavar
='FILE',
185 help='Write output into the specified file')
186 group
.add_argument('--output-directory', metavar
='OUTDIR', default
='',
187 help='Location to output generated files')
189 args
= arg_parser
.parse_args();
191 if len(args
.xml_files
) > 0:
192 print_warning('The "--xml-files" option is deprecated; use positional arguments instead')
194 if ((args
.generate_c_code
is not None or args
.generate_docbook
is not None) and
195 args
.output
is not None):
196 print_error('Using --generate-c-code or --generate-docbook and '
197 '--output at the same time is not allowed')
199 if args
.generate_c_code
:
200 header_name
= args
.generate_c_code
+ '.h'
201 h_file
= os
.path
.join(args
.output_directory
, header_name
)
203 c_file
= os
.path
.join(args
.output_directory
, args
.generate_c_code
+ '.c')
206 if args
.output
is None:
207 print_error('Using --header requires --output')
210 header_name
= os
.path
.basename(h_file
)
212 if args
.output
is None:
213 print_error('Using --body requires --output')
216 header_name
= os
.path
.splitext(os
.path
.basename(c_file
))[0] + '.h'
217 elif args
.interface_info_header
:
218 if args
.output
is None:
219 print_error('Using --interface-info-header requires --output')
220 if args
.c_generate_object_manager
:
221 print_error('--c-generate-object-manager is incompatible with '
222 '--interface-info-header')
225 header_name
= os
.path
.basename(h_file
)
226 elif args
.interface_info_body
:
227 if args
.output
is None:
228 print_error('Using --interface-info-body requires --output')
229 if args
.c_generate_object_manager
:
230 print_error('--c-generate-object-manager is incompatible with '
231 '--interface-info-body')
234 header_name
= os
.path
.splitext(os
.path
.basename(c_file
))[0] + '.h'
237 input_files_basenames
= []
238 for fname
in args
.files
+ args
.xml_files
:
239 with
open(fname
, 'rb') as f
:
241 parsed_ifaces
= parser
.parse_dbus_xml(xml_data
)
242 all_ifaces
.extend(parsed_ifaces
)
243 input_files_basenames
.append(os
.path
.basename(fname
))
245 if args
.annotate
is not None:
246 apply_annotations(all_ifaces
, args
.annotate
)
249 i
.post_process(args
.interface_prefix
, args
.c_namespace
)
251 docbook
= args
.generate_docbook
252 docbook_gen
= codegen_docbook
.DocbookCodeGenerator(all_ifaces
);
254 ret
= docbook_gen
.generate(docbook
, args
.output_directory
)
257 with
open(h_file
, 'w') as outfile
:
258 gen
= codegen
.HeaderCodeGenerator(all_ifaces
,
260 args
.c_generate_object_manager
,
261 args
.c_generate_autocleanup
,
263 input_files_basenames
,
269 with
open(c_file
, 'w') as outfile
:
270 gen
= codegen
.CodeGenerator(all_ifaces
,
272 args
.c_generate_object_manager
,
274 input_files_basenames
,
279 if args
.interface_info_header
:
280 with
open(h_file
, 'w') as outfile
:
281 gen
= codegen
.InterfaceInfoHeaderCodeGenerator(all_ifaces
,
288 if args
.interface_info_body
:
289 with
open(c_file
, 'w') as outfile
:
290 gen
= codegen
.InterfaceInfoBodyCodeGenerator(all_ifaces
,
298 if __name__
== "__main__":