Update Friulian translation
[glib.git] / gobject / glib-genmarshal.in
blobed6de0ae851cfb7ed7647d190bde3ae879bf40d9
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/>.
20 import argparse
21 import os
22 import re
23 import sys
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
56  */
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'
80 VA_ARG_STR = \
81     '  arg{:d} = ({:s}) va_arg (args_copy, {:s});'
82 STATIC_CHECK_STR = \
83     '(param_types[{:d}] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && '
84 BOX_TYPED_STR = \
85     '    arg{idx:d} = {box_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
86 BOX_UNTYPED_STR = \
87     '    arg{idx:d} = {box_func} (arg{idx:d});'
88 UNBOX_TYPED_STR = \
89     '    {unbox_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
90 UNBOX_UNTYPED_STR = \
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
123 class Color:
124     '''ANSI Terminal colors'''
125     GREEN = '\033[1;32m'
126     BLUE = '\033[1;34m'
127     YELLOW = '\033[1;33m'
128     RED = '\033[1;31m'
129     END = '\033[0m'
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)
136     else:
137         real_prefix = prefix
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')
144     sys.exit(1)
147 def print_warning(msg, fatal=False):
148     '''Print a warning, and optionally terminate'''
149     if fatal:
150         color = Color.RED
151         prefix = 'ERROR'
152     else:
153         color = Color.YELLOW
154         prefix = 'WARNING'
155     print_color(msg, color, prefix)
156     if fatal:
157         sys.exit(1)
160 def print_info(msg):
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')
168     if use_pragma:
169         outfile.write('#pragma once\n')
170         outfile.write('\n')
171     else:
172         outfile.write('#ifndef __{}_MARSHAL_H__\n'.format(prefix.upper()))
173         outfile.write('#define __{}_MARSHAL_H__\n'.format(prefix.upper()))
174         outfile.write('\n')
175     # Maintain compatibility with the old C-based tool
176     if std_includes:
177         outfile.write('#include <glib-object.h>\n')
178         outfile.write('\n')
180     outfile.write('G_BEGIN_DECLS\n')
181     outfile.write('\n')
184 def generate_header_postamble(outfile, prefix='', use_pragma=False):
185     '''Generate the postamble for the marshallers header file'''
186     outfile.write('\n')
187     outfile.write('G_END_DECLS\n')
189     if not use_pragma:
190         outfile.write('\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))
198     if include_headers:
199         outfile.write('\n')
201     for define in (cpp_defines or []):
202         s = define.split('=')
203         symbol = s[0]
204         value = s[1] if len(s) > 1 else '1'
205         outfile.write('#define {} {}\n'.format(symbol, value))
206     if cpp_defines:
207         outfile.write('\n')
209     for undefine in (cpp_undefines or []):
210         outfile.write('#undef {}\n'.format(undefine))
211     if cpp_undefines:
212         outfile.write('\n')
214     if std_includes:
215         outfile.write('#include <glib-object.h>\n')
216         outfile.write('\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
224 # keys:
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)
245 IN_ARGS = {
246     'VOID': {
247         'signal': 'VOID',
248         'ctype': 'void',
249     },
250     'BOOLEAN': {
251         'signal': 'BOOLEAN',
252         'ctype': 'gboolean',
253         'getter': 'g_marshal_value_peek_boolean',
254     },
255     'CHAR': {
256         'signal': 'CHAR',
257         'ctype': 'gchar',
258         'promoted': 'gint',
259         'getter': 'g_marshal_value_peek_char',
260     },
261     'UCHAR': {
262         'signal': 'UCHAR',
263         'ctype': 'guchar',
264         'promoted': 'guint',
265         'getter': 'g_marshal_value_peek_uchar',
266     },
267     'INT': {
268         'signal': 'INT',
269         'ctype': 'gint',
270         'getter': 'g_marshal_value_peek_int',
271     },
272     'UINT': {
273         'signal': 'UINT',
274         'ctype': 'guint',
275         'getter': 'g_marshal_value_peek_uint',
276     },
277     'LONG': {
278         'signal': 'LONG',
279         'ctype': 'glong',
280         'getter': 'g_marshal_value_peek_long',
281     },
282     'ULONG': {
283         'signal': 'ULONG',
284         'ctype': 'gulong',
285         'getter': 'g_marshal_value_peek_ulong',
286     },
287     'INT64': {
288         'signal': 'INT64',
289         'ctype': 'gint64',
290         'getter': 'g_marshal_value_peek_int64',
291     },
292     'UINT64': {
293         'signal': 'UINT64',
294         'ctype': 'guint64',
295         'getter': 'g_marshal_value_peek_uint64',
296     },
297     'ENUM': {
298         'signal': 'ENUM',
299         'ctype': 'gint',
300         'getter': 'g_marshal_value_peek_enum',
301     },
302     'FLAGS': {
303         'signal': 'FLAGS',
304         'ctype': 'guint',
305         'getter': 'g_marshal_value_peek_flags',
306     },
307     'FLOAT': {
308         'signal': 'FLOAT',
309         'ctype': 'gfloat',
310         'promoted': 'gdouble',
311         'getter': 'g_marshal_value_peek_float',
312     },
313     'DOUBLE': {
314         'signal': 'DOUBLE',
315         'ctype': 'gdouble',
316         'getter': 'g_marshal_value_peek_double',
317     },
318     'STRING': {
319         'signal': 'STRING',
320         'ctype': 'gpointer',
321         'getter': 'g_marshal_value_peek_string',
322         'box': ['g_strdup', 'g_free'],
323     },
324     'PARAM': {
325         'signal': 'PARAM',
326         'ctype': 'gpointer',
327         'getter': 'g_marshal_value_peek_param',
328         'box': ['g_param_spec_ref', 'g_param_spec_unref'],
329     },
330     'BOXED': {
331         'signal': 'BOXED',
332         'ctype': 'gpointer',
333         'getter': 'g_marshal_value_peek_boxed',
334         'box': ['g_boxed_copy', 'g_boxed_free'],
335         'static-check': True,
336         'takes-type': True,
337     },
338     'POINTER': {
339         'signal': 'POINTER',
340         'ctype': 'gpointer',
341         'getter': 'g_marshal_value_peek_pointer',
342     },
343     'OBJECT': {
344         'signal': 'OBJECT',
345         'ctype': 'gpointer',
346         'getter': 'g_marshal_value_peek_object',
347         'box': ['g_object_ref', 'g_object_unref'],
348     },
349     'VARIANT': {
350         'signal': 'VARIANT',
351         'ctype': 'gpointer',
352         'getter': 'g_marshal_value_peek_variant',
353         'box': ['g_variant_ref', 'g_variant_unref'],
354         'static-check': True,
355         'takes-type': False,
356     },
358     # Deprecated tokens
359     'NONE': {
360         'signal': 'VOID',
361         'ctype': 'void',
362         'deprecated': True,
363         'replaced_by': 'VOID'
364     },
365     'BOOL': {
366         'signal': 'BOOLEAN',
367         'ctype': 'gboolean',
368         'getter': 'g_marshal_value_peek_boolean',
369         'deprecated': True,
370         'replaced_by': 'BOOLEAN'
371     }
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
377 # keys:
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)
386 OUT_ARGS = {
387     'VOID': {
388         'signal': 'VOID',
389         'ctype': 'void',
390     },
391     'BOOLEAN': {
392         'signal': 'BOOLEAN',
393         'ctype': 'gboolean',
394         'setter': 'g_value_set_boolean',
395     },
396     'CHAR': {
397         'signal': 'CHAR',
398         'ctype': 'gchar',
399         'setter': 'g_value_set_char',
400     },
401     'UCHAR': {
402         'signal': 'UCHAR',
403         'ctype': 'guchar',
404         'setter': 'g_value_set_uchar',
405     },
406     'INT': {
407         'signal': 'INT',
408         'ctype': 'gint',
409         'setter': 'g_value_set_int',
410     },
411     'UINT': {
412         'signal': 'UINT',
413         'ctype': 'guint',
414         'setter': 'g_value_set_uint',
415     },
416     'LONG': {
417         'signal': 'LONG',
418         'ctype': 'glong',
419         'setter': 'g_value_set_long',
420     },
421     'ULONG': {
422         'signal': 'ULONG',
423         'ctype': 'gulong',
424         'setter': 'g_value_set_ulong',
425     },
426     'INT64': {
427         'signal': 'INT64',
428         'ctype': 'gint64',
429         'setter': 'g_value_set_int64',
430     },
431     'UINT64': {
432         'signal': 'UINT64',
433         'ctype': 'guint64',
434         'setter': 'g_value_set_uint64',
435     },
436     'ENUM': {
437         'signal': 'ENUM',
438         'ctype': 'gint',
439         'setter': 'g_value_set_enum',
440     },
441     'FLAGS': {
442         'signal': 'FLAGS',
443         'ctype': 'guint',
444         'setter': 'g_value_set_flags',
445     },
446     'FLOAT': {
447         'signal': 'FLOAT',
448         'ctype': 'gfloat',
449         'setter': 'g_value_set_float',
450     },
451     'DOUBLE': {
452         'signal': 'DOUBLE',
453         'ctype': 'gdouble',
454         'setter': 'g_value_set_double',
455     },
456     'STRING': {
457         'signal': 'STRING',
458         'ctype': 'gchar*',
459         'setter': 'g_value_take_string',
460     },
461     'PARAM': {
462         'signal': 'PARAM',
463         'ctype': 'GParamSpec*',
464         'setter': 'g_value_take_param',
465     },
466     'BOXED': {
467         'signal': 'BOXED',
468         'ctype': 'gpointer',
469         'setter': 'g_value_take_boxed',
470     },
471     'POINTER': {
472         'signal': 'POINTER',
473         'ctype': 'gpointer',
474         'setter': 'g_value_set_pointer',
475     },
476     'OBJECT': {
477         'signal': 'OBJECT',
478         'ctype': 'GObject*',
479         'setter': 'g_value_take_object',
480     },
481     'VARIANT': {
482         'signal': 'VARIANT',
483         'ctype': 'GVariant*',
484         'setter': 'g_value_take_variant',
485     },
487     # Deprecated tokens
488     'NONE': {
489         'signal': 'VOID',
490         'ctype': 'void',
491         'setter': None,
492         'deprecated': True,
493         'replaced_by': 'VOID',
494     },
495     'BOOL': {
496         'signal': 'BOOLEAN',
497         'ctype': 'gboolean',
498         'setter': 'g_value_set_boolean',
499         'deprecated': True,
500         'replaced_by': 'BOOLEAN',
501     },
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)
514     for param in params:
515         if param not in IN_ARGS:
516             print_error('Unknown parameter type "{}"'.format(param))
517         else:
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
529 class Visibility:
530     '''Symbol visibility options'''
531     NONE = 0
532     INTERNAL = 1
533     EXTERN = 2
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
539     tokens.'''
540     if replace_deprecated:
541         real_retval = OUT_ARGS[retval]['signal']
542         real_params = []
543         for param in params:
544             real_params.append(IN_ARGS[param]['signal'])
545     else:
546         real_retval = retval
547         real_params = params
548     return '{prefix}_{retval}__{args}'.format(prefix=prefix,
549                                               retval=real_retval,
550                                               args='_'.join(real_params))
553 def generate_prototype(retval, params,
554                        prefix='g_cclosure_user_marshal',
555                        visibility=Visibility.NONE,
556                        va_marshal=False):
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.'''
559     signature = ['G_BEGIN_DECLS']
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)
568     if not va_marshal:
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=' ')]
577     else:
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=' ')]
588     signature += ['G_END_DECLS']
590     return signature
593 # pylint: disable=too-many-statements, too-many-locals, too-many-branches
594 def generate_body(retval, params, prefix, va_marshal=False):
595     '''Generate a marshaller definition. If @va_marshal is True, the marshaller
596     will use va_list and variadic arguments in place of a GValue array.'''
597     retval_setter = OUT_ARGS[retval].get('setter', None)
598     # If there's no return value then we can mark the retval argument as unused
599     # and get a minor optimisation, as well as avoid a compiler warning
600     if not retval_setter:
601         unused = ' G_GNUC_UNUSED'
602     else:
603         unused = ''
605     body = ['void']
607     function_name = generate_marshaller_name(prefix, retval, params)
609     if not va_marshal:
610         body += [function_name + ' (GClosure     *closure,']
611         width = len(function_name) + 2
613         body += [indent('GValue       *return_value{},'.format(unused), level=width, fill=' ')]
614         body += [indent('guint         n_param_values,', level=width, fill=' ')]
615         body += [indent('const GValue *param_values,', level=width, fill=' ')]
616         body += [indent('gpointer      invocation_hint G_GNUC_UNUSED,', level=width, fill=' ')]
617         body += [indent('gpointer      marshal_data)', level=width, fill=' ')]
618     else:
619         body += [function_name + 'v (GClosure *closure,']
620         width = len(function_name) + 3
622         body += [indent('GValue   *return_value{},'.format(unused), level=width, fill=' ')]
623         body += [indent('gpointer  instance,', level=width, fill=' ')]
624         body += [indent('va_list   args,', level=width, fill=' ')]
625         body += [indent('gpointer  marshal_data,', level=width, fill=' ')]
626         body += [indent('int       n_params,', level=width, fill=' ')]
627         body += [indent('GType    *param_types)', level=width, fill=' ')]
629     # Filter the arguments that have a getter
630     get_args = [x for x in params if IN_ARGS[x].get('getter', None) is not None]
632     body += ['{']
634     # Generate the type of the marshaller function
635     typedef_marshal = generate_marshaller_name('GMarshalFunc', retval, params)
637     typedef = '  typedef {ctype} (*{func_name}) ('.format(ctype=OUT_ARGS[retval]['ctype'],
638                                                           func_name=typedef_marshal)
639     pad = len(typedef)
640     typedef += 'gpointer data1,'
641     body += [typedef]
643     for idx, in_arg in enumerate(get_args):
644         body += [indent('{} arg{:d},'.format(IN_ARGS[in_arg]['ctype'], idx + 1), level=pad)]
646     body += [indent('gpointer data2);', level=pad)]
648     # Variable declarations
649     body += ['  GCClosure *cc = (GCClosure *) closure;']
650     body += ['  gpointer data1, data2;']
651     body += ['  {} callback;'.format(typedef_marshal)]
653     if retval_setter:
654         body += ['  {} v_return;'.format(OUT_ARGS[retval]['ctype'])]
656     if va_marshal:
657         for idx, arg in enumerate(get_args):
658             body += ['  {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)]
660         if get_args:
661             body += ['  va_list args_copy;']
662             body += ['']
664             body += ['  G_VA_COPY (args_copy, args);']
666             for idx, arg in enumerate(get_args):
667                 ctype = IN_ARGS[arg]['ctype']
668                 promoted_ctype = IN_ARGS[arg].get('promoted', ctype)
669                 body += [VA_ARG_STR.format(idx, ctype, promoted_ctype)]
670                 if IN_ARGS[arg].get('box', None):
671                     box_func = IN_ARGS[arg]['box'][0]
672                     if IN_ARGS[arg].get('static-check', False):
673                         static_check = STATIC_CHECK_STR.format(idx)
674                     else:
675                         static_check = ''
676                     arg_check = 'arg{:d} != NULL'.format(idx)
677                     body += ['  if ({}{})'.format(static_check, arg_check)]
678                     if IN_ARGS[arg].get('takes-type', False):
679                         body += [BOX_TYPED_STR.format(idx=idx, box_func=box_func)]
680                     else:
681                         body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)]
683             body += ['  va_end (args_copy);']
685     body += ['']
687     # Preconditions check
688     if retval_setter:
689         body += ['  g_return_if_fail (return_value != NULL);']
691     if not va_marshal:
692         body += ['  g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)]
694     body += ['']
696     # Marshal instance, data, and callback set up
697     body += ['  if (G_CCLOSURE_SWAP_DATA (closure))']
698     body += ['    {']
699     body += ['      data1 = closure->data;']
700     if va_marshal:
701         body += ['      data2 = instance;']
702     else:
703         body += ['      data2 = g_value_peek_pointer (param_values + 0);']
704     body += ['    }']
705     body += ['  else']
706     body += ['    {']
707     if va_marshal:
708         body += ['      data1 = instance;']
709     else:
710         body += ['      data1 = g_value_peek_pointer (param_values + 0);']
711     body += ['      data2 = closure->data;']
712     body += ['    }']
713     # pylint: disable=line-too-long
714     body += ['  callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)]
715     body += ['']
717     # Marshal callback action
718     if retval_setter:
719         callback = ' {} callback ('.format(' v_return =')
720     else:
721         callback = '  callback ('
723     pad = len(callback)
724     body += [callback + 'data1,']
726     if va_marshal:
727         for idx, arg in enumerate(get_args):
728             body += [indent('arg{:d},'.format(idx), level=pad)]
729     else:
730         for idx, arg in enumerate(get_args):
731             arg_getter = IN_ARGS[arg]['getter']
732             body += [indent('{} (param_values + {:d}),'.format(arg_getter, idx + 1), level=pad)]
734     body += [indent('data2);', level=pad)]
736     if va_marshal:
737         boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None]
738         if not boxed_args:
739             body += ['']
740         else:
741             for idx, arg in enumerate(get_args):
742                 if not IN_ARGS[arg].get('box', None):
743                     continue
744                 unbox_func = IN_ARGS[arg]['box'][1]
745                 if IN_ARGS[arg].get('static-check', False):
746                     static_check = STATIC_CHECK_STR.format(idx)
747                 else:
748                     static_check = ''
749                 arg_check = 'arg{:d} != NULL'.format(idx)
750                 body += ['  if ({}{})'.format(static_check, arg_check)]
751                 if IN_ARGS[arg].get('takes-type', False):
752                     body += [UNBOX_TYPED_STR.format(idx=idx, unbox_func=unbox_func)]
753                 else:
754                     body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)]
756     if retval_setter:
757         body += ['']
758         body += ['  {} (return_value, v_return);'.format(retval_setter)]
760     body += ['}']
762     return body
765 def generate_marshaller_alias(outfile, marshaller, real_marshaller,
766                               include_va=False,
767                               source_location=None):
768     '''Generate an alias between @marshaller and @real_marshaller, including
769     an optional alias for va_list marshallers'''
770     if source_location:
771         outfile.write('/* {} */\n'.format(source_location))
773     outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller))
775     if include_va:
776         outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller))
778     outfile.write('\n')
781 def generate_marshallers_header(outfile, retval, params,
782                                 prefix='g_cclosure_user_marshal',
783                                 internal=False,
784                                 include_va=False, source_location=None):
785     '''Generate a declaration for a marshaller function, to be used in the header,
786     with the given @retval, @params, and @prefix. An optional va_list marshaller
787     for the same arguments is also generated. The generated buffer is written to
788     the @outfile stream object.'''
789     if source_location:
790         outfile.write('/* {} */\n'.format(source_location))
792     if internal:
793         visibility = Visibility.INTERNAL
794     else:
795         visibility = Visibility.EXTERN
797     signature = generate_prototype(retval, params, prefix, visibility, False)
798     if include_va:
799         signature += generate_prototype(retval, params, prefix, visibility, True)
800     signature += ['']
802     outfile.write('\n'.join(signature))
803     outfile.write('\n')
806 def generate_marshallers_body(outfile, retval, params,
807                               prefix='g_cclosure_user_marshal',
808                               include_prototype=True,
809                               internal=False,
810                               include_va=False, source_location=None):
811     '''Generate a definition for a marshaller function, to be used in the source,
812     with the given @retval, @params, and @prefix. An optional va_list marshaller
813     for the same arguments is also generated. The generated buffer is written to
814     the @outfile stream object.'''
815     if source_location:
816         outfile.write('/* {} */\n'.format(source_location))
818     if include_prototype:
819         # Declaration visibility
820         if internal:
821             decl_visibility = Visibility.INTERNAL
822         else:
823             decl_visibility = Visibility.EXTERN
824         proto = ['/* Prototype for -Wmissing-prototypes */']
825         proto += generate_prototype(retval, params, prefix, decl_visibility, False)
826         outfile.write('\n'.join(proto))
827         outfile.write('\n')
829     body = generate_body(retval, params, prefix, False)
830     outfile.write('\n'.join(body))
831     outfile.write('\n\n')
833     if include_va:
834         if include_prototype:
835             # Declaration visibility
836             if internal:
837                 decl_visibility = Visibility.INTERNAL
838             else:
839                 decl_visibility = Visibility.EXTERN
840             proto = ['/* Prototype for -Wmissing-prototypes */']
841             proto += generate_prototype(retval, params, prefix, decl_visibility, True)
842             outfile.write('\n'.join(proto))
843             outfile.write('\n')
845         body = generate_body(retval, params, prefix, True)
846         outfile.write('\n'.join(body))
847         outfile.write('\n\n')
850 if __name__ == '__main__':
851     arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject')
852     arg_parser.add_argument('--prefix', metavar='STRING',
853                             default='g_cclosure_user_marshal',
854                             help='Specify marshaller prefix')
855     arg_parser.add_argument('--output', metavar='FILE',
856                             type=argparse.FileType('w'),
857                             default=sys.stdout,
858                             help='Write output into the specified file')
859     arg_parser.add_argument('--skip-source',
860                             action='store_true',
861                             help='Skip source location comments')
862     arg_parser.add_argument('--internal',
863                             action='store_true',
864                             help='Mark generated functions as internal')
865     arg_parser.add_argument('--valist-marshallers',
866                             action='store_true',
867                             help='Generate va_list marshallers')
868     arg_parser.add_argument('-v', '--version',
869                             action='store_true',
870                             dest='show_version',
871                             help='Print version information, and exit')
872     arg_parser.add_argument('--g-fatal-warnings',
873                             action='store_true',
874                             dest='fatal_warnings',
875                             help='Make warnings fatal')
876     arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?',
877                             action='append',
878                             dest='include_headers',
879                             help='Include the specified header in the body')
880     arg_parser.add_argument('--pragma-once',
881                             action='store_true',
882                             help='Use "pragma once" as the inclusion guard')
883     arg_parser.add_argument('-D',
884                             action='append',
885                             dest='cpp_defines',
886                             default=[],
887                             help='Pre-processor define')
888     arg_parser.add_argument('-U',
889                             action='append',
890                             dest='cpp_undefines',
891                             default=[],
892                             help='Pre-processor undefine')
893     arg_parser.add_argument('files', metavar='FILE', nargs='*',
894                             type=argparse.FileType('r'),
895                             help='Files with lists of marshallers to generate, ' +
896                             'or "-" for standard input')
897     arg_parser.add_argument('--prototypes',
898                             action='store_true',
899                             help='Generate the marshallers prototype in the C code')
900     arg_parser.add_argument('--header',
901                             action='store_true',
902                             help='Generate C headers')
903     arg_parser.add_argument('--body',
904                             action='store_true',
905                             help='Generate C code')
907     group = arg_parser.add_mutually_exclusive_group()
908     group.add_argument('--stdinc',
909                        action='store_true',
910                        dest='stdinc', default=True,
911                        help='Include standard marshallers')
912     group.add_argument('--nostdinc',
913                        action='store_false',
914                        dest='stdinc', default=True,
915                        help='Use standard marshallers')
917     group = arg_parser.add_mutually_exclusive_group()
918     group.add_argument('--quiet',
919                        action='store_true',
920                        help='Only print warnings and errors')
921     group.add_argument('--verbose',
922                        action='store_true',
923                        help='Be verbose, and include debugging information')
925     args = arg_parser.parse_args()
927     if args.show_version:
928         print(VERSION_STR)
929         sys.exit(0)
931     # Backward compatibility hack; some projects use both arguments to
932     # generate the marshallers prototype in the C source, even though
933     # it's not really a supported use case. We keep this behaviour by
934     # forcing the --prototypes and --body arguments instead. We make this
935     # warning non-fatal even with --g-fatal-warnings, as it's a deprecation
936     compatibility_mode = False
937     if args.header and args.body:
938         print_warning('Using --header and --body at the same time time is deprecated; ' +
939                       'use --body --prototypes instead', False)
940         args.prototypes = True
941         args.header = False
942         compatibility_mode = True
944     if args.header:
945         generate_header_preamble(args.output,
946                                  prefix=args.prefix,
947                                  std_includes=args.stdinc,
948                                  use_pragma=args.pragma_once)
949     elif args.body:
950         generate_body_preamble(args.output,
951                                std_includes=args.stdinc,
952                                include_headers=args.include_headers,
953                                cpp_defines=args.cpp_defines,
954                                cpp_undefines=args.cpp_undefines)
956     seen_marshallers = set()
958     for infile in args.files:
959         if not args.quiet:
960             print_info('Reading {}...'.format(infile.name))
962         line_count = 0
963         for line in infile:
964             line_count += 1
966             if line == '\n' or line.startswith('#'):
967                 continue
969             matches = re.match(r'^([A-Z0-9]+)\s?:\s?([A-Z0-9,\s]+)$', line.strip())
970             if not matches or len(matches.groups()) != 2:
971                 print_warning('Invalid entry: "{}"'.format(line.strip()), args.fatal_warnings)
972                 continue
974             if not args.skip_source:
975                 location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count)
976             else:
977                 location = None
979             retval = matches.group(1).strip()
980             params = [x.strip() for x in matches.group(2).split(',')]
981             check_args(retval, params, args.fatal_warnings)
983             raw_marshaller = generate_marshaller_name(args.prefix, retval, params, False)
984             if raw_marshaller in seen_marshallers:
985                 if args.verbose:
986                     print_info('Skipping repeated marshaller {}'.format(line.strip()))
987                 continue
989             if args.header:
990                 if args.verbose:
991                     print_info('Generating declaration for {}'.format(line.strip()))
992                 generate_std_alias = False
993                 if args.stdinc:
994                     std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
995                     if std_marshaller in GOBJECT_MARSHALLERS:
996                         if args.verbose:
997                             print_info('Skipping default marshaller {}'.format(line.strip()))
998                         generate_std_alias = True
1000                 marshaller = generate_marshaller_name(args.prefix, retval, params)
1001                 if generate_std_alias:
1002                     generate_marshaller_alias(args.output, marshaller, std_marshaller,
1003                                               source_location=location,
1004                                               include_va=args.valist_marshallers)
1005                 else:
1006                     generate_marshallers_header(args.output, retval, params,
1007                                                 prefix=args.prefix,
1008                                                 internal=args.internal,
1009                                                 include_va=args.valist_marshallers,
1010                                                 source_location=location)
1011                 # If the marshaller is defined using a deprecated token, we want to maintain
1012                 # compatibility and generate an alias for the old name pointing to the new
1013                 # one
1014                 if marshaller != raw_marshaller:
1015                     if args.verbose:
1016                         print_info('Generating alias for deprecated tokens')
1017                     generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1018                                               include_va=args.valist_marshallers)
1019             elif args.body:
1020                 if args.verbose:
1021                     print_info('Generating definition for {}'.format(line.strip()))
1022                 if compatibility_mode:
1023                     generate_std_alias = False
1024                     if args.stdinc:
1025                         std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1026                         if std_marshaller in GOBJECT_MARSHALLERS:
1027                             if args.verbose:
1028                                 print_info('Skipping default marshaller {}'.format(line.strip()))
1029                             generate_std_alias = True
1030                 marshaller = generate_marshaller_name(args.prefix, retval, params)
1031                 if compatibility_mode and generate_std_alias:
1032                     generate_marshaller_alias(args.output, marshaller, std_marshaller,
1033                                               source_location=location,
1034                                               include_va=args.valist_marshallers)
1035                 else:
1036                     generate_marshallers_body(args.output, retval, params,
1037                                               prefix=args.prefix,
1038                                               internal=args.internal,
1039                                               include_prototype=args.prototypes,
1040                                               include_va=args.valist_marshallers,
1041                                               source_location=location)
1042                 if compatibility_mode and marshaller != raw_marshaller:
1043                     if args.verbose:
1044                         print_info('Generating alias for deprecated tokens')
1045                     generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1046                                               include_va=args.valist_marshallers)
1048             seen_marshallers.add(raw_marshaller)
1050         if args.header:
1051             generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)