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 # XXX See if this level thing is really necessary.
64 Changes the array that header lines are written to.
65 Supports writing different sections of the header file.
68 while len(_hlines) <= idx:
74 Changes the array that source lines are written to.
75 Supports writing to different sections of the source file.
78 while len(_clines) <= idx:
84 Does C-name conversion on a single string fragment.
85 Uses a regexp with some hard-coded special cases.
87 if str in _cname_special_cases:
88 return _cname_special_cases[str]
90 split = _cname_re.finditer(str)
91 name_parts = [match.group(0) for match in split]
92 return '_'.join(name_parts)
96 Checks for certain C++ reserved words and fixes them.
98 if str in _cplusplus_annoyances:
99 return _cplusplus_annoyances[str]
100 elif str in _c_keywords:
101 return _c_keywords[str]
107 Does C-name conversion on an extension name.
108 Has some additional special cases on top of _n_item.
110 if str in _extension_special_cases:
111 return _n_item(str).lower()
117 Does C-name conversion on a tuple of strings.
118 Different behavior depending on length of tuple, extension/not extension, etc.
119 Basically C-name converts the individual pieces, then joins with underscores.
124 parts = [list[0], _n_item(list[1])]
126 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
128 parts = [list[0]] + [_n_item(i) for i in list[1:]]
129 return '_'.join(parts).lower()
133 Does C-name conversion on a tuple of strings representing a type.
134 Same as _n but adds a "_t" on the end.
139 parts = [list[0], _n_item(list[1]), 't']
141 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
143 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
144 return '_'.join(parts).lower()
149 Exported function that handles module open.
150 Opens the files and writes out the auto-generated comment, header file includes, etc.
154 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
156 # Build the type-name collision avoidance table used by c_enum
157 build_collision_table()
163 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
164 _hc(' * Edit at your peril.')
169 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
170 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
174 _h('#ifndef __%s_H', _ns.header.upper())
175 _h('#define __%s_H', _ns.header.upper())
177 _h('#include "xcb.h"')
179 _c('#ifdef HAVE_CONFIG_H')
180 _c('#include "config.h"')
182 _c('#include <stdlib.h>')
183 _c('#include <string.h>')
184 _c('#include <assert.h>')
185 _c('#include <stddef.h> /* for offsetof() */')
186 _c('#include "xcbext.h"')
187 _c('#include "%s.h"', _ns.header)
190 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
193 for (n, h) in self.direct_imports:
194 _hc('#include "%s.h"', h)
197 _h('#ifdef __cplusplus')
203 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
204 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
206 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
209 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
213 Exported function that handles module close.
214 Writes out all the stored content lines, then closes the files.
221 _h('#ifdef __cplusplus')
233 hfile = open('%s.h' % _ns.header, 'w')
241 cfile = open('%s.c' % _ns.header, 'w')
248 def build_collision_table():
252 for v in module.types.values():
254 namecount[name] = (namecount.get(name) or 0) + 1
256 def c_enum(self, name):
258 Exported function that handles enum declarations.
264 if namecount[tname] > 1:
265 tname = _t(name + ('enum',))
269 _h('typedef enum %s {', tname)
271 count = len(self.values)
273 for (enam, eval) in self.values:
275 equals = ' = ' if eval != '' else ''
276 comma = ',' if count > 0 else ''
278 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
279 doc = '\n/**< %s */\n' % self.doc.fields[enam]
280 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
284 def _c_type_setup(self, name, postfix):
286 Sets up all the C-related state by adding additional data fields to
287 all Field and Type objects. Here is where we figure out most of our
288 variable and function names.
290 Recurses into child fields and list member types.
292 # Do all the various names in advance
293 self.c_type = _t(name + postfix)
294 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
296 self.c_iterator_type = _t(name + ('iterator',))
297 self.c_next_name = _n(name + ('next',))
298 self.c_end_name = _n(name + ('end',))
300 self.c_request_name = _n(name)
301 self.c_checked_name = _n(name + ('checked',))
302 self.c_unchecked_name = _n(name + ('unchecked',))
303 self.c_reply_name = _n(name + ('reply',))
304 self.c_reply_type = _t(name + ('reply',))
305 self.c_cookie_type = _t(name + ('cookie',))
306 self.c_reply_fds_name = _n(name + ('reply_fds',))
308 self.c_need_aux = False
309 self.c_need_serialize = False
310 self.c_need_sizeof = False
312 self.c_aux_name = _n(name + ('aux',))
313 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
314 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
315 self.c_serialize_name = _n(name + ('serialize',))
316 self.c_unserialize_name = _n(name + ('unserialize',))
317 self.c_unpack_name = _n(name + ('unpack',))
318 self.c_sizeof_name = _n(name + ('sizeof',))
320 # special case: structs where variable size fields are followed by fixed size fields
321 self.c_var_followed_by_fixed_fields = False
324 self.c_need_serialize = True
325 self.c_container = 'struct'
326 for bitcase in self.bitcases:
327 bitcase.c_field_name = _cpp(bitcase.field_name)
328 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
329 _c_type_setup(bitcase.type, bitcase_name, ())
331 elif self.is_container:
333 self.c_container = 'union' if self.is_union else 'struct'
334 prev_varsized_field = None
335 prev_varsized_offset = 0
336 first_field_after_varsized = None
338 for field in self.fields:
339 field.c_field_type = _t(field.field_type)
340 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
341 field.c_field_name = _cpp(field.field_name)
342 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
343 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
345 # correct the c_pointer field for variable size non-list types
346 if not field.type.fixed_size() and field.c_pointer == ' ':
347 field.c_pointer = '*'
348 if field.type.is_list and not field.type.member.fixed_size():
349 field.c_pointer = '*'
351 if field.type.is_switch:
352 field.c_pointer = '*'
353 field.c_field_const_type = 'const ' + field.c_field_type
354 self.c_need_aux = True
356 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
357 self.c_need_sizeof = True
359 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
360 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
361 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
362 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
363 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
365 field.prev_varsized_field = prev_varsized_field
366 field.prev_varsized_offset = prev_varsized_offset
368 if prev_varsized_offset == 0:
369 first_field_after_varsized = field
370 field.first_field_after_varsized = first_field_after_varsized
372 if field.type.fixed_size():
373 prev_varsized_offset += field.type.size
374 # special case: intermixed fixed and variable size fields
375 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
376 if not self.is_union:
377 self.c_need_serialize = True
378 self.c_var_followed_by_fixed_fields = True
380 self.last_varsized_field = field
381 prev_varsized_field = field
382 prev_varsized_offset = 0
384 if self.c_var_followed_by_fixed_fields:
385 if field.type.fixed_size():
386 field.prev_varsized_field = None
388 # recurse into this field this has to be done here, i.e.,
389 # after the field has been set up. Otherwise the function
390 # _c_helper_absolute_name will produce garbage or crash
391 _c_type_setup(field.type, field.field_type, ())
392 if field.type.is_list:
393 _c_type_setup(field.type.member, field.field_type, ())
394 if (field.type.nmemb is None):
395 self.c_need_sizeof = True
397 if self.c_need_serialize:
398 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
399 self.c_need_sizeof = True
401 # as switch does never appear at toplevel,
402 # continue here with type construction
404 if self.c_type not in finished_switch:
405 finished_switch.append(self.c_type)
406 # special: switch C structs get pointer fields for variable-sized members
408 for bitcase in self.bitcases:
409 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
410 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
411 # no list with switch as element, so no call to
412 # _c_iterator(field.type, field_name) necessary
414 if not self.is_case_or_bitcase:
415 if self.c_need_serialize:
416 if self.c_serialize_name not in finished_serializers:
417 finished_serializers.append(self.c_serialize_name)
418 _c_serialize('serialize', self)
420 # _unpack() and _unserialize() are only needed for special cases:
422 # special cases -> unserialize
423 if self.is_switch or self.c_var_followed_by_fixed_fields:
424 _c_serialize('unserialize', self)
426 if self.c_need_sizeof:
427 if self.c_sizeof_name not in finished_sizeof:
428 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
429 finished_sizeof.append(self.c_sizeof_name)
430 _c_serialize('sizeof', self)
433 # Functions for querying field properties
434 def _c_field_needs_list_accessor(field):
435 return field.type.is_list and not field.type.fixed_size()
437 def _c_field_needs_field_accessor(field):
438 if field.type.is_list:
441 return (field.prev_varsized_field is not None or
442 not field.type.fixed_size())
444 def _c_field_needs_accessor(field):
445 return (_c_field_needs_list_accessor(field) or
446 _c_field_needs_field_accessor(field))
448 def _c_field_is_member_of_case_or_bitcase(field):
449 return field.parent and field.parent.is_case_or_bitcase
451 def _c_helper_absolute_name(prefix, field=None):
453 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
454 representing a valid name in C (based on the context)
455 if field is not None, append the field name as well
459 for name, sep, obj in prefix:
460 prefix_str += last_sep + name
463 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
464 (obj.is_switch and len(obj.parents)>1)):
469 # add separator for access to a yet unknown field
470 prefix_str += last_sep
472 if _c_field_needs_accessor(field):
473 if _c_field_is_member_of_case_or_bitcase(field):
474 # case members are available in the deserialized struct,
475 # so there is no need to use the accessor function
476 # (also, their accessor function needs a different arglist
477 # so this would require special treatment here)
478 # Therefore: Access as struct member
479 prefix_str += last_sep + _cpp(field.field_name)
481 # Access with the accessor function
482 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
484 # Access as struct member
485 prefix_str += last_sep + _cpp(field.field_name)
490 def _c_helper_field_mapping(complex_type, prefix, flat=False):
492 generate absolute names, based on prefix, for all fields starting from complex_type
493 if flat == True, nested complex types are not taken into account
496 if complex_type.is_switch:
497 for b in complex_type.bitcases:
499 switch_name, switch_sep, switch_type = prefix[-1]
500 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
502 bitcase_prefix = prefix
504 if (True==flat and not b.type.has_name) or False==flat:
505 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
507 for f in complex_type.fields:
508 fname = _c_helper_absolute_name(prefix, f)
509 if f.field_name in all_fields:
510 raise Exception("field name %s has been registered before" % f.field_name)
512 all_fields[f.field_name] = (fname, f)
513 if f.type.is_container and flat==False:
514 if f.type.is_case_or_bitcase and not f.type.has_name:
516 elif f.type.is_switch and len(f.type.parents)>1:
517 # nested switch gets another separator
518 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
520 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
521 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
526 def _c_helper_resolve_field_names (prefix):
528 get field names for all objects in the prefix array
532 # look for fields in the remaining containers
533 for idx, p in enumerate(prefix):
536 # sep can be preset in prefix, if not, make a sensible guess
537 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
538 # exception: 'toplevel' object (switch as well!) always have sep '->'
539 sep = '->' if idx<1 else sep
540 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
541 tmp_prefix.append((name, sep, obj))
542 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
545 # _c_helper_resolve_field_names
547 def get_expr_fields(self):
549 get the Fields referenced by switch or list expression
551 def get_expr_field_names(expr):
553 if expr.lenfield_name is not None:
554 return [expr.lenfield_name]
556 # constant value expr
560 return get_expr_field_names(expr.rhs)
561 elif expr.op == 'popcount':
562 return get_expr_field_names(expr.rhs)
563 elif expr.op == 'sumof':
564 # sumof expr references another list,
565 # we need that list's length field here
567 for f in expr.lenfield_parent.fields:
568 if f.field_name == expr.lenfield_name:
572 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
573 # referenced list + its length field
574 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
575 elif expr.op == 'enumref':
578 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
579 # get_expr_field_names()
581 # resolve the field names with the parent structure(s)
582 unresolved_fields_names = get_expr_field_names(self.expr)
584 # construct prefix from self
585 prefix = [('', '', p) for p in self.parents]
586 if self.is_container:
587 prefix.append(('', '', self))
589 all_fields = _c_helper_resolve_field_names (prefix)
590 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
591 if len(unresolved_fields_names) != len(resolved_fields_names):
592 raise Exception("could not resolve all fields for %s" % self.name)
594 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
595 return resolved_fields
598 def resolve_expr_fields(complex_obj):
600 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
601 these are normally fields that need to be given as function parameters
607 for field in complex_obj.fields:
608 all_fields.append(field)
609 if field.type.is_switch or field.type.is_list:
610 expr_fields += get_expr_fields(field.type)
611 if field.type.is_container:
612 expr_fields += resolve_expr_fields(field.type)
614 # try to resolve expr fields
615 for e in expr_fields:
616 if e not in all_fields and e not in unresolved:
619 # resolve_expr_fields()
621 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
623 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
624 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
625 expression. This function tries to resolve all fields within a structure, and returns the
626 unresolved fields as the list of external parameters.
628 def add_param(params, param):
629 if param not in params:
632 # collect all fields into param_fields
636 for field in self.fields:
638 # the field should appear as a parameter in the function call
639 param_fields.append(field)
640 if field.wire and not field.auto:
641 if field.type.fixed_size() and not self.is_switch:
642 # field in the xcb_out structure
643 wire_fields.append(field)
644 # fields like 'pad0' are skipped!
646 # in case of switch, parameters always contain any fields referenced in the switch expr
647 # we do not need any variable size fields here, as the switch data type contains both
648 # fixed and variable size fields
650 param_fields = get_expr_fields(self)
652 # _serialize()/_unserialize()/_unpack() function parameters
653 # note: don't use set() for params, it is unsorted
656 # 1. the parameter for the void * buffer
657 if 'serialize' == context:
658 params.append(('void', '**', buffer_var))
659 elif context in ('unserialize', 'unpack', 'sizeof'):
660 params.append(('const void', '*', buffer_var))
662 # 2. any expr fields that cannot be resolved within self and descendants
663 unresolved_fields = resolve_expr_fields(self)
664 for f in unresolved_fields:
665 add_param(params, (f.c_field_type, '', f.c_field_name))
667 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
668 # that do not appear in the data type struct
669 for p in param_fields:
671 typespec = p.c_field_const_type
672 pointerspec = p.c_pointer
673 add_param(params, (typespec, pointerspec, p.c_field_name))
675 if p.visible and not p.wire and not p.auto:
676 typespec = p.c_field_type
678 add_param(params, (typespec, pointerspec, p.c_field_name))
681 if 'serialize' == context:
682 add_param(params, ('const %s' % self.c_type, '*', aux_var))
683 elif 'unserialize' == context:
684 add_param(params, ('%s' % self.c_type, '**', aux_var))
685 elif 'unpack' == context:
686 add_param(params, ('%s' % self.c_type, '*', aux_var))
688 # 5. switch contains all variable size fields as struct members
689 # for other data types though, these have to be supplied separately
690 # this is important for the special case of intermixed fixed and
691 # variable size fields
692 if not self.is_switch and 'serialize' == context:
693 for p in param_fields:
694 if not p.type.fixed_size():
695 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
697 return (param_fields, wire_fields, params)
698 # get_serialize_params()
700 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
701 code_lines.append('%s /* insert padding */' % space)
702 if is_case_or_bitcase:
704 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
708 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
709 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
710 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
713 code_lines.append('%s if (0 != xcb_pad) {' % space)
715 if 'serialize' == context:
716 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
717 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
718 code_lines.append('%s xcb_parts_idx++;' % space)
719 elif context in ('unserialize', 'unpack', 'sizeof'):
720 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
722 code_lines.append('%s xcb_pad = 0;' % space)
723 code_lines.append('%s }' % space)
725 code_lines.append('%s xcb_block_len = 0;' % space)
726 if is_case_or_bitcase:
727 code_lines.append('%s xcb_padding_offset = 0;' % space)
729 # keep tracking of xcb_parts entries for serialize
731 # _c_serialize_helper_insert_padding()
733 def _c_serialize_helper_switch(context, self, complex_name,
734 code_lines, temp_vars,
737 switch_expr = _c_accessor_get_expr(self.expr, None)
739 for b in self.bitcases:
740 len_expr = len(b.type.expr)
742 compare_operator = '&'
744 compare_operator = '=='
746 compare_operator = '&'
748 for n, expr in enumerate(b.type.expr):
749 bitcase_expr = _c_accessor_get_expr(expr, None)
750 # only one <enumref> in the <bitcase>
753 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
754 # multiple <enumref> in the <bitcase>
757 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
758 elif len_expr == (n + 1): # last
760 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
761 else: # between first and last
763 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
767 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
769 count += _c_serialize_helper_fields(context, b.type,
770 code_lines, temp_vars,
773 is_case_or_bitcase = True)
774 code_lines.append(' }')
776 # if 'serialize' == context:
777 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
778 # elif context in ('unserialize', 'unpack', 'sizeof'):
780 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
781 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
784 # _c_serialize_helper_switch
786 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
788 handle switch by calling _serialize() or _unpack(), depending on context
790 # switch is handled by this function as a special case
791 param_fields, wire_fields, params = get_serialize_params(context, self)
792 field_mapping = _c_helper_field_mapping(self, prefix)
793 prefix_str = _c_helper_absolute_name(prefix)
795 # find the parameters that need to be passed to _serialize()/_unpack():
796 # all switch expr fields must be given as parameters
797 args = get_expr_fields(field.type)
798 # length fields for variable size types in switch, normally only some of need
799 # need to be passed as parameters
800 switch_len_fields = resolve_expr_fields(field.type)
802 # a switch field at this point _must_ be a bitcase field
803 # we require that bitcases are "self-contiguous"
804 bitcase_unresolved = resolve_expr_fields(self)
805 if len(bitcase_unresolved) != 0:
806 raise Exception('unresolved fields within bitcase is not supported at this point')
808 # get the C names for the parameters
810 for a in switch_len_fields:
811 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
813 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
815 # call _serialize()/_unpack() to determine the actual size
816 if 'serialize' == context:
817 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
818 c_field_names, prefix_str, field.c_field_name)
819 elif context in ('unserialize', 'unpack'):
820 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
821 c_field_names, prefix_str, field.c_field_name)
822 elif 'sizeof' == context:
823 # remove trailing ", " from c_field_names because it will be used at end of arglist
824 my_c_field_names = c_field_names[:-2]
825 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
828 # _c_serialize_helper_switch_field()
830 def _c_serialize_helper_list_field(context, self, field,
831 code_lines, temp_vars,
834 helper function to cope with lists of variable length
836 expr = field.type.expr
837 prefix_str = _c_helper_absolute_name(prefix)
838 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
839 param_names = [p[2] for p in params]
841 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
842 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
843 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
847 field_mapping[r] = (r, None)
849 if len(unresolved)>0:
851 if len(tmp_prefix)==0:
852 raise Exception("found an empty prefix while resolving expr field names for list %s",
855 field_mapping.update(_c_helper_resolve_field_names(prefix))
856 resolved += list(filter(lambda x: x in field_mapping, unresolved))
857 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
858 if len(unresolved)>0:
859 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
861 list_length = _c_accessor_get_expr(expr, field_mapping)
863 # default: list with fixed size elements
864 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
866 # list with variable-sized elements
867 if not field.type.member.fixed_size():
869 if context in ('unserialize', 'sizeof', 'unpack'):
870 int_i = ' unsigned int i;'
871 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
872 if int_i not in temp_vars:
873 temp_vars.append(int_i)
874 if xcb_tmp_len not in temp_vars:
875 temp_vars.append(xcb_tmp_len)
876 # loop over all list elements and call sizeof repeatedly
877 # this should be a bit faster than using the iterators
878 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
879 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
880 (space, field.type.c_sizeof_name))
881 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
882 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
883 code_lines.append("%s }" % space)
885 elif 'serialize' == context:
886 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
887 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
888 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
889 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
890 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
891 code_lines.append('%s }' % space)
892 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
895 # _c_serialize_helper_list_field()
897 def _c_serialize_helper_fields_fixed_size(context, self, field,
898 code_lines, temp_vars,
900 # keep the C code a bit more readable by giving the field name
901 if not self.is_case_or_bitcase:
902 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
904 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
905 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
906 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
908 abs_field_name = _c_helper_absolute_name(prefix, field)
909 # default for simple cases: call sizeof()
910 length = "sizeof(%s)" % field.c_field_type
912 if context in ('unserialize', 'unpack', 'sizeof'):
913 # default: simple cast
914 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
916 # padding - we could probably just ignore it
917 if field.type.is_pad and field.type.nmemb > 1:
919 for i in range(field.type.nmemb):
920 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
921 (space, abs_field_name, i, field.c_field_type))
922 # total padding = sizeof(pad0) * nmemb
923 length += " * %d" % field.type.nmemb
925 elif field.type.is_list:
926 # list with fixed number of elements
927 # length of array = sizeof(arrayElementType) * nmemb
928 length += " * %d" % field.type.nmemb
929 # use memcpy because C cannot assign whole arrays with operator=
930 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
933 elif 'serialize' == context:
934 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
936 if field.type.is_expr:
937 # need to register a temporary variable for the expression in case we know its type
938 if field.type.c_type is None:
939 raise Exception("type for field '%s' (expression '%s') unkown" %
940 (field.field_name, _c_accessor_get_expr(field.type.expr)))
942 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
943 _c_accessor_get_expr(field.type.expr, prefix)))
944 value += "&xcb_expr_%s;" % _cpp(field.field_name)
946 elif field.type.is_pad:
947 if field.type.nmemb == 1:
950 # we could also set it to 0, see definition of xcb_send_request()
951 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
952 length += "*%d" % field.type.nmemb
955 # non-list type with fixed size
956 if field.type.nmemb == 1:
957 value += "&%s;" % (abs_field_name)
959 # list with nmemb (fixed size) elements
961 value += '%s;' % (abs_field_name)
962 length = '%d' % field.type.nmemb
964 return (value, length)
965 # _c_serialize_helper_fields_fixed_size()
967 def _c_serialize_helper_fields_variable_size(context, self, field,
968 code_lines, temp_vars,
970 prefix_str = _c_helper_absolute_name(prefix)
972 if context in ('unserialize', 'unpack', 'sizeof'):
974 var_field_name = 'xcb_tmp'
976 # special case: intermixed fixed and variable size fields
977 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
978 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
979 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
980 # special case: switch
981 if 'unpack' == context:
982 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
984 elif 'serialize' == context:
985 # variable size fields appear as parameters to _serialize() if the
986 # 'toplevel' container is not a switch
987 prefix_string = prefix_str if prefix[0][2].is_switch else ''
988 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
989 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
993 code_lines.append('%s /* %s */' % (space, field.c_field_name))
995 if field.type.is_list:
997 # in any context, list is already a pointer, so the default assignment is ok
998 code_lines.append("%s%s" % (space, value))
1000 length = _c_serialize_helper_list_field(context, self, field,
1001 code_lines, temp_vars,
1004 elif field.type.is_switch:
1006 if context == 'serialize':
1007 # the _serialize() function allocates the correct amount memory if given a NULL pointer
1008 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1009 length = _c_serialize_helper_switch_field(context, self, field,
1010 'xcb_parts[xcb_parts_idx].iov_base',
1014 # in all remaining special cases - call _sizeof()
1015 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1017 return (value, length)
1018 # _c_serialize_helper_fields_variable_size
1020 def _c_serialize_helper_fields(context, self,
1021 code_lines, temp_vars,
1022 space, prefix, is_case_or_bitcase):
1024 need_padding = False
1025 prev_field_was_variable = False
1027 for field in self.fields:
1028 if not field.visible:
1029 if not ((field.wire and not field.auto) or 'unserialize' == context):
1032 # switch/bitcase: fixed size fields must be considered explicitly
1033 if field.type.fixed_size():
1034 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1035 if prev_field_was_variable and need_padding:
1037 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
1038 # self.c_var_followed_by_fixed_fields)
1039 prev_field_was_variable = False
1041 # prefix for fixed size fields
1042 fixed_prefix = prefix
1044 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1045 code_lines, temp_vars,
1046 space, fixed_prefix)
1050 # fields with variable size
1052 if field.type.is_pad:
1053 # Variable length pad is <pad align= />
1054 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1055 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1056 self.c_var_followed_by_fixed_fields,
1060 # switch/bitcase: always calculate padding before and after variable sized fields
1061 if need_padding or is_case_or_bitcase:
1062 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1063 self.c_var_followed_by_fixed_fields,
1066 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1067 code_lines, temp_vars,
1069 prev_field_was_variable = True
1071 # save (un)serialization C code
1073 code_lines.append('%s%s' % (space, value))
1075 if field.type.fixed_size():
1076 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1077 # keep track of (un)serialized object's size
1078 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1079 if context in ('unserialize', 'unpack', 'sizeof'):
1080 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1082 # variable size objects or bitcase:
1083 # value & length might have been inserted earlier for special cases
1085 # special case: intermixed fixed and variable size fields
1086 if (not field.type.fixed_size() and
1087 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1088 temp_vars.append(' int %s_len;' % field.c_field_name)
1089 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1090 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1091 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1093 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1094 # increase pointer into the byte stream accordingly
1095 if context in ('unserialize', 'sizeof', 'unpack'):
1096 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1098 if 'serialize' == context:
1100 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1101 code_lines.append('%s xcb_parts_idx++;' % space)
1105 '%s xcb_align_to = ALIGNOF(%s);'
1108 if field.c_field_type == 'void' or field.type.is_switch
1109 else field.c_field_type))
1112 if self.c_var_followed_by_fixed_fields:
1113 need_padding = False
1116 # _c_serialize_helper_fields()
1118 def _c_serialize_helper(context, complex_type,
1119 code_lines, temp_vars,
1120 space='', prefix=[]):
1121 # count tracks the number of fields to serialize
1124 if hasattr(complex_type, 'type'):
1125 self = complex_type.type
1126 complex_name = complex_type.name
1129 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1130 complex_name = 'xcb_out'
1132 complex_name = '_aux'
1134 # special case: switch is serialized by evaluating each bitcase separately
1136 count += _c_serialize_helper_switch(context, self, complex_name,
1137 code_lines, temp_vars,
1140 # all other data types can be evaluated one field a time
1142 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1143 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1144 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1145 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1146 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1147 code_lines.append('%s xcb_block_len = 0;' % space)
1149 count += _c_serialize_helper_fields(context, self,
1150 code_lines, temp_vars,
1151 space, prefix, False)
1153 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1156 # _c_serialize_helper()
1158 def _c_serialize(context, self):
1160 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1161 for the ComplexType variable self
1167 # _serialize() returns the buffer size
1170 if self.is_switch and 'unserialize' == context:
1173 cases = { 'serialize' : self.c_serialize_name,
1174 'unserialize' : self.c_unserialize_name,
1175 'unpack' : self.c_unpack_name,
1176 'sizeof' : self.c_sizeof_name }
1177 func_name = cases[context]
1179 param_fields, wire_fields, params = get_serialize_params(context, self)
1180 variable_size_fields = 0
1181 # maximum space required for type definition of function arguments
1184 # determine N(variable_fields)
1185 for field in param_fields:
1186 # if self.is_switch, treat all fields as if they are variable sized
1187 if not field.type.fixed_size() or self.is_switch:
1188 variable_size_fields += 1
1189 # determine maxtypelen
1191 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1194 indent = ' '*(len(func_name)+2)
1197 typespec, pointerspec, field_name = p
1198 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1199 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1200 # insert function name
1201 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1202 param_str = list(map(lambda x: "%s," % x, param_str))
1203 for s in param_str[:-1]:
1205 _h("%s);" % param_str[-1].rstrip(','))
1206 _c("%s)" % param_str[-1].rstrip(','))
1213 if 'serialize' == context:
1214 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1215 _c(' %s *xcb_out = *_buffer;', self.c_type)
1216 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1217 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1218 _c(' unsigned int xcb_align_to = 0;')
1220 _c(' char *xcb_out = *_buffer;')
1221 _c(' unsigned int xcb_buffer_len = 0;')
1222 _c(' unsigned int xcb_align_to = 0;')
1224 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1225 prefix = [('_aux', '->', self)]
1228 elif context in ('unserialize', 'unpack'):
1229 _c(' char *xcb_tmp = (char *)_buffer;')
1230 if not self.is_switch:
1231 if not self.c_var_followed_by_fixed_fields:
1232 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1233 prefix = [('_aux', '->', self)]
1235 _c(' %s xcb_out;', self.c_type)
1236 prefix = [('xcb_out', '.', self)]
1238 aux_var = '_aux' # default for unpack: single pointer
1239 # note: unserialize not generated for switch
1240 if 'unserialize' == context:
1241 aux_var = '(*_aux)' # unserialize: double pointer (!)
1242 prefix = [(aux_var, '->', self)]
1244 _c(' unsigned int xcb_buffer_len = 0;')
1245 _c(' unsigned int xcb_block_len = 0;')
1246 _c(' unsigned int xcb_pad = 0;')
1247 _c(' unsigned int xcb_align_to = 0;')
1249 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1251 elif 'sizeof' == context:
1252 param_names = [p[2] for p in params]
1254 # switch: call _unpack()
1255 _c(' %s _aux;', self.c_type)
1256 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1259 elif self.c_var_followed_by_fixed_fields:
1260 # special case: call _unserialize()
1261 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1265 _c(' char *xcb_tmp = (char *)_buffer;')
1266 prefix = [('_aux', '->', self)]
1268 _c(' unsigned int xcb_padding_offset = 0;')
1270 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1271 # update variable size fields (only important for context=='serialize'
1272 variable_size_fields = count
1273 if 'serialize' == context:
1274 temp_vars.append(' unsigned int xcb_pad = 0;')
1275 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1276 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1277 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1278 temp_vars.append(' unsigned int xcb_block_len = 0;')
1279 temp_vars.append(' unsigned int i;')
1280 temp_vars.append(' char *xcb_tmp;')
1281 elif 'sizeof' == context:
1282 # neither switch nor intermixed fixed and variable size fields:
1283 # evaluate parameters directly
1284 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1286 # look if we have to declare an '_aux' variable at all
1287 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1288 if not self.c_var_followed_by_fixed_fields:
1289 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1291 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1293 _c(' unsigned int xcb_buffer_len = 0;')
1294 _c(' unsigned int xcb_block_len = 0;')
1295 _c(' unsigned int xcb_pad = 0;')
1296 _c(' unsigned int xcb_align_to = 0;')
1302 for l in code_lines:
1305 # variable sized fields have been collected, now
1306 # allocate memory and copy everything into a continuous memory area
1307 # note: this is not necessary in case of unpack
1308 if context in ('serialize', 'unserialize'):
1309 # unserialize: check for sizeof-only invocation
1310 if 'unserialize' == context:
1312 _c(' if (NULL == _aux)')
1313 _c(' return xcb_buffer_len;')
1316 _c(' if (NULL == %s) {', aux_ptr)
1317 _c(' /* allocate memory */')
1318 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1319 if 'serialize' == context:
1320 _c(' *_buffer = xcb_out;')
1324 # serialize: handle variable size fields in a loop
1325 if 'serialize' == context:
1326 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1327 if len(wire_fields)>0:
1328 _c(' *xcb_out = *_aux;')
1329 # copy variable size fields into the buffer
1330 if variable_size_fields > 0:
1332 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1333 _c(' xcb_tmp = (char*)++xcb_out;')
1334 _c(' xcb_tmp += xcb_out_pad;')
1336 _c(' xcb_tmp = xcb_out;')
1338 # variable sized fields
1339 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1340 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1341 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1342 _c(' if (0 != xcb_parts[i].iov_len)')
1343 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1346 # unserialize: assign variable size fields individually
1347 if 'unserialize' == context:
1348 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1349 param_fields.reverse()
1350 for field in param_fields:
1351 if not field.type.fixed_size():
1352 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1353 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1354 _c(' *%s = xcb_out;', aux_ptr)
1357 _c(' return xcb_buffer_len;')
1361 def _c_iterator_get_end(field, accum):
1363 Figures out what C code is needed to find the end of a variable-length structure field.
1364 For nested structures, recurses into its last variable-sized field.
1365 For lists, calls the end function
1367 if field.type.is_container:
1368 accum = field.c_accessor_name + '(' + accum + ')'
1369 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1370 if field.type.is_list:
1371 # XXX we can always use the first way
1372 if field.type.member.is_simple:
1373 return field.c_end_name + '(' + accum + ')'
1375 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1377 def _c_iterator(self, name):
1379 Declares the iterator structure and next/end functions for a given type.
1384 _h(' * @brief %s', self.c_iterator_type)
1386 _h('typedef struct %s {', self.c_iterator_type)
1387 _h(' %s *data; /**< */', self.c_type)
1388 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1389 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1390 _h('} %s;', self.c_iterator_type)
1396 _h(' * Get the next element of the iterator')
1397 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1399 _h(' * Get the next element in the iterator. The member rem is')
1400 _h(' * decreased by one. The member data points to the next')
1401 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1405 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1406 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1409 if not self.fixed_size():
1410 _c(' %s *R = i->data;', self.c_type)
1413 # FIXME - how to determine the size of a variable size union??
1414 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1416 if self.c_need_sizeof:
1417 _c(' xcb_generic_iterator_t child;')
1418 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1419 self.c_type, self.c_sizeof_name)
1420 _c(' i->index = (char *) child.data - (char *) i->data;')
1422 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1423 _c(' i->index = child.index;')
1425 _c(' i->data = (%s *) child.data;', self.c_type)
1430 _c(' i->index += sizeof(%s);', self.c_type)
1436 _h(' * Return the iterator pointing to the last element')
1437 _h(' * @param i An %s', self.c_iterator_type)
1438 _h(' * @return The iterator pointing to the last element')
1440 _h(' * Set the current element in the iterator to the last element.')
1441 _h(' * The member rem is set to 0. The member data points to the')
1442 _h(' * last element.')
1445 _hc('xcb_generic_iterator_t')
1446 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1447 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1449 _c(' xcb_generic_iterator_t ret;')
1451 if self.fixed_size():
1452 _c(' ret.data = i.data + i.rem;')
1453 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1456 _c(' while(i.rem > 0)')
1457 _c(' %s(&i);', self.c_next_name)
1458 _c(' ret.data = i.data;')
1459 _c(' ret.rem = i.rem;')
1460 _c(' ret.index = i.index;')
1465 def _c_accessor_get_length(expr, field_mapping=None):
1467 Figures out what C code is needed to get a length field.
1468 The field_mapping parameter can be used to change the absolute name of a length field.
1469 For fields that follow a variable-length field, use the accessor.
1470 Otherwise, just reference the structure field directly.
1473 lenfield_name = expr.lenfield_name
1474 if lenfield_name is not None:
1475 if field_mapping is not None:
1476 lenfield_name = field_mapping[lenfield_name][0]
1478 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1479 # special case: variable and fixed size fields are intermixed
1480 # if the lenfield is among the fixed size fields, there is no need
1481 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1482 return field_mapping(expr.lenfield_name)
1483 elif expr.lenfield_name is not None:
1484 return lenfield_name
1486 return str(expr.nmemb)
1488 def _c_accessor_get_expr(expr, field_mapping):
1490 Figures out what C code is needed to get the length of a list field.
1491 The field_mapping parameter can be used to change the absolute name of a length field.
1492 Recurses for math operations.
1493 Returns bitcount for value-mask fields.
1494 Otherwise, uses the value of the length field.
1496 lenexp = _c_accessor_get_length(expr, field_mapping)
1499 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1500 elif expr.op == 'popcount':
1501 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1502 elif expr.op == 'enumref':
1503 enum_name = expr.lenfield_type.name
1504 constant_name = expr.lenfield_name
1505 c_name = _n(enum_name + (constant_name,)).upper()
1507 elif expr.op == 'sumof':
1508 # locate the referenced list object
1509 list_obj = expr.lenfield_type
1511 for f in expr.lenfield_parent.fields:
1512 if f.field_name == expr.lenfield_name:
1517 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1518 list_name = field_mapping[field.c_field_name][0]
1519 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1520 # note: xcb_sumof() has only been defined for integers
1521 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1522 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1523 elif expr.op != None:
1524 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1525 ' ' + expr.op + ' ' +
1526 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1528 return 'xcb_popcount(' + lenexp + ')'
1532 def type_pad_type(type):
1537 def _c_accessors_field(self, field):
1539 Declares the accessor functions for a non-list field that follows a variable-length field.
1541 c_type = self.c_type
1543 # special case: switch
1544 switch_obj = self if self.is_switch else None
1545 if self.is_case_or_bitcase:
1546 switch_obj = self.parents[-1]
1547 if switch_obj is not None:
1548 c_type = switch_obj.c_type
1550 if field.type.is_simple:
1552 _hc('%s', field.c_field_type)
1553 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1554 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1556 if field.prev_varsized_field is None:
1557 _c(' return (%s *) (R + 1);', field.c_field_type)
1559 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1560 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1561 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1565 if field.type.is_switch and switch_obj is None:
1566 return_type = 'void *'
1568 return_type = '%s *' % field.c_field_type
1571 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1572 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1574 if field.prev_varsized_field is None:
1575 _c(' return (%s) (R + 1);', return_type)
1576 # note: the special case 'variable fields followed by fixed size fields'
1577 # is not of any consequence here, since the ordering gets
1578 # 'corrected' in the reply function
1580 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1581 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1582 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1586 def _c_accessors_list(self, field):
1588 Declares the accessor functions for a list field.
1589 Declares a direct-accessor function only if the list members are fixed size.
1590 Declares length and get-iterator functions always.
1593 def get_align_pad(field):
1594 prev = field.prev_varsized_field
1595 prev_prev = field.prev_varsized_field.prev_varsized_field
1597 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1598 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1604 c_type = self.c_type
1606 # special case: switch
1607 # in case of switch, 2 params have to be supplied to certain accessor functions:
1608 # 1. the anchestor object (request or reply)
1609 # 2. the (anchestor) switch object
1610 # the reason is that switch is either a child of a request/reply or nested in another switch,
1611 # so whenever we need to access a length field, we might need to refer to some anchestor type
1612 switch_obj = self if self.is_switch else None
1613 if self.is_case_or_bitcase:
1614 switch_obj = self.parents[-1]
1615 if switch_obj is not None:
1616 c_type = switch_obj.c_type
1620 parents = self.parents if hasattr(self, 'parents') else [self]
1621 # 'R': parents[0] is always the 'toplevel' container type
1622 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1623 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1624 # auxiliary object for 'R' parameters
1627 if switch_obj is not None:
1628 # now look where the fields are defined that are needed to evaluate
1629 # the switch expr, and store the parent objects in accessor_params and
1630 # the fields in switch_fields
1632 # 'S': name for the 'toplevel' switch
1633 toplevel_switch = parents[1]
1634 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1635 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1637 # initialize prefix for everything "below" S
1638 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1639 prefix = [(prefix_str, '->', toplevel_switch)]
1641 # look for fields in the remaining containers
1642 for p in parents[2:] + [self]:
1643 # the separator between parent and child is always '.' here,
1644 # because of nested switch statements
1645 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1646 prefix.append((p.name[-1], '.', p))
1647 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1649 # auxiliary object for 'S' parameter
1654 if list.member.fixed_size():
1655 idx = 1 if switch_obj is not None else 0
1657 _hc('%s *', field.c_field_type)
1659 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1660 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1663 if switch_obj is not None:
1664 _c(' return %s;', fields[field.c_field_name][0])
1665 elif field.prev_varsized_field is None:
1666 _c(' return (%s *) (R + 1);', field.c_field_type)
1668 (prev_varsized_field, align_pad) = get_align_pad(field)
1670 if align_pad is None:
1671 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1672 type_pad_type(field.first_field_after_varsized.type.c_type))
1674 _c(' xcb_generic_iterator_t prev = %s;',
1675 _c_iterator_get_end(prev_varsized_field, 'R'))
1676 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1677 field.c_field_type, align_pad, field.prev_varsized_offset)
1682 if switch_obj is not None:
1683 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1684 spacing = ' '*(len(field.c_length_name)+2)
1685 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1686 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1687 length = _c_accessor_get_expr(field.type.expr, fields)
1689 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1690 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1691 length = _c_accessor_get_expr(field.type.expr, fields)
1693 _c(' return %s;', length)
1696 if field.type.member.is_simple:
1698 _hc('xcb_generic_iterator_t')
1699 if switch_obj is not None:
1700 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1701 spacing = ' '*(len(field.c_end_name)+2)
1702 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1703 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1705 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1706 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1708 _c(' xcb_generic_iterator_t i;')
1710 param = 'R' if switch_obj is None else 'S'
1711 if switch_obj is not None:
1712 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1713 _c_accessor_get_expr(field.type.expr, fields))
1714 elif field.prev_varsized_field == None:
1715 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1716 _c_accessor_get_expr(field.type.expr, fields))
1718 _c(' xcb_generic_iterator_t child = %s;',
1719 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1720 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1721 _c_accessor_get_expr(field.type.expr, fields))
1724 _c(' i.index = (char *) i.data - (char *) %s;', param)
1730 _hc('%s', field.c_iterator_type)
1731 if switch_obj is not None:
1732 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1733 spacing = ' '*(len(field.c_iterator_name)+2)
1734 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1735 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1737 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1738 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1740 _c(' %s i;', field.c_iterator_type)
1742 if switch_obj is not None:
1743 _c(' i.data = %s;', fields[field.c_field_name][0])
1744 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1745 elif field.prev_varsized_field == None:
1746 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1748 (prev_varsized_field, align_pad) = get_align_pad(field)
1750 if align_pad is None:
1751 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1752 type_pad_type(field.c_field_type))
1754 _c(' xcb_generic_iterator_t prev = %s;',
1755 _c_iterator_get_end(prev_varsized_field, 'R'))
1756 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1757 field.c_field_type, align_pad)
1759 if switch_obj is None:
1760 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1761 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1765 def _c_accessors(self, name, base):
1767 Declares the accessor functions for the fields of a structure.
1769 # no accessors for switch itself -
1770 # switch always needs to be unpacked explicitly
1771 # if self.is_switch:
1775 for field in self.fields:
1776 if not field.type.is_pad:
1777 if _c_field_needs_list_accessor(field):
1778 _c_accessors_list(self, field)
1779 elif _c_field_needs_field_accessor(field):
1780 _c_accessors_field(self, field)
1782 def c_simple(self, name):
1784 Exported function that handles cardinal type declarations.
1785 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1787 _c_type_setup(self, name, ())
1789 if (self.name != name):
1794 _h('typedef %s %s;', _t(self.name), my_name)
1797 _c_iterator(self, name)
1799 def _c_complex(self, force_packed = False):
1801 Helper function for handling all structure types.
1802 Called for all structs, requests, replies, events, errors.
1807 _h(' * @brief %s', self.c_type)
1809 _h('typedef %s %s {', self.c_container, self.c_type)
1815 for field in self.fields:
1816 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1817 varfield = field.c_field_name
1820 struct_fields.append(field)
1822 for field in struct_fields:
1823 length = len(field.c_field_type)
1824 # account for '*' pointer_spec
1825 if not field.type.fixed_size() and not self.is_union:
1827 maxtypelen = max(maxtypelen, length)
1829 def _c_complex_field(self, field, space=''):
1830 if (field.type.fixed_size() or self.is_union or
1831 # in case of switch with switch children, don't make the field a pointer
1832 # necessary for unserialize to work
1833 (self.is_switch and field.type.is_switch)):
1834 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1835 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1837 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1838 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1840 if not self.is_switch:
1841 for field in struct_fields:
1842 _c_complex_field(self, field)
1844 for b in self.bitcases:
1849 for field in b.type.fields:
1850 _c_complex_field(self, field, space)
1852 _h(' } %s;', b.c_field_name)
1854 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1856 def c_struct(self, name):
1858 Exported function that handles structure declarations.
1860 _c_type_setup(self, name, ())
1862 _c_accessors(self, name, name)
1863 _c_iterator(self, name)
1865 def c_union(self, name):
1867 Exported function that handles union declarations.
1869 _c_type_setup(self, name, ())
1871 _c_iterator(self, name)
1873 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1875 Declares a request function.
1878 # Four stunningly confusing possibilities here:
1881 # ------------------------------
1883 # 0 flag CHECKED flag Normal Mode
1884 # void_cookie req_cookie
1885 # ------------------------------
1886 # "req_checked" "req_unchecked"
1887 # CHECKED flag 0 flag Abnormal Mode
1888 # void_cookie req_cookie
1889 # ------------------------------
1892 # Whether we are _checked or _unchecked
1893 checked = void and not regular
1894 unchecked = not void and not regular
1896 # What kind of cookie we return
1897 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1899 # What flag is passed to xcb_request
1900 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1903 if func_flags == '0':
1904 func_flags = 'XCB_REQUEST_REPLY_FDS'
1906 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1908 # Global extension id variable or NULL for xproto
1909 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1911 # What our function name is
1912 func_name = self.c_request_name if not aux else self.c_aux_name
1914 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1916 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1920 maxtypelen = len('xcb_connection_t')
1922 # special case: list with variable size elements
1923 list_with_var_size_elems = False
1925 for field in self.fields:
1927 # The field should appear as a call parameter
1928 param_fields.append(field)
1929 if field.wire and not field.auto:
1930 # We need to set the field up in the structure
1931 wire_fields.append(field)
1932 if field.type.c_need_serialize or field.type.c_need_sizeof:
1933 serial_fields.append(field)
1935 for field in param_fields:
1936 c_field_const_type = field.c_field_const_type
1937 if field.type.c_need_serialize and not aux:
1938 c_field_const_type = "const void"
1939 if len(c_field_const_type) > maxtypelen:
1940 maxtypelen = len(c_field_const_type)
1941 if field.type.is_list and not field.type.member.fixed_size():
1942 list_with_var_size_elems = True
1948 if hasattr(self, "doc") and self.doc:
1950 _h(' * @brief ' + self.doc.brief)
1952 _h(' * No brief doc yet')
1955 _h(' * @param c The connection')
1956 param_names = [f.c_field_name for f in param_fields]
1957 if hasattr(self, "doc") and self.doc:
1958 for field in param_fields:
1959 # XXX: hard-coded until we fix xproto.xml
1960 base_func_name = self.c_request_name if not aux else self.c_aux_name
1961 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1963 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1965 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1968 # XXX: why the 'xcb' prefix?
1969 key = ('xcb', field.enum)
1972 if namecount[tname] > 1:
1973 tname = _t(key + ('enum',))
1974 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1976 if self.doc and field.field_name in self.doc.fields:
1977 desc = self.doc.fields[field.field_name]
1978 for name in param_names:
1979 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1980 desc = desc.split("\n")
1981 desc = [line if line != '' else '\\n' for line in desc]
1982 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1983 # If there is no documentation yet, we simply don't generate an
1984 # @param tag. Doxygen will then warn about missing documentation.
1986 _h(' * @return A cookie')
1989 if hasattr(self, "doc") and self.doc:
1990 if self.doc.description:
1991 desc = self.doc.description
1992 for name in param_names:
1993 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1994 desc = desc.split("\n")
1995 _h(' * ' + "\n * ".join(desc))
1997 _h(' * No description yet')
1999 _h(' * Delivers a request to the X server.')
2002 _h(' * This form can be used only if the request will not cause')
2003 _h(' * a reply to be generated. Any returned error will be')
2004 _h(' * saved for handling by xcb_request_check().')
2006 _h(' * This form can be used only if the request will cause')
2007 _h(' * a reply to be generated. Any returned error will be')
2008 _h(' * placed in the event queue.')
2011 _hc('%s', cookie_type)
2013 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2014 comma = ',' if len(param_fields) else ');'
2015 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2016 comma = ',' if len(param_fields) else ')'
2017 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
2019 func_spacing = ' ' * (len(func_name) + 2)
2020 count = len(param_fields)
2021 for field in param_fields:
2023 c_field_const_type = field.c_field_const_type
2024 c_pointer = field.c_pointer
2025 if field.type.c_need_serialize and not aux:
2026 c_field_const_type = "const void"
2028 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2029 comma = ',' if count else ');'
2030 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2031 spacing, c_pointer, field.c_field_name, comma)
2032 comma = ',' if count else ')'
2033 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2034 spacing, c_pointer, field.c_field_name, comma)
2037 if not self.c_var_followed_by_fixed_fields:
2038 for field in param_fields:
2039 if not field.type.fixed_size():
2041 if field.type.c_need_serialize:
2042 # _serialize() keeps track of padding automatically
2044 dimension = count + 2
2047 _c(' static const xcb_protocol_request_t xcb_req = {')
2048 _c(' /* count */ %d,', count)
2049 _c(' /* ext */ %s,', func_ext_global)
2050 _c(' /* opcode */ %s,', self.c_request_name.upper())
2051 _c(' /* isvoid */ %d', 1 if void else 0)
2055 _c(' struct iovec xcb_parts[%d];', dimension)
2056 _c(' %s xcb_ret;', func_cookie)
2057 _c(' %s xcb_out;', self.c_type)
2058 if self.c_var_followed_by_fixed_fields:
2059 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2060 _c(' void *xcb_aux = 0;')
2063 for idx, f in enumerate(serial_fields):
2065 _c(' void *xcb_aux%d = 0;' % (idx))
2066 if list_with_var_size_elems:
2067 _c(' unsigned int i;')
2068 _c(' unsigned int xcb_tmp_len;')
2069 _c(' char *xcb_tmp;')
2071 # simple request call tracing
2072 # _c(' printf("in function %s\\n");' % func_name)
2075 for field in wire_fields:
2076 if field.type.fixed_size():
2077 if field.type.is_expr:
2078 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2079 elif field.type.is_pad:
2080 if field.type.nmemb == 1:
2081 _c(' xcb_out.%s = 0;', field.c_field_name)
2083 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2085 if field.type.nmemb == 1:
2086 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2088 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2090 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2091 serialize_args = get_serialize_params(context, type_obj,
2094 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2096 # calls in order to free dyn. all. memory
2100 if not self.c_var_followed_by_fixed_fields:
2101 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2102 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2103 _c(' xcb_parts[3].iov_base = 0;')
2104 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2108 for field in param_fields:
2109 if not field.type.fixed_size():
2110 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2111 # default: simple cast to char *
2112 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2113 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2114 if field.type.is_list:
2115 if field.type.member.fixed_size():
2116 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2117 _c_accessor_get_expr(field.type.expr, None),
2118 field.type.member.c_wiretype)
2120 list_length = _c_accessor_get_expr(field.type.expr, None)
2123 _c(" xcb_parts[%d].iov_len = 0;" % count)
2124 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2125 _c(" for(i=0; i<%s; i++) {" % list_length)
2126 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2127 (field.type.c_sizeof_name))
2128 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2129 _c(" xcb_tmp += xcb_tmp_len;")
2132 # not supposed to happen
2133 raise Exception("unhandled variable size field %s" % field.c_field_name)
2136 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2137 idx = serial_fields.index(field)
2138 aux_var = '&xcb_aux%d' % idx
2139 context = 'serialize' if aux else 'sizeof'
2140 _c(' xcb_parts[%d].iov_len =', count)
2142 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2143 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2144 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2145 free_calls.append(' free(xcb_aux%d);' % idx)
2147 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2148 func_name = field.type.c_sizeof_name
2149 _c(' %s (%s);', func_name, serialize_args)
2152 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2153 # the _serialize() function keeps track of padding automatically
2154 _c(' xcb_parts[%d].iov_base = 0;', count)
2155 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2158 # elif self.c_var_followed_by_fixed_fields:
2160 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2161 # request header: opcodes + length
2162 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2165 buffer_var = '&xcb_aux'
2166 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2167 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2168 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2169 free_calls.append(' free(xcb_aux);')
2170 # no padding necessary - _serialize() keeps track of padding automatically
2173 for field in param_fields:
2175 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2177 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2179 # free dyn. all. data, if any
2180 for f in free_calls:
2182 _c(' return xcb_ret;')
2185 def _c_reply(self, name):
2187 Declares the function that returns the reply structure.
2189 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2190 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2191 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2193 # check if _unserialize() has to be called for any field
2194 def look_for_special_cases(complex_obj):
2195 unserialize_fields = []
2196 # no unserialize call in case of switch
2197 if not complex_obj.is_switch:
2198 for field in complex_obj.fields:
2199 # three cases: 1. field with special case
2200 # 2. container that contains special case field
2201 # 3. list with special case elements
2202 if field.type.c_var_followed_by_fixed_fields:
2203 unserialize_fields.append(field)
2204 elif field.type.is_container:
2205 unserialize_fields += look_for_special_cases(field.type)
2206 elif field.type.is_list:
2207 if field.type.member.c_var_followed_by_fixed_fields:
2208 unserialize_fields.append(field)
2209 if field.type.member.is_container:
2210 unserialize_fields += look_for_special_cases(field.type.member)
2211 return unserialize_fields
2213 unserialize_fields = look_for_special_cases(self.reply)
2217 _h(' * Return the reply')
2218 _h(' * @param c The connection')
2219 _h(' * @param cookie The cookie')
2220 _h(' * @param e The xcb_generic_error_t supplied')
2222 _h(' * Returns the reply of the request asked by')
2224 _h(' * The parameter @p e supplied to this function must be NULL if')
2225 _h(' * %s(). is used.', self.c_unchecked_name)
2226 _h(' * Otherwise, it stores the error if any.')
2228 _h(' * The returned value must be freed by the caller using free().')
2231 _hc('%s *', self.c_reply_type)
2232 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2233 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2234 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2235 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2238 if len(unserialize_fields)>0:
2239 # certain variable size fields need to be unserialized explicitly
2240 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2241 self.c_reply_type, self.c_reply_type)
2243 for field in unserialize_fields:
2244 if field.type.is_list:
2245 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2246 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2247 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2249 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2250 # call _unserialize(), using the reply as source and target buffer
2251 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2252 for field in unserialize_fields:
2253 if field.type.is_list:
2254 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2255 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2256 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2257 field.c_field_name, field.c_field_name)
2258 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2260 # return the transformed reply
2261 _c(' return reply;')
2264 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2268 def _c_reply_has_fds(self):
2269 for field in self.fields:
2274 def _c_reply_fds(self, name):
2276 Declares the function that returns fds related to the reply.
2278 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2279 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2282 _h(' * Return the reply fds')
2283 _h(' * @param c The connection')
2284 _h(' * @param reply The reply')
2286 _h(' * Returns the array of reply fds of the request asked by')
2288 _h(' * The returned value must be freed by the caller using free().')
2292 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2293 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2294 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2297 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2302 def _c_opcode(name, opcode):
2304 Declares the opcode define for requests, events, and errors.
2308 _h('/** Opcode for %s. */', _n(name))
2309 _h('#define %s %s', _n(name).upper(), opcode)
2311 def _c_cookie(self, name):
2313 Declares the cookie type for a non-void request.
2318 _h(' * @brief %s', self.c_cookie_type)
2320 _h('typedef struct %s {', self.c_cookie_type)
2321 _h(' unsigned int sequence; /**< */')
2322 _h('} %s;', self.c_cookie_type)
2324 def _man_request(self, name, cookie_type, void, aux):
2325 param_fields = [f for f in self.fields if f.visible]
2327 func_name = self.c_request_name if not aux else self.c_aux_name
2329 def create_link(linkname):
2330 name = 'man/%s.%s' % (linkname, section)
2332 sys.stdout.write(name)
2334 f.write('.so man%s/%s.%s' % (section, func_name, section))
2338 sys.stdout.write('man/%s.%s ' % (func_name, section))
2339 # Our CWD is src/, so this will end up in src/man/
2340 f = open('man/%s.%s' % (func_name, section), 'w')
2341 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2342 # Left-adjust instead of adjusting to both sides
2344 f.write('.SH NAME\n')
2345 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2346 f.write('%s \\- %s\n' % (func_name, brief))
2347 f.write('.SH SYNOPSIS\n')
2348 # Don't split words (hyphenate)
2350 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2352 # function prototypes
2354 count = len(param_fields)
2355 for field in param_fields:
2357 c_field_const_type = field.c_field_const_type
2358 c_pointer = field.c_pointer
2359 if c_pointer == ' ':
2361 if field.type.c_need_serialize and not aux:
2362 c_field_const_type = "const void"
2364 comma = ', ' if count else ');'
2365 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2367 f.write('.SS Request function\n')
2369 base_func_name = self.c_request_name if not aux else self.c_aux_name
2370 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2371 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2374 f.write('.SS Reply datastructure\n')
2377 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2381 for field in self.reply.fields:
2382 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2385 struct_fields.append(field)
2387 for field in struct_fields:
2388 length = len(field.c_field_type)
2389 # account for '*' pointer_spec
2390 if not field.type.fixed_size():
2392 maxtypelen = max(maxtypelen, length)
2394 def _c_complex_field(self, field, space=''):
2395 if (field.type.fixed_size() or
2396 # in case of switch with switch children, don't make the field a pointer
2397 # necessary for unserialize to work
2398 (self.is_switch and field.type.is_switch)):
2399 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2400 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2402 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2403 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2404 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2406 if not self.is_switch:
2407 for field in struct_fields:
2408 _c_complex_field(self, field)
2410 for b in self.bitcases:
2414 for field in b.type.fields:
2415 _c_complex_field(self, field, space)
2417 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2420 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2423 f.write('.SS Reply function\n')
2425 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2426 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2427 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2428 create_link('%s' % self.c_reply_name)
2430 has_accessors = False
2431 for field in self.reply.fields:
2432 if field.type.is_list and not field.type.fixed_size():
2433 has_accessors = True
2434 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2435 has_accessors = True
2438 f.write('.SS Reply accessors\n')
2440 def _c_accessors_field(self, field):
2442 Declares the accessor functions for a non-list field that follows a variable-length field.
2444 c_type = self.c_type
2446 # special case: switch
2447 switch_obj = self if self.is_switch else None
2448 if self.is_case_or_bitcase:
2449 switch_obj = self.parents[-1]
2450 if switch_obj is not None:
2451 c_type = switch_obj.c_type
2453 if field.type.is_simple:
2454 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2455 create_link('%s' % field.c_accessor_name)
2457 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2458 create_link('%s' % field.c_accessor_name)
2460 def _c_accessors_list(self, field):
2462 Declares the accessor functions for a list field.
2463 Declares a direct-accessor function only if the list members are fixed size.
2464 Declares length and get-iterator functions always.
2467 c_type = self.reply.c_type
2469 # special case: switch
2470 # in case of switch, 2 params have to be supplied to certain accessor functions:
2471 # 1. the anchestor object (request or reply)
2472 # 2. the (anchestor) switch object
2473 # the reason is that switch is either a child of a request/reply or nested in another switch,
2474 # so whenever we need to access a length field, we might need to refer to some anchestor type
2475 switch_obj = self if self.is_switch else None
2476 if self.is_case_or_bitcase:
2477 switch_obj = self.parents[-1]
2478 if switch_obj is not None:
2479 c_type = switch_obj.c_type
2483 parents = self.parents if hasattr(self, 'parents') else [self]
2484 # 'R': parents[0] is always the 'toplevel' container type
2485 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2486 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2487 # auxiliary object for 'R' parameters
2490 if switch_obj is not None:
2491 # now look where the fields are defined that are needed to evaluate
2492 # the switch expr, and store the parent objects in accessor_params and
2493 # the fields in switch_fields
2495 # 'S': name for the 'toplevel' switch
2496 toplevel_switch = parents[1]
2497 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2498 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2500 # initialize prefix for everything "below" S
2501 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2502 prefix = [(prefix_str, '->', toplevel_switch)]
2504 # look for fields in the remaining containers
2505 for p in parents[2:] + [self]:
2506 # the separator between parent and child is always '.' here,
2507 # because of nested switch statements
2508 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2509 prefix.append((p.name[-1], '.', p))
2510 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2512 # auxiliary object for 'S' parameter
2515 if list.member.fixed_size():
2516 idx = 1 if switch_obj is not None else 0
2518 f.write('%s *\\fB%s\\fP(%s);\n' %
2519 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2520 create_link('%s' % field.c_accessor_name)
2523 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2524 (field.c_length_name, c_type))
2525 create_link('%s' % field.c_length_name)
2527 if field.type.member.is_simple:
2529 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2530 (field.c_end_name, c_type))
2531 create_link('%s' % field.c_end_name)
2534 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2535 (field.c_iterator_type, field.c_iterator_name,
2537 create_link('%s' % field.c_iterator_name)
2539 for field in self.reply.fields:
2540 if field.type.is_list and not field.type.fixed_size():
2541 _c_accessors_list(self, field)
2542 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2543 _c_accessors_field(self, field)
2547 # Re-enable hyphenation and adjusting to both sides
2550 # argument reference
2551 f.write('.SH REQUEST ARGUMENTS\n')
2552 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2553 f.write('The XCB connection to X11.\n')
2554 for field in param_fields:
2555 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2556 printed_enum = False
2557 # XXX: hard-coded until we fix xproto.xml
2558 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2560 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2562 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2564 if hasattr(field, "enum") and field.enum:
2565 # XXX: why the 'xcb' prefix?
2566 key = ('xcb', field.enum)
2568 f.write('One of the following values:\n')
2571 count = len(enum.values)
2572 for (enam, eval) in enum.values:
2574 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2575 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2576 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2577 f.write('%s\n' % desc)
2579 f.write('TODO: NOT YET DOCUMENTED.\n')
2584 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2585 desc = self.doc.fields[field.field_name]
2586 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2589 f.write('%s\n' % desc)
2591 f.write('TODO: NOT YET DOCUMENTED.\n')
2597 f.write('.SH REPLY FIELDS\n')
2598 # These fields are present in every reply:
2599 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2600 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2601 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2602 'be used to tell replies apart from each other.\n') %
2603 _n(self.reply.name).upper())
2604 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2605 f.write('The sequence number of the last request processed by the X11 server.\n')
2606 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2607 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2608 for field in self.reply.fields:
2609 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2610 field.c_field_name.startswith('pad')):
2613 if field.type.is_list and not field.type.fixed_size():
2615 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2617 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2618 printed_enum = False
2619 if hasattr(field, "enum") and field.enum:
2620 # XXX: why the 'xcb' prefix?
2621 key = ('xcb', field.enum)
2623 f.write('One of the following values:\n')
2626 count = len(enum.values)
2627 for (enam, eval) in enum.values:
2629 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2630 if enum.doc and enam in enum.doc.fields:
2631 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2632 f.write('%s\n' % desc)
2634 f.write('TODO: NOT YET DOCUMENTED.\n')
2639 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2640 desc = self.reply.doc.fields[field.field_name]
2641 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2644 f.write('%s\n' % desc)
2646 f.write('TODO: NOT YET DOCUMENTED.\n')
2653 f.write('.SH DESCRIPTION\n')
2654 if hasattr(self, "doc") and self.doc and self.doc.description:
2655 desc = self.doc.description
2656 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2657 lines = desc.split('\n')
2658 f.write('\n'.join(lines) + '\n')
2660 f.write('.SH RETURN VALUE\n')
2662 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2663 'have to be handled in the event loop.\n\nIf you want to '
2664 'handle errors directly with \\fIxcb_request_check\\fP '
2665 'instead, use \\fI%s_checked\\fP. See '
2666 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2668 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2669 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2670 'handle errors in the event loop instead, use '
2671 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2673 (cookie_type, self.c_reply_name, base_func_name, section))
2674 f.write('.SH ERRORS\n')
2675 if hasattr(self, "doc") and self.doc:
2676 for errtype, errtext in sorted(self.doc.errors.items()):
2677 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2678 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2679 f.write('%s\n' % (errtext))
2680 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2681 f.write('This request does never generate any errors.\n')
2682 if hasattr(self, "doc") and self.doc and self.doc.example:
2683 f.write('.SH EXAMPLE\n')
2686 lines = self.doc.example.split('\n')
2687 f.write('\n'.join(lines) + '\n')
2689 f.write('.SH SEE ALSO\n')
2690 if hasattr(self, "doc") and self.doc:
2691 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2692 if self.doc.example:
2693 see.append('.BR %s (%s)' % ('xcb-examples', section))
2694 for seename, seetype in sorted(self.doc.see.items()):
2695 if seetype == 'program':
2696 see.append('.BR %s (1)' % seename)
2697 elif seetype == 'event':
2698 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2699 elif seetype == 'request':
2700 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2701 elif seetype == 'function':
2702 see.append('.BR %s (%s)' % (seename, section))
2704 see.append('TODO: %s (type %s)' % (seename, seetype))
2705 f.write(',\n'.join(see) + '\n')
2706 f.write('.SH AUTHOR\n')
2707 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2710 def _man_event(self, name):
2712 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2713 # Our CWD is src/, so this will end up in src/man/
2714 f = open('man/%s.%s' % (self.c_type, section), 'w')
2715 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2716 # Left-adjust instead of adjusting to both sides
2718 f.write('.SH NAME\n')
2719 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2720 f.write('%s \\- %s\n' % (self.c_type, brief))
2721 f.write('.SH SYNOPSIS\n')
2722 # Don't split words (hyphenate)
2724 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2727 f.write('.SS Event datastructure\n')
2730 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2734 for field in self.fields:
2735 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2738 struct_fields.append(field)
2740 for field in struct_fields:
2741 length = len(field.c_field_type)
2742 # account for '*' pointer_spec
2743 if not field.type.fixed_size():
2745 maxtypelen = max(maxtypelen, length)
2747 def _c_complex_field(self, field, space=''):
2748 if (field.type.fixed_size() or
2749 # in case of switch with switch children, don't make the field a pointer
2750 # necessary for unserialize to work
2751 (self.is_switch and field.type.is_switch)):
2752 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2753 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2755 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2757 if not self.is_switch:
2758 for field in struct_fields:
2759 _c_complex_field(self, field)
2761 for b in self.bitcases:
2765 for field in b.type.fields:
2766 _c_complex_field(self, field, space)
2768 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2771 f.write('} \\fB%s\\fP;\n' % self.c_type)
2776 # Re-enable hyphenation and adjusting to both sides
2779 # argument reference
2780 f.write('.SH EVENT FIELDS\n')
2781 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2782 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2783 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2784 'to tell events apart from each other.\n') % _n(name).upper())
2785 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2786 f.write('The sequence number of the last request processed by the X11 server.\n')
2788 if not self.is_switch:
2789 for field in struct_fields:
2790 # Skip the fields which every event has, we already documented
2792 if field.c_field_name in ('response_type', 'sequence'):
2794 if isinstance(field.type, PadType):
2796 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2797 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2798 desc = self.doc.fields[field.field_name]
2799 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2800 f.write('%s\n' % desc)
2802 f.write('NOT YET DOCUMENTED.\n')
2805 f.write('.SH DESCRIPTION\n')
2806 if hasattr(self, "doc") and self.doc and self.doc.description:
2807 desc = self.doc.description
2808 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2809 lines = desc.split('\n')
2810 f.write('\n'.join(lines) + '\n')
2812 if hasattr(self, "doc") and self.doc and self.doc.example:
2813 f.write('.SH EXAMPLE\n')
2816 lines = self.doc.example.split('\n')
2817 f.write('\n'.join(lines) + '\n')
2819 f.write('.SH SEE ALSO\n')
2820 if hasattr(self, "doc") and self.doc:
2821 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2822 if self.doc.example:
2823 see.append('.BR %s (%s)' % ('xcb-examples', section))
2824 for seename, seetype in sorted(self.doc.see.items()):
2825 if seetype == 'program':
2826 see.append('.BR %s (1)' % seename)
2827 elif seetype == 'event':
2828 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2829 elif seetype == 'request':
2830 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2831 elif seetype == 'function':
2832 see.append('.BR %s (%s)' % (seename, section))
2834 see.append('TODO: %s (type %s)' % (seename, seetype))
2835 f.write(',\n'.join(see) + '\n')
2836 f.write('.SH AUTHOR\n')
2837 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2841 def c_request(self, name):
2843 Exported function that handles request declarations.
2845 _c_type_setup(self, name, ('request',))
2848 # Cookie type declaration
2849 _c_cookie(self, name)
2852 _c_opcode(name, self.opcode)
2854 # Request structure declaration
2858 _c_type_setup(self.reply, name, ('reply',))
2859 # Reply structure definition
2860 _c_complex(self.reply)
2861 # Request prototypes
2862 has_fds = _c_reply_has_fds(self.reply)
2863 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2864 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2866 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2867 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2869 _c_accessors(self.reply, name + ('reply',), name)
2870 _c_reply(self, name)
2872 _c_reply_fds(self, name)
2874 # Request prototypes
2875 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2876 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2878 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2879 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2881 # We generate the manpage afterwards because _c_type_setup has been called.
2882 # TODO: what about aux helpers?
2883 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2884 _man_request(self, name, cookie_type, not self.reply, False)
2886 def c_event(self, name):
2888 Exported function that handles event declarations.
2891 # The generic event structure xcb_ge_event_t has the full_sequence field
2892 # at the 32byte boundary. That's why we've to inject this field into GE
2893 # events while generating the structure for them. Otherwise we would read
2894 # garbage (the internal full_sequence) when accessing normal event fields
2896 force_packed = False
2897 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2899 for field in self.fields:
2900 if field.type.size != None and field.type.nmemb != None:
2901 event_size += field.type.size * field.type.nmemb
2902 if event_size == 32:
2903 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2904 idx = self.fields.index(field)
2905 self.fields.insert(idx + 1, full_sequence)
2907 # If the event contains any 64-bit extended fields, they need
2908 # to remain aligned on a 64-bit boundary. Adding full_sequence
2909 # would normally break that; force the struct to be packed.
2910 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
2913 _c_type_setup(self, name, ('event',))
2916 _c_opcode(name, self.opcodes[name])
2918 if self.name == name:
2919 # Structure definition
2920 _c_complex(self, force_packed)
2924 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2926 _man_event(self, name)
2928 def c_error(self, name):
2930 Exported function that handles error declarations.
2932 _c_type_setup(self, name, ('error',))
2935 _c_opcode(name, self.opcodes[name])
2937 if self.name == name:
2938 # Structure definition
2943 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2946 # Main routine starts here
2948 # Must create an "output" dictionary before any xcbgen imports.
2949 output = {'open' : c_open,
2951 'simple' : c_simple,
2953 'struct' : c_struct,
2955 'request' : c_request,
2960 # Boilerplate below this point
2962 # Check for the argument that specifies path to the xcbgen python package.
2964 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
2965 except getopt.GetoptError as err:
2967 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
2970 for (opt, arg) in opts:
2978 sys.path.insert(1, arg)
2981 sys.stdout.write('man_MANS = ')
2983 # Import the module class
2985 from xcbgen.state import Module
2986 from xcbgen.xtypes import *
2989 Failed to load the xcbgen Python package!
2990 Make sure that xcb/proto installed it on your Python path.
2991 If not, you will need to create a .pth file or define $PYTHONPATH
2993 Refer to the README file in xcb/proto for more info.
2997 # Ensure the man subdirectory exists
3000 except OSError as e:
3001 if e.errno != errno.EEXIST:
3004 # Parse the xml header
3005 module = Module(args[0], output)
3007 # Build type-registry and resolve type dependencies