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
573 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
574 (obj.is_switch and len(obj.parents)>1)):
579 # add separator for access to a yet unknown field
580 prefix_str += last_sep
582 if _c_field_needs_accessor(field):
583 if _c_field_is_member_of_case_or_bitcase(field):
584 # case members are available in the deserialized struct,
585 # so there is no need to use the accessor function
586 # (also, their accessor function needs a different arglist
587 # so this would require special treatment here)
588 # Therefore: Access as struct member
589 prefix_str += last_sep + _cpp(field.field_name)
591 # Access with the accessor function
592 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
594 # Access as struct member
595 prefix_str += last_sep + _cpp(field.field_name)
600 def _c_helper_field_mapping(complex_type, prefix, flat=False):
602 generate absolute names, based on prefix, for all fields starting from complex_type
603 if flat == True, nested complex types are not taken into account
606 if complex_type.is_switch:
607 for b in complex_type.bitcases:
609 switch_name, switch_sep, switch_type = prefix[-1]
610 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
612 bitcase_prefix = prefix
614 if (True==flat and not b.type.has_name) or False==flat:
615 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
617 for f in complex_type.fields:
618 fname = _c_helper_fieldaccess_expr(prefix, f)
619 if f.field_name in all_fields:
620 raise Exception("field name %s has been registered before" % f.field_name)
622 all_fields[f.field_name] = (fname, f)
623 if f.type.is_container and flat==False:
624 if f.type.is_case_or_bitcase and not f.type.has_name:
626 elif f.type.is_switch and len(f.type.parents)>1:
627 # nested switch gets another separator
628 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
630 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
631 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
636 def _c_helper_resolve_field_names (prefix):
638 get field names for all objects in the prefix array
642 # look for fields in the remaining containers
643 for idx, p in enumerate(prefix):
646 # sep can be preset in prefix, if not, make a sensible guess
647 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
648 # exception: 'toplevel' object (switch as well!) always have sep '->'
649 sep = '->' if idx<1 else sep
650 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
651 tmp_prefix.append((name, sep, obj))
652 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
655 # _c_helper_resolve_field_names
657 def get_expr_fields(self):
659 get the Fields referenced by switch or list expression
661 def get_expr_field_names(expr):
663 if expr.lenfield_name is not None:
664 return [expr.lenfield_name]
666 # constant value expr
670 return get_expr_field_names(expr.rhs)
671 elif expr.op == 'popcount':
672 return get_expr_field_names(expr.rhs)
673 elif expr.op == 'sumof':
674 # sumof expr references another list,
675 # we need that list's length field here
677 for f in expr.lenfield_parent.fields:
678 if f.field_name == expr.lenfield_name:
682 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
683 # referenced list + its length field
684 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
685 elif expr.op == 'enumref':
688 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
689 # get_expr_field_names()
691 # resolve the field names with the parent structure(s)
692 unresolved_fields_names = get_expr_field_names(self.expr)
694 # construct prefix from self
695 prefix = [('', '', p) for p in self.parents]
696 if self.is_container:
697 prefix.append(('', '', self))
699 all_fields = _c_helper_resolve_field_names (prefix)
700 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
701 if len(unresolved_fields_names) != len(resolved_fields_names):
702 raise Exception("could not resolve all fields for %s" % self.name)
704 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
705 return resolved_fields
708 def resolve_expr_fields(complex_obj):
710 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
711 these are normally fields that need to be given as function parameters
717 for field in complex_obj.fields:
718 all_fields.append(field)
719 if field.type.is_switch or field.type.is_list:
720 expr_fields += get_expr_fields(field.type)
721 if field.type.is_container:
722 expr_fields += resolve_expr_fields(field.type)
724 # try to resolve expr fields
725 for e in expr_fields:
726 if e not in all_fields and e not in unresolved:
729 # resolve_expr_fields()
731 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
733 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
734 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
735 expression. This function tries to resolve all fields within a structure, and returns the
736 unresolved fields as the list of external parameters.
738 def add_param(params, param):
739 if param not in params:
742 # collect all fields into param_fields
746 for field in self.fields:
748 # the field should appear as a parameter in the function call
749 param_fields.append(field)
750 if field.wire and not field.auto:
751 if field.type.fixed_size() and not self.is_switch:
752 # field in the xcb_out structure
753 wire_fields.append(field)
754 # fields like 'pad0' are skipped!
756 # in case of switch, parameters always contain any fields referenced in the switch expr
757 # we do not need any variable size fields here, as the switch data type contains both
758 # fixed and variable size fields
760 param_fields = get_expr_fields(self)
762 # _serialize()/_unserialize()/_unpack() function parameters
763 # note: don't use set() for params, it is unsorted
766 # 1. the parameter for the void * buffer
767 if 'serialize' == context:
768 params.append(('void', '**', buffer_var))
769 elif context in ('unserialize', 'unpack', 'sizeof'):
770 params.append(('const void', '*', buffer_var))
772 # 2. any expr fields that cannot be resolved within self and descendants
773 unresolved_fields = resolve_expr_fields(self)
774 for f in unresolved_fields:
775 add_param(params, (f.c_field_type, '', f.c_field_name))
777 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
778 # that do not appear in the data type struct
779 for p in param_fields:
781 typespec = p.c_field_const_type
782 pointerspec = p.c_pointer
783 add_param(params, (typespec, pointerspec, p.c_field_name))
785 if p.visible and not p.wire and not p.auto:
786 typespec = p.c_field_type
788 add_param(params, (typespec, pointerspec, p.c_field_name))
791 if 'serialize' == context:
792 add_param(params, ('const %s' % self.c_type, '*', aux_var))
793 elif 'unserialize' == context:
794 add_param(params, ('%s' % self.c_type, '**', aux_var))
795 elif 'unpack' == context:
796 add_param(params, ('%s' % self.c_type, '*', aux_var))
798 # 5. switch contains all variable size fields as struct members
799 # for other data types though, these have to be supplied separately
800 # this is important for the special case of intermixed fixed and
801 # variable size fields
802 if not self.is_switch and 'serialize' == context:
803 for p in param_fields:
804 if not p.type.fixed_size():
805 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
807 return (param_fields, wire_fields, params)
808 # get_serialize_params()
810 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
811 code_lines.append('%s /* insert padding */' % space)
812 if is_case_or_bitcase:
814 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
818 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
819 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
820 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
823 code_lines.append('%s if (0 != xcb_pad) {' % space)
825 if 'serialize' == context:
826 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
827 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
828 code_lines.append('%s xcb_parts_idx++;' % space)
829 elif context in ('unserialize', 'unpack', 'sizeof'):
830 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
832 code_lines.append('%s xcb_pad = 0;' % space)
833 code_lines.append('%s }' % space)
835 code_lines.append('%s xcb_block_len = 0;' % space)
836 if is_case_or_bitcase:
837 code_lines.append('%s xcb_padding_offset = 0;' % space)
839 # keep tracking of xcb_parts entries for serialize
841 # _c_serialize_helper_insert_padding()
843 def _c_serialize_helper_switch(context, self, complex_name,
844 code_lines, temp_vars,
847 switch_expr = _c_accessor_get_expr(self.expr, None)
849 for b in self.bitcases:
850 len_expr = len(b.type.expr)
852 compare_operator = '&'
854 compare_operator = '=='
856 compare_operator = '&'
858 for n, expr in enumerate(b.type.expr):
859 bitcase_expr = _c_accessor_get_expr(expr, None)
860 # only one <enumref> in the <bitcase>
863 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
864 # multiple <enumref> in the <bitcase>
867 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
868 elif len_expr == (n + 1): # last
870 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
871 else: # between first and last
873 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
877 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
879 count += _c_serialize_helper_fields(context, b.type,
880 code_lines, temp_vars,
883 is_case_or_bitcase = True)
884 code_lines.append(' }')
886 # if 'serialize' == context:
887 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
888 # elif context in ('unserialize', 'unpack', 'sizeof'):
890 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
891 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
894 # _c_serialize_helper_switch
896 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
898 handle switch by calling _serialize() or _unpack(), depending on context
900 # switch is handled by this function as a special case
901 param_fields, wire_fields, params = get_serialize_params(context, self)
902 field_mapping = _c_helper_field_mapping(self, prefix)
903 prefix_str = _c_helper_fieldaccess_expr(prefix)
905 # find the parameters that need to be passed to _serialize()/_unpack():
906 # all switch expr fields must be given as parameters
907 args = get_expr_fields(field.type)
908 # length fields for variable size types in switch, normally only some of need
909 # need to be passed as parameters
910 switch_len_fields = resolve_expr_fields(field.type)
912 # a switch field at this point _must_ be a bitcase field
913 # we require that bitcases are "self-contiguous"
914 bitcase_unresolved = resolve_expr_fields(self)
915 if len(bitcase_unresolved) != 0:
916 raise Exception('unresolved fields within bitcase is not supported at this point')
918 # get the C names for the parameters
920 for a in switch_len_fields:
921 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
923 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
925 # call _serialize()/_unpack() to determine the actual size
926 if 'serialize' == context:
927 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
928 c_field_names, prefix_str, field.c_field_name)
929 elif context in ('unserialize', 'unpack'):
930 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
931 c_field_names, prefix_str, field.c_field_name)
932 elif 'sizeof' == context:
933 # remove trailing ", " from c_field_names because it will be used at end of arglist
934 my_c_field_names = c_field_names[:-2]
935 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
938 # _c_serialize_helper_switch_field()
940 def _c_serialize_helper_list_field(context, self, field,
941 code_lines, temp_vars,
944 helper function to cope with lists of variable length
946 expr = field.type.expr
947 prefix_str = _c_helper_fieldaccess_expr(prefix)
948 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
949 param_names = [p[2] for p in params]
951 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
952 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
953 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
957 field_mapping[r] = (r, None)
959 if len(unresolved)>0:
961 if len(tmp_prefix)==0:
962 raise Exception("found an empty prefix while resolving expr field names for list %s",
965 field_mapping.update(_c_helper_resolve_field_names(prefix))
966 resolved += list(filter(lambda x: x in field_mapping, unresolved))
967 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
968 if len(unresolved)>0:
969 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
971 list_length = _c_accessor_get_expr(expr, field_mapping)
973 # default: list with fixed size elements
974 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
976 # list with variable-sized elements
977 if not field.type.member.fixed_size():
979 if context in ('unserialize', 'sizeof', 'unpack'):
980 int_i = ' unsigned int i;'
981 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
982 if int_i not in temp_vars:
983 temp_vars.append(int_i)
984 if xcb_tmp_len not in temp_vars:
985 temp_vars.append(xcb_tmp_len)
986 # loop over all list elements and call sizeof repeatedly
987 # this should be a bit faster than using the iterators
988 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
989 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
990 (space, field.type.c_sizeof_name))
991 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
992 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
993 code_lines.append("%s }" % space)
995 elif 'serialize' == context:
996 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
997 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
998 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
999 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
1000 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
1001 code_lines.append('%s }' % space)
1002 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1005 # _c_serialize_helper_list_field()
1007 def _c_serialize_helper_fields_fixed_size(context, self, field,
1008 code_lines, temp_vars,
1010 # keep the C code a bit more readable by giving the field name
1011 if not self.is_case_or_bitcase:
1012 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1014 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1015 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1016 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1018 abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1019 # default for simple cases: call sizeof()
1020 length = "sizeof(%s)" % field.c_field_type
1022 if context in ('unserialize', 'unpack', 'sizeof'):
1023 # default: simple cast
1024 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1026 # padding - we could probably just ignore it
1027 if field.type.is_pad and field.type.nmemb > 1:
1029 for i in range(field.type.nmemb):
1030 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1031 (space, abs_field_name, i, field.c_field_type))
1032 # total padding = sizeof(pad0) * nmemb
1033 length += " * %d" % field.type.nmemb
1035 elif field.type.is_list:
1036 # list with fixed number of elements
1037 # length of array = sizeof(arrayElementType) * nmemb
1038 length += " * %d" % field.type.nmemb
1039 # use memcpy because C cannot assign whole arrays with operator=
1040 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1043 elif 'serialize' == context:
1044 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1046 if field.type.is_expr:
1047 # need to register a temporary variable for the expression in case we know its type
1048 if field.type.c_type is None:
1049 raise Exception("type for field '%s' (expression '%s') unkown" %
1050 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1052 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1053 _c_accessor_get_expr(field.type.expr, prefix)))
1054 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1056 elif field.type.is_pad:
1057 if field.type.nmemb == 1:
1058 value += "&xcb_pad;"
1060 # we could also set it to 0, see definition of xcb_send_request()
1061 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1062 length += "*%d" % field.type.nmemb
1065 # non-list type with fixed size
1066 if field.type.nmemb == 1:
1067 value += "&%s;" % (abs_field_name)
1069 # list with nmemb (fixed size) elements
1071 value += '%s;' % (abs_field_name)
1072 length = '%d' % field.type.nmemb
1074 return (value, length)
1075 # _c_serialize_helper_fields_fixed_size()
1077 def _c_serialize_helper_fields_variable_size(context, self, field,
1078 code_lines, temp_vars,
1080 prefix_str = _c_helper_fieldaccess_expr(prefix)
1082 if context in ('unserialize', 'unpack', 'sizeof'):
1084 var_field_name = 'xcb_tmp'
1086 # special case: intermixed fixed and variable size fields
1087 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1088 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1089 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1090 # special case: switch
1091 if 'unpack' == context:
1092 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1094 elif 'serialize' == context:
1095 # variable size fields appear as parameters to _serialize() if the
1096 # 'toplevel' container is not a switch
1097 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1098 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1099 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1103 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1105 if field.type.is_list:
1107 # in any context, list is already a pointer, so the default assignment is ok
1108 code_lines.append("%s%s" % (space, value))
1110 length = _c_serialize_helper_list_field(context, self, field,
1111 code_lines, temp_vars,
1114 elif field.type.is_switch:
1116 if context == 'serialize':
1117 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1118 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1119 length = _c_serialize_helper_switch_field(context, self, field,
1120 'xcb_parts[xcb_parts_idx].iov_base',
1124 # in all remaining special cases - call _sizeof()
1125 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1127 return (value, length)
1128 # _c_serialize_helper_fields_variable_size
1130 def _c_serialize_helper_fields(context, self,
1131 code_lines, temp_vars,
1132 space, prefix, is_case_or_bitcase):
1134 need_padding = False
1135 prev_field_was_variable = False
1137 _c_pre.push_indent(space + ' ')
1139 for field in self.fields:
1140 if not field.visible:
1141 if not ((field.wire and not field.auto) or 'unserialize' == context):
1144 # switch/bitcase: fixed size fields must be considered explicitly
1145 if field.type.fixed_size():
1146 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1147 if prev_field_was_variable and need_padding:
1149 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1150 # self.c_var_followed_by_fixed_fields)
1151 prev_field_was_variable = False
1153 # prefix for fixed size fields
1154 fixed_prefix = prefix
1156 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1157 code_lines, temp_vars,
1158 space, fixed_prefix)
1162 # fields with variable size
1164 if field.type.is_pad:
1165 # Variable length pad is <pad align= />
1166 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1167 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1168 self.c_var_followed_by_fixed_fields,
1172 # switch/bitcase: always calculate padding before and after variable sized fields
1173 if need_padding or is_case_or_bitcase:
1174 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1175 self.c_var_followed_by_fixed_fields,
1178 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1179 code_lines, temp_vars,
1181 prev_field_was_variable = True
1183 # save (un)serialization C code
1185 code_lines.append('%s%s' % (space, value))
1187 if field.type.fixed_size():
1188 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1189 # keep track of (un)serialized object's size
1190 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1191 if context in ('unserialize', 'unpack', 'sizeof'):
1192 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1194 # variable size objects or bitcase:
1195 # value & length might have been inserted earlier for special cases
1197 # special case: intermixed fixed and variable size fields
1198 if (not field.type.fixed_size() and
1199 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1200 temp_vars.append(' int %s_len;' % field.c_field_name)
1201 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1202 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1203 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1205 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1206 # increase pointer into the byte stream accordingly
1207 if context in ('unserialize', 'sizeof', 'unpack'):
1208 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1210 if 'serialize' == context:
1212 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1213 code_lines.append('%s xcb_parts_idx++;' % space)
1217 '%s xcb_align_to = ALIGNOF(%s);'
1220 if field.c_field_type == 'void' or field.type.is_switch
1221 else field.c_field_type))
1224 if self.c_var_followed_by_fixed_fields:
1225 need_padding = False
1230 # _c_serialize_helper_fields()
1232 def _c_serialize_helper(context, complex_type,
1233 code_lines, temp_vars,
1234 space='', prefix=[]):
1235 # count tracks the number of fields to serialize
1238 if hasattr(complex_type, 'type'):
1239 self = complex_type.type
1240 complex_name = complex_type.name
1243 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1244 complex_name = 'xcb_out'
1246 complex_name = '_aux'
1248 # special case: switch is serialized by evaluating each bitcase separately
1250 count += _c_serialize_helper_switch(context, self, complex_name,
1251 code_lines, temp_vars,
1254 # all other data types can be evaluated one field a time
1256 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1257 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1258 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1259 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1260 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1261 code_lines.append('%s xcb_block_len = 0;' % space)
1263 count += _c_serialize_helper_fields(context, self,
1264 code_lines, temp_vars,
1265 space, prefix, False)
1267 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1270 # _c_serialize_helper()
1272 def _c_serialize(context, self):
1274 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1275 for the ComplexType variable self
1281 # _serialize() returns the buffer size
1284 if self.is_switch and 'unserialize' == context:
1287 cases = { 'serialize' : self.c_serialize_name,
1288 'unserialize' : self.c_unserialize_name,
1289 'unpack' : self.c_unpack_name,
1290 'sizeof' : self.c_sizeof_name }
1291 func_name = cases[context]
1293 param_fields, wire_fields, params = get_serialize_params(context, self)
1294 variable_size_fields = 0
1295 # maximum space required for type definition of function arguments
1298 # determine N(variable_fields)
1299 for field in param_fields:
1300 # if self.is_switch, treat all fields as if they are variable sized
1301 if not field.type.fixed_size() or self.is_switch:
1302 variable_size_fields += 1
1303 # determine maxtypelen
1305 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1308 indent = ' '*(len(func_name)+2)
1311 typespec, pointerspec, field_name = p
1312 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1313 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1314 # insert function name
1315 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1316 param_str = list(map(lambda x: "%s," % x, param_str))
1317 for s in param_str[:-1]:
1319 _h("%s);" % param_str[-1].rstrip(','))
1320 _c("%s)" % param_str[-1].rstrip(','))
1327 _c_pre.redirect_start(code_lines, temp_vars)
1329 if 'serialize' == context:
1330 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1331 _c(' %s *xcb_out = *_buffer;', self.c_type)
1332 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1333 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1334 _c(' unsigned int xcb_align_to = 0;')
1336 _c(' char *xcb_out = *_buffer;')
1337 _c(' unsigned int xcb_buffer_len = 0;')
1338 _c(' unsigned int xcb_align_to = 0;')
1340 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1341 prefix = [('_aux', '->', self)]
1344 elif context in ('unserialize', 'unpack'):
1345 _c(' char *xcb_tmp = (char *)_buffer;')
1346 if not self.is_switch:
1347 if not self.c_var_followed_by_fixed_fields:
1348 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1349 prefix = [('_aux', '->', self)]
1351 _c(' %s xcb_out;', self.c_type)
1352 prefix = [('xcb_out', '.', self)]
1354 aux_var = '_aux' # default for unpack: single pointer
1355 # note: unserialize not generated for switch
1356 if 'unserialize' == context:
1357 aux_var = '(*_aux)' # unserialize: double pointer (!)
1358 prefix = [(aux_var, '->', self)]
1360 _c(' unsigned int xcb_buffer_len = 0;')
1361 _c(' unsigned int xcb_block_len = 0;')
1362 _c(' unsigned int xcb_pad = 0;')
1363 _c(' unsigned int xcb_align_to = 0;')
1365 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1367 elif 'sizeof' == context:
1368 param_names = [p[2] for p in params]
1370 # switch: call _unpack()
1371 _c(' %s _aux;', self.c_type)
1372 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1374 _c_pre.redirect_end()
1376 elif self.c_var_followed_by_fixed_fields:
1377 # special case: call _unserialize()
1378 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1380 _c_pre.redirect_end()
1383 _c(' char *xcb_tmp = (char *)_buffer;')
1384 prefix = [('_aux', '->', self)]
1386 _c(' unsigned int xcb_padding_offset = 0;')
1388 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1389 # update variable size fields (only important for context=='serialize'
1390 variable_size_fields = count
1391 if 'serialize' == context:
1392 temp_vars.append(' unsigned int xcb_pad = 0;')
1393 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1394 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1395 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1396 temp_vars.append(' unsigned int xcb_block_len = 0;')
1397 temp_vars.append(' unsigned int i;')
1398 temp_vars.append(' char *xcb_tmp;')
1399 elif 'sizeof' == context:
1400 # neither switch nor intermixed fixed and variable size fields:
1401 # evaluate parameters directly
1402 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1404 # look if we have to declare an '_aux' variable at all
1405 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1406 if not self.c_var_followed_by_fixed_fields:
1407 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1409 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1411 _c(' unsigned int xcb_buffer_len = 0;')
1412 _c(' unsigned int xcb_block_len = 0;')
1413 _c(' unsigned int xcb_pad = 0;')
1414 _c(' unsigned int xcb_align_to = 0;')
1416 _c_pre.redirect_end()
1422 for l in code_lines:
1425 # variable sized fields have been collected, now
1426 # allocate memory and copy everything into a continuous memory area
1427 # note: this is not necessary in case of unpack
1428 if context in ('serialize', 'unserialize'):
1429 # unserialize: check for sizeof-only invocation
1430 if 'unserialize' == context:
1432 _c(' if (NULL == _aux)')
1433 _c(' return xcb_buffer_len;')
1436 _c(' if (NULL == %s) {', aux_ptr)
1437 _c(' /* allocate memory */')
1438 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1439 if 'serialize' == context:
1440 _c(' *_buffer = xcb_out;')
1444 # serialize: handle variable size fields in a loop
1445 if 'serialize' == context:
1446 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1447 if len(wire_fields)>0:
1448 _c(' *xcb_out = *_aux;')
1449 # copy variable size fields into the buffer
1450 if variable_size_fields > 0:
1452 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1453 _c(' xcb_tmp = (char*)++xcb_out;')
1454 _c(' xcb_tmp += xcb_out_pad;')
1456 _c(' xcb_tmp = xcb_out;')
1458 # variable sized fields
1459 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1460 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1461 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1462 _c(' if (0 != xcb_parts[i].iov_len)')
1463 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1466 # unserialize: assign variable size fields individually
1467 if 'unserialize' == context:
1468 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1469 param_fields.reverse()
1470 for field in param_fields:
1471 if not field.type.fixed_size():
1472 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1473 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1474 _c(' *%s = xcb_out;', aux_ptr)
1477 _c(' return xcb_buffer_len;')
1481 def _c_iterator_get_end(field, accum):
1483 Figures out what C code is needed to find the end of a variable-length structure field.
1484 For nested structures, recurses into its last variable-sized field.
1485 For lists, calls the end function
1487 if field.type.is_container:
1488 accum = field.c_accessor_name + '(' + accum + ')'
1489 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1490 if field.type.is_list:
1491 # XXX we can always use the first way
1492 if field.type.member.is_simple:
1493 return field.c_end_name + '(' + accum + ')'
1495 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1497 def _c_iterator(self, name):
1499 Declares the iterator structure and next/end functions for a given type.
1504 _h(' * @brief %s', self.c_iterator_type)
1506 _h('typedef struct %s {', self.c_iterator_type)
1507 _h(' %s *data; /**< */', self.c_type)
1508 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1509 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1510 _h('} %s;', self.c_iterator_type)
1516 _h(' * Get the next element of the iterator')
1517 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1519 _h(' * Get the next element in the iterator. The member rem is')
1520 _h(' * decreased by one. The member data points to the next')
1521 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1525 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1526 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1529 if not self.fixed_size():
1530 _c(' %s *R = i->data;', self.c_type)
1533 # FIXME - how to determine the size of a variable size union??
1534 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1536 if self.c_need_sizeof:
1537 _c(' xcb_generic_iterator_t child;')
1538 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1539 self.c_type, self.c_sizeof_name)
1540 _c(' i->index = (char *) child.data - (char *) i->data;')
1542 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1543 _c(' i->index = child.index;')
1545 _c(' i->data = (%s *) child.data;', self.c_type)
1550 _c(' i->index += sizeof(%s);', self.c_type)
1556 _h(' * Return the iterator pointing to the last element')
1557 _h(' * @param i An %s', self.c_iterator_type)
1558 _h(' * @return The iterator pointing to the last element')
1560 _h(' * Set the current element in the iterator to the last element.')
1561 _h(' * The member rem is set to 0. The member data points to the')
1562 _h(' * last element.')
1565 _hc('xcb_generic_iterator_t')
1566 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1567 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1569 _c(' xcb_generic_iterator_t ret;')
1571 if self.fixed_size():
1572 _c(' ret.data = i.data + i.rem;')
1573 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1576 _c(' while(i.rem > 0)')
1577 _c(' %s(&i);', self.c_next_name)
1578 _c(' ret.data = i.data;')
1579 _c(' ret.rem = i.rem;')
1580 _c(' ret.index = i.index;')
1585 def _c_accessor_get_length(expr, field_mapping=None):
1587 Figures out what C code is needed to get a length field.
1588 The field_mapping parameter can be used to change the absolute name of a length field.
1589 For fields that follow a variable-length field, use the accessor.
1590 Otherwise, just reference the structure field directly.
1593 lenfield_name = expr.lenfield_name
1594 if lenfield_name is not None:
1595 if field_mapping is not None:
1596 lenfield_name = field_mapping[lenfield_name][0]
1598 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1599 # special case: variable and fixed size fields are intermixed
1600 # if the lenfield is among the fixed size fields, there is no need
1601 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1602 return field_mapping(expr.lenfield_name)
1603 elif expr.lenfield_name is not None:
1604 return lenfield_name
1606 return str(expr.nmemb)
1608 def _c_accessor_get_expr(expr, field_mapping):
1610 Figures out what C code is needed to get the length of a list field.
1611 The field_mapping parameter can be used to change the absolute name of a length field.
1612 Recurses for math operations.
1613 Returns bitcount for value-mask fields.
1614 Otherwise, uses the value of the length field.
1616 lenexp = _c_accessor_get_length(expr, field_mapping)
1619 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1620 elif expr.op == 'popcount':
1621 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1622 elif expr.op == 'enumref':
1623 enum_name = expr.lenfield_type.name
1624 constant_name = expr.lenfield_name
1625 c_name = _n(enum_name + (constant_name,)).upper()
1627 elif expr.op == 'sumof':
1628 # locate the referenced list object
1629 list_obj = expr.lenfield_type
1631 for f in expr.lenfield_parent.fields:
1632 if f.field_name == expr.lenfield_name:
1637 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1638 list_name = field_mapping[field.c_field_name][0]
1639 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1640 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1641 # create explicit code for computing the sum.
1642 # This works for all C-types which can be added to int64_t with +=
1644 lengthvar = _c_pre.get_tempvarname()
1645 loopvar = _c_pre.get_tempvarname()
1646 sumvar = _c_pre.get_tempvarname()
1647 listvar = _c_pre.get_tempvarname()
1648 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1649 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1650 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1651 _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1652 _c_pre.code("/* sumof start */")
1653 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1654 _c_pre.code("%s = 0;", sumvar)
1655 _c_pre.code("%s = %s;", listvar, list_name)
1656 _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1659 if expr.rhs is None:
1660 _c_pre.code("%s += *%s;", sumvar, listvar)
1662 # sumof has a nested expression which has to be evaluated in
1663 # the context of this list element
1665 # field mapping for the subexpression needs to include
1666 # the fields of the list-member type
1667 scoped_field_mapping = field_mapping.copy()
1668 scoped_field_mapping.update(
1669 _c_helper_field_mapping(
1671 [(listvar, '->', field.type.member)]))
1673 # cause pre-code of the subexpression be added right here
1675 # compute the subexpression
1676 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1677 # resume with our code
1679 # output the summation expression
1680 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1682 _c_pre.code("%s++;", listvar)
1685 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1688 elif expr.op != None:
1689 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1690 ' ' + expr.op + ' ' +
1691 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1693 return 'xcb_popcount(' + lenexp + ')'
1697 def type_pad_type(type):
1702 def _c_accessors_field(self, field):
1704 Declares the accessor functions for a non-list field that follows a variable-length field.
1706 c_type = self.c_type
1708 # special case: switch
1709 switch_obj = self if self.is_switch else None
1710 if self.is_case_or_bitcase:
1711 switch_obj = self.parents[-1]
1712 if switch_obj is not None:
1713 c_type = switch_obj.c_type
1715 if field.type.is_simple:
1717 _hc('%s', field.c_field_type)
1718 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1719 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1721 if field.prev_varsized_field is None:
1722 _c(' return (%s *) (R + 1);', field.c_field_type)
1724 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1725 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1726 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1730 if field.type.is_switch and switch_obj is None:
1731 return_type = 'void *'
1733 return_type = '%s *' % field.c_field_type
1736 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1737 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1739 if field.prev_varsized_field is None:
1740 _c(' return (%s) (R + 1);', return_type)
1741 # note: the special case 'variable fields followed by fixed size fields'
1742 # is not of any consequence here, since the ordering gets
1743 # 'corrected' in the reply function
1745 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1746 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1747 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1751 def _c_accessors_list(self, field):
1753 Declares the accessor functions for a list field.
1754 Declares a direct-accessor function only if the list members are fixed size.
1755 Declares length and get-iterator functions always.
1758 def get_align_pad(field):
1759 prev = field.prev_varsized_field
1760 prev_prev = field.prev_varsized_field.prev_varsized_field
1762 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1763 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1769 c_type = self.c_type
1771 # special case: switch
1772 # in case of switch, 2 params have to be supplied to certain accessor functions:
1773 # 1. the anchestor object (request or reply)
1774 # 2. the (anchestor) switch object
1775 # the reason is that switch is either a child of a request/reply or nested in another switch,
1776 # so whenever we need to access a length field, we might need to refer to some anchestor type
1777 switch_obj = self if self.is_switch else None
1778 if self.is_case_or_bitcase:
1779 switch_obj = self.parents[-1]
1780 if switch_obj is not None:
1781 c_type = switch_obj.c_type
1785 parents = self.parents if hasattr(self, 'parents') else [self]
1786 # 'R': parents[0] is always the 'toplevel' container type
1787 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1788 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1789 # auxiliary object for 'R' parameters
1792 if switch_obj is not None:
1793 # now look where the fields are defined that are needed to evaluate
1794 # the switch expr, and store the parent objects in accessor_params and
1795 # the fields in switch_fields
1797 # 'S': name for the 'toplevel' switch
1798 toplevel_switch = parents[1]
1799 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1800 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1802 # initialize prefix for everything "below" S
1803 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1804 prefix = [(prefix_str, '->', toplevel_switch)]
1806 # look for fields in the remaining containers
1807 for p in parents[2:] + [self]:
1808 # the separator between parent and child is always '.' here,
1809 # because of nested switch statements
1810 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1811 prefix.append((p.name[-1], '.', p))
1812 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1814 # auxiliary object for 'S' parameter
1819 if list.member.fixed_size():
1820 idx = 1 if switch_obj is not None else 0
1822 _hc('%s *', field.c_field_type)
1824 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1825 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1828 if switch_obj is not None:
1829 _c(' return %s;', fields[field.c_field_name][0])
1830 elif field.prev_varsized_field is None:
1831 _c(' return (%s *) (R + 1);', field.c_field_type)
1833 (prev_varsized_field, align_pad) = get_align_pad(field)
1835 if align_pad is None:
1836 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1837 type_pad_type(field.first_field_after_varsized.type.c_type))
1839 _c(' xcb_generic_iterator_t prev = %s;',
1840 _c_iterator_get_end(prev_varsized_field, 'R'))
1841 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1842 field.c_field_type, align_pad, field.prev_varsized_offset)
1847 if switch_obj is not None:
1848 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1849 spacing = ' '*(len(field.c_length_name)+2)
1850 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1851 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1853 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1854 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1856 length = _c_accessor_get_expr(field.type.expr, fields)
1857 _c(' return %s;', length)
1860 if field.type.member.is_simple:
1862 _hc('xcb_generic_iterator_t')
1863 if switch_obj is not None:
1864 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1865 spacing = ' '*(len(field.c_end_name)+2)
1866 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1867 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1869 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1870 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1872 _c(' xcb_generic_iterator_t i;')
1874 param = 'R' if switch_obj is None else 'S'
1875 if switch_obj is not None:
1876 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1877 _c_accessor_get_expr(field.type.expr, fields))
1878 elif field.prev_varsized_field == None:
1879 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1880 _c_accessor_get_expr(field.type.expr, fields))
1882 _c(' xcb_generic_iterator_t child = %s;',
1883 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1884 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1885 _c_accessor_get_expr(field.type.expr, fields))
1888 _c(' i.index = (char *) i.data - (char *) %s;', param)
1894 _hc('%s', field.c_iterator_type)
1895 if switch_obj is not None:
1896 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1897 spacing = ' '*(len(field.c_iterator_name)+2)
1898 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1899 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1901 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1902 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1904 _c(' %s i;', field.c_iterator_type)
1907 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1909 if switch_obj is not None:
1911 _c(' i.data = %s;', fields[field.c_field_name][0])
1912 _c(' i.rem = %s;', length_expr_str)
1913 elif field.prev_varsized_field == None:
1915 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1917 (prev_varsized_field, align_pad) = get_align_pad(field)
1919 if align_pad is None:
1920 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1921 type_pad_type(field.c_field_type))
1923 _c(' xcb_generic_iterator_t prev = %s;',
1924 _c_iterator_get_end(prev_varsized_field, 'R'))
1926 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1927 field.c_field_type, align_pad)
1929 if switch_obj is None:
1930 _c(' i.rem = %s;', length_expr_str)
1931 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1935 def _c_accessors(self, name, base):
1937 Declares the accessor functions for the fields of a structure.
1939 # no accessors for switch itself -
1940 # switch always needs to be unpacked explicitly
1941 # if self.is_switch:
1945 for field in self.fields:
1946 if not field.type.is_pad:
1947 if _c_field_needs_list_accessor(field):
1948 _c_accessors_list(self, field)
1949 elif _c_field_needs_field_accessor(field):
1950 _c_accessors_field(self, field)
1952 def c_simple(self, name):
1954 Exported function that handles cardinal type declarations.
1955 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1957 _c_type_setup(self, name, ())
1959 if (self.name != name):
1964 _h('typedef %s %s;', _t(self.name), my_name)
1967 _c_iterator(self, name)
1969 def _c_complex(self, force_packed = False):
1971 Helper function for handling all structure types.
1972 Called for all structs, requests, replies, events, errors.
1977 _h(' * @brief %s', self.c_type)
1979 _h('typedef %s %s {', self.c_container, self.c_type)
1985 for field in self.fields:
1986 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1987 varfield = field.c_field_name
1990 struct_fields.append(field)
1992 for field in struct_fields:
1993 length = len(field.c_field_type)
1994 # account for '*' pointer_spec
1995 if not field.type.fixed_size() and not self.is_union:
1997 maxtypelen = max(maxtypelen, length)
1999 def _c_complex_field(self, field, space=''):
2000 if (field.type.fixed_size() or self.is_union or
2001 # in case of switch with switch children, don't make the field a pointer
2002 # necessary for unserialize to work
2003 (self.is_switch and field.type.is_switch)):
2004 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2005 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2007 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2008 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2010 if not self.is_switch:
2011 for field in struct_fields:
2012 _c_complex_field(self, field)
2014 for b in self.bitcases:
2019 for field in b.type.fields:
2020 _c_complex_field(self, field, space)
2022 _h(' } %s;', b.c_field_name)
2024 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2026 def c_struct(self, name):
2028 Exported function that handles structure declarations.
2030 _c_type_setup(self, name, ())
2032 _c_accessors(self, name, name)
2033 _c_iterator(self, name)
2035 def c_union(self, name):
2037 Exported function that handles union declarations.
2039 _c_type_setup(self, name, ())
2041 _c_iterator(self, name)
2043 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2045 Declares a request function.
2048 # Four stunningly confusing possibilities here:
2051 # ------------------------------
2053 # 0 flag CHECKED flag Normal Mode
2054 # void_cookie req_cookie
2055 # ------------------------------
2056 # "req_checked" "req_unchecked"
2057 # CHECKED flag 0 flag Abnormal Mode
2058 # void_cookie req_cookie
2059 # ------------------------------
2062 # Whether we are _checked or _unchecked
2063 checked = void and not regular
2064 unchecked = not void and not regular
2066 # What kind of cookie we return
2067 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2069 # What flag is passed to xcb_request
2070 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2073 if func_flags == '0':
2074 func_flags = 'XCB_REQUEST_REPLY_FDS'
2076 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2078 # Global extension id variable or NULL for xproto
2079 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2081 # What our function name is
2082 func_name = self.c_request_name if not aux else self.c_aux_name
2084 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2086 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2090 maxtypelen = len('xcb_connection_t')
2092 # special case: list with variable size elements
2093 list_with_var_size_elems = False
2095 for field in self.fields:
2097 # The field should appear as a call parameter
2098 param_fields.append(field)
2099 if field.wire and not field.auto:
2100 # We need to set the field up in the structure
2101 wire_fields.append(field)
2102 if field.type.c_need_serialize or field.type.c_need_sizeof:
2103 serial_fields.append(field)
2105 for field in param_fields:
2106 c_field_const_type = field.c_field_const_type
2107 if field.type.c_need_serialize and not aux:
2108 c_field_const_type = "const void"
2109 if len(c_field_const_type) > maxtypelen:
2110 maxtypelen = len(c_field_const_type)
2111 if field.type.is_list and not field.type.member.fixed_size():
2112 list_with_var_size_elems = True
2118 if hasattr(self, "doc") and self.doc:
2120 _h(' * @brief ' + self.doc.brief)
2122 _h(' * No brief doc yet')
2125 _h(' * @param c The connection')
2126 param_names = [f.c_field_name for f in param_fields]
2127 if hasattr(self, "doc") and self.doc:
2128 for field in param_fields:
2129 # XXX: hard-coded until we fix xproto.xml
2130 base_func_name = self.c_request_name if not aux else self.c_aux_name
2131 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2133 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2135 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2138 # XXX: why the 'xcb' prefix?
2139 key = ('xcb', field.enum)
2142 if namecount[tname] > 1:
2143 tname = _t(key + ('enum',))
2144 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2146 if self.doc and field.field_name in self.doc.fields:
2147 desc = self.doc.fields[field.field_name]
2148 for name in param_names:
2149 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2150 desc = desc.split("\n")
2151 desc = [line if line != '' else '\\n' for line in desc]
2152 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2153 # If there is no documentation yet, we simply don't generate an
2154 # @param tag. Doxygen will then warn about missing documentation.
2156 _h(' * @return A cookie')
2159 if hasattr(self, "doc") and self.doc:
2160 if self.doc.description:
2161 desc = self.doc.description
2162 for name in param_names:
2163 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2164 desc = desc.split("\n")
2165 _h(' * ' + "\n * ".join(desc))
2167 _h(' * No description yet')
2169 _h(' * Delivers a request to the X server.')
2172 _h(' * This form can be used only if the request will not cause')
2173 _h(' * a reply to be generated. Any returned error will be')
2174 _h(' * saved for handling by xcb_request_check().')
2176 _h(' * This form can be used only if the request will cause')
2177 _h(' * a reply to be generated. Any returned error will be')
2178 _h(' * placed in the event queue.')
2181 _hc('%s', cookie_type)
2183 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2184 comma = ',' if len(param_fields) else ');'
2185 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2186 comma = ',' if len(param_fields) else ')'
2187 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2189 func_spacing = ' ' * (len(func_name) + 2)
2190 count = len(param_fields)
2191 for field in param_fields:
2193 c_field_const_type = field.c_field_const_type
2194 c_pointer = field.c_pointer
2195 if field.type.c_need_serialize and not aux:
2196 c_field_const_type = "const void"
2198 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2199 comma = ',' if count else ');'
2200 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2201 spacing, c_pointer, field.c_field_name, comma)
2202 comma = ',' if count else ')'
2203 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2204 spacing, c_pointer, field.c_field_name, comma)
2207 if not self.c_var_followed_by_fixed_fields:
2208 for field in param_fields:
2209 if not field.type.fixed_size():
2211 if field.type.c_need_serialize:
2212 # _serialize() keeps track of padding automatically
2214 dimension = count + 2
2217 _c(' static const xcb_protocol_request_t xcb_req = {')
2218 _c(' /* count */ %d,', count)
2219 _c(' /* ext */ %s,', func_ext_global)
2220 _c(' /* opcode */ %s,', self.c_request_name.upper())
2221 _c(' /* isvoid */ %d', 1 if void else 0)
2225 _c(' struct iovec xcb_parts[%d];', dimension)
2226 _c(' %s xcb_ret;', func_cookie)
2227 _c(' %s xcb_out;', self.c_type)
2228 if self.c_var_followed_by_fixed_fields:
2229 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2230 _c(' void *xcb_aux = 0;')
2233 for idx, f in enumerate(serial_fields):
2235 _c(' void *xcb_aux%d = 0;' % (idx))
2236 if list_with_var_size_elems:
2237 _c(' unsigned int i;')
2238 _c(' unsigned int xcb_tmp_len;')
2239 _c(' char *xcb_tmp;')
2241 # simple request call tracing
2242 # _c(' printf("in function %s\\n");' % func_name)
2245 for field in wire_fields:
2246 if field.type.fixed_size():
2247 if field.type.is_expr:
2248 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2249 elif field.type.is_pad:
2250 if field.type.nmemb == 1:
2251 _c(' xcb_out.%s = 0;', field.c_field_name)
2253 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2255 if field.type.nmemb == 1:
2256 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2258 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2260 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2261 serialize_args = get_serialize_params(context, type_obj,
2264 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2266 # calls in order to free dyn. all. memory
2270 if not self.c_var_followed_by_fixed_fields:
2271 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2272 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2273 _c(' xcb_parts[3].iov_base = 0;')
2274 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2278 for field in param_fields:
2279 if not field.type.fixed_size():
2280 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2281 # default: simple cast to char *
2282 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2283 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2284 if field.type.is_list:
2285 if field.type.member.fixed_size():
2286 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2287 _c_accessor_get_expr(field.type.expr, None),
2288 field.type.member.c_wiretype)
2290 list_length = _c_accessor_get_expr(field.type.expr, None)
2293 _c(" xcb_parts[%d].iov_len = 0;" % count)
2294 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2295 _c(" for(i=0; i<%s; i++) {" % list_length)
2296 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2297 (field.type.c_sizeof_name))
2298 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2299 _c(" xcb_tmp += xcb_tmp_len;")
2302 # not supposed to happen
2303 raise Exception("unhandled variable size field %s" % field.c_field_name)
2306 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2307 idx = serial_fields.index(field)
2308 aux_var = '&xcb_aux%d' % idx
2309 context = 'serialize' if aux else 'sizeof'
2310 _c(' xcb_parts[%d].iov_len =', count)
2312 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2313 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2314 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2315 free_calls.append(' free(xcb_aux%d);' % idx)
2317 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2318 func_name = field.type.c_sizeof_name
2319 _c(' %s (%s);', func_name, serialize_args)
2322 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2323 # the _serialize() function keeps track of padding automatically
2324 _c(' xcb_parts[%d].iov_base = 0;', count)
2325 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2328 # elif self.c_var_followed_by_fixed_fields:
2330 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2331 # request header: opcodes + length
2332 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2335 buffer_var = '&xcb_aux'
2336 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2337 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2338 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2339 free_calls.append(' free(xcb_aux);')
2340 # no padding necessary - _serialize() keeps track of padding automatically
2343 for field in param_fields:
2345 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2347 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2349 # free dyn. all. data, if any
2350 for f in free_calls:
2352 _c(' return xcb_ret;')
2355 def _c_reply(self, name):
2357 Declares the function that returns the reply structure.
2359 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2360 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2361 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2363 # check if _unserialize() has to be called for any field
2364 def look_for_special_cases(complex_obj):
2365 unserialize_fields = []
2366 # no unserialize call in case of switch
2367 if not complex_obj.is_switch:
2368 for field in complex_obj.fields:
2369 # three cases: 1. field with special case
2370 # 2. container that contains special case field
2371 # 3. list with special case elements
2372 if field.type.c_var_followed_by_fixed_fields:
2373 unserialize_fields.append(field)
2374 elif field.type.is_container:
2375 unserialize_fields += look_for_special_cases(field.type)
2376 elif field.type.is_list:
2377 if field.type.member.c_var_followed_by_fixed_fields:
2378 unserialize_fields.append(field)
2379 if field.type.member.is_container:
2380 unserialize_fields += look_for_special_cases(field.type.member)
2381 return unserialize_fields
2383 unserialize_fields = look_for_special_cases(self.reply)
2387 _h(' * Return the reply')
2388 _h(' * @param c The connection')
2389 _h(' * @param cookie The cookie')
2390 _h(' * @param e The xcb_generic_error_t supplied')
2392 _h(' * Returns the reply of the request asked by')
2394 _h(' * The parameter @p e supplied to this function must be NULL if')
2395 _h(' * %s(). is used.', self.c_unchecked_name)
2396 _h(' * Otherwise, it stores the error if any.')
2398 _h(' * The returned value must be freed by the caller using free().')
2401 _hc('%s *', self.c_reply_type)
2402 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2403 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2404 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2405 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2408 if len(unserialize_fields)>0:
2409 # certain variable size fields need to be unserialized explicitly
2410 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2411 self.c_reply_type, self.c_reply_type)
2413 for field in unserialize_fields:
2414 if field.type.is_list:
2415 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2416 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2417 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2419 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2420 # call _unserialize(), using the reply as source and target buffer
2421 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2422 for field in unserialize_fields:
2423 if field.type.is_list:
2424 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2425 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2426 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2427 field.c_field_name, field.c_field_name)
2428 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2430 # return the transformed reply
2431 _c(' return reply;')
2434 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2438 def _c_reply_has_fds(self):
2439 for field in self.fields:
2444 def _c_reply_fds(self, name):
2446 Declares the function that returns fds related to the reply.
2448 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2449 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2452 _h(' * Return the reply fds')
2453 _h(' * @param c The connection')
2454 _h(' * @param reply The reply')
2456 _h(' * Returns the array of reply fds of the request asked by')
2458 _h(' * The returned value must be freed by the caller using free().')
2462 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2463 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2464 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2467 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2472 def _c_opcode(name, opcode):
2474 Declares the opcode define for requests, events, and errors.
2478 _h('/** Opcode for %s. */', _n(name))
2479 _h('#define %s %s', _n(name).upper(), opcode)
2481 def _c_cookie(self, name):
2483 Declares the cookie type for a non-void request.
2488 _h(' * @brief %s', self.c_cookie_type)
2490 _h('typedef struct %s {', self.c_cookie_type)
2491 _h(' unsigned int sequence; /**< */')
2492 _h('} %s;', self.c_cookie_type)
2494 def _man_request(self, name, cookie_type, void, aux):
2495 param_fields = [f for f in self.fields if f.visible]
2497 func_name = self.c_request_name if not aux else self.c_aux_name
2499 def create_link(linkname):
2500 name = 'man/%s.%s' % (linkname, section)
2502 sys.stdout.write(name)
2504 f.write('.so man%s/%s.%s' % (section, func_name, section))
2508 sys.stdout.write('man/%s.%s ' % (func_name, section))
2509 # Our CWD is src/, so this will end up in src/man/
2510 f = open('man/%s.%s' % (func_name, section), 'w')
2511 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2512 # Left-adjust instead of adjusting to both sides
2514 f.write('.SH NAME\n')
2515 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2516 f.write('%s \\- %s\n' % (func_name, brief))
2517 f.write('.SH SYNOPSIS\n')
2518 # Don't split words (hyphenate)
2520 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2522 # function prototypes
2524 count = len(param_fields)
2525 for field in param_fields:
2527 c_field_const_type = field.c_field_const_type
2528 c_pointer = field.c_pointer
2529 if c_pointer == ' ':
2531 if field.type.c_need_serialize and not aux:
2532 c_field_const_type = "const void"
2534 comma = ', ' if count else ');'
2535 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2537 f.write('.SS Request function\n')
2539 base_func_name = self.c_request_name if not aux else self.c_aux_name
2540 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2541 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2544 f.write('.SS Reply datastructure\n')
2547 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2551 for field in self.reply.fields:
2552 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2555 struct_fields.append(field)
2557 for field in struct_fields:
2558 length = len(field.c_field_type)
2559 # account for '*' pointer_spec
2560 if not field.type.fixed_size():
2562 maxtypelen = max(maxtypelen, length)
2564 def _c_complex_field(self, field, space=''):
2565 if (field.type.fixed_size() or
2566 # in case of switch with switch children, don't make the field a pointer
2567 # necessary for unserialize to work
2568 (self.is_switch and field.type.is_switch)):
2569 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2570 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2572 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2573 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2574 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2576 if not self.is_switch:
2577 for field in struct_fields:
2578 _c_complex_field(self, field)
2580 for b in self.bitcases:
2584 for field in b.type.fields:
2585 _c_complex_field(self, field, space)
2587 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2590 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2593 f.write('.SS Reply function\n')
2595 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2596 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2597 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2598 create_link('%s' % self.c_reply_name)
2600 has_accessors = False
2601 for field in self.reply.fields:
2602 if field.type.is_list and not field.type.fixed_size():
2603 has_accessors = True
2604 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2605 has_accessors = True
2608 f.write('.SS Reply accessors\n')
2610 def _c_accessors_field(self, field):
2612 Declares the accessor functions for a non-list field that follows a variable-length field.
2614 c_type = self.c_type
2616 # special case: switch
2617 switch_obj = self if self.is_switch else None
2618 if self.is_case_or_bitcase:
2619 switch_obj = self.parents[-1]
2620 if switch_obj is not None:
2621 c_type = switch_obj.c_type
2623 if field.type.is_simple:
2624 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2625 create_link('%s' % field.c_accessor_name)
2627 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2628 create_link('%s' % field.c_accessor_name)
2630 def _c_accessors_list(self, field):
2632 Declares the accessor functions for a list field.
2633 Declares a direct-accessor function only if the list members are fixed size.
2634 Declares length and get-iterator functions always.
2637 c_type = self.reply.c_type
2639 # special case: switch
2640 # in case of switch, 2 params have to be supplied to certain accessor functions:
2641 # 1. the anchestor object (request or reply)
2642 # 2. the (anchestor) switch object
2643 # the reason is that switch is either a child of a request/reply or nested in another switch,
2644 # so whenever we need to access a length field, we might need to refer to some anchestor type
2645 switch_obj = self if self.is_switch else None
2646 if self.is_case_or_bitcase:
2647 switch_obj = self.parents[-1]
2648 if switch_obj is not None:
2649 c_type = switch_obj.c_type
2653 parents = self.parents if hasattr(self, 'parents') else [self]
2654 # 'R': parents[0] is always the 'toplevel' container type
2655 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2656 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2657 # auxiliary object for 'R' parameters
2660 if switch_obj is not None:
2661 # now look where the fields are defined that are needed to evaluate
2662 # the switch expr, and store the parent objects in accessor_params and
2663 # the fields in switch_fields
2665 # 'S': name for the 'toplevel' switch
2666 toplevel_switch = parents[1]
2667 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2668 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2670 # initialize prefix for everything "below" S
2671 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2672 prefix = [(prefix_str, '->', toplevel_switch)]
2674 # look for fields in the remaining containers
2675 for p in parents[2:] + [self]:
2676 # the separator between parent and child is always '.' here,
2677 # because of nested switch statements
2678 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2679 prefix.append((p.name[-1], '.', p))
2680 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2682 # auxiliary object for 'S' parameter
2685 if list.member.fixed_size():
2686 idx = 1 if switch_obj is not None else 0
2688 f.write('%s *\\fB%s\\fP(%s);\n' %
2689 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2690 create_link('%s' % field.c_accessor_name)
2693 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2694 (field.c_length_name, c_type))
2695 create_link('%s' % field.c_length_name)
2697 if field.type.member.is_simple:
2699 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2700 (field.c_end_name, c_type))
2701 create_link('%s' % field.c_end_name)
2704 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2705 (field.c_iterator_type, field.c_iterator_name,
2707 create_link('%s' % field.c_iterator_name)
2709 for field in self.reply.fields:
2710 if field.type.is_list and not field.type.fixed_size():
2711 _c_accessors_list(self, field)
2712 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2713 _c_accessors_field(self, field)
2717 # Re-enable hyphenation and adjusting to both sides
2720 # argument reference
2721 f.write('.SH REQUEST ARGUMENTS\n')
2722 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2723 f.write('The XCB connection to X11.\n')
2724 for field in param_fields:
2725 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2726 printed_enum = False
2727 # XXX: hard-coded until we fix xproto.xml
2728 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2730 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2732 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2734 if hasattr(field, "enum") and field.enum:
2735 # XXX: why the 'xcb' prefix?
2736 key = ('xcb', field.enum)
2738 f.write('One of the following values:\n')
2741 count = len(enum.values)
2742 for (enam, eval) in enum.values:
2744 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2745 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2746 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2747 f.write('%s\n' % desc)
2749 f.write('TODO: NOT YET DOCUMENTED.\n')
2754 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2755 desc = self.doc.fields[field.field_name]
2756 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2759 f.write('%s\n' % desc)
2761 f.write('TODO: NOT YET DOCUMENTED.\n')
2767 f.write('.SH REPLY FIELDS\n')
2768 # These fields are present in every reply:
2769 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2770 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2771 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2772 'be used to tell replies apart from each other.\n') %
2773 _n(self.reply.name).upper())
2774 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2775 f.write('The sequence number of the last request processed by the X11 server.\n')
2776 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2777 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2778 for field in self.reply.fields:
2779 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2780 field.c_field_name.startswith('pad')):
2783 if field.type.is_list and not field.type.fixed_size():
2785 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2787 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2788 printed_enum = False
2789 if hasattr(field, "enum") and field.enum:
2790 # XXX: why the 'xcb' prefix?
2791 key = ('xcb', field.enum)
2793 f.write('One of the following values:\n')
2796 count = len(enum.values)
2797 for (enam, eval) in enum.values:
2799 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2800 if enum.doc and enam in enum.doc.fields:
2801 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2802 f.write('%s\n' % desc)
2804 f.write('TODO: NOT YET DOCUMENTED.\n')
2809 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2810 desc = self.reply.doc.fields[field.field_name]
2811 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2814 f.write('%s\n' % desc)
2816 f.write('TODO: NOT YET DOCUMENTED.\n')
2823 f.write('.SH DESCRIPTION\n')
2824 if hasattr(self, "doc") and self.doc and self.doc.description:
2825 desc = self.doc.description
2826 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2827 lines = desc.split('\n')
2828 f.write('\n'.join(lines) + '\n')
2830 f.write('.SH RETURN VALUE\n')
2832 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2833 'have to be handled in the event loop.\n\nIf you want to '
2834 'handle errors directly with \\fIxcb_request_check\\fP '
2835 'instead, use \\fI%s_checked\\fP. See '
2836 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2838 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2839 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2840 'handle errors in the event loop instead, use '
2841 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2843 (cookie_type, self.c_reply_name, base_func_name, section))
2844 f.write('.SH ERRORS\n')
2845 if hasattr(self, "doc") and self.doc:
2846 for errtype, errtext in sorted(self.doc.errors.items()):
2847 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2848 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2849 f.write('%s\n' % (errtext))
2850 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2851 f.write('This request does never generate any errors.\n')
2852 if hasattr(self, "doc") and self.doc and self.doc.example:
2853 f.write('.SH EXAMPLE\n')
2856 lines = self.doc.example.split('\n')
2857 f.write('\n'.join(lines) + '\n')
2859 f.write('.SH SEE ALSO\n')
2860 if hasattr(self, "doc") and self.doc:
2861 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2862 if self.doc.example:
2863 see.append('.BR %s (%s)' % ('xcb-examples', section))
2864 for seename, seetype in sorted(self.doc.see.items()):
2865 if seetype == 'program':
2866 see.append('.BR %s (1)' % seename)
2867 elif seetype == 'event':
2868 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2869 elif seetype == 'request':
2870 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2871 elif seetype == 'function':
2872 see.append('.BR %s (%s)' % (seename, section))
2874 see.append('TODO: %s (type %s)' % (seename, seetype))
2875 f.write(',\n'.join(see) + '\n')
2876 f.write('.SH AUTHOR\n')
2877 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2880 def _man_event(self, name):
2882 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2883 # Our CWD is src/, so this will end up in src/man/
2884 f = open('man/%s.%s' % (self.c_type, section), 'w')
2885 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2886 # Left-adjust instead of adjusting to both sides
2888 f.write('.SH NAME\n')
2889 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2890 f.write('%s \\- %s\n' % (self.c_type, brief))
2891 f.write('.SH SYNOPSIS\n')
2892 # Don't split words (hyphenate)
2894 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2897 f.write('.SS Event datastructure\n')
2900 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2904 for field in self.fields:
2905 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2908 struct_fields.append(field)
2910 for field in struct_fields:
2911 length = len(field.c_field_type)
2912 # account for '*' pointer_spec
2913 if not field.type.fixed_size():
2915 maxtypelen = max(maxtypelen, length)
2917 def _c_complex_field(self, field, space=''):
2918 if (field.type.fixed_size() or
2919 # in case of switch with switch children, don't make the field a pointer
2920 # necessary for unserialize to work
2921 (self.is_switch and field.type.is_switch)):
2922 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2923 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2925 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2927 if not self.is_switch:
2928 for field in struct_fields:
2929 _c_complex_field(self, field)
2931 for b in self.bitcases:
2935 for field in b.type.fields:
2936 _c_complex_field(self, field, space)
2938 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2941 f.write('} \\fB%s\\fP;\n' % self.c_type)
2946 # Re-enable hyphenation and adjusting to both sides
2949 # argument reference
2950 f.write('.SH EVENT FIELDS\n')
2951 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2952 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2953 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2954 'to tell events apart from each other.\n') % _n(name).upper())
2955 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2956 f.write('The sequence number of the last request processed by the X11 server.\n')
2958 if not self.is_switch:
2959 for field in struct_fields:
2960 # Skip the fields which every event has, we already documented
2962 if field.c_field_name in ('response_type', 'sequence'):
2964 if isinstance(field.type, PadType):
2966 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2967 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2968 desc = self.doc.fields[field.field_name]
2969 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2970 f.write('%s\n' % desc)
2972 f.write('NOT YET DOCUMENTED.\n')
2975 f.write('.SH DESCRIPTION\n')
2976 if hasattr(self, "doc") and self.doc and self.doc.description:
2977 desc = self.doc.description
2978 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2979 lines = desc.split('\n')
2980 f.write('\n'.join(lines) + '\n')
2982 if hasattr(self, "doc") and self.doc and self.doc.example:
2983 f.write('.SH EXAMPLE\n')
2986 lines = self.doc.example.split('\n')
2987 f.write('\n'.join(lines) + '\n')
2989 f.write('.SH SEE ALSO\n')
2990 if hasattr(self, "doc") and self.doc:
2991 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2992 if self.doc.example:
2993 see.append('.BR %s (%s)' % ('xcb-examples', section))
2994 for seename, seetype in sorted(self.doc.see.items()):
2995 if seetype == 'program':
2996 see.append('.BR %s (1)' % seename)
2997 elif seetype == 'event':
2998 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2999 elif seetype == 'request':
3000 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
3001 elif seetype == 'function':
3002 see.append('.BR %s (%s)' % (seename, section))
3004 see.append('TODO: %s (type %s)' % (seename, seetype))
3005 f.write(',\n'.join(see) + '\n')
3006 f.write('.SH AUTHOR\n')
3007 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3011 def c_request(self, name):
3013 Exported function that handles request declarations.
3015 _c_type_setup(self, name, ('request',))
3018 # Cookie type declaration
3019 _c_cookie(self, name)
3022 _c_opcode(name, self.opcode)
3024 # Request structure declaration
3028 _c_type_setup(self.reply, name, ('reply',))
3029 # Reply structure definition
3030 _c_complex(self.reply)
3031 # Request prototypes
3032 has_fds = _c_reply_has_fds(self.reply)
3033 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3034 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3036 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3037 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3039 _c_accessors(self.reply, name + ('reply',), name)
3040 _c_reply(self, name)
3042 _c_reply_fds(self, name)
3044 # Request prototypes
3045 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3046 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3048 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3049 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3051 # We generate the manpage afterwards because _c_type_setup has been called.
3052 # TODO: what about aux helpers?
3053 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3054 _man_request(self, name, cookie_type, not self.reply, False)
3056 def c_event(self, name):
3058 Exported function that handles event declarations.
3061 # The generic event structure xcb_ge_event_t has the full_sequence field
3062 # at the 32byte boundary. That's why we've to inject this field into GE
3063 # events while generating the structure for them. Otherwise we would read
3064 # garbage (the internal full_sequence) when accessing normal event fields
3066 force_packed = False
3067 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3069 for field in self.fields:
3070 if field.type.size != None and field.type.nmemb != None:
3071 event_size += field.type.size * field.type.nmemb
3072 if event_size == 32:
3073 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3074 idx = self.fields.index(field)
3075 self.fields.insert(idx + 1, full_sequence)
3077 # If the event contains any 64-bit extended fields, they need
3078 # to remain aligned on a 64-bit boundary. Adding full_sequence
3079 # would normally break that; force the struct to be packed.
3080 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3083 _c_type_setup(self, name, ('event',))
3086 _c_opcode(name, self.opcodes[name])
3088 if self.name == name:
3089 # Structure definition
3090 _c_complex(self, force_packed)
3094 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3096 _man_event(self, name)
3098 def c_error(self, name):
3100 Exported function that handles error declarations.
3102 _c_type_setup(self, name, ('error',))
3105 _c_opcode(name, self.opcodes[name])
3107 if self.name == name:
3108 # Structure definition
3113 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3116 # Main routine starts here
3118 # Must create an "output" dictionary before any xcbgen imports.
3119 output = {'open' : c_open,
3121 'simple' : c_simple,
3123 'struct' : c_struct,
3125 'request' : c_request,
3130 # Boilerplate below this point
3132 # Check for the argument that specifies path to the xcbgen python package.
3134 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3135 except getopt.GetoptError as err:
3137 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3140 for (opt, arg) in opts:
3148 sys.path.insert(1, arg)
3151 sys.stdout.write('man_MANS = ')
3153 # Import the module class
3155 from xcbgen.state import Module
3156 from xcbgen.xtypes import *
3159 Failed to load the xcbgen Python package!
3160 Make sure that xcb/proto installed it on your Python path.
3161 If not, you will need to create a .pth file or define $PYTHONPATH
3163 Refer to the README file in xcb/proto for more info.
3167 # Ensure the man subdirectory exists
3170 except OSError as e:
3171 if e.errno != errno.EEXIST:
3174 # Parse the xml header
3175 module = Module(args[0], output)
3177 # Build type-registry and resolve type dependencies