2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
9 # Jump to the bottom of this file for the main routine
11 # Some hacks to make the API more readable, and to keep backwards compability
12 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
13 _cname_special_cases = {'DECnet':'decnet'}
15 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
17 _cplusplus_annoyances = {'class' : '_class',
20 _c_keywords = {'default' : '_default'}
28 # global variable to keep track of serializers and
29 # switch data types due to weird dependencies
30 finished_serializers = []
36 Writes the given line to the header file.
38 _hlines[_hlevel].append(fmt % args)
42 Writes the given line to the source file.
44 _clines[_clevel].append(fmt % args)
48 Writes the given line to both the header and source files.
53 # XXX See if this level thing is really necessary.
56 Changes the array that header lines are written to.
57 Supports writing different sections of the header file.
60 while len(_hlines) <= idx:
66 Changes the array that source lines are written to.
67 Supports writing to different sections of the source file.
70 while len(_clines) <= idx:
76 Does C-name conversion on a single string fragment.
77 Uses a regexp with some hard-coded special cases.
79 if str in _cname_special_cases:
80 return _cname_special_cases[str]
82 split = _cname_re.finditer(str)
83 name_parts = [match.group(0) for match in split]
84 return '_'.join(name_parts)
88 Checks for certain C++ reserved words and fixes them.
90 if str in _cplusplus_annoyances:
91 return _cplusplus_annoyances[str]
92 elif str in _c_keywords:
93 return _c_keywords[str]
99 Does C-name conversion on an extension name.
100 Has some additional special cases on top of _n_item.
102 if str in _extension_special_cases:
103 return _n_item(str).lower()
109 Does C-name conversion on a tuple of strings.
110 Different behavior depending on length of tuple, extension/not extension, etc.
111 Basically C-name converts the individual pieces, then joins with underscores.
116 parts = [list[0], _n_item(list[1])]
118 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
120 parts = [list[0]] + [_n_item(i) for i in list[1:]]
121 return '_'.join(parts).lower()
125 Does C-name conversion on a tuple of strings representing a type.
126 Same as _n but adds a "_t" on the end.
131 parts = [list[0], _n_item(list[1]), 't']
133 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
135 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
136 return '_'.join(parts).lower()
141 Exported function that handles module open.
142 Opens the files and writes out the auto-generated comment, header file includes, etc.
146 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
148 # Build the type-name collision avoidance table used by c_enum
149 build_collision_table()
155 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
156 _hc(' * Edit at your peril.')
161 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
162 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
166 _h('#ifndef __%s_H', _ns.header.upper())
167 _h('#define __%s_H', _ns.header.upper())
169 _h('#include "xcb.h"')
171 _c('#include <stdlib.h>')
172 _c('#include <string.h>')
173 _c('#include <assert.h>')
174 _c('#include <stddef.h> /* for offsetof() */')
175 _c('#include "xcbext.h"')
176 _c('#include "%s.h"', _ns.header)
179 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
182 for (n, h) in self.imports:
183 _hc('#include "%s.h"', h)
186 _h('#ifdef __cplusplus')
192 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
193 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
195 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
198 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
202 Exported function that handles module close.
203 Writes out all the stored content lines, then closes the files.
210 _h('#ifdef __cplusplus')
222 hfile = open('%s.h' % _ns.header, 'w')
230 cfile = open('%s.c' % _ns.header, 'w')
237 def build_collision_table():
241 for v in module.types.values():
243 namecount[name] = (namecount.get(name) or 0) + 1
245 def c_enum(self, name):
247 Exported function that handles enum declarations.
251 if namecount[tname] > 1:
252 tname = _t(name + ('enum',))
256 _h('typedef enum %s {', tname)
258 count = len(self.values)
260 for (enam, eval) in self.values:
262 equals = ' = ' if eval != '' else ''
263 comma = ',' if count > 0 else ''
264 _h(' %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
268 def _c_type_setup(self, name, postfix):
270 Sets up all the C-related state by adding additional data fields to
271 all Field and Type objects. Here is where we figure out most of our
272 variable and function names.
274 Recurses into child fields and list member types.
276 # Do all the various names in advance
277 self.c_type = _t(name + postfix)
278 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
280 self.c_iterator_type = _t(name + ('iterator',))
281 self.c_next_name = _n(name + ('next',))
282 self.c_end_name = _n(name + ('end',))
284 self.c_request_name = _n(name)
285 self.c_checked_name = _n(name + ('checked',))
286 self.c_unchecked_name = _n(name + ('unchecked',))
287 self.c_reply_name = _n(name + ('reply',))
288 self.c_reply_type = _t(name + ('reply',))
289 self.c_cookie_type = _t(name + ('cookie',))
291 self.need_aux = False
292 self.need_serialize = False
293 self.need_sizeof = False
295 self.c_aux_name = _n(name + ('aux',))
296 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
297 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
298 self.c_serialize_name = _n(name + ('serialize',))
299 self.c_unserialize_name = _n(name + ('unserialize',))
300 self.c_unpack_name = _n(name + ('unpack',))
301 self.c_sizeof_name = _n(name + ('sizeof',))
303 # special case: structs where variable size fields are followed by fixed size fields
304 self.var_followed_by_fixed_fields = False
307 self.need_serialize = True
308 self.c_container = 'struct'
309 for bitcase in self.bitcases:
310 bitcase.c_field_name = _cpp(bitcase.field_name)
311 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
312 _c_type_setup(bitcase.type, bitcase_name, ())
314 elif self.is_container:
316 self.c_container = 'union' if self.is_union else 'struct'
317 prev_varsized_field = None
318 prev_varsized_offset = 0
319 first_field_after_varsized = None
321 for field in self.fields:
322 _c_type_setup(field.type, field.field_type, ())
323 if field.type.is_list:
324 _c_type_setup(field.type.member, field.field_type, ())
325 if (field.type.nmemb is None):
326 self.need_sizeof = True
328 field.c_field_type = _t(field.field_type)
329 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
330 field.c_field_name = _cpp(field.field_name)
331 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
332 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
334 # correct the c_pointer field for variable size non-list types
335 if not field.type.fixed_size() and field.c_pointer == ' ':
336 field.c_pointer = '*'
337 if field.type.is_list and not field.type.member.fixed_size():
338 field.c_pointer = '*'
340 if field.type.is_switch:
341 field.c_pointer = '*'
342 field.c_field_const_type = 'const ' + field.c_field_type
344 elif not field.type.fixed_size() and not field.type.is_bitcase:
345 self.need_sizeof = True
347 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
348 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
349 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
350 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
351 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
353 field.prev_varsized_field = prev_varsized_field
354 field.prev_varsized_offset = prev_varsized_offset
356 if prev_varsized_offset == 0:
357 first_field_after_varsized = field
358 field.first_field_after_varsized = first_field_after_varsized
360 if field.type.fixed_size():
361 prev_varsized_offset += field.type.size
362 # special case: intermixed fixed and variable size fields
363 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
364 if not self.is_union:
365 self.need_serialize = True
366 self.var_followed_by_fixed_fields = True
368 self.last_varsized_field = field
369 prev_varsized_field = field
370 prev_varsized_offset = 0
372 if self.var_followed_by_fixed_fields:
373 if field.type.fixed_size():
374 field.prev_varsized_field = None
376 if self.need_serialize:
377 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
378 self.need_sizeof = True
380 # as switch does never appear at toplevel,
381 # continue here with type construction
383 if self.c_type not in finished_switch:
384 finished_switch.append(self.c_type)
385 # special: switch C structs get pointer fields for variable-sized members
387 for bitcase in self.bitcases:
388 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
389 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
390 # no list with switch as element, so no call to
391 # _c_iterator(field.type, field_name) necessary
393 if not self.is_bitcase:
394 if self.need_serialize:
395 if self.c_serialize_name not in finished_serializers:
396 finished_serializers.append(self.c_serialize_name)
397 _c_serialize('serialize', self)
399 # _unpack() and _unserialize() are only needed for special cases:
401 # special cases -> unserialize
402 if self.is_switch or self.var_followed_by_fixed_fields:
403 _c_serialize('unserialize', self)
406 if self.c_sizeof_name not in finished_sizeof:
407 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
408 finished_sizeof.append(self.c_sizeof_name)
409 _c_serialize('sizeof', self)
412 def _c_helper_absolute_name(prefix, field=None):
414 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
415 representing a valid name in C (based on the context)
416 if field is not None, append the field name as well
419 for name, sep, obj in prefix:
423 if ((obj.is_bitcase and obj.has_name) or # named bitcase
424 (obj.is_switch and len(obj.parents)>1)):
427 if field is not None:
428 prefix_str += _cpp(field.field_name)
432 def _c_helper_field_mapping(complex_type, prefix, flat=False):
434 generate absolute names, based on prefix, for all fields starting from complex_type
435 if flat == True, nested complex types are not taken into account
438 if complex_type.is_switch:
439 for b in complex_type.bitcases:
441 switch_name, switch_sep, switch_type = prefix[-1]
442 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
444 bitcase_prefix = prefix
446 if (True==flat and not b.type.has_name) or False==flat:
447 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
449 for f in complex_type.fields:
450 fname = _c_helper_absolute_name(prefix, f)
451 if f.field_name in all_fields:
452 raise Exception("field name %s has been registered before" % f.field_name)
454 all_fields[f.field_name] = (fname, f)
455 if f.type.is_container and flat==False:
456 if f.type.is_bitcase and not f.type.has_name:
458 elif f.type.is_switch and len(f.type.parents)>1:
459 # nested switch gets another separator
460 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
462 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
463 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
468 def _c_helper_resolve_field_names (prefix):
470 get field names for all objects in the prefix array
474 # look for fields in the remaining containers
475 for idx, p in enumerate(prefix):
478 # sep can be preset in prefix, if not, make a sensible guess
479 sep = '.' if (obj.is_switch or obj.is_bitcase) else '->'
480 # exception: 'toplevel' object (switch as well!) always have sep '->'
481 sep = '->' if idx<1 else sep
482 if not obj.is_bitcase or (obj.is_bitcase and obj.has_name):
483 tmp_prefix.append((name, sep, obj))
484 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
487 # _c_helper_resolve_field_names
489 def get_expr_fields(self):
491 get the Fields referenced by switch or list expression
493 def get_expr_field_names(expr):
495 if expr.lenfield_name is not None:
496 return [expr.lenfield_name]
498 # constant value expr
502 return get_expr_field_names(expr.rhs)
503 elif expr.op == 'popcount':
504 return get_expr_field_names(expr.rhs)
505 elif expr.op == 'sumof':
506 # sumof expr references another list,
507 # we need that list's length field here
509 for f in expr.lenfield_parent.fields:
510 if f.field_name == expr.lenfield_name:
514 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
515 # referenced list + its length field
516 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
517 elif expr.op == 'enumref':
520 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
521 # get_expr_field_names()
523 # resolve the field names with the parent structure(s)
524 unresolved_fields_names = get_expr_field_names(self.expr)
526 # construct prefix from self
527 prefix = [('', '', p) for p in self.parents]
528 if self.is_container:
529 prefix.append(('', '', self))
531 all_fields = _c_helper_resolve_field_names (prefix)
532 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
533 if len(unresolved_fields_names) != len(resolved_fields_names):
534 raise Exception("could not resolve all fields for %s" % self.name)
536 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
537 return resolved_fields
540 def resolve_expr_fields(complex_obj):
542 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
543 these are normally fields that need to be given as function parameters
549 for field in complex_obj.fields:
550 all_fields.append(field)
551 if field.type.is_switch or field.type.is_list:
552 expr_fields += get_expr_fields(field.type)
553 if field.type.is_container:
554 expr_fields += resolve_expr_fields(field.type)
556 # try to resolve expr fields
557 for e in expr_fields:
558 if e not in all_fields and e not in unresolved:
561 # resolve_expr_fields()
563 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
565 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
566 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
567 expression. This function tries to resolve all fields within a structure, and returns the
568 unresolved fields as the list of external parameters.
570 def add_param(params, param):
571 if param not in params:
574 # collect all fields into param_fields
578 for field in self.fields:
580 # the field should appear as a parameter in the function call
581 param_fields.append(field)
582 if field.wire and not field.auto:
583 if field.type.fixed_size() and not self.is_switch:
584 # field in the xcb_out structure
585 wire_fields.append(field)
586 # fields like 'pad0' are skipped!
588 # in case of switch, parameters always contain any fields referenced in the switch expr
589 # we do not need any variable size fields here, as the switch data type contains both
590 # fixed and variable size fields
592 param_fields = get_expr_fields(self)
594 # _serialize()/_unserialize()/_unpack() function parameters
595 # note: don't use set() for params, it is unsorted
598 # 1. the parameter for the void * buffer
599 if 'serialize' == context:
600 params.append(('void', '**', buffer_var))
601 elif context in ('unserialize', 'unpack', 'sizeof'):
602 params.append(('const void', '*', buffer_var))
604 # 2. any expr fields that cannot be resolved within self and descendants
605 unresolved_fields = resolve_expr_fields(self)
606 for f in unresolved_fields:
607 add_param(params, (f.c_field_type, '', f.c_field_name))
609 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
610 # that do not appear in the data type struct
611 for p in param_fields:
613 typespec = p.c_field_const_type
614 pointerspec = p.c_pointer
615 add_param(params, (typespec, pointerspec, p.c_field_name))
617 if p.visible and not p.wire and not p.auto:
618 typespec = p.c_field_type
620 add_param(params, (typespec, pointerspec, p.c_field_name))
623 if 'serialize' == context:
624 add_param(params, ('const %s' % self.c_type, '*', aux_var))
625 elif 'unserialize' == context:
626 add_param(params, ('%s' % self.c_type, '**', aux_var))
627 elif 'unpack' == context:
628 add_param(params, ('%s' % self.c_type, '*', aux_var))
630 # 5. switch contains all variable size fields as struct members
631 # for other data types though, these have to be supplied separately
632 # this is important for the special case of intermixed fixed and
633 # variable size fields
634 if not self.is_switch and 'serialize' == context:
635 for p in param_fields:
636 if not p.type.fixed_size():
637 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
639 return (param_fields, wire_fields, params)
640 # get_serialize_params()
642 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
643 code_lines.append('%s /* insert padding */' % space)
644 code_lines.append('%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
645 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
646 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
649 code_lines.append('%s if (0 != xcb_pad) {' % space)
651 if 'serialize' == context:
652 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
653 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
654 code_lines.append('%s xcb_parts_idx++;' % space)
655 elif context in ('unserialize', 'unpack', 'sizeof'):
656 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
658 code_lines.append('%s xcb_pad = 0;' % space)
659 code_lines.append('%s }' % space)
661 code_lines.append('%s xcb_block_len = 0;' % space)
663 # keep tracking of xcb_parts entries for serialize
665 # _c_serialize_helper_insert_padding()
667 def _c_serialize_helper_switch(context, self, complex_name,
668 code_lines, temp_vars,
671 switch_expr = _c_accessor_get_expr(self.expr, None)
673 for b in self.bitcases:
674 bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
675 code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
676 # code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' %
677 # (self.name[-1], b.type.name[-1], bitcase_expr))
680 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
682 count += _c_serialize_helper_fields(context, b.type,
683 code_lines, temp_vars,
687 code_lines.append(' }')
689 # if 'serialize' == context:
690 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
691 # elif context in ('unserialize', 'unpack', 'sizeof'):
693 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
694 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
697 # _c_serialize_helper_switch
699 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
701 handle switch by calling _serialize() or _unpack(), depending on context
703 # switch is handled by this function as a special case
704 param_fields, wire_fields, params = get_serialize_params(context, self)
705 field_mapping = _c_helper_field_mapping(self, prefix)
706 prefix_str = _c_helper_absolute_name(prefix)
708 # find the parameters that need to be passed to _serialize()/_unpack():
709 # all switch expr fields must be given as parameters
710 args = get_expr_fields(field.type)
711 # length fields for variable size types in switch, normally only some of need
712 # need to be passed as parameters
713 switch_len_fields = resolve_expr_fields(field.type)
715 # a switch field at this point _must_ be a bitcase field
716 # we require that bitcases are "self-contiguous"
717 bitcase_unresolved = resolve_expr_fields(self)
718 if len(bitcase_unresolved) != 0:
719 raise Exception('unresolved fields within bitcase is not supported at this point')
721 # get the C names for the parameters
723 for a in switch_len_fields:
724 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
726 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
728 # call _serialize()/_unpack() to determine the actual size
729 if 'serialize' == context:
730 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
731 c_field_names, prefix_str, field.c_field_name)
732 elif context in ('unserialize', 'unpack'):
733 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
734 c_field_names, prefix_str, field.c_field_name)
737 # _c_serialize_helper_switch_field()
739 def _c_serialize_helper_list_field(context, self, field,
740 code_lines, temp_vars,
743 helper function to cope with lists of variable length
745 expr = field.type.expr
746 prefix_str = _c_helper_absolute_name(prefix)
747 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
748 param_names = [p[2] for p in params]
750 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
751 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
752 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
756 field_mapping[r] = (r, None)
758 if len(unresolved)>0:
760 if len(tmp_prefix)==0:
761 raise Exception("found an empty prefix while resolving expr field names for list %s",
764 field_mapping.update(_c_helper_resolve_field_names(prefix))
765 resolved += list(filter(lambda x: x in field_mapping, unresolved))
766 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
767 if len(unresolved)>0:
768 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
770 list_length = _c_accessor_get_expr(expr, field_mapping)
772 # default: list with fixed size elements
773 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
775 # list with variable-sized elements
776 if not field.type.member.fixed_size():
778 if context in ('unserialize', 'sizeof', 'unpack'):
779 int_i = ' unsigned int i;'
780 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
781 if int_i not in temp_vars:
782 temp_vars.append(int_i)
783 if xcb_tmp_len not in temp_vars:
784 temp_vars.append(xcb_tmp_len)
785 # loop over all list elements and call sizeof repeatedly
786 # this should be a bit faster than using the iterators
787 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
788 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
789 (space, field.type.c_sizeof_name))
790 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
791 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
792 code_lines.append("%s }" % space)
794 elif 'serialize' == context:
795 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
796 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
797 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
798 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
799 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
800 code_lines.append('%s }' % space)
801 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
804 # _c_serialize_helper_list_field()
806 def _c_serialize_helper_fields_fixed_size(context, self, field,
807 code_lines, temp_vars,
809 # keep the C code a bit more readable by giving the field name
810 if not self.is_bitcase:
811 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
813 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
814 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
815 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
817 abs_field_name = _c_helper_absolute_name(prefix, field)
818 # default for simple cases: call sizeof()
819 length = "sizeof(%s)" % field.c_field_type
821 if context in ('unserialize', 'unpack', 'sizeof'):
822 # default: simple cast
823 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
825 # padding - we could probably just ignore it
826 if field.type.is_pad and field.type.nmemb > 1:
828 for i in range(field.type.nmemb):
829 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
830 (space, abs_field_name, i, field.c_field_type))
831 # total padding = sizeof(pad0) * nmemb
832 length += " * %d" % field.type.nmemb
834 if field.type.is_list:
835 # no such case in the protocol, cannot be tested and therefore ignored for now
836 raise Exception('list with fixed number of elemens unhandled in _unserialize()')
838 elif 'serialize' == context:
839 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
841 if field.type.is_expr:
842 # need to register a temporary variable for the expression in case we know its type
843 if field.type.c_type is None:
844 raise Exception("type for field '%s' (expression '%s') unkown" %
845 (field.field_name, _c_accessor_get_expr(field.type.expr)))
847 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
848 _c_accessor_get_expr(field.type.expr, prefix)))
849 value += "&xcb_expr_%s;" % _cpp(field.field_name)
851 elif field.type.is_pad:
852 if field.type.nmemb == 1:
855 # we could also set it to 0, see definition of xcb_send_request()
856 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
857 length += "*%d" % field.type.nmemb
860 # non-list type with fixed size
861 if field.type.nmemb == 1:
862 value += "&%s;" % (abs_field_name)
864 # list with nmemb (fixed size) elements
866 value += '%s;' % (abs_field_name)
867 length = '%d' % field.type.nmemb
869 return (value, length)
870 # _c_serialize_helper_fields_fixed_size()
872 def _c_serialize_helper_fields_variable_size(context, self, field,
873 code_lines, temp_vars,
875 prefix_str = _c_helper_absolute_name(prefix)
877 if context in ('unserialize', 'unpack', 'sizeof'):
879 var_field_name = 'xcb_tmp'
881 # special case: intermixed fixed and variable size fields
882 if self.var_followed_by_fixed_fields and 'unserialize' == context:
883 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
884 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
885 # special case: switch
886 if 'unpack' == context:
887 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
889 elif 'serialize' == context:
890 # variable size fields appear as parameters to _serialize() if the
891 # 'toplevel' container is not a switch
892 prefix_string = prefix_str if prefix[0][2].is_switch else ''
893 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
894 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
898 code_lines.append('%s /* %s */' % (space, field.c_field_name))
900 if field.type.is_list:
902 # in any context, list is already a pointer, so the default assignment is ok
903 code_lines.append("%s%s" % (space, value))
905 length = _c_serialize_helper_list_field(context, self, field,
906 code_lines, temp_vars,
909 elif field.type.is_switch:
911 if context == 'serialize':
912 # the _serialize() function allocates the correct amount memory if given a NULL pointer
913 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
914 length = _c_serialize_helper_switch_field(context, self, field,
915 'xcb_parts[xcb_parts_idx].iov_base',
919 # in all remaining special cases - call _sizeof()
920 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
922 return (value, length)
923 # _c_serialize_helper_fields_variable_size
925 def _c_serialize_helper_fields(context, self,
926 code_lines, temp_vars,
927 space, prefix, is_bitcase):
930 prev_field_was_variable = False
932 for field in self.fields:
933 if not field.visible:
934 if not ((field.wire and not field.auto) or 'unserialize' == context):
937 # switch/bitcase: fixed size fields must be considered explicitly
938 if field.type.fixed_size():
939 if self.is_bitcase or self.var_followed_by_fixed_fields:
940 if prev_field_was_variable and need_padding:
942 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
943 # self.var_followed_by_fixed_fields)
944 prev_field_was_variable = False
946 # prefix for fixed size fields
947 fixed_prefix = prefix
949 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
950 code_lines, temp_vars,
955 # fields with variable size
957 # switch/bitcase: always calculate padding before and after variable sized fields
958 if need_padding or is_bitcase:
959 count += _c_serialize_helper_insert_padding(context, code_lines, space,
960 self.var_followed_by_fixed_fields)
962 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
963 code_lines, temp_vars,
965 prev_field_was_variable = True
967 # save (un)serialization C code
969 code_lines.append('%s%s' % (space, value))
971 if field.type.fixed_size():
972 if is_bitcase or self.var_followed_by_fixed_fields:
973 # keep track of (un)serialized object's size
974 code_lines.append('%s xcb_block_len += %s;' % (space, length))
975 if context in ('unserialize', 'unpack', 'sizeof'):
976 code_lines.append('%s xcb_tmp += %s;' % (space, length))
978 # variable size objects or bitcase:
979 # value & length might have been inserted earlier for special cases
981 # special case: intermixed fixed and variable size fields
982 if (not field.type.fixed_size() and
983 self.var_followed_by_fixed_fields and 'unserialize' == context):
984 temp_vars.append(' int %s_len;' % field.c_field_name)
985 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
986 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
987 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
989 code_lines.append('%s xcb_block_len += %s;' % (space, length))
990 # increase pointer into the byte stream accordingly
991 if context in ('unserialize', 'sizeof', 'unpack'):
992 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
994 if 'serialize' == context:
996 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
997 code_lines.append('%s xcb_parts_idx++;' % space)
1000 code_lines.append('%s xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1003 if self.var_followed_by_fixed_fields:
1004 need_padding = False
1007 # _c_serialize_helper_fields()
1009 def _c_serialize_helper(context, complex_type,
1010 code_lines, temp_vars,
1011 space='', prefix=[]):
1012 # count tracks the number of fields to serialize
1015 if hasattr(complex_type, 'type'):
1016 self = complex_type.type
1017 complex_name = complex_type.name
1020 if self.var_followed_by_fixed_fields and 'unserialize' == context:
1021 complex_name = 'xcb_out'
1023 complex_name = '_aux'
1025 # special case: switch is serialized by evaluating each bitcase separately
1027 count += _c_serialize_helper_switch(context, self, complex_name,
1028 code_lines, temp_vars,
1031 # all other data types can be evaluated one field a time
1033 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1034 if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
1035 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1036 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1037 # probably not needed
1038 #_c_serialize_helper_insert_padding(context, code_lines, space, False)
1040 count += _c_serialize_helper_fields(context, self,
1041 code_lines, temp_vars,
1042 space, prefix, False)
1044 count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1047 # _c_serialize_helper()
1049 def _c_serialize(context, self):
1051 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1052 for the ComplexType variable self
1058 # _serialize() returns the buffer size
1061 if self.is_switch and 'unserialize' == context:
1064 cases = { 'serialize' : self.c_serialize_name,
1065 'unserialize' : self.c_unserialize_name,
1066 'unpack' : self.c_unpack_name,
1067 'sizeof' : self.c_sizeof_name }
1068 func_name = cases[context]
1070 param_fields, wire_fields, params = get_serialize_params(context, self)
1071 variable_size_fields = 0
1072 # maximum space required for type definition of function arguments
1075 # determine N(variable_fields)
1076 for field in param_fields:
1077 # if self.is_switch, treat all fields as if they are variable sized
1078 if not field.type.fixed_size() or self.is_switch:
1079 variable_size_fields += 1
1080 # determine maxtypelen
1082 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1085 indent = ' '*(len(func_name)+2)
1088 typespec, pointerspec, field_name = p
1089 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1090 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1091 # insert function name
1092 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1093 param_str = list(map(lambda x: "%s," % x, param_str))
1094 for s in param_str[:-1]:
1096 _h("%s);" % param_str[-1].rstrip(','))
1097 _c("%s)" % param_str[-1].rstrip(','))
1104 if 'serialize' == context:
1105 if not self.is_switch and not self.var_followed_by_fixed_fields:
1106 _c(' %s *xcb_out = *_buffer;', self.c_type)
1107 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1108 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1109 _c(' unsigned int xcb_align_to;')
1111 _c(' char *xcb_out = *_buffer;')
1112 _c(' unsigned int xcb_buffer_len = 0;')
1113 _c(' unsigned int xcb_align_to;')
1114 prefix = [('_aux', '->', self)]
1117 elif context in ('unserialize', 'unpack'):
1118 _c(' char *xcb_tmp = (char *)_buffer;')
1119 if not self.is_switch:
1120 if not self.var_followed_by_fixed_fields:
1121 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1122 prefix = [('_aux', '->', self)]
1124 _c(' %s xcb_out;', self.c_type)
1125 prefix = [('xcb_out', '.', self)]
1127 aux_var = '_aux' # default for unpack: single pointer
1128 # note: unserialize not generated for switch
1129 if 'unserialize' == context:
1130 aux_var = '(*_aux)' # unserialize: double pointer (!)
1131 prefix = [(aux_var, '->', self)]
1133 _c(' unsigned int xcb_buffer_len = 0;')
1134 _c(' unsigned int xcb_block_len = 0;')
1135 _c(' unsigned int xcb_pad = 0;')
1136 _c(' unsigned int xcb_align_to;')
1138 elif 'sizeof' == context:
1139 param_names = [p[2] for p in params]
1141 # switch: call _unpack()
1142 _c(' %s _aux;', self.c_type)
1143 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1146 elif self.var_followed_by_fixed_fields:
1147 # special case: call _unserialize()
1148 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1152 _c(' char *xcb_tmp = (char *)_buffer;')
1153 prefix = [('_aux', '->', self)]
1155 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1156 # update variable size fields (only important for context=='serialize'
1157 variable_size_fields = count
1158 if 'serialize' == context:
1159 temp_vars.append(' unsigned int xcb_pad = 0;')
1160 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1161 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1162 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1163 temp_vars.append(' unsigned int xcb_block_len = 0;')
1164 temp_vars.append(' unsigned int i;')
1165 temp_vars.append(' char *xcb_tmp;')
1166 elif 'sizeof' == context:
1167 # neither switch nor intermixed fixed and variable size fields:
1168 # evaluate parameters directly
1169 if not (self.is_switch or self.var_followed_by_fixed_fields):
1171 # look if we have to declare an '_aux' variable at all
1172 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1173 if not self.var_followed_by_fixed_fields:
1174 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1176 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1178 _c(' unsigned int xcb_buffer_len = 0;')
1179 _c(' unsigned int xcb_block_len = 0;')
1180 _c(' unsigned int xcb_pad = 0;')
1181 _c(' unsigned int xcb_align_to;')
1187 for l in code_lines:
1190 # variable sized fields have been collected, now
1191 # allocate memory and copy everything into a continuous memory area
1192 # note: this is not necessary in case of unpack
1193 if context in ('serialize', 'unserialize'):
1194 # unserialize: check for sizeof-only invocation
1195 if 'unserialize' == context:
1197 _c(' if (NULL == _aux)')
1198 _c(' return xcb_buffer_len;')
1201 _c(' if (NULL == %s) {', aux_ptr)
1202 _c(' /* allocate memory */')
1203 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1204 if 'serialize' == context:
1205 _c(' *_buffer = xcb_out;')
1209 # serialize: handle variable size fields in a loop
1210 if 'serialize' == context:
1211 if not self.is_switch and not self.var_followed_by_fixed_fields:
1212 if len(wire_fields)>0:
1213 _c(' *xcb_out = *_aux;')
1214 # copy variable size fields into the buffer
1215 if variable_size_fields > 0:
1217 if not self.is_switch and not self.var_followed_by_fixed_fields:
1218 _c(' xcb_tmp = (char*)++xcb_out;')
1219 _c(' xcb_tmp += xcb_out_pad;')
1221 _c(' xcb_tmp = xcb_out;')
1223 # variable sized fields
1224 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1225 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1226 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1227 _c(' if (0 != xcb_parts[i].iov_len)')
1228 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1231 # unserialize: assign variable size fields individually
1232 if 'unserialize' == context:
1233 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1234 param_fields.reverse()
1235 for field in param_fields:
1236 if not field.type.fixed_size():
1237 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1238 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1239 _c(' *%s = xcb_out;', aux_ptr)
1242 _c(' return xcb_buffer_len;')
1246 def _c_iterator_get_end(field, accum):
1248 Figures out what C code is needed to find the end of a variable-length structure field.
1249 For nested structures, recurses into its last variable-sized field.
1250 For lists, calls the end function
1252 if field.type.is_container:
1253 accum = field.c_accessor_name + '(' + accum + ')'
1254 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1255 if field.type.is_list:
1256 # XXX we can always use the first way
1257 if field.type.member.is_simple:
1258 return field.c_end_name + '(' + accum + ')'
1260 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1262 def _c_iterator(self, name):
1264 Declares the iterator structure and next/end functions for a given type.
1269 _h(' * @brief %s', self.c_iterator_type)
1271 _h('typedef struct %s {', self.c_iterator_type)
1272 _h(' %s *data; /**< */', self.c_type)
1273 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1274 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1275 _h('} %s;', self.c_iterator_type)
1281 _h(' * Get the next element of the iterator')
1282 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1284 _h(' * Get the next element in the iterator. The member rem is')
1285 _h(' * decreased by one. The member data points to the next')
1286 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1290 _hc('/*****************************************************************************')
1292 _hc(' ** void %s', self.c_next_name)
1294 _hc(' ** @param %s *i', self.c_iterator_type)
1295 _hc(' ** @returns void')
1297 _hc(' *****************************************************************************/')
1300 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1301 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1304 if not self.fixed_size():
1305 _c(' %s *R = i->data;', self.c_type)
1308 # FIXME - how to determine the size of a variable size union??
1309 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1311 if self.need_sizeof:
1312 _c(' xcb_generic_iterator_t child;')
1313 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1314 self.c_type, self.c_sizeof_name)
1315 _c(' i->index = (char *) child.data - (char *) i->data;')
1317 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1318 _c(' i->index = child.index;')
1320 _c(' i->data = (%s *) child.data;', self.c_type)
1325 _c(' i->index += sizeof(%s);', self.c_type)
1331 _h(' * Return the iterator pointing to the last element')
1332 _h(' * @param i An %s', self.c_iterator_type)
1333 _h(' * @return The iterator pointing to the last element')
1335 _h(' * Set the current element in the iterator to the last element.')
1336 _h(' * The member rem is set to 0. The member data points to the')
1337 _h(' * last element.')
1341 _hc('/*****************************************************************************')
1343 _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1345 _hc(' ** @param %s i', self.c_iterator_type)
1346 _hc(' ** @returns xcb_generic_iterator_t')
1348 _hc(' *****************************************************************************/')
1350 _hc('xcb_generic_iterator_t')
1351 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1352 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1354 _c(' xcb_generic_iterator_t ret;')
1356 if self.fixed_size():
1357 _c(' ret.data = i.data + i.rem;')
1358 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1361 _c(' while(i.rem > 0)')
1362 _c(' %s(&i);', self.c_next_name)
1363 _c(' ret.data = i.data;')
1364 _c(' ret.rem = i.rem;')
1365 _c(' ret.index = i.index;')
1370 def _c_accessor_get_length(expr, field_mapping=None):
1372 Figures out what C code is needed to get a length field.
1373 The field_mapping parameter can be used to change the absolute name of a length field.
1374 For fields that follow a variable-length field, use the accessor.
1375 Otherwise, just reference the structure field directly.
1378 lenfield_name = expr.lenfield_name
1379 if lenfield_name is not None:
1380 if field_mapping is not None:
1381 lenfield_name = field_mapping[lenfield_name][0]
1383 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1384 # special case: variable and fixed size fields are intermixed
1385 # if the lenfield is among the fixed size fields, there is no need
1386 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1387 return field_mapping(expr.lenfield_name)
1388 elif expr.lenfield_name is not None:
1389 return lenfield_name
1391 return str(expr.nmemb)
1393 def _c_accessor_get_expr(expr, field_mapping):
1395 Figures out what C code is needed to get the length of a list field.
1396 The field_mapping parameter can be used to change the absolute name of a length field.
1397 Recurses for math operations.
1398 Returns bitcount for value-mask fields.
1399 Otherwise, uses the value of the length field.
1401 lenexp = _c_accessor_get_length(expr, field_mapping)
1404 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1405 elif expr.op == 'popcount':
1406 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1407 elif expr.op == 'enumref':
1408 enum_name = expr.lenfield_type.name
1409 constant_name = expr.lenfield_name
1410 c_name = _n(enum_name + (constant_name,)).upper()
1412 elif expr.op == 'sumof':
1413 # locate the referenced list object
1414 list_obj = expr.lenfield_type
1416 for f in expr.lenfield_parent.fields:
1417 if f.field_name == expr.lenfield_name:
1422 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1423 list_name = field_mapping[field.c_field_name][0]
1424 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1425 # note: xcb_sumof() has only been defined for integers
1426 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1427 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1428 elif expr.op != None:
1429 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1430 ' ' + expr.op + ' ' +
1431 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1433 return 'xcb_popcount(' + lenexp + ')'
1437 def type_pad_type(type):
1442 def _c_accessors_field(self, field):
1444 Declares the accessor functions for a non-list field that follows a variable-length field.
1446 c_type = self.c_type
1448 # special case: switch
1449 switch_obj = self if self.is_switch else None
1451 switch_obj = self.parents[-1]
1452 if switch_obj is not None:
1453 c_type = switch_obj.c_type
1455 if field.type.is_simple:
1458 _hc('/*****************************************************************************')
1460 _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1462 _hc(' ** @param const %s *R', c_type)
1463 _hc(' ** @returns %s', field.c_field_type)
1465 _hc(' *****************************************************************************/')
1467 _hc('%s', field.c_field_type)
1468 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1469 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1471 if field.prev_varsized_field is None:
1472 _c(' return (%s *) (R + 1);', field.c_field_type)
1474 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1475 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1476 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1481 _hc('/*****************************************************************************')
1483 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1485 _hc(' ** @param const %s *R', c_type)
1486 _hc(' ** @returns %s *', field.c_field_type)
1488 _hc(' *****************************************************************************/')
1490 if field.type.is_switch and switch_obj is None:
1491 return_type = 'void *'
1493 return_type = '%s *' % field.c_field_type
1496 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1497 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1499 if field.prev_varsized_field is None:
1500 _c(' return (%s) (R + 1);', return_type)
1501 # note: the special case 'variable fields followed by fixed size fields'
1502 # is not of any consequence here, since the ordering gets
1503 # 'corrected' in the reply function
1505 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1506 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1507 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1511 def _c_accessors_list(self, field):
1513 Declares the accessor functions for a list field.
1514 Declares a direct-accessor function only if the list members are fixed size.
1515 Declares length and get-iterator functions always.
1518 c_type = self.c_type
1520 # special case: switch
1521 # in case of switch, 2 params have to be supplied to certain accessor functions:
1522 # 1. the anchestor object (request or reply)
1523 # 2. the (anchestor) switch object
1524 # the reason is that switch is either a child of a request/reply or nested in another switch,
1525 # so whenever we need to access a length field, we might need to refer to some anchestor type
1526 switch_obj = self if self.is_switch else None
1528 switch_obj = self.parents[-1]
1529 if switch_obj is not None:
1530 c_type = switch_obj.c_type
1534 parents = self.parents if hasattr(self, 'parents') else [self]
1535 # 'R': parents[0] is always the 'toplevel' container type
1536 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1537 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1538 # auxiliary object for 'R' parameters
1541 if switch_obj is not None:
1542 # now look where the fields are defined that are needed to evaluate
1543 # the switch expr, and store the parent objects in accessor_params and
1544 # the fields in switch_fields
1546 # 'S': name for the 'toplevel' switch
1547 toplevel_switch = parents[1]
1548 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1549 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1551 # initialize prefix for everything "below" S
1552 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1553 prefix = [(prefix_str, '->', toplevel_switch)]
1555 # look for fields in the remaining containers
1556 for p in parents[2:] + [self]:
1557 # the separator between parent and child is always '.' here,
1558 # because of nested switch statements
1559 if not p.is_bitcase or (p.is_bitcase and p.has_name):
1560 prefix.append((p.name[-1], '.', p))
1561 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1563 # auxiliary object for 'S' parameter
1568 if list.member.fixed_size():
1569 idx = 1 if switch_obj is not None else 0
1572 _hc('/*****************************************************************************')
1574 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1576 _hc(' ** @param %s', params[idx][0])
1577 _hc(' ** @returns %s *', field.c_field_type)
1579 _hc(' *****************************************************************************/')
1581 _hc('%s *', field.c_field_type)
1583 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1584 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1587 if switch_obj is not None:
1588 _c(' return %s;', fields[field.c_field_name][0])
1589 elif field.prev_varsized_field is None:
1590 _c(' return (%s *) (R + 1);', field.c_field_type)
1592 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1593 _c(' return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1594 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1599 _hc('/*****************************************************************************')
1601 _hc(' ** int %s', field.c_length_name)
1603 _hc(' ** @param const %s *R', c_type)
1604 _hc(' ** @returns int')
1606 _hc(' *****************************************************************************/')
1609 if switch_obj is not None:
1610 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1611 spacing = ' '*(len(field.c_length_name)+2)
1612 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1613 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1614 length = _c_accessor_get_expr(field.type.expr, fields)
1616 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1617 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1618 length = _c_accessor_get_expr(field.type.expr, fields)
1620 _c(' return %s;', length)
1623 if field.type.member.is_simple:
1626 _hc('/*****************************************************************************')
1628 _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1630 _hc(' ** @param const %s *R', c_type)
1631 _hc(' ** @returns xcb_generic_iterator_t')
1633 _hc(' *****************************************************************************/')
1635 _hc('xcb_generic_iterator_t')
1636 if switch_obj is not None:
1637 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1638 spacing = ' '*(len(field.c_end_name)+2)
1639 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1640 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1642 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1643 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1645 _c(' xcb_generic_iterator_t i;')
1647 param = 'R' if switch_obj is None else 'S'
1648 if switch_obj is not None:
1649 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1650 _c_accessor_get_expr(field.type.expr, fields))
1651 elif field.prev_varsized_field == None:
1652 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1653 _c_accessor_get_expr(field.type.expr, fields))
1655 _c(' xcb_generic_iterator_t child = %s;',
1656 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1657 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1658 _c_accessor_get_expr(field.type.expr, fields))
1661 _c(' i.index = (char *) i.data - (char *) %s;', param)
1668 _hc('/*****************************************************************************')
1670 _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1672 _hc(' ** @param const %s *R', c_type)
1673 _hc(' ** @returns %s', field.c_iterator_type)
1675 _hc(' *****************************************************************************/')
1678 _hc('%s', field.c_iterator_type)
1679 if switch_obj is not None:
1680 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1681 spacing = ' '*(len(field.c_iterator_name)+2)
1682 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1683 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1685 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1686 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1688 _c(' %s i;', field.c_iterator_type)
1690 if switch_obj is not None:
1691 _c(' i.data = %s;', fields[field.c_field_name][0])
1692 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1693 elif field.prev_varsized_field == None:
1694 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1696 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1697 _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));',
1698 field.c_field_type, type_pad_type(field.c_field_type))
1699 if switch_obj is None:
1700 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1701 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1705 def _c_accessors(self, name, base):
1707 Declares the accessor functions for the fields of a structure.
1709 # no accessors for switch itself -
1710 # switch always needs to be unpacked explicitly
1711 # if self.is_switch:
1715 for field in self.fields:
1716 if field.type.is_list and not field.type.fixed_size():
1717 _c_accessors_list(self, field)
1718 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1719 _c_accessors_field(self, field)
1721 def c_simple(self, name):
1723 Exported function that handles cardinal type declarations.
1724 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1726 _c_type_setup(self, name, ())
1728 if (self.name != name):
1733 _h('typedef %s %s;', _t(self.name), my_name)
1736 _c_iterator(self, name)
1738 def _c_complex(self):
1740 Helper function for handling all structure types.
1741 Called for all structs, requests, replies, events, errors.
1746 _h(' * @brief %s', self.c_type)
1748 _h('typedef %s %s {', self.c_container, self.c_type)
1754 for field in self.fields:
1755 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1756 varfield = field.c_field_name
1759 struct_fields.append(field)
1761 for field in struct_fields:
1762 length = len(field.c_field_type)
1763 # account for '*' pointer_spec
1764 if not field.type.fixed_size():
1766 maxtypelen = max(maxtypelen, length)
1768 def _c_complex_field(self, field, space=''):
1769 if (field.type.fixed_size() or
1770 # in case of switch with switch children, don't make the field a pointer
1771 # necessary for unserialize to work
1772 (self.is_switch and field.type.is_switch)):
1773 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1774 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1776 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1777 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1779 if not self.is_switch:
1780 for field in struct_fields:
1781 _c_complex_field(self, field)
1783 for b in self.bitcases:
1786 _h(' struct _%s {', b.c_field_name)
1788 for field in b.type.fields:
1789 _c_complex_field(self, field, space)
1791 _h(' } %s;', b.c_field_name)
1793 _h('} %s;', self.c_type)
1795 def c_struct(self, name):
1797 Exported function that handles structure declarations.
1799 _c_type_setup(self, name, ())
1801 _c_accessors(self, name, name)
1802 _c_iterator(self, name)
1804 def c_union(self, name):
1806 Exported function that handles union declarations.
1808 _c_type_setup(self, name, ())
1810 _c_iterator(self, name)
1812 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1814 Declares a request function.
1817 # Four stunningly confusing possibilities here:
1820 # ------------------------------
1822 # 0 flag CHECKED flag Normal Mode
1823 # void_cookie req_cookie
1824 # ------------------------------
1825 # "req_checked" "req_unchecked"
1826 # CHECKED flag 0 flag Abnormal Mode
1827 # void_cookie req_cookie
1828 # ------------------------------
1831 # Whether we are _checked or _unchecked
1832 checked = void and not regular
1833 unchecked = not void and not regular
1835 # What kind of cookie we return
1836 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1838 # What flag is passed to xcb_request
1839 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1841 # Global extension id variable or NULL for xproto
1842 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1844 # What our function name is
1845 func_name = self.c_request_name if not aux else self.c_aux_name
1847 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1849 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1853 maxtypelen = len('xcb_connection_t')
1855 # special case: list with variable size elements
1856 list_with_var_size_elems = False
1858 for field in self.fields:
1860 # The field should appear as a call parameter
1861 param_fields.append(field)
1862 if field.wire and not field.auto:
1863 # We need to set the field up in the structure
1864 wire_fields.append(field)
1865 if field.type.need_serialize or field.type.need_sizeof:
1866 serial_fields.append(field)
1868 for field in param_fields:
1869 c_field_const_type = field.c_field_const_type
1870 if field.type.need_serialize and not aux:
1871 c_field_const_type = "const void"
1872 if len(c_field_const_type) > maxtypelen:
1873 maxtypelen = len(c_field_const_type)
1874 if field.type.is_list and not field.type.member.fixed_size():
1875 list_with_var_size_elems = True
1881 _h(' * Delivers a request to the X server')
1882 _h(' * @param c The connection')
1883 _h(' * @return A cookie')
1885 _h(' * Delivers a request to the X server.')
1888 _h(' * This form can be used only if the request will not cause')
1889 _h(' * a reply to be generated. Any returned error will be')
1890 _h(' * saved for handling by xcb_request_check().')
1892 _h(' * This form can be used only if the request will cause')
1893 _h(' * a reply to be generated. Any returned error will be')
1894 _h(' * placed in the event queue.')
1898 _hc('/*****************************************************************************')
1900 _hc(' ** %s %s', cookie_type, func_name)
1903 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1904 _hc(' ** @param xcb_connection_t%s *c', spacing)
1906 for field in param_fields:
1907 c_field_const_type = field.c_field_const_type
1908 if field.type.need_serialize and not aux:
1909 c_field_const_type = "const void"
1910 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1911 _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1913 _hc(' ** @returns %s', cookie_type)
1915 _hc(' *****************************************************************************/')
1917 _hc('%s', cookie_type)
1919 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1920 comma = ',' if len(param_fields) else ');'
1921 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1922 comma = ',' if len(param_fields) else ')'
1923 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1925 func_spacing = ' ' * (len(func_name) + 2)
1926 count = len(param_fields)
1927 for field in param_fields:
1929 c_field_const_type = field.c_field_const_type
1930 c_pointer = field.c_pointer
1931 if field.type.need_serialize and not aux:
1932 c_field_const_type = "const void"
1934 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1935 comma = ',' if count else ');'
1936 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1937 spacing, c_pointer, field.c_field_name, comma)
1938 comma = ',' if count else ')'
1939 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1940 spacing, c_pointer, field.c_field_name, comma)
1943 if not self.var_followed_by_fixed_fields:
1944 for field in param_fields:
1945 if not field.type.fixed_size():
1947 if field.type.need_serialize:
1948 # _serialize() keeps track of padding automatically
1950 dimension = count + 2
1953 _c(' static const xcb_protocol_request_t xcb_req = {')
1954 _c(' /* count */ %d,', count)
1955 _c(' /* ext */ %s,', func_ext_global)
1956 _c(' /* opcode */ %s,', self.c_request_name.upper())
1957 _c(' /* isvoid */ %d', 1 if void else 0)
1961 _c(' struct iovec xcb_parts[%d];', dimension)
1962 _c(' %s xcb_ret;', func_cookie)
1963 _c(' %s xcb_out;', self.c_type)
1964 if self.var_followed_by_fixed_fields:
1965 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
1966 _c(' void *xcb_aux = 0;')
1969 for idx, f in enumerate(serial_fields):
1971 _c(' void *xcb_aux%d = 0;' % (idx))
1972 if list_with_var_size_elems:
1973 _c(' unsigned int i;')
1974 _c(' unsigned int xcb_tmp_len;')
1975 _c(' char *xcb_tmp;')
1977 # simple request call tracing
1978 # _c(' printf("in function %s\\n");' % func_name)
1981 for field in wire_fields:
1982 if field.type.fixed_size():
1983 if field.type.is_expr:
1984 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
1985 elif field.type.is_pad:
1986 if field.type.nmemb == 1:
1987 _c(' xcb_out.%s = 0;', field.c_field_name)
1989 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
1991 if field.type.nmemb == 1:
1992 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
1994 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
1996 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
1997 serialize_args = get_serialize_params(context, type_obj,
2000 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2002 # calls in order to free dyn. all. memory
2006 if not self.var_followed_by_fixed_fields:
2007 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2008 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2009 _c(' xcb_parts[3].iov_base = 0;')
2010 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2014 for field in param_fields:
2015 if not field.type.fixed_size():
2016 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2017 # default: simple cast to char *
2018 if not field.type.need_serialize and not field.type.need_sizeof:
2019 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2020 if field.type.is_list:
2021 if field.type.member.fixed_size():
2022 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2023 _c_accessor_get_expr(field.type.expr, None),
2024 field.type.member.c_wiretype)
2026 list_length = _c_accessor_get_expr(field.type.expr, None)
2029 _c(" xcb_parts[%d].iov_len = 0;" % count)
2030 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2031 _c(" for(i=0; i<%s; i++) {" % list_length)
2032 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2033 (field.type.c_sizeof_name))
2034 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2035 _c(" xcb_tmp += xcb_tmp_len;")
2038 # not supposed to happen
2039 raise Exception("unhandled variable size field %s" % field.c_field_name)
2042 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2043 idx = serial_fields.index(field)
2044 aux_var = '&xcb_aux%d' % idx
2045 context = 'serialize' if aux else 'sizeof'
2046 _c(' xcb_parts[%d].iov_len = ', count)
2048 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2049 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2050 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2051 free_calls.append(' free(xcb_aux%d);' % idx)
2053 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2054 func_name = field.type.c_sizeof_name
2055 _c(' %s (%s);', func_name, serialize_args)
2058 if not (field.type.need_serialize or field.type.need_sizeof):
2059 # the _serialize() function keeps track of padding automatically
2060 _c(' xcb_parts[%d].iov_base = 0;', count)
2061 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2064 # elif self.var_followed_by_fixed_fields:
2066 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2067 # request header: opcodes + length
2068 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2071 buffer_var = '&xcb_aux'
2072 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2073 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2074 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2075 free_calls.append(' free(xcb_aux);')
2076 # no padding necessary - _serialize() keeps track of padding automatically
2079 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2081 # free dyn. all. data, if any
2082 for f in free_calls:
2084 _c(' return xcb_ret;')
2087 def _c_reply(self, name):
2089 Declares the function that returns the reply structure.
2091 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2092 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2093 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2095 # check if _unserialize() has to be called for any field
2096 def look_for_special_cases(complex_obj):
2097 unserialize_fields = []
2098 # no unserialize call in case of switch
2099 if not complex_obj.is_switch:
2100 for field in complex_obj.fields:
2101 # three cases: 1. field with special case
2102 # 2. container that contains special case field
2103 # 3. list with special case elements
2104 if field.type.var_followed_by_fixed_fields:
2105 unserialize_fields.append(field)
2106 elif field.type.is_container:
2107 unserialize_fields += look_for_special_cases(field.type)
2108 elif field.type.is_list:
2109 if field.type.member.var_followed_by_fixed_fields:
2110 unserialize_fields.append(field)
2111 if field.type.member.is_container:
2112 unserialize_fields += look_for_special_cases(field.type.member)
2113 return unserialize_fields
2115 unserialize_fields = look_for_special_cases(self.reply)
2119 _h(' * Return the reply')
2120 _h(' * @param c The connection')
2121 _h(' * @param cookie The cookie')
2122 _h(' * @param e The xcb_generic_error_t supplied')
2124 _h(' * Returns the reply of the request asked by')
2126 _h(' * The parameter @p e supplied to this function must be NULL if')
2127 _h(' * %s(). is used.', self.c_unchecked_name)
2128 _h(' * Otherwise, it stores the error if any.')
2130 _h(' * The returned value must be freed by the caller using free().')
2134 _hc('/*****************************************************************************')
2136 _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2138 _hc(' ** @param xcb_connection_t%s *c', spacing1)
2139 _hc(' ** @param %s cookie', self.c_cookie_type)
2140 _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2141 _hc(' ** @returns %s *', self.c_reply_type)
2143 _hc(' *****************************************************************************/')
2145 _hc('%s *', self.c_reply_type)
2146 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2147 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2148 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2149 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2152 if len(unserialize_fields)>0:
2153 # certain variable size fields need to be unserialized explicitly
2154 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2155 self.c_reply_type, self.c_reply_type)
2157 for field in unserialize_fields:
2158 if field.type.is_list:
2159 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2160 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2161 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2163 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2164 # call _unserialize(), using the reply as source and target buffer
2165 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2166 for field in unserialize_fields:
2167 if field.type.is_list:
2168 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2169 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2170 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2171 field.c_field_name, field.c_field_name)
2172 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2174 # return the transformed reply
2175 _c(' return reply;')
2178 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2182 def _c_opcode(name, opcode):
2184 Declares the opcode define for requests, events, and errors.
2188 _h('/** Opcode for %s. */', _n(name))
2189 _h('#define %s %s', _n(name).upper(), opcode)
2191 def _c_cookie(self, name):
2193 Declares the cookie type for a non-void request.
2198 _h(' * @brief %s', self.c_cookie_type)
2200 _h('typedef struct %s {', self.c_cookie_type)
2201 _h(' unsigned int sequence; /**< */')
2202 _h('} %s;', self.c_cookie_type)
2204 def c_request(self, name):
2206 Exported function that handles request declarations.
2208 _c_type_setup(self, name, ('request',))
2211 # Cookie type declaration
2212 _c_cookie(self, name)
2215 _c_opcode(name, self.opcode)
2217 # Request structure declaration
2221 _c_type_setup(self.reply, name, ('reply',))
2222 # Reply structure definition
2223 _c_complex(self.reply)
2224 # Request prototypes
2225 _c_request_helper(self, name, self.c_cookie_type, False, True)
2226 _c_request_helper(self, name, self.c_cookie_type, False, False)
2228 _c_request_helper(self, name, self.c_cookie_type, False, True, True)
2229 _c_request_helper(self, name, self.c_cookie_type, False, False, True)
2231 _c_accessors(self.reply, name + ('reply',), name)
2232 _c_reply(self, name)
2234 # Request prototypes
2235 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2236 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2238 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2239 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2242 def c_event(self, name):
2244 Exported function that handles event declarations.
2246 _c_type_setup(self, name, ('event',))
2249 _c_opcode(name, self.opcodes[name])
2251 if self.name == name:
2252 # Structure definition
2257 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2259 def c_error(self, name):
2261 Exported function that handles error declarations.
2263 _c_type_setup(self, name, ('error',))
2266 _c_opcode(name, self.opcodes[name])
2268 if self.name == name:
2269 # Structure definition
2274 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2277 # Main routine starts here
2279 # Must create an "output" dictionary before any xcbgen imports.
2280 output = {'open' : c_open,
2282 'simple' : c_simple,
2284 'struct' : c_struct,
2286 'request' : c_request,
2291 # Boilerplate below this point
2293 # Check for the argument that specifies path to the xcbgen python package.
2295 opts, args = getopt.getopt(sys.argv[1:], 'p:')
2296 except getopt.GetoptError as err:
2298 print('Usage: c_client.py [-p path] file.xml')
2301 for (opt, arg) in opts:
2303 sys.path.insert(1, arg)
2305 # Import the module class
2307 from xcbgen.state import Module
2310 Failed to load the xcbgen Python package!
2311 Make sure that xcb/proto installed it on your Python path.
2312 If not, you will need to create a .pth file or define $PYTHONPATH
2314 Refer to the README file in xcb/proto for more info.
2318 # Parse the xml header
2319 module = Module(args[0], output)
2321 # Build type-registry and resolve type dependencies