2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
12 # Jump to the bottom of this file for the main routine
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
20 _cplusplus_annoyances = {'class' : '_class',
23 _c_keywords = {'default' : '_default'}
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
37 # keeps enum objects so that we can refer to them when generating manpages.
44 Writes the given line to the header file.
46 _hlines[_hlevel].append(fmt % args)
50 Writes the given line to the source file.
52 _clines[_clevel].append(fmt % args)
56 Writes the given line to both the header and source files.
61 def _c_wr_stringlist(indent, strlist):
63 Writes the given list of strings to the source file.
64 Each line is prepended by the indent string
67 _c("%s%s", indent, str)
70 class PreCode(object):
72 For pre-code generated by expression generation
73 (for example, the for-loop of a sumof)
74 This has to account for recursiveness of the expression
75 generation, i.e., there may be pre-code for pre-code.
76 Therefore this is implemented as a stack of lists of lines.
78 If redirection is switched on, then all output is collected in
79 self.redirect_code and self.redirect_tempvars instead of
80 being sent to the output via _h und _c.
83 self.nesting_level = 0
86 self.redirect_code = None
87 self.redirect_tempvars = None
89 self.indent_stack = []
93 # start and end of pre-code blocks
95 self.nesting_level += 1
98 self.nesting_level -= 1
99 if self.nesting_level == 0:
100 # lowest pre-code level is finished -> output to source
101 if self.redirect_tempvars is None:
102 _c_wr_stringlist('', self.tempvars)
105 self.redirect_tempvars.extend(self.tempvars)
107 if self.redirect_code == None:
108 _c_wr_stringlist('', self.codelines)
111 self.redirect_code.extend(self.codelines)
115 def output_tempvars(self):
116 if self.redirect_code == None:
117 _c_wr_stringlist('', self.tempvars)
121 def code(self, fmt, *args):
122 self.codelines.append(self.indent_str + fmt % args)
124 def tempvar(self, fmt, *args):
125 self.tempvars.append(' ' + (fmt % args))
127 # get a unique name for a temporary variable
128 def get_tempvarname(self):
129 self.tempvar_num += 1
130 return "xcb_pre_tmp_%d" % self.tempvar_num
134 def push_indent(self, indentstr):
135 self.indent_stack.append(self.indent_str)
136 self.indent_str = indentstr
138 def push_addindent(self, indent_add_str):
139 self.push_indent(self.indent_str + indent_add_str)
142 self.push_addindent(' ')
144 def pop_indent(self):
145 self.indent_str = self.indent_stack.pop()
147 # redirection to lists
148 def redirect_start(self, redirect_code, redirect_tempvars=None):
149 self.redirect_code = redirect_code
150 self.redirect_tempvars = redirect_tempvars
151 if redirect_tempvars is not None:
154 def redirect_end(self):
155 self.redirect_code = None
156 self.redirect_tempvars = None
158 # global PreCode handler
162 # XXX See if this level thing is really necessary.
163 def _h_setlevel(idx):
165 Changes the array that header lines are written to.
166 Supports writing different sections of the header file.
169 while len(_hlines) <= idx:
173 def _c_setlevel(idx):
175 Changes the array that source lines are written to.
176 Supports writing to different sections of the source file.
179 while len(_clines) <= idx:
185 Does C-name conversion on a single string fragment.
186 Uses a regexp with some hard-coded special cases.
188 if str in _cname_special_cases:
189 return _cname_special_cases[str]
191 split = _cname_re.finditer(str)
192 name_parts = [match.group(0) for match in split]
193 return '_'.join(name_parts)
197 Checks for certain C++ reserved words and fixes them.
199 if str in _cplusplus_annoyances:
200 return _cplusplus_annoyances[str]
201 elif str in _c_keywords:
202 return _c_keywords[str]
208 Does C-name conversion on an extension name.
209 Has some additional special cases on top of _n_item.
211 if str in _extension_special_cases:
212 return _n_item(str).lower()
218 Does C-name conversion on a tuple of strings.
219 Different behavior depending on length of tuple, extension/not extension, etc.
220 Basically C-name converts the individual pieces, then joins with underscores.
225 parts = [list[0], _n_item(list[1])]
227 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
229 parts = [list[0]] + [_n_item(i) for i in list[1:]]
230 return '_'.join(parts).lower()
234 Does C-name conversion on a tuple of strings representing a type.
235 Same as _n but adds a "_t" on the end.
240 parts = [list[0], _n_item(list[1]), 't']
242 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
244 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
245 return '_'.join(parts).lower()
250 Exported function that handles module open.
251 Opens the files and writes out the auto-generated comment, header file includes, etc.
255 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
257 # Build the type-name collision avoidance table used by c_enum
258 build_collision_table()
264 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
265 _hc(' * Edit at your peril.')
270 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
271 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
275 _h('#ifndef __%s_H', _ns.header.upper())
276 _h('#define __%s_H', _ns.header.upper())
278 _h('#include "xcb.h"')
280 _c('#ifdef HAVE_CONFIG_H')
281 _c('#include "config.h"')
283 _c('#include <stdlib.h>')
284 _c('#include <string.h>')
285 _c('#include <assert.h>')
286 _c('#include <stddef.h> /* for offsetof() */')
287 _c('#include "xcbext.h"')
288 _c('#include "%s.h"', _ns.header)
291 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
294 for (n, h) in self.direct_imports:
295 _hc('#include "%s.h"', h)
298 _h('#ifdef __cplusplus')
304 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
305 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
307 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
310 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
314 Exported function that handles module close.
315 Writes out all the stored content lines, then closes the files.
322 _h('#ifdef __cplusplus')
334 hfile = open('%s.h' % _ns.header, 'w')
342 cfile = open('%s.c' % _ns.header, 'w')
349 def build_collision_table():
353 for v in module.types.values():
355 namecount[name] = (namecount.get(name) or 0) + 1
357 def c_enum(self, name):
359 Exported function that handles enum declarations.
365 if namecount[tname] > 1:
366 tname = _t(name + ('enum',))
370 _h('typedef enum %s {', tname)
372 count = len(self.values)
374 for (enam, eval) in self.values:
376 equals = ' = ' if eval != '' else ''
377 comma = ',' if count > 0 else ''
379 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
380 doc = '\n/**< %s */\n' % self.doc.fields[enam]
381 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
385 def _c_type_setup(self, name, postfix):
387 Sets up all the C-related state by adding additional data fields to
388 all Field and Type objects. Here is where we figure out most of our
389 variable and function names.
391 Recurses into child fields and list member types.
393 # Do all the various names in advance
394 self.c_type = _t(name + postfix)
395 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
397 self.c_iterator_type = _t(name + ('iterator',))
398 self.c_next_name = _n(name + ('next',))
399 self.c_end_name = _n(name + ('end',))
401 self.c_request_name = _n(name)
402 self.c_checked_name = _n(name + ('checked',))
403 self.c_unchecked_name = _n(name + ('unchecked',))
404 self.c_reply_name = _n(name + ('reply',))
405 self.c_reply_type = _t(name + ('reply',))
406 self.c_cookie_type = _t(name + ('cookie',))
407 self.c_reply_fds_name = _n(name + ('reply_fds',))
409 self.c_need_aux = False
410 self.c_need_serialize = False
411 self.c_need_sizeof = False
413 self.c_aux_name = _n(name + ('aux',))
414 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
415 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
416 self.c_serialize_name = _n(name + ('serialize',))
417 self.c_unserialize_name = _n(name + ('unserialize',))
418 self.c_unpack_name = _n(name + ('unpack',))
419 self.c_sizeof_name = _n(name + ('sizeof',))
421 # special case: structs where variable size fields are followed by fixed size fields
422 self.c_var_followed_by_fixed_fields = False
425 self.c_need_serialize = True
426 self.c_container = 'struct'
427 for bitcase in self.bitcases:
428 bitcase.c_field_name = _cpp(bitcase.field_name)
429 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
430 _c_type_setup(bitcase.type, bitcase_name, ())
432 elif self.is_container:
434 self.c_container = 'union' if self.is_union else 'struct'
435 prev_varsized_field = None
436 prev_varsized_offset = 0
437 first_field_after_varsized = None
439 for field in self.fields:
440 field.c_field_type = _t(field.field_type)
441 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
442 field.c_field_name = _cpp(field.field_name)
443 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
444 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
446 # correct the c_pointer field for variable size non-list types
447 if not field.type.fixed_size() and field.c_pointer == ' ':
448 field.c_pointer = '*'
449 if field.type.is_list and not field.type.member.fixed_size():
450 field.c_pointer = '*'
452 if field.type.is_switch:
453 field.c_pointer = '*'
454 field.c_field_const_type = 'const ' + field.c_field_type
455 self.c_need_aux = True
457 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
458 self.c_need_sizeof = True
460 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
461 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
462 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
463 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
464 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
466 field.prev_varsized_field = prev_varsized_field
467 field.prev_varsized_offset = prev_varsized_offset
469 if prev_varsized_offset == 0:
470 first_field_after_varsized = field
471 field.first_field_after_varsized = first_field_after_varsized
473 if field.type.fixed_size():
474 prev_varsized_offset += field.type.size
475 # special case: intermixed fixed and variable size fields
476 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
477 if not self.is_union:
478 self.c_need_serialize = True
479 self.c_var_followed_by_fixed_fields = True
481 self.last_varsized_field = field
482 prev_varsized_field = field
483 prev_varsized_offset = 0
485 if self.c_var_followed_by_fixed_fields:
486 if field.type.fixed_size():
487 field.prev_varsized_field = None
489 # recurse into this field this has to be done here, i.e.,
490 # after the field has been set up. Otherwise the function
491 # _c_helper_fieldaccess_expr will produce garbage or crash
492 _c_type_setup(field.type, field.field_type, ())
493 if field.type.is_list:
494 _c_type_setup(field.type.member, field.field_type, ())
495 if (field.type.nmemb is None):
496 self.c_need_sizeof = True
498 if self.c_need_serialize:
499 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
500 self.c_need_sizeof = True
502 # as switch does never appear at toplevel,
503 # continue here with type construction
505 if self.c_type not in finished_switch:
506 finished_switch.append(self.c_type)
507 # special: switch C structs get pointer fields for variable-sized members
509 for bitcase in self.bitcases:
510 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
511 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
512 # no list with switch as element, so no call to
513 # _c_iterator(field.type, field_name) necessary
515 if not self.is_case_or_bitcase:
516 if self.c_need_serialize:
517 if self.c_serialize_name not in finished_serializers:
518 finished_serializers.append(self.c_serialize_name)
519 _c_serialize('serialize', self)
521 # _unpack() and _unserialize() are only needed for special cases:
523 # special cases -> unserialize
524 if self.is_switch or self.c_var_followed_by_fixed_fields:
525 _c_serialize('unserialize', self)
527 if self.c_need_sizeof:
528 if self.c_sizeof_name not in finished_sizeof:
529 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
530 finished_sizeof.append(self.c_sizeof_name)
531 _c_serialize('sizeof', self)
534 # Functions for querying field properties
535 def _c_field_needs_list_accessor(field):
536 return field.type.is_list and not field.type.fixed_size()
538 def _c_field_needs_field_accessor(field):
539 if field.type.is_list:
542 return (field.prev_varsized_field is not None or
543 not field.type.fixed_size())
545 def _c_field_needs_accessor(field):
546 return (_c_field_needs_list_accessor(field) or
547 _c_field_needs_field_accessor(field))
549 def _c_field_is_member_of_case_or_bitcase(field):
550 return field.parent and field.parent.is_case_or_bitcase
552 def _c_helper_fieldaccess_expr(prefix, field=None):
554 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555 representing a valid field-access-expression in C (based on the context)
556 if field is not None, append access to the field as well.
558 "separator" is one of the C-operators "." or "->".
560 A field access expression can consist of the following components:
561 * struct/union member access from a value with the "."-operator
562 * struct/union member access from a pointer with "->"-operator
563 * function-call of an accessor function:
564 This is used when a xcb-field is not contained in a struct.
565 This can, e.g., happen for fields after var-sized fields, etc.
569 for name, sep, obj in prefix:
570 prefix_str += last_sep + name
574 # add separator for access to a yet unknown field
575 prefix_str += last_sep
577 if _c_field_needs_accessor(field):
578 if _c_field_is_member_of_case_or_bitcase(field):
579 # case members are available in the deserialized struct,
580 # so there is no need to use the accessor function
581 # (also, their accessor function needs a different arglist
582 # so this would require special treatment here)
583 # Therefore: Access as struct member
584 prefix_str += last_sep + _cpp(field.field_name)
586 # Access with the accessor function
587 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
589 # Access as struct member
590 prefix_str += last_sep + _cpp(field.field_name)
595 def _c_helper_field_mapping(complex_type, prefix, flat=False):
597 generate absolute names, based on prefix, for all fields starting from complex_type
598 if flat == True, nested complex types are not taken into account
601 if complex_type.is_switch:
602 for b in complex_type.bitcases:
604 switch_name, switch_sep, switch_type = prefix[-1]
605 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
607 bitcase_prefix = prefix
609 if (True==flat and not b.type.has_name) or False==flat:
610 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
612 for f in complex_type.fields:
613 fname = _c_helper_fieldaccess_expr(prefix, f)
614 if f.field_name in all_fields:
615 raise Exception("field name %s has been registered before" % f.field_name)
617 all_fields[f.field_name] = (fname, f)
618 if f.type.is_container and flat==False:
619 if f.type.is_case_or_bitcase and not f.type.has_name:
621 elif f.type.is_switch and len(f.type.parents)>1:
622 # nested switch gets another separator
623 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
625 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
626 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
631 def _c_helper_resolve_field_names (prefix):
633 get field names for all objects in the prefix array
637 # look for fields in the remaining containers
638 for idx, p in enumerate(prefix):
641 # sep can be preset in prefix, if not, make a sensible guess
642 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
643 # exception: 'toplevel' object (switch as well!) always have sep '->'
644 sep = '->' if idx<1 else sep
645 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
646 tmp_prefix.append((name, sep, obj))
647 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
650 # _c_helper_resolve_field_names
652 def get_expr_fields(self):
654 get the Fields referenced by switch or list expression
656 def get_expr_field_names(expr):
658 if expr.lenfield_name is not None:
659 return [expr.lenfield_name]
661 # constant value expr
665 return get_expr_field_names(expr.rhs)
666 elif expr.op == 'popcount':
667 return get_expr_field_names(expr.rhs)
668 elif expr.op == 'sumof':
669 # sumof expr references another list,
670 # we need that list's length field here
672 for f in expr.lenfield_parent.fields:
673 if f.field_name == expr.lenfield_name:
677 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
678 # referenced list + its length field
679 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
680 elif expr.op == 'enumref':
683 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
684 # get_expr_field_names()
686 # resolve the field names with the parent structure(s)
687 unresolved_fields_names = get_expr_field_names(self.expr)
689 # construct prefix from self
690 prefix = [('', '', p) for p in self.parents]
691 if self.is_container:
692 prefix.append(('', '', self))
694 all_fields = _c_helper_resolve_field_names (prefix)
695 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
696 if len(unresolved_fields_names) != len(resolved_fields_names):
697 raise Exception("could not resolve all fields for %s" % self.name)
699 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
700 return resolved_fields
703 def resolve_expr_fields(complex_obj):
705 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
706 these are normally fields that need to be given as function parameters
712 for field in complex_obj.fields:
713 all_fields.append(field)
714 if field.type.is_switch or field.type.is_list:
715 expr_fields += get_expr_fields(field.type)
716 if field.type.is_container:
717 expr_fields += resolve_expr_fields(field.type)
719 # try to resolve expr fields
720 for e in expr_fields:
721 if e not in all_fields and e not in unresolved:
724 # resolve_expr_fields()
726 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
728 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
729 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
730 expression. This function tries to resolve all fields within a structure, and returns the
731 unresolved fields as the list of external parameters.
733 def add_param(params, param):
734 if param not in params:
737 # collect all fields into param_fields
741 for field in self.fields:
743 # the field should appear as a parameter in the function call
744 param_fields.append(field)
745 if field.wire and not field.auto:
746 if field.type.fixed_size() and not self.is_switch:
747 # field in the xcb_out structure
748 wire_fields.append(field)
749 # fields like 'pad0' are skipped!
751 # in case of switch, parameters always contain any fields referenced in the switch expr
752 # we do not need any variable size fields here, as the switch data type contains both
753 # fixed and variable size fields
755 param_fields = get_expr_fields(self)
757 # _serialize()/_unserialize()/_unpack() function parameters
758 # note: don't use set() for params, it is unsorted
761 # 1. the parameter for the void * buffer
762 if 'serialize' == context:
763 params.append(('void', '**', buffer_var))
764 elif context in ('unserialize', 'unpack', 'sizeof'):
765 params.append(('const void', '*', buffer_var))
767 # 2. any expr fields that cannot be resolved within self and descendants
768 unresolved_fields = resolve_expr_fields(self)
769 for f in unresolved_fields:
770 add_param(params, (f.c_field_type, '', f.c_field_name))
772 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
773 # that do not appear in the data type struct
774 for p in param_fields:
776 typespec = p.c_field_const_type
777 pointerspec = p.c_pointer
778 add_param(params, (typespec, pointerspec, p.c_field_name))
780 if p.visible and not p.wire and not p.auto:
781 typespec = p.c_field_type
783 add_param(params, (typespec, pointerspec, p.c_field_name))
786 if 'serialize' == context:
787 add_param(params, ('const %s' % self.c_type, '*', aux_var))
788 elif 'unserialize' == context:
789 add_param(params, ('%s' % self.c_type, '**', aux_var))
790 elif 'unpack' == context:
791 add_param(params, ('%s' % self.c_type, '*', aux_var))
793 # 5. switch contains all variable size fields as struct members
794 # for other data types though, these have to be supplied separately
795 # this is important for the special case of intermixed fixed and
796 # variable size fields
797 if not self.is_switch and 'serialize' == context:
798 for p in param_fields:
799 if not p.type.fixed_size():
800 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
802 return (param_fields, wire_fields, params)
803 # get_serialize_params()
805 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
806 code_lines.append('%s /* insert padding */' % space)
807 if is_case_or_bitcase:
809 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
813 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
814 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
815 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
818 code_lines.append('%s if (0 != xcb_pad) {' % space)
820 if 'serialize' == context:
821 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
822 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
823 code_lines.append('%s xcb_parts_idx++;' % space)
824 elif context in ('unserialize', 'unpack', 'sizeof'):
825 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
827 code_lines.append('%s xcb_pad = 0;' % space)
828 code_lines.append('%s }' % space)
830 code_lines.append('%s xcb_block_len = 0;' % space)
831 if is_case_or_bitcase:
832 code_lines.append('%s xcb_padding_offset = 0;' % space)
834 # keep tracking of xcb_parts entries for serialize
836 # _c_serialize_helper_insert_padding()
838 def _c_serialize_helper_switch(context, self, complex_name,
839 code_lines, temp_vars,
842 switch_expr = _c_accessor_get_expr(self.expr, None)
844 for b in self.bitcases:
845 len_expr = len(b.type.expr)
847 compare_operator = '&'
849 compare_operator = '=='
851 compare_operator = '&'
853 for n, expr in enumerate(b.type.expr):
854 bitcase_expr = _c_accessor_get_expr(expr, None)
855 # only one <enumref> in the <bitcase>
858 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
859 # multiple <enumref> in the <bitcase>
862 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
863 elif len_expr == (n + 1): # last
865 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
866 else: # between first and last
868 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
872 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
874 count += _c_serialize_helper_fields(context, b.type,
875 code_lines, temp_vars,
878 is_case_or_bitcase = True)
879 code_lines.append(' }')
881 # if 'serialize' == context:
882 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
883 # elif context in ('unserialize', 'unpack', 'sizeof'):
885 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
886 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
889 # _c_serialize_helper_switch
891 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
893 handle switch by calling _serialize() or _unpack(), depending on context
895 # switch is handled by this function as a special case
896 param_fields, wire_fields, params = get_serialize_params(context, self)
897 field_mapping = _c_helper_field_mapping(self, prefix)
898 prefix_str = _c_helper_fieldaccess_expr(prefix)
900 # find the parameters that need to be passed to _serialize()/_unpack():
901 # all switch expr fields must be given as parameters
902 args = get_expr_fields(field.type)
903 # length fields for variable size types in switch, normally only some of need
904 # need to be passed as parameters
905 switch_len_fields = resolve_expr_fields(field.type)
907 # a switch field at this point _must_ be a bitcase field
908 # we require that bitcases are "self-contiguous"
909 bitcase_unresolved = resolve_expr_fields(self)
910 if len(bitcase_unresolved) != 0:
911 raise Exception('unresolved fields within bitcase is not supported at this point')
913 # get the C names for the parameters
915 for a in switch_len_fields:
916 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
918 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
920 # call _serialize()/_unpack() to determine the actual size
921 if 'serialize' == context:
922 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
923 c_field_names, prefix_str, field.c_field_name)
924 elif context in ('unserialize', 'unpack'):
925 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
926 c_field_names, prefix_str, field.c_field_name)
927 elif 'sizeof' == context:
928 # remove trailing ", " from c_field_names because it will be used at end of arglist
929 my_c_field_names = c_field_names[:-2]
930 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
933 # _c_serialize_helper_switch_field()
935 def _c_serialize_helper_list_field(context, self, field,
936 code_lines, temp_vars,
939 helper function to cope with lists of variable length
941 expr = field.type.expr
942 prefix_str = _c_helper_fieldaccess_expr(prefix)
943 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
944 param_names = [p[2] for p in params]
946 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
947 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
948 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
952 field_mapping[r] = (r, None)
954 if len(unresolved)>0:
956 if len(tmp_prefix)==0:
957 raise Exception("found an empty prefix while resolving expr field names for list %s",
960 field_mapping.update(_c_helper_resolve_field_names(prefix))
961 resolved += list(filter(lambda x: x in field_mapping, unresolved))
962 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
963 if len(unresolved)>0:
964 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
966 list_length = _c_accessor_get_expr(expr, field_mapping)
968 # default: list with fixed size elements
969 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
971 # list with variable-sized elements
972 if not field.type.member.fixed_size():
974 if context in ('unserialize', 'sizeof', 'unpack'):
975 int_i = ' unsigned int i;'
976 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
977 if int_i not in temp_vars:
978 temp_vars.append(int_i)
979 if xcb_tmp_len not in temp_vars:
980 temp_vars.append(xcb_tmp_len)
981 # loop over all list elements and call sizeof repeatedly
982 # this should be a bit faster than using the iterators
983 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
984 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
985 (space, field.type.c_sizeof_name))
986 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
987 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
988 code_lines.append("%s }" % space)
990 elif 'serialize' == context:
991 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
992 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
993 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
994 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
995 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
996 code_lines.append('%s }' % space)
997 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1000 # _c_serialize_helper_list_field()
1002 def _c_serialize_helper_fields_fixed_size(context, self, field,
1003 code_lines, temp_vars,
1005 # keep the C code a bit more readable by giving the field name
1006 if not self.is_case_or_bitcase:
1007 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1009 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1010 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1011 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1013 abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1014 # default for simple cases: call sizeof()
1015 length = "sizeof(%s)" % field.c_field_type
1017 if context in ('unserialize', 'unpack', 'sizeof'):
1018 # default: simple cast
1019 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1021 # padding - we could probably just ignore it
1022 if field.type.is_pad and field.type.nmemb > 1:
1024 for i in range(field.type.nmemb):
1025 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1026 (space, abs_field_name, i, field.c_field_type))
1027 # total padding = sizeof(pad0) * nmemb
1028 length += " * %d" % field.type.nmemb
1030 elif field.type.is_list:
1031 # list with fixed number of elements
1032 # length of array = sizeof(arrayElementType) * nmemb
1033 length += " * %d" % field.type.nmemb
1034 # use memcpy because C cannot assign whole arrays with operator=
1035 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1038 elif 'serialize' == context:
1039 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1041 if field.type.is_expr:
1042 # need to register a temporary variable for the expression in case we know its type
1043 if field.type.c_type is None:
1044 raise Exception("type for field '%s' (expression '%s') unkown" %
1045 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1047 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1048 _c_accessor_get_expr(field.type.expr, prefix)))
1049 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1051 elif field.type.is_pad:
1052 if field.type.nmemb == 1:
1053 value += "&xcb_pad;"
1055 # we could also set it to 0, see definition of xcb_send_request()
1056 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1057 length += "*%d" % field.type.nmemb
1060 # non-list type with fixed size
1061 if field.type.nmemb == 1:
1062 value += "&%s;" % (abs_field_name)
1064 # list with nmemb (fixed size) elements
1066 value += '%s;' % (abs_field_name)
1067 length = '%d' % field.type.nmemb
1069 return (value, length)
1070 # _c_serialize_helper_fields_fixed_size()
1072 def _c_serialize_helper_fields_variable_size(context, self, field,
1073 code_lines, temp_vars,
1075 prefix_str = _c_helper_fieldaccess_expr(prefix)
1077 if context in ('unserialize', 'unpack', 'sizeof'):
1079 var_field_name = 'xcb_tmp'
1081 # special case: intermixed fixed and variable size fields
1082 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1083 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1084 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1085 # special case: switch
1086 if 'unpack' == context:
1087 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1089 elif 'serialize' == context:
1090 # variable size fields appear as parameters to _serialize() if the
1091 # 'toplevel' container is not a switch
1092 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1093 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1094 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1098 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1100 if field.type.is_list:
1102 # in any context, list is already a pointer, so the default assignment is ok
1103 code_lines.append("%s%s" % (space, value))
1105 length = _c_serialize_helper_list_field(context, self, field,
1106 code_lines, temp_vars,
1109 elif field.type.is_switch:
1111 if context == 'serialize':
1112 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1113 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1114 length = _c_serialize_helper_switch_field(context, self, field,
1115 'xcb_parts[xcb_parts_idx].iov_base',
1119 # in all remaining special cases - call _sizeof()
1120 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1122 return (value, length)
1123 # _c_serialize_helper_fields_variable_size
1125 def _c_serialize_helper_fields(context, self,
1126 code_lines, temp_vars,
1127 space, prefix, is_case_or_bitcase):
1129 need_padding = False
1130 prev_field_was_variable = False
1132 _c_pre.push_indent(space + ' ')
1134 for field in self.fields:
1135 if not field.visible:
1136 if not ((field.wire and not field.auto) or 'unserialize' == context):
1139 # switch/bitcase: fixed size fields must be considered explicitly
1140 if field.type.fixed_size():
1141 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1142 if prev_field_was_variable and need_padding:
1144 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1145 # self.c_var_followed_by_fixed_fields)
1146 prev_field_was_variable = False
1148 # prefix for fixed size fields
1149 fixed_prefix = prefix
1151 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1152 code_lines, temp_vars,
1153 space, fixed_prefix)
1157 # fields with variable size
1159 if field.type.is_pad:
1160 # Variable length pad is <pad align= />
1161 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1162 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1163 self.c_var_followed_by_fixed_fields,
1167 # switch/bitcase: always calculate padding before and after variable sized fields
1168 if need_padding or is_case_or_bitcase:
1169 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1170 self.c_var_followed_by_fixed_fields,
1173 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1174 code_lines, temp_vars,
1176 prev_field_was_variable = True
1178 # save (un)serialization C code
1180 code_lines.append('%s%s' % (space, value))
1182 if field.type.fixed_size():
1183 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1184 # keep track of (un)serialized object's size
1185 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1186 if context in ('unserialize', 'unpack', 'sizeof'):
1187 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1189 # variable size objects or bitcase:
1190 # value & length might have been inserted earlier for special cases
1192 # special case: intermixed fixed and variable size fields
1193 if (not field.type.fixed_size() and
1194 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1195 temp_vars.append(' int %s_len;' % field.c_field_name)
1196 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1197 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1198 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1200 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1201 # increase pointer into the byte stream accordingly
1202 if context in ('unserialize', 'sizeof', 'unpack'):
1203 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1205 if 'serialize' == context:
1207 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1208 code_lines.append('%s xcb_parts_idx++;' % space)
1212 '%s xcb_align_to = ALIGNOF(%s);'
1215 if field.c_field_type == 'void' or field.type.is_switch
1216 else field.c_field_type))
1219 if self.c_var_followed_by_fixed_fields:
1220 need_padding = False
1225 # _c_serialize_helper_fields()
1227 def _c_serialize_helper(context, complex_type,
1228 code_lines, temp_vars,
1229 space='', prefix=[]):
1230 # count tracks the number of fields to serialize
1233 if hasattr(complex_type, 'type'):
1234 self = complex_type.type
1235 complex_name = complex_type.name
1238 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1239 complex_name = 'xcb_out'
1241 complex_name = '_aux'
1243 # special case: switch is serialized by evaluating each bitcase separately
1245 count += _c_serialize_helper_switch(context, self, complex_name,
1246 code_lines, temp_vars,
1249 # all other data types can be evaluated one field a time
1251 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1252 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1253 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1254 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1255 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1256 code_lines.append('%s xcb_block_len = 0;' % space)
1258 count += _c_serialize_helper_fields(context, self,
1259 code_lines, temp_vars,
1260 space, prefix, False)
1262 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1265 # _c_serialize_helper()
1267 def _c_serialize(context, self):
1269 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1270 for the ComplexType variable self
1276 # _serialize() returns the buffer size
1279 if self.is_switch and 'unserialize' == context:
1282 cases = { 'serialize' : self.c_serialize_name,
1283 'unserialize' : self.c_unserialize_name,
1284 'unpack' : self.c_unpack_name,
1285 'sizeof' : self.c_sizeof_name }
1286 func_name = cases[context]
1288 param_fields, wire_fields, params = get_serialize_params(context, self)
1289 variable_size_fields = 0
1290 # maximum space required for type definition of function arguments
1293 # determine N(variable_fields)
1294 for field in param_fields:
1295 # if self.is_switch, treat all fields as if they are variable sized
1296 if not field.type.fixed_size() or self.is_switch:
1297 variable_size_fields += 1
1298 # determine maxtypelen
1300 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1303 indent = ' '*(len(func_name)+2)
1306 typespec, pointerspec, field_name = p
1307 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1308 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1309 # insert function name
1310 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1311 param_str = list(map(lambda x: "%s," % x, param_str))
1312 for s in param_str[:-1]:
1314 _h("%s);" % param_str[-1].rstrip(','))
1315 _c("%s)" % param_str[-1].rstrip(','))
1322 _c_pre.redirect_start(code_lines, temp_vars)
1324 if 'serialize' == context:
1325 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1326 _c(' %s *xcb_out = *_buffer;', self.c_type)
1327 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1328 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1329 _c(' unsigned int xcb_align_to = 0;')
1331 _c(' char *xcb_out = *_buffer;')
1332 _c(' unsigned int xcb_buffer_len = 0;')
1333 _c(' unsigned int xcb_align_to = 0;')
1335 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1336 prefix = [('_aux', '->', self)]
1339 elif context in ('unserialize', 'unpack'):
1340 _c(' char *xcb_tmp = (char *)_buffer;')
1341 if not self.is_switch:
1342 if not self.c_var_followed_by_fixed_fields:
1343 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1344 prefix = [('_aux', '->', self)]
1346 _c(' %s xcb_out;', self.c_type)
1347 prefix = [('xcb_out', '.', self)]
1349 aux_var = '_aux' # default for unpack: single pointer
1350 # note: unserialize not generated for switch
1351 if 'unserialize' == context:
1352 aux_var = '(*_aux)' # unserialize: double pointer (!)
1353 prefix = [(aux_var, '->', self)]
1355 _c(' unsigned int xcb_buffer_len = 0;')
1356 _c(' unsigned int xcb_block_len = 0;')
1357 _c(' unsigned int xcb_pad = 0;')
1358 _c(' unsigned int xcb_align_to = 0;')
1360 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1362 elif 'sizeof' == context:
1363 param_names = [p[2] for p in params]
1365 # switch: call _unpack()
1366 _c(' %s _aux;', self.c_type)
1367 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1369 _c_pre.redirect_end()
1371 elif self.c_var_followed_by_fixed_fields:
1372 # special case: call _unserialize()
1373 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1375 _c_pre.redirect_end()
1378 _c(' char *xcb_tmp = (char *)_buffer;')
1379 prefix = [('_aux', '->', self)]
1381 _c(' unsigned int xcb_padding_offset = 0;')
1383 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1384 # update variable size fields (only important for context=='serialize'
1385 variable_size_fields = count
1386 if 'serialize' == context:
1387 temp_vars.append(' unsigned int xcb_pad = 0;')
1388 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1389 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1390 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1391 temp_vars.append(' unsigned int xcb_block_len = 0;')
1392 temp_vars.append(' unsigned int i;')
1393 temp_vars.append(' char *xcb_tmp;')
1394 elif 'sizeof' == context:
1395 # neither switch nor intermixed fixed and variable size fields:
1396 # evaluate parameters directly
1397 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1399 # look if we have to declare an '_aux' variable at all
1400 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1401 if not self.c_var_followed_by_fixed_fields:
1402 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1404 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1406 _c(' unsigned int xcb_buffer_len = 0;')
1407 _c(' unsigned int xcb_block_len = 0;')
1408 _c(' unsigned int xcb_pad = 0;')
1409 _c(' unsigned int xcb_align_to = 0;')
1411 _c_pre.redirect_end()
1417 for l in code_lines:
1420 # variable sized fields have been collected, now
1421 # allocate memory and copy everything into a continuous memory area
1422 # note: this is not necessary in case of unpack
1423 if context in ('serialize', 'unserialize'):
1424 # unserialize: check for sizeof-only invocation
1425 if 'unserialize' == context:
1427 _c(' if (NULL == _aux)')
1428 _c(' return xcb_buffer_len;')
1431 _c(' if (NULL == %s) {', aux_ptr)
1432 _c(' /* allocate memory */')
1433 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1434 if 'serialize' == context:
1435 _c(' *_buffer = xcb_out;')
1439 # serialize: handle variable size fields in a loop
1440 if 'serialize' == context:
1441 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1442 if len(wire_fields)>0:
1443 _c(' *xcb_out = *_aux;')
1444 # copy variable size fields into the buffer
1445 if variable_size_fields > 0:
1447 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1448 _c(' xcb_tmp = (char*)++xcb_out;')
1449 _c(' xcb_tmp += xcb_out_pad;')
1451 _c(' xcb_tmp = xcb_out;')
1453 # variable sized fields
1454 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1455 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1456 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1457 _c(' if (0 != xcb_parts[i].iov_len)')
1458 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1461 # unserialize: assign variable size fields individually
1462 if 'unserialize' == context:
1463 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1464 param_fields.reverse()
1465 for field in param_fields:
1466 if not field.type.fixed_size():
1467 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1468 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1469 _c(' *%s = xcb_out;', aux_ptr)
1472 _c(' return xcb_buffer_len;')
1476 def _c_iterator_get_end(field, accum):
1478 Figures out what C code is needed to find the end of a variable-length structure field.
1479 For nested structures, recurses into its last variable-sized field.
1480 For lists, calls the end function
1482 if field.type.is_container:
1483 accum = field.c_accessor_name + '(' + accum + ')'
1484 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1485 if field.type.is_list:
1486 # XXX we can always use the first way
1487 if field.type.member.is_simple:
1488 return field.c_end_name + '(' + accum + ')'
1490 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1492 def _c_iterator(self, name):
1494 Declares the iterator structure and next/end functions for a given type.
1499 _h(' * @brief %s', self.c_iterator_type)
1501 _h('typedef struct %s {', self.c_iterator_type)
1502 _h(' %s *data; /**< */', self.c_type)
1503 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1504 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1505 _h('} %s;', self.c_iterator_type)
1511 _h(' * Get the next element of the iterator')
1512 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1514 _h(' * Get the next element in the iterator. The member rem is')
1515 _h(' * decreased by one. The member data points to the next')
1516 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1520 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1521 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1524 if not self.fixed_size():
1525 _c(' %s *R = i->data;', self.c_type)
1528 # FIXME - how to determine the size of a variable size union??
1529 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1531 if self.c_need_sizeof:
1532 _c(' xcb_generic_iterator_t child;')
1533 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1534 self.c_type, self.c_sizeof_name)
1535 _c(' i->index = (char *) child.data - (char *) i->data;')
1537 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1538 _c(' i->index = child.index;')
1540 _c(' i->data = (%s *) child.data;', self.c_type)
1545 _c(' i->index += sizeof(%s);', self.c_type)
1551 _h(' * Return the iterator pointing to the last element')
1552 _h(' * @param i An %s', self.c_iterator_type)
1553 _h(' * @return The iterator pointing to the last element')
1555 _h(' * Set the current element in the iterator to the last element.')
1556 _h(' * The member rem is set to 0. The member data points to the')
1557 _h(' * last element.')
1560 _hc('xcb_generic_iterator_t')
1561 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1562 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1564 _c(' xcb_generic_iterator_t ret;')
1566 if self.fixed_size():
1567 _c(' ret.data = i.data + i.rem;')
1568 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1571 _c(' while(i.rem > 0)')
1572 _c(' %s(&i);', self.c_next_name)
1573 _c(' ret.data = i.data;')
1574 _c(' ret.rem = i.rem;')
1575 _c(' ret.index = i.index;')
1580 def _c_accessor_get_length(expr, field_mapping=None):
1582 Figures out what C code is needed to get a length field.
1583 The field_mapping parameter can be used to change the absolute name of a length field.
1584 For fields that follow a variable-length field, use the accessor.
1585 Otherwise, just reference the structure field directly.
1588 lenfield_name = expr.lenfield_name
1589 if lenfield_name is not None:
1590 if field_mapping is not None:
1591 lenfield_name = field_mapping[lenfield_name][0]
1593 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1594 # special case: variable and fixed size fields are intermixed
1595 # if the lenfield is among the fixed size fields, there is no need
1596 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1597 return field_mapping(expr.lenfield_name)
1598 elif expr.lenfield_name is not None:
1599 return lenfield_name
1601 return str(expr.nmemb)
1603 def _c_accessor_get_expr(expr, field_mapping):
1605 Figures out what C code is needed to get the length of a list field.
1606 The field_mapping parameter can be used to change the absolute name of a length field.
1607 Recurses for math operations.
1608 Returns bitcount for value-mask fields.
1609 Otherwise, uses the value of the length field.
1611 lenexp = _c_accessor_get_length(expr, field_mapping)
1614 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1615 elif expr.op == 'popcount':
1616 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1617 elif expr.op == 'enumref':
1618 enum_name = expr.lenfield_type.name
1619 constant_name = expr.lenfield_name
1620 c_name = _n(enum_name + (constant_name,)).upper()
1622 elif expr.op == 'sumof':
1623 # locate the referenced list object
1624 list_obj = expr.lenfield_type
1626 for f in expr.lenfield_parent.fields:
1627 if f.field_name == expr.lenfield_name:
1632 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1633 list_name = field_mapping[field.c_field_name][0]
1634 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1635 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1636 # create explicit code for computing the sum.
1637 # This works for all C-types which can be added to int64_t with +=
1639 lengthvar = _c_pre.get_tempvarname()
1640 loopvar = _c_pre.get_tempvarname()
1641 sumvar = _c_pre.get_tempvarname()
1642 listvar = _c_pre.get_tempvarname()
1643 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1644 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1645 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1646 _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1647 _c_pre.code("/* sumof start */")
1648 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1649 _c_pre.code("%s = 0;", sumvar)
1650 _c_pre.code("%s = %s;", listvar, list_name)
1651 _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1654 if expr.rhs is None:
1655 _c_pre.code("%s += *%s;", sumvar, listvar)
1657 # sumof has a nested expression which has to be evaluated in
1658 # the context of this list element
1660 # field mapping for the subexpression needs to include
1661 # the fields of the list-member type
1662 scoped_field_mapping = field_mapping.copy()
1663 scoped_field_mapping.update(
1664 _c_helper_field_mapping(
1666 [(listvar, '->', field.type.member)]))
1668 # cause pre-code of the subexpression be added right here
1670 # compute the subexpression
1671 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1672 # resume with our code
1674 # output the summation expression
1675 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1677 _c_pre.code("%s++;", listvar)
1680 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1683 elif expr.op != None:
1684 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1685 ' ' + expr.op + ' ' +
1686 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1688 return 'xcb_popcount(' + lenexp + ')'
1692 def type_pad_type(type):
1697 def _c_accessors_field(self, field):
1699 Declares the accessor functions for a non-list field that follows a variable-length field.
1701 c_type = self.c_type
1703 # special case: switch
1704 switch_obj = self if self.is_switch else None
1705 if self.is_case_or_bitcase:
1706 switch_obj = self.parents[-1]
1707 if switch_obj is not None:
1708 c_type = switch_obj.c_type
1710 if field.type.is_simple:
1712 _hc('%s', field.c_field_type)
1713 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1714 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1716 if field.prev_varsized_field is None:
1717 _c(' return (%s *) (R + 1);', field.c_field_type)
1719 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1720 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1721 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1725 if field.type.is_switch and switch_obj is None:
1726 return_type = 'void *'
1728 return_type = '%s *' % field.c_field_type
1731 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1732 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1734 if field.prev_varsized_field is None:
1735 _c(' return (%s) (R + 1);', return_type)
1736 # note: the special case 'variable fields followed by fixed size fields'
1737 # is not of any consequence here, since the ordering gets
1738 # 'corrected' in the reply function
1740 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1741 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1742 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1746 def _c_accessors_list(self, field):
1748 Declares the accessor functions for a list field.
1749 Declares a direct-accessor function only if the list members are fixed size.
1750 Declares length and get-iterator functions always.
1753 def get_align_pad(field):
1754 prev = field.prev_varsized_field
1755 prev_prev = field.prev_varsized_field.prev_varsized_field
1757 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1758 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1764 c_type = self.c_type
1766 # special case: switch
1767 # in case of switch, 2 params have to be supplied to certain accessor functions:
1768 # 1. the anchestor object (request or reply)
1769 # 2. the (anchestor) switch object
1770 # the reason is that switch is either a child of a request/reply or nested in another switch,
1771 # so whenever we need to access a length field, we might need to refer to some anchestor type
1772 switch_obj = self if self.is_switch else None
1773 if self.is_case_or_bitcase:
1774 switch_obj = self.parents[-1]
1775 if switch_obj is not None:
1776 c_type = switch_obj.c_type
1780 parents = self.parents if hasattr(self, 'parents') else [self]
1781 # 'R': parents[0] is always the 'toplevel' container type
1782 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1783 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1784 # auxiliary object for 'R' parameters
1787 if switch_obj is not None:
1788 # now look where the fields are defined that are needed to evaluate
1789 # the switch expr, and store the parent objects in accessor_params and
1790 # the fields in switch_fields
1792 # 'S': name for the 'toplevel' switch
1793 toplevel_switch = parents[1]
1794 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1795 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1797 # initialize prefix for everything "below" S
1798 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1799 prefix = [(prefix_str, '->', toplevel_switch)]
1801 # look for fields in the remaining containers
1802 for p in parents[2:] + [self]:
1803 # the separator between parent and child is always '.' here,
1804 # because of nested switch statements
1805 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1806 prefix.append((p.name[-1], '.', p))
1807 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1809 # auxiliary object for 'S' parameter
1814 if list.member.fixed_size():
1815 idx = 1 if switch_obj is not None else 0
1817 _hc('%s *', field.c_field_type)
1819 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1820 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1823 if switch_obj is not None:
1824 _c(' return %s;', fields[field.c_field_name][0])
1825 elif field.prev_varsized_field is None:
1826 _c(' return (%s *) (R + 1);', field.c_field_type)
1828 (prev_varsized_field, align_pad) = get_align_pad(field)
1830 if align_pad is None:
1831 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1832 type_pad_type(field.first_field_after_varsized.type.c_type))
1834 _c(' xcb_generic_iterator_t prev = %s;',
1835 _c_iterator_get_end(prev_varsized_field, 'R'))
1836 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1837 field.c_field_type, align_pad, field.prev_varsized_offset)
1842 if switch_obj is not None:
1843 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1844 spacing = ' '*(len(field.c_length_name)+2)
1845 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1846 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1848 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1849 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1851 length = _c_accessor_get_expr(field.type.expr, fields)
1852 _c(' return %s;', length)
1855 if field.type.member.is_simple:
1857 _hc('xcb_generic_iterator_t')
1858 if switch_obj is not None:
1859 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1860 spacing = ' '*(len(field.c_end_name)+2)
1861 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1862 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1864 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1865 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1867 _c(' xcb_generic_iterator_t i;')
1869 param = 'R' if switch_obj is None else 'S'
1870 if switch_obj is not None:
1871 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1872 _c_accessor_get_expr(field.type.expr, fields))
1873 elif field.prev_varsized_field == None:
1874 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1875 _c_accessor_get_expr(field.type.expr, fields))
1877 _c(' xcb_generic_iterator_t child = %s;',
1878 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1879 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1880 _c_accessor_get_expr(field.type.expr, fields))
1883 _c(' i.index = (char *) i.data - (char *) %s;', param)
1889 _hc('%s', field.c_iterator_type)
1890 if switch_obj is not None:
1891 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1892 spacing = ' '*(len(field.c_iterator_name)+2)
1893 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1894 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1896 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1897 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1899 _c(' %s i;', field.c_iterator_type)
1902 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1904 if switch_obj is not None:
1906 _c(' i.data = %s;', fields[field.c_field_name][0])
1907 _c(' i.rem = %s;', length_expr_str)
1908 elif field.prev_varsized_field == None:
1910 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1912 (prev_varsized_field, align_pad) = get_align_pad(field)
1914 if align_pad is None:
1915 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1916 type_pad_type(field.c_field_type))
1918 _c(' xcb_generic_iterator_t prev = %s;',
1919 _c_iterator_get_end(prev_varsized_field, 'R'))
1921 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1922 field.c_field_type, align_pad)
1924 if switch_obj is None:
1925 _c(' i.rem = %s;', length_expr_str)
1926 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1930 def _c_accessors(self, name, base):
1932 Declares the accessor functions for the fields of a structure.
1934 # no accessors for switch itself -
1935 # switch always needs to be unpacked explicitly
1936 # if self.is_switch:
1940 for field in self.fields:
1941 if not field.type.is_pad:
1942 if _c_field_needs_list_accessor(field):
1943 _c_accessors_list(self, field)
1944 elif _c_field_needs_field_accessor(field):
1945 _c_accessors_field(self, field)
1947 def c_simple(self, name):
1949 Exported function that handles cardinal type declarations.
1950 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1952 _c_type_setup(self, name, ())
1954 if (self.name != name):
1959 _h('typedef %s %s;', _t(self.name), my_name)
1962 _c_iterator(self, name)
1964 def _c_complex(self, force_packed = False):
1966 Helper function for handling all structure types.
1967 Called for all structs, requests, replies, events, errors.
1972 _h(' * @brief %s', self.c_type)
1974 _h('typedef %s %s {', self.c_container, self.c_type)
1980 for field in self.fields:
1981 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1982 varfield = field.c_field_name
1985 struct_fields.append(field)
1987 for field in struct_fields:
1988 length = len(field.c_field_type)
1989 # account for '*' pointer_spec
1990 if not field.type.fixed_size() and not self.is_union:
1992 maxtypelen = max(maxtypelen, length)
1994 def _c_complex_field(self, field, space=''):
1995 if (field.type.fixed_size() or self.is_union or
1996 # in case of switch with switch children, don't make the field a pointer
1997 # necessary for unserialize to work
1998 (self.is_switch and field.type.is_switch)):
1999 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2000 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2002 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2003 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2005 if not self.is_switch:
2006 for field in struct_fields:
2007 _c_complex_field(self, field)
2009 for b in self.bitcases:
2014 for field in b.type.fields:
2015 _c_complex_field(self, field, space)
2017 _h(' } %s;', b.c_field_name)
2019 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2021 def c_struct(self, name):
2023 Exported function that handles structure declarations.
2025 _c_type_setup(self, name, ())
2027 _c_accessors(self, name, name)
2028 _c_iterator(self, name)
2030 def c_union(self, name):
2032 Exported function that handles union declarations.
2034 _c_type_setup(self, name, ())
2036 _c_iterator(self, name)
2038 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2040 Declares a request function.
2043 # Four stunningly confusing possibilities here:
2046 # ------------------------------
2048 # 0 flag CHECKED flag Normal Mode
2049 # void_cookie req_cookie
2050 # ------------------------------
2051 # "req_checked" "req_unchecked"
2052 # CHECKED flag 0 flag Abnormal Mode
2053 # void_cookie req_cookie
2054 # ------------------------------
2057 # Whether we are _checked or _unchecked
2058 checked = void and not regular
2059 unchecked = not void and not regular
2061 # What kind of cookie we return
2062 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2064 # What flag is passed to xcb_request
2065 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2068 if func_flags == '0':
2069 func_flags = 'XCB_REQUEST_REPLY_FDS'
2071 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2073 # Global extension id variable or NULL for xproto
2074 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2076 # What our function name is
2077 func_name = self.c_request_name if not aux else self.c_aux_name
2079 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2081 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2085 maxtypelen = len('xcb_connection_t')
2087 # special case: list with variable size elements
2088 list_with_var_size_elems = False
2090 for field in self.fields:
2092 # The field should appear as a call parameter
2093 param_fields.append(field)
2094 if field.wire and not field.auto:
2095 # We need to set the field up in the structure
2096 wire_fields.append(field)
2097 if field.type.c_need_serialize or field.type.c_need_sizeof:
2098 serial_fields.append(field)
2100 for field in param_fields:
2101 c_field_const_type = field.c_field_const_type
2102 if field.type.c_need_serialize and not aux:
2103 c_field_const_type = "const void"
2104 if len(c_field_const_type) > maxtypelen:
2105 maxtypelen = len(c_field_const_type)
2106 if field.type.is_list and not field.type.member.fixed_size():
2107 list_with_var_size_elems = True
2113 if hasattr(self, "doc") and self.doc:
2115 _h(' * @brief ' + self.doc.brief)
2117 _h(' * No brief doc yet')
2120 _h(' * @param c The connection')
2121 param_names = [f.c_field_name for f in param_fields]
2122 if hasattr(self, "doc") and self.doc:
2123 for field in param_fields:
2124 # XXX: hard-coded until we fix xproto.xml
2125 base_func_name = self.c_request_name if not aux else self.c_aux_name
2126 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2128 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2130 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2133 # XXX: why the 'xcb' prefix?
2134 key = ('xcb', field.enum)
2137 if namecount[tname] > 1:
2138 tname = _t(key + ('enum',))
2139 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2141 if self.doc and field.field_name in self.doc.fields:
2142 desc = self.doc.fields[field.field_name]
2143 for name in param_names:
2144 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2145 desc = desc.split("\n")
2146 desc = [line if line != '' else '\\n' for line in desc]
2147 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2148 # If there is no documentation yet, we simply don't generate an
2149 # @param tag. Doxygen will then warn about missing documentation.
2151 _h(' * @return A cookie')
2154 if hasattr(self, "doc") and self.doc:
2155 if self.doc.description:
2156 desc = self.doc.description
2157 for name in param_names:
2158 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2159 desc = desc.split("\n")
2160 _h(' * ' + "\n * ".join(desc))
2162 _h(' * No description yet')
2164 _h(' * Delivers a request to the X server.')
2167 _h(' * This form can be used only if the request will not cause')
2168 _h(' * a reply to be generated. Any returned error will be')
2169 _h(' * saved for handling by xcb_request_check().')
2171 _h(' * This form can be used only if the request will cause')
2172 _h(' * a reply to be generated. Any returned error will be')
2173 _h(' * placed in the event queue.')
2176 _hc('%s', cookie_type)
2178 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2179 comma = ',' if len(param_fields) else ');'
2180 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2181 comma = ',' if len(param_fields) else ')'
2182 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2184 func_spacing = ' ' * (len(func_name) + 2)
2185 count = len(param_fields)
2186 for field in param_fields:
2188 c_field_const_type = field.c_field_const_type
2189 c_pointer = field.c_pointer
2190 if field.type.c_need_serialize and not aux:
2191 c_field_const_type = "const void"
2193 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2194 comma = ',' if count else ');'
2195 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2196 spacing, c_pointer, field.c_field_name, comma)
2197 comma = ',' if count else ')'
2198 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2199 spacing, c_pointer, field.c_field_name, comma)
2202 if not self.c_var_followed_by_fixed_fields:
2203 for field in param_fields:
2204 if not field.type.fixed_size():
2206 if field.type.c_need_serialize:
2207 # _serialize() keeps track of padding automatically
2209 dimension = count + 2
2212 _c(' static const xcb_protocol_request_t xcb_req = {')
2213 _c(' /* count */ %d,', count)
2214 _c(' /* ext */ %s,', func_ext_global)
2215 _c(' /* opcode */ %s,', self.c_request_name.upper())
2216 _c(' /* isvoid */ %d', 1 if void else 0)
2220 _c(' struct iovec xcb_parts[%d];', dimension)
2221 _c(' %s xcb_ret;', func_cookie)
2222 _c(' %s xcb_out;', self.c_type)
2223 if self.c_var_followed_by_fixed_fields:
2224 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2225 _c(' void *xcb_aux = 0;')
2228 for idx, f in enumerate(serial_fields):
2230 _c(' void *xcb_aux%d = 0;' % (idx))
2231 if list_with_var_size_elems:
2232 _c(' unsigned int i;')
2233 _c(' unsigned int xcb_tmp_len;')
2234 _c(' char *xcb_tmp;')
2236 # simple request call tracing
2237 # _c(' printf("in function %s\\n");' % func_name)
2240 for field in wire_fields:
2241 if field.type.fixed_size():
2242 if field.type.is_expr:
2243 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2244 elif field.type.is_pad:
2245 if field.type.nmemb == 1:
2246 _c(' xcb_out.%s = 0;', field.c_field_name)
2248 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2250 if field.type.nmemb == 1:
2251 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2253 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2255 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2256 serialize_args = get_serialize_params(context, type_obj,
2259 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2261 # calls in order to free dyn. all. memory
2265 if not self.c_var_followed_by_fixed_fields:
2266 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2267 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2268 _c(' xcb_parts[3].iov_base = 0;')
2269 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2273 for field in param_fields:
2274 if not field.type.fixed_size():
2275 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2276 # default: simple cast to char *
2277 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2278 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2279 if field.type.is_list:
2280 if field.type.member.fixed_size():
2281 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2282 _c_accessor_get_expr(field.type.expr, None),
2283 field.type.member.c_wiretype)
2285 list_length = _c_accessor_get_expr(field.type.expr, None)
2288 _c(" xcb_parts[%d].iov_len = 0;" % count)
2289 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2290 _c(" for(i=0; i<%s; i++) {" % list_length)
2291 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2292 (field.type.c_sizeof_name))
2293 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2294 _c(" xcb_tmp += xcb_tmp_len;")
2297 # not supposed to happen
2298 raise Exception("unhandled variable size field %s" % field.c_field_name)
2301 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2302 idx = serial_fields.index(field)
2303 aux_var = '&xcb_aux%d' % idx
2304 context = 'serialize' if aux else 'sizeof'
2305 _c(' xcb_parts[%d].iov_len =', count)
2307 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2308 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2309 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2310 free_calls.append(' free(xcb_aux%d);' % idx)
2312 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2313 func_name = field.type.c_sizeof_name
2314 _c(' %s (%s);', func_name, serialize_args)
2317 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2318 # the _serialize() function keeps track of padding automatically
2319 _c(' xcb_parts[%d].iov_base = 0;', count)
2320 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2323 # elif self.c_var_followed_by_fixed_fields:
2325 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2326 # request header: opcodes + length
2327 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2330 buffer_var = '&xcb_aux'
2331 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2332 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2333 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2334 free_calls.append(' free(xcb_aux);')
2335 # no padding necessary - _serialize() keeps track of padding automatically
2338 for field in param_fields:
2340 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2342 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2344 # free dyn. all. data, if any
2345 for f in free_calls:
2347 _c(' return xcb_ret;')
2350 def _c_reply(self, name):
2352 Declares the function that returns the reply structure.
2354 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2355 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2356 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2358 # check if _unserialize() has to be called for any field
2359 def look_for_special_cases(complex_obj):
2360 unserialize_fields = []
2361 # no unserialize call in case of switch
2362 if not complex_obj.is_switch:
2363 for field in complex_obj.fields:
2364 # three cases: 1. field with special case
2365 # 2. container that contains special case field
2366 # 3. list with special case elements
2367 if field.type.c_var_followed_by_fixed_fields:
2368 unserialize_fields.append(field)
2369 elif field.type.is_container:
2370 unserialize_fields += look_for_special_cases(field.type)
2371 elif field.type.is_list:
2372 if field.type.member.c_var_followed_by_fixed_fields:
2373 unserialize_fields.append(field)
2374 if field.type.member.is_container:
2375 unserialize_fields += look_for_special_cases(field.type.member)
2376 return unserialize_fields
2378 unserialize_fields = look_for_special_cases(self.reply)
2382 _h(' * Return the reply')
2383 _h(' * @param c The connection')
2384 _h(' * @param cookie The cookie')
2385 _h(' * @param e The xcb_generic_error_t supplied')
2387 _h(' * Returns the reply of the request asked by')
2389 _h(' * The parameter @p e supplied to this function must be NULL if')
2390 _h(' * %s(). is used.', self.c_unchecked_name)
2391 _h(' * Otherwise, it stores the error if any.')
2393 _h(' * The returned value must be freed by the caller using free().')
2396 _hc('%s *', self.c_reply_type)
2397 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2398 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2399 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2400 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2403 if len(unserialize_fields)>0:
2404 # certain variable size fields need to be unserialized explicitly
2405 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2406 self.c_reply_type, self.c_reply_type)
2408 for field in unserialize_fields:
2409 if field.type.is_list:
2410 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2411 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2412 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2414 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2415 # call _unserialize(), using the reply as source and target buffer
2416 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2417 for field in unserialize_fields:
2418 if field.type.is_list:
2419 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2420 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2421 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2422 field.c_field_name, field.c_field_name)
2423 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2425 # return the transformed reply
2426 _c(' return reply;')
2429 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2433 def _c_reply_has_fds(self):
2434 for field in self.fields:
2439 def _c_reply_fds(self, name):
2441 Declares the function that returns fds related to the reply.
2443 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2444 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2447 _h(' * Return the reply fds')
2448 _h(' * @param c The connection')
2449 _h(' * @param reply The reply')
2451 _h(' * Returns the array of reply fds of the request asked by')
2453 _h(' * The returned value must be freed by the caller using free().')
2457 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2458 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2459 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2462 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2467 def _c_opcode(name, opcode):
2469 Declares the opcode define for requests, events, and errors.
2473 _h('/** Opcode for %s. */', _n(name))
2474 _h('#define %s %s', _n(name).upper(), opcode)
2476 def _c_cookie(self, name):
2478 Declares the cookie type for a non-void request.
2483 _h(' * @brief %s', self.c_cookie_type)
2485 _h('typedef struct %s {', self.c_cookie_type)
2486 _h(' unsigned int sequence; /**< */')
2487 _h('} %s;', self.c_cookie_type)
2489 def _man_request(self, name, cookie_type, void, aux):
2490 param_fields = [f for f in self.fields if f.visible]
2492 func_name = self.c_request_name if not aux else self.c_aux_name
2494 def create_link(linkname):
2495 name = 'man/%s.%s' % (linkname, section)
2497 sys.stdout.write(name)
2499 f.write('.so man%s/%s.%s' % (section, func_name, section))
2503 sys.stdout.write('man/%s.%s ' % (func_name, section))
2504 # Our CWD is src/, so this will end up in src/man/
2505 f = open('man/%s.%s' % (func_name, section), 'w')
2506 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2507 # Left-adjust instead of adjusting to both sides
2509 f.write('.SH NAME\n')
2510 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2511 f.write('%s \\- %s\n' % (func_name, brief))
2512 f.write('.SH SYNOPSIS\n')
2513 # Don't split words (hyphenate)
2515 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2517 # function prototypes
2519 count = len(param_fields)
2520 for field in param_fields:
2522 c_field_const_type = field.c_field_const_type
2523 c_pointer = field.c_pointer
2524 if c_pointer == ' ':
2526 if field.type.c_need_serialize and not aux:
2527 c_field_const_type = "const void"
2529 comma = ', ' if count else ');'
2530 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2532 f.write('.SS Request function\n')
2534 base_func_name = self.c_request_name if not aux else self.c_aux_name
2535 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2536 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2539 f.write('.SS Reply datastructure\n')
2542 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2546 for field in self.reply.fields:
2547 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2550 struct_fields.append(field)
2552 for field in struct_fields:
2553 length = len(field.c_field_type)
2554 # account for '*' pointer_spec
2555 if not field.type.fixed_size():
2557 maxtypelen = max(maxtypelen, length)
2559 def _c_complex_field(self, field, space=''):
2560 if (field.type.fixed_size() or
2561 # in case of switch with switch children, don't make the field a pointer
2562 # necessary for unserialize to work
2563 (self.is_switch and field.type.is_switch)):
2564 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2565 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2567 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2568 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2569 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2571 if not self.is_switch:
2572 for field in struct_fields:
2573 _c_complex_field(self, field)
2575 for b in self.bitcases:
2579 for field in b.type.fields:
2580 _c_complex_field(self, field, space)
2582 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2585 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2588 f.write('.SS Reply function\n')
2590 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2591 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2592 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2593 create_link('%s' % self.c_reply_name)
2595 has_accessors = False
2596 for field in self.reply.fields:
2597 if field.type.is_list and not field.type.fixed_size():
2598 has_accessors = True
2599 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2600 has_accessors = True
2603 f.write('.SS Reply accessors\n')
2605 def _c_accessors_field(self, field):
2607 Declares the accessor functions for a non-list field that follows a variable-length field.
2609 c_type = self.c_type
2611 # special case: switch
2612 switch_obj = self if self.is_switch else None
2613 if self.is_case_or_bitcase:
2614 switch_obj = self.parents[-1]
2615 if switch_obj is not None:
2616 c_type = switch_obj.c_type
2618 if field.type.is_simple:
2619 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2620 create_link('%s' % field.c_accessor_name)
2622 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2623 create_link('%s' % field.c_accessor_name)
2625 def _c_accessors_list(self, field):
2627 Declares the accessor functions for a list field.
2628 Declares a direct-accessor function only if the list members are fixed size.
2629 Declares length and get-iterator functions always.
2632 c_type = self.reply.c_type
2634 # special case: switch
2635 # in case of switch, 2 params have to be supplied to certain accessor functions:
2636 # 1. the anchestor object (request or reply)
2637 # 2. the (anchestor) switch object
2638 # the reason is that switch is either a child of a request/reply or nested in another switch,
2639 # so whenever we need to access a length field, we might need to refer to some anchestor type
2640 switch_obj = self if self.is_switch else None
2641 if self.is_case_or_bitcase:
2642 switch_obj = self.parents[-1]
2643 if switch_obj is not None:
2644 c_type = switch_obj.c_type
2648 parents = self.parents if hasattr(self, 'parents') else [self]
2649 # 'R': parents[0] is always the 'toplevel' container type
2650 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2651 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2652 # auxiliary object for 'R' parameters
2655 if switch_obj is not None:
2656 # now look where the fields are defined that are needed to evaluate
2657 # the switch expr, and store the parent objects in accessor_params and
2658 # the fields in switch_fields
2660 # 'S': name for the 'toplevel' switch
2661 toplevel_switch = parents[1]
2662 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2663 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2665 # initialize prefix for everything "below" S
2666 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2667 prefix = [(prefix_str, '->', toplevel_switch)]
2669 # look for fields in the remaining containers
2670 for p in parents[2:] + [self]:
2671 # the separator between parent and child is always '.' here,
2672 # because of nested switch statements
2673 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2674 prefix.append((p.name[-1], '.', p))
2675 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2677 # auxiliary object for 'S' parameter
2680 if list.member.fixed_size():
2681 idx = 1 if switch_obj is not None else 0
2683 f.write('%s *\\fB%s\\fP(%s);\n' %
2684 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2685 create_link('%s' % field.c_accessor_name)
2688 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2689 (field.c_length_name, c_type))
2690 create_link('%s' % field.c_length_name)
2692 if field.type.member.is_simple:
2694 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2695 (field.c_end_name, c_type))
2696 create_link('%s' % field.c_end_name)
2699 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2700 (field.c_iterator_type, field.c_iterator_name,
2702 create_link('%s' % field.c_iterator_name)
2704 for field in self.reply.fields:
2705 if field.type.is_list and not field.type.fixed_size():
2706 _c_accessors_list(self, field)
2707 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2708 _c_accessors_field(self, field)
2712 # Re-enable hyphenation and adjusting to both sides
2715 # argument reference
2716 f.write('.SH REQUEST ARGUMENTS\n')
2717 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2718 f.write('The XCB connection to X11.\n')
2719 for field in param_fields:
2720 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2721 printed_enum = False
2722 # XXX: hard-coded until we fix xproto.xml
2723 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2725 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2727 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2729 if hasattr(field, "enum") and field.enum:
2730 # XXX: why the 'xcb' prefix?
2731 key = ('xcb', field.enum)
2733 f.write('One of the following values:\n')
2736 count = len(enum.values)
2737 for (enam, eval) in enum.values:
2739 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2740 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2741 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2742 f.write('%s\n' % desc)
2744 f.write('TODO: NOT YET DOCUMENTED.\n')
2749 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2750 desc = self.doc.fields[field.field_name]
2751 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2754 f.write('%s\n' % desc)
2756 f.write('TODO: NOT YET DOCUMENTED.\n')
2762 f.write('.SH REPLY FIELDS\n')
2763 # These fields are present in every reply:
2764 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2765 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2766 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2767 'be used to tell replies apart from each other.\n') %
2768 _n(self.reply.name).upper())
2769 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2770 f.write('The sequence number of the last request processed by the X11 server.\n')
2771 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2772 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2773 for field in self.reply.fields:
2774 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2775 field.c_field_name.startswith('pad')):
2778 if field.type.is_list and not field.type.fixed_size():
2780 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2782 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2783 printed_enum = False
2784 if hasattr(field, "enum") and field.enum:
2785 # XXX: why the 'xcb' prefix?
2786 key = ('xcb', field.enum)
2788 f.write('One of the following values:\n')
2791 count = len(enum.values)
2792 for (enam, eval) in enum.values:
2794 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2795 if enum.doc and enam in enum.doc.fields:
2796 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2797 f.write('%s\n' % desc)
2799 f.write('TODO: NOT YET DOCUMENTED.\n')
2804 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2805 desc = self.reply.doc.fields[field.field_name]
2806 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2809 f.write('%s\n' % desc)
2811 f.write('TODO: NOT YET DOCUMENTED.\n')
2818 f.write('.SH DESCRIPTION\n')
2819 if hasattr(self, "doc") and self.doc and self.doc.description:
2820 desc = self.doc.description
2821 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2822 lines = desc.split('\n')
2823 f.write('\n'.join(lines) + '\n')
2825 f.write('.SH RETURN VALUE\n')
2827 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2828 'have to be handled in the event loop.\n\nIf you want to '
2829 'handle errors directly with \\fIxcb_request_check\\fP '
2830 'instead, use \\fI%s_checked\\fP. See '
2831 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2833 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2834 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2835 'handle errors in the event loop instead, use '
2836 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2838 (cookie_type, self.c_reply_name, base_func_name, section))
2839 f.write('.SH ERRORS\n')
2840 if hasattr(self, "doc") and self.doc:
2841 for errtype, errtext in sorted(self.doc.errors.items()):
2842 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2843 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2844 f.write('%s\n' % (errtext))
2845 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2846 f.write('This request does never generate any errors.\n')
2847 if hasattr(self, "doc") and self.doc and self.doc.example:
2848 f.write('.SH EXAMPLE\n')
2851 lines = self.doc.example.split('\n')
2852 f.write('\n'.join(lines) + '\n')
2854 f.write('.SH SEE ALSO\n')
2855 if hasattr(self, "doc") and self.doc:
2856 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2857 if self.doc.example:
2858 see.append('.BR %s (%s)' % ('xcb-examples', section))
2859 for seename, seetype in sorted(self.doc.see.items()):
2860 if seetype == 'program':
2861 see.append('.BR %s (1)' % seename)
2862 elif seetype == 'event':
2863 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2864 elif seetype == 'request':
2865 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2866 elif seetype == 'function':
2867 see.append('.BR %s (%s)' % (seename, section))
2869 see.append('TODO: %s (type %s)' % (seename, seetype))
2870 f.write(',\n'.join(see) + '\n')
2871 f.write('.SH AUTHOR\n')
2872 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2875 def _man_event(self, name):
2877 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2878 # Our CWD is src/, so this will end up in src/man/
2879 f = open('man/%s.%s' % (self.c_type, section), 'w')
2880 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2881 # Left-adjust instead of adjusting to both sides
2883 f.write('.SH NAME\n')
2884 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2885 f.write('%s \\- %s\n' % (self.c_type, brief))
2886 f.write('.SH SYNOPSIS\n')
2887 # Don't split words (hyphenate)
2889 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2892 f.write('.SS Event datastructure\n')
2895 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2899 for field in self.fields:
2900 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2903 struct_fields.append(field)
2905 for field in struct_fields:
2906 length = len(field.c_field_type)
2907 # account for '*' pointer_spec
2908 if not field.type.fixed_size():
2910 maxtypelen = max(maxtypelen, length)
2912 def _c_complex_field(self, field, space=''):
2913 if (field.type.fixed_size() or
2914 # in case of switch with switch children, don't make the field a pointer
2915 # necessary for unserialize to work
2916 (self.is_switch and field.type.is_switch)):
2917 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2918 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2920 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2922 if not self.is_switch:
2923 for field in struct_fields:
2924 _c_complex_field(self, field)
2926 for b in self.bitcases:
2930 for field in b.type.fields:
2931 _c_complex_field(self, field, space)
2933 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2936 f.write('} \\fB%s\\fP;\n' % self.c_type)
2941 # Re-enable hyphenation and adjusting to both sides
2944 # argument reference
2945 f.write('.SH EVENT FIELDS\n')
2946 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2947 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2948 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2949 'to tell events apart from each other.\n') % _n(name).upper())
2950 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2951 f.write('The sequence number of the last request processed by the X11 server.\n')
2953 if not self.is_switch:
2954 for field in struct_fields:
2955 # Skip the fields which every event has, we already documented
2957 if field.c_field_name in ('response_type', 'sequence'):
2959 if isinstance(field.type, PadType):
2961 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2962 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2963 desc = self.doc.fields[field.field_name]
2964 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2965 f.write('%s\n' % desc)
2967 f.write('NOT YET DOCUMENTED.\n')
2970 f.write('.SH DESCRIPTION\n')
2971 if hasattr(self, "doc") and self.doc and self.doc.description:
2972 desc = self.doc.description
2973 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2974 lines = desc.split('\n')
2975 f.write('\n'.join(lines) + '\n')
2977 if hasattr(self, "doc") and self.doc and self.doc.example:
2978 f.write('.SH EXAMPLE\n')
2981 lines = self.doc.example.split('\n')
2982 f.write('\n'.join(lines) + '\n')
2984 f.write('.SH SEE ALSO\n')
2985 if hasattr(self, "doc") and self.doc:
2986 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2987 if self.doc.example:
2988 see.append('.BR %s (%s)' % ('xcb-examples', section))
2989 for seename, seetype in sorted(self.doc.see.items()):
2990 if seetype == 'program':
2991 see.append('.BR %s (1)' % seename)
2992 elif seetype == 'event':
2993 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2994 elif seetype == 'request':
2995 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2996 elif seetype == 'function':
2997 see.append('.BR %s (%s)' % (seename, section))
2999 see.append('TODO: %s (type %s)' % (seename, seetype))
3000 f.write(',\n'.join(see) + '\n')
3001 f.write('.SH AUTHOR\n')
3002 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3006 def c_request(self, name):
3008 Exported function that handles request declarations.
3010 _c_type_setup(self, name, ('request',))
3013 # Cookie type declaration
3014 _c_cookie(self, name)
3017 _c_opcode(name, self.opcode)
3019 # Request structure declaration
3023 _c_type_setup(self.reply, name, ('reply',))
3024 # Reply structure definition
3025 _c_complex(self.reply)
3026 # Request prototypes
3027 has_fds = _c_reply_has_fds(self.reply)
3028 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3029 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3031 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3032 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3034 _c_accessors(self.reply, name + ('reply',), name)
3035 _c_reply(self, name)
3037 _c_reply_fds(self, name)
3039 # Request prototypes
3040 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3041 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3043 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3044 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3046 # We generate the manpage afterwards because _c_type_setup has been called.
3047 # TODO: what about aux helpers?
3048 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3049 _man_request(self, name, cookie_type, not self.reply, False)
3051 def c_event(self, name):
3053 Exported function that handles event declarations.
3056 # The generic event structure xcb_ge_event_t has the full_sequence field
3057 # at the 32byte boundary. That's why we've to inject this field into GE
3058 # events while generating the structure for them. Otherwise we would read
3059 # garbage (the internal full_sequence) when accessing normal event fields
3061 force_packed = False
3062 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3064 for field in self.fields:
3065 if field.type.size != None and field.type.nmemb != None:
3066 event_size += field.type.size * field.type.nmemb
3067 if event_size == 32:
3068 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3069 idx = self.fields.index(field)
3070 self.fields.insert(idx + 1, full_sequence)
3072 # If the event contains any 64-bit extended fields, they need
3073 # to remain aligned on a 64-bit boundary. Adding full_sequence
3074 # would normally break that; force the struct to be packed.
3075 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3078 _c_type_setup(self, name, ('event',))
3081 _c_opcode(name, self.opcodes[name])
3083 if self.name == name:
3084 # Structure definition
3085 _c_complex(self, force_packed)
3089 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3091 _man_event(self, name)
3093 def c_error(self, name):
3095 Exported function that handles error declarations.
3097 _c_type_setup(self, name, ('error',))
3100 _c_opcode(name, self.opcodes[name])
3102 if self.name == name:
3103 # Structure definition
3108 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3111 # Main routine starts here
3113 # Must create an "output" dictionary before any xcbgen imports.
3114 output = {'open' : c_open,
3116 'simple' : c_simple,
3118 'struct' : c_struct,
3120 'request' : c_request,
3125 # Boilerplate below this point
3127 # Check for the argument that specifies path to the xcbgen python package.
3129 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3130 except getopt.GetoptError as err:
3132 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3135 for (opt, arg) in opts:
3143 sys.path.insert(1, arg)
3146 sys.stdout.write('man_MANS = ')
3148 # Import the module class
3150 from xcbgen.state import Module
3151 from xcbgen.xtypes import *
3154 Failed to load the xcbgen Python package!
3155 Make sure that xcb/proto installed it on your Python path.
3156 If not, you will need to create a .pth file or define $PYTHONPATH
3158 Refer to the README file in xcb/proto for more info.
3162 # Ensure the man subdirectory exists
3165 except OSError as e:
3166 if e.errno != errno.EEXIST:
3169 # Parse the xml header
3170 module = Module(args[0], output)
3172 # Build type-registry and resolve type dependencies