Blame src/c_client.py

Packit 071ada
#!/usr/bin/env python
Packit 071ada
from __future__ import print_function
Packit 071ada
import getopt
Packit 071ada
import os
Packit 071ada
import sys
Packit 071ada
import errno
Packit 071ada
import re
Packit 071ada
Packit 071ada
# Jump to the bottom of this file for the main routine
Packit 071ada
Packit 071ada
#config settings (can be changed with commandline options)
Packit 071ada
config_server_side = False
Packit 071ada
Packit 071ada
# Some hacks to make the API more readable, and to keep backwards compability
Packit 071ada
_cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
Packit 071ada
_cname_special_cases = {'DECnet':'decnet'}
Packit 071ada
Packit 071ada
_extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
Packit 071ada
Packit 071ada
_cplusplus_annoyances = {'class' : '_class',
Packit 071ada
                         'new'   : '_new',
Packit 071ada
                         'delete': '_delete'}
Packit 071ada
_c_keywords = {'default' : '_default'}
Packit 071ada
Packit 071ada
_hlines = []
Packit 071ada
_hlevel = 0
Packit 071ada
_clines = []
Packit 071ada
_clevel = 0
Packit 071ada
_ns = None
Packit 071ada
Packit 071ada
# global variable to keep track of serializers and
Packit 071ada
# switch data types due to weird dependencies
Packit 071ada
finished_serializers = []
Packit 071ada
finished_sizeof = []
Packit 071ada
finished_switch = []
Packit 071ada
Packit 071ada
# keeps enum objects so that we can refer to them when generating manpages.
Packit 071ada
enums = {}
Packit 071ada
Packit 071ada
manpaths = False
Packit 071ada
Packit 071ada
def _h(fmt, *args):
Packit 071ada
    '''
Packit 071ada
    Writes the given line to the header file.
Packit 071ada
    '''
Packit 071ada
    _hlines[_hlevel].append(fmt % args)
Packit 071ada
Packit 071ada
def _c(fmt, *args):
Packit 071ada
    '''
Packit 071ada
    Writes the given line to the source file.
Packit 071ada
    '''
Packit 071ada
    _clines[_clevel].append(fmt % args)
Packit 071ada
Packit 071ada
def _hc(fmt, *args):
Packit 071ada
    '''
Packit 071ada
    Writes the given line to both the header and source files.
Packit 071ada
    '''
Packit 071ada
    _h(fmt, *args)
Packit 071ada
    _c(fmt, *args)
Packit 071ada
Packit 071ada
def _c_wr_stringlist(indent, strlist):
Packit 071ada
    '''
Packit 071ada
    Writes the given list of strings to the source file.
Packit 071ada
    Each line is prepended by the indent string
Packit 071ada
    '''
Packit 071ada
    for str in strlist:
Packit 071ada
        _c("%s%s", indent, str)
Packit 071ada
Packit 071ada
Packit 071ada
class PreCode(object):
Packit 071ada
    '''
Packit 071ada
    For pre-code generated by expression generation
Packit 071ada
    (for example, the for-loop of a sumof)
Packit 071ada
    This has to account for recursiveness of the expression
Packit 071ada
    generation, i.e., there may be pre-code for pre-code.
Packit 071ada
    Therefore this is implemented as a stack of lists of lines.
Packit 071ada
Packit 071ada
    If redirection is switched on, then all output is collected in
Packit 071ada
    self.redirect_code and self.redirect_tempvars instead of
Packit 071ada
    being sent to the output via _h und _c.
Packit 071ada
    '''
Packit 071ada
    def __init__(self):
Packit 071ada
        self.nesting_level = 0
Packit 071ada
        self.tempvars = []
Packit 071ada
        self.codelines = []
Packit 071ada
        self.redirect_code = None
Packit 071ada
        self.redirect_tempvars = None
Packit 071ada
        self.indent_str = '    '
Packit 071ada
        self.indent_stack = []
Packit 071ada
        self.tempvar_num = 0
Packit 071ada
Packit 071ada
Packit 071ada
    # start and end of pre-code blocks
Packit 071ada
    def start(self):
Packit 071ada
        self.nesting_level += 1
Packit 071ada
Packit 071ada
    def end(self):
Packit 071ada
        self.nesting_level -= 1
Packit 071ada
        if self.nesting_level == 0:
Packit 071ada
            # lowest pre-code level is finished -> output to source
Packit 071ada
            if self.redirect_tempvars is None:
Packit 071ada
                _c_wr_stringlist('', self.tempvars)
Packit 071ada
                self.tempvars = []
Packit 071ada
            else:
Packit 071ada
                self.redirect_tempvars.extend(self.tempvars)
Packit 071ada
                self.tempvars = []
Packit 071ada
            if self.redirect_code == None:
Packit 071ada
                _c_wr_stringlist('', self.codelines)
Packit 071ada
                self.codelines = []
Packit 071ada
            else:
Packit 071ada
                self.redirect_code.extend(self.codelines)
Packit 071ada
                self.codelines = []
Packit 071ada
Packit 071ada
Packit 071ada
    def output_tempvars(self):
Packit 071ada
        if self.redirect_code == None:
Packit 071ada
            _c_wr_stringlist('', self.tempvars)
Packit 071ada
            self.tempvars = []
Packit 071ada
Packit 071ada
    # output to precode
Packit 071ada
    def code(self, fmt, *args):
Packit 071ada
        self.codelines.append(self.indent_str + fmt % args)
Packit 071ada
Packit 071ada
    def tempvar(self, fmt, *args):
Packit 071ada
        self.tempvars.append('    ' + (fmt % args))
Packit 071ada
Packit 071ada
    # get a unique name for a temporary variable
Packit 071ada
    def get_tempvarname(self):
Packit 071ada
        self.tempvar_num += 1
Packit 071ada
        return "xcb_pre_tmp_%d" % self.tempvar_num
Packit 071ada
Packit 071ada
    # indentation
Packit 071ada
Packit 071ada
    def push_indent(self, indentstr):
Packit 071ada
        self.indent_stack.append(self.indent_str)
Packit 071ada
        self.indent_str = indentstr
Packit 071ada
Packit 071ada
    def push_addindent(self, indent_add_str):
Packit 071ada
        self.push_indent(self.indent_str + indent_add_str)
Packit 071ada
Packit 071ada
    def indent(self):
Packit 071ada
        self.push_addindent('    ')
Packit 071ada
Packit 071ada
    def pop_indent(self):
Packit 071ada
        self.indent_str = self.indent_stack.pop()
Packit 071ada
Packit 071ada
    # redirection to lists
Packit 071ada
    def redirect_start(self, redirect_code, redirect_tempvars=None):
Packit 071ada
        self.redirect_code = redirect_code
Packit 071ada
        self.redirect_tempvars = redirect_tempvars
Packit 071ada
        if redirect_tempvars is not None:
Packit 071ada
            self.tempvar_num = 0
Packit 071ada
Packit 071ada
    def redirect_end(self):
Packit 071ada
        self.redirect_code = None
Packit 071ada
        self.redirect_tempvars = None
Packit 071ada
Packit 071ada
# global PreCode handler
Packit 071ada
_c_pre = PreCode()
Packit 071ada
Packit 071ada
Packit 071ada
# XXX See if this level thing is really necessary.
Packit 071ada
def _h_setlevel(idx):
Packit 071ada
    '''
Packit 071ada
    Changes the array that header lines are written to.
Packit 071ada
    Supports writing different sections of the header file.
Packit 071ada
    '''
Packit 071ada
    global _hlevel
Packit 071ada
    while len(_hlines) <= idx:
Packit 071ada
        _hlines.append([])
Packit 071ada
    _hlevel = idx
Packit 071ada
Packit 071ada
def _c_setlevel(idx):
Packit 071ada
    '''
Packit 071ada
    Changes the array that source lines are written to.
Packit 071ada
    Supports writing to different sections of the source file.
Packit 071ada
    '''
Packit 071ada
    global _clevel
Packit 071ada
    while len(_clines) <= idx:
Packit 071ada
        _clines.append([])
Packit 071ada
    _clevel = idx
Packit 071ada
Packit 071ada
def _n_item(str):
Packit 071ada
    '''
Packit 071ada
    Does C-name conversion on a single string fragment.
Packit 071ada
    Uses a regexp with some hard-coded special cases.
Packit 071ada
    '''
Packit 071ada
    if str in _cname_special_cases:
Packit 071ada
        return _cname_special_cases[str]
Packit 071ada
    else:
Packit 071ada
        split = _cname_re.finditer(str)
Packit 071ada
        name_parts = [match.group(0) for match in split]
Packit 071ada
        return '_'.join(name_parts)
Packit 071ada
Packit 071ada
def _cpp(str):
Packit 071ada
    '''
Packit 071ada
    Checks for certain C++ reserved words and fixes them.
Packit 071ada
    '''
Packit 071ada
    if str in _cplusplus_annoyances:
Packit 071ada
        return _cplusplus_annoyances[str]
Packit 071ada
    elif str in _c_keywords:
Packit 071ada
        return  _c_keywords[str]
Packit 071ada
    else:
Packit 071ada
        return str
Packit 071ada
Packit 071ada
def _ext(str):
Packit 071ada
    '''
Packit 071ada
    Does C-name conversion on an extension name.
Packit 071ada
    Has some additional special cases on top of _n_item.
Packit 071ada
    '''
Packit 071ada
    if str in _extension_special_cases:
Packit 071ada
        return _n_item(str).lower()
Packit 071ada
    else:
Packit 071ada
        return str.lower()
Packit 071ada
Packit 071ada
def _n(list):
Packit 071ada
    '''
Packit 071ada
    Does C-name conversion on a tuple of strings.
Packit 071ada
    Different behavior depending on length of tuple, extension/not extension, etc.
Packit 071ada
    Basically C-name converts the individual pieces, then joins with underscores.
Packit 071ada
    '''
Packit 071ada
    if len(list) == 1:
Packit 071ada
        parts = list
Packit 071ada
    elif len(list) == 2:
Packit 071ada
        parts = [list[0], _n_item(list[1])]
Packit 071ada
    elif _ns.is_ext:
Packit 071ada
        parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
Packit 071ada
    else:
Packit 071ada
        parts = [list[0]] + [_n_item(i) for i in list[1:]]
Packit 071ada
    return '_'.join(parts).lower()
Packit 071ada
Packit 071ada
def _t(list):
Packit 071ada
    '''
Packit 071ada
    Does C-name conversion on a tuple of strings representing a type.
Packit 071ada
    Same as _n but adds a "_t" on the end.
Packit 071ada
    '''
Packit 071ada
    if len(list) == 1:
Packit 071ada
        parts = list
Packit 071ada
    elif len(list) == 2:
Packit 071ada
        parts = [list[0], _n_item(list[1]), 't']
Packit 071ada
    elif _ns.is_ext:
Packit 071ada
        parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
Packit 071ada
    else:
Packit 071ada
        parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
Packit 071ada
    return '_'.join(parts).lower()
Packit 071ada
Packit 071ada
Packit 071ada
def c_open(self):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles module open.
Packit 071ada
    Opens the files and writes out the auto-generated comment, header file includes, etc.
Packit 071ada
    '''
Packit 071ada
    global _ns
Packit 071ada
    _ns = self.namespace
Packit 071ada
    _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
Packit 071ada
Packit 071ada
    # Build the type-name collision avoidance table used by c_enum
Packit 071ada
    build_collision_table()
Packit 071ada
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _c_setlevel(0)
Packit 071ada
Packit 071ada
    _hc('/*')
Packit 071ada
    _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
Packit 071ada
    _hc(' * Edit at your peril.')
Packit 071ada
    _hc(' */')
Packit 071ada
    _hc('')
Packit 071ada
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
Packit 071ada
    _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
Packit 071ada
    _h(' * @{')
Packit 071ada
    _h(' **/')
Packit 071ada
    _h('')
Packit 071ada
    _h('#ifndef __%s_H', _ns.header.upper())
Packit 071ada
    _h('#define __%s_H', _ns.header.upper())
Packit 071ada
    _h('')
Packit 071ada
    _h('#include "xcb.h"')
Packit 071ada
Packit 071ada
    _c('#ifdef HAVE_CONFIG_H')
Packit 071ada
    _c('#include "config.h"')
Packit 071ada
    _c('#endif')
Packit 071ada
    _c('#include <stdlib.h>')
Packit 071ada
    _c('#include <string.h>')
Packit 071ada
    _c('#include <assert.h>')
Packit 071ada
    _c('#include <stddef.h>  /* for offsetof() */')
Packit 071ada
    _c('#include "xcbext.h"')
Packit 071ada
    _c('#include "%s.h"', _ns.header)
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
    _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
Packit 071ada
Packit 071ada
    if _ns.is_ext:
Packit 071ada
        for (n, h) in self.direct_imports:
Packit 071ada
            _hc('#include "%s.h"', h)
Packit 071ada
Packit 071ada
    _h('')
Packit 071ada
    _h('#ifdef __cplusplus')
Packit 071ada
    _h('extern "C" {')
Packit 071ada
    _h('#endif')
Packit 071ada
Packit 071ada
    if _ns.is_ext:
Packit 071ada
        _h('')
Packit 071ada
        _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
Packit 071ada
        _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
Packit 071ada
        _h('') #XXX
Packit 071ada
        _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
Packit 071ada
Packit 071ada
        _c('')
Packit 071ada
        _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
Packit 071ada
Packit 071ada
def c_close(self):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles module close.
Packit 071ada
    Writes out all the stored content lines, then closes the files.
Packit 071ada
    '''
Packit 071ada
    _h_setlevel(2)
Packit 071ada
    _c_setlevel(2)
Packit 071ada
    _hc('')
Packit 071ada
Packit 071ada
    _h('')
Packit 071ada
    _h('#ifdef __cplusplus')
Packit 071ada
    _h('}')
Packit 071ada
    _h('#endif')
Packit 071ada
Packit 071ada
    _h('')
Packit 071ada
    _h('#endif')
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * @}')
Packit 071ada
    _h(' */')
Packit 071ada
Packit 071ada
    # Write header file
Packit 071ada
    hfile = open('%s.h' % _ns.header, 'w')
Packit 071ada
    for list in _hlines:
Packit 071ada
        for line in list:
Packit 071ada
            hfile.write(line)
Packit 071ada
            hfile.write('\n')
Packit 071ada
    hfile.close()
Packit 071ada
Packit 071ada
    # Write source file
Packit 071ada
    cfile = open('%s.c' % _ns.header, 'w')
Packit 071ada
    for list in _clines:
Packit 071ada
        for line in list:
Packit 071ada
            cfile.write(line)
Packit 071ada
            cfile.write('\n')
Packit 071ada
    cfile.close()
Packit 071ada
Packit 071ada
def build_collision_table():
Packit 071ada
    global namecount
Packit 071ada
    namecount = {}
Packit 071ada
Packit 071ada
    for v in module.types.values():
Packit 071ada
        name = _t(v[0])
Packit 071ada
        namecount[name] = (namecount.get(name) or 0) + 1
Packit 071ada
Packit 071ada
def c_enum(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles enum declarations.
Packit 071ada
    '''
Packit 071ada
Packit 071ada
    enums[name] = self
Packit 071ada
Packit 071ada
    tname = _t(name)
Packit 071ada
    if namecount[tname] > 1:
Packit 071ada
        tname = _t(name + ('enum',))
Packit 071ada
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _h('')
Packit 071ada
    _h('typedef enum %s {', tname)
Packit 071ada
Packit 071ada
    count = len(self.values)
Packit 071ada
Packit 071ada
    for (enam, eval) in self.values:
Packit 071ada
        count = count - 1
Packit 071ada
        equals = ' = ' if eval != '' else ''
Packit 071ada
        comma = ',' if count > 0 else ''
Packit 071ada
        doc = ''
Packit 071ada
        if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
Packit 071ada
            doc = '\n/**< %s */\n' % self.doc.fields[enam]
Packit 071ada
        _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
Packit 071ada
Packit 071ada
    _h('} %s;', tname)
Packit 071ada
Packit 071ada
def _c_type_setup(self, name, postfix):
Packit 071ada
    '''
Packit 071ada
    Sets up all the C-related state by adding additional data fields to
Packit 071ada
    all Field and Type objects.  Here is where we figure out most of our
Packit 071ada
    variable and function names.
Packit 071ada
Packit 071ada
    Recurses into child fields and list member types.
Packit 071ada
    '''
Packit 071ada
    # Do all the various names in advance
Packit 071ada
    self.c_type = _t(name + postfix)
Packit 071ada
    self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
Packit 071ada
Packit 071ada
    self.c_iterator_type = _t(name + ('iterator',))
Packit 071ada
    self.c_next_name = _n(name + ('next',))
Packit 071ada
    self.c_end_name = _n(name + ('end',))
Packit 071ada
Packit 071ada
    self.c_request_name = _n(name)
Packit 071ada
    self.c_checked_name = _n(name + ('checked',))
Packit 071ada
    self.c_unchecked_name = _n(name + ('unchecked',))
Packit 071ada
    self.c_reply_name = _n(name + ('reply',))
Packit 071ada
    self.c_reply_type = _t(name + ('reply',))
Packit 071ada
    self.c_cookie_type = _t(name + ('cookie',))
Packit 071ada
    self.c_reply_fds_name = _n(name + ('reply_fds',))
Packit 071ada
Packit 071ada
    self.c_need_aux = False
Packit 071ada
    self.c_need_serialize = False
Packit 071ada
    self.c_need_sizeof = False
Packit 071ada
Packit 071ada
    self.c_aux_name = _n(name + ('aux',))
Packit 071ada
    self.c_aux_checked_name = _n(name + ('aux', 'checked'))
Packit 071ada
    self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
Packit 071ada
    self.c_serialize_name = _n(name + ('serialize',))
Packit 071ada
    self.c_unserialize_name = _n(name + ('unserialize',))
Packit 071ada
    self.c_unpack_name = _n(name + ('unpack',))
Packit 071ada
    self.c_sizeof_name = _n(name + ('sizeof',))
Packit 071ada
Packit 071ada
    # special case: structs where variable size fields are followed by fixed size fields
Packit 071ada
    self.c_var_followed_by_fixed_fields = False
Packit 071ada
Packit 071ada
    if self.is_switch:
Packit 071ada
        self.c_need_serialize = True
Packit 071ada
        self.c_container = 'struct'
Packit 071ada
        for bitcase in self.bitcases:
Packit 071ada
            bitcase.c_field_name = _cpp(bitcase.field_name)
Packit 071ada
            bitcase_name = bitcase.field_type if bitcase.type.has_name else name
Packit 071ada
            _c_type_setup(bitcase.type, bitcase_name, ())
Packit 071ada
Packit 071ada
    elif self.is_container:
Packit 071ada
Packit 071ada
        self.c_container = 'union' if self.is_union else 'struct'
Packit 071ada
        prev_varsized_field = None
Packit 071ada
        prev_varsized_offset = 0
Packit 071ada
        first_field_after_varsized = None
Packit 071ada
Packit 071ada
        for field in self.fields:
Packit 071ada
            if field.type.is_event:
Packit 071ada
                field.c_field_type = _t(field.field_type + ('event',))
Packit 071ada
            else:
Packit 071ada
                field.c_field_type = _t(field.field_type)
Packit 071ada
Packit 071ada
            field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
Packit 071ada
            field.c_field_name = _cpp(field.field_name)
Packit 071ada
            field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
Packit 071ada
            field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
Packit 071ada
Packit 071ada
            # correct the c_pointer field for variable size non-list types
Packit 071ada
            if not field.type.fixed_size() and field.c_pointer == ' ':
Packit 071ada
                field.c_pointer = '*'
Packit 071ada
            if field.type.is_list and not field.type.member.fixed_size():
Packit 071ada
                field.c_pointer = '*'
Packit 071ada
Packit 071ada
            if field.type.is_switch:
Packit 071ada
                field.c_pointer = '*'
Packit 071ada
                field.c_field_const_type = 'const ' + field.c_field_type
Packit 071ada
                self.c_need_aux = True
Packit 071ada
Packit 071ada
            if not field.type.fixed_size() and not field.type.is_case_or_bitcase and field.wire:
Packit 071ada
                self.c_need_sizeof = True
Packit 071ada
Packit 071ada
            field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
Packit 071ada
            field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
Packit 071ada
            field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
Packit 071ada
            field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
Packit 071ada
            field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
Packit 071ada
Packit 071ada
            field.prev_varsized_field = prev_varsized_field
Packit 071ada
            field.prev_varsized_offset = prev_varsized_offset
Packit 071ada
Packit 071ada
            if prev_varsized_offset == 0:
Packit 071ada
                first_field_after_varsized = field
Packit 071ada
            field.first_field_after_varsized = first_field_after_varsized
Packit 071ada
Packit 071ada
            if field.type.fixed_size():
Packit 071ada
                if field.wire:
Packit 071ada
                    prev_varsized_offset += field.type.size
Packit 071ada
                # special case: intermixed fixed and variable size fields
Packit 071ada
                if prev_varsized_field is not None and not field.type.is_pad and field.wire:
Packit 071ada
                    if not self.is_union:
Packit 071ada
                        self.c_need_serialize = True
Packit 071ada
                        self.c_var_followed_by_fixed_fields = True
Packit 071ada
            else:
Packit 071ada
                self.last_varsized_field = field
Packit 071ada
                prev_varsized_field = field
Packit 071ada
                prev_varsized_offset = 0
Packit 071ada
Packit 071ada
            if self.c_var_followed_by_fixed_fields:
Packit 071ada
                if field.type.fixed_size():
Packit 071ada
                    field.prev_varsized_field = None
Packit 071ada
Packit 071ada
            # recurse into this field this has to be done here, i.e.,
Packit 071ada
            # after the field has been set up. Otherwise the function
Packit 071ada
            # _c_helper_fieldaccess_expr will produce garbage or crash
Packit 071ada
            _c_type_setup(field.type, field.field_type, ())
Packit 071ada
            if field.type.is_list:
Packit 071ada
                _c_type_setup(field.type.member, field.field_type, ())
Packit 071ada
                if (field.type.nmemb is None and field.wire):
Packit 071ada
                    self.c_need_sizeof = True
Packit 071ada
Packit 071ada
    if self.c_need_serialize:
Packit 071ada
        # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
Packit 071ada
        self.c_need_sizeof = True
Packit 071ada
Packit 071ada
    # as switch does never appear at toplevel,
Packit 071ada
    # continue here with type construction
Packit 071ada
    if self.is_switch:
Packit 071ada
        if self.c_type not in finished_switch:
Packit 071ada
            finished_switch.append(self.c_type)
Packit 071ada
            # special: switch C structs get pointer fields for variable-sized members
Packit 071ada
            _c_complex(self)
Packit 071ada
            for bitcase in self.bitcases:
Packit 071ada
                bitcase_name = bitcase.type.name if bitcase.type.has_name else name
Packit 071ada
                _c_accessors(bitcase.type, bitcase_name, bitcase_name)
Packit 071ada
                # no list with switch as element, so no call to
Packit 071ada
                # _c_iterator(field.type, field_name) necessary
Packit 071ada
Packit 071ada
    if not self.is_case_or_bitcase:
Packit 071ada
        if self.c_need_serialize:
Packit 071ada
            if self.c_serialize_name not in finished_serializers:
Packit 071ada
                finished_serializers.append(self.c_serialize_name)
Packit 071ada
                _c_serialize('serialize', self)
Packit 071ada
Packit 071ada
                # _unpack() and _unserialize() are only needed for special cases:
Packit 071ada
                #   switch -> unpack
Packit 071ada
                #   special cases -> unserialize
Packit 071ada
                if self.is_switch or self.c_var_followed_by_fixed_fields:
Packit 071ada
                    _c_serialize('unserialize', self)
Packit 071ada
Packit 071ada
        if self.c_need_sizeof:
Packit 071ada
            if self.c_sizeof_name not in finished_sizeof:
Packit 071ada
                if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
Packit 071ada
                    finished_sizeof.append(self.c_sizeof_name)
Packit 071ada
                    _c_serialize('sizeof', self)
Packit 071ada
Packit 071ada
# Functions for querying field properties
Packit 071ada
def _c_field_needs_list_accessor(field):
Packit 071ada
    return field.type.is_list and not field.type.fixed_size()
Packit 071ada
Packit 071ada
def _c_field_needs_field_accessor(field):
Packit 071ada
    if field.type.is_list:
Packit 071ada
        return False
Packit 071ada
    else:
Packit 071ada
        return (field.prev_varsized_field is not None or
Packit 071ada
                not field.type.fixed_size())
Packit 071ada
Packit 071ada
def _c_field_needs_accessor(field):
Packit 071ada
    return (_c_field_needs_list_accessor(field) or
Packit 071ada
            _c_field_needs_field_accessor(field))
Packit 071ada
Packit 071ada
def _c_field_is_member_of_case_or_bitcase(field):
Packit 071ada
    return field.parent and field.parent.is_case_or_bitcase
Packit 071ada
Packit 071ada
def _c_helper_fieldaccess_expr(prefix, field=None):
Packit 071ada
    """
Packit 071ada
    turn prefix, which is a list of tuples (name, separator, Type obj) into a string
Packit 071ada
    representing a valid field-access-expression in C (based on the context)
Packit 071ada
    if field is not None, append access to the field as well.
Packit 071ada
Packit 071ada
    "separator" is one of the C-operators "." or "->".
Packit 071ada
Packit 071ada
    A field access expression can consist of the following components:
Packit 071ada
    * struct/union member access from a value with the "."-operator
Packit 071ada
    * struct/union member access from a pointer with "->"-operator
Packit 071ada
    * function-call of an accessor function:
Packit 071ada
      This is used when a xcb-field is not contained in a struct.
Packit 071ada
      This can, e.g., happen for fields after var-sized fields, etc.
Packit 071ada
    """
Packit 071ada
    prefix_str = ''
Packit 071ada
    last_sep =''
Packit 071ada
    for name, sep, obj in prefix:
Packit 071ada
        prefix_str += last_sep + name
Packit 071ada
        last_sep = sep
Packit 071ada
Packit 071ada
    if field is None:
Packit 071ada
        # add separator for access to a yet unknown field
Packit 071ada
        prefix_str += last_sep
Packit 071ada
    else:
Packit 071ada
        if _c_field_needs_accessor(field):
Packit 071ada
            if _c_field_is_member_of_case_or_bitcase(field):
Packit 071ada
                # case members are available in the deserialized struct,
Packit 071ada
                # so there is no need to use the accessor function
Packit 071ada
                # (also, their accessor function needs a different arglist
Packit 071ada
                # so this would require special treatment here)
Packit 071ada
                # Therefore: Access as struct member
Packit 071ada
                prefix_str += last_sep + _cpp(field.field_name)
Packit 071ada
            else:
Packit 071ada
                # Access with the accessor function
Packit 071ada
                prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
Packit 071ada
        else:
Packit 071ada
            # Access as struct member
Packit 071ada
            prefix_str += last_sep + _cpp(field.field_name)
Packit 071ada
Packit 071ada
    return prefix_str
Packit 071ada
Packit 071ada
def _c_helper_field_mapping(complex_type, prefix, flat=False):
Packit 071ada
    """
Packit 071ada
    generate absolute names, based on prefix, for all fields starting from complex_type
Packit 071ada
    if flat == True, nested complex types are not taken into account
Packit 071ada
    """
Packit 071ada
    all_fields = {}
Packit 071ada
    if complex_type.is_switch:
Packit 071ada
        for b in complex_type.bitcases:
Packit 071ada
            if b.type.has_name:
Packit 071ada
                switch_name, switch_sep, switch_type = prefix[-1]
Packit 071ada
                bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
Packit 071ada
            else:
Packit 071ada
                bitcase_prefix = prefix
Packit 071ada
Packit 071ada
            if (flat and not b.type.has_name) or not flat:
Packit 071ada
                all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
Packit 071ada
    else:
Packit 071ada
        for f in complex_type.fields:
Packit 071ada
            fname = _c_helper_fieldaccess_expr(prefix, f)
Packit 071ada
            if f.field_name in all_fields:
Packit 071ada
                raise Exception("field name %s has been registered before" % f.field_name)
Packit 071ada
Packit 071ada
            all_fields[f.field_name] = (fname, f)
Packit 071ada
            if f.type.is_container and not flat:
Packit 071ada
                if f.type.is_case_or_bitcase and not f.type.has_name:
Packit 071ada
                    new_prefix = prefix
Packit 071ada
                elif f.type.is_switch and len(f.type.parents)>1:
Packit 071ada
                    # nested switch gets another separator
Packit 071ada
                    new_prefix = prefix+[(f.c_field_name, '.', f.type)]
Packit 071ada
                else:
Packit 071ada
                    new_prefix = prefix+[(f.c_field_name, '->', f.type)]
Packit 071ada
                all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
Packit 071ada
Packit 071ada
    return all_fields
Packit 071ada
Packit 071ada
def _c_helper_resolve_field_names (prefix):
Packit 071ada
    """
Packit 071ada
    get field names for all objects in the prefix array
Packit 071ada
    """
Packit 071ada
    all_fields = {}
Packit 071ada
    tmp_prefix = []
Packit 071ada
    # look for fields in the remaining containers
Packit 071ada
    for idx, (name, sep, obj) in enumerate(prefix):
Packit 071ada
        if ''==sep:
Packit 071ada
            # sep can be preset in prefix, if not, make a sensible guess
Packit 071ada
            sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
Packit 071ada
            # exception: 'toplevel' object (switch as well!) always have sep '->'
Packit 071ada
            sep = '->' if idx<1 else sep
Packit 071ada
        if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
Packit 071ada
            tmp_prefix.append((name, sep, obj))
Packit 071ada
        all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
Packit 071ada
Packit 071ada
    return all_fields
Packit 071ada
Packit 071ada
def get_expr_fields(self):
Packit 071ada
    """
Packit 071ada
    get the Fields referenced by switch or list expression
Packit 071ada
    """
Packit 071ada
    def get_expr_field_names(expr):
Packit 071ada
        if expr.op is None or expr.op == 'calculate_len':
Packit 071ada
            if expr.lenfield_name is not None:
Packit 071ada
                return [expr.lenfield_name]
Packit 071ada
            else:
Packit 071ada
                # constant value expr
Packit 071ada
                return []
Packit 071ada
        else:
Packit 071ada
            if expr.op == '~':
Packit 071ada
                return get_expr_field_names(expr.rhs)
Packit 071ada
            elif expr.op == 'popcount':
Packit 071ada
                return get_expr_field_names(expr.rhs)
Packit 071ada
            elif expr.op == 'sumof':
Packit 071ada
                # sumof expr references another list,
Packit 071ada
                # we need that list's length field here
Packit 071ada
                field = None
Packit 071ada
                for f in expr.lenfield_parent.fields:
Packit 071ada
                    if f.field_name == expr.lenfield_name:
Packit 071ada
                        field = f
Packit 071ada
                        break
Packit 071ada
                if field is None:
Packit 071ada
                    raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
Packit 071ada
                # referenced list + its length field
Packit 071ada
                return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
Packit 071ada
            elif expr.op == 'enumref':
Packit 071ada
                return []
Packit 071ada
            else:
Packit 071ada
                return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
Packit 071ada
    # get_expr_field_names()
Packit 071ada
Packit 071ada
    # resolve the field names with the parent structure(s)
Packit 071ada
    unresolved_fields_names = get_expr_field_names(self.expr)
Packit 071ada
Packit 071ada
    # construct prefix from self
Packit 071ada
    prefix = [('', '', p) for p in self.parents]
Packit 071ada
    if self.is_container:
Packit 071ada
        prefix.append(('', '', self))
Packit 071ada
Packit 071ada
    all_fields = _c_helper_resolve_field_names (prefix)
Packit 071ada
    resolved_fields_names = [x for x in unresolved_fields_names if x in all_fields]
Packit 071ada
    if len(unresolved_fields_names) != len(resolved_fields_names):
Packit 071ada
        raise Exception("could not resolve all fields for %s" % self.name)
Packit 071ada
Packit 071ada
    resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
Packit 071ada
    return resolved_fields
Packit 071ada
Packit 071ada
def resolve_expr_fields(complex_obj):
Packit 071ada
    """
Packit 071ada
    find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
Packit 071ada
    these are normally fields that need to be given as function parameters
Packit 071ada
    """
Packit 071ada
    all_fields = []
Packit 071ada
    expr_fields = []
Packit 071ada
    unresolved = []
Packit 071ada
Packit 071ada
    for field in complex_obj.fields:
Packit 071ada
        all_fields.append(field)
Packit 071ada
        if field.type.is_switch or field.type.is_list:
Packit 071ada
            expr_fields += get_expr_fields(field.type)
Packit 071ada
        if field.type.is_container:
Packit 071ada
            expr_fields += resolve_expr_fields(field.type)
Packit 071ada
Packit 071ada
    # try to resolve expr fields
Packit 071ada
    for e in expr_fields:
Packit 071ada
        if e not in all_fields and e not in unresolved:
Packit 071ada
            unresolved.append(e)
Packit 071ada
    return unresolved
Packit 071ada
Packit 071ada
def resolve_expr_fields_list(self, parents):
Packit 071ada
    """
Packit 071ada
    Find expr fields appearing in a list and descendents
Packit 071ada
    that cannot be resolved within the parents of the list.
Packit 071ada
    These are normally fields that need to be given as function parameters
Packit 071ada
    for length and iterator functions.
Packit 071ada
    """
Packit 071ada
    all_fields = []
Packit 071ada
    expr_fields = get_expr_fields(self)
Packit 071ada
    unresolved = []
Packit 071ada
    dont_resolve_this = ''
Packit 071ada
    for complex_obj in parents:
Packit 071ada
        for field in complex_obj.fields:
Packit 071ada
            if field.type.is_list and field.type.expr.op == 'calculate_len':
Packit 071ada
                dont_resolve_this = field.type.expr.lenfield_name
Packit 071ada
            if field.wire:
Packit 071ada
                all_fields.append(field)
Packit 071ada
Packit 071ada
    # try to resolve expr fields
Packit 071ada
    for e in expr_fields:
Packit 071ada
        if e not in all_fields and e not in unresolved and e.field_name != dont_resolve_this:
Packit 071ada
            unresolved.append(e)
Packit 071ada
Packit 071ada
    return unresolved
Packit 071ada
# resolve_expr_fields_list()
Packit 071ada
Packit 071ada
Packit 071ada
def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
Packit 071ada
    """
Packit 071ada
    functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
Packit 071ada
    E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
Packit 071ada
    expression. This function tries to resolve all fields within a structure, and returns the
Packit 071ada
    unresolved fields as the list of external parameters.
Packit 071ada
    """
Packit 071ada
    def add_param(params, param):
Packit 071ada
        if param not in params:
Packit 071ada
            params.append(param)
Packit 071ada
Packit 071ada
    # collect all fields into param_fields
Packit 071ada
    param_fields = []
Packit 071ada
    wire_fields = []
Packit 071ada
Packit 071ada
    for field in self.fields:
Packit 071ada
        if field.visible:
Packit 071ada
            # the field should appear as a parameter in the function call
Packit 071ada
            param_fields.append(field)
Packit 071ada
        if field.wire and not field.auto:
Packit 071ada
            if field.type.fixed_size() and not self.is_switch:
Packit 071ada
                # field in the xcb_out structure
Packit 071ada
                wire_fields.append(field)
Packit 071ada
        # fields like 'pad0' are skipped!
Packit 071ada
Packit 071ada
    # in case of switch, parameters always contain any fields referenced in the switch expr
Packit 071ada
    # we do not need any variable size fields here, as the switch data type contains both
Packit 071ada
    # fixed and variable size fields
Packit 071ada
    if self.is_switch:
Packit 071ada
        param_fields = get_expr_fields(self)
Packit 071ada
Packit 071ada
    # _serialize()/_unserialize()/_unpack() function parameters
Packit 071ada
    # note: don't use set() for params, it is unsorted
Packit 071ada
    params = []
Packit 071ada
    parameter = ''
Packit 071ada
    if self.is_list:
Packit 071ada
       parameter = self.type.expr.lenfield_name
Packit 071ada
    # 1. the parameter for the void * buffer
Packit 071ada
    if  'serialize' == context:
Packit 071ada
        params.append(('void', '**', buffer_var))
Packit 071ada
    elif context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
        params.append(('const void', '*', buffer_var))
Packit 071ada
Packit 071ada
    # 2. any expr fields that cannot be resolved within self and descendants
Packit 071ada
    unresolved_fields = resolve_expr_fields(self)
Packit 071ada
    for f in unresolved_fields:
Packit 071ada
        add_param(params, (f.c_field_type, '', f.c_field_name))
Packit 071ada
Packit 071ada
    # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
Packit 071ada
    #    that do not appear in the data type struct
Packit 071ada
    for p in param_fields:
Packit 071ada
        if self.is_switch:
Packit 071ada
            typespec = p.c_field_const_type
Packit 071ada
            pointerspec = p.c_pointer
Packit 071ada
            add_param(params, (typespec, pointerspec, p.c_field_name))
Packit 071ada
        else:
Packit 071ada
            if p.visible and not p.wire and not p.auto and p.field_name != parameter:
Packit 071ada
                typespec = p.c_field_type
Packit 071ada
                pointerspec = ''
Packit 071ada
                add_param(params, (typespec, pointerspec, p.c_field_name))
Packit 071ada
Packit 071ada
    # 4. aux argument
Packit 071ada
    if 'serialize' == context:
Packit 071ada
        add_param(params, ('const %s' % self.c_type, '*', aux_var))
Packit 071ada
    elif 'unserialize' == context:
Packit 071ada
        add_param(params, ('%s' % self.c_type, '**', aux_var))
Packit 071ada
    elif 'unpack' == context:
Packit 071ada
        add_param(params, ('%s' % self.c_type, '*', aux_var))
Packit 071ada
Packit 071ada
    # 5. switch contains all variable size fields as struct members
Packit 071ada
    #    for other data types though, these have to be supplied separately
Packit 071ada
    #    this is important for the special case of intermixed fixed and
Packit 071ada
    #    variable size fields
Packit 071ada
    if not self.is_switch and 'serialize' == context:
Packit 071ada
        for p in param_fields:
Packit 071ada
            if not p.type.fixed_size():
Packit 071ada
                add_param(params, (p.c_field_const_type, '*', p.c_field_name))
Packit 071ada
Packit 071ada
    return (param_fields, wire_fields, params)
Packit 071ada
Packit 071ada
def _c_serialize_helper_insert_padding(context, complex_type, code_lines, space, postpone, is_case_or_bitcase):
Packit 071ada
    code_lines.append('%s    /* insert padding */' % space)
Packit 071ada
    if is_case_or_bitcase:
Packit 071ada
        code_lines.append(
Packit 071ada
            '%s    xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
Packit 071ada
            % space)
Packit 071ada
    else:
Packit 071ada
        code_lines.append(
Packit 071ada
            '%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
Packit 071ada
    code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
Packit 071ada
Packit 071ada
    if not postpone:
Packit 071ada
        code_lines.append('%s    if (0 != xcb_pad) {' % space)
Packit 071ada
Packit 071ada
        if 'serialize' == context:
Packit 071ada
            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
Packit 071ada
            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
Packit 071ada
            code_lines.append('%s        xcb_parts_idx++;' % space)
Packit 071ada
        elif context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
            code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
Packit 071ada
Packit 071ada
        code_lines.append('%s        xcb_pad = 0;' % space)
Packit 071ada
        code_lines.append('%s    }' % space)
Packit 071ada
Packit 071ada
    code_lines.append('%s    xcb_block_len = 0;' % space)
Packit 071ada
    if is_case_or_bitcase:
Packit 071ada
        code_lines.append('%s    xcb_padding_offset = 0;' % space)
Packit 071ada
Packit 071ada
    # keep tracking of xcb_parts entries for serialize
Packit 071ada
    return 1
Packit 071ada
Packit 071ada
def _c_serialize_helper_switch(context, self, complex_name,
Packit 071ada
                               code_lines, temp_vars,
Packit 071ada
                               space, prefix):
Packit 071ada
    count = 0
Packit 071ada
    switch_expr = _c_accessor_get_expr(self.expr, None)
Packit 071ada
Packit 071ada
    for b in self.bitcases:
Packit 071ada
        len_expr = len(b.type.expr)
Packit 071ada
Packit 071ada
        compare_operator = '&'
Packit 071ada
        if b.type.is_case:
Packit 071ada
            compare_operator = '=='
Packit 071ada
        else:
Packit 071ada
            compare_operator = '&'
Packit 071ada
Packit 071ada
        for n, expr in enumerate(b.type.expr):
Packit 071ada
            bitcase_expr = _c_accessor_get_expr(expr, None)
Packit 071ada
            # only one <enumref> in the <bitcase>
Packit 071ada
            if len_expr == 1:
Packit 071ada
                code_lines.append(
Packit 071ada
                    '    if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
Packit 071ada
            # multiple <enumref> in the <bitcase>
Packit 071ada
            elif n == 0: # first
Packit 071ada
                code_lines.append(
Packit 071ada
                    '    if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
Packit 071ada
            elif len_expr == (n + 1): # last
Packit 071ada
                code_lines.append(
Packit 071ada
                    '       (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
Packit 071ada
            else: # between first and last
Packit 071ada
                code_lines.append(
Packit 071ada
                    '       (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
Packit 071ada
Packit 071ada
        b_prefix = prefix
Packit 071ada
        if b.type.has_name:
Packit 071ada
            b_prefix = prefix + [(b.c_field_name, '.', b.type)]
Packit 071ada
Packit 071ada
        count += _c_serialize_helper_fields(context, b.type,
Packit 071ada
                                            code_lines, temp_vars,
Packit 071ada
                                            "%s    " % space,
Packit 071ada
                                            b_prefix,
Packit 071ada
                                            is_case_or_bitcase = True)
Packit 071ada
        code_lines.append('    }')
Packit 071ada
Packit 071ada
#    if 'serialize' == context:
Packit 071ada
#        count += _c_serialize_helper_insert_padding(context, self, code_lines, space, False)
Packit 071ada
#    elif context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
#        # padding
Packit 071ada
#        code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
Packit 071ada
#        code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
Packit 071ada
Packit 071ada
    return count
Packit 071ada
Packit 071ada
def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
Packit 071ada
    """
Packit 071ada
    handle switch by calling _serialize() or _unpack(), depending on context
Packit 071ada
    """
Packit 071ada
    # switch is handled by this function as a special case
Packit 071ada
    field_mapping = _c_helper_field_mapping(self, prefix)
Packit 071ada
    prefix_str = _c_helper_fieldaccess_expr(prefix)
Packit 071ada
Packit 071ada
    # find the parameters that need to be passed to _serialize()/_unpack():
Packit 071ada
    # all switch expr fields must be given as parameters
Packit 071ada
    args = get_expr_fields(field.type)
Packit 071ada
    # length fields for variable size types in switch, normally only some of need
Packit 071ada
    # need to be passed as parameters
Packit 071ada
    switch_len_fields = resolve_expr_fields(field.type)
Packit 071ada
Packit 071ada
    # a switch field at this point _must_ be a bitcase field
Packit 071ada
    # we require that bitcases are "self-contiguous"
Packit 071ada
    bitcase_unresolved = resolve_expr_fields(self)
Packit 071ada
    if len(bitcase_unresolved) != 0:
Packit 071ada
        raise Exception('unresolved fields within bitcase is not supported at this point')
Packit 071ada
Packit 071ada
    # get the C names for the parameters
Packit 071ada
    c_field_names = ''
Packit 071ada
    for a in switch_len_fields:
Packit 071ada
        c_field_names += "%s, " % field_mapping[a.c_field_name][0]
Packit 071ada
    for a in args:
Packit 071ada
        c_field_names += "%s, " % field_mapping[a.c_field_name][0]
Packit 071ada
Packit 071ada
    # call _serialize()/_unpack() to determine the actual size
Packit 071ada
    if 'serialize' == context:
Packit 071ada
        length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
Packit 071ada
                                       c_field_names, prefix_str, field.c_field_name)
Packit 071ada
    elif context in ('unserialize', 'unpack'):
Packit 071ada
        length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
Packit 071ada
                                           c_field_names, prefix_str, field.c_field_name)
Packit 071ada
    elif 'sizeof' == context:
Packit 071ada
        # remove trailing ", " from c_field_names because it will be used at end of arglist
Packit 071ada
        my_c_field_names = c_field_names[:-2]
Packit 071ada
        length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
Packit 071ada
Packit 071ada
    return length
Packit 071ada
Packit 071ada
def _c_get_additional_type_params(type):
Packit 071ada
    """
Packit 071ada
    compute list of additional params for functions created for the given type
Packit 071ada
    """
Packit 071ada
    if type.is_simple:
Packit 071ada
        return []
Packit 071ada
    else:
Packit 071ada
        param_fields, wire_fields, params = get_serialize_params('sizeof', type)
Packit 071ada
        return params[1:]
Packit 071ada
Packit 071ada
def _c_serialize_helper_list_field(context, self, field,
Packit 071ada
                                   code_lines, temp_vars,
Packit 071ada
                                   space, prefix):
Packit 071ada
    """
Packit 071ada
    helper function to cope with lists of variable length
Packit 071ada
    """
Packit 071ada
    expr = field.type.expr
Packit 071ada
    prefix_str = _c_helper_fieldaccess_expr(prefix)
Packit 071ada
    param_fields, wire_fields, params = get_serialize_params('sizeof', self)
Packit 071ada
    param_names = [p[2] for p in params]
Packit 071ada
Packit 071ada
    expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
Packit 071ada
    resolved = [x for x in expr_fields_names if x in param_names]
Packit 071ada
    unresolved = [x for x in expr_fields_names if x not in param_names]
Packit 071ada
Packit 071ada
    field_mapping = {}
Packit 071ada
    for r in resolved:
Packit 071ada
        field_mapping[r] = (r, None)
Packit 071ada
Packit 071ada
    if len(unresolved)>0:
Packit 071ada
        tmp_prefix = prefix
Packit 071ada
        if len(tmp_prefix)==0:
Packit 071ada
            raise Exception("found an empty prefix while resolving expr field names for list %s",
Packit 071ada
                            field.c_field_name)
Packit 071ada
Packit 071ada
        field_mapping.update(_c_helper_resolve_field_names(prefix))
Packit 071ada
        resolved += [x for x in unresolved if x in field_mapping]
Packit 071ada
        unresolved = [x for x in unresolved if x not in field_mapping]
Packit 071ada
        if len(unresolved)>0:
Packit 071ada
            raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
Packit 071ada
    if expr.op == 'calculate_len':
Packit 071ada
        list_length = field.type.expr.lenfield_name
Packit 071ada
    else:
Packit 071ada
        list_length = _c_accessor_get_expr(expr, field_mapping)
Packit 071ada
Packit 071ada
    # default: list with fixed size elements
Packit 071ada
    length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
Packit 071ada
Packit 071ada
    # list with variable-sized elements
Packit 071ada
    if not field.type.member.fixed_size():
Packit 071ada
        # compute string for argumentlist for member-type functions
Packit 071ada
        member_params = _c_get_additional_type_params(field.type.member)
Packit 071ada
        member_arg_names = [p[2] for p in member_params]
Packit 071ada
        member_arg_str = ''
Packit 071ada
        for member_arg_name in member_arg_names:
Packit 071ada
            member_arg_str += ', ' + field_mapping[member_arg_name][0]
Packit 071ada
Packit 071ada
        #
Packit 071ada
        length = ''
Packit 071ada
        if context in ('unserialize', 'sizeof', 'unpack'):
Packit 071ada
            int_i = '    unsigned int i;'
Packit 071ada
            xcb_tmp_len = '    unsigned int xcb_tmp_len;'
Packit 071ada
            if int_i not in temp_vars:
Packit 071ada
                temp_vars.append(int_i)
Packit 071ada
            if xcb_tmp_len not in temp_vars:
Packit 071ada
                temp_vars.append(xcb_tmp_len)
Packit 071ada
            # loop over all list elements and call sizeof repeatedly
Packit 071ada
            # this should be a bit faster than using the iterators
Packit 071ada
            code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
Packit 071ada
            code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp%s);" %
Packit 071ada
                              (space, field.type.c_sizeof_name, member_arg_str))
Packit 071ada
            code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
Packit 071ada
            code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
Packit 071ada
            code_lines.append("%s    }" % space)
Packit 071ada
Packit 071ada
        elif 'serialize' == context:
Packit 071ada
            code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
Packit 071ada
            code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
Packit 071ada
            code_lines.append('%s    for(i=0; i<%s; i++) { ' % (space, list_length))
Packit 071ada
            code_lines.append('%s        xcb_block_len = %s(xcb_tmp%s);' % (space, field.type.c_sizeof_name, member_arg_str))
Packit 071ada
            code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
Packit 071ada
            code_lines.append('%s    }' % space)
Packit 071ada
            code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
Packit 071ada
Packit 071ada
    return length
Packit 071ada
Packit 071ada
def _c_serialize_helper_fields_fixed_size(context, self, field,
Packit 071ada
                                          code_lines, temp_vars,
Packit 071ada
                                          space, prefix):
Packit 071ada
    # keep the C code a bit more readable by giving the field name
Packit 071ada
    if not self.is_case_or_bitcase:
Packit 071ada
        code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
Packit 071ada
    else:
Packit 071ada
        scoped_name = [obj.c_type if idx==0 else name for idx, (name, _, obj) in enumerate(prefix)]
Packit 071ada
        typename = ".".join(scoped_name)
Packit 071ada
        code_lines.append('%s    /* %s.%s */' % (space, typename, field.c_field_name))
Packit 071ada
Packit 071ada
    abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
Packit 071ada
    # default for simple cases: call sizeof()
Packit 071ada
    length = "sizeof(%s)" % field.c_field_type
Packit 071ada
Packit 071ada
    if context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
        # default: simple cast
Packit 071ada
        value = '    %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
Packit 071ada
Packit 071ada
        # padding - we could probably just ignore it
Packit 071ada
        if field.type.is_pad and field.type.nmemb > 1:
Packit 071ada
            value = ''
Packit 071ada
            for i in range(field.type.nmemb):
Packit 071ada
                code_lines.append('%s    %s[%d] = *(%s *)xcb_tmp;' %
Packit 071ada
                                  (space, abs_field_name, i, field.c_field_type))
Packit 071ada
            # total padding = sizeof(pad0) * nmemb
Packit 071ada
            length += " * %d" % field.type.nmemb
Packit 071ada
Packit 071ada
        elif field.type.is_list:
Packit 071ada
            # list with fixed number of elements
Packit 071ada
            # length of array = sizeof(arrayElementType) * nmemb
Packit 071ada
            length += " * %d" % field.type.nmemb
Packit 071ada
            # use memcpy because C cannot assign whole arrays with operator=
Packit 071ada
            value = '    memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
Packit 071ada
Packit 071ada
Packit 071ada
    elif 'serialize' == context:
Packit 071ada
        value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) '
Packit 071ada
Packit 071ada
        if field.type.is_expr:
Packit 071ada
            # need to register a temporary variable for the expression in case we know its type
Packit 071ada
            if field.type.c_type is None:
Packit 071ada
                raise Exception("type for field '%s' (expression '%s') unkown" %
Packit 071ada
                                (field.field_name, _c_accessor_get_expr(field.type.expr)))
Packit 071ada
Packit 071ada
            temp_vars.append('    %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
Packit 071ada
                                                           _c_accessor_get_expr(field.type.expr, prefix)))
Packit 071ada
            value += "&xcb_expr_%s;" % _cpp(field.field_name)
Packit 071ada
Packit 071ada
        elif field.type.is_pad:
Packit 071ada
            if field.type.nmemb == 1:
Packit 071ada
                value += "&xcb_pad;"
Packit 071ada
            else:
Packit 071ada
                # we could also set it to 0, see definition of xcb_send_request()
Packit 071ada
                value = '    xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
Packit 071ada
                length += "*%d" % field.type.nmemb
Packit 071ada
Packit 071ada
        else:
Packit 071ada
            # non-list type with fixed size
Packit 071ada
            if field.type.nmemb == 1:
Packit 071ada
                value += "&%;;" % (abs_field_name)
Packit 071ada
Packit 071ada
            # list with nmemb (fixed size) elements
Packit 071ada
            else:
Packit 071ada
                value += '%s;' % (abs_field_name)
Packit 071ada
                length = '%d' % field.type.nmemb
Packit 071ada
Packit 071ada
    return (value, length)
Packit 071ada
Packit 071ada
def _c_serialize_helper_fields_variable_size(context, self, field,
Packit 071ada
                                             code_lines, temp_vars,
Packit 071ada
                                             space, prefix):
Packit 071ada
    prefix_str = _c_helper_fieldaccess_expr(prefix)
Packit 071ada
Packit 071ada
    if context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
        value = ''
Packit 071ada
        var_field_name = 'xcb_tmp'
Packit 071ada
Packit 071ada
        # special case: intermixed fixed and variable size fields
Packit 071ada
        if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
Packit 071ada
            value = '    %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
Packit 071ada
            temp_vars.append('    %s *%s;' % (field.type.c_type, field.c_field_name))
Packit 071ada
        # special case: switch
Packit 071ada
        if 'unpack' == context:
Packit 071ada
            value = '    %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
Packit 071ada
Packit 071ada
    elif 'serialize' == context:
Packit 071ada
        # variable size fields appear as parameters to _serialize() if the
Packit 071ada
        # 'toplevel' container is not a switch
Packit 071ada
        prefix_string = prefix_str if prefix[0][2].is_switch else ''
Packit 071ada
        var_field_name = "%s%s" % (prefix_string, field.c_field_name)
Packit 071ada
        value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
Packit 071ada
Packit 071ada
    length = ''
Packit 071ada
Packit 071ada
    code_lines.append('%s    /* %s */' % (space, field.c_field_name))
Packit 071ada
Packit 071ada
    if field.type.is_list:
Packit 071ada
        if value != '':
Packit 071ada
            # in any context, list is already a pointer, so the default assignment is ok
Packit 071ada
            code_lines.append("%s%s" % (space, value))
Packit 071ada
            value = ''
Packit 071ada
        length = _c_serialize_helper_list_field(context, self, field,
Packit 071ada
                                                code_lines, temp_vars,
Packit 071ada
                                                space, prefix)
Packit 071ada
Packit 071ada
    elif field.type.is_switch:
Packit 071ada
        value = ''
Packit 071ada
        if context == 'serialize':
Packit 071ada
            # the _serialize() function allocates the correct amount memory if given a NULL pointer
Packit 071ada
            value = '    xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
Packit 071ada
        length = _c_serialize_helper_switch_field(context, self, field,
Packit 071ada
                                                  'xcb_parts[xcb_parts_idx].iov_base',
Packit 071ada
                                                  prefix)
Packit 071ada
Packit 071ada
    else:
Packit 071ada
        # in all remaining special cases - call _sizeof()
Packit 071ada
        length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
Packit 071ada
Packit 071ada
    return (value, length)
Packit 071ada
Packit 071ada
def _c_serialize_helper_fields(context, self,
Packit 071ada
                               code_lines, temp_vars,
Packit 071ada
                               space, prefix, is_case_or_bitcase):
Packit 071ada
    count = 0
Packit 071ada
    need_padding = False
Packit 071ada
    prev_field_was_variable = False
Packit 071ada
Packit 071ada
    _c_pre.push_indent(space + '    ')
Packit 071ada
Packit 071ada
    for field in self.fields:
Packit 071ada
        if not field.wire:
Packit 071ada
            continue
Packit 071ada
        if not field.visible:
Packit 071ada
            if not ((field.wire and not field.auto) or 'unserialize' == context):
Packit 071ada
                continue
Packit 071ada
Packit 071ada
        # switch/bitcase: fixed size fields must be considered explicitly
Packit 071ada
        if field.type.fixed_size():
Packit 071ada
            if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
Packit 071ada
                if prev_field_was_variable and need_padding:
Packit 071ada
                    # insert padding
Packit 071ada
#                    count += _c_serialize_helper_insert_padding(context, self, code_lines, space,
Packit 071ada
#                                                                self.c_var_followed_by_fixed_fields)
Packit 071ada
                    prev_field_was_variable = False
Packit 071ada
Packit 071ada
                # prefix for fixed size fields
Packit 071ada
                fixed_prefix = prefix
Packit 071ada
Packit 071ada
                value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
Packit 071ada
                                                                      code_lines, temp_vars,
Packit 071ada
                                                                      space, fixed_prefix)
Packit 071ada
            else:
Packit 071ada
                continue
Packit 071ada
Packit 071ada
        # fields with variable size
Packit 071ada
        else:
Packit 071ada
            if not field.wire:
Packit 071ada
                continue
Packit 071ada
            elif field.type.is_pad:
Packit 071ada
                # Variable length pad is <pad align= />
Packit 071ada
                code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
Packit 071ada
                count += _c_serialize_helper_insert_padding(context, self, code_lines, space,
Packit 071ada
                                                            self.c_var_followed_by_fixed_fields,
Packit 071ada
                                                            is_case_or_bitcase)
Packit 071ada
                continue
Packit 071ada
            else:
Packit 071ada
                # switch/bitcase: always calculate padding before and after variable sized fields
Packit 071ada
                if need_padding or is_case_or_bitcase:
Packit 071ada
                    count += _c_serialize_helper_insert_padding(context, self, code_lines, space,
Packit 071ada
                                                                self.c_var_followed_by_fixed_fields,
Packit 071ada
                                                                is_case_or_bitcase)
Packit 071ada
Packit 071ada
                value, length = _c_serialize_helper_fields_variable_size(context, self, field,
Packit 071ada
                                                                         code_lines, temp_vars,
Packit 071ada
                                                                         space, prefix)
Packit 071ada
                prev_field_was_variable = True
Packit 071ada
Packit 071ada
        # save (un)serialization C code
Packit 071ada
        if '' != value:
Packit 071ada
            code_lines.append('%s%s' % (space, value))
Packit 071ada
Packit 071ada
        if field.type.fixed_size():
Packit 071ada
            if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
Packit 071ada
                # keep track of (un)serialized object's size
Packit 071ada
                code_lines.append('%s    xcb_block_len += %s;' % (space, length))
Packit 071ada
                if context in ('unserialize', 'unpack', 'sizeof'):
Packit 071ada
                    code_lines.append('%s    xcb_tmp += %s;' % (space, length))
Packit 071ada
        else:
Packit 071ada
            # variable size objects or bitcase:
Packit 071ada
            #   value & length might have been inserted earlier for special cases
Packit 071ada
            if '' != length:
Packit 071ada
                # special case: intermixed fixed and variable size fields
Packit 071ada
                if (not field.type.fixed_size() and
Packit 071ada
                    self.c_var_followed_by_fixed_fields and 'unserialize' == context):
Packit 071ada
                    temp_vars.append('    int %s_len;' % field.c_field_name)
Packit 071ada
                    code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
Packit 071ada
                    code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
Packit 071ada
                    code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
Packit 071ada
                else:
Packit 071ada
                    code_lines.append('%s    xcb_block_len += %s;' % (space, length))
Packit 071ada
                    # increase pointer into the byte stream accordingly
Packit 071ada
                    if context in ('unserialize', 'sizeof', 'unpack'):
Packit 071ada
                        code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
Packit 071ada
Packit 071ada
        if 'serialize' == context:
Packit 071ada
            if '' != length:
Packit 071ada
                code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
Packit 071ada
            code_lines.append('%s    xcb_parts_idx++;' % space)
Packit 071ada
            count += 1
Packit 071ada
Packit 071ada
        code_lines.append(
Packit 071ada
            '%s    xcb_align_to = ALIGNOF(%s);'
Packit 071ada
             % (space,
Packit 071ada
                 'char'
Packit 071ada
                  if field.c_field_type == 'void' or field.type.is_switch
Packit 071ada
                  else field.c_field_type))
Packit 071ada
Packit 071ada
        need_padding = True
Packit 071ada
        if self.c_var_followed_by_fixed_fields:
Packit 071ada
            need_padding = False
Packit 071ada
Packit 071ada
    _c_pre.pop_indent()
Packit 071ada
Packit 071ada
    return count
Packit 071ada
Packit 071ada
def _c_serialize_helper(context, complex_type,
Packit 071ada
                        code_lines, temp_vars,
Packit 071ada
                        space='', prefix=[]):
Packit 071ada
    # count tracks the number of fields to serialize
Packit 071ada
    count = 0
Packit 071ada
Packit 071ada
    if hasattr(complex_type, 'type'):
Packit 071ada
        self = complex_type.type
Packit 071ada
        complex_name = complex_type.name
Packit 071ada
    else:
Packit 071ada
        self = complex_type
Packit 071ada
        if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
Packit 071ada
            complex_name = 'xcb_out'
Packit 071ada
        else:
Packit 071ada
            complex_name = '_aux'
Packit 071ada
Packit 071ada
    # special case: switch is serialized by evaluating each bitcase separately
Packit 071ada
    if self.is_switch:
Packit 071ada
        count += _c_serialize_helper_switch(context, self, complex_name,
Packit 071ada
                                            code_lines, temp_vars,
Packit 071ada
                                            space, prefix)
Packit 071ada
Packit 071ada
    # all other data types can be evaluated one field a time
Packit 071ada
    else:
Packit 071ada
        # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
Packit 071ada
        if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
Packit 071ada
            code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
Packit 071ada
            code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
Packit 071ada
            code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
Packit 071ada
            code_lines.append('%s    xcb_block_len = 0;' % space)
Packit 071ada
Packit 071ada
        count += _c_serialize_helper_fields(context, self,
Packit 071ada
                                            code_lines, temp_vars,
Packit 071ada
                                            space, prefix, False)
Packit 071ada
    # "final padding"
Packit 071ada
    count += _c_serialize_helper_insert_padding(context, complex_type, code_lines, space, False, self.is_switch)
Packit 071ada
Packit 071ada
    return count
Packit 071ada
Packit 071ada
def _c_serialize(context, self):
Packit 071ada
    """
Packit 071ada
    depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
Packit 071ada
    for the ComplexType variable self
Packit 071ada
    """
Packit 071ada
    _h_setlevel(1)
Packit 071ada
    _c_setlevel(1)
Packit 071ada
Packit 071ada
    _hc('')
Packit 071ada
    # _serialize() returns the buffer size
Packit 071ada
    _hc('int')
Packit 071ada
Packit 071ada
    if self.is_switch and 'unserialize' == context:
Packit 071ada
        context = 'unpack'
Packit 071ada
Packit 071ada
    cases = { 'serialize'   : self.c_serialize_name,
Packit 071ada
              'unserialize' : self.c_unserialize_name,
Packit 071ada
              'unpack'      : self.c_unpack_name,
Packit 071ada
              'sizeof'      : self.c_sizeof_name }
Packit 071ada
    func_name = cases[context]
Packit 071ada
Packit 071ada
    param_fields, wire_fields, params = get_serialize_params(context, self)
Packit 071ada
    variable_size_fields = 0
Packit 071ada
    # maximum space required for type definition of function arguments
Packit 071ada
    maxtypelen = 0
Packit 071ada
Packit 071ada
    # determine N(variable_fields)
Packit 071ada
    for field in param_fields:
Packit 071ada
        # if self.is_switch, treat all fields as if they are variable sized
Packit 071ada
        if not field.type.fixed_size() or self.is_switch:
Packit 071ada
            variable_size_fields += 1
Packit 071ada
    # determine maxtypelen
Packit 071ada
    maxtypelen = max(len(p[0]) + len(p[1]) for p in params)
Packit 071ada
Packit 071ada
    # write to .c/.h
Packit 071ada
    indent = ' '*(len(func_name)+2)
Packit 071ada
    param_str = []
Packit 071ada
    for p in params:
Packit 071ada
        typespec, pointerspec, field_name = p
Packit 071ada
        spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
Packit 071ada
        param_str.append("%s%s%s  %s%s" % (indent, typespec, spacing, pointerspec, field_name))
Packit 071ada
    # insert function name
Packit 071ada
    param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
Packit 071ada
    param_str = ["%s," % x for x in param_str]
Packit 071ada
    for s in param_str[:-1]:
Packit 071ada
        _hc(s)
Packit 071ada
    _h("%s);" % param_str[-1].rstrip(','))
Packit 071ada
    _c("%s)" % param_str[-1].rstrip(','))
Packit 071ada
    _c('{')
Packit 071ada
Packit 071ada
    code_lines = []
Packit 071ada
    temp_vars = []
Packit 071ada
    prefix = []
Packit 071ada
Packit 071ada
    _c_pre.redirect_start(code_lines, temp_vars)
Packit 071ada
Packit 071ada
    if 'serialize' == context:
Packit 071ada
        if not self.is_switch and not self.c_var_followed_by_fixed_fields:
Packit 071ada
            _c('    %s *xcb_out = *_buffer;', self.c_type)
Packit 071ada
            _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
Packit 071ada
            _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
Packit 071ada
            _c('    unsigned int xcb_align_to = 0;')
Packit 071ada
        else:
Packit 071ada
            _c('    char *xcb_out = *_buffer;')
Packit 071ada
            _c('    unsigned int xcb_buffer_len = 0;')
Packit 071ada
            _c('    unsigned int xcb_align_to = 0;')
Packit 071ada
        if self.is_switch:
Packit 071ada
            _c('    unsigned int xcb_padding_offset = %d;',
Packit 071ada
               self.get_align_offset() )
Packit 071ada
        prefix = [('_aux', '->', self)]
Packit 071ada
        aux_ptr = 'xcb_out'
Packit 071ada
Packit 071ada
    elif context in ('unserialize', 'unpack'):
Packit 071ada
        _c('    char *xcb_tmp = (char *)_buffer;')
Packit 071ada
        if not self.is_switch:
Packit 071ada
            if not self.c_var_followed_by_fixed_fields:
Packit 071ada
                _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
Packit 071ada
                prefix = [('_aux', '->', self)]
Packit 071ada
            else:
Packit 071ada
                _c('    %s xcb_out;', self.c_type)
Packit 071ada
                prefix = [('xcb_out', '.', self)]
Packit 071ada
        else:
Packit 071ada
            aux_var = '_aux' # default for unpack: single pointer
Packit 071ada
            # note: unserialize not generated for switch
Packit 071ada
            if 'unserialize' == context:
Packit 071ada
                aux_var = '(*_aux)' # unserialize: double pointer (!)
Packit 071ada
            prefix = [(aux_var, '->', self)]
Packit 071ada
        aux_ptr = '*_aux'
Packit 071ada
        _c('    unsigned int xcb_buffer_len = 0;')
Packit 071ada
        _c('    unsigned int xcb_block_len = 0;')
Packit 071ada
        _c('    unsigned int xcb_pad = 0;')
Packit 071ada
        _c('    unsigned int xcb_align_to = 0;')
Packit 071ada
        if self.is_switch:
Packit 071ada
            _c('    unsigned int xcb_padding_offset = %d;',
Packit 071ada
               self.get_align_offset() )
Packit 071ada
Packit 071ada
    elif 'sizeof' == context:
Packit 071ada
        param_names = [p[2] for p in params]
Packit 071ada
        if self.is_switch:
Packit 071ada
            # switch: call _unpack()
Packit 071ada
            _c('    %s _aux;', self.c_type)
Packit 071ada
            _c('    return %s(%s, &_aux);', self.c_unpack_name, ", ".join(param_names))
Packit 071ada
            _c('}')
Packit 071ada
            _c_pre.redirect_end()
Packit 071ada
            return
Packit 071ada
        elif self.c_var_followed_by_fixed_fields:
Packit 071ada
            # special case: call _unserialize()
Packit 071ada
            _c('    return %s(%s, NULL);', self.c_unserialize_name, ", ".join(param_names))
Packit 071ada
            _c('}')
Packit 071ada
            _c_pre.redirect_end()
Packit 071ada
            return
Packit 071ada
        else:
Packit 071ada
            _c('    char *xcb_tmp = (char *)_buffer;')
Packit 071ada
            prefix = [('_aux', '->', self)]
Packit 071ada
            if self.is_switch:
Packit 071ada
                _c('    unsigned int xcb_padding_offset = 0;')
Packit 071ada
Packit 071ada
    count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
Packit 071ada
    # update variable size fields (only important for context=='serialize'
Packit 071ada
    variable_size_fields = count
Packit 071ada
    if 'serialize' == context:
Packit 071ada
        temp_vars.append('    unsigned int xcb_pad = 0;')
Packit 071ada
        temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};')
Packit 071ada
        temp_vars.append('    struct iovec xcb_parts[%d];' % count)
Packit 071ada
        temp_vars.append('    unsigned int xcb_parts_idx = 0;')
Packit 071ada
        temp_vars.append('    unsigned int xcb_block_len = 0;')
Packit 071ada
        temp_vars.append('    unsigned int i;')
Packit 071ada
        temp_vars.append('    char *xcb_tmp;')
Packit 071ada
    elif 'sizeof' == context:
Packit 071ada
        # neither switch nor intermixed fixed and variable size fields:
Packit 071ada
        # evaluate parameters directly
Packit 071ada
        if not (self.is_switch or self.c_var_followed_by_fixed_fields):
Packit 071ada
Packit 071ada
            # look if we have to declare an '_aux' variable at all
Packit 071ada
            if any('_aux' in x for x in code_lines):
Packit 071ada
                if not self.c_var_followed_by_fixed_fields:
Packit 071ada
                    _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
Packit 071ada
                else:
Packit 071ada
                    _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
Packit 071ada
Packit 071ada
            _c('    unsigned int xcb_buffer_len = 0;')
Packit 071ada
            _c('    unsigned int xcb_block_len = 0;')
Packit 071ada
            _c('    unsigned int xcb_pad = 0;')
Packit 071ada
            _c('    unsigned int xcb_align_to = 0;')
Packit 071ada
Packit 071ada
    _c_pre.redirect_end()
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
    for t in temp_vars:
Packit 071ada
        _c(t)
Packit 071ada
    _c('')
Packit 071ada
    for l in code_lines:
Packit 071ada
        _c(l)
Packit 071ada
Packit 071ada
    # variable sized fields have been collected, now
Packit 071ada
    # allocate memory and copy everything into a continuous memory area
Packit 071ada
    # note: this is not necessary in case of unpack
Packit 071ada
    if context in ('serialize', 'unserialize'):
Packit 071ada
        # unserialize: check for sizeof-only invocation
Packit 071ada
        if 'unserialize' == context:
Packit 071ada
            _c('')
Packit 071ada
            _c('    if (NULL == _aux)')
Packit 071ada
            _c('        return xcb_buffer_len;')
Packit 071ada
Packit 071ada
        _c('')
Packit 071ada
        _c('    if (NULL == %s) {', aux_ptr)
Packit 071ada
        _c('        /* allocate memory */')
Packit 071ada
        _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
Packit 071ada
        if 'serialize' == context:
Packit 071ada
            _c('        *_buffer = xcb_out;')
Packit 071ada
        _c('    }')
Packit 071ada
        _c('')
Packit 071ada
Packit 071ada
        # serialize: handle variable size fields in a loop
Packit 071ada
        if 'serialize' == context:
Packit 071ada
            if not self.is_switch and not self.c_var_followed_by_fixed_fields:
Packit 071ada
                if len(wire_fields)>0:
Packit 071ada
                    _c('    *xcb_out = *_aux;')
Packit 071ada
            # copy variable size fields into the buffer
Packit 071ada
            if variable_size_fields > 0:
Packit 071ada
                # xcb_out padding
Packit 071ada
                if not self.is_switch and not self.c_var_followed_by_fixed_fields:
Packit 071ada
                    _c('    xcb_tmp = (char*)++xcb_out;')
Packit 071ada
                    _c('    xcb_tmp += xcb_out_pad;')
Packit 071ada
                else:
Packit 071ada
                    _c('    xcb_tmp = xcb_out;')
Packit 071ada
Packit 071ada
                # variable sized fields
Packit 071ada
                _c('    for(i=0; i
Packit 071ada
                _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
Packit 071ada
                _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
Packit 071ada
                _c('        if (0 != xcb_parts[i].iov_len)')
Packit 071ada
                _c('            xcb_tmp += xcb_parts[i].iov_len;')
Packit 071ada
                _c('    }')
Packit 071ada
Packit 071ada
        # unserialize: assign variable size fields individually
Packit 071ada
        if 'unserialize' == context:
Packit 071ada
            _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
Packit 071ada
            param_fields.reverse()
Packit 071ada
            for field in param_fields:
Packit 071ada
                if not field.type.fixed_size():
Packit 071ada
                    _c('    xcb_tmp -= %s_len;', field.c_field_name)
Packit 071ada
                    _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
Packit 071ada
            _c('    *%s = xcb_out;', aux_ptr)
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
    _c('    return xcb_buffer_len;')
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
def _c_iterator_get_end(field, accum):
Packit 071ada
    '''
Packit 071ada
    Figures out what C code is needed to find the end of a variable-length structure field.
Packit 071ada
    For nested structures, recurses into its last variable-sized field.
Packit 071ada
    For lists, calls the end function
Packit 071ada
    '''
Packit 071ada
    if field.type.is_container:
Packit 071ada
        accum = field.c_accessor_name + '(' + accum + ')'
Packit 071ada
        return _c_iterator_get_end(field.type.last_varsized_field, accum)
Packit 071ada
    if field.type.is_list:
Packit 071ada
        # XXX we can always use the first way
Packit 071ada
        if field.type.member.is_simple:
Packit 071ada
            return field.c_end_name + '(' + accum + ')'
Packit 071ada
        else:
Packit 071ada
            return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
Packit 071ada
Packit 071ada
def _c_iterator(self, name):
Packit 071ada
    '''
Packit 071ada
    Declares the iterator structure and next/end functions for a given type.
Packit 071ada
    '''
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * @brief %s', self.c_iterator_type)
Packit 071ada
    _h(' **/')
Packit 071ada
    _h('typedef struct %s {', self.c_iterator_type)
Packit 071ada
    _h('    %s *data;', self.c_type)
Packit 071ada
    _h('    int%s rem;', ' ' * (len(self.c_type) - 2))
Packit 071ada
    _h('    int%s index;', ' ' * (len(self.c_type) - 2))
Packit 071ada
    # add additional params of the type "self" as fields to the iterator struct
Packit 071ada
    # so that they can be passed to the sizeof-function by the iterator's next-function
Packit 071ada
    params = _c_get_additional_type_params(self)
Packit 071ada
    for param in params:
Packit 071ada
        _h('    %s%s %s; /**<  */',
Packit 071ada
            param[0],
Packit 071ada
            ' ' * (len(self.c_type) + 1 - len(param[0])),
Packit 071ada
            param[2])
Packit 071ada
    _h('} %s;', self.c_iterator_type)
Packit 071ada
Packit 071ada
    _h_setlevel(1)
Packit 071ada
    _c_setlevel(1)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * Get the next element of the iterator')
Packit 071ada
    _h(' * @param i Pointer to a %s', self.c_iterator_type)
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * Get the next element in the iterator. The member rem is')
Packit 071ada
    _h(' * decreased by one. The member data points to the next')
Packit 071ada
    _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
Packit 071ada
    _h(' */')
Packit 071ada
    _c('')
Packit 071ada
    _hc('void')
Packit 071ada
    _h('%s (%s *i);', self.c_next_name, self.c_iterator_type)
Packit 071ada
    _c('%s (%s *i)', self.c_next_name, self.c_iterator_type)
Packit 071ada
    _c('{')
Packit 071ada
Packit 071ada
    if not self.fixed_size():
Packit 071ada
        _c('    %s *R = i->data;', self.c_type)
Packit 071ada
Packit 071ada
        if self.is_union:
Packit 071ada
            # FIXME - how to determine the size of a variable size union??
Packit 071ada
            _c('    /* FIXME - determine the size of the union %s */', self.c_type)
Packit 071ada
        else:
Packit 071ada
            if self.c_need_sizeof:
Packit 071ada
                # compute the string of additional arguments for the sizeof-function
Packit 071ada
                additional_args = ''
Packit 071ada
                for param in params:
Packit 071ada
                    additional_args += ', i->' + param[2]
Packit 071ada
Packit 071ada
                _c('    xcb_generic_iterator_t child;')
Packit 071ada
                _c('    child.data = (%s *)(((char *)R) + %s(R%s));',
Packit 071ada
                   self.c_type, self.c_sizeof_name, additional_args)
Packit 071ada
                _c('    i->index = (char *) child.data - (char *) i->data;')
Packit 071ada
            else:
Packit 071ada
                _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
Packit 071ada
                _c('    i->index = child.index;')
Packit 071ada
            _c('    --i->rem;')
Packit 071ada
            _c('    i->data = (%s *) child.data;', self.c_type)
Packit 071ada
Packit 071ada
    else:
Packit 071ada
        _c('    --i->rem;')
Packit 071ada
        _c('    ++i->data;')
Packit 071ada
        _c('    i->index += sizeof(%s);', self.c_type)
Packit 071ada
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * Return the iterator pointing to the last element')
Packit 071ada
    _h(' * @param i An %s', self.c_iterator_type)
Packit 071ada
    _h(' * @return  The iterator pointing to the last element')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * Set the current element in the iterator to the last element.')
Packit 071ada
    _h(' * The member rem is set to 0. The member data points to the')
Packit 071ada
    _h(' * last element.')
Packit 071ada
    _h(' */')
Packit 071ada
    _c('')
Packit 071ada
    _hc('xcb_generic_iterator_t')
Packit 071ada
    _h('%s (%s i);', self.c_end_name, self.c_iterator_type)
Packit 071ada
    _c('%s (%s i)', self.c_end_name, self.c_iterator_type)
Packit 071ada
    _c('{')
Packit 071ada
    _c('    xcb_generic_iterator_t ret;')
Packit 071ada
Packit 071ada
    if self.fixed_size():
Packit 071ada
        _c('    ret.data = i.data + i.rem;')
Packit 071ada
        _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
Packit 071ada
        _c('    ret.rem = 0;')
Packit 071ada
    else:
Packit 071ada
        _c('    while(i.rem > 0)')
Packit 071ada
        _c('        %s(&i);', self.c_next_name)
Packit 071ada
        _c('    ret.data = i.data;')
Packit 071ada
        _c('    ret.rem = i.rem;')
Packit 071ada
        _c('    ret.index = i.index;')
Packit 071ada
Packit 071ada
    _c('    return ret;')
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
def _c_accessor_get_length(expr, field_mapping=None):
Packit 071ada
    '''
Packit 071ada
    Figures out what C code is needed to get a length field.
Packit 071ada
    The field_mapping parameter can be used to change the absolute name of a length field.
Packit 071ada
    For fields that follow a variable-length field, use the accessor.
Packit 071ada
    Otherwise, just reference the structure field directly.
Packit 071ada
    '''
Packit 071ada
Packit 071ada
    lenfield_name = expr.lenfield_name
Packit 071ada
    if lenfield_name is not None:
Packit 071ada
        if field_mapping is not None:
Packit 071ada
            lenfield_name = field_mapping[lenfield_name][0]
Packit 071ada
Packit 071ada
    if expr.lenfield_name is not None:
Packit 071ada
        return lenfield_name
Packit 071ada
    else:
Packit 071ada
        return str(expr.nmemb)
Packit 071ada
Packit 071ada
def _c_accessor_get_expr(expr, field_mapping):
Packit 071ada
    '''
Packit 071ada
    Figures out what C code is needed to get the length of a list field.
Packit 071ada
    The field_mapping parameter can be used to change the absolute name of a length field.
Packit 071ada
    Recurses for math operations.
Packit 071ada
    Returns bitcount for value-mask fields.
Packit 071ada
    Otherwise, uses the value of the length field.
Packit 071ada
    '''
Packit 071ada
    lenexp = _c_accessor_get_length(expr, field_mapping)
Packit 071ada
Packit 071ada
    if expr.op == '~':
Packit 071ada
        return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
Packit 071ada
    elif expr.op == 'popcount':
Packit 071ada
        return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
Packit 071ada
    elif expr.op == 'enumref':
Packit 071ada
        enum_name = expr.lenfield_type.name
Packit 071ada
        constant_name = expr.lenfield_name
Packit 071ada
        c_name = _n(enum_name + (constant_name,)).upper()
Packit 071ada
        return c_name
Packit 071ada
    elif expr.op == 'sumof':
Packit 071ada
        # locate the referenced list object
Packit 071ada
        field = expr.lenfield
Packit 071ada
        list_name = field_mapping[field.c_field_name][0]
Packit 071ada
        c_length_func = "%s(%s)" % (field.c_length_name, list_name)
Packit 071ada
        c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
Packit 071ada
        # create explicit code for computing the sum.
Packit 071ada
        # This works for all C-types which can be added to int64_t with +=
Packit 071ada
        _c_pre.start()
Packit 071ada
        lengthvar = _c_pre.get_tempvarname()
Packit 071ada
        loopvar = _c_pre.get_tempvarname()
Packit 071ada
        sumvar = _c_pre.get_tempvarname()
Packit 071ada
        listvar = _c_pre.get_tempvarname()
Packit 071ada
        _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
Packit 071ada
        _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
Packit 071ada
        _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
Packit 071ada
        _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
Packit 071ada
        _c_pre.code("/* sumof start */")
Packit 071ada
        _c_pre.code("%s = %s;", lengthvar, c_length_func)
Packit 071ada
        _c_pre.code("%s = 0;", sumvar)
Packit 071ada
        _c_pre.code("%s = %s;", listvar, list_name)
Packit 071ada
        _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
Packit 071ada
        _c_pre.indent()
Packit 071ada
Packit 071ada
        # define and set xcb_listelement, so that it can be used by
Packit 071ada
        # listelement-ref expressions.
Packit 071ada
        if expr.contains_listelement_ref:
Packit 071ada
            _c_pre.code(
Packit 071ada
                "const %s *xcb_listelement = %s;",
Packit 071ada
                field.c_field_type, listvar)
Packit 071ada
Packit 071ada
        # summation
Packit 071ada
        if expr.rhs is None:
Packit 071ada
            _c_pre.code("%s += *%s;", sumvar, listvar)
Packit 071ada
        else:
Packit 071ada
            # sumof has a nested expression which has to be evaluated in
Packit 071ada
            # the context of this list element
Packit 071ada
Packit 071ada
            # field mapping for the subexpression needs to include
Packit 071ada
            # the fields of the list-member type
Packit 071ada
            scoped_field_mapping = field_mapping.copy()
Packit 071ada
            if not field.type.member.is_simple:
Packit 071ada
                scoped_field_mapping.update(
Packit 071ada
                    _c_helper_field_mapping(
Packit 071ada
                        field.type.member,
Packit 071ada
                        [(listvar, '->', field.type.member)]))
Packit 071ada
Packit 071ada
            # cause pre-code of the subexpression be added right here
Packit 071ada
            _c_pre.end()
Packit 071ada
            # compute the subexpression
Packit 071ada
            rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
Packit 071ada
            # resume with our code
Packit 071ada
            _c_pre.start()
Packit 071ada
            # output the summation expression
Packit 071ada
            _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
Packit 071ada
Packit 071ada
        _c_pre.code("%s++;", listvar)
Packit 071ada
        _c_pre.pop_indent()
Packit 071ada
        _c_pre.code("}")
Packit 071ada
        _c_pre.code("/* sumof end. Result is in %s */", sumvar)
Packit 071ada
        _c_pre.end()
Packit 071ada
        return sumvar
Packit 071ada
    elif expr.op == 'listelement-ref':
Packit 071ada
        return '(*xcb_listelement)'
Packit 071ada
    elif expr.op != None and expr.op != 'calculate_len':
Packit 071ada
        return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
Packit 071ada
                ' ' + expr.op + ' ' +
Packit 071ada
                _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
Packit 071ada
    elif expr.bitfield:
Packit 071ada
        return 'xcb_popcount(' + lenexp + ')'
Packit 071ada
    else:
Packit 071ada
        return lenexp
Packit 071ada
Packit 071ada
def type_pad_type(type):
Packit 071ada
    if type == 'void':
Packit 071ada
        return 'char'
Packit 071ada
    return type
Packit 071ada
Packit 071ada
def _c_accessors_field(self, field):
Packit 071ada
    '''
Packit 071ada
    Declares the accessor functions for a non-list field that follows a variable-length field.
Packit 071ada
    '''
Packit 071ada
    c_type = self.c_type
Packit 071ada
Packit 071ada
    # special case: switch
Packit 071ada
    switch_obj = self if self.is_switch else None
Packit 071ada
    if self.is_case_or_bitcase:
Packit 071ada
        switch_obj = self.parents[-1]
Packit 071ada
    if switch_obj is not None:
Packit 071ada
        c_type = switch_obj.c_type
Packit 071ada
Packit 071ada
    if field.type.is_simple:
Packit 071ada
        _hc('')
Packit 071ada
        _hc('%s', field.c_field_type)
Packit 071ada
        _h('%s (const %s *R);', field.c_accessor_name, c_type)
Packit 071ada
        _c('%s (const %s *R)', field.c_accessor_name, c_type)
Packit 071ada
        _c('{')
Packit 071ada
        if field.prev_varsized_field is None:
Packit 071ada
            _c('    return (%s *) (R + 1);', field.c_field_type)
Packit 071ada
        else:
Packit 071ada
            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
Packit 071ada
            _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
Packit 071ada
               field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
Packit 071ada
        _c('}')
Packit 071ada
    else:
Packit 071ada
        _hc('')
Packit 071ada
        if field.type.is_switch and switch_obj is None:
Packit 071ada
            return_type = 'void *'
Packit 071ada
        else:
Packit 071ada
            return_type = '%s *' % field.c_field_type
Packit 071ada
Packit 071ada
        _hc(return_type)
Packit 071ada
        _h('%s (const %s *R);', field.c_accessor_name, c_type)
Packit 071ada
        _c('%s (const %s *R)', field.c_accessor_name, c_type)
Packit 071ada
        _c('{')
Packit 071ada
        if field.prev_varsized_field is None:
Packit 071ada
            _c('    return (%s) (R + 1);', return_type)
Packit 071ada
            # note: the special case 'variable fields followed by fixed size fields'
Packit 071ada
            #       is not of any consequence here, since the ordering gets
Packit 071ada
            #       'corrected' in the reply function
Packit 071ada
        else:
Packit 071ada
            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
Packit 071ada
            _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
Packit 071ada
               return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
Packit 071ada
        _c('}')
Packit 071ada
Packit 071ada
Packit 071ada
def _c_accessors_list(self, field):
Packit 071ada
    '''
Packit 071ada
    Declares the accessor functions for a list field.
Packit 071ada
    Declares a direct-accessor function only if the list members are fixed size.
Packit 071ada
    Declares length and get-iterator functions always.
Packit 071ada
    '''
Packit 071ada
Packit 071ada
    def get_align_pad(field):
Packit 071ada
        prev = field.prev_varsized_field
Packit 071ada
        prev_prev = field.prev_varsized_field.prev_varsized_field
Packit 071ada
Packit 071ada
        if prev.type.is_pad and prev.type.align > 0 and prev_prev is not None:
Packit 071ada
            return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
Packit 071ada
        else:
Packit 071ada
            return (prev, None)
Packit 071ada
Packit 071ada
    list = field.type
Packit 071ada
    c_type = self.c_type
Packit 071ada
Packit 071ada
    # special case: switch
Packit 071ada
    # in case of switch, 2 params have to be supplied to certain accessor functions:
Packit 071ada
    #   1. the anchestor object (request or reply)
Packit 071ada
    #   2. the (anchestor) switch object
Packit 071ada
    # the reason is that switch is either a child of a request/reply or nested in another switch,
Packit 071ada
    # so whenever we need to access a length field, we might need to refer to some anchestor type
Packit 071ada
    switch_obj = self if self.is_switch else None
Packit 071ada
    if self.is_case_or_bitcase:
Packit 071ada
        switch_obj = self.parents[-1]
Packit 071ada
    if switch_obj is not None:
Packit 071ada
        c_type = switch_obj.c_type
Packit 071ada
Packit 071ada
    params = []
Packit 071ada
    fields = {}
Packit 071ada
    parents = self.parents if hasattr(self, 'parents') else [self]
Packit 071ada
    # 'R': parents[0] is always the 'toplevel' container type
Packit 071ada
    params.append(('const %s *R' % parents[0].c_type, parents[0]))
Packit 071ada
    fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
Packit 071ada
    # auxiliary object for 'R' parameters
Packit 071ada
    R_obj = parents[0]
Packit 071ada
Packit 071ada
    if switch_obj is not None:
Packit 071ada
        # now look where the fields are defined that are needed to evaluate
Packit 071ada
        # the switch expr, and store the parent objects in accessor_params and
Packit 071ada
        # the fields in switch_fields
Packit 071ada
Packit 071ada
        # 'S': name for the 'toplevel' switch
Packit 071ada
        toplevel_switch = parents[1]
Packit 071ada
        params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
Packit 071ada
        fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
Packit 071ada
Packit 071ada
        # initialize prefix for everything "below" S
Packit 071ada
        prefix = [('S', '->', toplevel_switch)]
Packit 071ada
Packit 071ada
        # look for fields in the remaining containers
Packit 071ada
        for p in parents[2:] + [self]:
Packit 071ada
            # the separator between parent and child is always '.' here,
Packit 071ada
            # because of nested switch statements
Packit 071ada
            if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
Packit 071ada
                prefix.append((p.name[-1], '.', p))
Packit 071ada
            fields.update(_c_helper_field_mapping(p, prefix, flat=True))
Packit 071ada
Packit 071ada
        # auxiliary object for 'S' parameter
Packit 071ada
        S_obj = parents[1]
Packit 071ada
Packit 071ada
    # for functions generated below:
Packit 071ada
    # * compute list of additional parameters which contains as parameter
Packit 071ada
    #   any expr fields that cannot be resolved within self and descendants.
Packit 071ada
    # * and make sure that they are accessed without prefix within the function.
Packit 071ada
    unresolved_fields = resolve_expr_fields_list(list, parents)
Packit 071ada
    additional_params = []
Packit 071ada
    additional_param_names = set();
Packit 071ada
    for f in unresolved_fields:
Packit 071ada
        if f.c_field_name not in additional_param_names:
Packit 071ada
            # add to the list of additional params
Packit 071ada
            additional_params.append((f.c_field_type, f.c_field_name));
Packit 071ada
            # make sure that the param is accessed without prefix within the function
Packit 071ada
            fields[ f.c_field_name ] = (f.c_field_name, f)
Packit 071ada
Packit 071ada
    # internal function to compute the parameterlist with given indentation
Packit 071ada
    # such that the formatting of the additional parameters is consistent with
Packit 071ada
    # the other parameters.
Packit 071ada
    def additional_params_to_str(indent):
Packit 071ada
        if len(additional_params) == 0:
Packit 071ada
            return ''
Packit 071ada
        else:
Packit 071ada
            return (',\n' + indent).join([''] + ['%s %s' % p for p in additional_params])
Packit 071ada
Packit 071ada
    _h_setlevel(1)
Packit 071ada
    _c_setlevel(1)
Packit 071ada
    if list.member.fixed_size():
Packit 071ada
        idx = 1 if switch_obj is not None else 0
Packit 071ada
        _hc('')
Packit 071ada
        _hc('%s *', field.c_field_type)
Packit 071ada
Packit 071ada
        _h('%s (%s);', field.c_accessor_name, params[idx][0])
Packit 071ada
        _c('%s (%s)', field.c_accessor_name, params[idx][0])
Packit 071ada
Packit 071ada
        _c('{')
Packit 071ada
        if switch_obj is not None:
Packit 071ada
            _c('    return %s;', fields[field.c_field_name][0])
Packit 071ada
        elif field.prev_varsized_field is None:
Packit 071ada
            _c('    return (%s *) (R + 1);', field.c_field_type)
Packit 071ada
        else:
Packit 071ada
            (prev_varsized_field, align_pad) = get_align_pad(field)
Packit 071ada
Packit 071ada
            if align_pad is None:
Packit 071ada
                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
Packit 071ada
                    type_pad_type(field.first_field_after_varsized.type.c_type))
Packit 071ada
Packit 071ada
            _c('    xcb_generic_iterator_t prev = %s;',
Packit 071ada
                _c_iterator_get_end(prev_varsized_field, 'R'))
Packit 071ada
            _c('    return (%s *) ((char *) prev.data + %s + %d);',
Packit 071ada
               field.c_field_type, align_pad, field.prev_varsized_offset)
Packit 071ada
        _c('}')
Packit 071ada
Packit 071ada
    _hc('')
Packit 071ada
    _hc('int')
Packit 071ada
    spacing = ' '*(len(field.c_length_name)+2)
Packit 071ada
    add_param_str = additional_params_to_str(spacing)
Packit 071ada
    if switch_obj is not None:
Packit 071ada
        _hc('%s (const %s *R,', field.c_length_name, R_obj.c_type)
Packit 071ada
        _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str)
Packit 071ada
        _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str)
Packit 071ada
    else:
Packit 071ada
        _h('%s (const %s *R%s);', field.c_length_name, c_type, add_param_str)
Packit 071ada
        _c('%s (const %s *R%s)', field.c_length_name, c_type, add_param_str)
Packit 071ada
    _c('{')
Packit 071ada
Packit 071ada
    def get_length():
Packit 071ada
        if field.type.expr.op == 'calculate_len':
Packit 071ada
            if field.type.member.fixed_size():
Packit 071ada
                if field.prev_varsized_field is None:
Packit 071ada
                    # the list is directly after the fixed size part of the
Packit 071ada
                    # request: simply subtract the size of the fixed-size part
Packit 071ada
                    # from the request size and divide that by the member size
Packit 071ada
                    return '(((R->length * 4) - sizeof('+ self.c_type + '))/'+'sizeof('+field.type.member.c_wiretype+'))'
Packit 071ada
                else:
Packit 071ada
                    # use the accessor to get the start of the list, then
Packit 071ada
                    # compute the length of it by subtracting it from
Packit 071ada
                    # the adress of the first byte after the end of the
Packit 071ada
                    # request
Packit 071ada
                    after_end_of_request = '(((char*)R) + R->length * 4)'
Packit 071ada
                    start_of_list = '%s(R)' % (field.c_accessor_name)
Packit 071ada
                    bytesize_of_list = '%s - (char*)(%s)' % (after_end_of_request, start_of_list)
Packit 071ada
                    return '(%s) / sizeof(%s)' % (bytesize_of_list, field.type.member.c_wiretype)
Packit 071ada
            else:
Packit 071ada
                raise Exception(
Packit 071ada
                    "lengthless lists with varsized members are not supported. Fieldname '%s'"
Packit 071ada
                    %
Packit 071ada
                    (field.c_field_name)
Packit 071ada
                );
Packit 071ada
        else:
Packit 071ada
            return _c_accessor_get_expr(field.type.expr, fields)
Packit 071ada
Packit 071ada
    _c('    return %s;', get_length())
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
    if field.type.member.is_simple:
Packit 071ada
        _hc('')
Packit 071ada
        _hc('xcb_generic_iterator_t')
Packit 071ada
        spacing = ' '*(len(field.c_end_name)+2)
Packit 071ada
        add_param_str = additional_params_to_str(spacing)
Packit 071ada
        if switch_obj is not None:
Packit 071ada
            _hc('%s (const %s *R,', field.c_end_name, R_obj.c_type)
Packit 071ada
            _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str)
Packit 071ada
            _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str)
Packit 071ada
        else:
Packit 071ada
            _h('%s (const %s *R%s);', field.c_end_name, c_type, add_param_str)
Packit 071ada
            _c('%s (const %s *R%s)', field.c_end_name, c_type, add_param_str)
Packit 071ada
        _c('{')
Packit 071ada
        _c('    xcb_generic_iterator_t i;')
Packit 071ada
Packit 071ada
        param = 'R' if switch_obj is None else 'S'
Packit 071ada
        if switch_obj is not None:
Packit 071ada
            _c('    i.data = %s + %s;', fields[field.c_field_name][0],
Packit 071ada
               get_length())
Packit 071ada
        elif field.prev_varsized_field == None:
Packit 071ada
            _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
Packit 071ada
               get_length())
Packit 071ada
        else:
Packit 071ada
            (prev_varsized_field, align_pad) = get_align_pad(field)
Packit 071ada
Packit 071ada
            if align_pad is None:
Packit 071ada
                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
Packit 071ada
                    type_pad_type(field.first_field_after_varsized.type.c_type))
Packit 071ada
Packit 071ada
            _c('    xcb_generic_iterator_t prev = %s;',
Packit 071ada
                _c_iterator_get_end(prev_varsized_field, 'R'))
Packit 071ada
            _c('    i.data = ((%s *) ((char*) prev.data + %s)) + (%s);',
Packit 071ada
                field.type.c_wiretype, align_pad,
Packit 071ada
                get_length())
Packit 071ada
Packit 071ada
        _c('    i.rem = 0;')
Packit 071ada
        _c('    i.index = (char *) i.data - (char *) %s;', param)
Packit 071ada
        _c('    return i;')
Packit 071ada
        _c('}')
Packit 071ada
Packit 071ada
    else:
Packit 071ada
        _hc('')
Packit 071ada
        _hc('%s', field.c_iterator_type)
Packit 071ada
        spacing = ' '*(len(field.c_iterator_name)+2)
Packit 071ada
        if switch_obj is not None:
Packit 071ada
            _hc('%s (const %s *R,', field.c_iterator_name, R_obj.c_type)
Packit 071ada
            _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str)
Packit 071ada
            _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str)
Packit 071ada
        else:
Packit 071ada
            _h('%s (const %s *R%s);', field.c_iterator_name, c_type, add_param_str)
Packit 071ada
            _c('%s (const %s *R%s)', field.c_iterator_name, c_type, add_param_str)
Packit 071ada
        _c('{')
Packit 071ada
        _c('    %s i;', field.c_iterator_type)
Packit 071ada
Packit 071ada
        _c_pre.start()
Packit 071ada
        length_expr_str = get_length()
Packit 071ada
Packit 071ada
        if switch_obj is not None:
Packit 071ada
            _c_pre.end()
Packit 071ada
            _c('    i.data = %s;', fields[field.c_field_name][0])
Packit 071ada
            _c('    i.rem = %s;', length_expr_str)
Packit 071ada
        elif field.prev_varsized_field == None:
Packit 071ada
            _c_pre.end()
Packit 071ada
            _c('    i.data = (%s *) (R + 1);', field.c_field_type)
Packit 071ada
        else:
Packit 071ada
            (prev_varsized_field, align_pad) = get_align_pad(field)
Packit 071ada
Packit 071ada
            if align_pad is None:
Packit 071ada
                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
Packit 071ada
                    type_pad_type(field.c_field_type))
Packit 071ada
Packit 071ada
            _c('    xcb_generic_iterator_t prev = %s;',
Packit 071ada
                _c_iterator_get_end(prev_varsized_field, 'R'))
Packit 071ada
            _c_pre.end()
Packit 071ada
            _c('    i.data = (%s *) ((char *) prev.data + %s);',
Packit 071ada
                field.c_field_type, align_pad)
Packit 071ada
Packit 071ada
        if switch_obj is None:
Packit 071ada
            _c('    i.rem = %s;', length_expr_str)
Packit 071ada
        _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
Packit 071ada
Packit 071ada
        # initialize additional iterator fields which are derived from
Packit 071ada
        # additional type parameters for the list member type.
Packit 071ada
        additional_iter_fields = _c_get_additional_type_params(field.type.member)
Packit 071ada
        for iter_field in additional_iter_fields:
Packit 071ada
             _c('    i.%s = %s;', iter_field[2], fields[iter_field[2]][0])
Packit 071ada
Packit 071ada
        _c('    return i;')
Packit 071ada
        _c('}')
Packit 071ada
Packit 071ada
def _c_accessors(self, name, base):
Packit 071ada
    '''
Packit 071ada
    Declares the accessor functions for the fields of a structure.
Packit 071ada
    '''
Packit 071ada
    # no accessors for switch itself -
Packit 071ada
    # switch always needs to be unpacked explicitly
Packit 071ada
#    if self.is_switch:
Packit 071ada
#        pass
Packit 071ada
#    else:
Packit 071ada
    if True:
Packit 071ada
        for field in self.fields:
Packit 071ada
            if not field.type.is_pad:
Packit 071ada
                if _c_field_needs_list_accessor(field):
Packit 071ada
                    _c_accessors_list(self, field)
Packit 071ada
                elif _c_field_needs_field_accessor(field):
Packit 071ada
                    _c_accessors_field(self, field)
Packit 071ada
Packit 071ada
def c_simple(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles cardinal type declarations.
Packit 071ada
    These are types which are typedef'd to one of the CARDx's, char, float, etc.
Packit 071ada
    '''
Packit 071ada
    _c_type_setup(self, name, ())
Packit 071ada
Packit 071ada
    if (self.name != name):
Packit 071ada
        # Typedef
Packit 071ada
        _h_setlevel(0)
Packit 071ada
        my_name = _t(name)
Packit 071ada
        _h('')
Packit 071ada
        _h('typedef %s %s;', _t(self.name), my_name)
Packit 071ada
Packit 071ada
        # Iterator
Packit 071ada
        _c_iterator(self, name)
Packit 071ada
Packit 071ada
def _c_complex(self, force_packed = False):
Packit 071ada
    '''
Packit 071ada
    Helper function for handling all structure types.
Packit 071ada
    Called for all structs, requests, replies, events, errors.
Packit 071ada
    '''
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * @brief %s', self.c_type)
Packit 071ada
    _h(' **/')
Packit 071ada
    _h('typedef %s %s {', self.c_container, self.c_type)
Packit 071ada
Packit 071ada
    struct_fields = []
Packit 071ada
    maxtypelen = 0
Packit 071ada
Packit 071ada
    for field in self.fields:
Packit 071ada
        if field.wire and (field.type.fixed_size() or self.is_switch or self.is_union):
Packit 071ada
            struct_fields.append(field)
Packit 071ada
Packit 071ada
    for field in struct_fields:
Packit 071ada
        length = len(field.c_field_type)
Packit 071ada
        # account for '*' pointer_spec
Packit 071ada
        if not field.type.fixed_size() and not self.is_union:
Packit 071ada
            length += 1
Packit 071ada
        maxtypelen = max(maxtypelen, length)
Packit 071ada
Packit 071ada
    def _c_complex_field(self, field, space=''):
Packit 071ada
        if (field.type.fixed_size() or self.is_union or
Packit 071ada
            # in case of switch with switch children, don't make the field a pointer
Packit 071ada
            # necessary for unserialize to work
Packit 071ada
            (self.is_switch and field.type.is_switch)):
Packit 071ada
            spacing = ' ' * (maxtypelen - len(field.c_field_type))
Packit 071ada
            _h('%s    %s%s %s%s;', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
Packit 071ada
        elif (not field.type.is_pad) or field.type.serialize:
Packit 071ada
            # serialize everything except pads (unless serialization of pads is enforced by serialize=true)
Packit 071ada
            spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
Packit 071ada
            _h('%s    %s%s *%s%s;', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
Packit 071ada
Packit 071ada
    if not self.is_switch:
Packit 071ada
        for field in struct_fields:
Packit 071ada
            _c_complex_field(self, field)
Packit 071ada
    else:
Packit 071ada
        for b in self.bitcases:
Packit 071ada
            space = ''
Packit 071ada
            if b.type.has_name:
Packit 071ada
                _h('    struct {')
Packit 071ada
                space = '    '
Packit 071ada
            for field in b.type.fields:
Packit 071ada
                _c_complex_field(self, field, space)
Packit 071ada
            if b.type.has_name:
Packit 071ada
                _h('    } %s;', b.c_field_name)
Packit 071ada
Packit 071ada
    _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
Packit 071ada
Packit 071ada
def c_struct(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles structure declarations.
Packit 071ada
    '''
Packit 071ada
    _c_type_setup(self, name, ())
Packit 071ada
    _c_complex(self)
Packit 071ada
    _c_accessors(self, name, name)
Packit 071ada
    _c_iterator(self, name)
Packit 071ada
Packit 071ada
def c_union(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles union declarations.
Packit 071ada
    '''
Packit 071ada
    _c_type_setup(self, name, ())
Packit 071ada
    _c_complex(self)
Packit 071ada
    _c_iterator(self, name)
Packit 071ada
Packit 071ada
def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False):
Packit 071ada
    '''
Packit 071ada
    Declares a request function.
Packit 071ada
    '''
Packit 071ada
Packit 071ada
    # Four stunningly confusing possibilities here:
Packit 071ada
    #
Packit 071ada
    #   Void            Non-void
Packit 071ada
    # ------------------------------
Packit 071ada
    # "req"            "req"
Packit 071ada
    # 0 flag           CHECKED flag   Normal Mode
Packit 071ada
    # void_cookie      req_cookie
Packit 071ada
    # ------------------------------
Packit 071ada
    # "req_checked"    "req_unchecked"
Packit 071ada
    # CHECKED flag     0 flag         Abnormal Mode
Packit 071ada
    # void_cookie      req_cookie
Packit 071ada
    # ------------------------------
Packit 071ada
Packit 071ada
Packit 071ada
    # Whether we are _checked or _unchecked
Packit 071ada
    checked = void and not regular
Packit 071ada
    unchecked = not void and not regular
Packit 071ada
Packit 071ada
    # What kind of cookie we return
Packit 071ada
    func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
Packit 071ada
Packit 071ada
    # What flag is passed to xcb_request
Packit 071ada
    func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
Packit 071ada
Packit 071ada
    if reply_fds:
Packit 071ada
        if func_flags == '0':
Packit 071ada
            func_flags = 'XCB_REQUEST_REPLY_FDS'
Packit 071ada
        else:
Packit 071ada
            func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
Packit 071ada
Packit 071ada
    # Global extension id variable or NULL for xproto
Packit 071ada
    func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
Packit 071ada
Packit 071ada
    # What our function name is
Packit 071ada
    func_name = self.c_request_name if not aux else self.c_aux_name
Packit 071ada
    if checked:
Packit 071ada
        func_name = self.c_checked_name if not aux else self.c_aux_checked_name
Packit 071ada
    if unchecked:
Packit 071ada
        func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
Packit 071ada
Packit 071ada
    param_fields = []
Packit 071ada
    wire_fields = []
Packit 071ada
    maxtypelen = len('xcb_connection_t')
Packit 071ada
    serial_fields = []
Packit 071ada
    # special case: list with variable size elements
Packit 071ada
    list_with_var_size_elems = False
Packit 071ada
Packit 071ada
    for field in self.fields:
Packit 071ada
        if field.visible:
Packit 071ada
            # The field should appear as a call parameter
Packit 071ada
            param_fields.append(field)
Packit 071ada
        if field.wire and not field.auto:
Packit 071ada
            # We need to set the field up in the structure
Packit 071ada
            wire_fields.append(field)
Packit 071ada
        if field.type.c_need_serialize or field.type.c_need_sizeof:
Packit 071ada
            serial_fields.append(field)
Packit 071ada
Packit 071ada
    for field in param_fields:
Packit 071ada
        c_field_const_type = field.c_field_const_type
Packit 071ada
        if field.type.c_need_serialize and not aux:
Packit 071ada
            c_field_const_type = "const void"
Packit 071ada
        if len(c_field_const_type) > maxtypelen:
Packit 071ada
            maxtypelen = len(c_field_const_type)
Packit 071ada
        if field.type.is_list and not field.type.member.fixed_size():
Packit 071ada
            list_with_var_size_elems = True
Packit 071ada
Packit 071ada
    _h_setlevel(1)
Packit 071ada
    _c_setlevel(1)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        if self.doc.brief:
Packit 071ada
            _h(' * @brief ' + self.doc.brief)
Packit 071ada
        else:
Packit 071ada
            _h(' * No brief doc yet')
Packit 071ada
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * @param c The connection')
Packit 071ada
    param_names = [f.c_field_name for f in param_fields]
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        for field in param_fields:
Packit 071ada
            # XXX: hard-coded until we fix xproto.xml
Packit 071ada
            base_func_name = self.c_request_name if not aux else self.c_aux_name
Packit 071ada
            if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
Packit 071ada
                field.enum = 'GC'
Packit 071ada
            elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
Packit 071ada
                field.enum = 'CW'
Packit 071ada
            elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
Packit 071ada
                field.enum = 'CW'
Packit 071ada
            if field.enum:
Packit 071ada
                # XXX: why the 'xcb' prefix?
Packit 071ada
                key = ('xcb', field.enum)
Packit 071ada
Packit 071ada
                tname = _t(key)
Packit 071ada
                if namecount[tname] > 1:
Packit 071ada
                    tname = _t(key + ('enum',))
Packit 071ada
                _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
Packit 071ada
Packit 071ada
            if self.doc and field.field_name in self.doc.fields:
Packit 071ada
                desc = self.doc.fields[field.field_name]
Packit 071ada
                for name in param_names:
Packit 071ada
                    desc = desc.replace('`%s`' % name, '\\a %s' % (name))
Packit 071ada
                desc = desc.split("\n")
Packit 071ada
                desc = [line if line != '' else '\\n' for line in desc]
Packit 071ada
                _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
Packit 071ada
            # If there is no documentation yet, we simply don't generate an
Packit 071ada
            # @param tag. Doxygen will then warn about missing documentation.
Packit 071ada
Packit 071ada
    _h(' * @return A cookie')
Packit 071ada
    _h(' *')
Packit 071ada
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        if self.doc.description:
Packit 071ada
            desc = self.doc.description
Packit 071ada
            for name in param_names:
Packit 071ada
                desc = desc.replace('`%s`' % name, '\\a %s' % (name))
Packit 071ada
            desc = desc.split("\n")
Packit 071ada
            _h(' * ' + "\n * ".join(desc))
Packit 071ada
        else:
Packit 071ada
            _h(' * No description yet')
Packit 071ada
    else:
Packit 071ada
        _h(' * Delivers a request to the X server.')
Packit 071ada
    _h(' *')
Packit 071ada
    if checked:
Packit 071ada
        _h(' * This form can be used only if the request will not cause')
Packit 071ada
        _h(' * a reply to be generated. Any returned error will be')
Packit 071ada
        _h(' * saved for handling by xcb_request_check().')
Packit 071ada
    if unchecked:
Packit 071ada
        _h(' * This form can be used only if the request will cause')
Packit 071ada
        _h(' * a reply to be generated. Any returned error will be')
Packit 071ada
        _h(' * placed in the event queue.')
Packit 071ada
    _h(' */')
Packit 071ada
    _c('')
Packit 071ada
    _hc('%s', func_cookie)
Packit 071ada
Packit 071ada
    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
Packit 071ada
    comma = ',' if len(param_fields) else ');'
Packit 071ada
    _h('%s (xcb_connection_t%s *c%s', func_name, spacing, comma)
Packit 071ada
    comma = ',' if len(param_fields) else ')'
Packit 071ada
    _c('%s (xcb_connection_t%s *c%s', func_name, spacing, comma)
Packit 071ada
Packit 071ada
    func_spacing = ' ' * (len(func_name) + 2)
Packit 071ada
    count = len(param_fields)
Packit 071ada
    for field in param_fields:
Packit 071ada
        count = count - 1
Packit 071ada
        c_field_const_type = field.c_field_const_type
Packit 071ada
        c_pointer = field.c_pointer
Packit 071ada
        if field.type.c_need_serialize and not aux:
Packit 071ada
            c_field_const_type = "const void"
Packit 071ada
            c_pointer = '*'
Packit 071ada
        spacing = ' ' * (maxtypelen - len(c_field_const_type))
Packit 071ada
        comma = ',' if count else ');'
Packit 071ada
        _h('%s%s%s %s%s%s', func_spacing, c_field_const_type,
Packit 071ada
           spacing, c_pointer, field.c_field_name, comma)
Packit 071ada
        comma = ',' if count else ')'
Packit 071ada
        _c('%s%s%s %s%s%s', func_spacing, c_field_const_type,
Packit 071ada
           spacing, c_pointer, field.c_field_name, comma)
Packit 071ada
Packit 071ada
    count = 2
Packit 071ada
    if not self.c_var_followed_by_fixed_fields:
Packit 071ada
        for field in param_fields:
Packit 071ada
            if not field.type.fixed_size() and field.wire:
Packit 071ada
                count = count + 2
Packit 071ada
                if field.type.c_need_serialize:
Packit 071ada
                    # _serialize() keeps track of padding automatically
Packit 071ada
                    count -= 1
Packit 071ada
    dimension = count + 2
Packit 071ada
Packit 071ada
    _c('{')
Packit 071ada
    _c('    static const xcb_protocol_request_t xcb_req = {')
Packit 071ada
    _c('        .count = %d,', count)
Packit 071ada
    _c('        .ext = %s,', func_ext_global)
Packit 071ada
    _c('        .opcode = %s,', self.c_request_name.upper())
Packit 071ada
    _c('        .isvoid = %d', 1 if void else 0)
Packit 071ada
    _c('    };')
Packit 071ada
    _c('')
Packit 071ada
Packit 071ada
    _c('    struct iovec xcb_parts[%d];', dimension)
Packit 071ada
    _c('    %s xcb_ret;', func_cookie)
Packit 071ada
    _c('    %s xcb_out;', self.c_type)
Packit 071ada
    if self.c_var_followed_by_fixed_fields:
Packit 071ada
        _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
Packit 071ada
        _c('    void *xcb_aux = 0;')
Packit 071ada
Packit 071ada
Packit 071ada
    for idx, _ in enumerate(serial_fields):
Packit 071ada
        if aux:
Packit 071ada
            _c('    void *xcb_aux%d = 0;' % (idx))
Packit 071ada
    if list_with_var_size_elems:
Packit 071ada
        _c('    unsigned int xcb_tmp_len;')
Packit 071ada
        _c('    char *xcb_tmp;')
Packit 071ada
Packit 071ada
    num_fds_fixed = 0
Packit 071ada
    num_fds_expr = []
Packit 071ada
    for field in param_fields:
Packit 071ada
        if field.isfd:
Packit 071ada
            if not field.type.is_list:
Packit 071ada
                num_fds_fixed += 1
Packit 071ada
            else:
Packit 071ada
                num_fds_expr.append(_c_accessor_get_expr(field.type.expr, None))
Packit 071ada
Packit 071ada
    if list_with_var_size_elems or len(num_fds_expr) > 0:
Packit 071ada
        _c('    unsigned int i;')
Packit 071ada
Packit 071ada
    if num_fds_fixed > 0:
Packit 071ada
        num_fds_expr.append('%d' % (num_fds_fixed))
Packit 071ada
    if len(num_fds_expr) > 0:
Packit 071ada
        num_fds = '+'.join(num_fds_expr)
Packit 071ada
        _c('    int fds[%s];' % (num_fds))
Packit 071ada
        _c('    int fd_index = 0;')
Packit 071ada
    else:
Packit 071ada
        num_fds = None
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
Packit 071ada
    # fixed size fields
Packit 071ada
    for field in wire_fields:
Packit 071ada
        if field.type.fixed_size():
Packit 071ada
            if field.type.is_expr:
Packit 071ada
                _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
Packit 071ada
            elif field.type.is_pad:
Packit 071ada
                if field.type.nmemb == 1:
Packit 071ada
                    _c('    xcb_out.%s = 0;', field.c_field_name)
Packit 071ada
                else:
Packit 071ada
                    _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
Packit 071ada
            else:
Packit 071ada
                if field.type.nmemb == 1:
Packit 071ada
                    _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
Packit 071ada
                else:
Packit 071ada
                    _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
Packit 071ada
Packit 071ada
    def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
Packit 071ada
        serialize_args = get_serialize_params(context, type_obj,
Packit 071ada
                                              c_field_name,
Packit 071ada
                                              aux_var)[2]
Packit 071ada
        return ", ".join(a[2] for a in serialize_args)
Packit 071ada
Packit 071ada
    # calls in order to free dyn. all. memory
Packit 071ada
    free_calls = []
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
    if not self.c_var_followed_by_fixed_fields:
Packit 071ada
        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
Packit 071ada
        _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
Packit 071ada
        _c('    xcb_parts[3].iov_base = 0;')
Packit 071ada
        _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
Packit 071ada
Packit 071ada
        count = 4
Packit 071ada
Packit 071ada
        for field in param_fields:
Packit 071ada
            if field.wire and not field.type.fixed_size():
Packit 071ada
                _c('    /* %s %s */', field.type.c_type, field.c_field_name)
Packit 071ada
                # default: simple cast to char *
Packit 071ada
                if not field.type.c_need_serialize and not field.type.c_need_sizeof:
Packit 071ada
                    _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
Packit 071ada
                    if field.type.is_list:
Packit 071ada
                        if field.type.member.fixed_size():
Packit 071ada
                            if field.type.expr.op == 'calculate_len':
Packit 071ada
                                lenfield = field.type.expr.lenfield_name
Packit 071ada
                            else:
Packit 071ada
                                lenfield = _c_accessor_get_expr(field.type.expr, None)
Packit 071ada
Packit 071ada
                            _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, lenfield,
Packit 071ada
                                        field.type.member.c_wiretype)
Packit 071ada
                        else:
Packit 071ada
                            list_length = _c_accessor_get_expr(field.type.expr, None)
Packit 071ada
                            length = ''
Packit 071ada
Packit 071ada
                            _c("    xcb_parts[%d].iov_len = 0;" % count)
Packit 071ada
                            _c("    xcb_tmp = (char *)%s;", field.c_field_name)
Packit 071ada
                            _c("    for(i=0; i<%s; i++) {" % list_length)
Packit 071ada
                            _c("        xcb_tmp_len = %s(xcb_tmp);" %
Packit 071ada
                                              (field.type.c_sizeof_name))
Packit 071ada
                            _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
Packit 071ada
                            _c("        xcb_tmp += xcb_tmp_len;")
Packit 071ada
                            _c("    }")
Packit 071ada
                    else:
Packit 071ada
                        # not supposed to happen
Packit 071ada
                        raise Exception("unhandled variable size field %s" % field.c_field_name)
Packit 071ada
                else:
Packit 071ada
                    if not aux:
Packit 071ada
                        _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
Packit 071ada
                    idx = serial_fields.index(field)
Packit 071ada
                    aux_var = '&xcb_aux%d' % idx
Packit 071ada
                    context = 'serialize' if aux else 'sizeof'
Packit 071ada
                    _c('    xcb_parts[%d].iov_len =', count)
Packit 071ada
                    if aux:
Packit 071ada
                        serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
Packit 071ada
                        _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
Packit 071ada
                        _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
Packit 071ada
                        free_calls.append('    free(xcb_aux%d);' % idx)
Packit 071ada
                    else:
Packit 071ada
                        serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
Packit 071ada
                        func_name = field.type.c_sizeof_name
Packit 071ada
                        _c('      %s (%s);', func_name, serialize_args)
Packit 071ada
Packit 071ada
                count += 1
Packit 071ada
                if not (field.type.c_need_serialize or field.type.c_need_sizeof):
Packit 071ada
                    # the _serialize() function keeps track of padding automatically
Packit 071ada
                    _c('    xcb_parts[%d].iov_base = 0;', count)
Packit 071ada
                    _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
Packit 071ada
                    count += 1
Packit 071ada
Packit 071ada
    # elif self.c_var_followed_by_fixed_fields:
Packit 071ada
    else:
Packit 071ada
        _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
Packit 071ada
        # request header: opcodes + length
Packit 071ada
        _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
Packit 071ada
        count += 1
Packit 071ada
        # call _serialize()
Packit 071ada
        buffer_var = '&xcb_aux'
Packit 071ada
        serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
Packit 071ada
        _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
Packit 071ada
        _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
Packit 071ada
        free_calls.append('    free(xcb_aux);')
Packit 071ada
        # no padding necessary - _serialize() keeps track of padding automatically
Packit 071ada
Packit 071ada
    _c('')
Packit 071ada
    for field in param_fields:
Packit 071ada
        if field.isfd:
Packit 071ada
            if not field.type.is_list:
Packit 071ada
                _c('    fds[fd_index++] = %s;', field.c_field_name)
Packit 071ada
            else:
Packit 071ada
                _c('    for (i = 0; i < %s; i++)', _c_accessor_get_expr(field.type.expr, None))
Packit 071ada
                _c('        fds[fd_index++] = %s[i];', field.c_field_name)
Packit 071ada
Packit 071ada
    if not num_fds:
Packit 071ada
        _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
Packit 071ada
    else:
Packit 071ada
        _c('    xcb_ret.sequence = xcb_send_request_with_fds(c, %s, xcb_parts + 2, &xcb_req, %s, fds);', func_flags, num_fds)
Packit 071ada
Packit 071ada
    # free dyn. all. data, if any
Packit 071ada
    for f in free_calls:
Packit 071ada
        _c(f)
Packit 071ada
    _c('    return xcb_ret;')
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
def _c_reply(self, name):
Packit 071ada
    '''
Packit 071ada
    Declares the function that returns the reply structure.
Packit 071ada
    '''
Packit 071ada
    spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
Packit 071ada
    spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
Packit 071ada
    spacing3 = ' ' * (len(self.c_reply_name) + 2)
Packit 071ada
Packit 071ada
    # check if _unserialize() has to be called for any field
Packit 071ada
    def look_for_special_cases(complex_obj):
Packit 071ada
        unserialize_fields = []
Packit 071ada
        # no unserialize call in case of switch
Packit 071ada
        if not complex_obj.is_switch:
Packit 071ada
            for field in complex_obj.fields:
Packit 071ada
                # three cases: 1. field with special case
Packit 071ada
                #              2. container that contains special case field
Packit 071ada
                #              3. list with special case elements
Packit 071ada
                if field.type.c_var_followed_by_fixed_fields:
Packit 071ada
                    unserialize_fields.append(field)
Packit 071ada
                elif field.type.is_container:
Packit 071ada
                    unserialize_fields += look_for_special_cases(field.type)
Packit 071ada
                elif field.type.is_list:
Packit 071ada
                    if field.type.member.c_var_followed_by_fixed_fields:
Packit 071ada
                        unserialize_fields.append(field)
Packit 071ada
                    if field.type.member.is_container:
Packit 071ada
                        unserialize_fields += look_for_special_cases(field.type.member)
Packit 071ada
        return unserialize_fields
Packit 071ada
Packit 071ada
    unserialize_fields = look_for_special_cases(self.reply)
Packit 071ada
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * Return the reply')
Packit 071ada
    _h(' * @param c      The connection')
Packit 071ada
    _h(' * @param cookie The cookie')
Packit 071ada
    _h(' * @param e      The xcb_generic_error_t supplied')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * Returns the reply of the request asked by')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * The parameter @p e supplied to this function must be NULL if')
Packit 071ada
    _h(' * %s(). is used.', self.c_unchecked_name)
Packit 071ada
    _h(' * Otherwise, it stores the error if any.')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * The returned value must be freed by the caller using free().')
Packit 071ada
    _h(' */')
Packit 071ada
    _c('')
Packit 071ada
    _hc('%s *', self.c_reply_type)
Packit 071ada
    _hc('%s (xcb_connection_t%s  *c,', self.c_reply_name, spacing1)
Packit 071ada
    _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
Packit 071ada
    _h('%sxcb_generic_error_t%s **e);', spacing3, spacing2)
Packit 071ada
    _c('%sxcb_generic_error_t%s **e)', spacing3, spacing2)
Packit 071ada
    _c('{')
Packit 071ada
Packit 071ada
    if len(unserialize_fields)>0:
Packit 071ada
        # certain variable size fields need to be unserialized explicitly
Packit 071ada
        _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
Packit 071ada
           self.c_reply_type, self.c_reply_type)
Packit 071ada
        _c('    int i;')
Packit 071ada
        for field in unserialize_fields:
Packit 071ada
            if field.type.is_list:
Packit 071ada
                _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
Packit 071ada
                _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
Packit 071ada
                _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
Packit 071ada
            else:
Packit 071ada
                raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
Packit 071ada
        # call _unserialize(), using the reply as source and target buffer
Packit 071ada
        _c('    /* special cases: transform parts of the reply to match XCB data structures */')
Packit 071ada
        for field in unserialize_fields:
Packit 071ada
            if field.type.is_list:
Packit 071ada
                _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
Packit 071ada
                _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
Packit 071ada
                _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
Packit 071ada
                   field.c_field_name, field.c_field_name)
Packit 071ada
                _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
Packit 071ada
                _c('    }')
Packit 071ada
        # return the transformed reply
Packit 071ada
        _c('    return reply;')
Packit 071ada
Packit 071ada
    else:
Packit 071ada
        _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
Packit 071ada
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
def _c_reply_has_fds(self):
Packit 071ada
    return any(field.isfd for field in self.fields)
Packit 071ada
Packit 071ada
def _c_reply_fds(self, name):
Packit 071ada
    '''
Packit 071ada
    Declares the function that returns fds related to the reply.
Packit 071ada
    '''
Packit 071ada
    spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
Packit 071ada
    spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * Return the reply fds')
Packit 071ada
    _h(' * @param c      The connection')
Packit 071ada
    _h(' * @param reply  The reply')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * Returns the array of reply fds of the request asked by')
Packit 071ada
    _h(' *')
Packit 071ada
    _h(' * The returned value must be freed by the caller using free().')
Packit 071ada
    _h(' */')
Packit 071ada
    _c('')
Packit 071ada
    _hc('int *')
Packit 071ada
    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
Packit 071ada
    _h('%s%s  *reply);', spacing3, self.c_reply_type)
Packit 071ada
    _c('%s%s  *reply)', spacing3, self.c_reply_type)
Packit 071ada
    _c('{')
Packit 071ada
Packit 071ada
    _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
Packit 071ada
Packit 071ada
    _c('}')
Packit 071ada
Packit 071ada
Packit 071ada
def _c_opcode(name, opcode):
Packit 071ada
    '''
Packit 071ada
    Declares the opcode define for requests, events, and errors.
Packit 071ada
    '''
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _h('')
Packit 071ada
    _h('/** Opcode for %s. */', _n(name))
Packit 071ada
    _h('#define %s %s', _n(name).upper(), opcode)
Packit 071ada
Packit 071ada
def _c_cookie(self, name):
Packit 071ada
    '''
Packit 071ada
    Declares the cookie type for a non-void request.
Packit 071ada
    '''
Packit 071ada
    _h_setlevel(0)
Packit 071ada
    _h('')
Packit 071ada
    _h('/**')
Packit 071ada
    _h(' * @brief %s', self.c_cookie_type)
Packit 071ada
    _h(' **/')
Packit 071ada
    _h('typedef struct %s {', self.c_cookie_type)
Packit 071ada
    _h('    unsigned int sequence;')
Packit 071ada
    _h('} %s;', self.c_cookie_type)
Packit 071ada
Packit 071ada
def _man_request(self, name, void, aux):
Packit 071ada
    param_fields = [f for f in self.fields if f.visible]
Packit 071ada
Packit 071ada
    func_name = self.c_request_name if not aux else self.c_aux_name
Packit 071ada
Packit 071ada
    def create_link(linkname):
Packit 071ada
        name = 'man/%s.%s' % (linkname, section)
Packit 071ada
        if manpaths:
Packit 071ada
            sys.stdout.write(name)
Packit 071ada
        f = open(name, 'w')
Packit 071ada
        f.write('.so man%s/%s.%s' % (section, func_name, section))
Packit 071ada
        f.close()
Packit 071ada
Packit 071ada
    if manpaths:
Packit 071ada
        sys.stdout.write('man/%s.%s ' % (func_name, section))
Packit 071ada
    # Our CWD is src/, so this will end up in src/man/
Packit 071ada
    f = open('man/%s.%s' % (func_name, section), 'w')
Packit 071ada
    f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
Packit 071ada
    # Left-adjust instead of adjusting to both sides
Packit 071ada
    f.write('.ad l\n')
Packit 071ada
    f.write('.SH NAME\n')
Packit 071ada
    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
Packit 071ada
    f.write('%s \\- %s\n' % (func_name, brief))
Packit 071ada
    f.write('.SH SYNOPSIS\n')
Packit 071ada
    # Don't split words (hyphenate)
Packit 071ada
    f.write('.hy 0\n')
Packit 071ada
    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
Packit 071ada
Packit 071ada
    # function prototypes
Packit 071ada
    prototype = ''
Packit 071ada
    count = len(param_fields)
Packit 071ada
    for field in param_fields:
Packit 071ada
        count = count - 1
Packit 071ada
        c_field_const_type = field.c_field_const_type
Packit 071ada
        c_pointer = field.c_pointer
Packit 071ada
        if c_pointer == ' ':
Packit 071ada
            c_pointer = ''
Packit 071ada
        if field.type.c_need_serialize and not aux:
Packit 071ada
            c_field_const_type = "const void"
Packit 071ada
            c_pointer = '*'
Packit 071ada
        comma = ', ' if count else ');'
Packit 071ada
        prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
Packit 071ada
Packit 071ada
    f.write('.SS Request function\n')
Packit 071ada
    f.write('.HP\n')
Packit 071ada
    base_func_name = self.c_request_name if not aux else self.c_aux_name
Packit 071ada
    func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
Packit 071ada
    f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (func_cookie, base_func_name, prototype))
Packit 071ada
    create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
Packit 071ada
    if not void:
Packit 071ada
        f.write('.PP\n')
Packit 071ada
        f.write('.SS Reply datastructure\n')
Packit 071ada
        f.write('.nf\n')
Packit 071ada
        f.write('.sp\n')
Packit 071ada
        f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
Packit 071ada
        struct_fields = []
Packit 071ada
        maxtypelen = 0
Packit 071ada
Packit 071ada
        for field in self.reply.fields:
Packit 071ada
            if not field.type.fixed_size() and not self.is_switch and not self.is_union:
Packit 071ada
                continue
Packit 071ada
            if field.wire:
Packit 071ada
                struct_fields.append(field)
Packit 071ada
Packit 071ada
        for field in struct_fields:
Packit 071ada
            length = len(field.c_field_type)
Packit 071ada
            # account for '*' pointer_spec
Packit 071ada
            if not field.type.fixed_size():
Packit 071ada
                length += 1
Packit 071ada
            maxtypelen = max(maxtypelen, length)
Packit 071ada
Packit 071ada
        def _c_complex_field(self, field, space=''):
Packit 071ada
            if (field.type.fixed_size() or
Packit 071ada
                # in case of switch with switch children, don't make the field a pointer
Packit 071ada
                # necessary for unserialize to work
Packit 071ada
                (self.is_switch and field.type.is_switch)):
Packit 071ada
                spacing = ' ' * (maxtypelen - len(field.c_field_type))
Packit 071ada
                f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
Packit 071ada
            else:
Packit 071ada
                spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
Packit 071ada
                f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
Packit 071ada
                #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
Packit 071ada
Packit 071ada
        if not self.is_switch:
Packit 071ada
            for field in struct_fields:
Packit 071ada
                _c_complex_field(self, field)
Packit 071ada
        else:
Packit 071ada
            for b in self.bitcases:
Packit 071ada
                space = ''
Packit 071ada
                if b.type.has_name:
Packit 071ada
                    space = '    '
Packit 071ada
                for field in b.type.fields:
Packit 071ada
                    _c_complex_field(self, field, space)
Packit 071ada
                if b.type.has_name:
Packit 071ada
                    print('ERROR: New unhandled documentation case\n', file=sys.stderr)
Packit 071ada
Packit 071ada
        f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
Packit 071ada
        f.write('.fi\n')
Packit 071ada
Packit 071ada
        f.write('.SS Reply function\n')
Packit 071ada
        f.write('.HP\n')
Packit 071ada
        f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
Packit 071ada
                 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
Packit 071ada
                (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
Packit 071ada
        create_link('%s' % self.c_reply_name)
Packit 071ada
Packit 071ada
        has_accessors = False
Packit 071ada
        for field in self.reply.fields:
Packit 071ada
            if field.type.is_list and not field.type.fixed_size():
Packit 071ada
                has_accessors = True
Packit 071ada
            elif field.prev_varsized_field is not None or not field.type.fixed_size():
Packit 071ada
                has_accessors = True
Packit 071ada
Packit 071ada
        if has_accessors:
Packit 071ada
            f.write('.SS Reply accessors\n')
Packit 071ada
Packit 071ada
        def _c_accessors_field(self, field):
Packit 071ada
            '''
Packit 071ada
            Declares the accessor functions for a non-list field that follows a variable-length field.
Packit 071ada
            '''
Packit 071ada
            c_type = self.c_type
Packit 071ada
Packit 071ada
            # special case: switch
Packit 071ada
            switch_obj = self if self.is_switch else None
Packit 071ada
            if self.is_case_or_bitcase:
Packit 071ada
                switch_obj = self.parents[-1]
Packit 071ada
            if switch_obj is not None:
Packit 071ada
                c_type = switch_obj.c_type
Packit 071ada
Packit 071ada
            if field.type.is_simple:
Packit 071ada
                f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
Packit 071ada
                create_link('%s' % field.c_accessor_name)
Packit 071ada
            else:
Packit 071ada
                f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
Packit 071ada
                create_link('%s' % field.c_accessor_name)
Packit 071ada
Packit 071ada
        def _c_accessors_list(self, field):
Packit 071ada
            '''
Packit 071ada
            Declares the accessor functions for a list field.
Packit 071ada
            Declares a direct-accessor function only if the list members are fixed size.
Packit 071ada
            Declares length and get-iterator functions always.
Packit 071ada
            '''
Packit 071ada
            list = field.type
Packit 071ada
            c_type = self.reply.c_type
Packit 071ada
Packit 071ada
            # special case: switch
Packit 071ada
            # in case of switch, 2 params have to be supplied to certain accessor functions:
Packit 071ada
            #   1. the anchestor object (request or reply)
Packit 071ada
            #   2. the (anchestor) switch object
Packit 071ada
            # the reason is that switch is either a child of a request/reply or nested in another switch,
Packit 071ada
            # so whenever we need to access a length field, we might need to refer to some anchestor type
Packit 071ada
            switch_obj = self if self.is_switch else None
Packit 071ada
            if self.is_case_or_bitcase:
Packit 071ada
                switch_obj = self.parents[-1]
Packit 071ada
            if switch_obj is not None:
Packit 071ada
                c_type = switch_obj.c_type
Packit 071ada
Packit 071ada
            params = []
Packit 071ada
            fields = {}
Packit 071ada
            parents = self.parents if hasattr(self, 'parents') else [self]
Packit 071ada
            # 'R': parents[0] is always the 'toplevel' container type
Packit 071ada
            params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
Packit 071ada
            fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
Packit 071ada
Packit 071ada
            if switch_obj is not None:
Packit 071ada
                # now look where the fields are defined that are needed to evaluate
Packit 071ada
                # the switch expr, and store the parent objects in accessor_params and
Packit 071ada
                # the fields in switch_fields
Packit 071ada
Packit 071ada
                # 'S': name for the 'toplevel' switch
Packit 071ada
                toplevel_switch = parents[1]
Packit 071ada
                params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
Packit 071ada
                fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
Packit 071ada
Packit 071ada
                # initialize prefix for everything "below" S
Packit 071ada
                prefix = [('S', '->', toplevel_switch)]
Packit 071ada
Packit 071ada
                # look for fields in the remaining containers
Packit 071ada
                for p in parents[2:] + [self]:
Packit 071ada
                    # the separator between parent and child is always '.' here,
Packit 071ada
                    # because of nested switch statements
Packit 071ada
                    if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
Packit 071ada
                        prefix.append((p.name[-1], '.', p))
Packit 071ada
                    fields.update(_c_helper_field_mapping(p, prefix, flat=True))
Packit 071ada
Packit 071ada
            if list.member.fixed_size():
Packit 071ada
                idx = 1 if switch_obj is not None else 0
Packit 071ada
                f.write('.HP\n')
Packit 071ada
                f.write('%s *\\fB%s\\fP(%s);\n' %
Packit 071ada
                        (field.c_field_type, field.c_accessor_name, params[idx][0]))
Packit 071ada
                create_link('%s' % field.c_accessor_name)
Packit 071ada
Packit 071ada
            f.write('.HP\n')
Packit 071ada
            f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
Packit 071ada
                    (field.c_length_name, c_type))
Packit 071ada
            create_link('%s' % field.c_length_name)
Packit 071ada
Packit 071ada
            if field.type.member.is_simple:
Packit 071ada
                f.write('.HP\n')
Packit 071ada
                f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
Packit 071ada
                        (field.c_end_name, c_type))
Packit 071ada
                create_link('%s' % field.c_end_name)
Packit 071ada
            else:
Packit 071ada
                f.write('.HP\n')
Packit 071ada
                f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
Packit 071ada
                        (field.c_iterator_type, field.c_iterator_name,
Packit 071ada
                         c_type))
Packit 071ada
                create_link('%s' % field.c_iterator_name)
Packit 071ada
Packit 071ada
        for field in self.reply.fields:
Packit 071ada
            if field.type.is_list and not field.type.fixed_size():
Packit 071ada
                _c_accessors_list(self, field)
Packit 071ada
            elif field.prev_varsized_field is not None or not field.type.fixed_size():
Packit 071ada
                _c_accessors_field(self, field)
Packit 071ada
Packit 071ada
Packit 071ada
    f.write('.br\n')
Packit 071ada
    # Re-enable hyphenation and adjusting to both sides
Packit 071ada
    f.write('.hy 1\n')
Packit 071ada
Packit 071ada
    # argument reference
Packit 071ada
    f.write('.SH REQUEST ARGUMENTS\n')
Packit 071ada
    f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
Packit 071ada
    f.write('The XCB connection to X11.\n')
Packit 071ada
    for field in param_fields:
Packit 071ada
        f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
Packit 071ada
        printed_enum = False
Packit 071ada
        # XXX: hard-coded until we fix xproto.xml
Packit 071ada
        if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
Packit 071ada
            field.enum = 'GC'
Packit 071ada
        elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
Packit 071ada
            field.enum = 'CW'
Packit 071ada
        elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
Packit 071ada
            field.enum = 'CW'
Packit 071ada
        if hasattr(field, "enum") and field.enum:
Packit 071ada
            # XXX: why the 'xcb' prefix?
Packit 071ada
            key = ('xcb', field.enum)
Packit 071ada
            if key in enums:
Packit 071ada
                f.write('One of the following values:\n')
Packit 071ada
                f.write('.RS 1i\n')
Packit 071ada
                enum = enums[key]
Packit 071ada
                count = len(enum.values)
Packit 071ada
                for (enam, eval) in enum.values:
Packit 071ada
                    count = count - 1
Packit 071ada
                    f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
Packit 071ada
                    if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
Packit 071ada
                        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
Packit 071ada
                        f.write('%s\n' % desc)
Packit 071ada
                    else:
Packit 071ada
                        f.write('TODO: NOT YET DOCUMENTED.\n')
Packit 071ada
                f.write('.RE\n')
Packit 071ada
                f.write('.RS 1i\n')
Packit 071ada
                printed_enum = True
Packit 071ada
Packit 071ada
        if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
Packit 071ada
            desc = self.doc.fields[field.field_name]
Packit 071ada
            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
Packit 071ada
            if printed_enum:
Packit 071ada
                f.write('\n')
Packit 071ada
            f.write('%s\n' % desc)
Packit 071ada
        else:
Packit 071ada
            f.write('TODO: NOT YET DOCUMENTED.\n')
Packit 071ada
        if printed_enum:
Packit 071ada
            f.write('.RE\n')
Packit 071ada
Packit 071ada
    # Reply reference
Packit 071ada
    if not void:
Packit 071ada
        f.write('.SH REPLY FIELDS\n')
Packit 071ada
        # These fields are present in every reply:
Packit 071ada
        f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
Packit 071ada
        f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
Packit 071ada
                 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
Packit 071ada
                 'be used to tell replies apart from each other.\n') %
Packit 071ada
                 _n(self.reply.name).upper())
Packit 071ada
        f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
Packit 071ada
        f.write('The sequence number of the last request processed by the X11 server.\n')
Packit 071ada
        f.write('.IP \\fI%s\\fP 1i\n' % 'length')
Packit 071ada
        f.write('The length of the reply, in words (a word is 4 bytes).\n')
Packit 071ada
        for field in self.reply.fields:
Packit 071ada
            if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
Packit 071ada
                field.c_field_name.startswith('pad')):
Packit 071ada
                continue
Packit 071ada
Packit 071ada
            if field.type.is_list and not field.type.fixed_size():
Packit 071ada
                continue
Packit 071ada
            elif field.prev_varsized_field is not None or not field.type.fixed_size():
Packit 071ada
                continue
Packit 071ada
            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
Packit 071ada
            printed_enum = False
Packit 071ada
            if hasattr(field, "enum") and field.enum:
Packit 071ada
                # XXX: why the 'xcb' prefix?
Packit 071ada
                key = ('xcb', field.enum)
Packit 071ada
                if key in enums:
Packit 071ada
                    f.write('One of the following values:\n')
Packit 071ada
                    f.write('.RS 1i\n')
Packit 071ada
                    enum = enums[key]
Packit 071ada
                    count = len(enum.values)
Packit 071ada
                    for (enam, eval) in enum.values:
Packit 071ada
                        count = count - 1
Packit 071ada
                        f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
Packit 071ada
                        if enum.doc and enam in enum.doc.fields:
Packit 071ada
                            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
Packit 071ada
                            f.write('%s\n' % desc)
Packit 071ada
                        else:
Packit 071ada
                            f.write('TODO: NOT YET DOCUMENTED.\n')
Packit 071ada
                    f.write('.RE\n')
Packit 071ada
                    f.write('.RS 1i\n')
Packit 071ada
                    printed_enum = True
Packit 071ada
Packit 071ada
            if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
Packit 071ada
                desc = self.reply.doc.fields[field.field_name]
Packit 071ada
                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
Packit 071ada
                if printed_enum:
Packit 071ada
                    f.write('\n')
Packit 071ada
                f.write('%s\n' % desc)
Packit 071ada
            else:
Packit 071ada
                f.write('TODO: NOT YET DOCUMENTED.\n')
Packit 071ada
            if printed_enum:
Packit 071ada
                f.write('.RE\n')
Packit 071ada
Packit 071ada
Packit 071ada
Packit 071ada
    # text description
Packit 071ada
    f.write('.SH DESCRIPTION\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc and self.doc.description:
Packit 071ada
        desc = self.doc.description
Packit 071ada
        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
Packit 071ada
        lines = desc.split('\n')
Packit 071ada
        f.write('\n'.join(lines) + '\n')
Packit 071ada
Packit 071ada
    f.write('.SH RETURN VALUE\n')
Packit 071ada
    if void:
Packit 071ada
        f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
Packit 071ada
                 'have to be handled in the event loop.\n\nIf you want to '
Packit 071ada
                 'handle errors directly with \\fIxcb_request_check\\fP '
Packit 071ada
                 'instead, use \\fI%s_checked\\fP. See '
Packit 071ada
                 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
Packit 071ada
    else:
Packit 071ada
        f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
Packit 071ada
                 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
Packit 071ada
                 'handle errors in the event loop instead, use '
Packit 071ada
                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
Packit 071ada
                 'details.\n') %
Packit 071ada
                (self.c_cookie_type, self.c_reply_name, base_func_name, section))
Packit 071ada
    f.write('.SH ERRORS\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        for errtype, errtext in sorted(self.doc.errors.items()):
Packit 071ada
            f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
Packit 071ada
            errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
Packit 071ada
            f.write('%s\n' % (errtext))
Packit 071ada
    if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
Packit 071ada
        f.write('This request does never generate any errors.\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc and self.doc.example:
Packit 071ada
        f.write('.SH EXAMPLE\n')
Packit 071ada
        f.write('.nf\n')
Packit 071ada
        f.write('.sp\n')
Packit 071ada
        lines = self.doc.example.split('\n')
Packit 071ada
        f.write('\n'.join(lines) + '\n')
Packit 071ada
        f.write('.fi\n')
Packit 071ada
    f.write('.SH SEE ALSO\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        see = ['.BR %s (%s)' % ('xcb-requests', section)]
Packit 071ada
        if self.doc.example:
Packit 071ada
            see.append('.BR %s (%s)' % ('xcb-examples', section))
Packit 071ada
        for seename, seetype in sorted(self.doc.see.items()):
Packit 071ada
            if seetype == 'program':
Packit 071ada
                see.append('.BR %s (1)' % seename)
Packit 071ada
            elif seetype == 'event':
Packit 071ada
                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
Packit 071ada
            elif seetype == 'request':
Packit 071ada
                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
Packit 071ada
            elif seetype == 'function':
Packit 071ada
                see.append('.BR %s (%s)' % (seename, section))
Packit 071ada
            else:
Packit 071ada
                see.append('TODO: %s (type %s)' % (seename, seetype))
Packit 071ada
        f.write(',\n'.join(see) + '\n')
Packit 071ada
    f.write('.SH AUTHOR\n')
Packit 071ada
    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
Packit 071ada
    f.close()
Packit 071ada
Packit 071ada
def _man_event(self, name):
Packit 071ada
    if manpaths:
Packit 071ada
        sys.stdout.write('man/%s.%s ' % (self.c_type, section))
Packit 071ada
    # Our CWD is src/, so this will end up in src/man/
Packit 071ada
    f = open('man/%s.%s' % (self.c_type, section), 'w')
Packit 071ada
    f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
Packit 071ada
    # Left-adjust instead of adjusting to both sides
Packit 071ada
    f.write('.ad l\n')
Packit 071ada
    f.write('.SH NAME\n')
Packit 071ada
    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
Packit 071ada
    f.write('%s \\- %s\n' % (self.c_type, brief))
Packit 071ada
    f.write('.SH SYNOPSIS\n')
Packit 071ada
    # Don't split words (hyphenate)
Packit 071ada
    f.write('.hy 0\n')
Packit 071ada
    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
Packit 071ada
Packit 071ada
    f.write('.PP\n')
Packit 071ada
    f.write('.SS Event datastructure\n')
Packit 071ada
    f.write('.nf\n')
Packit 071ada
    f.write('.sp\n')
Packit 071ada
    f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
Packit 071ada
    struct_fields = []
Packit 071ada
    maxtypelen = 0
Packit 071ada
Packit 071ada
    for field in self.fields:
Packit 071ada
        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
Packit 071ada
            continue
Packit 071ada
        if field.wire:
Packit 071ada
            struct_fields.append(field)
Packit 071ada
Packit 071ada
    for field in struct_fields:
Packit 071ada
        length = len(field.c_field_type)
Packit 071ada
        # account for '*' pointer_spec
Packit 071ada
        if not field.type.fixed_size():
Packit 071ada
            length += 1
Packit 071ada
        maxtypelen = max(maxtypelen, length)
Packit 071ada
Packit 071ada
    def _c_complex_field(self, field, space=''):
Packit 071ada
        if (field.type.fixed_size() or
Packit 071ada
            # in case of switch with switch children, don't make the field a pointer
Packit 071ada
            # necessary for unserialize to work
Packit 071ada
            (self.is_switch and field.type.is_switch)):
Packit 071ada
            spacing = ' ' * (maxtypelen - len(field.c_field_type))
Packit 071ada
            f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
Packit 071ada
        else:
Packit 071ada
            print('ERROR: New unhandled documentation case', file=sys.stderr)
Packit 071ada
Packit 071ada
    if not self.is_switch:
Packit 071ada
        for field in struct_fields:
Packit 071ada
            _c_complex_field(self, field)
Packit 071ada
    else:
Packit 071ada
        for b in self.bitcases:
Packit 071ada
            space = ''
Packit 071ada
            if b.type.has_name:
Packit 071ada
                space = '    '
Packit 071ada
            for field in b.type.fields:
Packit 071ada
                _c_complex_field(self, field, space)
Packit 071ada
            if b.type.has_name:
Packit 071ada
                print('ERROR: New unhandled documentation case', file=sys.stderr)
Packit 071ada
                pass
Packit 071ada
Packit 071ada
    f.write('} \\fB%s\\fP;\n' % self.c_type)
Packit 071ada
    f.write('.fi\n')
Packit 071ada
Packit 071ada
Packit 071ada
    f.write('.br\n')
Packit 071ada
    # Re-enable hyphenation and adjusting to both sides
Packit 071ada
    f.write('.hy 1\n')
Packit 071ada
Packit 071ada
    # argument reference
Packit 071ada
    f.write('.SH EVENT FIELDS\n')
Packit 071ada
    f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
Packit 071ada
    f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
Packit 071ada
             'also present in the \\fIxcb_generic_event_t\\fP and can be used '
Packit 071ada
             'to tell events apart from each other.\n') % _n(name).upper())
Packit 071ada
    f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
Packit 071ada
    f.write('The sequence number of the last request processed by the X11 server.\n')
Packit 071ada
Packit 071ada
    if not self.is_switch:
Packit 071ada
        for field in struct_fields:
Packit 071ada
            # Skip the fields which every event has, we already documented
Packit 071ada
            # them (see above).
Packit 071ada
            if field.c_field_name in ('response_type', 'sequence'):
Packit 071ada
                continue
Packit 071ada
            if isinstance(field.type, PadType):
Packit 071ada
                continue
Packit 071ada
            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
Packit 071ada
            if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
Packit 071ada
                desc = self.doc.fields[field.field_name]
Packit 071ada
                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
Packit 071ada
                f.write('%s\n' % desc)
Packit 071ada
            else:
Packit 071ada
                f.write('NOT YET DOCUMENTED.\n')
Packit 071ada
Packit 071ada
    # text description
Packit 071ada
    f.write('.SH DESCRIPTION\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc and self.doc.description:
Packit 071ada
        desc = self.doc.description
Packit 071ada
        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
Packit 071ada
        lines = desc.split('\n')
Packit 071ada
        f.write('\n'.join(lines) + '\n')
Packit 071ada
Packit 071ada
    if hasattr(self, "doc") and self.doc and self.doc.example:
Packit 071ada
        f.write('.SH EXAMPLE\n')
Packit 071ada
        f.write('.nf\n')
Packit 071ada
        f.write('.sp\n')
Packit 071ada
        lines = self.doc.example.split('\n')
Packit 071ada
        f.write('\n'.join(lines) + '\n')
Packit 071ada
        f.write('.fi\n')
Packit 071ada
    f.write('.SH SEE ALSO\n')
Packit 071ada
    if hasattr(self, "doc") and self.doc:
Packit 071ada
        see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
Packit 071ada
        if self.doc.example:
Packit 071ada
            see.append('.BR %s (%s)' % ('xcb-examples', section))
Packit 071ada
        for seename, seetype in sorted(self.doc.see.items()):
Packit 071ada
            if seetype == 'program':
Packit 071ada
                see.append('.BR %s (1)' % seename)
Packit 071ada
            elif seetype == 'event':
Packit 071ada
                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
Packit 071ada
            elif seetype == 'request':
Packit 071ada
                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
Packit 071ada
            elif seetype == 'function':
Packit 071ada
                see.append('.BR %s (%s)' % (seename, section))
Packit 071ada
            else:
Packit 071ada
                see.append('TODO: %s (type %s)' % (seename, seetype))
Packit 071ada
        f.write(',\n'.join(see) + '\n')
Packit 071ada
    f.write('.SH AUTHOR\n')
Packit 071ada
    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
Packit 071ada
    f.close()
Packit 071ada
Packit 071ada
Packit 071ada
def c_request(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles request declarations.
Packit 071ada
    '''
Packit 071ada
    _c_type_setup(self, name, ('request',))
Packit 071ada
Packit 071ada
    if self.reply:
Packit 071ada
        # Cookie type declaration
Packit 071ada
        _c_cookie(self, name)
Packit 071ada
Packit 071ada
    # Opcode define
Packit 071ada
    _c_opcode(name, self.opcode)
Packit 071ada
Packit 071ada
    # Request structure declaration
Packit 071ada
    _c_complex(self)
Packit 071ada
Packit 071ada
    if self.reply:
Packit 071ada
        _c_type_setup(self.reply, name, ('reply',))
Packit 071ada
        # Reply structure definition
Packit 071ada
        _c_complex(self.reply)
Packit 071ada
        # Request prototypes
Packit 071ada
        has_fds = _c_reply_has_fds(self.reply)
Packit 071ada
        _c_request_helper(self, name, void=False, regular=True, aux=False, reply_fds=has_fds)
Packit 071ada
        _c_request_helper(self, name, void=False, regular=False, aux=False, reply_fds=has_fds)
Packit 071ada
        if self.c_need_aux:
Packit 071ada
            _c_request_helper(self, name, void=False, regular=True, aux=True, reply_fs=has_fds)
Packit 071ada
            _c_request_helper(self, name, void=False, regular=False, aux=True, reply_fs=has_fds)
Packit 071ada
        # Reply accessors
Packit 071ada
        _c_accessors(self.reply, name + ('reply',), name)
Packit 071ada
        _c_reply(self, name)
Packit 071ada
        if has_fds:
Packit 071ada
            _c_reply_fds(self, name)
Packit 071ada
    else:
Packit 071ada
        # Request prototypes
Packit 071ada
        _c_request_helper(self, name, void=True, regular=False)
Packit 071ada
        _c_request_helper(self, name, void=True, regular=True)
Packit 071ada
        if self.c_need_aux:
Packit 071ada
            _c_request_helper(self, name, void=True, regular=False, aux=True)
Packit 071ada
            _c_request_helper(self, name, void=True, regular=True, aux=True)
Packit 071ada
        for field in self.fields:
Packit 071ada
            if not field.type.is_pad and field.wire:
Packit 071ada
                if _c_field_needs_list_accessor(field):
Packit 071ada
                    _c_accessors_list(self, field)
Packit 071ada
                elif _c_field_needs_field_accessor(field):
Packit 071ada
                    _c_accessors_field(self, field)
Packit 071ada
    # We generate the manpage afterwards because _c_type_setup has been called.
Packit 071ada
    # TODO: what about aux helpers?
Packit 071ada
    _man_request(self, name, void=not self.reply, aux=False)
Packit 071ada
Packit 071ada
Packit 071ada
def c_eventstruct(self, name):
Packit 071ada
    #add fields that are needed to get the event-type in a generic way
Packit 071ada
    self.fields.append( Field( tevent, tevent.name, 'event_header', False, True, True) )
Packit 071ada
Packit 071ada
    if self.contains_ge_events:
Packit 071ada
        #TODO: add header of ge-events as an extra field
Packit 071ada
        raise Exception( 'eventstructs with ge-events are not yet supported' )
Packit 071ada
Packit 071ada
    _c_type_setup(self, name, ())
Packit 071ada
Packit 071ada
    #correct the format of the field names
Packit 071ada
    for field in self.fields:
Packit 071ada
        field.c_field_name = _n_item(field.c_field_name).lower()
Packit 071ada
Packit 071ada
    _c_complex(self)
Packit 071ada
    _c_iterator(self, name)
Packit 071ada
Packit 071ada
    if not self.fixed_size():
Packit 071ada
        #TODO: Create sizeof function (and maybe other accessors) for var-sized eventstructs
Packit 071ada
        raise Exception( 'var sized eventstructs are not yet supported' )
Packit 071ada
Packit 071ada
def c_event(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles event declarations.
Packit 071ada
    '''
Packit 071ada
Packit 071ada
    # The generic event structure xcb_ge_event_t has the full_sequence field
Packit 071ada
    # at the 32byte boundary. That's why we've to inject this field into GE
Packit 071ada
    # events while generating the structure for them. Otherwise we would read
Packit 071ada
    # garbage (the internal full_sequence) when accessing normal event fields
Packit 071ada
    # there.
Packit 071ada
    force_packed = False
Packit 071ada
    if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
Packit 071ada
        event_size = 0
Packit 071ada
        for field in self.fields:
Packit 071ada
            if field.type.size != None and field.type.nmemb != None:
Packit 071ada
                event_size += field.type.size * field.type.nmemb
Packit 071ada
            if event_size == 32:
Packit 071ada
                full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
Packit 071ada
                idx = self.fields.index(field)
Packit 071ada
                self.fields.insert(idx + 1, full_sequence)
Packit 071ada
Packit 071ada
                # If the event contains any 64-bit extended fields, they need
Packit 071ada
                # to remain aligned on a 64-bit boundary.  Adding full_sequence
Packit 071ada
                # would normally break that; force the struct to be packed.
Packit 071ada
                force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
Packit 071ada
                break
Packit 071ada
Packit 071ada
    if self.name == name:
Packit 071ada
        _c_type_setup(self, name, ('event',))
Packit 071ada
        # generate accessors
Packit 071ada
        # (needed for fields after var-sized fields, for lists with var-sized elements,
Packit 071ada
        # switches, ...)
Packit 071ada
        _c_accessors(self, name, name)
Packit 071ada
    else:
Packit 071ada
        # no type-setup needed for eventcopies
Packit 071ada
        # (the type-setup of an eventcopy would overwrite members of the original
Packit 071ada
        # event, and it would create sizeof-etc funtions which
Packit 071ada
        # called undefined accessor functions)
Packit 071ada
        pass
Packit 071ada
Packit 071ada
    # Opcode define
Packit 071ada
    _c_opcode(name, self.opcodes[name])
Packit 071ada
Packit 071ada
    if self.name == name:
Packit 071ada
        # Structure definition
Packit 071ada
        _c_complex(self, force_packed)
Packit 071ada
    else:
Packit 071ada
        # Typedef
Packit 071ada
        _h('')
Packit 071ada
        _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
Packit 071ada
Packit 071ada
        # Create sizeof-function for eventcopies for compatibility reasons
Packit 071ada
        if self.c_need_sizeof:
Packit 071ada
            _h_setlevel(1)
Packit 071ada
            _c_setlevel(1)
Packit 071ada
            _h('')
Packit 071ada
            _h('int')
Packit 071ada
            _h('%s (const void  *_buffer  /**< */);', _n(name + ('sizeof',)))
Packit 071ada
            _c('')
Packit 071ada
            _c('int')
Packit 071ada
            _c('%s (const void  *_buffer  /**< */)', _n(name + ('sizeof',)))
Packit 071ada
            _c('{');
Packit 071ada
            _c('    return %s(_buffer);', _n(self.name + ('sizeof',)))
Packit 071ada
            _c('}');
Packit 071ada
            _h_setlevel(0)
Packit 071ada
            _c_setlevel(0)
Packit 071ada
Packit 071ada
    _man_event(self, name)
Packit 071ada
Packit 071ada
def c_error(self, name):
Packit 071ada
    '''
Packit 071ada
    Exported function that handles error declarations.
Packit 071ada
    '''
Packit 071ada
    _c_type_setup(self, name, ('error',))
Packit 071ada
Packit 071ada
    # Opcode define
Packit 071ada
    _c_opcode(name, self.opcodes[name])
Packit 071ada
Packit 071ada
    if self.name == name:
Packit 071ada
        # Structure definition
Packit 071ada
        _c_complex(self)
Packit 071ada
    else:
Packit 071ada
        # Typedef
Packit 071ada
        _h('')
Packit 071ada
        _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
Packit 071ada
Packit 071ada
Packit 071ada
# Main routine starts here
Packit 071ada
Packit 071ada
# Must create an "output" dictionary before any xcbgen imports.
Packit 071ada
output = {'open'    : c_open,
Packit 071ada
          'close'   : c_close,
Packit 071ada
          'simple'  : c_simple,
Packit 071ada
          'enum'    : c_enum,
Packit 071ada
          'struct'  : c_struct,
Packit 071ada
          'union'   : c_union,
Packit 071ada
          'request' : c_request,
Packit 071ada
          'eventstruct' : c_eventstruct,
Packit 071ada
          'event'   : c_event,
Packit 071ada
          'error'   : c_error,
Packit 071ada
          }
Packit 071ada
Packit 071ada
# Boilerplate below this point
Packit 071ada
Packit 071ada
# Check for the argument that specifies path to the xcbgen python package.
Packit 071ada
try:
Packit 071ada
    opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m', ["server-side"])
Packit 071ada
except getopt.GetoptError as err:
Packit 071ada
    print(err)
Packit 071ada
    print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
Packit 071ada
    sys.exit(1)
Packit 071ada
Packit 071ada
for (opt, arg) in opts:
Packit 071ada
    if opt == '-c':
Packit 071ada
        center_footer=arg
Packit 071ada
    if opt == '-l':
Packit 071ada
        left_footer=arg
Packit 071ada
    if opt == '-s':
Packit 071ada
        section=arg
Packit 071ada
    if opt == '-p':
Packit 071ada
        sys.path.insert(1, arg)
Packit 071ada
    if opt == '--server-side':
Packit 071ada
        config_server_side=True
Packit 071ada
    elif opt == '-m':
Packit 071ada
        manpaths = True
Packit 071ada
        sys.stdout.write('man_MANS = ')
Packit 071ada
Packit 071ada
# Import the module class
Packit 071ada
try:
Packit 071ada
    from xcbgen.state import Module
Packit 071ada
    from xcbgen.xtypes import *
Packit 071ada
except ImportError:
Packit 071ada
    print('''
Packit 071ada
Failed to load the xcbgen Python package!
Packit 071ada
Make sure that xcb/proto installed it on your Python path.
Packit 071ada
If not, you will need to create a .pth file or define $PYTHONPATH
Packit 071ada
to extend the path.
Packit 071ada
Refer to the README file in xcb/proto for more info.
Packit 071ada
''')
Packit 071ada
    raise
Packit 071ada
Packit 071ada
# predefined datatype globals.
Packit 071ada
tevent = SimpleType(('xcb_raw_generic_event_t',), 32)
Packit 071ada
Packit 071ada
# Ensure the man subdirectory exists
Packit 071ada
try:
Packit 071ada
    os.mkdir('man')
Packit 071ada
except OSError as e:
Packit 071ada
    if e.errno != errno.EEXIST:
Packit 071ada
        raise
Packit 071ada
Packit 071ada
# Parse the xml header
Packit 071ada
module = Module(args[0], output)
Packit 071ada
Packit 071ada
# Build type-registry and resolve type dependencies
Packit 071ada
module.register()
Packit 071ada
module.resolve()
Packit 071ada
Packit 071ada
# Output the code
Packit 071ada
module.generate()