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
584 # add separator for access to a yet unknown field
585 prefix_str += last_sep
587 if _c_field_needs_accessor(field):
588 if _c_field_is_member_of_case_or_bitcase(field):
589 # case members are available in the deserialized struct,
590 # so there is no need to use the accessor function
591 # (also, their accessor function needs a different arglist
592 # so this would require special treatment here)
593 # Therefore: Access as struct member
594 prefix_str += last_sep + _cpp(field.field_name)
596 # Access with the accessor function
597 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
599 # Access as struct member
600 prefix_str += last_sep + _cpp(field.field_name)
605 def _c_helper_field_mapping(complex_type, prefix, flat=False):
607 generate absolute names, based on prefix, for all fields starting from complex_type
608 if flat == True, nested complex types are not taken into account
611 if complex_type.is_switch:
612 for b in complex_type.bitcases:
614 switch_name, switch_sep, switch_type = prefix[-1]
615 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
617 bitcase_prefix = prefix
619 if (True==flat and not b.type.has_name) or False==flat:
620 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
622 for f in complex_type.fields:
623 fname = _c_helper_fieldaccess_expr(prefix, f)
624 if f.field_name in all_fields:
625 raise Exception("field name %s has been registered before" % f.field_name)
627 all_fields[f.field_name] = (fname, f)
628 if f.type.is_container and flat==False:
629 if f.type.is_case_or_bitcase and not f.type.has_name:
631 elif f.type.is_switch and len(f.type.parents)>1:
632 # nested switch gets another separator
633 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
635 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
636 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
641 def _c_helper_resolve_field_names (prefix):
643 get field names for all objects in the prefix array
647 # look for fields in the remaining containers
648 for idx, p in enumerate(prefix):
651 # sep can be preset in prefix, if not, make a sensible guess
652 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
653 # exception: 'toplevel' object (switch as well!) always have sep '->'
654 sep = '->' if idx<1 else sep
655 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
656 tmp_prefix.append((name, sep, obj))
657 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
660 # _c_helper_resolve_field_names
662 def get_expr_fields(self):
664 get the Fields referenced by switch or list expression
666 def get_expr_field_names(expr):
668 if expr.lenfield_name is not None:
669 return [expr.lenfield_name]
671 # constant value expr
675 return get_expr_field_names(expr.rhs)
676 elif expr.op == 'popcount':
677 return get_expr_field_names(expr.rhs)
678 elif expr.op == 'sumof':
679 # sumof expr references another list,
680 # we need that list's length field here
682 for f in expr.lenfield_parent.fields:
683 if f.field_name == expr.lenfield_name:
687 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
688 # referenced list + its length field
689 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
690 elif expr.op == 'enumref':
693 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
694 # get_expr_field_names()
696 # resolve the field names with the parent structure(s)
697 unresolved_fields_names = get_expr_field_names(self.expr)
699 # construct prefix from self
700 prefix = [('', '', p) for p in self.parents]
701 if self.is_container:
702 prefix.append(('', '', self))
704 all_fields = _c_helper_resolve_field_names (prefix)
705 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
706 if len(unresolved_fields_names) != len(resolved_fields_names):
707 raise Exception("could not resolve all fields for %s" % self.name)
709 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
710 return resolved_fields
713 def resolve_expr_fields(complex_obj):
715 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
716 these are normally fields that need to be given as function parameters
722 for field in complex_obj.fields:
723 all_fields.append(field)
724 if field.type.is_switch or field.type.is_list:
725 expr_fields += get_expr_fields(field.type)
726 if field.type.is_container:
727 expr_fields += resolve_expr_fields(field.type)
729 # try to resolve expr fields
730 for e in expr_fields:
731 if e not in all_fields and e not in unresolved:
734 # resolve_expr_fields()
736 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
738 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
739 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
740 expression. This function tries to resolve all fields within a structure, and returns the
741 unresolved fields as the list of external parameters.
743 def add_param(params, param):
744 if param not in params:
747 # collect all fields into param_fields
751 for field in self.fields:
753 # the field should appear as a parameter in the function call
754 param_fields.append(field)
755 if field.wire and not field.auto:
756 if field.type.fixed_size() and not self.is_switch:
757 # field in the xcb_out structure
758 wire_fields.append(field)
759 # fields like 'pad0' are skipped!
761 # in case of switch, parameters always contain any fields referenced in the switch expr
762 # we do not need any variable size fields here, as the switch data type contains both
763 # fixed and variable size fields
765 param_fields = get_expr_fields(self)
767 # _serialize()/_unserialize()/_unpack() function parameters
768 # note: don't use set() for params, it is unsorted
771 # 1. the parameter for the void * buffer
772 if 'serialize' == context:
773 params.append(('void', '**', buffer_var))
774 elif context in ('unserialize', 'unpack', 'sizeof'):
775 params.append(('const void', '*', buffer_var))
777 # 2. any expr fields that cannot be resolved within self and descendants
778 unresolved_fields = resolve_expr_fields(self)
779 for f in unresolved_fields:
780 add_param(params, (f.c_field_type, '', f.c_field_name))
782 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
783 # that do not appear in the data type struct
784 for p in param_fields:
786 typespec = p.c_field_const_type
787 pointerspec = p.c_pointer
788 add_param(params, (typespec, pointerspec, p.c_field_name))
790 if p.visible and not p.wire and not p.auto:
791 typespec = p.c_field_type
793 add_param(params, (typespec, pointerspec, p.c_field_name))
796 if 'serialize' == context:
797 add_param(params, ('const %s' % self.c_type, '*', aux_var))
798 elif 'unserialize' == context:
799 add_param(params, ('%s' % self.c_type, '**', aux_var))
800 elif 'unpack' == context:
801 add_param(params, ('%s' % self.c_type, '*', aux_var))
803 # 5. switch contains all variable size fields as struct members
804 # for other data types though, these have to be supplied separately
805 # this is important for the special case of intermixed fixed and
806 # variable size fields
807 if not self.is_switch and 'serialize' == context:
808 for p in param_fields:
809 if not p.type.fixed_size():
810 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
812 return (param_fields, wire_fields, params)
813 # get_serialize_params()
815 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
816 code_lines.append('%s /* insert padding */' % space)
817 if is_case_or_bitcase:
819 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
823 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
824 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
825 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
828 code_lines.append('%s if (0 != xcb_pad) {' % space)
830 if 'serialize' == context:
831 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
832 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
833 code_lines.append('%s xcb_parts_idx++;' % space)
834 elif context in ('unserialize', 'unpack', 'sizeof'):
835 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
837 code_lines.append('%s xcb_pad = 0;' % space)
838 code_lines.append('%s }' % space)
840 code_lines.append('%s xcb_block_len = 0;' % space)
841 if is_case_or_bitcase:
842 code_lines.append('%s xcb_padding_offset = 0;' % space)
844 # keep tracking of xcb_parts entries for serialize
846 # _c_serialize_helper_insert_padding()
848 def _c_serialize_helper_switch(context, self, complex_name,
849 code_lines, temp_vars,
852 switch_expr = _c_accessor_get_expr(self.expr, None)
854 for b in self.bitcases:
855 len_expr = len(b.type.expr)
857 compare_operator = '&'
859 compare_operator = '=='
861 compare_operator = '&'
863 for n, expr in enumerate(b.type.expr):
864 bitcase_expr = _c_accessor_get_expr(expr, None)
865 # only one <enumref> in the <bitcase>
868 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
869 # multiple <enumref> in the <bitcase>
872 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
873 elif len_expr == (n + 1): # last
875 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
876 else: # between first and last
878 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
882 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
884 count += _c_serialize_helper_fields(context, b.type,
885 code_lines, temp_vars,
888 is_case_or_bitcase = True)
889 code_lines.append(' }')
891 # if 'serialize' == context:
892 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
893 # elif context in ('unserialize', 'unpack', 'sizeof'):
895 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
896 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
899 # _c_serialize_helper_switch
901 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
903 handle switch by calling _serialize() or _unpack(), depending on context
905 # switch is handled by this function as a special case
906 param_fields, wire_fields, params = get_serialize_params(context, self)
907 field_mapping = _c_helper_field_mapping(self, prefix)
908 prefix_str = _c_helper_fieldaccess_expr(prefix)
910 # find the parameters that need to be passed to _serialize()/_unpack():
911 # all switch expr fields must be given as parameters
912 args = get_expr_fields(field.type)
913 # length fields for variable size types in switch, normally only some of need
914 # need to be passed as parameters
915 switch_len_fields = resolve_expr_fields(field.type)
917 # a switch field at this point _must_ be a bitcase field
918 # we require that bitcases are "self-contiguous"
919 bitcase_unresolved = resolve_expr_fields(self)
920 if len(bitcase_unresolved) != 0:
921 raise Exception('unresolved fields within bitcase is not supported at this point')
923 # get the C names for the parameters
925 for a in switch_len_fields:
926 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
928 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
930 # call _serialize()/_unpack() to determine the actual size
931 if 'serialize' == context:
932 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
933 c_field_names, prefix_str, field.c_field_name)
934 elif context in ('unserialize', 'unpack'):
935 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
936 c_field_names, prefix_str, field.c_field_name)
937 elif 'sizeof' == context:
938 # remove trailing ", " from c_field_names because it will be used at end of arglist
939 my_c_field_names = c_field_names[:-2]
940 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
943 # _c_serialize_helper_switch_field()
945 def _c_serialize_helper_list_field(context, self, field,
946 code_lines, temp_vars,
949 helper function to cope with lists of variable length
951 expr = field.type.expr
952 prefix_str = _c_helper_fieldaccess_expr(prefix)
953 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
954 param_names = [p[2] for p in params]
956 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
957 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
958 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
962 field_mapping[r] = (r, None)
964 if len(unresolved)>0:
966 if len(tmp_prefix)==0:
967 raise Exception("found an empty prefix while resolving expr field names for list %s",
970 field_mapping.update(_c_helper_resolve_field_names(prefix))
971 resolved += list(filter(lambda x: x in field_mapping, unresolved))
972 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
973 if len(unresolved)>0:
974 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
976 list_length = _c_accessor_get_expr(expr, field_mapping)
978 # default: list with fixed size elements
979 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
981 # list with variable-sized elements
982 if not field.type.member.fixed_size():
984 if context in ('unserialize', 'sizeof', 'unpack'):
985 int_i = ' unsigned int i;'
986 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
987 if int_i not in temp_vars:
988 temp_vars.append(int_i)
989 if xcb_tmp_len not in temp_vars:
990 temp_vars.append(xcb_tmp_len)
991 # loop over all list elements and call sizeof repeatedly
992 # this should be a bit faster than using the iterators
993 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
994 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
995 (space, field.type.c_sizeof_name))
996 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
997 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
998 code_lines.append("%s }" % space)
1000 elif 'serialize' == context:
1001 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
1002 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
1003 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
1004 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
1005 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
1006 code_lines.append('%s }' % space)
1007 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1010 # _c_serialize_helper_list_field()
1012 def _c_serialize_helper_fields_fixed_size(context, self, field,
1013 code_lines, temp_vars,
1015 # keep the C code a bit more readable by giving the field name
1016 if not self.is_case_or_bitcase:
1017 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1019 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1020 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1021 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1023 abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1024 # default for simple cases: call sizeof()
1025 length = "sizeof(%s)" % field.c_field_type
1027 if context in ('unserialize', 'unpack', 'sizeof'):
1028 # default: simple cast
1029 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1031 # padding - we could probably just ignore it
1032 if field.type.is_pad and field.type.nmemb > 1:
1034 for i in range(field.type.nmemb):
1035 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1036 (space, abs_field_name, i, field.c_field_type))
1037 # total padding = sizeof(pad0) * nmemb
1038 length += " * %d" % field.type.nmemb
1040 elif field.type.is_list:
1041 # list with fixed number of elements
1042 # length of array = sizeof(arrayElementType) * nmemb
1043 length += " * %d" % field.type.nmemb
1044 # use memcpy because C cannot assign whole arrays with operator=
1045 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1048 elif 'serialize' == context:
1049 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1051 if field.type.is_expr:
1052 # need to register a temporary variable for the expression in case we know its type
1053 if field.type.c_type is None:
1054 raise Exception("type for field '%s' (expression '%s') unkown" %
1055 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1057 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1058 _c_accessor_get_expr(field.type.expr, prefix)))
1059 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1061 elif field.type.is_pad:
1062 if field.type.nmemb == 1:
1063 value += "&xcb_pad;"
1065 # we could also set it to 0, see definition of xcb_send_request()
1066 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1067 length += "*%d" % field.type.nmemb
1070 # non-list type with fixed size
1071 if field.type.nmemb == 1:
1072 value += "&%s;" % (abs_field_name)
1074 # list with nmemb (fixed size) elements
1076 value += '%s;' % (abs_field_name)
1077 length = '%d' % field.type.nmemb
1079 return (value, length)
1080 # _c_serialize_helper_fields_fixed_size()
1082 def _c_serialize_helper_fields_variable_size(context, self, field,
1083 code_lines, temp_vars,
1085 prefix_str = _c_helper_fieldaccess_expr(prefix)
1087 if context in ('unserialize', 'unpack', 'sizeof'):
1089 var_field_name = 'xcb_tmp'
1091 # special case: intermixed fixed and variable size fields
1092 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1093 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1094 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1095 # special case: switch
1096 if 'unpack' == context:
1097 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1099 elif 'serialize' == context:
1100 # variable size fields appear as parameters to _serialize() if the
1101 # 'toplevel' container is not a switch
1102 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1103 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1104 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1108 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1110 if field.type.is_list:
1112 # in any context, list is already a pointer, so the default assignment is ok
1113 code_lines.append("%s%s" % (space, value))
1115 length = _c_serialize_helper_list_field(context, self, field,
1116 code_lines, temp_vars,
1119 elif field.type.is_switch:
1121 if context == 'serialize':
1122 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1123 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1124 length = _c_serialize_helper_switch_field(context, self, field,
1125 'xcb_parts[xcb_parts_idx].iov_base',
1129 # in all remaining special cases - call _sizeof()
1130 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1132 return (value, length)
1133 # _c_serialize_helper_fields_variable_size
1135 def _c_serialize_helper_fields(context, self,
1136 code_lines, temp_vars,
1137 space, prefix, is_case_or_bitcase):
1139 need_padding = False
1140 prev_field_was_variable = False
1142 _c_pre.push_indent(space + ' ')
1144 for field in self.fields:
1145 if not field.visible:
1146 if not ((field.wire and not field.auto) or 'unserialize' == context):
1149 # switch/bitcase: fixed size fields must be considered explicitly
1150 if field.type.fixed_size():
1151 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1152 if prev_field_was_variable and need_padding:
1154 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1155 # self.c_var_followed_by_fixed_fields)
1156 prev_field_was_variable = False
1158 # prefix for fixed size fields
1159 fixed_prefix = prefix
1161 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1162 code_lines, temp_vars,
1163 space, fixed_prefix)
1167 # fields with variable size
1169 if field.type.is_pad:
1170 # Variable length pad is <pad align= />
1171 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1172 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1173 self.c_var_followed_by_fixed_fields,
1177 # switch/bitcase: always calculate padding before and after variable sized fields
1178 if need_padding or is_case_or_bitcase:
1179 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1180 self.c_var_followed_by_fixed_fields,
1183 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1184 code_lines, temp_vars,
1186 prev_field_was_variable = True
1188 # save (un)serialization C code
1190 code_lines.append('%s%s' % (space, value))
1192 if field.type.fixed_size():
1193 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1194 # keep track of (un)serialized object's size
1195 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1196 if context in ('unserialize', 'unpack', 'sizeof'):
1197 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1199 # variable size objects or bitcase:
1200 # value & length might have been inserted earlier for special cases
1202 # special case: intermixed fixed and variable size fields
1203 if (not field.type.fixed_size() and
1204 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1205 temp_vars.append(' int %s_len;' % field.c_field_name)
1206 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1207 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1208 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1210 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1211 # increase pointer into the byte stream accordingly
1212 if context in ('unserialize', 'sizeof', 'unpack'):
1213 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1215 if 'serialize' == context:
1217 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1218 code_lines.append('%s xcb_parts_idx++;' % space)
1222 '%s xcb_align_to = ALIGNOF(%s);'
1225 if field.c_field_type == 'void' or field.type.is_switch
1226 else field.c_field_type))
1229 if self.c_var_followed_by_fixed_fields:
1230 need_padding = False
1235 # _c_serialize_helper_fields()
1237 def _c_serialize_helper(context, complex_type,
1238 code_lines, temp_vars,
1239 space='', prefix=[]):
1240 # count tracks the number of fields to serialize
1243 if hasattr(complex_type, 'type'):
1244 self = complex_type.type
1245 complex_name = complex_type.name
1248 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1249 complex_name = 'xcb_out'
1251 complex_name = '_aux'
1253 # special case: switch is serialized by evaluating each bitcase separately
1255 count += _c_serialize_helper_switch(context, self, complex_name,
1256 code_lines, temp_vars,
1259 # all other data types can be evaluated one field a time
1261 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1262 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1263 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1264 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1265 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1266 code_lines.append('%s xcb_block_len = 0;' % space)
1268 count += _c_serialize_helper_fields(context, self,
1269 code_lines, temp_vars,
1270 space, prefix, False)
1272 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1275 # _c_serialize_helper()
1277 def _c_serialize(context, self):
1279 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1280 for the ComplexType variable self
1286 # _serialize() returns the buffer size
1289 if self.is_switch and 'unserialize' == context:
1292 cases = { 'serialize' : self.c_serialize_name,
1293 'unserialize' : self.c_unserialize_name,
1294 'unpack' : self.c_unpack_name,
1295 'sizeof' : self.c_sizeof_name }
1296 func_name = cases[context]
1298 param_fields, wire_fields, params = get_serialize_params(context, self)
1299 variable_size_fields = 0
1300 # maximum space required for type definition of function arguments
1303 # determine N(variable_fields)
1304 for field in param_fields:
1305 # if self.is_switch, treat all fields as if they are variable sized
1306 if not field.type.fixed_size() or self.is_switch:
1307 variable_size_fields += 1
1308 # determine maxtypelen
1310 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1313 indent = ' '*(len(func_name)+2)
1316 typespec, pointerspec, field_name = p
1317 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1318 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1319 # insert function name
1320 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1321 param_str = list(map(lambda x: "%s," % x, param_str))
1322 for s in param_str[:-1]:
1324 _h("%s);" % param_str[-1].rstrip(','))
1325 _c("%s)" % param_str[-1].rstrip(','))
1332 _c_pre.redirect_start(code_lines, temp_vars)
1334 if 'serialize' == context:
1335 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1336 _c(' %s *xcb_out = *_buffer;', self.c_type)
1337 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1338 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1339 _c(' unsigned int xcb_align_to = 0;')
1341 _c(' char *xcb_out = *_buffer;')
1342 _c(' unsigned int xcb_buffer_len = 0;')
1343 _c(' unsigned int xcb_align_to = 0;')
1345 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1346 prefix = [('_aux', '->', self)]
1349 elif context in ('unserialize', 'unpack'):
1350 _c(' char *xcb_tmp = (char *)_buffer;')
1351 if not self.is_switch:
1352 if not self.c_var_followed_by_fixed_fields:
1353 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1354 prefix = [('_aux', '->', self)]
1356 _c(' %s xcb_out;', self.c_type)
1357 prefix = [('xcb_out', '.', self)]
1359 aux_var = '_aux' # default for unpack: single pointer
1360 # note: unserialize not generated for switch
1361 if 'unserialize' == context:
1362 aux_var = '(*_aux)' # unserialize: double pointer (!)
1363 prefix = [(aux_var, '->', self)]
1365 _c(' unsigned int xcb_buffer_len = 0;')
1366 _c(' unsigned int xcb_block_len = 0;')
1367 _c(' unsigned int xcb_pad = 0;')
1368 _c(' unsigned int xcb_align_to = 0;')
1370 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1372 elif 'sizeof' == context:
1373 param_names = [p[2] for p in params]
1375 # switch: call _unpack()
1376 _c(' %s _aux;', self.c_type)
1377 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1379 _c_pre.redirect_end()
1381 elif self.c_var_followed_by_fixed_fields:
1382 # special case: call _unserialize()
1383 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1385 _c_pre.redirect_end()
1388 _c(' char *xcb_tmp = (char *)_buffer;')
1389 prefix = [('_aux', '->', self)]
1391 _c(' unsigned int xcb_padding_offset = 0;')
1393 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1394 # update variable size fields (only important for context=='serialize'
1395 variable_size_fields = count
1396 if 'serialize' == context:
1397 temp_vars.append(' unsigned int xcb_pad = 0;')
1398 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1399 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1400 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1401 temp_vars.append(' unsigned int xcb_block_len = 0;')
1402 temp_vars.append(' unsigned int i;')
1403 temp_vars.append(' char *xcb_tmp;')
1404 elif 'sizeof' == context:
1405 # neither switch nor intermixed fixed and variable size fields:
1406 # evaluate parameters directly
1407 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1409 # look if we have to declare an '_aux' variable at all
1410 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1411 if not self.c_var_followed_by_fixed_fields:
1412 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1414 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1416 _c(' unsigned int xcb_buffer_len = 0;')
1417 _c(' unsigned int xcb_block_len = 0;')
1418 _c(' unsigned int xcb_pad = 0;')
1419 _c(' unsigned int xcb_align_to = 0;')
1421 _c_pre.redirect_end()
1427 for l in code_lines:
1430 # variable sized fields have been collected, now
1431 # allocate memory and copy everything into a continuous memory area
1432 # note: this is not necessary in case of unpack
1433 if context in ('serialize', 'unserialize'):
1434 # unserialize: check for sizeof-only invocation
1435 if 'unserialize' == context:
1437 _c(' if (NULL == _aux)')
1438 _c(' return xcb_buffer_len;')
1441 _c(' if (NULL == %s) {', aux_ptr)
1442 _c(' /* allocate memory */')
1443 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1444 if 'serialize' == context:
1445 _c(' *_buffer = xcb_out;')
1449 # serialize: handle variable size fields in a loop
1450 if 'serialize' == context:
1451 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1452 if len(wire_fields)>0:
1453 _c(' *xcb_out = *_aux;')
1454 # copy variable size fields into the buffer
1455 if variable_size_fields > 0:
1457 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1458 _c(' xcb_tmp = (char*)++xcb_out;')
1459 _c(' xcb_tmp += xcb_out_pad;')
1461 _c(' xcb_tmp = xcb_out;')
1463 # variable sized fields
1464 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1465 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1466 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1467 _c(' if (0 != xcb_parts[i].iov_len)')
1468 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1471 # unserialize: assign variable size fields individually
1472 if 'unserialize' == context:
1473 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1474 param_fields.reverse()
1475 for field in param_fields:
1476 if not field.type.fixed_size():
1477 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1478 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1479 _c(' *%s = xcb_out;', aux_ptr)
1482 _c(' return xcb_buffer_len;')
1486 def _c_iterator_get_end(field, accum):
1488 Figures out what C code is needed to find the end of a variable-length structure field.
1489 For nested structures, recurses into its last variable-sized field.
1490 For lists, calls the end function
1492 if field.type.is_container:
1493 accum = field.c_accessor_name + '(' + accum + ')'
1494 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1495 if field.type.is_list:
1496 # XXX we can always use the first way
1497 if field.type.member.is_simple:
1498 return field.c_end_name + '(' + accum + ')'
1500 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1502 def _c_iterator(self, name):
1504 Declares the iterator structure and next/end functions for a given type.
1509 _h(' * @brief %s', self.c_iterator_type)
1511 _h('typedef struct %s {', self.c_iterator_type)
1512 _h(' %s *data; /**< */', self.c_type)
1513 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1514 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1515 _h('} %s;', self.c_iterator_type)
1521 _h(' * Get the next element of the iterator')
1522 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1524 _h(' * Get the next element in the iterator. The member rem is')
1525 _h(' * decreased by one. The member data points to the next')
1526 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1530 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1531 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1534 if not self.fixed_size():
1535 _c(' %s *R = i->data;', self.c_type)
1538 # FIXME - how to determine the size of a variable size union??
1539 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1541 if self.c_need_sizeof:
1542 _c(' xcb_generic_iterator_t child;')
1543 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1544 self.c_type, self.c_sizeof_name)
1545 _c(' i->index = (char *) child.data - (char *) i->data;')
1547 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1548 _c(' i->index = child.index;')
1550 _c(' i->data = (%s *) child.data;', self.c_type)
1555 _c(' i->index += sizeof(%s);', self.c_type)
1561 _h(' * Return the iterator pointing to the last element')
1562 _h(' * @param i An %s', self.c_iterator_type)
1563 _h(' * @return The iterator pointing to the last element')
1565 _h(' * Set the current element in the iterator to the last element.')
1566 _h(' * The member rem is set to 0. The member data points to the')
1567 _h(' * last element.')
1570 _hc('xcb_generic_iterator_t')
1571 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1572 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1574 _c(' xcb_generic_iterator_t ret;')
1576 if self.fixed_size():
1577 _c(' ret.data = i.data + i.rem;')
1578 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1581 _c(' while(i.rem > 0)')
1582 _c(' %s(&i);', self.c_next_name)
1583 _c(' ret.data = i.data;')
1584 _c(' ret.rem = i.rem;')
1585 _c(' ret.index = i.index;')
1590 def _c_accessor_get_length(expr, field_mapping=None):
1592 Figures out what C code is needed to get a length field.
1593 The field_mapping parameter can be used to change the absolute name of a length field.
1594 For fields that follow a variable-length field, use the accessor.
1595 Otherwise, just reference the structure field directly.
1598 lenfield_name = expr.lenfield_name
1599 if lenfield_name is not None:
1600 if field_mapping is not None:
1601 lenfield_name = field_mapping[lenfield_name][0]
1603 if expr.lenfield_name is not None:
1604 return lenfield_name
1606 return str(expr.nmemb)
1608 def _c_accessor_get_expr(expr, field_mapping):
1610 Figures out what C code is needed to get the length of a list field.
1611 The field_mapping parameter can be used to change the absolute name of a length field.
1612 Recurses for math operations.
1613 Returns bitcount for value-mask fields.
1614 Otherwise, uses the value of the length field.
1616 lenexp = _c_accessor_get_length(expr, field_mapping)
1619 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1620 elif expr.op == 'popcount':
1621 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1622 elif expr.op == 'enumref':
1623 enum_name = expr.lenfield_type.name
1624 constant_name = expr.lenfield_name
1625 c_name = _n(enum_name + (constant_name,)).upper()
1627 elif expr.op == 'sumof':
1628 # locate the referenced list object
1629 list_obj = expr.lenfield_type
1631 for f in expr.lenfield_parent.fields:
1632 if f.field_name == expr.lenfield_name:
1637 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1638 list_name = field_mapping[field.c_field_name][0]
1639 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1640 # note: xcb_sumof() has only been defined for integers
1641 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1642 # create explicit code for computing the sum.
1643 # This works for all C-types which can be added to int64_t with +=
1645 lengthvar = _c_pre.get_tempvarname()
1646 loopvar = _c_pre.get_tempvarname()
1647 sumvar = _c_pre.get_tempvarname()
1648 listvar = _c_pre.get_tempvarname()
1649 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1650 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1651 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1653 "const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1654 _c_pre.code("/* sumof start */")
1655 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1656 _c_pre.code("%s = 0;", sumvar)
1657 _c_pre.code("%s = %s;", listvar, list_name)
1659 "for (%s = 0; %s < %s; %s++) {",
1660 loopvar, loopvar, lengthvar, loopvar)
1663 # define and set xcb_listelement, so that it can be used by
1664 # listelement-ref expressions.
1665 if expr.contains_listelement_ref:
1667 "const %s *xcb_listelement = %s;",
1668 field.c_field_type, listvar)
1671 if expr.rhs == None:
1672 _c_pre.code("%s += *%s;", sumvar, listvar)
1674 # sumof has a nested expression which
1675 # has to be evaluated in the context of this list element
1677 # field mapping for the subexpression needs to include
1678 # the fields of the list-member type
1679 scoped_field_mapping = field_mapping.copy()
1680 if not field.type.member.is_simple:
1681 scoped_field_mapping.update(
1682 _c_helper_field_mapping(
1684 [(listvar, '->', field.type.member)]))
1686 # cause pre-code of the subexpression be added right here
1688 # compute the subexpression
1689 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1690 # resume with our code
1692 # output the summation expression
1693 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1695 _c_pre.code("%s++;", listvar);
1698 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1701 # return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1702 elif expr.op == 'listelement-ref':
1703 return '(*xcb_listelement)';
1704 elif expr.op != None:
1705 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1706 ' ' + expr.op + ' ' +
1707 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1709 return 'xcb_popcount(' + lenexp + ')'
1713 def type_pad_type(type):
1718 def _c_accessors_field(self, field):
1720 Declares the accessor functions for a non-list field that follows a variable-length field.
1722 c_type = self.c_type
1724 # special case: switch
1725 switch_obj = self if self.is_switch else None
1726 if self.is_case_or_bitcase:
1727 switch_obj = self.parents[-1]
1728 if switch_obj is not None:
1729 c_type = switch_obj.c_type
1731 if field.type.is_simple:
1733 _hc('%s', field.c_field_type)
1734 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1735 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1737 if field.prev_varsized_field is None:
1738 _c(' return (%s *) (R + 1);', field.c_field_type)
1740 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1741 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1742 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1746 if field.type.is_switch and switch_obj is None:
1747 return_type = 'void *'
1749 return_type = '%s *' % field.c_field_type
1752 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1753 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1755 if field.prev_varsized_field is None:
1756 _c(' return (%s) (R + 1);', return_type)
1757 # note: the special case 'variable fields followed by fixed size fields'
1758 # is not of any consequence here, since the ordering gets
1759 # 'corrected' in the reply function
1761 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1762 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1763 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1767 def _c_accessors_list(self, field):
1769 Declares the accessor functions for a list field.
1770 Declares a direct-accessor function only if the list members are fixed size.
1771 Declares length and get-iterator functions always.
1774 def get_align_pad(field):
1775 prev = field.prev_varsized_field
1776 prev_prev = field.prev_varsized_field.prev_varsized_field
1778 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1779 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1785 c_type = self.c_type
1787 # special case: switch
1788 # in case of switch, 2 params have to be supplied to certain accessor functions:
1789 # 1. the anchestor object (request or reply)
1790 # 2. the (anchestor) switch object
1791 # the reason is that switch is either a child of a request/reply or nested in another switch,
1792 # so whenever we need to access a length field, we might need to refer to some anchestor type
1793 switch_obj = self if self.is_switch else None
1794 if self.is_case_or_bitcase:
1795 switch_obj = self.parents[-1]
1796 if switch_obj is not None:
1797 c_type = switch_obj.c_type
1801 parents = self.parents if hasattr(self, 'parents') else [self]
1802 # 'R': parents[0] is always the 'toplevel' container type
1803 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1804 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1805 # auxiliary object for 'R' parameters
1808 if switch_obj is not None:
1809 # now look where the fields are defined that are needed to evaluate
1810 # the switch expr, and store the parent objects in accessor_params and
1811 # the fields in switch_fields
1813 # 'S': name for the 'toplevel' switch
1814 toplevel_switch = parents[1]
1815 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1816 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1818 # initialize prefix for everything "below" S
1819 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1820 prefix = [(prefix_str, '->', toplevel_switch)]
1822 # look for fields in the remaining containers
1823 for p in parents[2:] + [self]:
1824 # the separator between parent and child is always '.' here,
1825 # because of nested switch statements
1826 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1827 prefix.append((p.name[-1], '.', p))
1828 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1830 # auxiliary object for 'S' parameter
1835 if list.member.fixed_size():
1836 idx = 1 if switch_obj is not None else 0
1838 _hc('%s *', field.c_field_type)
1840 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1841 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1844 if switch_obj is not None:
1845 _c(' return %s;', fields[field.c_field_name][0])
1846 elif field.prev_varsized_field is None:
1847 _c(' return (%s *) (R + 1);', field.c_field_type)
1849 (prev_varsized_field, align_pad) = get_align_pad(field)
1851 if align_pad is None:
1852 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1853 type_pad_type(field.first_field_after_varsized.type.c_type))
1855 _c(' xcb_generic_iterator_t prev = %s;',
1856 _c_iterator_get_end(prev_varsized_field, 'R'))
1857 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1858 field.c_field_type, align_pad, field.prev_varsized_offset)
1863 if switch_obj is not None:
1864 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1865 spacing = ' '*(len(field.c_length_name)+2)
1866 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1867 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1869 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1870 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1872 length = _c_accessor_get_expr(field.type.expr, fields)
1873 _c(' return %s;', length)
1876 if field.type.member.is_simple:
1878 _hc('xcb_generic_iterator_t')
1879 if switch_obj is not None:
1880 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1881 spacing = ' '*(len(field.c_end_name)+2)
1882 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1883 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1885 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1886 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1888 _c(' xcb_generic_iterator_t i;')
1890 param = 'R' if switch_obj is None else 'S'
1891 if switch_obj is not None:
1892 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1893 _c_accessor_get_expr(field.type.expr, fields))
1894 elif field.prev_varsized_field == None:
1895 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1896 _c_accessor_get_expr(field.type.expr, fields))
1898 _c(' xcb_generic_iterator_t child = %s;',
1899 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1900 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1901 _c_accessor_get_expr(field.type.expr, fields))
1904 _c(' i.index = (char *) i.data - (char *) %s;', param)
1910 _hc('%s', field.c_iterator_type)
1911 if switch_obj is not None:
1912 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1913 spacing = ' '*(len(field.c_iterator_name)+2)
1914 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1915 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1917 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1918 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1920 _c(' %s i;', field.c_iterator_type)
1923 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1925 if switch_obj is not None:
1927 _c(' i.data = %s;', fields[field.c_field_name][0])
1928 _c(' i.rem = %s;', length_expr_str)
1929 elif field.prev_varsized_field == None:
1931 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1933 (prev_varsized_field, align_pad) = get_align_pad(field)
1935 if align_pad is None:
1936 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1937 type_pad_type(field.c_field_type))
1939 _c(' xcb_generic_iterator_t prev = %s;',
1940 _c_iterator_get_end(prev_varsized_field, 'R'))
1942 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1943 field.c_field_type, align_pad)
1945 if switch_obj is None:
1946 _c(' i.rem = %s;', length_expr_str)
1947 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1951 def _c_accessors(self, name, base):
1953 Declares the accessor functions for the fields of a structure.
1955 # no accessors for switch itself -
1956 # switch always needs to be unpacked explicitly
1957 # if self.is_switch:
1961 for field in self.fields:
1962 if not field.type.is_pad:
1963 if _c_field_needs_list_accessor(field):
1964 _c_accessors_list(self, field)
1965 elif _c_field_needs_field_accessor(field):
1966 _c_accessors_field(self, field)
1968 def c_simple(self, name):
1970 Exported function that handles cardinal type declarations.
1971 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1973 _c_type_setup(self, name, ())
1975 if (self.name != name):
1980 _h('typedef %s %s;', _t(self.name), my_name)
1983 _c_iterator(self, name)
1985 def _c_complex(self, force_packed = False):
1987 Helper function for handling all structure types.
1988 Called for all structs, requests, replies, events, errors.
1993 _h(' * @brief %s', self.c_type)
1995 _h('typedef %s %s {', self.c_container, self.c_type)
2001 for field in self.fields:
2002 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2003 varfield = field.c_field_name
2006 struct_fields.append(field)
2008 for field in struct_fields:
2009 length = len(field.c_field_type)
2010 # account for '*' pointer_spec
2011 if not field.type.fixed_size() and not self.is_union:
2013 maxtypelen = max(maxtypelen, length)
2015 def _c_complex_field(self, field, space=''):
2016 if (field.type.fixed_size() or self.is_union or
2017 # in case of switch with switch children, don't make the field a pointer
2018 # necessary for unserialize to work
2019 (self.is_switch and field.type.is_switch)):
2020 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2021 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2023 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2024 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2026 if not self.is_switch:
2027 for field in struct_fields:
2028 _c_complex_field(self, field)
2030 for b in self.bitcases:
2035 for field in b.type.fields:
2036 _c_complex_field(self, field, space)
2038 _h(' } %s;', b.c_field_name)
2040 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2042 def c_struct(self, name):
2044 Exported function that handles structure declarations.
2046 _c_type_setup(self, name, ())
2048 _c_accessors(self, name, name)
2049 _c_iterator(self, name)
2051 def c_union(self, name):
2053 Exported function that handles union declarations.
2055 _c_type_setup(self, name, ())
2057 _c_iterator(self, name)
2059 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2061 Declares a request function.
2064 # Four stunningly confusing possibilities here:
2067 # ------------------------------
2069 # 0 flag CHECKED flag Normal Mode
2070 # void_cookie req_cookie
2071 # ------------------------------
2072 # "req_checked" "req_unchecked"
2073 # CHECKED flag 0 flag Abnormal Mode
2074 # void_cookie req_cookie
2075 # ------------------------------
2078 # Whether we are _checked or _unchecked
2079 checked = void and not regular
2080 unchecked = not void and not regular
2082 # What kind of cookie we return
2083 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2085 # What flag is passed to xcb_request
2086 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2089 if func_flags == '0':
2090 func_flags = 'XCB_REQUEST_REPLY_FDS'
2092 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2094 # Global extension id variable or NULL for xproto
2095 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2097 # What our function name is
2098 func_name = self.c_request_name if not aux else self.c_aux_name
2100 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2102 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2106 maxtypelen = len('xcb_connection_t')
2108 # special case: list with variable size elements
2109 list_with_var_size_elems = False
2111 for field in self.fields:
2113 # The field should appear as a call parameter
2114 param_fields.append(field)
2115 if field.wire and not field.auto:
2116 # We need to set the field up in the structure
2117 wire_fields.append(field)
2118 if field.type.c_need_serialize or field.type.c_need_sizeof:
2119 serial_fields.append(field)
2121 for field in param_fields:
2122 c_field_const_type = field.c_field_const_type
2123 if field.type.c_need_serialize and not aux:
2124 c_field_const_type = "const void"
2125 if len(c_field_const_type) > maxtypelen:
2126 maxtypelen = len(c_field_const_type)
2127 if field.type.is_list and not field.type.member.fixed_size():
2128 list_with_var_size_elems = True
2134 if hasattr(self, "doc") and self.doc:
2136 _h(' * @brief ' + self.doc.brief)
2138 _h(' * No brief doc yet')
2141 _h(' * @param c The connection')
2142 param_names = [f.c_field_name for f in param_fields]
2143 if hasattr(self, "doc") and self.doc:
2144 for field in param_fields:
2145 # XXX: hard-coded until we fix xproto.xml
2146 base_func_name = self.c_request_name if not aux else self.c_aux_name
2147 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2149 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2151 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2154 # XXX: why the 'xcb' prefix?
2155 key = ('xcb', field.enum)
2158 if namecount[tname] > 1:
2159 tname = _t(key + ('enum',))
2160 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2162 if self.doc and field.field_name in self.doc.fields:
2163 desc = self.doc.fields[field.field_name]
2164 for name in param_names:
2165 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2166 desc = desc.split("\n")
2167 desc = [line if line != '' else '\\n' for line in desc]
2168 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2169 # If there is no documentation yet, we simply don't generate an
2170 # @param tag. Doxygen will then warn about missing documentation.
2172 _h(' * @return A cookie')
2175 if hasattr(self, "doc") and self.doc:
2176 if self.doc.description:
2177 desc = self.doc.description
2178 for name in param_names:
2179 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2180 desc = desc.split("\n")
2181 _h(' * ' + "\n * ".join(desc))
2183 _h(' * No description yet')
2185 _h(' * Delivers a request to the X server.')
2188 _h(' * This form can be used only if the request will not cause')
2189 _h(' * a reply to be generated. Any returned error will be')
2190 _h(' * saved for handling by xcb_request_check().')
2192 _h(' * This form can be used only if the request will cause')
2193 _h(' * a reply to be generated. Any returned error will be')
2194 _h(' * placed in the event queue.')
2197 _hc('%s', cookie_type)
2199 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2200 comma = ',' if len(param_fields) else ');'
2201 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2202 comma = ',' if len(param_fields) else ')'
2203 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2205 func_spacing = ' ' * (len(func_name) + 2)
2206 count = len(param_fields)
2207 for field in param_fields:
2209 c_field_const_type = field.c_field_const_type
2210 c_pointer = field.c_pointer
2211 if field.type.c_need_serialize and not aux:
2212 c_field_const_type = "const void"
2214 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2215 comma = ',' if count else ');'
2216 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2217 spacing, c_pointer, field.c_field_name, comma)
2218 comma = ',' if count else ')'
2219 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2220 spacing, c_pointer, field.c_field_name, comma)
2223 if not self.c_var_followed_by_fixed_fields:
2224 for field in param_fields:
2225 if not field.type.fixed_size():
2227 if field.type.c_need_serialize:
2228 # _serialize() keeps track of padding automatically
2230 dimension = count + 2
2233 _c(' static const xcb_protocol_request_t xcb_req = {')
2234 _c(' /* count */ %d,', count)
2235 _c(' /* ext */ %s,', func_ext_global)
2236 _c(' /* opcode */ %s,', self.c_request_name.upper())
2237 _c(' /* isvoid */ %d', 1 if void else 0)
2241 _c(' struct iovec xcb_parts[%d];', dimension)
2242 _c(' %s xcb_ret;', func_cookie)
2243 _c(' %s xcb_out;', self.c_type)
2244 if self.c_var_followed_by_fixed_fields:
2245 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2246 _c(' void *xcb_aux = 0;')
2249 for idx, f in enumerate(serial_fields):
2251 _c(' void *xcb_aux%d = 0;' % (idx))
2252 if list_with_var_size_elems:
2253 _c(' unsigned int i;')
2254 _c(' unsigned int xcb_tmp_len;')
2255 _c(' char *xcb_tmp;')
2257 # simple request call tracing
2258 # _c(' printf("in function %s\\n");' % func_name)
2261 for field in wire_fields:
2262 if field.type.fixed_size():
2263 if field.type.is_expr:
2264 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2265 elif field.type.is_pad:
2266 if field.type.nmemb == 1:
2267 _c(' xcb_out.%s = 0;', field.c_field_name)
2269 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2271 if field.type.nmemb == 1:
2272 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2274 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2276 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2277 serialize_args = get_serialize_params(context, type_obj,
2280 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2282 # calls in order to free dyn. all. memory
2286 if not self.c_var_followed_by_fixed_fields:
2287 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2288 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2289 _c(' xcb_parts[3].iov_base = 0;')
2290 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2294 for field in param_fields:
2295 if not field.type.fixed_size():
2296 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2297 # default: simple cast to char *
2298 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2299 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2300 if field.type.is_list:
2301 if field.type.member.fixed_size():
2302 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2303 _c_accessor_get_expr(field.type.expr, None),
2304 field.type.member.c_wiretype)
2306 list_length = _c_accessor_get_expr(field.type.expr, None)
2309 _c(" xcb_parts[%d].iov_len = 0;" % count)
2310 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2311 _c(" for(i=0; i<%s; i++) {" % list_length)
2312 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2313 (field.type.c_sizeof_name))
2314 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2315 _c(" xcb_tmp += xcb_tmp_len;")
2318 # not supposed to happen
2319 raise Exception("unhandled variable size field %s" % field.c_field_name)
2322 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2323 idx = serial_fields.index(field)
2324 aux_var = '&xcb_aux%d' % idx
2325 context = 'serialize' if aux else 'sizeof'
2326 _c(' xcb_parts[%d].iov_len =', count)
2328 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2329 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2330 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2331 free_calls.append(' free(xcb_aux%d);' % idx)
2333 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2334 func_name = field.type.c_sizeof_name
2335 _c(' %s (%s);', func_name, serialize_args)
2338 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2339 # the _serialize() function keeps track of padding automatically
2340 _c(' xcb_parts[%d].iov_base = 0;', count)
2341 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2344 # elif self.c_var_followed_by_fixed_fields:
2346 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2347 # request header: opcodes + length
2348 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2351 buffer_var = '&xcb_aux'
2352 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2353 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2354 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2355 free_calls.append(' free(xcb_aux);')
2356 # no padding necessary - _serialize() keeps track of padding automatically
2359 for field in param_fields:
2361 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2363 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2365 # free dyn. all. data, if any
2366 for f in free_calls:
2368 _c(' return xcb_ret;')
2371 def _c_reply(self, name):
2373 Declares the function that returns the reply structure.
2375 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2376 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2377 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2379 # check if _unserialize() has to be called for any field
2380 def look_for_special_cases(complex_obj):
2381 unserialize_fields = []
2382 # no unserialize call in case of switch
2383 if not complex_obj.is_switch:
2384 for field in complex_obj.fields:
2385 # three cases: 1. field with special case
2386 # 2. container that contains special case field
2387 # 3. list with special case elements
2388 if field.type.c_var_followed_by_fixed_fields:
2389 unserialize_fields.append(field)
2390 elif field.type.is_container:
2391 unserialize_fields += look_for_special_cases(field.type)
2392 elif field.type.is_list:
2393 if field.type.member.c_var_followed_by_fixed_fields:
2394 unserialize_fields.append(field)
2395 if field.type.member.is_container:
2396 unserialize_fields += look_for_special_cases(field.type.member)
2397 return unserialize_fields
2399 unserialize_fields = look_for_special_cases(self.reply)
2403 _h(' * Return the reply')
2404 _h(' * @param c The connection')
2405 _h(' * @param cookie The cookie')
2406 _h(' * @param e The xcb_generic_error_t supplied')
2408 _h(' * Returns the reply of the request asked by')
2410 _h(' * The parameter @p e supplied to this function must be NULL if')
2411 _h(' * %s(). is used.', self.c_unchecked_name)
2412 _h(' * Otherwise, it stores the error if any.')
2414 _h(' * The returned value must be freed by the caller using free().')
2417 _hc('%s *', self.c_reply_type)
2418 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2419 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2420 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2421 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2424 if len(unserialize_fields)>0:
2425 # certain variable size fields need to be unserialized explicitly
2426 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2427 self.c_reply_type, self.c_reply_type)
2429 for field in unserialize_fields:
2430 if field.type.is_list:
2431 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2432 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2433 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2435 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2436 # call _unserialize(), using the reply as source and target buffer
2437 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2438 for field in unserialize_fields:
2439 if field.type.is_list:
2440 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2441 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2442 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2443 field.c_field_name, field.c_field_name)
2444 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2446 # return the transformed reply
2447 _c(' return reply;')
2450 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2454 def _c_reply_has_fds(self):
2455 for field in self.fields:
2460 def _c_reply_fds(self, name):
2462 Declares the function that returns fds related to the reply.
2464 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2465 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2468 _h(' * Return the reply fds')
2469 _h(' * @param c The connection')
2470 _h(' * @param reply The reply')
2472 _h(' * Returns the array of reply fds of the request asked by')
2474 _h(' * The returned value must be freed by the caller using free().')
2478 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2479 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2480 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2483 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2488 def _c_opcode(name, opcode):
2490 Declares the opcode define for requests, events, and errors.
2494 _h('/** Opcode for %s. */', _n(name))
2495 _h('#define %s %s', _n(name).upper(), opcode)
2497 def _c_cookie(self, name):
2499 Declares the cookie type for a non-void request.
2504 _h(' * @brief %s', self.c_cookie_type)
2506 _h('typedef struct %s {', self.c_cookie_type)
2507 _h(' unsigned int sequence; /**< */')
2508 _h('} %s;', self.c_cookie_type)
2510 def _man_request(self, name, cookie_type, void, aux):
2511 param_fields = [f for f in self.fields if f.visible]
2513 func_name = self.c_request_name if not aux else self.c_aux_name
2515 def create_link(linkname):
2516 name = 'man/%s.%s' % (linkname, section)
2518 sys.stdout.write(name)
2520 f.write('.so man%s/%s.%s' % (section, func_name, section))
2524 sys.stdout.write('man/%s.%s ' % (func_name, section))
2525 # Our CWD is src/, so this will end up in src/man/
2526 f = open('man/%s.%s' % (func_name, section), 'w')
2527 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2528 # Left-adjust instead of adjusting to both sides
2530 f.write('.SH NAME\n')
2531 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2532 f.write('%s \\- %s\n' % (func_name, brief))
2533 f.write('.SH SYNOPSIS\n')
2534 # Don't split words (hyphenate)
2536 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2538 # function prototypes
2540 count = len(param_fields)
2541 for field in param_fields:
2543 c_field_const_type = field.c_field_const_type
2544 c_pointer = field.c_pointer
2545 if c_pointer == ' ':
2547 if field.type.c_need_serialize and not aux:
2548 c_field_const_type = "const void"
2550 comma = ', ' if count else ');'
2551 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2553 f.write('.SS Request function\n')
2555 base_func_name = self.c_request_name if not aux else self.c_aux_name
2556 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2557 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2560 f.write('.SS Reply datastructure\n')
2563 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2567 for field in self.reply.fields:
2568 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2571 struct_fields.append(field)
2573 for field in struct_fields:
2574 length = len(field.c_field_type)
2575 # account for '*' pointer_spec
2576 if not field.type.fixed_size():
2578 maxtypelen = max(maxtypelen, length)
2580 def _c_complex_field(self, field, space=''):
2581 if (field.type.fixed_size() or
2582 # in case of switch with switch children, don't make the field a pointer
2583 # necessary for unserialize to work
2584 (self.is_switch and field.type.is_switch)):
2585 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2586 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2588 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2589 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2590 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2592 if not self.is_switch:
2593 for field in struct_fields:
2594 _c_complex_field(self, field)
2596 for b in self.bitcases:
2600 for field in b.type.fields:
2601 _c_complex_field(self, field, space)
2603 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2606 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2609 f.write('.SS Reply function\n')
2611 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2612 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2613 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2614 create_link('%s' % self.c_reply_name)
2616 has_accessors = False
2617 for field in self.reply.fields:
2618 if field.type.is_list and not field.type.fixed_size():
2619 has_accessors = True
2620 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2621 has_accessors = True
2624 f.write('.SS Reply accessors\n')
2626 def _c_accessors_field(self, field):
2628 Declares the accessor functions for a non-list field that follows a variable-length field.
2630 c_type = self.c_type
2632 # special case: switch
2633 switch_obj = self if self.is_switch else None
2634 if self.is_case_or_bitcase:
2635 switch_obj = self.parents[-1]
2636 if switch_obj is not None:
2637 c_type = switch_obj.c_type
2639 if field.type.is_simple:
2640 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2641 create_link('%s' % field.c_accessor_name)
2643 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2644 create_link('%s' % field.c_accessor_name)
2646 def _c_accessors_list(self, field):
2648 Declares the accessor functions for a list field.
2649 Declares a direct-accessor function only if the list members are fixed size.
2650 Declares length and get-iterator functions always.
2653 c_type = self.reply.c_type
2655 # special case: switch
2656 # in case of switch, 2 params have to be supplied to certain accessor functions:
2657 # 1. the anchestor object (request or reply)
2658 # 2. the (anchestor) switch object
2659 # the reason is that switch is either a child of a request/reply or nested in another switch,
2660 # so whenever we need to access a length field, we might need to refer to some anchestor type
2661 switch_obj = self if self.is_switch else None
2662 if self.is_case_or_bitcase:
2663 switch_obj = self.parents[-1]
2664 if switch_obj is not None:
2665 c_type = switch_obj.c_type
2669 parents = self.parents if hasattr(self, 'parents') else [self]
2670 # 'R': parents[0] is always the 'toplevel' container type
2671 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2672 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2673 # auxiliary object for 'R' parameters
2676 if switch_obj is not None:
2677 # now look where the fields are defined that are needed to evaluate
2678 # the switch expr, and store the parent objects in accessor_params and
2679 # the fields in switch_fields
2681 # 'S': name for the 'toplevel' switch
2682 toplevel_switch = parents[1]
2683 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2684 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2686 # initialize prefix for everything "below" S
2687 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2688 prefix = [(prefix_str, '->', toplevel_switch)]
2690 # look for fields in the remaining containers
2691 for p in parents[2:] + [self]:
2692 # the separator between parent and child is always '.' here,
2693 # because of nested switch statements
2694 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2695 prefix.append((p.name[-1], '.', p))
2696 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2698 # auxiliary object for 'S' parameter
2701 if list.member.fixed_size():
2702 idx = 1 if switch_obj is not None else 0
2704 f.write('%s *\\fB%s\\fP(%s);\n' %
2705 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2706 create_link('%s' % field.c_accessor_name)
2709 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2710 (field.c_length_name, c_type))
2711 create_link('%s' % field.c_length_name)
2713 if field.type.member.is_simple:
2715 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2716 (field.c_end_name, c_type))
2717 create_link('%s' % field.c_end_name)
2720 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2721 (field.c_iterator_type, field.c_iterator_name,
2723 create_link('%s' % field.c_iterator_name)
2725 for field in self.reply.fields:
2726 if field.type.is_list and not field.type.fixed_size():
2727 _c_accessors_list(self, field)
2728 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2729 _c_accessors_field(self, field)
2733 # Re-enable hyphenation and adjusting to both sides
2736 # argument reference
2737 f.write('.SH REQUEST ARGUMENTS\n')
2738 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2739 f.write('The XCB connection to X11.\n')
2740 for field in param_fields:
2741 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2742 printed_enum = False
2743 # XXX: hard-coded until we fix xproto.xml
2744 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2746 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2748 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2750 if hasattr(field, "enum") and field.enum:
2751 # XXX: why the 'xcb' prefix?
2752 key = ('xcb', field.enum)
2754 f.write('One of the following values:\n')
2757 count = len(enum.values)
2758 for (enam, eval) in enum.values:
2760 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2761 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2762 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2763 f.write('%s\n' % desc)
2765 f.write('TODO: NOT YET DOCUMENTED.\n')
2770 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2771 desc = self.doc.fields[field.field_name]
2772 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2775 f.write('%s\n' % desc)
2777 f.write('TODO: NOT YET DOCUMENTED.\n')
2783 f.write('.SH REPLY FIELDS\n')
2784 # These fields are present in every reply:
2785 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2786 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2787 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2788 'be used to tell replies apart from each other.\n') %
2789 _n(self.reply.name).upper())
2790 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2791 f.write('The sequence number of the last request processed by the X11 server.\n')
2792 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2793 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2794 for field in self.reply.fields:
2795 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2796 field.c_field_name.startswith('pad')):
2799 if field.type.is_list and not field.type.fixed_size():
2801 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2803 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2804 printed_enum = False
2805 if hasattr(field, "enum") and field.enum:
2806 # XXX: why the 'xcb' prefix?
2807 key = ('xcb', field.enum)
2809 f.write('One of the following values:\n')
2812 count = len(enum.values)
2813 for (enam, eval) in enum.values:
2815 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2816 if enum.doc and enam in enum.doc.fields:
2817 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2818 f.write('%s\n' % desc)
2820 f.write('TODO: NOT YET DOCUMENTED.\n')
2825 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2826 desc = self.reply.doc.fields[field.field_name]
2827 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2830 f.write('%s\n' % desc)
2832 f.write('TODO: NOT YET DOCUMENTED.\n')
2839 f.write('.SH DESCRIPTION\n')
2840 if hasattr(self, "doc") and self.doc and self.doc.description:
2841 desc = self.doc.description
2842 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2843 lines = desc.split('\n')
2844 f.write('\n'.join(lines) + '\n')
2846 f.write('.SH RETURN VALUE\n')
2848 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2849 'have to be handled in the event loop.\n\nIf you want to '
2850 'handle errors directly with \\fIxcb_request_check\\fP '
2851 'instead, use \\fI%s_checked\\fP. See '
2852 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2854 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2855 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2856 'handle errors in the event loop instead, use '
2857 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2859 (cookie_type, self.c_reply_name, base_func_name, section))
2860 f.write('.SH ERRORS\n')
2861 if hasattr(self, "doc") and self.doc:
2862 for errtype, errtext in sorted(self.doc.errors.items()):
2863 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2864 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2865 f.write('%s\n' % (errtext))
2866 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2867 f.write('This request does never generate any errors.\n')
2868 if hasattr(self, "doc") and self.doc and self.doc.example:
2869 f.write('.SH EXAMPLE\n')
2872 lines = self.doc.example.split('\n')
2873 f.write('\n'.join(lines) + '\n')
2875 f.write('.SH SEE ALSO\n')
2876 if hasattr(self, "doc") and self.doc:
2877 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2878 if self.doc.example:
2879 see.append('.BR %s (%s)' % ('xcb-examples', section))
2880 for seename, seetype in sorted(self.doc.see.items()):
2881 if seetype == 'program':
2882 see.append('.BR %s (1)' % seename)
2883 elif seetype == 'event':
2884 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2885 elif seetype == 'request':
2886 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2887 elif seetype == 'function':
2888 see.append('.BR %s (%s)' % (seename, section))
2890 see.append('TODO: %s (type %s)' % (seename, seetype))
2891 f.write(',\n'.join(see) + '\n')
2892 f.write('.SH AUTHOR\n')
2893 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2896 def _man_event(self, name):
2898 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2899 # Our CWD is src/, so this will end up in src/man/
2900 f = open('man/%s.%s' % (self.c_type, section), 'w')
2901 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2902 # Left-adjust instead of adjusting to both sides
2904 f.write('.SH NAME\n')
2905 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2906 f.write('%s \\- %s\n' % (self.c_type, brief))
2907 f.write('.SH SYNOPSIS\n')
2908 # Don't split words (hyphenate)
2910 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2913 f.write('.SS Event datastructure\n')
2916 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2920 for field in self.fields:
2921 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2924 struct_fields.append(field)
2926 for field in struct_fields:
2927 length = len(field.c_field_type)
2928 # account for '*' pointer_spec
2929 if not field.type.fixed_size():
2931 maxtypelen = max(maxtypelen, length)
2933 def _c_complex_field(self, field, space=''):
2934 if (field.type.fixed_size() or
2935 # in case of switch with switch children, don't make the field a pointer
2936 # necessary for unserialize to work
2937 (self.is_switch and field.type.is_switch)):
2938 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2939 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2941 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2943 if not self.is_switch:
2944 for field in struct_fields:
2945 _c_complex_field(self, field)
2947 for b in self.bitcases:
2951 for field in b.type.fields:
2952 _c_complex_field(self, field, space)
2954 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2957 f.write('} \\fB%s\\fP;\n' % self.c_type)
2962 # Re-enable hyphenation and adjusting to both sides
2965 # argument reference
2966 f.write('.SH EVENT FIELDS\n')
2967 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2968 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2969 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2970 'to tell events apart from each other.\n') % _n(name).upper())
2971 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2972 f.write('The sequence number of the last request processed by the X11 server.\n')
2974 if not self.is_switch:
2975 for field in struct_fields:
2976 # Skip the fields which every event has, we already documented
2978 if field.c_field_name in ('response_type', 'sequence'):
2980 if isinstance(field.type, PadType):
2982 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2983 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2984 desc = self.doc.fields[field.field_name]
2985 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2986 f.write('%s\n' % desc)
2988 f.write('NOT YET DOCUMENTED.\n')
2991 f.write('.SH DESCRIPTION\n')
2992 if hasattr(self, "doc") and self.doc and self.doc.description:
2993 desc = self.doc.description
2994 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2995 lines = desc.split('\n')
2996 f.write('\n'.join(lines) + '\n')
2998 if hasattr(self, "doc") and self.doc and self.doc.example:
2999 f.write('.SH EXAMPLE\n')
3002 lines = self.doc.example.split('\n')
3003 f.write('\n'.join(lines) + '\n')
3005 f.write('.SH SEE ALSO\n')
3006 if hasattr(self, "doc") and self.doc:
3007 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
3008 if self.doc.example:
3009 see.append('.BR %s (%s)' % ('xcb-examples', section))
3010 for seename, seetype in sorted(self.doc.see.items()):
3011 if seetype == 'program':
3012 see.append('.BR %s (1)' % seename)
3013 elif seetype == 'event':
3014 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
3015 elif seetype == 'request':
3016 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
3017 elif seetype == 'function':
3018 see.append('.BR %s (%s)' % (seename, section))
3020 see.append('TODO: %s (type %s)' % (seename, seetype))
3021 f.write(',\n'.join(see) + '\n')
3022 f.write('.SH AUTHOR\n')
3023 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3027 def c_request(self, name):
3029 Exported function that handles request declarations.
3031 _c_type_setup(self, name, ('request',))
3034 # Cookie type declaration
3035 _c_cookie(self, name)
3038 _c_opcode(name, self.opcode)
3040 # Request structure declaration
3044 _c_type_setup(self.reply, name, ('reply',))
3045 # Reply structure definition
3046 _c_complex(self.reply)
3047 # Request prototypes
3048 has_fds = _c_reply_has_fds(self.reply)
3049 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3050 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3052 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3053 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3055 _c_accessors(self.reply, name + ('reply',), name)
3056 _c_reply(self, name)
3058 _c_reply_fds(self, name)
3060 # Request prototypes
3061 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3062 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3064 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3065 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3067 # We generate the manpage afterwards because _c_type_setup has been called.
3068 # TODO: what about aux helpers?
3069 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3070 _man_request(self, name, cookie_type, not self.reply, False)
3072 def c_event(self, name):
3074 Exported function that handles event declarations.
3077 # The generic event structure xcb_ge_event_t has the full_sequence field
3078 # at the 32byte boundary. That's why we've to inject this field into GE
3079 # events while generating the structure for them. Otherwise we would read
3080 # garbage (the internal full_sequence) when accessing normal event fields
3082 force_packed = False
3083 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3085 for field in self.fields:
3086 if field.type.size != None and field.type.nmemb != None:
3087 event_size += field.type.size * field.type.nmemb
3088 if event_size == 32:
3089 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3090 idx = self.fields.index(field)
3091 self.fields.insert(idx + 1, full_sequence)
3093 # If the event contains any 64-bit extended fields, they need
3094 # to remain aligned on a 64-bit boundary. Adding full_sequence
3095 # would normally break that; force the struct to be packed.
3096 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3099 if self.name == name:
3100 _c_type_setup(self, name, ('event',))
3101 # generate accessors
3102 # (needed for fields after var-sized fields, for lists with var-sized elements,
3104 _c_accessors(self, name, name)
3106 # no type-setup needed for eventcopies
3107 # (the type-setup of an eventcopy would overwrite members of the original
3108 # event, and it would create sizeof-etc funtions which
3109 # called undefined accessor functions)
3113 _c_opcode(name, self.opcodes[name])
3115 if self.name == name:
3116 # Structure definition
3117 _c_complex(self, force_packed)
3121 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3123 # Create sizeof-function for eventcopies for compatibility reasons
3124 if self.c_need_sizeof:
3129 _h('%s (const void *_buffer /**< */);', _n(name + ('sizeof',)))
3132 _c('%s (const void *_buffer /**< */)', _n(name + ('sizeof',)))
3134 _c(' return %s(_buffer);', _n(self.name + ('sizeof',)))
3139 _man_event(self, name)
3141 def c_error(self, name):
3143 Exported function that handles error declarations.
3145 _c_type_setup(self, name, ('error',))
3148 _c_opcode(name, self.opcodes[name])
3150 if self.name == name:
3151 # Structure definition
3156 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3159 # Main routine starts here
3161 # Must create an "output" dictionary before any xcbgen imports.
3162 output = {'open' : c_open,
3164 'simple' : c_simple,
3166 'struct' : c_struct,
3168 'request' : c_request,
3173 # Boilerplate below this point
3175 # Check for the argument that specifies path to the xcbgen python package.
3177 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3178 except getopt.GetoptError as err:
3180 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3183 for (opt, arg) in opts:
3191 sys.path.insert(1, arg)
3194 sys.stdout.write('man_MANS = ')
3196 # Import the module class
3198 from xcbgen.state import Module
3199 from xcbgen.xtypes import *
3202 Failed to load the xcbgen Python package!
3203 Make sure that xcb/proto installed it on your Python path.
3204 If not, you will need to create a .pth file or define $PYTHONPATH
3206 Refer to the README file in xcb/proto for more info.
3210 # Ensure the man subdirectory exists
3213 except OSError as e:
3214 if e.errno != errno.EEXIST:
3217 # Parse the xml header
3218 module = Module(args[0], output)
3220 # Build type-registry and resolve type dependencies