2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
13 # Jump to the bottom of this file for the main routine
15 # Some hacks to make the API more readable, and to keep backwards compability
16 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
17 _cname_special_cases = {'DECnet':'decnet'}
19 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
21 _cplusplus_annoyances = {'class' : '_class',
24 _c_keywords = {'default' : '_default'}
32 # global variable to keep track of serializers and
33 # switch data types due to weird dependencies
34 finished_serializers = []
38 # keeps enum objects so that we can refer to them when generating manpages.
45 Writes the given line to the header file.
47 _hlines[_hlevel].append(fmt % args)
51 Writes the given line to the source file.
53 _clines[_clevel].append(fmt % args)
57 Writes the given line to both the header and source files.
62 def _c_wr_stringlist(indent, strlist):
64 Writes the given list of strings to the source file.
65 Each line is prepended by the indent string
68 _c("%s%s", indent, str)
71 # For pre-code generated by expression generation
72 # (for example, the for-loop of a sumof)
73 # This has to account for recursiveness of the expression
74 # generation, i.e., there may be pre-code for pre-code.
75 # Therefore this is implemented as a stack of lists of lines.
82 self.redirect_code = None
83 self.redirect_tempvars = None
85 self.indent_stack = []
89 # start and end of pre-code blocks
91 self.nestingLevel += 1
94 self.nestingLevel -= 1
95 if (self.nestingLevel == 0):
96 # lowest pre-code level is finished -> output to source
97 if self.redirect_tempvars == None:
98 _c_wr_stringlist('', self.tempvars)
101 self.redirect_tempvars.extend(self.tempvars)
103 if self.redirect_code == None:
104 _c_wr_stringlist('', self.codelines)
107 self.redirect_code.extend(self.codelines)
111 def output_tempvars(self):
112 if self.redirect_code == None:
113 _c_wr_stringlist('', self.tempvars)
117 def code(self, fmt, *args):
118 self.codelines.append(self.indent_str + fmt % args)
120 def tempvar(self, fmt, *args):
121 self.tempvars.append(' ' + (fmt % args))
123 # get a unique name for a temporary variable
124 def get_tempvarname(self):
126 return "xcb_pre_tmp_%d" % self.tempvarNum
130 def push_indent(self, indentstr):
131 self.indent_stack.append(self.indent_str)
132 self.indent_str = indentstr
134 def push_addindent(self, indent_add_str):
135 self.push_indent(self.indent_str + indent_add_str)
138 self.push_addindent(' ')
140 def pop_indent(self):
141 self.indent_str = self.indent_stack.pop()
143 # redirection to lists
144 def redirect_start(self, redirectCode, redirectTempvars = None):
145 self.redirect_code = redirectCode
146 self.redirect_tempvars = redirectTempvars
147 if redirectTempvars != None:
150 def redirect_end(self):
151 self.redirect_code = None
152 self.redirect_tempvars = None
154 # global PreCode handler
158 # XXX See if this level thing is really necessary.
159 def _h_setlevel(idx):
161 Changes the array that header lines are written to.
162 Supports writing different sections of the header file.
165 while len(_hlines) <= idx:
169 def _c_setlevel(idx):
171 Changes the array that source lines are written to.
172 Supports writing to different sections of the source file.
175 while len(_clines) <= idx:
181 Does C-name conversion on a single string fragment.
182 Uses a regexp with some hard-coded special cases.
184 if str in _cname_special_cases:
185 return _cname_special_cases[str]
187 split = _cname_re.finditer(str)
188 name_parts = [match.group(0) for match in split]
189 return '_'.join(name_parts)
193 Checks for certain C++ reserved words and fixes them.
195 if str in _cplusplus_annoyances:
196 return _cplusplus_annoyances[str]
197 elif str in _c_keywords:
198 return _c_keywords[str]
204 Does C-name conversion on an extension name.
205 Has some additional special cases on top of _n_item.
207 if str in _extension_special_cases:
208 return _n_item(str).lower()
214 Does C-name conversion on a tuple of strings.
215 Different behavior depending on length of tuple, extension/not extension, etc.
216 Basically C-name converts the individual pieces, then joins with underscores.
221 parts = [list[0], _n_item(list[1])]
223 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
225 parts = [list[0]] + [_n_item(i) for i in list[1:]]
226 return '_'.join(parts).lower()
230 Does C-name conversion on a tuple of strings representing a type.
231 Same as _n but adds a "_t" on the end.
236 parts = [list[0], _n_item(list[1]), 't']
238 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
240 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
241 return '_'.join(parts).lower()
246 Exported function that handles module open.
247 Opens the files and writes out the auto-generated comment, header file includes, etc.
251 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
253 # Build the type-name collision avoidance table used by c_enum
254 build_collision_table()
260 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
261 _hc(' * Edit at your peril.')
266 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
267 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
271 _h('#ifndef __%s_H', _ns.header.upper())
272 _h('#define __%s_H', _ns.header.upper())
274 _h('#include "xcb.h"')
276 _c('#ifdef HAVE_CONFIG_H')
277 _c('#include "config.h"')
279 _c('#include <stdlib.h>')
280 _c('#include <string.h>')
281 _c('#include <assert.h>')
282 _c('#include <stddef.h> /* for offsetof() */')
283 _c('#include "xcbext.h"')
284 _c('#include "%s.h"', _ns.header)
287 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
290 for (n, h) in self.direct_imports:
291 _hc('#include "%s.h"', h)
294 _h('#ifdef __cplusplus')
300 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
301 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
303 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
306 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
310 Exported function that handles module close.
311 Writes out all the stored content lines, then closes the files.
318 _h('#ifdef __cplusplus')
330 hfile = open('%s.h' % _ns.header, 'w')
338 cfile = open('%s.c' % _ns.header, 'w')
345 def build_collision_table():
349 for v in module.types.values():
351 namecount[name] = (namecount.get(name) or 0) + 1
353 def c_enum(self, name):
355 Exported function that handles enum declarations.
361 if namecount[tname] > 1:
362 tname = _t(name + ('enum',))
366 _h('typedef enum %s {', tname)
368 count = len(self.values)
370 for (enam, eval) in self.values:
372 equals = ' = ' if eval != '' else ''
373 comma = ',' if count > 0 else ''
375 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
376 doc = '\n/**< %s */\n' % self.doc.fields[enam]
377 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
381 def _c_type_setup(self, name, postfix):
383 Sets up all the C-related state by adding additional data fields to
384 all Field and Type objects. Here is where we figure out most of our
385 variable and function names.
387 Recurses into child fields and list member types.
389 # Do all the various names in advance
390 self.c_type = _t(name + postfix)
391 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
393 self.c_iterator_type = _t(name + ('iterator',))
394 self.c_next_name = _n(name + ('next',))
395 self.c_end_name = _n(name + ('end',))
397 self.c_request_name = _n(name)
398 self.c_checked_name = _n(name + ('checked',))
399 self.c_unchecked_name = _n(name + ('unchecked',))
400 self.c_reply_name = _n(name + ('reply',))
401 self.c_reply_type = _t(name + ('reply',))
402 self.c_cookie_type = _t(name + ('cookie',))
403 self.c_reply_fds_name = _n(name + ('reply_fds',))
405 self.c_need_aux = False
406 self.c_need_serialize = False
407 self.c_need_sizeof = False
409 self.c_aux_name = _n(name + ('aux',))
410 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
411 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
412 self.c_serialize_name = _n(name + ('serialize',))
413 self.c_unserialize_name = _n(name + ('unserialize',))
414 self.c_unpack_name = _n(name + ('unpack',))
415 self.c_sizeof_name = _n(name + ('sizeof',))
417 # special case: structs where variable size fields are followed by fixed size fields
418 self.c_var_followed_by_fixed_fields = False
421 self.c_need_serialize = True
422 self.c_container = 'struct'
423 for bitcase in self.bitcases:
424 bitcase.c_field_name = _cpp(bitcase.field_name)
425 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
426 _c_type_setup(bitcase.type, bitcase_name, ())
428 elif self.is_container:
430 self.c_container = 'union' if self.is_union else 'struct'
431 prev_varsized_field = None
432 prev_varsized_offset = 0
433 first_field_after_varsized = None
435 for field in self.fields:
436 field.c_field_type = _t(field.field_type)
437 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
438 field.c_field_name = _cpp(field.field_name)
439 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
440 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
442 # correct the c_pointer field for variable size non-list types
443 if not field.type.fixed_size() and field.c_pointer == ' ':
444 field.c_pointer = '*'
445 if field.type.is_list and not field.type.member.fixed_size():
446 field.c_pointer = '*'
448 if field.type.is_switch:
449 field.c_pointer = '*'
450 field.c_field_const_type = 'const ' + field.c_field_type
451 self.c_need_aux = True
453 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
454 self.c_need_sizeof = True
456 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
457 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
458 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
459 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
460 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
462 field.prev_varsized_field = prev_varsized_field
463 field.prev_varsized_offset = prev_varsized_offset
465 if prev_varsized_offset == 0:
466 first_field_after_varsized = field
467 field.first_field_after_varsized = first_field_after_varsized
469 if field.type.fixed_size():
470 prev_varsized_offset += field.type.size
471 # special case: intermixed fixed and variable size fields
472 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
473 if not self.is_union:
474 self.c_need_serialize = True
475 self.c_var_followed_by_fixed_fields = True
477 self.last_varsized_field = field
478 prev_varsized_field = field
479 prev_varsized_offset = 0
481 if self.c_var_followed_by_fixed_fields:
482 if field.type.fixed_size():
483 field.prev_varsized_field = None
485 # recurse into this field
486 # this has to be done here, i.e., after the field has been set up
487 # Otherwise the function _c_helper_fieldaccess_expr
488 # will produce garbage or crash
489 _c_type_setup(field.type, field.field_type, ())
490 if field.type.is_list:
491 _c_type_setup(field.type.member, field.field_type, ())
492 if (field.type.nmemb is None):
493 self.c_need_sizeof = True
496 if self.c_need_serialize:
497 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
498 self.c_need_sizeof = True
500 # as switch does never appear at toplevel,
501 # continue here with type construction
503 if self.c_type not in finished_switch:
504 finished_switch.append(self.c_type)
505 # special: switch C structs get pointer fields for variable-sized members
507 for bitcase in self.bitcases:
508 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
509 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
510 # no list with switch as element, so no call to
511 # _c_iterator(field.type, field_name) necessary
513 if not self.is_case_or_bitcase:
514 if self.c_need_serialize:
515 if self.c_serialize_name not in finished_serializers:
516 finished_serializers.append(self.c_serialize_name)
517 _c_serialize('serialize', self)
519 # _unpack() and _unserialize() are only needed for special cases:
521 # special cases -> unserialize
522 if self.is_switch or self.c_var_followed_by_fixed_fields:
523 _c_serialize('unserialize', self)
525 if self.c_need_sizeof:
526 if self.c_sizeof_name not in finished_sizeof:
527 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
528 finished_sizeof.append(self.c_sizeof_name)
529 _c_serialize('sizeof', self)
532 # Functions for querying field properties
533 def _c_field_needs_list_accessor(field):
534 return field.type.is_list and not field.type.fixed_size()
536 def _c_field_needs_field_accessor(field):
537 if field.type.is_list:
541 field.prev_varsized_field is not None
542 or not field.type.fixed_size()
545 def _c_field_needs_accessor(field):
547 _c_field_needs_list_accessor(field)
549 _c_field_needs_field_accessor(field)
552 def _c_field_is_member_of_case_or_bitcase(field):
553 if field.parent is None:
555 elif field.parent.is_case_or_bitcase:
560 # end of Functions for querying field properties
562 def _c_helper_fieldaccess_expr(prefix, field=None):
564 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
565 representing a valid field-access-expression in C (based on the context)
566 if field is not None, append access to the field as well.
568 "separator" is one of the C-operators "." or "->".
570 A field access expression can consist of the following components:
571 * struct/union member access from a value with the "."-operator
572 * struct/union member access from a pointer with "->"-operator
573 * function-call of an accessor function:
574 This is used when a xcb-field is not contained in a struct.
575 This can, e.g., happen for fields after var-sized fields, etc.
579 for name, sep, obj in prefix:
580 prefix_str += last_sep + name
583 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
584 (obj.is_switch and len(obj.parents)>1)):
589 # add separator for access to a yet unknown field
590 prefix_str += last_sep
592 if _c_field_needs_accessor(field):
593 if _c_field_is_member_of_case_or_bitcase(field):
594 # case members are available in the deserialized struct,
595 # so there is no need to use the accessor function
596 # (also, their accessor function needs a different arglist
597 # so this would require special treatment here)
598 # Therefore: Access as struct member
599 prefix_str += last_sep + _cpp(field.field_name)
601 # Access with the accessor function
602 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
604 # Access as struct member
605 prefix_str += last_sep + _cpp(field.field_name)
610 def _c_helper_field_mapping(complex_type, prefix, flat=False):
612 generate absolute names, based on prefix, for all fields starting from complex_type
613 if flat == True, nested complex types are not taken into account
616 if complex_type.is_switch:
617 for b in complex_type.bitcases:
619 switch_name, switch_sep, switch_type = prefix[-1]
620 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
622 bitcase_prefix = prefix
624 if (True==flat and not b.type.has_name) or False==flat:
625 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
627 for f in complex_type.fields:
628 fname = _c_helper_fieldaccess_expr(prefix, f)
629 if f.field_name in all_fields:
630 raise Exception("field name %s has been registered before" % f.field_name)
632 all_fields[f.field_name] = (fname, f)
633 if f.type.is_container and flat==False:
634 if f.type.is_case_or_bitcase and not f.type.has_name:
636 elif f.type.is_switch and len(f.type.parents)>1:
637 # nested switch gets another separator
638 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
640 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
641 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
646 def _c_helper_resolve_field_names (prefix):
648 get field names for all objects in the prefix array
652 # look for fields in the remaining containers
653 for idx, p in enumerate(prefix):
656 # sep can be preset in prefix, if not, make a sensible guess
657 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
658 # exception: 'toplevel' object (switch as well!) always have sep '->'
659 sep = '->' if idx<1 else sep
660 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
661 tmp_prefix.append((name, sep, obj))
662 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
665 # _c_helper_resolve_field_names
667 def get_expr_fields(self):
669 get the Fields referenced by switch or list expression
671 def get_expr_field_names(expr):
673 if expr.lenfield_name is not None:
674 return [expr.lenfield_name]
676 # constant value expr
680 return get_expr_field_names(expr.rhs)
681 elif expr.op == 'popcount':
682 return get_expr_field_names(expr.rhs)
683 elif expr.op == 'sumof':
684 # sumof expr references another list,
685 # we need that list's length field here
687 for f in expr.lenfield_parent.fields:
688 if f.field_name == expr.lenfield_name:
692 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
693 # referenced list + its length field
694 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
695 elif expr.op == 'enumref':
698 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
699 # get_expr_field_names()
701 # resolve the field names with the parent structure(s)
702 unresolved_fields_names = get_expr_field_names(self.expr)
704 # construct prefix from self
705 prefix = [('', '', p) for p in self.parents]
706 if self.is_container:
707 prefix.append(('', '', self))
709 all_fields = _c_helper_resolve_field_names (prefix)
710 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
711 if len(unresolved_fields_names) != len(resolved_fields_names):
712 raise Exception("could not resolve all fields for %s" % self.name)
714 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
715 return resolved_fields
718 def resolve_expr_fields(complex_obj):
720 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
721 these are normally fields that need to be given as function parameters
727 for field in complex_obj.fields:
728 all_fields.append(field)
729 if field.type.is_switch or field.type.is_list:
730 expr_fields += get_expr_fields(field.type)
731 if field.type.is_container:
732 expr_fields += resolve_expr_fields(field.type)
734 # try to resolve expr fields
735 for e in expr_fields:
736 if e not in all_fields and e not in unresolved:
739 # resolve_expr_fields()
741 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
743 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
744 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
745 expression. This function tries to resolve all fields within a structure, and returns the
746 unresolved fields as the list of external parameters.
748 def add_param(params, param):
749 if param not in params:
752 # collect all fields into param_fields
756 for field in self.fields:
758 # the field should appear as a parameter in the function call
759 param_fields.append(field)
760 if field.wire and not field.auto:
761 if field.type.fixed_size() and not self.is_switch:
762 # field in the xcb_out structure
763 wire_fields.append(field)
764 # fields like 'pad0' are skipped!
766 # in case of switch, parameters always contain any fields referenced in the switch expr
767 # we do not need any variable size fields here, as the switch data type contains both
768 # fixed and variable size fields
770 param_fields = get_expr_fields(self)
772 # _serialize()/_unserialize()/_unpack() function parameters
773 # note: don't use set() for params, it is unsorted
776 # 1. the parameter for the void * buffer
777 if 'serialize' == context:
778 params.append(('void', '**', buffer_var))
779 elif context in ('unserialize', 'unpack', 'sizeof'):
780 params.append(('const void', '*', buffer_var))
782 # 2. any expr fields that cannot be resolved within self and descendants
783 unresolved_fields = resolve_expr_fields(self)
784 for f in unresolved_fields:
785 add_param(params, (f.c_field_type, '', f.c_field_name))
787 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
788 # that do not appear in the data type struct
789 for p in param_fields:
791 typespec = p.c_field_const_type
792 pointerspec = p.c_pointer
793 add_param(params, (typespec, pointerspec, p.c_field_name))
795 if p.visible and not p.wire and not p.auto:
796 typespec = p.c_field_type
798 add_param(params, (typespec, pointerspec, p.c_field_name))
801 if 'serialize' == context:
802 add_param(params, ('const %s' % self.c_type, '*', aux_var))
803 elif 'unserialize' == context:
804 add_param(params, ('%s' % self.c_type, '**', aux_var))
805 elif 'unpack' == context:
806 add_param(params, ('%s' % self.c_type, '*', aux_var))
808 # 5. switch contains all variable size fields as struct members
809 # for other data types though, these have to be supplied separately
810 # this is important for the special case of intermixed fixed and
811 # variable size fields
812 if not self.is_switch and 'serialize' == context:
813 for p in param_fields:
814 if not p.type.fixed_size():
815 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
817 return (param_fields, wire_fields, params)
818 # get_serialize_params()
820 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
821 code_lines.append('%s /* insert padding */' % space)
822 if is_case_or_bitcase:
824 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
828 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
829 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
830 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
833 code_lines.append('%s if (0 != xcb_pad) {' % space)
835 if 'serialize' == context:
836 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
837 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
838 code_lines.append('%s xcb_parts_idx++;' % space)
839 elif context in ('unserialize', 'unpack', 'sizeof'):
840 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
842 code_lines.append('%s xcb_pad = 0;' % space)
843 code_lines.append('%s }' % space)
845 code_lines.append('%s xcb_block_len = 0;' % space)
846 if is_case_or_bitcase:
847 code_lines.append('%s xcb_padding_offset = 0;' % space)
849 # keep tracking of xcb_parts entries for serialize
851 # _c_serialize_helper_insert_padding()
853 def _c_serialize_helper_switch(context, self, complex_name,
854 code_lines, temp_vars,
857 switch_expr = _c_accessor_get_expr(self.expr, None)
859 for b in self.bitcases:
860 len_expr = len(b.type.expr)
862 compare_operator = '&'
864 compare_operator = '=='
866 compare_operator = '&'
868 for n, expr in enumerate(b.type.expr):
869 bitcase_expr = _c_accessor_get_expr(expr, None)
870 # only one <enumref> in the <bitcase>
873 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
874 # multiple <enumref> in the <bitcase>
877 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
878 elif len_expr == (n + 1): # last
880 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
881 else: # between first and last
883 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
887 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
889 count += _c_serialize_helper_fields(context, b.type,
890 code_lines, temp_vars,
893 is_case_or_bitcase = True)
894 code_lines.append(' }')
896 # if 'serialize' == context:
897 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
898 # elif context in ('unserialize', 'unpack', 'sizeof'):
900 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
901 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
904 # _c_serialize_helper_switch
906 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
908 handle switch by calling _serialize() or _unpack(), depending on context
910 # switch is handled by this function as a special case
911 param_fields, wire_fields, params = get_serialize_params(context, self)
912 field_mapping = _c_helper_field_mapping(self, prefix)
913 prefix_str = _c_helper_fieldaccess_expr(prefix)
915 # find the parameters that need to be passed to _serialize()/_unpack():
916 # all switch expr fields must be given as parameters
917 args = get_expr_fields(field.type)
918 # length fields for variable size types in switch, normally only some of need
919 # need to be passed as parameters
920 switch_len_fields = resolve_expr_fields(field.type)
922 # a switch field at this point _must_ be a bitcase field
923 # we require that bitcases are "self-contiguous"
924 bitcase_unresolved = resolve_expr_fields(self)
925 if len(bitcase_unresolved) != 0:
926 raise Exception('unresolved fields within bitcase is not supported at this point')
928 # get the C names for the parameters
930 for a in switch_len_fields:
931 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
933 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
935 # call _serialize()/_unpack() to determine the actual size
936 if 'serialize' == context:
937 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
938 c_field_names, prefix_str, field.c_field_name)
939 elif context in ('unserialize', 'unpack'):
940 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
941 c_field_names, prefix_str, field.c_field_name)
942 elif 'sizeof' == context:
943 # remove trailing ", " from c_field_names because it will be used at end of arglist
944 my_c_field_names = c_field_names[:-2]
945 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
948 # _c_serialize_helper_switch_field()
950 def _c_serialize_helper_list_field(context, self, field,
951 code_lines, temp_vars,
954 helper function to cope with lists of variable length
956 expr = field.type.expr
957 prefix_str = _c_helper_fieldaccess_expr(prefix)
958 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
959 param_names = [p[2] for p in params]
961 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
962 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
963 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
967 field_mapping[r] = (r, None)
969 if len(unresolved)>0:
971 if len(tmp_prefix)==0:
972 raise Exception("found an empty prefix while resolving expr field names for list %s",
975 field_mapping.update(_c_helper_resolve_field_names(prefix))
976 resolved += list(filter(lambda x: x in field_mapping, unresolved))
977 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
978 if len(unresolved)>0:
979 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
981 list_length = _c_accessor_get_expr(expr, field_mapping)
983 # default: list with fixed size elements
984 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
986 # list with variable-sized elements
987 if not field.type.member.fixed_size():
989 if context in ('unserialize', 'sizeof', 'unpack'):
990 int_i = ' unsigned int i;'
991 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
992 if int_i not in temp_vars:
993 temp_vars.append(int_i)
994 if xcb_tmp_len not in temp_vars:
995 temp_vars.append(xcb_tmp_len)
996 # loop over all list elements and call sizeof repeatedly
997 # this should be a bit faster than using the iterators
998 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
999 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
1000 (space, field.type.c_sizeof_name))
1001 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
1002 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
1003 code_lines.append("%s }" % space)
1005 elif 'serialize' == context:
1006 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
1007 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
1008 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
1009 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
1010 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
1011 code_lines.append('%s }' % space)
1012 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1015 # _c_serialize_helper_list_field()
1017 def _c_serialize_helper_fields_fixed_size(context, self, field,
1018 code_lines, temp_vars,
1020 # keep the C code a bit more readable by giving the field name
1021 if not self.is_case_or_bitcase:
1022 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1024 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1025 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1026 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1028 abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1029 # default for simple cases: call sizeof()
1030 length = "sizeof(%s)" % field.c_field_type
1032 if context in ('unserialize', 'unpack', 'sizeof'):
1033 # default: simple cast
1034 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1036 # padding - we could probably just ignore it
1037 if field.type.is_pad and field.type.nmemb > 1:
1039 for i in range(field.type.nmemb):
1040 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1041 (space, abs_field_name, i, field.c_field_type))
1042 # total padding = sizeof(pad0) * nmemb
1043 length += " * %d" % field.type.nmemb
1045 elif field.type.is_list:
1046 # list with fixed number of elements
1047 # length of array = sizeof(arrayElementType) * nmemb
1048 length += " * %d" % field.type.nmemb
1049 # use memcpy because C cannot assign whole arrays with operator=
1050 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1053 elif 'serialize' == context:
1054 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1056 if field.type.is_expr:
1057 # need to register a temporary variable for the expression in case we know its type
1058 if field.type.c_type is None:
1059 raise Exception("type for field '%s' (expression '%s') unkown" %
1060 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1062 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1063 _c_accessor_get_expr(field.type.expr, prefix)))
1064 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1066 elif field.type.is_pad:
1067 if field.type.nmemb == 1:
1068 value += "&xcb_pad;"
1070 # we could also set it to 0, see definition of xcb_send_request()
1071 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1072 length += "*%d" % field.type.nmemb
1075 # non-list type with fixed size
1076 if field.type.nmemb == 1:
1077 value += "&%s;" % (abs_field_name)
1079 # list with nmemb (fixed size) elements
1081 value += '%s;' % (abs_field_name)
1082 length = '%d' % field.type.nmemb
1084 return (value, length)
1085 # _c_serialize_helper_fields_fixed_size()
1087 def _c_serialize_helper_fields_variable_size(context, self, field,
1088 code_lines, temp_vars,
1090 prefix_str = _c_helper_fieldaccess_expr(prefix)
1092 if context in ('unserialize', 'unpack', 'sizeof'):
1094 var_field_name = 'xcb_tmp'
1096 # special case: intermixed fixed and variable size fields
1097 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1098 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1099 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1100 # special case: switch
1101 if 'unpack' == context:
1102 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1104 elif 'serialize' == context:
1105 # variable size fields appear as parameters to _serialize() if the
1106 # 'toplevel' container is not a switch
1107 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1108 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1109 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1113 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1115 if field.type.is_list:
1117 # in any context, list is already a pointer, so the default assignment is ok
1118 code_lines.append("%s%s" % (space, value))
1120 length = _c_serialize_helper_list_field(context, self, field,
1121 code_lines, temp_vars,
1124 elif field.type.is_switch:
1126 if context == 'serialize':
1127 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1128 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1129 length = _c_serialize_helper_switch_field(context, self, field,
1130 'xcb_parts[xcb_parts_idx].iov_base',
1134 # in all remaining special cases - call _sizeof()
1135 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1137 return (value, length)
1138 # _c_serialize_helper_fields_variable_size
1140 def _c_serialize_helper_fields(context, self,
1141 code_lines, temp_vars,
1142 space, prefix, is_case_or_bitcase):
1144 need_padding = False
1145 prev_field_was_variable = False
1147 _c_pre.push_indent(space + ' ')
1149 for field in self.fields:
1150 if not field.visible:
1151 if not ((field.wire and not field.auto) or 'unserialize' == context):
1154 # switch/bitcase: fixed size fields must be considered explicitly
1155 if field.type.fixed_size():
1156 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1157 if prev_field_was_variable and need_padding:
1159 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1160 # self.c_var_followed_by_fixed_fields)
1161 prev_field_was_variable = False
1163 # prefix for fixed size fields
1164 fixed_prefix = prefix
1166 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1167 code_lines, temp_vars,
1168 space, fixed_prefix)
1172 # fields with variable size
1174 if field.type.is_pad:
1175 # Variable length pad is <pad align= />
1176 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1177 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1178 self.c_var_followed_by_fixed_fields,
1182 # switch/bitcase: always calculate padding before and after variable sized fields
1183 if need_padding or is_case_or_bitcase:
1184 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1185 self.c_var_followed_by_fixed_fields,
1188 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1189 code_lines, temp_vars,
1191 prev_field_was_variable = True
1193 # save (un)serialization C code
1195 code_lines.append('%s%s' % (space, value))
1197 if field.type.fixed_size():
1198 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1199 # keep track of (un)serialized object's size
1200 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1201 if context in ('unserialize', 'unpack', 'sizeof'):
1202 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1204 # variable size objects or bitcase:
1205 # value & length might have been inserted earlier for special cases
1207 # special case: intermixed fixed and variable size fields
1208 if (not field.type.fixed_size() and
1209 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1210 temp_vars.append(' int %s_len;' % field.c_field_name)
1211 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1212 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1213 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1215 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1216 # increase pointer into the byte stream accordingly
1217 if context in ('unserialize', 'sizeof', 'unpack'):
1218 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1220 if 'serialize' == context:
1222 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1223 code_lines.append('%s xcb_parts_idx++;' % space)
1227 '%s xcb_align_to = ALIGNOF(%s);'
1230 if field.c_field_type == 'void' or field.type.is_switch
1231 else field.c_field_type))
1234 if self.c_var_followed_by_fixed_fields:
1235 need_padding = False
1240 # _c_serialize_helper_fields()
1242 def _c_serialize_helper(context, complex_type,
1243 code_lines, temp_vars,
1244 space='', prefix=[]):
1245 # count tracks the number of fields to serialize
1248 if hasattr(complex_type, 'type'):
1249 self = complex_type.type
1250 complex_name = complex_type.name
1253 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1254 complex_name = 'xcb_out'
1256 complex_name = '_aux'
1258 # special case: switch is serialized by evaluating each bitcase separately
1260 count += _c_serialize_helper_switch(context, self, complex_name,
1261 code_lines, temp_vars,
1264 # all other data types can be evaluated one field a time
1266 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1267 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1268 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1269 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1270 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1271 code_lines.append('%s xcb_block_len = 0;' % space)
1273 count += _c_serialize_helper_fields(context, self,
1274 code_lines, temp_vars,
1275 space, prefix, False)
1277 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1280 # _c_serialize_helper()
1282 def _c_serialize(context, self):
1284 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1285 for the ComplexType variable self
1291 # _serialize() returns the buffer size
1294 if self.is_switch and 'unserialize' == context:
1297 cases = { 'serialize' : self.c_serialize_name,
1298 'unserialize' : self.c_unserialize_name,
1299 'unpack' : self.c_unpack_name,
1300 'sizeof' : self.c_sizeof_name }
1301 func_name = cases[context]
1303 param_fields, wire_fields, params = get_serialize_params(context, self)
1304 variable_size_fields = 0
1305 # maximum space required for type definition of function arguments
1308 # determine N(variable_fields)
1309 for field in param_fields:
1310 # if self.is_switch, treat all fields as if they are variable sized
1311 if not field.type.fixed_size() or self.is_switch:
1312 variable_size_fields += 1
1313 # determine maxtypelen
1315 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1318 indent = ' '*(len(func_name)+2)
1321 typespec, pointerspec, field_name = p
1322 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1323 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1324 # insert function name
1325 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1326 param_str = list(map(lambda x: "%s," % x, param_str))
1327 for s in param_str[:-1]:
1329 _h("%s);" % param_str[-1].rstrip(','))
1330 _c("%s)" % param_str[-1].rstrip(','))
1337 _c_pre.redirect_start(code_lines, temp_vars)
1339 if 'serialize' == context:
1340 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1341 _c(' %s *xcb_out = *_buffer;', self.c_type)
1342 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1343 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1344 _c(' unsigned int xcb_align_to = 0;')
1346 _c(' char *xcb_out = *_buffer;')
1347 _c(' unsigned int xcb_buffer_len = 0;')
1348 _c(' unsigned int xcb_align_to = 0;')
1350 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1351 prefix = [('_aux', '->', self)]
1354 elif context in ('unserialize', 'unpack'):
1355 _c(' char *xcb_tmp = (char *)_buffer;')
1356 if not self.is_switch:
1357 if not self.c_var_followed_by_fixed_fields:
1358 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1359 prefix = [('_aux', '->', self)]
1361 _c(' %s xcb_out;', self.c_type)
1362 prefix = [('xcb_out', '.', self)]
1364 aux_var = '_aux' # default for unpack: single pointer
1365 # note: unserialize not generated for switch
1366 if 'unserialize' == context:
1367 aux_var = '(*_aux)' # unserialize: double pointer (!)
1368 prefix = [(aux_var, '->', self)]
1370 _c(' unsigned int xcb_buffer_len = 0;')
1371 _c(' unsigned int xcb_block_len = 0;')
1372 _c(' unsigned int xcb_pad = 0;')
1373 _c(' unsigned int xcb_align_to = 0;')
1375 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1377 elif 'sizeof' == context:
1378 param_names = [p[2] for p in params]
1380 # switch: call _unpack()
1381 _c(' %s _aux;', self.c_type)
1382 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1384 _c_pre.redirect_end()
1386 elif self.c_var_followed_by_fixed_fields:
1387 # special case: call _unserialize()
1388 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1390 _c_pre.redirect_end()
1393 _c(' char *xcb_tmp = (char *)_buffer;')
1394 prefix = [('_aux', '->', self)]
1396 _c(' unsigned int xcb_padding_offset = 0;')
1398 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1399 # update variable size fields (only important for context=='serialize'
1400 variable_size_fields = count
1401 if 'serialize' == context:
1402 temp_vars.append(' unsigned int xcb_pad = 0;')
1403 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1404 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1405 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1406 temp_vars.append(' unsigned int xcb_block_len = 0;')
1407 temp_vars.append(' unsigned int i;')
1408 temp_vars.append(' char *xcb_tmp;')
1409 elif 'sizeof' == context:
1410 # neither switch nor intermixed fixed and variable size fields:
1411 # evaluate parameters directly
1412 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1414 # look if we have to declare an '_aux' variable at all
1415 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1416 if not self.c_var_followed_by_fixed_fields:
1417 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1419 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1421 _c(' unsigned int xcb_buffer_len = 0;')
1422 _c(' unsigned int xcb_block_len = 0;')
1423 _c(' unsigned int xcb_pad = 0;')
1424 _c(' unsigned int xcb_align_to = 0;')
1426 _c_pre.redirect_end()
1432 for l in code_lines:
1435 # variable sized fields have been collected, now
1436 # allocate memory and copy everything into a continuous memory area
1437 # note: this is not necessary in case of unpack
1438 if context in ('serialize', 'unserialize'):
1439 # unserialize: check for sizeof-only invocation
1440 if 'unserialize' == context:
1442 _c(' if (NULL == _aux)')
1443 _c(' return xcb_buffer_len;')
1446 _c(' if (NULL == %s) {', aux_ptr)
1447 _c(' /* allocate memory */')
1448 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1449 if 'serialize' == context:
1450 _c(' *_buffer = xcb_out;')
1454 # serialize: handle variable size fields in a loop
1455 if 'serialize' == context:
1456 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1457 if len(wire_fields)>0:
1458 _c(' *xcb_out = *_aux;')
1459 # copy variable size fields into the buffer
1460 if variable_size_fields > 0:
1462 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1463 _c(' xcb_tmp = (char*)++xcb_out;')
1464 _c(' xcb_tmp += xcb_out_pad;')
1466 _c(' xcb_tmp = xcb_out;')
1468 # variable sized fields
1469 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1470 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1471 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1472 _c(' if (0 != xcb_parts[i].iov_len)')
1473 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1476 # unserialize: assign variable size fields individually
1477 if 'unserialize' == context:
1478 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1479 param_fields.reverse()
1480 for field in param_fields:
1481 if not field.type.fixed_size():
1482 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1483 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1484 _c(' *%s = xcb_out;', aux_ptr)
1487 _c(' return xcb_buffer_len;')
1491 def _c_iterator_get_end(field, accum):
1493 Figures out what C code is needed to find the end of a variable-length structure field.
1494 For nested structures, recurses into its last variable-sized field.
1495 For lists, calls the end function
1497 if field.type.is_container:
1498 accum = field.c_accessor_name + '(' + accum + ')'
1499 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1500 if field.type.is_list:
1501 # XXX we can always use the first way
1502 if field.type.member.is_simple:
1503 return field.c_end_name + '(' + accum + ')'
1505 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1507 def _c_iterator(self, name):
1509 Declares the iterator structure and next/end functions for a given type.
1514 _h(' * @brief %s', self.c_iterator_type)
1516 _h('typedef struct %s {', self.c_iterator_type)
1517 _h(' %s *data; /**< */', self.c_type)
1518 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1519 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1520 _h('} %s;', self.c_iterator_type)
1526 _h(' * Get the next element of the iterator')
1527 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1529 _h(' * Get the next element in the iterator. The member rem is')
1530 _h(' * decreased by one. The member data points to the next')
1531 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1535 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1536 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1539 if not self.fixed_size():
1540 _c(' %s *R = i->data;', self.c_type)
1543 # FIXME - how to determine the size of a variable size union??
1544 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1546 if self.c_need_sizeof:
1547 _c(' xcb_generic_iterator_t child;')
1548 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1549 self.c_type, self.c_sizeof_name)
1550 _c(' i->index = (char *) child.data - (char *) i->data;')
1552 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1553 _c(' i->index = child.index;')
1555 _c(' i->data = (%s *) child.data;', self.c_type)
1560 _c(' i->index += sizeof(%s);', self.c_type)
1566 _h(' * Return the iterator pointing to the last element')
1567 _h(' * @param i An %s', self.c_iterator_type)
1568 _h(' * @return The iterator pointing to the last element')
1570 _h(' * Set the current element in the iterator to the last element.')
1571 _h(' * The member rem is set to 0. The member data points to the')
1572 _h(' * last element.')
1575 _hc('xcb_generic_iterator_t')
1576 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1577 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1579 _c(' xcb_generic_iterator_t ret;')
1581 if self.fixed_size():
1582 _c(' ret.data = i.data + i.rem;')
1583 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1586 _c(' while(i.rem > 0)')
1587 _c(' %s(&i);', self.c_next_name)
1588 _c(' ret.data = i.data;')
1589 _c(' ret.rem = i.rem;')
1590 _c(' ret.index = i.index;')
1595 def _c_accessor_get_length(expr, field_mapping=None):
1597 Figures out what C code is needed to get a length field.
1598 The field_mapping parameter can be used to change the absolute name of a length field.
1599 For fields that follow a variable-length field, use the accessor.
1600 Otherwise, just reference the structure field directly.
1603 lenfield_name = expr.lenfield_name
1604 if lenfield_name is not None:
1605 if field_mapping is not None:
1606 lenfield_name = field_mapping[lenfield_name][0]
1608 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1609 # special case: variable and fixed size fields are intermixed
1610 # if the lenfield is among the fixed size fields, there is no need
1611 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1612 return field_mapping(expr.lenfield_name)
1613 elif expr.lenfield_name is not None:
1614 return lenfield_name
1616 return str(expr.nmemb)
1618 def _c_accessor_get_expr(expr, field_mapping):
1620 Figures out what C code is needed to get the length of a list field.
1621 The field_mapping parameter can be used to change the absolute name of a length field.
1622 Recurses for math operations.
1623 Returns bitcount for value-mask fields.
1624 Otherwise, uses the value of the length field.
1626 lenexp = _c_accessor_get_length(expr, field_mapping)
1629 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1630 elif expr.op == 'popcount':
1631 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1632 elif expr.op == 'enumref':
1633 enum_name = expr.lenfield_type.name
1634 constant_name = expr.lenfield_name
1635 c_name = _n(enum_name + (constant_name,)).upper()
1637 elif expr.op == 'sumof':
1638 # locate the referenced list object
1639 list_obj = expr.lenfield_type
1641 for f in expr.lenfield_parent.fields:
1642 if f.field_name == expr.lenfield_name:
1647 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1648 list_name = field_mapping[field.c_field_name][0]
1649 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1650 # note: xcb_sumof() has only been defined for integers
1651 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1652 # create explicit code for computing the sum.
1653 # This works for all C-types which can be added to int64_t with +=
1655 lengthvar = _c_pre.get_tempvarname()
1656 loopvar = _c_pre.get_tempvarname()
1657 sumvar = _c_pre.get_tempvarname()
1658 listvar = _c_pre.get_tempvarname()
1659 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1660 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1661 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1663 "const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1664 _c_pre.code("/* sumof start */")
1665 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1666 _c_pre.code("%s = 0;", sumvar)
1667 _c_pre.code("%s = %s;", listvar, list_name)
1669 "for (%s = 0; %s < %s; %s++) {",
1670 loopvar, loopvar, lengthvar, loopvar)
1673 if expr.rhs == None:
1674 _c_pre.code("%s += *%s;", sumvar, listvar)
1676 # sumof has a nested expression which
1677 # has to be evaluated in the context of this list element
1679 # field mapping for the subexpression needs to include
1680 # the fields of the list-member type
1681 scoped_field_mapping = field_mapping.copy()
1682 scoped_field_mapping.update(
1683 _c_helper_field_mapping(
1685 [(listvar, '->', field.type.member)]))
1687 # cause pre-code of the subexpression be added right here
1689 # compute the subexpression
1690 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1691 # resume with our code
1693 # output the summation expression
1694 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1696 _c_pre.code("%s++;", listvar);
1699 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1702 # return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1703 elif expr.op != None:
1704 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1705 ' ' + expr.op + ' ' +
1706 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1708 return 'xcb_popcount(' + lenexp + ')'
1712 def type_pad_type(type):
1717 def _c_accessors_field(self, field):
1719 Declares the accessor functions for a non-list field that follows a variable-length field.
1721 c_type = self.c_type
1723 # special case: switch
1724 switch_obj = self if self.is_switch else None
1725 if self.is_case_or_bitcase:
1726 switch_obj = self.parents[-1]
1727 if switch_obj is not None:
1728 c_type = switch_obj.c_type
1730 if field.type.is_simple:
1732 _hc('%s', field.c_field_type)
1733 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1734 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1736 if field.prev_varsized_field is None:
1737 _c(' return (%s *) (R + 1);', field.c_field_type)
1739 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1740 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1741 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1745 if field.type.is_switch and switch_obj is None:
1746 return_type = 'void *'
1748 return_type = '%s *' % field.c_field_type
1751 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1752 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1754 if field.prev_varsized_field is None:
1755 _c(' return (%s) (R + 1);', return_type)
1756 # note: the special case 'variable fields followed by fixed size fields'
1757 # is not of any consequence here, since the ordering gets
1758 # 'corrected' in the reply function
1760 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1761 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1762 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1766 def _c_accessors_list(self, field):
1768 Declares the accessor functions for a list field.
1769 Declares a direct-accessor function only if the list members are fixed size.
1770 Declares length and get-iterator functions always.
1773 def get_align_pad(field):
1774 prev = field.prev_varsized_field
1775 prev_prev = field.prev_varsized_field.prev_varsized_field
1777 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1778 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1784 c_type = self.c_type
1786 # special case: switch
1787 # in case of switch, 2 params have to be supplied to certain accessor functions:
1788 # 1. the anchestor object (request or reply)
1789 # 2. the (anchestor) switch object
1790 # the reason is that switch is either a child of a request/reply or nested in another switch,
1791 # so whenever we need to access a length field, we might need to refer to some anchestor type
1792 switch_obj = self if self.is_switch else None
1793 if self.is_case_or_bitcase:
1794 switch_obj = self.parents[-1]
1795 if switch_obj is not None:
1796 c_type = switch_obj.c_type
1800 parents = self.parents if hasattr(self, 'parents') else [self]
1801 # 'R': parents[0] is always the 'toplevel' container type
1802 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1803 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1804 # auxiliary object for 'R' parameters
1807 if switch_obj is not None:
1808 # now look where the fields are defined that are needed to evaluate
1809 # the switch expr, and store the parent objects in accessor_params and
1810 # the fields in switch_fields
1812 # 'S': name for the 'toplevel' switch
1813 toplevel_switch = parents[1]
1814 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1815 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1817 # initialize prefix for everything "below" S
1818 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1819 prefix = [(prefix_str, '->', toplevel_switch)]
1821 # look for fields in the remaining containers
1822 for p in parents[2:] + [self]:
1823 # the separator between parent and child is always '.' here,
1824 # because of nested switch statements
1825 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1826 prefix.append((p.name[-1], '.', p))
1827 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1829 # auxiliary object for 'S' parameter
1834 if list.member.fixed_size():
1835 idx = 1 if switch_obj is not None else 0
1837 _hc('%s *', field.c_field_type)
1839 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1840 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1843 if switch_obj is not None:
1844 _c(' return %s;', fields[field.c_field_name][0])
1845 elif field.prev_varsized_field is None:
1846 _c(' return (%s *) (R + 1);', field.c_field_type)
1848 (prev_varsized_field, align_pad) = get_align_pad(field)
1850 if align_pad is None:
1851 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1852 type_pad_type(field.first_field_after_varsized.type.c_type))
1854 _c(' xcb_generic_iterator_t prev = %s;',
1855 _c_iterator_get_end(prev_varsized_field, 'R'))
1856 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1857 field.c_field_type, align_pad, field.prev_varsized_offset)
1862 if switch_obj is not None:
1863 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1864 spacing = ' '*(len(field.c_length_name)+2)
1865 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1866 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1868 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1869 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1871 length = _c_accessor_get_expr(field.type.expr, fields)
1872 _c(' return %s;', length)
1875 if field.type.member.is_simple:
1877 _hc('xcb_generic_iterator_t')
1878 if switch_obj is not None:
1879 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1880 spacing = ' '*(len(field.c_end_name)+2)
1881 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1882 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1884 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1885 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1887 _c(' xcb_generic_iterator_t i;')
1889 param = 'R' if switch_obj is None else 'S'
1890 if switch_obj is not None:
1891 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1892 _c_accessor_get_expr(field.type.expr, fields))
1893 elif field.prev_varsized_field == None:
1894 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1895 _c_accessor_get_expr(field.type.expr, fields))
1897 _c(' xcb_generic_iterator_t child = %s;',
1898 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1899 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1900 _c_accessor_get_expr(field.type.expr, fields))
1903 _c(' i.index = (char *) i.data - (char *) %s;', param)
1909 _hc('%s', field.c_iterator_type)
1910 if switch_obj is not None:
1911 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1912 spacing = ' '*(len(field.c_iterator_name)+2)
1913 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1914 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1916 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1917 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1919 _c(' %s i;', field.c_iterator_type)
1922 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1924 if switch_obj is not None:
1926 _c(' i.data = %s;', fields[field.c_field_name][0])
1927 _c(' i.rem = %s;', length_expr_str)
1928 elif field.prev_varsized_field == None:
1930 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1932 (prev_varsized_field, align_pad) = get_align_pad(field)
1934 if align_pad is None:
1935 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1936 type_pad_type(field.c_field_type))
1938 _c(' xcb_generic_iterator_t prev = %s;',
1939 _c_iterator_get_end(prev_varsized_field, 'R'))
1941 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1942 field.c_field_type, align_pad)
1944 if switch_obj is None:
1945 _c(' i.rem = %s;', length_expr_str)
1946 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1950 def _c_accessors(self, name, base):
1952 Declares the accessor functions for the fields of a structure.
1954 # no accessors for switch itself -
1955 # switch always needs to be unpacked explicitly
1956 # if self.is_switch:
1960 for field in self.fields:
1961 if not field.type.is_pad:
1962 if _c_field_needs_list_accessor(field):
1963 _c_accessors_list(self, field)
1964 elif _c_field_needs_field_accessor(field):
1965 _c_accessors_field(self, field)
1967 def c_simple(self, name):
1969 Exported function that handles cardinal type declarations.
1970 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1972 _c_type_setup(self, name, ())
1974 if (self.name != name):
1979 _h('typedef %s %s;', _t(self.name), my_name)
1982 _c_iterator(self, name)
1984 def _c_complex(self, force_packed = False):
1986 Helper function for handling all structure types.
1987 Called for all structs, requests, replies, events, errors.
1992 _h(' * @brief %s', self.c_type)
1994 _h('typedef %s %s {', self.c_container, self.c_type)
2000 for field in self.fields:
2001 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2002 varfield = field.c_field_name
2005 struct_fields.append(field)
2007 for field in struct_fields:
2008 length = len(field.c_field_type)
2009 # account for '*' pointer_spec
2010 if not field.type.fixed_size() and not self.is_union:
2012 maxtypelen = max(maxtypelen, length)
2014 def _c_complex_field(self, field, space=''):
2015 if (field.type.fixed_size() or self.is_union or
2016 # in case of switch with switch children, don't make the field a pointer
2017 # necessary for unserialize to work
2018 (self.is_switch and field.type.is_switch)):
2019 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2020 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2022 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2023 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2025 if not self.is_switch:
2026 for field in struct_fields:
2027 _c_complex_field(self, field)
2029 for b in self.bitcases:
2034 for field in b.type.fields:
2035 _c_complex_field(self, field, space)
2037 _h(' } %s;', b.c_field_name)
2039 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2041 def c_struct(self, name):
2043 Exported function that handles structure declarations.
2045 _c_type_setup(self, name, ())
2047 _c_accessors(self, name, name)
2048 _c_iterator(self, name)
2050 def c_union(self, name):
2052 Exported function that handles union declarations.
2054 _c_type_setup(self, name, ())
2056 _c_iterator(self, name)
2058 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2060 Declares a request function.
2063 # Four stunningly confusing possibilities here:
2066 # ------------------------------
2068 # 0 flag CHECKED flag Normal Mode
2069 # void_cookie req_cookie
2070 # ------------------------------
2071 # "req_checked" "req_unchecked"
2072 # CHECKED flag 0 flag Abnormal Mode
2073 # void_cookie req_cookie
2074 # ------------------------------
2077 # Whether we are _checked or _unchecked
2078 checked = void and not regular
2079 unchecked = not void and not regular
2081 # What kind of cookie we return
2082 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2084 # What flag is passed to xcb_request
2085 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2088 if func_flags == '0':
2089 func_flags = 'XCB_REQUEST_REPLY_FDS'
2091 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2093 # Global extension id variable or NULL for xproto
2094 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2096 # What our function name is
2097 func_name = self.c_request_name if not aux else self.c_aux_name
2099 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2101 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2105 maxtypelen = len('xcb_connection_t')
2107 # special case: list with variable size elements
2108 list_with_var_size_elems = False
2110 for field in self.fields:
2112 # The field should appear as a call parameter
2113 param_fields.append(field)
2114 if field.wire and not field.auto:
2115 # We need to set the field up in the structure
2116 wire_fields.append(field)
2117 if field.type.c_need_serialize or field.type.c_need_sizeof:
2118 serial_fields.append(field)
2120 for field in param_fields:
2121 c_field_const_type = field.c_field_const_type
2122 if field.type.c_need_serialize and not aux:
2123 c_field_const_type = "const void"
2124 if len(c_field_const_type) > maxtypelen:
2125 maxtypelen = len(c_field_const_type)
2126 if field.type.is_list and not field.type.member.fixed_size():
2127 list_with_var_size_elems = True
2133 if hasattr(self, "doc") and self.doc:
2135 _h(' * @brief ' + self.doc.brief)
2137 _h(' * No brief doc yet')
2140 _h(' * @param c The connection')
2141 param_names = [f.c_field_name for f in param_fields]
2142 if hasattr(self, "doc") and self.doc:
2143 for field in param_fields:
2144 # XXX: hard-coded until we fix xproto.xml
2145 base_func_name = self.c_request_name if not aux else self.c_aux_name
2146 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2148 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2150 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2153 # XXX: why the 'xcb' prefix?
2154 key = ('xcb', field.enum)
2157 if namecount[tname] > 1:
2158 tname = _t(key + ('enum',))
2159 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2161 if self.doc and field.field_name in self.doc.fields:
2162 desc = self.doc.fields[field.field_name]
2163 for name in param_names:
2164 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2165 desc = desc.split("\n")
2166 desc = [line if line != '' else '\\n' for line in desc]
2167 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2168 # If there is no documentation yet, we simply don't generate an
2169 # @param tag. Doxygen will then warn about missing documentation.
2171 _h(' * @return A cookie')
2174 if hasattr(self, "doc") and self.doc:
2175 if self.doc.description:
2176 desc = self.doc.description
2177 for name in param_names:
2178 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2179 desc = desc.split("\n")
2180 _h(' * ' + "\n * ".join(desc))
2182 _h(' * No description yet')
2184 _h(' * Delivers a request to the X server.')
2187 _h(' * This form can be used only if the request will not cause')
2188 _h(' * a reply to be generated. Any returned error will be')
2189 _h(' * saved for handling by xcb_request_check().')
2191 _h(' * This form can be used only if the request will cause')
2192 _h(' * a reply to be generated. Any returned error will be')
2193 _h(' * placed in the event queue.')
2196 _hc('%s', cookie_type)
2198 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2199 comma = ',' if len(param_fields) else ');'
2200 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2201 comma = ',' if len(param_fields) else ')'
2202 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2204 func_spacing = ' ' * (len(func_name) + 2)
2205 count = len(param_fields)
2206 for field in param_fields:
2208 c_field_const_type = field.c_field_const_type
2209 c_pointer = field.c_pointer
2210 if field.type.c_need_serialize and not aux:
2211 c_field_const_type = "const void"
2213 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2214 comma = ',' if count else ');'
2215 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2216 spacing, c_pointer, field.c_field_name, comma)
2217 comma = ',' if count else ')'
2218 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2219 spacing, c_pointer, field.c_field_name, comma)
2222 if not self.c_var_followed_by_fixed_fields:
2223 for field in param_fields:
2224 if not field.type.fixed_size():
2226 if field.type.c_need_serialize:
2227 # _serialize() keeps track of padding automatically
2229 dimension = count + 2
2232 _c(' static const xcb_protocol_request_t xcb_req = {')
2233 _c(' /* count */ %d,', count)
2234 _c(' /* ext */ %s,', func_ext_global)
2235 _c(' /* opcode */ %s,', self.c_request_name.upper())
2236 _c(' /* isvoid */ %d', 1 if void else 0)
2240 _c(' struct iovec xcb_parts[%d];', dimension)
2241 _c(' %s xcb_ret;', func_cookie)
2242 _c(' %s xcb_out;', self.c_type)
2243 if self.c_var_followed_by_fixed_fields:
2244 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2245 _c(' void *xcb_aux = 0;')
2248 for idx, f in enumerate(serial_fields):
2250 _c(' void *xcb_aux%d = 0;' % (idx))
2251 if list_with_var_size_elems:
2252 _c(' unsigned int i;')
2253 _c(' unsigned int xcb_tmp_len;')
2254 _c(' char *xcb_tmp;')
2256 # simple request call tracing
2257 # _c(' printf("in function %s\\n");' % func_name)
2260 for field in wire_fields:
2261 if field.type.fixed_size():
2262 if field.type.is_expr:
2263 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2264 elif field.type.is_pad:
2265 if field.type.nmemb == 1:
2266 _c(' xcb_out.%s = 0;', field.c_field_name)
2268 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2270 if field.type.nmemb == 1:
2271 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2273 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2275 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2276 serialize_args = get_serialize_params(context, type_obj,
2279 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2281 # calls in order to free dyn. all. memory
2285 if not self.c_var_followed_by_fixed_fields:
2286 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2287 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2288 _c(' xcb_parts[3].iov_base = 0;')
2289 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2293 for field in param_fields:
2294 if not field.type.fixed_size():
2295 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2296 # default: simple cast to char *
2297 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2298 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2299 if field.type.is_list:
2300 if field.type.member.fixed_size():
2301 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2302 _c_accessor_get_expr(field.type.expr, None),
2303 field.type.member.c_wiretype)
2305 list_length = _c_accessor_get_expr(field.type.expr, None)
2308 _c(" xcb_parts[%d].iov_len = 0;" % count)
2309 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2310 _c(" for(i=0; i<%s; i++) {" % list_length)
2311 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2312 (field.type.c_sizeof_name))
2313 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2314 _c(" xcb_tmp += xcb_tmp_len;")
2317 # not supposed to happen
2318 raise Exception("unhandled variable size field %s" % field.c_field_name)
2321 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2322 idx = serial_fields.index(field)
2323 aux_var = '&xcb_aux%d' % idx
2324 context = 'serialize' if aux else 'sizeof'
2325 _c(' xcb_parts[%d].iov_len =', count)
2327 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2328 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2329 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2330 free_calls.append(' free(xcb_aux%d);' % idx)
2332 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2333 func_name = field.type.c_sizeof_name
2334 _c(' %s (%s);', func_name, serialize_args)
2337 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2338 # the _serialize() function keeps track of padding automatically
2339 _c(' xcb_parts[%d].iov_base = 0;', count)
2340 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2343 # elif self.c_var_followed_by_fixed_fields:
2345 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2346 # request header: opcodes + length
2347 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2350 buffer_var = '&xcb_aux'
2351 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2352 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2353 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2354 free_calls.append(' free(xcb_aux);')
2355 # no padding necessary - _serialize() keeps track of padding automatically
2358 for field in param_fields:
2360 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2362 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2364 # free dyn. all. data, if any
2365 for f in free_calls:
2367 _c(' return xcb_ret;')
2370 def _c_reply(self, name):
2372 Declares the function that returns the reply structure.
2374 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2375 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2376 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2378 # check if _unserialize() has to be called for any field
2379 def look_for_special_cases(complex_obj):
2380 unserialize_fields = []
2381 # no unserialize call in case of switch
2382 if not complex_obj.is_switch:
2383 for field in complex_obj.fields:
2384 # three cases: 1. field with special case
2385 # 2. container that contains special case field
2386 # 3. list with special case elements
2387 if field.type.c_var_followed_by_fixed_fields:
2388 unserialize_fields.append(field)
2389 elif field.type.is_container:
2390 unserialize_fields += look_for_special_cases(field.type)
2391 elif field.type.is_list:
2392 if field.type.member.c_var_followed_by_fixed_fields:
2393 unserialize_fields.append(field)
2394 if field.type.member.is_container:
2395 unserialize_fields += look_for_special_cases(field.type.member)
2396 return unserialize_fields
2398 unserialize_fields = look_for_special_cases(self.reply)
2402 _h(' * Return the reply')
2403 _h(' * @param c The connection')
2404 _h(' * @param cookie The cookie')
2405 _h(' * @param e The xcb_generic_error_t supplied')
2407 _h(' * Returns the reply of the request asked by')
2409 _h(' * The parameter @p e supplied to this function must be NULL if')
2410 _h(' * %s(). is used.', self.c_unchecked_name)
2411 _h(' * Otherwise, it stores the error if any.')
2413 _h(' * The returned value must be freed by the caller using free().')
2416 _hc('%s *', self.c_reply_type)
2417 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2418 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2419 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2420 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2423 if len(unserialize_fields)>0:
2424 # certain variable size fields need to be unserialized explicitly
2425 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2426 self.c_reply_type, self.c_reply_type)
2428 for field in unserialize_fields:
2429 if field.type.is_list:
2430 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2431 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2432 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2434 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2435 # call _unserialize(), using the reply as source and target buffer
2436 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2437 for field in unserialize_fields:
2438 if field.type.is_list:
2439 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2440 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2441 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2442 field.c_field_name, field.c_field_name)
2443 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2445 # return the transformed reply
2446 _c(' return reply;')
2449 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2453 def _c_reply_has_fds(self):
2454 for field in self.fields:
2459 def _c_reply_fds(self, name):
2461 Declares the function that returns fds related to the reply.
2463 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2464 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2467 _h(' * Return the reply fds')
2468 _h(' * @param c The connection')
2469 _h(' * @param reply The reply')
2471 _h(' * Returns the array of reply fds of the request asked by')
2473 _h(' * The returned value must be freed by the caller using free().')
2477 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2478 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2479 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2482 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2487 def _c_opcode(name, opcode):
2489 Declares the opcode define for requests, events, and errors.
2493 _h('/** Opcode for %s. */', _n(name))
2494 _h('#define %s %s', _n(name).upper(), opcode)
2496 def _c_cookie(self, name):
2498 Declares the cookie type for a non-void request.
2503 _h(' * @brief %s', self.c_cookie_type)
2505 _h('typedef struct %s {', self.c_cookie_type)
2506 _h(' unsigned int sequence; /**< */')
2507 _h('} %s;', self.c_cookie_type)
2509 def _man_request(self, name, cookie_type, void, aux):
2510 param_fields = [f for f in self.fields if f.visible]
2512 func_name = self.c_request_name if not aux else self.c_aux_name
2514 def create_link(linkname):
2515 name = 'man/%s.%s' % (linkname, section)
2517 sys.stdout.write(name)
2519 f.write('.so man%s/%s.%s' % (section, func_name, section))
2523 sys.stdout.write('man/%s.%s ' % (func_name, section))
2524 # Our CWD is src/, so this will end up in src/man/
2525 f = open('man/%s.%s' % (func_name, section), 'w')
2526 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2527 # Left-adjust instead of adjusting to both sides
2529 f.write('.SH NAME\n')
2530 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2531 f.write('%s \\- %s\n' % (func_name, brief))
2532 f.write('.SH SYNOPSIS\n')
2533 # Don't split words (hyphenate)
2535 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2537 # function prototypes
2539 count = len(param_fields)
2540 for field in param_fields:
2542 c_field_const_type = field.c_field_const_type
2543 c_pointer = field.c_pointer
2544 if c_pointer == ' ':
2546 if field.type.c_need_serialize and not aux:
2547 c_field_const_type = "const void"
2549 comma = ', ' if count else ');'
2550 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2552 f.write('.SS Request function\n')
2554 base_func_name = self.c_request_name if not aux else self.c_aux_name
2555 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2556 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2559 f.write('.SS Reply datastructure\n')
2562 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2566 for field in self.reply.fields:
2567 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2570 struct_fields.append(field)
2572 for field in struct_fields:
2573 length = len(field.c_field_type)
2574 # account for '*' pointer_spec
2575 if not field.type.fixed_size():
2577 maxtypelen = max(maxtypelen, length)
2579 def _c_complex_field(self, field, space=''):
2580 if (field.type.fixed_size() or
2581 # in case of switch with switch children, don't make the field a pointer
2582 # necessary for unserialize to work
2583 (self.is_switch and field.type.is_switch)):
2584 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2585 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2587 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2588 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2589 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2591 if not self.is_switch:
2592 for field in struct_fields:
2593 _c_complex_field(self, field)
2595 for b in self.bitcases:
2599 for field in b.type.fields:
2600 _c_complex_field(self, field, space)
2602 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2605 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2608 f.write('.SS Reply function\n')
2610 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2611 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2612 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2613 create_link('%s' % self.c_reply_name)
2615 has_accessors = False
2616 for field in self.reply.fields:
2617 if field.type.is_list and not field.type.fixed_size():
2618 has_accessors = True
2619 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2620 has_accessors = True
2623 f.write('.SS Reply accessors\n')
2625 def _c_accessors_field(self, field):
2627 Declares the accessor functions for a non-list field that follows a variable-length field.
2629 c_type = self.c_type
2631 # special case: switch
2632 switch_obj = self if self.is_switch else None
2633 if self.is_case_or_bitcase:
2634 switch_obj = self.parents[-1]
2635 if switch_obj is not None:
2636 c_type = switch_obj.c_type
2638 if field.type.is_simple:
2639 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2640 create_link('%s' % field.c_accessor_name)
2642 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2643 create_link('%s' % field.c_accessor_name)
2645 def _c_accessors_list(self, field):
2647 Declares the accessor functions for a list field.
2648 Declares a direct-accessor function only if the list members are fixed size.
2649 Declares length and get-iterator functions always.
2652 c_type = self.reply.c_type
2654 # special case: switch
2655 # in case of switch, 2 params have to be supplied to certain accessor functions:
2656 # 1. the anchestor object (request or reply)
2657 # 2. the (anchestor) switch object
2658 # the reason is that switch is either a child of a request/reply or nested in another switch,
2659 # so whenever we need to access a length field, we might need to refer to some anchestor type
2660 switch_obj = self if self.is_switch else None
2661 if self.is_case_or_bitcase:
2662 switch_obj = self.parents[-1]
2663 if switch_obj is not None:
2664 c_type = switch_obj.c_type
2668 parents = self.parents if hasattr(self, 'parents') else [self]
2669 # 'R': parents[0] is always the 'toplevel' container type
2670 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2671 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2672 # auxiliary object for 'R' parameters
2675 if switch_obj is not None:
2676 # now look where the fields are defined that are needed to evaluate
2677 # the switch expr, and store the parent objects in accessor_params and
2678 # the fields in switch_fields
2680 # 'S': name for the 'toplevel' switch
2681 toplevel_switch = parents[1]
2682 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2683 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2685 # initialize prefix for everything "below" S
2686 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2687 prefix = [(prefix_str, '->', toplevel_switch)]
2689 # look for fields in the remaining containers
2690 for p in parents[2:] + [self]:
2691 # the separator between parent and child is always '.' here,
2692 # because of nested switch statements
2693 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2694 prefix.append((p.name[-1], '.', p))
2695 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2697 # auxiliary object for 'S' parameter
2700 if list.member.fixed_size():
2701 idx = 1 if switch_obj is not None else 0
2703 f.write('%s *\\fB%s\\fP(%s);\n' %
2704 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2705 create_link('%s' % field.c_accessor_name)
2708 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2709 (field.c_length_name, c_type))
2710 create_link('%s' % field.c_length_name)
2712 if field.type.member.is_simple:
2714 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2715 (field.c_end_name, c_type))
2716 create_link('%s' % field.c_end_name)
2719 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2720 (field.c_iterator_type, field.c_iterator_name,
2722 create_link('%s' % field.c_iterator_name)
2724 for field in self.reply.fields:
2725 if field.type.is_list and not field.type.fixed_size():
2726 _c_accessors_list(self, field)
2727 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2728 _c_accessors_field(self, field)
2732 # Re-enable hyphenation and adjusting to both sides
2735 # argument reference
2736 f.write('.SH REQUEST ARGUMENTS\n')
2737 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2738 f.write('The XCB connection to X11.\n')
2739 for field in param_fields:
2740 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2741 printed_enum = False
2742 # XXX: hard-coded until we fix xproto.xml
2743 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2745 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2747 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2749 if hasattr(field, "enum") and field.enum:
2750 # XXX: why the 'xcb' prefix?
2751 key = ('xcb', field.enum)
2753 f.write('One of the following values:\n')
2756 count = len(enum.values)
2757 for (enam, eval) in enum.values:
2759 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2760 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2761 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2762 f.write('%s\n' % desc)
2764 f.write('TODO: NOT YET DOCUMENTED.\n')
2769 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2770 desc = self.doc.fields[field.field_name]
2771 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2774 f.write('%s\n' % desc)
2776 f.write('TODO: NOT YET DOCUMENTED.\n')
2782 f.write('.SH REPLY FIELDS\n')
2783 # These fields are present in every reply:
2784 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2785 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2786 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2787 'be used to tell replies apart from each other.\n') %
2788 _n(self.reply.name).upper())
2789 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2790 f.write('The sequence number of the last request processed by the X11 server.\n')
2791 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2792 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2793 for field in self.reply.fields:
2794 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2795 field.c_field_name.startswith('pad')):
2798 if field.type.is_list and not field.type.fixed_size():
2800 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2802 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2803 printed_enum = False
2804 if hasattr(field, "enum") and field.enum:
2805 # XXX: why the 'xcb' prefix?
2806 key = ('xcb', field.enum)
2808 f.write('One of the following values:\n')
2811 count = len(enum.values)
2812 for (enam, eval) in enum.values:
2814 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2815 if enum.doc and enam in enum.doc.fields:
2816 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2817 f.write('%s\n' % desc)
2819 f.write('TODO: NOT YET DOCUMENTED.\n')
2824 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2825 desc = self.reply.doc.fields[field.field_name]
2826 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2829 f.write('%s\n' % desc)
2831 f.write('TODO: NOT YET DOCUMENTED.\n')
2838 f.write('.SH DESCRIPTION\n')
2839 if hasattr(self, "doc") and self.doc and self.doc.description:
2840 desc = self.doc.description
2841 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2842 lines = desc.split('\n')
2843 f.write('\n'.join(lines) + '\n')
2845 f.write('.SH RETURN VALUE\n')
2847 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2848 'have to be handled in the event loop.\n\nIf you want to '
2849 'handle errors directly with \\fIxcb_request_check\\fP '
2850 'instead, use \\fI%s_checked\\fP. See '
2851 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2853 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2854 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2855 'handle errors in the event loop instead, use '
2856 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2858 (cookie_type, self.c_reply_name, base_func_name, section))
2859 f.write('.SH ERRORS\n')
2860 if hasattr(self, "doc") and self.doc:
2861 for errtype, errtext in sorted(self.doc.errors.items()):
2862 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2863 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2864 f.write('%s\n' % (errtext))
2865 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2866 f.write('This request does never generate any errors.\n')
2867 if hasattr(self, "doc") and self.doc and self.doc.example:
2868 f.write('.SH EXAMPLE\n')
2871 lines = self.doc.example.split('\n')
2872 f.write('\n'.join(lines) + '\n')
2874 f.write('.SH SEE ALSO\n')
2875 if hasattr(self, "doc") and self.doc:
2876 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2877 if self.doc.example:
2878 see.append('.BR %s (%s)' % ('xcb-examples', section))
2879 for seename, seetype in sorted(self.doc.see.items()):
2880 if seetype == 'program':
2881 see.append('.BR %s (1)' % seename)
2882 elif seetype == 'event':
2883 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2884 elif seetype == 'request':
2885 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2886 elif seetype == 'function':
2887 see.append('.BR %s (%s)' % (seename, section))
2889 see.append('TODO: %s (type %s)' % (seename, seetype))
2890 f.write(',\n'.join(see) + '\n')
2891 f.write('.SH AUTHOR\n')
2892 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2895 def _man_event(self, name):
2897 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2898 # Our CWD is src/, so this will end up in src/man/
2899 f = open('man/%s.%s' % (self.c_type, section), 'w')
2900 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2901 # Left-adjust instead of adjusting to both sides
2903 f.write('.SH NAME\n')
2904 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2905 f.write('%s \\- %s\n' % (self.c_type, brief))
2906 f.write('.SH SYNOPSIS\n')
2907 # Don't split words (hyphenate)
2909 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2912 f.write('.SS Event datastructure\n')
2915 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2919 for field in self.fields:
2920 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2923 struct_fields.append(field)
2925 for field in struct_fields:
2926 length = len(field.c_field_type)
2927 # account for '*' pointer_spec
2928 if not field.type.fixed_size():
2930 maxtypelen = max(maxtypelen, length)
2932 def _c_complex_field(self, field, space=''):
2933 if (field.type.fixed_size() or
2934 # in case of switch with switch children, don't make the field a pointer
2935 # necessary for unserialize to work
2936 (self.is_switch and field.type.is_switch)):
2937 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2938 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2940 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2942 if not self.is_switch:
2943 for field in struct_fields:
2944 _c_complex_field(self, field)
2946 for b in self.bitcases:
2950 for field in b.type.fields:
2951 _c_complex_field(self, field, space)
2953 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2956 f.write('} \\fB%s\\fP;\n' % self.c_type)
2961 # Re-enable hyphenation and adjusting to both sides
2964 # argument reference
2965 f.write('.SH EVENT FIELDS\n')
2966 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2967 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2968 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2969 'to tell events apart from each other.\n') % _n(name).upper())
2970 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2971 f.write('The sequence number of the last request processed by the X11 server.\n')
2973 if not self.is_switch:
2974 for field in struct_fields:
2975 # Skip the fields which every event has, we already documented
2977 if field.c_field_name in ('response_type', 'sequence'):
2979 if isinstance(field.type, PadType):
2981 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2982 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2983 desc = self.doc.fields[field.field_name]
2984 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2985 f.write('%s\n' % desc)
2987 f.write('NOT YET DOCUMENTED.\n')
2990 f.write('.SH DESCRIPTION\n')
2991 if hasattr(self, "doc") and self.doc and self.doc.description:
2992 desc = self.doc.description
2993 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2994 lines = desc.split('\n')
2995 f.write('\n'.join(lines) + '\n')
2997 if hasattr(self, "doc") and self.doc and self.doc.example:
2998 f.write('.SH EXAMPLE\n')
3001 lines = self.doc.example.split('\n')
3002 f.write('\n'.join(lines) + '\n')
3004 f.write('.SH SEE ALSO\n')
3005 if hasattr(self, "doc") and self.doc:
3006 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
3007 if self.doc.example:
3008 see.append('.BR %s (%s)' % ('xcb-examples', section))
3009 for seename, seetype in sorted(self.doc.see.items()):
3010 if seetype == 'program':
3011 see.append('.BR %s (1)' % seename)
3012 elif seetype == 'event':
3013 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
3014 elif seetype == 'request':
3015 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
3016 elif seetype == 'function':
3017 see.append('.BR %s (%s)' % (seename, section))
3019 see.append('TODO: %s (type %s)' % (seename, seetype))
3020 f.write(',\n'.join(see) + '\n')
3021 f.write('.SH AUTHOR\n')
3022 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3026 def c_request(self, name):
3028 Exported function that handles request declarations.
3030 _c_type_setup(self, name, ('request',))
3033 # Cookie type declaration
3034 _c_cookie(self, name)
3037 _c_opcode(name, self.opcode)
3039 # Request structure declaration
3043 _c_type_setup(self.reply, name, ('reply',))
3044 # Reply structure definition
3045 _c_complex(self.reply)
3046 # Request prototypes
3047 has_fds = _c_reply_has_fds(self.reply)
3048 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3049 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3051 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3052 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3054 _c_accessors(self.reply, name + ('reply',), name)
3055 _c_reply(self, name)
3057 _c_reply_fds(self, name)
3059 # Request prototypes
3060 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3061 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3063 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3064 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3066 # We generate the manpage afterwards because _c_type_setup has been called.
3067 # TODO: what about aux helpers?
3068 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3069 _man_request(self, name, cookie_type, not self.reply, False)
3071 def c_event(self, name):
3073 Exported function that handles event declarations.
3076 # The generic event structure xcb_ge_event_t has the full_sequence field
3077 # at the 32byte boundary. That's why we've to inject this field into GE
3078 # events while generating the structure for them. Otherwise we would read
3079 # garbage (the internal full_sequence) when accessing normal event fields
3081 force_packed = False
3082 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3084 for field in self.fields:
3085 if field.type.size != None and field.type.nmemb != None:
3086 event_size += field.type.size * field.type.nmemb
3087 if event_size == 32:
3088 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3089 idx = self.fields.index(field)
3090 self.fields.insert(idx + 1, full_sequence)
3092 # If the event contains any 64-bit extended fields, they need
3093 # to remain aligned on a 64-bit boundary. Adding full_sequence
3094 # would normally break that; force the struct to be packed.
3095 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3098 _c_type_setup(self, name, ('event',))
3101 _c_opcode(name, self.opcodes[name])
3103 if self.name == name:
3104 # Structure definition
3105 _c_complex(self, force_packed)
3109 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3111 _man_event(self, name)
3113 def c_error(self, name):
3115 Exported function that handles error declarations.
3117 _c_type_setup(self, name, ('error',))
3120 _c_opcode(name, self.opcodes[name])
3122 if self.name == name:
3123 # Structure definition
3128 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3131 # Main routine starts here
3133 # Must create an "output" dictionary before any xcbgen imports.
3134 output = {'open' : c_open,
3136 'simple' : c_simple,
3138 'struct' : c_struct,
3140 'request' : c_request,
3145 # Boilerplate below this point
3147 # Check for the argument that specifies path to the xcbgen python package.
3149 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3150 except getopt.GetoptError as err:
3152 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3155 for (opt, arg) in opts:
3163 sys.path.insert(1, arg)
3166 sys.stdout.write('man_MANS = ')
3168 # Import the module class
3170 from xcbgen.state import Module
3171 from xcbgen.xtypes import *
3174 Failed to load the xcbgen Python package!
3175 Make sure that xcb/proto installed it on your Python path.
3176 If not, you will need to create a .pth file or define $PYTHONPATH
3178 Refer to the README file in xcb/proto for more info.
3182 # Ensure the man subdirectory exists
3185 except OSError as e:
3186 if e.errno != errno.EEXIST:
3189 # Parse the xml header
3190 module = Module(args[0], output)
3192 # Build type-registry and resolve type dependencies