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