c_client.py: remove useless 'today' variable
[free-sw/xcb/libxcb] / src / c_client.py
index 85ae09b..4f66b48 100644 (file)
@@ -1,8 +1,12 @@
 #!/usr/bin/env python
 from xml.etree.cElementTree import *
 from os.path import basename
 #!/usr/bin/env python
 from xml.etree.cElementTree import *
 from os.path import basename
+from functools import reduce
 import getopt
 import getopt
+import os
 import sys
 import sys
+import errno
+import time
 import re
 
 # Jump to the bottom of this file for the main routine
 import re
 
 # Jump to the bottom of this file for the main routine
@@ -30,6 +34,11 @@ finished_serializers = []
 finished_sizeof = []
 finished_switch = []
 
 finished_sizeof = []
 finished_switch = []
 
+# keeps enum objects so that we can refer to them when generating manpages.
+enums = {}
+
+manpaths = False
+
 def _h(fmt, *args):
     '''
     Writes the given line to the header file.
 def _h(fmt, *args):
     '''
     Writes the given line to the header file.
@@ -167,14 +176,21 @@ def c_open(self):
     _h('')
     _h('#include "xcb.h"')
 
     _h('')
     _h('#include "xcb.h"')
 
+    _c('#ifdef HAVE_CONFIG_H')
+    _c('#include "config.h"')
+    _c('#endif')
     _c('#include <stdlib.h>')
     _c('#include <string.h>')
     _c('#include <assert.h>')
     _c('#include <stdlib.h>')
     _c('#include <string.h>')
     _c('#include <assert.h>')
+    _c('#include <stddef.h>  /* for offsetof() */')
     _c('#include "xcbext.h"')
     _c('#include "%s.h"', _ns.header)
         
     _c('#include "xcbext.h"')
     _c('#include "%s.h"', _ns.header)
         
+    _c('')
+    _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
+
     if _ns.is_ext:
     if _ns.is_ext:
-        for (n, h) in self.imports:
+        for (n, h) in self.direct_imports:
             _hc('#include "%s.h"', h)
 
     _h('')
             _hc('#include "%s.h"', h)
 
     _h('')
@@ -242,6 +258,8 @@ def c_enum(self, name):
     Exported function that handles enum declarations.
     '''
 
     Exported function that handles enum declarations.
     '''
 
+    enums[name] = self
+
     tname = _t(name)
     if namecount[tname] > 1:
         tname = _t(name + ('enum',))
     tname = _t(name)
     if namecount[tname] > 1:
         tname = _t(name + ('enum',))
@@ -256,7 +274,10 @@ def c_enum(self, name):
         count = count - 1
         equals = ' = ' if eval != '' else ''
         comma = ',' if count > 0 else ''
         count = count - 1
         equals = ' = ' if eval != '' else ''
         comma = ',' if count > 0 else ''
-        _h('    %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
+        doc = ''
+        if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
+            doc = '\n/**< %s */\n' % self.doc.fields[enam]
+        _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
 
     _h('} %s;', tname)
 
 
     _h('} %s;', tname)
 
@@ -282,6 +303,7 @@ def _c_type_setup(self, name, postfix):
     self.c_reply_name = _n(name + ('reply',))
     self.c_reply_type = _t(name + ('reply',))
     self.c_cookie_type = _t(name + ('cookie',))
     self.c_reply_name = _n(name + ('reply',))
     self.c_reply_type = _t(name + ('reply',))
     self.c_cookie_type = _t(name + ('cookie',))
+    self.c_reply_fds_name = _n(name + ('reply_fds',))
 
     self.need_aux = False
     self.need_serialize = False
 
     self.need_aux = False
     self.need_serialize = False
@@ -323,7 +345,7 @@ def _c_type_setup(self, name, postfix):
             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_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_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and 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
             field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
 
             # correct the c_pointer field for variable size non-list types
@@ -443,7 +465,7 @@ def _c_helper_field_mapping(complex_type, prefix, flat=False):
     else:
         for f in complex_type.fields:
             fname = _c_helper_absolute_name(prefix, f)
     else:
         for f in complex_type.fields:
             fname = _c_helper_absolute_name(prefix, f)
-            if all_fields.has_key(f.field_name):
+            if f.field_name in all_fields:
                 raise Exception("field name %s has been registered before" % f.field_name)
 
             all_fields[f.field_name] = (fname, f)
                 raise Exception("field name %s has been registered before" % f.field_name)
 
             all_fields[f.field_name] = (fname, f)
@@ -524,7 +546,7 @@ def get_expr_fields(self):
         prefix.append(('', '', self))
 
     all_fields = _c_helper_resolve_field_names (prefix)
         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)
+    resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
     if len(unresolved_fields_names) != len(resolved_fields_names):
         raise Exception("could not resolve all fields for %s" % self.name)
     
     if len(unresolved_fields_names) != len(resolved_fields_names):
         raise Exception("could not resolve all fields for %s" % self.name)
     
@@ -636,7 +658,7 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
 
 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
     code_lines.append('%s    /* insert 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    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
 
 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
 
@@ -666,10 +688,20 @@ def _c_serialize_helper_switch(context, self, complex_name,
     switch_expr = _c_accessor_get_expr(self.expr, None)
 
     for b in self.bitcases:            
     switch_expr = _c_accessor_get_expr(self.expr, None)
 
     for b in self.bitcases:            
-        bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
-        code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
-#        code_lines.append('        printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' % 
-#                          (self.name[-1], b.type.name[-1], bitcase_expr))
+        len_expr = len(b.type.expr)
+        for n, expr in enumerate(b.type.expr):
+            bitcase_expr = _c_accessor_get_expr(expr, None)
+            # only one <enumref> in the <bitcase>
+            if len_expr == 1:
+                code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
+            # multiple <enumref> in the <bitcase>
+            elif n == 0: # first
+                code_lines.append('    if((%s & %s) ||' % (switch_expr, bitcase_expr))
+            elif len_expr == (n + 1): # last
+                code_lines.append('       (%s & %s)) {' % (switch_expr, bitcase_expr))
+            else: # between first and last
+                code_lines.append('       (%s & %s) ||' % (switch_expr, bitcase_expr))
+
         b_prefix = prefix
         if b.type.has_name:
             b_prefix = prefix + [(b.c_field_name, '.', b.type)]
         b_prefix = prefix
         if b.type.has_name:
             b_prefix = prefix + [(b.c_field_name, '.', b.type)]
@@ -743,8 +775,8 @@ def _c_serialize_helper_list_field(context, self, field,
     param_names = [p[2] for p in params]
     
     expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
     param_names = [p[2] for p in params]
     
     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)
+    resolved = list(filter(lambda x: x in param_names, expr_fields_names))
+    unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
     
     field_mapping = {}
     for r in resolved:
     
     field_mapping = {}
     for r in resolved:
@@ -757,8 +789,8 @@ def _c_serialize_helper_list_field(context, self, field,
                             field.c_field_name)        
         
         field_mapping.update(_c_helper_resolve_field_names(prefix))
                             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)
+        resolved += list(filter(lambda x: x in field_mapping, unresolved))
+        unresolved = list(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)
 
         if len(unresolved)>0:
             raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
 
@@ -875,7 +907,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:
         
         # 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:
             temp_vars.append('    %s *%s;' % (field.type.c_type, field.c_field_name))
         # special case: switch
         if 'unpack' == context:
@@ -925,8 +957,9 @@ def _c_serialize_helper_fields(context, self,
     prev_field_was_variable = False
 
     for field in self.fields:
     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():
 
         # switch/bitcase: fixed size fields must be considered explicitly 
         if field.type.fixed_size():
@@ -948,15 +981,22 @@ def _c_serialize_helper_fields(context, self,
 
         # fields with variable size
         else:
 
         # fields with variable size
         else:
-            # switch/bitcase: always calculate padding before and after variable sized fields
-            if need_padding or is_bitcase:
+            if field.type.is_pad:
+                # Variable length pad is <pad align= />
+                code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
                 count += _c_serialize_helper_insert_padding(context, code_lines, space, 
                 count += _c_serialize_helper_insert_padding(context, code_lines, space, 
+                                                        self.var_followed_by_fixed_fields)
+                continue
+            else:
+                # switch/bitcase: always calculate padding before and after variable sized fields
+                if need_padding or is_bitcase:
+                    count += _c_serialize_helper_insert_padding(context, code_lines, space,
                                                             self.var_followed_by_fixed_fields)
 
                                                             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
+                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:
         
         # save (un)serialization C code
         if '' != value:
@@ -991,6 +1031,8 @@ def _c_serialize_helper_fields(context, self,
             code_lines.append('%s    xcb_parts_idx++;' % space)
             count += 1
 
             code_lines.append('%s    xcb_parts_idx++;' % space)
             count += 1
 
+        code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
+
         need_padding = True
         if self.var_followed_by_fixed_fields:
             need_padding = False
         need_padding = True
         if self.var_followed_by_fixed_fields:
             need_padding = False
@@ -1026,8 +1068,8 @@ 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)
         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)
-            # probably not needed
-            #_c_serialize_helper_insert_padding(context, code_lines, space, False)
+            code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
+            code_lines.append('%s    xcb_block_len = 0;' % space)
 
         count += _c_serialize_helper_fields(context, self, 
                                             code_lines, temp_vars, 
 
         count += _c_serialize_helper_fields(context, self, 
                                             code_lines, temp_vars, 
@@ -1082,7 +1124,7 @@ def _c_serialize(context, self):
         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.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)
+    param_str = list(map(lambda x: "%s," % x, param_str))
     for s in param_str[:-1]:
         _hc(s)
     _h("%s);" % param_str[-1].rstrip(','))
     for s in param_str[:-1]:
         _hc(s)
     _h("%s);" % param_str[-1].rstrip(','))
@@ -1098,9 +1140,11 @@ def _c_serialize(context, self):
             _c('    %s *xcb_out = *_buffer;', self.c_type)
             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
             _c('    %s *xcb_out = *_buffer;', self.c_type)
             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
+            _c('    unsigned int xcb_align_to = 0;')
         else:
             _c('    char *xcb_out = *_buffer;')
             _c('    unsigned int xcb_buffer_len = 0;')
         else:
             _c('    char *xcb_out = *_buffer;')
             _c('    unsigned int xcb_buffer_len = 0;')
+            _c('    unsigned int xcb_align_to = 0;')
         prefix = [('_aux', '->', self)]
         aux_ptr = 'xcb_out'
 
         prefix = [('_aux', '->', self)]
         aux_ptr = 'xcb_out'
 
@@ -1123,6 +1167,7 @@ def _c_serialize(context, self):
         _c('    unsigned int xcb_buffer_len = 0;')
         _c('    unsigned int xcb_block_len = 0;')
         _c('    unsigned int xcb_pad = 0;')
         _c('    unsigned int xcb_buffer_len = 0;')
         _c('    unsigned int xcb_block_len = 0;')
         _c('    unsigned int xcb_pad = 0;')
+        _c('    unsigned int xcb_align_to = 0;')
 
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
 
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
@@ -1134,8 +1179,7 @@ def _c_serialize(context, self):
             return
         elif self.var_followed_by_fixed_fields:
             # special case: call _unserialize()
             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:
             _c('}')
             return
         else:
@@ -1159,7 +1203,7 @@ def _c_serialize(context, self):
         if not (self.is_switch or self.var_followed_by_fixed_fields):
 
             # look if we have to declare an '_aux' variable at all
         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 len(list(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:
                 if not self.var_followed_by_fixed_fields:
                     _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
                 else:
@@ -1168,6 +1212,7 @@ def _c_serialize(context, self):
             _c('    unsigned int xcb_buffer_len = 0;')
             _c('    unsigned int xcb_block_len = 0;')
             _c('    unsigned int xcb_pad = 0;')        
             _c('    unsigned int xcb_buffer_len = 0;')
             _c('    unsigned int xcb_block_len = 0;')
             _c('    unsigned int xcb_pad = 0;')        
+            _c('    unsigned int xcb_align_to = 0;')
 
     _c('')
     for t in temp_vars:
 
     _c('')
     for t in temp_vars:
@@ -1180,6 +1225,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'):
     # 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 */')
         _c('')
         _c('    if (NULL == %s) {', aux_ptr)
         _c('        /* allocate memory */')
@@ -1213,12 +1264,13 @@ def _c_serialize(context, self):
             
         # unserialize: assign variable size fields individually
         if 'unserialize' == context:
             
         # 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():
             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;')
  
     _c('')
     _c('    return xcb_buffer_len;')
@@ -1416,6 +1468,11 @@ def _c_accessor_get_expr(expr, field_mapping):
     else:
         return lenexp
 
     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.
 def _c_accessors_field(self, field):
     '''
     Declares the accessor functions for a non-list field that follows a variable-length field.
@@ -1450,7 +1507,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);', 
         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('')
         _c('}')
     else:
         _hc('')
@@ -1481,7 +1538,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);', 
         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('}')
 
     
         _c('}')
 
     
@@ -1491,6 +1548,17 @@ def _c_accessors_list(self, field):
     Declares a direct-accessor function only if the list members are fixed size.
     Declares length and get-iterator functions always.
     '''
     Declares a direct-accessor function only if the list members are fixed size.
     Declares length and get-iterator functions always.
     '''
+
+    def get_align_pad(field):
+            prev = field.prev_varsized_field
+            prev_prev = field.prev_varsized_field.prev_varsized_field
+
+            if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
+                return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
+            else:
+                return (prev, None)
+
+
     list = field.type
     c_type = self.c_type
 
     list = field.type
     c_type = self.c_type
 
@@ -1566,9 +1634,16 @@ def _c_accessors_list(self, field):
         elif field.prev_varsized_field is None:
             _c('    return (%s *) (R + 1);', field.c_field_type)
         else:
         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)
+            (prev_varsized_field, align_pad) = get_align_pad(field)
+
+            if align_pad is None:
+                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+                    type_pad_type(field.first_field_after_varsized.type.c_type))
+
+            _c('    xcb_generic_iterator_t prev = %s;',
+                _c_iterator_get_end(prev_varsized_field, 'R'))
+            _c('    return (%s *) ((char *) prev.data + %s + %d);',
+               field.c_field_type, align_pad, field.prev_varsized_offset)
         _c('}')
 
     _hc('')
         _c('}')
 
     _hc('')
@@ -1670,9 +1745,17 @@ def _c_accessors_list(self, field):
         elif field.prev_varsized_field == None:
             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
         else:
         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)
+            (prev_varsized_field, align_pad) = get_align_pad(field)
+
+            if align_pad is None:
+                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+                    type_pad_type(field.c_field_type))
+
+            _c('    xcb_generic_iterator_t prev = %s;',
+                _c_iterator_get_end(prev_varsized_field, 'R'))
+            _c('    i.data = (%s *) ((char *) prev.data + %s);',
+                field.c_field_type, align_pad)
+
         if switch_obj is None:
             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
         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' )
@@ -1690,10 +1773,11 @@ def _c_accessors(self, name, base):
 #    else:
     if True:
         for field in self.fields:
 #    else:
     if True:
         for field in self.fields:
-            if field.type.is_list and not field.type.fixed_size():
-                _c_accessors_list(self, field)
-            elif field.prev_varsized_field is not None or not field.type.fixed_size():
-                _c_accessors_field(self, field)
+            if not field.type.is_pad:
+                if 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):
     '''
 
 def c_simple(self, name):
     '''
@@ -1712,7 +1796,7 @@ def c_simple(self, name):
         # Iterator
         _c_iterator(self, name)
 
         # Iterator
         _c_iterator(self, name)
 
-def _c_complex(self):
+def _c_complex(self, force_packed = False):
     '''
     Helper function for handling all structure types.
     Called for all structs, requests, replies, events, errors.
     '''
     Helper function for handling all structure types.
     Called for all structs, requests, replies, events, errors.
@@ -1738,12 +1822,12 @@ def _c_complex(self):
     for field in struct_fields:
         length = len(field.c_field_type)
         # account for '*' pointer_spec
     for field in struct_fields:
         length = len(field.c_field_type)
         # account for '*' pointer_spec
-        if not field.type.fixed_size():
+        if not field.type.fixed_size() and not self.is_union:
             length += 1
         maxtypelen = max(maxtypelen, length)
 
     def _c_complex_field(self, field, space=''):
             length += 1
         maxtypelen = max(maxtypelen, length)
 
     def _c_complex_field(self, field, space=''):
-        if (field.type.fixed_size() or 
+        if (field.type.fixed_size() or self.is_union or
             # in case of switch with switch children, don't make the field a pointer
             # necessary for unserialize to work
             (self.is_switch and field.type.is_switch)):
             # 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)):
@@ -1767,7 +1851,7 @@ def _c_complex(self):
             if b.type.has_name:
                 _h('    } %s;', b.c_field_name)
 
             if b.type.has_name:
                 _h('    } %s;', b.c_field_name)
 
-    _h('} %s;', self.c_type)
+    _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
 
 def c_struct(self, name):
     '''
 
 def c_struct(self, name):
     '''
@@ -1786,7 +1870,7 @@ def c_union(self, name):
     _c_complex(self)
     _c_iterator(self, name)
 
     _c_complex(self)
     _c_iterator(self, name)
 
-def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
+def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
     '''
     Declares a request function.
     '''
     '''
     Declares a request function.
     '''
@@ -1815,6 +1899,12 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     # What flag is passed to xcb_request
     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
 
     # What flag is passed to xcb_request
     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
 
+    if reply_fds:
+        if func_flags == '0':
+            func_flags = 'XCB_REQUEST_REPLY_FDS'
+        else:
+            func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
+
     # Global extension id variable or NULL for xproto
     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
 
     # Global extension id variable or NULL for xproto
     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
 
@@ -1855,11 +1945,58 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     _c_setlevel(1)
     _h('')
     _h('/**')
     _c_setlevel(1)
     _h('')
     _h('/**')
-    _h(' * Delivers a request to the X server')
+    if hasattr(self, "doc") and self.doc:
+        if self.doc.brief:
+            _h(' * @brief ' + self.doc.brief)
+        else:
+            _h(' * No brief doc yet')
+
+    _h(' *')
     _h(' * @param c The connection')
     _h(' * @param c The connection')
+    param_names = [f.c_field_name for f in param_fields]
+    if hasattr(self, "doc") and self.doc:
+        for field in param_fields:
+            # XXX: hard-coded until we fix xproto.xml
+            base_func_name = self.c_request_name if not aux else self.c_aux_name
+            if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+                field.enum = 'GC'
+            elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+                field.enum = 'CW'
+            elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+                field.enum = 'CW'
+            if field.enum:
+                # XXX: why the 'xcb' prefix?
+                key = ('xcb', field.enum)
+
+                tname = _t(key)
+                if namecount[tname] > 1:
+                    tname = _t(key + ('enum',))
+                _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
+
+            if self.doc and field.field_name in self.doc.fields:
+                desc = self.doc.fields[field.field_name]
+                for name in param_names:
+                    desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+                desc = desc.split("\n")
+                desc = [line if line != '' else '\\n' for line in desc]
+                _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
+            # If there is no documentation yet, we simply don't generate an
+            # @param tag. Doxygen will then warn about missing documentation.
+
     _h(' * @return A cookie')
     _h(' *')
     _h(' * @return A cookie')
     _h(' *')
-    _h(' * Delivers a request to the X server.')
+
+    if hasattr(self, "doc") and self.doc:
+        if self.doc.description:
+            desc = self.doc.description
+            for name in param_names:
+                desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+            desc = desc.split("\n")
+            _h(' * ' + "\n * ".join(desc))
+        else:
+            _h(' * No description yet')
+    else:
+        _h(' * Delivers a request to the X server.')
     _h(' * ')
     if checked:
         _h(' * This form can be used only if the request will not cause')
     _h(' * ')
     if checked:
         _h(' * This form can be used only if the request will not cause')
@@ -2053,6 +2190,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
         # no padding necessary - _serialize() keeps track of padding automatically
 
     _c('    ')
         # no padding necessary - _serialize() keeps track of padding automatically
 
     _c('    ')
+    for field in param_fields:
+        if field.isfd:
+            _c('    xcb_send_fd(c, %s);', field.c_field_name)
+    
     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
     
     # free dyn. all. data, if any
     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
     
     # free dyn. all. data, if any
@@ -2156,6 +2297,51 @@ def _c_reply(self, name):
 
     _c('}')
 
 
     _c('}')
 
+def _c_reply_has_fds(self):
+    for field in self.fields:
+        if field.isfd:
+            return True
+    return False
+
+def _c_reply_fds(self, name):
+    '''
+    Declares the function that returns fds related to the reply.
+    '''
+    spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
+    spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
+    _h('')
+    _h('/**')
+    _h(' * Return the reply fds')
+    _h(' * @param c      The connection')
+    _h(' * @param reply  The reply')
+    _h(' *')
+    _h(' * Returns the array of reply fds of the request asked by')
+    _h(' * ')
+    _h(' * The returned value must be freed by the caller using free().')
+    _h(' */')
+    _c('')
+    _hc('')
+    _hc('/*****************************************************************************')
+    _hc(' **')
+    _hc(' ** int * %s', self.c_reply_fds_name)
+    _hc(' ** ')
+    _hc(' ** @param xcb_connection_t%s  *c', spacing1)
+    _hc(' ** @param %s  *reply', self.c_reply_type)
+    _hc(' ** @returns int *')
+    _hc(' **')
+    _hc(' *****************************************************************************/')
+    _hc(' ')
+    _hc('int *')
+    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
+    _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
+    _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
+    _c('{')
+    
+    _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
+
+    _c('}')
+    
+
 def _c_opcode(name, opcode):
     '''
     Declares the opcode define for requests, events, and errors.
 def _c_opcode(name, opcode):
     '''
     Declares the opcode define for requests, events, and errors.
@@ -2178,6 +2364,523 @@ def _c_cookie(self, name):
     _h('    unsigned int sequence; /**<  */')
     _h('} %s;', self.c_cookie_type)
 
     _h('    unsigned int sequence; /**<  */')
     _h('} %s;', self.c_cookie_type)
 
+def _man_request(self, name, cookie_type, void, aux):
+    param_fields = [f for f in self.fields if f.visible]
+
+    func_name = self.c_request_name if not aux else self.c_aux_name
+
+    def create_link(linkname):
+        name = 'man/%s.%s' % (linkname, section)
+        if manpaths:
+            sys.stdout.write(name)
+        f = open(name, 'w')
+        f.write('.so man%s/%s.%s' % (section, func_name, section))
+        f.close()
+
+    if manpaths:
+        sys.stdout.write('man/%s.%s ' % (func_name, section))
+    # Our CWD is src/, so this will end up in src/man/
+    f = open('man/%s.%s' % (func_name, section), 'w')
+    f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
+    # Left-adjust instead of adjusting to both sides
+    f.write('.ad l\n')
+    f.write('.SH NAME\n')
+    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
+    f.write('%s \\- %s\n' % (func_name, brief))
+    f.write('.SH SYNOPSIS\n')
+    # Don't split words (hyphenate)
+    f.write('.hy 0\n')
+    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+    # function prototypes
+    prototype = ''
+    count = len(param_fields)
+    for field in param_fields:
+        count = count - 1
+        c_field_const_type = field.c_field_const_type
+        c_pointer = field.c_pointer
+        if c_pointer == ' ':
+            c_pointer = ''
+        if field.type.need_serialize and not aux:
+            c_field_const_type = "const void"
+            c_pointer = '*'
+        comma = ', ' if count else ');'
+        prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
+
+    f.write('.SS Request function\n')
+    f.write('.HP\n')
+    base_func_name = self.c_request_name if not aux else self.c_aux_name
+    f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
+    create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
+    if not void:
+        f.write('.PP\n')
+        f.write('.SS Reply datastructure\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
+        struct_fields = []
+        maxtypelen = 0
+
+        for field in self.reply.fields:
+            if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+                continue
+            if field.wire:
+                struct_fields.append(field)
+
+        for field in struct_fields:
+            length = len(field.c_field_type)
+            # account for '*' pointer_spec
+            if not field.type.fixed_size():
+                length += 1
+            maxtypelen = max(maxtypelen, length)
+
+        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))
+                f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+            else:
+                spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
+                f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
+                #_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:
+                    space = '    '
+                for field in b.type.fields:
+                    _c_complex_field(self, field, space)
+                if b.type.has_name:
+                    print >> sys.stderr, 'ERROR: New unhandled documentation case'
+                    pass
+
+        f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
+        f.write('.fi\n')
+
+        f.write('.SS Reply function\n')
+        f.write('.HP\n')
+        f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
+                 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
+                (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
+        create_link('%s' % self.c_reply_name)
+
+        has_accessors = False
+        for field in self.reply.fields:
+            if field.type.is_list and not field.type.fixed_size():
+                has_accessors = True
+            elif field.prev_varsized_field is not None or not field.type.fixed_size():
+                has_accessors = True
+
+        if has_accessors:
+            f.write('.SS Reply accessors\n')
+
+        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:
+                f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+                create_link('%s' % field.c_accessor_name)
+            else:
+                f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+                create_link('%s' % field.c_accessor_name)
+
+        def _c_accessors_list(self, field):
+            '''
+            Declares the accessor functions for a list field.
+            Declares a direct-accessor function only if the list members are fixed size.
+            Declares length and get-iterator functions always.
+            '''
+            list = field.type
+            c_type = self.reply.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 *\\fIreply\\fP' % 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]
+
+            if list.member.fixed_size():
+                idx = 1 if switch_obj is not None else 0
+                f.write('.HP\n')
+                f.write('%s *\\fB%s\\fP(%s);\n' %
+                        (field.c_field_type, field.c_accessor_name, params[idx][0]))
+                create_link('%s' % field.c_accessor_name)
+
+            f.write('.HP\n')
+            f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                    (field.c_length_name, c_type))
+            create_link('%s' % field.c_length_name)
+
+            if field.type.member.is_simple:
+                f.write('.HP\n')
+                f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                        (field.c_end_name, c_type))
+                create_link('%s' % field.c_end_name)
+            else:
+                f.write('.HP\n')
+                f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                        (field.c_iterator_type, field.c_iterator_name,
+                         c_type))
+                create_link('%s' % field.c_iterator_name)
+
+        for field in self.reply.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)
+
+
+    f.write('.br\n')
+    # Re-enable hyphenation and adjusting to both sides
+    f.write('.hy 1\n')
+
+    # argument reference
+    f.write('.SH REQUEST ARGUMENTS\n')
+    f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
+    f.write('The XCB connection to X11.\n')
+    for field in param_fields:
+        f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+        printed_enum = False
+        # XXX: hard-coded until we fix xproto.xml
+        if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+            field.enum = 'GC'
+        elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+            field.enum = 'CW'
+        elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+            field.enum = 'CW'
+        if hasattr(field, "enum") and field.enum:
+            # XXX: why the 'xcb' prefix?
+            key = ('xcb', field.enum)
+            if key in enums:
+                f.write('One of the following values:\n')
+                f.write('.RS 1i\n')
+                enum = enums[key]
+                count = len(enum.values)
+                for (enam, eval) in enum.values:
+                    count = count - 1
+                    f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+                    if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
+                        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+                        f.write('%s\n' % desc)
+                    else:
+                        f.write('TODO: NOT YET DOCUMENTED.\n')
+                f.write('.RE\n')
+                f.write('.RS 1i\n')
+                printed_enum = True
+
+        if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
+            desc = self.doc.fields[field.field_name]
+            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+            if printed_enum:
+                f.write('\n')
+            f.write('%s\n' % desc)
+        else:
+            f.write('TODO: NOT YET DOCUMENTED.\n')
+        if printed_enum:
+            f.write('.RE\n')
+
+    # Reply reference
+    if not void:
+        f.write('.SH REPLY FIELDS\n')
+        # These fields are present in every reply:
+        f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+        f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
+                 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
+                 'be used to tell replies apart from each other.\n') %
+                 _n(self.reply.name).upper())
+        f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+        f.write('The sequence number of the last request processed by the X11 server.\n')
+        f.write('.IP \\fI%s\\fP 1i\n' % 'length')
+        f.write('The length of the reply, in words (a word is 4 bytes).\n')
+        for field in self.reply.fields:
+            if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
+                field.c_field_name.startswith('pad')):
+                continue
+
+            if field.type.is_list and not field.type.fixed_size():
+                continue
+            elif field.prev_varsized_field is not None or not field.type.fixed_size():
+                continue
+            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+            printed_enum = False
+            if hasattr(field, "enum") and field.enum:
+                # XXX: why the 'xcb' prefix?
+                key = ('xcb', field.enum)
+                if key in enums:
+                    f.write('One of the following values:\n')
+                    f.write('.RS 1i\n')
+                    enum = enums[key]
+                    count = len(enum.values)
+                    for (enam, eval) in enum.values:
+                        count = count - 1
+                        f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+                        if enum.doc and enam in enum.doc.fields:
+                            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+                            f.write('%s\n' % desc)
+                        else:
+                            f.write('TODO: NOT YET DOCUMENTED.\n')
+                    f.write('.RE\n')
+                    f.write('.RS 1i\n')
+                    printed_enum = True
+
+            if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
+                desc = self.reply.doc.fields[field.field_name]
+                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+                if printed_enum:
+                    f.write('\n')
+                f.write('%s\n' % desc)
+            else:
+                f.write('TODO: NOT YET DOCUMENTED.\n')
+            if printed_enum:
+                f.write('.RE\n')
+
+
+
+    # text description
+    f.write('.SH DESCRIPTION\n')
+    if hasattr(self, "doc") and self.doc and self.doc.description:
+        desc = self.doc.description
+        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+        lines = desc.split('\n')
+        f.write('\n'.join(lines) + '\n')
+
+    f.write('.SH RETURN VALUE\n')
+    if void:
+        f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
+                 'have to be handled in the event loop.\n\nIf you want to '
+                 'handle errors directly with \\fIxcb_request_check\\fP '
+                 'instead, use \\fI%s_checked\\fP. See '
+                 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
+    else:
+        f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
+                 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
+                 'handle errors in the event loop instead, use '
+                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
+                 'details.\n') %
+                (cookie_type, self.c_reply_name, base_func_name, section))
+    f.write('.SH ERRORS\n')
+    if hasattr(self, "doc") and self.doc:
+        for errtype, errtext in self.doc.errors.items():
+            f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
+            errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
+            f.write('%s\n' % (errtext))
+    if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
+        f.write('This request does never generate any errors.\n')
+    if hasattr(self, "doc") and self.doc and self.doc.example:
+        f.write('.SH EXAMPLE\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        lines = self.doc.example.split('\n')
+        f.write('\n'.join(lines) + '\n')
+        f.write('.fi\n')
+    f.write('.SH SEE ALSO\n')
+    if hasattr(self, "doc") and self.doc:
+        see = ['.BR %s (%s)' % ('xcb-requests', section)]
+        if self.doc.example:
+            see.append('.BR %s (%s)' % ('xcb-examples', section))
+        for seename, seetype in self.doc.see.items():
+            if seetype == 'program':
+                see.append('.BR %s (1)' % seename)
+            elif seetype == 'event':
+                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
+            elif seetype == 'request':
+                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
+            elif seetype == 'function':
+                see.append('.BR %s (%s)' % (seename, section))
+            else:
+                see.append('TODO: %s (type %s)' % (seename, seetype))
+        f.write(',\n'.join(see) + '\n')
+    f.write('.SH AUTHOR\n')
+    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+    f.close()
+
+def _man_event(self, name):
+    if manpaths:
+        sys.stdout.write('man/%s.%s ' % (self.c_type, section))
+    # Our CWD is src/, so this will end up in src/man/
+    f = open('man/%s.%s' % (self.c_type, section), 'w')
+    f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
+    # Left-adjust instead of adjusting to both sides
+    f.write('.ad l\n')
+    f.write('.SH NAME\n')
+    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
+    f.write('%s \\- %s\n' % (self.c_type, brief))
+    f.write('.SH SYNOPSIS\n')
+    # Don't split words (hyphenate)
+    f.write('.hy 0\n')
+    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+    f.write('.PP\n')
+    f.write('.SS Event datastructure\n')
+    f.write('.nf\n')
+    f.write('.sp\n')
+    f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
+    struct_fields = []
+    maxtypelen = 0
+
+    for field in self.fields:
+        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+            continue
+        if field.wire:
+            struct_fields.append(field)
+
+    for field in struct_fields:
+        length = len(field.c_field_type)
+        # account for '*' pointer_spec
+        if not field.type.fixed_size():
+            length += 1
+        maxtypelen = max(maxtypelen, length)
+
+    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))
+            f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+        else:
+            print >> sys.stderr, 'ERROR: New unhandled documentation case'
+
+    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:
+                space = '    '
+            for field in b.type.fields:
+                _c_complex_field(self, field, space)
+            if b.type.has_name:
+                print >> sys.stderr, 'ERROR: New unhandled documentation case'
+                pass
+
+    f.write('} \\fB%s\\fP;\n' % self.c_type)
+    f.write('.fi\n')
+
+
+    f.write('.br\n')
+    # Re-enable hyphenation and adjusting to both sides
+    f.write('.hy 1\n')
+
+    # argument reference
+    f.write('.SH EVENT FIELDS\n')
+    f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+    f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
+             'also present in the \\fIxcb_generic_event_t\\fP and can be used '
+             'to tell events apart from each other.\n') % _n(name).upper())
+    f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+    f.write('The sequence number of the last request processed by the X11 server.\n')
+
+    if not self.is_switch:
+        for field in struct_fields:
+            # Skip the fields which every event has, we already documented
+            # them (see above).
+            if field.c_field_name in ('response_type', 'sequence'):
+                continue
+            if isinstance(field.type, PadType):
+                continue
+            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+            if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
+                desc = self.doc.fields[field.field_name]
+                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+                f.write('%s\n' % desc)
+            else:
+                f.write('NOT YET DOCUMENTED.\n')
+
+    # text description
+    f.write('.SH DESCRIPTION\n')
+    if hasattr(self, "doc") and self.doc and self.doc.description:
+        desc = self.doc.description
+        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+        lines = desc.split('\n')
+        f.write('\n'.join(lines) + '\n')
+
+    if hasattr(self, "doc") and self.doc and self.doc.example:
+        f.write('.SH EXAMPLE\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        lines = self.doc.example.split('\n')
+        f.write('\n'.join(lines) + '\n')
+        f.write('.fi\n')
+    f.write('.SH SEE ALSO\n')
+    if hasattr(self, "doc") and self.doc:
+        see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
+        if self.doc.example:
+            see.append('.BR %s (%s)' % ('xcb-examples', section))
+        for seename, seetype in self.doc.see.items():
+            if seetype == 'program':
+                see.append('.BR %s (1)' % seename)
+            elif seetype == 'event':
+                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
+            elif seetype == 'request':
+                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
+            elif seetype == 'function':
+                see.append('.BR %s (%s)' % (seename, section))
+            else:
+                see.append('TODO: %s (type %s)' % (seename, seetype))
+        f.write(',\n'.join(see) + '\n')
+    f.write('.SH AUTHOR\n')
+    f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+    f.close()
+
+
 def c_request(self, name):
     '''
     Exported function that handles request declarations.
 def c_request(self, name):
     '''
     Exported function that handles request declarations.
@@ -2199,14 +2902,17 @@ def c_request(self, name):
         # Reply structure definition
         _c_complex(self.reply)
         # Request prototypes
         # Reply structure definition
         _c_complex(self.reply)
         # Request prototypes
-        _c_request_helper(self, name, self.c_cookie_type, False, True)
-        _c_request_helper(self, name, self.c_cookie_type, False, False)
+        has_fds = _c_reply_has_fds(self.reply)
+        _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
+        _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
         if self.need_aux:
         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)
+            _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
+            _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
         # Reply accessors
         _c_accessors(self.reply, name + ('reply',), name)
         _c_reply(self, name)
         # Reply accessors
         _c_accessors(self.reply, name + ('reply',), name)
         _c_reply(self, name)
+        if has_fds:
+            _c_reply_fds(self, name)
     else:
         # Request prototypes
         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
     else:
         # Request prototypes
         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
@@ -2215,11 +2921,38 @@ def c_request(self, name):
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
 
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
 
+    # We generate the manpage afterwards because _c_type_setup has been called.
+    # TODO: what about aux helpers?
+    cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
+    _man_request(self, name, cookie_type, not self.reply, False)
 
 def c_event(self, name):
     '''
     Exported function that handles event declarations.
     '''
 
 def c_event(self, name):
     '''
     Exported function that handles event declarations.
     '''
+
+    # The generic event structure xcb_ge_event_t has the full_sequence field
+    # at the 32byte boundary. That's why we've to inject this field into GE
+    # events while generating the structure for them. Otherwise we would read
+    # garbage (the internal full_sequence) when accessing normal event fields
+    # there.
+    force_packed = False
+    if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
+        event_size = 0
+        for field in self.fields:
+            if field.type.size != None and field.type.nmemb != None:
+                event_size += field.type.size * field.type.nmemb
+            if event_size == 32:
+                full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
+                idx = self.fields.index(field)
+                self.fields.insert(idx + 1, full_sequence)
+
+                # If the event contains any 64-bit extended fields, they need
+                # to remain aligned on a 64-bit boundary.  Adding full_sequence
+                # would normally break that; force the struct to be packed.
+                force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
+                break
+
     _c_type_setup(self, name, ('event',))
 
     # Opcode define
     _c_type_setup(self, name, ('event',))
 
     # Opcode define
@@ -2227,12 +2960,14 @@ def c_event(self, name):
 
     if self.name == name:
         # Structure definition
 
     if self.name == name:
         # Structure definition
-        _c_complex(self)
+        _c_complex(self, force_packed)
     else:
         # Typedef
         _h('')
         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
 
     else:
         # Typedef
         _h('')
         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
 
+    _man_event(self, name)
+
 def c_error(self, name):
     '''
     Exported function that handles error declarations.
 def c_error(self, name):
     '''
     Exported function that handles error declarations.
@@ -2269,29 +3004,46 @@ output = {'open'    : c_open,
 
 # Check for the argument that specifies path to the xcbgen python package.
 try:
 
 # Check for the argument that specifies path to the xcbgen python package.
 try:
-    opts, args = getopt.getopt(sys.argv[1:], 'p:')
-except getopt.GetoptError, err:
-    print str(err)
-    print 'Usage: c_client.py [-p path] file.xml'
+    opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
+except getopt.GetoptError as err:
+    print(err)
+    print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
     sys.exit(1)
 
 for (opt, arg) in opts:
     sys.exit(1)
 
 for (opt, arg) in opts:
+    if opt == '-c':
+        center_footer=arg
+    if opt == '-l':
+        left_footer=arg
+    if opt == '-s':
+        section=arg
     if opt == '-p':
     if opt == '-p':
-        sys.path.append(arg)
+        sys.path.insert(1, arg)
+    elif opt == '-m':
+        manpaths = True
+        sys.stdout.write('man_MANS = ')
 
 # Import the module class
 try:
     from xcbgen.state import Module
 
 # Import the module class
 try:
     from xcbgen.state import Module
+    from xcbgen.xtypes import *
 except ImportError:
 except ImportError:
-    print ''
-    print 'Failed to load the xcbgen Python package!'
-    print 'Make sure that xcb/proto installed it on your Python path.'
-    print 'If not, you will need to create a .pth file or define $PYTHONPATH'
-    print 'to extend the path.'
-    print 'Refer to the README file in xcb/proto for more info.'
-    print ''
+    print('''
+Failed to load the xcbgen Python package!
+Make sure that xcb/proto installed it on your Python path.
+If not, you will need to create a .pth file or define $PYTHONPATH
+to extend the path.
+Refer to the README file in xcb/proto for more info.
+''')
     raise
 
     raise
 
+# Ensure the man subdirectory exists
+try:
+    os.mkdir('man')
+except OSError as e:
+    if e.errno != errno.EEXIST:
+        raise
+
 # Parse the xml header
 module = Module(args[0], output)
 
 # Parse the xml header
 module = Module(args[0], output)