Home | History | Annotate | Line # | Download | only in src
      1 #!/usr/bin/env python
      2 from __future__ import print_function
      3 import getopt
      4 import os
      5 import sys
      6 import errno
      7 import re
      8 
      9 # Jump to the bottom of this file for the main routine
     10 
     11 #config settings (can be changed with commandline options)
     12 config_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
     33 finished_serializers = []
     34 finished_sizeof = []
     35 finished_switch = []
     36 
     37 # keeps enum objects so that we can refer to them when generating manpages.
     38 enums = {}
     39 
     40 manpaths = False
     41 
     42 def _h(fmt, *args):
     43     '''
     44     Writes the given line to the header file.
     45     '''
     46     _hlines[_hlevel].append(fmt % args)
     47 
     48 def _c(fmt, *args):
     49     '''
     50     Writes the given line to the source file.
     51     '''
     52     _clines[_clevel].append(fmt % args)
     53 
     54 def _hc(fmt, *args):
     55     '''
     56     Writes the given line to both the header and source files.
     57     '''
     58     _h(fmt, *args)
     59     _c(fmt, *args)
     60 
     61 def _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 
     70 class 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.
    163 def _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 
    173 def _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 
    183 def _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 
    195 def _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 
    206 def _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 
    216 def _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 
    232 def _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 
    248 def 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 
    312 def 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 
    349 def 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 
    357 def 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 
    385 def _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
    539 def _c_field_needs_list_accessor(field):
    540     return field.type.is_list and not field.type.fixed_size()
    541 
    542 def _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 
    549 def _c_field_needs_accessor(field):
    550     return (_c_field_needs_list_accessor(field) or
    551             _c_field_needs_field_accessor(field))
    552 
    553 def _c_field_is_member_of_case_or_bitcase(field):
    554     return field.parent and field.parent.is_case_or_bitcase
    555 
    556 def _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 
    598 def _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 
    633 def _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 
    653 def 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 
    684 def 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 
    705 def 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 
    727 def 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 
    754 def 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 
    834 def _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 
    865 def _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 
    917 def _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 
    959 def _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 
    970 def _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 
   1000 def _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 
   1057 def _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 
   1126 def _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 
   1178 def _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 
   1283 def _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 
   1322 def _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 
   1541 def _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 
   1557 def _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 
   1658 def _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 
   1676 def _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 
   1768 def type_pad_type(type):
   1769     if type == 'void':
   1770         return 'char'
   1771     return type
   1772 
   1773 def _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 
   1822 def _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 
   2069 def _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 
   2086 def 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 
   2103 def _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 
   2157 def 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 
   2166 def 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 
   2174 def _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 
   2517 def _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 
   2600 def _c_reply_has_fds(self):
   2601     return any(field.isfd for field in self.fields)
   2602 
   2603 def _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 
   2632 def _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 
   2641 def _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 
   2654 def _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 (at] lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
   3032     f.close()
   3033 
   3034 def _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 (at] lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
   3162     f.close()
   3163 
   3164 
   3165 def 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 
   3215 def 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 
   3236 def 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 
   3305 def 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.
   3326 output = {'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.
   3341 try:
   3342     opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m', ["server-side"])
   3343 except 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 
   3348 for (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
   3364 try:
   3365     from xcbgen.state import Module
   3366     from xcbgen.xtypes import *
   3367 except ImportError:
   3368     print('''
   3369 Failed to load the xcbgen Python package!
   3370 Make sure that xcb/proto installed it on your Python path.
   3371 If not, you will need to create a .pth file or define $PYTHONPATH
   3372 to extend the path.
   3373 Refer to the README file in xcb/proto for more info.
   3374 ''')
   3375     raise
   3376 
   3377 # predefined datatype globals.
   3378 tevent = SimpleType(('xcb_raw_generic_event_t',), 32)
   3379 
   3380 # Ensure the man subdirectory exists
   3381 try:
   3382     os.mkdir('man')
   3383 except OSError as e:
   3384     if e.errno != errno.EEXIST:
   3385         raise
   3386 
   3387 # Parse the xml header
   3388 module = Module(args[0], output)
   3389 
   3390 # Build type-registry and resolve type dependencies
   3391 module.register()
   3392 module.resolve()
   3393 
   3394 # Output the code
   3395 module.generate()
   3396