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_absolute_name 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_absolute_name(prefix, field=None):
554 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555 representing a valid name in C (based on the context)
556 if field is not None, append the field name as well
560 for name, sep, obj in prefix:
561 prefix_str += last_sep + name
564 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
565 (obj.is_switch and len(obj.parents)>1)):
570 # add separator for access to a yet unknown field
571 prefix_str += last_sep
573 if _c_field_needs_accessor(field):
574 if _c_field_is_member_of_case_or_bitcase(field):
575 # case members are available in the deserialized struct,
576 # so there is no need to use the accessor function
577 # (also, their accessor function needs a different arglist
578 # so this would require special treatment here)
579 # Therefore: Access as struct member
580 prefix_str += last_sep + _cpp(field.field_name)
582 # Access with the accessor function
583 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
585 # Access as struct member
586 prefix_str += last_sep + _cpp(field.field_name)
591 def _c_helper_field_mapping(complex_type, prefix, flat=False):
593 generate absolute names, based on prefix, for all fields starting from complex_type
594 if flat == True, nested complex types are not taken into account
597 if complex_type.is_switch:
598 for b in complex_type.bitcases:
600 switch_name, switch_sep, switch_type = prefix[-1]
601 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
603 bitcase_prefix = prefix
605 if (True==flat and not b.type.has_name) or False==flat:
606 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
608 for f in complex_type.fields:
609 fname = _c_helper_absolute_name(prefix, f)
610 if f.field_name in all_fields:
611 raise Exception("field name %s has been registered before" % f.field_name)
613 all_fields[f.field_name] = (fname, f)
614 if f.type.is_container and flat==False:
615 if f.type.is_case_or_bitcase and not f.type.has_name:
617 elif f.type.is_switch and len(f.type.parents)>1:
618 # nested switch gets another separator
619 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
621 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
622 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
627 def _c_helper_resolve_field_names (prefix):
629 get field names for all objects in the prefix array
633 # look for fields in the remaining containers
634 for idx, p in enumerate(prefix):
637 # sep can be preset in prefix, if not, make a sensible guess
638 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
639 # exception: 'toplevel' object (switch as well!) always have sep '->'
640 sep = '->' if idx<1 else sep
641 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
642 tmp_prefix.append((name, sep, obj))
643 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
646 # _c_helper_resolve_field_names
648 def get_expr_fields(self):
650 get the Fields referenced by switch or list expression
652 def get_expr_field_names(expr):
654 if expr.lenfield_name is not None:
655 return [expr.lenfield_name]
657 # constant value expr
661 return get_expr_field_names(expr.rhs)
662 elif expr.op == 'popcount':
663 return get_expr_field_names(expr.rhs)
664 elif expr.op == 'sumof':
665 # sumof expr references another list,
666 # we need that list's length field here
668 for f in expr.lenfield_parent.fields:
669 if f.field_name == expr.lenfield_name:
673 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
674 # referenced list + its length field
675 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
676 elif expr.op == 'enumref':
679 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
680 # get_expr_field_names()
682 # resolve the field names with the parent structure(s)
683 unresolved_fields_names = get_expr_field_names(self.expr)
685 # construct prefix from self
686 prefix = [('', '', p) for p in self.parents]
687 if self.is_container:
688 prefix.append(('', '', self))
690 all_fields = _c_helper_resolve_field_names (prefix)
691 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
692 if len(unresolved_fields_names) != len(resolved_fields_names):
693 raise Exception("could not resolve all fields for %s" % self.name)
695 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
696 return resolved_fields
699 def resolve_expr_fields(complex_obj):
701 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
702 these are normally fields that need to be given as function parameters
708 for field in complex_obj.fields:
709 all_fields.append(field)
710 if field.type.is_switch or field.type.is_list:
711 expr_fields += get_expr_fields(field.type)
712 if field.type.is_container:
713 expr_fields += resolve_expr_fields(field.type)
715 # try to resolve expr fields
716 for e in expr_fields:
717 if e not in all_fields and e not in unresolved:
720 # resolve_expr_fields()
722 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
724 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
725 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
726 expression. This function tries to resolve all fields within a structure, and returns the
727 unresolved fields as the list of external parameters.
729 def add_param(params, param):
730 if param not in params:
733 # collect all fields into param_fields
737 for field in self.fields:
739 # the field should appear as a parameter in the function call
740 param_fields.append(field)
741 if field.wire and not field.auto:
742 if field.type.fixed_size() and not self.is_switch:
743 # field in the xcb_out structure
744 wire_fields.append(field)
745 # fields like 'pad0' are skipped!
747 # in case of switch, parameters always contain any fields referenced in the switch expr
748 # we do not need any variable size fields here, as the switch data type contains both
749 # fixed and variable size fields
751 param_fields = get_expr_fields(self)
753 # _serialize()/_unserialize()/_unpack() function parameters
754 # note: don't use set() for params, it is unsorted
757 # 1. the parameter for the void * buffer
758 if 'serialize' == context:
759 params.append(('void', '**', buffer_var))
760 elif context in ('unserialize', 'unpack', 'sizeof'):
761 params.append(('const void', '*', buffer_var))
763 # 2. any expr fields that cannot be resolved within self and descendants
764 unresolved_fields = resolve_expr_fields(self)
765 for f in unresolved_fields:
766 add_param(params, (f.c_field_type, '', f.c_field_name))
768 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
769 # that do not appear in the data type struct
770 for p in param_fields:
772 typespec = p.c_field_const_type
773 pointerspec = p.c_pointer
774 add_param(params, (typespec, pointerspec, p.c_field_name))
776 if p.visible and not p.wire and not p.auto:
777 typespec = p.c_field_type
779 add_param(params, (typespec, pointerspec, p.c_field_name))
782 if 'serialize' == context:
783 add_param(params, ('const %s' % self.c_type, '*', aux_var))
784 elif 'unserialize' == context:
785 add_param(params, ('%s' % self.c_type, '**', aux_var))
786 elif 'unpack' == context:
787 add_param(params, ('%s' % self.c_type, '*', aux_var))
789 # 5. switch contains all variable size fields as struct members
790 # for other data types though, these have to be supplied separately
791 # this is important for the special case of intermixed fixed and
792 # variable size fields
793 if not self.is_switch and 'serialize' == context:
794 for p in param_fields:
795 if not p.type.fixed_size():
796 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
798 return (param_fields, wire_fields, params)
799 # get_serialize_params()
801 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
802 code_lines.append('%s /* insert padding */' % space)
803 if is_case_or_bitcase:
805 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
809 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
810 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
811 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
814 code_lines.append('%s if (0 != xcb_pad) {' % space)
816 if 'serialize' == context:
817 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
818 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
819 code_lines.append('%s xcb_parts_idx++;' % space)
820 elif context in ('unserialize', 'unpack', 'sizeof'):
821 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
823 code_lines.append('%s xcb_pad = 0;' % space)
824 code_lines.append('%s }' % space)
826 code_lines.append('%s xcb_block_len = 0;' % space)
827 if is_case_or_bitcase:
828 code_lines.append('%s xcb_padding_offset = 0;' % space)
830 # keep tracking of xcb_parts entries for serialize
832 # _c_serialize_helper_insert_padding()
834 def _c_serialize_helper_switch(context, self, complex_name,
835 code_lines, temp_vars,
838 switch_expr = _c_accessor_get_expr(self.expr, None)
840 for b in self.bitcases:
841 len_expr = len(b.type.expr)
843 compare_operator = '&'
845 compare_operator = '=='
847 compare_operator = '&'
849 for n, expr in enumerate(b.type.expr):
850 bitcase_expr = _c_accessor_get_expr(expr, None)
851 # only one <enumref> in the <bitcase>
854 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
855 # multiple <enumref> in the <bitcase>
858 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
859 elif len_expr == (n + 1): # last
861 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
862 else: # between first and last
864 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
868 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
870 count += _c_serialize_helper_fields(context, b.type,
871 code_lines, temp_vars,
874 is_case_or_bitcase = True)
875 code_lines.append(' }')
877 # if 'serialize' == context:
878 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
879 # elif context in ('unserialize', 'unpack', 'sizeof'):
881 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
882 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
885 # _c_serialize_helper_switch
887 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
889 handle switch by calling _serialize() or _unpack(), depending on context
891 # switch is handled by this function as a special case
892 param_fields, wire_fields, params = get_serialize_params(context, self)
893 field_mapping = _c_helper_field_mapping(self, prefix)
894 prefix_str = _c_helper_absolute_name(prefix)
896 # find the parameters that need to be passed to _serialize()/_unpack():
897 # all switch expr fields must be given as parameters
898 args = get_expr_fields(field.type)
899 # length fields for variable size types in switch, normally only some of need
900 # need to be passed as parameters
901 switch_len_fields = resolve_expr_fields(field.type)
903 # a switch field at this point _must_ be a bitcase field
904 # we require that bitcases are "self-contiguous"
905 bitcase_unresolved = resolve_expr_fields(self)
906 if len(bitcase_unresolved) != 0:
907 raise Exception('unresolved fields within bitcase is not supported at this point')
909 # get the C names for the parameters
911 for a in switch_len_fields:
912 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
914 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
916 # call _serialize()/_unpack() to determine the actual size
917 if 'serialize' == context:
918 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
919 c_field_names, prefix_str, field.c_field_name)
920 elif context in ('unserialize', 'unpack'):
921 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
922 c_field_names, prefix_str, field.c_field_name)
923 elif 'sizeof' == context:
924 # remove trailing ", " from c_field_names because it will be used at end of arglist
925 my_c_field_names = c_field_names[:-2]
926 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
929 # _c_serialize_helper_switch_field()
931 def _c_serialize_helper_list_field(context, self, field,
932 code_lines, temp_vars,
935 helper function to cope with lists of variable length
937 expr = field.type.expr
938 prefix_str = _c_helper_absolute_name(prefix)
939 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
940 param_names = [p[2] for p in params]
942 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
943 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
944 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
948 field_mapping[r] = (r, None)
950 if len(unresolved)>0:
952 if len(tmp_prefix)==0:
953 raise Exception("found an empty prefix while resolving expr field names for list %s",
956 field_mapping.update(_c_helper_resolve_field_names(prefix))
957 resolved += list(filter(lambda x: x in field_mapping, unresolved))
958 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
959 if len(unresolved)>0:
960 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
962 list_length = _c_accessor_get_expr(expr, field_mapping)
964 # default: list with fixed size elements
965 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
967 # list with variable-sized elements
968 if not field.type.member.fixed_size():
970 if context in ('unserialize', 'sizeof', 'unpack'):
971 int_i = ' unsigned int i;'
972 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
973 if int_i not in temp_vars:
974 temp_vars.append(int_i)
975 if xcb_tmp_len not in temp_vars:
976 temp_vars.append(xcb_tmp_len)
977 # loop over all list elements and call sizeof repeatedly
978 # this should be a bit faster than using the iterators
979 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
980 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
981 (space, field.type.c_sizeof_name))
982 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
983 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
984 code_lines.append("%s }" % space)
986 elif 'serialize' == context:
987 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
988 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
989 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
990 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
991 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
992 code_lines.append('%s }' % space)
993 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
996 # _c_serialize_helper_list_field()
998 def _c_serialize_helper_fields_fixed_size(context, self, field,
999 code_lines, temp_vars,
1001 # keep the C code a bit more readable by giving the field name
1002 if not self.is_case_or_bitcase:
1003 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
1005 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1006 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1007 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
1009 abs_field_name = _c_helper_absolute_name(prefix, field)
1010 # default for simple cases: call sizeof()
1011 length = "sizeof(%s)" % field.c_field_type
1013 if context in ('unserialize', 'unpack', 'sizeof'):
1014 # default: simple cast
1015 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1017 # padding - we could probably just ignore it
1018 if field.type.is_pad and field.type.nmemb > 1:
1020 for i in range(field.type.nmemb):
1021 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1022 (space, abs_field_name, i, field.c_field_type))
1023 # total padding = sizeof(pad0) * nmemb
1024 length += " * %d" % field.type.nmemb
1026 elif field.type.is_list:
1027 # list with fixed number of elements
1028 # length of array = sizeof(arrayElementType) * nmemb
1029 length += " * %d" % field.type.nmemb
1030 # use memcpy because C cannot assign whole arrays with operator=
1031 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1034 elif 'serialize' == context:
1035 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1037 if field.type.is_expr:
1038 # need to register a temporary variable for the expression in case we know its type
1039 if field.type.c_type is None:
1040 raise Exception("type for field '%s' (expression '%s') unkown" %
1041 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1043 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1044 _c_accessor_get_expr(field.type.expr, prefix)))
1045 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1047 elif field.type.is_pad:
1048 if field.type.nmemb == 1:
1049 value += "&xcb_pad;"
1051 # we could also set it to 0, see definition of xcb_send_request()
1052 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1053 length += "*%d" % field.type.nmemb
1056 # non-list type with fixed size
1057 if field.type.nmemb == 1:
1058 value += "&%s;" % (abs_field_name)
1060 # list with nmemb (fixed size) elements
1062 value += '%s;' % (abs_field_name)
1063 length = '%d' % field.type.nmemb
1065 return (value, length)
1066 # _c_serialize_helper_fields_fixed_size()
1068 def _c_serialize_helper_fields_variable_size(context, self, field,
1069 code_lines, temp_vars,
1071 prefix_str = _c_helper_absolute_name(prefix)
1073 if context in ('unserialize', 'unpack', 'sizeof'):
1075 var_field_name = 'xcb_tmp'
1077 # special case: intermixed fixed and variable size fields
1078 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1079 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1080 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1081 # special case: switch
1082 if 'unpack' == context:
1083 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1085 elif 'serialize' == context:
1086 # variable size fields appear as parameters to _serialize() if the
1087 # 'toplevel' container is not a switch
1088 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1089 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1090 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1094 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1096 if field.type.is_list:
1098 # in any context, list is already a pointer, so the default assignment is ok
1099 code_lines.append("%s%s" % (space, value))
1101 length = _c_serialize_helper_list_field(context, self, field,
1102 code_lines, temp_vars,
1105 elif field.type.is_switch:
1107 if context == 'serialize':
1108 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1109 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1110 length = _c_serialize_helper_switch_field(context, self, field,
1111 'xcb_parts[xcb_parts_idx].iov_base',
1115 # in all remaining special cases - call _sizeof()
1116 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1118 return (value, length)
1119 # _c_serialize_helper_fields_variable_size
1121 def _c_serialize_helper_fields(context, self,
1122 code_lines, temp_vars,
1123 space, prefix, is_case_or_bitcase):
1125 need_padding = False
1126 prev_field_was_variable = False
1128 _c_pre.push_indent(space + ' ')
1130 for field in self.fields:
1131 if not field.visible:
1132 if not ((field.wire and not field.auto) or 'unserialize' == context):
1135 # switch/bitcase: fixed size fields must be considered explicitly
1136 if field.type.fixed_size():
1137 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1138 if prev_field_was_variable and need_padding:
1140 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1141 # self.c_var_followed_by_fixed_fields)
1142 prev_field_was_variable = False
1144 # prefix for fixed size fields
1145 fixed_prefix = prefix
1147 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1148 code_lines, temp_vars,
1149 space, fixed_prefix)
1153 # fields with variable size
1155 if field.type.is_pad:
1156 # Variable length pad is <pad align= />
1157 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1158 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1159 self.c_var_followed_by_fixed_fields,
1163 # switch/bitcase: always calculate padding before and after variable sized fields
1164 if need_padding or is_case_or_bitcase:
1165 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1166 self.c_var_followed_by_fixed_fields,
1169 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1170 code_lines, temp_vars,
1172 prev_field_was_variable = True
1174 # save (un)serialization C code
1176 code_lines.append('%s%s' % (space, value))
1178 if field.type.fixed_size():
1179 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1180 # keep track of (un)serialized object's size
1181 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1182 if context in ('unserialize', 'unpack', 'sizeof'):
1183 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1185 # variable size objects or bitcase:
1186 # value & length might have been inserted earlier for special cases
1188 # special case: intermixed fixed and variable size fields
1189 if (not field.type.fixed_size() and
1190 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1191 temp_vars.append(' int %s_len;' % field.c_field_name)
1192 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1193 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1194 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1196 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1197 # increase pointer into the byte stream accordingly
1198 if context in ('unserialize', 'sizeof', 'unpack'):
1199 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1201 if 'serialize' == context:
1203 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1204 code_lines.append('%s xcb_parts_idx++;' % space)
1208 '%s xcb_align_to = ALIGNOF(%s);'
1211 if field.c_field_type == 'void' or field.type.is_switch
1212 else field.c_field_type))
1215 if self.c_var_followed_by_fixed_fields:
1216 need_padding = False
1221 # _c_serialize_helper_fields()
1223 def _c_serialize_helper(context, complex_type,
1224 code_lines, temp_vars,
1225 space='', prefix=[]):
1226 # count tracks the number of fields to serialize
1229 if hasattr(complex_type, 'type'):
1230 self = complex_type.type
1231 complex_name = complex_type.name
1234 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1235 complex_name = 'xcb_out'
1237 complex_name = '_aux'
1239 # special case: switch is serialized by evaluating each bitcase separately
1241 count += _c_serialize_helper_switch(context, self, complex_name,
1242 code_lines, temp_vars,
1245 # all other data types can be evaluated one field a time
1247 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1248 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1249 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1250 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1251 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1252 code_lines.append('%s xcb_block_len = 0;' % space)
1254 count += _c_serialize_helper_fields(context, self,
1255 code_lines, temp_vars,
1256 space, prefix, False)
1258 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1261 # _c_serialize_helper()
1263 def _c_serialize(context, self):
1265 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1266 for the ComplexType variable self
1272 # _serialize() returns the buffer size
1275 if self.is_switch and 'unserialize' == context:
1278 cases = { 'serialize' : self.c_serialize_name,
1279 'unserialize' : self.c_unserialize_name,
1280 'unpack' : self.c_unpack_name,
1281 'sizeof' : self.c_sizeof_name }
1282 func_name = cases[context]
1284 param_fields, wire_fields, params = get_serialize_params(context, self)
1285 variable_size_fields = 0
1286 # maximum space required for type definition of function arguments
1289 # determine N(variable_fields)
1290 for field in param_fields:
1291 # if self.is_switch, treat all fields as if they are variable sized
1292 if not field.type.fixed_size() or self.is_switch:
1293 variable_size_fields += 1
1294 # determine maxtypelen
1296 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1299 indent = ' '*(len(func_name)+2)
1302 typespec, pointerspec, field_name = p
1303 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1304 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1305 # insert function name
1306 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1307 param_str = list(map(lambda x: "%s," % x, param_str))
1308 for s in param_str[:-1]:
1310 _h("%s);" % param_str[-1].rstrip(','))
1311 _c("%s)" % param_str[-1].rstrip(','))
1318 _c_pre.redirect_start(code_lines, temp_vars)
1320 if 'serialize' == context:
1321 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1322 _c(' %s *xcb_out = *_buffer;', self.c_type)
1323 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1324 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1325 _c(' unsigned int xcb_align_to = 0;')
1327 _c(' char *xcb_out = *_buffer;')
1328 _c(' unsigned int xcb_buffer_len = 0;')
1329 _c(' unsigned int xcb_align_to = 0;')
1331 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1332 prefix = [('_aux', '->', self)]
1335 elif context in ('unserialize', 'unpack'):
1336 _c(' char *xcb_tmp = (char *)_buffer;')
1337 if not self.is_switch:
1338 if not self.c_var_followed_by_fixed_fields:
1339 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1340 prefix = [('_aux', '->', self)]
1342 _c(' %s xcb_out;', self.c_type)
1343 prefix = [('xcb_out', '.', self)]
1345 aux_var = '_aux' # default for unpack: single pointer
1346 # note: unserialize not generated for switch
1347 if 'unserialize' == context:
1348 aux_var = '(*_aux)' # unserialize: double pointer (!)
1349 prefix = [(aux_var, '->', self)]
1351 _c(' unsigned int xcb_buffer_len = 0;')
1352 _c(' unsigned int xcb_block_len = 0;')
1353 _c(' unsigned int xcb_pad = 0;')
1354 _c(' unsigned int xcb_align_to = 0;')
1356 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1358 elif 'sizeof' == context:
1359 param_names = [p[2] for p in params]
1361 # switch: call _unpack()
1362 _c(' %s _aux;', self.c_type)
1363 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1365 _c_pre.redirect_end()
1367 elif self.c_var_followed_by_fixed_fields:
1368 # special case: call _unserialize()
1369 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1371 _c_pre.redirect_end()
1374 _c(' char *xcb_tmp = (char *)_buffer;')
1375 prefix = [('_aux', '->', self)]
1377 _c(' unsigned int xcb_padding_offset = 0;')
1379 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1380 # update variable size fields (only important for context=='serialize'
1381 variable_size_fields = count
1382 if 'serialize' == context:
1383 temp_vars.append(' unsigned int xcb_pad = 0;')
1384 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1385 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1386 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1387 temp_vars.append(' unsigned int xcb_block_len = 0;')
1388 temp_vars.append(' unsigned int i;')
1389 temp_vars.append(' char *xcb_tmp;')
1390 elif 'sizeof' == context:
1391 # neither switch nor intermixed fixed and variable size fields:
1392 # evaluate parameters directly
1393 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1395 # look if we have to declare an '_aux' variable at all
1396 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1397 if not self.c_var_followed_by_fixed_fields:
1398 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1400 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1402 _c(' unsigned int xcb_buffer_len = 0;')
1403 _c(' unsigned int xcb_block_len = 0;')
1404 _c(' unsigned int xcb_pad = 0;')
1405 _c(' unsigned int xcb_align_to = 0;')
1407 _c_pre.redirect_end()
1413 for l in code_lines:
1416 # variable sized fields have been collected, now
1417 # allocate memory and copy everything into a continuous memory area
1418 # note: this is not necessary in case of unpack
1419 if context in ('serialize', 'unserialize'):
1420 # unserialize: check for sizeof-only invocation
1421 if 'unserialize' == context:
1423 _c(' if (NULL == _aux)')
1424 _c(' return xcb_buffer_len;')
1427 _c(' if (NULL == %s) {', aux_ptr)
1428 _c(' /* allocate memory */')
1429 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1430 if 'serialize' == context:
1431 _c(' *_buffer = xcb_out;')
1435 # serialize: handle variable size fields in a loop
1436 if 'serialize' == context:
1437 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1438 if len(wire_fields)>0:
1439 _c(' *xcb_out = *_aux;')
1440 # copy variable size fields into the buffer
1441 if variable_size_fields > 0:
1443 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1444 _c(' xcb_tmp = (char*)++xcb_out;')
1445 _c(' xcb_tmp += xcb_out_pad;')
1447 _c(' xcb_tmp = xcb_out;')
1449 # variable sized fields
1450 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1451 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1452 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1453 _c(' if (0 != xcb_parts[i].iov_len)')
1454 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1457 # unserialize: assign variable size fields individually
1458 if 'unserialize' == context:
1459 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1460 param_fields.reverse()
1461 for field in param_fields:
1462 if not field.type.fixed_size():
1463 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1464 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1465 _c(' *%s = xcb_out;', aux_ptr)
1468 _c(' return xcb_buffer_len;')
1472 def _c_iterator_get_end(field, accum):
1474 Figures out what C code is needed to find the end of a variable-length structure field.
1475 For nested structures, recurses into its last variable-sized field.
1476 For lists, calls the end function
1478 if field.type.is_container:
1479 accum = field.c_accessor_name + '(' + accum + ')'
1480 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1481 if field.type.is_list:
1482 # XXX we can always use the first way
1483 if field.type.member.is_simple:
1484 return field.c_end_name + '(' + accum + ')'
1486 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1488 def _c_iterator(self, name):
1490 Declares the iterator structure and next/end functions for a given type.
1495 _h(' * @brief %s', self.c_iterator_type)
1497 _h('typedef struct %s {', self.c_iterator_type)
1498 _h(' %s *data; /**< */', self.c_type)
1499 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1500 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1501 _h('} %s;', self.c_iterator_type)
1507 _h(' * Get the next element of the iterator')
1508 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1510 _h(' * Get the next element in the iterator. The member rem is')
1511 _h(' * decreased by one. The member data points to the next')
1512 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1516 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1517 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1520 if not self.fixed_size():
1521 _c(' %s *R = i->data;', self.c_type)
1524 # FIXME - how to determine the size of a variable size union??
1525 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1527 if self.c_need_sizeof:
1528 _c(' xcb_generic_iterator_t child;')
1529 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1530 self.c_type, self.c_sizeof_name)
1531 _c(' i->index = (char *) child.data - (char *) i->data;')
1533 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1534 _c(' i->index = child.index;')
1536 _c(' i->data = (%s *) child.data;', self.c_type)
1541 _c(' i->index += sizeof(%s);', self.c_type)
1547 _h(' * Return the iterator pointing to the last element')
1548 _h(' * @param i An %s', self.c_iterator_type)
1549 _h(' * @return The iterator pointing to the last element')
1551 _h(' * Set the current element in the iterator to the last element.')
1552 _h(' * The member rem is set to 0. The member data points to the')
1553 _h(' * last element.')
1556 _hc('xcb_generic_iterator_t')
1557 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1558 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1560 _c(' xcb_generic_iterator_t ret;')
1562 if self.fixed_size():
1563 _c(' ret.data = i.data + i.rem;')
1564 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1567 _c(' while(i.rem > 0)')
1568 _c(' %s(&i);', self.c_next_name)
1569 _c(' ret.data = i.data;')
1570 _c(' ret.rem = i.rem;')
1571 _c(' ret.index = i.index;')
1576 def _c_accessor_get_length(expr, field_mapping=None):
1578 Figures out what C code is needed to get a length field.
1579 The field_mapping parameter can be used to change the absolute name of a length field.
1580 For fields that follow a variable-length field, use the accessor.
1581 Otherwise, just reference the structure field directly.
1584 lenfield_name = expr.lenfield_name
1585 if lenfield_name is not None:
1586 if field_mapping is not None:
1587 lenfield_name = field_mapping[lenfield_name][0]
1589 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1590 # special case: variable and fixed size fields are intermixed
1591 # if the lenfield is among the fixed size fields, there is no need
1592 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1593 return field_mapping(expr.lenfield_name)
1594 elif expr.lenfield_name is not None:
1595 return lenfield_name
1597 return str(expr.nmemb)
1599 def _c_accessor_get_expr(expr, field_mapping):
1601 Figures out what C code is needed to get the length of a list field.
1602 The field_mapping parameter can be used to change the absolute name of a length field.
1603 Recurses for math operations.
1604 Returns bitcount for value-mask fields.
1605 Otherwise, uses the value of the length field.
1607 lenexp = _c_accessor_get_length(expr, field_mapping)
1610 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1611 elif expr.op == 'popcount':
1612 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1613 elif expr.op == 'enumref':
1614 enum_name = expr.lenfield_type.name
1615 constant_name = expr.lenfield_name
1616 c_name = _n(enum_name + (constant_name,)).upper()
1618 elif expr.op == 'sumof':
1619 # locate the referenced list object
1620 list_obj = expr.lenfield_type
1622 for f in expr.lenfield_parent.fields:
1623 if f.field_name == expr.lenfield_name:
1628 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1629 list_name = field_mapping[field.c_field_name][0]
1630 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1631 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1632 # create explicit code for computing the sum.
1633 # This works for all C-types which can be added to int64_t with +=
1635 lengthvar = _c_pre.get_tempvarname()
1636 loopvar = _c_pre.get_tempvarname()
1637 sumvar = _c_pre.get_tempvarname()
1638 listvar = _c_pre.get_tempvarname()
1639 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1640 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1641 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1642 _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1643 _c_pre.code("/* sumof start */")
1644 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1645 _c_pre.code("%s = 0;", sumvar)
1646 _c_pre.code("%s = %s;", listvar, list_name)
1647 _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1649 _c_pre.code("%s += *%s;", sumvar, listvar)
1650 _c_pre.code("%s++;", listvar)
1653 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1656 elif expr.op != None:
1657 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1658 ' ' + expr.op + ' ' +
1659 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1661 return 'xcb_popcount(' + lenexp + ')'
1665 def type_pad_type(type):
1670 def _c_accessors_field(self, field):
1672 Declares the accessor functions for a non-list field that follows a variable-length field.
1674 c_type = self.c_type
1676 # special case: switch
1677 switch_obj = self if self.is_switch else None
1678 if self.is_case_or_bitcase:
1679 switch_obj = self.parents[-1]
1680 if switch_obj is not None:
1681 c_type = switch_obj.c_type
1683 if field.type.is_simple:
1685 _hc('%s', field.c_field_type)
1686 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1687 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1689 if field.prev_varsized_field is None:
1690 _c(' return (%s *) (R + 1);', field.c_field_type)
1692 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1693 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1694 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1698 if field.type.is_switch and switch_obj is None:
1699 return_type = 'void *'
1701 return_type = '%s *' % field.c_field_type
1704 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1705 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1707 if field.prev_varsized_field is None:
1708 _c(' return (%s) (R + 1);', return_type)
1709 # note: the special case 'variable fields followed by fixed size fields'
1710 # is not of any consequence here, since the ordering gets
1711 # 'corrected' in the reply function
1713 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1714 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1715 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1719 def _c_accessors_list(self, field):
1721 Declares the accessor functions for a list field.
1722 Declares a direct-accessor function only if the list members are fixed size.
1723 Declares length and get-iterator functions always.
1726 def get_align_pad(field):
1727 prev = field.prev_varsized_field
1728 prev_prev = field.prev_varsized_field.prev_varsized_field
1730 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1731 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1737 c_type = self.c_type
1739 # special case: switch
1740 # in case of switch, 2 params have to be supplied to certain accessor functions:
1741 # 1. the anchestor object (request or reply)
1742 # 2. the (anchestor) switch object
1743 # the reason is that switch is either a child of a request/reply or nested in another switch,
1744 # so whenever we need to access a length field, we might need to refer to some anchestor type
1745 switch_obj = self if self.is_switch else None
1746 if self.is_case_or_bitcase:
1747 switch_obj = self.parents[-1]
1748 if switch_obj is not None:
1749 c_type = switch_obj.c_type
1753 parents = self.parents if hasattr(self, 'parents') else [self]
1754 # 'R': parents[0] is always the 'toplevel' container type
1755 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1756 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1757 # auxiliary object for 'R' parameters
1760 if switch_obj is not None:
1761 # now look where the fields are defined that are needed to evaluate
1762 # the switch expr, and store the parent objects in accessor_params and
1763 # the fields in switch_fields
1765 # 'S': name for the 'toplevel' switch
1766 toplevel_switch = parents[1]
1767 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1768 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1770 # initialize prefix for everything "below" S
1771 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1772 prefix = [(prefix_str, '->', toplevel_switch)]
1774 # look for fields in the remaining containers
1775 for p in parents[2:] + [self]:
1776 # the separator between parent and child is always '.' here,
1777 # because of nested switch statements
1778 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1779 prefix.append((p.name[-1], '.', p))
1780 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1782 # auxiliary object for 'S' parameter
1787 if list.member.fixed_size():
1788 idx = 1 if switch_obj is not None else 0
1790 _hc('%s *', field.c_field_type)
1792 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1793 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1796 if switch_obj is not None:
1797 _c(' return %s;', fields[field.c_field_name][0])
1798 elif field.prev_varsized_field is None:
1799 _c(' return (%s *) (R + 1);', field.c_field_type)
1801 (prev_varsized_field, align_pad) = get_align_pad(field)
1803 if align_pad is None:
1804 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1805 type_pad_type(field.first_field_after_varsized.type.c_type))
1807 _c(' xcb_generic_iterator_t prev = %s;',
1808 _c_iterator_get_end(prev_varsized_field, 'R'))
1809 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1810 field.c_field_type, align_pad, field.prev_varsized_offset)
1815 if switch_obj is not None:
1816 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1817 spacing = ' '*(len(field.c_length_name)+2)
1818 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1819 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1821 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1822 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1824 length = _c_accessor_get_expr(field.type.expr, fields)
1825 _c(' return %s;', length)
1828 if field.type.member.is_simple:
1830 _hc('xcb_generic_iterator_t')
1831 if switch_obj is not None:
1832 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1833 spacing = ' '*(len(field.c_end_name)+2)
1834 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1835 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1837 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1838 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1840 _c(' xcb_generic_iterator_t i;')
1842 param = 'R' if switch_obj is None else 'S'
1843 if switch_obj is not None:
1844 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1845 _c_accessor_get_expr(field.type.expr, fields))
1846 elif field.prev_varsized_field == None:
1847 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1848 _c_accessor_get_expr(field.type.expr, fields))
1850 _c(' xcb_generic_iterator_t child = %s;',
1851 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1852 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1853 _c_accessor_get_expr(field.type.expr, fields))
1856 _c(' i.index = (char *) i.data - (char *) %s;', param)
1862 _hc('%s', field.c_iterator_type)
1863 if switch_obj is not None:
1864 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1865 spacing = ' '*(len(field.c_iterator_name)+2)
1866 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1867 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1869 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1870 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1872 _c(' %s i;', field.c_iterator_type)
1875 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1877 if switch_obj is not None:
1879 _c(' i.data = %s;', fields[field.c_field_name][0])
1880 _c(' i.rem = %s;', length_expr_str)
1881 elif field.prev_varsized_field == None:
1883 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1885 (prev_varsized_field, align_pad) = get_align_pad(field)
1887 if align_pad is None:
1888 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1889 type_pad_type(field.c_field_type))
1891 _c(' xcb_generic_iterator_t prev = %s;',
1892 _c_iterator_get_end(prev_varsized_field, 'R'))
1894 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1895 field.c_field_type, align_pad)
1897 if switch_obj is None:
1898 _c(' i.rem = %s;', length_expr_str)
1899 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1903 def _c_accessors(self, name, base):
1905 Declares the accessor functions for the fields of a structure.
1907 # no accessors for switch itself -
1908 # switch always needs to be unpacked explicitly
1909 # if self.is_switch:
1913 for field in self.fields:
1914 if not field.type.is_pad:
1915 if _c_field_needs_list_accessor(field):
1916 _c_accessors_list(self, field)
1917 elif _c_field_needs_field_accessor(field):
1918 _c_accessors_field(self, field)
1920 def c_simple(self, name):
1922 Exported function that handles cardinal type declarations.
1923 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1925 _c_type_setup(self, name, ())
1927 if (self.name != name):
1932 _h('typedef %s %s;', _t(self.name), my_name)
1935 _c_iterator(self, name)
1937 def _c_complex(self, force_packed = False):
1939 Helper function for handling all structure types.
1940 Called for all structs, requests, replies, events, errors.
1945 _h(' * @brief %s', self.c_type)
1947 _h('typedef %s %s {', self.c_container, self.c_type)
1953 for field in self.fields:
1954 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1955 varfield = field.c_field_name
1958 struct_fields.append(field)
1960 for field in struct_fields:
1961 length = len(field.c_field_type)
1962 # account for '*' pointer_spec
1963 if not field.type.fixed_size() and not self.is_union:
1965 maxtypelen = max(maxtypelen, length)
1967 def _c_complex_field(self, field, space=''):
1968 if (field.type.fixed_size() or self.is_union or
1969 # in case of switch with switch children, don't make the field a pointer
1970 # necessary for unserialize to work
1971 (self.is_switch and field.type.is_switch)):
1972 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1973 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1975 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1976 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1978 if not self.is_switch:
1979 for field in struct_fields:
1980 _c_complex_field(self, field)
1982 for b in self.bitcases:
1987 for field in b.type.fields:
1988 _c_complex_field(self, field, space)
1990 _h(' } %s;', b.c_field_name)
1992 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1994 def c_struct(self, name):
1996 Exported function that handles structure declarations.
1998 _c_type_setup(self, name, ())
2000 _c_accessors(self, name, name)
2001 _c_iterator(self, name)
2003 def c_union(self, name):
2005 Exported function that handles union declarations.
2007 _c_type_setup(self, name, ())
2009 _c_iterator(self, name)
2011 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2013 Declares a request function.
2016 # Four stunningly confusing possibilities here:
2019 # ------------------------------
2021 # 0 flag CHECKED flag Normal Mode
2022 # void_cookie req_cookie
2023 # ------------------------------
2024 # "req_checked" "req_unchecked"
2025 # CHECKED flag 0 flag Abnormal Mode
2026 # void_cookie req_cookie
2027 # ------------------------------
2030 # Whether we are _checked or _unchecked
2031 checked = void and not regular
2032 unchecked = not void and not regular
2034 # What kind of cookie we return
2035 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2037 # What flag is passed to xcb_request
2038 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2041 if func_flags == '0':
2042 func_flags = 'XCB_REQUEST_REPLY_FDS'
2044 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2046 # Global extension id variable or NULL for xproto
2047 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2049 # What our function name is
2050 func_name = self.c_request_name if not aux else self.c_aux_name
2052 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2054 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2058 maxtypelen = len('xcb_connection_t')
2060 # special case: list with variable size elements
2061 list_with_var_size_elems = False
2063 for field in self.fields:
2065 # The field should appear as a call parameter
2066 param_fields.append(field)
2067 if field.wire and not field.auto:
2068 # We need to set the field up in the structure
2069 wire_fields.append(field)
2070 if field.type.c_need_serialize or field.type.c_need_sizeof:
2071 serial_fields.append(field)
2073 for field in param_fields:
2074 c_field_const_type = field.c_field_const_type
2075 if field.type.c_need_serialize and not aux:
2076 c_field_const_type = "const void"
2077 if len(c_field_const_type) > maxtypelen:
2078 maxtypelen = len(c_field_const_type)
2079 if field.type.is_list and not field.type.member.fixed_size():
2080 list_with_var_size_elems = True
2086 if hasattr(self, "doc") and self.doc:
2088 _h(' * @brief ' + self.doc.brief)
2090 _h(' * No brief doc yet')
2093 _h(' * @param c The connection')
2094 param_names = [f.c_field_name for f in param_fields]
2095 if hasattr(self, "doc") and self.doc:
2096 for field in param_fields:
2097 # XXX: hard-coded until we fix xproto.xml
2098 base_func_name = self.c_request_name if not aux else self.c_aux_name
2099 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2101 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2103 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2106 # XXX: why the 'xcb' prefix?
2107 key = ('xcb', field.enum)
2110 if namecount[tname] > 1:
2111 tname = _t(key + ('enum',))
2112 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2114 if self.doc and field.field_name in self.doc.fields:
2115 desc = self.doc.fields[field.field_name]
2116 for name in param_names:
2117 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2118 desc = desc.split("\n")
2119 desc = [line if line != '' else '\\n' for line in desc]
2120 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2121 # If there is no documentation yet, we simply don't generate an
2122 # @param tag. Doxygen will then warn about missing documentation.
2124 _h(' * @return A cookie')
2127 if hasattr(self, "doc") and self.doc:
2128 if self.doc.description:
2129 desc = self.doc.description
2130 for name in param_names:
2131 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2132 desc = desc.split("\n")
2133 _h(' * ' + "\n * ".join(desc))
2135 _h(' * No description yet')
2137 _h(' * Delivers a request to the X server.')
2140 _h(' * This form can be used only if the request will not cause')
2141 _h(' * a reply to be generated. Any returned error will be')
2142 _h(' * saved for handling by xcb_request_check().')
2144 _h(' * This form can be used only if the request will cause')
2145 _h(' * a reply to be generated. Any returned error will be')
2146 _h(' * placed in the event queue.')
2149 _hc('%s', cookie_type)
2151 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2152 comma = ',' if len(param_fields) else ');'
2153 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2154 comma = ',' if len(param_fields) else ')'
2155 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2157 func_spacing = ' ' * (len(func_name) + 2)
2158 count = len(param_fields)
2159 for field in param_fields:
2161 c_field_const_type = field.c_field_const_type
2162 c_pointer = field.c_pointer
2163 if field.type.c_need_serialize and not aux:
2164 c_field_const_type = "const void"
2166 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2167 comma = ',' if count else ');'
2168 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2169 spacing, c_pointer, field.c_field_name, comma)
2170 comma = ',' if count else ')'
2171 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2172 spacing, c_pointer, field.c_field_name, comma)
2175 if not self.c_var_followed_by_fixed_fields:
2176 for field in param_fields:
2177 if not field.type.fixed_size():
2179 if field.type.c_need_serialize:
2180 # _serialize() keeps track of padding automatically
2182 dimension = count + 2
2185 _c(' static const xcb_protocol_request_t xcb_req = {')
2186 _c(' /* count */ %d,', count)
2187 _c(' /* ext */ %s,', func_ext_global)
2188 _c(' /* opcode */ %s,', self.c_request_name.upper())
2189 _c(' /* isvoid */ %d', 1 if void else 0)
2193 _c(' struct iovec xcb_parts[%d];', dimension)
2194 _c(' %s xcb_ret;', func_cookie)
2195 _c(' %s xcb_out;', self.c_type)
2196 if self.c_var_followed_by_fixed_fields:
2197 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2198 _c(' void *xcb_aux = 0;')
2201 for idx, f in enumerate(serial_fields):
2203 _c(' void *xcb_aux%d = 0;' % (idx))
2204 if list_with_var_size_elems:
2205 _c(' unsigned int i;')
2206 _c(' unsigned int xcb_tmp_len;')
2207 _c(' char *xcb_tmp;')
2209 # simple request call tracing
2210 # _c(' printf("in function %s\\n");' % func_name)
2213 for field in wire_fields:
2214 if field.type.fixed_size():
2215 if field.type.is_expr:
2216 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2217 elif field.type.is_pad:
2218 if field.type.nmemb == 1:
2219 _c(' xcb_out.%s = 0;', field.c_field_name)
2221 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2223 if field.type.nmemb == 1:
2224 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2226 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2228 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2229 serialize_args = get_serialize_params(context, type_obj,
2232 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2234 # calls in order to free dyn. all. memory
2238 if not self.c_var_followed_by_fixed_fields:
2239 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2240 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2241 _c(' xcb_parts[3].iov_base = 0;')
2242 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2246 for field in param_fields:
2247 if not field.type.fixed_size():
2248 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2249 # default: simple cast to char *
2250 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2251 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2252 if field.type.is_list:
2253 if field.type.member.fixed_size():
2254 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2255 _c_accessor_get_expr(field.type.expr, None),
2256 field.type.member.c_wiretype)
2258 list_length = _c_accessor_get_expr(field.type.expr, None)
2261 _c(" xcb_parts[%d].iov_len = 0;" % count)
2262 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2263 _c(" for(i=0; i<%s; i++) {" % list_length)
2264 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2265 (field.type.c_sizeof_name))
2266 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2267 _c(" xcb_tmp += xcb_tmp_len;")
2270 # not supposed to happen
2271 raise Exception("unhandled variable size field %s" % field.c_field_name)
2274 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2275 idx = serial_fields.index(field)
2276 aux_var = '&xcb_aux%d' % idx
2277 context = 'serialize' if aux else 'sizeof'
2278 _c(' xcb_parts[%d].iov_len =', count)
2280 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2281 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2282 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2283 free_calls.append(' free(xcb_aux%d);' % idx)
2285 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2286 func_name = field.type.c_sizeof_name
2287 _c(' %s (%s);', func_name, serialize_args)
2290 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2291 # the _serialize() function keeps track of padding automatically
2292 _c(' xcb_parts[%d].iov_base = 0;', count)
2293 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2296 # elif self.c_var_followed_by_fixed_fields:
2298 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2299 # request header: opcodes + length
2300 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2303 buffer_var = '&xcb_aux'
2304 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2305 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2306 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2307 free_calls.append(' free(xcb_aux);')
2308 # no padding necessary - _serialize() keeps track of padding automatically
2311 for field in param_fields:
2313 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2315 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2317 # free dyn. all. data, if any
2318 for f in free_calls:
2320 _c(' return xcb_ret;')
2323 def _c_reply(self, name):
2325 Declares the function that returns the reply structure.
2327 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2328 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2329 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2331 # check if _unserialize() has to be called for any field
2332 def look_for_special_cases(complex_obj):
2333 unserialize_fields = []
2334 # no unserialize call in case of switch
2335 if not complex_obj.is_switch:
2336 for field in complex_obj.fields:
2337 # three cases: 1. field with special case
2338 # 2. container that contains special case field
2339 # 3. list with special case elements
2340 if field.type.c_var_followed_by_fixed_fields:
2341 unserialize_fields.append(field)
2342 elif field.type.is_container:
2343 unserialize_fields += look_for_special_cases(field.type)
2344 elif field.type.is_list:
2345 if field.type.member.c_var_followed_by_fixed_fields:
2346 unserialize_fields.append(field)
2347 if field.type.member.is_container:
2348 unserialize_fields += look_for_special_cases(field.type.member)
2349 return unserialize_fields
2351 unserialize_fields = look_for_special_cases(self.reply)
2355 _h(' * Return the reply')
2356 _h(' * @param c The connection')
2357 _h(' * @param cookie The cookie')
2358 _h(' * @param e The xcb_generic_error_t supplied')
2360 _h(' * Returns the reply of the request asked by')
2362 _h(' * The parameter @p e supplied to this function must be NULL if')
2363 _h(' * %s(). is used.', self.c_unchecked_name)
2364 _h(' * Otherwise, it stores the error if any.')
2366 _h(' * The returned value must be freed by the caller using free().')
2369 _hc('%s *', self.c_reply_type)
2370 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2371 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2372 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2373 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2376 if len(unserialize_fields)>0:
2377 # certain variable size fields need to be unserialized explicitly
2378 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2379 self.c_reply_type, self.c_reply_type)
2381 for field in unserialize_fields:
2382 if field.type.is_list:
2383 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2384 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2385 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2387 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2388 # call _unserialize(), using the reply as source and target buffer
2389 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2390 for field in unserialize_fields:
2391 if field.type.is_list:
2392 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2393 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2394 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2395 field.c_field_name, field.c_field_name)
2396 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2398 # return the transformed reply
2399 _c(' return reply;')
2402 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2406 def _c_reply_has_fds(self):
2407 for field in self.fields:
2412 def _c_reply_fds(self, name):
2414 Declares the function that returns fds related to the reply.
2416 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2417 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2420 _h(' * Return the reply fds')
2421 _h(' * @param c The connection')
2422 _h(' * @param reply The reply')
2424 _h(' * Returns the array of reply fds of the request asked by')
2426 _h(' * The returned value must be freed by the caller using free().')
2430 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2431 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2432 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2435 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2440 def _c_opcode(name, opcode):
2442 Declares the opcode define for requests, events, and errors.
2446 _h('/** Opcode for %s. */', _n(name))
2447 _h('#define %s %s', _n(name).upper(), opcode)
2449 def _c_cookie(self, name):
2451 Declares the cookie type for a non-void request.
2456 _h(' * @brief %s', self.c_cookie_type)
2458 _h('typedef struct %s {', self.c_cookie_type)
2459 _h(' unsigned int sequence; /**< */')
2460 _h('} %s;', self.c_cookie_type)
2462 def _man_request(self, name, cookie_type, void, aux):
2463 param_fields = [f for f in self.fields if f.visible]
2465 func_name = self.c_request_name if not aux else self.c_aux_name
2467 def create_link(linkname):
2468 name = 'man/%s.%s' % (linkname, section)
2470 sys.stdout.write(name)
2472 f.write('.so man%s/%s.%s' % (section, func_name, section))
2476 sys.stdout.write('man/%s.%s ' % (func_name, section))
2477 # Our CWD is src/, so this will end up in src/man/
2478 f = open('man/%s.%s' % (func_name, section), 'w')
2479 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2480 # Left-adjust instead of adjusting to both sides
2482 f.write('.SH NAME\n')
2483 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2484 f.write('%s \\- %s\n' % (func_name, brief))
2485 f.write('.SH SYNOPSIS\n')
2486 # Don't split words (hyphenate)
2488 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2490 # function prototypes
2492 count = len(param_fields)
2493 for field in param_fields:
2495 c_field_const_type = field.c_field_const_type
2496 c_pointer = field.c_pointer
2497 if c_pointer == ' ':
2499 if field.type.c_need_serialize and not aux:
2500 c_field_const_type = "const void"
2502 comma = ', ' if count else ');'
2503 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2505 f.write('.SS Request function\n')
2507 base_func_name = self.c_request_name if not aux else self.c_aux_name
2508 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2509 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2512 f.write('.SS Reply datastructure\n')
2515 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2519 for field in self.reply.fields:
2520 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2523 struct_fields.append(field)
2525 for field in struct_fields:
2526 length = len(field.c_field_type)
2527 # account for '*' pointer_spec
2528 if not field.type.fixed_size():
2530 maxtypelen = max(maxtypelen, length)
2532 def _c_complex_field(self, field, space=''):
2533 if (field.type.fixed_size() or
2534 # in case of switch with switch children, don't make the field a pointer
2535 # necessary for unserialize to work
2536 (self.is_switch and field.type.is_switch)):
2537 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2538 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2540 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2541 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2542 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2544 if not self.is_switch:
2545 for field in struct_fields:
2546 _c_complex_field(self, field)
2548 for b in self.bitcases:
2552 for field in b.type.fields:
2553 _c_complex_field(self, field, space)
2555 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2558 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2561 f.write('.SS Reply function\n')
2563 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2564 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2565 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2566 create_link('%s' % self.c_reply_name)
2568 has_accessors = False
2569 for field in self.reply.fields:
2570 if field.type.is_list and not field.type.fixed_size():
2571 has_accessors = True
2572 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2573 has_accessors = True
2576 f.write('.SS Reply accessors\n')
2578 def _c_accessors_field(self, field):
2580 Declares the accessor functions for a non-list field that follows a variable-length field.
2582 c_type = self.c_type
2584 # special case: switch
2585 switch_obj = self if self.is_switch else None
2586 if self.is_case_or_bitcase:
2587 switch_obj = self.parents[-1]
2588 if switch_obj is not None:
2589 c_type = switch_obj.c_type
2591 if field.type.is_simple:
2592 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2593 create_link('%s' % field.c_accessor_name)
2595 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2596 create_link('%s' % field.c_accessor_name)
2598 def _c_accessors_list(self, field):
2600 Declares the accessor functions for a list field.
2601 Declares a direct-accessor function only if the list members are fixed size.
2602 Declares length and get-iterator functions always.
2605 c_type = self.reply.c_type
2607 # special case: switch
2608 # in case of switch, 2 params have to be supplied to certain accessor functions:
2609 # 1. the anchestor object (request or reply)
2610 # 2. the (anchestor) switch object
2611 # the reason is that switch is either a child of a request/reply or nested in another switch,
2612 # so whenever we need to access a length field, we might need to refer to some anchestor type
2613 switch_obj = self if self.is_switch else None
2614 if self.is_case_or_bitcase:
2615 switch_obj = self.parents[-1]
2616 if switch_obj is not None:
2617 c_type = switch_obj.c_type
2621 parents = self.parents if hasattr(self, 'parents') else [self]
2622 # 'R': parents[0] is always the 'toplevel' container type
2623 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2624 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2625 # auxiliary object for 'R' parameters
2628 if switch_obj is not None:
2629 # now look where the fields are defined that are needed to evaluate
2630 # the switch expr, and store the parent objects in accessor_params and
2631 # the fields in switch_fields
2633 # 'S': name for the 'toplevel' switch
2634 toplevel_switch = parents[1]
2635 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2636 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2638 # initialize prefix for everything "below" S
2639 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2640 prefix = [(prefix_str, '->', toplevel_switch)]
2642 # look for fields in the remaining containers
2643 for p in parents[2:] + [self]:
2644 # the separator between parent and child is always '.' here,
2645 # because of nested switch statements
2646 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2647 prefix.append((p.name[-1], '.', p))
2648 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2650 # auxiliary object for 'S' parameter
2653 if list.member.fixed_size():
2654 idx = 1 if switch_obj is not None else 0
2656 f.write('%s *\\fB%s\\fP(%s);\n' %
2657 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2658 create_link('%s' % field.c_accessor_name)
2661 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2662 (field.c_length_name, c_type))
2663 create_link('%s' % field.c_length_name)
2665 if field.type.member.is_simple:
2667 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2668 (field.c_end_name, c_type))
2669 create_link('%s' % field.c_end_name)
2672 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2673 (field.c_iterator_type, field.c_iterator_name,
2675 create_link('%s' % field.c_iterator_name)
2677 for field in self.reply.fields:
2678 if field.type.is_list and not field.type.fixed_size():
2679 _c_accessors_list(self, field)
2680 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2681 _c_accessors_field(self, field)
2685 # Re-enable hyphenation and adjusting to both sides
2688 # argument reference
2689 f.write('.SH REQUEST ARGUMENTS\n')
2690 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2691 f.write('The XCB connection to X11.\n')
2692 for field in param_fields:
2693 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2694 printed_enum = False
2695 # XXX: hard-coded until we fix xproto.xml
2696 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2698 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2700 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2702 if hasattr(field, "enum") and field.enum:
2703 # XXX: why the 'xcb' prefix?
2704 key = ('xcb', field.enum)
2706 f.write('One of the following values:\n')
2709 count = len(enum.values)
2710 for (enam, eval) in enum.values:
2712 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2713 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2714 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2715 f.write('%s\n' % desc)
2717 f.write('TODO: NOT YET DOCUMENTED.\n')
2722 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2723 desc = self.doc.fields[field.field_name]
2724 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2727 f.write('%s\n' % desc)
2729 f.write('TODO: NOT YET DOCUMENTED.\n')
2735 f.write('.SH REPLY FIELDS\n')
2736 # These fields are present in every reply:
2737 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2738 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2739 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2740 'be used to tell replies apart from each other.\n') %
2741 _n(self.reply.name).upper())
2742 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2743 f.write('The sequence number of the last request processed by the X11 server.\n')
2744 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2745 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2746 for field in self.reply.fields:
2747 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2748 field.c_field_name.startswith('pad')):
2751 if field.type.is_list and not field.type.fixed_size():
2753 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2755 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2756 printed_enum = False
2757 if hasattr(field, "enum") and field.enum:
2758 # XXX: why the 'xcb' prefix?
2759 key = ('xcb', field.enum)
2761 f.write('One of the following values:\n')
2764 count = len(enum.values)
2765 for (enam, eval) in enum.values:
2767 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2768 if enum.doc and enam in enum.doc.fields:
2769 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2770 f.write('%s\n' % desc)
2772 f.write('TODO: NOT YET DOCUMENTED.\n')
2777 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2778 desc = self.reply.doc.fields[field.field_name]
2779 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2782 f.write('%s\n' % desc)
2784 f.write('TODO: NOT YET DOCUMENTED.\n')
2791 f.write('.SH DESCRIPTION\n')
2792 if hasattr(self, "doc") and self.doc and self.doc.description:
2793 desc = self.doc.description
2794 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2795 lines = desc.split('\n')
2796 f.write('\n'.join(lines) + '\n')
2798 f.write('.SH RETURN VALUE\n')
2800 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2801 'have to be handled in the event loop.\n\nIf you want to '
2802 'handle errors directly with \\fIxcb_request_check\\fP '
2803 'instead, use \\fI%s_checked\\fP. See '
2804 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2806 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2807 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2808 'handle errors in the event loop instead, use '
2809 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2811 (cookie_type, self.c_reply_name, base_func_name, section))
2812 f.write('.SH ERRORS\n')
2813 if hasattr(self, "doc") and self.doc:
2814 for errtype, errtext in sorted(self.doc.errors.items()):
2815 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2816 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2817 f.write('%s\n' % (errtext))
2818 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2819 f.write('This request does never generate any errors.\n')
2820 if hasattr(self, "doc") and self.doc and self.doc.example:
2821 f.write('.SH EXAMPLE\n')
2824 lines = self.doc.example.split('\n')
2825 f.write('\n'.join(lines) + '\n')
2827 f.write('.SH SEE ALSO\n')
2828 if hasattr(self, "doc") and self.doc:
2829 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2830 if self.doc.example:
2831 see.append('.BR %s (%s)' % ('xcb-examples', section))
2832 for seename, seetype in sorted(self.doc.see.items()):
2833 if seetype == 'program':
2834 see.append('.BR %s (1)' % seename)
2835 elif seetype == 'event':
2836 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2837 elif seetype == 'request':
2838 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2839 elif seetype == 'function':
2840 see.append('.BR %s (%s)' % (seename, section))
2842 see.append('TODO: %s (type %s)' % (seename, seetype))
2843 f.write(',\n'.join(see) + '\n')
2844 f.write('.SH AUTHOR\n')
2845 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2848 def _man_event(self, name):
2850 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2851 # Our CWD is src/, so this will end up in src/man/
2852 f = open('man/%s.%s' % (self.c_type, section), 'w')
2853 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2854 # Left-adjust instead of adjusting to both sides
2856 f.write('.SH NAME\n')
2857 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2858 f.write('%s \\- %s\n' % (self.c_type, brief))
2859 f.write('.SH SYNOPSIS\n')
2860 # Don't split words (hyphenate)
2862 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2865 f.write('.SS Event datastructure\n')
2868 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2872 for field in self.fields:
2873 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2876 struct_fields.append(field)
2878 for field in struct_fields:
2879 length = len(field.c_field_type)
2880 # account for '*' pointer_spec
2881 if not field.type.fixed_size():
2883 maxtypelen = max(maxtypelen, length)
2885 def _c_complex_field(self, field, space=''):
2886 if (field.type.fixed_size() or
2887 # in case of switch with switch children, don't make the field a pointer
2888 # necessary for unserialize to work
2889 (self.is_switch and field.type.is_switch)):
2890 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2891 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2893 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2895 if not self.is_switch:
2896 for field in struct_fields:
2897 _c_complex_field(self, field)
2899 for b in self.bitcases:
2903 for field in b.type.fields:
2904 _c_complex_field(self, field, space)
2906 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2909 f.write('} \\fB%s\\fP;\n' % self.c_type)
2914 # Re-enable hyphenation and adjusting to both sides
2917 # argument reference
2918 f.write('.SH EVENT FIELDS\n')
2919 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2920 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2921 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2922 'to tell events apart from each other.\n') % _n(name).upper())
2923 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2924 f.write('The sequence number of the last request processed by the X11 server.\n')
2926 if not self.is_switch:
2927 for field in struct_fields:
2928 # Skip the fields which every event has, we already documented
2930 if field.c_field_name in ('response_type', 'sequence'):
2932 if isinstance(field.type, PadType):
2934 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2935 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2936 desc = self.doc.fields[field.field_name]
2937 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2938 f.write('%s\n' % desc)
2940 f.write('NOT YET DOCUMENTED.\n')
2943 f.write('.SH DESCRIPTION\n')
2944 if hasattr(self, "doc") and self.doc and self.doc.description:
2945 desc = self.doc.description
2946 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2947 lines = desc.split('\n')
2948 f.write('\n'.join(lines) + '\n')
2950 if hasattr(self, "doc") and self.doc and self.doc.example:
2951 f.write('.SH EXAMPLE\n')
2954 lines = self.doc.example.split('\n')
2955 f.write('\n'.join(lines) + '\n')
2957 f.write('.SH SEE ALSO\n')
2958 if hasattr(self, "doc") and self.doc:
2959 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2960 if self.doc.example:
2961 see.append('.BR %s (%s)' % ('xcb-examples', section))
2962 for seename, seetype in sorted(self.doc.see.items()):
2963 if seetype == 'program':
2964 see.append('.BR %s (1)' % seename)
2965 elif seetype == 'event':
2966 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2967 elif seetype == 'request':
2968 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2969 elif seetype == 'function':
2970 see.append('.BR %s (%s)' % (seename, section))
2972 see.append('TODO: %s (type %s)' % (seename, seetype))
2973 f.write(',\n'.join(see) + '\n')
2974 f.write('.SH AUTHOR\n')
2975 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2979 def c_request(self, name):
2981 Exported function that handles request declarations.
2983 _c_type_setup(self, name, ('request',))
2986 # Cookie type declaration
2987 _c_cookie(self, name)
2990 _c_opcode(name, self.opcode)
2992 # Request structure declaration
2996 _c_type_setup(self.reply, name, ('reply',))
2997 # Reply structure definition
2998 _c_complex(self.reply)
2999 # Request prototypes
3000 has_fds = _c_reply_has_fds(self.reply)
3001 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3002 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3004 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3005 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3007 _c_accessors(self.reply, name + ('reply',), name)
3008 _c_reply(self, name)
3010 _c_reply_fds(self, name)
3012 # Request prototypes
3013 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3014 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3016 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3017 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3019 # We generate the manpage afterwards because _c_type_setup has been called.
3020 # TODO: what about aux helpers?
3021 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3022 _man_request(self, name, cookie_type, not self.reply, False)
3024 def c_event(self, name):
3026 Exported function that handles event declarations.
3029 # The generic event structure xcb_ge_event_t has the full_sequence field
3030 # at the 32byte boundary. That's why we've to inject this field into GE
3031 # events while generating the structure for them. Otherwise we would read
3032 # garbage (the internal full_sequence) when accessing normal event fields
3034 force_packed = False
3035 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3037 for field in self.fields:
3038 if field.type.size != None and field.type.nmemb != None:
3039 event_size += field.type.size * field.type.nmemb
3040 if event_size == 32:
3041 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3042 idx = self.fields.index(field)
3043 self.fields.insert(idx + 1, full_sequence)
3045 # If the event contains any 64-bit extended fields, they need
3046 # to remain aligned on a 64-bit boundary. Adding full_sequence
3047 # would normally break that; force the struct to be packed.
3048 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3051 _c_type_setup(self, name, ('event',))
3054 _c_opcode(name, self.opcodes[name])
3056 if self.name == name:
3057 # Structure definition
3058 _c_complex(self, force_packed)
3062 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3064 _man_event(self, name)
3066 def c_error(self, name):
3068 Exported function that handles error declarations.
3070 _c_type_setup(self, name, ('error',))
3073 _c_opcode(name, self.opcodes[name])
3075 if self.name == name:
3076 # Structure definition
3081 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3084 # Main routine starts here
3086 # Must create an "output" dictionary before any xcbgen imports.
3087 output = {'open' : c_open,
3089 'simple' : c_simple,
3091 'struct' : c_struct,
3093 'request' : c_request,
3098 # Boilerplate below this point
3100 # Check for the argument that specifies path to the xcbgen python package.
3102 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3103 except getopt.GetoptError as err:
3105 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3108 for (opt, arg) in opts:
3116 sys.path.insert(1, arg)
3119 sys.stdout.write('man_MANS = ')
3121 # Import the module class
3123 from xcbgen.state import Module
3124 from xcbgen.xtypes import *
3127 Failed to load the xcbgen Python package!
3128 Make sure that xcb/proto installed it on your Python path.
3129 If not, you will need to create a .pth file or define $PYTHONPATH
3131 Refer to the README file in xcb/proto for more info.
3135 # Ensure the man subdirectory exists
3138 except OSError as e:
3139 if e.errno != errno.EEXIST:
3142 # Parse the xml header
3143 module = Module(args[0], output)
3145 # Build type-registry and resolve type dependencies