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 # For pre-code generated by expression generation
71 # (for example, the for-loop of a sumof)
72 # This has to account for recursiveness of the expression
73 # generation, i.e., there may be pre-code for pre-code.
74 # Therefore this is implemented as a stack of lists of lines.
81 self.redirect_code = None
82 self.redirect_tempvars = None
84 self.indent_stack = []
88 # start and end of pre-code blocks
90 self.nestingLevel += 1
93 self.nestingLevel -= 1
94 if (self.nestingLevel == 0):
95 # lowest pre-code level is finished -> output to source
96 if self.redirect_tempvars == None:
97 _c_wr_stringlist('', self.tempvars)
100 self.redirect_tempvars.extend(self.tempvars)
102 if self.redirect_code == None:
103 _c_wr_stringlist('', self.codelines)
106 self.redirect_code.extend(self.codelines)
110 def output_tempvars(self):
111 if self.redirect_code == None:
112 _c_wr_stringlist('', self.tempvars)
116 def code(self, fmt, *args):
117 self.codelines.append(self.indent_str + fmt % args)
119 def tempvar(self, fmt, *args):
120 self.tempvars.append(' ' + (fmt % args))
122 # get a unique name for a temporary variable
123 def get_tempvarname(self):
125 return "xcb_pre_tmp_%d" % self.tempvarNum
129 def push_indent(self, indentstr):
130 self.indent_stack.append(self.indent_str)
131 self.indent_str = indentstr
133 def push_addindent(self, indent_add_str):
134 self.push_indent(self.indent_str + indent_add_str)
137 self.push_addindent(' ')
139 def pop_indent(self):
140 self.indent_str = self.indent_stack.pop()
142 # redirection to lists
143 def redirect_start(self, redirectCode, redirectTempvars = None):
144 self.redirect_code = redirectCode
145 self.redirect_tempvars = redirectTempvars
146 if redirectTempvars != None:
149 def redirect_end(self):
150 self.redirect_code = None
151 self.redirect_tempvars = None
153 # global PreCode handler
157 # XXX See if this level thing is really necessary.
158 def _h_setlevel(idx):
160 Changes the array that header lines are written to.
161 Supports writing different sections of the header file.
164 while len(_hlines) <= idx:
168 def _c_setlevel(idx):
170 Changes the array that source lines are written to.
171 Supports writing to different sections of the source file.
174 while len(_clines) <= idx:
180 Does C-name conversion on a single string fragment.
181 Uses a regexp with some hard-coded special cases.
183 if str in _cname_special_cases:
184 return _cname_special_cases[str]
186 split = _cname_re.finditer(str)
187 name_parts = [match.group(0) for match in split]
188 return '_'.join(name_parts)
192 Checks for certain C++ reserved words and fixes them.
194 if str in _cplusplus_annoyances:
195 return _cplusplus_annoyances[str]
196 elif str in _c_keywords:
197 return _c_keywords[str]
203 Does C-name conversion on an extension name.
204 Has some additional special cases on top of _n_item.
206 if str in _extension_special_cases:
207 return _n_item(str).lower()
213 Does C-name conversion on a tuple of strings.
214 Different behavior depending on length of tuple, extension/not extension, etc.
215 Basically C-name converts the individual pieces, then joins with underscores.
220 parts = [list[0], _n_item(list[1])]
222 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
224 parts = [list[0]] + [_n_item(i) for i in list[1:]]
225 return '_'.join(parts).lower()
229 Does C-name conversion on a tuple of strings representing a type.
230 Same as _n but adds a "_t" on the end.
235 parts = [list[0], _n_item(list[1]), 't']
237 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
239 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
240 return '_'.join(parts).lower()
245 Exported function that handles module open.
246 Opens the files and writes out the auto-generated comment, header file includes, etc.
250 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
252 # Build the type-name collision avoidance table used by c_enum
253 build_collision_table()
259 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
260 _hc(' * Edit at your peril.')
265 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
266 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
270 _h('#ifndef __%s_H', _ns.header.upper())
271 _h('#define __%s_H', _ns.header.upper())
273 _h('#include "xcb.h"')
275 _c('#ifdef HAVE_CONFIG_H')
276 _c('#include "config.h"')
278 _c('#include <stdlib.h>')
279 _c('#include <string.h>')
280 _c('#include <assert.h>')
281 _c('#include <stddef.h> /* for offsetof() */')
282 _c('#include "xcbext.h"')
283 _c('#include "%s.h"', _ns.header)
286 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
289 for (n, h) in self.direct_imports:
290 _hc('#include "%s.h"', h)
293 _h('#ifdef __cplusplus')
299 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
300 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
302 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
305 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
309 Exported function that handles module close.
310 Writes out all the stored content lines, then closes the files.
317 _h('#ifdef __cplusplus')
329 hfile = open('%s.h' % _ns.header, 'w')
337 cfile = open('%s.c' % _ns.header, 'w')
344 def build_collision_table():
348 for v in module.types.values():
350 namecount[name] = (namecount.get(name) or 0) + 1
352 def c_enum(self, name):
354 Exported function that handles enum declarations.
360 if namecount[tname] > 1:
361 tname = _t(name + ('enum',))
365 _h('typedef enum %s {', tname)
367 count = len(self.values)
369 for (enam, eval) in self.values:
371 equals = ' = ' if eval != '' else ''
372 comma = ',' if count > 0 else ''
374 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
375 doc = '\n/**< %s */\n' % self.doc.fields[enam]
376 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
380 def _c_type_setup(self, name, postfix):
382 Sets up all the C-related state by adding additional data fields to
383 all Field and Type objects. Here is where we figure out most of our
384 variable and function names.
386 Recurses into child fields and list member types.
388 # Do all the various names in advance
389 self.c_type = _t(name + postfix)
390 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
392 self.c_iterator_type = _t(name + ('iterator',))
393 self.c_next_name = _n(name + ('next',))
394 self.c_end_name = _n(name + ('end',))
396 self.c_request_name = _n(name)
397 self.c_checked_name = _n(name + ('checked',))
398 self.c_unchecked_name = _n(name + ('unchecked',))
399 self.c_reply_name = _n(name + ('reply',))
400 self.c_reply_type = _t(name + ('reply',))
401 self.c_cookie_type = _t(name + ('cookie',))
402 self.c_reply_fds_name = _n(name + ('reply_fds',))
404 self.c_need_aux = False
405 self.c_need_serialize = False
406 self.c_need_sizeof = False
408 self.c_aux_name = _n(name + ('aux',))
409 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
410 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
411 self.c_serialize_name = _n(name + ('serialize',))
412 self.c_unserialize_name = _n(name + ('unserialize',))
413 self.c_unpack_name = _n(name + ('unpack',))
414 self.c_sizeof_name = _n(name + ('sizeof',))
416 # special case: structs where variable size fields are followed by fixed size fields
417 self.c_var_followed_by_fixed_fields = False
420 self.c_need_serialize = True
421 self.c_container = 'struct'
422 for bitcase in self.bitcases:
423 bitcase.c_field_name = _cpp(bitcase.field_name)
424 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
425 _c_type_setup(bitcase.type, bitcase_name, ())
427 elif self.is_container:
429 self.c_container = 'union' if self.is_union else 'struct'
430 prev_varsized_field = None
431 prev_varsized_offset = 0
432 first_field_after_varsized = None
434 for field in self.fields:
435 _c_type_setup(field.type, field.field_type, ())
436 if field.type.is_list:
437 _c_type_setup(field.type.member, field.field_type, ())
438 if (field.type.nmemb is None):
439 self.c_need_sizeof = True
441 field.c_field_type = _t(field.field_type)
442 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
443 field.c_field_name = _cpp(field.field_name)
444 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
445 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
447 # correct the c_pointer field for variable size non-list types
448 if not field.type.fixed_size() and field.c_pointer == ' ':
449 field.c_pointer = '*'
450 if field.type.is_list and not field.type.member.fixed_size():
451 field.c_pointer = '*'
453 if field.type.is_switch:
454 field.c_pointer = '*'
455 field.c_field_const_type = 'const ' + field.c_field_type
456 self.c_need_aux = True
458 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
459 self.c_need_sizeof = True
461 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
462 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
463 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
464 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
465 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
467 field.prev_varsized_field = prev_varsized_field
468 field.prev_varsized_offset = prev_varsized_offset
470 if prev_varsized_offset == 0:
471 first_field_after_varsized = field
472 field.first_field_after_varsized = first_field_after_varsized
474 if field.type.fixed_size():
475 prev_varsized_offset += field.type.size
476 # special case: intermixed fixed and variable size fields
477 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
478 if not self.is_union:
479 self.c_need_serialize = True
480 self.c_var_followed_by_fixed_fields = True
482 self.last_varsized_field = field
483 prev_varsized_field = field
484 prev_varsized_offset = 0
486 if self.c_var_followed_by_fixed_fields:
487 if field.type.fixed_size():
488 field.prev_varsized_field = None
490 if self.c_need_serialize:
491 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
492 self.c_need_sizeof = True
494 # as switch does never appear at toplevel,
495 # continue here with type construction
497 if self.c_type not in finished_switch:
498 finished_switch.append(self.c_type)
499 # special: switch C structs get pointer fields for variable-sized members
501 for bitcase in self.bitcases:
502 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
503 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
504 # no list with switch as element, so no call to
505 # _c_iterator(field.type, field_name) necessary
507 if not self.is_case_or_bitcase:
508 if self.c_need_serialize:
509 if self.c_serialize_name not in finished_serializers:
510 finished_serializers.append(self.c_serialize_name)
511 _c_serialize('serialize', self)
513 # _unpack() and _unserialize() are only needed for special cases:
515 # special cases -> unserialize
516 if self.is_switch or self.c_var_followed_by_fixed_fields:
517 _c_serialize('unserialize', self)
519 if self.c_need_sizeof:
520 if self.c_sizeof_name not in finished_sizeof:
521 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
522 finished_sizeof.append(self.c_sizeof_name)
523 _c_serialize('sizeof', self)
526 def _c_helper_absolute_name(prefix, field=None):
528 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
529 representing a valid name in C (based on the context)
530 if field is not None, append the field name as well
534 for name, sep, obj in prefix:
536 prefix_str += last_sep
540 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
541 (obj.is_switch and len(obj.parents)>1)):
545 prefix_str_without_lastsep = prefix_str
546 prefix_str += last_sep
548 if field is not None:
549 prefix_str += _cpp(field.field_name)
554 and hasattr(field, 'c_accessor_name')
555 and field.parent is not None
556 and field.parent.is_container
557 and not field.parent.is_switch
558 and not field.parent.is_case_or_bitcase
559 and (# the following conditions are taken from _c_accessors()
560 (field.type.is_list and not field.type.fixed_size())
562 (field.prev_varsized_field is not None
563 or not field.type.fixed_size()
567 prefix_str = field.c_accessor_name + "(" + prefix_str_without_lastsep + ")";
572 def _c_helper_field_mapping(complex_type, prefix, flat=False):
574 generate absolute names, based on prefix, for all fields starting from complex_type
575 if flat == True, nested complex types are not taken into account
578 if complex_type.is_switch:
579 for b in complex_type.bitcases:
581 switch_name, switch_sep, switch_type = prefix[-1]
582 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
584 bitcase_prefix = prefix
586 if (True==flat and not b.type.has_name) or False==flat:
587 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
589 for f in complex_type.fields:
590 fname = _c_helper_absolute_name(prefix, f)
591 if f.field_name in all_fields:
592 raise Exception("field name %s has been registered before" % f.field_name)
594 all_fields[f.field_name] = (fname, f)
595 if f.type.is_container and flat==False:
596 if f.type.is_case_or_bitcase and not f.type.has_name:
598 elif f.type.is_switch and len(f.type.parents)>1:
599 # nested switch gets another separator
600 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
602 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
603 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
608 def _c_helper_resolve_field_names (prefix):
610 get field names for all objects in the prefix array
614 # look for fields in the remaining containers
615 for idx, p in enumerate(prefix):
618 # sep can be preset in prefix, if not, make a sensible guess
619 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
620 # exception: 'toplevel' object (switch as well!) always have sep '->'
621 sep = '->' if idx<1 else sep
622 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
623 tmp_prefix.append((name, sep, obj))
624 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
627 # _c_helper_resolve_field_names
629 def get_expr_fields(self):
631 get the Fields referenced by switch or list expression
633 def get_expr_field_names(expr):
635 if expr.lenfield_name is not None:
636 return [expr.lenfield_name]
638 # constant value expr
642 return get_expr_field_names(expr.rhs)
643 elif expr.op == 'popcount':
644 return get_expr_field_names(expr.rhs)
645 elif expr.op == 'sumof':
646 # sumof expr references another list,
647 # we need that list's length field here
649 for f in expr.lenfield_parent.fields:
650 if f.field_name == expr.lenfield_name:
654 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
655 # referenced list + its length field
656 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
657 elif expr.op == 'enumref':
660 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
661 # get_expr_field_names()
663 # resolve the field names with the parent structure(s)
664 unresolved_fields_names = get_expr_field_names(self.expr)
666 # construct prefix from self
667 prefix = [('', '', p) for p in self.parents]
668 if self.is_container:
669 prefix.append(('', '', self))
671 all_fields = _c_helper_resolve_field_names (prefix)
672 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
673 if len(unresolved_fields_names) != len(resolved_fields_names):
674 raise Exception("could not resolve all fields for %s" % self.name)
676 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
677 return resolved_fields
680 def resolve_expr_fields(complex_obj):
682 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
683 these are normally fields that need to be given as function parameters
689 for field in complex_obj.fields:
690 all_fields.append(field)
691 if field.type.is_switch or field.type.is_list:
692 expr_fields += get_expr_fields(field.type)
693 if field.type.is_container:
694 expr_fields += resolve_expr_fields(field.type)
696 # try to resolve expr fields
697 for e in expr_fields:
698 if e not in all_fields and e not in unresolved:
701 # resolve_expr_fields()
703 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
705 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
706 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
707 expression. This function tries to resolve all fields within a structure, and returns the
708 unresolved fields as the list of external parameters.
710 def add_param(params, param):
711 if param not in params:
714 # collect all fields into param_fields
718 for field in self.fields:
720 # the field should appear as a parameter in the function call
721 param_fields.append(field)
722 if field.wire and not field.auto:
723 if field.type.fixed_size() and not self.is_switch:
724 # field in the xcb_out structure
725 wire_fields.append(field)
726 # fields like 'pad0' are skipped!
728 # in case of switch, parameters always contain any fields referenced in the switch expr
729 # we do not need any variable size fields here, as the switch data type contains both
730 # fixed and variable size fields
732 param_fields = get_expr_fields(self)
734 # _serialize()/_unserialize()/_unpack() function parameters
735 # note: don't use set() for params, it is unsorted
738 # 1. the parameter for the void * buffer
739 if 'serialize' == context:
740 params.append(('void', '**', buffer_var))
741 elif context in ('unserialize', 'unpack', 'sizeof'):
742 params.append(('const void', '*', buffer_var))
744 # 2. any expr fields that cannot be resolved within self and descendants
745 unresolved_fields = resolve_expr_fields(self)
746 for f in unresolved_fields:
747 add_param(params, (f.c_field_type, '', f.c_field_name))
749 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
750 # that do not appear in the data type struct
751 for p in param_fields:
753 typespec = p.c_field_const_type
754 pointerspec = p.c_pointer
755 add_param(params, (typespec, pointerspec, p.c_field_name))
757 if p.visible and not p.wire and not p.auto:
758 typespec = p.c_field_type
760 add_param(params, (typespec, pointerspec, p.c_field_name))
763 if 'serialize' == context:
764 add_param(params, ('const %s' % self.c_type, '*', aux_var))
765 elif 'unserialize' == context:
766 add_param(params, ('%s' % self.c_type, '**', aux_var))
767 elif 'unpack' == context:
768 add_param(params, ('%s' % self.c_type, '*', aux_var))
770 # 5. switch contains all variable size fields as struct members
771 # for other data types though, these have to be supplied separately
772 # this is important for the special case of intermixed fixed and
773 # variable size fields
774 if not self.is_switch and 'serialize' == context:
775 for p in param_fields:
776 if not p.type.fixed_size():
777 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
779 return (param_fields, wire_fields, params)
780 # get_serialize_params()
782 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
783 code_lines.append('%s /* insert padding */' % space)
784 if is_case_or_bitcase:
786 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
790 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
791 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
792 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
795 code_lines.append('%s if (0 != xcb_pad) {' % space)
797 if 'serialize' == context:
798 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
799 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
800 code_lines.append('%s xcb_parts_idx++;' % space)
801 elif context in ('unserialize', 'unpack', 'sizeof'):
802 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
804 code_lines.append('%s xcb_pad = 0;' % space)
805 code_lines.append('%s }' % space)
807 code_lines.append('%s xcb_block_len = 0;' % space)
808 if is_case_or_bitcase:
809 code_lines.append('%s xcb_padding_offset = 0;' % space)
811 # keep tracking of xcb_parts entries for serialize
813 # _c_serialize_helper_insert_padding()
815 def _c_serialize_helper_switch(context, self, complex_name,
816 code_lines, temp_vars,
819 switch_expr = _c_accessor_get_expr(self.expr, None)
821 for b in self.bitcases:
822 len_expr = len(b.type.expr)
824 compare_operator = '&'
826 compare_operator = '=='
828 compare_operator = '&'
830 for n, expr in enumerate(b.type.expr):
831 bitcase_expr = _c_accessor_get_expr(expr, None)
832 # only one <enumref> in the <bitcase>
835 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
836 # multiple <enumref> in the <bitcase>
839 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
840 elif len_expr == (n + 1): # last
842 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
843 else: # between first and last
845 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
849 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
851 count += _c_serialize_helper_fields(context, b.type,
852 code_lines, temp_vars,
855 is_case_or_bitcase = True)
856 code_lines.append(' }')
858 # if 'serialize' == context:
859 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
860 # elif context in ('unserialize', 'unpack', 'sizeof'):
862 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
863 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
866 # _c_serialize_helper_switch
868 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
870 handle switch by calling _serialize() or _unpack(), depending on context
872 # switch is handled by this function as a special case
873 param_fields, wire_fields, params = get_serialize_params(context, self)
874 field_mapping = _c_helper_field_mapping(self, prefix)
875 prefix_str = _c_helper_absolute_name(prefix)
877 # find the parameters that need to be passed to _serialize()/_unpack():
878 # all switch expr fields must be given as parameters
879 args = get_expr_fields(field.type)
880 # length fields for variable size types in switch, normally only some of need
881 # need to be passed as parameters
882 switch_len_fields = resolve_expr_fields(field.type)
884 # a switch field at this point _must_ be a bitcase field
885 # we require that bitcases are "self-contiguous"
886 bitcase_unresolved = resolve_expr_fields(self)
887 if len(bitcase_unresolved) != 0:
888 raise Exception('unresolved fields within bitcase is not supported at this point')
890 # get the C names for the parameters
892 for a in switch_len_fields:
893 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
895 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
897 # call _serialize()/_unpack() to determine the actual size
898 if 'serialize' == context:
899 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
900 c_field_names, prefix_str, field.c_field_name)
901 elif context in ('unserialize', 'unpack'):
902 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
903 c_field_names, prefix_str, field.c_field_name)
904 elif 'sizeof' == context:
905 # remove trailing ", " from c_field_names because it will be used at end of arglist
906 my_c_field_names = c_field_names[:-2]
907 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
910 # _c_serialize_helper_switch_field()
912 def _c_serialize_helper_list_field(context, self, field,
913 code_lines, temp_vars,
916 helper function to cope with lists of variable length
918 expr = field.type.expr
919 prefix_str = _c_helper_absolute_name(prefix)
920 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
921 param_names = [p[2] for p in params]
923 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
924 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
925 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
929 field_mapping[r] = (r, None)
931 if len(unresolved)>0:
933 if len(tmp_prefix)==0:
934 raise Exception("found an empty prefix while resolving expr field names for list %s",
937 field_mapping.update(_c_helper_resolve_field_names(prefix))
938 resolved += list(filter(lambda x: x in field_mapping, unresolved))
939 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
940 if len(unresolved)>0:
941 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
943 list_length = _c_accessor_get_expr(expr, field_mapping)
945 # default: list with fixed size elements
946 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
948 # list with variable-sized elements
949 if not field.type.member.fixed_size():
951 if context in ('unserialize', 'sizeof', 'unpack'):
952 int_i = ' unsigned int i;'
953 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
954 if int_i not in temp_vars:
955 temp_vars.append(int_i)
956 if xcb_tmp_len not in temp_vars:
957 temp_vars.append(xcb_tmp_len)
958 # loop over all list elements and call sizeof repeatedly
959 # this should be a bit faster than using the iterators
960 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
961 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
962 (space, field.type.c_sizeof_name))
963 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
964 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
965 code_lines.append("%s }" % space)
967 elif 'serialize' == context:
968 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
969 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
970 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
971 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
972 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
973 code_lines.append('%s }' % space)
974 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
977 # _c_serialize_helper_list_field()
979 def _c_serialize_helper_fields_fixed_size(context, self, field,
980 code_lines, temp_vars,
982 # keep the C code a bit more readable by giving the field name
983 if not self.is_case_or_bitcase:
984 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
986 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
987 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
988 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
990 abs_field_name = _c_helper_absolute_name(prefix, field)
991 # default for simple cases: call sizeof()
992 length = "sizeof(%s)" % field.c_field_type
994 if context in ('unserialize', 'unpack', 'sizeof'):
995 # default: simple cast
996 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
998 # padding - we could probably just ignore it
999 if field.type.is_pad and field.type.nmemb > 1:
1001 for i in range(field.type.nmemb):
1002 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
1003 (space, abs_field_name, i, field.c_field_type))
1004 # total padding = sizeof(pad0) * nmemb
1005 length += " * %d" % field.type.nmemb
1007 elif field.type.is_list:
1008 # list with fixed number of elements
1009 # length of array = sizeof(arrayElementType) * nmemb
1010 length += " * %d" % field.type.nmemb
1011 # use memcpy because C cannot assign whole arrays with operator=
1012 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1015 elif 'serialize' == context:
1016 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
1018 if field.type.is_expr:
1019 # need to register a temporary variable for the expression in case we know its type
1020 if field.type.c_type is None:
1021 raise Exception("type for field '%s' (expression '%s') unkown" %
1022 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1024 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1025 _c_accessor_get_expr(field.type.expr, prefix)))
1026 value += "&xcb_expr_%s;" % _cpp(field.field_name)
1028 elif field.type.is_pad:
1029 if field.type.nmemb == 1:
1030 value += "&xcb_pad;"
1032 # we could also set it to 0, see definition of xcb_send_request()
1033 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1034 length += "*%d" % field.type.nmemb
1037 # non-list type with fixed size
1038 if field.type.nmemb == 1:
1039 value += "&%s;" % (abs_field_name)
1041 # list with nmemb (fixed size) elements
1043 value += '%s;' % (abs_field_name)
1044 length = '%d' % field.type.nmemb
1046 return (value, length)
1047 # _c_serialize_helper_fields_fixed_size()
1049 def _c_serialize_helper_fields_variable_size(context, self, field,
1050 code_lines, temp_vars,
1052 prefix_str = _c_helper_absolute_name(prefix)
1054 if context in ('unserialize', 'unpack', 'sizeof'):
1056 var_field_name = 'xcb_tmp'
1058 # special case: intermixed fixed and variable size fields
1059 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1060 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1061 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
1062 # special case: switch
1063 if 'unpack' == context:
1064 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1066 elif 'serialize' == context:
1067 # variable size fields appear as parameters to _serialize() if the
1068 # 'toplevel' container is not a switch
1069 prefix_string = prefix_str if prefix[0][2].is_switch else ''
1070 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1071 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1075 code_lines.append('%s /* %s */' % (space, field.c_field_name))
1077 if field.type.is_list:
1079 # in any context, list is already a pointer, so the default assignment is ok
1080 code_lines.append("%s%s" % (space, value))
1082 length = _c_serialize_helper_list_field(context, self, field,
1083 code_lines, temp_vars,
1086 elif field.type.is_switch:
1088 if context == 'serialize':
1089 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1090 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1091 length = _c_serialize_helper_switch_field(context, self, field,
1092 'xcb_parts[xcb_parts_idx].iov_base',
1096 # in all remaining special cases - call _sizeof()
1097 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1099 return (value, length)
1100 # _c_serialize_helper_fields_variable_size
1102 def _c_serialize_helper_fields(context, self,
1103 code_lines, temp_vars,
1104 space, prefix, is_case_or_bitcase):
1106 need_padding = False
1107 prev_field_was_variable = False
1109 _c_pre.push_indent(space + ' ')
1111 for field in self.fields:
1112 if not field.visible:
1113 if not ((field.wire and not field.auto) or 'unserialize' == context):
1116 # switch/bitcase: fixed size fields must be considered explicitly
1117 if field.type.fixed_size():
1118 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1119 if prev_field_was_variable and need_padding:
1121 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1122 # self.c_var_followed_by_fixed_fields)
1123 prev_field_was_variable = False
1125 # prefix for fixed size fields
1126 fixed_prefix = prefix
1128 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1129 code_lines, temp_vars,
1130 space, fixed_prefix)
1134 # fields with variable size
1136 if field.type.is_pad:
1137 # Variable length pad is <pad align= />
1138 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1139 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1140 self.c_var_followed_by_fixed_fields,
1144 # switch/bitcase: always calculate padding before and after variable sized fields
1145 if need_padding or is_case_or_bitcase:
1146 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1147 self.c_var_followed_by_fixed_fields,
1150 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1151 code_lines, temp_vars,
1153 prev_field_was_variable = True
1155 # save (un)serialization C code
1157 code_lines.append('%s%s' % (space, value))
1159 if field.type.fixed_size():
1160 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1161 # keep track of (un)serialized object's size
1162 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1163 if context in ('unserialize', 'unpack', 'sizeof'):
1164 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1166 # variable size objects or bitcase:
1167 # value & length might have been inserted earlier for special cases
1169 # special case: intermixed fixed and variable size fields
1170 if (not field.type.fixed_size() and
1171 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1172 temp_vars.append(' int %s_len;' % field.c_field_name)
1173 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1174 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1175 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1177 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1178 # increase pointer into the byte stream accordingly
1179 if context in ('unserialize', 'sizeof', 'unpack'):
1180 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1182 if 'serialize' == context:
1184 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1185 code_lines.append('%s xcb_parts_idx++;' % space)
1189 '%s xcb_align_to = ALIGNOF(%s);'
1192 if field.c_field_type == 'void' or field.type.is_switch
1193 else field.c_field_type))
1196 if self.c_var_followed_by_fixed_fields:
1197 need_padding = False
1202 # _c_serialize_helper_fields()
1204 def _c_serialize_helper(context, complex_type,
1205 code_lines, temp_vars,
1206 space='', prefix=[]):
1207 # count tracks the number of fields to serialize
1210 if hasattr(complex_type, 'type'):
1211 self = complex_type.type
1212 complex_name = complex_type.name
1215 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1216 complex_name = 'xcb_out'
1218 complex_name = '_aux'
1220 # special case: switch is serialized by evaluating each bitcase separately
1222 count += _c_serialize_helper_switch(context, self, complex_name,
1223 code_lines, temp_vars,
1226 # all other data types can be evaluated one field a time
1228 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1229 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1230 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1231 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1232 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1233 code_lines.append('%s xcb_block_len = 0;' % space)
1235 count += _c_serialize_helper_fields(context, self,
1236 code_lines, temp_vars,
1237 space, prefix, False)
1239 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1242 # _c_serialize_helper()
1244 def _c_serialize(context, self):
1246 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1247 for the ComplexType variable self
1253 # _serialize() returns the buffer size
1256 if self.is_switch and 'unserialize' == context:
1259 cases = { 'serialize' : self.c_serialize_name,
1260 'unserialize' : self.c_unserialize_name,
1261 'unpack' : self.c_unpack_name,
1262 'sizeof' : self.c_sizeof_name }
1263 func_name = cases[context]
1265 param_fields, wire_fields, params = get_serialize_params(context, self)
1266 variable_size_fields = 0
1267 # maximum space required for type definition of function arguments
1270 # determine N(variable_fields)
1271 for field in param_fields:
1272 # if self.is_switch, treat all fields as if they are variable sized
1273 if not field.type.fixed_size() or self.is_switch:
1274 variable_size_fields += 1
1275 # determine maxtypelen
1277 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1280 indent = ' '*(len(func_name)+2)
1283 typespec, pointerspec, field_name = p
1284 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1285 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1286 # insert function name
1287 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1288 param_str = list(map(lambda x: "%s," % x, param_str))
1289 for s in param_str[:-1]:
1291 _h("%s);" % param_str[-1].rstrip(','))
1292 _c("%s)" % param_str[-1].rstrip(','))
1299 _c_pre.redirect_start(code_lines, temp_vars)
1301 if 'serialize' == context:
1302 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1303 _c(' %s *xcb_out = *_buffer;', self.c_type)
1304 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1305 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1306 _c(' unsigned int xcb_align_to = 0;')
1308 _c(' char *xcb_out = *_buffer;')
1309 _c(' unsigned int xcb_buffer_len = 0;')
1310 _c(' unsigned int xcb_align_to = 0;')
1312 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1313 prefix = [('_aux', '->', self)]
1316 elif context in ('unserialize', 'unpack'):
1317 _c(' char *xcb_tmp = (char *)_buffer;')
1318 if not self.is_switch:
1319 if not self.c_var_followed_by_fixed_fields:
1320 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1321 prefix = [('_aux', '->', self)]
1323 _c(' %s xcb_out;', self.c_type)
1324 prefix = [('xcb_out', '.', self)]
1326 aux_var = '_aux' # default for unpack: single pointer
1327 # note: unserialize not generated for switch
1328 if 'unserialize' == context:
1329 aux_var = '(*_aux)' # unserialize: double pointer (!)
1330 prefix = [(aux_var, '->', self)]
1332 _c(' unsigned int xcb_buffer_len = 0;')
1333 _c(' unsigned int xcb_block_len = 0;')
1334 _c(' unsigned int xcb_pad = 0;')
1335 _c(' unsigned int xcb_align_to = 0;')
1337 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1339 elif 'sizeof' == context:
1340 param_names = [p[2] for p in params]
1342 # switch: call _unpack()
1343 _c(' %s _aux;', self.c_type)
1344 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1346 _c_pre.redirect_end()
1348 elif self.c_var_followed_by_fixed_fields:
1349 # special case: call _unserialize()
1350 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1352 _c_pre.redirect_end()
1355 _c(' char *xcb_tmp = (char *)_buffer;')
1356 prefix = [('_aux', '->', self)]
1358 _c(' unsigned int xcb_padding_offset = 0;')
1360 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1361 # update variable size fields (only important for context=='serialize'
1362 variable_size_fields = count
1363 if 'serialize' == context:
1364 temp_vars.append(' unsigned int xcb_pad = 0;')
1365 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1366 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1367 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1368 temp_vars.append(' unsigned int xcb_block_len = 0;')
1369 temp_vars.append(' unsigned int i;')
1370 temp_vars.append(' char *xcb_tmp;')
1371 elif 'sizeof' == context:
1372 # neither switch nor intermixed fixed and variable size fields:
1373 # evaluate parameters directly
1374 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1376 # look if we have to declare an '_aux' variable at all
1377 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1378 if not self.c_var_followed_by_fixed_fields:
1379 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1381 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1383 _c(' unsigned int xcb_buffer_len = 0;')
1384 _c(' unsigned int xcb_block_len = 0;')
1385 _c(' unsigned int xcb_pad = 0;')
1386 _c(' unsigned int xcb_align_to = 0;')
1388 _c_pre.redirect_end()
1394 for l in code_lines:
1397 # variable sized fields have been collected, now
1398 # allocate memory and copy everything into a continuous memory area
1399 # note: this is not necessary in case of unpack
1400 if context in ('serialize', 'unserialize'):
1401 # unserialize: check for sizeof-only invocation
1402 if 'unserialize' == context:
1404 _c(' if (NULL == _aux)')
1405 _c(' return xcb_buffer_len;')
1408 _c(' if (NULL == %s) {', aux_ptr)
1409 _c(' /* allocate memory */')
1410 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1411 if 'serialize' == context:
1412 _c(' *_buffer = xcb_out;')
1416 # serialize: handle variable size fields in a loop
1417 if 'serialize' == context:
1418 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1419 if len(wire_fields)>0:
1420 _c(' *xcb_out = *_aux;')
1421 # copy variable size fields into the buffer
1422 if variable_size_fields > 0:
1424 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1425 _c(' xcb_tmp = (char*)++xcb_out;')
1426 _c(' xcb_tmp += xcb_out_pad;')
1428 _c(' xcb_tmp = xcb_out;')
1430 # variable sized fields
1431 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1432 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1433 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1434 _c(' if (0 != xcb_parts[i].iov_len)')
1435 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1438 # unserialize: assign variable size fields individually
1439 if 'unserialize' == context:
1440 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1441 param_fields.reverse()
1442 for field in param_fields:
1443 if not field.type.fixed_size():
1444 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1445 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1446 _c(' *%s = xcb_out;', aux_ptr)
1449 _c(' return xcb_buffer_len;')
1453 def _c_iterator_get_end(field, accum):
1455 Figures out what C code is needed to find the end of a variable-length structure field.
1456 For nested structures, recurses into its last variable-sized field.
1457 For lists, calls the end function
1459 if field.type.is_container:
1460 accum = field.c_accessor_name + '(' + accum + ')'
1461 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1462 if field.type.is_list:
1463 # XXX we can always use the first way
1464 if field.type.member.is_simple:
1465 return field.c_end_name + '(' + accum + ')'
1467 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1469 def _c_iterator(self, name):
1471 Declares the iterator structure and next/end functions for a given type.
1476 _h(' * @brief %s', self.c_iterator_type)
1478 _h('typedef struct %s {', self.c_iterator_type)
1479 _h(' %s *data; /**< */', self.c_type)
1480 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1481 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1482 _h('} %s;', self.c_iterator_type)
1488 _h(' * Get the next element of the iterator')
1489 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1491 _h(' * Get the next element in the iterator. The member rem is')
1492 _h(' * decreased by one. The member data points to the next')
1493 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1497 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1498 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1501 if not self.fixed_size():
1502 _c(' %s *R = i->data;', self.c_type)
1505 # FIXME - how to determine the size of a variable size union??
1506 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1508 if self.c_need_sizeof:
1509 _c(' xcb_generic_iterator_t child;')
1510 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1511 self.c_type, self.c_sizeof_name)
1512 _c(' i->index = (char *) child.data - (char *) i->data;')
1514 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1515 _c(' i->index = child.index;')
1517 _c(' i->data = (%s *) child.data;', self.c_type)
1522 _c(' i->index += sizeof(%s);', self.c_type)
1528 _h(' * Return the iterator pointing to the last element')
1529 _h(' * @param i An %s', self.c_iterator_type)
1530 _h(' * @return The iterator pointing to the last element')
1532 _h(' * Set the current element in the iterator to the last element.')
1533 _h(' * The member rem is set to 0. The member data points to the')
1534 _h(' * last element.')
1537 _hc('xcb_generic_iterator_t')
1538 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1539 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1541 _c(' xcb_generic_iterator_t ret;')
1543 if self.fixed_size():
1544 _c(' ret.data = i.data + i.rem;')
1545 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1548 _c(' while(i.rem > 0)')
1549 _c(' %s(&i);', self.c_next_name)
1550 _c(' ret.data = i.data;')
1551 _c(' ret.rem = i.rem;')
1552 _c(' ret.index = i.index;')
1557 def _c_accessor_get_length(expr, field_mapping=None):
1559 Figures out what C code is needed to get a length field.
1560 The field_mapping parameter can be used to change the absolute name of a length field.
1561 For fields that follow a variable-length field, use the accessor.
1562 Otherwise, just reference the structure field directly.
1565 lenfield_name = expr.lenfield_name
1566 if lenfield_name is not None:
1567 if field_mapping is not None:
1568 lenfield_name = field_mapping[lenfield_name][0]
1570 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1571 # special case: variable and fixed size fields are intermixed
1572 # if the lenfield is among the fixed size fields, there is no need
1573 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1574 return field_mapping(expr.lenfield_name)
1575 elif expr.lenfield_name is not None:
1576 return lenfield_name
1578 return str(expr.nmemb)
1580 def _c_accessor_get_expr(expr, field_mapping):
1582 Figures out what C code is needed to get the length of a list field.
1583 The field_mapping parameter can be used to change the absolute name of a length field.
1584 Recurses for math operations.
1585 Returns bitcount for value-mask fields.
1586 Otherwise, uses the value of the length field.
1588 lenexp = _c_accessor_get_length(expr, field_mapping)
1591 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1592 elif expr.op == 'popcount':
1593 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1594 elif expr.op == 'enumref':
1595 enum_name = expr.lenfield_type.name
1596 constant_name = expr.lenfield_name
1597 c_name = _n(enum_name + (constant_name,)).upper()
1599 elif expr.op == 'sumof':
1600 # locate the referenced list object
1601 list_obj = expr.lenfield_type
1603 for f in expr.lenfield_parent.fields:
1604 if f.field_name == expr.lenfield_name:
1609 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1610 list_name = field_mapping[field.c_field_name][0]
1611 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1612 # note: xcb_sumof() has only been defined for integers
1613 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1614 # create explicit code for computing the sum.
1615 # This works for all C-types which can be added to int64_t with +=
1617 lengthvar = _c_pre.get_tempvarname()
1618 loopvar = _c_pre.get_tempvarname()
1619 sumvar = _c_pre.get_tempvarname()
1620 listvar = _c_pre.get_tempvarname()
1621 _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1622 _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1623 _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1625 "const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1626 _c_pre.code("/* sumof start */")
1627 _c_pre.code("%s = %s;", lengthvar, c_length_func)
1628 _c_pre.code("%s = 0;", sumvar)
1629 _c_pre.code("%s = %s;", listvar, list_name)
1631 "for (%s = 0; %s < %s; %s++) {",
1632 loopvar, loopvar, lengthvar, loopvar)
1634 _c_pre.code("%s += *%s;", sumvar, listvar)
1635 _c_pre.code("%s++;", listvar);
1638 _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1641 # return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1642 elif expr.op != None:
1643 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1644 ' ' + expr.op + ' ' +
1645 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1647 return 'xcb_popcount(' + lenexp + ')'
1651 def type_pad_type(type):
1656 def _c_accessors_field(self, field):
1658 Declares the accessor functions for a non-list field that follows a variable-length field.
1660 c_type = self.c_type
1662 # special case: switch
1663 switch_obj = self if self.is_switch else None
1664 if self.is_case_or_bitcase:
1665 switch_obj = self.parents[-1]
1666 if switch_obj is not None:
1667 c_type = switch_obj.c_type
1669 if field.type.is_simple:
1671 _hc('%s', field.c_field_type)
1672 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1673 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1675 if field.prev_varsized_field is None:
1676 _c(' return (%s *) (R + 1);', field.c_field_type)
1678 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1679 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1680 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1684 if field.type.is_switch and switch_obj is None:
1685 return_type = 'void *'
1687 return_type = '%s *' % field.c_field_type
1690 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1691 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1693 if field.prev_varsized_field is None:
1694 _c(' return (%s) (R + 1);', return_type)
1695 # note: the special case 'variable fields followed by fixed size fields'
1696 # is not of any consequence here, since the ordering gets
1697 # 'corrected' in the reply function
1699 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1700 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1701 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1705 def _c_accessors_list(self, field):
1707 Declares the accessor functions for a list field.
1708 Declares a direct-accessor function only if the list members are fixed size.
1709 Declares length and get-iterator functions always.
1712 def get_align_pad(field):
1713 prev = field.prev_varsized_field
1714 prev_prev = field.prev_varsized_field.prev_varsized_field
1716 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1717 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1723 c_type = self.c_type
1725 # special case: switch
1726 # in case of switch, 2 params have to be supplied to certain accessor functions:
1727 # 1. the anchestor object (request or reply)
1728 # 2. the (anchestor) switch object
1729 # the reason is that switch is either a child of a request/reply or nested in another switch,
1730 # so whenever we need to access a length field, we might need to refer to some anchestor type
1731 switch_obj = self if self.is_switch else None
1732 if self.is_case_or_bitcase:
1733 switch_obj = self.parents[-1]
1734 if switch_obj is not None:
1735 c_type = switch_obj.c_type
1739 parents = self.parents if hasattr(self, 'parents') else [self]
1740 # 'R': parents[0] is always the 'toplevel' container type
1741 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1742 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1743 # auxiliary object for 'R' parameters
1746 if switch_obj is not None:
1747 # now look where the fields are defined that are needed to evaluate
1748 # the switch expr, and store the parent objects in accessor_params and
1749 # the fields in switch_fields
1751 # 'S': name for the 'toplevel' switch
1752 toplevel_switch = parents[1]
1753 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1754 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1756 # initialize prefix for everything "below" S
1757 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1758 prefix = [(prefix_str, '->', toplevel_switch)]
1760 # look for fields in the remaining containers
1761 for p in parents[2:] + [self]:
1762 # the separator between parent and child is always '.' here,
1763 # because of nested switch statements
1764 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1765 prefix.append((p.name[-1], '.', p))
1766 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1768 # auxiliary object for 'S' parameter
1773 if list.member.fixed_size():
1774 idx = 1 if switch_obj is not None else 0
1776 _hc('%s *', field.c_field_type)
1778 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1779 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1782 if switch_obj is not None:
1783 _c(' return %s;', fields[field.c_field_name][0])
1784 elif field.prev_varsized_field is None:
1785 _c(' return (%s *) (R + 1);', field.c_field_type)
1787 (prev_varsized_field, align_pad) = get_align_pad(field)
1789 if align_pad is None:
1790 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1791 type_pad_type(field.first_field_after_varsized.type.c_type))
1793 _c(' xcb_generic_iterator_t prev = %s;',
1794 _c_iterator_get_end(prev_varsized_field, 'R'))
1795 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1796 field.c_field_type, align_pad, field.prev_varsized_offset)
1801 if switch_obj is not None:
1802 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1803 spacing = ' '*(len(field.c_length_name)+2)
1804 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1805 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1807 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1808 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1810 length = _c_accessor_get_expr(field.type.expr, fields)
1811 _c(' return %s;', length)
1814 if field.type.member.is_simple:
1816 _hc('xcb_generic_iterator_t')
1817 if switch_obj is not None:
1818 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1819 spacing = ' '*(len(field.c_end_name)+2)
1820 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1821 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1823 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1824 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1826 _c(' xcb_generic_iterator_t i;')
1828 param = 'R' if switch_obj is None else 'S'
1829 if switch_obj is not None:
1830 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1831 _c_accessor_get_expr(field.type.expr, fields))
1832 elif field.prev_varsized_field == None:
1833 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1834 _c_accessor_get_expr(field.type.expr, fields))
1836 _c(' xcb_generic_iterator_t child = %s;',
1837 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1838 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1839 _c_accessor_get_expr(field.type.expr, fields))
1842 _c(' i.index = (char *) i.data - (char *) %s;', param)
1848 _hc('%s', field.c_iterator_type)
1849 if switch_obj is not None:
1850 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1851 spacing = ' '*(len(field.c_iterator_name)+2)
1852 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1853 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1855 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1856 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1858 _c(' %s i;', field.c_iterator_type)
1861 length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1863 if switch_obj is not None:
1865 _c(' i.data = %s;', fields[field.c_field_name][0])
1866 _c(' i.rem = %s;', length_expr_str)
1867 elif field.prev_varsized_field == None:
1869 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1871 (prev_varsized_field, align_pad) = get_align_pad(field)
1873 if align_pad is None:
1874 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1875 type_pad_type(field.c_field_type))
1877 _c(' xcb_generic_iterator_t prev = %s;',
1878 _c_iterator_get_end(prev_varsized_field, 'R'))
1880 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1881 field.c_field_type, align_pad)
1883 if switch_obj is None:
1884 _c(' i.rem = %s;', length_expr_str)
1885 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1889 def _c_accessors(self, name, base):
1891 Declares the accessor functions for the fields of a structure.
1893 # no accessors for switch itself -
1894 # switch always needs to be unpacked explicitly
1895 # if self.is_switch:
1899 for field in self.fields:
1900 if not field.type.is_pad:
1901 if field.type.is_list and not field.type.fixed_size():
1902 _c_accessors_list(self, field)
1903 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1904 _c_accessors_field(self, field)
1906 def c_simple(self, name):
1908 Exported function that handles cardinal type declarations.
1909 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1911 _c_type_setup(self, name, ())
1913 if (self.name != name):
1918 _h('typedef %s %s;', _t(self.name), my_name)
1921 _c_iterator(self, name)
1923 def _c_complex(self, force_packed = False):
1925 Helper function for handling all structure types.
1926 Called for all structs, requests, replies, events, errors.
1931 _h(' * @brief %s', self.c_type)
1933 _h('typedef %s %s {', self.c_container, self.c_type)
1939 for field in self.fields:
1940 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1941 varfield = field.c_field_name
1944 struct_fields.append(field)
1946 for field in struct_fields:
1947 length = len(field.c_field_type)
1948 # account for '*' pointer_spec
1949 if not field.type.fixed_size() and not self.is_union:
1951 maxtypelen = max(maxtypelen, length)
1953 def _c_complex_field(self, field, space=''):
1954 if (field.type.fixed_size() or self.is_union or
1955 # in case of switch with switch children, don't make the field a pointer
1956 # necessary for unserialize to work
1957 (self.is_switch and field.type.is_switch)):
1958 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1959 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1961 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1962 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1964 if not self.is_switch:
1965 for field in struct_fields:
1966 _c_complex_field(self, field)
1968 for b in self.bitcases:
1973 for field in b.type.fields:
1974 _c_complex_field(self, field, space)
1976 _h(' } %s;', b.c_field_name)
1978 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1980 def c_struct(self, name):
1982 Exported function that handles structure declarations.
1984 _c_type_setup(self, name, ())
1986 _c_accessors(self, name, name)
1987 _c_iterator(self, name)
1989 def c_union(self, name):
1991 Exported function that handles union declarations.
1993 _c_type_setup(self, name, ())
1995 _c_iterator(self, name)
1997 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1999 Declares a request function.
2002 # Four stunningly confusing possibilities here:
2005 # ------------------------------
2007 # 0 flag CHECKED flag Normal Mode
2008 # void_cookie req_cookie
2009 # ------------------------------
2010 # "req_checked" "req_unchecked"
2011 # CHECKED flag 0 flag Abnormal Mode
2012 # void_cookie req_cookie
2013 # ------------------------------
2016 # Whether we are _checked or _unchecked
2017 checked = void and not regular
2018 unchecked = not void and not regular
2020 # What kind of cookie we return
2021 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2023 # What flag is passed to xcb_request
2024 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2027 if func_flags == '0':
2028 func_flags = 'XCB_REQUEST_REPLY_FDS'
2030 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2032 # Global extension id variable or NULL for xproto
2033 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2035 # What our function name is
2036 func_name = self.c_request_name if not aux else self.c_aux_name
2038 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2040 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2044 maxtypelen = len('xcb_connection_t')
2046 # special case: list with variable size elements
2047 list_with_var_size_elems = False
2049 for field in self.fields:
2051 # The field should appear as a call parameter
2052 param_fields.append(field)
2053 if field.wire and not field.auto:
2054 # We need to set the field up in the structure
2055 wire_fields.append(field)
2056 if field.type.c_need_serialize or field.type.c_need_sizeof:
2057 serial_fields.append(field)
2059 for field in param_fields:
2060 c_field_const_type = field.c_field_const_type
2061 if field.type.c_need_serialize and not aux:
2062 c_field_const_type = "const void"
2063 if len(c_field_const_type) > maxtypelen:
2064 maxtypelen = len(c_field_const_type)
2065 if field.type.is_list and not field.type.member.fixed_size():
2066 list_with_var_size_elems = True
2072 if hasattr(self, "doc") and self.doc:
2074 _h(' * @brief ' + self.doc.brief)
2076 _h(' * No brief doc yet')
2079 _h(' * @param c The connection')
2080 param_names = [f.c_field_name for f in param_fields]
2081 if hasattr(self, "doc") and self.doc:
2082 for field in param_fields:
2083 # XXX: hard-coded until we fix xproto.xml
2084 base_func_name = self.c_request_name if not aux else self.c_aux_name
2085 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2087 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2089 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2092 # XXX: why the 'xcb' prefix?
2093 key = ('xcb', field.enum)
2096 if namecount[tname] > 1:
2097 tname = _t(key + ('enum',))
2098 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2100 if self.doc and field.field_name in self.doc.fields:
2101 desc = self.doc.fields[field.field_name]
2102 for name in param_names:
2103 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2104 desc = desc.split("\n")
2105 desc = [line if line != '' else '\\n' for line in desc]
2106 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2107 # If there is no documentation yet, we simply don't generate an
2108 # @param tag. Doxygen will then warn about missing documentation.
2110 _h(' * @return A cookie')
2113 if hasattr(self, "doc") and self.doc:
2114 if self.doc.description:
2115 desc = self.doc.description
2116 for name in param_names:
2117 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2118 desc = desc.split("\n")
2119 _h(' * ' + "\n * ".join(desc))
2121 _h(' * No description yet')
2123 _h(' * Delivers a request to the X server.')
2126 _h(' * This form can be used only if the request will not cause')
2127 _h(' * a reply to be generated. Any returned error will be')
2128 _h(' * saved for handling by xcb_request_check().')
2130 _h(' * This form can be used only if the request will cause')
2131 _h(' * a reply to be generated. Any returned error will be')
2132 _h(' * placed in the event queue.')
2135 _hc('%s', cookie_type)
2137 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2138 comma = ',' if len(param_fields) else ');'
2139 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2140 comma = ',' if len(param_fields) else ')'
2141 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2143 func_spacing = ' ' * (len(func_name) + 2)
2144 count = len(param_fields)
2145 for field in param_fields:
2147 c_field_const_type = field.c_field_const_type
2148 c_pointer = field.c_pointer
2149 if field.type.c_need_serialize and not aux:
2150 c_field_const_type = "const void"
2152 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2153 comma = ',' if count else ');'
2154 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2155 spacing, c_pointer, field.c_field_name, comma)
2156 comma = ',' if count else ')'
2157 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2158 spacing, c_pointer, field.c_field_name, comma)
2161 if not self.c_var_followed_by_fixed_fields:
2162 for field in param_fields:
2163 if not field.type.fixed_size():
2165 if field.type.c_need_serialize:
2166 # _serialize() keeps track of padding automatically
2168 dimension = count + 2
2171 _c(' static const xcb_protocol_request_t xcb_req = {')
2172 _c(' /* count */ %d,', count)
2173 _c(' /* ext */ %s,', func_ext_global)
2174 _c(' /* opcode */ %s,', self.c_request_name.upper())
2175 _c(' /* isvoid */ %d', 1 if void else 0)
2179 _c(' struct iovec xcb_parts[%d];', dimension)
2180 _c(' %s xcb_ret;', func_cookie)
2181 _c(' %s xcb_out;', self.c_type)
2182 if self.c_var_followed_by_fixed_fields:
2183 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2184 _c(' void *xcb_aux = 0;')
2187 for idx, f in enumerate(serial_fields):
2189 _c(' void *xcb_aux%d = 0;' % (idx))
2190 if list_with_var_size_elems:
2191 _c(' unsigned int i;')
2192 _c(' unsigned int xcb_tmp_len;')
2193 _c(' char *xcb_tmp;')
2195 # simple request call tracing
2196 # _c(' printf("in function %s\\n");' % func_name)
2199 for field in wire_fields:
2200 if field.type.fixed_size():
2201 if field.type.is_expr:
2202 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2203 elif field.type.is_pad:
2204 if field.type.nmemb == 1:
2205 _c(' xcb_out.%s = 0;', field.c_field_name)
2207 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2209 if field.type.nmemb == 1:
2210 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2212 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2214 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2215 serialize_args = get_serialize_params(context, type_obj,
2218 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2220 # calls in order to free dyn. all. memory
2224 if not self.c_var_followed_by_fixed_fields:
2225 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2226 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2227 _c(' xcb_parts[3].iov_base = 0;')
2228 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2232 for field in param_fields:
2233 if not field.type.fixed_size():
2234 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2235 # default: simple cast to char *
2236 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2237 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2238 if field.type.is_list:
2239 if field.type.member.fixed_size():
2240 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2241 _c_accessor_get_expr(field.type.expr, None),
2242 field.type.member.c_wiretype)
2244 list_length = _c_accessor_get_expr(field.type.expr, None)
2247 _c(" xcb_parts[%d].iov_len = 0;" % count)
2248 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2249 _c(" for(i=0; i<%s; i++) {" % list_length)
2250 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2251 (field.type.c_sizeof_name))
2252 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2253 _c(" xcb_tmp += xcb_tmp_len;")
2256 # not supposed to happen
2257 raise Exception("unhandled variable size field %s" % field.c_field_name)
2260 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2261 idx = serial_fields.index(field)
2262 aux_var = '&xcb_aux%d' % idx
2263 context = 'serialize' if aux else 'sizeof'
2264 _c(' xcb_parts[%d].iov_len =', count)
2266 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2267 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2268 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2269 free_calls.append(' free(xcb_aux%d);' % idx)
2271 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2272 func_name = field.type.c_sizeof_name
2273 _c(' %s (%s);', func_name, serialize_args)
2276 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2277 # the _serialize() function keeps track of padding automatically
2278 _c(' xcb_parts[%d].iov_base = 0;', count)
2279 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2282 # elif self.c_var_followed_by_fixed_fields:
2284 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2285 # request header: opcodes + length
2286 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2289 buffer_var = '&xcb_aux'
2290 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2291 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2292 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2293 free_calls.append(' free(xcb_aux);')
2294 # no padding necessary - _serialize() keeps track of padding automatically
2297 for field in param_fields:
2299 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2301 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2303 # free dyn. all. data, if any
2304 for f in free_calls:
2306 _c(' return xcb_ret;')
2309 def _c_reply(self, name):
2311 Declares the function that returns the reply structure.
2313 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2314 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2315 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2317 # check if _unserialize() has to be called for any field
2318 def look_for_special_cases(complex_obj):
2319 unserialize_fields = []
2320 # no unserialize call in case of switch
2321 if not complex_obj.is_switch:
2322 for field in complex_obj.fields:
2323 # three cases: 1. field with special case
2324 # 2. container that contains special case field
2325 # 3. list with special case elements
2326 if field.type.c_var_followed_by_fixed_fields:
2327 unserialize_fields.append(field)
2328 elif field.type.is_container:
2329 unserialize_fields += look_for_special_cases(field.type)
2330 elif field.type.is_list:
2331 if field.type.member.c_var_followed_by_fixed_fields:
2332 unserialize_fields.append(field)
2333 if field.type.member.is_container:
2334 unserialize_fields += look_for_special_cases(field.type.member)
2335 return unserialize_fields
2337 unserialize_fields = look_for_special_cases(self.reply)
2341 _h(' * Return the reply')
2342 _h(' * @param c The connection')
2343 _h(' * @param cookie The cookie')
2344 _h(' * @param e The xcb_generic_error_t supplied')
2346 _h(' * Returns the reply of the request asked by')
2348 _h(' * The parameter @p e supplied to this function must be NULL if')
2349 _h(' * %s(). is used.', self.c_unchecked_name)
2350 _h(' * Otherwise, it stores the error if any.')
2352 _h(' * The returned value must be freed by the caller using free().')
2355 _hc('%s *', self.c_reply_type)
2356 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2357 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2358 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2359 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2362 if len(unserialize_fields)>0:
2363 # certain variable size fields need to be unserialized explicitly
2364 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2365 self.c_reply_type, self.c_reply_type)
2367 for field in unserialize_fields:
2368 if field.type.is_list:
2369 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2370 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2371 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2373 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2374 # call _unserialize(), using the reply as source and target buffer
2375 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2376 for field in unserialize_fields:
2377 if field.type.is_list:
2378 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2379 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2380 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2381 field.c_field_name, field.c_field_name)
2382 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2384 # return the transformed reply
2385 _c(' return reply;')
2388 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2392 def _c_reply_has_fds(self):
2393 for field in self.fields:
2398 def _c_reply_fds(self, name):
2400 Declares the function that returns fds related to the reply.
2402 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2403 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2406 _h(' * Return the reply fds')
2407 _h(' * @param c The connection')
2408 _h(' * @param reply The reply')
2410 _h(' * Returns the array of reply fds of the request asked by')
2412 _h(' * The returned value must be freed by the caller using free().')
2416 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2417 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2418 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2421 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2426 def _c_opcode(name, opcode):
2428 Declares the opcode define for requests, events, and errors.
2432 _h('/** Opcode for %s. */', _n(name))
2433 _h('#define %s %s', _n(name).upper(), opcode)
2435 def _c_cookie(self, name):
2437 Declares the cookie type for a non-void request.
2442 _h(' * @brief %s', self.c_cookie_type)
2444 _h('typedef struct %s {', self.c_cookie_type)
2445 _h(' unsigned int sequence; /**< */')
2446 _h('} %s;', self.c_cookie_type)
2448 def _man_request(self, name, cookie_type, void, aux):
2449 param_fields = [f for f in self.fields if f.visible]
2451 func_name = self.c_request_name if not aux else self.c_aux_name
2453 def create_link(linkname):
2454 name = 'man/%s.%s' % (linkname, section)
2456 sys.stdout.write(name)
2458 f.write('.so man%s/%s.%s' % (section, func_name, section))
2462 sys.stdout.write('man/%s.%s ' % (func_name, section))
2463 # Our CWD is src/, so this will end up in src/man/
2464 f = open('man/%s.%s' % (func_name, section), 'w')
2465 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2466 # Left-adjust instead of adjusting to both sides
2468 f.write('.SH NAME\n')
2469 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2470 f.write('%s \\- %s\n' % (func_name, brief))
2471 f.write('.SH SYNOPSIS\n')
2472 # Don't split words (hyphenate)
2474 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2476 # function prototypes
2478 count = len(param_fields)
2479 for field in param_fields:
2481 c_field_const_type = field.c_field_const_type
2482 c_pointer = field.c_pointer
2483 if c_pointer == ' ':
2485 if field.type.c_need_serialize and not aux:
2486 c_field_const_type = "const void"
2488 comma = ', ' if count else ');'
2489 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2491 f.write('.SS Request function\n')
2493 base_func_name = self.c_request_name if not aux else self.c_aux_name
2494 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2495 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2498 f.write('.SS Reply datastructure\n')
2501 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2505 for field in self.reply.fields:
2506 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2509 struct_fields.append(field)
2511 for field in struct_fields:
2512 length = len(field.c_field_type)
2513 # account for '*' pointer_spec
2514 if not field.type.fixed_size():
2516 maxtypelen = max(maxtypelen, length)
2518 def _c_complex_field(self, field, space=''):
2519 if (field.type.fixed_size() or
2520 # in case of switch with switch children, don't make the field a pointer
2521 # necessary for unserialize to work
2522 (self.is_switch and field.type.is_switch)):
2523 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2524 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2526 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2527 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2528 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2530 if not self.is_switch:
2531 for field in struct_fields:
2532 _c_complex_field(self, field)
2534 for b in self.bitcases:
2538 for field in b.type.fields:
2539 _c_complex_field(self, field, space)
2541 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2544 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2547 f.write('.SS Reply function\n')
2549 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2550 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2551 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2552 create_link('%s' % self.c_reply_name)
2554 has_accessors = False
2555 for field in self.reply.fields:
2556 if field.type.is_list and not field.type.fixed_size():
2557 has_accessors = True
2558 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2559 has_accessors = True
2562 f.write('.SS Reply accessors\n')
2564 def _c_accessors_field(self, field):
2566 Declares the accessor functions for a non-list field that follows a variable-length field.
2568 c_type = self.c_type
2570 # special case: switch
2571 switch_obj = self if self.is_switch else None
2572 if self.is_case_or_bitcase:
2573 switch_obj = self.parents[-1]
2574 if switch_obj is not None:
2575 c_type = switch_obj.c_type
2577 if field.type.is_simple:
2578 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2579 create_link('%s' % field.c_accessor_name)
2581 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2582 create_link('%s' % field.c_accessor_name)
2584 def _c_accessors_list(self, field):
2586 Declares the accessor functions for a list field.
2587 Declares a direct-accessor function only if the list members are fixed size.
2588 Declares length and get-iterator functions always.
2591 c_type = self.reply.c_type
2593 # special case: switch
2594 # in case of switch, 2 params have to be supplied to certain accessor functions:
2595 # 1. the anchestor object (request or reply)
2596 # 2. the (anchestor) switch object
2597 # the reason is that switch is either a child of a request/reply or nested in another switch,
2598 # so whenever we need to access a length field, we might need to refer to some anchestor type
2599 switch_obj = self if self.is_switch else None
2600 if self.is_case_or_bitcase:
2601 switch_obj = self.parents[-1]
2602 if switch_obj is not None:
2603 c_type = switch_obj.c_type
2607 parents = self.parents if hasattr(self, 'parents') else [self]
2608 # 'R': parents[0] is always the 'toplevel' container type
2609 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2610 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2611 # auxiliary object for 'R' parameters
2614 if switch_obj is not None:
2615 # now look where the fields are defined that are needed to evaluate
2616 # the switch expr, and store the parent objects in accessor_params and
2617 # the fields in switch_fields
2619 # 'S': name for the 'toplevel' switch
2620 toplevel_switch = parents[1]
2621 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2622 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2624 # initialize prefix for everything "below" S
2625 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2626 prefix = [(prefix_str, '->', toplevel_switch)]
2628 # look for fields in the remaining containers
2629 for p in parents[2:] + [self]:
2630 # the separator between parent and child is always '.' here,
2631 # because of nested switch statements
2632 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2633 prefix.append((p.name[-1], '.', p))
2634 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2636 # auxiliary object for 'S' parameter
2639 if list.member.fixed_size():
2640 idx = 1 if switch_obj is not None else 0
2642 f.write('%s *\\fB%s\\fP(%s);\n' %
2643 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2644 create_link('%s' % field.c_accessor_name)
2647 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2648 (field.c_length_name, c_type))
2649 create_link('%s' % field.c_length_name)
2651 if field.type.member.is_simple:
2653 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2654 (field.c_end_name, c_type))
2655 create_link('%s' % field.c_end_name)
2658 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2659 (field.c_iterator_type, field.c_iterator_name,
2661 create_link('%s' % field.c_iterator_name)
2663 for field in self.reply.fields:
2664 if field.type.is_list and not field.type.fixed_size():
2665 _c_accessors_list(self, field)
2666 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2667 _c_accessors_field(self, field)
2671 # Re-enable hyphenation and adjusting to both sides
2674 # argument reference
2675 f.write('.SH REQUEST ARGUMENTS\n')
2676 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2677 f.write('The XCB connection to X11.\n')
2678 for field in param_fields:
2679 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2680 printed_enum = False
2681 # XXX: hard-coded until we fix xproto.xml
2682 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2684 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2686 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2688 if hasattr(field, "enum") and field.enum:
2689 # XXX: why the 'xcb' prefix?
2690 key = ('xcb', field.enum)
2692 f.write('One of the following values:\n')
2695 count = len(enum.values)
2696 for (enam, eval) in enum.values:
2698 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2699 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2700 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2701 f.write('%s\n' % desc)
2703 f.write('TODO: NOT YET DOCUMENTED.\n')
2708 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2709 desc = self.doc.fields[field.field_name]
2710 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2713 f.write('%s\n' % desc)
2715 f.write('TODO: NOT YET DOCUMENTED.\n')
2721 f.write('.SH REPLY FIELDS\n')
2722 # These fields are present in every reply:
2723 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2724 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2725 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2726 'be used to tell replies apart from each other.\n') %
2727 _n(self.reply.name).upper())
2728 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2729 f.write('The sequence number of the last request processed by the X11 server.\n')
2730 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2731 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2732 for field in self.reply.fields:
2733 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2734 field.c_field_name.startswith('pad')):
2737 if field.type.is_list and not field.type.fixed_size():
2739 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2741 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2742 printed_enum = False
2743 if hasattr(field, "enum") and field.enum:
2744 # XXX: why the 'xcb' prefix?
2745 key = ('xcb', field.enum)
2747 f.write('One of the following values:\n')
2750 count = len(enum.values)
2751 for (enam, eval) in enum.values:
2753 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2754 if enum.doc and enam in enum.doc.fields:
2755 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2756 f.write('%s\n' % desc)
2758 f.write('TODO: NOT YET DOCUMENTED.\n')
2763 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2764 desc = self.reply.doc.fields[field.field_name]
2765 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2768 f.write('%s\n' % desc)
2770 f.write('TODO: NOT YET DOCUMENTED.\n')
2777 f.write('.SH DESCRIPTION\n')
2778 if hasattr(self, "doc") and self.doc and self.doc.description:
2779 desc = self.doc.description
2780 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2781 lines = desc.split('\n')
2782 f.write('\n'.join(lines) + '\n')
2784 f.write('.SH RETURN VALUE\n')
2786 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2787 'have to be handled in the event loop.\n\nIf you want to '
2788 'handle errors directly with \\fIxcb_request_check\\fP '
2789 'instead, use \\fI%s_checked\\fP. See '
2790 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2792 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2793 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2794 'handle errors in the event loop instead, use '
2795 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2797 (cookie_type, self.c_reply_name, base_func_name, section))
2798 f.write('.SH ERRORS\n')
2799 if hasattr(self, "doc") and self.doc:
2800 for errtype, errtext in sorted(self.doc.errors.items()):
2801 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2802 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2803 f.write('%s\n' % (errtext))
2804 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2805 f.write('This request does never generate any errors.\n')
2806 if hasattr(self, "doc") and self.doc and self.doc.example:
2807 f.write('.SH EXAMPLE\n')
2810 lines = self.doc.example.split('\n')
2811 f.write('\n'.join(lines) + '\n')
2813 f.write('.SH SEE ALSO\n')
2814 if hasattr(self, "doc") and self.doc:
2815 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2816 if self.doc.example:
2817 see.append('.BR %s (%s)' % ('xcb-examples', section))
2818 for seename, seetype in sorted(self.doc.see.items()):
2819 if seetype == 'program':
2820 see.append('.BR %s (1)' % seename)
2821 elif seetype == 'event':
2822 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2823 elif seetype == 'request':
2824 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2825 elif seetype == 'function':
2826 see.append('.BR %s (%s)' % (seename, section))
2828 see.append('TODO: %s (type %s)' % (seename, seetype))
2829 f.write(',\n'.join(see) + '\n')
2830 f.write('.SH AUTHOR\n')
2831 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2834 def _man_event(self, name):
2836 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2837 # Our CWD is src/, so this will end up in src/man/
2838 f = open('man/%s.%s' % (self.c_type, section), 'w')
2839 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2840 # Left-adjust instead of adjusting to both sides
2842 f.write('.SH NAME\n')
2843 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2844 f.write('%s \\- %s\n' % (self.c_type, brief))
2845 f.write('.SH SYNOPSIS\n')
2846 # Don't split words (hyphenate)
2848 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2851 f.write('.SS Event datastructure\n')
2854 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2858 for field in self.fields:
2859 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2862 struct_fields.append(field)
2864 for field in struct_fields:
2865 length = len(field.c_field_type)
2866 # account for '*' pointer_spec
2867 if not field.type.fixed_size():
2869 maxtypelen = max(maxtypelen, length)
2871 def _c_complex_field(self, field, space=''):
2872 if (field.type.fixed_size() or
2873 # in case of switch with switch children, don't make the field a pointer
2874 # necessary for unserialize to work
2875 (self.is_switch and field.type.is_switch)):
2876 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2877 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2879 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2881 if not self.is_switch:
2882 for field in struct_fields:
2883 _c_complex_field(self, field)
2885 for b in self.bitcases:
2889 for field in b.type.fields:
2890 _c_complex_field(self, field, space)
2892 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2895 f.write('} \\fB%s\\fP;\n' % self.c_type)
2900 # Re-enable hyphenation and adjusting to both sides
2903 # argument reference
2904 f.write('.SH EVENT FIELDS\n')
2905 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2906 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2907 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2908 'to tell events apart from each other.\n') % _n(name).upper())
2909 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2910 f.write('The sequence number of the last request processed by the X11 server.\n')
2912 if not self.is_switch:
2913 for field in struct_fields:
2914 # Skip the fields which every event has, we already documented
2916 if field.c_field_name in ('response_type', 'sequence'):
2918 if isinstance(field.type, PadType):
2920 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2921 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2922 desc = self.doc.fields[field.field_name]
2923 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2924 f.write('%s\n' % desc)
2926 f.write('NOT YET DOCUMENTED.\n')
2929 f.write('.SH DESCRIPTION\n')
2930 if hasattr(self, "doc") and self.doc and self.doc.description:
2931 desc = self.doc.description
2932 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2933 lines = desc.split('\n')
2934 f.write('\n'.join(lines) + '\n')
2936 if hasattr(self, "doc") and self.doc and self.doc.example:
2937 f.write('.SH EXAMPLE\n')
2940 lines = self.doc.example.split('\n')
2941 f.write('\n'.join(lines) + '\n')
2943 f.write('.SH SEE ALSO\n')
2944 if hasattr(self, "doc") and self.doc:
2945 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2946 if self.doc.example:
2947 see.append('.BR %s (%s)' % ('xcb-examples', section))
2948 for seename, seetype in sorted(self.doc.see.items()):
2949 if seetype == 'program':
2950 see.append('.BR %s (1)' % seename)
2951 elif seetype == 'event':
2952 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2953 elif seetype == 'request':
2954 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2955 elif seetype == 'function':
2956 see.append('.BR %s (%s)' % (seename, section))
2958 see.append('TODO: %s (type %s)' % (seename, seetype))
2959 f.write(',\n'.join(see) + '\n')
2960 f.write('.SH AUTHOR\n')
2961 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2965 def c_request(self, name):
2967 Exported function that handles request declarations.
2969 _c_type_setup(self, name, ('request',))
2972 # Cookie type declaration
2973 _c_cookie(self, name)
2976 _c_opcode(name, self.opcode)
2978 # Request structure declaration
2982 _c_type_setup(self.reply, name, ('reply',))
2983 # Reply structure definition
2984 _c_complex(self.reply)
2985 # Request prototypes
2986 has_fds = _c_reply_has_fds(self.reply)
2987 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2988 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2990 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2991 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2993 _c_accessors(self.reply, name + ('reply',), name)
2994 _c_reply(self, name)
2996 _c_reply_fds(self, name)
2998 # Request prototypes
2999 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3000 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3002 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3003 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3005 # We generate the manpage afterwards because _c_type_setup has been called.
3006 # TODO: what about aux helpers?
3007 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3008 _man_request(self, name, cookie_type, not self.reply, False)
3010 def c_event(self, name):
3012 Exported function that handles event declarations.
3015 # The generic event structure xcb_ge_event_t has the full_sequence field
3016 # at the 32byte boundary. That's why we've to inject this field into GE
3017 # events while generating the structure for them. Otherwise we would read
3018 # garbage (the internal full_sequence) when accessing normal event fields
3020 force_packed = False
3021 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3023 for field in self.fields:
3024 if field.type.size != None and field.type.nmemb != None:
3025 event_size += field.type.size * field.type.nmemb
3026 if event_size == 32:
3027 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3028 idx = self.fields.index(field)
3029 self.fields.insert(idx + 1, full_sequence)
3031 # If the event contains any 64-bit extended fields, they need
3032 # to remain aligned on a 64-bit boundary. Adding full_sequence
3033 # would normally break that; force the struct to be packed.
3034 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3037 _c_type_setup(self, name, ('event',))
3040 _c_opcode(name, self.opcodes[name])
3042 if self.name == name:
3043 # Structure definition
3044 _c_complex(self, force_packed)
3048 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3050 _man_event(self, name)
3052 def c_error(self, name):
3054 Exported function that handles error declarations.
3056 _c_type_setup(self, name, ('error',))
3059 _c_opcode(name, self.opcodes[name])
3061 if self.name == name:
3062 # Structure definition
3067 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3070 # Main routine starts here
3072 # Must create an "output" dictionary before any xcbgen imports.
3073 output = {'open' : c_open,
3075 'simple' : c_simple,
3077 'struct' : c_struct,
3079 'request' : c_request,
3084 # Boilerplate below this point
3086 # Check for the argument that specifies path to the xcbgen python package.
3088 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3089 except getopt.GetoptError as err:
3091 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3094 for (opt, arg) in opts:
3102 sys.path.insert(1, arg)
3105 sys.stdout.write('man_MANS = ')
3107 # Import the module class
3109 from xcbgen.state import Module
3110 from xcbgen.xtypes import *
3113 Failed to load the xcbgen Python package!
3114 Make sure that xcb/proto installed it on your Python path.
3115 If not, you will need to create a .pth file or define $PYTHONPATH
3117 Refer to the README file in xcb/proto for more info.
3121 # Ensure the man subdirectory exists
3124 except OSError as e:
3125 if e.errno != errno.EEXIST:
3128 # Parse the xml header
3129 module = Module(args[0], output)
3131 # Build type-registry and resolve type dependencies