1 #!/usr/bin/env @PYTHON@
3 # pylint: disable=too-many-lines, missing-docstring, invalid-name
5 # This file is part of GLib
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.1 of the License, or (at your option) any later version.
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.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 VERSION_STR = '''glib-genmarshal version @VERSION@
26 glib-genmarshal comes with ABSOLUTELY NO WARRANTY.
27 You may redistribute copies of glib-genmarshal under the terms of
28 the GNU General Public License which can be found in the
29 GLib source package. Sources, examples and contact
30 information are available at http://www.gtk.org'''
32 GETTERS_STR = '''#ifdef G_ENABLE_DEBUG
33 #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
34 #define g_marshal_value_peek_char(v) g_value_get_schar (v)
35 #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
36 #define g_marshal_value_peek_int(v) g_value_get_int (v)
37 #define g_marshal_value_peek_uint(v) g_value_get_uint (v)
38 #define g_marshal_value_peek_long(v) g_value_get_long (v)
39 #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
40 #define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
41 #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
42 #define g_marshal_value_peek_enum(v) g_value_get_enum (v)
43 #define g_marshal_value_peek_flags(v) g_value_get_flags (v)
44 #define g_marshal_value_peek_float(v) g_value_get_float (v)
45 #define g_marshal_value_peek_double(v) g_value_get_double (v)
46 #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
47 #define g_marshal_value_peek_param(v) g_value_get_param (v)
48 #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
49 #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
50 #define g_marshal_value_peek_object(v) g_value_get_object (v)
51 #define g_marshal_value_peek_variant(v) g_value_get_variant (v)
52 #else /* !G_ENABLE_DEBUG */
53 /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
54 * Do not access GValues directly in your code. Instead, use the
55 * g_value_get_*() functions
57 #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
58 #define g_marshal_value_peek_char(v) (v)->data[0].v_int
59 #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
60 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
61 #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
62 #define g_marshal_value_peek_long(v) (v)->data[0].v_long
63 #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
64 #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
65 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
66 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long
67 #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
68 #define g_marshal_value_peek_float(v) (v)->data[0].v_float
69 #define g_marshal_value_peek_double(v) (v)->data[0].v_double
70 #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
71 #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
72 #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
73 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
74 #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
75 #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
76 #endif /* !G_ENABLE_DEBUG */'''
78 DEPRECATED_MSG_STR = 'The token "{}" is deprecated; use "{}" instead'
81 ' arg{:d} = ({:s}) va_arg (args_copy, {:s});'
83 '(param_types[{:d}] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && '
85 ' arg{idx:d} = {box_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
87 ' arg{idx:d} = {box_func} (arg{idx:d});'
89 ' {unbox_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
91 ' {unbox_func} (arg{idx:d});'
93 STD_PREFIX = 'g_cclosure_marshal'
95 # These are part of our ABI; keep this in sync with gmarshal.h
96 GOBJECT_MARSHALLERS = {
97 'g_cclosure_marshal_VOID__VOID',
98 'g_cclosure_marshal_VOID__BOOLEAN',
99 'g_cclosure_marshal_VOID__CHAR',
100 'g_cclosure_marshal_VOID__UCHAR',
101 'g_cclosure_marshal_VOID__INT',
102 'g_cclosure_marshal_VOID__UINT',
103 'g_cclosure_marshal_VOID__LONG',
104 'g_cclosure_marshal_VOID__ULONG',
105 'g_cclosure_marshal_VOID__ENUM',
106 'g_cclosure_marshal_VOID__FLAGS',
107 'g_cclosure_marshal_VOID__FLOAT',
108 'g_cclosure_marshal_VOID__DOUBLE',
109 'g_cclosure_marshal_VOID__STRING',
110 'g_cclosure_marshal_VOID__PARAM',
111 'g_cclosure_marshal_VOID__BOXED',
112 'g_cclosure_marshal_VOID__POINTER',
113 'g_cclosure_marshal_VOID__OBJECT',
114 'g_cclosure_marshal_VOID__VARIANT',
115 'g_cclosure_marshal_VOID__UINT_POINTER',
116 'g_cclosure_marshal_BOOLEAN__FLAGS',
117 'g_cclosure_marshal_STRING__OBJECT_POINTER',
118 'g_cclosure_marshal_BOOLEAN__BOXED_BOXED',
122 # pylint: disable=too-few-public-methods
124 '''ANSI Terminal colors'''
127 YELLOW = '\033[1;33m'
132 def print_color(msg, color=Color.END, prefix='MESSAGE'):
133 '''Print a string with a color prefix'''
134 if os.isatty(sys.stderr.fileno()):
135 real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END)
138 sys.stderr.write('{prefix}: {msg}\n'.format(prefix=real_prefix, msg=msg))
141 def print_error(msg):
142 '''Print an error, and terminate'''
143 print_color(msg, color=Color.RED, prefix='ERROR')
147 def print_warning(msg, fatal=False):
148 '''Print a warning, and optionally terminate'''
155 print_color(msg, color, prefix)
161 '''Print a message'''
162 print_color(msg, color=Color.GREEN, prefix='INFO')
165 def generate_header_preamble(outfile, prefix='', std_includes=True, use_pragma=False):
166 '''Generate the preamble for the marshallers header file'''
167 outfile.write('/* This file is generated, all changes will be lost */\n')
169 outfile.write('#pragma once\n')
172 outfile.write('#ifndef __{}_MARSHAL_H__\n'.format(prefix.upper()))
173 outfile.write('#define __{}_MARSHAL_H__\n'.format(prefix.upper()))
175 # Maintain compatibility with the old C-based tool
177 outfile.write('#include <glib-object.h>\n')
180 outfile.write('G_BEGIN_DECLS\n')
184 def generate_header_postamble(outfile, prefix='', use_pragma=False):
185 '''Generate the postamble for the marshallers header file'''
187 outfile.write('G_END_DECLS\n')
191 outfile.write('#endif /* __{}_MARSHAL_H__ */\n'.format(prefix.upper()))
194 def generate_body_preamble(outfile, std_includes=True, include_headers=None, cpp_defines=None, cpp_undefines=None):
195 '''Generate the preamble for the marshallers source file'''
196 for header in (include_headers or []):
197 outfile.write('#include "{}"\n'.format(header))
201 for define in (cpp_defines or []):
202 s = define.split('=')
204 value = s[1] if len(s) > 1 else '1'
205 outfile.write('#define {} {}\n'.format(symbol, value))
209 for undefine in (cpp_undefines or []):
210 outfile.write('#undef {}\n'.format(undefine))
215 outfile.write('#include <glib-object.h>\n')
218 outfile.write(GETTERS_STR)
219 outfile.write('\n\n')
222 # Marshaller arguments, as a dictionary where the key is the token used in
223 # the source file, and the value is another dictionary with the following
226 # - signal: the token used in the marshaller prototype (mandatory)
227 # - ctype: the C type for the marshaller argument (mandatory)
228 # - getter: the function used to retrieve the argument from the GValue
229 # array when invoking the callback (optional)
230 # - promoted: the C type used by va_arg() to retrieve the argument from
231 # the va_list when invoking the callback (optional, only used when
232 # generating va_list marshallers)
233 # - box: an array of two elements, containing the boxing and unboxing
234 # functions for the given type (optional, only used when generating
235 # va_list marshallers)
236 # - static-check: a boolean value, if the given type should perform
237 # a static type check before boxing or unboxing the argument (optional,
238 # only used when generating va_list marshallers)
239 # - takes-type: a boolean value, if the boxing and unboxing functions
240 # for the given type require the type (optional, only used when
241 # generating va_list marshallers)
242 # - deprecated: whether the token has been deprecated (optional)
243 # - replaced-by: the token used to replace a deprecated token (optional,
244 # only used if deprecated is True)
253 'getter': 'g_marshal_value_peek_boolean',
259 'getter': 'g_marshal_value_peek_char',
265 'getter': 'g_marshal_value_peek_uchar',
270 'getter': 'g_marshal_value_peek_int',
275 'getter': 'g_marshal_value_peek_uint',
280 'getter': 'g_marshal_value_peek_long',
285 'getter': 'g_marshal_value_peek_ulong',
290 'getter': 'g_marshal_value_peek_int64',
295 'getter': 'g_marshal_value_peek_uint64',
300 'getter': 'g_marshal_value_peek_enum',
305 'getter': 'g_marshal_value_peek_flags',
310 'promoted': 'gdouble',
311 'getter': 'g_marshal_value_peek_float',
316 'getter': 'g_marshal_value_peek_double',
321 'getter': 'g_marshal_value_peek_string',
322 'box': ['g_strdup', 'g_free'],
327 'getter': 'g_marshal_value_peek_param',
328 'box': ['g_param_spec_ref', 'g_param_spec_unref'],
333 'getter': 'g_marshal_value_peek_boxed',
334 'box': ['g_boxed_copy', 'g_boxed_free'],
335 'static-check': True,
341 'getter': 'g_marshal_value_peek_pointer',
346 'getter': 'g_marshal_value_peek_object',
347 'box': ['g_object_ref', 'g_object_unref'],
352 'getter': 'g_marshal_value_peek_variant',
353 'box': ['g_variant_ref', 'g_variant_unref'],
354 'static-check': True,
363 'replaced_by': 'VOID'
368 'getter': 'g_marshal_value_peek_boolean',
370 'replaced_by': 'BOOLEAN'
375 # Marshaller return values, as a dictionary where the key is the token used
376 # in the source file, and the value is another dictionary with the following
379 # - signal: the token used in the marshaller prototype (mandatory)
380 # - ctype: the C type for the marshaller argument (mandatory)
381 # - setter: the function used to set the return value of the callback
382 # into a GValue (optional)
383 # - deprecated: whether the token has been deprecated (optional)
384 # - replaced-by: the token used to replace a deprecated token (optional,
385 # only used if deprecated is True)
394 'setter': 'g_value_set_boolean',
399 'setter': 'g_value_set_char',
404 'setter': 'g_value_set_uchar',
409 'setter': 'g_value_set_int',
414 'setter': 'g_value_set_uint',
419 'setter': 'g_value_set_long',
424 'setter': 'g_value_set_ulong',
429 'setter': 'g_value_set_int64',
434 'setter': 'g_value_set_uint64',
439 'setter': 'g_value_set_enum',
444 'setter': 'g_value_set_flags',
449 'setter': 'g_value_set_float',
454 'setter': 'g_value_set_double',
459 'setter': 'g_value_take_string',
463 'ctype': 'GParamSpec*',
464 'setter': 'g_value_take_param',
469 'setter': 'g_value_take_boxed',
474 'setter': 'g_value_set_pointer',
479 'setter': 'g_value_take_object',
483 'ctype': 'GVariant*',
484 'setter': 'g_value_take_variant',
493 'replaced_by': 'VOID',
498 'setter': 'g_value_set_boolean',
500 'replaced_by': 'BOOLEAN',
505 def check_args(retval, params, fatal_warnings=False):
506 '''Check the @retval and @params tokens for invalid and deprecated symbols.'''
507 if retval not in OUT_ARGS:
508 print_error('Unknown return value type "{}"'.format(retval))
510 if OUT_ARGS[retval].get('deprecated', False):
511 replaced_by = OUT_ARGS[retval]['replaced_by']
512 print_warning(DEPRECATED_MSG_STR.format(retval, replaced_by), fatal_warnings)
515 if param not in IN_ARGS:
516 print_error('Unknown parameter type "{}"'.format(param))
518 if IN_ARGS[param].get('deprecated', False):
519 replaced_by = IN_ARGS[param]['replaced_by']
520 print_warning(DEPRECATED_MSG_STR.format(param, replaced_by), fatal_warnings)
523 def indent(text, level=0, fill=' '):
524 '''Indent @text by @level columns, using the @fill character'''
525 return ''.join([fill for x in range(level)]) + text
528 # pylint: disable=too-few-public-methods
530 '''Symbol visibility options'''
536 def generate_marshaller_name(prefix, retval, params, replace_deprecated=True):
537 '''Generate a marshaller name for the given @prefix, @retval, and @params.
538 If @replace_deprecated is True, the generated name will replace deprecated
540 if replace_deprecated:
541 real_retval = OUT_ARGS[retval]['signal']
544 real_params.append(IN_ARGS[param]['signal'])
548 return '{prefix}_{retval}__{args}'.format(prefix=prefix,
550 args='_'.join(real_params))
553 def generate_prototype(retval, params,
554 prefix='g_cclosure_user_marshal',
555 visibility=Visibility.NONE,
557 '''Generate a marshaller declaration with the given @visibility. If @va_marshal
558 is True, the marshaller will use variadic arguments in place of a GValue array.'''
561 if visibility == Visibility.INTERNAL:
562 signature += ['G_GNUC_INTERNAL']
563 elif visibility == Visibility.EXTERN:
564 signature += ['extern']
566 function_name = generate_marshaller_name(prefix, retval, params)
569 signature += ['void ' + function_name + ' (GClosure *closure,']
570 width = len('void ') + len(function_name) + 2
572 signature += [indent('GValue *return_value,', level=width, fill=' ')]
573 signature += [indent('guint n_param_values,', level=width, fill=' ')]
574 signature += [indent('const GValue *param_values,', level=width, fill=' ')]
575 signature += [indent('gpointer invocation_hint,', level=width, fill=' ')]
576 signature += [indent('gpointer marshal_data);', level=width, fill=' ')]
578 signature += ['void ' + function_name + 'v (GClosure *closure,']
579 width = len('void ') + len(function_name) + 3
581 signature += [indent('GValue *return_value,', level=width, fill=' ')]
582 signature += [indent('gpointer instance,', level=width, fill=' ')]
583 signature += [indent('va_list args,', level=width, fill=' ')]
584 signature += [indent('gpointer marshal_data,', level=width, fill=' ')]
585 signature += [indent('int n_params,', level=width, fill=' ')]
586 signature += [indent('GType *param_types);', level=width, fill=' ')]
591 # pylint: disable=too-many-statements, too-many-locals, too-many-branches
592 def generate_body(retval, params, prefix, va_marshal=False):
593 '''Generate a marshaller definition. If @va_marshal is True, the marshaller
594 will use va_list and variadic arguments in place of a GValue array.'''
595 retval_setter = OUT_ARGS[retval].get('setter', None)
596 # If there's no return value then we can mark the retval argument as unused
597 # and get a minor optimisation, as well as avoid a compiler warning
598 if not retval_setter:
599 unused = ' G_GNUC_UNUSED'
605 function_name = generate_marshaller_name(prefix, retval, params)
608 body += [function_name + ' (GClosure *closure,']
609 width = len(function_name) + 2
611 body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
612 body += [indent('guint n_param_values,', level=width, fill=' ')]
613 body += [indent('const GValue *param_values,', level=width, fill=' ')]
614 body += [indent('gpointer invocation_hint G_GNUC_UNUSED,', level=width, fill=' ')]
615 body += [indent('gpointer marshal_data)', level=width, fill=' ')]
617 body += [function_name + 'v (GClosure *closure,']
618 width = len(function_name) + 3
620 body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
621 body += [indent('gpointer instance,', level=width, fill=' ')]
622 body += [indent('va_list args,', level=width, fill=' ')]
623 body += [indent('gpointer marshal_data,', level=width, fill=' ')]
624 body += [indent('int n_params,', level=width, fill=' ')]
625 body += [indent('GType *param_types)', level=width, fill=' ')]
627 # Filter the arguments that have a getter
628 get_args = [x for x in params if IN_ARGS[x].get('getter', None) is not None]
632 # Generate the type of the marshaller function
633 typedef_marshal = generate_marshaller_name('GMarshalFunc', retval, params)
635 typedef = ' typedef {ctype} (*{func_name}) ('.format(ctype=OUT_ARGS[retval]['ctype'],
636 func_name=typedef_marshal)
638 typedef += 'gpointer data1,'
641 for idx, in_arg in enumerate(get_args):
642 body += [indent('{} arg{:d},'.format(IN_ARGS[in_arg]['ctype'], idx + 1), level=pad)]
644 body += [indent('gpointer data2);', level=pad)]
646 # Variable declarations
647 body += [' GCClosure *cc = (GCClosure *) closure;']
648 body += [' gpointer data1, data2;']
649 body += [' {} callback;'.format(typedef_marshal)]
652 body += [' {} v_return;'.format(OUT_ARGS[retval]['ctype'])]
655 for idx, arg in enumerate(get_args):
656 body += [' {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)]
659 body += [' va_list args_copy;']
662 body += [' G_VA_COPY (args_copy, args);']
664 for idx, arg in enumerate(get_args):
665 ctype = IN_ARGS[arg]['ctype']
666 promoted_ctype = IN_ARGS[arg].get('promoted', ctype)
667 body += [VA_ARG_STR.format(idx, ctype, promoted_ctype)]
668 if IN_ARGS[arg].get('box', None):
669 box_func = IN_ARGS[arg]['box'][0]
670 if IN_ARGS[arg].get('static-check', False):
671 static_check = STATIC_CHECK_STR.format(idx)
674 arg_check = 'arg{:d} != NULL'.format(idx)
675 body += [' if ({}{})'.format(static_check, arg_check)]
676 if IN_ARGS[arg].get('takes-type', False):
677 body += [BOX_TYPED_STR.format(idx=idx, box_func=box_func)]
679 body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)]
681 body += [' va_end (args_copy);']
685 # Preconditions check
687 body += [' g_return_if_fail (return_value != NULL);']
690 body += [' g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)]
694 # Marshal instance, data, and callback set up
695 body += [' if (G_CCLOSURE_SWAP_DATA (closure))']
697 body += [' data1 = closure->data;']
699 body += [' data2 = instance;']
701 body += [' data2 = g_value_peek_pointer (param_values + 0);']
706 body += [' data1 = instance;']
708 body += [' data1 = g_value_peek_pointer (param_values + 0);']
709 body += [' data2 = closure->data;']
711 # pylint: disable=line-too-long
712 body += [' callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)]
715 # Marshal callback action
717 callback = ' {} callback ('.format(' v_return =')
719 callback = ' callback ('
722 body += [callback + 'data1,']
725 for idx, arg in enumerate(get_args):
726 body += [indent('arg{:d},'.format(idx), level=pad)]
728 for idx, arg in enumerate(get_args):
729 arg_getter = IN_ARGS[arg]['getter']
730 body += [indent('{} (param_values + {:d}),'.format(arg_getter, idx + 1), level=pad)]
732 body += [indent('data2);', level=pad)]
735 boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None]
739 for idx, arg in enumerate(get_args):
740 if not IN_ARGS[arg].get('box', None):
742 unbox_func = IN_ARGS[arg]['box'][1]
743 if IN_ARGS[arg].get('static-check', False):
744 static_check = STATIC_CHECK_STR.format(idx)
747 arg_check = 'arg{:d} != NULL'.format(idx)
748 body += [' if ({}{})'.format(static_check, arg_check)]
749 if IN_ARGS[arg].get('takes-type', False):
750 body += [UNBOX_TYPED_STR.format(idx=idx, unbox_func=unbox_func)]
752 body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)]
756 body += [' {} (return_value, v_return);'.format(retval_setter)]
763 def generate_marshaller_alias(outfile, marshaller, real_marshaller,
765 source_location=None):
766 '''Generate an alias between @marshaller and @real_marshaller, including
767 an optional alias for va_list marshallers'''
769 outfile.write('/* {} */\n'.format(source_location))
771 outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller))
774 outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller))
779 def generate_marshallers_header(outfile, retval, params,
780 prefix='g_cclosure_user_marshal',
782 include_va=False, source_location=None):
783 '''Generate a declaration for a marshaller function, to be used in the header,
784 with the given @retval, @params, and @prefix. An optional va_list marshaller
785 for the same arguments is also generated. The generated buffer is written to
786 the @outfile stream object.'''
788 outfile.write('/* {} */\n'.format(source_location))
791 visibility = Visibility.INTERNAL
793 visibility = Visibility.EXTERN
795 signature = generate_prototype(retval, params, prefix, visibility, False)
797 signature += generate_prototype(retval, params, prefix, visibility, True)
800 outfile.write('\n'.join(signature))
804 def generate_marshallers_body(outfile, retval, params,
805 prefix='g_cclosure_user_marshal',
806 include_prototype=True,
808 include_va=False, source_location=None):
809 '''Generate a definition for a marshaller function, to be used in the source,
810 with the given @retval, @params, and @prefix. An optional va_list marshaller
811 for the same arguments is also generated. The generated buffer is written to
812 the @outfile stream object.'''
814 outfile.write('/* {} */\n'.format(source_location))
816 if include_prototype:
817 # Declaration visibility
819 decl_visibility = Visibility.INTERNAL
821 decl_visibility = Visibility.EXTERN
822 proto = ['/* Prototype for -Wmissing-prototypes */']
823 # Add C++ guards in case somebody compiles the generated code
824 # with a C++ compiler
825 proto += ['G_BEGIN_DECLS']
826 proto += generate_prototype(retval, params, prefix, decl_visibility, False)
827 proto += ['G_END_DECLS']
828 outfile.write('\n'.join(proto))
831 body = generate_body(retval, params, prefix, False)
832 outfile.write('\n'.join(body))
833 outfile.write('\n\n')
836 if include_prototype:
837 # Declaration visibility
839 decl_visibility = Visibility.INTERNAL
841 decl_visibility = Visibility.EXTERN
842 proto = ['/* Prototype for -Wmissing-prototypes */']
843 # Add C++ guards here as well
844 proto += ['G_BEGIN_DECLS']
845 proto += generate_prototype(retval, params, prefix, decl_visibility, True)
846 proto += ['G_END_DECLS']
847 outfile.write('\n'.join(proto))
850 body = generate_body(retval, params, prefix, True)
851 outfile.write('\n'.join(body))
852 outfile.write('\n\n')
855 if __name__ == '__main__':
856 arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject')
857 arg_parser.add_argument('--prefix', metavar='STRING',
858 default='g_cclosure_user_marshal',
859 help='Specify marshaller prefix')
860 arg_parser.add_argument('--output', metavar='FILE',
861 type=argparse.FileType('w'),
863 help='Write output into the specified file')
864 arg_parser.add_argument('--skip-source',
866 help='Skip source location comments')
867 arg_parser.add_argument('--internal',
869 help='Mark generated functions as internal')
870 arg_parser.add_argument('--valist-marshallers',
872 help='Generate va_list marshallers')
873 arg_parser.add_argument('-v', '--version',
876 help='Print version information, and exit')
877 arg_parser.add_argument('--g-fatal-warnings',
879 dest='fatal_warnings',
880 help='Make warnings fatal')
881 arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?',
883 dest='include_headers',
884 help='Include the specified header in the body')
885 arg_parser.add_argument('--pragma-once',
887 help='Use "pragma once" as the inclusion guard')
888 arg_parser.add_argument('-D',
892 help='Pre-processor define')
893 arg_parser.add_argument('-U',
895 dest='cpp_undefines',
897 help='Pre-processor undefine')
898 arg_parser.add_argument('files', metavar='FILE', nargs='*',
899 type=argparse.FileType('r'),
900 help='Files with lists of marshallers to generate, ' +
901 'or "-" for standard input')
902 arg_parser.add_argument('--prototypes',
904 help='Generate the marshallers prototype in the C code')
905 arg_parser.add_argument('--header',
907 help='Generate C headers')
908 arg_parser.add_argument('--body',
910 help='Generate C code')
912 group = arg_parser.add_mutually_exclusive_group()
913 group.add_argument('--stdinc',
915 dest='stdinc', default=True,
916 help='Include standard marshallers')
917 group.add_argument('--nostdinc',
918 action='store_false',
919 dest='stdinc', default=True,
920 help='Use standard marshallers')
922 group = arg_parser.add_mutually_exclusive_group()
923 group.add_argument('--quiet',
925 help='Only print warnings and errors')
926 group.add_argument('--verbose',
928 help='Be verbose, and include debugging information')
930 args = arg_parser.parse_args()
932 if args.show_version:
936 # Backward compatibility hack; some projects use both arguments to
937 # generate the marshallers prototype in the C source, even though
938 # it's not really a supported use case. We keep this behaviour by
939 # forcing the --prototypes and --body arguments instead. We make this
940 # warning non-fatal even with --g-fatal-warnings, as it's a deprecation
941 compatibility_mode = False
942 if args.header and args.body:
943 print_warning('Using --header and --body at the same time time is deprecated; ' +
944 'use --body --prototypes instead', False)
945 args.prototypes = True
947 compatibility_mode = True
950 generate_header_preamble(args.output,
952 std_includes=args.stdinc,
953 use_pragma=args.pragma_once)
955 generate_body_preamble(args.output,
956 std_includes=args.stdinc,
957 include_headers=args.include_headers,
958 cpp_defines=args.cpp_defines,
959 cpp_undefines=args.cpp_undefines)
961 seen_marshallers = set()
963 for infile in args.files:
965 print_info('Reading {}...'.format(infile.name))
971 if line == '\n' or line.startswith('#'):
974 matches = re.match(r'^([A-Z0-9]+)\s?:\s?([A-Z0-9,\s]+)$', line.strip())
975 if not matches or len(matches.groups()) != 2:
976 print_warning('Invalid entry: "{}"'.format(line.strip()), args.fatal_warnings)
979 if not args.skip_source:
980 location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count)
984 retval = matches.group(1).strip()
985 params = [x.strip() for x in matches.group(2).split(',')]
986 check_args(retval, params, args.fatal_warnings)
988 raw_marshaller = generate_marshaller_name(args.prefix, retval, params, False)
989 if raw_marshaller in seen_marshallers:
991 print_info('Skipping repeated marshaller {}'.format(line.strip()))
996 print_info('Generating declaration for {}'.format(line.strip()))
997 generate_std_alias = False
999 std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1000 if std_marshaller in GOBJECT_MARSHALLERS:
1002 print_info('Skipping default marshaller {}'.format(line.strip()))
1003 generate_std_alias = True
1005 marshaller = generate_marshaller_name(args.prefix, retval, params)
1006 if generate_std_alias:
1007 generate_marshaller_alias(args.output, marshaller, std_marshaller,
1008 source_location=location,
1009 include_va=args.valist_marshallers)
1011 generate_marshallers_header(args.output, retval, params,
1013 internal=args.internal,
1014 include_va=args.valist_marshallers,
1015 source_location=location)
1016 # If the marshaller is defined using a deprecated token, we want to maintain
1017 # compatibility and generate an alias for the old name pointing to the new
1019 if marshaller != raw_marshaller:
1021 print_info('Generating alias for deprecated tokens')
1022 generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1023 include_va=args.valist_marshallers)
1026 print_info('Generating definition for {}'.format(line.strip()))
1027 if compatibility_mode:
1028 generate_std_alias = False
1030 std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1031 if std_marshaller in GOBJECT_MARSHALLERS:
1033 print_info('Skipping default marshaller {}'.format(line.strip()))
1034 generate_std_alias = True
1035 marshaller = generate_marshaller_name(args.prefix, retval, params)
1036 if compatibility_mode and generate_std_alias:
1037 generate_marshaller_alias(args.output, marshaller, std_marshaller,
1038 source_location=location,
1039 include_va=args.valist_marshallers)
1041 generate_marshallers_body(args.output, retval, params,
1043 internal=args.internal,
1044 include_prototype=args.prototypes,
1045 include_va=args.valist_marshallers,
1046 source_location=location)
1047 if compatibility_mode and marshaller != raw_marshaller:
1049 print_info('Generating alias for deprecated tokens')
1050 generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1051 include_va=args.valist_marshallers)
1053 seen_marshallers.add(raw_marshaller)
1056 generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)