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 # note: xcb_sumof() has only been defined for integers
1632 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1633 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1634 elif expr.op != None:
1635 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1636 ' ' + expr.op + ' ' +
1637 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1639 return 'xcb_popcount(' + lenexp + ')'
1643 def type_pad_type(type):
1648 def _c_accessors_field(self, field):
1650 Declares the accessor functions for a non-list field that follows a variable-length field.
1652 c_type = self.c_type
1654 # special case: switch
1655 switch_obj = self if self.is_switch else None
1656 if self.is_case_or_bitcase:
1657 switch_obj = self.parents[-1]
1658 if switch_obj is not None:
1659 c_type = switch_obj.c_type
1661 if field.type.is_simple:
1663 _hc('%s', field.c_field_type)
1664 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1665 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1667 if field.prev_varsized_field is None:
1668 _c(' return (%s *) (R + 1);', field.c_field_type)
1670 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1671 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1672 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1676 if field.type.is_switch and switch_obj is None:
1677 return_type = 'void *'
1679 return_type = '%s *' % field.c_field_type
1682 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1683 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1685 if field.prev_varsized_field is None:
1686 _c(' return (%s) (R + 1);', return_type)
1687 # note: the special case 'variable fields followed by fixed size fields'
1688 # is not of any consequence here, since the ordering gets
1689 # 'corrected' in the reply function
1691 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1692 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1693 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1697 def _c_accessors_list(self, field):
1699 Declares the accessor functions for a list field.
1700 Declares a direct-accessor function only if the list members are fixed size.
1701 Declares length and get-iterator functions always.
1704 def get_align_pad(field):
1705 prev = field.prev_varsized_field
1706 prev_prev = field.prev_varsized_field.prev_varsized_field
1708 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1709 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1715 c_type = self.c_type
1717 # special case: switch
1718 # in case of switch, 2 params have to be supplied to certain accessor functions:
1719 # 1. the anchestor object (request or reply)
1720 # 2. the (anchestor) switch object
1721 # the reason is that switch is either a child of a request/reply or nested in another switch,
1722 # so whenever we need to access a length field, we might need to refer to some anchestor type
1723 switch_obj = self if self.is_switch else None
1724 if self.is_case_or_bitcase:
1725 switch_obj = self.parents[-1]
1726 if switch_obj is not None:
1727 c_type = switch_obj.c_type
1731 parents = self.parents if hasattr(self, 'parents') else [self]
1732 # 'R': parents[0] is always the 'toplevel' container type
1733 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1734 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1735 # auxiliary object for 'R' parameters
1738 if switch_obj is not None:
1739 # now look where the fields are defined that are needed to evaluate
1740 # the switch expr, and store the parent objects in accessor_params and
1741 # the fields in switch_fields
1743 # 'S': name for the 'toplevel' switch
1744 toplevel_switch = parents[1]
1745 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1746 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1748 # initialize prefix for everything "below" S
1749 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1750 prefix = [(prefix_str, '->', toplevel_switch)]
1752 # look for fields in the remaining containers
1753 for p in parents[2:] + [self]:
1754 # the separator between parent and child is always '.' here,
1755 # because of nested switch statements
1756 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1757 prefix.append((p.name[-1], '.', p))
1758 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1760 # auxiliary object for 'S' parameter
1765 if list.member.fixed_size():
1766 idx = 1 if switch_obj is not None else 0
1768 _hc('%s *', field.c_field_type)
1770 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1771 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1774 if switch_obj is not None:
1775 _c(' return %s;', fields[field.c_field_name][0])
1776 elif field.prev_varsized_field is None:
1777 _c(' return (%s *) (R + 1);', field.c_field_type)
1779 (prev_varsized_field, align_pad) = get_align_pad(field)
1781 if align_pad is None:
1782 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1783 type_pad_type(field.first_field_after_varsized.type.c_type))
1785 _c(' xcb_generic_iterator_t prev = %s;',
1786 _c_iterator_get_end(prev_varsized_field, 'R'))
1787 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1788 field.c_field_type, align_pad, field.prev_varsized_offset)
1793 if switch_obj is not None:
1794 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1795 spacing = ' '*(len(field.c_length_name)+2)
1796 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1797 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1799 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1800 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1802 length = _c_accessor_get_expr(field.type.expr, fields)
1803 _c(' return %s;', length)
1806 if field.type.member.is_simple:
1808 _hc('xcb_generic_iterator_t')
1809 if switch_obj is not None:
1810 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1811 spacing = ' '*(len(field.c_end_name)+2)
1812 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1813 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1815 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1816 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1818 _c(' xcb_generic_iterator_t i;')
1820 param = 'R' if switch_obj is None else 'S'
1821 if switch_obj is not None:
1822 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1823 _c_accessor_get_expr(field.type.expr, fields))
1824 elif field.prev_varsized_field == None:
1825 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1826 _c_accessor_get_expr(field.type.expr, fields))
1828 _c(' xcb_generic_iterator_t child = %s;',
1829 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1830 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1831 _c_accessor_get_expr(field.type.expr, fields))
1834 _c(' i.index = (char *) i.data - (char *) %s;', param)
1840 _hc('%s', field.c_iterator_type)
1841 if switch_obj is not None:
1842 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1843 spacing = ' '*(len(field.c_iterator_name)+2)
1844 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1845 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1847 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1848 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1850 _c(' %s i;', field.c_iterator_type)
1853 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1855 if switch_obj is not None:
1857 _c(' i.data = %s;', fields[field.c_field_name][0])
1858 _c(' i.rem = %s;', length_expr_str)
1859 elif field.prev_varsized_field == None:
1861 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1863 (prev_varsized_field, align_pad) = get_align_pad(field)
1865 if align_pad is None:
1866 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1867 type_pad_type(field.c_field_type))
1869 _c(' xcb_generic_iterator_t prev = %s;',
1870 _c_iterator_get_end(prev_varsized_field, 'R'))
1872 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1873 field.c_field_type, align_pad)
1875 if switch_obj is None:
1876 _c(' i.rem = %s;', length_expr_str)
1877 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1881 def _c_accessors(self, name, base):
1883 Declares the accessor functions for the fields of a structure.
1885 # no accessors for switch itself -
1886 # switch always needs to be unpacked explicitly
1887 # if self.is_switch:
1891 for field in self.fields:
1892 if not field.type.is_pad:
1893 if _c_field_needs_list_accessor(field):
1894 _c_accessors_list(self, field)
1895 elif _c_field_needs_field_accessor(field):
1896 _c_accessors_field(self, field)
1898 def c_simple(self, name):
1900 Exported function that handles cardinal type declarations.
1901 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1903 _c_type_setup(self, name, ())
1905 if (self.name != name):
1910 _h('typedef %s %s;', _t(self.name), my_name)
1913 _c_iterator(self, name)
1915 def _c_complex(self, force_packed = False):
1917 Helper function for handling all structure types.
1918 Called for all structs, requests, replies, events, errors.
1923 _h(' * @brief %s', self.c_type)
1925 _h('typedef %s %s {', self.c_container, self.c_type)
1931 for field in self.fields:
1932 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1933 varfield = field.c_field_name
1936 struct_fields.append(field)
1938 for field in struct_fields:
1939 length = len(field.c_field_type)
1940 # account for '*' pointer_spec
1941 if not field.type.fixed_size() and not self.is_union:
1943 maxtypelen = max(maxtypelen, length)
1945 def _c_complex_field(self, field, space=''):
1946 if (field.type.fixed_size() or self.is_union or
1947 # in case of switch with switch children, don't make the field a pointer
1948 # necessary for unserialize to work
1949 (self.is_switch and field.type.is_switch)):
1950 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1951 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1953 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1954 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1956 if not self.is_switch:
1957 for field in struct_fields:
1958 _c_complex_field(self, field)
1960 for b in self.bitcases:
1965 for field in b.type.fields:
1966 _c_complex_field(self, field, space)
1968 _h(' } %s;', b.c_field_name)
1970 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1972 def c_struct(self, name):
1974 Exported function that handles structure declarations.
1976 _c_type_setup(self, name, ())
1978 _c_accessors(self, name, name)
1979 _c_iterator(self, name)
1981 def c_union(self, name):
1983 Exported function that handles union declarations.
1985 _c_type_setup(self, name, ())
1987 _c_iterator(self, name)
1989 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1991 Declares a request function.
1994 # Four stunningly confusing possibilities here:
1997 # ------------------------------
1999 # 0 flag CHECKED flag Normal Mode
2000 # void_cookie req_cookie
2001 # ------------------------------
2002 # "req_checked" "req_unchecked"
2003 # CHECKED flag 0 flag Abnormal Mode
2004 # void_cookie req_cookie
2005 # ------------------------------
2008 # Whether we are _checked or _unchecked
2009 checked = void and not regular
2010 unchecked = not void and not regular
2012 # What kind of cookie we return
2013 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2015 # What flag is passed to xcb_request
2016 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2019 if func_flags == '0':
2020 func_flags = 'XCB_REQUEST_REPLY_FDS'
2022 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2024 # Global extension id variable or NULL for xproto
2025 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2027 # What our function name is
2028 func_name = self.c_request_name if not aux else self.c_aux_name
2030 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2032 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2036 maxtypelen = len('xcb_connection_t')
2038 # special case: list with variable size elements
2039 list_with_var_size_elems = False
2041 for field in self.fields:
2043 # The field should appear as a call parameter
2044 param_fields.append(field)
2045 if field.wire and not field.auto:
2046 # We need to set the field up in the structure
2047 wire_fields.append(field)
2048 if field.type.c_need_serialize or field.type.c_need_sizeof:
2049 serial_fields.append(field)
2051 for field in param_fields:
2052 c_field_const_type = field.c_field_const_type
2053 if field.type.c_need_serialize and not aux:
2054 c_field_const_type = "const void"
2055 if len(c_field_const_type) > maxtypelen:
2056 maxtypelen = len(c_field_const_type)
2057 if field.type.is_list and not field.type.member.fixed_size():
2058 list_with_var_size_elems = True
2064 if hasattr(self, "doc") and self.doc:
2066 _h(' * @brief ' + self.doc.brief)
2068 _h(' * No brief doc yet')
2071 _h(' * @param c The connection')
2072 param_names = [f.c_field_name for f in param_fields]
2073 if hasattr(self, "doc") and self.doc:
2074 for field in param_fields:
2075 # XXX: hard-coded until we fix xproto.xml
2076 base_func_name = self.c_request_name if not aux else self.c_aux_name
2077 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2079 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2081 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2084 # XXX: why the 'xcb' prefix?
2085 key = ('xcb', field.enum)
2088 if namecount[tname] > 1:
2089 tname = _t(key + ('enum',))
2090 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2092 if self.doc and field.field_name in self.doc.fields:
2093 desc = self.doc.fields[field.field_name]
2094 for name in param_names:
2095 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2096 desc = desc.split("\n")
2097 desc = [line if line != '' else '\\n' for line in desc]
2098 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2099 # If there is no documentation yet, we simply don't generate an
2100 # @param tag. Doxygen will then warn about missing documentation.
2102 _h(' * @return A cookie')
2105 if hasattr(self, "doc") and self.doc:
2106 if self.doc.description:
2107 desc = self.doc.description
2108 for name in param_names:
2109 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2110 desc = desc.split("\n")
2111 _h(' * ' + "\n * ".join(desc))
2113 _h(' * No description yet')
2115 _h(' * Delivers a request to the X server.')
2118 _h(' * This form can be used only if the request will not cause')
2119 _h(' * a reply to be generated. Any returned error will be')
2120 _h(' * saved for handling by xcb_request_check().')
2122 _h(' * This form can be used only if the request will cause')
2123 _h(' * a reply to be generated. Any returned error will be')
2124 _h(' * placed in the event queue.')
2127 _hc('%s', cookie_type)
2129 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2130 comma = ',' if len(param_fields) else ');'
2131 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2132 comma = ',' if len(param_fields) else ')'
2133 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2135 func_spacing = ' ' * (len(func_name) + 2)
2136 count = len(param_fields)
2137 for field in param_fields:
2139 c_field_const_type = field.c_field_const_type
2140 c_pointer = field.c_pointer
2141 if field.type.c_need_serialize and not aux:
2142 c_field_const_type = "const void"
2144 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2145 comma = ',' if count else ');'
2146 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2147 spacing, c_pointer, field.c_field_name, comma)
2148 comma = ',' if count else ')'
2149 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2150 spacing, c_pointer, field.c_field_name, comma)
2153 if not self.c_var_followed_by_fixed_fields:
2154 for field in param_fields:
2155 if not field.type.fixed_size():
2157 if field.type.c_need_serialize:
2158 # _serialize() keeps track of padding automatically
2160 dimension = count + 2
2163 _c(' static const xcb_protocol_request_t xcb_req = {')
2164 _c(' /* count */ %d,', count)
2165 _c(' /* ext */ %s,', func_ext_global)
2166 _c(' /* opcode */ %s,', self.c_request_name.upper())
2167 _c(' /* isvoid */ %d', 1 if void else 0)
2171 _c(' struct iovec xcb_parts[%d];', dimension)
2172 _c(' %s xcb_ret;', func_cookie)
2173 _c(' %s xcb_out;', self.c_type)
2174 if self.c_var_followed_by_fixed_fields:
2175 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2176 _c(' void *xcb_aux = 0;')
2179 for idx, f in enumerate(serial_fields):
2181 _c(' void *xcb_aux%d = 0;' % (idx))
2182 if list_with_var_size_elems:
2183 _c(' unsigned int i;')
2184 _c(' unsigned int xcb_tmp_len;')
2185 _c(' char *xcb_tmp;')
2187 # simple request call tracing
2188 # _c(' printf("in function %s\\n");' % func_name)
2191 for field in wire_fields:
2192 if field.type.fixed_size():
2193 if field.type.is_expr:
2194 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2195 elif field.type.is_pad:
2196 if field.type.nmemb == 1:
2197 _c(' xcb_out.%s = 0;', field.c_field_name)
2199 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2201 if field.type.nmemb == 1:
2202 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2204 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2206 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2207 serialize_args = get_serialize_params(context, type_obj,
2210 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2212 # calls in order to free dyn. all. memory
2216 if not self.c_var_followed_by_fixed_fields:
2217 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2218 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2219 _c(' xcb_parts[3].iov_base = 0;')
2220 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2224 for field in param_fields:
2225 if not field.type.fixed_size():
2226 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2227 # default: simple cast to char *
2228 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2229 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2230 if field.type.is_list:
2231 if field.type.member.fixed_size():
2232 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2233 _c_accessor_get_expr(field.type.expr, None),
2234 field.type.member.c_wiretype)
2236 list_length = _c_accessor_get_expr(field.type.expr, None)
2239 _c(" xcb_parts[%d].iov_len = 0;" % count)
2240 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2241 _c(" for(i=0; i<%s; i++) {" % list_length)
2242 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2243 (field.type.c_sizeof_name))
2244 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2245 _c(" xcb_tmp += xcb_tmp_len;")
2248 # not supposed to happen
2249 raise Exception("unhandled variable size field %s" % field.c_field_name)
2252 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2253 idx = serial_fields.index(field)
2254 aux_var = '&xcb_aux%d' % idx
2255 context = 'serialize' if aux else 'sizeof'
2256 _c(' xcb_parts[%d].iov_len =', count)
2258 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2259 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2260 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2261 free_calls.append(' free(xcb_aux%d);' % idx)
2263 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2264 func_name = field.type.c_sizeof_name
2265 _c(' %s (%s);', func_name, serialize_args)
2268 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2269 # the _serialize() function keeps track of padding automatically
2270 _c(' xcb_parts[%d].iov_base = 0;', count)
2271 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2274 # elif self.c_var_followed_by_fixed_fields:
2276 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2277 # request header: opcodes + length
2278 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2281 buffer_var = '&xcb_aux'
2282 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2283 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2284 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2285 free_calls.append(' free(xcb_aux);')
2286 # no padding necessary - _serialize() keeps track of padding automatically
2289 for field in param_fields:
2291 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2293 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2295 # free dyn. all. data, if any
2296 for f in free_calls:
2298 _c(' return xcb_ret;')
2301 def _c_reply(self, name):
2303 Declares the function that returns the reply structure.
2305 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2306 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2307 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2309 # check if _unserialize() has to be called for any field
2310 def look_for_special_cases(complex_obj):
2311 unserialize_fields = []
2312 # no unserialize call in case of switch
2313 if not complex_obj.is_switch:
2314 for field in complex_obj.fields:
2315 # three cases: 1. field with special case
2316 # 2. container that contains special case field
2317 # 3. list with special case elements
2318 if field.type.c_var_followed_by_fixed_fields:
2319 unserialize_fields.append(field)
2320 elif field.type.is_container:
2321 unserialize_fields += look_for_special_cases(field.type)
2322 elif field.type.is_list:
2323 if field.type.member.c_var_followed_by_fixed_fields:
2324 unserialize_fields.append(field)
2325 if field.type.member.is_container:
2326 unserialize_fields += look_for_special_cases(field.type.member)
2327 return unserialize_fields
2329 unserialize_fields = look_for_special_cases(self.reply)
2333 _h(' * Return the reply')
2334 _h(' * @param c The connection')
2335 _h(' * @param cookie The cookie')
2336 _h(' * @param e The xcb_generic_error_t supplied')
2338 _h(' * Returns the reply of the request asked by')
2340 _h(' * The parameter @p e supplied to this function must be NULL if')
2341 _h(' * %s(). is used.', self.c_unchecked_name)
2342 _h(' * Otherwise, it stores the error if any.')
2344 _h(' * The returned value must be freed by the caller using free().')
2347 _hc('%s *', self.c_reply_type)
2348 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2349 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2350 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2351 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2354 if len(unserialize_fields)>0:
2355 # certain variable size fields need to be unserialized explicitly
2356 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2357 self.c_reply_type, self.c_reply_type)
2359 for field in unserialize_fields:
2360 if field.type.is_list:
2361 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2362 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2363 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2365 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2366 # call _unserialize(), using the reply as source and target buffer
2367 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2368 for field in unserialize_fields:
2369 if field.type.is_list:
2370 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2371 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2372 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2373 field.c_field_name, field.c_field_name)
2374 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2376 # return the transformed reply
2377 _c(' return reply;')
2380 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2384 def _c_reply_has_fds(self):
2385 for field in self.fields:
2390 def _c_reply_fds(self, name):
2392 Declares the function that returns fds related to the reply.
2394 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2395 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2398 _h(' * Return the reply fds')
2399 _h(' * @param c The connection')
2400 _h(' * @param reply The reply')
2402 _h(' * Returns the array of reply fds of the request asked by')
2404 _h(' * The returned value must be freed by the caller using free().')
2408 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2409 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2410 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2413 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2418 def _c_opcode(name, opcode):
2420 Declares the opcode define for requests, events, and errors.
2424 _h('/** Opcode for %s. */', _n(name))
2425 _h('#define %s %s', _n(name).upper(), opcode)
2427 def _c_cookie(self, name):
2429 Declares the cookie type for a non-void request.
2434 _h(' * @brief %s', self.c_cookie_type)
2436 _h('typedef struct %s {', self.c_cookie_type)
2437 _h(' unsigned int sequence; /**< */')
2438 _h('} %s;', self.c_cookie_type)
2440 def _man_request(self, name, cookie_type, void, aux):
2441 param_fields = [f for f in self.fields if f.visible]
2443 func_name = self.c_request_name if not aux else self.c_aux_name
2445 def create_link(linkname):
2446 name = 'man/%s.%s' % (linkname, section)
2448 sys.stdout.write(name)
2450 f.write('.so man%s/%s.%s' % (section, func_name, section))
2454 sys.stdout.write('man/%s.%s ' % (func_name, section))
2455 # Our CWD is src/, so this will end up in src/man/
2456 f = open('man/%s.%s' % (func_name, section), 'w')
2457 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2458 # Left-adjust instead of adjusting to both sides
2460 f.write('.SH NAME\n')
2461 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2462 f.write('%s \\- %s\n' % (func_name, brief))
2463 f.write('.SH SYNOPSIS\n')
2464 # Don't split words (hyphenate)
2466 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2468 # function prototypes
2470 count = len(param_fields)
2471 for field in param_fields:
2473 c_field_const_type = field.c_field_const_type
2474 c_pointer = field.c_pointer
2475 if c_pointer == ' ':
2477 if field.type.c_need_serialize and not aux:
2478 c_field_const_type = "const void"
2480 comma = ', ' if count else ');'
2481 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2483 f.write('.SS Request function\n')
2485 base_func_name = self.c_request_name if not aux else self.c_aux_name
2486 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2487 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2490 f.write('.SS Reply datastructure\n')
2493 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2497 for field in self.reply.fields:
2498 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2501 struct_fields.append(field)
2503 for field in struct_fields:
2504 length = len(field.c_field_type)
2505 # account for '*' pointer_spec
2506 if not field.type.fixed_size():
2508 maxtypelen = max(maxtypelen, length)
2510 def _c_complex_field(self, field, space=''):
2511 if (field.type.fixed_size() or
2512 # in case of switch with switch children, don't make the field a pointer
2513 # necessary for unserialize to work
2514 (self.is_switch and field.type.is_switch)):
2515 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2516 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2518 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2519 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2520 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2522 if not self.is_switch:
2523 for field in struct_fields:
2524 _c_complex_field(self, field)
2526 for b in self.bitcases:
2530 for field in b.type.fields:
2531 _c_complex_field(self, field, space)
2533 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2536 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2539 f.write('.SS Reply function\n')
2541 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2542 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2543 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2544 create_link('%s' % self.c_reply_name)
2546 has_accessors = False
2547 for field in self.reply.fields:
2548 if field.type.is_list and not field.type.fixed_size():
2549 has_accessors = True
2550 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2551 has_accessors = True
2554 f.write('.SS Reply accessors\n')
2556 def _c_accessors_field(self, field):
2558 Declares the accessor functions for a non-list field that follows a variable-length field.
2560 c_type = self.c_type
2562 # special case: switch
2563 switch_obj = self if self.is_switch else None
2564 if self.is_case_or_bitcase:
2565 switch_obj = self.parents[-1]
2566 if switch_obj is not None:
2567 c_type = switch_obj.c_type
2569 if field.type.is_simple:
2570 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2571 create_link('%s' % field.c_accessor_name)
2573 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2574 create_link('%s' % field.c_accessor_name)
2576 def _c_accessors_list(self, field):
2578 Declares the accessor functions for a list field.
2579 Declares a direct-accessor function only if the list members are fixed size.
2580 Declares length and get-iterator functions always.
2583 c_type = self.reply.c_type
2585 # special case: switch
2586 # in case of switch, 2 params have to be supplied to certain accessor functions:
2587 # 1. the anchestor object (request or reply)
2588 # 2. the (anchestor) switch object
2589 # the reason is that switch is either a child of a request/reply or nested in another switch,
2590 # so whenever we need to access a length field, we might need to refer to some anchestor type
2591 switch_obj = self if self.is_switch else None
2592 if self.is_case_or_bitcase:
2593 switch_obj = self.parents[-1]
2594 if switch_obj is not None:
2595 c_type = switch_obj.c_type
2599 parents = self.parents if hasattr(self, 'parents') else [self]
2600 # 'R': parents[0] is always the 'toplevel' container type
2601 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2602 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2603 # auxiliary object for 'R' parameters
2606 if switch_obj is not None:
2607 # now look where the fields are defined that are needed to evaluate
2608 # the switch expr, and store the parent objects in accessor_params and
2609 # the fields in switch_fields
2611 # 'S': name for the 'toplevel' switch
2612 toplevel_switch = parents[1]
2613 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2614 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2616 # initialize prefix for everything "below" S
2617 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2618 prefix = [(prefix_str, '->', toplevel_switch)]
2620 # look for fields in the remaining containers
2621 for p in parents[2:] + [self]:
2622 # the separator between parent and child is always '.' here,
2623 # because of nested switch statements
2624 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2625 prefix.append((p.name[-1], '.', p))
2626 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2628 # auxiliary object for 'S' parameter
2631 if list.member.fixed_size():
2632 idx = 1 if switch_obj is not None else 0
2634 f.write('%s *\\fB%s\\fP(%s);\n' %
2635 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2636 create_link('%s' % field.c_accessor_name)
2639 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2640 (field.c_length_name, c_type))
2641 create_link('%s' % field.c_length_name)
2643 if field.type.member.is_simple:
2645 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2646 (field.c_end_name, c_type))
2647 create_link('%s' % field.c_end_name)
2650 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2651 (field.c_iterator_type, field.c_iterator_name,
2653 create_link('%s' % field.c_iterator_name)
2655 for field in self.reply.fields:
2656 if field.type.is_list and not field.type.fixed_size():
2657 _c_accessors_list(self, field)
2658 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2659 _c_accessors_field(self, field)
2663 # Re-enable hyphenation and adjusting to both sides
2666 # argument reference
2667 f.write('.SH REQUEST ARGUMENTS\n')
2668 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2669 f.write('The XCB connection to X11.\n')
2670 for field in param_fields:
2671 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2672 printed_enum = False
2673 # XXX: hard-coded until we fix xproto.xml
2674 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2676 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2678 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2680 if hasattr(field, "enum") and field.enum:
2681 # XXX: why the 'xcb' prefix?
2682 key = ('xcb', field.enum)
2684 f.write('One of the following values:\n')
2687 count = len(enum.values)
2688 for (enam, eval) in enum.values:
2690 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2691 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2692 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2693 f.write('%s\n' % desc)
2695 f.write('TODO: NOT YET DOCUMENTED.\n')
2700 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2701 desc = self.doc.fields[field.field_name]
2702 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2705 f.write('%s\n' % desc)
2707 f.write('TODO: NOT YET DOCUMENTED.\n')
2713 f.write('.SH REPLY FIELDS\n')
2714 # These fields are present in every reply:
2715 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2716 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2717 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2718 'be used to tell replies apart from each other.\n') %
2719 _n(self.reply.name).upper())
2720 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2721 f.write('The sequence number of the last request processed by the X11 server.\n')
2722 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2723 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2724 for field in self.reply.fields:
2725 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2726 field.c_field_name.startswith('pad')):
2729 if field.type.is_list and not field.type.fixed_size():
2731 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2733 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2734 printed_enum = False
2735 if hasattr(field, "enum") and field.enum:
2736 # XXX: why the 'xcb' prefix?
2737 key = ('xcb', field.enum)
2739 f.write('One of the following values:\n')
2742 count = len(enum.values)
2743 for (enam, eval) in enum.values:
2745 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2746 if enum.doc and enam in enum.doc.fields:
2747 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2748 f.write('%s\n' % desc)
2750 f.write('TODO: NOT YET DOCUMENTED.\n')
2755 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2756 desc = self.reply.doc.fields[field.field_name]
2757 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2760 f.write('%s\n' % desc)
2762 f.write('TODO: NOT YET DOCUMENTED.\n')
2769 f.write('.SH DESCRIPTION\n')
2770 if hasattr(self, "doc") and self.doc and self.doc.description:
2771 desc = self.doc.description
2772 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2773 lines = desc.split('\n')
2774 f.write('\n'.join(lines) + '\n')
2776 f.write('.SH RETURN VALUE\n')
2778 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2779 'have to be handled in the event loop.\n\nIf you want to '
2780 'handle errors directly with \\fIxcb_request_check\\fP '
2781 'instead, use \\fI%s_checked\\fP. See '
2782 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2784 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2785 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2786 'handle errors in the event loop instead, use '
2787 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2789 (cookie_type, self.c_reply_name, base_func_name, section))
2790 f.write('.SH ERRORS\n')
2791 if hasattr(self, "doc") and self.doc:
2792 for errtype, errtext in sorted(self.doc.errors.items()):
2793 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2794 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2795 f.write('%s\n' % (errtext))
2796 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2797 f.write('This request does never generate any errors.\n')
2798 if hasattr(self, "doc") and self.doc and self.doc.example:
2799 f.write('.SH EXAMPLE\n')
2802 lines = self.doc.example.split('\n')
2803 f.write('\n'.join(lines) + '\n')
2805 f.write('.SH SEE ALSO\n')
2806 if hasattr(self, "doc") and self.doc:
2807 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2808 if self.doc.example:
2809 see.append('.BR %s (%s)' % ('xcb-examples', section))
2810 for seename, seetype in sorted(self.doc.see.items()):
2811 if seetype == 'program':
2812 see.append('.BR %s (1)' % seename)
2813 elif seetype == 'event':
2814 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2815 elif seetype == 'request':
2816 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2817 elif seetype == 'function':
2818 see.append('.BR %s (%s)' % (seename, section))
2820 see.append('TODO: %s (type %s)' % (seename, seetype))
2821 f.write(',\n'.join(see) + '\n')
2822 f.write('.SH AUTHOR\n')
2823 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2826 def _man_event(self, name):
2828 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2829 # Our CWD is src/, so this will end up in src/man/
2830 f = open('man/%s.%s' % (self.c_type, section), 'w')
2831 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2832 # Left-adjust instead of adjusting to both sides
2834 f.write('.SH NAME\n')
2835 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2836 f.write('%s \\- %s\n' % (self.c_type, brief))
2837 f.write('.SH SYNOPSIS\n')
2838 # Don't split words (hyphenate)
2840 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2843 f.write('.SS Event datastructure\n')
2846 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2850 for field in self.fields:
2851 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2854 struct_fields.append(field)
2856 for field in struct_fields:
2857 length = len(field.c_field_type)
2858 # account for '*' pointer_spec
2859 if not field.type.fixed_size():
2861 maxtypelen = max(maxtypelen, length)
2863 def _c_complex_field(self, field, space=''):
2864 if (field.type.fixed_size() or
2865 # in case of switch with switch children, don't make the field a pointer
2866 # necessary for unserialize to work
2867 (self.is_switch and field.type.is_switch)):
2868 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2869 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2871 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2873 if not self.is_switch:
2874 for field in struct_fields:
2875 _c_complex_field(self, field)
2877 for b in self.bitcases:
2881 for field in b.type.fields:
2882 _c_complex_field(self, field, space)
2884 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2887 f.write('} \\fB%s\\fP;\n' % self.c_type)
2892 # Re-enable hyphenation and adjusting to both sides
2895 # argument reference
2896 f.write('.SH EVENT FIELDS\n')
2897 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2898 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2899 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2900 'to tell events apart from each other.\n') % _n(name).upper())
2901 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2902 f.write('The sequence number of the last request processed by the X11 server.\n')
2904 if not self.is_switch:
2905 for field in struct_fields:
2906 # Skip the fields which every event has, we already documented
2908 if field.c_field_name in ('response_type', 'sequence'):
2910 if isinstance(field.type, PadType):
2912 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2913 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2914 desc = self.doc.fields[field.field_name]
2915 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2916 f.write('%s\n' % desc)
2918 f.write('NOT YET DOCUMENTED.\n')
2921 f.write('.SH DESCRIPTION\n')
2922 if hasattr(self, "doc") and self.doc and self.doc.description:
2923 desc = self.doc.description
2924 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2925 lines = desc.split('\n')
2926 f.write('\n'.join(lines) + '\n')
2928 if hasattr(self, "doc") and self.doc and self.doc.example:
2929 f.write('.SH EXAMPLE\n')
2932 lines = self.doc.example.split('\n')
2933 f.write('\n'.join(lines) + '\n')
2935 f.write('.SH SEE ALSO\n')
2936 if hasattr(self, "doc") and self.doc:
2937 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2938 if self.doc.example:
2939 see.append('.BR %s (%s)' % ('xcb-examples', section))
2940 for seename, seetype in sorted(self.doc.see.items()):
2941 if seetype == 'program':
2942 see.append('.BR %s (1)' % seename)
2943 elif seetype == 'event':
2944 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2945 elif seetype == 'request':
2946 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2947 elif seetype == 'function':
2948 see.append('.BR %s (%s)' % (seename, section))
2950 see.append('TODO: %s (type %s)' % (seename, seetype))
2951 f.write(',\n'.join(see) + '\n')
2952 f.write('.SH AUTHOR\n')
2953 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2957 def c_request(self, name):
2959 Exported function that handles request declarations.
2961 _c_type_setup(self, name, ('request',))
2964 # Cookie type declaration
2965 _c_cookie(self, name)
2968 _c_opcode(name, self.opcode)
2970 # Request structure declaration
2974 _c_type_setup(self.reply, name, ('reply',))
2975 # Reply structure definition
2976 _c_complex(self.reply)
2977 # Request prototypes
2978 has_fds = _c_reply_has_fds(self.reply)
2979 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2980 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2982 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2983 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2985 _c_accessors(self.reply, name + ('reply',), name)
2986 _c_reply(self, name)
2988 _c_reply_fds(self, name)
2990 # Request prototypes
2991 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2992 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2994 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2995 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2997 # We generate the manpage afterwards because _c_type_setup has been called.
2998 # TODO: what about aux helpers?
2999 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3000 _man_request(self, name, cookie_type, not self.reply, False)
3002 def c_event(self, name):
3004 Exported function that handles event declarations.
3007 # The generic event structure xcb_ge_event_t has the full_sequence field
3008 # at the 32byte boundary. That's why we've to inject this field into GE
3009 # events while generating the structure for them. Otherwise we would read
3010 # garbage (the internal full_sequence) when accessing normal event fields
3012 force_packed = False
3013 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3015 for field in self.fields:
3016 if field.type.size != None and field.type.nmemb != None:
3017 event_size += field.type.size * field.type.nmemb
3018 if event_size == 32:
3019 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3020 idx = self.fields.index(field)
3021 self.fields.insert(idx + 1, full_sequence)
3023 # If the event contains any 64-bit extended fields, they need
3024 # to remain aligned on a 64-bit boundary. Adding full_sequence
3025 # would normally break that; force the struct to be packed.
3026 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3029 _c_type_setup(self, name, ('event',))
3032 _c_opcode(name, self.opcodes[name])
3034 if self.name == name:
3035 # Structure definition
3036 _c_complex(self, force_packed)
3040 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3042 _man_event(self, name)
3044 def c_error(self, name):
3046 Exported function that handles error declarations.
3048 _c_type_setup(self, name, ('error',))
3051 _c_opcode(name, self.opcodes[name])
3053 if self.name == name:
3054 # Structure definition
3059 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3062 # Main routine starts here
3064 # Must create an "output" dictionary before any xcbgen imports.
3065 output = {'open' : c_open,
3067 'simple' : c_simple,
3069 'struct' : c_struct,
3071 'request' : c_request,
3076 # Boilerplate below this point
3078 # Check for the argument that specifies path to the xcbgen python package.
3080 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3081 except getopt.GetoptError as err:
3083 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3086 for (opt, arg) in opts:
3094 sys.path.insert(1, arg)
3097 sys.stdout.write('man_MANS = ')
3099 # Import the module class
3101 from xcbgen.state import Module
3102 from xcbgen.xtypes import *
3105 Failed to load the xcbgen Python package!
3106 Make sure that xcb/proto installed it on your Python path.
3107 If not, you will need to create a .pth file or define $PYTHONPATH
3109 Refer to the README file in xcb/proto for more info.
3113 # Ensure the man subdirectory exists
3116 except OSError as e:
3117 if e.errno != errno.EEXIST:
3120 # Parse the xml header
3121 module = Module(args[0], output)
3123 # Build type-registry and resolve type dependencies