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