_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('')
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
# 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:
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,
_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'
_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]
_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:
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
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('')
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' )
# 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):
'''
# 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.
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)):
if b.type.has_name:
_h(' } %s;', b.c_field_name)
- _h('} %s;', self.c_type)
+ _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
def c_struct(self, name):
'''
_c_complex(self)
_c_iterator(self, name)
-def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
+def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
'''
Declares a request function.
'''
# What flag is passed to xcb_request
func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
+ if reply_fds:
+ if func_flags == '0':
+ func_flags = 'XCB_REQUEST_REPLY_FDS'
+ else:
+ func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
+
# Global extension id variable or NULL for xproto
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
# 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('}')
+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.
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')
'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.items():
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')
+ 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')
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')
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')
+ 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')
# 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)
# 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:
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',))
if self.name == name:
# Structure definition
- _c_complex(self)
+ _c_complex(self, force_packed)
else:
# Typedef
_h('')
# 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':