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