c_client.py revision 1016ad83
1#!/usr/bin/env python
2from xml.etree.cElementTree import *
3from os.path import basename
4from functools import reduce
5import getopt
6import os
7import sys
8import errno
9import time
10import re
11
12# Jump to the bottom of this file for the main routine
13
14# Some hacks to make the API more readable, and to keep backwards compability
15_cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16_cname_special_cases = {'DECnet':'decnet'}
17
18_extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
19
20_cplusplus_annoyances = {'class' : '_class',
21                         'new'   : '_new',
22                         'delete': '_delete'}
23_c_keywords = {'default' : '_default'}
24
25_hlines = []
26_hlevel = 0
27_clines = []
28_clevel = 0
29_ns = None
30
31# global variable to keep track of serializers and
32# switch data types due to weird dependencies
33finished_serializers = []
34finished_sizeof = []
35finished_switch = []
36
37# keeps enum objects so that we can refer to them when generating manpages.
38enums = {}
39
40manpaths = False
41
42def _h(fmt, *args):
43    '''
44    Writes the given line to the header file.
45    '''
46    _hlines[_hlevel].append(fmt % args)
47
48def _c(fmt, *args):
49    '''
50    Writes the given line to the source file.
51    '''
52    _clines[_clevel].append(fmt % args)
53
54def _hc(fmt, *args):
55    '''
56    Writes the given line to both the header and source files.
57    '''
58    _h(fmt, *args)
59    _c(fmt, *args)
60
61# XXX See if this level thing is really necessary.
62def _h_setlevel(idx):
63    '''
64    Changes the array that header lines are written to.
65    Supports writing different sections of the header file.
66    '''
67    global _hlevel
68    while len(_hlines) <= idx:
69        _hlines.append([])
70    _hlevel = idx
71
72def _c_setlevel(idx):
73    '''
74    Changes the array that source lines are written to.
75    Supports writing to different sections of the source file.
76    '''
77    global _clevel
78    while len(_clines) <= idx:
79        _clines.append([])
80    _clevel = idx
81
82def _n_item(str):
83    '''
84    Does C-name conversion on a single string fragment.
85    Uses a regexp with some hard-coded special cases.
86    '''
87    if str in _cname_special_cases:
88        return _cname_special_cases[str]
89    else:
90        split = _cname_re.finditer(str)
91        name_parts = [match.group(0) for match in split]
92        return '_'.join(name_parts)
93
94def _cpp(str):
95    '''
96    Checks for certain C++ reserved words and fixes them.
97    '''
98    if str in _cplusplus_annoyances:
99        return _cplusplus_annoyances[str]
100    elif str in _c_keywords:
101        return  _c_keywords[str]
102    else:
103        return str
104
105def _ext(str):
106    '''
107    Does C-name conversion on an extension name.
108    Has some additional special cases on top of _n_item.
109    '''
110    if str in _extension_special_cases:
111        return _n_item(str).lower()
112    else:
113        return str.lower()
114
115def _n(list):
116    '''
117    Does C-name conversion on a tuple of strings.
118    Different behavior depending on length of tuple, extension/not extension, etc.
119    Basically C-name converts the individual pieces, then joins with underscores.
120    '''
121    if len(list) == 1:
122        parts = list
123    elif len(list) == 2:
124        parts = [list[0], _n_item(list[1])]
125    elif _ns.is_ext:
126        parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
127    else:
128        parts = [list[0]] + [_n_item(i) for i in list[1:]]
129    return '_'.join(parts).lower()
130
131def _t(list):
132    '''
133    Does C-name conversion on a tuple of strings representing a type.
134    Same as _n but adds a "_t" on the end.
135    '''
136    if len(list) == 1:
137        parts = list
138    elif len(list) == 2:
139        parts = [list[0], _n_item(list[1]), 't']
140    elif _ns.is_ext:
141        parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
142    else:
143        parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
144    return '_'.join(parts).lower()
145
146
147def c_open(self):
148    '''
149    Exported function that handles module open.
150    Opens the files and writes out the auto-generated comment, header file includes, etc.
151    '''
152    global _ns
153    _ns = self.namespace
154    _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
155
156    # Build the type-name collision avoidance table used by c_enum
157    build_collision_table()
158
159    _h_setlevel(0)
160    _c_setlevel(0)
161
162    _hc('/*')
163    _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
164    _hc(' * Edit at your peril.')
165    _hc(' */')
166    _hc('')
167
168    _h('/**')
169    _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
170    _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
171    _h(' * @{')
172    _h(' **/')
173    _h('')
174    _h('#ifndef __%s_H', _ns.header.upper())
175    _h('#define __%s_H', _ns.header.upper())
176    _h('')
177    _h('#include "xcb.h"')
178
179    _c('#ifdef HAVE_CONFIG_H')
180    _c('#include "config.h"')
181    _c('#endif')
182    _c('#include <stdlib.h>')
183    _c('#include <string.h>')
184    _c('#include <assert.h>')
185    _c('#include <stddef.h>  /* for offsetof() */')
186    _c('#include "xcbext.h"')
187    _c('#include "%s.h"', _ns.header)
188
189    _c('')
190    _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
191
192    if _ns.is_ext:
193        for (n, h) in self.imports:
194            _hc('#include "%s.h"', h)
195
196    _h('')
197    _h('#ifdef __cplusplus')
198    _h('extern "C" {')
199    _h('#endif')
200
201    if _ns.is_ext:
202        _h('')
203        _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
204        _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
205        _h('  ') #XXX
206        _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
207
208        _c('')
209        _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
210
211def c_close(self):
212    '''
213    Exported function that handles module close.
214    Writes out all the stored content lines, then closes the files.
215    '''
216    _h_setlevel(2)
217    _c_setlevel(2)
218    _hc('')
219
220    _h('')
221    _h('#ifdef __cplusplus')
222    _h('}')
223    _h('#endif')
224
225    _h('')
226    _h('#endif')
227    _h('')
228    _h('/**')
229    _h(' * @}')
230    _h(' */')
231
232    # Write header file
233    hfile = open('%s.h' % _ns.header, 'w')
234    for list in _hlines:
235        for line in list:
236            hfile.write(line)
237            hfile.write('\n')
238    hfile.close()
239
240    # Write source file
241    cfile = open('%s.c' % _ns.header, 'w')
242    for list in _clines:
243        for line in list:
244            cfile.write(line)
245            cfile.write('\n')
246    cfile.close()
247
248def build_collision_table():
249    global namecount
250    namecount = {}
251
252    for v in module.types.values():
253        name = _t(v[0])
254        namecount[name] = (namecount.get(name) or 0) + 1
255
256def c_enum(self, name):
257    '''
258    Exported function that handles enum declarations.
259    '''
260
261    enums[name] = self
262
263    tname = _t(name)
264    if namecount[tname] > 1:
265        tname = _t(name + ('enum',))
266
267    _h_setlevel(0)
268    _h('')
269    _h('typedef enum %s {', tname)
270
271    count = len(self.values)
272
273    for (enam, eval) in self.values:
274        count = count - 1
275        equals = ' = ' if eval != '' else ''
276        comma = ',' if count > 0 else ''
277        doc = ''
278        if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
279            doc = '\n/**< %s */\n' % self.doc.fields[enam]
280        _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
281
282    _h('} %s;', tname)
283
284def _c_type_setup(self, name, postfix):
285    '''
286    Sets up all the C-related state by adding additional data fields to
287    all Field and Type objects.  Here is where we figure out most of our
288    variable and function names.
289
290    Recurses into child fields and list member types.
291    '''
292    # Do all the various names in advance
293    self.c_type = _t(name + postfix)
294    self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
295
296    self.c_iterator_type = _t(name + ('iterator',))
297    self.c_next_name = _n(name + ('next',))
298    self.c_end_name = _n(name + ('end',))
299
300    self.c_request_name = _n(name)
301    self.c_checked_name = _n(name + ('checked',))
302    self.c_unchecked_name = _n(name + ('unchecked',))
303    self.c_reply_name = _n(name + ('reply',))
304    self.c_reply_type = _t(name + ('reply',))
305    self.c_cookie_type = _t(name + ('cookie',))
306    self.c_reply_fds_name = _n(name + ('reply_fds',))
307
308    self.need_aux = False
309    self.need_serialize = False
310    self.need_sizeof = False
311
312    self.c_aux_name = _n(name + ('aux',))
313    self.c_aux_checked_name = _n(name + ('aux', 'checked'))
314    self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
315    self.c_serialize_name = _n(name + ('serialize',))
316    self.c_unserialize_name = _n(name + ('unserialize',))
317    self.c_unpack_name = _n(name + ('unpack',))
318    self.c_sizeof_name = _n(name + ('sizeof',))
319
320    # special case: structs where variable size fields are followed by fixed size fields
321    self.var_followed_by_fixed_fields = False
322
323    if self.is_switch:
324        self.need_serialize = True
325        self.c_container = 'struct'
326        for bitcase in self.bitcases:
327            bitcase.c_field_name = _cpp(bitcase.field_name)
328            bitcase_name = bitcase.field_type if bitcase.type.has_name else name
329            _c_type_setup(bitcase.type, bitcase_name, ())
330
331    elif self.is_container:
332
333        self.c_container = 'union' if self.is_union else 'struct'
334        prev_varsized_field = None
335        prev_varsized_offset = 0
336        first_field_after_varsized = None
337
338        for field in self.fields:
339            _c_type_setup(field.type, field.field_type, ())
340            if field.type.is_list:
341                _c_type_setup(field.type.member, field.field_type, ())
342                if (field.type.nmemb is None):
343                    self.need_sizeof = True
344
345            field.c_field_type = _t(field.field_type)
346            field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
347            field.c_field_name = _cpp(field.field_name)
348            field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
349            field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
350
351            # correct the c_pointer field for variable size non-list types
352            if not field.type.fixed_size() and field.c_pointer == ' ':
353                field.c_pointer = '*'
354            if field.type.is_list and not field.type.member.fixed_size():
355                field.c_pointer = '*'
356
357            if field.type.is_switch:
358                field.c_pointer = '*'
359                field.c_field_const_type = 'const ' + field.c_field_type
360                self.need_aux = True
361            elif not field.type.fixed_size() and not field.type.is_bitcase:
362                self.need_sizeof = True
363
364            field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
365            field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
366            field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
367            field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
368            field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
369
370            field.prev_varsized_field = prev_varsized_field
371            field.prev_varsized_offset = prev_varsized_offset
372
373            if prev_varsized_offset == 0:
374                first_field_after_varsized = field
375            field.first_field_after_varsized = first_field_after_varsized
376
377            if field.type.fixed_size():
378                prev_varsized_offset += field.type.size
379                # special case: intermixed fixed and variable size fields
380                if prev_varsized_field is not None and not field.type.is_pad and field.wire:
381                    if not self.is_union:
382                        self.need_serialize = True
383                        self.var_followed_by_fixed_fields = True
384            else:
385                self.last_varsized_field = field
386                prev_varsized_field = field
387                prev_varsized_offset = 0
388
389            if self.var_followed_by_fixed_fields:
390                if field.type.fixed_size():
391                    field.prev_varsized_field = None
392
393    if self.need_serialize:
394        # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
395        self.need_sizeof = True
396
397    # as switch does never appear at toplevel,
398    # continue here with type construction
399    if self.is_switch:
400        if self.c_type not in finished_switch:
401            finished_switch.append(self.c_type)
402            # special: switch C structs get pointer fields for variable-sized members
403            _c_complex(self)
404            for bitcase in self.bitcases:
405                bitcase_name = bitcase.type.name if bitcase.type.has_name else name
406                _c_accessors(bitcase.type, bitcase_name, bitcase_name)
407                # no list with switch as element, so no call to
408                # _c_iterator(field.type, field_name) necessary
409
410    if not self.is_bitcase:
411        if self.need_serialize:
412            if self.c_serialize_name not in finished_serializers:
413                finished_serializers.append(self.c_serialize_name)
414                _c_serialize('serialize', self)
415
416                # _unpack() and _unserialize() are only needed for special cases:
417                #   switch -> unpack
418                #   special cases -> unserialize
419                if self.is_switch or self.var_followed_by_fixed_fields:
420                    _c_serialize('unserialize', self)
421
422        if self.need_sizeof:
423            if self.c_sizeof_name not in finished_sizeof:
424                if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
425                    finished_sizeof.append(self.c_sizeof_name)
426                    _c_serialize('sizeof', self)
427# _c_type_setup()
428
429def _c_helper_absolute_name(prefix, field=None):
430    """
431    turn prefix, which is a list of tuples (name, separator, Type obj) into a string
432    representing a valid name in C (based on the context)
433    if field is not None, append the field name as well
434    """
435    prefix_str = ''
436    for name, sep, obj in prefix:
437        prefix_str += name
438        if '' == sep:
439            sep = '->'
440            if ((obj.is_bitcase and obj.has_name) or     # named bitcase
441                (obj.is_switch and len(obj.parents)>1)):
442                sep = '.'
443        prefix_str += sep
444    if field is not None:
445        prefix_str += _cpp(field.field_name)
446    return prefix_str
447# _c_absolute_name
448
449def _c_helper_field_mapping(complex_type, prefix, flat=False):
450    """
451    generate absolute names, based on prefix, for all fields starting from complex_type
452    if flat == True, nested complex types are not taken into account
453    """
454    all_fields = {}
455    if complex_type.is_switch:
456        for b in complex_type.bitcases:
457            if b.type.has_name:
458                switch_name, switch_sep, switch_type = prefix[-1]
459                bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
460            else:
461                bitcase_prefix = prefix
462
463            if (True==flat and not b.type.has_name) or False==flat:
464                all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
465    else:
466        for f in complex_type.fields:
467            fname = _c_helper_absolute_name(prefix, f)
468            if f.field_name in all_fields:
469                raise Exception("field name %s has been registered before" % f.field_name)
470
471            all_fields[f.field_name] = (fname, f)
472            if f.type.is_container and flat==False:
473                if f.type.is_bitcase and not f.type.has_name:
474                    new_prefix = prefix
475                elif f.type.is_switch and len(f.type.parents)>1:
476                    # nested switch gets another separator
477                    new_prefix = prefix+[(f.c_field_name, '.', f.type)]
478                else:
479                    new_prefix = prefix+[(f.c_field_name, '->', f.type)]
480                all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
481
482    return all_fields
483# _c_field_mapping()
484
485def _c_helper_resolve_field_names (prefix):
486    """
487    get field names for all objects in the prefix array
488    """
489    all_fields = {}
490    tmp_prefix = []
491    # look for fields in the remaining containers
492    for idx, p in enumerate(prefix):
493        name, sep, obj = p
494        if ''==sep:
495            # sep can be preset in prefix, if not, make a sensible guess
496            sep = '.' if (obj.is_switch or obj.is_bitcase) else '->'
497            # exception: 'toplevel' object (switch as well!) always have sep '->'
498            sep = '->' if idx<1 else sep
499        if not obj.is_bitcase or (obj.is_bitcase and obj.has_name):
500            tmp_prefix.append((name, sep, obj))
501        all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
502
503    return all_fields
504# _c_helper_resolve_field_names
505
506def get_expr_fields(self):
507    """
508    get the Fields referenced by switch or list expression
509    """
510    def get_expr_field_names(expr):
511        if expr.op is None:
512            if expr.lenfield_name is not None:
513                return [expr.lenfield_name]
514            else:
515                # constant value expr
516                return []
517        else:
518            if expr.op == '~':
519                return get_expr_field_names(expr.rhs)
520            elif expr.op == 'popcount':
521                return get_expr_field_names(expr.rhs)
522            elif expr.op == 'sumof':
523                # sumof expr references another list,
524                # we need that list's length field here
525                field = None
526                for f in expr.lenfield_parent.fields:
527                    if f.field_name == expr.lenfield_name:
528                        field = f
529                        break
530                if field is None:
531                    raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
532                # referenced list + its length field
533                return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
534            elif expr.op == 'enumref':
535                return []
536            else:
537                return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
538    # get_expr_field_names()
539
540    # resolve the field names with the parent structure(s)
541    unresolved_fields_names = get_expr_field_names(self.expr)
542
543    # construct prefix from self
544    prefix = [('', '', p) for p in self.parents]
545    if self.is_container:
546        prefix.append(('', '', self))
547
548    all_fields = _c_helper_resolve_field_names (prefix)
549    resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
550    if len(unresolved_fields_names) != len(resolved_fields_names):
551        raise Exception("could not resolve all fields for %s" % self.name)
552
553    resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
554    return resolved_fields
555# get_expr_fields()
556
557def resolve_expr_fields(complex_obj):
558    """
559    find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
560    these are normally fields that need to be given as function parameters
561    """
562    all_fields = []
563    expr_fields = []
564    unresolved = []
565
566    for field in complex_obj.fields:
567        all_fields.append(field)
568        if field.type.is_switch or field.type.is_list:
569            expr_fields += get_expr_fields(field.type)
570        if field.type.is_container:
571            expr_fields += resolve_expr_fields(field.type)
572
573    # try to resolve expr fields
574    for e in expr_fields:
575        if e not in all_fields and e not in unresolved:
576            unresolved.append(e)
577    return unresolved
578# resolve_expr_fields()
579
580def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
581    """
582    functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
583    E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
584    expression. This function tries to resolve all fields within a structure, and returns the
585    unresolved fields as the list of external parameters.
586    """
587    def add_param(params, param):
588        if param not in params:
589            params.append(param)
590
591    # collect all fields into param_fields
592    param_fields = []
593    wire_fields = []
594
595    for field in self.fields:
596        if field.visible:
597            # the field should appear as a parameter in the function call
598            param_fields.append(field)
599        if field.wire and not field.auto:
600            if field.type.fixed_size() and not self.is_switch:
601                # field in the xcb_out structure
602                wire_fields.append(field)
603        # fields like 'pad0' are skipped!
604
605    # in case of switch, parameters always contain any fields referenced in the switch expr
606    # we do not need any variable size fields here, as the switch data type contains both
607    # fixed and variable size fields
608    if self.is_switch:
609        param_fields = get_expr_fields(self)
610
611    # _serialize()/_unserialize()/_unpack() function parameters
612    # note: don't use set() for params, it is unsorted
613    params = []
614
615    # 1. the parameter for the void * buffer
616    if  'serialize' == context:
617        params.append(('void', '**', buffer_var))
618    elif context in ('unserialize', 'unpack', 'sizeof'):
619        params.append(('const void', '*', buffer_var))
620
621    # 2. any expr fields that cannot be resolved within self and descendants
622    unresolved_fields = resolve_expr_fields(self)
623    for f in unresolved_fields:
624        add_param(params, (f.c_field_type, '', f.c_field_name))
625
626    # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
627    #    that do not appear in the data type struct
628    for p in param_fields:
629        if self.is_switch:
630            typespec = p.c_field_const_type
631            pointerspec = p.c_pointer
632            add_param(params, (typespec, pointerspec, p.c_field_name))
633        else:
634            if p.visible and not p.wire and not p.auto:
635                typespec = p.c_field_type
636                pointerspec = ''
637                add_param(params, (typespec, pointerspec, p.c_field_name))
638
639    # 4. aux argument
640    if 'serialize' == context:
641        add_param(params, ('const %s' % self.c_type, '*', aux_var))
642    elif 'unserialize' == context:
643        add_param(params, ('%s' % self.c_type, '**', aux_var))
644    elif 'unpack' == context:
645        add_param(params, ('%s' % self.c_type, '*', aux_var))
646
647    # 5. switch contains all variable size fields as struct members
648    #    for other data types though, these have to be supplied separately
649    #    this is important for the special case of intermixed fixed and
650    #    variable size fields
651    if not self.is_switch and 'serialize' == context:
652        for p in param_fields:
653            if not p.type.fixed_size():
654                add_param(params, (p.c_field_const_type, '*', p.c_field_name))
655
656    return (param_fields, wire_fields, params)
657# get_serialize_params()
658
659def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
660    code_lines.append('%s    /* insert padding */' % space)
661    code_lines.append('%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
662#    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
663    code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
664
665    if not postpone:
666        code_lines.append('%s    if (0 != xcb_pad) {' % space)
667
668        if 'serialize' == context:
669            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
670            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
671            code_lines.append('%s        xcb_parts_idx++;' % space)
672        elif context in ('unserialize', 'unpack', 'sizeof'):
673            code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
674
675        code_lines.append('%s        xcb_pad = 0;' % space)
676        code_lines.append('%s    }' % space)
677
678    code_lines.append('%s    xcb_block_len = 0;' % space)
679
680    # keep tracking of xcb_parts entries for serialize
681    return 1
682# _c_serialize_helper_insert_padding()
683
684def _c_serialize_helper_switch(context, self, complex_name,
685                               code_lines, temp_vars,
686                               space, prefix):
687    count = 0
688    switch_expr = _c_accessor_get_expr(self.expr, None)
689
690    for b in self.bitcases:
691        len_expr = len(b.type.expr)
692        for n, expr in enumerate(b.type.expr):
693            bitcase_expr = _c_accessor_get_expr(expr, None)
694            # only one <enumref> in the <bitcase>
695            if len_expr == 1:
696                code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
697            # multiple <enumref> in the <bitcase>
698            elif n == 0: # first
699                code_lines.append('    if((%s & %s) ||' % (switch_expr, bitcase_expr))
700            elif len_expr == (n + 1): # last
701                code_lines.append('       (%s & %s)) {' % (switch_expr, bitcase_expr))
702            else: # between first and last
703                code_lines.append('       (%s & %s) ||' % (switch_expr, bitcase_expr))
704
705        b_prefix = prefix
706        if b.type.has_name:
707            b_prefix = prefix + [(b.c_field_name, '.', b.type)]
708
709        count += _c_serialize_helper_fields(context, b.type,
710                                            code_lines, temp_vars,
711                                            "%s    " % space,
712                                            b_prefix,
713                                            is_bitcase = True)
714        code_lines.append('    }')
715
716#    if 'serialize' == context:
717#        count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
718#    elif context in ('unserialize', 'unpack', 'sizeof'):
719#        # padding
720#        code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
721#        code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
722
723    return count
724# _c_serialize_helper_switch
725
726def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
727    """
728    handle switch by calling _serialize() or _unpack(), depending on context
729    """
730    # switch is handled by this function as a special case
731    param_fields, wire_fields, params = get_serialize_params(context, self)
732    field_mapping = _c_helper_field_mapping(self, prefix)
733    prefix_str = _c_helper_absolute_name(prefix)
734
735    # find the parameters that need to be passed to _serialize()/_unpack():
736    # all switch expr fields must be given as parameters
737    args = get_expr_fields(field.type)
738    # length fields for variable size types in switch, normally only some of need
739    # need to be passed as parameters
740    switch_len_fields = resolve_expr_fields(field.type)
741
742    # a switch field at this point _must_ be a bitcase field
743    # we require that bitcases are "self-contiguous"
744    bitcase_unresolved = resolve_expr_fields(self)
745    if len(bitcase_unresolved) != 0:
746        raise Exception('unresolved fields within bitcase is not supported at this point')
747
748    # get the C names for the parameters
749    c_field_names = ''
750    for a in switch_len_fields:
751        c_field_names += "%s, " % field_mapping[a.c_field_name][0]
752    for a in args:
753        c_field_names += "%s, " % field_mapping[a.c_field_name][0]
754
755    # call _serialize()/_unpack() to determine the actual size
756    if 'serialize' == context:
757        length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
758                                       c_field_names, prefix_str, field.c_field_name)
759    elif context in ('unserialize', 'unpack'):
760        length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
761                                           c_field_names, prefix_str, field.c_field_name)
762
763    return length
764# _c_serialize_helper_switch_field()
765
766def _c_serialize_helper_list_field(context, self, field,
767                                   code_lines, temp_vars,
768                                   space, prefix):
769    """
770    helper function to cope with lists of variable length
771    """
772    expr = field.type.expr
773    prefix_str = _c_helper_absolute_name(prefix)
774    param_fields, wire_fields, params = get_serialize_params('sizeof', self)
775    param_names = [p[2] for p in params]
776
777    expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
778    resolved = list(filter(lambda x: x in param_names, expr_fields_names))
779    unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
780
781    field_mapping = {}
782    for r in resolved:
783        field_mapping[r] = (r, None)
784
785    if len(unresolved)>0:
786        tmp_prefix = prefix
787        if len(tmp_prefix)==0:
788            raise Exception("found an empty prefix while resolving expr field names for list %s",
789                            field.c_field_name)
790
791        field_mapping.update(_c_helper_resolve_field_names(prefix))
792        resolved += list(filter(lambda x: x in field_mapping, unresolved))
793        unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
794        if len(unresolved)>0:
795            raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
796
797    list_length = _c_accessor_get_expr(expr, field_mapping)
798
799    # default: list with fixed size elements
800    length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
801
802    # list with variable-sized elements
803    if not field.type.member.fixed_size():
804        length = ''
805        if context in ('unserialize', 'sizeof', 'unpack'):
806            int_i = '    unsigned int i;'
807            xcb_tmp_len = '    unsigned int xcb_tmp_len;'
808            if int_i not in temp_vars:
809                temp_vars.append(int_i)
810            if xcb_tmp_len not in temp_vars:
811                temp_vars.append(xcb_tmp_len)
812            # loop over all list elements and call sizeof repeatedly
813            # this should be a bit faster than using the iterators
814            code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
815            code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp);" %
816                              (space, field.type.c_sizeof_name))
817            code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
818            code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
819            code_lines.append("%s    }" % space)
820
821        elif 'serialize' == context:
822            code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
823            code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
824            code_lines.append('%s    for(i=0; i<%s; i++) { ' % (space, list_length))
825            code_lines.append('%s        xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
826            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
827            code_lines.append('%s    }' % space)
828            code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
829
830    return length
831# _c_serialize_helper_list_field()
832
833def _c_serialize_helper_fields_fixed_size(context, self, field,
834                                          code_lines, temp_vars,
835                                          space, prefix):
836    # keep the C code a bit more readable by giving the field name
837    if not self.is_bitcase:
838        code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
839    else:
840        scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
841        typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
842        code_lines.append('%s    /* %s.%s */' % (space, typename, field.c_field_name))
843
844    abs_field_name = _c_helper_absolute_name(prefix, field)
845    # default for simple cases: call sizeof()
846    length = "sizeof(%s)" % field.c_field_type
847
848    if context in ('unserialize', 'unpack', 'sizeof'):
849        # default: simple cast
850        value = '    %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
851
852        # padding - we could probably just ignore it
853        if field.type.is_pad and field.type.nmemb > 1:
854            value = ''
855            for i in range(field.type.nmemb):
856                code_lines.append('%s    %s[%d] = *(%s *)xcb_tmp;' %
857                                  (space, abs_field_name, i, field.c_field_type))
858            # total padding = sizeof(pad0) * nmemb
859            length += " * %d" % field.type.nmemb
860
861        if field.type.is_list:
862            # no such case in the protocol, cannot be tested and therefore ignored for now
863            raise Exception('list with fixed number of elemens unhandled in _unserialize()')
864
865    elif 'serialize' == context:
866        value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) '
867
868        if field.type.is_expr:
869            # need to register a temporary variable for the expression in case we know its type
870            if field.type.c_type is None:
871                raise Exception("type for field '%s' (expression '%s') unkown" %
872                                (field.field_name, _c_accessor_get_expr(field.type.expr)))
873
874            temp_vars.append('    %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
875                                                           _c_accessor_get_expr(field.type.expr, prefix)))
876            value += "&xcb_expr_%s;" % _cpp(field.field_name)
877
878        elif field.type.is_pad:
879            if field.type.nmemb == 1:
880                value += "&xcb_pad;"
881            else:
882                # we could also set it to 0, see definition of xcb_send_request()
883                value = '    xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
884                length += "*%d" % field.type.nmemb
885
886        else:
887            # non-list type with fixed size
888            if field.type.nmemb == 1:
889                value += "&%s;" % (abs_field_name)
890
891            # list with nmemb (fixed size) elements
892            else:
893                value += '%s;' % (abs_field_name)
894                length = '%d' % field.type.nmemb
895
896    return (value, length)
897# _c_serialize_helper_fields_fixed_size()
898
899def _c_serialize_helper_fields_variable_size(context, self, field,
900                                             code_lines, temp_vars,
901                                             space, prefix):
902    prefix_str = _c_helper_absolute_name(prefix)
903
904    if context in ('unserialize', 'unpack', 'sizeof'):
905        value = ''
906        var_field_name = 'xcb_tmp'
907
908        # special case: intermixed fixed and variable size fields
909        if self.var_followed_by_fixed_fields and 'unserialize' == context:
910            value = '    %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
911            temp_vars.append('    %s *%s;' % (field.type.c_type, field.c_field_name))
912        # special case: switch
913        if 'unpack' == context:
914            value = '    %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
915
916    elif 'serialize' == context:
917        # variable size fields appear as parameters to _serialize() if the
918        # 'toplevel' container is not a switch
919        prefix_string = prefix_str if prefix[0][2].is_switch else ''
920        var_field_name = "%s%s" % (prefix_string, field.c_field_name)
921        value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
922
923    length = ''
924
925    code_lines.append('%s    /* %s */' % (space, field.c_field_name))
926
927    if field.type.is_list:
928        if value != '':
929            # in any context, list is already a pointer, so the default assignment is ok
930            code_lines.append("%s%s" % (space, value))
931            value = ''
932        length = _c_serialize_helper_list_field(context, self, field,
933                                                code_lines, temp_vars,
934                                                space, prefix)
935
936    elif field.type.is_switch:
937        value = ''
938        if context == 'serialize':
939            # the _serialize() function allocates the correct amount memory if given a NULL pointer
940            value = '    xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
941        length = _c_serialize_helper_switch_field(context, self, field,
942                                                  'xcb_parts[xcb_parts_idx].iov_base',
943                                                  prefix)
944
945    else:
946        # in all remaining special cases - call _sizeof()
947        length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
948
949    return (value, length)
950# _c_serialize_helper_fields_variable_size
951
952def _c_serialize_helper_fields(context, self,
953                               code_lines, temp_vars,
954                               space, prefix, is_bitcase):
955    count = 0
956    need_padding = False
957    prev_field_was_variable = False
958
959    for field in self.fields:
960        if not field.visible:
961            if not ((field.wire and not field.auto) or 'unserialize' == context):
962                continue
963
964        # switch/bitcase: fixed size fields must be considered explicitly
965        if field.type.fixed_size():
966            if self.is_bitcase or self.var_followed_by_fixed_fields:
967                if prev_field_was_variable and need_padding:
968                    # insert padding
969#                    count += _c_serialize_helper_insert_padding(context, code_lines, space,
970#                                                                self.var_followed_by_fixed_fields)
971                    prev_field_was_variable = False
972
973                # prefix for fixed size fields
974                fixed_prefix = prefix
975
976                value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
977                                                                      code_lines, temp_vars,
978                                                                      space, fixed_prefix)
979            else:
980                continue
981
982        # fields with variable size
983        else:
984            # switch/bitcase: always calculate padding before and after variable sized fields
985            if need_padding or is_bitcase:
986                count += _c_serialize_helper_insert_padding(context, code_lines, space,
987                                                            self.var_followed_by_fixed_fields)
988
989            value, length = _c_serialize_helper_fields_variable_size(context, self, field,
990                                                                     code_lines, temp_vars,
991                                                                     space, prefix)
992            prev_field_was_variable = True
993
994        # save (un)serialization C code
995        if '' != value:
996            code_lines.append('%s%s' % (space, value))
997
998        if field.type.fixed_size():
999            if is_bitcase or self.var_followed_by_fixed_fields:
1000                # keep track of (un)serialized object's size
1001                code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1002                if context in ('unserialize', 'unpack', 'sizeof'):
1003                    code_lines.append('%s    xcb_tmp += %s;' % (space, length))
1004        else:
1005            # variable size objects or bitcase:
1006            #   value & length might have been inserted earlier for special cases
1007            if '' != length:
1008                # special case: intermixed fixed and variable size fields
1009                if (not field.type.fixed_size() and
1010                    self.var_followed_by_fixed_fields and 'unserialize' == context):
1011                    temp_vars.append('    int %s_len;' % field.c_field_name)
1012                    code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
1013                    code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
1014                    code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
1015                else:
1016                    code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1017                    # increase pointer into the byte stream accordingly
1018                    if context in ('unserialize', 'sizeof', 'unpack'):
1019                        code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1020
1021        if 'serialize' == context:
1022            if '' != length:
1023                code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1024            code_lines.append('%s    xcb_parts_idx++;' % space)
1025            count += 1
1026
1027        code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1028
1029        need_padding = True
1030        if self.var_followed_by_fixed_fields:
1031            need_padding = False
1032
1033    return count
1034# _c_serialize_helper_fields()
1035
1036def _c_serialize_helper(context, complex_type,
1037                        code_lines, temp_vars,
1038                        space='', prefix=[]):
1039    # count tracks the number of fields to serialize
1040    count = 0
1041
1042    if hasattr(complex_type, 'type'):
1043        self = complex_type.type
1044        complex_name = complex_type.name
1045    else:
1046        self = complex_type
1047        if self.var_followed_by_fixed_fields and 'unserialize' == context:
1048            complex_name = 'xcb_out'
1049        else:
1050            complex_name = '_aux'
1051
1052    # special case: switch is serialized by evaluating each bitcase separately
1053    if self.is_switch:
1054        count += _c_serialize_helper_switch(context, self, complex_name,
1055                                            code_lines, temp_vars,
1056                                            space, prefix)
1057
1058    # all other data types can be evaluated one field a time
1059    else:
1060        # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1061        if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
1062            code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
1063            code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1064            code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
1065            code_lines.append('%s    xcb_block_len = 0;' % space)
1066
1067        count += _c_serialize_helper_fields(context, self,
1068                                            code_lines, temp_vars,
1069                                            space, prefix, False)
1070    # "final padding"
1071    count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1072
1073    return count
1074# _c_serialize_helper()
1075
1076def _c_serialize(context, self):
1077    """
1078    depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1079    for the ComplexType variable self
1080    """
1081    _h_setlevel(1)
1082    _c_setlevel(1)
1083
1084    _hc('')
1085    # _serialize() returns the buffer size
1086    _hc('int')
1087
1088    if self.is_switch and 'unserialize' == context:
1089        context = 'unpack'
1090
1091    cases = { 'serialize'   : self.c_serialize_name,
1092              'unserialize' : self.c_unserialize_name,
1093              'unpack'      : self.c_unpack_name,
1094              'sizeof'      : self.c_sizeof_name }
1095    func_name = cases[context]
1096
1097    param_fields, wire_fields, params = get_serialize_params(context, self)
1098    variable_size_fields = 0
1099    # maximum space required for type definition of function arguments
1100    maxtypelen = 0
1101
1102    # determine N(variable_fields)
1103    for field in param_fields:
1104        # if self.is_switch, treat all fields as if they are variable sized
1105        if not field.type.fixed_size() or self.is_switch:
1106            variable_size_fields += 1
1107    # determine maxtypelen
1108    for p in params:
1109        maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1110
1111    # write to .c/.h
1112    indent = ' '*(len(func_name)+2)
1113    param_str = []
1114    for p in params:
1115        typespec, pointerspec, field_name = p
1116        spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1117        param_str.append("%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1118    # insert function name
1119    param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1120    param_str = list(map(lambda x: "%s," % x, param_str))
1121    for s in param_str[:-1]:
1122        _hc(s)
1123    _h("%s);" % param_str[-1].rstrip(','))
1124    _c("%s)" % param_str[-1].rstrip(','))
1125    _c('{')
1126
1127    code_lines = []
1128    temp_vars = []
1129    prefix = []
1130
1131    if 'serialize' == context:
1132        if not self.is_switch and not self.var_followed_by_fixed_fields:
1133            _c('    %s *xcb_out = *_buffer;', self.c_type)
1134            _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1135            _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1136            _c('    unsigned int xcb_align_to = 0;')
1137        else:
1138            _c('    char *xcb_out = *_buffer;')
1139            _c('    unsigned int xcb_buffer_len = 0;')
1140            _c('    unsigned int xcb_align_to = 0;')
1141        prefix = [('_aux', '->', self)]
1142        aux_ptr = 'xcb_out'
1143
1144    elif context in ('unserialize', 'unpack'):
1145        _c('    char *xcb_tmp = (char *)_buffer;')
1146        if not self.is_switch:
1147            if not self.var_followed_by_fixed_fields:
1148                _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1149                prefix = [('_aux', '->', self)]
1150            else:
1151                _c('    %s xcb_out;', self.c_type)
1152                prefix = [('xcb_out', '.', self)]
1153        else:
1154            aux_var = '_aux' # default for unpack: single pointer
1155            # note: unserialize not generated for switch
1156            if 'unserialize' == context:
1157                aux_var = '(*_aux)' # unserialize: double pointer (!)
1158            prefix = [(aux_var, '->', self)]
1159        aux_ptr = '*_aux'
1160        _c('    unsigned int xcb_buffer_len = 0;')
1161        _c('    unsigned int xcb_block_len = 0;')
1162        _c('    unsigned int xcb_pad = 0;')
1163        _c('    unsigned int xcb_align_to = 0;')
1164
1165    elif 'sizeof' == context:
1166        param_names = [p[2] for p in params]
1167        if self.is_switch:
1168            # switch: call _unpack()
1169            _c('    %s _aux;', self.c_type)
1170            _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1171            _c('}')
1172            return
1173        elif self.var_followed_by_fixed_fields:
1174            # special case: call _unserialize()
1175            _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1176            _c('}')
1177            return
1178        else:
1179            _c('    char *xcb_tmp = (char *)_buffer;')
1180            prefix = [('_aux', '->', self)]
1181
1182    count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1183    # update variable size fields (only important for context=='serialize'
1184    variable_size_fields = count
1185    if 'serialize' == context:
1186        temp_vars.append('    unsigned int xcb_pad = 0;')
1187        temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};')
1188        temp_vars.append('    struct iovec xcb_parts[%d];' % count)
1189        temp_vars.append('    unsigned int xcb_parts_idx = 0;')
1190        temp_vars.append('    unsigned int xcb_block_len = 0;')
1191        temp_vars.append('    unsigned int i;')
1192        temp_vars.append('    char *xcb_tmp;')
1193    elif 'sizeof' == context:
1194        # neither switch nor intermixed fixed and variable size fields:
1195        # evaluate parameters directly
1196        if not (self.is_switch or self.var_followed_by_fixed_fields):
1197
1198            # look if we have to declare an '_aux' variable at all
1199            if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1200                if not self.var_followed_by_fixed_fields:
1201                    _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1202                else:
1203                    _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1204
1205            _c('    unsigned int xcb_buffer_len = 0;')
1206            _c('    unsigned int xcb_block_len = 0;')
1207            _c('    unsigned int xcb_pad = 0;')
1208            _c('    unsigned int xcb_align_to = 0;')
1209
1210    _c('')
1211    for t in temp_vars:
1212        _c(t)
1213    _c('')
1214    for l in code_lines:
1215        _c(l)
1216
1217    # variable sized fields have been collected, now
1218    # allocate memory and copy everything into a continuous memory area
1219    # note: this is not necessary in case of unpack
1220    if context in ('serialize', 'unserialize'):
1221        # unserialize: check for sizeof-only invocation
1222        if 'unserialize' == context:
1223            _c('')
1224            _c('    if (NULL == _aux)')
1225            _c('        return xcb_buffer_len;')
1226
1227        _c('')
1228        _c('    if (NULL == %s) {', aux_ptr)
1229        _c('        /* allocate memory */')
1230        _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
1231        if 'serialize' == context:
1232            _c('        *_buffer = xcb_out;')
1233        _c('    }')
1234        _c('')
1235
1236        # serialize: handle variable size fields in a loop
1237        if 'serialize' == context:
1238            if not self.is_switch and not self.var_followed_by_fixed_fields:
1239                if len(wire_fields)>0:
1240                    _c('    *xcb_out = *_aux;')
1241            # copy variable size fields into the buffer
1242            if variable_size_fields > 0:
1243                # xcb_out padding
1244                if not self.is_switch and not self.var_followed_by_fixed_fields:
1245                    _c('    xcb_tmp = (char*)++xcb_out;')
1246                    _c('    xcb_tmp += xcb_out_pad;')
1247                else:
1248                    _c('    xcb_tmp = xcb_out;')
1249
1250                # variable sized fields
1251                _c('    for(i=0; i<xcb_parts_idx; i++) {')
1252                _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1253                _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1254                _c('        if (0 != xcb_parts[i].iov_len)')
1255                _c('            xcb_tmp += xcb_parts[i].iov_len;')
1256                _c('    }')
1257
1258        # unserialize: assign variable size fields individually
1259        if 'unserialize' == context:
1260            _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1261            param_fields.reverse()
1262            for field in param_fields:
1263                if not field.type.fixed_size():
1264                    _c('    xcb_tmp -= %s_len;', field.c_field_name)
1265                    _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1266            _c('    *%s = xcb_out;', aux_ptr)
1267
1268    _c('')
1269    _c('    return xcb_buffer_len;')
1270    _c('}')
1271# _c_serialize()
1272
1273def _c_iterator_get_end(field, accum):
1274    '''
1275    Figures out what C code is needed to find the end of a variable-length structure field.
1276    For nested structures, recurses into its last variable-sized field.
1277    For lists, calls the end function
1278    '''
1279    if field.type.is_container:
1280        accum = field.c_accessor_name + '(' + accum + ')'
1281        return _c_iterator_get_end(field.type.last_varsized_field, accum)
1282    if field.type.is_list:
1283        # XXX we can always use the first way
1284        if field.type.member.is_simple:
1285            return field.c_end_name + '(' + accum + ')'
1286        else:
1287            return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1288
1289def _c_iterator(self, name):
1290    '''
1291    Declares the iterator structure and next/end functions for a given type.
1292    '''
1293    _h_setlevel(0)
1294    _h('')
1295    _h('/**')
1296    _h(' * @brief %s', self.c_iterator_type)
1297    _h(' **/')
1298    _h('typedef struct %s {', self.c_iterator_type)
1299    _h('    %s *data; /**<  */', self.c_type)
1300    _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1301    _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1302    _h('} %s;', self.c_iterator_type)
1303
1304    _h_setlevel(1)
1305    _c_setlevel(1)
1306    _h('')
1307    _h('/**')
1308    _h(' * Get the next element of the iterator')
1309    _h(' * @param i Pointer to a %s', self.c_iterator_type)
1310    _h(' *')
1311    _h(' * Get the next element in the iterator. The member rem is')
1312    _h(' * decreased by one. The member data points to the next')
1313    _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1314    _h(' */')
1315    _c('')
1316    _hc('')
1317    _hc('/*****************************************************************************')
1318    _hc(' **')
1319    _hc(' ** void %s', self.c_next_name)
1320    _hc(' ** ')
1321    _hc(' ** @param %s *i', self.c_iterator_type)
1322    _hc(' ** @returns void')
1323    _hc(' **')
1324    _hc(' *****************************************************************************/')
1325    _hc(' ')
1326    _hc('void')
1327    _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1328    _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1329    _c('{')
1330
1331    if not self.fixed_size():
1332        _c('    %s *R = i->data;', self.c_type)
1333
1334        if self.is_union:
1335            # FIXME - how to determine the size of a variable size union??
1336            _c('    /* FIXME - determine the size of the union %s */', self.c_type)
1337        else:
1338            if self.need_sizeof:
1339                _c('    xcb_generic_iterator_t child;')
1340                _c('    child.data = (%s *)(((char *)R) + %s(R));',
1341                   self.c_type, self.c_sizeof_name)
1342                _c('    i->index = (char *) child.data - (char *) i->data;')
1343            else:
1344                _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1345                _c('    i->index = child.index;')
1346            _c('    --i->rem;')
1347            _c('    i->data = (%s *) child.data;', self.c_type)
1348
1349    else:
1350        _c('    --i->rem;')
1351        _c('    ++i->data;')
1352        _c('    i->index += sizeof(%s);', self.c_type)
1353
1354    _c('}')
1355
1356    _h('')
1357    _h('/**')
1358    _h(' * Return the iterator pointing to the last element')
1359    _h(' * @param i An %s', self.c_iterator_type)
1360    _h(' * @return  The iterator pointing to the last element')
1361    _h(' *')
1362    _h(' * Set the current element in the iterator to the last element.')
1363    _h(' * The member rem is set to 0. The member data points to the')
1364    _h(' * last element.')
1365    _h(' */')
1366    _c('')
1367    _hc('')
1368    _hc('/*****************************************************************************')
1369    _hc(' **')
1370    _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1371    _hc(' ** ')
1372    _hc(' ** @param %s i', self.c_iterator_type)
1373    _hc(' ** @returns xcb_generic_iterator_t')
1374    _hc(' **')
1375    _hc(' *****************************************************************************/')
1376    _hc(' ')
1377    _hc('xcb_generic_iterator_t')
1378    _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1379    _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1380    _c('{')
1381    _c('    xcb_generic_iterator_t ret;')
1382
1383    if self.fixed_size():
1384        _c('    ret.data = i.data + i.rem;')
1385        _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1386        _c('    ret.rem = 0;')
1387    else:
1388        _c('    while(i.rem > 0)')
1389        _c('        %s(&i);', self.c_next_name)
1390        _c('    ret.data = i.data;')
1391        _c('    ret.rem = i.rem;')
1392        _c('    ret.index = i.index;')
1393
1394    _c('    return ret;')
1395    _c('}')
1396
1397def _c_accessor_get_length(expr, field_mapping=None):
1398    '''
1399    Figures out what C code is needed to get a length field.
1400    The field_mapping parameter can be used to change the absolute name of a length field.
1401    For fields that follow a variable-length field, use the accessor.
1402    Otherwise, just reference the structure field directly.
1403    '''
1404
1405    lenfield_name = expr.lenfield_name
1406    if lenfield_name is not None:
1407        if field_mapping is not None:
1408            lenfield_name = field_mapping[lenfield_name][0]
1409
1410    if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1411        # special case: variable and fixed size fields are intermixed
1412        # if the lenfield is among the fixed size fields, there is no need
1413        # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1414        return field_mapping(expr.lenfield_name)
1415    elif expr.lenfield_name is not None:
1416        return lenfield_name
1417    else:
1418        return str(expr.nmemb)
1419
1420def _c_accessor_get_expr(expr, field_mapping):
1421    '''
1422    Figures out what C code is needed to get the length of a list field.
1423    The field_mapping parameter can be used to change the absolute name of a length field.
1424    Recurses for math operations.
1425    Returns bitcount for value-mask fields.
1426    Otherwise, uses the value of the length field.
1427    '''
1428    lenexp = _c_accessor_get_length(expr, field_mapping)
1429
1430    if expr.op == '~':
1431        return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1432    elif expr.op == 'popcount':
1433        return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1434    elif expr.op == 'enumref':
1435        enum_name = expr.lenfield_type.name
1436        constant_name = expr.lenfield_name
1437        c_name = _n(enum_name + (constant_name,)).upper()
1438        return c_name
1439    elif expr.op == 'sumof':
1440        # locate the referenced list object
1441        list_obj = expr.lenfield_type
1442        field = None
1443        for f in expr.lenfield_parent.fields:
1444            if f.field_name == expr.lenfield_name:
1445                field = f
1446                break
1447
1448        if field is None:
1449            raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1450        list_name = field_mapping[field.c_field_name][0]
1451        c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1452        # note: xcb_sumof() has only been defined for integers
1453        c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1454        return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1455    elif expr.op != None:
1456        return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1457                ' ' + expr.op + ' ' +
1458                _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1459    elif expr.bitfield:
1460        return 'xcb_popcount(' + lenexp + ')'
1461    else:
1462        return lenexp
1463
1464def type_pad_type(type):
1465    if type == 'void':
1466        return 'char'
1467    return type
1468
1469def _c_accessors_field(self, field):
1470    '''
1471    Declares the accessor functions for a non-list field that follows a variable-length field.
1472    '''
1473    c_type = self.c_type
1474
1475    # special case: switch
1476    switch_obj = self if self.is_switch else None
1477    if self.is_bitcase:
1478        switch_obj = self.parents[-1]
1479    if switch_obj is not None:
1480        c_type = switch_obj.c_type
1481
1482    if field.type.is_simple:
1483        _hc('')
1484        _hc('')
1485        _hc('/*****************************************************************************')
1486        _hc(' ** ')
1487        _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1488        _hc(' ** ')
1489        _hc(' ** @param const %s *R', c_type)
1490        _hc(' ** @returns %s', field.c_field_type)
1491        _hc(' **')
1492        _hc(' *****************************************************************************/')
1493        _hc(' ')
1494        _hc('%s', field.c_field_type)
1495        _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1496        _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1497        _c('{')
1498        if field.prev_varsized_field is None:
1499            _c('    return (%s *) (R + 1);', field.c_field_type)
1500        else:
1501            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1502            _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1503               field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1504        _c('}')
1505    else:
1506        _hc('')
1507        _hc('')
1508        _hc('/*****************************************************************************')
1509        _hc(' **')
1510        _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1511        _hc(' ** ')
1512        _hc(' ** @param const %s *R', c_type)
1513        _hc(' ** @returns %s *', field.c_field_type)
1514        _hc(' **')
1515        _hc(' *****************************************************************************/')
1516        _hc(' ')
1517        if field.type.is_switch and switch_obj is None:
1518            return_type = 'void *'
1519        else:
1520            return_type = '%s *' % field.c_field_type
1521
1522        _hc(return_type)
1523        _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1524        _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1525        _c('{')
1526        if field.prev_varsized_field is None:
1527            _c('    return (%s) (R + 1);', return_type)
1528            # note: the special case 'variable fields followed by fixed size fields'
1529            #       is not of any consequence here, since the ordering gets
1530            #       'corrected' in the reply function
1531        else:
1532            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1533            _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1534               return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1535        _c('}')
1536
1537
1538def _c_accessors_list(self, field):
1539    '''
1540    Declares the accessor functions for a list field.
1541    Declares a direct-accessor function only if the list members are fixed size.
1542    Declares length and get-iterator functions always.
1543    '''
1544    list = field.type
1545    c_type = self.c_type
1546
1547    # special case: switch
1548    # in case of switch, 2 params have to be supplied to certain accessor functions:
1549    #   1. the anchestor object (request or reply)
1550    #   2. the (anchestor) switch object
1551    # the reason is that switch is either a child of a request/reply or nested in another switch,
1552    # so whenever we need to access a length field, we might need to refer to some anchestor type
1553    switch_obj = self if self.is_switch else None
1554    if self.is_bitcase:
1555        switch_obj = self.parents[-1]
1556    if switch_obj is not None:
1557        c_type = switch_obj.c_type
1558
1559    params = []
1560    fields = {}
1561    parents = self.parents if hasattr(self, 'parents') else [self]
1562    # 'R': parents[0] is always the 'toplevel' container type
1563    params.append(('const %s *R' % parents[0].c_type, parents[0]))
1564    fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1565    # auxiliary object for 'R' parameters
1566    R_obj = parents[0]
1567
1568    if switch_obj is not None:
1569        # now look where the fields are defined that are needed to evaluate
1570        # the switch expr, and store the parent objects in accessor_params and
1571        # the fields in switch_fields
1572
1573        # 'S': name for the 'toplevel' switch
1574        toplevel_switch = parents[1]
1575        params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1576        fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1577
1578        # initialize prefix for everything "below" S
1579        prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1580        prefix = [(prefix_str, '->', toplevel_switch)]
1581
1582        # look for fields in the remaining containers
1583        for p in parents[2:] + [self]:
1584            # the separator between parent and child is always '.' here,
1585            # because of nested switch statements
1586            if not p.is_bitcase or (p.is_bitcase and p.has_name):
1587                prefix.append((p.name[-1], '.', p))
1588            fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1589
1590        # auxiliary object for 'S' parameter
1591        S_obj = parents[1]
1592
1593    _h_setlevel(1)
1594    _c_setlevel(1)
1595    if list.member.fixed_size():
1596        idx = 1 if switch_obj is not None else 0
1597        _hc('')
1598        _hc('')
1599        _hc('/*****************************************************************************')
1600        _hc(' **')
1601        _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1602        _hc(' ** ')
1603        _hc(' ** @param %s', params[idx][0])
1604        _hc(' ** @returns %s *', field.c_field_type)
1605        _hc(' **')
1606        _hc(' *****************************************************************************/')
1607        _hc(' ')
1608        _hc('%s *', field.c_field_type)
1609
1610        _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1611        _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1612
1613        _c('{')
1614        if switch_obj is not None:
1615            _c('    return %s;', fields[field.c_field_name][0])
1616        elif field.prev_varsized_field is None:
1617            _c('    return (%s *) (R + 1);', field.c_field_type)
1618        else:
1619            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1620            _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1621               field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1622        _c('}')
1623
1624    _hc('')
1625    _hc('')
1626    _hc('/*****************************************************************************')
1627    _hc(' **')
1628    _hc(' ** int %s', field.c_length_name)
1629    _hc(' ** ')
1630    _hc(' ** @param const %s *R', c_type)
1631    _hc(' ** @returns int')
1632    _hc(' **')
1633    _hc(' *****************************************************************************/')
1634    _hc(' ')
1635    _hc('int')
1636    if switch_obj is not None:
1637        _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1638        spacing = ' '*(len(field.c_length_name)+2)
1639        _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1640        _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1641        length = _c_accessor_get_expr(field.type.expr, fields)
1642    else:
1643        _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1644        _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1645        length = _c_accessor_get_expr(field.type.expr, fields)
1646    _c('{')
1647    _c('    return %s;', length)
1648    _c('}')
1649
1650    if field.type.member.is_simple:
1651        _hc('')
1652        _hc('')
1653        _hc('/*****************************************************************************')
1654        _hc(' **')
1655        _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1656        _hc(' ** ')
1657        _hc(' ** @param const %s *R', c_type)
1658        _hc(' ** @returns xcb_generic_iterator_t')
1659        _hc(' **')
1660        _hc(' *****************************************************************************/')
1661        _hc(' ')
1662        _hc('xcb_generic_iterator_t')
1663        if switch_obj is not None:
1664            _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1665            spacing = ' '*(len(field.c_end_name)+2)
1666            _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1667            _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1668        else:
1669            _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1670            _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1671        _c('{')
1672        _c('    xcb_generic_iterator_t i;')
1673
1674        param = 'R' if switch_obj is None else 'S'
1675        if switch_obj is not None:
1676            _c('    i.data = %s + %s;', fields[field.c_field_name][0],
1677               _c_accessor_get_expr(field.type.expr, fields))
1678        elif field.prev_varsized_field == None:
1679            _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1680               _c_accessor_get_expr(field.type.expr, fields))
1681        else:
1682            _c('    xcb_generic_iterator_t child = %s;',
1683               _c_iterator_get_end(field.prev_varsized_field, 'R'))
1684            _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1685               _c_accessor_get_expr(field.type.expr, fields))
1686
1687        _c('    i.rem = 0;')
1688        _c('    i.index = (char *) i.data - (char *) %s;', param)
1689        _c('    return i;')
1690        _c('}')
1691
1692    else:
1693        _hc('')
1694        _hc('')
1695        _hc('/*****************************************************************************')
1696        _hc(' **')
1697        _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1698        _hc(' ** ')
1699        _hc(' ** @param const %s *R', c_type)
1700        _hc(' ** @returns %s', field.c_iterator_type)
1701        _hc(' **')
1702        _hc(' *****************************************************************************/')
1703        _hc(' ')
1704
1705        _hc('%s', field.c_iterator_type)
1706        if switch_obj is not None:
1707            _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1708            spacing = ' '*(len(field.c_iterator_name)+2)
1709            _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1710            _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1711        else:
1712            _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1713            _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1714        _c('{')
1715        _c('    %s i;', field.c_iterator_type)
1716
1717        if switch_obj is not None:
1718            _c('    i.data = %s;', fields[field.c_field_name][0])
1719            _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1720        elif field.prev_varsized_field == None:
1721            _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1722        else:
1723            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1724            _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));',
1725               field.c_field_type, type_pad_type(field.c_field_type))
1726        if switch_obj is None:
1727            _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1728        _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1729        _c('    return i;')
1730        _c('}')
1731
1732def _c_accessors(self, name, base):
1733    '''
1734    Declares the accessor functions for the fields of a structure.
1735    '''
1736    # no accessors for switch itself -
1737    # switch always needs to be unpacked explicitly
1738#    if self.is_switch:
1739#        pass
1740#    else:
1741    if True:
1742        for field in self.fields:
1743            if field.type.is_list and not field.type.fixed_size():
1744                _c_accessors_list(self, field)
1745            elif field.prev_varsized_field is not None or not field.type.fixed_size():
1746                _c_accessors_field(self, field)
1747
1748def c_simple(self, name):
1749    '''
1750    Exported function that handles cardinal type declarations.
1751    These are types which are typedef'd to one of the CARDx's, char, float, etc.
1752    '''
1753    _c_type_setup(self, name, ())
1754
1755    if (self.name != name):
1756        # Typedef
1757        _h_setlevel(0)
1758        my_name = _t(name)
1759        _h('')
1760        _h('typedef %s %s;', _t(self.name), my_name)
1761
1762        # Iterator
1763        _c_iterator(self, name)
1764
1765def _c_complex(self):
1766    '''
1767    Helper function for handling all structure types.
1768    Called for all structs, requests, replies, events, errors.
1769    '''
1770    _h_setlevel(0)
1771    _h('')
1772    _h('/**')
1773    _h(' * @brief %s', self.c_type)
1774    _h(' **/')
1775    _h('typedef %s %s {', self.c_container, self.c_type)
1776
1777    struct_fields = []
1778    maxtypelen = 0
1779
1780    varfield = None
1781    for field in self.fields:
1782        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1783            varfield = field.c_field_name
1784            continue
1785        if field.wire:
1786            struct_fields.append(field)
1787
1788    for field in struct_fields:
1789        length = len(field.c_field_type)
1790        # account for '*' pointer_spec
1791        if not field.type.fixed_size() and not self.is_union:
1792            length += 1
1793        maxtypelen = max(maxtypelen, length)
1794
1795    def _c_complex_field(self, field, space=''):
1796        if (field.type.fixed_size() or self.is_union or
1797            # in case of switch with switch children, don't make the field a pointer
1798            # necessary for unserialize to work
1799            (self.is_switch and field.type.is_switch)):
1800            spacing = ' ' * (maxtypelen - len(field.c_field_type))
1801            _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1802        else:
1803            spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1804            _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1805
1806    if not self.is_switch:
1807        for field in struct_fields:
1808            _c_complex_field(self, field)
1809    else:
1810        for b in self.bitcases:
1811            space = ''
1812            if b.type.has_name:
1813                _h('    struct _%s {', b.c_field_name)
1814                space = '    '
1815            for field in b.type.fields:
1816                _c_complex_field(self, field, space)
1817            if b.type.has_name:
1818                _h('    } %s;', b.c_field_name)
1819
1820    _h('} %s;', self.c_type)
1821
1822def c_struct(self, name):
1823    '''
1824    Exported function that handles structure declarations.
1825    '''
1826    _c_type_setup(self, name, ())
1827    _c_complex(self)
1828    _c_accessors(self, name, name)
1829    _c_iterator(self, name)
1830
1831def c_union(self, name):
1832    '''
1833    Exported function that handles union declarations.
1834    '''
1835    _c_type_setup(self, name, ())
1836    _c_complex(self)
1837    _c_iterator(self, name)
1838
1839def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1840    '''
1841    Declares a request function.
1842    '''
1843
1844    # Four stunningly confusing possibilities here:
1845    #
1846    #   Void            Non-void
1847    # ------------------------------
1848    # "req"            "req"
1849    # 0 flag           CHECKED flag   Normal Mode
1850    # void_cookie      req_cookie
1851    # ------------------------------
1852    # "req_checked"    "req_unchecked"
1853    # CHECKED flag     0 flag         Abnormal Mode
1854    # void_cookie      req_cookie
1855    # ------------------------------
1856
1857
1858    # Whether we are _checked or _unchecked
1859    checked = void and not regular
1860    unchecked = not void and not regular
1861
1862    # What kind of cookie we return
1863    func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1864
1865    # What flag is passed to xcb_request
1866    func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1867
1868    if reply_fds:
1869        if func_flags == '0':
1870            func_flags = 'XCB_REQUEST_REPLY_FDS'
1871        else:
1872            func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1873
1874    # Global extension id variable or NULL for xproto
1875    func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1876
1877    # What our function name is
1878    func_name = self.c_request_name if not aux else self.c_aux_name
1879    if checked:
1880        func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1881    if unchecked:
1882        func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1883
1884    param_fields = []
1885    wire_fields = []
1886    maxtypelen = len('xcb_connection_t')
1887    serial_fields = []
1888    # special case: list with variable size elements
1889    list_with_var_size_elems = False
1890
1891    for field in self.fields:
1892        if field.visible:
1893            # The field should appear as a call parameter
1894            param_fields.append(field)
1895        if field.wire and not field.auto:
1896            # We need to set the field up in the structure
1897            wire_fields.append(field)
1898        if field.type.need_serialize or field.type.need_sizeof:
1899            serial_fields.append(field)
1900
1901    for field in param_fields:
1902        c_field_const_type = field.c_field_const_type
1903        if field.type.need_serialize and not aux:
1904            c_field_const_type = "const void"
1905        if len(c_field_const_type) > maxtypelen:
1906            maxtypelen = len(c_field_const_type)
1907        if field.type.is_list and not field.type.member.fixed_size():
1908            list_with_var_size_elems = True
1909
1910    _h_setlevel(1)
1911    _c_setlevel(1)
1912    _h('')
1913    _h('/**')
1914    if hasattr(self, "doc") and self.doc:
1915        if self.doc.brief:
1916            _h(' * @brief ' + self.doc.brief)
1917        else:
1918            _h(' * No brief doc yet')
1919
1920    _h(' *')
1921    _h(' * @param c The connection')
1922    param_names = [f.c_field_name for f in param_fields]
1923    if hasattr(self, "doc") and self.doc:
1924        for field in param_fields:
1925            # XXX: hard-coded until we fix xproto.xml
1926            base_func_name = self.c_request_name if not aux else self.c_aux_name
1927            if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1928                field.enum = 'GC'
1929            elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1930                field.enum = 'CW'
1931            elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1932                field.enum = 'CW'
1933            if field.enum:
1934                # XXX: why the 'xcb' prefix?
1935                key = ('xcb', field.enum)
1936
1937                tname = _t(key)
1938                if namecount[tname] > 1:
1939                    tname = _t(key + ('enum',))
1940                _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1941
1942            if self.doc and field.field_name in self.doc.fields:
1943                desc = self.doc.fields[field.field_name]
1944                for name in param_names:
1945                    desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1946                desc = desc.split("\n")
1947                desc = [line if line != '' else '\\n' for line in desc]
1948                _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1949            # If there is no documentation yet, we simply don't generate an
1950            # @param tag. Doxygen will then warn about missing documentation.
1951
1952    _h(' * @return A cookie')
1953    _h(' *')
1954
1955    if hasattr(self, "doc") and self.doc:
1956        if self.doc.description:
1957            desc = self.doc.description
1958            for name in param_names:
1959                desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1960            desc = desc.split("\n")
1961            _h(' * ' + "\n * ".join(desc))
1962        else:
1963            _h(' * No description yet')
1964    else:
1965        _h(' * Delivers a request to the X server.')
1966    _h(' * ')
1967    if checked:
1968        _h(' * This form can be used only if the request will not cause')
1969        _h(' * a reply to be generated. Any returned error will be')
1970        _h(' * saved for handling by xcb_request_check().')
1971    if unchecked:
1972        _h(' * This form can be used only if the request will cause')
1973        _h(' * a reply to be generated. Any returned error will be')
1974        _h(' * placed in the event queue.')
1975    _h(' */')
1976    _c('')
1977    _hc('')
1978    _hc('/*****************************************************************************')
1979    _hc(' **')
1980    _hc(' ** %s %s', cookie_type, func_name)
1981    _hc(' ** ')
1982
1983    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1984    _hc(' ** @param xcb_connection_t%s *c', spacing)
1985
1986    for field in param_fields:
1987        c_field_const_type = field.c_field_const_type
1988        if field.type.need_serialize and not aux:
1989            c_field_const_type = "const void"
1990        spacing = ' ' * (maxtypelen - len(c_field_const_type))
1991        _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1992
1993    _hc(' ** @returns %s', cookie_type)
1994    _hc(' **')
1995    _hc(' *****************************************************************************/')
1996    _hc(' ')
1997    _hc('%s', cookie_type)
1998
1999    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2000    comma = ',' if len(param_fields) else ');'
2001    _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2002    comma = ',' if len(param_fields) else ')'
2003    _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2004
2005    func_spacing = ' ' * (len(func_name) + 2)
2006    count = len(param_fields)
2007    for field in param_fields:
2008        count = count - 1
2009        c_field_const_type = field.c_field_const_type
2010        c_pointer = field.c_pointer
2011        if field.type.need_serialize and not aux:
2012            c_field_const_type = "const void"
2013            c_pointer = '*'
2014        spacing = ' ' * (maxtypelen - len(c_field_const_type))
2015        comma = ',' if count else ');'
2016        _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2017           spacing, c_pointer, field.c_field_name, comma)
2018        comma = ',' if count else ')'
2019        _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2020           spacing, c_pointer, field.c_field_name, comma)
2021
2022    count = 2
2023    if not self.var_followed_by_fixed_fields:
2024        for field in param_fields:
2025            if not field.type.fixed_size():
2026                count = count + 2
2027                if field.type.need_serialize:
2028                    # _serialize() keeps track of padding automatically
2029                    count -= 1
2030    dimension = count + 2
2031
2032    _c('{')
2033    _c('    static const xcb_protocol_request_t xcb_req = {')
2034    _c('        /* count */ %d,', count)
2035    _c('        /* ext */ %s,', func_ext_global)
2036    _c('        /* opcode */ %s,', self.c_request_name.upper())
2037    _c('        /* isvoid */ %d', 1 if void else 0)
2038    _c('    };')
2039    _c('    ')
2040
2041    _c('    struct iovec xcb_parts[%d];', dimension)
2042    _c('    %s xcb_ret;', func_cookie)
2043    _c('    %s xcb_out;', self.c_type)
2044    if self.var_followed_by_fixed_fields:
2045        _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2046        _c('    void *xcb_aux = 0;')
2047
2048
2049    for idx, f in enumerate(serial_fields):
2050        if aux:
2051            _c('    void *xcb_aux%d = 0;' % (idx))
2052    if list_with_var_size_elems:
2053        _c('    unsigned int i;')
2054        _c('    unsigned int xcb_tmp_len;')
2055        _c('    char *xcb_tmp;')
2056    _c('    ')
2057    # simple request call tracing
2058#    _c('    printf("in function %s\\n");' % func_name)
2059
2060    # fixed size fields
2061    for field in wire_fields:
2062        if field.type.fixed_size():
2063            if field.type.is_expr:
2064                _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2065            elif field.type.is_pad:
2066                if field.type.nmemb == 1:
2067                    _c('    xcb_out.%s = 0;', field.c_field_name)
2068                else:
2069                    _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2070            else:
2071                if field.type.nmemb == 1:
2072                    _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2073                else:
2074                    _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2075
2076    def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2077        serialize_args = get_serialize_params(context, type_obj,
2078                                              c_field_name,
2079                                              aux_var)[2]
2080        return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2081
2082    # calls in order to free dyn. all. memory
2083    free_calls = []
2084
2085    _c('    ')
2086    if not self.var_followed_by_fixed_fields:
2087        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2088        _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2089        _c('    xcb_parts[3].iov_base = 0;')
2090        _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2091
2092        count = 4
2093
2094        for field in param_fields:
2095            if not field.type.fixed_size():
2096                _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2097                # default: simple cast to char *
2098                if not field.type.need_serialize and not field.type.need_sizeof:
2099                    _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2100                    if field.type.is_list:
2101                        if field.type.member.fixed_size():
2102                            _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2103                               _c_accessor_get_expr(field.type.expr, None),
2104                               field.type.member.c_wiretype)
2105                        else:
2106                            list_length = _c_accessor_get_expr(field.type.expr, None)
2107
2108                            length = ''
2109                            _c("    xcb_parts[%d].iov_len = 0;" % count)
2110                            _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2111                            _c("    for(i=0; i<%s; i++) {" % list_length)
2112                            _c("        xcb_tmp_len = %s(xcb_tmp);" %
2113                                              (field.type.c_sizeof_name))
2114                            _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2115                            _c("        xcb_tmp += xcb_tmp_len;")
2116                            _c("    }")
2117                    else:
2118                        # not supposed to happen
2119                        raise Exception("unhandled variable size field %s" % field.c_field_name)
2120                else:
2121                    if not aux:
2122                        _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2123                    idx = serial_fields.index(field)
2124                    aux_var = '&xcb_aux%d' % idx
2125                    context = 'serialize' if aux else 'sizeof'
2126                    _c('    xcb_parts[%d].iov_len = ', count)
2127                    if aux:
2128                        serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2129                        _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2130                        _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2131                        free_calls.append('    free(xcb_aux%d);' % idx)
2132                    else:
2133                        serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2134                        func_name = field.type.c_sizeof_name
2135                        _c('      %s (%s);', func_name, serialize_args)
2136
2137                count += 1
2138                if not (field.type.need_serialize or field.type.need_sizeof):
2139                    # the _serialize() function keeps track of padding automatically
2140                    _c('    xcb_parts[%d].iov_base = 0;', count)
2141                    _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2142                    count += 1
2143
2144    # elif self.var_followed_by_fixed_fields:
2145    else:
2146        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2147        # request header: opcodes + length
2148        _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2149        count += 1
2150        # call _serialize()
2151        buffer_var = '&xcb_aux'
2152        serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2153        _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2154        _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2155        free_calls.append('    free(xcb_aux);')
2156        # no padding necessary - _serialize() keeps track of padding automatically
2157
2158    _c('    ')
2159    for field in param_fields:
2160        if field.isfd:
2161            _c('    xcb_send_fd(c, %s);', field.c_field_name)
2162
2163    _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2164
2165    # free dyn. all. data, if any
2166    for f in free_calls:
2167        _c(f)
2168    _c('    return xcb_ret;')
2169    _c('}')
2170
2171def _c_reply(self, name):
2172    '''
2173    Declares the function that returns the reply structure.
2174    '''
2175    spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2176    spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2177    spacing3 = ' ' * (len(self.c_reply_name) + 2)
2178
2179    # check if _unserialize() has to be called for any field
2180    def look_for_special_cases(complex_obj):
2181        unserialize_fields = []
2182        # no unserialize call in case of switch
2183        if not complex_obj.is_switch:
2184            for field in complex_obj.fields:
2185                # three cases: 1. field with special case
2186                #              2. container that contains special case field
2187                #              3. list with special case elements
2188                if field.type.var_followed_by_fixed_fields:
2189                    unserialize_fields.append(field)
2190                elif field.type.is_container:
2191                    unserialize_fields += look_for_special_cases(field.type)
2192                elif field.type.is_list:
2193                    if field.type.member.var_followed_by_fixed_fields:
2194                        unserialize_fields.append(field)
2195                    if field.type.member.is_container:
2196                        unserialize_fields += look_for_special_cases(field.type.member)
2197        return unserialize_fields
2198
2199    unserialize_fields = look_for_special_cases(self.reply)
2200
2201    _h('')
2202    _h('/**')
2203    _h(' * Return the reply')
2204    _h(' * @param c      The connection')
2205    _h(' * @param cookie The cookie')
2206    _h(' * @param e      The xcb_generic_error_t supplied')
2207    _h(' *')
2208    _h(' * Returns the reply of the request asked by')
2209    _h(' * ')
2210    _h(' * The parameter @p e supplied to this function must be NULL if')
2211    _h(' * %s(). is used.', self.c_unchecked_name)
2212    _h(' * Otherwise, it stores the error if any.')
2213    _h(' *')
2214    _h(' * The returned value must be freed by the caller using free().')
2215    _h(' */')
2216    _c('')
2217    _hc('')
2218    _hc('/*****************************************************************************')
2219    _hc(' **')
2220    _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2221    _hc(' ** ')
2222    _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2223    _hc(' ** @param %s   cookie', self.c_cookie_type)
2224    _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2225    _hc(' ** @returns %s *', self.c_reply_type)
2226    _hc(' **')
2227    _hc(' *****************************************************************************/')
2228    _hc(' ')
2229    _hc('%s *', self.c_reply_type)
2230    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2231    _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2232    _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2233    _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2234    _c('{')
2235
2236    if len(unserialize_fields)>0:
2237        # certain variable size fields need to be unserialized explicitly
2238        _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2239           self.c_reply_type, self.c_reply_type)
2240        _c('    int i;')
2241        for field in unserialize_fields:
2242            if field.type.is_list:
2243                _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2244                _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2245                _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2246            else:
2247                raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2248        # call _unserialize(), using the reply as source and target buffer
2249        _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2250        for field in unserialize_fields:
2251            if field.type.is_list:
2252                _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2253                _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2254                _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2255                   field.c_field_name, field.c_field_name)
2256                _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2257                _c('    }')
2258        # return the transformed reply
2259        _c('    return reply;')
2260
2261    else:
2262        _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2263
2264    _c('}')
2265
2266def _c_reply_has_fds(self):
2267    for field in self.fields:
2268        if field.isfd:
2269            return True
2270    return False
2271
2272def _c_reply_fds(self, name):
2273    '''
2274    Declares the function that returns fds related to the reply.
2275    '''
2276    spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2277    spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2278    _h('')
2279    _h('/**')
2280    _h(' * Return the reply fds')
2281    _h(' * @param c      The connection')
2282    _h(' * @param reply  The reply')
2283    _h(' *')
2284    _h(' * Returns the array of reply fds of the request asked by')
2285    _h(' * ')
2286    _h(' * The returned value must be freed by the caller using free().')
2287    _h(' */')
2288    _c('')
2289    _hc('')
2290    _hc('/*****************************************************************************')
2291    _hc(' **')
2292    _hc(' ** int * %s', self.c_reply_fds_name)
2293    _hc(' ** ')
2294    _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2295    _hc(' ** @param %s  *reply', self.c_reply_type)
2296    _hc(' ** @returns int *')
2297    _hc(' **')
2298    _hc(' *****************************************************************************/')
2299    _hc(' ')
2300    _hc('int *')
2301    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2302    _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2303    _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2304    _c('{')
2305
2306    _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2307
2308    _c('}')
2309
2310
2311def _c_opcode(name, opcode):
2312    '''
2313    Declares the opcode define for requests, events, and errors.
2314    '''
2315    _h_setlevel(0)
2316    _h('')
2317    _h('/** Opcode for %s. */', _n(name))
2318    _h('#define %s %s', _n(name).upper(), opcode)
2319
2320def _c_cookie(self, name):
2321    '''
2322    Declares the cookie type for a non-void request.
2323    '''
2324    _h_setlevel(0)
2325    _h('')
2326    _h('/**')
2327    _h(' * @brief %s', self.c_cookie_type)
2328    _h(' **/')
2329    _h('typedef struct %s {', self.c_cookie_type)
2330    _h('    unsigned int sequence; /**<  */')
2331    _h('} %s;', self.c_cookie_type)
2332
2333def _man_request(self, name, cookie_type, void, aux):
2334    param_fields = [f for f in self.fields if f.visible]
2335
2336    func_name = self.c_request_name if not aux else self.c_aux_name
2337
2338    def create_link(linkname):
2339        name = 'man/%s.3' % linkname
2340        if manpaths:
2341            sys.stdout.write(name)
2342        f = open(name, 'w')
2343        f.write('.so man3/%s.3' % func_name)
2344        f.close()
2345
2346    if manpaths:
2347        sys.stdout.write('man/%s.3 ' % func_name)
2348    # Our CWD is src/, so this will end up in src/man/
2349    f = open('man/%s.3' % func_name, 'w')
2350    f.write('.TH %s 3  %s "XCB" "XCB Requests"\n' % (func_name, today))
2351    # Left-adjust instead of adjusting to both sides
2352    f.write('.ad l\n')
2353    f.write('.SH NAME\n')
2354    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2355    f.write('%s \\- %s\n' % (func_name, brief))
2356    f.write('.SH SYNOPSIS\n')
2357    # Don't split words (hyphenate)
2358    f.write('.hy 0\n')
2359    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2360
2361    # function prototypes
2362    prototype = ''
2363    count = len(param_fields)
2364    for field in param_fields:
2365        count = count - 1
2366        c_field_const_type = field.c_field_const_type
2367        c_pointer = field.c_pointer
2368        if c_pointer == ' ':
2369            c_pointer = ''
2370        if field.type.need_serialize and not aux:
2371            c_field_const_type = "const void"
2372            c_pointer = '*'
2373        comma = ', ' if count else ');'
2374        prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2375
2376    f.write('.SS Request function\n')
2377    f.write('.HP\n')
2378    base_func_name = self.c_request_name if not aux else self.c_aux_name
2379    f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2380    create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2381    if not void:
2382        f.write('.PP\n')
2383        f.write('.SS Reply datastructure\n')
2384        f.write('.nf\n')
2385        f.write('.sp\n')
2386        f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2387        struct_fields = []
2388        maxtypelen = 0
2389
2390        for field in self.reply.fields:
2391            if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2392                continue
2393            if field.wire:
2394                struct_fields.append(field)
2395
2396        for field in struct_fields:
2397            length = len(field.c_field_type)
2398            # account for '*' pointer_spec
2399            if not field.type.fixed_size():
2400                length += 1
2401            maxtypelen = max(maxtypelen, length)
2402
2403        def _c_complex_field(self, field, space=''):
2404            if (field.type.fixed_size() or
2405                # in case of switch with switch children, don't make the field a pointer
2406                # necessary for unserialize to work
2407                (self.is_switch and field.type.is_switch)):
2408                spacing = ' ' * (maxtypelen - len(field.c_field_type))
2409                f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2410            else:
2411                spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2412                f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2413                #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2414
2415        if not self.is_switch:
2416            for field in struct_fields:
2417                _c_complex_field(self, field)
2418        else:
2419            for b in self.bitcases:
2420                space = ''
2421                if b.type.has_name:
2422                    space = '    '
2423                for field in b.type.fields:
2424                    _c_complex_field(self, field, space)
2425                if b.type.has_name:
2426                    print >> sys.stderr, 'ERROR: New unhandled documentation case'
2427                    pass
2428
2429        f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2430        f.write('.fi\n')
2431
2432        f.write('.SS Reply function\n')
2433        f.write('.HP\n')
2434        f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2435                 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2436                (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2437        create_link('%s' % self.c_reply_name)
2438
2439        has_accessors = False
2440        for field in self.reply.fields:
2441            if field.type.is_list and not field.type.fixed_size():
2442                has_accessors = True
2443            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2444                has_accessors = True
2445
2446        if has_accessors:
2447            f.write('.SS Reply accessors\n')
2448
2449        def _c_accessors_field(self, field):
2450            '''
2451            Declares the accessor functions for a non-list field that follows a variable-length field.
2452            '''
2453            c_type = self.c_type
2454
2455            # special case: switch
2456            switch_obj = self if self.is_switch else None
2457            if self.is_bitcase:
2458                switch_obj = self.parents[-1]
2459            if switch_obj is not None:
2460                c_type = switch_obj.c_type
2461
2462            if field.type.is_simple:
2463                f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2464                create_link('%s' % field.c_accessor_name)
2465            else:
2466                f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2467                create_link('%s' % field.c_accessor_name)
2468
2469        def _c_accessors_list(self, field):
2470            '''
2471            Declares the accessor functions for a list field.
2472            Declares a direct-accessor function only if the list members are fixed size.
2473            Declares length and get-iterator functions always.
2474            '''
2475            list = field.type
2476            c_type = self.reply.c_type
2477
2478            # special case: switch
2479            # in case of switch, 2 params have to be supplied to certain accessor functions:
2480            #   1. the anchestor object (request or reply)
2481            #   2. the (anchestor) switch object
2482            # the reason is that switch is either a child of a request/reply or nested in another switch,
2483            # so whenever we need to access a length field, we might need to refer to some anchestor type
2484            switch_obj = self if self.is_switch else None
2485            if self.is_bitcase:
2486                switch_obj = self.parents[-1]
2487            if switch_obj is not None:
2488                c_type = switch_obj.c_type
2489
2490            params = []
2491            fields = {}
2492            parents = self.parents if hasattr(self, 'parents') else [self]
2493            # 'R': parents[0] is always the 'toplevel' container type
2494            params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2495            fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2496            # auxiliary object for 'R' parameters
2497            R_obj = parents[0]
2498
2499            if switch_obj is not None:
2500                # now look where the fields are defined that are needed to evaluate
2501                # the switch expr, and store the parent objects in accessor_params and
2502                # the fields in switch_fields
2503
2504                # 'S': name for the 'toplevel' switch
2505                toplevel_switch = parents[1]
2506                params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2507                fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2508
2509                # initialize prefix for everything "below" S
2510                prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2511                prefix = [(prefix_str, '->', toplevel_switch)]
2512
2513                # look for fields in the remaining containers
2514                for p in parents[2:] + [self]:
2515                    # the separator between parent and child is always '.' here,
2516                    # because of nested switch statements
2517                    if not p.is_bitcase or (p.is_bitcase and p.has_name):
2518                        prefix.append((p.name[-1], '.', p))
2519                    fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2520
2521                # auxiliary object for 'S' parameter
2522                S_obj = parents[1]
2523
2524            if list.member.fixed_size():
2525                idx = 1 if switch_obj is not None else 0
2526                f.write('.HP\n')
2527                f.write('%s *\\fB%s\\fP(%s);\n' %
2528                        (field.c_field_type, field.c_accessor_name, params[idx][0]))
2529                create_link('%s' % field.c_accessor_name)
2530
2531            f.write('.HP\n')
2532            f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2533                    (field.c_length_name, c_type))
2534            create_link('%s' % field.c_length_name)
2535
2536            if field.type.member.is_simple:
2537                f.write('.HP\n')
2538                f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2539                        (field.c_end_name, c_type))
2540                create_link('%s' % field.c_end_name)
2541            else:
2542                f.write('.HP\n')
2543                f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2544                        (field.c_iterator_type, field.c_iterator_name,
2545                         c_type))
2546                create_link('%s' % field.c_iterator_name)
2547
2548        for field in self.reply.fields:
2549            if field.type.is_list and not field.type.fixed_size():
2550                _c_accessors_list(self, field)
2551            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2552                _c_accessors_field(self, field)
2553
2554
2555    f.write('.br\n')
2556    # Re-enable hyphenation and adjusting to both sides
2557    f.write('.hy 1\n')
2558
2559    # argument reference
2560    f.write('.SH REQUEST ARGUMENTS\n')
2561    f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2562    f.write('The XCB connection to X11.\n')
2563    for field in param_fields:
2564        f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2565        printed_enum = False
2566        # XXX: hard-coded until we fix xproto.xml
2567        if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2568            field.enum = 'GC'
2569        elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2570            field.enum = 'CW'
2571        elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2572            field.enum = 'CW'
2573        if hasattr(field, "enum") and field.enum:
2574            # XXX: why the 'xcb' prefix?
2575            key = ('xcb', field.enum)
2576            if key in enums:
2577                f.write('One of the following values:\n')
2578                f.write('.RS 1i\n')
2579                enum = enums[key]
2580                count = len(enum.values)
2581                for (enam, eval) in enum.values:
2582                    count = count - 1
2583                    f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2584                    if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2585                        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2586                        f.write('%s\n' % desc)
2587                    else:
2588                        f.write('TODO: NOT YET DOCUMENTED.\n')
2589                f.write('.RE\n')
2590                f.write('.RS 1i\n')
2591                printed_enum = True
2592
2593        if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2594            desc = self.doc.fields[field.field_name]
2595            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2596            if printed_enum:
2597                f.write('\n')
2598            f.write('%s\n' % desc)
2599        else:
2600            f.write('TODO: NOT YET DOCUMENTED.\n')
2601        if printed_enum:
2602            f.write('.RE\n')
2603
2604    # Reply reference
2605    if not void:
2606        f.write('.SH REPLY FIELDS\n')
2607        # These fields are present in every reply:
2608        f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2609        f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2610                 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2611                 'be used to tell replies apart from each other.\n') %
2612                 _n(self.reply.name).upper())
2613        f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2614        f.write('The sequence number of the last request processed by the X11 server.\n')
2615        f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2616        f.write('The length of the reply, in words (a word is 4 bytes).\n')
2617        for field in self.reply.fields:
2618            if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2619                field.c_field_name.startswith('pad')):
2620                continue
2621
2622            if field.type.is_list and not field.type.fixed_size():
2623                continue
2624            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2625                continue
2626            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2627            printed_enum = False
2628            if hasattr(field, "enum") and field.enum:
2629                # XXX: why the 'xcb' prefix?
2630                key = ('xcb', field.enum)
2631                if key in enums:
2632                    f.write('One of the following values:\n')
2633                    f.write('.RS 1i\n')
2634                    enum = enums[key]
2635                    count = len(enum.values)
2636                    for (enam, eval) in enum.values:
2637                        count = count - 1
2638                        f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2639                        if enum.doc and enam in enum.doc.fields:
2640                            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2641                            f.write('%s\n' % desc)
2642                        else:
2643                            f.write('TODO: NOT YET DOCUMENTED.\n')
2644                    f.write('.RE\n')
2645                    f.write('.RS 1i\n')
2646                    printed_enum = True
2647
2648            if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2649                desc = self.reply.doc.fields[field.field_name]
2650                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2651                if printed_enum:
2652                    f.write('\n')
2653                f.write('%s\n' % desc)
2654            else:
2655                f.write('TODO: NOT YET DOCUMENTED.\n')
2656            if printed_enum:
2657                f.write('.RE\n')
2658
2659
2660
2661    # text description
2662    f.write('.SH DESCRIPTION\n')
2663    if hasattr(self, "doc") and self.doc and self.doc.description:
2664        desc = self.doc.description
2665        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2666        lines = desc.split('\n')
2667        f.write('\n'.join(lines) + '\n')
2668
2669    f.write('.SH RETURN VALUE\n')
2670    if void:
2671        f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2672                 'have to be handled in the event loop.\n\nIf you want to '
2673                 'handle errors directly with \\fIxcb_request_check\\fP '
2674                 'instead, use \\fI%s_checked\\fP. See '
2675                 '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
2676    else:
2677        f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2678                 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2679                 'handle errors in the event loop instead, use '
2680                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
2681                 'details.\n') %
2682                (cookie_type, self.c_reply_name, base_func_name))
2683    f.write('.SH ERRORS\n')
2684    if hasattr(self, "doc") and self.doc:
2685        for errtype, errtext in self.doc.errors.items():
2686            f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2687            errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2688            f.write('%s\n' % (errtext))
2689    if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2690        f.write('This request does never generate any errors.\n')
2691    if hasattr(self, "doc") and self.doc and self.doc.example:
2692        f.write('.SH EXAMPLE\n')
2693        f.write('.nf\n')
2694        f.write('.sp\n')
2695        lines = self.doc.example.split('\n')
2696        f.write('\n'.join(lines) + '\n')
2697        f.write('.fi\n')
2698    f.write('.SH SEE ALSO\n')
2699    if hasattr(self, "doc") and self.doc:
2700        see = ['.BR %s (3)' % 'xcb-requests']
2701        if self.doc.example:
2702            see.append('.BR %s (3)' % 'xcb-examples')
2703        for seename, seetype in self.doc.see.items():
2704            if seetype == 'program':
2705                see.append('.BR %s (1)' % seename)
2706            elif seetype == 'event':
2707                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2708            elif seetype == 'request':
2709                see.append('.BR %s (3)' % _n(('xcb', seename)))
2710            elif seetype == 'function':
2711                see.append('.BR %s (3)' % seename)
2712            else:
2713                see.append('TODO: %s (type %s)' % (seename, seetype))
2714        f.write(',\n'.join(see) + '\n')
2715    f.write('.SH AUTHOR\n')
2716    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2717    f.close()
2718
2719def _man_event(self, name):
2720    if manpaths:
2721        sys.stdout.write('man/%s.3 ' % self.c_type)
2722    # Our CWD is src/, so this will end up in src/man/
2723    f = open('man/%s.3' % self.c_type, 'w')
2724    f.write('.TH %s 3  %s "XCB" "XCB Events"\n' % (self.c_type, today))
2725    # Left-adjust instead of adjusting to both sides
2726    f.write('.ad l\n')
2727    f.write('.SH NAME\n')
2728    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2729    f.write('%s \\- %s\n' % (self.c_type, brief))
2730    f.write('.SH SYNOPSIS\n')
2731    # Don't split words (hyphenate)
2732    f.write('.hy 0\n')
2733    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2734
2735    f.write('.PP\n')
2736    f.write('.SS Event datastructure\n')
2737    f.write('.nf\n')
2738    f.write('.sp\n')
2739    f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2740    struct_fields = []
2741    maxtypelen = 0
2742
2743    for field in self.fields:
2744        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2745            continue
2746        if field.wire:
2747            struct_fields.append(field)
2748
2749    for field in struct_fields:
2750        length = len(field.c_field_type)
2751        # account for '*' pointer_spec
2752        if not field.type.fixed_size():
2753            length += 1
2754        maxtypelen = max(maxtypelen, length)
2755
2756    def _c_complex_field(self, field, space=''):
2757        if (field.type.fixed_size() or
2758            # in case of switch with switch children, don't make the field a pointer
2759            # necessary for unserialize to work
2760            (self.is_switch and field.type.is_switch)):
2761            spacing = ' ' * (maxtypelen - len(field.c_field_type))
2762            f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2763        else:
2764            print >> sys.stderr, 'ERROR: New unhandled documentation case'
2765
2766    if not self.is_switch:
2767        for field in struct_fields:
2768            _c_complex_field(self, field)
2769    else:
2770        for b in self.bitcases:
2771            space = ''
2772            if b.type.has_name:
2773                space = '    '
2774            for field in b.type.fields:
2775                _c_complex_field(self, field, space)
2776            if b.type.has_name:
2777                print >> sys.stderr, 'ERROR: New unhandled documentation case'
2778                pass
2779
2780    f.write('} \\fB%s\\fP;\n' % self.c_type)
2781    f.write('.fi\n')
2782
2783
2784    f.write('.br\n')
2785    # Re-enable hyphenation and adjusting to both sides
2786    f.write('.hy 1\n')
2787
2788    # argument reference
2789    f.write('.SH EVENT FIELDS\n')
2790    f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2791    f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2792             'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2793             'to tell events apart from each other.\n') % _n(name).upper())
2794    f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2795    f.write('The sequence number of the last request processed by the X11 server.\n')
2796
2797    if not self.is_switch:
2798        for field in struct_fields:
2799            # Skip the fields which every event has, we already documented
2800            # them (see above).
2801            if field.c_field_name in ('response_type', 'sequence'):
2802                continue
2803            if isinstance(field.type, PadType):
2804                continue
2805            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2806            if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2807                desc = self.doc.fields[field.field_name]
2808                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2809                f.write('%s\n' % desc)
2810            else:
2811                f.write('NOT YET DOCUMENTED.\n')
2812
2813    # text description
2814    f.write('.SH DESCRIPTION\n')
2815    if hasattr(self, "doc") and self.doc and self.doc.description:
2816        desc = self.doc.description
2817        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2818        lines = desc.split('\n')
2819        f.write('\n'.join(lines) + '\n')
2820
2821    if hasattr(self, "doc") and self.doc and self.doc.example:
2822        f.write('.SH EXAMPLE\n')
2823        f.write('.nf\n')
2824        f.write('.sp\n')
2825        lines = self.doc.example.split('\n')
2826        f.write('\n'.join(lines) + '\n')
2827        f.write('.fi\n')
2828    f.write('.SH SEE ALSO\n')
2829    if hasattr(self, "doc") and self.doc:
2830        see = ['.BR %s (3)' % 'xcb_generic_event_t']
2831        if self.doc.example:
2832            see.append('.BR %s (3)' % 'xcb-examples')
2833        for seename, seetype in self.doc.see.items():
2834            if seetype == 'program':
2835                see.append('.BR %s (1)' % seename)
2836            elif seetype == 'event':
2837                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2838            elif seetype == 'request':
2839                see.append('.BR %s (3)' % _n(('xcb', seename)))
2840            elif seetype == 'function':
2841                see.append('.BR %s (3)' % seename)
2842            else:
2843                see.append('TODO: %s (type %s)' % (seename, seetype))
2844        f.write(',\n'.join(see) + '\n')
2845    f.write('.SH AUTHOR\n')
2846    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2847    f.close()
2848
2849
2850def c_request(self, name):
2851    '''
2852    Exported function that handles request declarations.
2853    '''
2854    _c_type_setup(self, name, ('request',))
2855
2856    if self.reply:
2857        # Cookie type declaration
2858        _c_cookie(self, name)
2859
2860    # Opcode define
2861    _c_opcode(name, self.opcode)
2862
2863    # Request structure declaration
2864    _c_complex(self)
2865
2866    if self.reply:
2867        _c_type_setup(self.reply, name, ('reply',))
2868        # Reply structure definition
2869        _c_complex(self.reply)
2870        # Request prototypes
2871        has_fds = _c_reply_has_fds(self.reply)
2872        _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2873        _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2874        if self.need_aux:
2875            _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2876            _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2877        # Reply accessors
2878        _c_accessors(self.reply, name + ('reply',), name)
2879        _c_reply(self, name)
2880        if has_fds:
2881            _c_reply_fds(self, name)
2882    else:
2883        # Request prototypes
2884        _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2885        _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2886        if self.need_aux:
2887            _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2888            _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2889
2890    # We generate the manpage afterwards because _c_type_setup has been called.
2891    # TODO: what about aux helpers?
2892    cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2893    _man_request(self, name, cookie_type, not self.reply, False)
2894
2895def c_event(self, name):
2896    '''
2897    Exported function that handles event declarations.
2898    '''
2899
2900    # The generic event structure xcb_ge_event_t has the full_sequence field
2901    # at the 32byte boundary. That's why we've to inject this field into GE
2902    # events while generating the structure for them. Otherwise we would read
2903    # garbage (the internal full_sequence) when accessing normal event fields
2904    # there.
2905    if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2906        event_size = 0
2907        for field in self.fields:
2908            if field.type.size != None and field.type.nmemb != None:
2909                event_size += field.type.size * field.type.nmemb
2910            if event_size == 32:
2911                full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2912                idx = self.fields.index(field)
2913                self.fields.insert(idx + 1, full_sequence)
2914                break
2915
2916    _c_type_setup(self, name, ('event',))
2917
2918    # Opcode define
2919    _c_opcode(name, self.opcodes[name])
2920
2921    if self.name == name:
2922        # Structure definition
2923        _c_complex(self)
2924    else:
2925        # Typedef
2926        _h('')
2927        _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2928
2929    _man_event(self, name)
2930
2931def c_error(self, name):
2932    '''
2933    Exported function that handles error declarations.
2934    '''
2935    _c_type_setup(self, name, ('error',))
2936
2937    # Opcode define
2938    _c_opcode(name, self.opcodes[name])
2939
2940    if self.name == name:
2941        # Structure definition
2942        _c_complex(self)
2943    else:
2944        # Typedef
2945        _h('')
2946        _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2947
2948
2949# Main routine starts here
2950
2951# Must create an "output" dictionary before any xcbgen imports.
2952output = {'open'    : c_open,
2953          'close'   : c_close,
2954          'simple'  : c_simple,
2955          'enum'    : c_enum,
2956          'struct'  : c_struct,
2957          'union'   : c_union,
2958          'request' : c_request,
2959          'event'   : c_event,
2960          'error'   : c_error,
2961          }
2962
2963# Boilerplate below this point
2964
2965# Check for the argument that specifies path to the xcbgen python package.
2966try:
2967    opts, args = getopt.getopt(sys.argv[1:], 'p:m')
2968except getopt.GetoptError as err:
2969    print(err)
2970    print('Usage: c_client.py [-p path] file.xml')
2971    sys.exit(1)
2972
2973for (opt, arg) in opts:
2974    if opt == '-p':
2975        sys.path.insert(1, arg)
2976    elif opt == '-m':
2977        manpaths = True
2978        sys.stdout.write('man_MANS = ')
2979
2980# Import the module class
2981try:
2982    from xcbgen.state import Module
2983    from xcbgen.xtypes import *
2984except ImportError:
2985    print('''
2986Failed to load the xcbgen Python package!
2987Make sure that xcb/proto installed it on your Python path.
2988If not, you will need to create a .pth file or define $PYTHONPATH
2989to extend the path.
2990Refer to the README file in xcb/proto for more info.
2991''')
2992    raise
2993
2994# Ensure the man subdirectory exists
2995try:
2996    os.mkdir('man')
2997except OSError as e:
2998    if e.errno != errno.EEXIST:
2999        raise
3000
3001today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
3002
3003# Parse the xml header
3004module = Module(args[0], output)
3005
3006# Build type-registry and resolve type dependencies
3007module.register()
3008module.resolve()
3009
3010# Output the code
3011module.generate()
3012