2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
12 # Jump to the bottom of this file for the main routine
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
20 _cplusplus_annoyances = {'class' : '_class',
23 _c_keywords = {'default' : '_default'}
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
37 # keeps enum objects so that we can refer to them when generating manpages.
44 Writes the given line to the header file.
46 _hlines[_hlevel].append(fmt % args)
50 Writes the given line to the source file.
52 _clines[_clevel].append(fmt % args)
56 Writes the given line to both the header and source files.
61 def _c_wr_stringlist(indent, strlist):
63 Writes the given list of strings to the source file.
64 Each line is prepended by the indent string
67 _c("%s%s", indent, str)
70 class PreCode(object):
72 For pre-code generated by expression generation
73 (for example, the for-loop of a sumof)
74 This has to account for recursiveness of the expression
75 generation, i.e., there may be pre-code for pre-code.
76 Therefore this is implemented as a stack of lists of lines.
78 If redirection is switched on, then all output is collected in
79 self.redirect_code and self.redirect_tempvars instead of
80 being sent to the output via _h und _c.
83 self.nesting_level = 0
86 self.redirect_code = None
87 self.redirect_tempvars = None
89 self.indent_stack = []
93 # start and end of pre-code blocks
95 self.nesting_level += 1
98 self.nesting_level -= 1
99 if self.nesting_level == 0:
100 # lowest pre-code level is finished -> output to source
101 if self.redirect_tempvars is None:
102 _c_wr_stringlist('', self.tempvars)
105 self.redirect_tempvars.extend(self.tempvars)
107 if self.redirect_code == None:
108 _c_wr_stringlist('', self.codelines)
111 self.redirect_code.extend(self.codelines)
115 def output_tempvars(self):
116 if self.redirect_code == None:
117 _c_wr_stringlist('', self.tempvars)
121 def code(self, fmt, *args):
122 self.codelines.append(self.indent_str + fmt % args)
124 def tempvar(self, fmt, *args):
125 self.tempvars.append(' ' + (fmt % args))
127 # get a unique name for a temporary variable
128 def get_tempvarname(self):
129 self.tempvar_num += 1
130 return "xcb_pre_tmp_%d" % self.tempvar_num
134 def push_indent(self, indentstr):
135 self.indent_stack.append(self.indent_str)
136 self.indent_str = indentstr
138 def push_addindent(self, indent_add_str):
139 self.push_indent(self.indent_str + indent_add_str)
142 self.push_addindent(' ')
144 def pop_indent(self):
145 self.indent_str = self.indent_stack.pop()
147 # redirection to lists
148 def redirect_start(self, redirect_code, redirect_tempvars=None):
149 self.redirect_code = redirect_code
150 self.redirect_tempvars = redirect_tempvars
151 if redirect_tempvars is not None:
154 def redirect_end(self):
155 self.redirect_code = None
156 self.redirect_tempvars = None
158 # global PreCode handler
162 # XXX See if this level thing is really necessary.
163 def _h_setlevel(idx):
165 Changes the array that header lines are written to.
166 Supports writing different sections of the header file.
169 while len(_hlines) <= idx:
173 def _c_setlevel(idx):
175 Changes the array that source lines are written to.
176 Supports writing to different sections of the source file.
179 while len(_clines) <= idx:
185 Does C-name conversion on a single string fragment.
186 Uses a regexp with some hard-coded special cases.
188 if str in _cname_special_cases:
189 return _cname_special_cases[str]
191 split = _cname_re.finditer(str)
192 name_parts = [match.group(0) for match in split]
193 return '_'.join(name_parts)
197 Checks for certain C++ reserved words and fixes them.
199 if str in _cplusplus_annoyances:
200 return _cplusplus_annoyances[str]
201 elif str in _c_keywords:
202 return _c_keywords[str]
208 Does C-name conversion on an extension name.
209 Has some additional special cases on top of _n_item.
211 if str in _extension_special_cases:
212 return _n_item(str).lower()
218 Does C-name conversion on a tuple of strings.
219 Different behavior depending on length of tuple, extension/not extension, etc.
220 Basically C-name converts the individual pieces, then joins with underscores.
225 parts = [list[0], _n_item(list[1])]
227 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
229 parts = [list[0]] + [_n_item(i) for i in list[1:]]
230 return '_'.join(parts).lower()
234 Does C-name conversion on a tuple of strings representing a type.
235 Same as _n but adds a "_t" on the end.
240 parts = [list[0], _n_item(list[1]), 't']
242 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
244 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
245 return '_'.join(parts).lower()
250 Exported function that handles module open.
251 Opens the files and writes out the auto-generated comment, header file includes, etc.
255 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
257 # Build the type-name collision avoidance table used by c_enum
258 build_collision_table()
264 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
265 _hc(' * Edit at your peril.')
270 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
271 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
275 _h('#ifndef __%s_H', _ns.header.upper())
276 _h('#define __%s_H', _ns.header.upper())
278 _h('#include "xcb.h"')
280 _c('#ifdef HAVE_CONFIG_H')
281 _c('#include "config.h"')
283 _c('#include <stdlib.h>')
284 _c('#include <string.h>')
285 _c('#include <assert.h>')
286 _c('#include <stddef.h> /* for offsetof() */')
287 _c('#include "xcbext.h"')
288 _c('#include "%s.h"', _ns.header)
291 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
294 for (n, h) in self.direct_imports:
295 _hc('#include "%s.h"', h)
298 _h('#ifdef __cplusplus')
304 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
305 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
307 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
310 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
314 Exported function that handles module close.
315 Writes out all the stored content lines, then closes the files.
322 _h('#ifdef __cplusplus')
334 hfile = open('%s.h' % _ns.header, 'w')
342 cfile = open('%s.c' % _ns.header, 'w')
349 def build_collision_table():
353 for v in module.types.values():
355 namecount[name] = (namecount.get(name) or 0) + 1
357 def c_enum(self, name):
359 Exported function that handles enum declarations.
365 if namecount[tname] > 1:
366 tname = _t(name + ('enum',))
370 _h('typedef enum %s {', tname)
372 count = len(self.values)
374 for (enam, eval) in self.values:
376 equals = ' = ' if eval != '' else ''
377 comma = ',' if count > 0 else ''
379 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
380 doc = '\n/**< %s */\n' % self.doc.fields[enam]
381 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
385 def _c_type_setup(self, name, postfix):
387 Sets up all the C-related state by adding additional data fields to
388 all Field and Type objects. Here is where we figure out most of our
389 variable and function names.
391 Recurses into child fields and list member types.
393 # Do all the various names in advance
394 self.c_type = _t(name + postfix)
395 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
397 self.c_iterator_type = _t(name + ('iterator',))
398 self.c_next_name = _n(name + ('next',))
399 self.c_end_name = _n(name + ('end',))
401 self.c_request_name = _n(name)
402 self.c_checked_name = _n(name + ('checked',))
403 self.c_unchecked_name = _n(name + ('unchecked',))
404 self.c_reply_name = _n(name + ('reply',))
405 self.c_reply_type = _t(name + ('reply',))
406 self.c_cookie_type = _t(name + ('cookie',))
407 self.c_reply_fds_name = _n(name + ('reply_fds',))
409 self.c_need_aux = False
410 self.c_need_serialize = False
411 self.c_need_sizeof = False
413 self.c_aux_name = _n(name + ('aux',))
414 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
415 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
416 self.c_serialize_name = _n(name + ('serialize',))
417 self.c_unserialize_name = _n(name + ('unserialize',))
418 self.c_unpack_name = _n(name + ('unpack',))
419 self.c_sizeof_name = _n(name + ('sizeof',))
421 # special case: structs where variable size fields are followed by fixed size fields
422 self.c_var_followed_by_fixed_fields = False
425 self.c_need_serialize = True
426 self.c_container = 'struct'
427 for bitcase in self.bitcases:
428 bitcase.c_field_name = _cpp(bitcase.field_name)
429 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
430 _c_type_setup(bitcase.type, bitcase_name, ())
432 elif self.is_container:
434 self.c_container = 'union' if self.is_union else 'struct'
435 prev_varsized_field = None
436 prev_varsized_offset = 0
437 first_field_after_varsized = None
439 for field in self.fields:
440 field.c_field_type = _t(field.field_type)
441 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
442 field.c_field_name = _cpp(field.field_name)
443 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
444 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
446 # correct the c_pointer field for variable size non-list types
447 if not field.type.fixed_size() and field.c_pointer == ' ':
448 field.c_pointer = '*'
449 if field.type.is_list and not field.type.member.fixed_size():
450 field.c_pointer = '*'
452 if field.type.is_switch:
453 field.c_pointer = '*'
454 field.c_field_const_type = 'const ' + field.c_field_type
455 self.c_need_aux = True
457 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
458 self.c_need_sizeof = True
460 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
461 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
462 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
463 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
464 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
466 field.prev_varsized_field = prev_varsized_field
467 field.prev_varsized_offset = prev_varsized_offset
469 if prev_varsized_offset == 0:
470 first_field_after_varsized = field
471 field.first_field_after_varsized = first_field_after_varsized
473 if field.type.fixed_size():
474 prev_varsized_offset += field.type.size
475 # special case: intermixed fixed and variable size fields
476 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
477 if not self.is_union:
478 self.c_need_serialize = True
479 self.c_var_followed_by_fixed_fields = True
481 self.last_varsized_field = field
482 prev_varsized_field = field
483 prev_varsized_offset = 0
485 if self.c_var_followed_by_fixed_fields:
486 if field.type.fixed_size():
487 field.prev_varsized_field = None
489 # recurse into this field this has to be done here, i.e.,
490 # after the field has been set up. Otherwise the function
491 # _c_helper_fieldaccess_expr will produce garbage or crash
492 _c_type_setup(field.type, field.field_type, ())
493 if field.type.is_list:
494 _c_type_setup(field.type.member, field.field_type, ())
495 if (field.type.nmemb is None):
496 self.c_need_sizeof = True
498 if self.c_need_serialize:
499 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
500 self.c_need_sizeof = True
502 # as switch does never appear at toplevel,
503 # continue here with type construction
505 if self.c_type not in finished_switch:
506 finished_switch.append(self.c_type)
507 # special: switch C structs get pointer fields for variable-sized members
509 for bitcase in self.bitcases:
510 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
511 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
512 # no list with switch as element, so no call to
513 # _c_iterator(field.type, field_name) necessary
515 if not self.is_case_or_bitcase:
516 if self.c_need_serialize:
517 if self.c_serialize_name not in finished_serializers:
518 finished_serializers.append(self.c_serialize_name)
519 _c_serialize('serialize', self)
521 # _unpack() and _unserialize() are only needed for special cases:
523 # special cases -> unserialize
524 if self.is_switch or self.c_var_followed_by_fixed_fields:
525 _c_serialize('unserialize', self)
527 if self.c_need_sizeof:
528 if self.c_sizeof_name not in finished_sizeof:
529 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
530 finished_sizeof.append(self.c_sizeof_name)
531 _c_serialize('sizeof', self)
534 # Functions for querying field properties
535 def _c_field_needs_list_accessor(field):
536 return field.type.is_list and not field.type.fixed_size()
538 def _c_field_needs_field_accessor(field):
539 if field.type.is_list:
542 return (field.prev_varsized_field is not None or
543 not field.type.fixed_size())
545 def _c_field_needs_accessor(field):
546 return (_c_field_needs_list_accessor(field) or
547 _c_field_needs_field_accessor(field))
549 def _c_field_is_member_of_case_or_bitcase(field):
550 return field.parent and field.parent.is_case_or_bitcase
552 def _c_helper_fieldaccess_expr(prefix, field=None):
554 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555 representing a valid 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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(prefix)
1073 if context in ('unserialize', 'unpack', 'sizeof'):
1075 var_field_name = 'xcb_tmp'
1077 # special case: intermixed fixed and variable size fields
1078 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1079 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1080 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1081 # special case: switch
1082 if 'unpack' == context:
1083 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1085 elif 'serialize' == context:
1086 # variable size fields appear as parameters to _serialize() if the
1087 # 'toplevel' container is not a switch
1088 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1089 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1090 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1094 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1096 if field.type.is_list:
1098 # in any context, list is already a pointer, so the default assignment is ok
1099 code_lines.append("%s%s" % (space, value))
1101 length = _c_serialize_helper_list_field(context, self, field,
1102 code_lines, temp_vars,
1105 elif field.type.is_switch:
1107 if context == 'serialize':
1108 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1109 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1110 length = _c_serialize_helper_switch_field(context, self, field,
1111 'xcb_parts[xcb_parts_idx].iov_base',
1115 # in all remaining special cases - call _sizeof()
1116 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1118 return (value, length)
1119 # _c_serialize_helper_fields_variable_size
1121 def _c_serialize_helper_fields(context, self,
1122 code_lines, temp_vars,
1123 space, prefix, is_case_or_bitcase):
1125 need_padding = False
1126 prev_field_was_variable = False
1128 _c_pre.push_indent(space + ' ')
1130 for field in self.fields:
1131 if not field.visible:
1132 if not ((field.wire and not field.auto) or 'unserialize' == context):
1135 # switch/bitcase: fixed size fields must be considered explicitly
1136 if field.type.fixed_size():
1137 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1138 if prev_field_was_variable and need_padding:
1140 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1141 # self.c_var_followed_by_fixed_fields)
1142 prev_field_was_variable = False
1144 # prefix for fixed size fields
1145 fixed_prefix = prefix
1147 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1148 code_lines, temp_vars,
1149 space, fixed_prefix)
1153 # fields with variable size
1155 if field.type.is_pad:
1156 # Variable length pad is <pad align= />
1157 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1158 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1159 self.c_var_followed_by_fixed_fields,
1163 # switch/bitcase: always calculate padding before and after variable sized fields
1164 if need_padding or is_case_or_bitcase:
1165 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1166 self.c_var_followed_by_fixed_fields,
1169 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1170 code_lines, temp_vars,
1172 prev_field_was_variable = True
1174 # save (un)serialization C code
1176 code_lines.append('%s%s' % (space, value))
1178 if field.type.fixed_size():
1179 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1180 # keep track of (un)serialized object's size
1181 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1182 if context in ('unserialize', 'unpack', 'sizeof'):
1183 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1185 # variable size objects or bitcase:
1186 # value & length might have been inserted earlier for special cases
1188 # special case: intermixed fixed and variable size fields
1189 if (not field.type.fixed_size() and
1190 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1191 temp_vars.append(' int %s_len;' % field.c_field_name)
1192 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1193 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1194 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1196 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1197 # increase pointer into the byte stream accordingly
1198 if context in ('unserialize', 'sizeof', 'unpack'):
1199 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1201 if 'serialize' == context:
1203 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1204 code_lines.append('%s xcb_parts_idx++;' % space)
1208 '%s xcb_align_to = ALIGNOF(%s);'
1211 if field.c_field_type == 'void' or field.type.is_switch
1212 else field.c_field_type))
1215 if self.c_var_followed_by_fixed_fields:
1216 need_padding = False
1221 # _c_serialize_helper_fields()
1223 def _c_serialize_helper(context, complex_type,
1224 code_lines, temp_vars,
1225 space='', prefix=[]):
1226 # count tracks the number of fields to serialize
1229 if hasattr(complex_type, 'type'):
1230 self = complex_type.type
1231 complex_name = complex_type.name
1234 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1235 complex_name = 'xcb_out'
1237 complex_name = '_aux'
1239 # special case: switch is serialized by evaluating each bitcase separately
1241 count += _c_serialize_helper_switch(context, self, complex_name,
1242 code_lines, temp_vars,
1245 # all other data types can be evaluated one field a time
1247 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1248 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1249 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1250 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1251 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1252 code_lines.append('%s xcb_block_len = 0;' % space)
1254 count += _c_serialize_helper_fields(context, self,
1255 code_lines, temp_vars,
1256 space, prefix, False)
1258 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1261 # _c_serialize_helper()
1263 def _c_serialize(context, self):
1265 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1266 for the ComplexType variable self
1272 # _serialize() returns the buffer size
1275 if self.is_switch and 'unserialize' == context:
1278 cases = { 'serialize' : self.c_serialize_name,
1279 'unserialize' : self.c_unserialize_name,
1280 'unpack' : self.c_unpack_name,
1281 'sizeof' : self.c_sizeof_name }
1282 func_name = cases[context]
1284 param_fields, wire_fields, params = get_serialize_params(context, self)
1285 variable_size_fields = 0
1286 # maximum space required for type definition of function arguments
1289 # determine N(variable_fields)
1290 for field in param_fields:
1291 # if self.is_switch, treat all fields as if they are variable sized
1292 if not field.type.fixed_size() or self.is_switch:
1293 variable_size_fields += 1
1294 # determine maxtypelen
1296 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1299 indent = ' '*(len(func_name)+2)
1302 typespec, pointerspec, field_name = p
1303 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1304 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1305 # insert function name
1306 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1307 param_str = list(map(lambda x: "%s," % x, param_str))
1308 for s in param_str[:-1]:
1310 _h("%s);" % param_str[-1].rstrip(','))
1311 _c("%s)" % param_str[-1].rstrip(','))
1318 _c_pre.redirect_start(code_lines, temp_vars)
1320 if 'serialize' == context:
1321 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1322 _c(' %s *xcb_out = *_buffer;', self.c_type)
1323 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1324 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1325 _c(' unsigned int xcb_align_to = 0;')
1327 _c(' char *xcb_out = *_buffer;')
1328 _c(' unsigned int xcb_buffer_len = 0;')
1329 _c(' unsigned int xcb_align_to = 0;')
1331 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1332 prefix = [('_aux', '->', self)]
1335 elif context in ('unserialize', 'unpack'):
1336 _c(' char *xcb_tmp = (char *)_buffer;')
1337 if not self.is_switch:
1338 if not self.c_var_followed_by_fixed_fields:
1339 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1340 prefix = [('_aux', '->', self)]
1342 _c(' %s xcb_out;', self.c_type)
1343 prefix = [('xcb_out', '.', self)]
1345 aux_var = '_aux' # default for unpack: single pointer
1346 # note: unserialize not generated for switch
1347 if 'unserialize' == context:
1348 aux_var = '(*_aux)' # unserialize: double pointer (!)
1349 prefix = [(aux_var, '->', self)]
1351 _c(' unsigned int xcb_buffer_len = 0;')
1352 _c(' unsigned int xcb_block_len = 0;')
1353 _c(' unsigned int xcb_pad = 0;')
1354 _c(' unsigned int xcb_align_to = 0;')
1356 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1358 elif 'sizeof' == context:
1359 param_names = [p[2] for p in params]
1361 # switch: call _unpack()
1362 _c(' %s _aux;', self.c_type)
1363 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1365 _c_pre.redirect_end()
1367 elif self.c_var_followed_by_fixed_fields:
1368 # special case: call _unserialize()
1369 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1371 _c_pre.redirect_end()
1374 _c(' char *xcb_tmp = (char *)_buffer;')
1375 prefix = [('_aux', '->', self)]
1377 _c(' unsigned int xcb_padding_offset = 0;')
1379 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1380 # update variable size fields (only important for context=='serialize'
1381 variable_size_fields = count
1382 if 'serialize' == context:
1383 temp_vars.append(' unsigned int xcb_pad = 0;')
1384 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1385 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1386 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1387 temp_vars.append(' unsigned int xcb_block_len = 0;')
1388 temp_vars.append(' unsigned int i;')
1389 temp_vars.append(' char *xcb_tmp;')
1390 elif 'sizeof' == context:
1391 # neither switch nor intermixed fixed and variable size fields:
1392 # evaluate parameters directly
1393 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1395 # look if we have to declare an '_aux' variable at all
1396 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1397 if not self.c_var_followed_by_fixed_fields:
1398 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1400 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1402 _c(' unsigned int xcb_buffer_len = 0;')
1403 _c(' unsigned int xcb_block_len = 0;')
1404 _c(' unsigned int xcb_pad = 0;')
1405 _c(' unsigned int xcb_align_to = 0;')
1407 _c_pre.redirect_end()
1413 for l in code_lines:
1416 # variable sized fields have been collected, now
1417 # allocate memory and copy everything into a continuous memory area
1418 # note: this is not necessary in case of unpack
1419 if context in ('serialize', 'unserialize'):
1420 # unserialize: check for sizeof-only invocation
1421 if 'unserialize' == context:
1423 _c(' if (NULL == _aux)')
1424 _c(' return xcb_buffer_len;')
1427 _c(' if (NULL == %s) {', aux_ptr)
1428 _c(' /* allocate memory */')
1429 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1430 if 'serialize' == context:
1431 _c(' *_buffer = xcb_out;')
1435 # serialize: handle variable size fields in a loop
1436 if 'serialize' == context:
1437 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1438 if len(wire_fields)>0:
1439 _c(' *xcb_out = *_aux;')
1440 # copy variable size fields into the buffer
1441 if variable_size_fields > 0:
1443 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1444 _c(' xcb_tmp = (char*)++xcb_out;')
1445 _c(' xcb_tmp += xcb_out_pad;')
1447 _c(' xcb_tmp = xcb_out;')
1449 # variable sized fields
1450 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1451 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1452 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1453 _c(' if (0 != xcb_parts[i].iov_len)')
1454 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1457 # unserialize: assign variable size fields individually
1458 if 'unserialize' == context:
1459 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1460 param_fields.reverse()
1461 for field in param_fields:
1462 if not field.type.fixed_size():
1463 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1464 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1465 _c(' *%s = xcb_out;', aux_ptr)
1468 _c(' return xcb_buffer_len;')
1472 def _c_iterator_get_end(field, accum):
1474 Figures out what C code is needed to find the end of a variable-length structure field.
1475 For nested structures, recurses into its last variable-sized field.
1476 For lists, calls the end function
1478 if field.type.is_container:
1479 accum = field.c_accessor_name + '(' + accum + ')'
1480 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1481 if field.type.is_list:
1482 # XXX we can always use the first way
1483 if field.type.member.is_simple:
1484 return field.c_end_name + '(' + accum + ')'
1486 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1488 def _c_iterator(self, name):
1490 Declares the iterator structure and next/end functions for a given type.
1495 _h(' * @brief %s', self.c_iterator_type)
1497 _h('typedef struct %s {', self.c_iterator_type)
1498 _h(' %s *data; /**< */', self.c_type)
1499 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1500 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1501 _h('} %s;', self.c_iterator_type)
1507 _h(' * Get the next element of the iterator')
1508 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1510 _h(' * Get the next element in the iterator. The member rem is')
1511 _h(' * decreased by one. The member data points to the next')
1512 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1516 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1517 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1520 if not self.fixed_size():
1521 _c(' %s *R = i->data;', self.c_type)
1524 # FIXME - how to determine the size of a variable size union??
1525 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1527 if self.c_need_sizeof:
1528 _c(' xcb_generic_iterator_t child;')
1529 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1530 self.c_type, self.c_sizeof_name)
1531 _c(' i->index = (char *) child.data - (char *) i->data;')
1533 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1534 _c(' i->index = child.index;')
1536 _c(' i->data = (%s *) child.data;', self.c_type)
1541 _c(' i->index += sizeof(%s);', self.c_type)
1547 _h(' * Return the iterator pointing to the last element')
1548 _h(' * @param i An %s', self.c_iterator_type)
1549 _h(' * @return The iterator pointing to the last element')
1551 _h(' * Set the current element in the iterator to the last element.')
1552 _h(' * The member rem is set to 0. The member data points to the')
1553 _h(' * last element.')
1556 _hc('xcb_generic_iterator_t')
1557 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1558 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1560 _c(' xcb_generic_iterator_t ret;')
1562 if self.fixed_size():
1563 _c(' ret.data = i.data + i.rem;')
1564 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1567 _c(' while(i.rem > 0)')
1568 _c(' %s(&i);', self.c_next_name)
1569 _c(' ret.data = i.data;')
1570 _c(' ret.rem = i.rem;')
1571 _c(' ret.index = i.index;')
1576 def _c_accessor_get_length(expr, field_mapping=None):
1578 Figures out what C code is needed to get a length field.
1579 The field_mapping parameter can be used to change the absolute name of a length field.
1580 For fields that follow a variable-length field, use the accessor.
1581 Otherwise, just reference the structure field directly.
1584 lenfield_name = expr.lenfield_name
1585 if lenfield_name is not None:
1586 if field_mapping is not None:
1587 lenfield_name = field_mapping[lenfield_name][0]
1589 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1590 # special case: variable and fixed size fields are intermixed
1591 # if the lenfield is among the fixed size fields, there is no need
1592 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1593 return field_mapping(expr.lenfield_name)
1594 elif expr.lenfield_name is not None:
1595 return lenfield_name
1597 return str(expr.nmemb)
1599 def _c_accessor_get_expr(expr, field_mapping):
1601 Figures out what C code is needed to get the length of a list field.
1602 The field_mapping parameter can be used to change the absolute name of a length field.
1603 Recurses for math operations.
1604 Returns bitcount for value-mask fields.
1605 Otherwise, uses the value of the length field.
1607 lenexp = _c_accessor_get_length(expr, field_mapping)
1610 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1611 elif expr.op == 'popcount':
1612 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1613 elif expr.op == 'enumref':
1614 enum_name = expr.lenfield_type.name
1615 constant_name = expr.lenfield_name
1616 c_name = _n(enum_name + (constant_name,)).upper()
1618 elif expr.op == 'sumof':
1619 # locate the referenced list object
1620 list_obj = expr.lenfield_type
1622 for f in expr.lenfield_parent.fields:
1623 if f.field_name == expr.lenfield_name:
1628 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1629 list_name = field_mapping[field.c_field_name][0]
1630 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1631 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1632 # create explicit code for computing the sum.
1633 # This works for all C-types which can be added to int64_t with +=
1635 lengthvar = _c_pre.get_tempvarname()
1636 loopvar = _c_pre.get_tempvarname()
1637 sumvar = _c_pre.get_tempvarname()
1638 listvar = _c_pre.get_tempvarname()
1639 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1640 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1641 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1642 _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1643 _c_pre.code("/* sumof start */")
1644 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1645 _c_pre.code("%s = 0;", sumvar)
1646 _c_pre.code("%s = %s;", listvar, list_name)
1647 _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1650 if expr.rhs is None:
1651 _c_pre.code("%s += *%s;", sumvar, listvar)
1653 # sumof has a nested expression which has to be evaluated in
1654 # the context of this list element
1656 # field mapping for the subexpression needs to include
1657 # the fields of the list-member type
1658 scoped_field_mapping = field_mapping.copy()
1659 scoped_field_mapping.update(
1660 _c_helper_field_mapping(
1662 [(listvar, '->', field.type.member)]))
1664 # cause pre-code of the subexpression be added right here
1666 # compute the subexpression
1667 rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1668 # resume with our code
1670 # output the summation expression
1671 _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1673 _c_pre.code("%s++;", listvar)
1676 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1679 elif expr.op != None:
1680 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1681 ' ' + expr.op + ' ' +
1682 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1684 return 'xcb_popcount(' + lenexp + ')'
1688 def type_pad_type(type):
1693 def _c_accessors_field(self, field):
1695 Declares the accessor functions for a non-list field that follows a variable-length field.
1697 c_type = self.c_type
1699 # special case: switch
1700 switch_obj = self if self.is_switch else None
1701 if self.is_case_or_bitcase:
1702 switch_obj = self.parents[-1]
1703 if switch_obj is not None:
1704 c_type = switch_obj.c_type
1706 if field.type.is_simple:
1708 _hc('%s', field.c_field_type)
1709 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1710 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1712 if field.prev_varsized_field is None:
1713 _c(' return (%s *) (R + 1);', field.c_field_type)
1715 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1716 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1717 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1721 if field.type.is_switch and switch_obj is None:
1722 return_type = 'void *'
1724 return_type = '%s *' % field.c_field_type
1727 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1728 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1730 if field.prev_varsized_field is None:
1731 _c(' return (%s) (R + 1);', return_type)
1732 # note: the special case 'variable fields followed by fixed size fields'
1733 # is not of any consequence here, since the ordering gets
1734 # 'corrected' in the reply function
1736 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1737 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1738 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1742 def _c_accessors_list(self, field):
1744 Declares the accessor functions for a list field.
1745 Declares a direct-accessor function only if the list members are fixed size.
1746 Declares length and get-iterator functions always.
1749 def get_align_pad(field):
1750 prev = field.prev_varsized_field
1751 prev_prev = field.prev_varsized_field.prev_varsized_field
1753 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1754 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1760 c_type = self.c_type
1762 # special case: switch
1763 # in case of switch, 2 params have to be supplied to certain accessor functions:
1764 # 1. the anchestor object (request or reply)
1765 # 2. the (anchestor) switch object
1766 # the reason is that switch is either a child of a request/reply or nested in another switch,
1767 # so whenever we need to access a length field, we might need to refer to some anchestor type
1768 switch_obj = self if self.is_switch else None
1769 if self.is_case_or_bitcase:
1770 switch_obj = self.parents[-1]
1771 if switch_obj is not None:
1772 c_type = switch_obj.c_type
1776 parents = self.parents if hasattr(self, 'parents') else [self]
1777 # 'R': parents[0] is always the 'toplevel' container type
1778 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1779 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1780 # auxiliary object for 'R' parameters
1783 if switch_obj is not None:
1784 # now look where the fields are defined that are needed to evaluate
1785 # the switch expr, and store the parent objects in accessor_params and
1786 # the fields in switch_fields
1788 # 'S': name for the 'toplevel' switch
1789 toplevel_switch = parents[1]
1790 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1791 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1793 # initialize prefix for everything "below" S
1794 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1795 prefix = [(prefix_str, '->', toplevel_switch)]
1797 # look for fields in the remaining containers
1798 for p in parents[2:] + [self]:
1799 # the separator between parent and child is always '.' here,
1800 # because of nested switch statements
1801 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1802 prefix.append((p.name[-1], '.', p))
1803 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1805 # auxiliary object for 'S' parameter
1810 if list.member.fixed_size():
1811 idx = 1 if switch_obj is not None else 0
1813 _hc('%s *', field.c_field_type)
1815 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1816 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1819 if switch_obj is not None:
1820 _c(' return %s;', fields[field.c_field_name][0])
1821 elif field.prev_varsized_field is None:
1822 _c(' return (%s *) (R + 1);', field.c_field_type)
1824 (prev_varsized_field, align_pad) = get_align_pad(field)
1826 if align_pad is None:
1827 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1828 type_pad_type(field.first_field_after_varsized.type.c_type))
1830 _c(' xcb_generic_iterator_t prev = %s;',
1831 _c_iterator_get_end(prev_varsized_field, 'R'))
1832 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1833 field.c_field_type, align_pad, field.prev_varsized_offset)
1838 if switch_obj is not None:
1839 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1840 spacing = ' '*(len(field.c_length_name)+2)
1841 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1842 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1844 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1845 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1847 length = _c_accessor_get_expr(field.type.expr, fields)
1848 _c(' return %s;', length)
1851 if field.type.member.is_simple:
1853 _hc('xcb_generic_iterator_t')
1854 if switch_obj is not None:
1855 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1856 spacing = ' '*(len(field.c_end_name)+2)
1857 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1858 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1860 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1861 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1863 _c(' xcb_generic_iterator_t i;')
1865 param = 'R' if switch_obj is None else 'S'
1866 if switch_obj is not None:
1867 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1868 _c_accessor_get_expr(field.type.expr, fields))
1869 elif field.prev_varsized_field == None:
1870 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1871 _c_accessor_get_expr(field.type.expr, fields))
1873 _c(' xcb_generic_iterator_t child = %s;',
1874 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1875 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1876 _c_accessor_get_expr(field.type.expr, fields))
1879 _c(' i.index = (char *) i.data - (char *) %s;', param)
1885 _hc('%s', field.c_iterator_type)
1886 if switch_obj is not None:
1887 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1888 spacing = ' '*(len(field.c_iterator_name)+2)
1889 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1890 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1892 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1893 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1895 _c(' %s i;', field.c_iterator_type)
1898 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1900 if switch_obj is not None:
1902 _c(' i.data = %s;', fields[field.c_field_name][0])
1903 _c(' i.rem = %s;', length_expr_str)
1904 elif field.prev_varsized_field == None:
1906 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1908 (prev_varsized_field, align_pad) = get_align_pad(field)
1910 if align_pad is None:
1911 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1912 type_pad_type(field.c_field_type))
1914 _c(' xcb_generic_iterator_t prev = %s;',
1915 _c_iterator_get_end(prev_varsized_field, 'R'))
1917 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1918 field.c_field_type, align_pad)
1920 if switch_obj is None:
1921 _c(' i.rem = %s;', length_expr_str)
1922 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1926 def _c_accessors(self, name, base):
1928 Declares the accessor functions for the fields of a structure.
1930 # no accessors for switch itself -
1931 # switch always needs to be unpacked explicitly
1932 # if self.is_switch:
1936 for field in self.fields:
1937 if not field.type.is_pad:
1938 if _c_field_needs_list_accessor(field):
1939 _c_accessors_list(self, field)
1940 elif _c_field_needs_field_accessor(field):
1941 _c_accessors_field(self, field)
1943 def c_simple(self, name):
1945 Exported function that handles cardinal type declarations.
1946 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1948 _c_type_setup(self, name, ())
1950 if (self.name != name):
1955 _h('typedef %s %s;', _t(self.name), my_name)
1958 _c_iterator(self, name)
1960 def _c_complex(self, force_packed = False):
1962 Helper function for handling all structure types.
1963 Called for all structs, requests, replies, events, errors.
1968 _h(' * @brief %s', self.c_type)
1970 _h('typedef %s %s {', self.c_container, self.c_type)
1976 for field in self.fields:
1977 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1978 varfield = field.c_field_name
1981 struct_fields.append(field)
1983 for field in struct_fields:
1984 length = len(field.c_field_type)
1985 # account for '*' pointer_spec
1986 if not field.type.fixed_size() and not self.is_union:
1988 maxtypelen = max(maxtypelen, length)
1990 def _c_complex_field(self, field, space=''):
1991 if (field.type.fixed_size() or self.is_union or
1992 # in case of switch with switch children, don't make the field a pointer
1993 # necessary for unserialize to work
1994 (self.is_switch and field.type.is_switch)):
1995 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1996 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1998 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1999 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2001 if not self.is_switch:
2002 for field in struct_fields:
2003 _c_complex_field(self, field)
2005 for b in self.bitcases:
2010 for field in b.type.fields:
2011 _c_complex_field(self, field, space)
2013 _h(' } %s;', b.c_field_name)
2015 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2017 def c_struct(self, name):
2019 Exported function that handles structure declarations.
2021 _c_type_setup(self, name, ())
2023 _c_accessors(self, name, name)
2024 _c_iterator(self, name)
2026 def c_union(self, name):
2028 Exported function that handles union declarations.
2030 _c_type_setup(self, name, ())
2032 _c_iterator(self, name)
2034 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2036 Declares a request function.
2039 # Four stunningly confusing possibilities here:
2042 # ------------------------------
2044 # 0 flag CHECKED flag Normal Mode
2045 # void_cookie req_cookie
2046 # ------------------------------
2047 # "req_checked" "req_unchecked"
2048 # CHECKED flag 0 flag Abnormal Mode
2049 # void_cookie req_cookie
2050 # ------------------------------
2053 # Whether we are _checked or _unchecked
2054 checked = void and not regular
2055 unchecked = not void and not regular
2057 # What kind of cookie we return
2058 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2060 # What flag is passed to xcb_request
2061 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2064 if func_flags == '0':
2065 func_flags = 'XCB_REQUEST_REPLY_FDS'
2067 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2069 # Global extension id variable or NULL for xproto
2070 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2072 # What our function name is
2073 func_name = self.c_request_name if not aux else self.c_aux_name
2075 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2077 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2081 maxtypelen = len('xcb_connection_t')
2083 # special case: list with variable size elements
2084 list_with_var_size_elems = False
2086 for field in self.fields:
2088 # The field should appear as a call parameter
2089 param_fields.append(field)
2090 if field.wire and not field.auto:
2091 # We need to set the field up in the structure
2092 wire_fields.append(field)
2093 if field.type.c_need_serialize or field.type.c_need_sizeof:
2094 serial_fields.append(field)
2096 for field in param_fields:
2097 c_field_const_type = field.c_field_const_type
2098 if field.type.c_need_serialize and not aux:
2099 c_field_const_type = "const void"
2100 if len(c_field_const_type) > maxtypelen:
2101 maxtypelen = len(c_field_const_type)
2102 if field.type.is_list and not field.type.member.fixed_size():
2103 list_with_var_size_elems = True
2109 if hasattr(self, "doc") and self.doc:
2111 _h(' * @brief ' + self.doc.brief)
2113 _h(' * No brief doc yet')
2116 _h(' * @param c The connection')
2117 param_names = [f.c_field_name for f in param_fields]
2118 if hasattr(self, "doc") and self.doc:
2119 for field in param_fields:
2120 # XXX: hard-coded until we fix xproto.xml
2121 base_func_name = self.c_request_name if not aux else self.c_aux_name
2122 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2124 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2126 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2129 # XXX: why the 'xcb' prefix?
2130 key = ('xcb', field.enum)
2133 if namecount[tname] > 1:
2134 tname = _t(key + ('enum',))
2135 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2137 if self.doc and field.field_name in self.doc.fields:
2138 desc = self.doc.fields[field.field_name]
2139 for name in param_names:
2140 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2141 desc = desc.split("\n")
2142 desc = [line if line != '' else '\\n' for line in desc]
2143 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2144 # If there is no documentation yet, we simply don't generate an
2145 # @param tag. Doxygen will then warn about missing documentation.
2147 _h(' * @return A cookie')
2150 if hasattr(self, "doc") and self.doc:
2151 if self.doc.description:
2152 desc = self.doc.description
2153 for name in param_names:
2154 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2155 desc = desc.split("\n")
2156 _h(' * ' + "\n * ".join(desc))
2158 _h(' * No description yet')
2160 _h(' * Delivers a request to the X server.')
2163 _h(' * This form can be used only if the request will not cause')
2164 _h(' * a reply to be generated. Any returned error will be')
2165 _h(' * saved for handling by xcb_request_check().')
2167 _h(' * This form can be used only if the request will cause')
2168 _h(' * a reply to be generated. Any returned error will be')
2169 _h(' * placed in the event queue.')
2172 _hc('%s', cookie_type)
2174 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2175 comma = ',' if len(param_fields) else ');'
2176 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2177 comma = ',' if len(param_fields) else ')'
2178 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2180 func_spacing = ' ' * (len(func_name) + 2)
2181 count = len(param_fields)
2182 for field in param_fields:
2184 c_field_const_type = field.c_field_const_type
2185 c_pointer = field.c_pointer
2186 if field.type.c_need_serialize and not aux:
2187 c_field_const_type = "const void"
2189 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2190 comma = ',' if count else ');'
2191 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2192 spacing, c_pointer, field.c_field_name, comma)
2193 comma = ',' if count else ')'
2194 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2195 spacing, c_pointer, field.c_field_name, comma)
2198 if not self.c_var_followed_by_fixed_fields:
2199 for field in param_fields:
2200 if not field.type.fixed_size():
2202 if field.type.c_need_serialize:
2203 # _serialize() keeps track of padding automatically
2205 dimension = count + 2
2208 _c(' static const xcb_protocol_request_t xcb_req = {')
2209 _c(' /* count */ %d,', count)
2210 _c(' /* ext */ %s,', func_ext_global)
2211 _c(' /* opcode */ %s,', self.c_request_name.upper())
2212 _c(' /* isvoid */ %d', 1 if void else 0)
2216 _c(' struct iovec xcb_parts[%d];', dimension)
2217 _c(' %s xcb_ret;', func_cookie)
2218 _c(' %s xcb_out;', self.c_type)
2219 if self.c_var_followed_by_fixed_fields:
2220 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2221 _c(' void *xcb_aux = 0;')
2224 for idx, f in enumerate(serial_fields):
2226 _c(' void *xcb_aux%d = 0;' % (idx))
2227 if list_with_var_size_elems:
2228 _c(' unsigned int i;')
2229 _c(' unsigned int xcb_tmp_len;')
2230 _c(' char *xcb_tmp;')
2232 # simple request call tracing
2233 # _c(' printf("in function %s\\n");' % func_name)
2236 for field in wire_fields:
2237 if field.type.fixed_size():
2238 if field.type.is_expr:
2239 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2240 elif field.type.is_pad:
2241 if field.type.nmemb == 1:
2242 _c(' xcb_out.%s = 0;', field.c_field_name)
2244 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2246 if field.type.nmemb == 1:
2247 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2249 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2251 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2252 serialize_args = get_serialize_params(context, type_obj,
2255 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2257 # calls in order to free dyn. all. memory
2261 if not self.c_var_followed_by_fixed_fields:
2262 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2263 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2264 _c(' xcb_parts[3].iov_base = 0;')
2265 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2269 for field in param_fields:
2270 if not field.type.fixed_size():
2271 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2272 # default: simple cast to char *
2273 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2274 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2275 if field.type.is_list:
2276 if field.type.member.fixed_size():
2277 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2278 _c_accessor_get_expr(field.type.expr, None),
2279 field.type.member.c_wiretype)
2281 list_length = _c_accessor_get_expr(field.type.expr, None)
2284 _c(" xcb_parts[%d].iov_len = 0;" % count)
2285 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2286 _c(" for(i=0; i<%s; i++) {" % list_length)
2287 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2288 (field.type.c_sizeof_name))
2289 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2290 _c(" xcb_tmp += xcb_tmp_len;")
2293 # not supposed to happen
2294 raise Exception("unhandled variable size field %s" % field.c_field_name)
2297 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2298 idx = serial_fields.index(field)
2299 aux_var = '&xcb_aux%d' % idx
2300 context = 'serialize' if aux else 'sizeof'
2301 _c(' xcb_parts[%d].iov_len =', count)
2303 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2304 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2305 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2306 free_calls.append(' free(xcb_aux%d);' % idx)
2308 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2309 func_name = field.type.c_sizeof_name
2310 _c(' %s (%s);', func_name, serialize_args)
2313 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2314 # the _serialize() function keeps track of padding automatically
2315 _c(' xcb_parts[%d].iov_base = 0;', count)
2316 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2319 # elif self.c_var_followed_by_fixed_fields:
2321 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2322 # request header: opcodes + length
2323 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2326 buffer_var = '&xcb_aux'
2327 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2328 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2329 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2330 free_calls.append(' free(xcb_aux);')
2331 # no padding necessary - _serialize() keeps track of padding automatically
2334 for field in param_fields:
2336 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2338 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2340 # free dyn. all. data, if any
2341 for f in free_calls:
2343 _c(' return xcb_ret;')
2346 def _c_reply(self, name):
2348 Declares the function that returns the reply structure.
2350 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2351 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2352 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2354 # check if _unserialize() has to be called for any field
2355 def look_for_special_cases(complex_obj):
2356 unserialize_fields = []
2357 # no unserialize call in case of switch
2358 if not complex_obj.is_switch:
2359 for field in complex_obj.fields:
2360 # three cases: 1. field with special case
2361 # 2. container that contains special case field
2362 # 3. list with special case elements
2363 if field.type.c_var_followed_by_fixed_fields:
2364 unserialize_fields.append(field)
2365 elif field.type.is_container:
2366 unserialize_fields += look_for_special_cases(field.type)
2367 elif field.type.is_list:
2368 if field.type.member.c_var_followed_by_fixed_fields:
2369 unserialize_fields.append(field)
2370 if field.type.member.is_container:
2371 unserialize_fields += look_for_special_cases(field.type.member)
2372 return unserialize_fields
2374 unserialize_fields = look_for_special_cases(self.reply)
2378 _h(' * Return the reply')
2379 _h(' * @param c The connection')
2380 _h(' * @param cookie The cookie')
2381 _h(' * @param e The xcb_generic_error_t supplied')
2383 _h(' * Returns the reply of the request asked by')
2385 _h(' * The parameter @p e supplied to this function must be NULL if')
2386 _h(' * %s(). is used.', self.c_unchecked_name)
2387 _h(' * Otherwise, it stores the error if any.')
2389 _h(' * The returned value must be freed by the caller using free().')
2392 _hc('%s *', self.c_reply_type)
2393 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2394 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2395 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2396 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2399 if len(unserialize_fields)>0:
2400 # certain variable size fields need to be unserialized explicitly
2401 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2402 self.c_reply_type, self.c_reply_type)
2404 for field in unserialize_fields:
2405 if field.type.is_list:
2406 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2407 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2408 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2410 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2411 # call _unserialize(), using the reply as source and target buffer
2412 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2413 for field in unserialize_fields:
2414 if field.type.is_list:
2415 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2416 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2417 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2418 field.c_field_name, field.c_field_name)
2419 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2421 # return the transformed reply
2422 _c(' return reply;')
2425 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2429 def _c_reply_has_fds(self):
2430 for field in self.fields:
2435 def _c_reply_fds(self, name):
2437 Declares the function that returns fds related to the reply.
2439 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2440 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2443 _h(' * Return the reply fds')
2444 _h(' * @param c The connection')
2445 _h(' * @param reply The reply')
2447 _h(' * Returns the array of reply fds of the request asked by')
2449 _h(' * The returned value must be freed by the caller using free().')
2453 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2454 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2455 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2458 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2463 def _c_opcode(name, opcode):
2465 Declares the opcode define for requests, events, and errors.
2469 _h('/** Opcode for %s. */', _n(name))
2470 _h('#define %s %s', _n(name).upper(), opcode)
2472 def _c_cookie(self, name):
2474 Declares the cookie type for a non-void request.
2479 _h(' * @brief %s', self.c_cookie_type)
2481 _h('typedef struct %s {', self.c_cookie_type)
2482 _h(' unsigned int sequence; /**< */')
2483 _h('} %s;', self.c_cookie_type)
2485 def _man_request(self, name, cookie_type, void, aux):
2486 param_fields = [f for f in self.fields if f.visible]
2488 func_name = self.c_request_name if not aux else self.c_aux_name
2490 def create_link(linkname):
2491 name = 'man/%s.%s' % (linkname, section)
2493 sys.stdout.write(name)
2495 f.write('.so man%s/%s.%s' % (section, func_name, section))
2499 sys.stdout.write('man/%s.%s ' % (func_name, section))
2500 # Our CWD is src/, so this will end up in src/man/
2501 f = open('man/%s.%s' % (func_name, section), 'w')
2502 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2503 # Left-adjust instead of adjusting to both sides
2505 f.write('.SH NAME\n')
2506 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2507 f.write('%s \\- %s\n' % (func_name, brief))
2508 f.write('.SH SYNOPSIS\n')
2509 # Don't split words (hyphenate)
2511 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2513 # function prototypes
2515 count = len(param_fields)
2516 for field in param_fields:
2518 c_field_const_type = field.c_field_const_type
2519 c_pointer = field.c_pointer
2520 if c_pointer == ' ':
2522 if field.type.c_need_serialize and not aux:
2523 c_field_const_type = "const void"
2525 comma = ', ' if count else ');'
2526 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2528 f.write('.SS Request function\n')
2530 base_func_name = self.c_request_name if not aux else self.c_aux_name
2531 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2532 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2535 f.write('.SS Reply datastructure\n')
2538 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2542 for field in self.reply.fields:
2543 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2546 struct_fields.append(field)
2548 for field in struct_fields:
2549 length = len(field.c_field_type)
2550 # account for '*' pointer_spec
2551 if not field.type.fixed_size():
2553 maxtypelen = max(maxtypelen, length)
2555 def _c_complex_field(self, field, space=''):
2556 if (field.type.fixed_size() or
2557 # in case of switch with switch children, don't make the field a pointer
2558 # necessary for unserialize to work
2559 (self.is_switch and field.type.is_switch)):
2560 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2561 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2563 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2564 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2565 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2567 if not self.is_switch:
2568 for field in struct_fields:
2569 _c_complex_field(self, field)
2571 for b in self.bitcases:
2575 for field in b.type.fields:
2576 _c_complex_field(self, field, space)
2578 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2581 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2584 f.write('.SS Reply function\n')
2586 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2587 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2588 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2589 create_link('%s' % self.c_reply_name)
2591 has_accessors = False
2592 for field in self.reply.fields:
2593 if field.type.is_list and not field.type.fixed_size():
2594 has_accessors = True
2595 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2596 has_accessors = True
2599 f.write('.SS Reply accessors\n')
2601 def _c_accessors_field(self, field):
2603 Declares the accessor functions for a non-list field that follows a variable-length field.
2605 c_type = self.c_type
2607 # special case: switch
2608 switch_obj = self if self.is_switch else None
2609 if self.is_case_or_bitcase:
2610 switch_obj = self.parents[-1]
2611 if switch_obj is not None:
2612 c_type = switch_obj.c_type
2614 if field.type.is_simple:
2615 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2616 create_link('%s' % field.c_accessor_name)
2618 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2619 create_link('%s' % field.c_accessor_name)
2621 def _c_accessors_list(self, field):
2623 Declares the accessor functions for a list field.
2624 Declares a direct-accessor function only if the list members are fixed size.
2625 Declares length and get-iterator functions always.
2628 c_type = self.reply.c_type
2630 # special case: switch
2631 # in case of switch, 2 params have to be supplied to certain accessor functions:
2632 # 1. the anchestor object (request or reply)
2633 # 2. the (anchestor) switch object
2634 # the reason is that switch is either a child of a request/reply or nested in another switch,
2635 # so whenever we need to access a length field, we might need to refer to some anchestor type
2636 switch_obj = self if self.is_switch else None
2637 if self.is_case_or_bitcase:
2638 switch_obj = self.parents[-1]
2639 if switch_obj is not None:
2640 c_type = switch_obj.c_type
2644 parents = self.parents if hasattr(self, 'parents') else [self]
2645 # 'R': parents[0] is always the 'toplevel' container type
2646 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2647 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2648 # auxiliary object for 'R' parameters
2651 if switch_obj is not None:
2652 # now look where the fields are defined that are needed to evaluate
2653 # the switch expr, and store the parent objects in accessor_params and
2654 # the fields in switch_fields
2656 # 'S': name for the 'toplevel' switch
2657 toplevel_switch = parents[1]
2658 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2659 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2661 # initialize prefix for everything "below" S
2662 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2663 prefix = [(prefix_str, '->', toplevel_switch)]
2665 # look for fields in the remaining containers
2666 for p in parents[2:] + [self]:
2667 # the separator between parent and child is always '.' here,
2668 # because of nested switch statements
2669 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2670 prefix.append((p.name[-1], '.', p))
2671 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2673 # auxiliary object for 'S' parameter
2676 if list.member.fixed_size():
2677 idx = 1 if switch_obj is not None else 0
2679 f.write('%s *\\fB%s\\fP(%s);\n' %
2680 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2681 create_link('%s' % field.c_accessor_name)
2684 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2685 (field.c_length_name, c_type))
2686 create_link('%s' % field.c_length_name)
2688 if field.type.member.is_simple:
2690 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2691 (field.c_end_name, c_type))
2692 create_link('%s' % field.c_end_name)
2695 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2696 (field.c_iterator_type, field.c_iterator_name,
2698 create_link('%s' % field.c_iterator_name)
2700 for field in self.reply.fields:
2701 if field.type.is_list and not field.type.fixed_size():
2702 _c_accessors_list(self, field)
2703 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2704 _c_accessors_field(self, field)
2708 # Re-enable hyphenation and adjusting to both sides
2711 # argument reference
2712 f.write('.SH REQUEST ARGUMENTS\n')
2713 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2714 f.write('The XCB connection to X11.\n')
2715 for field in param_fields:
2716 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2717 printed_enum = False
2718 # XXX: hard-coded until we fix xproto.xml
2719 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2721 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2723 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2725 if hasattr(field, "enum") and field.enum:
2726 # XXX: why the 'xcb' prefix?
2727 key = ('xcb', field.enum)
2729 f.write('One of the following values:\n')
2732 count = len(enum.values)
2733 for (enam, eval) in enum.values:
2735 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2736 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2737 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2738 f.write('%s\n' % desc)
2740 f.write('TODO: NOT YET DOCUMENTED.\n')
2745 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2746 desc = self.doc.fields[field.field_name]
2747 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2750 f.write('%s\n' % desc)
2752 f.write('TODO: NOT YET DOCUMENTED.\n')
2758 f.write('.SH REPLY FIELDS\n')
2759 # These fields are present in every reply:
2760 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2761 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2762 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2763 'be used to tell replies apart from each other.\n') %
2764 _n(self.reply.name).upper())
2765 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2766 f.write('The sequence number of the last request processed by the X11 server.\n')
2767 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2768 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2769 for field in self.reply.fields:
2770 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2771 field.c_field_name.startswith('pad')):
2774 if field.type.is_list and not field.type.fixed_size():
2776 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2778 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2779 printed_enum = False
2780 if hasattr(field, "enum") and field.enum:
2781 # XXX: why the 'xcb' prefix?
2782 key = ('xcb', field.enum)
2784 f.write('One of the following values:\n')
2787 count = len(enum.values)
2788 for (enam, eval) in enum.values:
2790 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2791 if enum.doc and enam in enum.doc.fields:
2792 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2793 f.write('%s\n' % desc)
2795 f.write('TODO: NOT YET DOCUMENTED.\n')
2800 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2801 desc = self.reply.doc.fields[field.field_name]
2802 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2805 f.write('%s\n' % desc)
2807 f.write('TODO: NOT YET DOCUMENTED.\n')
2814 f.write('.SH DESCRIPTION\n')
2815 if hasattr(self, "doc") and self.doc and self.doc.description:
2816 desc = self.doc.description
2817 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2818 lines = desc.split('\n')
2819 f.write('\n'.join(lines) + '\n')
2821 f.write('.SH RETURN VALUE\n')
2823 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2824 'have to be handled in the event loop.\n\nIf you want to '
2825 'handle errors directly with \\fIxcb_request_check\\fP '
2826 'instead, use \\fI%s_checked\\fP. See '
2827 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2829 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2830 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2831 'handle errors in the event loop instead, use '
2832 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2834 (cookie_type, self.c_reply_name, base_func_name, section))
2835 f.write('.SH ERRORS\n')
2836 if hasattr(self, "doc") and self.doc:
2837 for errtype, errtext in sorted(self.doc.errors.items()):
2838 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2839 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2840 f.write('%s\n' % (errtext))
2841 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2842 f.write('This request does never generate any errors.\n')
2843 if hasattr(self, "doc") and self.doc and self.doc.example:
2844 f.write('.SH EXAMPLE\n')
2847 lines = self.doc.example.split('\n')
2848 f.write('\n'.join(lines) + '\n')
2850 f.write('.SH SEE ALSO\n')
2851 if hasattr(self, "doc") and self.doc:
2852 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2853 if self.doc.example:
2854 see.append('.BR %s (%s)' % ('xcb-examples', section))
2855 for seename, seetype in sorted(self.doc.see.items()):
2856 if seetype == 'program':
2857 see.append('.BR %s (1)' % seename)
2858 elif seetype == 'event':
2859 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2860 elif seetype == 'request':
2861 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2862 elif seetype == 'function':
2863 see.append('.BR %s (%s)' % (seename, section))
2865 see.append('TODO: %s (type %s)' % (seename, seetype))
2866 f.write(',\n'.join(see) + '\n')
2867 f.write('.SH AUTHOR\n')
2868 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2871 def _man_event(self, name):
2873 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2874 # Our CWD is src/, so this will end up in src/man/
2875 f = open('man/%s.%s' % (self.c_type, section), 'w')
2876 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2877 # Left-adjust instead of adjusting to both sides
2879 f.write('.SH NAME\n')
2880 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2881 f.write('%s \\- %s\n' % (self.c_type, brief))
2882 f.write('.SH SYNOPSIS\n')
2883 # Don't split words (hyphenate)
2885 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2888 f.write('.SS Event datastructure\n')
2891 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2895 for field in self.fields:
2896 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2899 struct_fields.append(field)
2901 for field in struct_fields:
2902 length = len(field.c_field_type)
2903 # account for '*' pointer_spec
2904 if not field.type.fixed_size():
2906 maxtypelen = max(maxtypelen, length)
2908 def _c_complex_field(self, field, space=''):
2909 if (field.type.fixed_size() or
2910 # in case of switch with switch children, don't make the field a pointer
2911 # necessary for unserialize to work
2912 (self.is_switch and field.type.is_switch)):
2913 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2914 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2916 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2918 if not self.is_switch:
2919 for field in struct_fields:
2920 _c_complex_field(self, field)
2922 for b in self.bitcases:
2926 for field in b.type.fields:
2927 _c_complex_field(self, field, space)
2929 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2932 f.write('} \\fB%s\\fP;\n' % self.c_type)
2937 # Re-enable hyphenation and adjusting to both sides
2940 # argument reference
2941 f.write('.SH EVENT FIELDS\n')
2942 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2943 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2944 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2945 'to tell events apart from each other.\n') % _n(name).upper())
2946 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2947 f.write('The sequence number of the last request processed by the X11 server.\n')
2949 if not self.is_switch:
2950 for field in struct_fields:
2951 # Skip the fields which every event has, we already documented
2953 if field.c_field_name in ('response_type', 'sequence'):
2955 if isinstance(field.type, PadType):
2957 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2958 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2959 desc = self.doc.fields[field.field_name]
2960 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2961 f.write('%s\n' % desc)
2963 f.write('NOT YET DOCUMENTED.\n')
2966 f.write('.SH DESCRIPTION\n')
2967 if hasattr(self, "doc") and self.doc and self.doc.description:
2968 desc = self.doc.description
2969 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2970 lines = desc.split('\n')
2971 f.write('\n'.join(lines) + '\n')
2973 if hasattr(self, "doc") and self.doc and self.doc.example:
2974 f.write('.SH EXAMPLE\n')
2977 lines = self.doc.example.split('\n')
2978 f.write('\n'.join(lines) + '\n')
2980 f.write('.SH SEE ALSO\n')
2981 if hasattr(self, "doc") and self.doc:
2982 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2983 if self.doc.example:
2984 see.append('.BR %s (%s)' % ('xcb-examples', section))
2985 for seename, seetype in sorted(self.doc.see.items()):
2986 if seetype == 'program':
2987 see.append('.BR %s (1)' % seename)
2988 elif seetype == 'event':
2989 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2990 elif seetype == 'request':
2991 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2992 elif seetype == 'function':
2993 see.append('.BR %s (%s)' % (seename, section))
2995 see.append('TODO: %s (type %s)' % (seename, seetype))
2996 f.write(',\n'.join(see) + '\n')
2997 f.write('.SH AUTHOR\n')
2998 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3002 def c_request(self, name):
3004 Exported function that handles request declarations.
3006 _c_type_setup(self, name, ('request',))
3009 # Cookie type declaration
3010 _c_cookie(self, name)
3013 _c_opcode(name, self.opcode)
3015 # Request structure declaration
3019 _c_type_setup(self.reply, name, ('reply',))
3020 # Reply structure definition
3021 _c_complex(self.reply)
3022 # Request prototypes
3023 has_fds = _c_reply_has_fds(self.reply)
3024 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3025 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3027 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3028 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3030 _c_accessors(self.reply, name + ('reply',), name)
3031 _c_reply(self, name)
3033 _c_reply_fds(self, name)
3035 # Request prototypes
3036 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3037 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3039 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3040 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3042 # We generate the manpage afterwards because _c_type_setup has been called.
3043 # TODO: what about aux helpers?
3044 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3045 _man_request(self, name, cookie_type, not self.reply, False)
3047 def c_event(self, name):
3049 Exported function that handles event declarations.
3052 # The generic event structure xcb_ge_event_t has the full_sequence field
3053 # at the 32byte boundary. That's why we've to inject this field into GE
3054 # events while generating the structure for them. Otherwise we would read
3055 # garbage (the internal full_sequence) when accessing normal event fields
3057 force_packed = False
3058 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3060 for field in self.fields:
3061 if field.type.size != None and field.type.nmemb != None:
3062 event_size += field.type.size * field.type.nmemb
3063 if event_size == 32:
3064 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3065 idx = self.fields.index(field)
3066 self.fields.insert(idx + 1, full_sequence)
3068 # If the event contains any 64-bit extended fields, they need
3069 # to remain aligned on a 64-bit boundary. Adding full_sequence
3070 # would normally break that; force the struct to be packed.
3071 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3074 _c_type_setup(self, name, ('event',))
3077 _c_opcode(name, self.opcodes[name])
3079 if self.name == name:
3080 # Structure definition
3081 _c_complex(self, force_packed)
3085 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3087 _man_event(self, name)
3089 def c_error(self, name):
3091 Exported function that handles error declarations.
3093 _c_type_setup(self, name, ('error',))
3096 _c_opcode(name, self.opcodes[name])
3098 if self.name == name:
3099 # Structure definition
3104 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3107 # Main routine starts here
3109 # Must create an "output" dictionary before any xcbgen imports.
3110 output = {'open' : c_open,
3112 'simple' : c_simple,
3114 'struct' : c_struct,
3116 'request' : c_request,
3121 # Boilerplate below this point
3123 # Check for the argument that specifies path to the xcbgen python package.
3125 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3126 except getopt.GetoptError as err:
3128 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3131 for (opt, arg) in opts:
3139 sys.path.insert(1, arg)
3142 sys.stdout.write('man_MANS = ')
3144 # Import the module class
3146 from xcbgen.state import Module
3147 from xcbgen.xtypes import *
3150 Failed to load the xcbgen Python package!
3151 Make sure that xcb/proto installed it on your Python path.
3152 If not, you will need to create a .pth file or define $PYTHONPATH
3154 Refer to the README file in xcb/proto for more info.
3158 # Ensure the man subdirectory exists
3161 except OSError as e:
3162 if e.errno != errno.EEXIST:
3165 # Parse the xml header
3166 module = Module(args[0], output)
3168 # Build type-registry and resolve type dependencies