Update Friulian translation
[glib.git] / gobject / glib-genmarshal.in
blob09e84083f828693e2bffc6cc47f9f73d729d1cfd
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 = []
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     return signature
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'
600     else:
601         unused = ''
603     body = ['void']
605     function_name = generate_marshaller_name(prefix, retval, params)
607     if not va_marshal:
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=' ')]
616     else:
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]
630     body += ['{']
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)
637     pad = len(typedef)
638     typedef += 'gpointer data1,'
639     body += [typedef]
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)]
651     if retval_setter:
652         body += ['  {} v_return;'.format(OUT_ARGS[retval]['ctype'])]
654     if va_marshal:
655         for idx, arg in enumerate(get_args):
656             body += ['  {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)]
658         if get_args:
659             body += ['  va_list args_copy;']
660             body += ['']
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)
672                     else:
673                         static_check = ''
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)]
678                     else:
679                         body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)]
681             body += ['  va_end (args_copy);']
683     body += ['']
685     # Preconditions check
686     if retval_setter:
687         body += ['  g_return_if_fail (return_value != NULL);']
689     if not va_marshal:
690         body += ['  g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)]
692     body += ['']
694     # Marshal instance, data, and callback set up
695     body += ['  if (G_CCLOSURE_SWAP_DATA (closure))']
696     body += ['    {']
697     body += ['      data1 = closure->data;']
698     if va_marshal:
699         body += ['      data2 = instance;']
700     else:
701         body += ['      data2 = g_value_peek_pointer (param_values + 0);']
702     body += ['    }']
703     body += ['  else']
704     body += ['    {']
705     if va_marshal:
706         body += ['      data1 = instance;']
707     else:
708         body += ['      data1 = g_value_peek_pointer (param_values + 0);']
709     body += ['      data2 = closure->data;']
710     body += ['    }']
711     # pylint: disable=line-too-long
712     body += ['  callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)]
713     body += ['']
715     # Marshal callback action
716     if retval_setter:
717         callback = ' {} callback ('.format(' v_return =')
718     else:
719         callback = '  callback ('
721     pad = len(callback)
722     body += [callback + 'data1,']
724     if va_marshal:
725         for idx, arg in enumerate(get_args):
726             body += [indent('arg{:d},'.format(idx), level=pad)]
727     else:
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)]
734     if va_marshal:
735         boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None]
736         if not boxed_args:
737             body += ['']
738         else:
739             for idx, arg in enumerate(get_args):
740                 if not IN_ARGS[arg].get('box', None):
741                     continue
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)
745                 else:
746                     static_check = ''
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)]
751                 else:
752                     body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)]
754     if retval_setter:
755         body += ['']
756         body += ['  {} (return_value, v_return);'.format(retval_setter)]
758     body += ['}']
760     return body
763 def generate_marshaller_alias(outfile, marshaller, real_marshaller,
764                               include_va=False,
765                               source_location=None):
766     '''Generate an alias between @marshaller and @real_marshaller, including
767     an optional alias for va_list marshallers'''
768     if source_location:
769         outfile.write('/* {} */\n'.format(source_location))
771     outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller))
773     if include_va:
774         outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller))
776     outfile.write('\n')
779 def generate_marshallers_header(outfile, retval, params,
780                                 prefix='g_cclosure_user_marshal',
781                                 internal=False,
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.'''
787     if source_location:
788         outfile.write('/* {} */\n'.format(source_location))
790     if internal:
791         visibility = Visibility.INTERNAL
792     else:
793         visibility = Visibility.EXTERN
795     signature = generate_prototype(retval, params, prefix, visibility, False)
796     if include_va:
797         signature += generate_prototype(retval, params, prefix, visibility, True)
798     signature += ['']
800     outfile.write('\n'.join(signature))
801     outfile.write('\n')
804 def generate_marshallers_body(outfile, retval, params,
805                               prefix='g_cclosure_user_marshal',
806                               include_prototype=True,
807                               internal=False,
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.'''
813     if source_location:
814         outfile.write('/* {} */\n'.format(source_location))
816     if include_prototype:
817         # Declaration visibility
818         if internal:
819             decl_visibility = Visibility.INTERNAL
820         else:
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))
829         outfile.write('\n')
831     body = generate_body(retval, params, prefix, False)
832     outfile.write('\n'.join(body))
833     outfile.write('\n\n')
835     if include_va:
836         if include_prototype:
837             # Declaration visibility
838             if internal:
839                 decl_visibility = Visibility.INTERNAL
840             else:
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))
848             outfile.write('\n')
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'),
862                             default=sys.stdout,
863                             help='Write output into the specified file')
864     arg_parser.add_argument('--skip-source',
865                             action='store_true',
866                             help='Skip source location comments')
867     arg_parser.add_argument('--internal',
868                             action='store_true',
869                             help='Mark generated functions as internal')
870     arg_parser.add_argument('--valist-marshallers',
871                             action='store_true',
872                             help='Generate va_list marshallers')
873     arg_parser.add_argument('-v', '--version',
874                             action='store_true',
875                             dest='show_version',
876                             help='Print version information, and exit')
877     arg_parser.add_argument('--g-fatal-warnings',
878                             action='store_true',
879                             dest='fatal_warnings',
880                             help='Make warnings fatal')
881     arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?',
882                             action='append',
883                             dest='include_headers',
884                             help='Include the specified header in the body')
885     arg_parser.add_argument('--pragma-once',
886                             action='store_true',
887                             help='Use "pragma once" as the inclusion guard')
888     arg_parser.add_argument('-D',
889                             action='append',
890                             dest='cpp_defines',
891                             default=[],
892                             help='Pre-processor define')
893     arg_parser.add_argument('-U',
894                             action='append',
895                             dest='cpp_undefines',
896                             default=[],
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',
903                             action='store_true',
904                             help='Generate the marshallers prototype in the C code')
905     arg_parser.add_argument('--header',
906                             action='store_true',
907                             help='Generate C headers')
908     arg_parser.add_argument('--body',
909                             action='store_true',
910                             help='Generate C code')
912     group = arg_parser.add_mutually_exclusive_group()
913     group.add_argument('--stdinc',
914                        action='store_true',
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',
924                        action='store_true',
925                        help='Only print warnings and errors')
926     group.add_argument('--verbose',
927                        action='store_true',
928                        help='Be verbose, and include debugging information')
930     args = arg_parser.parse_args()
932     if args.show_version:
933         print(VERSION_STR)
934         sys.exit(0)
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
946         args.header = False
947         compatibility_mode = True
949     if args.header:
950         generate_header_preamble(args.output,
951                                  prefix=args.prefix,
952                                  std_includes=args.stdinc,
953                                  use_pragma=args.pragma_once)
954     elif args.body:
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:
964         if not args.quiet:
965             print_info('Reading {}...'.format(infile.name))
967         line_count = 0
968         for line in infile:
969             line_count += 1
971             if line == '\n' or line.startswith('#'):
972                 continue
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)
977                 continue
979             if not args.skip_source:
980                 location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count)
981             else:
982                 location = None
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:
990                 if args.verbose:
991                     print_info('Skipping repeated marshaller {}'.format(line.strip()))
992                 continue
994             if args.header:
995                 if args.verbose:
996                     print_info('Generating declaration for {}'.format(line.strip()))
997                 generate_std_alias = False
998                 if args.stdinc:
999                     std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1000                     if std_marshaller in GOBJECT_MARSHALLERS:
1001                         if args.verbose:
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)
1010                 else:
1011                     generate_marshallers_header(args.output, retval, params,
1012                                                 prefix=args.prefix,
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
1018                 # one
1019                 if marshaller != raw_marshaller:
1020                     if args.verbose:
1021                         print_info('Generating alias for deprecated tokens')
1022                     generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1023                                               include_va=args.valist_marshallers)
1024             elif args.body:
1025                 if args.verbose:
1026                     print_info('Generating definition for {}'.format(line.strip()))
1027                 if compatibility_mode:
1028                     generate_std_alias = False
1029                     if args.stdinc:
1030                         std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1031                         if std_marshaller in GOBJECT_MARSHALLERS:
1032                             if args.verbose:
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)
1040                 else:
1041                     generate_marshallers_body(args.output, retval, params,
1042                                               prefix=args.prefix,
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:
1048                     if args.verbose:
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)
1055         if args.header:
1056             generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)