2 from xml.etree.cElementTree import *
3 from os.path import basename
8 # Jump to the bottom of this file for the main routine
10 # Some hacks to make the API more readable, and to keep backwards compability
11 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
12 _cname_special_cases = {'DECnet':'decnet'}
14 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
16 _cplusplus_annoyances = {'class' : '_class',
19 _c_keywords = {'default' : '_default'}
27 # global variable to keep track of serializers and switch data types
28 # due to weird dependencies, I see no way to do this more elegant at the moment
29 finished_serializers = []
35 Writes the given line to the header file.
37 _hlines[_hlevel].append(fmt % args)
41 Writes the given line to the source file.
43 _clines[_clevel].append(fmt % args)
47 Writes the given line to both the header and source files.
52 # XXX See if this level thing is really necessary.
55 Changes the array that header lines are written to.
56 Supports writing different sections of the header file.
59 while len(_hlines) <= idx:
65 Changes the array that source lines are written to.
66 Supports writing to different sections of the source file.
69 while len(_clines) <= idx:
75 Does C-name conversion on a single string fragment.
76 Uses a regexp with some hard-coded special cases.
78 if str in _cname_special_cases:
79 return _cname_special_cases[str]
81 split = _cname_re.finditer(str)
82 name_parts = [match.group(0) for match in split]
83 return '_'.join(name_parts)
87 Checks for certain C++ reserved words and fixes them.
89 if str in _cplusplus_annoyances:
90 return _cplusplus_annoyances[str]
91 elif str in _c_keywords:
92 return _c_keywords[str]
98 Does C-name conversion on an extension name.
99 Has some additional special cases on top of _n_item.
101 if str in _extension_special_cases:
102 return _n_item(str).lower()
108 Does C-name conversion on a tuple of strings.
109 Different behavior depending on length of tuple, extension/not extension, etc.
110 Basically C-name converts the individual pieces, then joins with underscores.
115 parts = [list[0], _n_item(list[1])]
117 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
119 parts = [list[0]] + [_n_item(i) for i in list[1:]]
120 return '_'.join(parts).lower()
124 Does C-name conversion on a tuple of strings representing a type.
125 Same as _n but adds a "_t" on the end.
130 parts = [list[0], _n_item(list[1]), 't']
132 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
134 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
135 return '_'.join(parts).lower()
140 Exported function that handles module open.
141 Opens the files and writes out the auto-generated comment, header file includes, etc.
145 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
147 # Build the type-name collision avoidance table used by c_enum
148 build_collision_table()
154 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
155 _hc(' * Edit at your peril.')
160 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
161 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
165 _h('#ifndef __%s_H', _ns.header.upper())
166 _h('#define __%s_H', _ns.header.upper())
168 _h('#include "xcb.h"')
170 _c('#include <stdlib.h>')
171 _c('#include <string.h>')
172 _c('#include <assert.h>')
173 _c('#include "xcbext.h"')
174 _c('#include "%s.h"', _ns.header)
177 for (n, h) in self.imports:
178 _hc('#include "%s.h"', h)
181 _h('#ifdef __cplusplus')
187 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
188 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
190 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
193 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
197 Exported function that handles module close.
198 Writes out all the stored content lines, then closes the files.
205 _h('#ifdef __cplusplus')
217 hfile = open('%s.h' % _ns.header, 'w')
225 cfile = open('%s.c' % _ns.header, 'w')
232 def build_collision_table():
236 for v in module.types.values():
238 namecount[name] = (namecount.get(name) or 0) + 1
240 def c_enum(self, name):
242 Exported function that handles enum declarations.
246 if namecount[tname] > 1:
247 tname = _t(name + ('enum',))
251 _h('typedef enum %s {', tname)
253 count = len(self.values)
255 for (enam, eval) in self.values:
257 equals = ' = ' if eval != '' else ''
258 comma = ',' if count > 0 else ''
259 _h(' %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
263 def _c_type_setup(self, name, postfix):
265 Sets up all the C-related state by adding additional data fields to
266 all Field and Type objects. Here is where we figure out most of our
267 variable and function names.
269 Recurses into child fields and list member types.
271 # Do all the various names in advance
272 self.c_type = _t(name + postfix)
273 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
275 self.c_iterator_type = _t(name + ('iterator',))
276 self.c_next_name = _n(name + ('next',))
277 self.c_end_name = _n(name + ('end',))
279 self.c_request_name = _n(name)
280 self.c_checked_name = _n(name + ('checked',))
281 self.c_unchecked_name = _n(name + ('unchecked',))
282 self.c_reply_name = _n(name + ('reply',))
283 self.c_reply_type = _t(name + ('reply',))
284 self.c_cookie_type = _t(name + ('cookie',))
286 self.need_aux = False
287 self.need_serialize = False
288 self.need_sizeof = False
290 self.c_aux_name = _n(name + ('aux',))
291 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
292 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
293 self.c_serialize_name = _n(name + ('serialize',))
294 self.c_unserialize_name = _n(name + ('unserialize',))
295 self.c_unpack_name = _n(name + ('unpack',))
296 self.c_sizeof_name = _n(name + ('sizeof',))
298 # special case: structs where variable size fields are followed by fixed size fields
299 self.var_followed_by_fixed_fields = False
301 # whether a request or reply has a switch field
303 self.need_serialize = True
304 self.c_container = 'struct'
305 for bitcase in self.bitcases:
306 bitcase.c_field_name = _cpp(bitcase.field_name)
307 _c_type_setup(bitcase.type, bitcase.field_type, ())
309 elif self.is_container:
311 self.c_container = 'union' if self.is_union else 'struct'
312 prev_varsized_field = None
313 prev_varsized_offset = 0
314 first_field_after_varsized = None
316 for field in self.fields:
317 _c_type_setup(field.type, field.field_type, ())
318 if field.type.is_list:
319 _c_type_setup(field.type.member, field.field_type, ())
320 if (field.type.nmemb is None):
321 # if field.type.member.need_serialize:
322 # self.need_serialize = True
323 self.need_sizeof = True
325 field.c_field_type = _t(field.field_type)
326 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
327 field.c_field_name = _cpp(field.field_name)
328 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else ''
329 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
331 # correct the c_pointer field for variable size non-list types
332 if not field.type.fixed_size() and field.c_pointer == ' ':
333 field.c_pointer = '*'
334 if field.type.is_list and not field.type.member.fixed_size():
335 field.c_pointer = '*'
337 if field.type.is_switch:
338 field.c_pointer = '*'
339 field.c_field_const_type = 'const ' + field.c_field_type
341 elif not field.type.fixed_size() and not field.type.is_bitcase:
342 #self.need_serialize = True
343 self.need_sizeof = True
345 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
346 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
347 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
348 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
350 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
352 field.prev_varsized_field = prev_varsized_field
353 field.prev_varsized_offset = prev_varsized_offset
355 if prev_varsized_offset == 0:
356 first_field_after_varsized = field
357 field.first_field_after_varsized = first_field_after_varsized
359 if field.type.fixed_size():
360 prev_varsized_offset += field.type.size
361 # special case: intermixed fixed and variable size fields
362 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
363 if not self.is_union:
364 self.need_serialize = True
365 self.var_followed_by_fixed_fields = True
367 self.last_varsized_field = field
368 prev_varsized_field = field
369 prev_varsized_offset = 0
371 if self.var_followed_by_fixed_fields:
372 if field.type.fixed_size():
373 field.prev_varsized_field = None
375 if self.need_serialize:
376 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
377 self.need_sizeof = True
379 # as switch does never appear at toplevel,
380 # continue here with type construction
382 if self.c_type not in finished_switch:
383 finished_switch.append(self.c_type)
384 # special: switch C structs get pointer fields for variable-sized members
386 # FIXME: what about accessors & switch (un)packing functions
387 # _c_iterator() does not seem to be the right place to do it,
388 # as the accessors would need any parameters to pass to _unpack() as well
390 if not self.is_bitcase:
391 if self.need_serialize:
392 if self.c_serialize_name not in finished_serializers:
393 finished_serializers.append(self.c_serialize_name)
395 # _unpack() and _unserialize() are only needed for special cases
396 if self.is_switch or self.var_followed_by_fixed_fields:
399 if self.c_sizeof_name not in finished_sizeof:
400 finished_sizeof.append(self.c_sizeof_name)
401 _c_sizeof_helper(self)
404 def get_request_fields(self):
408 for field in self.fields:
410 # the field should appear as a parameter in the function call
411 param_fields.append(field)
412 if field.wire and not field.auto:
413 if field.type.fixed_size() and not self.is_switch:
414 # field in the xcb_out structure
415 wire_fields.append(field)
416 # fields like 'pad0' are skipped!
418 return (param_fields, wire_fields)
419 # get_request_fields()
421 def get_expr_fields(self):
422 # get the fields referenced by switch or list expression
423 def get_expr_field_names(expr):
425 if expr.lenfield_name is not None:
426 return [expr.lenfield_name]
428 # constant value expr
432 return get_expr_field_names(expr.rhs)
433 elif expr.op == 'popcount':
434 return get_expr_field_names(expr.rhs)
435 elif expr.op == 'sumof':
436 return [expr.lenfield_name]
437 elif expr.op == 'enumref':
440 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
441 # get_expr_field_names()
443 # resolve the field names with the parent structure(s)
444 unresolved_fields = get_expr_field_names(self.expr)
445 if unresolved_fields is None:
447 expr_fields = dict.fromkeys(unresolved_fields)
448 for p in reversed(self.parent):
449 parent_fields = dict((f.field_name, f) for f in p.fields)
450 for f in parent_fields.keys():
451 if f in unresolved_fields:
452 expr_fields[f] = parent_fields[f]
453 unresolved_fields.remove(f)
454 if len(unresolved_fields) == 0:
457 if None in expr_fields.values():
458 raise Exception("could not resolve all fields for %s" % self.name)
460 params = expr_fields.values()
464 def resolve_fields(anchestor, complex_obj=None):
465 """find fields referenced by anchestor or descendents with external scope"""
469 if complex_obj is None:
470 complex_obj = anchestor
471 for field in complex_obj.fields:
472 all_fields.append(field)
473 if field.type.is_switch or field.type.is_list:
474 expr_fields += get_expr_fields(field.type)
475 if field.type.is_container:
476 expr_fields += resolve_fields(anchestor, field.type)
477 # try to resolve expr fields
478 for e in expr_fields:
479 if e not in all_fields:
484 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
485 def add_param(params, param):
486 if param not in params:
489 param_fields, wire_fields = get_request_fields(self)
491 param_fields = get_expr_fields(self)
493 # _serialize function parameters
494 # cannot use set() for params, as series is important
496 if 'serialize' == context:
497 params.append(('void', '**', buffer_var))
498 elif context in ('unserialize', 'unpack', 'sizeof'):
499 params.append(('const void', '*', buffer_var))
501 # look for special cases
502 unresolved_fields = resolve_fields(self)
503 for f in unresolved_fields:
504 add_param(params, (f.c_field_type, '', f.c_field_name))
506 # make sure all required length fields are present
507 for p in param_fields:
508 if p.visible and not p.wire and not p.auto:
509 typespec = p.c_field_type
511 add_param(params, (typespec, pointerspec, p.c_field_name))
513 # parameter fields if any
515 for p in get_expr_fields(self):
516 typespec = p.c_field_const_type
517 pointerspec = p.c_pointer
518 add_param(params, (typespec, pointerspec, p.c_field_name))
520 # aux argument - structure to be serialized
521 if 'serialize' == context:
522 add_param(params, ('const %s' % self.c_type, '*', aux_var))
523 elif 'unserialize' == context:
524 add_param(params, ('%s' % self.c_type, '**', aux_var))
525 elif 'unpack' == context:
526 add_param(params, ('%s' % self.c_type, '*', aux_var))
528 if not self.is_switch and 'serialize' == context:
529 for p in param_fields:
530 if not p.type.fixed_size():
531 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
532 return (param_fields, wire_fields, params)
533 # get_serialize_params()
535 def _c_serialize_helper_prefix(prefix, aux_var='_aux', aux_sep='->'):
536 # prefix is a list of (field_name, anchestor object) tuples
537 # concatenate field names
539 for name, sep, obj in prefix:
542 sep = '.' if (obj.is_bitcase and obj.has_name) else '->'
545 lenfield_prefix = '' if prefix_str.find(aux_var)==0 else aux_var
548 if lenfield_prefix != '':
549 lenfield_prefix += aux_sep
550 lenfield_prefix += prefix_str
551 return (prefix_str, lenfield_prefix)
552 # _c_serialize_helper_prefix
554 def _c_field_mapping(context, complex_type, prefix):
555 def get_prefix(field, prefix):
556 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
558 if context in ('serialize', 'unserialize'):
559 if field.type.fixed_size() or complex_type.is_switch:
560 prefix_str = '_aux->'
562 raise Exception("unknown context '%s' in c_field_mapping" % context)
565 def get_field_name(fields, complex_type, prefix):
566 for f in complex_type.fields:
567 prefix_str = get_prefix(f, prefix)
569 fname = "%s%s" % (prefix_str, f.c_field_name)
570 if fields.has_key(f.field_name):
571 raise Exception("field name %s has been registered before" % f.field_name)
572 fields[f.field_name] = (fname, f)
573 if f.type.is_container:
574 get_field_name(fields, f.type, prefix+[(f.c_field_name, '', f.type)])
577 # dict(field_name : (c_field_name, field))
579 get_field_name(fields, complex_type, prefix)
581 # switch: get the fields referenced by the switch expr as well
582 # these may not belong to any structure
583 if complex_type.is_switch:
585 # FIXME: fields += get_serialize_params(context, complex_type)
590 def _c_serialize_helper_insert_padding(context, code_lines, space):
591 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
592 code_lines.append('%s /* padding */' % space)
593 code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
594 code_lines.append('%s if (0 != xcb_pad) {' % space)
596 if 'serialize' == context:
597 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
598 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
599 code_lines.append('%s xcb_parts_idx++;' % space)
600 elif context in ('unserialize', 'unpack', 'sizeof'):
601 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
603 code_lines.append('%s xcb_buffer_len += xcb_pad;' % space)
604 code_lines.append('%s xcb_pad = 0;' % space)
605 code_lines.append('%s }' % space)
606 code_lines.append('%s xcb_block_len = 0;' % space)
609 # _c_serialize_helper_insert_padding()
611 def _c_serialize_helper_switch(context, self, complex_name,
612 code_lines, temp_vars,
615 switch_prefix = prefix + [(complex_name, '->', self)]
616 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(switch_prefix)
617 switch_expr = _c_accessor_get_expr(self.expr)
619 for b in self.bitcases:
620 bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix_str)
621 code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
622 code_lines.append(' printf("entering bitcase section for %%%%d...\\n", %s);' % bitcase_expr)
623 b_prefix = switch_prefix
625 b_prefix = switch_prefix + [(b.c_field_name, '.', b.type)]
626 count += _c_serialize_helper_fields(context, b.type,
627 code_lines, temp_vars,
631 code_lines.append(' }')
633 if 'serialize' == context:
634 count += _c_serialize_helper_insert_padding(context, code_lines, space)
635 if context in ('unserialize', 'unpack', 'sizeof'):
637 code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
638 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
641 # _c_serialize_helper_switch
643 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
644 # switch is handled by this function as a special case
645 param_fields, wire_fields, params = get_serialize_params(context, self)
646 args = get_expr_fields(field.type)
647 field_mapping = _c_field_mapping(context, self, prefix)
648 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
650 # determine which params to pass to _unserialize() and their prefixes
651 switch_len_fields = resolve_fields(self, field.type)
652 bitcase_unresolved = resolve_fields(self, self)
653 if len(bitcase_unresolved) != 0:
654 raise Exception('unresolved fields within bitcase is not supported at this point')
656 for a in switch_len_fields:
657 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
659 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
661 # call _serialize()/_unpack() to determine the actual size
662 if 'serialize' == context:
663 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
664 c_field_names, prefix_str, field.c_field_name)
665 elif context in ('unserialize', 'unpack'):
666 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
667 c_field_names, prefix_str, field.c_field_name)
669 # _c_serialize_helper_switch_field()
671 def _c_serialize_helper_list_field(context, self, field,
672 code_lines, temp_vars,
675 helper function for (un)serialize to cope with lists of variable length
677 expr = field.type.expr
678 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
679 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
680 param_names = [p[2] for p in params]
682 # look if the list's lenfield is a struct member or a function argument
683 # special case: if the list has a length field, its name will be returned
684 # unchanged by calling c_accessor_get_length(expr)
685 if expr.lenfield_name == _c_accessor_get_length(expr):
686 if expr.lenfield_name in param_names:
687 # the length field appears as separate argument in unserialize,
688 # so no need for a prefix
690 sep = '.' if (self.is_bitcase and self.has_name) else '->'
692 # special case: unserializing of structs where variable and
693 # fixed size fields are intermixed
694 if self.var_followed_by_fixed_fields and 'unserialize' == context:
695 if lenfield_prefix == '_aux':
696 lenfield_prefix = 'xcb_out'
699 list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep)
701 # default: list with fixed size elements
702 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
703 # list with variable-sized elements
704 if not field.type.member.fixed_size():
706 if context in ('unserialize', 'sizeof', 'unpack'):
707 int_i = ' unsigned int i;'
708 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
709 if int_i not in temp_vars:
710 temp_vars.append(int_i)
711 if xcb_tmp_len not in temp_vars:
712 temp_vars.append(xcb_tmp_len)
713 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
714 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
715 (space, field.type.c_sizeof_name))
716 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
717 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
718 code_lines.append("%s }" % space)
719 elif 'serialize' == context:
720 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
721 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
722 code_lines.append('%s for(i=0; i<%s; i++) { '
723 % (space, _c_accessor_get_expr(expr, lenfield_prefix, sep)))
724 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
725 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
726 code_lines.append('%s }' % space)
727 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
730 # _c_serialize_helper_list_field()
732 def _c_serialize_helper_fields_fixed_size(context, self, field,
733 code_lines, temp_vars,
735 if not self.is_bitcase:
736 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
738 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
739 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
740 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
741 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
743 length = "sizeof(%s)" % field.c_field_type
745 if context in ('unserialize', 'unpack', 'sizeof'):
746 value = ' %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
747 if field.type.is_pad and field.type.nmemb > 1:
749 for i in range(field.type.nmemb):
750 code_lines.append('%s %s%s[%d] = *(%s *)xcb_tmp;' %
751 (space, prefix_str, field.c_field_name, i, field.c_field_type))
752 length += " * %d" % field.type.nmemb
754 if field.type.is_list:
755 raise Exception('list with fixed number of elemens unhandled in _unserialize()')
756 elif 'serialize' == context:
757 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
759 if field.type.is_expr:
760 # need to register a temporary variable for the expression
761 if field.type.c_type is None:
762 raise Exception("type for field '%s' (expression '%s') unkown" %
763 (field.field_name, _c_accessor_get_expr(field.type.expr)))
764 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name,
765 _c_accessor_get_expr(field.type.expr, prefix)))
766 value += "&xcb_expr_%s;" % field.field_name
768 elif field.type.is_pad:
769 if field.type.nmemb == 1:
772 # FIXME - possible segmentation fault!!
773 value = ' memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb
774 length += "*%d" % field.type.nmemb
777 # non-list type with fixed size
778 if field.type.nmemb == 1:
779 value += "&%s%s;" % (prefix_str, field.c_field_name)
780 # list with nmemb (fixed size) elements
782 value += '%s%s;' % (prefix_str, field.c_field_name)
783 length = '%d' % field.type.nmemb
785 return (value, length)
786 # _c_serialize_helper_fields_fixed_size()
788 def _c_serialize_helper_fields_variable_size(context, self, field,
789 code_lines, temp_vars,
791 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
793 if context in ('unserialize', 'unpack', 'sizeof'):
795 var_field_name = 'xcb_tmp'
796 if self.var_followed_by_fixed_fields and 'unserialize' == context:
797 value = ' %s = xcb_tmp;' % field.c_field_name
798 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
799 if 'unpack' == context:
800 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
801 elif 'serialize' == context:
802 address_of = '&' if (self.is_bitcase and self.has_name) else ''
803 var_field_name = "%s%s%s" % (address_of, prefix_str, field.c_field_name)
804 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
807 prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
808 code_lines.append('%s /* %s */' % (space, field.c_field_name))
810 if field.type.is_list:
812 code_lines.append("%s%s" % (space, value))
814 length = _c_serialize_helper_list_field(context, self, field,
815 code_lines, temp_vars,
817 elif field.type.is_switch:
819 if context == 'serialize':
820 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
821 length = _c_serialize_helper_switch_field(context, self, field, 'xcb_parts[xcb_parts_idx].iov_base', prefix)
823 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
825 return (value, length)
826 # _c_serialize_helper_fields_variable_size
828 def _c_serialize_helper_fields(context, self,
829 code_lines, temp_vars,
830 space, prefix, is_bitcase):
833 prev_field_was_variable = False
835 for field in self.fields:
836 if not ((field.wire and not field.auto) or field.visible):
839 # switch/bitcase: fixed size fields must be considered explicitly
840 if field.type.fixed_size():
841 if self.is_bitcase or self.var_followed_by_fixed_fields:
842 if prev_field_was_variable and need_padding:
844 _c_serialize_helper_insert_padding(context, code_lines, space)
845 prev_field_was_variable = False
846 fixed_prefix = prefix
847 if self.var_followed_by_fixed_fields and len(prefix)==0:
848 if 'unserialize' == context:
849 fixed_prefix = [('xcb_out', '.', self)]
851 fixed_prefix = [('_aux', '->', self)]
852 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
853 code_lines, temp_vars,
858 # fields with variable size
860 # switch/bitcase: always calculate padding before and after variable sized fields
861 if need_padding or is_bitcase:
862 _c_serialize_helper_insert_padding(context, code_lines, space)
864 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
865 code_lines, temp_vars,
868 prev_field_was_variable = True
870 # save (un)serialization C code
872 code_lines.append('%s%s' % (space, value))
873 if field.type.fixed_size() and is_bitcase:
874 code_lines.append('%s xcb_block_len += %s;' % (space, length))
875 if context in ('unserialize', 'unpack', 'sizeof'):
876 code_lines.append('%s xcb_tmp += %s;' % (space, length))
880 code_lines.append('%s xcb_block_len = %s;' % (space, length))
881 if (not field.type.fixed_size() and
882 self.var_followed_by_fixed_fields and 'unserialize' == context):
883 temp_vars.append(' int %s_len;' % field.c_field_name)
884 code_lines.append(' %s_len = xcb_block_len;' % field.c_field_name)
885 if context in ('unserialize', 'sizeof', 'unpack'):
886 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
887 if 'serialize' == context:
889 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space)
890 code_lines.append('%s xcb_parts_idx++;' % space)
895 # _c_serialize_helper_fields()
897 def _c_serialize_helper(context, complex_type,
898 code_lines, temp_vars,
899 space='', prefix=[]):
901 if hasattr(complex_type, 'type'):
902 self = complex_type.type
903 complex_name = complex_type.name
906 if self.var_followed_by_fixed_fields and 'unserialize' == context:
907 complex_name = 'xcb_out'
909 complex_name = '_aux'
911 # special case: switch is serialized by evaluating each bitcase separately
913 count += _c_serialize_helper_switch(context, self, complex_name,
914 code_lines, temp_vars,
917 # all other data types can be evaluated one field a time
919 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
920 if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
921 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
922 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
923 _c_serialize_helper_insert_padding(context, code_lines, space)
925 count += _c_serialize_helper_fields(context, self,
926 code_lines, temp_vars,
927 space, prefix, False)
929 count += _c_serialize_helper_insert_padding(context, code_lines, space)
932 # _c_serialize_helper()
934 def _c_serialize(self):
939 # _serialize() returns the buffer size
942 variable_size_fields = 0
943 # maximum space required for type definition of function arguments
945 param_fields, wire_fields, params = get_serialize_params('serialize', self)
947 # determine N(variable_fields)
948 for field in param_fields:
949 # if self.is_switch, treat all fields as if they are variable sized
950 if not field.type.fixed_size() or self.is_switch:
951 variable_size_fields += 1
952 # determine maxtypelen
954 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
957 for idx, p in enumerate(params):
959 typespec, pointerspec, field_name = p
960 indent = ' '*(len(self.c_serialize_name)+2)
961 # p==0: function declaration
963 line = "%s (" % self.c_serialize_name
965 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
966 line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)
967 if idx < len(params)-1:
974 if not self.is_switch:
975 _c(' %s *xcb_out = *_buffer;', self.c_type)
976 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
977 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
979 _c(' char *xcb_out = *_buffer;')
980 _c(' unsigned int xcb_buffer_len = 0;')
981 if variable_size_fields > 0:
984 count = _c_serialize_helper('serialize', self,
985 code_lines, temp_vars)
986 # update variable size fields
987 variable_size_fields = count
988 temp_vars.append(' unsigned int xcb_pad = 0;')
989 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
990 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
991 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
992 temp_vars.append(' unsigned int xcb_block_len = 0;')
993 temp_vars.append(' unsigned int i;')
994 temp_vars.append(' char *xcb_tmp;')
1000 if variable_size_fields > 0:
1001 for l in code_lines:
1005 # variable sized fields have been collected, now
1006 # allocate memory and copy everything into a continuous memory area
1007 _c(' if (NULL == xcb_out) {')
1008 _c(' /* allocate memory */')
1009 _c(' *_buffer = malloc(xcb_buffer_len);')
1010 _c(' xcb_out = *_buffer;')
1014 # fill in struct members
1015 if not self.is_switch:
1016 if len(wire_fields)>0:
1017 _c(' *xcb_out = *_aux;')
1019 # copy variable size fields into the buffer
1020 if variable_size_fields > 0:
1022 if not self.is_switch:
1023 _c(' xcb_tmp = (char*)++xcb_out;')
1024 _c(' xcb_tmp += xcb_out_pad;')
1026 _c(' xcb_tmp = xcb_out;')
1028 # variable sized fields
1029 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1030 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1031 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1034 _c(' return xcb_buffer_len;')
1038 def _c_unserialize(self):
1044 # _unserialize() returns the buffer size as well
1048 variable_size_fields = 0
1049 # maximum space required for type definition of function arguments
1053 func_name = self.c_unpack_name
1055 context = 'unserialize'
1056 func_name = self.c_unserialize_name
1057 param_fields, wire_fields, params = get_serialize_params(context, self)
1059 # determine N(variable_fields)
1060 for field in param_fields:
1061 # if self.is_switch, treat all fields as if they are variable sized
1062 if not field.type.fixed_size() or self.is_switch:
1063 variable_size_fields += 1
1064 # determine maxtypelen
1066 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1069 for idx, p in enumerate(params):
1071 typespec, pointerspec, field_name = p
1072 indent = ' '*(len(func_name)+2)
1073 # p==0: function declaration
1075 line = "%s (" % func_name
1077 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1078 line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)
1079 if idx < len(params)-1:
1086 _c(' char *xcb_tmp = (char *)_buffer;')
1087 if not self.is_switch:
1088 if not self.var_followed_by_fixed_fields:
1089 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1091 _c(' %s xcb_out;', self.c_type)
1092 _c(' unsigned int xcb_buffer_len = 0;')
1093 _c(' unsigned int xcb_block_len = 0;')
1094 _c(' unsigned int xcb_pad = 0;')
1098 _c_serialize_helper(context, self,
1099 code_lines, temp_vars)
1104 for l in code_lines:
1108 if 'unserialize' == context:
1109 # allocate memory automatically
1110 _c(' if (NULL == *_aux) {')
1111 _c(' /* allocate memory */')
1112 _c(' *_aux = malloc(xcb_buffer_len);')
1115 _c(' **_aux = xcb_out;')
1116 _c(' xcb_tmp = (char *)++(*_aux);')
1117 for field in param_fields:
1118 if not field.type.fixed_size():
1119 _c(' memcpy(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1120 _c(' xcb_tmp += %s_len;', field.c_field_name)
1123 _c(' return xcb_buffer_len;')
1127 def _c_sizeof_helper(self):
1133 # _unserialize() returns the buffer size as well
1136 variable_size_fields = 0
1137 # maximum space required for type definition of function arguments
1139 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
1141 # determine N(variable_fields)
1142 for field in param_fields:
1143 # if self.is_switch, treat all fields as if they are variable sized
1144 if not field.type.fixed_size() or self.is_switch:
1145 variable_size_fields += 1
1146 # determine maxtypelen
1148 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1151 for idx, p in enumerate(params):
1153 typespec, pointerspec, field_name = p
1154 indent = ' '*(len(self.c_sizeof_name)+2)
1155 # p==0: function declaration
1157 line = "%s (" % self.c_sizeof_name
1159 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1160 line += "%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)
1161 if idx < len(params)-1:
1169 param_names = [p[2] for p in params]
1171 # switch: call _unpack()
1172 _c(' %s _aux;', self.c_type)
1173 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1174 elif self.var_followed_by_fixed_fields:
1175 # special case: call _unserialize()
1176 _c(' %s *_aux = NULL;', self.c_type)
1177 _c(' return %s(%s, &_aux);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1178 # otherwise: evaluate parameters directly
1182 _c_serialize_helper('sizeof', self,
1183 code_lines, temp_vars)
1184 _c(' char *xcb_tmp = (char *)_buffer;')
1185 if len(filter(lambda x: x.find('_aux')!=-1, code_lines))>0:
1186 if not self.var_followed_by_fixed_fields:
1187 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1189 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1190 _c(' unsigned int xcb_buffer_len = 0;')
1191 _c(' unsigned int xcb_block_len = 0;')
1192 _c(' unsigned int xcb_pad = 0;')
1197 for l in code_lines:
1200 _c(' return xcb_buffer_len;')
1202 # _c_sizeof_helper()
1204 def _c_iterator_get_end(field, accum):
1206 Figures out what C code is needed to find the end of a variable-length structure field.
1207 For nested structures, recurses into its last variable-sized field.
1208 For lists, calls the end function
1210 if field.type.is_container:
1211 accum = field.c_accessor_name + '(' + accum + ')'
1212 # XXX there could be fixed-length fields at the end
1213 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1214 if field.type.is_list:
1215 # XXX we can always use the first way
1216 if field.type.member.is_simple:
1217 return field.c_end_name + '(' + accum + ')'
1219 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1221 def _c_iterator(self, name):
1223 Declares the iterator structure and next/end functions for a given type.
1228 _h(' * @brief %s', self.c_iterator_type)
1230 _h('typedef struct %s {', self.c_iterator_type)
1231 _h(' %s *data; /**< */', self.c_type)
1232 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1233 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1234 _h('} %s;', self.c_iterator_type)
1240 _h(' * Get the next element of the iterator')
1241 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1243 _h(' * Get the next element in the iterator. The member rem is')
1244 _h(' * decreased by one. The member data points to the next')
1245 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1249 _hc('/*****************************************************************************')
1251 _hc(' ** void %s', self.c_next_name)
1253 _hc(' ** @param %s *i', self.c_iterator_type)
1254 _hc(' ** @returns void')
1256 _hc(' *****************************************************************************/')
1259 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1260 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1263 if not self.fixed_size():
1264 _c(' %s *R = i->data;', self.c_type)
1266 # FIXME - how to determine the size of a variable size union??
1267 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1269 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1271 _c(' i->data = (%s *) child.data;', self.c_type)
1272 _c(' i->index = child.index;')
1276 _c(' i->index += sizeof(%s);', self.c_type)
1282 _h(' * Return the iterator pointing to the last element')
1283 _h(' * @param i An %s', self.c_iterator_type)
1284 _h(' * @return The iterator pointing to the last element')
1286 _h(' * Set the current element in the iterator to the last element.')
1287 _h(' * The member rem is set to 0. The member data points to the')
1288 _h(' * last element.')
1292 _hc('/*****************************************************************************')
1294 _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1296 _hc(' ** @param %s i', self.c_iterator_type)
1297 _hc(' ** @returns xcb_generic_iterator_t')
1299 _hc(' *****************************************************************************/')
1301 _hc('xcb_generic_iterator_t')
1302 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1303 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1305 _c(' xcb_generic_iterator_t ret;')
1307 if self.fixed_size():
1308 _c(' ret.data = i.data + i.rem;')
1309 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1312 _c(' while(i.rem > 0)')
1313 _c(' %s(&i);', self.c_next_name)
1314 _c(' ret.data = i.data;')
1315 _c(' ret.rem = i.rem;')
1316 _c(' ret.index = i.index;')
1321 def _c_accessor_get_length(expr, prefix='', sep='->'):
1323 Figures out what C code is needed to get a length field.
1324 For fields that follow a variable-length field, use the accessor.
1325 Otherwise, just reference the structure field directly.
1327 prefarrow = '' if prefix == '' else prefix + sep
1329 if expr.lenfield != None and expr.lenfield.prev_varsized_field != None:
1330 # special case: variable and fixed size fields are intermixed
1331 # if the lenfield is among the fixed size fields, there is no need
1332 # to call a special accessor function!
1333 retval = expr.lenfield.c_accessor_name + '(' + prefix + ')'
1334 if prefix in ('', '_aux', 'xcb_out'):
1335 prefix_str = '' if prefix=='' else '%s' % (prefarrow)
1336 retval = '%s%s' % (prefix_str, expr.lenfield_name)
1338 elif expr.lenfield_name != None:
1339 if prefix.endswith(sep):
1340 return prefix + expr.lenfield_name
1342 return prefarrow + expr.lenfield_name
1344 return str(expr.nmemb)
1346 def _c_accessor_get_expr(expr, prefix='', sep='->'):
1348 Figures out what C code is needed to get the length of a list field.
1349 Recurses for math operations.
1350 Returns bitcount for value-mask fields.
1351 Otherwise, uses the value of the length field.
1353 lenexp = _c_accessor_get_length(expr, prefix, sep)
1356 return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1357 elif expr.op == 'popcount':
1358 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1359 elif expr.op == 'enumref':
1360 enum_name = expr.lenfield_type.name
1361 constant_name = expr.lenfield_name
1362 c_name = _n(enum_name + (constant_name,)).upper()
1364 elif expr.op == 'sumof':
1365 # 1. locate the referenced list object
1366 list_obj = expr.lenfield_type
1368 for f in expr.lenfield_parent.fields:
1369 if f.field_name == expr.lenfield_name:
1373 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1374 if prefix != '' and not prefix.endswith(sep):
1376 list_name = "%s%s" % (prefix, field.c_field_name)
1377 c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name)
1378 # FIXME - works only for integers this way!!
1379 c_length_func = _c_accessor_get_expr(field.type.expr, prefix='', sep='')
1380 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1381 elif expr.op != None:
1382 return '(' + _c_accessor_get_expr(expr.lhs, prefix, sep) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1384 return 'xcb_popcount(' + lenexp + ')'
1388 def _c_accessors_field(self, field):
1390 Declares the accessor functions for a non-list field that follows a variable-length field.
1392 if field.type.is_simple:
1395 _hc('/*****************************************************************************')
1397 _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1399 _hc(' ** @param const %s *R', self.c_type)
1400 _hc(' ** @returns %s', field.c_field_type)
1402 _hc(' *****************************************************************************/')
1404 _hc('%s', field.c_field_type)
1405 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type)
1406 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type)
1408 if field.prev_varsized_field is None:
1409 _c(' return (%s *) (R + 1);', field.c_field_type)
1411 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1412 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1413 field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1418 _hc('/*****************************************************************************')
1420 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1422 _hc(' ** @param const %s *R', self.c_type)
1423 _hc(' ** @returns %s *', field.c_field_type)
1425 _hc(' *****************************************************************************/')
1427 if field.type.is_switch:
1428 return_type = 'void *'
1430 return_type = '%s *' % field.c_field_type
1433 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type)
1434 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type)
1436 if field.prev_varsized_field is None:
1437 _c(' return (%s) (R + 1);', return_type)
1438 # note: the special case 'variable fields followed by fixed size fields'
1439 # is not of any consequence here, since the ordering gets
1440 # 'corrected' in the reply function
1442 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1443 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1444 return_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1447 def _c_accessors_list(self, field):
1449 Declares the accessor functions for a list field.
1450 Declares a direct-accessor function only if the list members are fixed size.
1451 Declares length and get-iterator functions always.
1457 if list.member.fixed_size():
1460 _hc('/*****************************************************************************')
1462 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1464 _hc(' ** @param const %s *R', self.c_type)
1465 _hc(' ** @returns %s *', field.c_field_type)
1467 _hc(' *****************************************************************************/')
1469 _hc('%s *', field.c_field_type)
1470 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type)
1471 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type)
1474 if field.prev_varsized_field is None:
1475 _c(' return (%s *) (R + 1);', field.c_field_type)
1477 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1478 _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)
1484 _hc('/*****************************************************************************')
1486 _hc(' ** int %s', field.c_length_name)
1488 _hc(' ** @param const %s *R', self.c_type)
1489 _hc(' ** @returns int')
1491 _hc(' *****************************************************************************/')
1494 _h('%s (const %s *R /**< */);', field.c_length_name, self.c_type)
1495 _c('%s (const %s *R /**< */)', field.c_length_name, self.c_type)
1497 _c(' return %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1500 if field.type.member.is_simple:
1503 _hc('/*****************************************************************************')
1505 _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1507 _hc(' ** @param const %s *R', self.c_type)
1508 _hc(' ** @returns xcb_generic_iterator_t')
1510 _hc(' *****************************************************************************/')
1512 _hc('xcb_generic_iterator_t')
1513 _h('%s (const %s *R /**< */);', field.c_end_name, self.c_type)
1514 _c('%s (const %s *R /**< */)', field.c_end_name, self.c_type)
1516 _c(' xcb_generic_iterator_t i;')
1518 if field.prev_varsized_field == None:
1519 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1521 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1522 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1525 _c(' i.index = (char *) i.data - (char *) R;')
1532 _hc('/*****************************************************************************')
1534 _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1536 _hc(' ** @param const %s *R', self.c_type)
1537 _hc(' ** @returns %s', field.c_iterator_type)
1539 _hc(' *****************************************************************************/')
1541 _hc('%s', field.c_iterator_type)
1542 _h('%s (const %s *R /**< */);', field.c_iterator_name, self.c_type)
1543 _c('%s (const %s *R /**< */)', field.c_iterator_name, self.c_type)
1545 _c(' %s i;', field.c_iterator_type)
1547 if field.prev_varsized_field == None:
1548 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1550 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1551 _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', field.c_field_type, field.c_field_type)
1553 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1554 _c(' i.index = (char *) i.data - (char *) R;')
1558 def _c_accessors(self, name, base):
1560 Declares the accessor functions for the fields of a structure.
1562 # no accessors for switch -
1563 # switch always needs to be unpacked explicitly
1564 if not self.is_switch:
1565 for field in self.fields:
1566 if field.type.is_list and not field.type.fixed_size():
1567 _c_accessors_list(self, field)
1568 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1569 _c_accessors_field(self, field)
1571 def c_simple(self, name):
1573 Exported function that handles cardinal type declarations.
1574 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1576 _c_type_setup(self, name, ())
1578 if (self.name != name):
1583 _h('typedef %s %s;', _t(self.name), my_name)
1586 _c_iterator(self, name)
1588 def _c_complex(self):
1590 Helper function for handling all structure types.
1591 Called for all structs, requests, replies, events, errors.
1596 _h(' * @brief %s', self.c_type)
1598 _h('typedef %s %s {', self.c_container, self.c_type)
1604 for field in self.fields:
1605 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1606 varfield = field.c_field_name
1608 # if varfield != None and not field.type.is_pad and field.wire:
1609 # errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name)
1610 # sys.stderr.write(errmsg)
1613 struct_fields.append(field)
1615 for field in struct_fields:
1616 length = len(field.c_field_type)
1617 # account for '*' pointer_spec
1618 if not field.type.fixed_size():
1620 maxtypelen = max(maxtypelen, length)
1622 def _c_complex_field(self, field, space=''):
1623 if (field.type.fixed_size() or
1624 # in case of switch with switch children, don't make the field a pointer
1625 # necessary for unserialize to work
1626 (self.is_switch and field.type.is_switch)):
1627 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1628 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1630 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1631 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1633 if not self.is_switch:
1634 for field in struct_fields:
1635 _c_complex_field(self, field)
1637 for b in self.bitcases:
1640 _h(' struct _%s {', b.c_field_name)
1642 for field in b.type.fields:
1643 _c_complex_field(self, field, space)
1645 _h(' } %s;', b.c_field_name)
1647 _h('} %s;', self.c_type)
1649 def c_struct(self, name):
1651 Exported function that handles structure declarations.
1653 _c_type_setup(self, name, ())
1655 _c_accessors(self, name, name)
1656 _c_iterator(self, name)
1658 def c_union(self, name):
1660 Exported function that handles union declarations.
1662 _c_type_setup(self, name, ())
1664 _c_iterator(self, name)
1666 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1668 Declares a request function.
1671 # Four stunningly confusing possibilities here:
1674 # ------------------------------
1676 # 0 flag CHECKED flag Normal Mode
1677 # void_cookie req_cookie
1678 # ------------------------------
1679 # "req_checked" "req_unchecked"
1680 # CHECKED flag 0 flag Abnormal Mode
1681 # void_cookie req_cookie
1682 # ------------------------------
1685 # Whether we are _checked or _unchecked
1686 checked = void and not regular
1687 unchecked = not void and not regular
1689 # What kind of cookie we return
1690 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1692 # What flag is passed to xcb_request
1693 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1695 # Global extension id variable or NULL for xproto
1696 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1698 # What our function name is
1699 func_name = self.c_request_name if not aux else self.c_aux_name
1701 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1703 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1707 maxtypelen = len('xcb_connection_t')
1709 # special case: list with variable size elements
1710 list_with_var_size_elems = False
1712 for field in self.fields:
1714 # The field should appear as a call parameter
1715 param_fields.append(field)
1716 if field.wire and not field.auto:
1717 # We need to set the field up in the structure
1718 wire_fields.append(field)
1719 if field.type.need_serialize or field.type.need_sizeof:
1720 serial_fields.append(field)
1722 for field in param_fields:
1723 c_field_const_type = field.c_field_const_type
1724 if field.type.need_serialize and not aux:
1725 c_field_const_type = "const void"
1726 if len(c_field_const_type) > maxtypelen:
1727 maxtypelen = len(c_field_const_type)
1728 if field.type.is_list and not field.type.member.fixed_size():
1729 list_with_var_size_elems = True
1735 _h(' * Delivers a request to the X server')
1736 _h(' * @param c The connection')
1737 _h(' * @return A cookie')
1739 _h(' * Delivers a request to the X server.')
1742 _h(' * This form can be used only if the request will not cause')
1743 _h(' * a reply to be generated. Any returned error will be')
1744 _h(' * saved for handling by xcb_request_check().')
1746 _h(' * This form can be used only if the request will cause')
1747 _h(' * a reply to be generated. Any returned error will be')
1748 _h(' * placed in the event queue.')
1752 _hc('/*****************************************************************************')
1754 _hc(' ** %s %s', cookie_type, func_name)
1757 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1758 _hc(' ** @param xcb_connection_t%s *c', spacing)
1760 for field in param_fields:
1761 c_field_const_type = field.c_field_const_type
1762 if field.type.need_serialize and not aux:
1763 c_field_const_type = "const void"
1764 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1765 _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1767 _hc(' ** @returns %s', cookie_type)
1769 _hc(' *****************************************************************************/')
1771 _hc('%s', cookie_type)
1773 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1774 comma = ',' if len(param_fields) else ');'
1775 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1776 comma = ',' if len(param_fields) else ')'
1777 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1779 func_spacing = ' ' * (len(func_name) + 2)
1780 count = len(param_fields)
1781 for field in param_fields:
1783 c_field_const_type = field.c_field_const_type
1784 c_pointer = field.c_pointer
1785 if field.type.need_serialize and not aux:
1786 c_field_const_type = "const void"
1788 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1789 comma = ',' if count else ');'
1790 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1791 spacing, c_pointer, field.c_field_name, comma)
1792 comma = ',' if count else ')'
1793 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1794 spacing, c_pointer, field.c_field_name, comma)
1797 if not self.var_followed_by_fixed_fields:
1798 for field in param_fields:
1799 if not field.type.fixed_size():
1801 if field.type.need_serialize:
1802 # _serialize() keeps track of padding automatically
1804 dimension = count + 2
1805 if self.var_followed_by_fixed_fields:
1806 # there will be only one call to _serialize() and no need for additional padding
1810 _c(' static const xcb_protocol_request_t xcb_req = {')
1811 _c(' /* count */ %d,', count)
1812 _c(' /* ext */ %s,', func_ext_global)
1813 _c(' /* opcode */ %s,', self.c_request_name.upper())
1814 _c(' /* isvoid */ %d', 1 if void else 0)
1818 _c(' struct iovec xcb_parts[%d];', dimension)
1819 _c(' %s xcb_ret;', func_cookie)
1820 _c(' %s xcb_out;', self.c_type)
1821 if self.var_followed_by_fixed_fields:
1822 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
1825 for idx, f in enumerate(serial_fields):
1827 _c(' void *xcb_aux%d = 0;' % (idx))
1828 if list_with_var_size_elems:
1829 _c(' unsigned int i;')
1830 _c(' unsigned int xcb_tmp_len;')
1831 _c(' char *xcb_tmp;')
1833 # _c(' printf("in function %s\\n");' % func_name)
1836 for field in wire_fields:
1837 if field.type.fixed_size():
1838 if field.type.is_expr:
1839 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr))
1840 elif field.type.is_pad:
1841 if field.type.nmemb == 1:
1842 _c(' xcb_out.%s = 0;', field.c_field_name)
1844 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
1846 if field.type.nmemb == 1:
1847 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
1849 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
1851 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
1852 serialize_args = get_serialize_params(context, type_obj,
1855 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
1857 # calls in order to free dyn. all. memory
1860 if not self.var_followed_by_fixed_fields:
1862 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
1863 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
1864 _c(' xcb_parts[3].iov_base = 0;')
1865 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
1869 for field in param_fields:
1870 if not field.type.fixed_size():
1871 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
1872 # default: simple cast to char *
1873 if not field.type.need_serialize and not field.type.need_sizeof:
1874 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1875 if field.type.is_list:
1876 if field.type.member.fixed_size():
1877 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
1878 _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype)
1880 expr = field.type.expr
1881 prefix_str, lenfield_prefix = _c_serialize_helper_prefix([('xcb_out', '.', self)],
1883 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
1884 param_names = [p[2] for p in params]
1887 # look if the list's lenfield is a struct member or a function argument
1888 # special case: if the list has a length field, its name will be returned
1889 # unchanged by calling c_accessor_get_length(expr)
1890 if expr.lenfield_name == _c_accessor_get_length(expr):
1891 if expr.lenfield_name in param_names:
1892 # the length field appears as separate argument,
1893 # so no need for a prefix
1894 lenfield_prefix = ''
1896 list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep)
1899 _c(" xcb_parts[%d].iov_len = 0;" % count)
1900 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
1901 _c(" for(i=0; i<%s; i++) {" % list_length)
1902 _c(" xcb_tmp_len = %s(xcb_tmp);" %
1903 (field.type.c_sizeof_name))
1904 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
1905 _c(" xcb_tmp += xcb_tmp_len;")
1908 # not supposed to happen
1909 raise Exception("unhandled variable size field %s" % field.c_field_name)
1912 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1913 idx = serial_fields.index(field)
1914 aux_var = '&xcb_aux%d' % idx
1915 context = 'serialize' if aux else 'sizeof'
1916 _c(' xcb_parts[%d].iov_len = ', count)
1918 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
1919 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
1920 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
1921 free_calls.append(' free(xcb_aux%d);' % idx)
1923 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
1924 func_name = field.type.c_sizeof_name
1925 _c(' %s (%s);', func_name, serialize_args)
1928 if not (field.type.need_serialize or field.type.need_sizeof):
1929 # the _serialize() function keeps track of padding automatically
1930 _c(' xcb_parts[%d].iov_base = 0;', count)
1931 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
1934 # elif self.var_followed_by_fixed_fields:
1937 buffer_var = 'xcb_parts[%d].iov_base' % count
1938 serialize_args = get_serialize_args(self, '&%s' % buffer_var, '&xcb_out', 'serialize')
1939 _c(' %s = (char *) 0;', buffer_var)
1940 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
1941 free_calls.append(' free(xcb_parts[%d].iov_base);' % count)
1942 # no padding necessary - _serialize() keeps track of padding automatically
1945 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
1947 # free dyn. all. data, if any
1948 for f in free_calls:
1950 _c(' return xcb_ret;')
1953 def _c_reply(self, name):
1955 Declares the function that returns the reply structure.
1957 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
1958 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
1959 spacing3 = ' ' * (len(self.c_reply_name) + 2)
1961 # check if _unserialize() has to be called for any field
1962 def look_for_special_cases(complex_obj):
1963 unserialize_fields = []
1964 # no unserialize call in case of switch
1965 if not complex_obj.is_switch:
1966 for field in complex_obj.fields:
1967 # three cases: 1. field with special case
1968 # 2. container that contains special case field
1969 # 3. list with special case elements
1970 if field.type.var_followed_by_fixed_fields:
1971 unserialize_fields.append(field)
1972 elif field.type.is_container:
1973 unserialize_fields += look_for_special_cases(field.type)
1974 elif field.type.is_list:
1975 if field.type.member.var_followed_by_fixed_fields:
1976 unserialize_fields.append(field)
1977 if field.type.member.is_container:
1978 unserialize_fields += look_for_special_cases(field.type.member)
1979 return unserialize_fields
1981 unserialize_fields = look_for_special_cases(self.reply)
1985 _h(' * Return the reply')
1986 _h(' * @param c The connection')
1987 _h(' * @param cookie The cookie')
1988 _h(' * @param e The xcb_generic_error_t supplied')
1990 _h(' * Returns the reply of the request asked by')
1992 _h(' * The parameter @p e supplied to this function must be NULL if')
1993 _h(' * %s(). is used.', self.c_unchecked_name)
1994 _h(' * Otherwise, it stores the error if any.')
1996 _h(' * The returned value must be freed by the caller using free().')
2000 _hc('/*****************************************************************************')
2002 _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2004 _hc(' ** @param xcb_connection_t%s *c', spacing1)
2005 _hc(' ** @param %s cookie', self.c_cookie_type)
2006 _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2007 _hc(' ** @returns %s *', self.c_reply_type)
2009 _hc(' *****************************************************************************/')
2011 _hc('%s *', self.c_reply_type)
2012 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2013 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2014 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2015 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2018 if len(unserialize_fields)>0:
2019 # certain variable size fields need to be unserialized explicitly
2020 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2021 self.c_reply_type, self.c_reply_type)
2023 for field in unserialize_fields:
2024 if field.type.is_list:
2025 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2026 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2027 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2029 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2030 # call _unserialize(), using the reply as source and target buffer
2031 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2032 for field in unserialize_fields:
2033 if field.type.is_list:
2034 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2035 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2036 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2037 field.c_field_name, field.c_field_name)
2038 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2040 # return the transformed reply
2041 _c(' return reply;')
2044 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2048 def _c_opcode(name, opcode):
2050 Declares the opcode define for requests, events, and errors.
2054 _h('/** Opcode for %s. */', _n(name))
2055 _h('#define %s %s', _n(name).upper(), opcode)
2057 def _c_cookie(self, name):
2059 Declares the cookie type for a non-void request.
2064 _h(' * @brief %s', self.c_cookie_type)
2066 _h('typedef struct %s {', self.c_cookie_type)
2067 _h(' unsigned int sequence; /**< */')
2068 _h('} %s;', self.c_cookie_type)
2070 def c_request(self, name):
2072 Exported function that handles request declarations.
2074 _c_type_setup(self, name, ('request',))
2077 # Cookie type declaration
2078 _c_cookie(self, name)
2081 _c_opcode(name, self.opcode)
2083 # Request structure declaration
2087 _c_type_setup(self.reply, name, ('reply',))
2088 # Reply structure definition
2089 _c_complex(self.reply)
2090 # Request prototypes
2091 _c_request_helper(self, name, self.c_cookie_type, False, True)
2092 _c_request_helper(self, name, self.c_cookie_type, False, False)
2094 _c_request_helper(self, name, self.c_cookie_type, False, True, True)
2095 _c_request_helper(self, name, self.c_cookie_type, False, False, True)
2097 _c_accessors(self.reply, name + ('reply',), name)
2098 _c_reply(self, name)
2100 # Request prototypes
2101 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2102 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2104 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2105 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2108 def c_event(self, name):
2110 Exported function that handles event declarations.
2112 _c_type_setup(self, name, ('event',))
2115 _c_opcode(name, self.opcodes[name])
2117 if self.name == name:
2118 # Structure definition
2123 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2125 def c_error(self, name):
2127 Exported function that handles error declarations.
2129 _c_type_setup(self, name, ('error',))
2132 _c_opcode(name, self.opcodes[name])
2134 if self.name == name:
2135 # Structure definition
2140 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2143 # Main routine starts here
2145 # Must create an "output" dictionary before any xcbgen imports.
2146 output = {'open' : c_open,
2148 'simple' : c_simple,
2150 'struct' : c_struct,
2152 'request' : c_request,
2157 # Boilerplate below this point
2159 # Check for the argument that specifies path to the xcbgen python package.
2161 opts, args = getopt.getopt(sys.argv[1:], 'p:')
2162 except getopt.GetoptError, err:
2164 print 'Usage: c_client.py [-p path] file.xml'
2167 for (opt, arg) in opts:
2169 sys.path.append(arg)
2171 # Import the module class
2173 from xcbgen.state import Module
2176 print 'Failed to load the xcbgen Python package!'
2177 print 'Make sure that xcb/proto installed it on your Python path.'
2178 print 'If not, you will need to create a .pth file or define $PYTHONPATH'
2179 print 'to extend the path.'
2180 print 'Refer to the README file in xcb/proto for more info.'
2184 # Parse the xml header
2185 module = Module(args[0], output)
2187 # Build type-registry and resolve type dependencies