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 _c_type_setup(field.type, field.field_type, ())
437 if field.type.is_list:
438 _c_type_setup(field.type.member, field.field_type, ())
439 if (field.type.nmemb is None):
440 self.c_need_sizeof = True
442 field.c_field_type = _t(field.field_type)
443 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
444 field.c_field_name = _cpp(field.field_name)
445 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
446 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
448 # correct the c_pointer field for variable size non-list types
449 if not field.type.fixed_size() and field.c_pointer == ' ':
450 field.c_pointer = '*'
451 if field.type.is_list and not field.type.member.fixed_size():
452 field.c_pointer = '*'
454 if field.type.is_switch:
455 field.c_pointer = '*'
456 field.c_field_const_type = 'const ' + field.c_field_type
457 self.c_need_aux = True
459 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
460 self.c_need_sizeof = True
462 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
463 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
464 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
465 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
466 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
468 field.prev_varsized_field = prev_varsized_field
469 field.prev_varsized_offset = prev_varsized_offset
471 if prev_varsized_offset == 0:
472 first_field_after_varsized = field
473 field.first_field_after_varsized = first_field_after_varsized
475 if field.type.fixed_size():
476 prev_varsized_offset += field.type.size
477 # special case: intermixed fixed and variable size fields
478 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
479 if not self.is_union:
480 self.c_need_serialize = True
481 self.c_var_followed_by_fixed_fields = True
483 self.last_varsized_field = field
484 prev_varsized_field = field
485 prev_varsized_offset = 0
487 if self.c_var_followed_by_fixed_fields:
488 if field.type.fixed_size():
489 field.prev_varsized_field = None
491 if self.c_need_serialize:
492 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
493 self.c_need_sizeof = True
495 # as switch does never appear at toplevel,
496 # continue here with type construction
498 if self.c_type not in finished_switch:
499 finished_switch.append(self.c_type)
500 # special: switch C structs get pointer fields for variable-sized members
502 for bitcase in self.bitcases:
503 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
504 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
505 # no list with switch as element, so no call to
506 # _c_iterator(field.type, field_name) necessary
508 if not self.is_case_or_bitcase:
509 if self.c_need_serialize:
510 if self.c_serialize_name not in finished_serializers:
511 finished_serializers.append(self.c_serialize_name)
512 _c_serialize('serialize', self)
514 # _unpack() and _unserialize() are only needed for special cases:
516 # special cases -> unserialize
517 if self.is_switch or self.c_var_followed_by_fixed_fields:
518 _c_serialize('unserialize', self)
520 if self.c_need_sizeof:
521 if self.c_sizeof_name not in finished_sizeof:
522 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
523 finished_sizeof.append(self.c_sizeof_name)
524 _c_serialize('sizeof', self)
527 def _c_helper_absolute_name(prefix, field=None):
529 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
530 representing a valid name in C (based on the context)
531 if field is not None, append the field name as well
535 for name, sep, obj in prefix:
537 prefix_str += last_sep
541 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
542 (obj.is_switch and len(obj.parents)>1)):
546 prefix_str_without_lastsep = prefix_str
547 prefix_str += last_sep
549 if field is not None:
550 prefix_str += _cpp(field.field_name)
555 and hasattr(field, 'c_accessor_name')
556 and field.parent is not None
557 and field.parent.is_container
558 and not field.parent.is_switch
559 and not field.parent.is_case_or_bitcase
560 and (# the following conditions are taken from _c_accessors()
561 (field.type.is_list and not field.type.fixed_size())
563 (field.prev_varsized_field is not None
564 or not field.type.fixed_size()
568 prefix_str = field.c_accessor_name + "(" + prefix_str_without_lastsep + ")";
573 def _c_helper_field_mapping(complex_type, prefix, flat=False):
575 generate absolute names, based on prefix, for all fields starting from complex_type
576 if flat == True, nested complex types are not taken into account
579 if complex_type.is_switch:
580 for b in complex_type.bitcases:
582 switch_name, switch_sep, switch_type = prefix[-1]
583 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
585 bitcase_prefix = prefix
587 if (True==flat and not b.type.has_name) or False==flat:
588 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
590 for f in complex_type.fields:
591 fname = _c_helper_absolute_name(prefix, f)
592 if f.field_name in all_fields:
593 raise Exception("field name %s has been registered before" % f.field_name)
595 all_fields[f.field_name] = (fname, f)
596 if f.type.is_container and flat==False:
597 if f.type.is_case_or_bitcase and not f.type.has_name:
599 elif f.type.is_switch and len(f.type.parents)>1:
600 # nested switch gets another separator
601 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
603 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
604 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
609 def _c_helper_resolve_field_names (prefix):
611 get field names for all objects in the prefix array
615 # look for fields in the remaining containers
616 for idx, p in enumerate(prefix):
619 # sep can be preset in prefix, if not, make a sensible guess
620 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
621 # exception: 'toplevel' object (switch as well!) always have sep '->'
622 sep = '->' if idx<1 else sep
623 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
624 tmp_prefix.append((name, sep, obj))
625 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
628 # _c_helper_resolve_field_names
630 def get_expr_fields(self):
632 get the Fields referenced by switch or list expression
634 def get_expr_field_names(expr):
636 if expr.lenfield_name is not None:
637 return [expr.lenfield_name]
639 # constant value expr
643 return get_expr_field_names(expr.rhs)
644 elif expr.op == 'popcount':
645 return get_expr_field_names(expr.rhs)
646 elif expr.op == 'sumof':
647 # sumof expr references another list,
648 # we need that list's length field here
650 for f in expr.lenfield_parent.fields:
651 if f.field_name == expr.lenfield_name:
655 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
656 # referenced list + its length field
657 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
658 elif expr.op == 'enumref':
661 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
662 # get_expr_field_names()
664 # resolve the field names with the parent structure(s)
665 unresolved_fields_names = get_expr_field_names(self.expr)
667 # construct prefix from self
668 prefix = [('', '', p) for p in self.parents]
669 if self.is_container:
670 prefix.append(('', '', self))
672 all_fields = _c_helper_resolve_field_names (prefix)
673 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
674 if len(unresolved_fields_names) != len(resolved_fields_names):
675 raise Exception("could not resolve all fields for %s" % self.name)
677 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
678 return resolved_fields
681 def resolve_expr_fields(complex_obj):
683 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
684 these are normally fields that need to be given as function parameters
690 for field in complex_obj.fields:
691 all_fields.append(field)
692 if field.type.is_switch or field.type.is_list:
693 expr_fields += get_expr_fields(field.type)
694 if field.type.is_container:
695 expr_fields += resolve_expr_fields(field.type)
697 # try to resolve expr fields
698 for e in expr_fields:
699 if e not in all_fields and e not in unresolved:
702 # resolve_expr_fields()
704 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
706 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
707 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
708 expression. This function tries to resolve all fields within a structure, and returns the
709 unresolved fields as the list of external parameters.
711 def add_param(params, param):
712 if param not in params:
715 # collect all fields into param_fields
719 for field in self.fields:
721 # the field should appear as a parameter in the function call
722 param_fields.append(field)
723 if field.wire and not field.auto:
724 if field.type.fixed_size() and not self.is_switch:
725 # field in the xcb_out structure
726 wire_fields.append(field)
727 # fields like 'pad0' are skipped!
729 # in case of switch, parameters always contain any fields referenced in the switch expr
730 # we do not need any variable size fields here, as the switch data type contains both
731 # fixed and variable size fields
733 param_fields = get_expr_fields(self)
735 # _serialize()/_unserialize()/_unpack() function parameters
736 # note: don't use set() for params, it is unsorted
739 # 1. the parameter for the void * buffer
740 if 'serialize' == context:
741 params.append(('void', '**', buffer_var))
742 elif context in ('unserialize', 'unpack', 'sizeof'):
743 params.append(('const void', '*', buffer_var))
745 # 2. any expr fields that cannot be resolved within self and descendants
746 unresolved_fields = resolve_expr_fields(self)
747 for f in unresolved_fields:
748 add_param(params, (f.c_field_type, '', f.c_field_name))
750 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
751 # that do not appear in the data type struct
752 for p in param_fields:
754 typespec = p.c_field_const_type
755 pointerspec = p.c_pointer
756 add_param(params, (typespec, pointerspec, p.c_field_name))
758 if p.visible and not p.wire and not p.auto:
759 typespec = p.c_field_type
761 add_param(params, (typespec, pointerspec, p.c_field_name))
764 if 'serialize' == context:
765 add_param(params, ('const %s' % self.c_type, '*', aux_var))
766 elif 'unserialize' == context:
767 add_param(params, ('%s' % self.c_type, '**', aux_var))
768 elif 'unpack' == context:
769 add_param(params, ('%s' % self.c_type, '*', aux_var))
771 # 5. switch contains all variable size fields as struct members
772 # for other data types though, these have to be supplied separately
773 # this is important for the special case of intermixed fixed and
774 # variable size fields
775 if not self.is_switch and 'serialize' == context:
776 for p in param_fields:
777 if not p.type.fixed_size():
778 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
780 return (param_fields, wire_fields, params)
781 # get_serialize_params()
783 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
784 code_lines.append('%s /* insert padding */' % space)
785 if is_case_or_bitcase:
787 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
791 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
792 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
793 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
796 code_lines.append('%s if (0 != xcb_pad) {' % space)
798 if 'serialize' == context:
799 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
800 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
801 code_lines.append('%s xcb_parts_idx++;' % space)
802 elif context in ('unserialize', 'unpack', 'sizeof'):
803 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
805 code_lines.append('%s xcb_pad = 0;' % space)
806 code_lines.append('%s }' % space)
808 code_lines.append('%s xcb_block_len = 0;' % space)
809 if is_case_or_bitcase:
810 code_lines.append('%s xcb_padding_offset = 0;' % space)
812 # keep tracking of xcb_parts entries for serialize
814 # _c_serialize_helper_insert_padding()
816 def _c_serialize_helper_switch(context, self, complex_name,
817 code_lines, temp_vars,
820 switch_expr = _c_accessor_get_expr(self.expr, None)
822 for b in self.bitcases:
823 len_expr = len(b.type.expr)
825 compare_operator = '&'
827 compare_operator = '=='
829 compare_operator = '&'
831 for n, expr in enumerate(b.type.expr):
832 bitcase_expr = _c_accessor_get_expr(expr, None)
833 # only one <enumref> in the <bitcase>
836 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
837 # multiple <enumref> in the <bitcase>
840 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
841 elif len_expr == (n + 1): # last
843 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
844 else: # between first and last
846 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
850 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
852 count += _c_serialize_helper_fields(context, b.type,
853 code_lines, temp_vars,
856 is_case_or_bitcase = True)
857 code_lines.append(' }')
859 # if 'serialize' == context:
860 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
861 # elif context in ('unserialize', 'unpack', 'sizeof'):
863 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
864 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
867 # _c_serialize_helper_switch
869 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
871 handle switch by calling _serialize() or _unpack(), depending on context
873 # switch is handled by this function as a special case
874 param_fields, wire_fields, params = get_serialize_params(context, self)
875 field_mapping = _c_helper_field_mapping(self, prefix)
876 prefix_str = _c_helper_absolute_name(prefix)
878 # find the parameters that need to be passed to _serialize()/_unpack():
879 # all switch expr fields must be given as parameters
880 args = get_expr_fields(field.type)
881 # length fields for variable size types in switch, normally only some of need
882 # need to be passed as parameters
883 switch_len_fields = resolve_expr_fields(field.type)
885 # a switch field at this point _must_ be a bitcase field
886 # we require that bitcases are "self-contiguous"
887 bitcase_unresolved = resolve_expr_fields(self)
888 if len(bitcase_unresolved) != 0:
889 raise Exception('unresolved fields within bitcase is not supported at this point')
891 # get the C names for the parameters
893 for a in switch_len_fields:
894 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
896 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
898 # call _serialize()/_unpack() to determine the actual size
899 if 'serialize' == context:
900 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
901 c_field_names, prefix_str, field.c_field_name)
902 elif context in ('unserialize', 'unpack'):
903 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
904 c_field_names, prefix_str, field.c_field_name)
905 elif 'sizeof' == context:
906 # remove trailing ", " from c_field_names because it will be used at end of arglist
907 my_c_field_names = c_field_names[:-2]
908 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
911 # _c_serialize_helper_switch_field()
913 def _c_serialize_helper_list_field(context, self, field,
914 code_lines, temp_vars,
917 helper function to cope with lists of variable length
919 expr = field.type.expr
920 prefix_str = _c_helper_absolute_name(prefix)
921 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
922 param_names = [p[2] for p in params]
924 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
925 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
926 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
930 field_mapping[r] = (r, None)
932 if len(unresolved)>0:
934 if len(tmp_prefix)==0:
935 raise Exception("found an empty prefix while resolving expr field names for list %s",
938 field_mapping.update(_c_helper_resolve_field_names(prefix))
939 resolved += list(filter(lambda x: x in field_mapping, unresolved))
940 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
941 if len(unresolved)>0:
942 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
944 list_length = _c_accessor_get_expr(expr, field_mapping)
946 # default: list with fixed size elements
947 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
949 # list with variable-sized elements
950 if not field.type.member.fixed_size():
952 if context in ('unserialize', 'sizeof', 'unpack'):
953 int_i = ' unsigned int i;'
954 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
955 if int_i not in temp_vars:
956 temp_vars.append(int_i)
957 if xcb_tmp_len not in temp_vars:
958 temp_vars.append(xcb_tmp_len)
959 # loop over all list elements and call sizeof repeatedly
960 # this should be a bit faster than using the iterators
961 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
962 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
963 (space, field.type.c_sizeof_name))
964 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
965 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
966 code_lines.append("%s }" % space)
968 elif 'serialize' == context:
969 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
970 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
971 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
972 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
973 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
974 code_lines.append('%s }' % space)
975 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
978 # _c_serialize_helper_list_field()
980 def _c_serialize_helper_fields_fixed_size(context, self, field,
981 code_lines, temp_vars,
983 # keep the C code a bit more readable by giving the field name
984 if not self.is_case_or_bitcase:
985 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
987 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
988 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
989 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
991 abs_field_name = _c_helper_absolute_name(prefix, field)
992 # default for simple cases: call sizeof()
993 length = "sizeof(%s)" % field.c_field_type
995 if context in ('unserialize', 'unpack', 'sizeof'):
996 # default: simple cast
997 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
999 # padding - we could probably just ignore it
1000 if field.type.is_pad and field.type.nmemb > 1:
1002 for i in range(field.type.nmemb):
1003 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1004 (space, abs_field_name, i, field.c_field_type))
1005 # total padding = sizeof(pad0) * nmemb
1006 length += " * %d" % field.type.nmemb
1008 elif field.type.is_list:
1009 # list with fixed number of elements
1010 # length of array = sizeof(arrayElementType) * nmemb
1011 length += " * %d" % field.type.nmemb
1012 # use memcpy because C cannot assign whole arrays with operator=
1013 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1016 elif 'serialize' == context:
1017 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1019 if field.type.is_expr:
1020 # need to register a temporary variable for the expression in case we know its type
1021 if field.type.c_type is None:
1022 raise Exception("type for field '%s' (expression '%s') unkown" %
1023 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1025 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1026 _c_accessor_get_expr(field.type.expr, prefix)))
1027 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1029 elif field.type.is_pad:
1030 if field.type.nmemb == 1:
1031 value += "&xcb_pad;"
1033 # we could also set it to 0, see definition of xcb_send_request()
1034 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1035 length += "*%d" % field.type.nmemb
1038 # non-list type with fixed size
1039 if field.type.nmemb == 1:
1040 value += "&%s;" % (abs_field_name)
1042 # list with nmemb (fixed size) elements
1044 value += '%s;' % (abs_field_name)
1045 length = '%d' % field.type.nmemb
1047 return (value, length)
1048 # _c_serialize_helper_fields_fixed_size()
1050 def _c_serialize_helper_fields_variable_size(context, self, field,
1051 code_lines, temp_vars,
1053 prefix_str = _c_helper_absolute_name(prefix)
1055 if context in ('unserialize', 'unpack', 'sizeof'):
1057 var_field_name = 'xcb_tmp'
1059 # special case: intermixed fixed and variable size fields
1060 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1061 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1062 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1063 # special case: switch
1064 if 'unpack' == context:
1065 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1067 elif 'serialize' == context:
1068 # variable size fields appear as parameters to _serialize() if the
1069 # 'toplevel' container is not a switch
1070 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1071 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1072 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1076 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1078 if field.type.is_list:
1080 # in any context, list is already a pointer, so the default assignment is ok
1081 code_lines.append("%s%s" % (space, value))
1083 length = _c_serialize_helper_list_field(context, self, field,
1084 code_lines, temp_vars,
1087 elif field.type.is_switch:
1089 if context == 'serialize':
1090 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1091 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1092 length = _c_serialize_helper_switch_field(context, self, field,
1093 'xcb_parts[xcb_parts_idx].iov_base',
1097 # in all remaining special cases - call _sizeof()
1098 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1100 return (value, length)
1101 # _c_serialize_helper_fields_variable_size
1103 def _c_serialize_helper_fields(context, self,
1104 code_lines, temp_vars,
1105 space, prefix, is_case_or_bitcase):
1107 need_padding = False
1108 prev_field_was_variable = False
1110 _c_pre.push_indent(space + ' ')
1112 for field in self.fields:
1113 if not field.visible:
1114 if not ((field.wire and not field.auto) or 'unserialize' == context):
1117 # switch/bitcase: fixed size fields must be considered explicitly
1118 if field.type.fixed_size():
1119 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1120 if prev_field_was_variable and need_padding:
1122 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1123 # self.c_var_followed_by_fixed_fields)
1124 prev_field_was_variable = False
1126 # prefix for fixed size fields
1127 fixed_prefix = prefix
1129 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1130 code_lines, temp_vars,
1131 space, fixed_prefix)
1135 # fields with variable size
1137 if field.type.is_pad:
1138 # Variable length pad is <pad align= />
1139 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1140 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1141 self.c_var_followed_by_fixed_fields,
1145 # switch/bitcase: always calculate padding before and after variable sized fields
1146 if need_padding or is_case_or_bitcase:
1147 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1148 self.c_var_followed_by_fixed_fields,
1151 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1152 code_lines, temp_vars,
1154 prev_field_was_variable = True
1156 # save (un)serialization C code
1158 code_lines.append('%s%s' % (space, value))
1160 if field.type.fixed_size():
1161 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1162 # keep track of (un)serialized object's size
1163 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1164 if context in ('unserialize', 'unpack', 'sizeof'):
1165 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1167 # variable size objects or bitcase:
1168 # value & length might have been inserted earlier for special cases
1170 # special case: intermixed fixed and variable size fields
1171 if (not field.type.fixed_size() and
1172 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1173 temp_vars.append(' int %s_len;' % field.c_field_name)
1174 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1175 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1176 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1178 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1179 # increase pointer into the byte stream accordingly
1180 if context in ('unserialize', 'sizeof', 'unpack'):
1181 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1183 if 'serialize' == context:
1185 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1186 code_lines.append('%s xcb_parts_idx++;' % space)
1190 '%s xcb_align_to = ALIGNOF(%s);'
1193 if field.c_field_type == 'void' or field.type.is_switch
1194 else field.c_field_type))
1197 if self.c_var_followed_by_fixed_fields:
1198 need_padding = False
1203 # _c_serialize_helper_fields()
1205 def _c_serialize_helper(context, complex_type,
1206 code_lines, temp_vars,
1207 space='', prefix=[]):
1208 # count tracks the number of fields to serialize
1211 if hasattr(complex_type, 'type'):
1212 self = complex_type.type
1213 complex_name = complex_type.name
1216 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1217 complex_name = 'xcb_out'
1219 complex_name = '_aux'
1221 # special case: switch is serialized by evaluating each bitcase separately
1223 count += _c_serialize_helper_switch(context, self, complex_name,
1224 code_lines, temp_vars,
1227 # all other data types can be evaluated one field a time
1229 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1230 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1231 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1232 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1233 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1234 code_lines.append('%s xcb_block_len = 0;' % space)
1236 count += _c_serialize_helper_fields(context, self,
1237 code_lines, temp_vars,
1238 space, prefix, False)
1240 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1243 # _c_serialize_helper()
1245 def _c_serialize(context, self):
1247 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1248 for the ComplexType variable self
1254 # _serialize() returns the buffer size
1257 if self.is_switch and 'unserialize' == context:
1260 cases = { 'serialize' : self.c_serialize_name,
1261 'unserialize' : self.c_unserialize_name,
1262 'unpack' : self.c_unpack_name,
1263 'sizeof' : self.c_sizeof_name }
1264 func_name = cases[context]
1266 param_fields, wire_fields, params = get_serialize_params(context, self)
1267 variable_size_fields = 0
1268 # maximum space required for type definition of function arguments
1271 # determine N(variable_fields)
1272 for field in param_fields:
1273 # if self.is_switch, treat all fields as if they are variable sized
1274 if not field.type.fixed_size() or self.is_switch:
1275 variable_size_fields += 1
1276 # determine maxtypelen
1278 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1281 indent = ' '*(len(func_name)+2)
1284 typespec, pointerspec, field_name = p
1285 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1286 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1287 # insert function name
1288 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1289 param_str = list(map(lambda x: "%s," % x, param_str))
1290 for s in param_str[:-1]:
1292 _h("%s);" % param_str[-1].rstrip(','))
1293 _c("%s)" % param_str[-1].rstrip(','))
1300 _c_pre.redirect_start(code_lines, temp_vars)
1302 if 'serialize' == context:
1303 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1304 _c(' %s *xcb_out = *_buffer;', self.c_type)
1305 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1306 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1307 _c(' unsigned int xcb_align_to = 0;')
1309 _c(' char *xcb_out = *_buffer;')
1310 _c(' unsigned int xcb_buffer_len = 0;')
1311 _c(' unsigned int xcb_align_to = 0;')
1313 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1314 prefix = [('_aux', '->', self)]
1317 elif context in ('unserialize', 'unpack'):
1318 _c(' char *xcb_tmp = (char *)_buffer;')
1319 if not self.is_switch:
1320 if not self.c_var_followed_by_fixed_fields:
1321 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1322 prefix = [('_aux', '->', self)]
1324 _c(' %s xcb_out;', self.c_type)
1325 prefix = [('xcb_out', '.', self)]
1327 aux_var = '_aux' # default for unpack: single pointer
1328 # note: unserialize not generated for switch
1329 if 'unserialize' == context:
1330 aux_var = '(*_aux)' # unserialize: double pointer (!)
1331 prefix = [(aux_var, '->', self)]
1333 _c(' unsigned int xcb_buffer_len = 0;')
1334 _c(' unsigned int xcb_block_len = 0;')
1335 _c(' unsigned int xcb_pad = 0;')
1336 _c(' unsigned int xcb_align_to = 0;')
1338 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1340 elif 'sizeof' == context:
1341 param_names = [p[2] for p in params]
1343 # switch: call _unpack()
1344 _c(' %s _aux;', self.c_type)
1345 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1347 _c_pre.redirect_end()
1349 elif self.c_var_followed_by_fixed_fields:
1350 # special case: call _unserialize()
1351 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1353 _c_pre.redirect_end()
1356 _c(' char *xcb_tmp = (char *)_buffer;')
1357 prefix = [('_aux', '->', self)]
1359 _c(' unsigned int xcb_padding_offset = 0;')
1361 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1362 # update variable size fields (only important for context=='serialize'
1363 variable_size_fields = count
1364 if 'serialize' == context:
1365 temp_vars.append(' unsigned int xcb_pad = 0;')
1366 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1367 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1368 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1369 temp_vars.append(' unsigned int xcb_block_len = 0;')
1370 temp_vars.append(' unsigned int i;')
1371 temp_vars.append(' char *xcb_tmp;')
1372 elif 'sizeof' == context:
1373 # neither switch nor intermixed fixed and variable size fields:
1374 # evaluate parameters directly
1375 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1377 # look if we have to declare an '_aux' variable at all
1378 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1379 if not self.c_var_followed_by_fixed_fields:
1380 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1382 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1384 _c(' unsigned int xcb_buffer_len = 0;')
1385 _c(' unsigned int xcb_block_len = 0;')
1386 _c(' unsigned int xcb_pad = 0;')
1387 _c(' unsigned int xcb_align_to = 0;')
1389 _c_pre.redirect_end()
1395 for l in code_lines:
1398 # variable sized fields have been collected, now
1399 # allocate memory and copy everything into a continuous memory area
1400 # note: this is not necessary in case of unpack
1401 if context in ('serialize', 'unserialize'):
1402 # unserialize: check for sizeof-only invocation
1403 if 'unserialize' == context:
1405 _c(' if (NULL == _aux)')
1406 _c(' return xcb_buffer_len;')
1409 _c(' if (NULL == %s) {', aux_ptr)
1410 _c(' /* allocate memory */')
1411 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1412 if 'serialize' == context:
1413 _c(' *_buffer = xcb_out;')
1417 # serialize: handle variable size fields in a loop
1418 if 'serialize' == context:
1419 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1420 if len(wire_fields)>0:
1421 _c(' *xcb_out = *_aux;')
1422 # copy variable size fields into the buffer
1423 if variable_size_fields > 0:
1425 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1426 _c(' xcb_tmp = (char*)++xcb_out;')
1427 _c(' xcb_tmp += xcb_out_pad;')
1429 _c(' xcb_tmp = xcb_out;')
1431 # variable sized fields
1432 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1433 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1434 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1435 _c(' if (0 != xcb_parts[i].iov_len)')
1436 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1439 # unserialize: assign variable size fields individually
1440 if 'unserialize' == context:
1441 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1442 param_fields.reverse()
1443 for field in param_fields:
1444 if not field.type.fixed_size():
1445 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1446 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1447 _c(' *%s = xcb_out;', aux_ptr)
1450 _c(' return xcb_buffer_len;')
1454 def _c_iterator_get_end(field, accum):
1456 Figures out what C code is needed to find the end of a variable-length structure field.
1457 For nested structures, recurses into its last variable-sized field.
1458 For lists, calls the end function
1460 if field.type.is_container:
1461 accum = field.c_accessor_name + '(' + accum + ')'
1462 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1463 if field.type.is_list:
1464 # XXX we can always use the first way
1465 if field.type.member.is_simple:
1466 return field.c_end_name + '(' + accum + ')'
1468 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1470 def _c_iterator(self, name):
1472 Declares the iterator structure and next/end functions for a given type.
1477 _h(' * @brief %s', self.c_iterator_type)
1479 _h('typedef struct %s {', self.c_iterator_type)
1480 _h(' %s *data; /**< */', self.c_type)
1481 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1482 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1483 _h('} %s;', self.c_iterator_type)
1489 _h(' * Get the next element of the iterator')
1490 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1492 _h(' * Get the next element in the iterator. The member rem is')
1493 _h(' * decreased by one. The member data points to the next')
1494 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1498 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1499 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1502 if not self.fixed_size():
1503 _c(' %s *R = i->data;', self.c_type)
1506 # FIXME - how to determine the size of a variable size union??
1507 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1509 if self.c_need_sizeof:
1510 _c(' xcb_generic_iterator_t child;')
1511 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1512 self.c_type, self.c_sizeof_name)
1513 _c(' i->index = (char *) child.data - (char *) i->data;')
1515 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1516 _c(' i->index = child.index;')
1518 _c(' i->data = (%s *) child.data;', self.c_type)
1523 _c(' i->index += sizeof(%s);', self.c_type)
1529 _h(' * Return the iterator pointing to the last element')
1530 _h(' * @param i An %s', self.c_iterator_type)
1531 _h(' * @return The iterator pointing to the last element')
1533 _h(' * Set the current element in the iterator to the last element.')
1534 _h(' * The member rem is set to 0. The member data points to the')
1535 _h(' * last element.')
1538 _hc('xcb_generic_iterator_t')
1539 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1540 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1542 _c(' xcb_generic_iterator_t ret;')
1544 if self.fixed_size():
1545 _c(' ret.data = i.data + i.rem;')
1546 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1549 _c(' while(i.rem > 0)')
1550 _c(' %s(&i);', self.c_next_name)
1551 _c(' ret.data = i.data;')
1552 _c(' ret.rem = i.rem;')
1553 _c(' ret.index = i.index;')
1558 def _c_accessor_get_length(expr, field_mapping=None):
1560 Figures out what C code is needed to get a length field.
1561 The field_mapping parameter can be used to change the absolute name of a length field.
1562 For fields that follow a variable-length field, use the accessor.
1563 Otherwise, just reference the structure field directly.
1566 lenfield_name = expr.lenfield_name
1567 if lenfield_name is not None:
1568 if field_mapping is not None:
1569 lenfield_name = field_mapping[lenfield_name][0]
1571 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1572 # special case: variable and fixed size fields are intermixed
1573 # if the lenfield is among the fixed size fields, there is no need
1574 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1575 return field_mapping(expr.lenfield_name)
1576 elif expr.lenfield_name is not None:
1577 return lenfield_name
1579 return str(expr.nmemb)
1581 def _c_accessor_get_expr(expr, field_mapping):
1583 Figures out what C code is needed to get the length of a list field.
1584 The field_mapping parameter can be used to change the absolute name of a length field.
1585 Recurses for math operations.
1586 Returns bitcount for value-mask fields.
1587 Otherwise, uses the value of the length field.
1589 lenexp = _c_accessor_get_length(expr, field_mapping)
1592 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1593 elif expr.op == 'popcount':
1594 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1595 elif expr.op == 'enumref':
1596 enum_name = expr.lenfield_type.name
1597 constant_name = expr.lenfield_name
1598 c_name = _n(enum_name + (constant_name,)).upper()
1600 elif expr.op == 'sumof':
1601 # locate the referenced list object
1602 list_obj = expr.lenfield_type
1604 for f in expr.lenfield_parent.fields:
1605 if f.field_name == expr.lenfield_name:
1610 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1611 list_name = field_mapping[field.c_field_name][0]
1612 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1613 # note: xcb_sumof() has only been defined for integers
1614 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1615 # create explicit code for computing the sum.
1616 # This works for all C-types which can be added to int64_t with +=
1618 lengthvar = _c_pre.get_tempvarname()
1619 loopvar = _c_pre.get_tempvarname()
1620 sumvar = _c_pre.get_tempvarname()
1621 listvar = _c_pre.get_tempvarname()
1622 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1623 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1624 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1626 "const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1627 _c_pre.code("/* sumof start */")
1628 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1629 _c_pre.code("%s = 0;", sumvar)
1630 _c_pre.code("%s = %s;", listvar, list_name)
1632 "for (%s = 0; %s < %s; %s++) {",
1633 loopvar, loopvar, lengthvar, loopvar)
1636 if expr.rhs == None:
1637 _c_pre.code("%s += *%s;", sumvar, listvar)
1639 # sumof has a nested expression which
1640 # has to be evaluated in the context of this list element
1642 # field mapping for the subexpression needs to include
1643 # the fields of the list-member type
1644 scoped_field_mapping = field_mapping.copy()
1645 scoped_field_mapping.update(
1646 _c_helper_field_mapping(
1648 [(listvar, '', field.type.member)]))
1650 # cause pre-code of the subexpression be added right here
1652 # compute the subexpression
1653 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1654 # resume with our code
1656 # output the summation expression
1657 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1659 _c_pre.code("%s++;", listvar);
1662 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1665 # return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1666 elif expr.op != None:
1667 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1668 ' ' + expr.op + ' ' +
1669 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1671 return 'xcb_popcount(' + lenexp + ')'
1675 def type_pad_type(type):
1680 def _c_accessors_field(self, field):
1682 Declares the accessor functions for a non-list field that follows a variable-length field.
1684 c_type = self.c_type
1686 # special case: switch
1687 switch_obj = self if self.is_switch else None
1688 if self.is_case_or_bitcase:
1689 switch_obj = self.parents[-1]
1690 if switch_obj is not None:
1691 c_type = switch_obj.c_type
1693 if field.type.is_simple:
1695 _hc('%s', field.c_field_type)
1696 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1697 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1699 if field.prev_varsized_field is None:
1700 _c(' return (%s *) (R + 1);', field.c_field_type)
1702 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1703 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1704 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1708 if field.type.is_switch and switch_obj is None:
1709 return_type = 'void *'
1711 return_type = '%s *' % field.c_field_type
1714 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1715 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1717 if field.prev_varsized_field is None:
1718 _c(' return (%s) (R + 1);', return_type)
1719 # note: the special case 'variable fields followed by fixed size fields'
1720 # is not of any consequence here, since the ordering gets
1721 # 'corrected' in the reply function
1723 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1724 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1725 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1729 def _c_accessors_list(self, field):
1731 Declares the accessor functions for a list field.
1732 Declares a direct-accessor function only if the list members are fixed size.
1733 Declares length and get-iterator functions always.
1736 def get_align_pad(field):
1737 prev = field.prev_varsized_field
1738 prev_prev = field.prev_varsized_field.prev_varsized_field
1740 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1741 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1747 c_type = self.c_type
1749 # special case: switch
1750 # in case of switch, 2 params have to be supplied to certain accessor functions:
1751 # 1. the anchestor object (request or reply)
1752 # 2. the (anchestor) switch object
1753 # the reason is that switch is either a child of a request/reply or nested in another switch,
1754 # so whenever we need to access a length field, we might need to refer to some anchestor type
1755 switch_obj = self if self.is_switch else None
1756 if self.is_case_or_bitcase:
1757 switch_obj = self.parents[-1]
1758 if switch_obj is not None:
1759 c_type = switch_obj.c_type
1763 parents = self.parents if hasattr(self, 'parents') else [self]
1764 # 'R': parents[0] is always the 'toplevel' container type
1765 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1766 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1767 # auxiliary object for 'R' parameters
1770 if switch_obj is not None:
1771 # now look where the fields are defined that are needed to evaluate
1772 # the switch expr, and store the parent objects in accessor_params and
1773 # the fields in switch_fields
1775 # 'S': name for the 'toplevel' switch
1776 toplevel_switch = parents[1]
1777 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1778 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1780 # initialize prefix for everything "below" S
1781 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1782 prefix = [(prefix_str, '->', toplevel_switch)]
1784 # look for fields in the remaining containers
1785 for p in parents[2:] + [self]:
1786 # the separator between parent and child is always '.' here,
1787 # because of nested switch statements
1788 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1789 prefix.append((p.name[-1], '.', p))
1790 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1792 # auxiliary object for 'S' parameter
1797 if list.member.fixed_size():
1798 idx = 1 if switch_obj is not None else 0
1800 _hc('%s *', field.c_field_type)
1802 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1803 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1806 if switch_obj is not None:
1807 _c(' return %s;', fields[field.c_field_name][0])
1808 elif field.prev_varsized_field is None:
1809 _c(' return (%s *) (R + 1);', field.c_field_type)
1811 (prev_varsized_field, align_pad) = get_align_pad(field)
1813 if align_pad is None:
1814 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1815 type_pad_type(field.first_field_after_varsized.type.c_type))
1817 _c(' xcb_generic_iterator_t prev = %s;',
1818 _c_iterator_get_end(prev_varsized_field, 'R'))
1819 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1820 field.c_field_type, align_pad, field.prev_varsized_offset)
1825 if switch_obj is not None:
1826 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1827 spacing = ' '*(len(field.c_length_name)+2)
1828 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1829 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1831 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1832 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1834 length = _c_accessor_get_expr(field.type.expr, fields)
1835 _c(' return %s;', length)
1838 if field.type.member.is_simple:
1840 _hc('xcb_generic_iterator_t')
1841 if switch_obj is not None:
1842 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1843 spacing = ' '*(len(field.c_end_name)+2)
1844 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1845 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1847 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1848 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1850 _c(' xcb_generic_iterator_t i;')
1852 param = 'R' if switch_obj is None else 'S'
1853 if switch_obj is not None:
1854 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1855 _c_accessor_get_expr(field.type.expr, fields))
1856 elif field.prev_varsized_field == None:
1857 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1858 _c_accessor_get_expr(field.type.expr, fields))
1860 _c(' xcb_generic_iterator_t child = %s;',
1861 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1862 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1863 _c_accessor_get_expr(field.type.expr, fields))
1866 _c(' i.index = (char *) i.data - (char *) %s;', param)
1872 _hc('%s', field.c_iterator_type)
1873 if switch_obj is not None:
1874 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1875 spacing = ' '*(len(field.c_iterator_name)+2)
1876 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1877 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1879 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1880 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1882 _c(' %s i;', field.c_iterator_type)
1885 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1887 if switch_obj is not None:
1889 _c(' i.data = %s;', fields[field.c_field_name][0])
1890 _c(' i.rem = %s;', length_expr_str)
1891 elif field.prev_varsized_field == None:
1893 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1895 (prev_varsized_field, align_pad) = get_align_pad(field)
1897 if align_pad is None:
1898 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1899 type_pad_type(field.c_field_type))
1901 _c(' xcb_generic_iterator_t prev = %s;',
1902 _c_iterator_get_end(prev_varsized_field, 'R'))
1904 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1905 field.c_field_type, align_pad)
1907 if switch_obj is None:
1908 _c(' i.rem = %s;', length_expr_str)
1909 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1913 def _c_accessors(self, name, base):
1915 Declares the accessor functions for the fields of a structure.
1917 # no accessors for switch itself -
1918 # switch always needs to be unpacked explicitly
1919 # if self.is_switch:
1923 for field in self.fields:
1924 if not field.type.is_pad:
1925 if field.type.is_list and not field.type.fixed_size():
1926 _c_accessors_list(self, field)
1927 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1928 _c_accessors_field(self, field)
1930 def c_simple(self, name):
1932 Exported function that handles cardinal type declarations.
1933 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1935 _c_type_setup(self, name, ())
1937 if (self.name != name):
1942 _h('typedef %s %s;', _t(self.name), my_name)
1945 _c_iterator(self, name)
1947 def _c_complex(self, force_packed = False):
1949 Helper function for handling all structure types.
1950 Called for all structs, requests, replies, events, errors.
1955 _h(' * @brief %s', self.c_type)
1957 _h('typedef %s %s {', self.c_container, self.c_type)
1963 for field in self.fields:
1964 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1965 varfield = field.c_field_name
1968 struct_fields.append(field)
1970 for field in struct_fields:
1971 length = len(field.c_field_type)
1972 # account for '*' pointer_spec
1973 if not field.type.fixed_size() and not self.is_union:
1975 maxtypelen = max(maxtypelen, length)
1977 def _c_complex_field(self, field, space=''):
1978 if (field.type.fixed_size() or self.is_union or
1979 # in case of switch with switch children, don't make the field a pointer
1980 # necessary for unserialize to work
1981 (self.is_switch and field.type.is_switch)):
1982 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1983 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1985 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1986 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1988 if not self.is_switch:
1989 for field in struct_fields:
1990 _c_complex_field(self, field)
1992 for b in self.bitcases:
1997 for field in b.type.fields:
1998 _c_complex_field(self, field, space)
2000 _h(' } %s;', b.c_field_name)
2002 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2004 def c_struct(self, name):
2006 Exported function that handles structure declarations.
2008 _c_type_setup(self, name, ())
2010 _c_accessors(self, name, name)
2011 _c_iterator(self, name)
2013 def c_union(self, name):
2015 Exported function that handles union declarations.
2017 _c_type_setup(self, name, ())
2019 _c_iterator(self, name)
2021 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2023 Declares a request function.
2026 # Four stunningly confusing possibilities here:
2029 # ------------------------------
2031 # 0 flag CHECKED flag Normal Mode
2032 # void_cookie req_cookie
2033 # ------------------------------
2034 # "req_checked" "req_unchecked"
2035 # CHECKED flag 0 flag Abnormal Mode
2036 # void_cookie req_cookie
2037 # ------------------------------
2040 # Whether we are _checked or _unchecked
2041 checked = void and not regular
2042 unchecked = not void and not regular
2044 # What kind of cookie we return
2045 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2047 # What flag is passed to xcb_request
2048 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2051 if func_flags == '0':
2052 func_flags = 'XCB_REQUEST_REPLY_FDS'
2054 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2056 # Global extension id variable or NULL for xproto
2057 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2059 # What our function name is
2060 func_name = self.c_request_name if not aux else self.c_aux_name
2062 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2064 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2068 maxtypelen = len('xcb_connection_t')
2070 # special case: list with variable size elements
2071 list_with_var_size_elems = False
2073 for field in self.fields:
2075 # The field should appear as a call parameter
2076 param_fields.append(field)
2077 if field.wire and not field.auto:
2078 # We need to set the field up in the structure
2079 wire_fields.append(field)
2080 if field.type.c_need_serialize or field.type.c_need_sizeof:
2081 serial_fields.append(field)
2083 for field in param_fields:
2084 c_field_const_type = field.c_field_const_type
2085 if field.type.c_need_serialize and not aux:
2086 c_field_const_type = "const void"
2087 if len(c_field_const_type) > maxtypelen:
2088 maxtypelen = len(c_field_const_type)
2089 if field.type.is_list and not field.type.member.fixed_size():
2090 list_with_var_size_elems = True
2096 if hasattr(self, "doc") and self.doc:
2098 _h(' * @brief ' + self.doc.brief)
2100 _h(' * No brief doc yet')
2103 _h(' * @param c The connection')
2104 param_names = [f.c_field_name for f in param_fields]
2105 if hasattr(self, "doc") and self.doc:
2106 for field in param_fields:
2107 # XXX: hard-coded until we fix xproto.xml
2108 base_func_name = self.c_request_name if not aux else self.c_aux_name
2109 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2111 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2113 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2116 # XXX: why the 'xcb' prefix?
2117 key = ('xcb', field.enum)
2120 if namecount[tname] > 1:
2121 tname = _t(key + ('enum',))
2122 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2124 if self.doc and field.field_name in self.doc.fields:
2125 desc = self.doc.fields[field.field_name]
2126 for name in param_names:
2127 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2128 desc = desc.split("\n")
2129 desc = [line if line != '' else '\\n' for line in desc]
2130 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2131 # If there is no documentation yet, we simply don't generate an
2132 # @param tag. Doxygen will then warn about missing documentation.
2134 _h(' * @return A cookie')
2137 if hasattr(self, "doc") and self.doc:
2138 if self.doc.description:
2139 desc = self.doc.description
2140 for name in param_names:
2141 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2142 desc = desc.split("\n")
2143 _h(' * ' + "\n * ".join(desc))
2145 _h(' * No description yet')
2147 _h(' * Delivers a request to the X server.')
2150 _h(' * This form can be used only if the request will not cause')
2151 _h(' * a reply to be generated. Any returned error will be')
2152 _h(' * saved for handling by xcb_request_check().')
2154 _h(' * This form can be used only if the request will cause')
2155 _h(' * a reply to be generated. Any returned error will be')
2156 _h(' * placed in the event queue.')
2159 _hc('%s', cookie_type)
2161 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2162 comma = ',' if len(param_fields) else ');'
2163 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2164 comma = ',' if len(param_fields) else ')'
2165 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2167 func_spacing = ' ' * (len(func_name) + 2)
2168 count = len(param_fields)
2169 for field in param_fields:
2171 c_field_const_type = field.c_field_const_type
2172 c_pointer = field.c_pointer
2173 if field.type.c_need_serialize and not aux:
2174 c_field_const_type = "const void"
2176 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2177 comma = ',' if count else ');'
2178 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2179 spacing, c_pointer, field.c_field_name, comma)
2180 comma = ',' if count else ')'
2181 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2182 spacing, c_pointer, field.c_field_name, comma)
2185 if not self.c_var_followed_by_fixed_fields:
2186 for field in param_fields:
2187 if not field.type.fixed_size():
2189 if field.type.c_need_serialize:
2190 # _serialize() keeps track of padding automatically
2192 dimension = count + 2
2195 _c(' static const xcb_protocol_request_t xcb_req = {')
2196 _c(' /* count */ %d,', count)
2197 _c(' /* ext */ %s,', func_ext_global)
2198 _c(' /* opcode */ %s,', self.c_request_name.upper())
2199 _c(' /* isvoid */ %d', 1 if void else 0)
2203 _c(' struct iovec xcb_parts[%d];', dimension)
2204 _c(' %s xcb_ret;', func_cookie)
2205 _c(' %s xcb_out;', self.c_type)
2206 if self.c_var_followed_by_fixed_fields:
2207 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2208 _c(' void *xcb_aux = 0;')
2211 for idx, f in enumerate(serial_fields):
2213 _c(' void *xcb_aux%d = 0;' % (idx))
2214 if list_with_var_size_elems:
2215 _c(' unsigned int i;')
2216 _c(' unsigned int xcb_tmp_len;')
2217 _c(' char *xcb_tmp;')
2219 # simple request call tracing
2220 # _c(' printf("in function %s\\n");' % func_name)
2223 for field in wire_fields:
2224 if field.type.fixed_size():
2225 if field.type.is_expr:
2226 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2227 elif field.type.is_pad:
2228 if field.type.nmemb == 1:
2229 _c(' xcb_out.%s = 0;', field.c_field_name)
2231 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2233 if field.type.nmemb == 1:
2234 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2236 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2238 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2239 serialize_args = get_serialize_params(context, type_obj,
2242 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2244 # calls in order to free dyn. all. memory
2248 if not self.c_var_followed_by_fixed_fields:
2249 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2250 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2251 _c(' xcb_parts[3].iov_base = 0;')
2252 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2256 for field in param_fields:
2257 if not field.type.fixed_size():
2258 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2259 # default: simple cast to char *
2260 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2261 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2262 if field.type.is_list:
2263 if field.type.member.fixed_size():
2264 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2265 _c_accessor_get_expr(field.type.expr, None),
2266 field.type.member.c_wiretype)
2268 list_length = _c_accessor_get_expr(field.type.expr, None)
2271 _c(" xcb_parts[%d].iov_len = 0;" % count)
2272 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2273 _c(" for(i=0; i<%s; i++) {" % list_length)
2274 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2275 (field.type.c_sizeof_name))
2276 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2277 _c(" xcb_tmp += xcb_tmp_len;")
2280 # not supposed to happen
2281 raise Exception("unhandled variable size field %s" % field.c_field_name)
2284 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2285 idx = serial_fields.index(field)
2286 aux_var = '&xcb_aux%d' % idx
2287 context = 'serialize' if aux else 'sizeof'
2288 _c(' xcb_parts[%d].iov_len =', count)
2290 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2291 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2292 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2293 free_calls.append(' free(xcb_aux%d);' % idx)
2295 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2296 func_name = field.type.c_sizeof_name
2297 _c(' %s (%s);', func_name, serialize_args)
2300 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2301 # the _serialize() function keeps track of padding automatically
2302 _c(' xcb_parts[%d].iov_base = 0;', count)
2303 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2306 # elif self.c_var_followed_by_fixed_fields:
2308 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2309 # request header: opcodes + length
2310 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2313 buffer_var = '&xcb_aux'
2314 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2315 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2316 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2317 free_calls.append(' free(xcb_aux);')
2318 # no padding necessary - _serialize() keeps track of padding automatically
2321 for field in param_fields:
2323 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2325 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2327 # free dyn. all. data, if any
2328 for f in free_calls:
2330 _c(' return xcb_ret;')
2333 def _c_reply(self, name):
2335 Declares the function that returns the reply structure.
2337 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2338 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2339 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2341 # check if _unserialize() has to be called for any field
2342 def look_for_special_cases(complex_obj):
2343 unserialize_fields = []
2344 # no unserialize call in case of switch
2345 if not complex_obj.is_switch:
2346 for field in complex_obj.fields:
2347 # three cases: 1. field with special case
2348 # 2. container that contains special case field
2349 # 3. list with special case elements
2350 if field.type.c_var_followed_by_fixed_fields:
2351 unserialize_fields.append(field)
2352 elif field.type.is_container:
2353 unserialize_fields += look_for_special_cases(field.type)
2354 elif field.type.is_list:
2355 if field.type.member.c_var_followed_by_fixed_fields:
2356 unserialize_fields.append(field)
2357 if field.type.member.is_container:
2358 unserialize_fields += look_for_special_cases(field.type.member)
2359 return unserialize_fields
2361 unserialize_fields = look_for_special_cases(self.reply)
2365 _h(' * Return the reply')
2366 _h(' * @param c The connection')
2367 _h(' * @param cookie The cookie')
2368 _h(' * @param e The xcb_generic_error_t supplied')
2370 _h(' * Returns the reply of the request asked by')
2372 _h(' * The parameter @p e supplied to this function must be NULL if')
2373 _h(' * %s(). is used.', self.c_unchecked_name)
2374 _h(' * Otherwise, it stores the error if any.')
2376 _h(' * The returned value must be freed by the caller using free().')
2379 _hc('%s *', self.c_reply_type)
2380 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2381 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2382 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2383 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2386 if len(unserialize_fields)>0:
2387 # certain variable size fields need to be unserialized explicitly
2388 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2389 self.c_reply_type, self.c_reply_type)
2391 for field in unserialize_fields:
2392 if field.type.is_list:
2393 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2394 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2395 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2397 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2398 # call _unserialize(), using the reply as source and target buffer
2399 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2400 for field in unserialize_fields:
2401 if field.type.is_list:
2402 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2403 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2404 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2405 field.c_field_name, field.c_field_name)
2406 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2408 # return the transformed reply
2409 _c(' return reply;')
2412 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2416 def _c_reply_has_fds(self):
2417 for field in self.fields:
2422 def _c_reply_fds(self, name):
2424 Declares the function that returns fds related to the reply.
2426 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2427 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2430 _h(' * Return the reply fds')
2431 _h(' * @param c The connection')
2432 _h(' * @param reply The reply')
2434 _h(' * Returns the array of reply fds of the request asked by')
2436 _h(' * The returned value must be freed by the caller using free().')
2440 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2441 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2442 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2445 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2450 def _c_opcode(name, opcode):
2452 Declares the opcode define for requests, events, and errors.
2456 _h('/** Opcode for %s. */', _n(name))
2457 _h('#define %s %s', _n(name).upper(), opcode)
2459 def _c_cookie(self, name):
2461 Declares the cookie type for a non-void request.
2466 _h(' * @brief %s', self.c_cookie_type)
2468 _h('typedef struct %s {', self.c_cookie_type)
2469 _h(' unsigned int sequence; /**< */')
2470 _h('} %s;', self.c_cookie_type)
2472 def _man_request(self, name, cookie_type, void, aux):
2473 param_fields = [f for f in self.fields if f.visible]
2475 func_name = self.c_request_name if not aux else self.c_aux_name
2477 def create_link(linkname):
2478 name = 'man/%s.%s' % (linkname, section)
2480 sys.stdout.write(name)
2482 f.write('.so man%s/%s.%s' % (section, func_name, section))
2486 sys.stdout.write('man/%s.%s ' % (func_name, section))
2487 # Our CWD is src/, so this will end up in src/man/
2488 f = open('man/%s.%s' % (func_name, section), 'w')
2489 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2490 # Left-adjust instead of adjusting to both sides
2492 f.write('.SH NAME\n')
2493 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2494 f.write('%s \\- %s\n' % (func_name, brief))
2495 f.write('.SH SYNOPSIS\n')
2496 # Don't split words (hyphenate)
2498 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2500 # function prototypes
2502 count = len(param_fields)
2503 for field in param_fields:
2505 c_field_const_type = field.c_field_const_type
2506 c_pointer = field.c_pointer
2507 if c_pointer == ' ':
2509 if field.type.c_need_serialize and not aux:
2510 c_field_const_type = "const void"
2512 comma = ', ' if count else ');'
2513 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2515 f.write('.SS Request function\n')
2517 base_func_name = self.c_request_name if not aux else self.c_aux_name
2518 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2519 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2522 f.write('.SS Reply datastructure\n')
2525 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2529 for field in self.reply.fields:
2530 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2533 struct_fields.append(field)
2535 for field in struct_fields:
2536 length = len(field.c_field_type)
2537 # account for '*' pointer_spec
2538 if not field.type.fixed_size():
2540 maxtypelen = max(maxtypelen, length)
2542 def _c_complex_field(self, field, space=''):
2543 if (field.type.fixed_size() or
2544 # in case of switch with switch children, don't make the field a pointer
2545 # necessary for unserialize to work
2546 (self.is_switch and field.type.is_switch)):
2547 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2548 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2550 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2551 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2552 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2554 if not self.is_switch:
2555 for field in struct_fields:
2556 _c_complex_field(self, field)
2558 for b in self.bitcases:
2562 for field in b.type.fields:
2563 _c_complex_field(self, field, space)
2565 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2568 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2571 f.write('.SS Reply function\n')
2573 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2574 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2575 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2576 create_link('%s' % self.c_reply_name)
2578 has_accessors = False
2579 for field in self.reply.fields:
2580 if field.type.is_list and not field.type.fixed_size():
2581 has_accessors = True
2582 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2583 has_accessors = True
2586 f.write('.SS Reply accessors\n')
2588 def _c_accessors_field(self, field):
2590 Declares the accessor functions for a non-list field that follows a variable-length field.
2592 c_type = self.c_type
2594 # special case: switch
2595 switch_obj = self if self.is_switch else None
2596 if self.is_case_or_bitcase:
2597 switch_obj = self.parents[-1]
2598 if switch_obj is not None:
2599 c_type = switch_obj.c_type
2601 if field.type.is_simple:
2602 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2603 create_link('%s' % field.c_accessor_name)
2605 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2606 create_link('%s' % field.c_accessor_name)
2608 def _c_accessors_list(self, field):
2610 Declares the accessor functions for a list field.
2611 Declares a direct-accessor function only if the list members are fixed size.
2612 Declares length and get-iterator functions always.
2615 c_type = self.reply.c_type
2617 # special case: switch
2618 # in case of switch, 2 params have to be supplied to certain accessor functions:
2619 # 1. the anchestor object (request or reply)
2620 # 2. the (anchestor) switch object
2621 # the reason is that switch is either a child of a request/reply or nested in another switch,
2622 # so whenever we need to access a length field, we might need to refer to some anchestor type
2623 switch_obj = self if self.is_switch else None
2624 if self.is_case_or_bitcase:
2625 switch_obj = self.parents[-1]
2626 if switch_obj is not None:
2627 c_type = switch_obj.c_type
2631 parents = self.parents if hasattr(self, 'parents') else [self]
2632 # 'R': parents[0] is always the 'toplevel' container type
2633 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2634 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2635 # auxiliary object for 'R' parameters
2638 if switch_obj is not None:
2639 # now look where the fields are defined that are needed to evaluate
2640 # the switch expr, and store the parent objects in accessor_params and
2641 # the fields in switch_fields
2643 # 'S': name for the 'toplevel' switch
2644 toplevel_switch = parents[1]
2645 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2646 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2648 # initialize prefix for everything "below" S
2649 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2650 prefix = [(prefix_str, '->', toplevel_switch)]
2652 # look for fields in the remaining containers
2653 for p in parents[2:] + [self]:
2654 # the separator between parent and child is always '.' here,
2655 # because of nested switch statements
2656 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2657 prefix.append((p.name[-1], '.', p))
2658 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2660 # auxiliary object for 'S' parameter
2663 if list.member.fixed_size():
2664 idx = 1 if switch_obj is not None else 0
2666 f.write('%s *\\fB%s\\fP(%s);\n' %
2667 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2668 create_link('%s' % field.c_accessor_name)
2671 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2672 (field.c_length_name, c_type))
2673 create_link('%s' % field.c_length_name)
2675 if field.type.member.is_simple:
2677 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2678 (field.c_end_name, c_type))
2679 create_link('%s' % field.c_end_name)
2682 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2683 (field.c_iterator_type, field.c_iterator_name,
2685 create_link('%s' % field.c_iterator_name)
2687 for field in self.reply.fields:
2688 if field.type.is_list and not field.type.fixed_size():
2689 _c_accessors_list(self, field)
2690 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2691 _c_accessors_field(self, field)
2695 # Re-enable hyphenation and adjusting to both sides
2698 # argument reference
2699 f.write('.SH REQUEST ARGUMENTS\n')
2700 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2701 f.write('The XCB connection to X11.\n')
2702 for field in param_fields:
2703 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2704 printed_enum = False
2705 # XXX: hard-coded until we fix xproto.xml
2706 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2708 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2710 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2712 if hasattr(field, "enum") and field.enum:
2713 # XXX: why the 'xcb' prefix?
2714 key = ('xcb', field.enum)
2716 f.write('One of the following values:\n')
2719 count = len(enum.values)
2720 for (enam, eval) in enum.values:
2722 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2723 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2724 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2725 f.write('%s\n' % desc)
2727 f.write('TODO: NOT YET DOCUMENTED.\n')
2732 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2733 desc = self.doc.fields[field.field_name]
2734 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2737 f.write('%s\n' % desc)
2739 f.write('TODO: NOT YET DOCUMENTED.\n')
2745 f.write('.SH REPLY FIELDS\n')
2746 # These fields are present in every reply:
2747 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2748 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2749 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2750 'be used to tell replies apart from each other.\n') %
2751 _n(self.reply.name).upper())
2752 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2753 f.write('The sequence number of the last request processed by the X11 server.\n')
2754 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2755 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2756 for field in self.reply.fields:
2757 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2758 field.c_field_name.startswith('pad')):
2761 if field.type.is_list and not field.type.fixed_size():
2763 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2765 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2766 printed_enum = False
2767 if hasattr(field, "enum") and field.enum:
2768 # XXX: why the 'xcb' prefix?
2769 key = ('xcb', field.enum)
2771 f.write('One of the following values:\n')
2774 count = len(enum.values)
2775 for (enam, eval) in enum.values:
2777 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2778 if enum.doc and enam in enum.doc.fields:
2779 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2780 f.write('%s\n' % desc)
2782 f.write('TODO: NOT YET DOCUMENTED.\n')
2787 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2788 desc = self.reply.doc.fields[field.field_name]
2789 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2792 f.write('%s\n' % desc)
2794 f.write('TODO: NOT YET DOCUMENTED.\n')
2801 f.write('.SH DESCRIPTION\n')
2802 if hasattr(self, "doc") and self.doc and self.doc.description:
2803 desc = self.doc.description
2804 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2805 lines = desc.split('\n')
2806 f.write('\n'.join(lines) + '\n')
2808 f.write('.SH RETURN VALUE\n')
2810 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2811 'have to be handled in the event loop.\n\nIf you want to '
2812 'handle errors directly with \\fIxcb_request_check\\fP '
2813 'instead, use \\fI%s_checked\\fP. See '
2814 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2816 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2817 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2818 'handle errors in the event loop instead, use '
2819 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2821 (cookie_type, self.c_reply_name, base_func_name, section))
2822 f.write('.SH ERRORS\n')
2823 if hasattr(self, "doc") and self.doc:
2824 for errtype, errtext in sorted(self.doc.errors.items()):
2825 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2826 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2827 f.write('%s\n' % (errtext))
2828 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2829 f.write('This request does never generate any errors.\n')
2830 if hasattr(self, "doc") and self.doc and self.doc.example:
2831 f.write('.SH EXAMPLE\n')
2834 lines = self.doc.example.split('\n')
2835 f.write('\n'.join(lines) + '\n')
2837 f.write('.SH SEE ALSO\n')
2838 if hasattr(self, "doc") and self.doc:
2839 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2840 if self.doc.example:
2841 see.append('.BR %s (%s)' % ('xcb-examples', section))
2842 for seename, seetype in sorted(self.doc.see.items()):
2843 if seetype == 'program':
2844 see.append('.BR %s (1)' % seename)
2845 elif seetype == 'event':
2846 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2847 elif seetype == 'request':
2848 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2849 elif seetype == 'function':
2850 see.append('.BR %s (%s)' % (seename, section))
2852 see.append('TODO: %s (type %s)' % (seename, seetype))
2853 f.write(',\n'.join(see) + '\n')
2854 f.write('.SH AUTHOR\n')
2855 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2858 def _man_event(self, name):
2860 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2861 # Our CWD is src/, so this will end up in src/man/
2862 f = open('man/%s.%s' % (self.c_type, section), 'w')
2863 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2864 # Left-adjust instead of adjusting to both sides
2866 f.write('.SH NAME\n')
2867 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2868 f.write('%s \\- %s\n' % (self.c_type, brief))
2869 f.write('.SH SYNOPSIS\n')
2870 # Don't split words (hyphenate)
2872 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2875 f.write('.SS Event datastructure\n')
2878 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2882 for field in self.fields:
2883 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2886 struct_fields.append(field)
2888 for field in struct_fields:
2889 length = len(field.c_field_type)
2890 # account for '*' pointer_spec
2891 if not field.type.fixed_size():
2893 maxtypelen = max(maxtypelen, length)
2895 def _c_complex_field(self, field, space=''):
2896 if (field.type.fixed_size() or
2897 # in case of switch with switch children, don't make the field a pointer
2898 # necessary for unserialize to work
2899 (self.is_switch and field.type.is_switch)):
2900 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2901 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2903 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2905 if not self.is_switch:
2906 for field in struct_fields:
2907 _c_complex_field(self, field)
2909 for b in self.bitcases:
2913 for field in b.type.fields:
2914 _c_complex_field(self, field, space)
2916 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2919 f.write('} \\fB%s\\fP;\n' % self.c_type)
2924 # Re-enable hyphenation and adjusting to both sides
2927 # argument reference
2928 f.write('.SH EVENT FIELDS\n')
2929 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2930 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2931 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2932 'to tell events apart from each other.\n') % _n(name).upper())
2933 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2934 f.write('The sequence number of the last request processed by the X11 server.\n')
2936 if not self.is_switch:
2937 for field in struct_fields:
2938 # Skip the fields which every event has, we already documented
2940 if field.c_field_name in ('response_type', 'sequence'):
2942 if isinstance(field.type, PadType):
2944 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2945 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2946 desc = self.doc.fields[field.field_name]
2947 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2948 f.write('%s\n' % desc)
2950 f.write('NOT YET DOCUMENTED.\n')
2953 f.write('.SH DESCRIPTION\n')
2954 if hasattr(self, "doc") and self.doc and self.doc.description:
2955 desc = self.doc.description
2956 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2957 lines = desc.split('\n')
2958 f.write('\n'.join(lines) + '\n')
2960 if hasattr(self, "doc") and self.doc and self.doc.example:
2961 f.write('.SH EXAMPLE\n')
2964 lines = self.doc.example.split('\n')
2965 f.write('\n'.join(lines) + '\n')
2967 f.write('.SH SEE ALSO\n')
2968 if hasattr(self, "doc") and self.doc:
2969 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2970 if self.doc.example:
2971 see.append('.BR %s (%s)' % ('xcb-examples', section))
2972 for seename, seetype in sorted(self.doc.see.items()):
2973 if seetype == 'program':
2974 see.append('.BR %s (1)' % seename)
2975 elif seetype == 'event':
2976 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2977 elif seetype == 'request':
2978 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2979 elif seetype == 'function':
2980 see.append('.BR %s (%s)' % (seename, section))
2982 see.append('TODO: %s (type %s)' % (seename, seetype))
2983 f.write(',\n'.join(see) + '\n')
2984 f.write('.SH AUTHOR\n')
2985 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2989 def c_request(self, name):
2991 Exported function that handles request declarations.
2993 _c_type_setup(self, name, ('request',))
2996 # Cookie type declaration
2997 _c_cookie(self, name)
3000 _c_opcode(name, self.opcode)
3002 # Request structure declaration
3006 _c_type_setup(self.reply, name, ('reply',))
3007 # Reply structure definition
3008 _c_complex(self.reply)
3009 # Request prototypes
3010 has_fds = _c_reply_has_fds(self.reply)
3011 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3012 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3014 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3015 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3017 _c_accessors(self.reply, name + ('reply',), name)
3018 _c_reply(self, name)
3020 _c_reply_fds(self, name)
3022 # Request prototypes
3023 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3024 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3026 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3027 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3029 # We generate the manpage afterwards because _c_type_setup has been called.
3030 # TODO: what about aux helpers?
3031 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3032 _man_request(self, name, cookie_type, not self.reply, False)
3034 def c_event(self, name):
3036 Exported function that handles event declarations.
3039 # The generic event structure xcb_ge_event_t has the full_sequence field
3040 # at the 32byte boundary. That's why we've to inject this field into GE
3041 # events while generating the structure for them. Otherwise we would read
3042 # garbage (the internal full_sequence) when accessing normal event fields
3044 force_packed = False
3045 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3047 for field in self.fields:
3048 if field.type.size != None and field.type.nmemb != None:
3049 event_size += field.type.size * field.type.nmemb
3050 if event_size == 32:
3051 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3052 idx = self.fields.index(field)
3053 self.fields.insert(idx + 1, full_sequence)
3055 # If the event contains any 64-bit extended fields, they need
3056 # to remain aligned on a 64-bit boundary. Adding full_sequence
3057 # would normally break that; force the struct to be packed.
3058 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3061 _c_type_setup(self, name, ('event',))
3064 _c_opcode(name, self.opcodes[name])
3066 if self.name == name:
3067 # Structure definition
3068 _c_complex(self, force_packed)
3072 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3074 _man_event(self, name)
3076 def c_error(self, name):
3078 Exported function that handles error declarations.
3080 _c_type_setup(self, name, ('error',))
3083 _c_opcode(name, self.opcodes[name])
3085 if self.name == name:
3086 # Structure definition
3091 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3094 # Main routine starts here
3096 # Must create an "output" dictionary before any xcbgen imports.
3097 output = {'open' : c_open,
3099 'simple' : c_simple,
3101 'struct' : c_struct,
3103 'request' : c_request,
3108 # Boilerplate below this point
3110 # Check for the argument that specifies path to the xcbgen python package.
3112 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3113 except getopt.GetoptError as err:
3115 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3118 for (opt, arg) in opts:
3126 sys.path.insert(1, arg)
3129 sys.stdout.write('man_MANS = ')
3131 # Import the module class
3133 from xcbgen.state import Module
3134 from xcbgen.xtypes import *
3137 Failed to load the xcbgen Python package!
3138 Make sure that xcb/proto installed it on your Python path.
3139 If not, you will need to create a .pth file or define $PYTHONPATH
3141 Refer to the README file in xcb/proto for more info.
3145 # Ensure the man subdirectory exists
3148 except OSError as e:
3149 if e.errno != errno.EEXIST:
3152 # Parse the xml header
3153 module = Module(args[0], output)
3155 # Build type-registry and resolve type dependencies