From 8c2707773b3621fb8bbda9021d23944f5be34aab Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Tue, 13 Jul 2010 19:56:44 +0200 Subject: [PATCH 01/26] added xcb_sumof() with restriction to uint8_t --- src/xcb_util.c | 10 ++++++++++ src/xcbext.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/xcb_util.c b/src/xcb_util.c index 8c2a031..58bd12d 100644 --- a/src/xcb_util.c +++ b/src/xcb_util.c @@ -59,6 +59,16 @@ int xcb_popcount(uint32_t mask) return ((y + (y >> 3)) & 030707070707) % 077; } +int xcb_sumof(uint8_t *list, int len) +{ + int i, s = 0; + for(i=0; i Date: Tue, 13 Jul 2010 19:59:23 +0200 Subject: [PATCH 02/26] xkb: updated configure.ac/Makefile.am --- Makefile.am | 3 +++ configure.ac | 2 ++ src/Makefile.am | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/Makefile.am b/Makefile.am index ff9dea1..1f88b72 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,9 @@ endif if BUILD_XINPUT pkgconfig_DATA += xcb-xinput.pc endif +if BUILD_XKB +pkgconfig_DATA += xcb-xkb.pc +endif if BUILD_XPRINT pkgconfig_DATA += xcb-xprint.pc endif diff --git a/configure.ac b/configure.ac index c5f454b..67295f8 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,7 @@ XCB_EXTENSION(XFixes, "yes") XCB_EXTENSION(XFree86-DRI, "yes") XCB_EXTENSION(Xinerama, "yes") XCB_EXTENSION(XInput, "no") +XCB_EXTENSION(XKB, "no") XCB_EXTENSION(Xprint, "yes") XCB_EXTENSION(SELinux, "no") XCB_EXTENSION(XTest, "yes") @@ -189,6 +190,7 @@ xcb-xf86dri.pc xcb-xfixes.pc xcb-xinerama.pc xcb-xinput.pc +xcb-xkb.pc xcb-xprint.pc xcb-xselinux.pc xcb-xtest.pc diff --git a/src/Makefile.am b/src/Makefile.am index f0bdeaa..9b90914 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -168,6 +168,14 @@ libxcb_xinput_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xinput_la_SOURCES = xinput.c xinput.h endif +EXTSOURCES += xkb.c +if BUILD_XKB +lib_LTLIBRARIES += libxcb-xkb.la +libxcb_xkb_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xkb_la_LIBADD = $(XCB_LIBS) +nodist_libxcb_xkb_la_SOURCES = xkb.c xkb.h +endif + EXTSOURCES += xprint.c if BUILD_XPRINT lib_LTLIBRARIES += libxcb-xprint.la From 86704124b1fd62c30441ace1f3f8e2c316801c53 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Tue, 13 Jul 2010 20:06:08 +0200 Subject: [PATCH 03/26] new and still preliminary functions for switch; feautures include - API compatibility with valueparam - request _aux() auxiliary functions - _serialize() and _unserialize() auxiliary functions - new data type that allows mixing of fixed and variable size members --- src/c_client.py | 694 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 668 insertions(+), 26 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 4f3b089..469a7f5 100755 --- a/src/c_client.py +++ b/src/c_client.py @@ -273,6 +273,20 @@ def _c_type_setup(self, name, postfix): self.c_reply_type = _t(name + ('reply',)) self.c_cookie_type = _t(name + ('cookie',)) + self.c_aux_name = _n(name + ('aux',)) + self.c_aux_checked_name = _n(name + ('aux', 'checked')) + self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) + self.c_serialize_name = _n(name + ('serialize',)) + self.c_unserialize_name = _n(name + ('unserialize',)) + + # whether a request or reply has a switch field + self.need_aux = False + self.need_serialize = False + if self.is_switch: + self.need_serialize = True + for bitcase in self.bitcases: + _c_type_setup(bitcase.type, bitcase.field_type, ()) + if self.is_container: self.c_container = 'union' if self.is_union else 'struct' @@ -281,6 +295,10 @@ def _c_type_setup(self, name, postfix): first_field_after_varsized = None for field in self.fields: + # information about a fields anchestors + if self.is_reply or hasattr(self, 'in_reply'): + field.type.in_reply = True + _c_type_setup(field.type, field.field_type, ()) if field.type.is_list: _c_type_setup(field.type.member, field.field_type, ()) @@ -290,6 +308,10 @@ def _c_type_setup(self, name, postfix): field.c_field_name = _cpp(field.field_name) field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else '' field.c_pointer = ' ' if field.type.nmemb == 1 else '*' + if field.type.is_switch: + field.c_pointer = '*' + field.c_field_const_type = 'const ' + field.c_field_type + self.need_aux = 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 @@ -311,6 +333,541 @@ def _c_type_setup(self, name, postfix): prev_varsized_field = field prev_varsized_offset = 0 + # FIXME - structures with variable sized members, sort out when serialize() is needed + + # as switch does never appear at toplevel, + # continue here with type construction + if self.is_switch: + # special: switch C structs get pointer fields for variable-sized members + _c_complex(self) + # declare switch (un)packing functions + _c_accessors(self, name, name) + + if self.need_serialize: + if not hasattr(self, 'in_reply'): + _c_serialize(self) + _c_unserialize(self) + +# _c_type_setup() + +def get_request_fields(self): + param_fields = [] + wire_fields = [] + + for field in self.fields: + if field.visible: + # the field should appear as a parameter in the function call + param_fields.append(field) + if field.wire and not field.auto: + if field.type.fixed_size() and not self.is_switch: + # need to set the field up in the xcb_out structure + wire_fields.append(field) + # fields like 'pad0' are skipped! + + return (param_fields, wire_fields) +# get_request_fields() + +def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase=False): + prefix_str = prefix + need_padding = False + + if prefix != '': + prefix_str += "->" + if hasattr(complex_type, 'type'): + self = complex_type.type + complex_name = complex_type.name + else: + self = complex_type + complex_name = '_aux' + + if self.is_switch: + switch_expr = _c_accessor_get_expr(self.expr) + need_padding = True + for b in self.bitcases: + bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) + code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) + unserialize_fields(b.type, code_lines, space="%s " % space, + prefix="%s%s" % (prefix_str, complex_name), bitcase=True) + code_lines.append(' }') + + else: + for field in self.fields: + if not ((field.wire and not field.auto) or field.visible): + continue + + length = "sizeof(%s)" % field.c_field_type + + # 1. fields with fixed size + if field.type.fixed_size(): + need_padding = True + value = ' _aux->%s = (%s) *xcb_tmp;' % (field.c_field_name, field.type.c_type) + # FIXME - lists + + # 2. fields with variable size + else: + #if need_padding: + # unserialize: always calculate padding before variable sized fields + code_lines.append('%s if (0 != xcb_block_len) {' % space) + code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) + code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) + code_lines.append('%s xcb_block_len = 0;' % space) + code_lines.append('%s }' % space) + + # FIXME + print("unserialize not yet implemented for variable size fields like %s" % field.c_field_name) + + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + if field.type.is_list: + # FIXME - list with variable-sized elements + if field.type.size is None: + errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' + sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) + length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, prefix), field.type.member.c_wiretype) + elif field.type.is_switch: + # switch is handled by this function as a special case + unserialize_fields(field.type, code_lines, space, prefix="%s%s" % (prefix_str, field.c_field_name)) + else: + # FIXME - variable sized field that is not a list + errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' + sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) + length = '%s * sizeof(%s)' % ('Uh oh', field.type.c_wiretype) + + # save serialization C code + if value is not None: + if field.type.fixed_size(): + # field appears in the request structure + code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) + else: + code_lines.append('%s /* %s */' % (space, field.c_field_name)) + + # _aux->XXX = + code_lines.append('%s%s' % (space, value)) + if field.type.fixed_size(): + code_lines.append('%s xcb_block_len += %s;' % (space, length)) + code_lines.append('%s xcb_tmp += %s;' % (space, length)) + else: + # take account of padding + code_lines.append('%s xcb_block_len = %s;' % (space, length)) + code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) + code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) + code_lines.append('%s xcb_block_len = 0;' % space) + + if not bitcase: + code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) + #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) + +# unserialize_fields() + + +def serialize_fields(complex_type, code_lines=[], temp_vars=set(), + space='', prefix='', serialize_fixed_size_fields=False, + bitcase=False): + """ + helper routine to build up iovec arrays that will later be copied into a single buffer + + complex_type - encapsulating Type/Field + code_lines, temp_vars - containers for generated code & variable declarations + space - extra space to be inserted before any statement + prefix - prefix to be used for struct members, needed for switch/bitcase mapping + bitcase - flags whether fields are bitcase members + """ + + # count -> no. of entries in xcb_parts array + count = 0 + # flag to mark wether explicit padding needs to be inserted + need_padding = False + prefix_str = prefix + if prefix != '': + prefix_str += "->" + + if hasattr(complex_type, 'type'): + self = complex_type.type + complex_name = complex_type.name + else: + self = complex_type + complex_name = '_aux' + + def end_block(count): + "end a block => insert padding" + if need_padding and not bitcase: + code_lines.append(' /* padding */') + code_lines.append(' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;') + code_lines.append(' xcb_pad = -xcb_block_len & 3;') + code_lines.append(' xcb_parts[xcb_parts_idx].iov_len = xcb_pad;') + code_lines.append(' xcb_parts_idx++;') + code_lines.append('') + code_lines.append(' xcb_buffer_len += xcb_pad + %s;' % 'xcb_block_len') + code_lines.append('') + count += 1 + return count + # end_block() + + def insert_padding(count): + code_lines.append('%s /* implicit padding */' % space) + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + code_lines.append('%s if (0 != xcb_pad) {' % space) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 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 xcb_parts_idx++;' % space) + code_lines.append('%s }' % space) + return count + 1 + # insert_padding() + + # special case - if self.is_switch, all fields need to be serialized conditionally + if self.is_switch: + switch_expr = _c_accessor_get_expr(self.expr) + need_padding = True + + for b in self.bitcases: + bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) + code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) + + count += serialize_fields(b.type, code_lines, temp_vars, '%s ' % space, + prefix="%s%s" % (prefix_str, complex_name), + serialize_fixed_size_fields=True, bitcase=True) + code_lines.append(' }') + + else: + for field in self.fields: + value = None + + # sort out invisible fields + if not ((field.wire and not field.auto) or field.visible): + continue + # else + length = "sizeof(%s)" % field.c_field_type + + # 1. fields with fixed size + # fixed size fields are not always handled here, + # dependent on serialize_fixed_size_fields + if field.type.fixed_size() and serialize_fixed_size_fields: + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' + need_padding = True + + if field.type.is_expr: + # need to register a temporary variable for the expression + if field.type.c_type is None: + raise Exception("type for field '%s' (expression '%s') unkown" % + (field.field_name, _c_accessor_get_expr(field.type.expr))) + temp_vars.add(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, + _c_accessor_get_expr(field.type.expr, prefix))) + value += "&xcb_expr_%s;" % field.field_name + + elif field.type.is_pad: + if field.type.nmemb == 1: + temp_vars.add(' unsigned int xcb_pad = 0;') + temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') + value += "&xcb_pad;" + else: + value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb + length += "*%d" % field.type.nmemb + + else: + # non-list type with fixed size + if field.type.nmemb == 1: + value += "&%s%s;" % (prefix_str, field.c_field_name) + # list with nmemb (fixed size) elements + else: + value += '%s%s;' % (prefix_str, field.c_field_name) + length = '%d' % field.type.nmemb + + # 2. fields with variable size + elif not field.type.fixed_size(): + # always calculate padding before variable sized fields + count = insert_padding(count) + code_lines.append('%s xcb_block_len = 0;' % space) + + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + + if field.type.is_list: + # FIXME - list of variable length with variable size elements + if field.type.size is None: + errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' + sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) + length = 'undefined' + # list of variable length with fixed size elements + else: + length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, prefix), + field.type.member.c_wiretype) + + elif field.type.is_switch: + # switch is handled at the beginning of this function as a special case + count += serialize_fields(field.type, code_lines, temp_vars, space, + prefix="%s%s" % (prefix_str, field.c_field_name)) + + else: + # FIXME - variable sized field that is not a list + errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' + sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) + length = '%s * sizeof(%s)' % ('Uh oh', field.type.c_wiretype) + + # 3. save serialization C code + if value is not None: + # insert a comment so one can easily trace back to the XML + if field.type.fixed_size(): + # field belongs to some anchestor structure + code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) + else: + code_lines.append('%s /* %s */' % (space, field.c_field_name)) + + # set xcb_parts[].iov_base and xcb_parts[].iov_len + code_lines.append('%s%s' % (space, value)) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length)) + # increase xcb_parts index + code_lines.append('%s xcb_parts_idx++;' % space) + count += 1 + + # record required memory + if field.type.fixed_size(): + code_lines.append('%s xcb_block_len += %s;' % (space, length)) + else: + # FIXME + count = insert_padding(count) + # raise Exception("obsolete - should not be reached") + # code_lines.append('%s xcb_unpadded = xcb_parts[xcb_parts_idx].iov_len;' % space) + + count = end_block(count) + if count > 0: + temp_vars.add(' unsigned int xcb_parts_idx = 0;') + temp_vars.add(' unsigned int xcb_block_len = 0;') + if need_padding: + temp_vars.add(' unsigned int xcb_pad = 0;') + temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') + return count +# serialize_fields() + +def _c_switch_aux_params(self): + # get the fields referenced by the switch expression + def get_expr_fields(expr): + if expr.op is None: + if expr.lenfield_name is not None: + return [expr.lenfield_name] + else: + if expr.op == '~': + return get_expr_fields(expr.rhs) + elif expr.op == 'popcount': + return get_expr_fields(expr.rhs) + elif expr.op == 'sumof': + return [expr.lenfield_name] + elif expr.op == 'enumref': + return [] + else: + return get_expr_fields(expr.lhs) + get_expr_fields(expr.rhs) + # get_expr_fields() + + # resolve the field names with the parent structure(s) + unresolved_fields = get_expr_fields(self.expr) + expr_fields = dict.fromkeys(unresolved_fields) + for p in reversed(self.parent): + parent_fields = dict((f.field_name, f) for f in p.fields) + if len(unresolved_fields) == 0: + break + for f in parent_fields.keys(): + if f in unresolved_fields: + expr_fields[f] = parent_fields[f] + unresolved_fields.remove(f) + + if None in expr_fields.values(): + raise Exception("could not resolve all fields for %s" % self.name) + + params = [] + for name, field in expr_fields.iteritems(): + params.append((field, name)) + + return params +# _c_switch_aux_params() + +def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize=False): + param_fields, wire_fields = get_request_fields(self) + if self.is_switch: + switch_params = _c_switch_aux_params(self) + param_fields += [s[0] for s in switch_params] + + # _serialize function parameters + params = [('void', '**', buffer_var)] + # parameter fields if any + if self.is_switch: + for p in switch_params: + typespec = p[0].c_field_const_type + pointerspec = p[0].c_pointer + params.append((typespec, pointerspec, p[0].c_field_name)) + # aux argument - structure to be serialized + if not unserialize: + params.append(('const %s' % self.c_type, '*', aux_var)) + else: + params.append(('%s' % self.c_type, '*', aux_var)) + if not self.is_switch: + for p in param_fields: + if not p.type.fixed_size(): + params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) + return (param_fields, wire_fields, params) +# get_serialize_params() + +def _c_serialize(self): + _h_setlevel(1) + _c_setlevel(1) + + _hc('') + # _serialize() returns the buffer size + _hc('int') + + variable_size_fields = 0 + # maximum space required for type definition of function arguments + maxtypelen = 0 + param_fields, wire_fields, params = get_serialize_params(self) + + # 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])) + + # write to .c/.h + for p in range(len(params)): + line = "" + typespec, pointerspec, field_name = params[p] + indent = ' '*(len(self.c_serialize_name)+2) + # p==0: function declaration + if 0==p: + line = "%s (" % self.c_serialize_name + indent = '' + spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) + line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) + if p < len(params)-1: + _hc("%s," % line) + else: + _h("%s);" % line) + _c("%s)" % line) + + _c('{') + if not self.is_switch: + _c(' %s *xcb_out = *_buffer;', self.c_type) + _c(' unsigned int xcb_buffer_len = sizeof(%s);', self.c_type) + else: + _c(' char *xcb_out = *_buffer;') + _c(' unsigned int xcb_buffer_len = 0;') + if variable_size_fields > 0: + code_lines = [] + temp_vars = set() + count = serialize_fields(self, code_lines, temp_vars, + serialize_fixed_size_fields=False) + # update variable size fields + variable_size_fields = count + _c(' struct iovec xcb_parts[%d];', count) + for t in temp_vars: + _c(t) + _c(' char *xcb_tmp;') + _c(' unsigned int i;') + if not self.is_switch: + _c(' unsigned int xcb_out_pad = -xcb_buffer_len & 3;') + _c(' /* add size of padding */') + _c(' xcb_buffer_len += xcb_out_pad;') + + _c('') + + if variable_size_fields > 0: + for l in code_lines: + _c(l) + + # variable sized fields have been collected, now + # allocate memory and copy everything into a continuous memory area + _c(' if (NULL == xcb_out) {') + _c(' /* allocate memory */') + _c(' *_buffer = malloc(xcb_buffer_len);') + _c(' xcb_out = *_buffer;') + _c(' }') + _c('') + + # fill in struct members + if not self.is_switch: + 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: + _c(' xcb_tmp = (char*)++xcb_out;') + _c(' xcb_tmp += xcb_out_pad;') + else: + _c(' xcb_tmp = xcb_out;') + + # variable sized fields + _c(' for(i=0; i maxtypelen: - maxtypelen = len(field.c_field_type) + length = len(field.c_field_type) + if field.type.fixed_size(): + length += 1 + if length > maxtypelen: + maxtypelen = length for field in struct_fields: - spacing = ' ' * (maxtypelen - len(field.c_field_type)) - _h(' %s%s %s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) + if field.type.fixed_size(): + spacing = ' ' * (maxtypelen - len(field.c_field_type)) + _h(' %s%s %s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) + else: + spacing = ' ' * (maxtypelen - (len(field.c_field_type) - 1)) + _h(' %s%s *%s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) _h('} %s;', self.c_type) @@ -692,7 +1279,7 @@ def c_union(self, name): _c_complex(self) _c_iterator(self, name) -def _c_request_helper(self, name, cookie_type, void, regular): +def _c_request_helper(self, name, cookie_type, void, regular, aux=False): ''' Declares a request function. ''' @@ -725,15 +1312,16 @@ def _c_request_helper(self, name, cookie_type, void, regular): func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0' # What our function name is - func_name = self.c_request_name + func_name = self.c_request_name if not aux else self.c_aux_name if checked: - func_name = self.c_checked_name + func_name = self.c_checked_name if not aux else self.c_aux_checked_name if unchecked: - func_name = self.c_unchecked_name + func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name param_fields = [] wire_fields = [] maxtypelen = len('xcb_connection_t') + serial_fields = [] for field in self.fields: if field.visible: @@ -742,10 +1330,15 @@ def _c_request_helper(self, name, cookie_type, void, regular): 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: + serial_fields.append(field) for field in param_fields: - if len(field.c_field_const_type) > maxtypelen: - maxtypelen = len(field.c_field_const_type) + c_field_const_type = field.c_field_const_type + if field.type.need_serialize and not aux: + c_field_const_type = "const void" + if len(c_field_const_type) > maxtypelen: + maxtypelen = len(c_field_const_type) _h_setlevel(1) _c_setlevel(1) @@ -777,8 +1370,11 @@ def _c_request_helper(self, name, cookie_type, void, regular): _hc(' ** @param xcb_connection_t%s *c', spacing) for field in param_fields: - spacing = ' ' * (maxtypelen - len(field.c_field_const_type)) - _hc(' ** @param %s%s %s%s', field.c_field_const_type, spacing, field.c_pointer, field.c_field_name) + 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(' **') @@ -796,16 +1392,24 @@ def _c_request_helper(self, name, cookie_type, void, regular): count = len(param_fields) for field in param_fields: count = count - 1 - spacing = ' ' * (maxtypelen - len(field.c_field_const_type)) + 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)) comma = ',' if count else ');' - _h('%s%s%s %s%s /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma) + _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, + spacing, field.c_pointer, field.c_field_name, comma) comma = ',' if count else ')' - _c('%s%s%s %s%s /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma) + _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, + spacing, field.c_pointer, field.c_field_name, comma) count = 2 for field in param_fields: if not field.type.fixed_size(): count = count + 2 + if field.type.need_serialize: + # _serialize() keeps track of padding automatically + count -= 1 _c('{') _c(' static const xcb_protocol_request_t xcb_req = {') @@ -815,16 +1419,20 @@ def _c_request_helper(self, name, cookie_type, void, regular): _c(' /* isvoid */ %d', 1 if void else 0) _c(' };') _c(' ') + _c(' struct iovec xcb_parts[%d];', count + 2) _c(' %s xcb_ret;', func_cookie) _c(' %s xcb_out;', self.c_type) + for idx, f in enumerate(serial_fields): + _c(' %s xcb_aux%d;', f.type.c_type, idx) _c(' ') - + _c(' printf("in function %s\\n");' % func_name) + + # fixed size fields for field in wire_fields: if field.type.fixed_size(): if field.type.is_expr: _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) - elif field.type.is_pad: if field.type.nmemb == 1: _c(' xcb_out.%s = 0;', field.c_field_name) @@ -842,19 +1450,46 @@ def _c_request_helper(self, name, cookie_type, void, regular): _c(' xcb_parts[3].iov_base = 0;') _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') + # calls in order to free dyn. all. memory + free_calls = [] count = 4 for field in param_fields: if not field.type.fixed_size(): _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + if field.type.need_serialize: + idx = serial_fields.index(field) + serialize_args = get_serialize_params(field.type, + field.c_field_name, + '&xcb_aux%d' % idx, + )[2] + serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) + _c(' xcb_parts[%d].iov_len = ', count) + if aux: + _c(' %s (%s);', field.type.c_serialize_name, serialize_args) + free_calls.append(' free(xcb_parts[%d].iov_base);' % count) + else: + _c(' %s (%s);', field.type.c_unserialize_name, serialize_args) if field.type.is_list: - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) - else: - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 'Uh oh', field.type.c_wiretype) - _c(' xcb_parts[%d].iov_base = 0;', count + 1) - _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count + 1, count) - count = count + 2 + _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, + _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) + elif not field.type.need_serialize: + # FIXME - _serialize() + _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', + count, 'Uh oh', field.type.c_wiretype) + + count += 1 + if not field.type.need_serialize: + # 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 + _c(' ') _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) _c(' return xcb_ret;') _c('}') @@ -948,6 +1583,9 @@ def c_request(self, name): # 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) # Reply accessors _c_accessors(self.reply, name + ('reply',), name) _c_reply(self, name) @@ -955,6 +1593,10 @@ def c_request(self, name): # 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: + _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True) + _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True) + def c_event(self, name): ''' @@ -1002,7 +1644,7 @@ output = {'open' : c_open, 'union' : c_union, 'request' : c_request, 'event' : c_event, - 'error' : c_error + 'error' : c_error, } # Boilerplate below this point From d0031456097f009bdb82fb979924e71ca38c539b Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Tue, 13 Jul 2010 20:08:51 +0200 Subject: [PATCH 04/26] xkb: added pkg config file --- xcb-xkb.pc.in | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 xcb-xkb.pc.in diff --git a/xcb-xkb.pc.in b/xcb-xkb.pc.in new file mode 100644 index 0000000..31ccaa3 --- /dev/null +++ b/xcb-xkb.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: XCB XKB +Description: XCB Keyboard Extension (EXPERIMENTAL) +Version: @PACKAGE_VERSION@ +Requires: xcb +Libs: -L${libdir} -lxcb-xinput +Cflags: -I${includedir} From 4e665e1580ece7bc9505f3a2f657959669ffcd05 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Thu, 15 Jul 2010 18:43:43 +0200 Subject: [PATCH 05/26] added generating code for _serialize() in case of variable sized structs (largely untested) --- src/c_client.py | 267 ++++++++++++++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 102 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 469a7f5..66f36be 100755 --- a/src/c_client.py +++ b/src/c_client.py @@ -23,6 +23,10 @@ _clines = [] _clevel = 0 _ns = None +# global variable to keep track of serializers +# due to weird dependencies, I see no way to do this more elegant at the moment +finished_serializers = [] + def _h(fmt, *args): ''' Writes the given line to the header file. @@ -158,6 +162,7 @@ def c_open(self): _h('') _h('#include "xcb.h"') + _c('#include ') _c('#include ') _c('#include ') _c('#include "xcbext.h"') @@ -302,6 +307,9 @@ def _c_type_setup(self, name, postfix): _c_type_setup(field.type, field.field_type, ()) if field.type.is_list: _c_type_setup(field.type.member, field.field_type, ()) + # FIXME - structures with variable sized members, sort out when serialize() is needed + if (field.type.nmemb is None): # and not field.type.member.fixed_size(): + self.need_serialize = 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 @@ -331,23 +339,23 @@ def _c_type_setup(self, name, postfix): else: self.last_varsized_field = field prev_varsized_field = field - prev_varsized_offset = 0 - - # FIXME - structures with variable sized members, sort out when serialize() is needed + prev_varsized_offset = 0 # as switch does never appear at toplevel, # continue here with type construction if self.is_switch: + print "switch", self.name # special: switch C structs get pointer fields for variable-sized members _c_complex(self) # declare switch (un)packing functions _c_accessors(self, name, name) - if self.need_serialize: - if not hasattr(self, 'in_reply'): + if self.need_serialize and not self.is_bitcase: + if self.c_serialize_name not in finished_serializers: + # if not hasattr(self, 'in_reply'): _c_serialize(self) - _c_unserialize(self) - + _c_unserialize(self) + finished_serializers.append(self.c_serialize_name) # _c_type_setup() def get_request_fields(self): @@ -363,16 +371,19 @@ def get_request_fields(self): # need to set the field up in the xcb_out structure wire_fields.append(field) # fields like 'pad0' are skipped! - + return (param_fields, wire_fields) # get_request_fields() def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase=False): - prefix_str = prefix need_padding = False + prefix_str = prefix + lenfield_prefix = "_aux" if prefix != '': prefix_str += "->" + lenfield_prefix += "->%s" % prefix + if hasattr(complex_type, 'type'): self = complex_type.type complex_name = complex_type.name @@ -380,6 +391,9 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase self = complex_type complex_name = '_aux' + param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) + param_names = [p[2] for p in params] + if self.is_switch: switch_expr = _c_accessor_get_expr(self.expr) need_padding = True @@ -389,41 +403,62 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase unserialize_fields(b.type, code_lines, space="%s " % space, prefix="%s%s" % (prefix_str, complex_name), bitcase=True) code_lines.append(' }') + # padding + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) + else: + # if not inside switch, simply cast the buffer to the respective xcb_out type + if not bitcase: + code_lines.append('%s /* %s */' % (space, self.c_type)) + code_lines.append('%s xcb_buffer_len = sizeof(%s);' % (space, self.c_type)) + code_lines.append('%s /* padding */' % space) + code_lines.append('%s xcb_buffer_len += -xcb_buffer_len & 3;' % space) + code_lines.append('%s xcb_tmp += xcb_buffer_len;' % space) + for field in self.fields: if not ((field.wire and not field.auto) or field.visible): continue length = "sizeof(%s)" % field.c_field_type - # 1. fields with fixed size + # 1. fields with fixed size need only be filled explicitly inside switch if field.type.fixed_size(): - need_padding = True - value = ' _aux->%s = (%s) *xcb_tmp;' % (field.c_field_name, field.type.c_type) - # FIXME - lists - + if bitcase: + need_padding = True + value = ' _aux->%s = (%s) *xcb_tmp;' % (field.c_field_name, field.type.c_type) + # FIXME - lists + else: + continue # 2. fields with variable size - else: - #if need_padding: - # unserialize: always calculate padding before variable sized fields - code_lines.append('%s if (0 != xcb_block_len) {' % space) - code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) - code_lines.append('%s xcb_tmp += xcb_block_len;' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) - code_lines.append('%s xcb_block_len = 0;' % space) - code_lines.append('%s }' % space) - + elif not field.type.fixed_size(): + # unserialize: always calculate padding before variable sized fields in bitcase # FIXME - print("unserialize not yet implemented for variable size fields like %s" % field.c_field_name) + if need_padding or bitcase: + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + code_lines.append('%s if (0 != xcb_pad) {' % space) + code_lines.append('%s xcb_tmp += xcb_pad;' % space) + code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) + code_lines.append('%s xcb_block_len = 0;' % space) + code_lines.append('%s xcb_pad = 0;' % space) + code_lines.append('%s }' % space) - value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) +# value = ' *%s = (%s *) xcb_tmp;' % (field.c_field_name, field.type.c_type) + value = '' if field.type.is_list: # FIXME - list with variable-sized elements if field.type.size is None: errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, prefix), field.type.member.c_wiretype) + expr = field.type.expr + # look if the list's lenfield is a struct member or a function argument + lf_prefix = lenfield_prefix + if expr.lenfield_name == _c_accessor_get_length(expr): + if expr.lenfield_name in param_names: + lf_prefix = '' + length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lf_prefix), field.type.member.c_wiretype) elif field.type.is_switch: # switch is handled by this function as a special case unserialize_fields(field.type, code_lines, space, prefix="%s%s" % (prefix_str, field.c_field_name)) @@ -431,7 +466,7 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase # FIXME - variable sized field that is not a list errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = '%s * sizeof(%s)' % ('Uh oh', field.type.c_wiretype) + length = '%s * sizeof(%s)' % ('undefined', field.type.c_wiretype) # save serialization C code if value is not None: @@ -442,23 +477,21 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase code_lines.append('%s /* %s */' % (space, field.c_field_name)) # _aux->XXX = - code_lines.append('%s%s' % (space, value)) + if value != '': + code_lines.append('%s%s' % (space, value)) if field.type.fixed_size(): code_lines.append('%s xcb_block_len += %s;' % (space, length)) code_lines.append('%s xcb_tmp += %s;' % (space, length)) else: # take account of padding code_lines.append('%s xcb_block_len = %s;' % (space, length)) - code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) - code_lines.append('%s xcb_tmp += xcb_block_len;' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + code_lines.append('%s xcb_tmp += xcb_block_len + xcb_pad;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) code_lines.append('%s xcb_block_len = 0;' % space) - - if not bitcase: - code_lines.append('%s xcb_block_len += -xcb_block_len & 3;' % space) - #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) - + code_lines.append('%s xcb_pad = 0;' % space) + need_padding = False + # unserialize_fields() @@ -480,8 +513,11 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # flag to mark wether explicit padding needs to be inserted need_padding = False prefix_str = prefix + lenfield_prefix = "_aux" if prefix != '': prefix_str += "->" + lenfield_prefix += "->%s" % prefix + if hasattr(complex_type, 'type'): self = complex_type.type @@ -490,31 +526,18 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), self = complex_type complex_name = '_aux' - def end_block(count): - "end a block => insert padding" - if need_padding and not bitcase: - code_lines.append(' /* padding */') - code_lines.append(' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;') - code_lines.append(' xcb_pad = -xcb_block_len & 3;') - code_lines.append(' xcb_parts[xcb_parts_idx].iov_len = xcb_pad;') - code_lines.append(' xcb_parts_idx++;') - code_lines.append('') - code_lines.append(' xcb_buffer_len += xcb_pad + %s;' % 'xcb_block_len') - code_lines.append('') - count += 1 - return count - # end_block() - def insert_padding(count): - code_lines.append('%s /* implicit padding */' % space) + code_lines.append('%s /* padding */' % space) code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) code_lines.append('%s if (0 != xcb_pad) {' % space) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 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 xcb_parts_idx++;' % space) code_lines.append('%s }' % 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 xcb_block_len = 0;' % space) + need_padding = True return count + 1 # insert_padding() @@ -531,6 +554,7 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), prefix="%s%s" % (prefix_str, complex_name), serialize_fixed_size_fields=True, bitcase=True) code_lines.append(' }') + count = insert_padding(count) else: for field in self.fields: @@ -545,7 +569,7 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # 1. fields with fixed size # fixed size fields are not always handled here, # dependent on serialize_fixed_size_fields - if field.type.fixed_size() and serialize_fixed_size_fields: + if field.type.fixed_size() and bitcase: value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' need_padding = True @@ -560,8 +584,6 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), elif field.type.is_pad: if field.type.nmemb == 1: - temp_vars.add(' unsigned int xcb_pad = 0;') - temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') value += "&xcb_pad;" else: value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb @@ -579,65 +601,70 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # 2. fields with variable size elif not field.type.fixed_size(): # always calculate padding before variable sized fields - count = insert_padding(count) - code_lines.append('%s xcb_block_len = 0;' % space) + if bitcase or need_padding: + count = insert_padding(count) + code_lines.append('%s xcb_block_len = 0;' % space) + need_padding = False + code_lines.append('%s /* %s */' % (space, field.c_field_name)) value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + code_lines.append('%s%s' % (space, value)) if field.type.is_list: - # FIXME - list of variable length with variable size elements + # list of variable length with variable size elements if field.type.size is None: errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = 'undefined' + 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 for(i=0; i<%s; i++) {' + % (space, _c_accessor_get_expr(field.type.expr, lenfield_prefix))) + code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name)) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space) + code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s }' % space) + code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space) + # list of variable length with fixed size elements else: - length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, prefix), + length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lenfield_prefix), field.type.member.c_wiretype) elif field.type.is_switch: # switch is handled at the beginning of this function as a special case - count += serialize_fields(field.type, code_lines, temp_vars, space, - prefix="%s%s" % (prefix_str, field.c_field_name)) - +# count += serialize_fields(field.type, code_lines, temp_vars, space, + # prefix="%s%s" % (prefix_str, field.c_field_name)) + # FIXME - call another serialize + sys.stderr.write("FIXME: call %s" % field.type.c_serialize_name) else: # FIXME - variable sized field that is not a list errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = '%s * sizeof(%s)' % ('Uh oh', field.type.c_wiretype) + length = '%s * sizeof(%s)' % ('undefined', field.type.c_wiretype) # 3. save serialization C code if value is not None: + # set xcb_parts[].iov_base and xcb_parts[].iov_len # insert a comment so one can easily trace back to the XML if field.type.fixed_size(): # field belongs to some anchestor structure code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) - else: - code_lines.append('%s /* %s */' % (space, field.c_field_name)) + code_lines.append('%s%s' % (space, value)) + if bitcase: + code_lines.append('%s xcb_block_len += %s;' % (space, length)) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space) - # set xcb_parts[].iov_base and xcb_parts[].iov_len - code_lines.append('%s%s' % (space, value)) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length)) # increase xcb_parts index code_lines.append('%s xcb_parts_idx++;' % space) count += 1 - # record required memory - if field.type.fixed_size(): - code_lines.append('%s xcb_block_len += %s;' % (space, length)) - else: + if not field.type.fixed_size(): # FIXME count = insert_padding(count) + need_padding = False # raise Exception("obsolete - should not be reached") # code_lines.append('%s xcb_unpadded = xcb_parts[xcb_parts_idx].iov_len;' % space) - count = end_block(count) - if count > 0: - temp_vars.add(' unsigned int xcb_parts_idx = 0;') - temp_vars.add(' unsigned int xcb_block_len = 0;') - if need_padding: - temp_vars.add(' unsigned int xcb_pad = 0;') - temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') return count # serialize_fields() @@ -689,7 +716,18 @@ def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize param_fields += [s[0] for s in switch_params] # _serialize function parameters - params = [('void', '**', buffer_var)] + if not unserialize: + params = [('void', '**', buffer_var)] + else: + params = [('const void', '*', buffer_var)] + + # make sure all required length fields are present + for p in param_fields: + if p.visible and not p.wire and not p.auto: + typespec = p.c_field_type + pointerspec = '' + params.append((typespec, pointerspec, p.c_field_name)) + # parameter fields if any if self.is_switch: for p in switch_params: @@ -699,9 +737,9 @@ def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize # aux argument - structure to be serialized if not unserialize: params.append(('const %s' % self.c_type, '*', aux_var)) - else: + elif self.is_switch: params.append(('%s' % self.c_type, '*', aux_var)) - if not self.is_switch: + if not self.is_switch and not unserialize: for p in param_fields: if not p.type.fixed_size(): params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) @@ -750,7 +788,8 @@ def _c_serialize(self): _c('{') if not self.is_switch: _c(' %s *xcb_out = *_buffer;', self.c_type) - _c(' unsigned int xcb_buffer_len = sizeof(%s);', 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) else: _c(' char *xcb_out = *_buffer;') _c(' unsigned int xcb_buffer_len = 0;') @@ -761,15 +800,15 @@ def _c_serialize(self): serialize_fixed_size_fields=False) # update variable size fields variable_size_fields = count - _c(' struct iovec xcb_parts[%d];', count) + _c(' unsigned int xcb_pad = 0;') + _c(' char xcb_pad0[3] = {0, 0, 0};') + _c(' struct iovec xcb_parts[%d];', count+1) + _c(' unsigned int xcb_parts_idx = 0;') + _c(' unsigned int xcb_block_len = 0;') for t in temp_vars: _c(t) _c(' char *xcb_tmp;') _c(' unsigned int i;') - if not self.is_switch: - _c(' unsigned int xcb_out_pad = -xcb_buffer_len & 3;') - _c(' /* add size of padding */') - _c(' xcb_buffer_len += xcb_out_pad;') _c('') @@ -777,6 +816,16 @@ def _c_serialize(self): for l in code_lines: _c(l) +# _c(' /* padding */') +# _c(' xcb_pad = -xcb_block_len & 3;') +# _c(' if (0 != xcb_pad) {') +# _c(' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;') +# _c(' xcb_parts[xcb_parts_idx].iov_len = xcb_pad;') +# _c(' xcb_parts_idx++;') +# _c(' }') +# _c(' xcb_buffer_len += xcb_block_len + xcb_pad;') + _c('') + # variable sized fields have been collected, now # allocate memory and copy everything into a continuous memory area _c(' if (NULL == xcb_out) {') @@ -845,7 +894,6 @@ def _c_unserialize(self): if 0==p: line = "%s (" % self.c_unserialize_name indent = '' - pointerspec = '*' spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) if p < len(params)-1: @@ -855,10 +903,14 @@ def _c_unserialize(self): _c("%s)" % line) _c('{') - _c(' char *xcb_tmp = _buffer;') + _c(' char *xcb_tmp = (char *)_buffer;') + if not self.is_switch: + _c(' const %s *_aux = (%s *)_buffer;', 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('') + code_lines = [] unserialize_fields(self, code_lines) for l in code_lines: @@ -1424,7 +1476,8 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' %s xcb_ret;', func_cookie) _c(' %s xcb_out;', self.c_type) for idx, f in enumerate(serial_fields): - _c(' %s xcb_aux%d;', f.type.c_type, idx) + if not aux: + _c(' %s xcb_aux%d;' % (f.type.c_type, idx)) _c(' ') _c(' printf("in function %s\\n");' % func_name) @@ -1455,13 +1508,23 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): count = 4 for field in param_fields: if not field.type.fixed_size(): - _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) - if field.type.need_serialize: + if not field.type.need_serialize: + _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + else: + if not aux: + _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + else: + _c(' xcb_parts[%d].iov_base = (char *) 0;', count) idx = serial_fields.index(field) - serialize_args = get_serialize_params(field.type, - field.c_field_name, - '&xcb_aux%d' % idx, - )[2] + if not aux: + serialize_args = get_serialize_params(field.type, + field.c_field_name, + '&xcb_aux%d' % idx)[2] + else: + serialize_args = get_serialize_params(field.type, + '&xcb_parts[%d].iov_base' % count, + field.c_field_name)[2] + serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) _c(' xcb_parts[%d].iov_len = ', count) if aux: From 566ae9baee20fb6147b94b89a26796087461bae8 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Tue, 20 Jul 2010 22:46:37 +0200 Subject: [PATCH 06/26] preliminary handling of further special cases in unserialize first attempts to unify serialize and unserialize --- src/c_client.py | 452 ++++++++++++++++++++++++++++++------------------ 1 file changed, 287 insertions(+), 165 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 66f36be..40df493 100755 --- a/src/c_client.py +++ b/src/c_client.py @@ -283,6 +283,10 @@ def _c_type_setup(self, name, postfix): self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) self.c_serialize_name = _n(name + ('serialize',)) self.c_unserialize_name = _n(name + ('unserialize',)) + if hasattr(self, 'reply'): + if self.reply is not None: + self.c_serialize_name = _n(name + ('reply', 'serialize')) + self.c_unserialize_name = _n(name + ('reply', 'unserialize')) # whether a request or reply has a switch field self.need_aux = False @@ -300,10 +304,6 @@ def _c_type_setup(self, name, postfix): first_field_after_varsized = None for field in self.fields: - # information about a fields anchestors - if self.is_reply or hasattr(self, 'in_reply'): - field.type.in_reply = True - _c_type_setup(field.type, field.field_type, ()) if field.type.is_list: _c_type_setup(field.type.member, field.field_type, ()) @@ -350,6 +350,7 @@ def _c_type_setup(self, name, postfix): # declare switch (un)packing functions _c_accessors(self, name, name) + # FIXME - in case of request/reply, serialize() is not always needed if self.need_serialize and not self.is_bitcase: if self.c_serialize_name not in finished_serializers: # if not hasattr(self, 'in_reply'): @@ -375,14 +376,222 @@ def get_request_fields(self): return (param_fields, wire_fields) # get_request_fields() -def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase=False): - need_padding = False +def get_switch_expr_fields(self): + # get the fields referenced by the switch expression + def get_expr_fields(expr): + if expr.op is None: + if expr.lenfield_name is not None: + return [expr.lenfield_name] + else: + if expr.op == '~': + return get_expr_fields(expr.rhs) + elif expr.op == 'popcount': + return get_expr_fields(expr.rhs) + elif expr.op == 'sumof': + return [expr.lenfield_name] + elif expr.op == 'enumref': + return [] + else: + return get_expr_fields(expr.lhs) + get_expr_fields(expr.rhs) + # get_expr_fields() + + # resolve the field names with the parent structure(s) + unresolved_fields = get_expr_fields(self.expr) + expr_fields = dict.fromkeys(unresolved_fields) + for p in reversed(self.parent): + parent_fields = dict((f.field_name, f) for f in p.fields) + for f in parent_fields.keys(): + if f in unresolved_fields: + expr_fields[f] = parent_fields[f] + unresolved_fields.remove(f) + if len(unresolved_fields) == 0: + break + + if None in expr_fields.values(): + raise Exception("could not resolve all fields for %s" % self.name) + params = expr_fields.values() + return params +# get_switch_expr_fields() + +def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize=False): + param_fields, wire_fields = get_request_fields(self) + if self.is_switch: + param_fields = get_switch_expr_fields(self) + + # _serialize function parameters + if not unserialize: + params = [('void', '**', buffer_var)] + else: + params = [('const void', '*', buffer_var)] + + # make sure all required length fields are present + for p in param_fields: + if p.visible and not p.wire and not p.auto: + typespec = p.c_field_type + pointerspec = '' + params.append((typespec, pointerspec, p.c_field_name)) + + # parameter fields if any + if self.is_switch: + for p in get_switch_expr_fields(self): + typespec = p.c_field_const_type + pointerspec = p.c_pointer + params.append((typespec, pointerspec, p.c_field_name)) + + # aux argument - structure to be serialized + if not unserialize: + params.append(('const %s' % self.c_type, '*', aux_var)) + elif self.is_switch: + params.append(('%s' % self.c_type, '*', aux_var)) + if not self.is_switch and not unserialize: + for p in param_fields: + if not p.type.fixed_size(): + params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) + return (param_fields, wire_fields, params) +# get_serialize_params() + +def _c_field_mapping(complex_type, context): + def get_prefix(field): + prefix = '' + if context in ('serialize', 'unserialize'): + if field.type.fixed_size() or complex_type.is_switch: + prefix = '_aux->' + else: + raise Exception("unknown context '%s' in c_field_mapping" % context) + return prefix + # get_prefix() + def get_field_name(fields, complex_type, prefix=''): + for f in complex_type.fields: + if '' == prefix: + prefix = get_prefix(f) + + fname = "%s%s" % (prefix, f.c_field_name) + if fields.has_key(f.field_name): + raise Exception("field name %s has been registered before" % f.field_name) + fields[f.field_name] = (fname, f) + if f.type.is_container: + new_prefix = "%s%s" % (prefix, f.c_field_name) + new_prefix += "." if f.type.is_switch else "->" + get_field_name(fields, f.type, new_prefix) + # get_field_name() + + # dict(field_name : (c_field_name, field)) + fields = {} + get_field_name(fields, complex_type) + + # switch: get the fields referenced by the switch expr as well + # these may not belong to any structure + if complex_type.is_switch: + fields += get_serialize_params() + + return fields +# _c_field_mapping() + +def _c_serialize_helper_prefix(prefix): prefix_str = prefix lenfield_prefix = "_aux" if prefix != '': prefix_str += "->" lenfield_prefix += "->%s" % prefix + return (prefix_str, lenfield_prefix) +# _c_serialize_helper_prefix + +def _c_serialize_helper_insert_padding(context, code_lines, space, count=0): + code_lines.append('%s /* padding */' % space) + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + code_lines.append('%s if (0 != xcb_pad) {' % space) + + if 'serialize' == context: + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) + code_lines.append('%s xcb_parts_idx++;' % space) + elif 'unserialize' == context: + code_lines.append('%s xcb_tmp += xcb_pad;' % space) + code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) + + code_lines.append('%s xcb_pad = 0;' % space) + code_lines.append('%s }' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) + code_lines.append('%s xcb_block_len = 0;' % space) + return count + 1 +# _c_serialize_helper_insert_padding() + +def _c_serialize_helper_switch(self, context, complex_name, code_lines, temp_vars, space, prefix, prefix_str): + switch_expr = _c_accessor_get_expr(self.expr) + for b in self.bitcases: + bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) + code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) + # FIXME: change function call depending on context + if 'unserialize' == context: + unserialize_fields(b.type, code_lines, temp_vars, space="%s " % space, + prefix="%s%s" % (prefix_str, complex_name), bitcase=True) + elif 'serialize' == context: + count += serialize_fields(b.type, code_lines, temp_vars, '%s ' % space, + prefix="%s%s" % (prefix_str, complex_name), + serialize_fixed_size_fields=True, bitcase=True) + code_lines.append(' }') + + if 'serialize' == context: + count = insert_padding(count) + return count + if 'unserialize' == context: + # padding + code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) + #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) +# _c_serialize_helper_switch + +def _c_serialize_helper_switch_field(self, field): + # switch is handled by this function as a special case + args = get_switch_expr_fields(field.type) + field_mapping = _c_field_mapping(self, 'unserialize') + c_field_names = '' + for a in args: + c_field_names += "%s, " % field_mapping[a.field_name][0] + switch_field_name = field_mapping[field.field_name][0] + length = "%s(xcb_tmp, %s&%s)" % (field.type.c_unserialize_name, + c_field_names, switch_field_name) + return length +# _c_serialize_helper_switch_field() + +def _c_serialize_helper_list_field(context, self, field, lenfield_prefix, code_lines, temp_vars, space): + expr = field.type.expr + param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) + param_names = [p[2] for p in params] + + # look if the list's lenfield is a struct member or a function argument + # special case: if the list has a length field, its name will returned + # unchanged by calling c_accessor_get_length(expr) + if expr.lenfield_name == _c_accessor_get_length(expr): + if expr.lenfield_name in param_names: + # the length field appears as separate argument in unserialize, + # so no need for a prefix + lenfield_prefix = '' + list_length = _c_accessor_get_expr(field.type.expr, lenfield_prefix) + + if 'unserialize' == context: + length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) + # FIXME? - list with variable-sized elements + if field.type.size is None: + length = '' + temp_vars.add(' unsigned int i, xcb_tmp_len;') + code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length)) + code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" % + (space, field.type.c_unserialize_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) + # errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' + # raise Exception(errmsg % (self.c_type, field.c_field_name)) + + return length +# _c_serialize_helper_list_field() + +def unserialize_fields(complex_type, code_lines=[], temp_vars=set(), space='', prefix='', bitcase=False): + need_padding = False + + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) if hasattr(complex_type, 'type'): self = complex_type.type @@ -391,40 +600,26 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase self = complex_type complex_name = '_aux' - param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) - param_names = [p[2] for p in params] - + # special case: switch is serialized by evaluating each bitcase separately if self.is_switch: - switch_expr = _c_accessor_get_expr(self.expr) need_padding = True - for b in self.bitcases: - bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) - code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) - unserialize_fields(b.type, code_lines, space="%s " % space, - prefix="%s%s" % (prefix_str, complex_name), bitcase=True) - code_lines.append(' }') - # padding - code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) - - + _c_serialize_helper_switch(self, 'unserialize', complex_name, code_lines, temp_vars, space, prefix, prefix_str) + + # all other data types can be evaluated one field a time else: - # if not inside switch, simply cast the buffer to the respective xcb_out type + # fixed sized fields: simply cast the buffer to the respective xcb_out type + # this would of course not work for switch/bitcase if not bitcase: - code_lines.append('%s /* %s */' % (space, self.c_type)) - code_lines.append('%s xcb_buffer_len = sizeof(%s);' % (space, self.c_type)) - code_lines.append('%s /* padding */' % space) - code_lines.append('%s xcb_buffer_len += -xcb_buffer_len & 3;' % space) - code_lines.append('%s xcb_tmp += xcb_buffer_len;' % space) + _c_serialize_helper_insert_padding('unserialize', code_lines, space) for field in self.fields: if not ((field.wire and not field.auto) or field.visible): continue + # generic length statement length = "sizeof(%s)" % field.c_field_type - # 1. fields with fixed size need only be filled explicitly inside switch + # switch/bitcase: fixed size fields must be considered explicitly if field.type.fixed_size(): if bitcase: need_padding = True @@ -432,43 +627,31 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase # FIXME - lists else: continue - # 2. fields with variable size + + # fields with variable size elif not field.type.fixed_size(): - # unserialize: always calculate padding before variable sized fields in bitcase + # switch/bitcase: always calculate padding before and after variable sized fields # FIXME if need_padding or bitcase: - code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - code_lines.append('%s if (0 != xcb_pad) {' % space) - code_lines.append('%s xcb_tmp += xcb_pad;' % space) - code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) - code_lines.append('%s xcb_block_len = 0;' % space) - code_lines.append('%s xcb_pad = 0;' % space) - code_lines.append('%s }' % space) + _c_serialize_helper_insert_padding('unserialize', code_lines, space) # value = ' *%s = (%s *) xcb_tmp;' % (field.c_field_name, field.type.c_type) value = '' - if field.type.is_list: - # FIXME - list with variable-sized elements - if field.type.size is None: - errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' - sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - expr = field.type.expr - # look if the list's lenfield is a struct member or a function argument - lf_prefix = lenfield_prefix - if expr.lenfield_name == _c_accessor_get_length(expr): - if expr.lenfield_name in param_names: - lf_prefix = '' - length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lf_prefix), field.type.member.c_wiretype) - elif field.type.is_switch: - # switch is handled by this function as a special case - unserialize_fields(field.type, code_lines, space, prefix="%s%s" % (prefix_str, field.c_field_name)) - else: - # FIXME - variable sized field that is not a list - errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' - sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = '%s * sizeof(%s)' % ('undefined', field.type.c_wiretype) - # save serialization C code + if field.type.is_list: + length = _c_serialize_helper_list_field('unserialize', + self, field, lenfield_prefix, + code_lines, temp_vars, space) + + elif field.type.is_switch: + length = _c_serialize_helper_switch_field(self, field) + + else: + length = "%s(xcb_tmp)" % (field.type.c_unserialize_name) + # errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' + # raise Exception(errmsg % (self.c_type, field.c_field_name)) + + # save unserialization C code if value is not None: if field.type.fixed_size(): # field appears in the request structure @@ -483,17 +666,16 @@ def unserialize_fields(complex_type, code_lines=[], space='', prefix='', bitcase code_lines.append('%s xcb_block_len += %s;' % (space, length)) code_lines.append('%s xcb_tmp += %s;' % (space, length)) else: - # take account of padding - code_lines.append('%s xcb_block_len = %s;' % (space, length)) + # padding + if length != '': + code_lines.append('%s xcb_block_len = %s;' % (space, length)) code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) code_lines.append('%s xcb_tmp += xcb_block_len + xcb_pad;' % space) code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) code_lines.append('%s xcb_block_len = 0;' % space) code_lines.append('%s xcb_pad = 0;' % space) need_padding = False - # unserialize_fields() - def serialize_fields(complex_type, code_lines=[], temp_vars=set(), space='', prefix='', serialize_fixed_size_fields=False, @@ -512,12 +694,7 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), count = 0 # flag to mark wether explicit padding needs to be inserted need_padding = False - prefix_str = prefix - lenfield_prefix = "_aux" - if prefix != '': - prefix_str += "->" - lenfield_prefix += "->%s" % prefix - + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) if hasattr(complex_type, 'type'): self = complex_type.type @@ -526,6 +703,9 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), self = complex_type complex_name = '_aux' + param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) + param_names = [p[2] for p in params] + def insert_padding(count): code_lines.append('%s /* padding */' % space) code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) @@ -563,12 +743,10 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # sort out invisible fields if not ((field.wire and not field.auto) or field.visible): continue - # else + length = "sizeof(%s)" % field.c_field_type - # 1. fields with fixed size - # fixed size fields are not always handled here, - # dependent on serialize_fixed_size_fields + # switch/bitcase: fixed size fields are serialized explicitly if field.type.fixed_size() and bitcase: value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' need_padding = True @@ -598,9 +776,9 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), value += '%s%s;' % (prefix_str, field.c_field_name) length = '%d' % field.type.nmemb - # 2. fields with variable size + # fields with variable size elif not field.type.fixed_size(): - # always calculate padding before variable sized fields + # calculate padding before variable sized fields only if necessary if bitcase or need_padding: count = insert_padding(count) code_lines.append('%s xcb_block_len = 0;' % space) @@ -608,6 +786,7 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), code_lines.append('%s /* %s */' % (space, field.c_field_name)) value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + length = '' code_lines.append('%s%s' % (space, value)) if field.type.is_list: @@ -627,7 +806,18 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # list of variable length with fixed size elements else: - length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lenfield_prefix), + # look if the list's lenfield is a struct member or a function argument + lf_prefix = lenfield_prefix + # special case: if the list has a length field, its name will returned + # unchanged by calling c_accessor_get_length(expr) + expr = field.type.expr + if expr.lenfield_name == _c_accessor_get_length(expr): + if expr.lenfield_name in param_names: + # the length field appears as separate argument in unserialize, + # so no need for a prefix + lf_prefix = '' + + length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lf_prefix), field.type.member.c_wiretype) elif field.type.is_switch: @@ -635,25 +825,27 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), # count += serialize_fields(field.type, code_lines, temp_vars, space, # prefix="%s%s" % (prefix_str, field.c_field_name)) # FIXME - call another serialize + value = '' sys.stderr.write("FIXME: call %s" % field.type.c_serialize_name) + length = 'undefined' else: # FIXME - variable sized field that is not a list errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) length = '%s * sizeof(%s)' % ('undefined', field.type.c_wiretype) - # 3. save serialization C code + # save serialization C code using xcb_parts[].iov_base and xcb_parts[].iov_len if value is not None: - # set xcb_parts[].iov_base and xcb_parts[].iov_len - # insert a comment so one can easily trace back to the XML if field.type.fixed_size(): # field belongs to some anchestor structure code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) code_lines.append('%s%s' % (space, value)) if bitcase: code_lines.append('%s xcb_block_len += %s;' % (space, length)) + if length != '': + if not field.type.fixed_size(): + code_lines.append('%s xcb_block_len = %s;' % (space, length)) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space) - # increase xcb_parts index code_lines.append('%s xcb_parts_idx++;' % space) count += 1 @@ -668,84 +860,6 @@ def serialize_fields(complex_type, code_lines=[], temp_vars=set(), return count # serialize_fields() -def _c_switch_aux_params(self): - # get the fields referenced by the switch expression - def get_expr_fields(expr): - if expr.op is None: - if expr.lenfield_name is not None: - return [expr.lenfield_name] - else: - if expr.op == '~': - return get_expr_fields(expr.rhs) - elif expr.op == 'popcount': - return get_expr_fields(expr.rhs) - elif expr.op == 'sumof': - return [expr.lenfield_name] - elif expr.op == 'enumref': - return [] - else: - return get_expr_fields(expr.lhs) + get_expr_fields(expr.rhs) - # get_expr_fields() - - # resolve the field names with the parent structure(s) - unresolved_fields = get_expr_fields(self.expr) - expr_fields = dict.fromkeys(unresolved_fields) - for p in reversed(self.parent): - parent_fields = dict((f.field_name, f) for f in p.fields) - if len(unresolved_fields) == 0: - break - for f in parent_fields.keys(): - if f in unresolved_fields: - expr_fields[f] = parent_fields[f] - unresolved_fields.remove(f) - - if None in expr_fields.values(): - raise Exception("could not resolve all fields for %s" % self.name) - - params = [] - for name, field in expr_fields.iteritems(): - params.append((field, name)) - - return params -# _c_switch_aux_params() - -def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize=False): - param_fields, wire_fields = get_request_fields(self) - if self.is_switch: - switch_params = _c_switch_aux_params(self) - param_fields += [s[0] for s in switch_params] - - # _serialize function parameters - if not unserialize: - params = [('void', '**', buffer_var)] - else: - params = [('const void', '*', buffer_var)] - - # make sure all required length fields are present - for p in param_fields: - if p.visible and not p.wire and not p.auto: - typespec = p.c_field_type - pointerspec = '' - params.append((typespec, pointerspec, p.c_field_name)) - - # parameter fields if any - if self.is_switch: - for p in switch_params: - typespec = p[0].c_field_const_type - pointerspec = p[0].c_pointer - params.append((typespec, pointerspec, p[0].c_field_name)) - # aux argument - structure to be serialized - if not unserialize: - params.append(('const %s' % self.c_type, '*', aux_var)) - elif self.is_switch: - params.append(('%s' % self.c_type, '*', aux_var)) - if not self.is_switch and not unserialize: - for p in param_fields: - if not p.type.fixed_size(): - params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) - return (param_fields, wire_fields, params) -# get_serialize_params() - def _c_serialize(self): _h_setlevel(1) _c_setlevel(1) @@ -909,10 +1023,14 @@ def _c_unserialize(self): _c(' unsigned int xcb_buffer_len = 0;') _c(' unsigned int xcb_block_len = 0;') _c(' unsigned int xcb_pad = 0;') - _c('') code_lines = [] - unserialize_fields(self, code_lines) + temp_vars = set() + unserialize_fields(self, code_lines, temp_vars) + for t in temp_vars: + _c(t) + _c('') + for l in code_lines: _c(l) _c('') @@ -1299,17 +1417,21 @@ def _c_complex(self): for field in struct_fields: length = len(field.c_field_type) - if field.type.fixed_size(): + # account for '*' pointer_spec + if not field.type.fixed_size(): length += 1 - if length > maxtypelen: - maxtypelen = length + maxtypelen = max(maxtypelen, length) for field in struct_fields: - if field.type.fixed_size(): + if (field.type.fixed_size() 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)): spacing = ' ' * (maxtypelen - len(field.c_field_type)) _h(' %s%s %s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) + else: - spacing = ' ' * (maxtypelen - (len(field.c_field_type) - 1)) + spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) _h(' %s%s *%s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) _h('} %s;', self.c_type) From 1c590d5a86ae854e53f388e40c952e92f11d59e6 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Thu, 22 Jul 2010 16:41:15 +0200 Subject: [PATCH 07/26] partial rewrite of serialize helper functions completed; _serialize() & _unserialize() have been tested for switch derived from valueparam --- src/c_client.py | 548 +++++++++++++++++++----------------------------- 1 file changed, 221 insertions(+), 327 deletions(-) mode change 100755 => 100644 src/c_client.py diff --git a/src/c_client.py b/src/c_client.py old mode 100755 new mode 100644 index 40df493..7b05077 --- a/src/c_client.py +++ b/src/c_client.py @@ -344,16 +344,14 @@ def _c_type_setup(self, name, postfix): # as switch does never appear at toplevel, # continue here with type construction if self.is_switch: - print "switch", self.name # special: switch C structs get pointer fields for variable-sized members _c_complex(self) - # declare switch (un)packing functions + # FIXME: declare switch (un)packing functions _c_accessors(self, name, name) # FIXME - in case of request/reply, serialize() is not always needed if self.need_serialize and not self.is_bitcase: if self.c_serialize_name not in finished_serializers: - # if not hasattr(self, 'in_reply'): _c_serialize(self) _c_unserialize(self) finished_serializers.append(self.c_serialize_name) @@ -369,7 +367,7 @@ def get_request_fields(self): param_fields.append(field) if field.wire and not field.auto: if field.type.fixed_size() and not self.is_switch: - # need to set the field up in the xcb_out structure + # field in the xcb_out structure wire_fields.append(field) # fields like 'pad0' are skipped! @@ -414,15 +412,15 @@ def get_switch_expr_fields(self): return params # get_switch_expr_fields() -def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize=False): +def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): param_fields, wire_fields = get_request_fields(self) if self.is_switch: param_fields = get_switch_expr_fields(self) # _serialize function parameters - if not unserialize: + if 'serialize' == context: params = [('void', '**', buffer_var)] - else: + elif 'unserialize' == context: params = [('const void', '*', buffer_var)] # make sure all required length fields are present @@ -440,18 +438,18 @@ def get_serialize_params(self, buffer_var='_buffer', aux_var='_aux', unserialize params.append((typespec, pointerspec, p.c_field_name)) # aux argument - structure to be serialized - if not unserialize: + if 'serialize' == context: params.append(('const %s' % self.c_type, '*', aux_var)) - elif self.is_switch: + elif 'unserialize' == context and self.is_switch: params.append(('%s' % self.c_type, '*', aux_var)) - if not self.is_switch and not unserialize: + if not self.is_switch and 'serialize' == context: for p in param_fields: if not p.type.fixed_size(): params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) return (param_fields, wire_fields, params) # get_serialize_params() -def _c_field_mapping(complex_type, context): +def _c_field_mapping(context, complex_type): def get_prefix(field): prefix = '' if context in ('serialize', 'unserialize'): @@ -468,6 +466,7 @@ def _c_field_mapping(complex_type, context): fname = "%s%s" % (prefix, f.c_field_name) if fields.has_key(f.field_name): + continue raise Exception("field name %s has been registered before" % f.field_name) fields[f.field_name] = (fname, f) if f.type.is_container: @@ -483,7 +482,8 @@ def _c_field_mapping(complex_type, context): # switch: get the fields referenced by the switch expr as well # these may not belong to any structure if complex_type.is_switch: - fields += get_serialize_params() + pass +# FIXME: fields += get_serialize_params(context, complex_type) return fields # _c_field_mapping() @@ -497,7 +497,8 @@ def _c_serialize_helper_prefix(prefix): return (prefix_str, lenfield_prefix) # _c_serialize_helper_prefix -def _c_serialize_helper_insert_padding(context, code_lines, space, count=0): +def _c_serialize_helper_insert_padding(context, code_lines, space): + code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) code_lines.append('%s /* padding */' % space) code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) code_lines.append('%s if (0 != xcb_pad) {' % space) @@ -508,44 +509,47 @@ def _c_serialize_helper_insert_padding(context, code_lines, space, count=0): code_lines.append('%s xcb_parts_idx++;' % space) elif 'unserialize' == context: code_lines.append('%s xcb_tmp += xcb_pad;' % space) - code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) - + + code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) code_lines.append('%s xcb_pad = 0;' % space) code_lines.append('%s }' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) code_lines.append('%s xcb_block_len = 0;' % space) - return count + 1 + + return 1 # _c_serialize_helper_insert_padding() -def _c_serialize_helper_switch(self, context, complex_name, code_lines, temp_vars, space, prefix, prefix_str): +def _c_serialize_helper_switch(context, self, complex_name, + code_lines, temp_vars, + space, prefix): + count = 0 + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) switch_expr = _c_accessor_get_expr(self.expr) + for b in self.bitcases: bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) - # FIXME: change function call depending on context - if 'unserialize' == context: - unserialize_fields(b.type, code_lines, temp_vars, space="%s " % space, - prefix="%s%s" % (prefix_str, complex_name), bitcase=True) - elif 'serialize' == context: - count += serialize_fields(b.type, code_lines, temp_vars, '%s ' % space, - prefix="%s%s" % (prefix_str, complex_name), - serialize_fixed_size_fields=True, bitcase=True) + + _c_serialize_helper_fields(context, b.type, + code_lines, temp_vars, + space="%s " % space, + prefix="%s%s" % (prefix_str, complex_name), + is_bitcase = True) code_lines.append(' }') if 'serialize' == context: - count = insert_padding(count) - return count + count = _c_serialize_helper_insert_padding(context, code_lines, space) if 'unserialize' == context: # padding code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - #code_lines.append('%s xcb_tmp += xcb_block_len;' % space) code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) + + return count # _c_serialize_helper_switch def _c_serialize_helper_switch_field(self, field): # switch is handled by this function as a special case args = get_switch_expr_fields(field.type) - field_mapping = _c_field_mapping(self, 'unserialize') + field_mapping = _c_field_mapping('unserialize', self) c_field_names = '' for a in args: c_field_names += "%s, " % field_mapping[a.field_name][0] @@ -555,9 +559,15 @@ def _c_serialize_helper_switch_field(self, field): return length # _c_serialize_helper_switch_field() -def _c_serialize_helper_list_field(context, self, field, lenfield_prefix, code_lines, temp_vars, space): +def _c_serialize_helper_list_field(context, self, field, + code_lines, temp_vars, + space, prefix): + """ + helper function for (un)serialize to cope with lists of variable length + """ expr = field.type.expr - param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + param_fields, wire_fields, params = get_serialize_params('unserialize', self) param_names = [p[2] for p in params] # look if the list's lenfield is a struct member or a function argument @@ -568,31 +578,162 @@ def _c_serialize_helper_list_field(context, self, field, lenfield_prefix, code_l # the length field appears as separate argument in unserialize, # so no need for a prefix lenfield_prefix = '' - list_length = _c_accessor_get_expr(field.type.expr, lenfield_prefix) + list_length = _c_accessor_get_expr(expr, lenfield_prefix) - if 'unserialize' == context: - length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) - # FIXME? - list with variable-sized elements - if field.type.size is None: - length = '' - temp_vars.add(' unsigned int i, xcb_tmp_len;') + # default: list with fixed size elements + length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) + # list with variable-sized elements + if field.type.size is None: + length = '' + if 'unserialize' == context: + temp_vars.add(' unsigned int i;') + temp_vars.add(' unsigned int xcb_tmp_len;') code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length)) code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" % (space, field.type.c_unserialize_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) - # errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' - # raise Exception(errmsg % (self.c_type, field.c_field_name)) - + 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 for(i=0; i<%s; i++) {' + % (space, _c_accessor_get_expr(expr, lenfield_prefix))) + code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_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 unserialize_fields(complex_type, code_lines=[], temp_vars=set(), space='', prefix='', bitcase=False): - need_padding = False +def _c_serialize_helper_fields_fixed_size(context, self, field, + code_lines, temp_vars, + space, prefix): + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) + length = "sizeof(%s)" % field.c_field_type + + if 'unserialize' == context: + value = ' _aux->%s = *(%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type) + # FIXME? - lists + if field.type.is_list: + raise Exception('list with fixed number of elemens unhandled in _unserialize()') + elif 'serialize' == context: + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' + + if field.type.is_expr: + # need to register a temporary variable for the expression + if field.type.c_type is None: + raise Exception("type for field '%s' (expression '%s') unkown" % + (field.field_name, _c_accessor_get_expr(field.type.expr))) + temp_vars.add(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, + _c_accessor_get_expr(field.type.expr, prefix))) + value += "&xcb_expr_%s;" % field.field_name + + elif field.type.is_pad: + if field.type.nmemb == 1: + value += "&xcb_pad;" + else: + value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb + length += "*%d" % field.type.nmemb + + else: + # non-list type with fixed size + if field.type.nmemb == 1: + value += "&%s%s;" % (prefix_str, field.c_field_name) + # list with nmemb (fixed size) elements + else: + value += '%s%s;' % (prefix_str, field.c_field_name) + length = '%d' % field.type.nmemb + + return (value, length) +# _c_serialize_helper_fields_fixed_size() + +def _c_serialize_helper_fields_variable_size(context, self, field, + code_lines, temp_vars, + space, prefix): prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + if 'unserialize' == context: + value = '' + elif 'serialize' == context: + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + length = '' + + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + code_lines.append('%s /* %s */' % (space, field.c_field_name)) + + if field.type.is_list: + length = _c_serialize_helper_list_field(context, self, field, + code_lines, temp_vars, + space, prefix) + elif field.type.is_switch: + length = _c_serialize_helper_switch_field(self, field) + else: + length = "%s(xcb_tmp)" % (field.type.c_unserialize_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): + count = 0 + need_padding = False + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + + for field in self.fields: + if not ((field.wire and not field.auto) or field.visible): + continue + + # switch/bitcase: fixed size fields must be considered explicitly + if field.type.fixed_size(): + if is_bitcase: + value, length = _c_serialize_helper_fields_fixed_size(context, self, field, + code_lines, temp_vars, + space, 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: + _c_serialize_helper_insert_padding(context, code_lines, space) + + value, length = _c_serialize_helper_fields_variable_size(context, self, field, + code_lines, temp_vars, + space, prefix) + + # save (un)serialization C code + if '' != value: + code_lines.append('%s%s' % (space, value)) + if field.type.fixed_size() and is_bitcase: + code_lines.append('%s xcb_block_len += %s;' % (space, length)) + if 'unserialize' == context: + code_lines.append('%s xcb_tmp += %s;' % (space, length)) + else: + # padding + if '' != length: + code_lines.append('%s xcb_block_len = %s;' % (space, length)) + if 'unserialize' == context: + 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 = xcb_block_len;' % space) + code_lines.append('%s xcb_parts_idx++;' % space) + count += 1 + need_padding = True + + return count +# _c_serialize_helper_fields() + +def _c_serialize_helper(context, complex_type, + code_lines, temp_vars, + space='', prefix=''): + count = 0 if hasattr(complex_type, 'type'): self = complex_type.type complex_name = complex_type.name @@ -602,263 +743,26 @@ def unserialize_fields(complex_type, code_lines=[], temp_vars=set(), space='', p # special case: switch is serialized by evaluating each bitcase separately if self.is_switch: - need_padding = True - _c_serialize_helper_switch(self, 'unserialize', complex_name, code_lines, temp_vars, space, prefix, prefix_str) - + 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: - # fixed sized fields: simply cast the buffer to the respective xcb_out type - # this would of course not work for switch/bitcase - if not bitcase: - _c_serialize_helper_insert_padding('unserialize', code_lines, space) + # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type + if 'unserialize' == context: + code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type)) + code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + _c_serialize_helper_insert_padding(context, code_lines, space) - for field in self.fields: - if not ((field.wire and not field.auto) or field.visible): - continue + 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) - # generic length statement - length = "sizeof(%s)" % field.c_field_type - - # switch/bitcase: fixed size fields must be considered explicitly - if field.type.fixed_size(): - if bitcase: - need_padding = True - value = ' _aux->%s = (%s) *xcb_tmp;' % (field.c_field_name, field.type.c_type) - # FIXME - lists - else: - continue - - # fields with variable size - elif not field.type.fixed_size(): - # switch/bitcase: always calculate padding before and after variable sized fields - # FIXME - if need_padding or bitcase: - _c_serialize_helper_insert_padding('unserialize', code_lines, space) - -# value = ' *%s = (%s *) xcb_tmp;' % (field.c_field_name, field.type.c_type) - value = '' - - if field.type.is_list: - length = _c_serialize_helper_list_field('unserialize', - self, field, lenfield_prefix, - code_lines, temp_vars, space) - - elif field.type.is_switch: - length = _c_serialize_helper_switch_field(self, field) - - else: - length = "%s(xcb_tmp)" % (field.type.c_unserialize_name) - # errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' - # raise Exception(errmsg % (self.c_type, field.c_field_name)) - - # save unserialization C code - if value is not None: - if field.type.fixed_size(): - # field appears in the request structure - code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) - else: - code_lines.append('%s /* %s */' % (space, field.c_field_name)) - - # _aux->XXX = - if value != '': - code_lines.append('%s%s' % (space, value)) - if field.type.fixed_size(): - code_lines.append('%s xcb_block_len += %s;' % (space, length)) - code_lines.append('%s xcb_tmp += %s;' % (space, length)) - else: - # padding - if length != '': - code_lines.append('%s xcb_block_len = %s;' % (space, length)) - code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - code_lines.append('%s xcb_tmp += xcb_block_len + xcb_pad;' % space) - code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) - code_lines.append('%s xcb_block_len = 0;' % space) - code_lines.append('%s xcb_pad = 0;' % space) - need_padding = False -# unserialize_fields() - -def serialize_fields(complex_type, code_lines=[], temp_vars=set(), - space='', prefix='', serialize_fixed_size_fields=False, - bitcase=False): - """ - helper routine to build up iovec arrays that will later be copied into a single buffer - - complex_type - encapsulating Type/Field - code_lines, temp_vars - containers for generated code & variable declarations - space - extra space to be inserted before any statement - prefix - prefix to be used for struct members, needed for switch/bitcase mapping - bitcase - flags whether fields are bitcase members - """ - - # count -> no. of entries in xcb_parts array - count = 0 - # flag to mark wether explicit padding needs to be inserted - need_padding = False - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) - - if hasattr(complex_type, 'type'): - self = complex_type.type - complex_name = complex_type.name - else: - self = complex_type - complex_name = '_aux' - - param_fields, wire_fields, params = get_serialize_params(self, unserialize=True) - param_names = [p[2] for p in params] - - def insert_padding(count): - code_lines.append('%s /* padding */' % space) - code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - code_lines.append('%s if (0 != xcb_pad) {' % space) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) - code_lines.append('%s xcb_parts_idx++;' % space) - code_lines.append('%s }' % 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 xcb_block_len = 0;' % space) - need_padding = True - return count + 1 - # insert_padding() - - # special case - if self.is_switch, all fields need to be serialized conditionally - if self.is_switch: - switch_expr = _c_accessor_get_expr(self.expr) - need_padding = True - - for b in self.bitcases: - bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) - code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) - - count += serialize_fields(b.type, code_lines, temp_vars, '%s ' % space, - prefix="%s%s" % (prefix_str, complex_name), - serialize_fixed_size_fields=True, bitcase=True) - code_lines.append(' }') - count = insert_padding(count) - - else: - for field in self.fields: - value = None - - # sort out invisible fields - if not ((field.wire and not field.auto) or field.visible): - continue - - length = "sizeof(%s)" % field.c_field_type - - # switch/bitcase: fixed size fields are serialized explicitly - if field.type.fixed_size() and bitcase: - value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' - need_padding = True - - if field.type.is_expr: - # need to register a temporary variable for the expression - if field.type.c_type is None: - raise Exception("type for field '%s' (expression '%s') unkown" % - (field.field_name, _c_accessor_get_expr(field.type.expr))) - temp_vars.add(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, - _c_accessor_get_expr(field.type.expr, prefix))) - value += "&xcb_expr_%s;" % field.field_name - - elif field.type.is_pad: - if field.type.nmemb == 1: - value += "&xcb_pad;" - else: - value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb - length += "*%d" % field.type.nmemb - - else: - # non-list type with fixed size - if field.type.nmemb == 1: - value += "&%s%s;" % (prefix_str, field.c_field_name) - # list with nmemb (fixed size) elements - else: - value += '%s%s;' % (prefix_str, field.c_field_name) - length = '%d' % field.type.nmemb - - # fields with variable size - elif not field.type.fixed_size(): - # calculate padding before variable sized fields only if necessary - if bitcase or need_padding: - count = insert_padding(count) - code_lines.append('%s xcb_block_len = 0;' % space) - need_padding = False - - code_lines.append('%s /* %s */' % (space, field.c_field_name)) - value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) - length = '' - code_lines.append('%s%s' % (space, value)) - - if field.type.is_list: - # list of variable length with variable size elements - if field.type.size is None: - errmsg = '%s: warning: list object with variable-sized members not supported for field %s\n' - sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - 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 for(i=0; i<%s; i++) {' - % (space, _c_accessor_get_expr(field.type.expr, lenfield_prefix))) - code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name)) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space) - code_lines.append('%s xcb_tmp += xcb_block_len;' % space) - code_lines.append('%s }' % space) - code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space) - - # list of variable length with fixed size elements - else: - # look if the list's lenfield is a struct member or a function argument - lf_prefix = lenfield_prefix - # special case: if the list has a length field, its name will returned - # unchanged by calling c_accessor_get_length(expr) - expr = field.type.expr - if expr.lenfield_name == _c_accessor_get_length(expr): - if expr.lenfield_name in param_names: - # the length field appears as separate argument in unserialize, - # so no need for a prefix - lf_prefix = '' - - length = '%s * sizeof(%s)' % (_c_accessor_get_expr(field.type.expr, lf_prefix), - field.type.member.c_wiretype) - - elif field.type.is_switch: - # switch is handled at the beginning of this function as a special case -# count += serialize_fields(field.type, code_lines, temp_vars, space, - # prefix="%s%s" % (prefix_str, field.c_field_name)) - # FIXME - call another serialize - value = '' - sys.stderr.write("FIXME: call %s" % field.type.c_serialize_name) - length = 'undefined' - else: - # FIXME - variable sized field that is not a list - errmsg = '%s: warning: non-list object of variable size not supported for field %s\n' - sys.stderr.write(errmsg % (self.c_type, field.c_field_name)) - length = '%s * sizeof(%s)' % ('undefined', field.type.c_wiretype) - - # save serialization C code using xcb_parts[].iov_base and xcb_parts[].iov_len - if value is not None: - if field.type.fixed_size(): - # field belongs to some anchestor structure - code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) - code_lines.append('%s%s' % (space, value)) - if bitcase: - code_lines.append('%s xcb_block_len += %s;' % (space, length)) - if length != '': - if not field.type.fixed_size(): - code_lines.append('%s xcb_block_len = %s;' % (space, length)) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space) - # increase xcb_parts index - code_lines.append('%s xcb_parts_idx++;' % space) - count += 1 - - if not field.type.fixed_size(): - # FIXME - count = insert_padding(count) - need_padding = False - # raise Exception("obsolete - should not be reached") - # code_lines.append('%s xcb_unpadded = xcb_parts[xcb_parts_idx].iov_len;' % space) - - return count -# serialize_fields() + return count +# _c_serialize_helper() def _c_serialize(self): _h_setlevel(1) @@ -871,7 +775,7 @@ def _c_serialize(self): variable_size_fields = 0 # maximum space required for type definition of function arguments maxtypelen = 0 - param_fields, wire_fields, params = get_serialize_params(self) + param_fields, wire_fields, params = get_serialize_params('serialize', self) # determine N(variable_fields) for field in param_fields: @@ -910,34 +814,25 @@ def _c_serialize(self): if variable_size_fields > 0: code_lines = [] temp_vars = set() - count = serialize_fields(self, code_lines, temp_vars, - serialize_fixed_size_fields=False) + count =_c_serialize_helper('serialize', self, + code_lines, temp_vars) # update variable size fields variable_size_fields = count - _c(' unsigned int xcb_pad = 0;') - _c(' char xcb_pad0[3] = {0, 0, 0};') - _c(' struct iovec xcb_parts[%d];', count+1) - _c(' unsigned int xcb_parts_idx = 0;') - _c(' unsigned int xcb_block_len = 0;') + temp_vars.add(' unsigned int xcb_pad = 0;') + temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') + temp_vars.add(' struct iovec xcb_parts[%d];' % (count+1)) + temp_vars.add(' unsigned int xcb_parts_idx = 0;') + temp_vars.add(' unsigned int xcb_block_len = 0;') + temp_vars.add(' unsigned int i;') + temp_vars.add(' char *xcb_tmp;') for t in temp_vars: _c(t) - _c(' char *xcb_tmp;') - _c(' unsigned int i;') _c('') if variable_size_fields > 0: for l in code_lines: _c(l) - -# _c(' /* padding */') -# _c(' xcb_pad = -xcb_block_len & 3;') -# _c(' if (0 != xcb_pad) {') -# _c(' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;') -# _c(' xcb_parts[xcb_parts_idx].iov_len = xcb_pad;') -# _c(' xcb_parts_idx++;') -# _c(' }') -# _c(' xcb_buffer_len += xcb_block_len + xcb_pad;') _c('') # variable sized fields have been collected, now @@ -965,9 +860,7 @@ def _c_serialize(self): # variable sized fields _c(' for(i=0; i Date: Sun, 1 Aug 2010 23:40:20 +0200 Subject: [PATCH 08/26] bug fixes for all kinds of 'special cases' --- src/c_client.py | 455 +++++++++++++++++++++++++++++++----------------- 1 file changed, 300 insertions(+), 155 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 7b05077..bd502b3 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -16,6 +16,7 @@ _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests'] _cplusplus_annoyances = {'class' : '_class', 'new' : '_new', 'delete': '_delete'} +_c_keywords = {'default' : '_default'} _hlines = [] _hlevel = 0 @@ -23,9 +24,10 @@ _clines = [] _clevel = 0 _ns = None -# global variable to keep track of serializers +# global variable to keep track of serializers and switch data types # due to weird dependencies, I see no way to do this more elegant at the moment finished_serializers = [] +finished_switch = [] def _h(fmt, *args): ''' @@ -85,6 +87,8 @@ def _cpp(str): ''' if str in _cplusplus_annoyances: return _cplusplus_annoyances[str] + elif str in _c_keywords: + return _c_keywords[str] else: return str @@ -287,16 +291,20 @@ def _c_type_setup(self, name, postfix): if self.reply is not None: self.c_serialize_name = _n(name + ('reply', 'serialize')) self.c_unserialize_name = _n(name + ('reply', 'unserialize')) + # indicates rare structs where variable size fields are followed fixed size fields + self.var_followed_by_fixed_fields = False # whether a request or reply has a switch field self.need_aux = False self.need_serialize = False if self.is_switch: self.need_serialize = True + self.c_container = 'struct' for bitcase in self.bitcases: + bitcase.c_field_name = _cpp(bitcase.field_name) _c_type_setup(bitcase.type, bitcase.field_type, ()) - if self.is_container: + elif self.is_container: self.c_container = 'union' if self.is_union else 'struct' prev_varsized_field = None @@ -320,11 +328,17 @@ def _c_type_setup(self, name, postfix): 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_serialize = 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 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length + # special case - c_field_name ends with _length as well + #if field.c_field_name.endswith('length'): + # c_field_name = field.c_field_name.rsplit('length', 1) + # field.c_field_name = c_field_name[0] + "_length" field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end field.prev_varsized_field = prev_varsized_field @@ -336,6 +350,12 @@ def _c_type_setup(self, name, postfix): if field.type.fixed_size(): prev_varsized_offset += field.type.size + 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 +# print "WARNING (%s): variable size field %s followed by fixed size field %s" % ( +# self.c_type, prev_varsized_field.field_name, field.field_name) else: self.last_varsized_field = field prev_varsized_field = field @@ -344,17 +364,19 @@ def _c_type_setup(self, name, postfix): # as switch does never appear at toplevel, # continue here with type construction if self.is_switch: - # special: switch C structs get pointer fields for variable-sized members - _c_complex(self) - # FIXME: declare switch (un)packing functions - _c_accessors(self, name, name) + if self.c_type not in finished_switch: + finished_switch.append(self.c_type) + # special: switch C structs get pointer fields for variable-sized members + _c_complex(self) + # FIXME: declare switch (un)packing functions + _c_accessors(self, name, name) # FIXME - in case of request/reply, serialize() is not always needed if self.need_serialize and not self.is_bitcase: if self.c_serialize_name not in finished_serializers: + finished_serializers.append(self.c_serialize_name) _c_serialize(self) _c_unserialize(self) - finished_serializers.append(self.c_serialize_name) # _c_type_setup() def get_request_fields(self): @@ -374,27 +396,32 @@ def get_request_fields(self): return (param_fields, wire_fields) # get_request_fields() -def get_switch_expr_fields(self): - # get the fields referenced by the switch expression - def get_expr_fields(expr): +def get_expr_fields(self): + # get the fields referenced by switch or list expression + def get_expr_field_names(expr): if expr.op is None: if expr.lenfield_name is not None: return [expr.lenfield_name] + else: + # constant value expr + return [] else: if expr.op == '~': - return get_expr_fields(expr.rhs) + return get_expr_field_names(expr.rhs) elif expr.op == 'popcount': - return get_expr_fields(expr.rhs) + return get_expr_field_names(expr.rhs) elif expr.op == 'sumof': return [expr.lenfield_name] elif expr.op == 'enumref': return [] - else: - return get_expr_fields(expr.lhs) + get_expr_fields(expr.rhs) - # get_expr_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 = get_expr_fields(self.expr) + unresolved_fields = get_expr_field_names(self.expr) + if unresolved_fields is None: + return [] expr_fields = dict.fromkeys(unresolved_fields) for p in reversed(self.parent): parent_fields = dict((f.field_name, f) for f in p.fields) @@ -406,78 +433,122 @@ def get_switch_expr_fields(self): break if None in expr_fields.values(): - raise Exception("could not resolve all fields for %s" % self.name) + raise Exception("could not resolve all fields for %s" % self.name) params = expr_fields.values() return params -# get_switch_expr_fields() +# get_expr_fields() +def resolve_fields(anchestor, complex_obj=None): + """find fields referenced by anchestor or descendents with external scope""" + expr_fields = [] + unresolved = [] + all_fields = [] + if complex_obj is None: + complex_obj = anchestor + for field in complex_obj.fields: + all_fields.append(field) + if field.type.is_switch or field.type.is_list: + expr_fields += get_expr_fields(field.type) + if field.type.is_container: + expr_fields += resolve_fields(anchestor, field.type) + # try to resolve expr fields + for e in expr_fields: + if e not in all_fields: + unresolved.append(e) + return unresolved + def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): + def add_param(params, param): + if param not in params: + params.append(param) + param_fields, wire_fields = get_request_fields(self) if self.is_switch: - param_fields = get_switch_expr_fields(self) + param_fields = get_expr_fields(self) # _serialize function parameters + # cannot use set() for params, as series is important + params = [] if 'serialize' == context: - params = [('void', '**', buffer_var)] + params.append(('void', '**', buffer_var)) elif 'unserialize' == context: - params = [('const void', '*', buffer_var)] + params.append(('const void', '*', buffer_var)) + + # look for special cases + unresolved_fields = resolve_fields(self) + for f in unresolved_fields: + add_param(params, (f.c_field_type, '', f.c_field_name)) # make sure all required length fields are present for p in param_fields: if p.visible and not p.wire and not p.auto: typespec = p.c_field_type pointerspec = '' - params.append((typespec, pointerspec, p.c_field_name)) + add_param(params, (typespec, pointerspec, p.c_field_name)) # parameter fields if any if self.is_switch: - for p in get_switch_expr_fields(self): + for p in get_expr_fields(self): typespec = p.c_field_const_type - pointerspec = p.c_pointer - params.append((typespec, pointerspec, p.c_field_name)) + pointerspec = p.c_pointer + add_param(params, (typespec, pointerspec, p.c_field_name)) # aux argument - structure to be serialized if 'serialize' == context: - params.append(('const %s' % self.c_type, '*', aux_var)) + add_param(params, ('const %s' % self.c_type, '*', aux_var)) elif 'unserialize' == context and self.is_switch: - params.append(('%s' % self.c_type, '*', aux_var)) + add_param(params, ('%s' % self.c_type, '*', aux_var)) if not self.is_switch and 'serialize' == context: for p in param_fields: if not p.type.fixed_size(): - params.append((p.c_field_const_type, p.c_pointer, p.c_field_name)) + add_param(params, (p.c_field_const_type, '*', p.c_field_name)) return (param_fields, wire_fields, params) # get_serialize_params() -def _c_field_mapping(context, complex_type): - def get_prefix(field): - prefix = '' - if context in ('serialize', 'unserialize'): - if field.type.fixed_size() or complex_type.is_switch: - prefix = '_aux->' - else: - raise Exception("unknown context '%s' in c_field_mapping" % context) - return prefix - # get_prefix() - def get_field_name(fields, complex_type, prefix=''): - for f in complex_type.fields: - if '' == prefix: - prefix = get_prefix(f) +def _c_serialize_helper_prefix(prefix): + # prefix is a list of (field_name, anchestor object) tuples + # concatenate field names + prefix_str = '' + for name, obj in prefix: + prefix_str += name + prefix_str += '.' if (obj.is_bitcase and obj.has_name) else '->' + lenfield_prefix = '' if prefix_str.find('_aux')==0 else "_aux" + if prefix_str != '': + if lenfield_prefix != '': + lenfield_prefix += '->' + lenfield_prefix += prefix_str + return (prefix_str, lenfield_prefix) +# _c_serialize_helper_prefix - fname = "%s%s" % (prefix, f.c_field_name) +def _c_field_mapping(context, complex_type, prefix): + def get_prefix(field, prefix): + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + if prefix_str == '': + if context in ('serialize', 'unserialize'): + if field.type.fixed_size() or complex_type.is_switch: + prefix_str = '_aux->' + else: + raise Exception("unknown context '%s' in c_field_mapping" % context) + return prefix_str + # get_prefix() + def get_field_name(fields, complex_type, prefix): + for f in complex_type.fields: + prefix_str = get_prefix(f, prefix) + + fname = "%s%s" % (prefix_str, f.c_field_name) if fields.has_key(f.field_name): continue + # FIXME raise Exception("field name %s has been registered before" % f.field_name) fields[f.field_name] = (fname, f) if f.type.is_container: - new_prefix = "%s%s" % (prefix, f.c_field_name) - new_prefix += "." if f.type.is_switch else "->" - get_field_name(fields, f.type, new_prefix) + get_field_name(fields, f.type, prefix+[(f.c_field_name, f.type)]) # get_field_name() # dict(field_name : (c_field_name, field)) fields = {} - get_field_name(fields, complex_type) + get_field_name(fields, complex_type, prefix) # switch: get the fields referenced by the switch expr as well # these may not belong to any structure @@ -488,15 +559,6 @@ def _c_field_mapping(context, complex_type): return fields # _c_field_mapping() -def _c_serialize_helper_prefix(prefix): - prefix_str = prefix - lenfield_prefix = "_aux" - if prefix != '': - prefix_str += "->" - lenfield_prefix += "->%s" % prefix - return (prefix_str, lenfield_prefix) -# _c_serialize_helper_prefix - def _c_serialize_helper_insert_padding(context, code_lines, space): code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) code_lines.append('%s /* padding */' % space) @@ -522,17 +584,20 @@ def _c_serialize_helper_switch(context, self, complex_name, code_lines, temp_vars, space, prefix): count = 0 - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + switch_prefix = prefix + [(complex_name, self)] + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(switch_prefix) switch_expr = _c_accessor_get_expr(self.expr) - + for b in self.bitcases: - bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix) + bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix_str) code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) - + b_prefix = switch_prefix + if b.type.has_name: + b_prefix = switch_prefix + [(b.c_field_name, b.type)] _c_serialize_helper_fields(context, b.type, code_lines, temp_vars, - space="%s " % space, - prefix="%s%s" % (prefix_str, complex_name), + "%s " % space, + b_prefix, is_bitcase = True) code_lines.append(' }') @@ -546,16 +611,26 @@ def _c_serialize_helper_switch(context, self, complex_name, return count # _c_serialize_helper_switch -def _c_serialize_helper_switch_field(self, field): +def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix): # switch is handled by this function as a special case - args = get_switch_expr_fields(field.type) - field_mapping = _c_field_mapping('unserialize', self) + param_fields, wire_fields, params = get_serialize_params(context, self) + args = get_expr_fields(field.type) + field_mapping = _c_field_mapping(context, self, prefix) + + # determine which params to pass to _unserialize() and their prefixes + switch_len_fields = resolve_fields(self, field.type) + bitcase_unresolved = resolve_fields(self, self) + if len(bitcase_unresolved) != 0: + raise Exception('unresolved fields within bitcase is not supported at this point') c_field_names = '' + for a in switch_len_fields: + c_field_names += "%s, " % field_mapping[a.c_field_name][0] for a in args: - c_field_names += "%s, " % field_mapping[a.field_name][0] - switch_field_name = field_mapping[field.field_name][0] + c_field_names += "%s, " % field_mapping[a.c_field_name][0] +# switch_field_name = field_mapping[field.field_name][0] + # call _unserialize() to determine the actual size length = "%s(xcb_tmp, %s&%s)" % (field.type.c_unserialize_name, - c_field_names, switch_field_name) + c_field_names, c_switch_variable) #switch_field_name) return length # _c_serialize_helper_switch_field() @@ -571,14 +646,15 @@ def _c_serialize_helper_list_field(context, self, field, param_names = [p[2] for p in params] # look if the list's lenfield is a struct member or a function argument - # special case: if the list has a length field, its name will returned + # special case: if the list has a length field, its name will be returned # unchanged by calling c_accessor_get_length(expr) if expr.lenfield_name == _c_accessor_get_length(expr): if expr.lenfield_name in param_names: # the length field appears as separate argument in unserialize, # so no need for a prefix lenfield_prefix = '' - list_length = _c_accessor_get_expr(expr, lenfield_prefix) + sep = '.' if (self.is_bitcase and self.has_name) else '->' + list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) # default: list with fixed size elements length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) @@ -586,8 +662,12 @@ def _c_serialize_helper_list_field(context, self, field, if field.type.size is None: length = '' if 'unserialize' == context: - temp_vars.add(' unsigned int i;') - temp_vars.add(' unsigned int xcb_tmp_len;') + int_i = ' unsigned int i;' + xcb_tmp_len = ' unsigned int xcb_tmp_len;' + if int_i not in temp_vars: + temp_vars.append(int_i) + if xcb_tmp_len not in temp_vars: + temp_vars.append(xcb_tmp_len) code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length)) code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" % (space, field.type.c_unserialize_name)) @@ -597,8 +677,8 @@ def _c_serialize_helper_list_field(context, self, field, 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 for(i=0; i<%s; i++) {' - % (space, _c_accessor_get_expr(expr, lenfield_prefix))) + code_lines.append('%s for(i=0; i<%s; i++) { ' + % (space, _c_accessor_get_expr(expr, lenfield_prefix, sep))) code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name)) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space) code_lines.append('%s }' % space) @@ -610,13 +690,19 @@ def _c_serialize_helper_list_field(context, self, field, def _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, space, prefix): - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) length = "sizeof(%s)" % field.c_field_type if 'unserialize' == context: - value = ' _aux->%s = *(%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type) + value = ' %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) + if field.type.is_pad and field.type.nmemb > 1: + value = '' + for i in range(field.type.nmemb): + code_lines.append('%s %s%s[%d] = *(%s *)xcb_tmp;' % + (space, prefix_str, field.c_field_name, i, field.c_field_type)) + length += " * %d" % field.type.nmemb # FIXME? - lists if field.type.is_list: raise Exception('list with fixed number of elemens unhandled in _unserialize()') @@ -628,14 +714,15 @@ def _c_serialize_helper_fields_fixed_size(context, self, field, if field.type.c_type is None: raise Exception("type for field '%s' (expression '%s') unkown" % (field.field_name, _c_accessor_get_expr(field.type.expr))) - temp_vars.add(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, - _c_accessor_get_expr(field.type.expr, prefix))) + temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, + _c_accessor_get_expr(field.type.expr, prefix))) value += "&xcb_expr_%s;" % field.field_name elif field.type.is_pad: if field.type.nmemb == 1: value += "&xcb_pad;" else: + # FIXME - possible segmentation fault!! value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb length += "*%d" % field.type.nmemb @@ -659,7 +746,8 @@ def _c_serialize_helper_fields_variable_size(context, self, field, if 'unserialize' == context: value = '' elif 'serialize' == context: - value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name) + address_of = '&' if (self.is_bitcase and self.has_name) else '' + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s%s;' % (address_of, prefix_str, field.c_field_name) length = '' prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) @@ -670,7 +758,10 @@ def _c_serialize_helper_fields_variable_size(context, self, field, code_lines, temp_vars, space, prefix) elif field.type.is_switch: - length = _c_serialize_helper_switch_field(self, field) + prev = filter(lambda x: x.find('xcb_switch_field'), temp_vars) + var_name = 'xcb_switch_field%d' % len(prev) + temp_vars.append(' %s %s;' % (field.type.c_type, var_name)) + length = _c_serialize_helper_switch_field(context, self, field, var_name, prefix) else: length = "%s(xcb_tmp)" % (field.type.c_unserialize_name) @@ -682,7 +773,6 @@ def _c_serialize_helper_fields(context, self, space, prefix, is_bitcase): count = 0 need_padding = False - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) for field in self.fields: if not ((field.wire and not field.auto) or field.visible): @@ -690,7 +780,7 @@ def _c_serialize_helper_fields(context, self, # switch/bitcase: fixed size fields must be considered explicitly if field.type.fixed_size(): - if is_bitcase: + if self.is_bitcase: value, length = _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, space, prefix) @@ -732,7 +822,7 @@ def _c_serialize_helper_fields(context, self, def _c_serialize_helper(context, complex_type, code_lines, temp_vars, - space='', prefix=''): + space='', prefix=[]): count = 0 if hasattr(complex_type, 'type'): self = complex_type.type @@ -787,17 +877,17 @@ def _c_serialize(self): maxtypelen = max(maxtypelen, len(p[0]) + len(p[1])) # write to .c/.h - for p in range(len(params)): + for idx, p in enumerate(params): line = "" - typespec, pointerspec, field_name = params[p] + typespec, pointerspec, field_name = p indent = ' '*(len(self.c_serialize_name)+2) # p==0: function declaration - if 0==p: + if 0==idx: line = "%s (" % self.c_serialize_name indent = '' spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) - if p < len(params)-1: + if idx < len(params)-1: _hc("%s," % line) else: _h("%s);" % line) @@ -813,18 +903,18 @@ def _c_serialize(self): _c(' unsigned int xcb_buffer_len = 0;') if variable_size_fields > 0: code_lines = [] - temp_vars = set() + temp_vars = [] count =_c_serialize_helper('serialize', self, code_lines, temp_vars) # update variable size fields variable_size_fields = count - temp_vars.add(' unsigned int xcb_pad = 0;') - temp_vars.add(' char xcb_pad0[3] = {0, 0, 0};') - temp_vars.add(' struct iovec xcb_parts[%d];' % (count+1)) - temp_vars.add(' unsigned int xcb_parts_idx = 0;') - temp_vars.add(' unsigned int xcb_block_len = 0;') - temp_vars.add(' unsigned int i;') - temp_vars.add(' char *xcb_tmp;') + temp_vars.append(' unsigned int xcb_pad = 0;') + temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};') + temp_vars.append(' struct iovec xcb_parts[%d];' % (count+1)) + temp_vars.append(' unsigned int xcb_parts_idx = 0;') + temp_vars.append(' unsigned int xcb_block_len = 0;') + temp_vars.append(' unsigned int i;') + temp_vars.append(' char *xcb_tmp;') for t in temp_vars: _c(t) @@ -893,17 +983,17 @@ def _c_unserialize(self): maxtypelen = max(maxtypelen, len(p[0]) + len(p[1])) # write to .c/.h - for p in range(len(params)): + for idx, p in enumerate(params): line = "" - typespec, pointerspec, field_name = params[p] + typespec, pointerspec, field_name = p indent = ' '*(len(self.c_unserialize_name)+2) # p==0: function declaration - if 0==p: + if 0==idx: line = "%s (" % self.c_unserialize_name indent = '' spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) - if p < len(params)-1: + if idx < len(params)-1: _hc("%s," % line) else: _h("%s);" % line) @@ -918,7 +1008,7 @@ def _c_unserialize(self): _c(' unsigned int xcb_pad = 0;') code_lines = [] - temp_vars = set() + temp_vars = [] _c_serialize_helper('unserialize', self, code_lines, temp_vars) for t in temp_vars: @@ -940,6 +1030,8 @@ def _c_iterator_get_end(field, accum): ''' if field.type.is_container: accum = field.c_accessor_name + '(' + accum + ')' + if field.type.fixed_size(): + print "iterator_get_end()", accum, field.c_field_name # XXX there could be fixed-length fields at the end return _c_iterator_get_end(field.type.last_varsized_field, accum) if field.type.is_list: @@ -1045,34 +1137,42 @@ def _c_iterator(self, name): _c(' return ret;') _c('}') -def _c_accessor_get_length(expr, prefix=''): +def _c_accessor_get_length(expr, prefix='', sep='->'): ''' Figures out what C code is needed to get a length field. For fields that follow a variable-length field, use the accessor. Otherwise, just reference the structure field directly. ''' - prefarrow = '' if prefix == '' else prefix + '->' - + prefarrow = '' if prefix == '' else prefix + sep + if expr.lenfield != None and expr.lenfield.prev_varsized_field != None: - return expr.lenfield.c_accessor_name + '(' + prefix + ')' + # special case: variable and fixed size fields are intermixed + retval = expr.lenfield.c_accessor_name + '(' + prefix + ')' + if prefix in ('', '_aux'): + prefix_str = '' if prefix=='' else '%s' % (prefarrow) + retval = '%s%s' % (prefix_str, expr.lenfield_name) + return retval elif expr.lenfield_name != None: - return prefarrow + expr.lenfield_name + if prefix.endswith(sep): + return prefix + expr.lenfield_name + else: + return prefarrow + expr.lenfield_name else: return str(expr.nmemb) -def _c_accessor_get_expr(expr, prefix=''): +def _c_accessor_get_expr(expr, prefix='', sep='->'): ''' Figures out what C code is needed to get the length of a list field. Recurses for math operations. Returns bitcount for value-mask fields. Otherwise, uses the value of the length field. ''' - lenexp = _c_accessor_get_length(expr, prefix) + lenexp = _c_accessor_get_length(expr, prefix, sep) if expr.op == '~': - return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix) + ')' + return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' elif expr.op == 'popcount': - return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix) + ')' + return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' elif expr.op == 'enumref': enum_name = expr.lenfield_type.name constant_name = expr.lenfield_name @@ -1088,17 +1188,19 @@ def _c_accessor_get_expr(expr, prefix=''): break if field is None: raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) - if prefix != '': - prefix = "%s->" % prefix + if prefix != '' and not prefix.endswith(sep): + prefix += sep list_name = "%s%s" % (prefix, field.c_field_name) c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name) + # FIXME + c_length_func = _c_accessor_get_expr(field.type.expr, prefix='', sep='') return 'xcb_sumof(%s, %s)' % (list_name, c_length_func) elif expr.op != None: - return '(' + _c_accessor_get_expr(expr.lhs, prefix) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix) + ')' + return '(' + _c_accessor_get_expr(expr.lhs, prefix, sep) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' elif expr.bitfield: return 'xcb_popcount(' + lenexp + ')' else: - return lenexp + return lenexp + '/* bla */' def _c_accessors_field(self, field): ''' @@ -1120,9 +1222,12 @@ def _c_accessors_field(self, field): _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) _c('{') - _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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + if 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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) _c('}') else: _hc('') @@ -1140,8 +1245,12 @@ def _c_accessors_field(self, field): _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) _c('{') - _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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + if 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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) _c('}') def _c_accessors_list(self, field): @@ -1171,7 +1280,7 @@ def _c_accessors_list(self, field): _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) _c('{') - if field.prev_varsized_field == None: + if 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')) @@ -1260,9 +1369,13 @@ def _c_accessors(self, name, base): Declares the accessor functions for the fields of a structure. ''' for field in self.fields: + # no accessors for switch - + # switch always needs to be unserialized explicitly + if self.is_switch: + continue if field.type.is_list and not field.type.fixed_size(): _c_accessors_list(self, field) - elif field.prev_varsized_field != None: + elif field.prev_varsized_field != None or not field.type.fixed_size(): _c_accessors_field(self, field) def c_simple(self, name): @@ -1316,17 +1429,30 @@ def _c_complex(self): length += 1 maxtypelen = max(maxtypelen, length) - for field in struct_fields: + def _c_complex_field(self, field, space=''): if (field.type.fixed_size() 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)): spacing = ' ' * (maxtypelen - len(field.c_field_type)) - _h(' %s%s %s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) - + _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) else: spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) - _h(' %s%s *%s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) + _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) + + if not self.is_switch: + for field in struct_fields: + _c_complex_field(self, field) + else: + for b in self.bitcases: + space = '' + if b.type.has_name: + _h(' struct _%s {', b.c_field_name) + 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) @@ -1461,17 +1587,21 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): for field in param_fields: count = count - 1 c_field_const_type = field.c_field_const_type + c_pointer = field.c_pointer if field.type.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, - spacing, field.c_pointer, field.c_field_name, comma) + 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, - spacing, field.c_pointer, field.c_field_name, comma) + spacing, c_pointer, field.c_field_name, comma) count = 2 + if self.var_followed_by_fixed_fields: + count += len(wire_fields)*2 for field in param_fields: if not field.type.fixed_size(): count = count + 2 @@ -1490,44 +1620,65 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' struct iovec xcb_parts[%d];', count + 2) _c(' %s xcb_ret;', func_cookie) - _c(' %s xcb_out;', self.c_type) + if not self.var_followed_by_fixed_fields: + _c(' %s xcb_out;', self.c_type) + for idx, f in enumerate(serial_fields): if not aux: _c(' %s xcb_aux%d;' % (f.type.c_type, idx)) else: _c(' void *xcb_aux%d = 0;' % (idx)) _c(' ') - _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(): - if field.type.is_expr: - _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) - elif field.type.is_pad: - if field.type.nmemb == 1: - _c(' xcb_out.%s = 0;', field.c_field_name) + if not self.var_followed_by_fixed_fields: + for field in wire_fields: + if field.type.fixed_size(): + if field.type.is_expr: + _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) + elif field.type.is_pad: + if field.type.nmemb == 1: + _c(' xcb_out.%s = 0;', field.c_field_name) + else: + _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) else: - _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) - else: - if field.type.nmemb == 1: - _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) - else: - _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) + if field.type.nmemb == 1: + _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) + else: + _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) - _c(' ') - _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;') - _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') + _c(' ') + _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;') + _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') # calls in order to free dyn. all. memory free_calls = [] - count = 4 - for field in param_fields: + if not self.var_followed_by_fixed_fields: + count = 4 + else: + count = 2 + var_size_fields = param_fields + if self.var_followed_by_fixed_fields: + var_size_fields = wire_fields + param_fields + for field in var_size_fields: + if field.type.fixed_size and self.var_followed_by_fixed_fields: + _c(' xcb_parts[%d].iov_base = (char *) &%s;', count, field.c_field_name) + _c(' xcb_parts[%d].iov_len = sizeof(%s);', count, field.type.c_type) + count += 1 if not field.type.fixed_size(): + # default: simple cast to char * if not field.type.need_serialize: _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + if field.type.is_list: + _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, + _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) + else: + # not supposed to happen + raise Exception("unhandled variable size field %s" % field.c_field_name) + #_c('/* eeeeeeeeeee */') else: if not aux: _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) @@ -1548,13 +1699,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): free_calls.append(' free(xcb_aux%d);' % idx) else: _c(' %s (%s);', field.type.c_unserialize_name, serialize_args) - if field.type.is_list: - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, - _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) - elif not field.type.need_serialize: - # FIXME - _serialize() - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', - count, 'Uh oh', field.type.c_wiretype) + count += 1 if not field.type.need_serialize: From b187f029d6bb693f0294bad5261ec486b140f185 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Mon, 2 Aug 2010 23:30:42 +0200 Subject: [PATCH 09/26] attempt to fix special case: variable fields followed by fixed size fields --- src/c_client.py | 245 ++++++++++++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 102 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index bd502b3..3e8f9c6 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -287,10 +287,10 @@ def _c_type_setup(self, name, postfix): self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) self.c_serialize_name = _n(name + ('serialize',)) self.c_unserialize_name = _n(name + ('unserialize',)) - if hasattr(self, 'reply'): - if self.reply is not None: - self.c_serialize_name = _n(name + ('reply', 'serialize')) - self.c_unserialize_name = _n(name + ('reply', 'unserialize')) +# if hasattr(self, 'reply'): +# if self.reply is not None: +# self.c_serialize_name = _n(name + ('reply', 'serialize')) +# self.c_unserialize_name = _n(name + ('reply', 'unserialize')) # indicates rare structs where variable size fields are followed fixed size fields self.var_followed_by_fixed_fields = False @@ -335,7 +335,10 @@ def _c_type_setup(self, name, postfix): field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length + # special case - c_field_name ends with _length as well + # if field.c_accessor_name.endswith('_length'): + # raise Exception(field.c_field_name) #if field.c_field_name.endswith('length'): # c_field_name = field.c_field_name.rsplit('length', 1) # field.c_field_name = c_field_name[0] + "_length" @@ -354,13 +357,21 @@ def _c_type_setup(self, name, postfix): if not self.is_union: self.need_serialize = True self.var_followed_by_fixed_fields = True -# print "WARNING (%s): variable size field %s followed by fixed size field %s" % ( -# self.c_type, prev_varsized_field.field_name, field.field_name) else: self.last_varsized_field = field prev_varsized_field = field prev_varsized_offset = 0 + # very special case - if self.var_followed_by_fixed_fields==True, + # we have to generate accessor functions also for fixed size fields + # now there might a naming conflict if the length field ends with _length + if self.var_followed_by_fixed_fields: + if field.type.is_list: + if field.type.expr.lenfield_name is not None: + full_lenfield_name = _n(name + (field.type.expr.lenfield_name,)) + if full_lenfield_name == field.c_length_name: + field.c_length_name += '_' + # as switch does never appear at toplevel, # continue here with type construction if self.is_switch: @@ -510,9 +521,11 @@ def _c_serialize_helper_prefix(prefix): # prefix is a list of (field_name, anchestor object) tuples # concatenate field names prefix_str = '' - for name, obj in prefix: + for name, sep, obj in prefix: prefix_str += name - prefix_str += '.' if (obj.is_bitcase and obj.has_name) else '->' + if sep == '': + sep = '.' if (obj.is_bitcase and obj.has_name) else '->' + prefix_str += sep lenfield_prefix = '' if prefix_str.find('_aux')==0 else "_aux" if prefix_str != '': if lenfield_prefix != '': @@ -543,7 +556,7 @@ def _c_field_mapping(context, complex_type, prefix): raise Exception("field name %s has been registered before" % f.field_name) fields[f.field_name] = (fname, f) if f.type.is_container: - get_field_name(fields, f.type, prefix+[(f.c_field_name, f.type)]) + get_field_name(fields, f.type, prefix+[(f.c_field_name, '', f.type)]) # get_field_name() # dict(field_name : (c_field_name, field)) @@ -584,7 +597,7 @@ def _c_serialize_helper_switch(context, self, complex_name, code_lines, temp_vars, space, prefix): count = 0 - switch_prefix = prefix + [(complex_name, self)] + switch_prefix = prefix + [(complex_name, '->', self)] prefix_str, lenfield_prefix = _c_serialize_helper_prefix(switch_prefix) switch_expr = _c_accessor_get_expr(self.expr) @@ -593,7 +606,7 @@ def _c_serialize_helper_switch(context, self, complex_name, code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) b_prefix = switch_prefix if b.type.has_name: - b_prefix = switch_prefix + [(b.c_field_name, b.type)] + b_prefix = switch_prefix + [(b.c_field_name, '.', b.type)] _c_serialize_helper_fields(context, b.type, code_lines, temp_vars, "%s " % space, @@ -773,6 +786,7 @@ def _c_serialize_helper_fields(context, self, space, prefix, is_bitcase): count = 0 need_padding = False + prev_field_was_variable = False for field in self.fields: if not ((field.wire and not field.auto) or field.visible): @@ -780,10 +794,17 @@ def _c_serialize_helper_fields(context, self, # switch/bitcase: fixed size fields must be considered explicitly if field.type.fixed_size(): - if self.is_bitcase: + if self.is_bitcase or self.var_followed_by_fixed_fields: + if prev_field_was_variable and need_padding: + # insert padding + _c_serialize_helper_insert_padding(context, code_lines, space) + prev_field_was_variable = False + fixed_prefix = prefix + if self.var_followed_by_fixed_fields and len(prefix)==0: + fixed_prefix = [('_aux', '->', self)] value, length = _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, - space, prefix) + space, fixed_prefix) else: continue @@ -796,6 +817,7 @@ def _c_serialize_helper_fields(context, self, 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: @@ -840,7 +862,7 @@ def _c_serialize_helper(context, complex_type, # all other data types can be evaluated one field a time else: # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type - if 'unserialize' == context: + if 'unserialize' == context and not self.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) _c_serialize_helper_insert_padding(context, code_lines, space) @@ -1002,7 +1024,10 @@ def _c_unserialize(self): _c('{') _c(' char *xcb_tmp = (char *)_buffer;') if not self.is_switch: - _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) + if not self.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;') @@ -1018,6 +1043,10 @@ def _c_unserialize(self): for l in code_lines: _c(l) _c('') + if not self.is_switch: + if self.var_followed_by_fixed_fields: + _c(' free(_aux);') + _c(' return xcb_buffer_len;') _c('}') # _c_unserialize() @@ -1030,8 +1059,6 @@ def _c_iterator_get_end(field, accum): ''' if field.type.is_container: accum = field.c_accessor_name + '(' + accum + ')' - if field.type.fixed_size(): - print "iterator_get_end()", accum, field.c_field_name # XXX there could be fixed-length fields at the end return _c_iterator_get_end(field.type.last_varsized_field, accum) if field.type.is_list: @@ -1085,10 +1112,14 @@ def _c_iterator(self, name): if not self.fixed_size(): _c(' %s *R = i->data;', self.c_type) - _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) - _c(' --i->rem;') - _c(' i->data = (%s *) child.data;', self.c_type) - _c(' i->index = child.index;') + 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) + else: + _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) + _c(' --i->rem;') + _c(' i->data = (%s *) child.data;', self.c_type) + _c(' i->index = child.index;') else: _c(' --i->rem;') _c(' ++i->data;') @@ -1412,16 +1443,16 @@ def _c_complex(self): varfield = None for field in self.fields: - if not field.type.fixed_size() and not self.is_switch: + if not field.type.fixed_size() and not self.is_switch and not self.is_union: varfield = field.c_field_name continue - if varfield != None and not field.type.is_pad and field.wire: - errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name) - sys.stderr.write(errmsg) - # sys.exit(1) +# if varfield != None and not field.type.is_pad and field.wire: +# errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name) +# sys.stderr.write(errmsg) +# sys.exit(1) if field.wire: struct_fields.append(field) - + for field in struct_fields: length = len(field.c_field_type) # account for '*' pointer_spec @@ -1600,14 +1631,16 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): spacing, c_pointer, field.c_field_name, comma) count = 2 - if self.var_followed_by_fixed_fields: - count += len(wire_fields)*2 - for field in param_fields: - if not field.type.fixed_size(): - count = count + 2 - if field.type.need_serialize: - # _serialize() keeps track of padding automatically - count -= 1 + if not self.var_followed_by_fixed_fields: + for field in param_fields: + if not field.type.fixed_size(): + count = count + 2 + if field.type.need_serialize: + # _serialize() keeps track of padding automatically + count -= 1 + else: + # there will be only one call to _serialize() and no need for additional padding + count -= 1 _c('{') _c(' static const xcb_protocol_request_t xcb_req = {') @@ -1620,8 +1653,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' struct iovec xcb_parts[%d];', count + 2) _c(' %s xcb_ret;', func_cookie) - if not self.var_followed_by_fixed_fields: - _c(' %s xcb_out;', self.c_type) + _c(' %s xcb_out;', self.c_type) + if self.var_followed_by_fixed_fields: + _c(' /* in the protocol description, variable size fields are followed by fixed size fields */') + for idx, f in enumerate(serial_fields): if not aux: @@ -1629,84 +1664,90 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): else: _c(' void *xcb_aux%d = 0;' % (idx)) _c(' ') -# _c(' printf("in function %s\\n");' % func_name) + _c(' printf("in function %s\\n");' % func_name) # fixed size fields - if not self.var_followed_by_fixed_fields: - for field in wire_fields: - if field.type.fixed_size(): - if field.type.is_expr: - _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) - elif field.type.is_pad: - if field.type.nmemb == 1: - _c(' xcb_out.%s = 0;', field.c_field_name) - else: - _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) + for field in wire_fields: + if field.type.fixed_size(): + if field.type.is_expr: + _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) + elif field.type.is_pad: + if field.type.nmemb == 1: + _c(' xcb_out.%s = 0;', field.c_field_name) else: - if field.type.nmemb == 1: - _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) - else: - _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) + _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) + else: + if field.type.nmemb == 1: + _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) + else: + _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, unserialize=False): + if unserialize: + serialize_args = get_serialize_params('unserialize', type_obj, + c_field_name, + aux_var)[2] + else: + serialize_args = get_serialize_params('serialize', type_obj, + aux_var, + c_field_name)[2] + serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) + return serialize_args + + # calls in order to free dyn. all. memory + free_calls = [] + + if not self.var_followed_by_fixed_fields: _c(' ') _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;') _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') - # calls in order to free dyn. all. memory - free_calls = [] - if not self.var_followed_by_fixed_fields: count = 4 - else: - count = 2 - var_size_fields = param_fields - if self.var_followed_by_fixed_fields: - var_size_fields = wire_fields + param_fields - for field in var_size_fields: - if field.type.fixed_size and self.var_followed_by_fixed_fields: - _c(' xcb_parts[%d].iov_base = (char *) &%s;', count, field.c_field_name) - _c(' xcb_parts[%d].iov_len = sizeof(%s);', count, field.type.c_type) - count += 1 - if not field.type.fixed_size(): - # default: simple cast to char * - if not field.type.need_serialize: - _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) - if field.type.is_list: - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, - _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) - else: - # not supposed to happen - raise Exception("unhandled variable size field %s" % field.c_field_name) - #_c('/* eeeeeeeeeee */') - else: - if not aux: - _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) - idx = serial_fields.index(field) - if not aux: - serialize_args = get_serialize_params('unserialize', field.type, - field.c_field_name, - '&xcb_aux%d' % idx)[2] - else: - serialize_args = get_serialize_params('serialize', field.type, - '&xcb_aux%d' % idx, - field.c_field_name)[2] - serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) - _c(' xcb_parts[%d].iov_len = ', count) - if aux: - _c(' %s (%s);', field.type.c_serialize_name, serialize_args) - _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx)) - free_calls.append(' free(xcb_aux%d);' % idx) - else: - _c(' %s (%s);', field.type.c_unserialize_name, serialize_args) - - count += 1 - if not field.type.need_serialize: - # 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) + for field in param_fields: + 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: + _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + if field.type.is_list: + _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, + _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) + else: + # not supposed to happen + raise Exception("unhandled variable size field %s" % field.c_field_name) + else: + if not aux: + _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) + idx = serial_fields.index(field) + aux_var = '&xcb_aux%d' % idx + serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, not aux) + _c(' xcb_parts[%d].iov_len = ', count) + if aux: + _c(' %s (%s);', field.type.c_serialize_name, serialize_args) + _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx)) + free_calls.append(' free(xcb_aux%d);' % idx) + else: + _c(' %s (%s);', field.type.c_unserialize_name, serialize_args) + count += 1 + if not field.type.need_serialize: + # 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: + else: + # call _serialize() + buffer_var = 'xcb_parts[%d].iov_base' % count + serialize_args = get_serialize_args(self, '&xcb_out', '&%s' % buffer_var, False) + _c(' %s = (char *) 0;', buffer_var) + _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args) + free_calls.append(' free(xcb_parts[%d].iov_base);' % count) + # no padding necessary - _serialize() keeps track of padding automatically _c(' ') _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) From 77b594f9583ea0247ff27130316d8e045da7f921 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Thu, 5 Aug 2010 15:55:28 +0200 Subject: [PATCH 10/26] renamed most _unserialize() functions to _sizeof() and fixed _unserialize() for the special case of intermixed variable and fixed size fields --- src/c_client.py | 320 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 240 insertions(+), 80 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 3e8f9c6..14607e5 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -27,6 +27,7 @@ _ns = None # global variable to keep track of serializers and switch data types # due to weird dependencies, I see no way to do this more elegant at the moment finished_serializers = [] +finished_sizeof = [] finished_switch = [] def _h(fmt, *args): @@ -282,11 +283,16 @@ def _c_type_setup(self, name, postfix): self.c_reply_type = _t(name + ('reply',)) self.c_cookie_type = _t(name + ('cookie',)) + self.need_aux = False + self.need_serialize = False + self.need_sizeof = False + self.c_aux_name = _n(name + ('aux',)) self.c_aux_checked_name = _n(name + ('aux', 'checked')) self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) self.c_serialize_name = _n(name + ('serialize',)) self.c_unserialize_name = _n(name + ('unserialize',)) + self.c_sizeof_name = _n(name + ('sizeof',)) # if hasattr(self, 'reply'): # if self.reply is not None: # self.c_serialize_name = _n(name + ('reply', 'serialize')) @@ -294,9 +300,7 @@ def _c_type_setup(self, name, postfix): # indicates rare structs where variable size fields are followed fixed size fields self.var_followed_by_fixed_fields = False - # whether a request or reply has a switch field - self.need_aux = False - self.need_serialize = False + # whether a request or reply has a switch field if self.is_switch: self.need_serialize = True self.c_container = 'struct' @@ -315,33 +319,35 @@ def _c_type_setup(self, name, postfix): _c_type_setup(field.type, field.field_type, ()) if field.type.is_list: _c_type_setup(field.type.member, field.field_type, ()) - # FIXME - structures with variable sized members, sort out when serialize() is needed - if (field.type.nmemb is None): # and not field.type.member.fixed_size(): - self.need_serialize = True + if (field.type.nmemb is None): +# if field.type.member.need_serialize: +# self.need_serialize = True + self.need_sizeof = True +# print "-> variable size list elements: %s (%s %s)" % (self.c_type, field.field_type, field.field_name) 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) field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else '' field.c_pointer = ' ' if field.type.nmemb == 1 else '*' + # correct the c_pointer field for variable size non-list types + if not field.type.fixed_size() and field.c_pointer == ' ': + field.c_pointer = '*' + if field.type.is_list and not field.type.member.fixed_size(): + field.c_pointer = '*' 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_serialize = True + #self.need_serialize = True + self.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 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length - # special case - c_field_name ends with _length as well - # if field.c_accessor_name.endswith('_length'): - # raise Exception(field.c_field_name) - #if field.c_field_name.endswith('length'): - # c_field_name = field.c_field_name.rsplit('length', 1) - # field.c_field_name = c_field_name[0] + "_length" field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end field.prev_varsized_field = prev_varsized_field @@ -353,6 +359,7 @@ def _c_type_setup(self, name, postfix): if field.type.fixed_size(): prev_varsized_offset += field.type.size + # 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 @@ -372,6 +379,10 @@ def _c_type_setup(self, name, postfix): if full_lenfield_name == field.c_length_name: field.c_length_name += '_' + 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, # continue here with type construction if self.is_switch: @@ -383,11 +394,16 @@ def _c_type_setup(self, name, postfix): _c_accessors(self, name, name) # FIXME - in case of request/reply, serialize() is not always needed - if self.need_serialize and not self.is_bitcase: - if self.c_serialize_name not in finished_serializers: - finished_serializers.append(self.c_serialize_name) - _c_serialize(self) - _c_unserialize(self) + if not self.is_bitcase: + if self.need_serialize: + if self.c_serialize_name not in finished_serializers: + finished_serializers.append(self.c_serialize_name) + _c_serialize(self) + _c_unserialize(self) + if self.need_sizeof: + if self.c_sizeof_name not in finished_sizeof: + finished_sizeof.append(self.c_sizeof_name) + _c_sizeof_helper(self) # _c_type_setup() def get_request_fields(self): @@ -468,6 +484,7 @@ def resolve_fields(anchestor, complex_obj=None): if e not in all_fields: unresolved.append(e) return unresolved +# resolve_fields() def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): def add_param(params, param): @@ -483,7 +500,7 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): params = [] if 'serialize' == context: params.append(('void', '**', buffer_var)) - elif 'unserialize' == context: + elif context in ('unserialize', 'sizeof'): params.append(('const void', '*', buffer_var)) # look for special cases @@ -508,8 +525,11 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): # aux argument - structure to be serialized if 'serialize' == context: add_param(params, ('const %s' % self.c_type, '*', aux_var)) - elif 'unserialize' == context and self.is_switch: - add_param(params, ('%s' % self.c_type, '*', aux_var)) + elif 'unserialize' == context: + if self.is_switch: + add_param(params, ('%s' % self.c_type, '*', aux_var)) + else: + add_param(params, ('%s' % self.c_type, '**', aux_var)) if not self.is_switch and 'serialize' == context: for p in param_fields: if not p.type.fixed_size(): @@ -517,7 +537,7 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): return (param_fields, wire_fields, params) # get_serialize_params() -def _c_serialize_helper_prefix(prefix): +def _c_serialize_helper_prefix(prefix, aux_var='_aux', aux_sep='->'): # prefix is a list of (field_name, anchestor object) tuples # concatenate field names prefix_str = '' @@ -526,10 +546,12 @@ def _c_serialize_helper_prefix(prefix): if sep == '': sep = '.' if (obj.is_bitcase and obj.has_name) else '->' prefix_str += sep - lenfield_prefix = '' if prefix_str.find('_aux')==0 else "_aux" + + lenfield_prefix = '' if prefix_str.find(aux_var)==0 else aux_var + if prefix_str != '': if lenfield_prefix != '': - lenfield_prefix += '->' + lenfield_prefix += aux_sep lenfield_prefix += prefix_str return (prefix_str, lenfield_prefix) # _c_serialize_helper_prefix @@ -607,15 +629,15 @@ def _c_serialize_helper_switch(context, self, complex_name, b_prefix = switch_prefix if b.type.has_name: b_prefix = switch_prefix + [(b.c_field_name, '.', b.type)] - _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_bitcase = True) code_lines.append(' }') if 'serialize' == context: - count = _c_serialize_helper_insert_padding(context, code_lines, space) + count += _c_serialize_helper_insert_padding(context, code_lines, space) if 'unserialize' == context: # padding code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) @@ -655,7 +677,7 @@ def _c_serialize_helper_list_field(context, self, field, """ expr = field.type.expr prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) - param_fields, wire_fields, params = get_serialize_params('unserialize', self) + param_fields, wire_fields, params = get_serialize_params('sizeof', self) param_names = [p[2] for p in params] # look if the list's lenfield is a struct member or a function argument @@ -667,14 +689,22 @@ def _c_serialize_helper_list_field(context, self, field, # so no need for a prefix lenfield_prefix = '' sep = '.' if (self.is_bitcase and self.has_name) else '->' - list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) + + # special case: unserializing of structs where variable and + # fixed size fields are intermixed + if self.var_followed_by_fixed_fields and 'unserialize' == context: + if lenfield_prefix == '_aux': + lenfield_prefix = 'xcb_out' + sep = '.' + list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) + # default: list with fixed size elements length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) # list with variable-sized elements - if field.type.size is None: + if not field.type.member.fixed_size(): length = '' - if 'unserialize' == context: + if context in ('unserialize', 'sizeof'): int_i = ' unsigned int i;' xcb_tmp_len = ' unsigned int xcb_tmp_len;' if int_i not in temp_vars: @@ -683,7 +713,7 @@ def _c_serialize_helper_list_field(context, self, field, temp_vars.append(xcb_tmp_len) code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length)) code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" % - (space, field.type.c_unserialize_name)) + (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) @@ -692,7 +722,7 @@ def _c_serialize_helper_list_field(context, self, field, code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name)) code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, _c_accessor_get_expr(expr, lenfield_prefix, sep))) - code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name)) + code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_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) @@ -703,12 +733,17 @@ def _c_serialize_helper_list_field(context, self, field, def _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, space, prefix): - code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) + if not self.is_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)) prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) length = "sizeof(%s)" % field.c_field_type - if 'unserialize' == context: + if context in ('unserialize', 'sizeof'): value = ' %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) if field.type.is_pad and field.type.nmemb > 1: value = '' @@ -756,8 +791,11 @@ def _c_serialize_helper_fields_variable_size(context, self, field, space, prefix): prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) - if 'unserialize' == context: + if context in ('unserialize', 'sizeof'): value = '' + if self.var_followed_by_fixed_fields and 'unserialize' == context: + value = ' %s = xcb_tmp;' % field.c_field_name + temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name)) elif 'serialize' == context: address_of = '&' if (self.is_bitcase and self.has_name) else '' value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s%s;' % (address_of, prefix_str, field.c_field_name) @@ -776,7 +814,7 @@ def _c_serialize_helper_fields_variable_size(context, self, field, temp_vars.append(' %s %s;' % (field.type.c_type, var_name)) length = _c_serialize_helper_switch_field(context, self, field, var_name, prefix) else: - length = "%s(xcb_tmp)" % (field.type.c_unserialize_name) + length = "%s(xcb_tmp)" % (field.type.c_sizeof_name) return (value, length) # _c_serialize_helper_fields_variable_size @@ -801,7 +839,10 @@ def _c_serialize_helper_fields(context, self, prev_field_was_variable = False fixed_prefix = prefix if self.var_followed_by_fixed_fields and len(prefix)==0: - fixed_prefix = [('_aux', '->', self)] + if 'unserialize' == context: + fixed_prefix = [('xcb_out', '.', self)] + else: + fixed_prefix = [('_aux', '->', self)] value, length = _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, space, fixed_prefix) @@ -817,20 +858,26 @@ def _c_serialize_helper_fields(context, self, 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() and is_bitcase: code_lines.append('%s xcb_block_len += %s;' % (space, length)) - if 'unserialize' == context: + if context in ('unserialize', 'sizeof'): code_lines.append('%s xcb_tmp += %s;' % (space, length)) else: # padding if '' != length: code_lines.append('%s xcb_block_len = %s;' % (space, length)) - if 'unserialize' == context: + if (not field.type.fixed_size() and + self.var_followed_by_fixed_fields and + 'unserialize' == context): + temp_vars.append(' int %s_len;' % field.c_field_name) + code_lines.append(' %s_len = xcb_block_len;' % field.c_field_name) + if context in ('unserialize', 'sizeof'): code_lines.append('%s xcb_tmp += xcb_block_len;' % space) if 'serialize' == context: if '' != length: @@ -851,8 +898,11 @@ def _c_serialize_helper(context, complex_type, complex_name = complex_type.name else: self = complex_type - complex_name = '_aux' - + if self.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, @@ -862,11 +912,11 @@ def _c_serialize_helper(context, complex_type, # all other data types can be evaluated one field a time else: # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type - if 'unserialize' == context and not self.var_followed_by_fixed_fields: + if context in ('unserialize', 'sizeof') and not self.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) _c_serialize_helper_insert_padding(context, code_lines, space) - + count += _c_serialize_helper_fields(context, self, code_lines, temp_vars, space, prefix, False) @@ -926,13 +976,13 @@ def _c_serialize(self): if variable_size_fields > 0: code_lines = [] temp_vars = [] - count =_c_serialize_helper('serialize', self, - code_lines, temp_vars) + count = _c_serialize_helper('serialize', self, + code_lines, temp_vars) # update variable size fields variable_size_fields = count temp_vars.append(' unsigned int xcb_pad = 0;') temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};') - temp_vars.append(' struct iovec xcb_parts[%d];' % (count+1)) + 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;') temp_vars.append(' unsigned int i;') @@ -1027,7 +1077,7 @@ def _c_unserialize(self): if not self.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(' %s xcb_out;', self.c_type) _c(' unsigned int xcb_buffer_len = 0;') _c(' unsigned int xcb_block_len = 0;') _c(' unsigned int xcb_pad = 0;') @@ -1051,6 +1101,81 @@ def _c_unserialize(self): _c('}') # _c_unserialize() +def _c_sizeof_helper(self): + _h_setlevel(1) + _c_setlevel(1) + + # _unserialize() + _hc('') + # _unserialize() returns the buffer size as well + _hc('int') + + variable_size_fields = 0 + # maximum space required for type definition of function arguments + maxtypelen = 0 + param_fields, wire_fields, params = get_serialize_params('sizeof', self) + + # 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])) + + # write to .c/.h + for idx, p in enumerate(params): + line = "" + typespec, pointerspec, field_name = p + indent = ' '*(len(self.c_sizeof_name)+2) + # p==0: function declaration + if 0==idx: + line = "%s (" % self.c_sizeof_name + indent = '' + spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) + line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) + if idx < len(params)-1: + _hc("%s," % line) + else: + _h("%s);" % line) + _c("%s)" % line) + + _c('{') + # if self.is_switch: call serialize + if self.is_switch: + _c(' %s _aux;', self.c_type) + param_names = [p[2] for p in params] + _c(' return %s(%s, &_aux);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) + # otherwise: evaluate parameters directly + else: + _c(' char *xcb_tmp = (char *)_buffer;') + if not self.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;') + code_lines = [] + temp_vars = [] + _c_serialize_helper('sizeof', self, + code_lines, temp_vars) + for t in temp_vars: + _c(t) + _c('') + + for l in code_lines: + _c(l) + _c('') + if not self.is_switch: + if self.var_followed_by_fixed_fields: + _c(' free(_aux);') + _c(' return xcb_buffer_len;') + + _c('}') +# _c_sizeof_helper() + def _c_iterator_get_end(field, accum): ''' Figures out what C code is needed to find the end of a variable-length structure field. @@ -1178,8 +1303,10 @@ def _c_accessor_get_length(expr, prefix='', sep='->'): if expr.lenfield != None and expr.lenfield.prev_varsized_field != None: # special case: variable and fixed size fields are intermixed + # if the lenfield is among the fixed size fields, there is no need + # to call a special accessor function! retval = expr.lenfield.c_accessor_name + '(' + prefix + ')' - if prefix in ('', '_aux'): + if prefix in ('', '_aux', 'xcb_out'): prefix_str = '' if prefix=='' else '%s' % (prefarrow) retval = '%s%s' % (prefix_str, expr.lenfield_name) return retval @@ -1231,7 +1358,7 @@ def _c_accessor_get_expr(expr, prefix='', sep='->'): elif expr.bitfield: return 'xcb_popcount(' + lenexp + ')' else: - return lenexp + '/* bla */' + return lenexp def _c_accessors_field(self, field): ''' @@ -1547,6 +1674,8 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): wire_fields = [] maxtypelen = len('xcb_connection_t') serial_fields = [] + # special case: list with variable size elements + list_with_var_size_elems = False for field in self.fields: if field.visible: @@ -1555,7 +1684,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): 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: + if field.type.need_serialize or field.type.need_sizeof: serial_fields.append(field) for field in param_fields: @@ -1564,6 +1693,8 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): c_field_const_type = "const void" if len(c_field_const_type) > maxtypelen: maxtypelen = len(c_field_const_type) + if field.type.is_list and not field.type.member.fixed_size(): + list_with_var_size_elems = True _h_setlevel(1) _c_setlevel(1) @@ -1638,9 +1769,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): if field.type.need_serialize: # _serialize() keeps track of padding automatically count -= 1 - else: + dimension = count + 2 + if self.var_followed_by_fixed_fields: # there will be only one call to _serialize() and no need for additional padding - count -= 1 + dimension -= 1 _c('{') _c(' static const xcb_protocol_request_t xcb_req = {') @@ -1651,7 +1783,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' };') _c(' ') - _c(' struct iovec xcb_parts[%d];', count + 2) + _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: @@ -1659,12 +1791,14 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): for idx, f in enumerate(serial_fields): - if not aux: - _c(' %s xcb_aux%d;' % (f.type.c_type, idx)) - else: + if aux: _c(' void *xcb_aux%d = 0;' % (idx)) + if list_with_var_size_elems: + _c(' unsigned int i;') + _c(' unsigned int xcb_tmp_len;') + _c(' char *xcb_tmp;') _c(' ') - _c(' printf("in function %s\\n");' % func_name) +# _c(' printf("in function %s\\n");' % func_name) # fixed size fields for field in wire_fields: @@ -1682,17 +1816,11 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): else: _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, unserialize=False): - if unserialize: - serialize_args = get_serialize_params('unserialize', type_obj, - c_field_name, - aux_var)[2] - else: - serialize_args = get_serialize_params('serialize', type_obj, - aux_var, - c_field_name)[2] - serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) - return serialize_args + def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'): + 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 = [] @@ -1710,11 +1838,40 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): 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: + if not field.type.need_serialize and not field.type.need_sizeof: _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) if field.type.is_list: - _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, - _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) + if field.type.member.fixed_size(): + _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, + _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) + else: + expr = field.type.expr + prefix_str, lenfield_prefix = _c_serialize_helper_prefix([('xcb_out', '.', self)], + 'xcb_out', '.') + param_fields, wire_fields, params = get_serialize_params('sizeof', self) + param_names = [p[2] for p in params] + sep = '.' + + # look if the list's lenfield is a struct member or a function argument + # special case: if the list has a length field, its name will be returned + # unchanged by calling c_accessor_get_length(expr) + if expr.lenfield_name == _c_accessor_get_length(expr): + if expr.lenfield_name in param_names: + # the length field appears as separate argument, + # so no need for a prefix + lenfield_prefix = '' + + list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) + + 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);" % + (field.type.c_sizeof_name)) + _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count) + _c(" xcb_tmp += xcb_tmp_len;") + _c(" }") else: # not supposed to happen raise Exception("unhandled variable size field %s" % field.c_field_name) @@ -1723,17 +1880,20 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) idx = serial_fields.index(field) aux_var = '&xcb_aux%d' % idx - serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, not aux) + context = 'serialize' if aux else 'sizeof' _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(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx)) free_calls.append(' free(xcb_aux%d);' % idx) else: - _c(' %s (%s);', field.type.c_unserialize_name, serialize_args) + serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context) + func_name = field.type.c_sizeof_name + _c(' %s (%s);', func_name, serialize_args) count += 1 - if not field.type.need_serialize: + if not (field.type.need_serialize or field.type.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) @@ -1743,7 +1903,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): else: # call _serialize() buffer_var = 'xcb_parts[%d].iov_base' % count - serialize_args = get_serialize_args(self, '&xcb_out', '&%s' % buffer_var, False) + serialize_args = get_serialize_args(self, '&%s' % buffer_var, '&xcb_out', 'serialize') _c(' %s = (char *) 0;', buffer_var) _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args) free_calls.append(' free(xcb_parts[%d].iov_base);' % count) From fe0e32b5fa3923fae97210e974c0f96a085116cb Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Sun, 8 Aug 2010 21:25:13 +0200 Subject: [PATCH 11/26] special case 'intermixed variable and fixed size fields': fixed reply side, needs testing --- src/c_client.py | 250 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 166 insertions(+), 84 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 14607e5..bf2f34d 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -292,12 +292,10 @@ def _c_type_setup(self, name, postfix): self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) self.c_serialize_name = _n(name + ('serialize',)) self.c_unserialize_name = _n(name + ('unserialize',)) + self.c_unpack_name = _n(name + ('unpack',)) self.c_sizeof_name = _n(name + ('sizeof',)) -# if hasattr(self, 'reply'): -# if self.reply is not None: -# self.c_serialize_name = _n(name + ('reply', 'serialize')) -# self.c_unserialize_name = _n(name + ('reply', 'unserialize')) - # indicates rare structs where variable size fields are followed fixed size fields + + # special case: structs where variable size fields are followed by fixed size fields self.var_followed_by_fixed_fields = False # whether a request or reply has a switch field @@ -323,18 +321,19 @@ def _c_type_setup(self, name, postfix): # if field.type.member.need_serialize: # self.need_serialize = True self.need_sizeof = True -# print "-> variable size list elements: %s (%s %s)" % (self.c_type, field.field_type, field.field_name) 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) field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else '' field.c_pointer = ' ' if field.type.nmemb == 1 else '*' + # correct the c_pointer field for variable size non-list types if not field.type.fixed_size() and field.c_pointer == ' ': field.c_pointer = '*' if field.type.is_list and not field.type.member.fixed_size(): field.c_pointer = '*' + if field.type.is_switch: field.c_pointer = '*' field.c_field_const_type = 'const ' + field.c_field_type @@ -369,16 +368,10 @@ def _c_type_setup(self, name, postfix): prev_varsized_field = field prev_varsized_offset = 0 - # very special case - if self.var_followed_by_fixed_fields==True, - # we have to generate accessor functions also for fixed size fields - # now there might a naming conflict if the length field ends with _length if self.var_followed_by_fixed_fields: - if field.type.is_list: - if field.type.expr.lenfield_name is not None: - full_lenfield_name = _n(name + (field.type.expr.lenfield_name,)) - if full_lenfield_name == field.c_length_name: - field.c_length_name += '_' - + 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 @@ -390,16 +383,18 @@ def _c_type_setup(self, name, postfix): finished_switch.append(self.c_type) # special: switch C structs get pointer fields for variable-sized members _c_complex(self) - # FIXME: declare switch (un)packing functions - _c_accessors(self, name, name) + # FIXME: what about accessors & switch (un)packing functions + # _c_iterator() does not seem to be the right place to do it, + # as the accessors would need any parameters to pass to _unpack() as well - # FIXME - in case of request/reply, serialize() is not always needed if not self.is_bitcase: if self.need_serialize: if self.c_serialize_name not in finished_serializers: finished_serializers.append(self.c_serialize_name) _c_serialize(self) - _c_unserialize(self) + # _unpack() and _unserialize() are only needed for special cases + if self.is_switch or self.var_followed_by_fixed_fields: + _c_unserialize(self) if self.need_sizeof: if self.c_sizeof_name not in finished_sizeof: finished_sizeof.append(self.c_sizeof_name) @@ -500,7 +495,7 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): params = [] if 'serialize' == context: params.append(('void', '**', buffer_var)) - elif context in ('unserialize', 'sizeof'): + elif context in ('unserialize', 'unpack', 'sizeof'): params.append(('const void', '*', buffer_var)) # look for special cases @@ -526,10 +521,10 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): if 'serialize' == context: add_param(params, ('const %s' % self.c_type, '*', aux_var)) elif 'unserialize' == context: - if self.is_switch: - add_param(params, ('%s' % self.c_type, '*', aux_var)) - else: - add_param(params, ('%s' % self.c_type, '**', aux_var)) + add_param(params, ('%s' % self.c_type, '**', aux_var)) + elif 'unpack' == context: + add_param(params, ('%s' % self.c_type, '*', aux_var)) + if not self.is_switch and 'serialize' == context: for p in param_fields: if not p.type.fixed_size(): @@ -573,8 +568,6 @@ def _c_field_mapping(context, complex_type, prefix): fname = "%s%s" % (prefix_str, f.c_field_name) if fields.has_key(f.field_name): - continue - # FIXME raise Exception("field name %s has been registered before" % f.field_name) fields[f.field_name] = (fname, f) if f.type.is_container: @@ -604,7 +597,7 @@ def _c_serialize_helper_insert_padding(context, code_lines, space): code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) code_lines.append('%s xcb_parts_idx++;' % space) - elif 'unserialize' == context: + elif context in ('unserialize', 'unpack', 'sizeof'): code_lines.append('%s xcb_tmp += xcb_pad;' % space) code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) @@ -626,6 +619,7 @@ def _c_serialize_helper_switch(context, self, complex_name, for b in self.bitcases: bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix_str) code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) + code_lines.append(' printf("entering bitcase section for %%%%d...\\n", %s);' % bitcase_expr) b_prefix = switch_prefix if b.type.has_name: b_prefix = switch_prefix + [(b.c_field_name, '.', b.type)] @@ -638,7 +632,7 @@ def _c_serialize_helper_switch(context, self, complex_name, if 'serialize' == context: count += _c_serialize_helper_insert_padding(context, code_lines, space) - if 'unserialize' == context: + if context in ('unserialize', 'unpack', 'sizeof'): # 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) @@ -651,6 +645,7 @@ def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, pr param_fields, wire_fields, params = get_serialize_params(context, self) args = get_expr_fields(field.type) field_mapping = _c_field_mapping(context, self, prefix) + prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) # determine which params to pass to _unserialize() and their prefixes switch_len_fields = resolve_fields(self, field.type) @@ -662,10 +657,14 @@ def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, pr c_field_names += "%s, " % field_mapping[a.c_field_name][0] for a in args: c_field_names += "%s, " % field_mapping[a.c_field_name][0] -# switch_field_name = field_mapping[field.field_name][0] - # call _unserialize() to determine the actual size - length = "%s(xcb_tmp, %s&%s)" % (field.type.c_unserialize_name, - c_field_names, c_switch_variable) #switch_field_name) + + # 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) + elif context in ('unserialize', 'unpack'): + length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name, + c_field_names, prefix_str, field.c_field_name) return length # _c_serialize_helper_switch_field() @@ -704,7 +703,7 @@ def _c_serialize_helper_list_field(context, self, field, # list with variable-sized elements if not field.type.member.fixed_size(): length = '' - if context in ('unserialize', 'sizeof'): + if context in ('unserialize', 'sizeof', 'unpack'): int_i = ' unsigned int i;' xcb_tmp_len = ' unsigned int xcb_tmp_len;' if int_i not in temp_vars: @@ -743,7 +742,7 @@ def _c_serialize_helper_fields_fixed_size(context, self, field, length = "sizeof(%s)" % field.c_field_type - if context in ('unserialize', 'sizeof'): + if context in ('unserialize', 'unpack', 'sizeof'): value = ' %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) if field.type.is_pad and field.type.nmemb > 1: value = '' @@ -751,7 +750,7 @@ def _c_serialize_helper_fields_fixed_size(context, self, field, code_lines.append('%s %s%s[%d] = *(%s *)xcb_tmp;' % (space, prefix_str, field.c_field_name, i, field.c_field_type)) length += " * %d" % field.type.nmemb - # FIXME? - lists + if field.type.is_list: raise Exception('list with fixed number of elemens unhandled in _unserialize()') elif 'serialize' == context: @@ -791,30 +790,37 @@ def _c_serialize_helper_fields_variable_size(context, self, field, space, prefix): prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) - if context in ('unserialize', 'sizeof'): + if context in ('unserialize', 'unpack', 'sizeof'): value = '' + var_field_name = 'xcb_tmp' if self.var_followed_by_fixed_fields and 'unserialize' == context: value = ' %s = xcb_tmp;' % field.c_field_name temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name)) + if 'unpack' == context: + value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) elif 'serialize' == context: address_of = '&' if (self.is_bitcase and self.has_name) else '' - value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s%s;' % (address_of, prefix_str, field.c_field_name) + var_field_name = "%s%s%s" % (address_of, prefix_str, field.c_field_name) + value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name length = '' prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) code_lines.append('%s /* %s */' % (space, field.c_field_name)) if field.type.is_list: + if value != '': + code_lines.append("%s%s" % (space, value)) + value = '' length = _c_serialize_helper_list_field(context, self, field, code_lines, temp_vars, space, prefix) elif field.type.is_switch: - prev = filter(lambda x: x.find('xcb_switch_field'), temp_vars) - var_name = 'xcb_switch_field%d' % len(prev) - temp_vars.append(' %s %s;' % (field.type.c_type, var_name)) - length = _c_serialize_helper_switch_field(context, self, field, var_name, prefix) + value = '' + if context == 'serialize': + 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', prefix) else: - length = "%s(xcb_tmp)" % (field.type.c_sizeof_name) + length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name) return (value, length) # _c_serialize_helper_fields_variable_size @@ -866,18 +872,17 @@ def _c_serialize_helper_fields(context, self, code_lines.append('%s%s' % (space, value)) if field.type.fixed_size() and is_bitcase: code_lines.append('%s xcb_block_len += %s;' % (space, length)) - if context in ('unserialize', 'sizeof'): + if context in ('unserialize', 'unpack', 'sizeof'): code_lines.append('%s xcb_tmp += %s;' % (space, length)) else: # padding if '' != length: code_lines.append('%s xcb_block_len = %s;' % (space, length)) if (not field.type.fixed_size() and - self.var_followed_by_fixed_fields and - 'unserialize' == context): + self.var_followed_by_fixed_fields and 'unserialize' == context): temp_vars.append(' int %s_len;' % field.c_field_name) code_lines.append(' %s_len = xcb_block_len;' % field.c_field_name) - if context in ('unserialize', 'sizeof'): + if context in ('unserialize', 'sizeof', 'unpack'): code_lines.append('%s xcb_tmp += xcb_block_len;' % space) if 'serialize' == context: if '' != length: @@ -912,7 +917,7 @@ def _c_serialize_helper(context, complex_type, # all other data types can be evaluated one field a time else: # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type - if context in ('unserialize', 'sizeof') and not self.var_followed_by_fixed_fields: + if context in ('unserialize', 'unpack', 'sizeof') and not self.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) _c_serialize_helper_insert_padding(context, code_lines, space) @@ -1043,7 +1048,13 @@ def _c_unserialize(self): variable_size_fields = 0 # maximum space required for type definition of function arguments maxtypelen = 0 - param_fields, wire_fields, params = get_serialize_params('unserialize', self) + if self.is_switch: + context = 'unpack' + func_name = self.c_unpack_name + else: + context = 'unserialize' + func_name = self.c_unserialize_name + param_fields, wire_fields, params = get_serialize_params(context, self) # determine N(variable_fields) for field in param_fields: @@ -1058,10 +1069,10 @@ def _c_unserialize(self): for idx, p in enumerate(params): line = "" typespec, pointerspec, field_name = p - indent = ' '*(len(self.c_unserialize_name)+2) + indent = ' '*(len(func_name)+2) # p==0: function declaration if 0==idx: - line = "%s (" % self.c_unserialize_name + line = "%s (" % func_name indent = '' spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) @@ -1084,7 +1095,7 @@ def _c_unserialize(self): code_lines = [] temp_vars = [] - _c_serialize_helper('unserialize', self, + _c_serialize_helper(context, self, code_lines, temp_vars) for t in temp_vars: _c(t) @@ -1093,9 +1104,21 @@ def _c_unserialize(self): for l in code_lines: _c(l) _c('') - if not self.is_switch: - if self.var_followed_by_fixed_fields: - _c(' free(_aux);') + + if 'unserialize' == context: + # allocate memory automatically + _c(' if (NULL == *_aux) {') + _c(' /* allocate memory */') + _c(' *_aux = malloc(xcb_buffer_len);') + _c(' }') + _c('') + _c(' **_aux = xcb_out;') + _c(' xcb_tmp = (char *)++(*_aux);') + for field in param_fields: + if not field.type.fixed_size(): + _c(' memcpy(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name) + _c(' xcb_tmp += %s_len;', field.c_field_name) + _c('') _c(' return xcb_buffer_len;') _c('}') @@ -1142,25 +1165,31 @@ def _c_sizeof_helper(self): _c("%s)" % line) _c('{') - # if self.is_switch: call serialize + + param_names = [p[2] for p in params] if self.is_switch: + # switch: call _unpack() _c(' %s _aux;', self.c_type) - param_names = [p[2] for p in params] + _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) + elif self.var_followed_by_fixed_fields: + # special case: call _unserialize() + _c(' %s *_aux = NULL;', self.c_type) _c(' return %s(%s, &_aux);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) # otherwise: evaluate parameters directly else: - _c(' char *xcb_tmp = (char *)_buffer;') - if not self.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;') code_lines = [] temp_vars = [] _c_serialize_helper('sizeof', self, code_lines, temp_vars) + _c(' char *xcb_tmp = (char *)_buffer;') + if len(filter(lambda x: x.find('_aux')!=-1, code_lines))>0: + if not self.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;') for t in temp_vars: _c(t) _c('') @@ -1168,11 +1197,7 @@ def _c_sizeof_helper(self): for l in code_lines: _c(l) _c('') - if not self.is_switch: - if self.var_followed_by_fixed_fields: - _c(' free(_aux);') _c(' return xcb_buffer_len;') - _c('}') # _c_sizeof_helper() @@ -1350,7 +1375,7 @@ def _c_accessor_get_expr(expr, prefix='', sep='->'): prefix += sep list_name = "%s%s" % (prefix, field.c_field_name) c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name) - # FIXME + # FIXME - works only for integers this way!! c_length_func = _c_accessor_get_expr(field.type.expr, prefix='', sep='') return 'xcb_sumof(%s, %s)' % (list_name, c_length_func) elif expr.op != None: @@ -1399,16 +1424,24 @@ def _c_accessors_field(self, field): _hc(' **') _hc(' *****************************************************************************/') _hc(' ') - _hc('%s *', field.c_field_type) + if field.type.is_switch: + return_type = 'void *' + else: + return_type = '%s *' % field.c_field_type + + _hc(return_type) _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) _c('{') if field.prev_varsized_field is None: - _c(' return (%s *) (R + 1);', field.c_field_type) + _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 + # '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);', - field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', + return_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) _c('}') def _c_accessors_list(self, field): @@ -1526,15 +1559,14 @@ def _c_accessors(self, name, base): ''' Declares the accessor functions for the fields of a structure. ''' - for field in self.fields: - # no accessors for switch - - # switch always needs to be unserialized explicitly - if self.is_switch: - continue - if field.type.is_list and not field.type.fixed_size(): - _c_accessors_list(self, field) - elif field.prev_varsized_field != None or not field.type.fixed_size(): - _c_accessors_field(self, field) + # no accessors for switch - + # switch always needs to be unpacked explicitly + if not self.is_switch: + 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) def c_simple(self, name): ''' @@ -1925,7 +1957,29 @@ def _c_reply(self, name): 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 = [] + # no unserialize call in case of switch + if not complex_obj.is_switch: + for field in complex_obj.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: + 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: + 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') @@ -1960,7 +2014,35 @@ def _c_reply(self, name): _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2) _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2) _c('{') - _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type) + + 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);', + self.c_reply_type, self.c_reply_type) + _c(' int i;') + for field in unserialize_fields: + if field.type.is_list: + _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name) + _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name) + _c(' %s *%s_data;', field.c_field_type, field.c_field_name) + else: + raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type) + # call _unserialize(), using the reply as source and target buffer + _c(' /* special cases: transform parts of the reply to match XCB data structures */') + 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, + 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_opcode(name, opcode): From 22e1013131984a217e9bddeac3a6a4183e35f0c1 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Mon, 16 Aug 2010 18:19:16 +0200 Subject: [PATCH 12/26] added accessors for special cases major bugfixes include: rewrite of prefix related functions, merge of serialize/unserialize/... generators, extended field name resolution --- src/c_client.py | 1210 ++++++++++++++++++++++++++--------------------- 1 file changed, 659 insertions(+), 551 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index bf2f34d..8e79480 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -24,8 +24,8 @@ _clines = [] _clevel = 0 _ns = None -# global variable to keep track of serializers and switch data types -# due to weird dependencies, I see no way to do this more elegant at the moment +# global variable to keep track of serializers and +# switch data types due to weird dependencies finished_serializers = [] finished_sizeof = [] finished_switch = [] @@ -298,13 +298,13 @@ def _c_type_setup(self, name, postfix): # special case: structs where variable size fields are followed by fixed size fields self.var_followed_by_fixed_fields = False - # whether a request or reply has a switch field if self.is_switch: self.need_serialize = True self.c_container = 'struct' for bitcase in self.bitcases: bitcase.c_field_name = _cpp(bitcase.field_name) - _c_type_setup(bitcase.type, bitcase.field_type, ()) + bitcase_name = bitcase.field_type if bitcase.type.has_name else name + _c_type_setup(bitcase.type, bitcase_name, ()) elif self.is_container: @@ -318,8 +318,6 @@ def _c_type_setup(self, name, postfix): if field.type.is_list: _c_type_setup(field.type.member, field.field_type, ()) if (field.type.nmemb is None): -# if field.type.member.need_serialize: -# self.need_serialize = True self.need_sizeof = True field.c_field_type = _t(field.field_type) @@ -339,14 +337,12 @@ def _c_type_setup(self, name, postfix): 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_serialize = True self.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 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length - field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end field.prev_varsized_field = prev_varsized_field @@ -383,43 +379,111 @@ def _c_type_setup(self, name, postfix): finished_switch.append(self.c_type) # special: switch C structs get pointer fields for variable-sized members _c_complex(self) - # FIXME: what about accessors & switch (un)packing functions - # _c_iterator() does not seem to be the right place to do it, - # as the accessors would need any parameters to pass to _unpack() as well + 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 + # _c_iterator(field.type, field_name) necessary if not self.is_bitcase: if self.need_serialize: if self.c_serialize_name not in finished_serializers: finished_serializers.append(self.c_serialize_name) - _c_serialize(self) - # _unpack() and _unserialize() are only needed for special cases + _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: - _c_unserialize(self) + _c_serialize('unserialize', self) + if self.need_sizeof: if self.c_sizeof_name not in finished_sizeof: finished_sizeof.append(self.c_sizeof_name) - _c_sizeof_helper(self) + _c_serialize('sizeof', self) # _c_type_setup() -def get_request_fields(self): - param_fields = [] - wire_fields = [] +def _c_helper_absolute_name(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 = '' + for name, sep, obj in prefix: + prefix_str += name + if '' == sep: + sep = '->' + if ((obj.is_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) + 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 + if flat == True, nested complex types are not taken into account + """ + all_fields = {} + if complex_type.is_switch: + for b in complex_type.bitcases: + if b.type.has_name: + switch_name, switch_sep, switch_type = prefix[-1] + bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)] + else: + bitcase_prefix = prefix - for field in self.fields: - if field.visible: - # the field should appear as a parameter in the function call - param_fields.append(field) - if field.wire and not field.auto: - if field.type.fixed_size() and not self.is_switch: - # field in the xcb_out structure - wire_fields.append(field) - # fields like 'pad0' are skipped! - - return (param_fields, wire_fields) -# get_request_fields() + 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) + if all_fields.has_key(f.field_name): + 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: + new_prefix = prefix + elif f.type.is_switch and len(f.type.parents)>1: + # nested switch gets another separator + new_prefix = prefix+[(f.c_field_name, '.', f.type)] + else: + new_prefix = prefix+[(f.c_field_name, '->', f.type)] + all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat)) + + return all_fields +# _c_field_mapping() + +def _c_helper_resolve_field_names (prefix): + """ + get field names for all objects in the prefix array + """ + all_fields = {} + tmp_prefix = [] + # look for fields in the remaining containers + for idx, p in enumerate(prefix): + 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 '->' + # 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): + tmp_prefix.append((name, sep, obj)) + all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True)) + + return all_fields +# _c_helper_resolve_field_names 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: if expr.lenfield_name is not None: @@ -433,7 +497,17 @@ def get_expr_fields(self): elif expr.op == 'popcount': return get_expr_field_names(expr.rhs) elif expr.op == 'sumof': - return [expr.lenfield_name] + # sumof expr references another list, + # we need that list's length field here + field = None + for f in expr.lenfield_parent.fields: + if f.field_name == expr.lenfield_name: + field = f + break + if field is None: + raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) + # referenced list + its length field + return [expr.lenfield_name] + get_expr_field_names(field.type.expr) elif expr.op == 'enumref': return [] else: @@ -441,83 +515,105 @@ def get_expr_fields(self): # get_expr_field_names() # resolve the field names with the parent structure(s) - unresolved_fields = get_expr_field_names(self.expr) - if unresolved_fields is None: - return [] - expr_fields = dict.fromkeys(unresolved_fields) - for p in reversed(self.parent): - parent_fields = dict((f.field_name, f) for f in p.fields) - for f in parent_fields.keys(): - if f in unresolved_fields: - expr_fields[f] = parent_fields[f] - unresolved_fields.remove(f) - if len(unresolved_fields) == 0: - break - - if None in expr_fields.values(): - raise Exception("could not resolve all fields for %s" % self.name) + unresolved_fields_names = get_expr_field_names(self.expr) - params = expr_fields.values() - return params + # construct prefix from self + prefix = [('', '', p) for p in self.parents] + if self.is_container: + prefix.append(('', '', self)) + + all_fields = _c_helper_resolve_field_names (prefix) + resolved_fields_names = 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() -def resolve_fields(anchestor, complex_obj=None): - """find fields referenced by anchestor or descendents with external scope""" +def resolve_expr_fields(complex_obj): + """ + find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj + these are normally fields that need to be given as function parameters + """ + all_fields = [] expr_fields = [] unresolved = [] - all_fields = [] - if complex_obj is None: - complex_obj = anchestor + for field in complex_obj.fields: all_fields.append(field) if field.type.is_switch or field.type.is_list: expr_fields += get_expr_fields(field.type) if field.type.is_container: - expr_fields += resolve_fields(anchestor, field.type) + expr_fields += resolve_expr_fields(field.type) + # try to resolve expr fields for e in expr_fields: - if e not in all_fields: + if e not in all_fields and e not in unresolved: unresolved.append(e) return unresolved -# resolve_fields() +# 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. + """ def add_param(params, param): if param not in params: params.append(param) - param_fields, wire_fields = get_request_fields(self) + # collect all fields into param_fields + param_fields = [] + wire_fields = [] + + for field in self.fields: + if field.visible: + # the field should appear as a parameter in the function call + param_fields.append(field) + if field.wire and not field.auto: + if field.type.fixed_size() and not self.is_switch: + # 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 + # fixed and variable size fields if self.is_switch: param_fields = get_expr_fields(self) - # _serialize function parameters - # cannot use set() for params, as series is important + # _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)) elif context in ('unserialize', 'unpack', 'sizeof'): params.append(('const void', '*', buffer_var)) - # look for special cases - unresolved_fields = resolve_fields(self) + # 2. any expr fields that cannot be resolved within self and descendants + unresolved_fields = resolve_expr_fields(self) for f in unresolved_fields: add_param(params, (f.c_field_type, '', f.c_field_name)) - # make sure all required length fields are present + # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields + # that do not appear in the data type struct for p in param_fields: - 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)) - - # parameter fields if any - if self.is_switch: - for p in get_expr_fields(self): + if self.is_switch: typespec = p.c_field_const_type 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)) - # aux argument - structure to be serialized + # 4. aux argument if 'serialize' == context: add_param(params, ('const %s' % self.c_type, '*', aux_var)) elif 'unserialize' == context: @@ -525,86 +621,40 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): 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 + # variable size fields if not self.is_switch and 'serialize' == context: for p in param_fields: if not p.type.fixed_size(): add_param(params, (p.c_field_const_type, '*', p.c_field_name)) + return (param_fields, wire_fields, params) # get_serialize_params() -def _c_serialize_helper_prefix(prefix, aux_var='_aux', aux_sep='->'): - # prefix is a list of (field_name, anchestor object) tuples - # concatenate field names - prefix_str = '' - for name, sep, obj in prefix: - prefix_str += name - if sep == '': - sep = '.' if (obj.is_bitcase and obj.has_name) else '->' - prefix_str += sep - - lenfield_prefix = '' if prefix_str.find(aux_var)==0 else aux_var - - if prefix_str != '': - if lenfield_prefix != '': - lenfield_prefix += aux_sep - lenfield_prefix += prefix_str - return (prefix_str, lenfield_prefix) -# _c_serialize_helper_prefix - -def _c_field_mapping(context, complex_type, prefix): - def get_prefix(field, prefix): - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) - if prefix_str == '': - if context in ('serialize', 'unserialize'): - if field.type.fixed_size() or complex_type.is_switch: - prefix_str = '_aux->' - else: - raise Exception("unknown context '%s' in c_field_mapping" % context) - return prefix_str - # get_prefix() - def get_field_name(fields, complex_type, prefix): - for f in complex_type.fields: - prefix_str = get_prefix(f, prefix) - - fname = "%s%s" % (prefix_str, f.c_field_name) - if fields.has_key(f.field_name): - raise Exception("field name %s has been registered before" % f.field_name) - fields[f.field_name] = (fname, f) - if f.type.is_container: - get_field_name(fields, f.type, prefix+[(f.c_field_name, '', f.type)]) - # get_field_name() - - # dict(field_name : (c_field_name, field)) - fields = {} - get_field_name(fields, complex_type, prefix) - - # switch: get the fields referenced by the switch expr as well - # these may not belong to any structure - if complex_type.is_switch: - pass -# FIXME: fields += get_serialize_params(context, complex_type) - - return fields -# _c_field_mapping() - -def _c_serialize_helper_insert_padding(context, code_lines, space): - code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) - code_lines.append('%s /* padding */' % space) +def _c_serialize_helper_insert_padding(context, code_lines, space, postpone): + code_lines.append('%s /* insert padding */' % space) code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) - code_lines.append('%s if (0 != xcb_pad) {' % 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) - if 'serialize' == context: - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) - code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) - code_lines.append('%s xcb_parts_idx++;' % space) - elif context in ('unserialize', 'unpack', 'sizeof'): - code_lines.append('%s xcb_tmp += xcb_pad;' % space) + if not postpone: + code_lines.append('%s if (0 != xcb_pad) {' % space) - code_lines.append('%s xcb_buffer_len += xcb_pad;' % space) - code_lines.append('%s xcb_pad = 0;' % space) - code_lines.append('%s }' % space) + if 'serialize' == context: + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) + code_lines.append('%s xcb_parts_idx++;' % space) + elif context in ('unserialize', 'unpack', 'sizeof'): + code_lines.append('%s xcb_tmp += 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) - + + # keep tracking of xcb_parts entries for serialize return 1 # _c_serialize_helper_insert_padding() @@ -612,17 +662,17 @@ def _c_serialize_helper_switch(context, self, complex_name, code_lines, temp_vars, space, prefix): count = 0 - switch_prefix = prefix + [(complex_name, '->', self)] - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(switch_prefix) - switch_expr = _c_accessor_get_expr(self.expr) - + switch_expr = _c_accessor_get_expr(self.expr, None) + for b in self.bitcases: - bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix_str) + bitcase_expr = _c_accessor_get_expr(b.type.expr, None) code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) - code_lines.append(' printf("entering bitcase section for %%%%d...\\n", %s);' % bitcase_expr) - b_prefix = switch_prefix +# code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' % +# (self.name[-1], b.type.name[-1], bitcase_expr)) + b_prefix = prefix if b.type.has_name: - b_prefix = switch_prefix + [(b.c_field_name, '.', b.type)] + b_prefix = prefix + [(b.c_field_name, '.', b.type)] + count += _c_serialize_helper_fields(context, b.type, code_lines, temp_vars, "%s " % space, @@ -630,28 +680,39 @@ def _c_serialize_helper_switch(context, self, complex_name, is_bitcase = True) code_lines.append(' }') - if 'serialize' == context: - count += _c_serialize_helper_insert_padding(context, code_lines, space) - if context in ('unserialize', 'unpack', 'sizeof'): - # 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) - +# if 'serialize' == context: +# count += _c_serialize_helper_insert_padding(context, code_lines, space, False) +# elif context in ('unserialize', 'unpack', 'sizeof'): +# # 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 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix): + """ + handle switch by calling _serialize() or _unpack(), depending on context + """ # switch is handled by this function as a special case param_fields, wire_fields, params = get_serialize_params(context, self) - args = get_expr_fields(field.type) - field_mapping = _c_field_mapping(context, self, prefix) - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + field_mapping = _c_helper_field_mapping(self, prefix) + prefix_str = _c_helper_absolute_name(prefix) - # determine which params to pass to _unserialize() and their prefixes - switch_len_fields = resolve_fields(self, field.type) - bitcase_unresolved = resolve_fields(self, self) + # 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 + # need to be passed as parameters + switch_len_fields = resolve_expr_fields(field.type) + + # a switch field at this point _must_ be a bitcase field + # we require that bitcases are "self-contiguous" + bitcase_unresolved = resolve_expr_fields(self) if len(bitcase_unresolved) != 0: raise Exception('unresolved fields within bitcase is not supported at this point') + + # 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] @@ -665,6 +726,7 @@ def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, pr elif context in ('unserialize', 'unpack'): length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name, c_field_names, prefix_str, field.c_field_name) + return length # _c_serialize_helper_switch_field() @@ -672,34 +734,38 @@ def _c_serialize_helper_list_field(context, self, field, code_lines, temp_vars, space, prefix): """ - helper function for (un)serialize to cope with lists of variable length + helper function to cope with lists of variable length """ expr = field.type.expr - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + prefix_str = _c_helper_absolute_name(prefix) param_fields, wire_fields, params = get_serialize_params('sizeof', self) param_names = [p[2] for p in params] - - # look if the list's lenfield is a struct member or a function argument - # special case: if the list has a length field, its name will be returned - # unchanged by calling c_accessor_get_length(expr) - if expr.lenfield_name == _c_accessor_get_length(expr): - if expr.lenfield_name in param_names: - # the length field appears as separate argument in unserialize, - # so no need for a prefix - lenfield_prefix = '' - sep = '.' if (self.is_bitcase and self.has_name) else '->' - # special case: unserializing of structs where variable and - # fixed size fields are intermixed - if self.var_followed_by_fixed_fields and 'unserialize' == context: - if lenfield_prefix == '_aux': - lenfield_prefix = 'xcb_out' - sep = '.' - - list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) + expr_fields_names = [f.field_name for f in get_expr_fields(field.type)] + resolved = filter(lambda x: x in param_names, expr_fields_names) + unresolved = 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) + + field_mapping.update(_c_helper_resolve_field_names(prefix)) + resolved += filter(lambda x: x in field_mapping, unresolved) + unresolved = filter(lambda x: x not in field_mapping, unresolved) + if len(unresolved)>0: + raise Exception('could not resolve the length fields required for list %s' % field.c_field_name) + + list_length = _c_accessor_get_expr(expr, field_mapping) + # default: list with fixed size elements length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) + # list with variable-sized elements if not field.type.member.fixed_size(): length = '' @@ -710,17 +776,19 @@ def _c_serialize_helper_list_field(context, self, field, temp_vars.append(int_i) if xcb_tmp_len not in temp_vars: temp_vars.append(xcb_tmp_len) + # 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);" % (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 for(i=0; i<%s; i++) { ' - % (space, _c_accessor_get_expr(expr, lenfield_prefix, sep))) + code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length)) code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name)) code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space) code_lines.append('%s }' % space) @@ -732,54 +800,64 @@ def _c_serialize_helper_list_field(context, self, field, 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: 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)) - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + abs_field_name = _c_helper_absolute_name(prefix, field) + # default for simple cases: call sizeof() length = "sizeof(%s)" % field.c_field_type if context in ('unserialize', 'unpack', 'sizeof'): - value = ' %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) + # default: simple cast + 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%s[%d] = *(%s *)xcb_tmp;' % - (space, prefix_str, field.c_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 'serialize' == context: value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' if field.type.is_expr: - # need to register a temporary variable for the expression + # 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" % (field.field_name, _c_accessor_get_expr(field.type.expr))) - temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, 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;" % field.field_name + value += "&xcb_expr_%s;" % _cpp(field.field_name) elif field.type.is_pad: if field.type.nmemb == 1: value += "&xcb_pad;" else: - # FIXME - possible segmentation fault!! - value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb + # we could also set it to 0, see definition of xcb_send_request() + value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' length += "*%d" % field.type.nmemb else: # non-list type with fixed size if field.type.nmemb == 1: - value += "&%s%s;" % (prefix_str, field.c_field_name) + value += "&%s;" % (abs_field_name) + # list with nmemb (fixed size) elements else: - value += '%s%s;' % (prefix_str, field.c_field_name) + value += '%s;' % (abs_field_name) length = '%d' % field.type.nmemb return (value, length) @@ -788,38 +866,51 @@ def _c_serialize_helper_fields_fixed_size(context, self, field, def _c_serialize_helper_fields_variable_size(context, self, field, code_lines, temp_vars, space, prefix): - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) + prefix_str = _c_helper_absolute_name(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: value = ' %s = xcb_tmp;' % field.c_field_name 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: - address_of = '&' if (self.is_bitcase and self.has_name) else '' - var_field_name = "%s%s%s" % (address_of, prefix_str, field.c_field_name) + # 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) value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name + length = '' - prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix) code_lines.append('%s /* %s */' % (space, field.c_field_name)) if field.type.is_list: if value != '': + # 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, 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', prefix) + 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) @@ -841,14 +932,13 @@ def _c_serialize_helper_fields(context, self, if self.is_bitcase or self.var_followed_by_fixed_fields: if prev_field_was_variable and need_padding: # insert padding - _c_serialize_helper_insert_padding(context, code_lines, space) +# count += _c_serialize_helper_insert_padding(context, code_lines, space, +# self.var_followed_by_fixed_fields) prev_field_was_variable = False + + # prefix for fixed size fields fixed_prefix = prefix - if self.var_followed_by_fixed_fields and len(prefix)==0: - if 'unserialize' == context: - fixed_prefix = [('xcb_out', '.', self)] - else: - fixed_prefix = [('_aux', '->', self)] + value, length = _c_serialize_helper_fields_fixed_size(context, self, field, code_lines, temp_vars, space, fixed_prefix) @@ -859,37 +949,50 @@ def _c_serialize_helper_fields(context, self, else: # switch/bitcase: always calculate padding before and after variable sized fields if need_padding or is_bitcase: - _c_serialize_helper_insert_padding(context, code_lines, space) + 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 - + # save (un)serialization C code if '' != value: code_lines.append('%s%s' % (space, value)) - if field.type.fixed_size() and is_bitcase: - 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: - # padding + + if field.type.fixed_size(): + if is_bitcase or self.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: + # variable size objects or bitcase: + # value & length might have been inserted earlier for special cases if '' != length: - code_lines.append('%s xcb_block_len = %s;' % (space, 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): temp_vars.append(' int %s_len;' % field.c_field_name) - code_lines.append(' %s_len = xcb_block_len;' % field.c_field_name) - if context in ('unserialize', 'sizeof', 'unpack'): - code_lines.append('%s xcb_tmp += xcb_block_len;' % space) + 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)) + code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name)) + else: + code_lines.append('%s xcb_block_len += %s;' % (space, length)) + # 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 = xcb_block_len;' % space) + code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length)) code_lines.append('%s xcb_parts_idx++;' % space) count += 1 + need_padding = True + if self.var_followed_by_fixed_fields: + need_padding = False return count # _c_serialize_helper_fields() @@ -897,7 +1000,9 @@ def _c_serialize_helper_fields(context, self, def _c_serialize_helper(context, complex_type, code_lines, temp_vars, space='', prefix=[]): + # count tracks the number of fields to serialize count = 0 + if hasattr(complex_type, 'type'): self = complex_type.type complex_name = complex_type.name @@ -920,18 +1025,23 @@ def _c_serialize_helper(context, complex_type, if context in ('unserialize', 'unpack', 'sizeof') and not self.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) - _c_serialize_helper_insert_padding(context, code_lines, space) - + # probably not needed + #_c_serialize_helper_insert_padding(context, code_lines, space, False) + 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) + # "final padding" + count += _c_serialize_helper_insert_padding(context, code_lines, space, False) return count # _c_serialize_helper() -def _c_serialize(self): +def _c_serialize(context, self): + """ + depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof() + for the ComplexType variable self + """ _h_setlevel(1) _c_setlevel(1) @@ -939,10 +1049,19 @@ def _c_serialize(self): # _serialize() returns the buffer size _hc('int') + 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, + '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 - param_fields, wire_fields, params = get_serialize_params('serialize', self) # determine N(variable_fields) for field in param_fields: @@ -954,37 +1073,78 @@ def _c_serialize(self): maxtypelen = max(maxtypelen, len(p[0]) + len(p[1])) # write to .c/.h - for idx, p in enumerate(params): - line = "" + indent = ' '*(len(func_name)+2) + param_str = [] + for p in params: typespec, pointerspec, field_name = p - indent = ' '*(len(self.c_serialize_name)+2) - # p==0: function declaration - if 0==idx: - line = "%s (" % self.c_serialize_name - indent = '' spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) - line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name) - if idx < len(params)-1: - _hc("%s," % line) - else: - _h("%s);" % line) - _c("%s)" % line) - + param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)) + # insert function name + param_str[0] = "%s (%s" % (func_name, param_str[0].strip()) + param_str = map(lambda x: "%s," % x, param_str) + for s in param_str[:-1]: + _hc(s) + _h("%s);" % param_str[-1].rstrip(',')) + _c("%s)" % param_str[-1].rstrip(',')) _c('{') - if not self.is_switch: - _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) - else: - _c(' char *xcb_out = *_buffer;') + + code_lines = [] + temp_vars = [] + prefix = [] + + if 'serialize' == context: + if not self.is_switch and not self.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) + else: + _c(' char *xcb_out = *_buffer;') + _c(' unsigned int xcb_buffer_len = 0;') + 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: + _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) + prefix = [('_aux', '->', self)] + else: + _c(' %s xcb_out;', self.c_type) + prefix = [('xcb_out', '.', self)] + else: + aux_var = '_aux' # default for unpack: single pointer + # note: unserialize not generated for switch + if 'unserialize' == context: + aux_var = '(*_aux)' # unserialize: double pointer (!) + prefix = [(aux_var, '->', self)] + aux_ptr = '*_aux' _c(' unsigned int xcb_buffer_len = 0;') - if variable_size_fields > 0: - code_lines = [] - temp_vars = [] - count = _c_serialize_helper('serialize', self, - code_lines, temp_vars) - # update variable size fields - variable_size_fields = count + _c(' unsigned int xcb_block_len = 0;') + _c(' unsigned int xcb_pad = 0;') + + elif 'sizeof' == context: + param_names = [p[2] for p in params] + if self.is_switch: + # switch: call _unpack() + _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('}') + return + elif self.var_followed_by_fixed_fields: + # special case: call _unserialize() + _c(' %s *_aux = NULL;', self.c_type) + _c(' return %s(%s, &_aux);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) + _c('}') + return + else: + _c(' char *xcb_tmp = (char *)_buffer;') + prefix = [('_aux', '->', self)] + + 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(' struct iovec xcb_parts[%d];' % count) @@ -992,215 +1152,78 @@ def _c_serialize(self): temp_vars.append(' unsigned int xcb_block_len = 0;') temp_vars.append(' unsigned int i;') temp_vars.append(' char *xcb_tmp;') - for t in temp_vars: - _c(t) + 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): + + # look if we have to declare an '_aux' variable at all + if len(filter(lambda x: x.find('_aux')!=-1, code_lines))>0: + if not self.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('') - - if variable_size_fields > 0: - for l in code_lines: - _c(l) + for t in temp_vars: + _c(t) _c('') + for l in code_lines: + _c(l) # variable sized fields have been collected, now - # allocate memory and copy everything into a continuous memory area - _c(' if (NULL == xcb_out) {') - _c(' /* allocate memory */') - _c(' *_buffer = malloc(xcb_buffer_len);') - _c(' xcb_out = *_buffer;') - _c(' }') - _c('') - - # fill in struct members - if not self.is_switch: - 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: - _c(' xcb_tmp = (char*)++xcb_out;') - _c(' xcb_tmp += xcb_out_pad;') - else: - _c(' xcb_tmp = xcb_out;') - - # variable sized fields - _c(' for(i=0; i0: + _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: + _c(' xcb_tmp = (char*)++xcb_out;') + _c(' xcb_tmp += xcb_out_pad;') + else: + _c(' xcb_tmp = xcb_out;') + + # variable sized fields + _c(' for(i=0; i0: - if not self.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;') - for t in temp_vars: - _c(t) - _c('') - - for l in code_lines: - _c(l) - _c('') - _c(' return xcb_buffer_len;') - _c('}') -# _c_sizeof_helper() - def _c_iterator_get_end(field, accum): ''' Figures out what C code is needed to find the end of a variable-length structure field. @@ -1209,7 +1232,6 @@ def _c_iterator_get_end(field, accum): ''' if field.type.is_container: accum = field.c_accessor_name + '(' + accum + ')' - # XXX there could be fixed-length fields at the end return _c_iterator_get_end(field.type.last_varsized_field, accum) if field.type.is_list: # XXX we can always use the first way @@ -1262,11 +1284,17 @@ def _c_iterator(self, name): if not self.fixed_size(): _c(' %s *R = i->data;', self.c_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: - _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) + if self.need_sizeof: + _c(' xcb_generic_iterator_t child;') + _c(' child.data = (%s *)(((char *)R) + %s(R));', + self.c_type, self.c_sizeof_name) + else: + _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) _c(' --i->rem;') _c(' i->data = (%s *) child.data;', self.c_type) _c(' i->index = child.index;') @@ -1318,68 +1346,68 @@ def _c_iterator(self, name): _c(' return ret;') _c('}') -def _c_accessor_get_length(expr, prefix='', sep='->'): +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. For fields that follow a variable-length field, use the accessor. Otherwise, just reference the structure field directly. ''' - prefarrow = '' if prefix == '' else prefix + sep - - if expr.lenfield != None and expr.lenfield.prev_varsized_field != None: + + lenfield_name = expr.lenfield_name + 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 - # to call a special accessor function! - retval = expr.lenfield.c_accessor_name + '(' + prefix + ')' - if prefix in ('', '_aux', 'xcb_out'): - prefix_str = '' if prefix=='' else '%s' % (prefarrow) - retval = '%s%s' % (prefix_str, expr.lenfield_name) - return retval - elif expr.lenfield_name != None: - if prefix.endswith(sep): - return prefix + expr.lenfield_name - else: - return prefarrow + expr.lenfield_name + # to call a special accessor function like + return field_mapping(expr.lenfield_name) + elif expr.lenfield_name is not None: + return lenfield_name else: return str(expr.nmemb) -def _c_accessor_get_expr(expr, prefix='', sep='->'): +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. Recurses for math operations. Returns bitcount for value-mask fields. Otherwise, uses the value of the length field. ''' - lenexp = _c_accessor_get_length(expr, prefix, sep) + lenexp = _c_accessor_get_length(expr, field_mapping) if expr.op == '~': - return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' + return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' elif expr.op == 'popcount': - return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' + return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' elif expr.op == 'enumref': enum_name = expr.lenfield_type.name constant_name = expr.lenfield_name c_name = _n(enum_name + (constant_name,)).upper() return c_name elif expr.op == 'sumof': - # 1. locate the referenced list object + # locate the referenced list object list_obj = expr.lenfield_type field = None for f in expr.lenfield_parent.fields: if f.field_name == expr.lenfield_name: field = f break + if field is None: raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) - if prefix != '' and not prefix.endswith(sep): - prefix += sep - list_name = "%s%s" % (prefix, field.c_field_name) - c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name) - # FIXME - works only for integers this way!! - c_length_func = _c_accessor_get_expr(field.type.expr, prefix='', sep='') + 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) elif expr.op != None: - return '(' + _c_accessor_get_expr(expr.lhs, prefix, sep) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')' + 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 + ')' else: @@ -1389,21 +1417,30 @@ def _c_accessors_field(self, field): ''' Declares the accessor functions for a non-list field that follows a variable-length field. ''' + c_type = self.c_type + + # special case: switch + switch_obj = self if self.is_switch else None + if self.is_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(' ** ') _hc(' ** %s %s', field.c_field_type, field.c_accessor_name) _hc(' ** ') - _hc(' ** @param const %s *R', self.c_type) + _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, self.c_type) - _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) + _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) + _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) _c('{') if field.prev_varsized_field is None: _c(' return (%s *) (R + 1);', field.c_field_type) @@ -1419,19 +1456,19 @@ def _c_accessors_field(self, field): _hc(' **') _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name) _hc(' ** ') - _hc(' ** @param const %s *R', self.c_type) + _hc(' ** @param const %s *R', c_type) _hc(' ** @returns %s *', field.c_field_type) _hc(' **') _hc(' *****************************************************************************/') _hc(' ') - if field.type.is_switch: + if field.type.is_switch and switch_obj is None: return_type = 'void *' else: return_type = '%s *' % field.c_field_type _hc(return_type) - _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) - _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) + _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) + _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) _c('{') if field.prev_varsized_field is None: _c(' return (%s) (R + 1);', return_type) @@ -1443,6 +1480,7 @@ def _c_accessors_field(self, field): _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', return_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) _c('}') + def _c_accessors_list(self, field): ''' @@ -1451,32 +1489,83 @@ def _c_accessors_list(self, field): Declares length and get-iterator functions always. ''' list = field.type + c_type = self.c_type + + # special case: switch + # 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, + # 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: + 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 + 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 + # the switch expr, and store the parent objects in accessor_params and + # the fields in switch_fields + + # 'S': name for the 'toplevel' switch + toplevel_switch = parents[1] + params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch)) + fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True)) + + # initialize prefix for everything "below" S + prefix_str = '/* %s */ S' % toplevel_switch.name[-1] + prefix = [(prefix_str, '->', toplevel_switch)] + + # look for fields in the remaining containers + 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): + prefix.append((p.name[-1], '.', p)) + fields.update(_c_helper_field_mapping(p, prefix, flat=True)) + + # auxiliary object for 'S' parameter + S_obj = parents[1] _h_setlevel(1) _c_setlevel(1) 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 const %s *R', self.c_type) + _hc(' ** @param %s', params[idx][0]) _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, self.c_type) - _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) - _c('{') - if field.prev_varsized_field is None: + _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0]) + _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0]) + + _c('{') + if switch_obj is not None: + _c(' return %s;', fields[field.c_field_name][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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) - + _c(' return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', + field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) _c('}') _hc('') @@ -1485,16 +1574,24 @@ def _c_accessors_list(self, field): _hc(' **') _hc(' ** int %s', field.c_length_name) _hc(' ** ') - _hc(' ** @param const %s *R', self.c_type) + _hc(' ** @param const %s *R', c_type) _hc(' ** @returns int') _hc(' **') _hc(' *****************************************************************************/') _hc(' ') _hc('int') - _h('%s (const %s *R /**< */);', field.c_length_name, self.c_type) - _c('%s (const %s *R /**< */)', field.c_length_name, self.c_type) + 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('{') - _c(' return %s;', _c_accessor_get_expr(field.type.expr, 'R')) + _c(' return %s;', length) _c('}') if field.type.member.is_simple: @@ -1504,25 +1601,38 @@ def _c_accessors_list(self, field): _hc(' **') _hc(' ** xcb_generic_iterator_t %s', field.c_end_name) _hc(' ** ') - _hc(' ** @param const %s *R', self.c_type) + _hc(' ** @param const %s *R', c_type) _hc(' ** @returns xcb_generic_iterator_t') _hc(' **') _hc(' *****************************************************************************/') _hc(' ') _hc('xcb_generic_iterator_t') - _h('%s (const %s *R /**< */);', field.c_end_name, self.c_type) - _c('%s (const %s *R /**< */)', field.c_end_name, self.c_type) + if switch_obj is not None: + _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type) + spacing = ' '*(len(field.c_end_name)+2) + _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) + _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) + else: + _h('%s (const %s *R /**< */);', field.c_end_name, c_type) + _c('%s (const %s *R /**< */)', field.c_end_name, c_type) _c('{') _c(' xcb_generic_iterator_t i;') - - if field.prev_varsized_field == None: - _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R')) + + 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_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_accessor_get_expr(field.type.expr, fields)) else: - _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_accessor_get_expr(field.type.expr, 'R')) + _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_accessor_get_expr(field.type.expr, fields)) _c(' i.rem = 0;') - _c(' i.index = (char *) i.data - (char *) R;') + _c(' i.index = (char *) i.data - (char *) %s;', param) _c(' return i;') _c('}') @@ -1533,25 +1643,36 @@ def _c_accessors_list(self, field): _hc(' **') _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name) _hc(' ** ') - _hc(' ** @param const %s *R', self.c_type) + _hc(' ** @param const %s *R', c_type) _hc(' ** @returns %s', field.c_iterator_type) _hc(' **') _hc(' *****************************************************************************/') _hc(' ') + _hc('%s', field.c_iterator_type) - _h('%s (const %s *R /**< */);', field.c_iterator_name, self.c_type) - _c('%s (const %s *R /**< */)', field.c_iterator_name, self.c_type) + if switch_obj is not None: + _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type) + spacing = ' '*(len(field.c_iterator_name)+2) + _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) + _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) + else: + _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type) + _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type) _c('{') _c(' %s i;', field.c_iterator_type) - if field.prev_varsized_field == None: + if switch_obj is not None: + _c(' i.data = %s;', fields[field.c_field_name][0]) + _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) + elif field.prev_varsized_field == None: _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, field.c_field_type) - - _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R')) - _c(' i.index = (char *) i.data - (char *) R;') + _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', + field.c_field_type, field.c_field_type) + if switch_obj is None: + _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) + _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' ) _c(' return i;') _c('}') @@ -1559,9 +1680,12 @@ def _c_accessors(self, name, base): ''' Declares the accessor functions for the fields of a structure. ''' - # no accessors for switch - + # no accessors for switch itself - # switch always needs to be unpacked explicitly - if not self.is_switch: +# 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) @@ -1605,10 +1729,6 @@ def _c_complex(self): if not field.type.fixed_size() and not self.is_switch and not self.is_union: varfield = field.c_field_name continue -# if varfield != None and not field.type.is_pad and field.wire: -# errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name) -# sys.stderr.write(errmsg) -# sys.exit(1) if field.wire: struct_fields.append(field) @@ -1802,9 +1922,6 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): # _serialize() keeps track of padding automatically count -= 1 dimension = count + 2 - if self.var_followed_by_fixed_fields: - # there will be only one call to _serialize() and no need for additional padding - dimension -= 1 _c('{') _c(' static const xcb_protocol_request_t xcb_req = {') @@ -1820,6 +1937,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' %s xcb_out;', self.c_type) if self.var_followed_by_fixed_fields: _c(' /* in the protocol description, variable size fields are followed by fixed size fields */') + _c(' char *xcb_aux = 0;') for idx, f in enumerate(serial_fields): @@ -1830,13 +1948,14 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' unsigned int xcb_tmp_len;') _c(' char *xcb_tmp;') _c(' ') + # simple request call tracing # _c(' printf("in function %s\\n");' % func_name) # fixed size fields for field in wire_fields: if field.type.fixed_size(): if field.type.is_expr: - _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) + _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None)) elif field.type.is_pad: if field.type.nmemb == 1: _c(' xcb_out.%s = 0;', field.c_field_name) @@ -1857,8 +1976,8 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): # calls in order to free dyn. all. memory free_calls = [] + _c(' ') if not self.var_followed_by_fixed_fields: - _c(' ') _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;') @@ -1875,25 +1994,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): 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), field.type.member.c_wiretype) + _c_accessor_get_expr(field.type.expr, None), + field.type.member.c_wiretype) else: - expr = field.type.expr - prefix_str, lenfield_prefix = _c_serialize_helper_prefix([('xcb_out', '.', self)], - 'xcb_out', '.') - param_fields, wire_fields, params = get_serialize_params('sizeof', self) - param_names = [p[2] for p in params] - sep = '.' - - # look if the list's lenfield is a struct member or a function argument - # special case: if the list has a length field, its name will be returned - # unchanged by calling c_accessor_get_length(expr) - if expr.lenfield_name == _c_accessor_get_length(expr): - if expr.lenfield_name in param_names: - # the length field appears as separate argument, - # so no need for a prefix - lenfield_prefix = '' - - list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep) + list_length = _c_accessor_get_expr(field.type.expr, None) length = '' _c(" xcb_parts[%d].iov_len = 0;" % count) @@ -1933,12 +2037,16 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): # elif self.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);') + count += 1 # call _serialize() - buffer_var = 'xcb_parts[%d].iov_base' % count - serialize_args = get_serialize_args(self, '&%s' % buffer_var, '&xcb_out', 'serialize') - _c(' %s = (char *) 0;', buffer_var) + buffer_var = '&xcb_aux' + serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize') _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args) - free_calls.append(' free(xcb_parts[%d].iov_base);' % count) + _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count) + free_calls.append(' free(xcb_aux);') # no padding necessary - _serialize() keeps track of padding automatically _c(' ') From b89f634ff9b321f21874cd45e398d661a6ff726e Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Mon, 16 Aug 2010 18:22:42 +0200 Subject: [PATCH 13/26] small fix in the xkb pkg file --- xcb-xkb.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcb-xkb.pc.in b/xcb-xkb.pc.in index 31ccaa3..6ed0035 100644 --- a/xcb-xkb.pc.in +++ b/xcb-xkb.pc.in @@ -7,5 +7,5 @@ Name: XCB XKB Description: XCB Keyboard Extension (EXPERIMENTAL) Version: @PACKAGE_VERSION@ Requires: xcb -Libs: -L${libdir} -lxcb-xinput +Libs: -L${libdir} -lxcb-xkb Cflags: -I${includedir} From 5e8a7ade2dc8aeeeb8013785ca3f24c6057ae443 Mon Sep 17 00:00:00 2001 From: Christoph Reimann Date: Mon, 16 Aug 2010 20:24:40 +0200 Subject: [PATCH 14/26] small fix to get rid of some compiler warnings also added very basic documentation for xkb --- doc/xkb_internals | 49 +++++++++++++++++++++++++++++++++++++++++++++++ doc/xkb_issues | 38 ++++++++++++++++++++++++++++++++++++ src/c_client.py | 6 ++++-- 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 doc/xkb_internals create mode 100644 doc/xkb_issues diff --git a/doc/xkb_internals b/doc/xkb_internals new file mode 100644 index 0000000..93c6d01 --- /dev/null +++ b/doc/xkb_internals @@ -0,0 +1,49 @@ + +XKB introduces several uncommon data structures: + - switch allows conditional inclusion of fields + - several complex objects intermix variable and fixed size fields + - lists with a variable number of variable size objects + +To handle these objects, a number of new functions is generated: + - _serialize() turns a structured object into a byte stream, + (re)ordering or including fields according to the protocol + - _unserialize() rewrites data from a buffer into a structured object + - _unpack() expands a buffer representing a switch object into + a special structured type, all flags needed to resolve the switch + expression have to given as parameters + - _sizeof() calculates the size of a serialized object, often by calling + _unserialize()/_unpack() internally + +The new structured data type for switch is special as it contains fixed +and variable size fields. Variable size fields can be accessed via pointers. + +If switch appears in a request, an additional set of request helpers is +generated with the suffix _aux or _aux_(un)checked. While the 'common' +request functions require that switch has been serialized before, the _aux +variants take the structured data type. They are especially designed to +replace certain functions in xcb-util/aux. + +Accessors for switch members need two parameters, where the first is usually +a pointer to the respective request or reply structure, while the second +is a pointer to the unpacked switch data structure. + +Functions from the serialize family that take a double pointer can allocate +memory on their own, which is useful if the size of a buffer has to be +calculated depending on the data within. These functions call malloc() when +the double pointer is given as the address of a pointer that has been +initialized to 0. It is the responsibility of the user to free any allocated +memory. + +Intermixed variable and fixed size fields are an important special case in XKB. +The current implementation resolves the issue by reordering the fields before +sending them on the wire as well as before returning a reply. That means that +these objects look like 'common' XCB data types and they can be accessed as such +(i.e. fixed size fields directly via the structured type and variable size fields +via accessors/iterators). + +In case a list with variable size elements needs to be accessed, it is necessary +to use iterators. The iterator functions take care of determining the actual +object size for each element automatically. + +A small and preliminary set of auxiliary functions is available in xkb_util.c +in the check_xkb module. diff --git a/doc/xkb_issues b/doc/xkb_issues new file mode 100644 index 0000000..80efcc1 --- /dev/null +++ b/doc/xkb_issues @@ -0,0 +1,38 @@ + +There are a number of problematic special cases in XKB. The issues +mentioned here are at most partly resolved. + +1. The are several XxxDoodad structures defined in xkb.xml. They are used + in a few lists, but in a rather special way: + The struct "CommonDoodad" is supposed to be a rather generic data type, + combining the most basic Doodad fields that are common in all these structures. + All Doodads are encapsulated in a union type simply called "Doodad". + Now this union is used in subsequent list definitions, aiming at a kind of + 'polymorphism': From inspection of the protocol and Xlib, the Doodads are to + be discriminated based on their type field. + However the special meaning of the type field is not encoded in the protocol. + Furthermore the TextDoodad and the LogoDoodad are variable size types due to + some fields of type CountedString16, thereby turning the union into a + possibly variable size type as well. + However, for lists with variable size elements, special sizeof functions are + required. These cannot be autogenerated as it cannot be referred which + Doodad type to use for the union. + Therefore, the Doodad type structures are unsupported at the moment. + +2. There are still some bugs in xkb.xml: Either certain fields are missing + that are required by the protocol, or Xlib simply has another understanding + of the protocol. + +3. The interface for accessors should be reviewed. + +4. Currently some bitcases carry 'name' attributes. These could be avoided if + the data within would consist of a singe struct field only. + +5. switch could get a 'fixed_size' attribute, so when rewriting valueparam to switch, + an uint32_t * pointer could be used instead of void *. + +6. The automatic inclusion of padding requires some complicated coding in the + generator. This is errorprone and could be avoided if all padding is explicitly + given in the protocol definition. For variable size fields that require padding, + the pad tag could get a 'fieldref' attribute. That way padding could be handled + a lot easier in the autogenerator. \ No newline at end of file diff --git a/src/c_client.py b/src/c_client.py index 8e79480..26826e4 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -1293,11 +1293,13 @@ def _c_iterator(self, name): _c(' xcb_generic_iterator_t child;') _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: _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) + _c(' i->index = child.index;') _c(' --i->rem;') _c(' i->data = (%s *) child.data;', self.c_type) - _c(' i->index = child.index;') + else: _c(' --i->rem;') _c(' ++i->data;') @@ -1937,7 +1939,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False): _c(' %s xcb_out;', self.c_type) if self.var_followed_by_fixed_fields: _c(' /* in the protocol description, variable size fields are followed by fixed size fields */') - _c(' char *xcb_aux = 0;') + _c(' void *xcb_aux = 0;') for idx, f in enumerate(serial_fields): From 03bcccb132249142ba908a075e0bd5075fc20d97 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Fri, 10 Sep 2010 15:53:13 -0400 Subject: [PATCH 15/26] Add xkb.* to gitignore Signed-off-by: Peter Harris --- src/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/src/.gitignore b/src/.gitignore index 21421a2..a402afe 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -18,6 +18,7 @@ xf86dri.* xfixes.* xinerama.* xinput.* +xkb.* xprint.* xselinux.* xtest.* From a22909c0f513fe28347c56be65a345831c3ce744 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 8 Sep 2010 15:57:00 -0400 Subject: [PATCH 16/26] Don't emit out-of-module sizeof definitions Signed-off-by: Peter Harris --- src/c_client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 26826e4..85ae09b 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -399,8 +399,9 @@ def _c_type_setup(self, name, postfix): if self.need_sizeof: if self.c_sizeof_name not in finished_sizeof: - finished_sizeof.append(self.c_sizeof_name) - _c_serialize('sizeof', self) + 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): From 28a71c6567d08272dc9c1c2b32f0529f11f62b9e Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Fri, 10 Sep 2010 15:51:56 -0400 Subject: [PATCH 17/26] Fix memory leak in _sizeof implemented with _unserialize Signed-off-by: Peter Harris --- src/c_client.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 85ae09b..08d6ec4 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -1134,8 +1134,7 @@ def _c_serialize(context, self): return elif self.var_followed_by_fixed_fields: # special case: call _unserialize() - _c(' %s *_aux = NULL;', self.c_type) - _c(' return %s(%s, &_aux);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) + _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) _c('}') return else: @@ -1180,6 +1179,12 @@ def _c_serialize(context, self): # 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 + if 'unserialize' == context: + _c('') + _c(' if (NULL == _aux)') + _c(' return xcb_buffer_len;') + _c('') _c(' if (NULL == %s) {', aux_ptr) _c(' /* allocate memory */') From 8c1d2021ca611c1452a8d2ff2a705569e4ebd056 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 22 Sep 2010 21:16:51 -0400 Subject: [PATCH 18/26] Make *_unserialize safe to use on buffers in-place By calling memmove instead of memcpy, and walking the buffer backward from the end, *_unserialize is safe to use in-place. Signed-off-by: Peter Harris --- src/c_client.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 08d6ec4..a66c7e3 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -1218,12 +1218,13 @@ def _c_serialize(context, self): # unserialize: assign variable size fields individually if 'unserialize' == context: - _c(' *%s = xcb_out;', aux_ptr) - _c(' xcb_tmp = (char *)(*_aux+1);') + _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;') + param_fields.reverse() for field in param_fields: if not field.type.fixed_size(): - _c(' memcpy(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name) - _c(' xcb_tmp += %s_len;', field.c_field_name) + _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;') From 29cca33b9001961fa2c33bb9d9fe4a9983913fce Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 22 Sep 2010 22:32:34 -0400 Subject: [PATCH 19/26] Clean up a couple of warnings in xprint Signed-off-by: Peter Harris --- src/c_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c_client.py b/src/c_client.py index a66c7e3..1f3277a 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -875,7 +875,7 @@ def _c_serialize_helper_fields_variable_size(context, self, field, # special case: intermixed fixed and variable size fields if self.var_followed_by_fixed_fields and 'unserialize' == context: - value = ' %s = xcb_tmp;' % field.c_field_name + 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: From b672d1514c88e119f3aaeded8c8a488cad36db52 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 22 Sep 2010 23:15:38 -0400 Subject: [PATCH 20/26] Fix _unserialize of reply headers This cleans up a number of warnings, and passes the sequence number through correctly. Signed-off-by: Peter Harris --- src/c_client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 1f3277a..91719b7 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -925,8 +925,9 @@ def _c_serialize_helper_fields(context, self, prev_field_was_variable = False for field in self.fields: - if not ((field.wire and not field.auto) or field.visible): - continue + 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 if field.type.fixed_size(): From 5755582444ad0ba79e661ab3173cc38e9e588d83 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 10 Nov 2010 20:49:41 -0500 Subject: [PATCH 21/26] xcb_auth: Fix memory leak in _xcb_get_auth_info. If the initial get_peer_sock_name(getpeername ...) succeeds, the pointer to allocated memory is overwritten by the later call to get_peer_sock_name(getsockname ...). Fix that up by freeing the allocated memory before overwriting the pointer. Signed-off-by: Nick Bowler Signed-off-by: Julien Danjou --- src/xcb_auth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/xcb_auth.c b/src/xcb_auth.c index 1af27fc..4839b78 100644 --- a/src/xcb_auth.c +++ b/src/xcb_auth.c @@ -327,10 +327,15 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display) if (!info->namelen) goto no_auth; /* out of memory */ - if (!gotsockname && (sockname = get_peer_sock_name(getsockname, fd)) == NULL) + if (!gotsockname) { - free(info->name); - goto no_auth; /* can only authenticate sockets */ + free(sockname); + + if ((sockname = get_peer_sock_name(getsockname, fd)) == NULL) + { + free(info->name); + goto no_auth; /* can only authenticate sockets */ + } } ret = compute_auth(info, authptr, sockname); From 8ecd754b168a0352783bf1ba0f0887f7ff479ee8 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Wed, 17 Nov 2010 20:26:11 +0100 Subject: [PATCH 22/26] xcb_take_socket: Document sequence wrap requirements If lots of requests are send without one causing a reply, xcb can get confused about the current sequence number of a reply. Document the requirements of an external socket owner to avoid this problem. The return_socket callback for xcb_take_socket() originally was supposed to return the last sequence number used, but the version committed to libxcb never actually had this signature. This fixes the function's documentation not to mention this non-existent return value. Signed-off-by: Uli Schlachter Signed-off-by: Julien Danjou --- src/xcbext.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/xcbext.h b/src/xcbext.h index 2e10ba2..d6366cb 100644 --- a/src/xcbext.h +++ b/src/xcbext.h @@ -65,15 +65,22 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect * request XCB sent. The caller of xcb_take_socket must supply a * callback which XCB can call when it wants the write side of the * socket back to make a request. This callback synchronizes with the - * external socket owner, flushes any output queues if appropriate, and - * then returns the sequence number of the last request sent over the - * socket. */ + * external socket owner and flushes any output queues if appropriate. + * If you are sending requests which won't cause a reply, please note the + * comment for xcb_writev which explains some sequence number wrap issues. + * */ int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent); /* You must own the write-side of the socket (you've called * xcb_take_socket, and haven't returned from return_socket yet) to call * xcb_writev. Also, the iovec must have at least 1 byte of data in it. - * */ + * You have to make sure that xcb can detect sequence number wraps correctly. + * This means that the first request you send after xcb_take_socket must cause a + * reply (e.g. just insert a GetInputFocus request). After every (1 << 16) - 1 + * requests without a reply, you have to insert a request which will cause a + * reply. You can again use GetInputFocus for this. You do not have to wait for + * any of the GetInputFocus replies, but can instead handle them via + * xcb_discard_reply(). */ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t requests); From 69b78ced1a7bcdca538c0720fde9cf3e6f70d040 Mon Sep 17 00:00:00 2001 From: Jeetu Golani Date: Sun, 12 Dec 2010 16:48:41 -0500 Subject: [PATCH 23/26] Don't validate FD_SETSIZE on Win32 Windows' file handles have never been small or consecutive, so Windows' select has always been implemented the same way as everyone else's poll. On Windows, FD_SETSIZE is the size of the poll array, not the maximum SOCKET number. Signed-off-by: Peter Harris --- src/xcb_conn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xcb_conn.c b/src/xcb_conn.c index 35b9996..a017c20 100644 --- a/src/xcb_conn.c +++ b/src/xcb_conn.c @@ -257,6 +257,7 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info) { xcb_connection_t* c; +#ifndef _WIN32 #ifndef USE_POLL if(fd >= FD_SETSIZE) /* would overflow in FD_SET */ { @@ -264,6 +265,7 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info) return (xcb_connection_t *) &error_connection; } #endif +#endif /* !_WIN32*/ c = calloc(1, sizeof(xcb_connection_t)); if(!c) { From 9efced72a3cb8072fa60fbed4f04d61cde412494 Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Sun, 28 Nov 2010 14:02:40 +0100 Subject: [PATCH 24/26] fix Windows build and installation --- configure.ac | 10 ++++++++++ src/Makefile.am | 51 ++++++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 848310e..a8e171b 100644 --- a/configure.ac +++ b/configure.ac @@ -15,6 +15,7 @@ AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xyes) AC_CONFIG_HEADERS([src/config.h]) +AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL AC_PROG_CC @@ -72,12 +73,21 @@ AC_HEADER_STDC AC_SEARCH_LIBS(getaddrinfo, socket) AC_SEARCH_LIBS(connect, socket) +have_win32="no" +lt_enable_auto_import="" case $host_os in +mingw*) + have_win32="yes" + lt_enable_auto_import="-Wl,--enable-auto-import" + ;; linux*) AC_DEFINE([HAVE_ABSTRACT_SOCKETS], 1, [Define if your platform supports abstract sockets]) ;; esac +AC_SUBST(lt_enable_auto_import) +AM_CONDITIONAL([XCB_HAVE_WIN32], [test "x${have_win32}" = "xyes"]) + dnl define buffer queue size AC_ARG_WITH([queue-size], AC_HELP_STRING([--with-queue-size=SIZE], diff --git a/src/Makefile.am b/src/Makefile.am index 9b90914..950de5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ nodist_libxcb_la_SOURCES = xproto.c bigreq.c xc_misc.c # * If you add an interface, increment current and age and set revision to 0. # * If you change or remove an interface, increment current and set revision # and age to 0. -libxcb_la_LDFLAGS = -version-info 2:0:1 -no-undefined +libxcb_la_LDFLAGS = -version-info 2:0:1 -no-undefined @lt_enable_auto_import@ XCB_LIBS = libxcb.la @@ -27,7 +27,7 @@ XCB_LIBS = libxcb.la EXTSOURCES += composite.c if BUILD_COMPOSITE lib_LTLIBRARIES += libxcb-composite.la -libxcb_composite_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_composite_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_composite_la_LIBADD = $(XCB_LIBS) nodist_libxcb_composite_la_SOURCES = composite.c composite.h endif @@ -35,7 +35,7 @@ endif EXTSOURCES += damage.c if BUILD_DAMAGE lib_LTLIBRARIES += libxcb-damage.la -libxcb_damage_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_damage_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_damage_la_LIBADD = $(XCB_LIBS) nodist_libxcb_damage_la_SOURCES = damage.c damage.h endif @@ -43,7 +43,7 @@ endif EXTSOURCES += dpms.c if BUILD_DPMS lib_LTLIBRARIES += libxcb-dpms.la -libxcb_dpms_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_dpms_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_dpms_la_LIBADD = $(XCB_LIBS) nodist_libxcb_dpms_la_SOURCES = dpms.c dpms.h endif @@ -51,7 +51,7 @@ endif EXTSOURCES += dri2.c if BUILD_DRI2 lib_LTLIBRARIES += libxcb-dri2.la -libxcb_dri2_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_dri2_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_dri2_la_LIBADD = $(XCB_LIBS) nodist_libxcb_dri2_la_SOURCES = dri2.c dri2.h endif @@ -59,7 +59,7 @@ endif EXTSOURCES += glx.c if BUILD_GLX lib_LTLIBRARIES += libxcb-glx.la -libxcb_glx_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_glx_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_glx_la_LIBADD = $(XCB_LIBS) nodist_libxcb_glx_la_SOURCES = glx.c glx.h endif @@ -67,7 +67,7 @@ endif EXTSOURCES += randr.c if BUILD_RANDR lib_LTLIBRARIES += libxcb-randr.la -libxcb_randr_la_LDFLAGS = -version-info 1:0:1 -no-undefined +libxcb_randr_la_LDFLAGS = -version-info 1:0:1 -no-undefined @lt_enable_auto_import@ libxcb_randr_la_LIBADD = $(XCB_LIBS) nodist_libxcb_randr_la_SOURCES = randr.c randr.h endif @@ -75,7 +75,7 @@ endif EXTSOURCES += record.c if BUILD_RECORD lib_LTLIBRARIES += libxcb-record.la -libxcb_record_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_record_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_record_la_LIBADD = $(XCB_LIBS) nodist_libxcb_record_la_SOURCES = record.c record.h endif @@ -83,7 +83,7 @@ endif EXTSOURCES += render.c if BUILD_RENDER lib_LTLIBRARIES += libxcb-render.la -libxcb_render_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_render_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_render_la_LIBADD = $(XCB_LIBS) nodist_libxcb_render_la_SOURCES = render.c render.h endif @@ -91,7 +91,7 @@ endif EXTSOURCES += res.c if BUILD_RESOURCE lib_LTLIBRARIES += libxcb-res.la -libxcb_res_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_res_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_res_la_LIBADD = $(XCB_LIBS) nodist_libxcb_res_la_SOURCES = res.c res.h endif @@ -99,7 +99,7 @@ endif EXTSOURCES += screensaver.c if BUILD_SCREENSAVER lib_LTLIBRARIES += libxcb-screensaver.la -libxcb_screensaver_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_screensaver_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_screensaver_la_LIBADD = $(XCB_LIBS) nodist_libxcb_screensaver_la_SOURCES = screensaver.c screensaver.h endif @@ -107,7 +107,7 @@ endif EXTSOURCES += shape.c if BUILD_SHAPE lib_LTLIBRARIES += libxcb-shape.la -libxcb_shape_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_shape_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_shape_la_LIBADD = $(XCB_LIBS) nodist_libxcb_shape_la_SOURCES = shape.c shape.h endif @@ -115,7 +115,7 @@ endif EXTSOURCES += shm.c if BUILD_SHM lib_LTLIBRARIES += libxcb-shm.la -libxcb_shm_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_shm_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_shm_la_LIBADD = $(XCB_LIBS) nodist_libxcb_shm_la_SOURCES = shm.c shm.h endif @@ -123,7 +123,7 @@ endif EXTSOURCES += sync.c if BUILD_SYNC lib_LTLIBRARIES += libxcb-sync.la -libxcb_sync_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_sync_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_sync_la_LIBADD = $(XCB_LIBS) nodist_libxcb_sync_la_SOURCES = sync.c sync.h endif @@ -131,7 +131,7 @@ endif EXTSOURCES += xevie.c if BUILD_XEVIE lib_LTLIBRARIES += libxcb-xevie.la -libxcb_xevie_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xevie_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xevie_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xevie_la_SOURCES = xevie.c xevie.h endif @@ -139,7 +139,7 @@ endif EXTSOURCES += xf86dri.c if BUILD_XFREE86_DRI lib_LTLIBRARIES += libxcb-xf86dri.la -libxcb_xf86dri_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xf86dri_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xf86dri_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xf86dri_la_SOURCES = xf86dri.c xf86dri.h endif @@ -147,7 +147,7 @@ endif EXTSOURCES += xfixes.c if BUILD_XFIXES lib_LTLIBRARIES += libxcb-xfixes.la -libxcb_xfixes_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xfixes_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xfixes_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xfixes_la_SOURCES = xfixes.c xfixes.h endif @@ -155,7 +155,7 @@ endif EXTSOURCES += xinerama.c if BUILD_XINERAMA lib_LTLIBRARIES += libxcb-xinerama.la -libxcb_xinerama_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xinerama_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xinerama_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xinerama_la_SOURCES = xinerama.c xinerama.h endif @@ -163,7 +163,7 @@ endif EXTSOURCES += xinput.c if BUILD_XINPUT lib_LTLIBRARIES += libxcb-xinput.la -libxcb_xinput_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xinput_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xinput_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xinput_la_SOURCES = xinput.c xinput.h endif @@ -179,7 +179,7 @@ endif EXTSOURCES += xprint.c if BUILD_XPRINT lib_LTLIBRARIES += libxcb-xprint.la -libxcb_xprint_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xprint_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xprint_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xprint_la_SOURCES = xprint.c xprint.h endif @@ -187,7 +187,7 @@ endif EXTSOURCES += xselinux.c if BUILD_SELINUX lib_LTLIBRARIES += libxcb-xselinux.la -libxcb_xselinux_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xselinux_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xselinux_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xselinux_la_SOURCES = xselinux.c xselinux.h endif @@ -195,7 +195,7 @@ endif EXTSOURCES += xtest.c if BUILD_XTEST lib_LTLIBRARIES += libxcb-xtest.la -libxcb_xtest_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xtest_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xtest_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xtest_la_SOURCES = xtest.c xtest.h endif @@ -203,7 +203,7 @@ endif EXTSOURCES += xv.c if BUILD_XV lib_LTLIBRARIES += libxcb-xv.la -libxcb_xv_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xv_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xv_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xv_la_SOURCES = xv.c xv.h endif @@ -211,7 +211,7 @@ endif EXTSOURCES += xvmc.c if BUILD_XVMC lib_LTLIBRARIES += libxcb-xvmc.la -libxcb_xvmc_la_LDFLAGS = -version-info 0:0:0 -no-undefined +libxcb_xvmc_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@ libxcb_xvmc_la_LIBADD = $(XCB_LIBS) nodist_libxcb_xvmc_la_SOURCES = xvmc.c xvmc.h endif @@ -219,6 +219,9 @@ endif EXTHEADERS=$(EXTSOURCES:.c=.h) xcbinclude_HEADERS = xcb.h xcbext.h +if XCB_HAVE_WIN32 +xcbinclude_HEADERS += xcb_windefs.h +endif nodist_xcbinclude_HEADERS = $(EXTHEADERS) noinst_HEADERS = xcbint.h From c2e023646298da05e212056fbc6b329e4dd9a100 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Thu, 23 Dec 2010 13:32:17 -0500 Subject: [PATCH 25/26] Don't try to sizeof(void) sizeof(void) is a gcc extension, and not portable. Xorg Bugzilla 31959 http://bugs.freedesktop.org/show_bug.cgi?id=31959 http://lists.freedesktop.org/archives/xcb/2010-May/006039.html Signed-off-by: Peter Harris Tested-by: Cyril Brulebois --- src/c_client.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/c_client.py b/src/c_client.py index 91719b7..a10b3f1 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -1423,6 +1423,11 @@ def _c_accessor_get_expr(expr, field_mapping): else: return lenexp +def type_pad_type(type): + if type == 'void': + return 'char' + return type + def _c_accessors_field(self, field): ''' Declares the accessor functions for a non-list field that follows a variable-length field. @@ -1457,7 +1462,7 @@ def _c_accessors_field(self, field): 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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) _c('}') else: _hc('') @@ -1488,7 +1493,7 @@ def _c_accessors_field(self, field): 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);', - return_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) _c('}') @@ -1575,7 +1580,7 @@ def _c_accessors_list(self, field): 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, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset) + field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) _c('}') _hc('') @@ -1679,7 +1684,7 @@ def _c_accessors_list(self, field): 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, field.c_field_type) + field.c_field_type, type_pad_type(field.c_field_type)) if switch_obj is None: _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' ) From 8c3325f8bbdb1e8975bdb01525a52d6b0f80cfa3 Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Fri, 4 Mar 2011 12:41:55 -0800 Subject: [PATCH 26/26] darwin: Don't use poll() when expected to run on darwin10 and prior Signed-off-by: Jeremy Huddleston --- configure.ac | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a8e171b..b8d5471 100644 --- a/configure.ac +++ b/configure.ac @@ -131,8 +131,23 @@ AC_PREREQ([2.59c], [], [AC_SUBST([htmldir], [m4_ifset([AC_PACKAGE_TARNAME], XCB_CHECK_DOXYGEN() case $host_os in - # darwin has poll() but can't be used to poll character devices (atleast through SnowLeopard) - darwin*) ;; + # darwin through Snow Leopard has poll() but can't be used to poll character devices. + darwin@<:@789@:>@*|darwin10*) ;; + darwin*) + _ac_xorg_macosx_version_min="" + if echo $CPPFLAGS $CFLAGS | grep -q mmacosx-version-min ; then + _ac_xorg_macosx_version_min=`echo $CPPFLAGS $CFLAGS | sed 's/^.*-mmacosx-version-min=\(@<:@^ @:>@*\).*$/\1/'` + else + _ac_xorg_macosx_version_min=$MACOSX_DEPLOYMENT_TARGET + fi + case $_ac_xorg_macosx_version_min in + 10.@<:@0123456@:>@|10.@<:@0123456@:>@.*) ;; + *) + AC_CHECK_FUNC(poll, [AC_DEFINE(USE_POLL, 1, [poll() function is available])], ) + ;; + esac + unset _ac_xorg_macosx_version_min + ;; *) AC_CHECK_FUNC(poll, [AC_DEFINE(USE_POLL, 1, [poll() function is available])], ) ;;