c_client.py revision 1c7386f4
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.direct_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.c_need_aux = False
309    self.c_need_serialize = False
310    self.c_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.c_var_followed_by_fixed_fields = False
322
323    if self.is_switch:
324        self.c_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.c_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.c_need_aux = True
361            elif not field.type.fixed_size() and not field.type.is_bitcase:
362                self.c_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.c_need_serialize = True
383                        self.c_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.c_var_followed_by_fixed_fields:
390                if field.type.fixed_size():
391                    field.prev_varsized_field = None
392
393    if self.c_need_serialize:
394        # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
395        self.c_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.c_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.c_var_followed_by_fixed_fields:
420                    _c_serialize('unserialize', self)
421
422        if self.c_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.c_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.c_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.c_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            if field.type.is_pad:
985                # Variable length pad is <pad align= />
986                code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
987                count += _c_serialize_helper_insert_padding(context, code_lines, space,
988                                                        self.c_var_followed_by_fixed_fields)
989                continue
990            else:
991                # switch/bitcase: always calculate padding before and after variable sized fields
992                if need_padding or is_bitcase:
993                    count += _c_serialize_helper_insert_padding(context, code_lines, space,
994                                                            self.c_var_followed_by_fixed_fields)
995
996                value, length = _c_serialize_helper_fields_variable_size(context, self, field,
997                                                                         code_lines, temp_vars,
998                                                                         space, prefix)
999                prev_field_was_variable = True
1000
1001        # save (un)serialization C code
1002        if '' != value:
1003            code_lines.append('%s%s' % (space, value))
1004
1005        if field.type.fixed_size():
1006            if is_bitcase or self.c_var_followed_by_fixed_fields:
1007                # keep track of (un)serialized object's size
1008                code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1009                if context in ('unserialize', 'unpack', 'sizeof'):
1010                    code_lines.append('%s    xcb_tmp += %s;' % (space, length))
1011        else:
1012            # variable size objects or bitcase:
1013            #   value & length might have been inserted earlier for special cases
1014            if '' != length:
1015                # special case: intermixed fixed and variable size fields
1016                if (not field.type.fixed_size() and
1017                    self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1018                    temp_vars.append('    int %s_len;' % field.c_field_name)
1019                    code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
1020                    code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
1021                    code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
1022                else:
1023                    code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1024                    # increase pointer into the byte stream accordingly
1025                    if context in ('unserialize', 'sizeof', 'unpack'):
1026                        code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1027
1028        if 'serialize' == context:
1029            if '' != length:
1030                code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1031            code_lines.append('%s    xcb_parts_idx++;' % space)
1032            count += 1
1033
1034        code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1035
1036        need_padding = True
1037        if self.c_var_followed_by_fixed_fields:
1038            need_padding = False
1039
1040    return count
1041# _c_serialize_helper_fields()
1042
1043def _c_serialize_helper(context, complex_type,
1044                        code_lines, temp_vars,
1045                        space='', prefix=[]):
1046    # count tracks the number of fields to serialize
1047    count = 0
1048
1049    if hasattr(complex_type, 'type'):
1050        self = complex_type.type
1051        complex_name = complex_type.name
1052    else:
1053        self = complex_type
1054        if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1055            complex_name = 'xcb_out'
1056        else:
1057            complex_name = '_aux'
1058
1059    # special case: switch is serialized by evaluating each bitcase separately
1060    if self.is_switch:
1061        count += _c_serialize_helper_switch(context, self, complex_name,
1062                                            code_lines, temp_vars,
1063                                            space, prefix)
1064
1065    # all other data types can be evaluated one field a time
1066    else:
1067        # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1068        if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1069            code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
1070            code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1071            code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
1072            code_lines.append('%s    xcb_block_len = 0;' % space)
1073
1074        count += _c_serialize_helper_fields(context, self,
1075                                            code_lines, temp_vars,
1076                                            space, prefix, False)
1077    # "final padding"
1078    count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1079
1080    return count
1081# _c_serialize_helper()
1082
1083def _c_serialize(context, self):
1084    """
1085    depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1086    for the ComplexType variable self
1087    """
1088    _h_setlevel(1)
1089    _c_setlevel(1)
1090
1091    _hc('')
1092    # _serialize() returns the buffer size
1093    _hc('int')
1094
1095    if self.is_switch and 'unserialize' == context:
1096        context = 'unpack'
1097
1098    cases = { 'serialize'   : self.c_serialize_name,
1099              'unserialize' : self.c_unserialize_name,
1100              'unpack'      : self.c_unpack_name,
1101              'sizeof'      : self.c_sizeof_name }
1102    func_name = cases[context]
1103
1104    param_fields, wire_fields, params = get_serialize_params(context, self)
1105    variable_size_fields = 0
1106    # maximum space required for type definition of function arguments
1107    maxtypelen = 0
1108
1109    # determine N(variable_fields)
1110    for field in param_fields:
1111        # if self.is_switch, treat all fields as if they are variable sized
1112        if not field.type.fixed_size() or self.is_switch:
1113            variable_size_fields += 1
1114    # determine maxtypelen
1115    for p in params:
1116        maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1117
1118    # write to .c/.h
1119    indent = ' '*(len(func_name)+2)
1120    param_str = []
1121    for p in params:
1122        typespec, pointerspec, field_name = p
1123        spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1124        param_str.append("%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1125    # insert function name
1126    param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1127    param_str = list(map(lambda x: "%s," % x, param_str))
1128    for s in param_str[:-1]:
1129        _hc(s)
1130    _h("%s);" % param_str[-1].rstrip(','))
1131    _c("%s)" % param_str[-1].rstrip(','))
1132    _c('{')
1133
1134    code_lines = []
1135    temp_vars = []
1136    prefix = []
1137
1138    if 'serialize' == context:
1139        if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1140            _c('    %s *xcb_out = *_buffer;', self.c_type)
1141            _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1142            _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1143            _c('    unsigned int xcb_align_to = 0;')
1144        else:
1145            _c('    char *xcb_out = *_buffer;')
1146            _c('    unsigned int xcb_buffer_len = 0;')
1147            _c('    unsigned int xcb_align_to = 0;')
1148        prefix = [('_aux', '->', self)]
1149        aux_ptr = 'xcb_out'
1150
1151    elif context in ('unserialize', 'unpack'):
1152        _c('    char *xcb_tmp = (char *)_buffer;')
1153        if not self.is_switch:
1154            if not self.c_var_followed_by_fixed_fields:
1155                _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1156                prefix = [('_aux', '->', self)]
1157            else:
1158                _c('    %s xcb_out;', self.c_type)
1159                prefix = [('xcb_out', '.', self)]
1160        else:
1161            aux_var = '_aux' # default for unpack: single pointer
1162            # note: unserialize not generated for switch
1163            if 'unserialize' == context:
1164                aux_var = '(*_aux)' # unserialize: double pointer (!)
1165            prefix = [(aux_var, '->', self)]
1166        aux_ptr = '*_aux'
1167        _c('    unsigned int xcb_buffer_len = 0;')
1168        _c('    unsigned int xcb_block_len = 0;')
1169        _c('    unsigned int xcb_pad = 0;')
1170        _c('    unsigned int xcb_align_to = 0;')
1171
1172    elif 'sizeof' == context:
1173        param_names = [p[2] for p in params]
1174        if self.is_switch:
1175            # switch: call _unpack()
1176            _c('    %s _aux;', self.c_type)
1177            _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1178            _c('}')
1179            return
1180        elif self.c_var_followed_by_fixed_fields:
1181            # special case: call _unserialize()
1182            _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1183            _c('}')
1184            return
1185        else:
1186            _c('    char *xcb_tmp = (char *)_buffer;')
1187            prefix = [('_aux', '->', self)]
1188
1189    count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1190    # update variable size fields (only important for context=='serialize'
1191    variable_size_fields = count
1192    if 'serialize' == context:
1193        temp_vars.append('    unsigned int xcb_pad = 0;')
1194        temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};')
1195        temp_vars.append('    struct iovec xcb_parts[%d];' % count)
1196        temp_vars.append('    unsigned int xcb_parts_idx = 0;')
1197        temp_vars.append('    unsigned int xcb_block_len = 0;')
1198        temp_vars.append('    unsigned int i;')
1199        temp_vars.append('    char *xcb_tmp;')
1200    elif 'sizeof' == context:
1201        # neither switch nor intermixed fixed and variable size fields:
1202        # evaluate parameters directly
1203        if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1204
1205            # look if we have to declare an '_aux' variable at all
1206            if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1207                if not self.c_var_followed_by_fixed_fields:
1208                    _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1209                else:
1210                    _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1211
1212            _c('    unsigned int xcb_buffer_len = 0;')
1213            _c('    unsigned int xcb_block_len = 0;')
1214            _c('    unsigned int xcb_pad = 0;')
1215            _c('    unsigned int xcb_align_to = 0;')
1216
1217    _c('')
1218    for t in temp_vars:
1219        _c(t)
1220    _c('')
1221    for l in code_lines:
1222        _c(l)
1223
1224    # variable sized fields have been collected, now
1225    # allocate memory and copy everything into a continuous memory area
1226    # note: this is not necessary in case of unpack
1227    if context in ('serialize', 'unserialize'):
1228        # unserialize: check for sizeof-only invocation
1229        if 'unserialize' == context:
1230            _c('')
1231            _c('    if (NULL == _aux)')
1232            _c('        return xcb_buffer_len;')
1233
1234        _c('')
1235        _c('    if (NULL == %s) {', aux_ptr)
1236        _c('        /* allocate memory */')
1237        _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
1238        if 'serialize' == context:
1239            _c('        *_buffer = xcb_out;')
1240        _c('    }')
1241        _c('')
1242
1243        # serialize: handle variable size fields in a loop
1244        if 'serialize' == context:
1245            if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1246                if len(wire_fields)>0:
1247                    _c('    *xcb_out = *_aux;')
1248            # copy variable size fields into the buffer
1249            if variable_size_fields > 0:
1250                # xcb_out padding
1251                if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1252                    _c('    xcb_tmp = (char*)++xcb_out;')
1253                    _c('    xcb_tmp += xcb_out_pad;')
1254                else:
1255                    _c('    xcb_tmp = xcb_out;')
1256
1257                # variable sized fields
1258                _c('    for(i=0; i<xcb_parts_idx; i++) {')
1259                _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1260                _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1261                _c('        if (0 != xcb_parts[i].iov_len)')
1262                _c('            xcb_tmp += xcb_parts[i].iov_len;')
1263                _c('    }')
1264
1265        # unserialize: assign variable size fields individually
1266        if 'unserialize' == context:
1267            _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1268            param_fields.reverse()
1269            for field in param_fields:
1270                if not field.type.fixed_size():
1271                    _c('    xcb_tmp -= %s_len;', field.c_field_name)
1272                    _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1273            _c('    *%s = xcb_out;', aux_ptr)
1274
1275    _c('')
1276    _c('    return xcb_buffer_len;')
1277    _c('}')
1278# _c_serialize()
1279
1280def _c_iterator_get_end(field, accum):
1281    '''
1282    Figures out what C code is needed to find the end of a variable-length structure field.
1283    For nested structures, recurses into its last variable-sized field.
1284    For lists, calls the end function
1285    '''
1286    if field.type.is_container:
1287        accum = field.c_accessor_name + '(' + accum + ')'
1288        return _c_iterator_get_end(field.type.last_varsized_field, accum)
1289    if field.type.is_list:
1290        # XXX we can always use the first way
1291        if field.type.member.is_simple:
1292            return field.c_end_name + '(' + accum + ')'
1293        else:
1294            return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1295
1296def _c_iterator(self, name):
1297    '''
1298    Declares the iterator structure and next/end functions for a given type.
1299    '''
1300    _h_setlevel(0)
1301    _h('')
1302    _h('/**')
1303    _h(' * @brief %s', self.c_iterator_type)
1304    _h(' **/')
1305    _h('typedef struct %s {', self.c_iterator_type)
1306    _h('    %s *data; /**<  */', self.c_type)
1307    _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1308    _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1309    _h('} %s;', self.c_iterator_type)
1310
1311    _h_setlevel(1)
1312    _c_setlevel(1)
1313    _h('')
1314    _h('/**')
1315    _h(' * Get the next element of the iterator')
1316    _h(' * @param i Pointer to a %s', self.c_iterator_type)
1317    _h(' *')
1318    _h(' * Get the next element in the iterator. The member rem is')
1319    _h(' * decreased by one. The member data points to the next')
1320    _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1321    _h(' */')
1322    _c('')
1323    _hc('void')
1324    _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1325    _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1326    _c('{')
1327
1328    if not self.fixed_size():
1329        _c('    %s *R = i->data;', self.c_type)
1330
1331        if self.is_union:
1332            # FIXME - how to determine the size of a variable size union??
1333            _c('    /* FIXME - determine the size of the union %s */', self.c_type)
1334        else:
1335            if self.c_need_sizeof:
1336                _c('    xcb_generic_iterator_t child;')
1337                _c('    child.data = (%s *)(((char *)R) + %s(R));',
1338                   self.c_type, self.c_sizeof_name)
1339                _c('    i->index = (char *) child.data - (char *) i->data;')
1340            else:
1341                _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1342                _c('    i->index = child.index;')
1343            _c('    --i->rem;')
1344            _c('    i->data = (%s *) child.data;', self.c_type)
1345
1346    else:
1347        _c('    --i->rem;')
1348        _c('    ++i->data;')
1349        _c('    i->index += sizeof(%s);', self.c_type)
1350
1351    _c('}')
1352
1353    _h('')
1354    _h('/**')
1355    _h(' * Return the iterator pointing to the last element')
1356    _h(' * @param i An %s', self.c_iterator_type)
1357    _h(' * @return  The iterator pointing to the last element')
1358    _h(' *')
1359    _h(' * Set the current element in the iterator to the last element.')
1360    _h(' * The member rem is set to 0. The member data points to the')
1361    _h(' * last element.')
1362    _h(' */')
1363    _c('')
1364    _hc('xcb_generic_iterator_t')
1365    _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1366    _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1367    _c('{')
1368    _c('    xcb_generic_iterator_t ret;')
1369
1370    if self.fixed_size():
1371        _c('    ret.data = i.data + i.rem;')
1372        _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1373        _c('    ret.rem = 0;')
1374    else:
1375        _c('    while(i.rem > 0)')
1376        _c('        %s(&i);', self.c_next_name)
1377        _c('    ret.data = i.data;')
1378        _c('    ret.rem = i.rem;')
1379        _c('    ret.index = i.index;')
1380
1381    _c('    return ret;')
1382    _c('}')
1383
1384def _c_accessor_get_length(expr, field_mapping=None):
1385    '''
1386    Figures out what C code is needed to get a length field.
1387    The field_mapping parameter can be used to change the absolute name of a length field.
1388    For fields that follow a variable-length field, use the accessor.
1389    Otherwise, just reference the structure field directly.
1390    '''
1391
1392    lenfield_name = expr.lenfield_name
1393    if lenfield_name is not None:
1394        if field_mapping is not None:
1395            lenfield_name = field_mapping[lenfield_name][0]
1396
1397    if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1398        # special case: variable and fixed size fields are intermixed
1399        # if the lenfield is among the fixed size fields, there is no need
1400        # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1401        return field_mapping(expr.lenfield_name)
1402    elif expr.lenfield_name is not None:
1403        return lenfield_name
1404    else:
1405        return str(expr.nmemb)
1406
1407def _c_accessor_get_expr(expr, field_mapping):
1408    '''
1409    Figures out what C code is needed to get the length of a list field.
1410    The field_mapping parameter can be used to change the absolute name of a length field.
1411    Recurses for math operations.
1412    Returns bitcount for value-mask fields.
1413    Otherwise, uses the value of the length field.
1414    '''
1415    lenexp = _c_accessor_get_length(expr, field_mapping)
1416
1417    if expr.op == '~':
1418        return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1419    elif expr.op == 'popcount':
1420        return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1421    elif expr.op == 'enumref':
1422        enum_name = expr.lenfield_type.name
1423        constant_name = expr.lenfield_name
1424        c_name = _n(enum_name + (constant_name,)).upper()
1425        return c_name
1426    elif expr.op == 'sumof':
1427        # locate the referenced list object
1428        list_obj = expr.lenfield_type
1429        field = None
1430        for f in expr.lenfield_parent.fields:
1431            if f.field_name == expr.lenfield_name:
1432                field = f
1433                break
1434
1435        if field is None:
1436            raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1437        list_name = field_mapping[field.c_field_name][0]
1438        c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1439        # note: xcb_sumof() has only been defined for integers
1440        c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1441        return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1442    elif expr.op != None:
1443        return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1444                ' ' + expr.op + ' ' +
1445                _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1446    elif expr.bitfield:
1447        return 'xcb_popcount(' + lenexp + ')'
1448    else:
1449        return lenexp
1450
1451def type_pad_type(type):
1452    if type == 'void':
1453        return 'char'
1454    return type
1455
1456def _c_accessors_field(self, field):
1457    '''
1458    Declares the accessor functions for a non-list field that follows a variable-length field.
1459    '''
1460    c_type = self.c_type
1461
1462    # special case: switch
1463    switch_obj = self if self.is_switch else None
1464    if self.is_bitcase:
1465        switch_obj = self.parents[-1]
1466    if switch_obj is not None:
1467        c_type = switch_obj.c_type
1468
1469    if field.type.is_simple:
1470        _hc('')
1471        _hc('%s', field.c_field_type)
1472        _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1473        _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1474        _c('{')
1475        if field.prev_varsized_field is None:
1476            _c('    return (%s *) (R + 1);', field.c_field_type)
1477        else:
1478            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1479            _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1480               field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1481        _c('}')
1482    else:
1483        _hc('')
1484        if field.type.is_switch and switch_obj is None:
1485            return_type = 'void *'
1486        else:
1487            return_type = '%s *' % field.c_field_type
1488
1489        _hc(return_type)
1490        _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1491        _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1492        _c('{')
1493        if field.prev_varsized_field is None:
1494            _c('    return (%s) (R + 1);', return_type)
1495            # note: the special case 'variable fields followed by fixed size fields'
1496            #       is not of any consequence here, since the ordering gets
1497            #       'corrected' in the reply function
1498        else:
1499            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1500            _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1501               return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1502        _c('}')
1503
1504
1505def _c_accessors_list(self, field):
1506    '''
1507    Declares the accessor functions for a list field.
1508    Declares a direct-accessor function only if the list members are fixed size.
1509    Declares length and get-iterator functions always.
1510    '''
1511
1512    def get_align_pad(field):
1513            prev = field.prev_varsized_field
1514            prev_prev = field.prev_varsized_field.prev_varsized_field
1515
1516            if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1517                return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1518            else:
1519                return (prev, None)
1520
1521
1522    list = field.type
1523    c_type = self.c_type
1524
1525    # special case: switch
1526    # in case of switch, 2 params have to be supplied to certain accessor functions:
1527    #   1. the anchestor object (request or reply)
1528    #   2. the (anchestor) switch object
1529    # the reason is that switch is either a child of a request/reply or nested in another switch,
1530    # so whenever we need to access a length field, we might need to refer to some anchestor type
1531    switch_obj = self if self.is_switch else None
1532    if self.is_bitcase:
1533        switch_obj = self.parents[-1]
1534    if switch_obj is not None:
1535        c_type = switch_obj.c_type
1536
1537    params = []
1538    fields = {}
1539    parents = self.parents if hasattr(self, 'parents') else [self]
1540    # 'R': parents[0] is always the 'toplevel' container type
1541    params.append(('const %s *R' % parents[0].c_type, parents[0]))
1542    fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1543    # auxiliary object for 'R' parameters
1544    R_obj = parents[0]
1545
1546    if switch_obj is not None:
1547        # now look where the fields are defined that are needed to evaluate
1548        # the switch expr, and store the parent objects in accessor_params and
1549        # the fields in switch_fields
1550
1551        # 'S': name for the 'toplevel' switch
1552        toplevel_switch = parents[1]
1553        params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1554        fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1555
1556        # initialize prefix for everything "below" S
1557        prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1558        prefix = [(prefix_str, '->', toplevel_switch)]
1559
1560        # look for fields in the remaining containers
1561        for p in parents[2:] + [self]:
1562            # the separator between parent and child is always '.' here,
1563            # because of nested switch statements
1564            if not p.is_bitcase or (p.is_bitcase and p.has_name):
1565                prefix.append((p.name[-1], '.', p))
1566            fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1567
1568        # auxiliary object for 'S' parameter
1569        S_obj = parents[1]
1570
1571    _h_setlevel(1)
1572    _c_setlevel(1)
1573    if list.member.fixed_size():
1574        idx = 1 if switch_obj is not None else 0
1575        _hc('')
1576        _hc('%s *', field.c_field_type)
1577
1578        _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1579        _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1580
1581        _c('{')
1582        if switch_obj is not None:
1583            _c('    return %s;', fields[field.c_field_name][0])
1584        elif field.prev_varsized_field is None:
1585            _c('    return (%s *) (R + 1);', field.c_field_type)
1586        else:
1587            (prev_varsized_field, align_pad) = get_align_pad(field)
1588
1589            if align_pad is None:
1590                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1591                    type_pad_type(field.first_field_after_varsized.type.c_type))
1592
1593            _c('    xcb_generic_iterator_t prev = %s;',
1594                _c_iterator_get_end(prev_varsized_field, 'R'))
1595            _c('    return (%s *) ((char *) prev.data + %s + %d);',
1596               field.c_field_type, align_pad, field.prev_varsized_offset)
1597        _c('}')
1598
1599    _hc('')
1600    _hc('int')
1601    if switch_obj is not None:
1602        _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1603        spacing = ' '*(len(field.c_length_name)+2)
1604        _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1605        _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1606        length = _c_accessor_get_expr(field.type.expr, fields)
1607    else:
1608        _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1609        _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1610        length = _c_accessor_get_expr(field.type.expr, fields)
1611    _c('{')
1612    _c('    return %s;', length)
1613    _c('}')
1614
1615    if field.type.member.is_simple:
1616        _hc('')
1617        _hc('xcb_generic_iterator_t')
1618        if switch_obj is not None:
1619            _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1620            spacing = ' '*(len(field.c_end_name)+2)
1621            _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1622            _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1623        else:
1624            _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1625            _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1626        _c('{')
1627        _c('    xcb_generic_iterator_t i;')
1628
1629        param = 'R' if switch_obj is None else 'S'
1630        if switch_obj is not None:
1631            _c('    i.data = %s + %s;', fields[field.c_field_name][0],
1632               _c_accessor_get_expr(field.type.expr, fields))
1633        elif field.prev_varsized_field == None:
1634            _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1635               _c_accessor_get_expr(field.type.expr, fields))
1636        else:
1637            _c('    xcb_generic_iterator_t child = %s;',
1638               _c_iterator_get_end(field.prev_varsized_field, 'R'))
1639            _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1640               _c_accessor_get_expr(field.type.expr, fields))
1641
1642        _c('    i.rem = 0;')
1643        _c('    i.index = (char *) i.data - (char *) %s;', param)
1644        _c('    return i;')
1645        _c('}')
1646
1647    else:
1648        _hc('')
1649        _hc('%s', field.c_iterator_type)
1650        if switch_obj is not None:
1651            _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1652            spacing = ' '*(len(field.c_iterator_name)+2)
1653            _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1654            _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1655        else:
1656            _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1657            _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1658        _c('{')
1659        _c('    %s i;', field.c_iterator_type)
1660
1661        if switch_obj is not None:
1662            _c('    i.data = %s;', fields[field.c_field_name][0])
1663            _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1664        elif field.prev_varsized_field == None:
1665            _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1666        else:
1667            (prev_varsized_field, align_pad) = get_align_pad(field)
1668
1669            if align_pad is None:
1670                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1671                    type_pad_type(field.c_field_type))
1672
1673            _c('    xcb_generic_iterator_t prev = %s;',
1674                _c_iterator_get_end(prev_varsized_field, 'R'))
1675            _c('    i.data = (%s *) ((char *) prev.data + %s);',
1676                field.c_field_type, align_pad)
1677
1678        if switch_obj is None:
1679            _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1680        _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1681        _c('    return i;')
1682        _c('}')
1683
1684def _c_accessors(self, name, base):
1685    '''
1686    Declares the accessor functions for the fields of a structure.
1687    '''
1688    # no accessors for switch itself -
1689    # switch always needs to be unpacked explicitly
1690#    if self.is_switch:
1691#        pass
1692#    else:
1693    if True:
1694        for field in self.fields:
1695            if not field.type.is_pad:
1696                if field.type.is_list and not field.type.fixed_size():
1697                    _c_accessors_list(self, field)
1698                elif field.prev_varsized_field is not None or not field.type.fixed_size():
1699                    _c_accessors_field(self, field)
1700
1701def c_simple(self, name):
1702    '''
1703    Exported function that handles cardinal type declarations.
1704    These are types which are typedef'd to one of the CARDx's, char, float, etc.
1705    '''
1706    _c_type_setup(self, name, ())
1707
1708    if (self.name != name):
1709        # Typedef
1710        _h_setlevel(0)
1711        my_name = _t(name)
1712        _h('')
1713        _h('typedef %s %s;', _t(self.name), my_name)
1714
1715        # Iterator
1716        _c_iterator(self, name)
1717
1718def _c_complex(self, force_packed = False):
1719    '''
1720    Helper function for handling all structure types.
1721    Called for all structs, requests, replies, events, errors.
1722    '''
1723    _h_setlevel(0)
1724    _h('')
1725    _h('/**')
1726    _h(' * @brief %s', self.c_type)
1727    _h(' **/')
1728    _h('typedef %s %s {', self.c_container, self.c_type)
1729
1730    struct_fields = []
1731    maxtypelen = 0
1732
1733    varfield = None
1734    for field in self.fields:
1735        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1736            varfield = field.c_field_name
1737            continue
1738        if field.wire:
1739            struct_fields.append(field)
1740
1741    for field in struct_fields:
1742        length = len(field.c_field_type)
1743        # account for '*' pointer_spec
1744        if not field.type.fixed_size() and not self.is_union:
1745            length += 1
1746        maxtypelen = max(maxtypelen, length)
1747
1748    def _c_complex_field(self, field, space=''):
1749        if (field.type.fixed_size() or self.is_union or
1750            # in case of switch with switch children, don't make the field a pointer
1751            # necessary for unserialize to work
1752            (self.is_switch and field.type.is_switch)):
1753            spacing = ' ' * (maxtypelen - len(field.c_field_type))
1754            _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1755        else:
1756            spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1757            _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1758
1759    if not self.is_switch:
1760        for field in struct_fields:
1761            _c_complex_field(self, field)
1762    else:
1763        for b in self.bitcases:
1764            space = ''
1765            if b.type.has_name:
1766                _h('    struct _%s {', b.c_field_name)
1767                space = '    '
1768            for field in b.type.fields:
1769                _c_complex_field(self, field, space)
1770            if b.type.has_name:
1771                _h('    } %s;', b.c_field_name)
1772
1773    _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1774
1775def c_struct(self, name):
1776    '''
1777    Exported function that handles structure declarations.
1778    '''
1779    _c_type_setup(self, name, ())
1780    _c_complex(self)
1781    _c_accessors(self, name, name)
1782    _c_iterator(self, name)
1783
1784def c_union(self, name):
1785    '''
1786    Exported function that handles union declarations.
1787    '''
1788    _c_type_setup(self, name, ())
1789    _c_complex(self)
1790    _c_iterator(self, name)
1791
1792def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1793    '''
1794    Declares a request function.
1795    '''
1796
1797    # Four stunningly confusing possibilities here:
1798    #
1799    #   Void            Non-void
1800    # ------------------------------
1801    # "req"            "req"
1802    # 0 flag           CHECKED flag   Normal Mode
1803    # void_cookie      req_cookie
1804    # ------------------------------
1805    # "req_checked"    "req_unchecked"
1806    # CHECKED flag     0 flag         Abnormal Mode
1807    # void_cookie      req_cookie
1808    # ------------------------------
1809
1810
1811    # Whether we are _checked or _unchecked
1812    checked = void and not regular
1813    unchecked = not void and not regular
1814
1815    # What kind of cookie we return
1816    func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1817
1818    # What flag is passed to xcb_request
1819    func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1820
1821    if reply_fds:
1822        if func_flags == '0':
1823            func_flags = 'XCB_REQUEST_REPLY_FDS'
1824        else:
1825            func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1826
1827    # Global extension id variable or NULL for xproto
1828    func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1829
1830    # What our function name is
1831    func_name = self.c_request_name if not aux else self.c_aux_name
1832    if checked:
1833        func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1834    if unchecked:
1835        func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1836
1837    param_fields = []
1838    wire_fields = []
1839    maxtypelen = len('xcb_connection_t')
1840    serial_fields = []
1841    # special case: list with variable size elements
1842    list_with_var_size_elems = False
1843
1844    for field in self.fields:
1845        if field.visible:
1846            # The field should appear as a call parameter
1847            param_fields.append(field)
1848        if field.wire and not field.auto:
1849            # We need to set the field up in the structure
1850            wire_fields.append(field)
1851        if field.type.c_need_serialize or field.type.c_need_sizeof:
1852            serial_fields.append(field)
1853
1854    for field in param_fields:
1855        c_field_const_type = field.c_field_const_type
1856        if field.type.c_need_serialize and not aux:
1857            c_field_const_type = "const void"
1858        if len(c_field_const_type) > maxtypelen:
1859            maxtypelen = len(c_field_const_type)
1860        if field.type.is_list and not field.type.member.fixed_size():
1861            list_with_var_size_elems = True
1862
1863    _h_setlevel(1)
1864    _c_setlevel(1)
1865    _h('')
1866    _h('/**')
1867    if hasattr(self, "doc") and self.doc:
1868        if self.doc.brief:
1869            _h(' * @brief ' + self.doc.brief)
1870        else:
1871            _h(' * No brief doc yet')
1872
1873    _h(' *')
1874    _h(' * @param c The connection')
1875    param_names = [f.c_field_name for f in param_fields]
1876    if hasattr(self, "doc") and self.doc:
1877        for field in param_fields:
1878            # XXX: hard-coded until we fix xproto.xml
1879            base_func_name = self.c_request_name if not aux else self.c_aux_name
1880            if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1881                field.enum = 'GC'
1882            elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1883                field.enum = 'CW'
1884            elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1885                field.enum = 'CW'
1886            if field.enum:
1887                # XXX: why the 'xcb' prefix?
1888                key = ('xcb', field.enum)
1889
1890                tname = _t(key)
1891                if namecount[tname] > 1:
1892                    tname = _t(key + ('enum',))
1893                _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1894
1895            if self.doc and field.field_name in self.doc.fields:
1896                desc = self.doc.fields[field.field_name]
1897                for name in param_names:
1898                    desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1899                desc = desc.split("\n")
1900                desc = [line if line != '' else '\\n' for line in desc]
1901                _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1902            # If there is no documentation yet, we simply don't generate an
1903            # @param tag. Doxygen will then warn about missing documentation.
1904
1905    _h(' * @return A cookie')
1906    _h(' *')
1907
1908    if hasattr(self, "doc") and self.doc:
1909        if self.doc.description:
1910            desc = self.doc.description
1911            for name in param_names:
1912                desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1913            desc = desc.split("\n")
1914            _h(' * ' + "\n * ".join(desc))
1915        else:
1916            _h(' * No description yet')
1917    else:
1918        _h(' * Delivers a request to the X server.')
1919    _h(' *')
1920    if checked:
1921        _h(' * This form can be used only if the request will not cause')
1922        _h(' * a reply to be generated. Any returned error will be')
1923        _h(' * saved for handling by xcb_request_check().')
1924    if unchecked:
1925        _h(' * This form can be used only if the request will cause')
1926        _h(' * a reply to be generated. Any returned error will be')
1927        _h(' * placed in the event queue.')
1928    _h(' */')
1929    _c('')
1930    _hc('%s', cookie_type)
1931
1932    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1933    comma = ',' if len(param_fields) else ');'
1934    _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1935    comma = ',' if len(param_fields) else ')'
1936    _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1937
1938    func_spacing = ' ' * (len(func_name) + 2)
1939    count = len(param_fields)
1940    for field in param_fields:
1941        count = count - 1
1942        c_field_const_type = field.c_field_const_type
1943        c_pointer = field.c_pointer
1944        if field.type.c_need_serialize and not aux:
1945            c_field_const_type = "const void"
1946            c_pointer = '*'
1947        spacing = ' ' * (maxtypelen - len(c_field_const_type))
1948        comma = ',' if count else ');'
1949        _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
1950           spacing, c_pointer, field.c_field_name, comma)
1951        comma = ',' if count else ')'
1952        _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
1953           spacing, c_pointer, field.c_field_name, comma)
1954
1955    count = 2
1956    if not self.c_var_followed_by_fixed_fields:
1957        for field in param_fields:
1958            if not field.type.fixed_size():
1959                count = count + 2
1960                if field.type.c_need_serialize:
1961                    # _serialize() keeps track of padding automatically
1962                    count -= 1
1963    dimension = count + 2
1964
1965    _c('{')
1966    _c('    static const xcb_protocol_request_t xcb_req = {')
1967    _c('        /* count */ %d,', count)
1968    _c('        /* ext */ %s,', func_ext_global)
1969    _c('        /* opcode */ %s,', self.c_request_name.upper())
1970    _c('        /* isvoid */ %d', 1 if void else 0)
1971    _c('    };')
1972    _c('')
1973
1974    _c('    struct iovec xcb_parts[%d];', dimension)
1975    _c('    %s xcb_ret;', func_cookie)
1976    _c('    %s xcb_out;', self.c_type)
1977    if self.c_var_followed_by_fixed_fields:
1978        _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
1979        _c('    void *xcb_aux = 0;')
1980
1981
1982    for idx, f in enumerate(serial_fields):
1983        if aux:
1984            _c('    void *xcb_aux%d = 0;' % (idx))
1985    if list_with_var_size_elems:
1986        _c('    unsigned int i;')
1987        _c('    unsigned int xcb_tmp_len;')
1988        _c('    char *xcb_tmp;')
1989    _c('')
1990    # simple request call tracing
1991#    _c('    printf("in function %s\\n");' % func_name)
1992
1993    # fixed size fields
1994    for field in wire_fields:
1995        if field.type.fixed_size():
1996            if field.type.is_expr:
1997                _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
1998            elif field.type.is_pad:
1999                if field.type.nmemb == 1:
2000                    _c('    xcb_out.%s = 0;', field.c_field_name)
2001                else:
2002                    _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2003            else:
2004                if field.type.nmemb == 1:
2005                    _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2006                else:
2007                    _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2008
2009    def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2010        serialize_args = get_serialize_params(context, type_obj,
2011                                              c_field_name,
2012                                              aux_var)[2]
2013        return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2014
2015    # calls in order to free dyn. all. memory
2016    free_calls = []
2017
2018    _c('')
2019    if not self.c_var_followed_by_fixed_fields:
2020        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2021        _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2022        _c('    xcb_parts[3].iov_base = 0;')
2023        _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2024
2025        count = 4
2026
2027        for field in param_fields:
2028            if not field.type.fixed_size():
2029                _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2030                # default: simple cast to char *
2031                if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2032                    _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2033                    if field.type.is_list:
2034                        if field.type.member.fixed_size():
2035                            _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2036                               _c_accessor_get_expr(field.type.expr, None),
2037                               field.type.member.c_wiretype)
2038                        else:
2039                            list_length = _c_accessor_get_expr(field.type.expr, None)
2040
2041                            length = ''
2042                            _c("    xcb_parts[%d].iov_len = 0;" % count)
2043                            _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2044                            _c("    for(i=0; i<%s; i++) {" % list_length)
2045                            _c("        xcb_tmp_len = %s(xcb_tmp);" %
2046                                              (field.type.c_sizeof_name))
2047                            _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2048                            _c("        xcb_tmp += xcb_tmp_len;")
2049                            _c("    }")
2050                    else:
2051                        # not supposed to happen
2052                        raise Exception("unhandled variable size field %s" % field.c_field_name)
2053                else:
2054                    if not aux:
2055                        _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2056                    idx = serial_fields.index(field)
2057                    aux_var = '&xcb_aux%d' % idx
2058                    context = 'serialize' if aux else 'sizeof'
2059                    _c('    xcb_parts[%d].iov_len =', count)
2060                    if aux:
2061                        serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2062                        _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2063                        _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2064                        free_calls.append('    free(xcb_aux%d);' % idx)
2065                    else:
2066                        serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2067                        func_name = field.type.c_sizeof_name
2068                        _c('      %s (%s);', func_name, serialize_args)
2069
2070                count += 1
2071                if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2072                    # the _serialize() function keeps track of padding automatically
2073                    _c('    xcb_parts[%d].iov_base = 0;', count)
2074                    _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2075                    count += 1
2076
2077    # elif self.c_var_followed_by_fixed_fields:
2078    else:
2079        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2080        # request header: opcodes + length
2081        _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2082        count += 1
2083        # call _serialize()
2084        buffer_var = '&xcb_aux'
2085        serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2086        _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2087        _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2088        free_calls.append('    free(xcb_aux);')
2089        # no padding necessary - _serialize() keeps track of padding automatically
2090
2091    _c('')
2092    for field in param_fields:
2093        if field.isfd:
2094            _c('    xcb_send_fd(c, %s);', field.c_field_name)
2095
2096    _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2097
2098    # free dyn. all. data, if any
2099    for f in free_calls:
2100        _c(f)
2101    _c('    return xcb_ret;')
2102    _c('}')
2103
2104def _c_reply(self, name):
2105    '''
2106    Declares the function that returns the reply structure.
2107    '''
2108    spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2109    spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2110    spacing3 = ' ' * (len(self.c_reply_name) + 2)
2111
2112    # check if _unserialize() has to be called for any field
2113    def look_for_special_cases(complex_obj):
2114        unserialize_fields = []
2115        # no unserialize call in case of switch
2116        if not complex_obj.is_switch:
2117            for field in complex_obj.fields:
2118                # three cases: 1. field with special case
2119                #              2. container that contains special case field
2120                #              3. list with special case elements
2121                if field.type.c_var_followed_by_fixed_fields:
2122                    unserialize_fields.append(field)
2123                elif field.type.is_container:
2124                    unserialize_fields += look_for_special_cases(field.type)
2125                elif field.type.is_list:
2126                    if field.type.member.c_var_followed_by_fixed_fields:
2127                        unserialize_fields.append(field)
2128                    if field.type.member.is_container:
2129                        unserialize_fields += look_for_special_cases(field.type.member)
2130        return unserialize_fields
2131
2132    unserialize_fields = look_for_special_cases(self.reply)
2133
2134    _h('')
2135    _h('/**')
2136    _h(' * Return the reply')
2137    _h(' * @param c      The connection')
2138    _h(' * @param cookie The cookie')
2139    _h(' * @param e      The xcb_generic_error_t supplied')
2140    _h(' *')
2141    _h(' * Returns the reply of the request asked by')
2142    _h(' *')
2143    _h(' * The parameter @p e supplied to this function must be NULL if')
2144    _h(' * %s(). is used.', self.c_unchecked_name)
2145    _h(' * Otherwise, it stores the error if any.')
2146    _h(' *')
2147    _h(' * The returned value must be freed by the caller using free().')
2148    _h(' */')
2149    _c('')
2150    _hc('%s *', self.c_reply_type)
2151    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2152    _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2153    _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2154    _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2155    _c('{')
2156
2157    if len(unserialize_fields)>0:
2158        # certain variable size fields need to be unserialized explicitly
2159        _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2160           self.c_reply_type, self.c_reply_type)
2161        _c('    int i;')
2162        for field in unserialize_fields:
2163            if field.type.is_list:
2164                _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2165                _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2166                _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2167            else:
2168                raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2169        # call _unserialize(), using the reply as source and target buffer
2170        _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2171        for field in unserialize_fields:
2172            if field.type.is_list:
2173                _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2174                _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2175                _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2176                   field.c_field_name, field.c_field_name)
2177                _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2178                _c('    }')
2179        # return the transformed reply
2180        _c('    return reply;')
2181
2182    else:
2183        _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2184
2185    _c('}')
2186
2187def _c_reply_has_fds(self):
2188    for field in self.fields:
2189        if field.isfd:
2190            return True
2191    return False
2192
2193def _c_reply_fds(self, name):
2194    '''
2195    Declares the function that returns fds related to the reply.
2196    '''
2197    spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2198    spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2199    _h('')
2200    _h('/**')
2201    _h(' * Return the reply fds')
2202    _h(' * @param c      The connection')
2203    _h(' * @param reply  The reply')
2204    _h(' *')
2205    _h(' * Returns the array of reply fds of the request asked by')
2206    _h(' *')
2207    _h(' * The returned value must be freed by the caller using free().')
2208    _h(' */')
2209    _c('')
2210    _hc('int *')
2211    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2212    _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2213    _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2214    _c('{')
2215
2216    _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2217
2218    _c('}')
2219
2220
2221def _c_opcode(name, opcode):
2222    '''
2223    Declares the opcode define for requests, events, and errors.
2224    '''
2225    _h_setlevel(0)
2226    _h('')
2227    _h('/** Opcode for %s. */', _n(name))
2228    _h('#define %s %s', _n(name).upper(), opcode)
2229
2230def _c_cookie(self, name):
2231    '''
2232    Declares the cookie type for a non-void request.
2233    '''
2234    _h_setlevel(0)
2235    _h('')
2236    _h('/**')
2237    _h(' * @brief %s', self.c_cookie_type)
2238    _h(' **/')
2239    _h('typedef struct %s {', self.c_cookie_type)
2240    _h('    unsigned int sequence; /**<  */')
2241    _h('} %s;', self.c_cookie_type)
2242
2243def _man_request(self, name, cookie_type, void, aux):
2244    param_fields = [f for f in self.fields if f.visible]
2245
2246    func_name = self.c_request_name if not aux else self.c_aux_name
2247
2248    def create_link(linkname):
2249        name = 'man/%s.%s' % (linkname, section)
2250        if manpaths:
2251            sys.stdout.write(name)
2252        f = open(name, 'w')
2253        f.write('.so man%s/%s.%s' % (section, func_name, section))
2254        f.close()
2255
2256    if manpaths:
2257        sys.stdout.write('man/%s.%s ' % (func_name, section))
2258    # Our CWD is src/, so this will end up in src/man/
2259    f = open('man/%s.%s' % (func_name, section), 'w')
2260    f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2261    # Left-adjust instead of adjusting to both sides
2262    f.write('.ad l\n')
2263    f.write('.SH NAME\n')
2264    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2265    f.write('%s \\- %s\n' % (func_name, brief))
2266    f.write('.SH SYNOPSIS\n')
2267    # Don't split words (hyphenate)
2268    f.write('.hy 0\n')
2269    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2270
2271    # function prototypes
2272    prototype = ''
2273    count = len(param_fields)
2274    for field in param_fields:
2275        count = count - 1
2276        c_field_const_type = field.c_field_const_type
2277        c_pointer = field.c_pointer
2278        if c_pointer == ' ':
2279            c_pointer = ''
2280        if field.type.c_need_serialize and not aux:
2281            c_field_const_type = "const void"
2282            c_pointer = '*'
2283        comma = ', ' if count else ');'
2284        prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2285
2286    f.write('.SS Request function\n')
2287    f.write('.HP\n')
2288    base_func_name = self.c_request_name if not aux else self.c_aux_name
2289    f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2290    create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2291    if not void:
2292        f.write('.PP\n')
2293        f.write('.SS Reply datastructure\n')
2294        f.write('.nf\n')
2295        f.write('.sp\n')
2296        f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2297        struct_fields = []
2298        maxtypelen = 0
2299
2300        for field in self.reply.fields:
2301            if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2302                continue
2303            if field.wire:
2304                struct_fields.append(field)
2305
2306        for field in struct_fields:
2307            length = len(field.c_field_type)
2308            # account for '*' pointer_spec
2309            if not field.type.fixed_size():
2310                length += 1
2311            maxtypelen = max(maxtypelen, length)
2312
2313        def _c_complex_field(self, field, space=''):
2314            if (field.type.fixed_size() or
2315                # in case of switch with switch children, don't make the field a pointer
2316                # necessary for unserialize to work
2317                (self.is_switch and field.type.is_switch)):
2318                spacing = ' ' * (maxtypelen - len(field.c_field_type))
2319                f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2320            else:
2321                spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2322                f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2323                #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2324
2325        if not self.is_switch:
2326            for field in struct_fields:
2327                _c_complex_field(self, field)
2328        else:
2329            for b in self.bitcases:
2330                space = ''
2331                if b.type.has_name:
2332                    space = '    '
2333                for field in b.type.fields:
2334                    _c_complex_field(self, field, space)
2335                if b.type.has_name:
2336                    print >> sys.stderr, 'ERROR: New unhandled documentation case'
2337                    pass
2338
2339        f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2340        f.write('.fi\n')
2341
2342        f.write('.SS Reply function\n')
2343        f.write('.HP\n')
2344        f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2345                 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2346                (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2347        create_link('%s' % self.c_reply_name)
2348
2349        has_accessors = False
2350        for field in self.reply.fields:
2351            if field.type.is_list and not field.type.fixed_size():
2352                has_accessors = True
2353            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2354                has_accessors = True
2355
2356        if has_accessors:
2357            f.write('.SS Reply accessors\n')
2358
2359        def _c_accessors_field(self, field):
2360            '''
2361            Declares the accessor functions for a non-list field that follows a variable-length field.
2362            '''
2363            c_type = self.c_type
2364
2365            # special case: switch
2366            switch_obj = self if self.is_switch else None
2367            if self.is_bitcase:
2368                switch_obj = self.parents[-1]
2369            if switch_obj is not None:
2370                c_type = switch_obj.c_type
2371
2372            if field.type.is_simple:
2373                f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2374                create_link('%s' % field.c_accessor_name)
2375            else:
2376                f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2377                create_link('%s' % field.c_accessor_name)
2378
2379        def _c_accessors_list(self, field):
2380            '''
2381            Declares the accessor functions for a list field.
2382            Declares a direct-accessor function only if the list members are fixed size.
2383            Declares length and get-iterator functions always.
2384            '''
2385            list = field.type
2386            c_type = self.reply.c_type
2387
2388            # special case: switch
2389            # in case of switch, 2 params have to be supplied to certain accessor functions:
2390            #   1. the anchestor object (request or reply)
2391            #   2. the (anchestor) switch object
2392            # the reason is that switch is either a child of a request/reply or nested in another switch,
2393            # so whenever we need to access a length field, we might need to refer to some anchestor type
2394            switch_obj = self if self.is_switch else None
2395            if self.is_bitcase:
2396                switch_obj = self.parents[-1]
2397            if switch_obj is not None:
2398                c_type = switch_obj.c_type
2399
2400            params = []
2401            fields = {}
2402            parents = self.parents if hasattr(self, 'parents') else [self]
2403            # 'R': parents[0] is always the 'toplevel' container type
2404            params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2405            fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2406            # auxiliary object for 'R' parameters
2407            R_obj = parents[0]
2408
2409            if switch_obj is not None:
2410                # now look where the fields are defined that are needed to evaluate
2411                # the switch expr, and store the parent objects in accessor_params and
2412                # the fields in switch_fields
2413
2414                # 'S': name for the 'toplevel' switch
2415                toplevel_switch = parents[1]
2416                params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2417                fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2418
2419                # initialize prefix for everything "below" S
2420                prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2421                prefix = [(prefix_str, '->', toplevel_switch)]
2422
2423                # look for fields in the remaining containers
2424                for p in parents[2:] + [self]:
2425                    # the separator between parent and child is always '.' here,
2426                    # because of nested switch statements
2427                    if not p.is_bitcase or (p.is_bitcase and p.has_name):
2428                        prefix.append((p.name[-1], '.', p))
2429                    fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2430
2431                # auxiliary object for 'S' parameter
2432                S_obj = parents[1]
2433
2434            if list.member.fixed_size():
2435                idx = 1 if switch_obj is not None else 0
2436                f.write('.HP\n')
2437                f.write('%s *\\fB%s\\fP(%s);\n' %
2438                        (field.c_field_type, field.c_accessor_name, params[idx][0]))
2439                create_link('%s' % field.c_accessor_name)
2440
2441            f.write('.HP\n')
2442            f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2443                    (field.c_length_name, c_type))
2444            create_link('%s' % field.c_length_name)
2445
2446            if field.type.member.is_simple:
2447                f.write('.HP\n')
2448                f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2449                        (field.c_end_name, c_type))
2450                create_link('%s' % field.c_end_name)
2451            else:
2452                f.write('.HP\n')
2453                f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2454                        (field.c_iterator_type, field.c_iterator_name,
2455                         c_type))
2456                create_link('%s' % field.c_iterator_name)
2457
2458        for field in self.reply.fields:
2459            if field.type.is_list and not field.type.fixed_size():
2460                _c_accessors_list(self, field)
2461            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2462                _c_accessors_field(self, field)
2463
2464
2465    f.write('.br\n')
2466    # Re-enable hyphenation and adjusting to both sides
2467    f.write('.hy 1\n')
2468
2469    # argument reference
2470    f.write('.SH REQUEST ARGUMENTS\n')
2471    f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2472    f.write('The XCB connection to X11.\n')
2473    for field in param_fields:
2474        f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2475        printed_enum = False
2476        # XXX: hard-coded until we fix xproto.xml
2477        if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2478            field.enum = 'GC'
2479        elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2480            field.enum = 'CW'
2481        elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2482            field.enum = 'CW'
2483        if hasattr(field, "enum") and field.enum:
2484            # XXX: why the 'xcb' prefix?
2485            key = ('xcb', field.enum)
2486            if key in enums:
2487                f.write('One of the following values:\n')
2488                f.write('.RS 1i\n')
2489                enum = enums[key]
2490                count = len(enum.values)
2491                for (enam, eval) in enum.values:
2492                    count = count - 1
2493                    f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2494                    if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2495                        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2496                        f.write('%s\n' % desc)
2497                    else:
2498                        f.write('TODO: NOT YET DOCUMENTED.\n')
2499                f.write('.RE\n')
2500                f.write('.RS 1i\n')
2501                printed_enum = True
2502
2503        if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2504            desc = self.doc.fields[field.field_name]
2505            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2506            if printed_enum:
2507                f.write('\n')
2508            f.write('%s\n' % desc)
2509        else:
2510            f.write('TODO: NOT YET DOCUMENTED.\n')
2511        if printed_enum:
2512            f.write('.RE\n')
2513
2514    # Reply reference
2515    if not void:
2516        f.write('.SH REPLY FIELDS\n')
2517        # These fields are present in every reply:
2518        f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2519        f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2520                 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2521                 'be used to tell replies apart from each other.\n') %
2522                 _n(self.reply.name).upper())
2523        f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2524        f.write('The sequence number of the last request processed by the X11 server.\n')
2525        f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2526        f.write('The length of the reply, in words (a word is 4 bytes).\n')
2527        for field in self.reply.fields:
2528            if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2529                field.c_field_name.startswith('pad')):
2530                continue
2531
2532            if field.type.is_list and not field.type.fixed_size():
2533                continue
2534            elif field.prev_varsized_field is not None or not field.type.fixed_size():
2535                continue
2536            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2537            printed_enum = False
2538            if hasattr(field, "enum") and field.enum:
2539                # XXX: why the 'xcb' prefix?
2540                key = ('xcb', field.enum)
2541                if key in enums:
2542                    f.write('One of the following values:\n')
2543                    f.write('.RS 1i\n')
2544                    enum = enums[key]
2545                    count = len(enum.values)
2546                    for (enam, eval) in enum.values:
2547                        count = count - 1
2548                        f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2549                        if enum.doc and enam in enum.doc.fields:
2550                            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2551                            f.write('%s\n' % desc)
2552                        else:
2553                            f.write('TODO: NOT YET DOCUMENTED.\n')
2554                    f.write('.RE\n')
2555                    f.write('.RS 1i\n')
2556                    printed_enum = True
2557
2558            if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2559                desc = self.reply.doc.fields[field.field_name]
2560                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2561                if printed_enum:
2562                    f.write('\n')
2563                f.write('%s\n' % desc)
2564            else:
2565                f.write('TODO: NOT YET DOCUMENTED.\n')
2566            if printed_enum:
2567                f.write('.RE\n')
2568
2569
2570
2571    # text description
2572    f.write('.SH DESCRIPTION\n')
2573    if hasattr(self, "doc") and self.doc and self.doc.description:
2574        desc = self.doc.description
2575        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2576        lines = desc.split('\n')
2577        f.write('\n'.join(lines) + '\n')
2578
2579    f.write('.SH RETURN VALUE\n')
2580    if void:
2581        f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2582                 'have to be handled in the event loop.\n\nIf you want to '
2583                 'handle errors directly with \\fIxcb_request_check\\fP '
2584                 'instead, use \\fI%s_checked\\fP. See '
2585                 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2586    else:
2587        f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2588                 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2589                 'handle errors in the event loop instead, use '
2590                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2591                 'details.\n') %
2592                (cookie_type, self.c_reply_name, base_func_name, section))
2593    f.write('.SH ERRORS\n')
2594    if hasattr(self, "doc") and self.doc:
2595        for errtype, errtext in sorted(self.doc.errors.items()):
2596            f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2597            errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2598            f.write('%s\n' % (errtext))
2599    if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2600        f.write('This request does never generate any errors.\n')
2601    if hasattr(self, "doc") and self.doc and self.doc.example:
2602        f.write('.SH EXAMPLE\n')
2603        f.write('.nf\n')
2604        f.write('.sp\n')
2605        lines = self.doc.example.split('\n')
2606        f.write('\n'.join(lines) + '\n')
2607        f.write('.fi\n')
2608    f.write('.SH SEE ALSO\n')
2609    if hasattr(self, "doc") and self.doc:
2610        see = ['.BR %s (%s)' % ('xcb-requests', section)]
2611        if self.doc.example:
2612            see.append('.BR %s (%s)' % ('xcb-examples', section))
2613        for seename, seetype in sorted(self.doc.see.items()):
2614            if seetype == 'program':
2615                see.append('.BR %s (1)' % seename)
2616            elif seetype == 'event':
2617                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2618            elif seetype == 'request':
2619                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2620            elif seetype == 'function':
2621                see.append('.BR %s (%s)' % (seename, section))
2622            else:
2623                see.append('TODO: %s (type %s)' % (seename, seetype))
2624        f.write(',\n'.join(see) + '\n')
2625    f.write('.SH AUTHOR\n')
2626    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2627    f.close()
2628
2629def _man_event(self, name):
2630    if manpaths:
2631        sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2632    # Our CWD is src/, so this will end up in src/man/
2633    f = open('man/%s.%s' % (self.c_type, section), 'w')
2634    f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2635    # Left-adjust instead of adjusting to both sides
2636    f.write('.ad l\n')
2637    f.write('.SH NAME\n')
2638    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2639    f.write('%s \\- %s\n' % (self.c_type, brief))
2640    f.write('.SH SYNOPSIS\n')
2641    # Don't split words (hyphenate)
2642    f.write('.hy 0\n')
2643    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2644
2645    f.write('.PP\n')
2646    f.write('.SS Event datastructure\n')
2647    f.write('.nf\n')
2648    f.write('.sp\n')
2649    f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2650    struct_fields = []
2651    maxtypelen = 0
2652
2653    for field in self.fields:
2654        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2655            continue
2656        if field.wire:
2657            struct_fields.append(field)
2658
2659    for field in struct_fields:
2660        length = len(field.c_field_type)
2661        # account for '*' pointer_spec
2662        if not field.type.fixed_size():
2663            length += 1
2664        maxtypelen = max(maxtypelen, length)
2665
2666    def _c_complex_field(self, field, space=''):
2667        if (field.type.fixed_size() or
2668            # in case of switch with switch children, don't make the field a pointer
2669            # necessary for unserialize to work
2670            (self.is_switch and field.type.is_switch)):
2671            spacing = ' ' * (maxtypelen - len(field.c_field_type))
2672            f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2673        else:
2674            print >> sys.stderr, 'ERROR: New unhandled documentation case'
2675
2676    if not self.is_switch:
2677        for field in struct_fields:
2678            _c_complex_field(self, field)
2679    else:
2680        for b in self.bitcases:
2681            space = ''
2682            if b.type.has_name:
2683                space = '    '
2684            for field in b.type.fields:
2685                _c_complex_field(self, field, space)
2686            if b.type.has_name:
2687                print >> sys.stderr, 'ERROR: New unhandled documentation case'
2688                pass
2689
2690    f.write('} \\fB%s\\fP;\n' % self.c_type)
2691    f.write('.fi\n')
2692
2693
2694    f.write('.br\n')
2695    # Re-enable hyphenation and adjusting to both sides
2696    f.write('.hy 1\n')
2697
2698    # argument reference
2699    f.write('.SH EVENT FIELDS\n')
2700    f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2701    f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2702             'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2703             'to tell events apart from each other.\n') % _n(name).upper())
2704    f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2705    f.write('The sequence number of the last request processed by the X11 server.\n')
2706
2707    if not self.is_switch:
2708        for field in struct_fields:
2709            # Skip the fields which every event has, we already documented
2710            # them (see above).
2711            if field.c_field_name in ('response_type', 'sequence'):
2712                continue
2713            if isinstance(field.type, PadType):
2714                continue
2715            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2716            if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2717                desc = self.doc.fields[field.field_name]
2718                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2719                f.write('%s\n' % desc)
2720            else:
2721                f.write('NOT YET DOCUMENTED.\n')
2722
2723    # text description
2724    f.write('.SH DESCRIPTION\n')
2725    if hasattr(self, "doc") and self.doc and self.doc.description:
2726        desc = self.doc.description
2727        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2728        lines = desc.split('\n')
2729        f.write('\n'.join(lines) + '\n')
2730
2731    if hasattr(self, "doc") and self.doc and self.doc.example:
2732        f.write('.SH EXAMPLE\n')
2733        f.write('.nf\n')
2734        f.write('.sp\n')
2735        lines = self.doc.example.split('\n')
2736        f.write('\n'.join(lines) + '\n')
2737        f.write('.fi\n')
2738    f.write('.SH SEE ALSO\n')
2739    if hasattr(self, "doc") and self.doc:
2740        see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2741        if self.doc.example:
2742            see.append('.BR %s (%s)' % ('xcb-examples', section))
2743        for seename, seetype in sorted(self.doc.see.items()):
2744            if seetype == 'program':
2745                see.append('.BR %s (1)' % seename)
2746            elif seetype == 'event':
2747                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2748            elif seetype == 'request':
2749                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2750            elif seetype == 'function':
2751                see.append('.BR %s (%s)' % (seename, section))
2752            else:
2753                see.append('TODO: %s (type %s)' % (seename, seetype))
2754        f.write(',\n'.join(see) + '\n')
2755    f.write('.SH AUTHOR\n')
2756    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2757    f.close()
2758
2759
2760def c_request(self, name):
2761    '''
2762    Exported function that handles request declarations.
2763    '''
2764    _c_type_setup(self, name, ('request',))
2765
2766    if self.reply:
2767        # Cookie type declaration
2768        _c_cookie(self, name)
2769
2770    # Opcode define
2771    _c_opcode(name, self.opcode)
2772
2773    # Request structure declaration
2774    _c_complex(self)
2775
2776    if self.reply:
2777        _c_type_setup(self.reply, name, ('reply',))
2778        # Reply structure definition
2779        _c_complex(self.reply)
2780        # Request prototypes
2781        has_fds = _c_reply_has_fds(self.reply)
2782        _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2783        _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2784        if self.c_need_aux:
2785            _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2786            _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2787        # Reply accessors
2788        _c_accessors(self.reply, name + ('reply',), name)
2789        _c_reply(self, name)
2790        if has_fds:
2791            _c_reply_fds(self, name)
2792    else:
2793        # Request prototypes
2794        _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2795        _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2796        if self.c_need_aux:
2797            _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2798            _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2799
2800    # We generate the manpage afterwards because _c_type_setup has been called.
2801    # TODO: what about aux helpers?
2802    cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2803    _man_request(self, name, cookie_type, not self.reply, False)
2804
2805def c_event(self, name):
2806    '''
2807    Exported function that handles event declarations.
2808    '''
2809
2810    # The generic event structure xcb_ge_event_t has the full_sequence field
2811    # at the 32byte boundary. That's why we've to inject this field into GE
2812    # events while generating the structure for them. Otherwise we would read
2813    # garbage (the internal full_sequence) when accessing normal event fields
2814    # there.
2815    force_packed = False
2816    if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2817        event_size = 0
2818        for field in self.fields:
2819            if field.type.size != None and field.type.nmemb != None:
2820                event_size += field.type.size * field.type.nmemb
2821            if event_size == 32:
2822                full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2823                idx = self.fields.index(field)
2824                self.fields.insert(idx + 1, full_sequence)
2825
2826                # If the event contains any 64-bit extended fields, they need
2827                # to remain aligned on a 64-bit boundary.  Adding full_sequence
2828                # would normally break that; force the struct to be packed.
2829                force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
2830                break
2831
2832    _c_type_setup(self, name, ('event',))
2833
2834    # Opcode define
2835    _c_opcode(name, self.opcodes[name])
2836
2837    if self.name == name:
2838        # Structure definition
2839        _c_complex(self, force_packed)
2840    else:
2841        # Typedef
2842        _h('')
2843        _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2844
2845    _man_event(self, name)
2846
2847def c_error(self, name):
2848    '''
2849    Exported function that handles error declarations.
2850    '''
2851    _c_type_setup(self, name, ('error',))
2852
2853    # Opcode define
2854    _c_opcode(name, self.opcodes[name])
2855
2856    if self.name == name:
2857        # Structure definition
2858        _c_complex(self)
2859    else:
2860        # Typedef
2861        _h('')
2862        _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2863
2864
2865# Main routine starts here
2866
2867# Must create an "output" dictionary before any xcbgen imports.
2868output = {'open'    : c_open,
2869          'close'   : c_close,
2870          'simple'  : c_simple,
2871          'enum'    : c_enum,
2872          'struct'  : c_struct,
2873          'union'   : c_union,
2874          'request' : c_request,
2875          'event'   : c_event,
2876          'error'   : c_error,
2877          }
2878
2879# Boilerplate below this point
2880
2881# Check for the argument that specifies path to the xcbgen python package.
2882try:
2883    opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
2884except getopt.GetoptError as err:
2885    print(err)
2886    print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
2887    sys.exit(1)
2888
2889for (opt, arg) in opts:
2890    if opt == '-c':
2891        center_footer=arg
2892    if opt == '-l':
2893        left_footer=arg
2894    if opt == '-s':
2895        section=arg
2896    if opt == '-p':
2897        sys.path.insert(1, arg)
2898    elif opt == '-m':
2899        manpaths = True
2900        sys.stdout.write('man_MANS = ')
2901
2902# Import the module class
2903try:
2904    from xcbgen.state import Module
2905    from xcbgen.xtypes import *
2906except ImportError:
2907    print('''
2908Failed to load the xcbgen Python package!
2909Make sure that xcb/proto installed it on your Python path.
2910If not, you will need to create a .pth file or define $PYTHONPATH
2911to extend the path.
2912Refer to the README file in xcb/proto for more info.
2913''')
2914    raise
2915
2916# Ensure the man subdirectory exists
2917try:
2918    os.mkdir('man')
2919except OSError as e:
2920    if e.errno != errno.EEXIST:
2921        raise
2922
2923# Parse the xml header
2924module = Module(args[0], output)
2925
2926# Build type-registry and resolve type dependencies
2927module.register()
2928module.resolve()
2929
2930# Output the code
2931module.generate()
2932