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