2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
12 # Jump to the bottom of this file for the main routine
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
20 _cplusplus_annoyances = {'class' : '_class',
23 _c_keywords = {'default' : '_default'}
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
37 # keeps enum objects so that we can refer to them when generating manpages.
44 Writes the given line to the header file.
46 _hlines[_hlevel].append(fmt % args)
50 Writes the given line to the source file.
52 _clines[_clevel].append(fmt % args)
56 Writes the given line to both the header and source files.
61 def _c_wr_stringlist(indent, strlist):
63 Writes the given list of strings to the source file.
64 Each line is prepended by the indent string
67 _c("%s%s", indent, str)
70 class PreCode(object):
72 For pre-code generated by expression generation
73 (for example, the for-loop of a sumof)
74 This has to account for recursiveness of the expression
75 generation, i.e., there may be pre-code for pre-code.
76 Therefore this is implemented as a stack of lists of lines.
78 If redirection is switched on, then all output is collected in
79 self.redirect_code and self.redirect_tempvars instead of
80 being sent to the output via _h und _c.
83 self.nesting_level = 0
86 self.redirect_code = None
87 self.redirect_tempvars = None
89 self.indent_stack = []
93 # start and end of pre-code blocks
95 self.nesting_level += 1
98 self.nesting_level -= 1
99 if self.nesting_level == 0:
100 # lowest pre-code level is finished -> output to source
101 if self.redirect_tempvars is None:
102 _c_wr_stringlist('', self.tempvars)
105 self.redirect_tempvars.extend(self.tempvars)
107 if self.redirect_code == None:
108 _c_wr_stringlist('', self.codelines)
111 self.redirect_code.extend(self.codelines)
115 def output_tempvars(self):
116 if self.redirect_code == None:
117 _c_wr_stringlist('', self.tempvars)
121 def code(self, fmt, *args):
122 self.codelines.append(self.indent_str + fmt % args)
124 def tempvar(self, fmt, *args):
125 self.tempvars.append(' ' + (fmt % args))
127 # get a unique name for a temporary variable
128 def get_tempvarname(self):
129 self.tempvar_num += 1
130 return "xcb_pre_tmp_%d" % self.tempvar_num
134 def push_indent(self, indentstr):
135 self.indent_stack.append(self.indent_str)
136 self.indent_str = indentstr
138 def push_addindent(self, indent_add_str):
139 self.push_indent(self.indent_str + indent_add_str)
142 self.push_addindent(' ')
144 def pop_indent(self):
145 self.indent_str = self.indent_stack.pop()
147 # redirection to lists
148 def redirect_start(self, redirect_code, redirect_tempvars=None):
149 self.redirect_code = redirect_code
150 self.redirect_tempvars = redirect_tempvars
151 if redirect_tempvars is not None:
154 def redirect_end(self):
155 self.redirect_code = None
156 self.redirect_tempvars = None
158 # global PreCode handler
162 # XXX See if this level thing is really necessary.
163 def _h_setlevel(idx):
165 Changes the array that header lines are written to.
166 Supports writing different sections of the header file.
169 while len(_hlines) <= idx:
173 def _c_setlevel(idx):
175 Changes the array that source lines are written to.
176 Supports writing to different sections of the source file.
179 while len(_clines) <= idx:
185 Does C-name conversion on a single string fragment.
186 Uses a regexp with some hard-coded special cases.
188 if str in _cname_special_cases:
189 return _cname_special_cases[str]
191 split = _cname_re.finditer(str)
192 name_parts = [match.group(0) for match in split]
193 return '_'.join(name_parts)
197 Checks for certain C++ reserved words and fixes them.
199 if str in _cplusplus_annoyances:
200 return _cplusplus_annoyances[str]
201 elif str in _c_keywords:
202 return _c_keywords[str]
208 Does C-name conversion on an extension name.
209 Has some additional special cases on top of _n_item.
211 if str in _extension_special_cases:
212 return _n_item(str).lower()
218 Does C-name conversion on a tuple of strings.
219 Different behavior depending on length of tuple, extension/not extension, etc.
220 Basically C-name converts the individual pieces, then joins with underscores.
225 parts = [list[0], _n_item(list[1])]
227 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
229 parts = [list[0]] + [_n_item(i) for i in list[1:]]
230 return '_'.join(parts).lower()
234 Does C-name conversion on a tuple of strings representing a type.
235 Same as _n but adds a "_t" on the end.
240 parts = [list[0], _n_item(list[1]), 't']
242 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
244 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
245 return '_'.join(parts).lower()
250 Exported function that handles module open.
251 Opens the files and writes out the auto-generated comment, header file includes, etc.
255 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
257 # Build the type-name collision avoidance table used by c_enum
258 build_collision_table()
264 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
265 _hc(' * Edit at your peril.')
270 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
271 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
275 _h('#ifndef __%s_H', _ns.header.upper())
276 _h('#define __%s_H', _ns.header.upper())
278 _h('#include "xcb.h"')
280 _c('#ifdef HAVE_CONFIG_H')
281 _c('#include "config.h"')
283 _c('#include <stdlib.h>')
284 _c('#include <string.h>')
285 _c('#include <assert.h>')
286 _c('#include <stddef.h> /* for offsetof() */')
287 _c('#include "xcbext.h"')
288 _c('#include "%s.h"', _ns.header)
291 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
294 for (n, h) in self.direct_imports:
295 _hc('#include "%s.h"', h)
298 _h('#ifdef __cplusplus')
304 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
305 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
307 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
310 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
314 Exported function that handles module close.
315 Writes out all the stored content lines, then closes the files.
322 _h('#ifdef __cplusplus')
334 hfile = open('%s.h' % _ns.header, 'w')
342 cfile = open('%s.c' % _ns.header, 'w')
349 def build_collision_table():
353 for v in module.types.values():
355 namecount[name] = (namecount.get(name) or 0) + 1
357 def c_enum(self, name):
359 Exported function that handles enum declarations.
365 if namecount[tname] > 1:
366 tname = _t(name + ('enum',))
370 _h('typedef enum %s {', tname)
372 count = len(self.values)
374 for (enam, eval) in self.values:
376 equals = ' = ' if eval != '' else ''
377 comma = ',' if count > 0 else ''
379 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
380 doc = '\n/**< %s */\n' % self.doc.fields[enam]
381 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
385 def _c_type_setup(self, name, postfix):
387 Sets up all the C-related state by adding additional data fields to
388 all Field and Type objects. Here is where we figure out most of our
389 variable and function names.
391 Recurses into child fields and list member types.
393 # Do all the various names in advance
394 self.c_type = _t(name + postfix)
395 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
397 self.c_iterator_type = _t(name + ('iterator',))
398 self.c_next_name = _n(name + ('next',))
399 self.c_end_name = _n(name + ('end',))
401 self.c_request_name = _n(name)
402 self.c_checked_name = _n(name + ('checked',))
403 self.c_unchecked_name = _n(name + ('unchecked',))
404 self.c_reply_name = _n(name + ('reply',))
405 self.c_reply_type = _t(name + ('reply',))
406 self.c_cookie_type = _t(name + ('cookie',))
407 self.c_reply_fds_name = _n(name + ('reply_fds',))
409 self.c_need_aux = False
410 self.c_need_serialize = False
411 self.c_need_sizeof = False
413 self.c_aux_name = _n(name + ('aux',))
414 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
415 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
416 self.c_serialize_name = _n(name + ('serialize',))
417 self.c_unserialize_name = _n(name + ('unserialize',))
418 self.c_unpack_name = _n(name + ('unpack',))
419 self.c_sizeof_name = _n(name + ('sizeof',))
421 # special case: structs where variable size fields are followed by fixed size fields
422 self.c_var_followed_by_fixed_fields = False
425 self.c_need_serialize = True
426 self.c_container = 'struct'
427 for bitcase in self.bitcases:
428 bitcase.c_field_name = _cpp(bitcase.field_name)
429 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
430 _c_type_setup(bitcase.type, bitcase_name, ())
432 elif self.is_container:
434 self.c_container = 'union' if self.is_union else 'struct'
435 prev_varsized_field = None
436 prev_varsized_offset = 0
437 first_field_after_varsized = None
439 for field in self.fields:
440 field.c_field_type = _t(field.field_type)
441 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
442 field.c_field_name = _cpp(field.field_name)
443 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
444 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
446 # correct the c_pointer field for variable size non-list types
447 if not field.type.fixed_size() and field.c_pointer == ' ':
448 field.c_pointer = '*'
449 if field.type.is_list and not field.type.member.fixed_size():
450 field.c_pointer = '*'
452 if field.type.is_switch:
453 field.c_pointer = '*'
454 field.c_field_const_type = 'const ' + field.c_field_type
455 self.c_need_aux = True
457 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
458 self.c_need_sizeof = True
460 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
461 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
462 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
463 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
464 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
466 field.prev_varsized_field = prev_varsized_field
467 field.prev_varsized_offset = prev_varsized_offset
469 if prev_varsized_offset == 0:
470 first_field_after_varsized = field
471 field.first_field_after_varsized = first_field_after_varsized
473 if field.type.fixed_size():
474 prev_varsized_offset += field.type.size
475 # special case: intermixed fixed and variable size fields
476 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
477 if not self.is_union:
478 self.c_need_serialize = True
479 self.c_var_followed_by_fixed_fields = True
481 self.last_varsized_field = field
482 prev_varsized_field = field
483 prev_varsized_offset = 0
485 if self.c_var_followed_by_fixed_fields:
486 if field.type.fixed_size():
487 field.prev_varsized_field = None
489 # recurse into this field this has to be done here, i.e.,
490 # after the field has been set up. Otherwise the function
491 # _c_helper_fieldaccess_expr will produce garbage or crash
492 _c_type_setup(field.type, field.field_type, ())
493 if field.type.is_list:
494 _c_type_setup(field.type.member, field.field_type, ())
495 if (field.type.nmemb is None):
496 self.c_need_sizeof = True
498 if self.c_need_serialize:
499 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
500 self.c_need_sizeof = True
502 # as switch does never appear at toplevel,
503 # continue here with type construction
505 if self.c_type not in finished_switch:
506 finished_switch.append(self.c_type)
507 # special: switch C structs get pointer fields for variable-sized members
509 for bitcase in self.bitcases:
510 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
511 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
512 # no list with switch as element, so no call to
513 # _c_iterator(field.type, field_name) necessary
515 if not self.is_case_or_bitcase:
516 if self.c_need_serialize:
517 if self.c_serialize_name not in finished_serializers:
518 finished_serializers.append(self.c_serialize_name)
519 _c_serialize('serialize', self)
521 # _unpack() and _unserialize() are only needed for special cases:
523 # special cases -> unserialize
524 if self.is_switch or self.c_var_followed_by_fixed_fields:
525 _c_serialize('unserialize', self)
527 if self.c_need_sizeof:
528 if self.c_sizeof_name not in finished_sizeof:
529 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
530 finished_sizeof.append(self.c_sizeof_name)
531 _c_serialize('sizeof', self)
534 # Functions for querying field properties
535 def _c_field_needs_list_accessor(field):
536 return field.type.is_list and not field.type.fixed_size()
538 def _c_field_needs_field_accessor(field):
539 if field.type.is_list:
542 return (field.prev_varsized_field is not None or
543 not field.type.fixed_size())
545 def _c_field_needs_accessor(field):
546 return (_c_field_needs_list_accessor(field) or
547 _c_field_needs_field_accessor(field))
549 def _c_field_is_member_of_case_or_bitcase(field):
550 return field.parent and field.parent.is_case_or_bitcase
552 def _c_helper_fieldaccess_expr(prefix, field=None):
554 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555 representing a valid field-access-expression in C (based on the context)
556 if field is not None, append access to the field as well.
558 "separator" is one of the C-operators "." or "->".
560 A field access expression can consist of the following components:
561 * struct/union member access from a value with the "."-operator
562 * struct/union member access from a pointer with "->"-operator
563 * function-call of an accessor function:
564 This is used when a xcb-field is not contained in a struct.
565 This can, e.g., happen for fields after var-sized fields, etc.
569 for name, sep, obj in prefix:
570 prefix_str += last_sep + name
574 # add separator for access to a yet unknown field
575 prefix_str += last_sep
577 if _c_field_needs_accessor(field):
578 if _c_field_is_member_of_case_or_bitcase(field):
579 # case members are available in the deserialized struct,
580 # so there is no need to use the accessor function
581 # (also, their accessor function needs a different arglist
582 # so this would require special treatment here)
583 # Therefore: Access as struct member
584 prefix_str += last_sep + _cpp(field.field_name)
586 # Access with the accessor function
587 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
589 # Access as struct member
590 prefix_str += last_sep + _cpp(field.field_name)
595 def _c_helper_field_mapping(complex_type, prefix, flat=False):
597 generate absolute names, based on prefix, for all fields starting from complex_type
598 if flat == True, nested complex types are not taken into account
601 if complex_type.is_switch:
602 for b in complex_type.bitcases:
604 switch_name, switch_sep, switch_type = prefix[-1]
605 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
607 bitcase_prefix = prefix
609 if (True==flat and not b.type.has_name) or False==flat:
610 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
612 for f in complex_type.fields:
613 fname = _c_helper_fieldaccess_expr(prefix, f)
614 if f.field_name in all_fields:
615 raise Exception("field name %s has been registered before" % f.field_name)
617 all_fields[f.field_name] = (fname, f)
618 if f.type.is_container and flat==False:
619 if f.type.is_case_or_bitcase and not f.type.has_name:
621 elif f.type.is_switch and len(f.type.parents)>1:
622 # nested switch gets another separator
623 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
625 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
626 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
631 def _c_helper_resolve_field_names (prefix):
633 get field names for all objects in the prefix array
637 # look for fields in the remaining containers
638 for idx, p in enumerate(prefix):
641 # sep can be preset in prefix, if not, make a sensible guess
642 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
643 # exception: 'toplevel' object (switch as well!) always have sep '->'
644 sep = '->' if idx<1 else sep
645 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
646 tmp_prefix.append((name, sep, obj))
647 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
650 # _c_helper_resolve_field_names
652 def get_expr_fields(self):
654 get the Fields referenced by switch or list expression
656 def get_expr_field_names(expr):
658 if expr.lenfield_name is not None:
659 return [expr.lenfield_name]
661 # constant value expr
665 return get_expr_field_names(expr.rhs)
666 elif expr.op == 'popcount':
667 return get_expr_field_names(expr.rhs)
668 elif expr.op == 'sumof':
669 # sumof expr references another list,
670 # we need that list's length field here
672 for f in expr.lenfield_parent.fields:
673 if f.field_name == expr.lenfield_name:
677 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
678 # referenced list + its length field
679 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
680 elif expr.op == 'enumref':
683 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
684 # get_expr_field_names()
686 # resolve the field names with the parent structure(s)
687 unresolved_fields_names = get_expr_field_names(self.expr)
689 # construct prefix from self
690 prefix = [('', '', p) for p in self.parents]
691 if self.is_container:
692 prefix.append(('', '', self))
694 all_fields = _c_helper_resolve_field_names (prefix)
695 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
696 if len(unresolved_fields_names) != len(resolved_fields_names):
697 raise Exception("could not resolve all fields for %s" % self.name)
699 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
700 return resolved_fields
703 def resolve_expr_fields(complex_obj):
705 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
706 these are normally fields that need to be given as function parameters
712 for field in complex_obj.fields:
713 all_fields.append(field)
714 if field.type.is_switch or field.type.is_list:
715 expr_fields += get_expr_fields(field.type)
716 if field.type.is_container:
717 expr_fields += resolve_expr_fields(field.type)
719 # try to resolve expr fields
720 for e in expr_fields:
721 if e not in all_fields and e not in unresolved:
724 # resolve_expr_fields()
726 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
728 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
729 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
730 expression. This function tries to resolve all fields within a structure, and returns the
731 unresolved fields as the list of external parameters.
733 def add_param(params, param):
734 if param not in params:
737 # collect all fields into param_fields
741 for field in self.fields:
743 # the field should appear as a parameter in the function call
744 param_fields.append(field)
745 if field.wire and not field.auto:
746 if field.type.fixed_size() and not self.is_switch:
747 # field in the xcb_out structure
748 wire_fields.append(field)
749 # fields like 'pad0' are skipped!
751 # in case of switch, parameters always contain any fields referenced in the switch expr
752 # we do not need any variable size fields here, as the switch data type contains both
753 # fixed and variable size fields
755 param_fields = get_expr_fields(self)
757 # _serialize()/_unserialize()/_unpack() function parameters
758 # note: don't use set() for params, it is unsorted
761 # 1. the parameter for the void * buffer
762 if 'serialize' == context:
763 params.append(('void', '**', buffer_var))
764 elif context in ('unserialize', 'unpack', 'sizeof'):
765 params.append(('const void', '*', buffer_var))
767 # 2. any expr fields that cannot be resolved within self and descendants
768 unresolved_fields = resolve_expr_fields(self)
769 for f in unresolved_fields:
770 add_param(params, (f.c_field_type, '', f.c_field_name))
772 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
773 # that do not appear in the data type struct
774 for p in param_fields:
776 typespec = p.c_field_const_type
777 pointerspec = p.c_pointer
778 add_param(params, (typespec, pointerspec, p.c_field_name))
780 if p.visible and not p.wire and not p.auto:
781 typespec = p.c_field_type
783 add_param(params, (typespec, pointerspec, p.c_field_name))
786 if 'serialize' == context:
787 add_param(params, ('const %s' % self.c_type, '*', aux_var))
788 elif 'unserialize' == context:
789 add_param(params, ('%s' % self.c_type, '**', aux_var))
790 elif 'unpack' == context:
791 add_param(params, ('%s' % self.c_type, '*', aux_var))
793 # 5. switch contains all variable size fields as struct members
794 # for other data types though, these have to be supplied separately
795 # this is important for the special case of intermixed fixed and
796 # variable size fields
797 if not self.is_switch and 'serialize' == context:
798 for p in param_fields:
799 if not p.type.fixed_size():
800 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
802 return (param_fields, wire_fields, params)
803 # get_serialize_params()
805 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
806 code_lines.append('%s /* insert padding */' % space)
807 if is_case_or_bitcase:
809 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
813 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
814 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
815 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
818 code_lines.append('%s if (0 != xcb_pad) {' % space)
820 if 'serialize' == context:
821 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
822 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
823 code_lines.append('%s xcb_parts_idx++;' % space)
824 elif context in ('unserialize', 'unpack', 'sizeof'):
825 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
827 code_lines.append('%s xcb_pad = 0;' % space)
828 code_lines.append('%s }' % space)
830 code_lines.append('%s xcb_block_len = 0;' % space)
831 if is_case_or_bitcase:
832 code_lines.append('%s xcb_padding_offset = 0;' % space)
834 # keep tracking of xcb_parts entries for serialize
836 # _c_serialize_helper_insert_padding()
838 def _c_serialize_helper_switch(context, self, complex_name,
839 code_lines, temp_vars,
842 switch_expr = _c_accessor_get_expr(self.expr, None)
844 for b in self.bitcases:
845 len_expr = len(b.type.expr)
847 compare_operator = '&'
849 compare_operator = '=='
851 compare_operator = '&'
853 for n, expr in enumerate(b.type.expr):
854 bitcase_expr = _c_accessor_get_expr(expr, None)
855 # only one <enumref> in the <bitcase>
858 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
859 # multiple <enumref> in the <bitcase>
862 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
863 elif len_expr == (n + 1): # last
865 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
866 else: # between first and last
868 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
872 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
874 count += _c_serialize_helper_fields(context, b.type,
875 code_lines, temp_vars,
878 is_case_or_bitcase = True)
879 code_lines.append(' }')
881 # if 'serialize' == context:
882 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
883 # elif context in ('unserialize', 'unpack', 'sizeof'):
885 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
886 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
889 # _c_serialize_helper_switch
891 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
893 handle switch by calling _serialize() or _unpack(), depending on context
895 # switch is handled by this function as a special case
896 param_fields, wire_fields, params = get_serialize_params(context, self)
897 field_mapping = _c_helper_field_mapping(self, prefix)
898 prefix_str = _c_helper_fieldaccess_expr(prefix)
900 # find the parameters that need to be passed to _serialize()/_unpack():
901 # all switch expr fields must be given as parameters
902 args = get_expr_fields(field.type)
903 # length fields for variable size types in switch, normally only some of need
904 # need to be passed as parameters
905 switch_len_fields = resolve_expr_fields(field.type)
907 # a switch field at this point _must_ be a bitcase field
908 # we require that bitcases are "self-contiguous"
909 bitcase_unresolved = resolve_expr_fields(self)
910 if len(bitcase_unresolved) != 0:
911 raise Exception('unresolved fields within bitcase is not supported at this point')
913 # get the C names for the parameters
915 for a in switch_len_fields:
916 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
918 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
920 # call _serialize()/_unpack() to determine the actual size
921 if 'serialize' == context:
922 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
923 c_field_names, prefix_str, field.c_field_name)
924 elif context in ('unserialize', 'unpack'):
925 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
926 c_field_names, prefix_str, field.c_field_name)
927 elif 'sizeof' == context:
928 # remove trailing ", " from c_field_names because it will be used at end of arglist
929 my_c_field_names = c_field_names[:-2]
930 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
933 # _c_serialize_helper_switch_field()
935 def _c_serialize_helper_list_field(context, self, field,
936 code_lines, temp_vars,
939 helper function to cope with lists of variable length
941 expr = field.type.expr
942 prefix_str = _c_helper_fieldaccess_expr(prefix)
943 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
944 param_names = [p[2] for p in params]
946 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
947 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
948 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
952 field_mapping[r] = (r, None)
954 if len(unresolved)>0:
956 if len(tmp_prefix)==0:
957 raise Exception("found an empty prefix while resolving expr field names for list %s",
960 field_mapping.update(_c_helper_resolve_field_names(prefix))
961 resolved += list(filter(lambda x: x in field_mapping, unresolved))
962 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
963 if len(unresolved)>0:
964 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
966 list_length = _c_accessor_get_expr(expr, field_mapping)
968 # default: list with fixed size elements
969 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
971 # list with variable-sized elements
972 if not field.type.member.fixed_size():
974 if context in ('unserialize', 'sizeof', 'unpack'):
975 int_i = ' unsigned int i;'
976 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
977 if int_i not in temp_vars:
978 temp_vars.append(int_i)
979 if xcb_tmp_len not in temp_vars:
980 temp_vars.append(xcb_tmp_len)
981 # loop over all list elements and call sizeof repeatedly
982 # this should be a bit faster than using the iterators
983 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
984 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
985 (space, field.type.c_sizeof_name))
986 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
987 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
988 code_lines.append("%s }" % space)
990 elif 'serialize' == context:
991 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
992 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
993 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
994 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
995 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
996 code_lines.append('%s }' % space)
997 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1000 # _c_serialize_helper_list_field()
1002 def _c_serialize_helper_fields_fixed_size(context, self, field,
1003 code_lines, temp_vars,
1005 # keep the C code a bit more readable by giving the field name
1006 if not self.is_case_or_bitcase:
1007 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1009 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1010 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1011 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1013 abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1014 # default for simple cases: call sizeof()
1015 length = "sizeof(%s)" % field.c_field_type
1017 if context in ('unserialize', 'unpack', 'sizeof'):
1018 # default: simple cast
1019 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1021 # padding - we could probably just ignore it
1022 if field.type.is_pad and field.type.nmemb > 1:
1024 for i in range(field.type.nmemb):
1025 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1026 (space, abs_field_name, i, field.c_field_type))
1027 # total padding = sizeof(pad0) * nmemb
1028 length += " * %d" % field.type.nmemb
1030 elif field.type.is_list:
1031 # list with fixed number of elements
1032 # length of array = sizeof(arrayElementType) * nmemb
1033 length += " * %d" % field.type.nmemb
1034 # use memcpy because C cannot assign whole arrays with operator=
1035 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1038 elif 'serialize' == context:
1039 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1041 if field.type.is_expr:
1042 # need to register a temporary variable for the expression in case we know its type
1043 if field.type.c_type is None:
1044 raise Exception("type for field '%s' (expression '%s') unkown" %
1045 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1047 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1048 _c_accessor_get_expr(field.type.expr, prefix)))
1049 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1051 elif field.type.is_pad:
1052 if field.type.nmemb == 1:
1053 value += "&xcb_pad;"
1055 # we could also set it to 0, see definition of xcb_send_request()
1056 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1057 length += "*%d" % field.type.nmemb
1060 # non-list type with fixed size
1061 if field.type.nmemb == 1:
1062 value += "&%s;" % (abs_field_name)
1064 # list with nmemb (fixed size) elements
1066 value += '%s;' % (abs_field_name)
1067 length = '%d' % field.type.nmemb
1069 return (value, length)
1070 # _c_serialize_helper_fields_fixed_size()
1072 def _c_serialize_helper_fields_variable_size(context, self, field,
1073 code_lines, temp_vars,
1075 prefix_str = _c_helper_fieldaccess_expr(prefix)
1077 if context in ('unserialize', 'unpack', 'sizeof'):
1079 var_field_name = 'xcb_tmp'
1081 # special case: intermixed fixed and variable size fields
1082 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1083 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1084 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1085 # special case: switch
1086 if 'unpack' == context:
1087 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1089 elif 'serialize' == context:
1090 # variable size fields appear as parameters to _serialize() if the
1091 # 'toplevel' container is not a switch
1092 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1093 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1094 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1098 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1100 if field.type.is_list:
1102 # in any context, list is already a pointer, so the default assignment is ok
1103 code_lines.append("%s%s" % (space, value))
1105 length = _c_serialize_helper_list_field(context, self, field,
1106 code_lines, temp_vars,
1109 elif field.type.is_switch:
1111 if context == 'serialize':
1112 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1113 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1114 length = _c_serialize_helper_switch_field(context, self, field,
1115 'xcb_parts[xcb_parts_idx].iov_base',
1119 # in all remaining special cases - call _sizeof()
1120 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1122 return (value, length)
1123 # _c_serialize_helper_fields_variable_size
1125 def _c_serialize_helper_fields(context, self,
1126 code_lines, temp_vars,
1127 space, prefix, is_case_or_bitcase):
1129 need_padding = False
1130 prev_field_was_variable = False
1132 _c_pre.push_indent(space + ' ')
1134 for field in self.fields:
1135 if not field.visible:
1136 if not ((field.wire and not field.auto) or 'unserialize' == context):
1139 # switch/bitcase: fixed size fields must be considered explicitly
1140 if field.type.fixed_size():
1141 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1142 if prev_field_was_variable and need_padding:
1144 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1145 # self.c_var_followed_by_fixed_fields)
1146 prev_field_was_variable = False
1148 # prefix for fixed size fields
1149 fixed_prefix = prefix
1151 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1152 code_lines, temp_vars,
1153 space, fixed_prefix)
1157 # fields with variable size
1159 if field.type.is_pad:
1160 # Variable length pad is <pad align= />
1161 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1162 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1163 self.c_var_followed_by_fixed_fields,
1167 # switch/bitcase: always calculate padding before and after variable sized fields
1168 if need_padding or is_case_or_bitcase:
1169 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1170 self.c_var_followed_by_fixed_fields,
1173 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1174 code_lines, temp_vars,
1176 prev_field_was_variable = True
1178 # save (un)serialization C code
1180 code_lines.append('%s%s' % (space, value))
1182 if field.type.fixed_size():
1183 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1184 # keep track of (un)serialized object's size
1185 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1186 if context in ('unserialize', 'unpack', 'sizeof'):
1187 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1189 # variable size objects or bitcase:
1190 # value & length might have been inserted earlier for special cases
1192 # special case: intermixed fixed and variable size fields
1193 if (not field.type.fixed_size() and
1194 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1195 temp_vars.append(' int %s_len;' % field.c_field_name)
1196 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1197 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1198 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1200 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1201 # increase pointer into the byte stream accordingly
1202 if context in ('unserialize', 'sizeof', 'unpack'):
1203 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1205 if 'serialize' == context:
1207 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1208 code_lines.append('%s xcb_parts_idx++;' % space)
1212 '%s xcb_align_to = ALIGNOF(%s);'
1215 if field.c_field_type == 'void' or field.type.is_switch
1216 else field.c_field_type))
1219 if self.c_var_followed_by_fixed_fields:
1220 need_padding = False
1225 # _c_serialize_helper_fields()
1227 def _c_serialize_helper(context, complex_type,
1228 code_lines, temp_vars,
1229 space='', prefix=[]):
1230 # count tracks the number of fields to serialize
1233 if hasattr(complex_type, 'type'):
1234 self = complex_type.type
1235 complex_name = complex_type.name
1238 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1239 complex_name = 'xcb_out'
1241 complex_name = '_aux'
1243 # special case: switch is serialized by evaluating each bitcase separately
1245 count += _c_serialize_helper_switch(context, self, complex_name,
1246 code_lines, temp_vars,
1249 # all other data types can be evaluated one field a time
1251 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1252 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1253 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1254 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1255 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1256 code_lines.append('%s xcb_block_len = 0;' % space)
1258 count += _c_serialize_helper_fields(context, self,
1259 code_lines, temp_vars,
1260 space, prefix, False)
1262 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1265 # _c_serialize_helper()
1267 def _c_serialize(context, self):
1269 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1270 for the ComplexType variable self
1276 # _serialize() returns the buffer size
1279 if self.is_switch and 'unserialize' == context:
1282 cases = { 'serialize' : self.c_serialize_name,
1283 'unserialize' : self.c_unserialize_name,
1284 'unpack' : self.c_unpack_name,
1285 'sizeof' : self.c_sizeof_name }
1286 func_name = cases[context]
1288 param_fields, wire_fields, params = get_serialize_params(context, self)
1289 variable_size_fields = 0
1290 # maximum space required for type definition of function arguments
1293 # determine N(variable_fields)
1294 for field in param_fields:
1295 # if self.is_switch, treat all fields as if they are variable sized
1296 if not field.type.fixed_size() or self.is_switch:
1297 variable_size_fields += 1
1298 # determine maxtypelen
1300 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1303 indent = ' '*(len(func_name)+2)
1306 typespec, pointerspec, field_name = p
1307 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1308 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1309 # insert function name
1310 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1311 param_str = list(map(lambda x: "%s," % x, param_str))
1312 for s in param_str[:-1]:
1314 _h("%s);" % param_str[-1].rstrip(','))
1315 _c("%s)" % param_str[-1].rstrip(','))
1322 _c_pre.redirect_start(code_lines, temp_vars)
1324 if 'serialize' == context:
1325 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1326 _c(' %s *xcb_out = *_buffer;', self.c_type)
1327 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1328 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1329 _c(' unsigned int xcb_align_to = 0;')
1331 _c(' char *xcb_out = *_buffer;')
1332 _c(' unsigned int xcb_buffer_len = 0;')
1333 _c(' unsigned int xcb_align_to = 0;')
1335 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1336 prefix = [('_aux', '->', self)]
1339 elif context in ('unserialize', 'unpack'):
1340 _c(' char *xcb_tmp = (char *)_buffer;')
1341 if not self.is_switch:
1342 if not self.c_var_followed_by_fixed_fields:
1343 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1344 prefix = [('_aux', '->', self)]
1346 _c(' %s xcb_out;', self.c_type)
1347 prefix = [('xcb_out', '.', self)]
1349 aux_var = '_aux' # default for unpack: single pointer
1350 # note: unserialize not generated for switch
1351 if 'unserialize' == context:
1352 aux_var = '(*_aux)' # unserialize: double pointer (!)
1353 prefix = [(aux_var, '->', self)]
1355 _c(' unsigned int xcb_buffer_len = 0;')
1356 _c(' unsigned int xcb_block_len = 0;')
1357 _c(' unsigned int xcb_pad = 0;')
1358 _c(' unsigned int xcb_align_to = 0;')
1360 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1362 elif 'sizeof' == context:
1363 param_names = [p[2] for p in params]
1365 # switch: call _unpack()
1366 _c(' %s _aux;', self.c_type)
1367 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1369 _c_pre.redirect_end()
1371 elif self.c_var_followed_by_fixed_fields:
1372 # special case: call _unserialize()
1373 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1375 _c_pre.redirect_end()
1378 _c(' char *xcb_tmp = (char *)_buffer;')
1379 prefix = [('_aux', '->', self)]
1381 _c(' unsigned int xcb_padding_offset = 0;')
1383 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1384 # update variable size fields (only important for context=='serialize'
1385 variable_size_fields = count
1386 if 'serialize' == context:
1387 temp_vars.append(' unsigned int xcb_pad = 0;')
1388 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1389 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1390 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1391 temp_vars.append(' unsigned int xcb_block_len = 0;')
1392 temp_vars.append(' unsigned int i;')
1393 temp_vars.append(' char *xcb_tmp;')
1394 elif 'sizeof' == context:
1395 # neither switch nor intermixed fixed and variable size fields:
1396 # evaluate parameters directly
1397 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1399 # look if we have to declare an '_aux' variable at all
1400 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1401 if not self.c_var_followed_by_fixed_fields:
1402 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1404 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1406 _c(' unsigned int xcb_buffer_len = 0;')
1407 _c(' unsigned int xcb_block_len = 0;')
1408 _c(' unsigned int xcb_pad = 0;')
1409 _c(' unsigned int xcb_align_to = 0;')
1411 _c_pre.redirect_end()
1417 for l in code_lines:
1420 # variable sized fields have been collected, now
1421 # allocate memory and copy everything into a continuous memory area
1422 # note: this is not necessary in case of unpack
1423 if context in ('serialize', 'unserialize'):
1424 # unserialize: check for sizeof-only invocation
1425 if 'unserialize' == context:
1427 _c(' if (NULL == _aux)')
1428 _c(' return xcb_buffer_len;')
1431 _c(' if (NULL == %s) {', aux_ptr)
1432 _c(' /* allocate memory */')
1433 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1434 if 'serialize' == context:
1435 _c(' *_buffer = xcb_out;')
1439 # serialize: handle variable size fields in a loop
1440 if 'serialize' == context:
1441 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1442 if len(wire_fields)>0:
1443 _c(' *xcb_out = *_aux;')
1444 # copy variable size fields into the buffer
1445 if variable_size_fields > 0:
1447 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1448 _c(' xcb_tmp = (char*)++xcb_out;')
1449 _c(' xcb_tmp += xcb_out_pad;')
1451 _c(' xcb_tmp = xcb_out;')
1453 # variable sized fields
1454 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1455 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1456 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1457 _c(' if (0 != xcb_parts[i].iov_len)')
1458 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1461 # unserialize: assign variable size fields individually
1462 if 'unserialize' == context:
1463 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1464 param_fields.reverse()
1465 for field in param_fields:
1466 if not field.type.fixed_size():
1467 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1468 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1469 _c(' *%s = xcb_out;', aux_ptr)
1472 _c(' return xcb_buffer_len;')
1476 def _c_iterator_get_end(field, accum):
1478 Figures out what C code is needed to find the end of a variable-length structure field.
1479 For nested structures, recurses into its last variable-sized field.
1480 For lists, calls the end function
1482 if field.type.is_container:
1483 accum = field.c_accessor_name + '(' + accum + ')'
1484 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1485 if field.type.is_list:
1486 # XXX we can always use the first way
1487 if field.type.member.is_simple:
1488 return field.c_end_name + '(' + accum + ')'
1490 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1492 def _c_iterator(self, name):
1494 Declares the iterator structure and next/end functions for a given type.
1499 _h(' * @brief %s', self.c_iterator_type)
1501 _h('typedef struct %s {', self.c_iterator_type)
1502 _h(' %s *data; /**< */', self.c_type)
1503 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1504 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1505 _h('} %s;', self.c_iterator_type)
1511 _h(' * Get the next element of the iterator')
1512 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1514 _h(' * Get the next element in the iterator. The member rem is')
1515 _h(' * decreased by one. The member data points to the next')
1516 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1520 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1521 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1524 if not self.fixed_size():
1525 _c(' %s *R = i->data;', self.c_type)
1528 # FIXME - how to determine the size of a variable size union??
1529 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1531 if self.c_need_sizeof:
1532 _c(' xcb_generic_iterator_t child;')
1533 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1534 self.c_type, self.c_sizeof_name)
1535 _c(' i->index = (char *) child.data - (char *) i->data;')
1537 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1538 _c(' i->index = child.index;')
1540 _c(' i->data = (%s *) child.data;', self.c_type)
1545 _c(' i->index += sizeof(%s);', self.c_type)
1551 _h(' * Return the iterator pointing to the last element')
1552 _h(' * @param i An %s', self.c_iterator_type)
1553 _h(' * @return The iterator pointing to the last element')
1555 _h(' * Set the current element in the iterator to the last element.')
1556 _h(' * The member rem is set to 0. The member data points to the')
1557 _h(' * last element.')
1560 _hc('xcb_generic_iterator_t')
1561 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1562 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1564 _c(' xcb_generic_iterator_t ret;')
1566 if self.fixed_size():
1567 _c(' ret.data = i.data + i.rem;')
1568 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1571 _c(' while(i.rem > 0)')
1572 _c(' %s(&i);', self.c_next_name)
1573 _c(' ret.data = i.data;')
1574 _c(' ret.rem = i.rem;')
1575 _c(' ret.index = i.index;')
1580 def _c_accessor_get_length(expr, field_mapping=None):
1582 Figures out what C code is needed to get a length field.
1583 The field_mapping parameter can be used to change the absolute name of a length field.
1584 For fields that follow a variable-length field, use the accessor.
1585 Otherwise, just reference the structure field directly.
1588 lenfield_name = expr.lenfield_name
1589 if lenfield_name is not None:
1590 if field_mapping is not None:
1591 lenfield_name = field_mapping[lenfield_name][0]
1593 if expr.lenfield_name is not None:
1594 return lenfield_name
1596 return str(expr.nmemb)
1598 def _c_accessor_get_expr(expr, field_mapping):
1600 Figures out what C code is needed to get the length of a list field.
1601 The field_mapping parameter can be used to change the absolute name of a length field.
1602 Recurses for math operations.
1603 Returns bitcount for value-mask fields.
1604 Otherwise, uses the value of the length field.
1606 lenexp = _c_accessor_get_length(expr, field_mapping)
1609 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1610 elif expr.op == 'popcount':
1611 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1612 elif expr.op == 'enumref':
1613 enum_name = expr.lenfield_type.name
1614 constant_name = expr.lenfield_name
1615 c_name = _n(enum_name + (constant_name,)).upper()
1617 elif expr.op == 'sumof':
1618 # locate the referenced list object
1619 list_obj = expr.lenfield_type
1621 for f in expr.lenfield_parent.fields:
1622 if f.field_name == expr.lenfield_name:
1627 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1628 list_name = field_mapping[field.c_field_name][0]
1629 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1630 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1631 # create explicit code for computing the sum.
1632 # This works for all C-types which can be added to int64_t with +=
1634 lengthvar = _c_pre.get_tempvarname()
1635 loopvar = _c_pre.get_tempvarname()
1636 sumvar = _c_pre.get_tempvarname()
1637 listvar = _c_pre.get_tempvarname()
1638 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1639 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1640 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1641 _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1642 _c_pre.code("/* sumof start */")
1643 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1644 _c_pre.code("%s = 0;", sumvar)
1645 _c_pre.code("%s = %s;", listvar, list_name)
1646 _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1649 if expr.rhs is None:
1650 _c_pre.code("%s += *%s;", sumvar, listvar)
1652 # sumof has a nested expression which has to be evaluated in
1653 # the context of this list element
1655 # field mapping for the subexpression needs to include
1656 # the fields of the list-member type
1657 scoped_field_mapping = field_mapping.copy()
1658 scoped_field_mapping.update(
1659 _c_helper_field_mapping(
1661 [(listvar, '->', field.type.member)]))
1663 # cause pre-code of the subexpression be added right here
1665 # compute the subexpression
1666 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1667 # resume with our code
1669 # output the summation expression
1670 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1672 _c_pre.code("%s++;", listvar)
1675 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1678 elif expr.op != None:
1679 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1680 ' ' + expr.op + ' ' +
1681 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1683 return 'xcb_popcount(' + lenexp + ')'
1687 def type_pad_type(type):
1692 def _c_accessors_field(self, field):
1694 Declares the accessor functions for a non-list field that follows a variable-length field.
1696 c_type = self.c_type
1698 # special case: switch
1699 switch_obj = self if self.is_switch else None
1700 if self.is_case_or_bitcase:
1701 switch_obj = self.parents[-1]
1702 if switch_obj is not None:
1703 c_type = switch_obj.c_type
1705 if field.type.is_simple:
1707 _hc('%s', field.c_field_type)
1708 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1709 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1711 if field.prev_varsized_field is None:
1712 _c(' return (%s *) (R + 1);', field.c_field_type)
1714 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1715 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1716 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1720 if field.type.is_switch and switch_obj is None:
1721 return_type = 'void *'
1723 return_type = '%s *' % field.c_field_type
1726 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1727 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1729 if field.prev_varsized_field is None:
1730 _c(' return (%s) (R + 1);', return_type)
1731 # note: the special case 'variable fields followed by fixed size fields'
1732 # is not of any consequence here, since the ordering gets
1733 # 'corrected' in the reply function
1735 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1736 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1737 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1741 def _c_accessors_list(self, field):
1743 Declares the accessor functions for a list field.
1744 Declares a direct-accessor function only if the list members are fixed size.
1745 Declares length and get-iterator functions always.
1748 def get_align_pad(field):
1749 prev = field.prev_varsized_field
1750 prev_prev = field.prev_varsized_field.prev_varsized_field
1752 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1753 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1759 c_type = self.c_type
1761 # special case: switch
1762 # in case of switch, 2 params have to be supplied to certain accessor functions:
1763 # 1. the anchestor object (request or reply)
1764 # 2. the (anchestor) switch object
1765 # the reason is that switch is either a child of a request/reply or nested in another switch,
1766 # so whenever we need to access a length field, we might need to refer to some anchestor type
1767 switch_obj = self if self.is_switch else None
1768 if self.is_case_or_bitcase:
1769 switch_obj = self.parents[-1]
1770 if switch_obj is not None:
1771 c_type = switch_obj.c_type
1775 parents = self.parents if hasattr(self, 'parents') else [self]
1776 # 'R': parents[0] is always the 'toplevel' container type
1777 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1778 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1779 # auxiliary object for 'R' parameters
1782 if switch_obj is not None:
1783 # now look where the fields are defined that are needed to evaluate
1784 # the switch expr, and store the parent objects in accessor_params and
1785 # the fields in switch_fields
1787 # 'S': name for the 'toplevel' switch
1788 toplevel_switch = parents[1]
1789 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1790 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1792 # initialize prefix for everything "below" S
1793 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1794 prefix = [(prefix_str, '->', toplevel_switch)]
1796 # look for fields in the remaining containers
1797 for p in parents[2:] + [self]:
1798 # the separator between parent and child is always '.' here,
1799 # because of nested switch statements
1800 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1801 prefix.append((p.name[-1], '.', p))
1802 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1804 # auxiliary object for 'S' parameter
1809 if list.member.fixed_size():
1810 idx = 1 if switch_obj is not None else 0
1812 _hc('%s *', field.c_field_type)
1814 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1815 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1818 if switch_obj is not None:
1819 _c(' return %s;', fields[field.c_field_name][0])
1820 elif field.prev_varsized_field is None:
1821 _c(' return (%s *) (R + 1);', field.c_field_type)
1823 (prev_varsized_field, align_pad) = get_align_pad(field)
1825 if align_pad is None:
1826 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1827 type_pad_type(field.first_field_after_varsized.type.c_type))
1829 _c(' xcb_generic_iterator_t prev = %s;',
1830 _c_iterator_get_end(prev_varsized_field, 'R'))
1831 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1832 field.c_field_type, align_pad, field.prev_varsized_offset)
1837 if switch_obj is not None:
1838 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1839 spacing = ' '*(len(field.c_length_name)+2)
1840 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1841 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1843 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1844 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1846 length = _c_accessor_get_expr(field.type.expr, fields)
1847 _c(' return %s;', length)
1850 if field.type.member.is_simple:
1852 _hc('xcb_generic_iterator_t')
1853 if switch_obj is not None:
1854 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1855 spacing = ' '*(len(field.c_end_name)+2)
1856 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1857 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1859 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1860 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1862 _c(' xcb_generic_iterator_t i;')
1864 param = 'R' if switch_obj is None else 'S'
1865 if switch_obj is not None:
1866 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1867 _c_accessor_get_expr(field.type.expr, fields))
1868 elif field.prev_varsized_field == None:
1869 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1870 _c_accessor_get_expr(field.type.expr, fields))
1872 _c(' xcb_generic_iterator_t child = %s;',
1873 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1874 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1875 _c_accessor_get_expr(field.type.expr, fields))
1878 _c(' i.index = (char *) i.data - (char *) %s;', param)
1884 _hc('%s', field.c_iterator_type)
1885 if switch_obj is not None:
1886 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1887 spacing = ' '*(len(field.c_iterator_name)+2)
1888 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1889 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1891 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1892 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1894 _c(' %s i;', field.c_iterator_type)
1897 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1899 if switch_obj is not None:
1901 _c(' i.data = %s;', fields[field.c_field_name][0])
1902 _c(' i.rem = %s;', length_expr_str)
1903 elif field.prev_varsized_field == None:
1905 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1907 (prev_varsized_field, align_pad) = get_align_pad(field)
1909 if align_pad is None:
1910 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1911 type_pad_type(field.c_field_type))
1913 _c(' xcb_generic_iterator_t prev = %s;',
1914 _c_iterator_get_end(prev_varsized_field, 'R'))
1916 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1917 field.c_field_type, align_pad)
1919 if switch_obj is None:
1920 _c(' i.rem = %s;', length_expr_str)
1921 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1925 def _c_accessors(self, name, base):
1927 Declares the accessor functions for the fields of a structure.
1929 # no accessors for switch itself -
1930 # switch always needs to be unpacked explicitly
1931 # if self.is_switch:
1935 for field in self.fields:
1936 if not field.type.is_pad:
1937 if _c_field_needs_list_accessor(field):
1938 _c_accessors_list(self, field)
1939 elif _c_field_needs_field_accessor(field):
1940 _c_accessors_field(self, field)
1942 def c_simple(self, name):
1944 Exported function that handles cardinal type declarations.
1945 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1947 _c_type_setup(self, name, ())
1949 if (self.name != name):
1954 _h('typedef %s %s;', _t(self.name), my_name)
1957 _c_iterator(self, name)
1959 def _c_complex(self, force_packed = False):
1961 Helper function for handling all structure types.
1962 Called for all structs, requests, replies, events, errors.
1967 _h(' * @brief %s', self.c_type)
1969 _h('typedef %s %s {', self.c_container, self.c_type)
1975 for field in self.fields:
1976 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1977 varfield = field.c_field_name
1980 struct_fields.append(field)
1982 for field in struct_fields:
1983 length = len(field.c_field_type)
1984 # account for '*' pointer_spec
1985 if not field.type.fixed_size() and not self.is_union:
1987 maxtypelen = max(maxtypelen, length)
1989 def _c_complex_field(self, field, space=''):
1990 if (field.type.fixed_size() or self.is_union or
1991 # in case of switch with switch children, don't make the field a pointer
1992 # necessary for unserialize to work
1993 (self.is_switch and field.type.is_switch)):
1994 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1995 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1997 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1998 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2000 if not self.is_switch:
2001 for field in struct_fields:
2002 _c_complex_field(self, field)
2004 for b in self.bitcases:
2009 for field in b.type.fields:
2010 _c_complex_field(self, field, space)
2012 _h(' } %s;', b.c_field_name)
2014 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2016 def c_struct(self, name):
2018 Exported function that handles structure declarations.
2020 _c_type_setup(self, name, ())
2022 _c_accessors(self, name, name)
2023 _c_iterator(self, name)
2025 def c_union(self, name):
2027 Exported function that handles union declarations.
2029 _c_type_setup(self, name, ())
2031 _c_iterator(self, name)
2033 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2035 Declares a request function.
2038 # Four stunningly confusing possibilities here:
2041 # ------------------------------
2043 # 0 flag CHECKED flag Normal Mode
2044 # void_cookie req_cookie
2045 # ------------------------------
2046 # "req_checked" "req_unchecked"
2047 # CHECKED flag 0 flag Abnormal Mode
2048 # void_cookie req_cookie
2049 # ------------------------------
2052 # Whether we are _checked or _unchecked
2053 checked = void and not regular
2054 unchecked = not void and not regular
2056 # What kind of cookie we return
2057 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2059 # What flag is passed to xcb_request
2060 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2063 if func_flags == '0':
2064 func_flags = 'XCB_REQUEST_REPLY_FDS'
2066 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2068 # Global extension id variable or NULL for xproto
2069 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2071 # What our function name is
2072 func_name = self.c_request_name if not aux else self.c_aux_name
2074 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2076 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2080 maxtypelen = len('xcb_connection_t')
2082 # special case: list with variable size elements
2083 list_with_var_size_elems = False
2085 for field in self.fields:
2087 # The field should appear as a call parameter
2088 param_fields.append(field)
2089 if field.wire and not field.auto:
2090 # We need to set the field up in the structure
2091 wire_fields.append(field)
2092 if field.type.c_need_serialize or field.type.c_need_sizeof:
2093 serial_fields.append(field)
2095 for field in param_fields:
2096 c_field_const_type = field.c_field_const_type
2097 if field.type.c_need_serialize and not aux:
2098 c_field_const_type = "const void"
2099 if len(c_field_const_type) > maxtypelen:
2100 maxtypelen = len(c_field_const_type)
2101 if field.type.is_list and not field.type.member.fixed_size():
2102 list_with_var_size_elems = True
2108 if hasattr(self, "doc") and self.doc:
2110 _h(' * @brief ' + self.doc.brief)
2112 _h(' * No brief doc yet')
2115 _h(' * @param c The connection')
2116 param_names = [f.c_field_name for f in param_fields]
2117 if hasattr(self, "doc") and self.doc:
2118 for field in param_fields:
2119 # XXX: hard-coded until we fix xproto.xml
2120 base_func_name = self.c_request_name if not aux else self.c_aux_name
2121 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2123 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2125 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2128 # XXX: why the 'xcb' prefix?
2129 key = ('xcb', field.enum)
2132 if namecount[tname] > 1:
2133 tname = _t(key + ('enum',))
2134 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2136 if self.doc and field.field_name in self.doc.fields:
2137 desc = self.doc.fields[field.field_name]
2138 for name in param_names:
2139 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2140 desc = desc.split("\n")
2141 desc = [line if line != '' else '\\n' for line in desc]
2142 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2143 # If there is no documentation yet, we simply don't generate an
2144 # @param tag. Doxygen will then warn about missing documentation.
2146 _h(' * @return A cookie')
2149 if hasattr(self, "doc") and self.doc:
2150 if self.doc.description:
2151 desc = self.doc.description
2152 for name in param_names:
2153 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2154 desc = desc.split("\n")
2155 _h(' * ' + "\n * ".join(desc))
2157 _h(' * No description yet')
2159 _h(' * Delivers a request to the X server.')
2162 _h(' * This form can be used only if the request will not cause')
2163 _h(' * a reply to be generated. Any returned error will be')
2164 _h(' * saved for handling by xcb_request_check().')
2166 _h(' * This form can be used only if the request will cause')
2167 _h(' * a reply to be generated. Any returned error will be')
2168 _h(' * placed in the event queue.')
2171 _hc('%s', cookie_type)
2173 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2174 comma = ',' if len(param_fields) else ');'
2175 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2176 comma = ',' if len(param_fields) else ')'
2177 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2179 func_spacing = ' ' * (len(func_name) + 2)
2180 count = len(param_fields)
2181 for field in param_fields:
2183 c_field_const_type = field.c_field_const_type
2184 c_pointer = field.c_pointer
2185 if field.type.c_need_serialize and not aux:
2186 c_field_const_type = "const void"
2188 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2189 comma = ',' if count else ');'
2190 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2191 spacing, c_pointer, field.c_field_name, comma)
2192 comma = ',' if count else ')'
2193 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2194 spacing, c_pointer, field.c_field_name, comma)
2197 if not self.c_var_followed_by_fixed_fields:
2198 for field in param_fields:
2199 if not field.type.fixed_size():
2201 if field.type.c_need_serialize:
2202 # _serialize() keeps track of padding automatically
2204 dimension = count + 2
2207 _c(' static const xcb_protocol_request_t xcb_req = {')
2208 _c(' /* count */ %d,', count)
2209 _c(' /* ext */ %s,', func_ext_global)
2210 _c(' /* opcode */ %s,', self.c_request_name.upper())
2211 _c(' /* isvoid */ %d', 1 if void else 0)
2215 _c(' struct iovec xcb_parts[%d];', dimension)
2216 _c(' %s xcb_ret;', func_cookie)
2217 _c(' %s xcb_out;', self.c_type)
2218 if self.c_var_followed_by_fixed_fields:
2219 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2220 _c(' void *xcb_aux = 0;')
2223 for idx, f in enumerate(serial_fields):
2225 _c(' void *xcb_aux%d = 0;' % (idx))
2226 if list_with_var_size_elems:
2227 _c(' unsigned int i;')
2228 _c(' unsigned int xcb_tmp_len;')
2229 _c(' char *xcb_tmp;')
2231 # simple request call tracing
2232 # _c(' printf("in function %s\\n");' % func_name)
2235 for field in wire_fields:
2236 if field.type.fixed_size():
2237 if field.type.is_expr:
2238 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2239 elif field.type.is_pad:
2240 if field.type.nmemb == 1:
2241 _c(' xcb_out.%s = 0;', field.c_field_name)
2243 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2245 if field.type.nmemb == 1:
2246 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2248 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2250 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2251 serialize_args = get_serialize_params(context, type_obj,
2254 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2256 # calls in order to free dyn. all. memory
2260 if not self.c_var_followed_by_fixed_fields:
2261 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2262 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2263 _c(' xcb_parts[3].iov_base = 0;')
2264 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2268 for field in param_fields:
2269 if not field.type.fixed_size():
2270 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2271 # default: simple cast to char *
2272 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2273 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2274 if field.type.is_list:
2275 if field.type.member.fixed_size():
2276 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2277 _c_accessor_get_expr(field.type.expr, None),
2278 field.type.member.c_wiretype)
2280 list_length = _c_accessor_get_expr(field.type.expr, None)
2283 _c(" xcb_parts[%d].iov_len = 0;" % count)
2284 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2285 _c(" for(i=0; i<%s; i++) {" % list_length)
2286 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2287 (field.type.c_sizeof_name))
2288 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2289 _c(" xcb_tmp += xcb_tmp_len;")
2292 # not supposed to happen
2293 raise Exception("unhandled variable size field %s" % field.c_field_name)
2296 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2297 idx = serial_fields.index(field)
2298 aux_var = '&xcb_aux%d' % idx
2299 context = 'serialize' if aux else 'sizeof'
2300 _c(' xcb_parts[%d].iov_len =', count)
2302 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2303 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2304 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2305 free_calls.append(' free(xcb_aux%d);' % idx)
2307 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2308 func_name = field.type.c_sizeof_name
2309 _c(' %s (%s);', func_name, serialize_args)
2312 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2313 # the _serialize() function keeps track of padding automatically
2314 _c(' xcb_parts[%d].iov_base = 0;', count)
2315 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2318 # elif self.c_var_followed_by_fixed_fields:
2320 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2321 # request header: opcodes + length
2322 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2325 buffer_var = '&xcb_aux'
2326 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2327 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2328 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2329 free_calls.append(' free(xcb_aux);')
2330 # no padding necessary - _serialize() keeps track of padding automatically
2333 for field in param_fields:
2335 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2337 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2339 # free dyn. all. data, if any
2340 for f in free_calls:
2342 _c(' return xcb_ret;')
2345 def _c_reply(self, name):
2347 Declares the function that returns the reply structure.
2349 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2350 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2351 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2353 # check if _unserialize() has to be called for any field
2354 def look_for_special_cases(complex_obj):
2355 unserialize_fields = []
2356 # no unserialize call in case of switch
2357 if not complex_obj.is_switch:
2358 for field in complex_obj.fields:
2359 # three cases: 1. field with special case
2360 # 2. container that contains special case field
2361 # 3. list with special case elements
2362 if field.type.c_var_followed_by_fixed_fields:
2363 unserialize_fields.append(field)
2364 elif field.type.is_container:
2365 unserialize_fields += look_for_special_cases(field.type)
2366 elif field.type.is_list:
2367 if field.type.member.c_var_followed_by_fixed_fields:
2368 unserialize_fields.append(field)
2369 if field.type.member.is_container:
2370 unserialize_fields += look_for_special_cases(field.type.member)
2371 return unserialize_fields
2373 unserialize_fields = look_for_special_cases(self.reply)
2377 _h(' * Return the reply')
2378 _h(' * @param c The connection')
2379 _h(' * @param cookie The cookie')
2380 _h(' * @param e The xcb_generic_error_t supplied')
2382 _h(' * Returns the reply of the request asked by')
2384 _h(' * The parameter @p e supplied to this function must be NULL if')
2385 _h(' * %s(). is used.', self.c_unchecked_name)
2386 _h(' * Otherwise, it stores the error if any.')
2388 _h(' * The returned value must be freed by the caller using free().')
2391 _hc('%s *', self.c_reply_type)
2392 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2393 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2394 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2395 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2398 if len(unserialize_fields)>0:
2399 # certain variable size fields need to be unserialized explicitly
2400 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2401 self.c_reply_type, self.c_reply_type)
2403 for field in unserialize_fields:
2404 if field.type.is_list:
2405 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2406 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2407 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2409 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2410 # call _unserialize(), using the reply as source and target buffer
2411 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2412 for field in unserialize_fields:
2413 if field.type.is_list:
2414 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2415 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2416 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2417 field.c_field_name, field.c_field_name)
2418 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2420 # return the transformed reply
2421 _c(' return reply;')
2424 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2428 def _c_reply_has_fds(self):
2429 for field in self.fields:
2434 def _c_reply_fds(self, name):
2436 Declares the function that returns fds related to the reply.
2438 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2439 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2442 _h(' * Return the reply fds')
2443 _h(' * @param c The connection')
2444 _h(' * @param reply The reply')
2446 _h(' * Returns the array of reply fds of the request asked by')
2448 _h(' * The returned value must be freed by the caller using free().')
2452 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2453 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2454 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2457 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2462 def _c_opcode(name, opcode):
2464 Declares the opcode define for requests, events, and errors.
2468 _h('/** Opcode for %s. */', _n(name))
2469 _h('#define %s %s', _n(name).upper(), opcode)
2471 def _c_cookie(self, name):
2473 Declares the cookie type for a non-void request.
2478 _h(' * @brief %s', self.c_cookie_type)
2480 _h('typedef struct %s {', self.c_cookie_type)
2481 _h(' unsigned int sequence; /**< */')
2482 _h('} %s;', self.c_cookie_type)
2484 def _man_request(self, name, cookie_type, void, aux):
2485 param_fields = [f for f in self.fields if f.visible]
2487 func_name = self.c_request_name if not aux else self.c_aux_name
2489 def create_link(linkname):
2490 name = 'man/%s.%s' % (linkname, section)
2492 sys.stdout.write(name)
2494 f.write('.so man%s/%s.%s' % (section, func_name, section))
2498 sys.stdout.write('man/%s.%s ' % (func_name, section))
2499 # Our CWD is src/, so this will end up in src/man/
2500 f = open('man/%s.%s' % (func_name, section), 'w')
2501 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2502 # Left-adjust instead of adjusting to both sides
2504 f.write('.SH NAME\n')
2505 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2506 f.write('%s \\- %s\n' % (func_name, brief))
2507 f.write('.SH SYNOPSIS\n')
2508 # Don't split words (hyphenate)
2510 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2512 # function prototypes
2514 count = len(param_fields)
2515 for field in param_fields:
2517 c_field_const_type = field.c_field_const_type
2518 c_pointer = field.c_pointer
2519 if c_pointer == ' ':
2521 if field.type.c_need_serialize and not aux:
2522 c_field_const_type = "const void"
2524 comma = ', ' if count else ');'
2525 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2527 f.write('.SS Request function\n')
2529 base_func_name = self.c_request_name if not aux else self.c_aux_name
2530 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2531 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2534 f.write('.SS Reply datastructure\n')
2537 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2541 for field in self.reply.fields:
2542 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2545 struct_fields.append(field)
2547 for field in struct_fields:
2548 length = len(field.c_field_type)
2549 # account for '*' pointer_spec
2550 if not field.type.fixed_size():
2552 maxtypelen = max(maxtypelen, length)
2554 def _c_complex_field(self, field, space=''):
2555 if (field.type.fixed_size() or
2556 # in case of switch with switch children, don't make the field a pointer
2557 # necessary for unserialize to work
2558 (self.is_switch and field.type.is_switch)):
2559 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2560 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2562 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2563 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2564 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2566 if not self.is_switch:
2567 for field in struct_fields:
2568 _c_complex_field(self, field)
2570 for b in self.bitcases:
2574 for field in b.type.fields:
2575 _c_complex_field(self, field, space)
2577 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2580 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2583 f.write('.SS Reply function\n')
2585 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2586 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2587 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2588 create_link('%s' % self.c_reply_name)
2590 has_accessors = False
2591 for field in self.reply.fields:
2592 if field.type.is_list and not field.type.fixed_size():
2593 has_accessors = True
2594 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2595 has_accessors = True
2598 f.write('.SS Reply accessors\n')
2600 def _c_accessors_field(self, field):
2602 Declares the accessor functions for a non-list field that follows a variable-length field.
2604 c_type = self.c_type
2606 # special case: switch
2607 switch_obj = self if self.is_switch else None
2608 if self.is_case_or_bitcase:
2609 switch_obj = self.parents[-1]
2610 if switch_obj is not None:
2611 c_type = switch_obj.c_type
2613 if field.type.is_simple:
2614 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2615 create_link('%s' % field.c_accessor_name)
2617 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2618 create_link('%s' % field.c_accessor_name)
2620 def _c_accessors_list(self, field):
2622 Declares the accessor functions for a list field.
2623 Declares a direct-accessor function only if the list members are fixed size.
2624 Declares length and get-iterator functions always.
2627 c_type = self.reply.c_type
2629 # special case: switch
2630 # in case of switch, 2 params have to be supplied to certain accessor functions:
2631 # 1. the anchestor object (request or reply)
2632 # 2. the (anchestor) switch object
2633 # the reason is that switch is either a child of a request/reply or nested in another switch,
2634 # so whenever we need to access a length field, we might need to refer to some anchestor type
2635 switch_obj = self if self.is_switch else None
2636 if self.is_case_or_bitcase:
2637 switch_obj = self.parents[-1]
2638 if switch_obj is not None:
2639 c_type = switch_obj.c_type
2643 parents = self.parents if hasattr(self, 'parents') else [self]
2644 # 'R': parents[0] is always the 'toplevel' container type
2645 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2646 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2647 # auxiliary object for 'R' parameters
2650 if switch_obj is not None:
2651 # now look where the fields are defined that are needed to evaluate
2652 # the switch expr, and store the parent objects in accessor_params and
2653 # the fields in switch_fields
2655 # 'S': name for the 'toplevel' switch
2656 toplevel_switch = parents[1]
2657 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2658 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2660 # initialize prefix for everything "below" S
2661 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2662 prefix = [(prefix_str, '->', toplevel_switch)]
2664 # look for fields in the remaining containers
2665 for p in parents[2:] + [self]:
2666 # the separator between parent and child is always '.' here,
2667 # because of nested switch statements
2668 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2669 prefix.append((p.name[-1], '.', p))
2670 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2672 # auxiliary object for 'S' parameter
2675 if list.member.fixed_size():
2676 idx = 1 if switch_obj is not None else 0
2678 f.write('%s *\\fB%s\\fP(%s);\n' %
2679 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2680 create_link('%s' % field.c_accessor_name)
2683 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2684 (field.c_length_name, c_type))
2685 create_link('%s' % field.c_length_name)
2687 if field.type.member.is_simple:
2689 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2690 (field.c_end_name, c_type))
2691 create_link('%s' % field.c_end_name)
2694 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2695 (field.c_iterator_type, field.c_iterator_name,
2697 create_link('%s' % field.c_iterator_name)
2699 for field in self.reply.fields:
2700 if field.type.is_list and not field.type.fixed_size():
2701 _c_accessors_list(self, field)
2702 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2703 _c_accessors_field(self, field)
2707 # Re-enable hyphenation and adjusting to both sides
2710 # argument reference
2711 f.write('.SH REQUEST ARGUMENTS\n')
2712 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2713 f.write('The XCB connection to X11.\n')
2714 for field in param_fields:
2715 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2716 printed_enum = False
2717 # XXX: hard-coded until we fix xproto.xml
2718 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2720 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2722 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2724 if hasattr(field, "enum") and field.enum:
2725 # XXX: why the 'xcb' prefix?
2726 key = ('xcb', field.enum)
2728 f.write('One of the following values:\n')
2731 count = len(enum.values)
2732 for (enam, eval) in enum.values:
2734 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2735 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2736 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2737 f.write('%s\n' % desc)
2739 f.write('TODO: NOT YET DOCUMENTED.\n')
2744 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2745 desc = self.doc.fields[field.field_name]
2746 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2749 f.write('%s\n' % desc)
2751 f.write('TODO: NOT YET DOCUMENTED.\n')
2757 f.write('.SH REPLY FIELDS\n')
2758 # These fields are present in every reply:
2759 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2760 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2761 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2762 'be used to tell replies apart from each other.\n') %
2763 _n(self.reply.name).upper())
2764 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2765 f.write('The sequence number of the last request processed by the X11 server.\n')
2766 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2767 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2768 for field in self.reply.fields:
2769 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2770 field.c_field_name.startswith('pad')):
2773 if field.type.is_list and not field.type.fixed_size():
2775 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2777 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2778 printed_enum = False
2779 if hasattr(field, "enum") and field.enum:
2780 # XXX: why the 'xcb' prefix?
2781 key = ('xcb', field.enum)
2783 f.write('One of the following values:\n')
2786 count = len(enum.values)
2787 for (enam, eval) in enum.values:
2789 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2790 if enum.doc and enam in enum.doc.fields:
2791 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2792 f.write('%s\n' % desc)
2794 f.write('TODO: NOT YET DOCUMENTED.\n')
2799 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2800 desc = self.reply.doc.fields[field.field_name]
2801 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2804 f.write('%s\n' % desc)
2806 f.write('TODO: NOT YET DOCUMENTED.\n')
2813 f.write('.SH DESCRIPTION\n')
2814 if hasattr(self, "doc") and self.doc and self.doc.description:
2815 desc = self.doc.description
2816 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2817 lines = desc.split('\n')
2818 f.write('\n'.join(lines) + '\n')
2820 f.write('.SH RETURN VALUE\n')
2822 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2823 'have to be handled in the event loop.\n\nIf you want to '
2824 'handle errors directly with \\fIxcb_request_check\\fP '
2825 'instead, use \\fI%s_checked\\fP. See '
2826 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2828 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2829 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2830 'handle errors in the event loop instead, use '
2831 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2833 (cookie_type, self.c_reply_name, base_func_name, section))
2834 f.write('.SH ERRORS\n')
2835 if hasattr(self, "doc") and self.doc:
2836 for errtype, errtext in sorted(self.doc.errors.items()):
2837 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2838 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2839 f.write('%s\n' % (errtext))
2840 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2841 f.write('This request does never generate any errors.\n')
2842 if hasattr(self, "doc") and self.doc and self.doc.example:
2843 f.write('.SH EXAMPLE\n')
2846 lines = self.doc.example.split('\n')
2847 f.write('\n'.join(lines) + '\n')
2849 f.write('.SH SEE ALSO\n')
2850 if hasattr(self, "doc") and self.doc:
2851 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2852 if self.doc.example:
2853 see.append('.BR %s (%s)' % ('xcb-examples', section))
2854 for seename, seetype in sorted(self.doc.see.items()):
2855 if seetype == 'program':
2856 see.append('.BR %s (1)' % seename)
2857 elif seetype == 'event':
2858 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2859 elif seetype == 'request':
2860 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2861 elif seetype == 'function':
2862 see.append('.BR %s (%s)' % (seename, section))
2864 see.append('TODO: %s (type %s)' % (seename, seetype))
2865 f.write(',\n'.join(see) + '\n')
2866 f.write('.SH AUTHOR\n')
2867 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2870 def _man_event(self, name):
2872 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2873 # Our CWD is src/, so this will end up in src/man/
2874 f = open('man/%s.%s' % (self.c_type, section), 'w')
2875 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2876 # Left-adjust instead of adjusting to both sides
2878 f.write('.SH NAME\n')
2879 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2880 f.write('%s \\- %s\n' % (self.c_type, brief))
2881 f.write('.SH SYNOPSIS\n')
2882 # Don't split words (hyphenate)
2884 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2887 f.write('.SS Event datastructure\n')
2890 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2894 for field in self.fields:
2895 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2898 struct_fields.append(field)
2900 for field in struct_fields:
2901 length = len(field.c_field_type)
2902 # account for '*' pointer_spec
2903 if not field.type.fixed_size():
2905 maxtypelen = max(maxtypelen, length)
2907 def _c_complex_field(self, field, space=''):
2908 if (field.type.fixed_size() or
2909 # in case of switch with switch children, don't make the field a pointer
2910 # necessary for unserialize to work
2911 (self.is_switch and field.type.is_switch)):
2912 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2913 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2915 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2917 if not self.is_switch:
2918 for field in struct_fields:
2919 _c_complex_field(self, field)
2921 for b in self.bitcases:
2925 for field in b.type.fields:
2926 _c_complex_field(self, field, space)
2928 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2931 f.write('} \\fB%s\\fP;\n' % self.c_type)
2936 # Re-enable hyphenation and adjusting to both sides
2939 # argument reference
2940 f.write('.SH EVENT FIELDS\n')
2941 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2942 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2943 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2944 'to tell events apart from each other.\n') % _n(name).upper())
2945 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2946 f.write('The sequence number of the last request processed by the X11 server.\n')
2948 if not self.is_switch:
2949 for field in struct_fields:
2950 # Skip the fields which every event has, we already documented
2952 if field.c_field_name in ('response_type', 'sequence'):
2954 if isinstance(field.type, PadType):
2956 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2957 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2958 desc = self.doc.fields[field.field_name]
2959 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2960 f.write('%s\n' % desc)
2962 f.write('NOT YET DOCUMENTED.\n')
2965 f.write('.SH DESCRIPTION\n')
2966 if hasattr(self, "doc") and self.doc and self.doc.description:
2967 desc = self.doc.description
2968 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2969 lines = desc.split('\n')
2970 f.write('\n'.join(lines) + '\n')
2972 if hasattr(self, "doc") and self.doc and self.doc.example:
2973 f.write('.SH EXAMPLE\n')
2976 lines = self.doc.example.split('\n')
2977 f.write('\n'.join(lines) + '\n')
2979 f.write('.SH SEE ALSO\n')
2980 if hasattr(self, "doc") and self.doc:
2981 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2982 if self.doc.example:
2983 see.append('.BR %s (%s)' % ('xcb-examples', section))
2984 for seename, seetype in sorted(self.doc.see.items()):
2985 if seetype == 'program':
2986 see.append('.BR %s (1)' % seename)
2987 elif seetype == 'event':
2988 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2989 elif seetype == 'request':
2990 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2991 elif seetype == 'function':
2992 see.append('.BR %s (%s)' % (seename, section))
2994 see.append('TODO: %s (type %s)' % (seename, seetype))
2995 f.write(',\n'.join(see) + '\n')
2996 f.write('.SH AUTHOR\n')
2997 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3001 def c_request(self, name):
3003 Exported function that handles request declarations.
3005 _c_type_setup(self, name, ('request',))
3008 # Cookie type declaration
3009 _c_cookie(self, name)
3012 _c_opcode(name, self.opcode)
3014 # Request structure declaration
3018 _c_type_setup(self.reply, name, ('reply',))
3019 # Reply structure definition
3020 _c_complex(self.reply)
3021 # Request prototypes
3022 has_fds = _c_reply_has_fds(self.reply)
3023 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3024 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3026 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3027 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3029 _c_accessors(self.reply, name + ('reply',), name)
3030 _c_reply(self, name)
3032 _c_reply_fds(self, name)
3034 # Request prototypes
3035 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3036 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3038 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3039 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3041 # We generate the manpage afterwards because _c_type_setup has been called.
3042 # TODO: what about aux helpers?
3043 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3044 _man_request(self, name, cookie_type, not self.reply, False)
3046 def c_event(self, name):
3048 Exported function that handles event declarations.
3051 # The generic event structure xcb_ge_event_t has the full_sequence field
3052 # at the 32byte boundary. That's why we've to inject this field into GE
3053 # events while generating the structure for them. Otherwise we would read
3054 # garbage (the internal full_sequence) when accessing normal event fields
3056 force_packed = False
3057 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3059 for field in self.fields:
3060 if field.type.size != None and field.type.nmemb != None:
3061 event_size += field.type.size * field.type.nmemb
3062 if event_size == 32:
3063 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3064 idx = self.fields.index(field)
3065 self.fields.insert(idx + 1, full_sequence)
3067 # If the event contains any 64-bit extended fields, they need
3068 # to remain aligned on a 64-bit boundary. Adding full_sequence
3069 # would normally break that; force the struct to be packed.
3070 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3073 if self.name == name:
3074 _c_type_setup(self, name, ('event',))
3075 # generate accessors
3076 # (needed for fields after var-sized fields, for lists with var-sized elements,
3078 _c_accessors(self, name, name)
3080 # no type-setup needed for eventcopies
3081 # (the type-setup of an eventcopy would overwrite members of the original
3082 # event, and it would create sizeof-etc funtions which
3083 # called undefined accessor functions)
3087 _c_opcode(name, self.opcodes[name])
3089 if self.name == name:
3090 # Structure definition
3091 _c_complex(self, force_packed)
3095 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3097 # Create sizeof-function for eventcopies for compatibility reasons
3098 if self.c_need_sizeof:
3103 _h('%s (const void *_buffer /**< */);', _n(name + ('sizeof',)))
3106 _c('%s (const void *_buffer /**< */)', _n(name + ('sizeof',)))
3108 _c(' return %s(_buffer);', _n(self.name + ('sizeof',)))
3113 _man_event(self, name)
3115 def c_error(self, name):
3117 Exported function that handles error declarations.
3119 _c_type_setup(self, name, ('error',))
3122 _c_opcode(name, self.opcodes[name])
3124 if self.name == name:
3125 # Structure definition
3130 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3133 # Main routine starts here
3135 # Must create an "output" dictionary before any xcbgen imports.
3136 output = {'open' : c_open,
3138 'simple' : c_simple,
3140 'struct' : c_struct,
3142 'request' : c_request,
3147 # Boilerplate below this point
3149 # Check for the argument that specifies path to the xcbgen python package.
3151 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3152 except getopt.GetoptError as err:
3154 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3157 for (opt, arg) in opts:
3165 sys.path.insert(1, arg)
3168 sys.stdout.write('man_MANS = ')
3170 # Import the module class
3172 from xcbgen.state import Module
3173 from xcbgen.xtypes import *
3176 Failed to load the xcbgen Python package!
3177 Make sure that xcb/proto installed it on your Python path.
3178 If not, you will need to create a .pth file or define $PYTHONPATH
3180 Refer to the README file in xcb/proto for more info.
3184 # Ensure the man subdirectory exists
3187 except OSError as e:
3188 if e.errno != errno.EEXIST:
3191 # Parse the xml header
3192 module = Module(args[0], output)
3194 # Build type-registry and resolve type dependencies