c_client.py: remove useless 'today' variable
[free-sw/xcb/libxcb] / src / c_client.py
index 31ed3b5..4f66b48 100644 (file)
@@ -176,6 +176,9 @@ def c_open(self):
     _h('')
     _h('#include "xcb.h"')
 
+    _c('#ifdef HAVE_CONFIG_H')
+    _c('#include "config.h"')
+    _c('#endif')
     _c('#include <stdlib.h>')
     _c('#include <string.h>')
     _c('#include <assert.h>')
@@ -187,7 +190,7 @@ def c_open(self):
     _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
 
     if _ns.is_ext:
-        for (n, h) in self.imports:
+        for (n, h) in self.direct_imports:
             _hc('#include "%s.h"', h)
 
     _h('')
@@ -300,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_fds_name = _n(name + ('reply_fds',))
 
     self.need_aux = False
     self.need_serialize = False
@@ -684,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:            
-        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)]
@@ -967,15 +981,22 @@ def _c_serialize_helper_fields(context, self,
 
         # 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, 
+                                                        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)
 
-            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:
@@ -1047,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)
-            # 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, 
@@ -1119,11 +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('    unsigned int xcb_align_to;')
+            _c('    unsigned int xcb_align_to = 0;')
         else:
             _c('    char *xcb_out = *_buffer;')
             _c('    unsigned int xcb_buffer_len = 0;')
-            _c('    unsigned int xcb_align_to;')
+            _c('    unsigned int xcb_align_to = 0;')
         prefix = [('_aux', '->', self)]
         aux_ptr = 'xcb_out'
 
@@ -1146,7 +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_align_to;')
+        _c('    unsigned int xcb_align_to = 0;')
 
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
@@ -1191,7 +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_align_to;')
+            _c('    unsigned int xcb_align_to = 0;')
 
     _c('')
     for t in temp_vars:
@@ -1527,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.
     '''
+
+    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
 
@@ -1602,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:
-            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
-            _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
-               field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
+            (prev_varsized_field, align_pad) = get_align_pad(field)
+
+            if align_pad is None:
+                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+                    type_pad_type(field.first_field_after_varsized.type.c_type))
+
+            _c('    xcb_generic_iterator_t prev = %s;',
+                _c_iterator_get_end(prev_varsized_field, 'R'))
+            _c('    return (%s *) ((char *) prev.data + %s + %d);',
+               field.c_field_type, align_pad, field.prev_varsized_offset)
         _c('}')
 
     _hc('')
@@ -1706,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:
-            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
-            _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', 
-               field.c_field_type, type_pad_type(field.c_field_type))
+            (prev_varsized_field, align_pad) = get_align_pad(field)
+
+            if align_pad is None:
+                align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
+                    type_pad_type(field.c_field_type))
+
+            _c('    xcb_generic_iterator_t prev = %s;',
+                _c_iterator_get_end(prev_varsized_field, 'R'))
+            _c('    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' )
@@ -1726,10 +1773,11 @@ def _c_accessors(self, name, base):
 #    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):
     '''
@@ -1748,7 +1796,7 @@ def c_simple(self, name):
         # Iterator
         _c_iterator(self, name)
 
-def _c_complex(self):
+def _c_complex(self, force_packed = False):
     '''
     Helper function for handling all structure types.
     Called for all structs, requests, replies, events, errors.
@@ -1774,12 +1822,12 @@ def _c_complex(self):
     for field in struct_fields:
         length = len(field.c_field_type)
         # account for '*' pointer_spec
-        if not field.type.fixed_size():
+        if not field.type.fixed_size() and not self.is_union:
             length += 1
         maxtypelen = max(maxtypelen, length)
 
     def _c_complex_field(self, field, space=''):
-        if (field.type.fixed_size() or 
+        if (field.type.fixed_size() or self.is_union or
             # in case of switch with switch children, don't make the field a pointer
             # necessary for unserialize to work
             (self.is_switch and field.type.is_switch)):
@@ -1803,7 +1851,7 @@ def _c_complex(self):
             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):
     '''
@@ -1822,7 +1870,7 @@ def c_union(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.
     '''
@@ -1851,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'
 
+    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'
 
@@ -2136,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('    ')
+    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
@@ -2239,6 +2297,51 @@ def _c_reply(self, name):
 
     _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.
@@ -2267,18 +2370,18 @@ def _man_request(self, name, cookie_type, void, aux):
     func_name = self.c_request_name if not aux else self.c_aux_name
 
     def create_link(linkname):
-        name = 'man/%s.3' % linkname
+        name = 'man/%s.%s' % (linkname, section)
         if manpaths:
             sys.stdout.write(name)
         f = open(name, 'w')
-        f.write('.so man3/%s.3' % func_name)
+        f.write('.so man%s/%s.%s' % (section, func_name, section))
         f.close()
 
     if manpaths:
-        sys.stdout.write('man/%s.3 ' % func_name)
+        sys.stdout.write('man/%s.%s ' % (func_name, section))
     # Our CWD is src/, so this will end up in src/man/
-    f = open('man/%s.3' % func_name, 'w')
-    f.write('.TH %s 3  %s "XCB" "XCB Requests"\n' % (func_name, today))
+    f = open('man/%s.%s' % (func_name, section), 'w')
+    f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
     # Left-adjust instead of adjusting to both sides
     f.write('.ad l\n')
     f.write('.SH NAME\n')
@@ -2603,17 +2706,17 @@ def _man_request(self, name, cookie_type, void, aux):
                  'have to be handled in the event loop.\n\nIf you want to '
                  'handle errors directly with \\fIxcb_request_check\\fP '
                  'instead, use \\fI%s_checked\\fP. See '
-                 '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
+                 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
     else:
         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
                  'handle errors in the event loop instead, use '
-                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
+                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
                  'details.\n') %
-                (cookie_type, self.c_reply_name, base_func_name))
+                (cookie_type, self.c_reply_name, base_func_name, section))
     f.write('.SH ERRORS\n')
     if hasattr(self, "doc") and self.doc:
-        for errtype, errtext in self.doc.errors.iteritems():
+        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))
@@ -2628,18 +2731,18 @@ def _man_request(self, name, cookie_type, void, aux):
         f.write('.fi\n')
     f.write('.SH SEE ALSO\n')
     if hasattr(self, "doc") and self.doc:
-        see = ['.BR %s (3)' % 'xcb-requests']
+        see = ['.BR %s (%s)' % ('xcb-requests', section)]
         if self.doc.example:
-            see.append('.BR %s (3)' % 'xcb-examples')
-        for seename, seetype in self.doc.see.iteritems():
+            see.append('.BR %s (%s)' % ('xcb-examples', section))
+        for seename, seetype in self.doc.see.items():
             if seetype == 'program':
                 see.append('.BR %s (1)' % seename)
             elif seetype == 'event':
-                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
             elif seetype == 'request':
-                see.append('.BR %s (3)' % _n(('xcb', seename)))
+                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
             elif seetype == 'function':
-                see.append('.BR %s (3)' % seename)
+                see.append('.BR %s (%s)' % (seename, section))
             else:
                 see.append('TODO: %s (type %s)' % (seename, seetype))
         f.write(',\n'.join(see) + '\n')
@@ -2649,10 +2752,10 @@ def _man_request(self, name, cookie_type, void, aux):
 
 def _man_event(self, name):
     if manpaths:
-        sys.stdout.write('man/%s.3 ' % self.c_type)
+        sys.stdout.write('man/%s.%s ' % (self.c_type, section))
     # Our CWD is src/, so this will end up in src/man/
-    f = open('man/%s.3' % self.c_type, 'w')
-    f.write('.TH %s 3  %s "XCB" "XCB Events"\n' % (self.c_type, today))
+    f = open('man/%s.%s' % (self.c_type, section), 'w')
+    f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
     # Left-adjust instead of adjusting to both sides
     f.write('.ad l\n')
     f.write('.SH NAME\n')
@@ -2758,18 +2861,18 @@ def _man_event(self, name):
         f.write('.fi\n')
     f.write('.SH SEE ALSO\n')
     if hasattr(self, "doc") and self.doc:
-        see = ['.BR %s (3)' % 'xcb_generic_event_t']
+        see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
         if self.doc.example:
-            see.append('.BR %s (3)' % 'xcb-examples')
-        for seename, seetype in self.doc.see.iteritems():
+            see.append('.BR %s (%s)' % ('xcb-examples', section))
+        for seename, seetype in self.doc.see.items():
             if seetype == 'program':
                 see.append('.BR %s (1)' % seename)
             elif seetype == 'event':
-                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+                see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
             elif seetype == 'request':
-                see.append('.BR %s (3)' % _n(('xcb', seename)))
+                see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
             elif seetype == 'function':
-                see.append('.BR %s (3)' % seename)
+                see.append('.BR %s (%s)' % (seename, section))
             else:
                 see.append('TODO: %s (type %s)' % (seename, seetype))
         f.write(',\n'.join(see) + '\n')
@@ -2799,14 +2902,17 @@ def c_request(self, name):
         # 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:
-            _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)
+        if has_fds:
+            _c_reply_fds(self, name)
     else:
         # Request prototypes
         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
@@ -2824,6 +2930,29 @@ 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
@@ -2831,7 +2960,7 @@ def c_event(self, name):
 
     if self.name == name:
         # Structure definition
-        _c_complex(self)
+        _c_complex(self, force_packed)
     else:
         # Typedef
         _h('')
@@ -2875,13 +3004,19 @@ output = {'open'    : c_open,
 
 # Check for the argument that specifies path to the xcbgen python package.
 try:
-    opts, args = getopt.getopt(sys.argv[1:], 'p:m')
+    opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
 except getopt.GetoptError as err:
     print(err)
-    print('Usage: c_client.py [-p path] file.xml')
+    print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
     sys.exit(1)
 
 for (opt, arg) in opts:
+    if opt == '-c':
+        center_footer=arg
+    if opt == '-l':
+        left_footer=arg
+    if opt == '-s':
+        section=arg
     if opt == '-p':
         sys.path.insert(1, arg)
     elif opt == '-m':
@@ -2905,12 +3040,10 @@ Refer to the README file in xcb/proto for more info.
 # Ensure the man subdirectory exists
 try:
     os.mkdir('man')
-except OSError, e:
+except OSError as e:
     if e.errno != errno.EEXIST:
         raise
 
-today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
-
 # Parse the xml header
 module = Module(args[0], output)