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