import getopt
import os
import sys
+import errno
import time
import re
_clevel = 0
_ns = None
-# global variable to keep track of serializers and
+# global variable to keep track of serializers and
# switch data types due to weird dependencies
finished_serializers = []
finished_sizeof = []
Writes the given line to the header file.
'''
_hlines[_hlevel].append(fmt % args)
-
+
def _c(fmt, *args):
'''
Writes the given line to the source file.
'''
_clines[_clevel].append(fmt % args)
-
+
def _hc(fmt, *args):
'''
Writes the given line to both the header and source files.
_h(fmt, *args)
_c(fmt, *args)
+def _c_wr_stringlist(indent, strlist):
+ '''
+ Writes the given list of strings to the source file.
+ Each line is prepended by the indent string
+ '''
+ for str in strlist:
+ _c("%s%s", indent, str)
+
+
+class PreCode(object):
+ '''
+ For pre-code generated by expression generation
+ (for example, the for-loop of a sumof)
+ This has to account for recursiveness of the expression
+ generation, i.e., there may be pre-code for pre-code.
+ Therefore this is implemented as a stack of lists of lines.
+
+ If redirection is switched on, then all output is collected in
+ self.redirect_code and self.redirect_tempvars instead of
+ being sent to the output via _h und _c.
+ '''
+ def __init__(self):
+ self.nesting_level = 0
+ self.tempvars = []
+ self.codelines = []
+ self.redirect_code = None
+ self.redirect_tempvars = None
+ self.indent_str = ' '
+ self.indent_stack = []
+ self.tempvar_num = 0
+
+
+ # start and end of pre-code blocks
+ def start(self):
+ self.nesting_level += 1
+
+ def end(self):
+ self.nesting_level -= 1
+ if self.nesting_level == 0:
+ # lowest pre-code level is finished -> output to source
+ if self.redirect_tempvars is None:
+ _c_wr_stringlist('', self.tempvars)
+ self.tempvars = []
+ else:
+ self.redirect_tempvars.extend(self.tempvars)
+ self.tempvars = []
+ if self.redirect_code == None:
+ _c_wr_stringlist('', self.codelines)
+ self.codelines = []
+ else:
+ self.redirect_code.extend(self.codelines)
+ self.codelines = []
+
+
+ def output_tempvars(self):
+ if self.redirect_code == None:
+ _c_wr_stringlist('', self.tempvars)
+ self.tempvars = []
+
+ # output to precode
+ def code(self, fmt, *args):
+ self.codelines.append(self.indent_str + fmt % args)
+
+ def tempvar(self, fmt, *args):
+ self.tempvars.append(' ' + (fmt % args))
+
+ # get a unique name for a temporary variable
+ def get_tempvarname(self):
+ self.tempvar_num += 1
+ return "xcb_pre_tmp_%d" % self.tempvar_num
+
+ # indentation
+
+ def push_indent(self, indentstr):
+ self.indent_stack.append(self.indent_str)
+ self.indent_str = indentstr
+
+ def push_addindent(self, indent_add_str):
+ self.push_indent(self.indent_str + indent_add_str)
+
+ def indent(self):
+ self.push_addindent(' ')
+
+ def pop_indent(self):
+ self.indent_str = self.indent_stack.pop()
+
+ # redirection to lists
+ def redirect_start(self, redirect_code, redirect_tempvars=None):
+ self.redirect_code = redirect_code
+ self.redirect_tempvars = redirect_tempvars
+ if redirect_tempvars is not None:
+ self.tempvar_num = 0
+
+ def redirect_end(self):
+ self.redirect_code = None
+ self.redirect_tempvars = None
+
+# global PreCode handler
+_c_pre = PreCode()
+
+
# XXX See if this level thing is really necessary.
def _h_setlevel(idx):
'''
while len(_hlines) <= idx:
_hlines.append([])
_hlevel = idx
-
+
def _c_setlevel(idx):
'''
Changes the array that source lines are written to.
while len(_clines) <= idx:
_clines.append([])
_clevel = idx
-
+
def _n_item(str):
'''
Does C-name conversion on a single string fragment.
split = _cname_re.finditer(str)
name_parts = [match.group(0) for match in split]
return '_'.join(name_parts)
-
+
def _cpp(str):
'''
Checks for certain C++ reserved words and fixes them.
return _n_item(str).lower()
else:
return str.lower()
-
+
def _n(list):
'''
Does C-name conversion on a tuple of strings.
else:
parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
return '_'.join(parts).lower()
-
+
def c_open(self):
'''
_h('')
_h('#include "xcb.h"')
+ _c('#ifdef HAVE_CONFIG_H')
+ _c('#include "config.h"')
+ _c('#endif')
_c('#include <stdlib.h>')
_c('#include <string.h>')
_c('#include <assert.h>')
_c('#include <stddef.h> /* for offsetof() */')
_c('#include "xcbext.h"')
_c('#include "%s.h"', _ns.header)
-
+
_c('')
_c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
if _ns.is_ext:
- for (n, h) in self.imports:
+ for (n, h) in self.direct_imports:
_hc('#include "%s.h"', h)
_h('')
_h('')
_h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
_h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
- _h(' ') #XXX
+ _h('') #XXX
_h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
_c('')
equals = ' = ' if eval != '' else ''
comma = ',' if count > 0 else ''
doc = ''
- if self.doc and enam in self.doc.fields:
+ if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
doc = '\n/**< %s */\n' % self.doc.fields[enam]
_h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
self.c_reply_name = _n(name + ('reply',))
self.c_reply_type = _t(name + ('reply',))
self.c_cookie_type = _t(name + ('cookie',))
+ self.c_reply_fds_name = _n(name + ('reply_fds',))
- self.need_aux = False
- self.need_serialize = False
- self.need_sizeof = False
+ self.c_need_aux = False
+ self.c_need_serialize = False
+ self.c_need_sizeof = False
self.c_aux_name = _n(name + ('aux',))
self.c_aux_checked_name = _n(name + ('aux', 'checked'))
self.c_sizeof_name = _n(name + ('sizeof',))
# special case: structs where variable size fields are followed by fixed size fields
- self.var_followed_by_fixed_fields = False
+ self.c_var_followed_by_fixed_fields = False
if self.is_switch:
- self.need_serialize = True
+ self.c_need_serialize = True
self.c_container = 'struct'
for bitcase in self.bitcases:
bitcase.c_field_name = _cpp(bitcase.field_name)
first_field_after_varsized = None
for field in self.fields:
- _c_type_setup(field.type, field.field_type, ())
- if field.type.is_list:
- _c_type_setup(field.type.member, field.field_type, ())
- if (field.type.nmemb is None):
- self.need_sizeof = True
-
field.c_field_type = _t(field.field_type)
field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
field.c_field_name = _cpp(field.field_name)
if field.type.is_switch:
field.c_pointer = '*'
field.c_field_const_type = 'const ' + field.c_field_type
- self.need_aux = True
- elif not field.type.fixed_size() and not field.type.is_bitcase:
- self.need_sizeof = True
+ self.c_need_aux = True
+
+ if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
+ self.c_need_sizeof = True
field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
# special case: intermixed fixed and variable size fields
if prev_varsized_field is not None and not field.type.is_pad and field.wire:
if not self.is_union:
- self.need_serialize = True
- self.var_followed_by_fixed_fields = True
+ self.c_need_serialize = True
+ self.c_var_followed_by_fixed_fields = True
else:
self.last_varsized_field = field
prev_varsized_field = field
- prev_varsized_offset = 0
+ prev_varsized_offset = 0
- if self.var_followed_by_fixed_fields:
+ if self.c_var_followed_by_fixed_fields:
if field.type.fixed_size():
field.prev_varsized_field = None
-
- if self.need_serialize:
- # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
- self.need_sizeof = True
- # as switch does never appear at toplevel,
+ # recurse into this field this has to be done here, i.e.,
+ # after the field has been set up. Otherwise the function
+ # _c_helper_fieldaccess_expr will produce garbage or crash
+ _c_type_setup(field.type, field.field_type, ())
+ if field.type.is_list:
+ _c_type_setup(field.type.member, field.field_type, ())
+ if (field.type.nmemb is None):
+ self.c_need_sizeof = True
+
+ if self.c_need_serialize:
+ # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
+ self.c_need_sizeof = True
+
+ # as switch does never appear at toplevel,
# continue here with type construction
if self.is_switch:
if self.c_type not in finished_switch:
for bitcase in self.bitcases:
bitcase_name = bitcase.type.name if bitcase.type.has_name else name
_c_accessors(bitcase.type, bitcase_name, bitcase_name)
- # no list with switch as element, so no call to
+ # no list with switch as element, so no call to
# _c_iterator(field.type, field_name) necessary
- if not self.is_bitcase:
- if self.need_serialize:
+ if not self.is_case_or_bitcase:
+ if self.c_need_serialize:
if self.c_serialize_name not in finished_serializers:
finished_serializers.append(self.c_serialize_name)
_c_serialize('serialize', self)
# _unpack() and _unserialize() are only needed for special cases:
# switch -> unpack
# special cases -> unserialize
- if self.is_switch or self.var_followed_by_fixed_fields:
+ if self.is_switch or self.c_var_followed_by_fixed_fields:
_c_serialize('unserialize', self)
-
- if self.need_sizeof:
+
+ if self.c_need_sizeof:
if self.c_sizeof_name not in finished_sizeof:
if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
finished_sizeof.append(self.c_sizeof_name)
_c_serialize('sizeof', self)
# _c_type_setup()
-def _c_helper_absolute_name(prefix, field=None):
+# Functions for querying field properties
+def _c_field_needs_list_accessor(field):
+ return field.type.is_list and not field.type.fixed_size()
+
+def _c_field_needs_field_accessor(field):
+ if field.type.is_list:
+ return False
+ else:
+ return (field.prev_varsized_field is not None or
+ not field.type.fixed_size())
+
+def _c_field_needs_accessor(field):
+ return (_c_field_needs_list_accessor(field) or
+ _c_field_needs_field_accessor(field))
+
+def _c_field_is_member_of_case_or_bitcase(field):
+ return field.parent and field.parent.is_case_or_bitcase
+
+def _c_helper_fieldaccess_expr(prefix, field=None):
"""
turn prefix, which is a list of tuples (name, separator, Type obj) into a string
representing a valid name in C (based on the context)
if field is not None, append the field name as well
"""
prefix_str = ''
+ last_sep =''
for name, sep, obj in prefix:
- prefix_str += name
+ prefix_str += last_sep + name
if '' == sep:
sep = '->'
- if ((obj.is_bitcase and obj.has_name) or # named bitcase
+ if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
(obj.is_switch and len(obj.parents)>1)):
sep = '.'
- prefix_str += sep
- if field is not None:
- prefix_str += _cpp(field.field_name)
+ last_sep = sep
+
+ if field is None:
+ # add separator for access to a yet unknown field
+ prefix_str += last_sep
+ else:
+ if _c_field_needs_accessor(field):
+ if _c_field_is_member_of_case_or_bitcase(field):
+ # case members are available in the deserialized struct,
+ # so there is no need to use the accessor function
+ # (also, their accessor function needs a different arglist
+ # so this would require special treatment here)
+ # Therefore: Access as struct member
+ prefix_str += last_sep + _cpp(field.field_name)
+ else:
+ # Access with the accessor function
+ prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
+ else:
+ # Access as struct member
+ prefix_str += last_sep + _cpp(field.field_name)
+
return prefix_str
# _c_absolute_name
-
+
def _c_helper_field_mapping(complex_type, prefix, flat=False):
"""
generate absolute names, based on prefix, for all fields starting from complex_type
switch_name, switch_sep, switch_type = prefix[-1]
bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
else:
- bitcase_prefix = prefix
+ bitcase_prefix = prefix
if (True==flat and not b.type.has_name) or False==flat:
all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
else:
for f in complex_type.fields:
- fname = _c_helper_absolute_name(prefix, f)
+ fname = _c_helper_fieldaccess_expr(prefix, f)
if f.field_name in all_fields:
raise Exception("field name %s has been registered before" % f.field_name)
all_fields[f.field_name] = (fname, f)
if f.type.is_container and flat==False:
- if f.type.is_bitcase and not f.type.has_name:
+ if f.type.is_case_or_bitcase and not f.type.has_name:
new_prefix = prefix
elif f.type.is_switch and len(f.type.parents)>1:
# nested switch gets another separator
name, sep, obj = p
if ''==sep:
# sep can be preset in prefix, if not, make a sensible guess
- sep = '.' if (obj.is_switch or obj.is_bitcase) else '->'
+ sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
# exception: 'toplevel' object (switch as well!) always have sep '->'
sep = '->' if idx<1 else sep
- if not obj.is_bitcase or (obj.is_bitcase and obj.has_name):
+ if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
tmp_prefix.append((name, sep, obj))
all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
def get_expr_fields(self):
"""
- get the Fields referenced by switch or list expression
+ get the Fields referenced by switch or list expression
"""
def get_expr_field_names(expr):
if expr.op is None:
elif expr.op == 'popcount':
return get_expr_field_names(expr.rhs)
elif expr.op == 'sumof':
- # sumof expr references another list,
+ # sumof expr references another list,
# we need that list's length field here
field = None
for f in expr.lenfield_parent.fields:
else:
return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
# get_expr_field_names()
-
+
# resolve the field names with the parent structure(s)
unresolved_fields_names = get_expr_field_names(self.expr)
resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
if len(unresolved_fields_names) != len(resolved_fields_names):
raise Exception("could not resolve all fields for %s" % self.name)
-
+
resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
return resolved_fields
# get_expr_fields()
unresolved.append(e)
return unresolved
# resolve_expr_fields()
-
+
def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
"""
functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
- E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
- expression. This function tries to resolve all fields within a structure, and returns the
- unresolved fields as the list of external parameters.
+ E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
+ expression. This function tries to resolve all fields within a structure, and returns the
+ unresolved fields as the list of external parameters.
"""
def add_param(params, param):
if param not in params:
# field in the xcb_out structure
wire_fields.append(field)
# fields like 'pad0' are skipped!
-
+
# in case of switch, parameters always contain any fields referenced in the switch expr
- # we do not need any variable size fields here, as the switch data type contains both
+ # we do not need any variable size fields here, as the switch data type contains both
# fixed and variable size fields
if self.is_switch:
param_fields = get_expr_fields(self)
# _serialize()/_unserialize()/_unpack() function parameters
# note: don't use set() for params, it is unsorted
params = []
-
+
# 1. the parameter for the void * buffer
if 'serialize' == context:
params.append(('void', '**', buffer_var))
for p in param_fields:
if self.is_switch:
typespec = p.c_field_const_type
- pointerspec = p.c_pointer
+ pointerspec = p.c_pointer
add_param(params, (typespec, pointerspec, p.c_field_name))
else:
if p.visible and not p.wire and not p.auto:
typespec = p.c_field_type
pointerspec = ''
add_param(params, (typespec, pointerspec, p.c_field_name))
-
+
# 4. aux argument
if 'serialize' == context:
add_param(params, ('const %s' % self.c_type, '*', aux_var))
- elif 'unserialize' == context:
+ elif 'unserialize' == context:
add_param(params, ('%s' % self.c_type, '**', aux_var))
elif 'unpack' == context:
add_param(params, ('%s' % self.c_type, '*', aux_var))
# 5. switch contains all variable size fields as struct members
# for other data types though, these have to be supplied separately
- # this is important for the special case of intermixed fixed and
+ # this is important for the special case of intermixed fixed and
# variable size fields
if not self.is_switch and 'serialize' == context:
for p in param_fields:
return (param_fields, wire_fields, params)
# get_serialize_params()
-def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
+def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
code_lines.append('%s /* insert padding */' % space)
- code_lines.append('%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
+ if is_case_or_bitcase:
+ code_lines.append(
+ '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
+ % space)
+ else:
+ code_lines.append(
+ '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
# code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
code_lines.append('%s xcb_pad = 0;' % space)
code_lines.append('%s }' % space)
-
+
code_lines.append('%s xcb_block_len = 0;' % space)
+ if is_case_or_bitcase:
+ code_lines.append('%s xcb_padding_offset = 0;' % space)
# keep tracking of xcb_parts entries for serialize
return 1
# _c_serialize_helper_insert_padding()
-def _c_serialize_helper_switch(context, self, complex_name,
- code_lines, temp_vars,
+def _c_serialize_helper_switch(context, self, complex_name,
+ code_lines, temp_vars,
space, prefix):
count = 0
switch_expr = _c_accessor_get_expr(self.expr, None)
- for b in self.bitcases:
- bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
- code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
-# code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' %
-# (self.name[-1], b.type.name[-1], bitcase_expr))
+ for b in self.bitcases:
+ len_expr = len(b.type.expr)
+
+ compare_operator = '&'
+ if b.type.is_case:
+ compare_operator = '=='
+ else:
+ compare_operator = '&'
+
+ for n, expr in enumerate(b.type.expr):
+ bitcase_expr = _c_accessor_get_expr(expr, None)
+ # only one <enumref> in the <bitcase>
+ if len_expr == 1:
+ code_lines.append(
+ ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
+ # multiple <enumref> in the <bitcase>
+ elif n == 0: # first
+ code_lines.append(
+ ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
+ elif len_expr == (n + 1): # last
+ code_lines.append(
+ ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
+ else: # between first and last
+ code_lines.append(
+ ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
+
b_prefix = prefix
if b.type.has_name:
b_prefix = prefix + [(b.c_field_name, '.', b.type)]
-
- count += _c_serialize_helper_fields(context, b.type,
- code_lines, temp_vars,
- "%s " % space,
- b_prefix,
- is_bitcase = True)
+
+ count += _c_serialize_helper_fields(context, b.type,
+ code_lines, temp_vars,
+ "%s " % space,
+ b_prefix,
+ is_case_or_bitcase = True)
code_lines.append(' }')
# if 'serialize' == context:
# # padding
# code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
# code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
-
+
return count
# _c_serialize_helper_switch
# switch is handled by this function as a special case
param_fields, wire_fields, params = get_serialize_params(context, self)
field_mapping = _c_helper_field_mapping(self, prefix)
- prefix_str = _c_helper_absolute_name(prefix)
+ prefix_str = _c_helper_fieldaccess_expr(prefix)
# find the parameters that need to be passed to _serialize()/_unpack():
# all switch expr fields must be given as parameters
args = get_expr_fields(field.type)
- # length fields for variable size types in switch, normally only some of need
+ # length fields for variable size types in switch, normally only some of need
# need to be passed as parameters
switch_len_fields = resolve_expr_fields(field.type)
if len(bitcase_unresolved) != 0:
raise Exception('unresolved fields within bitcase is not supported at this point')
- # get the C names for the parameters
+ # get the C names for the parameters
c_field_names = ''
for a in switch_len_fields:
c_field_names += "%s, " % field_mapping[a.c_field_name][0]
# call _serialize()/_unpack() to determine the actual size
if 'serialize' == context:
length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
- c_field_names, prefix_str, field.c_field_name)
+ c_field_names, prefix_str, field.c_field_name)
elif context in ('unserialize', 'unpack'):
- length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
+ length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
c_field_names, prefix_str, field.c_field_name)
+ elif 'sizeof' == context:
+ # remove trailing ", " from c_field_names because it will be used at end of arglist
+ my_c_field_names = c_field_names[:-2]
+ length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
return length
# _c_serialize_helper_switch_field()
-def _c_serialize_helper_list_field(context, self, field,
- code_lines, temp_vars,
+def _c_serialize_helper_list_field(context, self, field,
+ code_lines, temp_vars,
space, prefix):
"""
helper function to cope with lists of variable length
"""
expr = field.type.expr
- prefix_str = _c_helper_absolute_name(prefix)
+ prefix_str = _c_helper_fieldaccess_expr(prefix)
param_fields, wire_fields, params = get_serialize_params('sizeof', self)
param_names = [p[2] for p in params]
-
+
expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
resolved = list(filter(lambda x: x in param_names, expr_fields_names))
unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
-
+
field_mapping = {}
for r in resolved:
field_mapping[r] = (r, None)
-
+
if len(unresolved)>0:
tmp_prefix = prefix
if len(tmp_prefix)==0:
- raise Exception("found an empty prefix while resolving expr field names for list %s",
- field.c_field_name)
-
+ raise Exception("found an empty prefix while resolving expr field names for list %s",
+ field.c_field_name)
+
field_mapping.update(_c_helper_resolve_field_names(prefix))
resolved += list(filter(lambda x: x in field_mapping, unresolved))
unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
# default: list with fixed size elements
length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
- # list with variable-sized elements
+ # list with variable-sized elements
if not field.type.member.fixed_size():
length = ''
if context in ('unserialize', 'sizeof', 'unpack'):
# loop over all list elements and call sizeof repeatedly
# this should be a bit faster than using the iterators
code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
- code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
+ code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
(space, field.type.c_sizeof_name))
code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
- code_lines.append("%s }" % space)
-
+ code_lines.append("%s }" % space)
+
elif 'serialize' == context:
code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
code_lines.append('%s }' % space)
code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
-
+
return length
# _c_serialize_helper_list_field()
-def _c_serialize_helper_fields_fixed_size(context, self, field,
- code_lines, temp_vars,
+def _c_serialize_helper_fields_fixed_size(context, self, field,
+ code_lines, temp_vars,
space, prefix):
# keep the C code a bit more readable by giving the field name
- if not self.is_bitcase:
+ if not self.is_case_or_bitcase:
code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
else:
scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
- abs_field_name = _c_helper_absolute_name(prefix, field)
+ abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
# default for simple cases: call sizeof()
length = "sizeof(%s)" % field.c_field_type
if context in ('unserialize', 'unpack', 'sizeof'):
# default: simple cast
- value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
-
+ value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
+
# padding - we could probably just ignore it
if field.type.is_pad and field.type.nmemb > 1:
value = ''
for i in range(field.type.nmemb):
- code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
- (space, abs_field_name, i, field.c_field_type))
+ code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
+ (space, abs_field_name, i, field.c_field_type))
# total padding = sizeof(pad0) * nmemb
length += " * %d" % field.type.nmemb
- if field.type.is_list:
- # no such case in the protocol, cannot be tested and therefore ignored for now
- raise Exception('list with fixed number of elemens unhandled in _unserialize()')
+ elif field.type.is_list:
+ # list with fixed number of elements
+ # length of array = sizeof(arrayElementType) * nmemb
+ length += " * %d" % field.type.nmemb
+ # use memcpy because C cannot assign whole arrays with operator=
+ value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
+
elif 'serialize' == context:
- value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
+ value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
if field.type.is_expr:
# need to register a temporary variable for the expression in case we know its type
if field.type.c_type is None:
- raise Exception("type for field '%s' (expression '%s') unkown" %
+ raise Exception("type for field '%s' (expression '%s') unkown" %
(field.field_name, _c_accessor_get_expr(field.type.expr)))
-
- temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
+
+ temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
_c_accessor_get_expr(field.type.expr, prefix)))
value += "&xcb_expr_%s;" % _cpp(field.field_name)
return (value, length)
# _c_serialize_helper_fields_fixed_size()
-def _c_serialize_helper_fields_variable_size(context, self, field,
- code_lines, temp_vars,
+def _c_serialize_helper_fields_variable_size(context, self, field,
+ code_lines, temp_vars,
space, prefix):
- prefix_str = _c_helper_absolute_name(prefix)
+ prefix_str = _c_helper_fieldaccess_expr(prefix)
if context in ('unserialize', 'unpack', 'sizeof'):
value = ''
var_field_name = 'xcb_tmp'
-
+
# special case: intermixed fixed and variable size fields
- if self.var_followed_by_fixed_fields and 'unserialize' == context:
+ if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
# special case: switch
if 'unpack' == context:
value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
-
+
elif 'serialize' == context:
- # variable size fields appear as parameters to _serialize() if the
+ # variable size fields appear as parameters to _serialize() if the
# 'toplevel' container is not a switch
prefix_string = prefix_str if prefix[0][2].is_switch else ''
var_field_name = "%s%s" % (prefix_string, field.c_field_name)
# in any context, list is already a pointer, so the default assignment is ok
code_lines.append("%s%s" % (space, value))
value = ''
- length = _c_serialize_helper_list_field(context, self, field,
- code_lines, temp_vars,
+ length = _c_serialize_helper_list_field(context, self, field,
+ code_lines, temp_vars,
space, prefix)
-
+
elif field.type.is_switch:
value = ''
if context == 'serialize':
# the _serialize() function allocates the correct amount memory if given a NULL pointer
value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
- length = _c_serialize_helper_switch_field(context, self, field,
- 'xcb_parts[xcb_parts_idx].iov_base',
+ length = _c_serialize_helper_switch_field(context, self, field,
+ 'xcb_parts[xcb_parts_idx].iov_base',
prefix)
-
+
else:
# in all remaining special cases - call _sizeof()
length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
return (value, length)
# _c_serialize_helper_fields_variable_size
-def _c_serialize_helper_fields(context, self,
- code_lines, temp_vars,
- space, prefix, is_bitcase):
+def _c_serialize_helper_fields(context, self,
+ code_lines, temp_vars,
+ space, prefix, is_case_or_bitcase):
count = 0
need_padding = False
prev_field_was_variable = False
+ _c_pre.push_indent(space + ' ')
+
for field in self.fields:
if not field.visible:
if not ((field.wire and not field.auto) or 'unserialize' == context):
continue
- # switch/bitcase: fixed size fields must be considered explicitly
+ # switch/bitcase: fixed size fields must be considered explicitly
if field.type.fixed_size():
- if self.is_bitcase or self.var_followed_by_fixed_fields:
+ if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
if prev_field_was_variable and need_padding:
# insert padding
-# count += _c_serialize_helper_insert_padding(context, code_lines, space,
-# self.var_followed_by_fixed_fields)
+# count += _c_serialize_helper_insert_padding(context, code_lines, space,
+# self.c_var_followed_by_fixed_fields)
prev_field_was_variable = False
# prefix for fixed size fields
fixed_prefix = prefix
- value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
- code_lines, temp_vars,
+ value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
+ code_lines, temp_vars,
space, fixed_prefix)
else:
continue
# fields with variable size
else:
- # switch/bitcase: always calculate padding before and after variable sized fields
- if need_padding or is_bitcase:
- count += _c_serialize_helper_insert_padding(context, code_lines, space,
- self.var_followed_by_fixed_fields)
-
- value, length = _c_serialize_helper_fields_variable_size(context, self, field,
- code_lines, temp_vars,
- space, prefix)
- prev_field_was_variable = True
-
+ if field.type.is_pad:
+ # Variable length pad is <pad align= />
+ code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
+ count += _c_serialize_helper_insert_padding(context, code_lines, space,
+ self.c_var_followed_by_fixed_fields,
+ is_case_or_bitcase)
+ continue
+ else:
+ # switch/bitcase: always calculate padding before and after variable sized fields
+ if need_padding or is_case_or_bitcase:
+ count += _c_serialize_helper_insert_padding(context, code_lines, space,
+ self.c_var_followed_by_fixed_fields,
+ is_case_or_bitcase)
+
+ value, length = _c_serialize_helper_fields_variable_size(context, self, field,
+ code_lines, temp_vars,
+ space, prefix)
+ prev_field_was_variable = True
+
# save (un)serialization C code
if '' != value:
- code_lines.append('%s%s' % (space, value))
-
+ code_lines.append('%s%s' % (space, value))
+
if field.type.fixed_size():
- if is_bitcase or self.var_followed_by_fixed_fields:
+ if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
# keep track of (un)serialized object's size
code_lines.append('%s xcb_block_len += %s;' % (space, length))
if context in ('unserialize', 'unpack', 'sizeof'):
code_lines.append('%s xcb_tmp += %s;' % (space, length))
- else:
+ else:
# variable size objects or bitcase:
# value & length might have been inserted earlier for special cases
if '' != length:
# special case: intermixed fixed and variable size fields
- if (not field.type.fixed_size() and
- self.var_followed_by_fixed_fields and 'unserialize' == context):
+ if (not field.type.fixed_size() and
+ self.c_var_followed_by_fixed_fields and 'unserialize' == context):
temp_vars.append(' int %s_len;' % field.c_field_name)
code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
# increase pointer into the byte stream accordingly
if context in ('unserialize', 'sizeof', 'unpack'):
code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
-
+
if 'serialize' == context:
if '' != length:
code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
code_lines.append('%s xcb_parts_idx++;' % space)
count += 1
- code_lines.append('%s xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
+ code_lines.append(
+ '%s xcb_align_to = ALIGNOF(%s);'
+ % (space,
+ 'char'
+ if field.c_field_type == 'void' or field.type.is_switch
+ else field.c_field_type))
need_padding = True
- if self.var_followed_by_fixed_fields:
+ if self.c_var_followed_by_fixed_fields:
need_padding = False
-
+
+ _c_pre.pop_indent()
+
return count
-# _c_serialize_helper_fields()
+# _c_serialize_helper_fields()
-def _c_serialize_helper(context, complex_type,
- code_lines, temp_vars,
+def _c_serialize_helper(context, complex_type,
+ code_lines, temp_vars,
space='', prefix=[]):
# count tracks the number of fields to serialize
count = 0
complex_name = complex_type.name
else:
self = complex_type
- if self.var_followed_by_fixed_fields and 'unserialize' == context:
+ if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
complex_name = 'xcb_out'
else:
complex_name = '_aux'
-
+
# special case: switch is serialized by evaluating each bitcase separately
if self.is_switch:
- count += _c_serialize_helper_switch(context, self, complex_name,
- code_lines, temp_vars,
+ count += _c_serialize_helper_switch(context, self, complex_name,
+ code_lines, temp_vars,
space, prefix)
# all other data types can be evaluated one field a time
- else:
+ else:
# unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
- if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
+ if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
- # probably not needed
- #_c_serialize_helper_insert_padding(context, code_lines, space, False)
+ code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
+ code_lines.append('%s xcb_block_len = 0;' % space)
- count += _c_serialize_helper_fields(context, self,
- code_lines, temp_vars,
+ count += _c_serialize_helper_fields(context, self,
+ code_lines, temp_vars,
space, prefix, False)
# "final padding"
- count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
+ count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
- return count
+ return count
# _c_serialize_helper()
def _c_serialize(context, self):
"""
- depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
+ depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
for the ComplexType variable self
"""
_h_setlevel(1)
if self.is_switch and 'unserialize' == context:
context = 'unpack'
- cases = { 'serialize' : self.c_serialize_name,
- 'unserialize' : self.c_unserialize_name,
- 'unpack' : self.c_unpack_name,
+ cases = { 'serialize' : self.c_serialize_name,
+ 'unserialize' : self.c_unserialize_name,
+ 'unpack' : self.c_unpack_name,
'sizeof' : self.c_sizeof_name }
func_name = cases[context]
-
+
param_fields, wire_fields, params = get_serialize_params(context, self)
variable_size_fields = 0
# maximum space required for type definition of function arguments
maxtypelen = 0
- # determine N(variable_fields)
+ # determine N(variable_fields)
for field in param_fields:
# if self.is_switch, treat all fields as if they are variable sized
if not field.type.fixed_size() or self.is_switch:
variable_size_fields += 1
# determine maxtypelen
for p in params:
- maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
+ maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
# write to .c/.h
indent = ' '*(len(func_name)+2)
temp_vars = []
prefix = []
+ _c_pre.redirect_start(code_lines, temp_vars)
+
if 'serialize' == context:
- if not self.is_switch and not self.var_followed_by_fixed_fields:
+ if not self.is_switch and not self.c_var_followed_by_fixed_fields:
_c(' %s *xcb_out = *_buffer;', self.c_type)
_c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
_c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
else:
_c(' char *xcb_out = *_buffer;')
_c(' unsigned int xcb_buffer_len = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
+ if self.is_switch:
+ _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
prefix = [('_aux', '->', self)]
aux_ptr = 'xcb_out'
elif context in ('unserialize', 'unpack'):
_c(' char *xcb_tmp = (char *)_buffer;')
if not self.is_switch:
- if not self.var_followed_by_fixed_fields:
+ if not self.c_var_followed_by_fixed_fields:
_c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
prefix = [('_aux', '->', self)]
else:
_c(' unsigned int xcb_buffer_len = 0;')
_c(' unsigned int xcb_block_len = 0;')
_c(' unsigned int xcb_pad = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
+ if self.is_switch:
+ _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
elif 'sizeof' == context:
param_names = [p[2] for p in params]
_c(' %s _aux;', self.c_type)
_c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
_c('}')
+ _c_pre.redirect_end()
return
- elif self.var_followed_by_fixed_fields:
+ elif self.c_var_followed_by_fixed_fields:
# special case: call _unserialize()
_c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
_c('}')
+ _c_pre.redirect_end()
return
else:
_c(' char *xcb_tmp = (char *)_buffer;')
prefix = [('_aux', '->', self)]
+ if self.is_switch:
+ _c(' unsigned int xcb_padding_offset = 0;')
count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
# update variable size fields (only important for context=='serialize'
variable_size_fields = count
if 'serialize' == context:
temp_vars.append(' unsigned int xcb_pad = 0;')
- temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
+ temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
temp_vars.append(' struct iovec xcb_parts[%d];' % count)
temp_vars.append(' unsigned int xcb_parts_idx = 0;')
temp_vars.append(' unsigned int xcb_block_len = 0;')
elif 'sizeof' == context:
# neither switch nor intermixed fixed and variable size fields:
# evaluate parameters directly
- if not (self.is_switch or self.var_followed_by_fixed_fields):
+ if not (self.is_switch or self.c_var_followed_by_fixed_fields):
# look if we have to declare an '_aux' variable at all
if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
- if not self.var_followed_by_fixed_fields:
+ if not self.c_var_followed_by_fixed_fields:
_c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
else:
_c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
_c(' unsigned int xcb_buffer_len = 0;')
_c(' unsigned int xcb_block_len = 0;')
- _c(' unsigned int xcb_pad = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_pad = 0;')
+ _c(' unsigned int xcb_align_to = 0;')
+
+ _c_pre.redirect_end()
_c('')
for t in temp_vars:
_c(l)
# variable sized fields have been collected, now
- # allocate memory and copy everything into a continuous memory area
+ # allocate memory and copy everything into a continuous memory area
# note: this is not necessary in case of unpack
if context in ('serialize', 'unserialize'):
# unserialize: check for sizeof-only invocation
# serialize: handle variable size fields in a loop
if 'serialize' == context:
- if not self.is_switch and not self.var_followed_by_fixed_fields:
+ if not self.is_switch and not self.c_var_followed_by_fixed_fields:
if len(wire_fields)>0:
_c(' *xcb_out = *_aux;')
# copy variable size fields into the buffer
if variable_size_fields > 0:
# xcb_out padding
- if not self.is_switch and not self.var_followed_by_fixed_fields:
+ if not self.is_switch and not self.c_var_followed_by_fixed_fields:
_c(' xcb_tmp = (char*)++xcb_out;')
_c(' xcb_tmp += xcb_out_pad;')
else:
_c(' if (0 != xcb_parts[i].iov_len)')
_c(' xcb_tmp += xcb_parts[i].iov_len;')
_c(' }')
-
+
# unserialize: assign variable size fields individually
if 'unserialize' == context:
_c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
_c(' xcb_tmp -= %s_len;', field.c_field_name)
_c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
_c(' *%s = xcb_out;', aux_ptr)
-
+
_c('')
_c(' return xcb_buffer_len;')
_c('}')
_h(' * element. The member index is increased by sizeof(%s)', self.c_type)
_h(' */')
_c('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** void %s', self.c_next_name)
- _hc(' ** ')
- _hc(' ** @param %s *i', self.c_iterator_type)
- _hc(' ** @returns void')
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('void')
_h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
_c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
if self.is_union:
# FIXME - how to determine the size of a variable size union??
- _c(' /* FIXME - determine the size of the union %s */', self.c_type)
+ _c(' /* FIXME - determine the size of the union %s */', self.c_type)
else:
- if self.need_sizeof:
+ if self.c_need_sizeof:
_c(' xcb_generic_iterator_t child;')
- _c(' child.data = (%s *)(((char *)R) + %s(R));',
+ _c(' child.data = (%s *)(((char *)R) + %s(R));',
self.c_type, self.c_sizeof_name)
_c(' i->index = (char *) child.data - (char *) i->data;')
else:
_h(' * last element.')
_h(' */')
_c('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
- _hc(' ** ')
- _hc(' ** @param %s i', self.c_iterator_type)
- _hc(' ** @returns xcb_generic_iterator_t')
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('xcb_generic_iterator_t')
_h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
_c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
def _c_accessor_get_length(expr, field_mapping=None):
'''
Figures out what C code is needed to get a length field.
- The field_mapping parameter can be used to change the absolute name of a length field.
+ The field_mapping parameter can be used to change the absolute name of a length field.
For fields that follow a variable-length field, use the accessor.
Otherwise, just reference the structure field directly.
'''
if lenfield_name is not None:
if field_mapping is not None:
lenfield_name = field_mapping[lenfield_name][0]
-
+
if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
# special case: variable and fixed size fields are intermixed
# if the lenfield is among the fixed size fields, there is no need
def _c_accessor_get_expr(expr, field_mapping):
'''
Figures out what C code is needed to get the length of a list field.
- The field_mapping parameter can be used to change the absolute name of a length field.
+ The field_mapping parameter can be used to change the absolute name of a length field.
Recurses for math operations.
Returns bitcount for value-mask fields.
Otherwise, uses the value of the length field.
raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
list_name = field_mapping[field.c_field_name][0]
c_length_func = "%s(%s)" % (field.c_length_name, list_name)
- # note: xcb_sumof() has only been defined for integers
c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
- return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
+ # create explicit code for computing the sum.
+ # This works for all C-types which can be added to int64_t with +=
+ _c_pre.start()
+ lengthvar = _c_pre.get_tempvarname()
+ loopvar = _c_pre.get_tempvarname()
+ sumvar = _c_pre.get_tempvarname()
+ listvar = _c_pre.get_tempvarname()
+ _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
+ _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
+ _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
+ _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
+ _c_pre.code("/* sumof start */")
+ _c_pre.code("%s = %s;", lengthvar, c_length_func)
+ _c_pre.code("%s = 0;", sumvar)
+ _c_pre.code("%s = %s;", listvar, list_name)
+ _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
+ _c_pre.indent()
+
+ if expr.rhs is None:
+ _c_pre.code("%s += *%s;", sumvar, listvar)
+ else:
+ # sumof has a nested expression which has to be evaluated in
+ # the context of this list element
+
+ # field mapping for the subexpression needs to include
+ # the fields of the list-member type
+ scoped_field_mapping = field_mapping.copy()
+ scoped_field_mapping.update(
+ _c_helper_field_mapping(
+ field.type.member,
+ [(listvar, '->', field.type.member)]))
+
+ # cause pre-code of the subexpression be added right here
+ _c_pre.end()
+ # compute the subexpression
+ rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
+ # resume with our code
+ _c_pre.start()
+ # output the summation expression
+ _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
+
+ _c_pre.code("%s++;", listvar)
+ _c_pre.pop_indent()
+ _c_pre.code("}")
+ _c_pre.code("/* sumof end. Result is in %s */", sumvar)
+ _c_pre.end()
+ return sumvar
elif expr.op != None:
- return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
- ' ' + expr.op + ' ' +
+ return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
+ ' ' + expr.op + ' ' +
_c_accessor_get_expr(expr.rhs, field_mapping) + ')')
elif expr.bitfield:
return 'xcb_popcount(' + lenexp + ')'
# special case: switch
switch_obj = self if self.is_switch else None
- if self.is_bitcase:
+ if self.is_case_or_bitcase:
switch_obj = self.parents[-1]
if switch_obj is not None:
c_type = switch_obj.c_type
if field.type.is_simple:
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' ** ')
- _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
- _hc(' ** ')
- _hc(' ** @param const %s *R', c_type)
- _hc(' ** @returns %s', field.c_field_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('%s', field.c_field_type)
_h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
_c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
_c(' return (%s *) (R + 1);', field.c_field_type)
else:
_c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
- _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
+ _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
_c('}')
else:
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
- _hc(' ** ')
- _hc(' ** @param const %s *R', c_type)
- _hc(' ** @returns %s *', field.c_field_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
if field.type.is_switch and switch_obj is None:
return_type = 'void *'
else:
if field.prev_varsized_field is None:
_c(' return (%s) (R + 1);', return_type)
# note: the special case 'variable fields followed by fixed size fields'
- # is not of any consequence here, since the ordering gets
+ # is not of any consequence here, since the ordering gets
# 'corrected' in the reply function
else:
_c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
- _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
+ _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
_c('}')
-
+
def _c_accessors_list(self, field):
'''
Declares the accessor functions for a list field.
Declares a direct-accessor function only if the list members are fixed size.
Declares length and get-iterator functions always.
'''
+
+ def get_align_pad(field):
+ prev = field.prev_varsized_field
+ prev_prev = field.prev_varsized_field.prev_varsized_field
+
+ if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
+ return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
+ else:
+ return (prev, None)
+
+
list = field.type
c_type = self.c_type
# in case of switch, 2 params have to be supplied to certain accessor functions:
# 1. the anchestor object (request or reply)
# 2. the (anchestor) switch object
- # the reason is that switch is either a child of a request/reply or nested in another switch,
+ # the reason is that switch is either a child of a request/reply or nested in another switch,
# so whenever we need to access a length field, we might need to refer to some anchestor type
switch_obj = self if self.is_switch else None
- if self.is_bitcase:
+ if self.is_case_or_bitcase:
switch_obj = self.parents[-1]
if switch_obj is not None:
c_type = switch_obj.c_type
params = []
fields = {}
parents = self.parents if hasattr(self, 'parents') else [self]
- # 'R': parents[0] is always the 'toplevel' container type
+ # 'R': parents[0] is always the 'toplevel' container type
params.append(('const %s *R' % parents[0].c_type, parents[0]))
fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
# auxiliary object for 'R' parameters
R_obj = parents[0]
if switch_obj is not None:
- # now look where the fields are defined that are needed to evaluate
+ # now look where the fields are defined that are needed to evaluate
# the switch expr, and store the parent objects in accessor_params and
# the fields in switch_fields
# look for fields in the remaining containers
for p in parents[2:] + [self]:
- # the separator between parent and child is always '.' here,
+ # the separator between parent and child is always '.' here,
# because of nested switch statements
- if not p.is_bitcase or (p.is_bitcase and p.has_name):
+ if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
prefix.append((p.name[-1], '.', p))
fields.update(_c_helper_field_mapping(p, prefix, flat=True))
if list.member.fixed_size():
idx = 1 if switch_obj is not None else 0
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
- _hc(' ** ')
- _hc(' ** @param %s', params[idx][0])
- _hc(' ** @returns %s *', field.c_field_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('%s *', field.c_field_type)
_h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
elif field.prev_varsized_field is None:
_c(' return (%s *) (R + 1);', field.c_field_type)
else:
- _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
- _c(' return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
- field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
+ (prev_varsized_field, align_pad) = get_align_pad(field)
+
+ if align_pad is None:
+ align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+ type_pad_type(field.first_field_after_varsized.type.c_type))
+
+ _c(' xcb_generic_iterator_t prev = %s;',
+ _c_iterator_get_end(prev_varsized_field, 'R'))
+ _c(' return (%s *) ((char *) prev.data + %s + %d);',
+ field.c_field_type, align_pad, field.prev_varsized_offset)
_c('}')
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** int %s', field.c_length_name)
- _hc(' ** ')
- _hc(' ** @param const %s *R', c_type)
- _hc(' ** @returns int')
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('int')
if switch_obj is not None:
_hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
spacing = ' '*(len(field.c_length_name)+2)
_h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
_c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
- length = _c_accessor_get_expr(field.type.expr, fields)
else:
_h('%s (const %s *R /**< */);', field.c_length_name, c_type)
_c('%s (const %s *R /**< */)', field.c_length_name, c_type)
- length = _c_accessor_get_expr(field.type.expr, fields)
_c('{')
+ length = _c_accessor_get_expr(field.type.expr, fields)
_c(' return %s;', length)
_c('}')
if field.type.member.is_simple:
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
- _hc(' ** ')
- _hc(' ** @param const %s *R', c_type)
- _hc(' ** @returns xcb_generic_iterator_t')
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('xcb_generic_iterator_t')
if switch_obj is not None:
_hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
_c('%s (const %s *R /**< */)', field.c_end_name, c_type)
_c('{')
_c(' xcb_generic_iterator_t i;')
-
+
param = 'R' if switch_obj is None else 'S'
if switch_obj is not None:
- _c(' i.data = %s + %s;', fields[field.c_field_name][0],
+ _c(' i.data = %s + %s;', fields[field.c_field_name][0],
_c_accessor_get_expr(field.type.expr, fields))
elif field.prev_varsized_field == None:
- _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
+ _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
_c_accessor_get_expr(field.type.expr, fields))
else:
- _c(' xcb_generic_iterator_t child = %s;',
+ _c(' xcb_generic_iterator_t child = %s;',
_c_iterator_get_end(field.prev_varsized_field, 'R'))
- _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
+ _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
_c_accessor_get_expr(field.type.expr, fields))
_c(' i.rem = 0;')
else:
_hc('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
- _hc(' ** ')
- _hc(' ** @param const %s *R', c_type)
- _hc(' ** @returns %s', field.c_iterator_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
-
_hc('%s', field.c_iterator_type)
if switch_obj is not None:
_hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
_c('{')
_c(' %s i;', field.c_iterator_type)
+ _c_pre.start()
+ length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
+
if switch_obj is not None:
+ _c_pre.end()
_c(' i.data = %s;', fields[field.c_field_name][0])
- _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
+ _c(' i.rem = %s;', length_expr_str)
elif field.prev_varsized_field == None:
+ _c_pre.end()
_c(' i.data = (%s *) (R + 1);', field.c_field_type)
else:
- _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
- _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));',
- field.c_field_type, type_pad_type(field.c_field_type))
+ (prev_varsized_field, align_pad) = get_align_pad(field)
+
+ if align_pad is None:
+ align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+ type_pad_type(field.c_field_type))
+
+ _c(' xcb_generic_iterator_t prev = %s;',
+ _c_iterator_get_end(prev_varsized_field, 'R'))
+ _c_pre.end()
+ _c(' i.data = (%s *) ((char *) prev.data + %s);',
+ field.c_field_type, align_pad)
+
if switch_obj is None:
- _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
+ _c(' i.rem = %s;', length_expr_str)
_c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
_c(' return i;')
_c('}')
'''
Declares the accessor functions for the fields of a structure.
'''
- # no accessors for switch itself -
+ # no accessors for switch itself -
# switch always needs to be unpacked explicitly
# if self.is_switch:
# pass
# else:
if True:
for field in self.fields:
- if field.type.is_list and not field.type.fixed_size():
- _c_accessors_list(self, field)
- elif field.prev_varsized_field is not None or not field.type.fixed_size():
- _c_accessors_field(self, field)
+ if not field.type.is_pad:
+ if _c_field_needs_list_accessor(field):
+ _c_accessors_list(self, field)
+ elif _c_field_needs_field_accessor(field):
+ _c_accessors_field(self, field)
def c_simple(self, name):
'''
# Iterator
_c_iterator(self, name)
-def _c_complex(self):
+def _c_complex(self, force_packed = False):
'''
Helper function for handling all structure types.
Called for all structs, requests, replies, events, errors.
continue
if field.wire:
struct_fields.append(field)
-
+
for field in struct_fields:
length = len(field.c_field_type)
# account for '*' pointer_spec
- if not field.type.fixed_size():
+ if not field.type.fixed_size() and not self.is_union:
length += 1
maxtypelen = max(maxtypelen, length)
def _c_complex_field(self, field, space=''):
- if (field.type.fixed_size() or
+ if (field.type.fixed_size() or self.is_union or
# in case of switch with switch children, don't make the field a pointer
# necessary for unserialize to work
(self.is_switch and field.type.is_switch)):
for b in self.bitcases:
space = ''
if b.type.has_name:
- _h(' struct _%s {', b.c_field_name)
+ _h(' struct {')
space = ' '
for field in b.type.fields:
_c_complex_field(self, field, space)
if b.type.has_name:
_h(' } %s;', b.c_field_name)
- _h('} %s;', self.c_type)
+ _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
def c_struct(self, name):
'''
_c_complex(self)
_c_iterator(self, name)
-def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
+def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
'''
Declares a request function.
'''
# What flag is passed to xcb_request
func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
+ if reply_fds:
+ if func_flags == '0':
+ func_flags = 'XCB_REQUEST_REPLY_FDS'
+ else:
+ func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
+
# Global extension id variable or NULL for xproto
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
if field.wire and not field.auto:
# We need to set the field up in the structure
wire_fields.append(field)
- if field.type.need_serialize or field.type.need_sizeof:
+ if field.type.c_need_serialize or field.type.c_need_sizeof:
serial_fields.append(field)
-
+
for field in param_fields:
- c_field_const_type = field.c_field_const_type
- if field.type.need_serialize and not aux:
+ c_field_const_type = field.c_field_const_type
+ if field.type.c_need_serialize and not aux:
c_field_const_type = "const void"
if len(c_field_const_type) > maxtypelen:
maxtypelen = len(c_field_const_type)
_c_setlevel(1)
_h('')
_h('/**')
- if self.doc:
+ if hasattr(self, "doc") and self.doc:
if self.doc.brief:
_h(' * @brief ' + self.doc.brief)
else:
_h(' *')
_h(' * @param c The connection')
param_names = [f.c_field_name for f in param_fields]
- if self.doc:
+ if hasattr(self, "doc") and self.doc:
for field in param_fields:
# XXX: hard-coded until we fix xproto.xml
base_func_name = self.c_request_name if not aux else self.c_aux_name
_h(' * @return A cookie')
_h(' *')
- if self.doc:
+ if hasattr(self, "doc") and self.doc:
if self.doc.description:
desc = self.doc.description
for name in param_names:
_h(' * No description yet')
else:
_h(' * Delivers a request to the X server.')
- _h(' * ')
+ _h(' *')
if checked:
_h(' * This form can be used only if the request will not cause')
_h(' * a reply to be generated. Any returned error will be')
_h(' * placed in the event queue.')
_h(' */')
_c('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** %s %s', cookie_type, func_name)
- _hc(' ** ')
-
- spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
- _hc(' ** @param xcb_connection_t%s *c', spacing)
-
- for field in param_fields:
- c_field_const_type = field.c_field_const_type
- if field.type.need_serialize and not aux:
- c_field_const_type = "const void"
- spacing = ' ' * (maxtypelen - len(c_field_const_type))
- _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
-
- _hc(' ** @returns %s', cookie_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('%s', cookie_type)
spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
count = len(param_fields)
for field in param_fields:
count = count - 1
- c_field_const_type = field.c_field_const_type
+ c_field_const_type = field.c_field_const_type
c_pointer = field.c_pointer
- if field.type.need_serialize and not aux:
+ if field.type.c_need_serialize and not aux:
c_field_const_type = "const void"
c_pointer = '*'
spacing = ' ' * (maxtypelen - len(c_field_const_type))
comma = ',' if count else ');'
- _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
+ _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
spacing, c_pointer, field.c_field_name, comma)
comma = ',' if count else ')'
- _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
+ _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
spacing, c_pointer, field.c_field_name, comma)
count = 2
- if not self.var_followed_by_fixed_fields:
+ if not self.c_var_followed_by_fixed_fields:
for field in param_fields:
if not field.type.fixed_size():
count = count + 2
- if field.type.need_serialize:
+ if field.type.c_need_serialize:
# _serialize() keeps track of padding automatically
count -= 1
dimension = count + 2
_c(' /* opcode */ %s,', self.c_request_name.upper())
_c(' /* isvoid */ %d', 1 if void else 0)
_c(' };')
- _c(' ')
+ _c('')
_c(' struct iovec xcb_parts[%d];', dimension)
_c(' %s xcb_ret;', func_cookie)
_c(' %s xcb_out;', self.c_type)
- if self.var_followed_by_fixed_fields:
+ if self.c_var_followed_by_fixed_fields:
_c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
_c(' void *xcb_aux = 0;')
-
+
for idx, f in enumerate(serial_fields):
if aux:
_c(' unsigned int i;')
_c(' unsigned int xcb_tmp_len;')
_c(' char *xcb_tmp;')
- _c(' ')
+ _c('')
# simple request call tracing
-# _c(' printf("in function %s\\n");' % func_name)
-
+# _c(' printf("in function %s\\n");' % func_name)
+
# fixed size fields
for field in wire_fields:
if field.type.fixed_size():
_c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
- serialize_args = get_serialize_params(context, type_obj,
- c_field_name,
+ serialize_args = get_serialize_params(context, type_obj,
+ c_field_name,
aux_var)[2]
return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
# calls in order to free dyn. all. memory
free_calls = []
- _c(' ')
- if not self.var_followed_by_fixed_fields:
+ _c('')
+ if not self.c_var_followed_by_fixed_fields:
_c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
_c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
_c(' xcb_parts[3].iov_base = 0;')
if not field.type.fixed_size():
_c(' /* %s %s */', field.type.c_type, field.c_field_name)
# default: simple cast to char *
- if not field.type.need_serialize and not field.type.need_sizeof:
+ if not field.type.c_need_serialize and not field.type.c_need_sizeof:
_c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
if field.type.is_list:
if field.type.member.fixed_size():
- _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
- _c_accessor_get_expr(field.type.expr, None),
+ _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
+ _c_accessor_get_expr(field.type.expr, None),
field.type.member.c_wiretype)
else:
list_length = _c_accessor_get_expr(field.type.expr, None)
-
+
length = ''
_c(" xcb_parts[%d].iov_len = 0;" % count)
_c(" xcb_tmp = (char *)%s;", field.c_field_name)
_c(" for(i=0; i<%s; i++) {" % list_length)
- _c(" xcb_tmp_len = %s(xcb_tmp);" %
+ _c(" xcb_tmp_len = %s(xcb_tmp);" %
(field.type.c_sizeof_name))
_c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
_c(" xcb_tmp += xcb_tmp_len;")
- _c(" }")
+ _c(" }")
else:
# not supposed to happen
raise Exception("unhandled variable size field %s" % field.c_field_name)
idx = serial_fields.index(field)
aux_var = '&xcb_aux%d' % idx
context = 'serialize' if aux else 'sizeof'
- _c(' xcb_parts[%d].iov_len = ', count)
+ _c(' xcb_parts[%d].iov_len =', count)
if aux:
serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
_c(' %s (%s);', field.type.c_serialize_name, serialize_args)
_c(' %s (%s);', func_name, serialize_args)
count += 1
- if not (field.type.need_serialize or field.type.need_sizeof):
+ if not (field.type.c_need_serialize or field.type.c_need_sizeof):
# the _serialize() function keeps track of padding automatically
_c(' xcb_parts[%d].iov_base = 0;', count)
_c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
count += 1
- # elif self.var_followed_by_fixed_fields:
+ # elif self.c_var_followed_by_fixed_fields:
else:
_c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
# request header: opcodes + length
- _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
+ _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
count += 1
# call _serialize()
buffer_var = '&xcb_aux'
free_calls.append(' free(xcb_aux);')
# no padding necessary - _serialize() keeps track of padding automatically
- _c(' ')
+ _c('')
+ for field in param_fields:
+ if field.isfd:
+ _c(' xcb_send_fd(c, %s);', field.c_field_name)
+
_c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
-
+
# free dyn. all. data, if any
for f in free_calls:
_c(f)
spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
spacing3 = ' ' * (len(self.c_reply_name) + 2)
-
+
# check if _unserialize() has to be called for any field
def look_for_special_cases(complex_obj):
unserialize_fields = []
# three cases: 1. field with special case
# 2. container that contains special case field
# 3. list with special case elements
- if field.type.var_followed_by_fixed_fields:
+ if field.type.c_var_followed_by_fixed_fields:
unserialize_fields.append(field)
elif field.type.is_container:
unserialize_fields += look_for_special_cases(field.type)
elif field.type.is_list:
- if field.type.member.var_followed_by_fixed_fields:
+ if field.type.member.c_var_followed_by_fixed_fields:
unserialize_fields.append(field)
if field.type.member.is_container:
unserialize_fields += look_for_special_cases(field.type.member)
return unserialize_fields
-
+
unserialize_fields = look_for_special_cases(self.reply)
-
+
_h('')
_h('/**')
_h(' * Return the reply')
_h(' * @param e The xcb_generic_error_t supplied')
_h(' *')
_h(' * Returns the reply of the request asked by')
- _h(' * ')
+ _h(' *')
_h(' * The parameter @p e supplied to this function must be NULL if')
_h(' * %s(). is used.', self.c_unchecked_name)
_h(' * Otherwise, it stores the error if any.')
_h(' * The returned value must be freed by the caller using free().')
_h(' */')
_c('')
- _hc('')
- _hc('/*****************************************************************************')
- _hc(' **')
- _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
- _hc(' ** ')
- _hc(' ** @param xcb_connection_t%s *c', spacing1)
- _hc(' ** @param %s cookie', self.c_cookie_type)
- _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
- _hc(' ** @returns %s *', self.c_reply_type)
- _hc(' **')
- _hc(' *****************************************************************************/')
- _hc(' ')
_hc('%s *', self.c_reply_type)
_hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
_hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
_h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
_c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
_c('{')
-
+
if len(unserialize_fields)>0:
# certain variable size fields need to be unserialized explicitly
- _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
+ _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
self.c_reply_type, self.c_reply_type)
_c(' int i;')
for field in unserialize_fields:
if field.type.is_list:
_c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
_c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
- _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
+ _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
field.c_field_name, field.c_field_name)
_c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
_c(' }')
# return the transformed reply
_c(' return reply;')
-
+
else:
_c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
_c('}')
+def _c_reply_has_fds(self):
+ for field in self.fields:
+ if field.isfd:
+ return True
+ return False
+
+def _c_reply_fds(self, name):
+ '''
+ Declares the function that returns fds related to the reply.
+ '''
+ spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
+ spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
+ _h('')
+ _h('/**')
+ _h(' * Return the reply fds')
+ _h(' * @param c The connection')
+ _h(' * @param reply The reply')
+ _h(' *')
+ _h(' * Returns the array of reply fds of the request asked by')
+ _h(' *')
+ _h(' * The returned value must be freed by the caller using free().')
+ _h(' */')
+ _c('')
+ _hc('int *')
+ _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
+ _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
+ _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
+ _c('{')
+
+ _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
+
+ _c('}')
+
+
def _c_opcode(name, opcode):
'''
Declares the opcode define for requests, events, and errors.
_h('')
_h('/** Opcode for %s. */', _n(name))
_h('#define %s %s', _n(name).upper(), opcode)
-
+
def _c_cookie(self, name):
'''
Declares the cookie type for a non-void request.
func_name = self.c_request_name if not aux else self.c_aux_name
def create_link(linkname):
- name = 'man/%s.3' % linkname
+ name = 'man/%s.%s' % (linkname, section)
if manpaths:
sys.stdout.write(name)
f = open(name, 'w')
- f.write('.so man3/%s.3' % func_name)
+ f.write('.so man%s/%s.%s' % (section, func_name, section))
f.close()
if manpaths:
- sys.stdout.write('man/%s.3 ' % func_name)
+ sys.stdout.write('man/%s.%s ' % (func_name, section))
# Our CWD is src/, so this will end up in src/man/
- f = open('man/%s.3' % func_name, 'w')
- f.write('.TH %s 3 %s "XCB" "XCB Requests"\n' % (func_name, today))
+ f = open('man/%s.%s' % (func_name, section), 'w')
+ f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
# Left-adjust instead of adjusting to both sides
f.write('.ad l\n')
f.write('.SH NAME\n')
- brief = self.doc.brief if self.doc else ''
+ brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
f.write('%s \\- %s\n' % (func_name, brief))
f.write('.SH SYNOPSIS\n')
# Don't split words (hyphenate)
c_pointer = field.c_pointer
if c_pointer == ' ':
c_pointer = ''
- if field.type.need_serialize and not aux:
+ if field.type.c_need_serialize and not aux:
c_field_const_type = "const void"
c_pointer = '*'
comma = ', ' if count else ');'
# special case: switch
switch_obj = self if self.is_switch else None
- if self.is_bitcase:
+ if self.is_case_or_bitcase:
switch_obj = self.parents[-1]
if switch_obj is not None:
c_type = switch_obj.c_type
# the reason is that switch is either a child of a request/reply or nested in another switch,
# so whenever we need to access a length field, we might need to refer to some anchestor type
switch_obj = self if self.is_switch else None
- if self.is_bitcase:
+ if self.is_case_or_bitcase:
switch_obj = self.parents[-1]
if switch_obj is not None:
c_type = switch_obj.c_type
for p in parents[2:] + [self]:
# the separator between parent and child is always '.' here,
# because of nested switch statements
- if not p.is_bitcase or (p.is_bitcase and p.has_name):
+ if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
prefix.append((p.name[-1], '.', p))
fields.update(_c_helper_field_mapping(p, prefix, flat=True))
field.enum = 'CW'
elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
field.enum = 'CW'
- if field.enum:
+ if hasattr(field, "enum") and field.enum:
# XXX: why the 'xcb' prefix?
key = ('xcb', field.enum)
if key in enums:
for (enam, eval) in enum.values:
count = count - 1
f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
- if enum.doc and enam in enum.doc.fields:
+ if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
f.write('%s\n' % desc)
else:
f.write('.RS 1i\n')
printed_enum = True
- if self.doc and field.field_name in self.doc.fields:
+ if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
desc = self.doc.fields[field.field_name]
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
if printed_enum:
continue
f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
printed_enum = False
- if field.enum:
+ if hasattr(field, "enum") and field.enum:
# XXX: why the 'xcb' prefix?
key = ('xcb', field.enum)
if key in enums:
f.write('.RS 1i\n')
printed_enum = True
- if self.reply.doc and field.field_name in self.reply.doc.fields:
+ if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
desc = self.reply.doc.fields[field.field_name]
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
if printed_enum:
# text description
f.write('.SH DESCRIPTION\n')
- if self.doc and self.doc.description:
+ if hasattr(self, "doc") and self.doc and self.doc.description:
desc = self.doc.description
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
lines = desc.split('\n')
'have to be handled in the event loop.\n\nIf you want to '
'handle errors directly with \\fIxcb_request_check\\fP '
'instead, use \\fI%s_checked\\fP. See '
- '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
+ '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
else:
f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
'calling the reply function \\fI%s\\fP.\n\nIf you want to '
'handle errors in the event loop instead, use '
- '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
+ '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
'details.\n') %
- (cookie_type, self.c_reply_name, base_func_name))
+ (cookie_type, self.c_reply_name, base_func_name, section))
f.write('.SH ERRORS\n')
- if self.doc:
- for errtype, errtext in self.doc.errors.iteritems():
+ if hasattr(self, "doc") and self.doc:
+ for errtype, errtext in sorted(self.doc.errors.items()):
f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
f.write('%s\n' % (errtext))
- if not self.doc or len(self.doc.errors) == 0:
+ if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
f.write('This request does never generate any errors.\n')
- if self.doc and self.doc.example:
+ if hasattr(self, "doc") and self.doc and self.doc.example:
f.write('.SH EXAMPLE\n')
f.write('.nf\n')
f.write('.sp\n')
f.write('\n'.join(lines) + '\n')
f.write('.fi\n')
f.write('.SH SEE ALSO\n')
- if self.doc:
- see = ['.BR %s (3)' % 'xcb-requests']
+ if hasattr(self, "doc") and self.doc:
+ see = ['.BR %s (%s)' % ('xcb-requests', section)]
if self.doc.example:
- see.append('.BR %s (3)' % 'xcb-examples')
- for seename, seetype in self.doc.see.iteritems():
+ see.append('.BR %s (%s)' % ('xcb-examples', section))
+ for seename, seetype in sorted(self.doc.see.items()):
if seetype == 'program':
see.append('.BR %s (1)' % seename)
elif seetype == 'event':
- see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+ see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
elif seetype == 'request':
- see.append('.BR %s (3)' % _n(('xcb', seename)))
+ see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
elif seetype == 'function':
- see.append('.BR %s (3)' % seename)
+ see.append('.BR %s (%s)' % (seename, section))
else:
see.append('TODO: %s (type %s)' % (seename, seetype))
f.write(',\n'.join(see) + '\n')
def _man_event(self, name):
if manpaths:
- sys.stdout.write('man/%s.3 ' % self.c_type)
+ sys.stdout.write('man/%s.%s ' % (self.c_type, section))
# Our CWD is src/, so this will end up in src/man/
- f = open('man/%s.3' % self.c_type, 'w')
- f.write('.TH %s 3 %s "XCB" "XCB Events"\n' % (self.c_type, today))
+ f = open('man/%s.%s' % (self.c_type, section), 'w')
+ f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
# Left-adjust instead of adjusting to both sides
f.write('.ad l\n')
f.write('.SH NAME\n')
- brief = self.doc.brief if self.doc else ''
+ brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
f.write('%s \\- %s\n' % (self.c_type, brief))
f.write('.SH SYNOPSIS\n')
# Don't split words (hyphenate)
if isinstance(field.type, PadType):
continue
f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
- if self.doc and field.field_name in self.doc.fields:
+ if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
desc = self.doc.fields[field.field_name]
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
f.write('%s\n' % desc)
# text description
f.write('.SH DESCRIPTION\n')
- if self.doc and self.doc.description:
+ if hasattr(self, "doc") and self.doc and self.doc.description:
desc = self.doc.description
desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
lines = desc.split('\n')
f.write('\n'.join(lines) + '\n')
- if self.doc and self.doc.example:
+ if hasattr(self, "doc") and self.doc and self.doc.example:
f.write('.SH EXAMPLE\n')
f.write('.nf\n')
f.write('.sp\n')
f.write('\n'.join(lines) + '\n')
f.write('.fi\n')
f.write('.SH SEE ALSO\n')
- if self.doc:
- see = ['.BR %s (3)' % 'xcb_generic_event_t']
+ if hasattr(self, "doc") and self.doc:
+ see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
if self.doc.example:
- see.append('.BR %s (3)' % 'xcb-examples')
- for seename, seetype in self.doc.see.iteritems():
+ see.append('.BR %s (%s)' % ('xcb-examples', section))
+ for seename, seetype in sorted(self.doc.see.items()):
if seetype == 'program':
see.append('.BR %s (1)' % seename)
elif seetype == 'event':
- see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+ see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
elif seetype == 'request':
- see.append('.BR %s (3)' % _n(('xcb', seename)))
+ see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
elif seetype == 'function':
- see.append('.BR %s (3)' % seename)
+ see.append('.BR %s (%s)' % (seename, section))
else:
see.append('TODO: %s (type %s)' % (seename, seetype))
f.write(',\n'.join(see) + '\n')
# Reply structure definition
_c_complex(self.reply)
# Request prototypes
- _c_request_helper(self, name, self.c_cookie_type, False, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False)
- if self.need_aux:
- _c_request_helper(self, name, self.c_cookie_type, False, True, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False, True)
+ has_fds = _c_reply_has_fds(self.reply)
+ _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
+ if self.c_need_aux:
+ _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
# Reply accessors
_c_accessors(self.reply, name + ('reply',), name)
_c_reply(self, name)
+ if has_fds:
+ _c_reply_fds(self, name)
else:
# Request prototypes
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
_c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
- if self.need_aux:
+ if self.c_need_aux:
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
_c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
'''
Exported function that handles event declarations.
'''
+
+ # The generic event structure xcb_ge_event_t has the full_sequence field
+ # at the 32byte boundary. That's why we've to inject this field into GE
+ # events while generating the structure for them. Otherwise we would read
+ # garbage (the internal full_sequence) when accessing normal event fields
+ # there.
+ force_packed = False
+ if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
+ event_size = 0
+ for field in self.fields:
+ if field.type.size != None and field.type.nmemb != None:
+ event_size += field.type.size * field.type.nmemb
+ if event_size == 32:
+ full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
+ idx = self.fields.index(field)
+ self.fields.insert(idx + 1, full_sequence)
+
+ # If the event contains any 64-bit extended fields, they need
+ # to remain aligned on a 64-bit boundary. Adding full_sequence
+ # would normally break that; force the struct to be packed.
+ force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
+ break
+
_c_type_setup(self, name, ('event',))
# Opcode define
if self.name == name:
# Structure definition
- _c_complex(self)
+ _c_complex(self, force_packed)
else:
# Typedef
_h('')
'union' : c_union,
'request' : c_request,
'event' : c_event,
- 'error' : c_error,
+ 'error' : c_error,
}
# Boilerplate below this point
# Check for the argument that specifies path to the xcbgen python package.
try:
- opts, args = getopt.getopt(sys.argv[1:], 'p:m')
+ opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
except getopt.GetoptError as err:
print(err)
- print('Usage: c_client.py [-p path] file.xml')
+ print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
sys.exit(1)
for (opt, arg) in opts:
+ if opt == '-c':
+ center_footer=arg
+ if opt == '-l':
+ left_footer=arg
+ if opt == '-s':
+ section=arg
if opt == '-p':
sys.path.insert(1, arg)
elif opt == '-m':
raise
# Ensure the man subdirectory exists
-if not os.path.exists('man'):
+try:
os.mkdir('man')
-
-today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
+except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
# Parse the xml header
module = Module(args[0], output)