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.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',))
307 self.need_aux = False
308 self.need_serialize = False
309 self.need_sizeof = False
311 self.c_aux_name = _n(name + ('aux',))
312 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
313 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
314 self.c_serialize_name = _n(name + ('serialize',))
315 self.c_unserialize_name = _n(name + ('unserialize',))
316 self.c_unpack_name = _n(name + ('unpack',))
317 self.c_sizeof_name = _n(name + ('sizeof',))
319 # special case: structs where variable size fields are followed by fixed size fields
320 self.var_followed_by_fixed_fields = False
323 self.need_serialize = True
324 self.c_container = 'struct'
325 for bitcase in self.bitcases:
326 bitcase.c_field_name = _cpp(bitcase.field_name)
327 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
328 _c_type_setup(bitcase.type, bitcase_name, ())
330 elif self.is_container:
332 self.c_container = 'union' if self.is_union else 'struct'
333 prev_varsized_field = None
334 prev_varsized_offset = 0
335 first_field_after_varsized = None
337 for field in self.fields:
338 _c_type_setup(field.type, field.field_type, ())
339 if field.type.is_list:
340 _c_type_setup(field.type.member, field.field_type, ())
341 if (field.type.nmemb is None):
342 self.need_sizeof = True
344 field.c_field_type = _t(field.field_type)
345 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
346 field.c_field_name = _cpp(field.field_name)
347 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
348 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
350 # correct the c_pointer field for variable size non-list types
351 if not field.type.fixed_size() and field.c_pointer == ' ':
352 field.c_pointer = '*'
353 if field.type.is_list and not field.type.member.fixed_size():
354 field.c_pointer = '*'
356 if field.type.is_switch:
357 field.c_pointer = '*'
358 field.c_field_const_type = 'const ' + field.c_field_type
360 elif not field.type.fixed_size() and not field.type.is_bitcase:
361 self.need_sizeof = True
363 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
364 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
365 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
366 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
367 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
369 field.prev_varsized_field = prev_varsized_field
370 field.prev_varsized_offset = prev_varsized_offset
372 if prev_varsized_offset == 0:
373 first_field_after_varsized = field
374 field.first_field_after_varsized = first_field_after_varsized
376 if field.type.fixed_size():
377 prev_varsized_offset += field.type.size
378 # special case: intermixed fixed and variable size fields
379 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
380 if not self.is_union:
381 self.need_serialize = True
382 self.var_followed_by_fixed_fields = True
384 self.last_varsized_field = field
385 prev_varsized_field = field
386 prev_varsized_offset = 0
388 if self.var_followed_by_fixed_fields:
389 if field.type.fixed_size():
390 field.prev_varsized_field = None
392 if self.need_serialize:
393 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
394 self.need_sizeof = True
396 # as switch does never appear at toplevel,
397 # continue here with type construction
399 if self.c_type not in finished_switch:
400 finished_switch.append(self.c_type)
401 # special: switch C structs get pointer fields for variable-sized members
403 for bitcase in self.bitcases:
404 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
405 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
406 # no list with switch as element, so no call to
407 # _c_iterator(field.type, field_name) necessary
409 if not self.is_bitcase:
410 if self.need_serialize:
411 if self.c_serialize_name not in finished_serializers:
412 finished_serializers.append(self.c_serialize_name)
413 _c_serialize('serialize', self)
415 # _unpack() and _unserialize() are only needed for special cases:
417 # special cases -> unserialize
418 if self.is_switch or self.var_followed_by_fixed_fields:
419 _c_serialize('unserialize', self)
422 if self.c_sizeof_name not in finished_sizeof:
423 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
424 finished_sizeof.append(self.c_sizeof_name)
425 _c_serialize('sizeof', self)
428 def _c_helper_absolute_name(prefix, field=None):
430 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
431 representing a valid name in C (based on the context)
432 if field is not None, append the field name as well
435 for name, sep, obj in prefix:
439 if ((obj.is_bitcase and obj.has_name) or # named bitcase
440 (obj.is_switch and len(obj.parents)>1)):
443 if field is not None:
444 prefix_str += _cpp(field.field_name)
448 def _c_helper_field_mapping(complex_type, prefix, flat=False):
450 generate absolute names, based on prefix, for all fields starting from complex_type
451 if flat == True, nested complex types are not taken into account
454 if complex_type.is_switch:
455 for b in complex_type.bitcases:
457 switch_name, switch_sep, switch_type = prefix[-1]
458 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
460 bitcase_prefix = prefix
462 if (True==flat and not b.type.has_name) or False==flat:
463 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
465 for f in complex_type.fields:
466 fname = _c_helper_absolute_name(prefix, f)
467 if f.field_name in all_fields:
468 raise Exception("field name %s has been registered before" % f.field_name)
470 all_fields[f.field_name] = (fname, f)
471 if f.type.is_container and flat==False:
472 if f.type.is_bitcase and not f.type.has_name:
474 elif f.type.is_switch and len(f.type.parents)>1:
475 # nested switch gets another separator
476 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
478 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
479 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
484 def _c_helper_resolve_field_names (prefix):
486 get field names for all objects in the prefix array
490 # look for fields in the remaining containers
491 for idx, p in enumerate(prefix):
494 # sep can be preset in prefix, if not, make a sensible guess
495 sep = '.' if (obj.is_switch or obj.is_bitcase) else '->'
496 # exception: 'toplevel' object (switch as well!) always have sep '->'
497 sep = '->' if idx<1 else sep
498 if not obj.is_bitcase or (obj.is_bitcase and obj.has_name):
499 tmp_prefix.append((name, sep, obj))
500 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
503 # _c_helper_resolve_field_names
505 def get_expr_fields(self):
507 get the Fields referenced by switch or list expression
509 def get_expr_field_names(expr):
511 if expr.lenfield_name is not None:
512 return [expr.lenfield_name]
514 # constant value expr
518 return get_expr_field_names(expr.rhs)
519 elif expr.op == 'popcount':
520 return get_expr_field_names(expr.rhs)
521 elif expr.op == 'sumof':
522 # sumof expr references another list,
523 # we need that list's length field here
525 for f in expr.lenfield_parent.fields:
526 if f.field_name == expr.lenfield_name:
530 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
531 # referenced list + its length field
532 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
533 elif expr.op == 'enumref':
536 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
537 # get_expr_field_names()
539 # resolve the field names with the parent structure(s)
540 unresolved_fields_names = get_expr_field_names(self.expr)
542 # construct prefix from self
543 prefix = [('', '', p) for p in self.parents]
544 if self.is_container:
545 prefix.append(('', '', self))
547 all_fields = _c_helper_resolve_field_names (prefix)
548 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
549 if len(unresolved_fields_names) != len(resolved_fields_names):
550 raise Exception("could not resolve all fields for %s" % self.name)
552 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
553 return resolved_fields
556 def resolve_expr_fields(complex_obj):
558 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
559 these are normally fields that need to be given as function parameters
565 for field in complex_obj.fields:
566 all_fields.append(field)
567 if field.type.is_switch or field.type.is_list:
568 expr_fields += get_expr_fields(field.type)
569 if field.type.is_container:
570 expr_fields += resolve_expr_fields(field.type)
572 # try to resolve expr fields
573 for e in expr_fields:
574 if e not in all_fields and e not in unresolved:
577 # resolve_expr_fields()
579 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
581 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
582 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
583 expression. This function tries to resolve all fields within a structure, and returns the
584 unresolved fields as the list of external parameters.
586 def add_param(params, param):
587 if param not in params:
590 # collect all fields into param_fields
594 for field in self.fields:
596 # the field should appear as a parameter in the function call
597 param_fields.append(field)
598 if field.wire and not field.auto:
599 if field.type.fixed_size() and not self.is_switch:
600 # field in the xcb_out structure
601 wire_fields.append(field)
602 # fields like 'pad0' are skipped!
604 # in case of switch, parameters always contain any fields referenced in the switch expr
605 # we do not need any variable size fields here, as the switch data type contains both
606 # fixed and variable size fields
608 param_fields = get_expr_fields(self)
610 # _serialize()/_unserialize()/_unpack() function parameters
611 # note: don't use set() for params, it is unsorted
614 # 1. the parameter for the void * buffer
615 if 'serialize' == context:
616 params.append(('void', '**', buffer_var))
617 elif context in ('unserialize', 'unpack', 'sizeof'):
618 params.append(('const void', '*', buffer_var))
620 # 2. any expr fields that cannot be resolved within self and descendants
621 unresolved_fields = resolve_expr_fields(self)
622 for f in unresolved_fields:
623 add_param(params, (f.c_field_type, '', f.c_field_name))
625 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
626 # that do not appear in the data type struct
627 for p in param_fields:
629 typespec = p.c_field_const_type
630 pointerspec = p.c_pointer
631 add_param(params, (typespec, pointerspec, p.c_field_name))
633 if p.visible and not p.wire and not p.auto:
634 typespec = p.c_field_type
636 add_param(params, (typespec, pointerspec, p.c_field_name))
639 if 'serialize' == context:
640 add_param(params, ('const %s' % self.c_type, '*', aux_var))
641 elif 'unserialize' == context:
642 add_param(params, ('%s' % self.c_type, '**', aux_var))
643 elif 'unpack' == context:
644 add_param(params, ('%s' % self.c_type, '*', aux_var))
646 # 5. switch contains all variable size fields as struct members
647 # for other data types though, these have to be supplied separately
648 # this is important for the special case of intermixed fixed and
649 # variable size fields
650 if not self.is_switch and 'serialize' == context:
651 for p in param_fields:
652 if not p.type.fixed_size():
653 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
655 return (param_fields, wire_fields, params)
656 # get_serialize_params()
658 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
659 code_lines.append('%s /* insert padding */' % space)
660 code_lines.append('%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
661 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
662 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
665 code_lines.append('%s if (0 != xcb_pad) {' % space)
667 if 'serialize' == context:
668 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
669 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
670 code_lines.append('%s xcb_parts_idx++;' % space)
671 elif context in ('unserialize', 'unpack', 'sizeof'):
672 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
674 code_lines.append('%s xcb_pad = 0;' % space)
675 code_lines.append('%s }' % space)
677 code_lines.append('%s xcb_block_len = 0;' % space)
679 # keep tracking of xcb_parts entries for serialize
681 # _c_serialize_helper_insert_padding()
683 def _c_serialize_helper_switch(context, self, complex_name,
684 code_lines, temp_vars,
687 switch_expr = _c_accessor_get_expr(self.expr, None)
689 for b in self.bitcases:
690 len_expr = len(b.type.expr)
691 for n, expr in enumerate(b.type.expr):
692 bitcase_expr = _c_accessor_get_expr(expr, None)
693 # only one <enumref> in the <bitcase>
695 code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
696 # multiple <enumref> in the <bitcase>
698 code_lines.append(' if((%s & %s) ||' % (switch_expr, bitcase_expr))
699 elif len_expr == (n + 1): # last
700 code_lines.append(' (%s & %s)) {' % (switch_expr, bitcase_expr))
701 else: # between first and last
702 code_lines.append(' (%s & %s) ||' % (switch_expr, bitcase_expr))
706 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
708 count += _c_serialize_helper_fields(context, b.type,
709 code_lines, temp_vars,
713 code_lines.append(' }')
715 # if 'serialize' == context:
716 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
717 # elif context in ('unserialize', 'unpack', 'sizeof'):
719 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
720 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
723 # _c_serialize_helper_switch
725 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
727 handle switch by calling _serialize() or _unpack(), depending on context
729 # switch is handled by this function as a special case
730 param_fields, wire_fields, params = get_serialize_params(context, self)
731 field_mapping = _c_helper_field_mapping(self, prefix)
732 prefix_str = _c_helper_absolute_name(prefix)
734 # find the parameters that need to be passed to _serialize()/_unpack():
735 # all switch expr fields must be given as parameters
736 args = get_expr_fields(field.type)
737 # length fields for variable size types in switch, normally only some of need
738 # need to be passed as parameters
739 switch_len_fields = resolve_expr_fields(field.type)
741 # a switch field at this point _must_ be a bitcase field
742 # we require that bitcases are "self-contiguous"
743 bitcase_unresolved = resolve_expr_fields(self)
744 if len(bitcase_unresolved) != 0:
745 raise Exception('unresolved fields within bitcase is not supported at this point')
747 # get the C names for the parameters
749 for a in switch_len_fields:
750 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
752 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
754 # call _serialize()/_unpack() to determine the actual size
755 if 'serialize' == context:
756 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
757 c_field_names, prefix_str, field.c_field_name)
758 elif context in ('unserialize', 'unpack'):
759 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
760 c_field_names, prefix_str, field.c_field_name)
763 # _c_serialize_helper_switch_field()
765 def _c_serialize_helper_list_field(context, self, field,
766 code_lines, temp_vars,
769 helper function to cope with lists of variable length
771 expr = field.type.expr
772 prefix_str = _c_helper_absolute_name(prefix)
773 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
774 param_names = [p[2] for p in params]
776 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
777 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
778 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
782 field_mapping[r] = (r, None)
784 if len(unresolved)>0:
786 if len(tmp_prefix)==0:
787 raise Exception("found an empty prefix while resolving expr field names for list %s",
790 field_mapping.update(_c_helper_resolve_field_names(prefix))
791 resolved += list(filter(lambda x: x in field_mapping, unresolved))
792 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
793 if len(unresolved)>0:
794 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
796 list_length = _c_accessor_get_expr(expr, field_mapping)
798 # default: list with fixed size elements
799 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
801 # list with variable-sized elements
802 if not field.type.member.fixed_size():
804 if context in ('unserialize', 'sizeof', 'unpack'):
805 int_i = ' unsigned int i;'
806 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
807 if int_i not in temp_vars:
808 temp_vars.append(int_i)
809 if xcb_tmp_len not in temp_vars:
810 temp_vars.append(xcb_tmp_len)
811 # loop over all list elements and call sizeof repeatedly
812 # this should be a bit faster than using the iterators
813 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
814 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
815 (space, field.type.c_sizeof_name))
816 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
817 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
818 code_lines.append("%s }" % space)
820 elif 'serialize' == context:
821 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
822 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
823 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
824 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
825 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
826 code_lines.append('%s }' % space)
827 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
830 # _c_serialize_helper_list_field()
832 def _c_serialize_helper_fields_fixed_size(context, self, field,
833 code_lines, temp_vars,
835 # keep the C code a bit more readable by giving the field name
836 if not self.is_bitcase:
837 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
839 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
840 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
841 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
843 abs_field_name = _c_helper_absolute_name(prefix, field)
844 # default for simple cases: call sizeof()
845 length = "sizeof(%s)" % field.c_field_type
847 if context in ('unserialize', 'unpack', 'sizeof'):
848 # default: simple cast
849 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
851 # padding - we could probably just ignore it
852 if field.type.is_pad and field.type.nmemb > 1:
854 for i in range(field.type.nmemb):
855 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
856 (space, abs_field_name, i, field.c_field_type))
857 # total padding = sizeof(pad0) * nmemb
858 length += " * %d" % field.type.nmemb
860 if field.type.is_list:
861 # no such case in the protocol, cannot be tested and therefore ignored for now
862 raise Exception('list with fixed number of elemens unhandled in _unserialize()')
864 elif 'serialize' == context:
865 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
867 if field.type.is_expr:
868 # need to register a temporary variable for the expression in case we know its type
869 if field.type.c_type is None:
870 raise Exception("type for field '%s' (expression '%s') unkown" %
871 (field.field_name, _c_accessor_get_expr(field.type.expr)))
873 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
874 _c_accessor_get_expr(field.type.expr, prefix)))
875 value += "&xcb_expr_%s;" % _cpp(field.field_name)
877 elif field.type.is_pad:
878 if field.type.nmemb == 1:
881 # we could also set it to 0, see definition of xcb_send_request()
882 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
883 length += "*%d" % field.type.nmemb
886 # non-list type with fixed size
887 if field.type.nmemb == 1:
888 value += "&%s;" % (abs_field_name)
890 # list with nmemb (fixed size) elements
892 value += '%s;' % (abs_field_name)
893 length = '%d' % field.type.nmemb
895 return (value, length)
896 # _c_serialize_helper_fields_fixed_size()
898 def _c_serialize_helper_fields_variable_size(context, self, field,
899 code_lines, temp_vars,
901 prefix_str = _c_helper_absolute_name(prefix)
903 if context in ('unserialize', 'unpack', 'sizeof'):
905 var_field_name = 'xcb_tmp'
907 # special case: intermixed fixed and variable size fields
908 if self.var_followed_by_fixed_fields and 'unserialize' == context:
909 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
910 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
911 # special case: switch
912 if 'unpack' == context:
913 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
915 elif 'serialize' == context:
916 # variable size fields appear as parameters to _serialize() if the
917 # 'toplevel' container is not a switch
918 prefix_string = prefix_str if prefix[0][2].is_switch else ''
919 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
920 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
924 code_lines.append('%s /* %s */' % (space, field.c_field_name))
926 if field.type.is_list:
928 # in any context, list is already a pointer, so the default assignment is ok
929 code_lines.append("%s%s" % (space, value))
931 length = _c_serialize_helper_list_field(context, self, field,
932 code_lines, temp_vars,
935 elif field.type.is_switch:
937 if context == 'serialize':
938 # the _serialize() function allocates the correct amount memory if given a NULL pointer
939 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
940 length = _c_serialize_helper_switch_field(context, self, field,
941 'xcb_parts[xcb_parts_idx].iov_base',
945 # in all remaining special cases - call _sizeof()
946 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
948 return (value, length)
949 # _c_serialize_helper_fields_variable_size
951 def _c_serialize_helper_fields(context, self,
952 code_lines, temp_vars,
953 space, prefix, is_bitcase):
956 prev_field_was_variable = False
958 for field in self.fields:
959 if not field.visible:
960 if not ((field.wire and not field.auto) or 'unserialize' == context):
963 # switch/bitcase: fixed size fields must be considered explicitly
964 if field.type.fixed_size():
965 if self.is_bitcase or self.var_followed_by_fixed_fields:
966 if prev_field_was_variable and need_padding:
968 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
969 # self.var_followed_by_fixed_fields)
970 prev_field_was_variable = False
972 # prefix for fixed size fields
973 fixed_prefix = prefix
975 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
976 code_lines, temp_vars,
981 # fields with variable size
983 # switch/bitcase: always calculate padding before and after variable sized fields
984 if need_padding or is_bitcase:
985 count += _c_serialize_helper_insert_padding(context, code_lines, space,
986 self.var_followed_by_fixed_fields)
988 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
989 code_lines, temp_vars,
991 prev_field_was_variable = True
993 # save (un)serialization C code
995 code_lines.append('%s%s' % (space, value))
997 if field.type.fixed_size():
998 if is_bitcase or self.var_followed_by_fixed_fields:
999 # keep track of (un)serialized object's size
1000 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1001 if context in ('unserialize', 'unpack', 'sizeof'):
1002 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1004 # variable size objects or bitcase:
1005 # value & length might have been inserted earlier for special cases
1007 # special case: intermixed fixed and variable size fields
1008 if (not field.type.fixed_size() and
1009 self.var_followed_by_fixed_fields and 'unserialize' == context):
1010 temp_vars.append(' int %s_len;' % field.c_field_name)
1011 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1012 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1013 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1015 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1016 # increase pointer into the byte stream accordingly
1017 if context in ('unserialize', 'sizeof', 'unpack'):
1018 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1020 if 'serialize' == context:
1022 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1023 code_lines.append('%s xcb_parts_idx++;' % space)
1026 code_lines.append('%s xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1029 if self.var_followed_by_fixed_fields:
1030 need_padding = False
1033 # _c_serialize_helper_fields()
1035 def _c_serialize_helper(context, complex_type,
1036 code_lines, temp_vars,
1037 space='', prefix=[]):
1038 # count tracks the number of fields to serialize
1041 if hasattr(complex_type, 'type'):
1042 self = complex_type.type
1043 complex_name = complex_type.name
1046 if self.var_followed_by_fixed_fields and 'unserialize' == context:
1047 complex_name = 'xcb_out'
1049 complex_name = '_aux'
1051 # special case: switch is serialized by evaluating each bitcase separately
1053 count += _c_serialize_helper_switch(context, self, complex_name,
1054 code_lines, temp_vars,
1057 # all other data types can be evaluated one field a time
1059 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1060 if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
1061 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1062 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1063 # probably not needed
1064 #_c_serialize_helper_insert_padding(context, code_lines, space, False)
1066 count += _c_serialize_helper_fields(context, self,
1067 code_lines, temp_vars,
1068 space, prefix, False)
1070 count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1073 # _c_serialize_helper()
1075 def _c_serialize(context, self):
1077 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1078 for the ComplexType variable self
1084 # _serialize() returns the buffer size
1087 if self.is_switch and 'unserialize' == context:
1090 cases = { 'serialize' : self.c_serialize_name,
1091 'unserialize' : self.c_unserialize_name,
1092 'unpack' : self.c_unpack_name,
1093 'sizeof' : self.c_sizeof_name }
1094 func_name = cases[context]
1096 param_fields, wire_fields, params = get_serialize_params(context, self)
1097 variable_size_fields = 0
1098 # maximum space required for type definition of function arguments
1101 # determine N(variable_fields)
1102 for field in param_fields:
1103 # if self.is_switch, treat all fields as if they are variable sized
1104 if not field.type.fixed_size() or self.is_switch:
1105 variable_size_fields += 1
1106 # determine maxtypelen
1108 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1111 indent = ' '*(len(func_name)+2)
1114 typespec, pointerspec, field_name = p
1115 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1116 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1117 # insert function name
1118 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1119 param_str = list(map(lambda x: "%s," % x, param_str))
1120 for s in param_str[:-1]:
1122 _h("%s);" % param_str[-1].rstrip(','))
1123 _c("%s)" % param_str[-1].rstrip(','))
1130 if 'serialize' == context:
1131 if not self.is_switch and not self.var_followed_by_fixed_fields:
1132 _c(' %s *xcb_out = *_buffer;', self.c_type)
1133 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1134 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1135 _c(' unsigned int xcb_align_to;')
1137 _c(' char *xcb_out = *_buffer;')
1138 _c(' unsigned int xcb_buffer_len = 0;')
1139 _c(' unsigned int xcb_align_to;')
1140 prefix = [('_aux', '->', self)]
1143 elif context in ('unserialize', 'unpack'):
1144 _c(' char *xcb_tmp = (char *)_buffer;')
1145 if not self.is_switch:
1146 if not self.var_followed_by_fixed_fields:
1147 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1148 prefix = [('_aux', '->', self)]
1150 _c(' %s xcb_out;', self.c_type)
1151 prefix = [('xcb_out', '.', self)]
1153 aux_var = '_aux' # default for unpack: single pointer
1154 # note: unserialize not generated for switch
1155 if 'unserialize' == context:
1156 aux_var = '(*_aux)' # unserialize: double pointer (!)
1157 prefix = [(aux_var, '->', self)]
1159 _c(' unsigned int xcb_buffer_len = 0;')
1160 _c(' unsigned int xcb_block_len = 0;')
1161 _c(' unsigned int xcb_pad = 0;')
1162 _c(' unsigned int xcb_align_to;')
1164 elif 'sizeof' == context:
1165 param_names = [p[2] for p in params]
1167 # switch: call _unpack()
1168 _c(' %s _aux;', self.c_type)
1169 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1172 elif self.var_followed_by_fixed_fields:
1173 # special case: call _unserialize()
1174 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1178 _c(' char *xcb_tmp = (char *)_buffer;')
1179 prefix = [('_aux', '->', self)]
1181 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1182 # update variable size fields (only important for context=='serialize'
1183 variable_size_fields = count
1184 if 'serialize' == context:
1185 temp_vars.append(' unsigned int xcb_pad = 0;')
1186 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1187 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1188 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1189 temp_vars.append(' unsigned int xcb_block_len = 0;')
1190 temp_vars.append(' unsigned int i;')
1191 temp_vars.append(' char *xcb_tmp;')
1192 elif 'sizeof' == context:
1193 # neither switch nor intermixed fixed and variable size fields:
1194 # evaluate parameters directly
1195 if not (self.is_switch or self.var_followed_by_fixed_fields):
1197 # look if we have to declare an '_aux' variable at all
1198 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1199 if not self.var_followed_by_fixed_fields:
1200 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1202 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1204 _c(' unsigned int xcb_buffer_len = 0;')
1205 _c(' unsigned int xcb_block_len = 0;')
1206 _c(' unsigned int xcb_pad = 0;')
1207 _c(' unsigned int xcb_align_to;')
1213 for l in code_lines:
1216 # variable sized fields have been collected, now
1217 # allocate memory and copy everything into a continuous memory area
1218 # note: this is not necessary in case of unpack
1219 if context in ('serialize', 'unserialize'):
1220 # unserialize: check for sizeof-only invocation
1221 if 'unserialize' == context:
1223 _c(' if (NULL == _aux)')
1224 _c(' return xcb_buffer_len;')
1227 _c(' if (NULL == %s) {', aux_ptr)
1228 _c(' /* allocate memory */')
1229 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1230 if 'serialize' == context:
1231 _c(' *_buffer = xcb_out;')
1235 # serialize: handle variable size fields in a loop
1236 if 'serialize' == context:
1237 if not self.is_switch and not self.var_followed_by_fixed_fields:
1238 if len(wire_fields)>0:
1239 _c(' *xcb_out = *_aux;')
1240 # copy variable size fields into the buffer
1241 if variable_size_fields > 0:
1243 if not self.is_switch and not self.var_followed_by_fixed_fields:
1244 _c(' xcb_tmp = (char*)++xcb_out;')
1245 _c(' xcb_tmp += xcb_out_pad;')
1247 _c(' xcb_tmp = xcb_out;')
1249 # variable sized fields
1250 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1251 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1252 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1253 _c(' if (0 != xcb_parts[i].iov_len)')
1254 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1257 # unserialize: assign variable size fields individually
1258 if 'unserialize' == context:
1259 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1260 param_fields.reverse()
1261 for field in param_fields:
1262 if not field.type.fixed_size():
1263 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1264 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1265 _c(' *%s = xcb_out;', aux_ptr)
1268 _c(' return xcb_buffer_len;')
1272 def _c_iterator_get_end(field, accum):
1274 Figures out what C code is needed to find the end of a variable-length structure field.
1275 For nested structures, recurses into its last variable-sized field.
1276 For lists, calls the end function
1278 if field.type.is_container:
1279 accum = field.c_accessor_name + '(' + accum + ')'
1280 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1281 if field.type.is_list:
1282 # XXX we can always use the first way
1283 if field.type.member.is_simple:
1284 return field.c_end_name + '(' + accum + ')'
1286 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1288 def _c_iterator(self, name):
1290 Declares the iterator structure and next/end functions for a given type.
1295 _h(' * @brief %s', self.c_iterator_type)
1297 _h('typedef struct %s {', self.c_iterator_type)
1298 _h(' %s *data; /**< */', self.c_type)
1299 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1300 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1301 _h('} %s;', self.c_iterator_type)
1307 _h(' * Get the next element of the iterator')
1308 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1310 _h(' * Get the next element in the iterator. The member rem is')
1311 _h(' * decreased by one. The member data points to the next')
1312 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1316 _hc('/*****************************************************************************')
1318 _hc(' ** void %s', self.c_next_name)
1320 _hc(' ** @param %s *i', self.c_iterator_type)
1321 _hc(' ** @returns void')
1323 _hc(' *****************************************************************************/')
1326 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1327 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1330 if not self.fixed_size():
1331 _c(' %s *R = i->data;', self.c_type)
1334 # FIXME - how to determine the size of a variable size union??
1335 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1337 if self.need_sizeof:
1338 _c(' xcb_generic_iterator_t child;')
1339 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1340 self.c_type, self.c_sizeof_name)
1341 _c(' i->index = (char *) child.data - (char *) i->data;')
1343 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1344 _c(' i->index = child.index;')
1346 _c(' i->data = (%s *) child.data;', self.c_type)
1351 _c(' i->index += sizeof(%s);', self.c_type)
1357 _h(' * Return the iterator pointing to the last element')
1358 _h(' * @param i An %s', self.c_iterator_type)
1359 _h(' * @return The iterator pointing to the last element')
1361 _h(' * Set the current element in the iterator to the last element.')
1362 _h(' * The member rem is set to 0. The member data points to the')
1363 _h(' * last element.')
1367 _hc('/*****************************************************************************')
1369 _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1371 _hc(' ** @param %s i', self.c_iterator_type)
1372 _hc(' ** @returns xcb_generic_iterator_t')
1374 _hc(' *****************************************************************************/')
1376 _hc('xcb_generic_iterator_t')
1377 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1378 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1380 _c(' xcb_generic_iterator_t ret;')
1382 if self.fixed_size():
1383 _c(' ret.data = i.data + i.rem;')
1384 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1387 _c(' while(i.rem > 0)')
1388 _c(' %s(&i);', self.c_next_name)
1389 _c(' ret.data = i.data;')
1390 _c(' ret.rem = i.rem;')
1391 _c(' ret.index = i.index;')
1396 def _c_accessor_get_length(expr, field_mapping=None):
1398 Figures out what C code is needed to get a length field.
1399 The field_mapping parameter can be used to change the absolute name of a length field.
1400 For fields that follow a variable-length field, use the accessor.
1401 Otherwise, just reference the structure field directly.
1404 lenfield_name = expr.lenfield_name
1405 if lenfield_name is not None:
1406 if field_mapping is not None:
1407 lenfield_name = field_mapping[lenfield_name][0]
1409 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1410 # special case: variable and fixed size fields are intermixed
1411 # if the lenfield is among the fixed size fields, there is no need
1412 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1413 return field_mapping(expr.lenfield_name)
1414 elif expr.lenfield_name is not None:
1415 return lenfield_name
1417 return str(expr.nmemb)
1419 def _c_accessor_get_expr(expr, field_mapping):
1421 Figures out what C code is needed to get the length of a list field.
1422 The field_mapping parameter can be used to change the absolute name of a length field.
1423 Recurses for math operations.
1424 Returns bitcount for value-mask fields.
1425 Otherwise, uses the value of the length field.
1427 lenexp = _c_accessor_get_length(expr, field_mapping)
1430 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1431 elif expr.op == 'popcount':
1432 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1433 elif expr.op == 'enumref':
1434 enum_name = expr.lenfield_type.name
1435 constant_name = expr.lenfield_name
1436 c_name = _n(enum_name + (constant_name,)).upper()
1438 elif expr.op == 'sumof':
1439 # locate the referenced list object
1440 list_obj = expr.lenfield_type
1442 for f in expr.lenfield_parent.fields:
1443 if f.field_name == expr.lenfield_name:
1448 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1449 list_name = field_mapping[field.c_field_name][0]
1450 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1451 # note: xcb_sumof() has only been defined for integers
1452 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1453 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1454 elif expr.op != None:
1455 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1456 ' ' + expr.op + ' ' +
1457 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1459 return 'xcb_popcount(' + lenexp + ')'
1463 def type_pad_type(type):
1468 def _c_accessors_field(self, field):
1470 Declares the accessor functions for a non-list field that follows a variable-length field.
1472 c_type = self.c_type
1474 # special case: switch
1475 switch_obj = self if self.is_switch else None
1477 switch_obj = self.parents[-1]
1478 if switch_obj is not None:
1479 c_type = switch_obj.c_type
1481 if field.type.is_simple:
1484 _hc('/*****************************************************************************')
1486 _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1488 _hc(' ** @param const %s *R', c_type)
1489 _hc(' ** @returns %s', field.c_field_type)
1491 _hc(' *****************************************************************************/')
1493 _hc('%s', field.c_field_type)
1494 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1495 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1497 if field.prev_varsized_field is None:
1498 _c(' return (%s *) (R + 1);', field.c_field_type)
1500 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1501 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1502 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1507 _hc('/*****************************************************************************')
1509 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1511 _hc(' ** @param const %s *R', c_type)
1512 _hc(' ** @returns %s *', field.c_field_type)
1514 _hc(' *****************************************************************************/')
1516 if field.type.is_switch and switch_obj is None:
1517 return_type = 'void *'
1519 return_type = '%s *' % field.c_field_type
1522 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1523 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1525 if field.prev_varsized_field is None:
1526 _c(' return (%s) (R + 1);', return_type)
1527 # note: the special case 'variable fields followed by fixed size fields'
1528 # is not of any consequence here, since the ordering gets
1529 # 'corrected' in the reply function
1531 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1532 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1533 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1537 def _c_accessors_list(self, field):
1539 Declares the accessor functions for a list field.
1540 Declares a direct-accessor function only if the list members are fixed size.
1541 Declares length and get-iterator functions always.
1544 c_type = self.c_type
1546 # special case: switch
1547 # in case of switch, 2 params have to be supplied to certain accessor functions:
1548 # 1. the anchestor object (request or reply)
1549 # 2. the (anchestor) switch object
1550 # the reason is that switch is either a child of a request/reply or nested in another switch,
1551 # so whenever we need to access a length field, we might need to refer to some anchestor type
1552 switch_obj = self if self.is_switch else None
1554 switch_obj = self.parents[-1]
1555 if switch_obj is not None:
1556 c_type = switch_obj.c_type
1560 parents = self.parents if hasattr(self, 'parents') else [self]
1561 # 'R': parents[0] is always the 'toplevel' container type
1562 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1563 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1564 # auxiliary object for 'R' parameters
1567 if switch_obj is not None:
1568 # now look where the fields are defined that are needed to evaluate
1569 # the switch expr, and store the parent objects in accessor_params and
1570 # the fields in switch_fields
1572 # 'S': name for the 'toplevel' switch
1573 toplevel_switch = parents[1]
1574 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1575 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1577 # initialize prefix for everything "below" S
1578 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1579 prefix = [(prefix_str, '->', toplevel_switch)]
1581 # look for fields in the remaining containers
1582 for p in parents[2:] + [self]:
1583 # the separator between parent and child is always '.' here,
1584 # because of nested switch statements
1585 if not p.is_bitcase or (p.is_bitcase and p.has_name):
1586 prefix.append((p.name[-1], '.', p))
1587 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1589 # auxiliary object for 'S' parameter
1594 if list.member.fixed_size():
1595 idx = 1 if switch_obj is not None else 0
1598 _hc('/*****************************************************************************')
1600 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1602 _hc(' ** @param %s', params[idx][0])
1603 _hc(' ** @returns %s *', field.c_field_type)
1605 _hc(' *****************************************************************************/')
1607 _hc('%s *', field.c_field_type)
1609 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1610 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1613 if switch_obj is not None:
1614 _c(' return %s;', fields[field.c_field_name][0])
1615 elif field.prev_varsized_field is None:
1616 _c(' return (%s *) (R + 1);', field.c_field_type)
1618 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1619 _c(' return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1620 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1625 _hc('/*****************************************************************************')
1627 _hc(' ** int %s', field.c_length_name)
1629 _hc(' ** @param const %s *R', c_type)
1630 _hc(' ** @returns int')
1632 _hc(' *****************************************************************************/')
1635 if switch_obj is not None:
1636 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1637 spacing = ' '*(len(field.c_length_name)+2)
1638 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1639 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1640 length = _c_accessor_get_expr(field.type.expr, fields)
1642 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1643 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1644 length = _c_accessor_get_expr(field.type.expr, fields)
1646 _c(' return %s;', length)
1649 if field.type.member.is_simple:
1652 _hc('/*****************************************************************************')
1654 _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1656 _hc(' ** @param const %s *R', c_type)
1657 _hc(' ** @returns xcb_generic_iterator_t')
1659 _hc(' *****************************************************************************/')
1661 _hc('xcb_generic_iterator_t')
1662 if switch_obj is not None:
1663 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1664 spacing = ' '*(len(field.c_end_name)+2)
1665 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1666 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1668 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1669 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1671 _c(' xcb_generic_iterator_t i;')
1673 param = 'R' if switch_obj is None else 'S'
1674 if switch_obj is not None:
1675 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1676 _c_accessor_get_expr(field.type.expr, fields))
1677 elif field.prev_varsized_field == None:
1678 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1679 _c_accessor_get_expr(field.type.expr, fields))
1681 _c(' xcb_generic_iterator_t child = %s;',
1682 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1683 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1684 _c_accessor_get_expr(field.type.expr, fields))
1687 _c(' i.index = (char *) i.data - (char *) %s;', param)
1694 _hc('/*****************************************************************************')
1696 _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1698 _hc(' ** @param const %s *R', c_type)
1699 _hc(' ** @returns %s', field.c_iterator_type)
1701 _hc(' *****************************************************************************/')
1704 _hc('%s', field.c_iterator_type)
1705 if switch_obj is not None:
1706 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1707 spacing = ' '*(len(field.c_iterator_name)+2)
1708 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1709 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1711 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1712 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1714 _c(' %s i;', field.c_iterator_type)
1716 if switch_obj is not None:
1717 _c(' i.data = %s;', fields[field.c_field_name][0])
1718 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1719 elif field.prev_varsized_field == None:
1720 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1722 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1723 _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));',
1724 field.c_field_type, type_pad_type(field.c_field_type))
1725 if switch_obj is None:
1726 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1727 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1731 def _c_accessors(self, name, base):
1733 Declares the accessor functions for the fields of a structure.
1735 # no accessors for switch itself -
1736 # switch always needs to be unpacked explicitly
1737 # if self.is_switch:
1741 for field in self.fields:
1742 if field.type.is_list and not field.type.fixed_size():
1743 _c_accessors_list(self, field)
1744 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1745 _c_accessors_field(self, field)
1747 def c_simple(self, name):
1749 Exported function that handles cardinal type declarations.
1750 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1752 _c_type_setup(self, name, ())
1754 if (self.name != name):
1759 _h('typedef %s %s;', _t(self.name), my_name)
1762 _c_iterator(self, name)
1764 def _c_complex(self):
1766 Helper function for handling all structure types.
1767 Called for all structs, requests, replies, events, errors.
1772 _h(' * @brief %s', self.c_type)
1774 _h('typedef %s %s {', self.c_container, self.c_type)
1780 for field in self.fields:
1781 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1782 varfield = field.c_field_name
1785 struct_fields.append(field)
1787 for field in struct_fields:
1788 length = len(field.c_field_type)
1789 # account for '*' pointer_spec
1790 if not field.type.fixed_size():
1792 maxtypelen = max(maxtypelen, length)
1794 def _c_complex_field(self, field, space=''):
1795 if (field.type.fixed_size() or
1796 # in case of switch with switch children, don't make the field a pointer
1797 # necessary for unserialize to work
1798 (self.is_switch and field.type.is_switch)):
1799 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1800 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1802 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1803 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1805 if not self.is_switch:
1806 for field in struct_fields:
1807 _c_complex_field(self, field)
1809 for b in self.bitcases:
1812 _h(' struct _%s {', b.c_field_name)
1814 for field in b.type.fields:
1815 _c_complex_field(self, field, space)
1817 _h(' } %s;', b.c_field_name)
1819 _h('} %s;', self.c_type)
1821 def c_struct(self, name):
1823 Exported function that handles structure declarations.
1825 _c_type_setup(self, name, ())
1827 _c_accessors(self, name, name)
1828 _c_iterator(self, name)
1830 def c_union(self, name):
1832 Exported function that handles union declarations.
1834 _c_type_setup(self, name, ())
1836 _c_iterator(self, name)
1838 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1840 Declares a request function.
1843 # Four stunningly confusing possibilities here:
1846 # ------------------------------
1848 # 0 flag CHECKED flag Normal Mode
1849 # void_cookie req_cookie
1850 # ------------------------------
1851 # "req_checked" "req_unchecked"
1852 # CHECKED flag 0 flag Abnormal Mode
1853 # void_cookie req_cookie
1854 # ------------------------------
1857 # Whether we are _checked or _unchecked
1858 checked = void and not regular
1859 unchecked = not void and not regular
1861 # What kind of cookie we return
1862 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1864 # What flag is passed to xcb_request
1865 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1867 # Global extension id variable or NULL for xproto
1868 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1870 # What our function name is
1871 func_name = self.c_request_name if not aux else self.c_aux_name
1873 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1875 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1879 maxtypelen = len('xcb_connection_t')
1881 # special case: list with variable size elements
1882 list_with_var_size_elems = False
1884 for field in self.fields:
1886 # The field should appear as a call parameter
1887 param_fields.append(field)
1888 if field.wire and not field.auto:
1889 # We need to set the field up in the structure
1890 wire_fields.append(field)
1891 if field.type.need_serialize or field.type.need_sizeof:
1892 serial_fields.append(field)
1894 for field in param_fields:
1895 c_field_const_type = field.c_field_const_type
1896 if field.type.need_serialize and not aux:
1897 c_field_const_type = "const void"
1898 if len(c_field_const_type) > maxtypelen:
1899 maxtypelen = len(c_field_const_type)
1900 if field.type.is_list and not field.type.member.fixed_size():
1901 list_with_var_size_elems = True
1907 if hasattr(self, "doc") and self.doc:
1909 _h(' * @brief ' + self.doc.brief)
1911 _h(' * No brief doc yet')
1914 _h(' * @param c The connection')
1915 param_names = [f.c_field_name for f in param_fields]
1916 if hasattr(self, "doc") and self.doc:
1917 for field in param_fields:
1918 # XXX: hard-coded until we fix xproto.xml
1919 base_func_name = self.c_request_name if not aux else self.c_aux_name
1920 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1922 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1924 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1927 # XXX: why the 'xcb' prefix?
1928 key = ('xcb', field.enum)
1931 if namecount[tname] > 1:
1932 tname = _t(key + ('enum',))
1933 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1935 if self.doc and field.field_name in self.doc.fields:
1936 desc = self.doc.fields[field.field_name]
1937 for name in param_names:
1938 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1939 desc = desc.split("\n")
1940 desc = [line if line != '' else '\\n' for line in desc]
1941 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1942 # If there is no documentation yet, we simply don't generate an
1943 # @param tag. Doxygen will then warn about missing documentation.
1945 _h(' * @return A cookie')
1948 if hasattr(self, "doc") and self.doc:
1949 if self.doc.description:
1950 desc = self.doc.description
1951 for name in param_names:
1952 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1953 desc = desc.split("\n")
1954 _h(' * ' + "\n * ".join(desc))
1956 _h(' * No description yet')
1958 _h(' * Delivers a request to the X server.')
1961 _h(' * This form can be used only if the request will not cause')
1962 _h(' * a reply to be generated. Any returned error will be')
1963 _h(' * saved for handling by xcb_request_check().')
1965 _h(' * This form can be used only if the request will cause')
1966 _h(' * a reply to be generated. Any returned error will be')
1967 _h(' * placed in the event queue.')
1971 _hc('/*****************************************************************************')
1973 _hc(' ** %s %s', cookie_type, func_name)
1976 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1977 _hc(' ** @param xcb_connection_t%s *c', spacing)
1979 for field in param_fields:
1980 c_field_const_type = field.c_field_const_type
1981 if field.type.need_serialize and not aux:
1982 c_field_const_type = "const void"
1983 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1984 _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1986 _hc(' ** @returns %s', cookie_type)
1988 _hc(' *****************************************************************************/')
1990 _hc('%s', cookie_type)
1992 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1993 comma = ',' if len(param_fields) else ');'
1994 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1995 comma = ',' if len(param_fields) else ')'
1996 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1998 func_spacing = ' ' * (len(func_name) + 2)
1999 count = len(param_fields)
2000 for field in param_fields:
2002 c_field_const_type = field.c_field_const_type
2003 c_pointer = field.c_pointer
2004 if field.type.need_serialize and not aux:
2005 c_field_const_type = "const void"
2007 spacing = ' ' * (maxtypelen - len(c_field_const_type))
2008 comma = ',' if count else ');'
2009 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2010 spacing, c_pointer, field.c_field_name, comma)
2011 comma = ',' if count else ')'
2012 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
2013 spacing, c_pointer, field.c_field_name, comma)
2016 if not self.var_followed_by_fixed_fields:
2017 for field in param_fields:
2018 if not field.type.fixed_size():
2020 if field.type.need_serialize:
2021 # _serialize() keeps track of padding automatically
2023 dimension = count + 2
2026 _c(' static const xcb_protocol_request_t xcb_req = {')
2027 _c(' /* count */ %d,', count)
2028 _c(' /* ext */ %s,', func_ext_global)
2029 _c(' /* opcode */ %s,', self.c_request_name.upper())
2030 _c(' /* isvoid */ %d', 1 if void else 0)
2034 _c(' struct iovec xcb_parts[%d];', dimension)
2035 _c(' %s xcb_ret;', func_cookie)
2036 _c(' %s xcb_out;', self.c_type)
2037 if self.var_followed_by_fixed_fields:
2038 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2039 _c(' void *xcb_aux = 0;')
2042 for idx, f in enumerate(serial_fields):
2044 _c(' void *xcb_aux%d = 0;' % (idx))
2045 if list_with_var_size_elems:
2046 _c(' unsigned int i;')
2047 _c(' unsigned int xcb_tmp_len;')
2048 _c(' char *xcb_tmp;')
2050 # simple request call tracing
2051 # _c(' printf("in function %s\\n");' % func_name)
2054 for field in wire_fields:
2055 if field.type.fixed_size():
2056 if field.type.is_expr:
2057 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2058 elif field.type.is_pad:
2059 if field.type.nmemb == 1:
2060 _c(' xcb_out.%s = 0;', field.c_field_name)
2062 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2064 if field.type.nmemb == 1:
2065 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2067 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2069 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2070 serialize_args = get_serialize_params(context, type_obj,
2073 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2075 # calls in order to free dyn. all. memory
2079 if not self.var_followed_by_fixed_fields:
2080 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2081 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2082 _c(' xcb_parts[3].iov_base = 0;')
2083 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2087 for field in param_fields:
2088 if not field.type.fixed_size():
2089 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2090 # default: simple cast to char *
2091 if not field.type.need_serialize and not field.type.need_sizeof:
2092 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2093 if field.type.is_list:
2094 if field.type.member.fixed_size():
2095 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2096 _c_accessor_get_expr(field.type.expr, None),
2097 field.type.member.c_wiretype)
2099 list_length = _c_accessor_get_expr(field.type.expr, None)
2102 _c(" xcb_parts[%d].iov_len = 0;" % count)
2103 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2104 _c(" for(i=0; i<%s; i++) {" % list_length)
2105 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2106 (field.type.c_sizeof_name))
2107 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2108 _c(" xcb_tmp += xcb_tmp_len;")
2111 # not supposed to happen
2112 raise Exception("unhandled variable size field %s" % field.c_field_name)
2115 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2116 idx = serial_fields.index(field)
2117 aux_var = '&xcb_aux%d' % idx
2118 context = 'serialize' if aux else 'sizeof'
2119 _c(' xcb_parts[%d].iov_len = ', count)
2121 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2122 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2123 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2124 free_calls.append(' free(xcb_aux%d);' % idx)
2126 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2127 func_name = field.type.c_sizeof_name
2128 _c(' %s (%s);', func_name, serialize_args)
2131 if not (field.type.need_serialize or field.type.need_sizeof):
2132 # the _serialize() function keeps track of padding automatically
2133 _c(' xcb_parts[%d].iov_base = 0;', count)
2134 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2137 # elif self.var_followed_by_fixed_fields:
2139 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2140 # request header: opcodes + length
2141 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2144 buffer_var = '&xcb_aux'
2145 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2146 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2147 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2148 free_calls.append(' free(xcb_aux);')
2149 # no padding necessary - _serialize() keeps track of padding automatically
2152 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2154 # free dyn. all. data, if any
2155 for f in free_calls:
2157 _c(' return xcb_ret;')
2160 def _c_reply(self, name):
2162 Declares the function that returns the reply structure.
2164 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2165 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2166 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2168 # check if _unserialize() has to be called for any field
2169 def look_for_special_cases(complex_obj):
2170 unserialize_fields = []
2171 # no unserialize call in case of switch
2172 if not complex_obj.is_switch:
2173 for field in complex_obj.fields:
2174 # three cases: 1. field with special case
2175 # 2. container that contains special case field
2176 # 3. list with special case elements
2177 if field.type.var_followed_by_fixed_fields:
2178 unserialize_fields.append(field)
2179 elif field.type.is_container:
2180 unserialize_fields += look_for_special_cases(field.type)
2181 elif field.type.is_list:
2182 if field.type.member.var_followed_by_fixed_fields:
2183 unserialize_fields.append(field)
2184 if field.type.member.is_container:
2185 unserialize_fields += look_for_special_cases(field.type.member)
2186 return unserialize_fields
2188 unserialize_fields = look_for_special_cases(self.reply)
2192 _h(' * Return the reply')
2193 _h(' * @param c The connection')
2194 _h(' * @param cookie The cookie')
2195 _h(' * @param e The xcb_generic_error_t supplied')
2197 _h(' * Returns the reply of the request asked by')
2199 _h(' * The parameter @p e supplied to this function must be NULL if')
2200 _h(' * %s(). is used.', self.c_unchecked_name)
2201 _h(' * Otherwise, it stores the error if any.')
2203 _h(' * The returned value must be freed by the caller using free().')
2207 _hc('/*****************************************************************************')
2209 _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2211 _hc(' ** @param xcb_connection_t%s *c', spacing1)
2212 _hc(' ** @param %s cookie', self.c_cookie_type)
2213 _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2214 _hc(' ** @returns %s *', self.c_reply_type)
2216 _hc(' *****************************************************************************/')
2218 _hc('%s *', self.c_reply_type)
2219 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2220 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2221 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2222 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2225 if len(unserialize_fields)>0:
2226 # certain variable size fields need to be unserialized explicitly
2227 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2228 self.c_reply_type, self.c_reply_type)
2230 for field in unserialize_fields:
2231 if field.type.is_list:
2232 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2233 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2234 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2236 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2237 # call _unserialize(), using the reply as source and target buffer
2238 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2239 for field in unserialize_fields:
2240 if field.type.is_list:
2241 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2242 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2243 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2244 field.c_field_name, field.c_field_name)
2245 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2247 # return the transformed reply
2248 _c(' return reply;')
2251 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2255 def _c_opcode(name, opcode):
2257 Declares the opcode define for requests, events, and errors.
2261 _h('/** Opcode for %s. */', _n(name))
2262 _h('#define %s %s', _n(name).upper(), opcode)
2264 def _c_cookie(self, name):
2266 Declares the cookie type for a non-void request.
2271 _h(' * @brief %s', self.c_cookie_type)
2273 _h('typedef struct %s {', self.c_cookie_type)
2274 _h(' unsigned int sequence; /**< */')
2275 _h('} %s;', self.c_cookie_type)
2277 def _man_request(self, name, cookie_type, void, aux):
2278 param_fields = [f for f in self.fields if f.visible]
2280 func_name = self.c_request_name if not aux else self.c_aux_name
2282 def create_link(linkname):
2283 name = 'man/%s.3' % linkname
2285 sys.stdout.write(name)
2287 f.write('.so man3/%s.3' % func_name)
2291 sys.stdout.write('man/%s.3 ' % func_name)
2292 # Our CWD is src/, so this will end up in src/man/
2293 f = open('man/%s.3' % func_name, 'w')
2294 f.write('.TH %s 3 %s "XCB" "XCB Requests"\n' % (func_name, today))
2295 # Left-adjust instead of adjusting to both sides
2297 f.write('.SH NAME\n')
2298 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2299 f.write('%s \\- %s\n' % (func_name, brief))
2300 f.write('.SH SYNOPSIS\n')
2301 # Don't split words (hyphenate)
2303 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2305 # function prototypes
2307 count = len(param_fields)
2308 for field in param_fields:
2310 c_field_const_type = field.c_field_const_type
2311 c_pointer = field.c_pointer
2312 if c_pointer == ' ':
2314 if field.type.need_serialize and not aux:
2315 c_field_const_type = "const void"
2317 comma = ', ' if count else ');'
2318 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2320 f.write('.SS Request function\n')
2322 base_func_name = self.c_request_name if not aux else self.c_aux_name
2323 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2324 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2327 f.write('.SS Reply datastructure\n')
2330 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2334 for field in self.reply.fields:
2335 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2338 struct_fields.append(field)
2340 for field in struct_fields:
2341 length = len(field.c_field_type)
2342 # account for '*' pointer_spec
2343 if not field.type.fixed_size():
2345 maxtypelen = max(maxtypelen, length)
2347 def _c_complex_field(self, field, space=''):
2348 if (field.type.fixed_size() or
2349 # in case of switch with switch children, don't make the field a pointer
2350 # necessary for unserialize to work
2351 (self.is_switch and field.type.is_switch)):
2352 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2353 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2355 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2356 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2357 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2359 if not self.is_switch:
2360 for field in struct_fields:
2361 _c_complex_field(self, field)
2363 for b in self.bitcases:
2367 for field in b.type.fields:
2368 _c_complex_field(self, field, space)
2370 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2373 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2376 f.write('.SS Reply function\n')
2378 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2379 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2380 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2381 create_link('%s' % self.c_reply_name)
2383 has_accessors = False
2384 for field in self.reply.fields:
2385 if field.type.is_list and not field.type.fixed_size():
2386 has_accessors = True
2387 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2388 has_accessors = True
2391 f.write('.SS Reply accessors\n')
2393 def _c_accessors_field(self, field):
2395 Declares the accessor functions for a non-list field that follows a variable-length field.
2397 c_type = self.c_type
2399 # special case: switch
2400 switch_obj = self if self.is_switch else None
2402 switch_obj = self.parents[-1]
2403 if switch_obj is not None:
2404 c_type = switch_obj.c_type
2406 if field.type.is_simple:
2407 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2408 create_link('%s' % field.c_accessor_name)
2410 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2411 create_link('%s' % field.c_accessor_name)
2413 def _c_accessors_list(self, field):
2415 Declares the accessor functions for a list field.
2416 Declares a direct-accessor function only if the list members are fixed size.
2417 Declares length and get-iterator functions always.
2420 c_type = self.reply.c_type
2422 # special case: switch
2423 # in case of switch, 2 params have to be supplied to certain accessor functions:
2424 # 1. the anchestor object (request or reply)
2425 # 2. the (anchestor) switch object
2426 # the reason is that switch is either a child of a request/reply or nested in another switch,
2427 # so whenever we need to access a length field, we might need to refer to some anchestor type
2428 switch_obj = self if self.is_switch else None
2430 switch_obj = self.parents[-1]
2431 if switch_obj is not None:
2432 c_type = switch_obj.c_type
2436 parents = self.parents if hasattr(self, 'parents') else [self]
2437 # 'R': parents[0] is always the 'toplevel' container type
2438 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2439 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2440 # auxiliary object for 'R' parameters
2443 if switch_obj is not None:
2444 # now look where the fields are defined that are needed to evaluate
2445 # the switch expr, and store the parent objects in accessor_params and
2446 # the fields in switch_fields
2448 # 'S': name for the 'toplevel' switch
2449 toplevel_switch = parents[1]
2450 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2451 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2453 # initialize prefix for everything "below" S
2454 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2455 prefix = [(prefix_str, '->', toplevel_switch)]
2457 # look for fields in the remaining containers
2458 for p in parents[2:] + [self]:
2459 # the separator between parent and child is always '.' here,
2460 # because of nested switch statements
2461 if not p.is_bitcase or (p.is_bitcase and p.has_name):
2462 prefix.append((p.name[-1], '.', p))
2463 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2465 # auxiliary object for 'S' parameter
2468 if list.member.fixed_size():
2469 idx = 1 if switch_obj is not None else 0
2471 f.write('%s *\\fB%s\\fP(%s);\n' %
2472 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2473 create_link('%s' % field.c_accessor_name)
2476 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2477 (field.c_length_name, c_type))
2478 create_link('%s' % field.c_length_name)
2480 if field.type.member.is_simple:
2482 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2483 (field.c_end_name, c_type))
2484 create_link('%s' % field.c_end_name)
2487 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2488 (field.c_iterator_type, field.c_iterator_name,
2490 create_link('%s' % field.c_iterator_name)
2492 for field in self.reply.fields:
2493 if field.type.is_list and not field.type.fixed_size():
2494 _c_accessors_list(self, field)
2495 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2496 _c_accessors_field(self, field)
2500 # Re-enable hyphenation and adjusting to both sides
2503 # argument reference
2504 f.write('.SH REQUEST ARGUMENTS\n')
2505 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2506 f.write('The XCB connection to X11.\n')
2507 for field in param_fields:
2508 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2509 printed_enum = False
2510 # XXX: hard-coded until we fix xproto.xml
2511 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2513 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2515 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2517 if hasattr(field, "enum") and field.enum:
2518 # XXX: why the 'xcb' prefix?
2519 key = ('xcb', field.enum)
2521 f.write('One of the following values:\n')
2524 count = len(enum.values)
2525 for (enam, eval) in enum.values:
2527 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2528 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2529 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2530 f.write('%s\n' % desc)
2532 f.write('TODO: NOT YET DOCUMENTED.\n')
2537 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2538 desc = self.doc.fields[field.field_name]
2539 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2542 f.write('%s\n' % desc)
2544 f.write('TODO: NOT YET DOCUMENTED.\n')
2550 f.write('.SH REPLY FIELDS\n')
2551 # These fields are present in every reply:
2552 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2553 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2554 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2555 'be used to tell replies apart from each other.\n') %
2556 _n(self.reply.name).upper())
2557 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2558 f.write('The sequence number of the last request processed by the X11 server.\n')
2559 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2560 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2561 for field in self.reply.fields:
2562 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2563 field.c_field_name.startswith('pad')):
2566 if field.type.is_list and not field.type.fixed_size():
2568 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2570 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2571 printed_enum = False
2572 if hasattr(field, "enum") and field.enum:
2573 # XXX: why the 'xcb' prefix?
2574 key = ('xcb', field.enum)
2576 f.write('One of the following values:\n')
2579 count = len(enum.values)
2580 for (enam, eval) in enum.values:
2582 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2583 if enum.doc and enam in enum.doc.fields:
2584 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2585 f.write('%s\n' % desc)
2587 f.write('TODO: NOT YET DOCUMENTED.\n')
2592 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2593 desc = self.reply.doc.fields[field.field_name]
2594 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2597 f.write('%s\n' % desc)
2599 f.write('TODO: NOT YET DOCUMENTED.\n')
2606 f.write('.SH DESCRIPTION\n')
2607 if hasattr(self, "doc") and self.doc and self.doc.description:
2608 desc = self.doc.description
2609 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2610 lines = desc.split('\n')
2611 f.write('\n'.join(lines) + '\n')
2613 f.write('.SH RETURN VALUE\n')
2615 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2616 'have to be handled in the event loop.\n\nIf you want to '
2617 'handle errors directly with \\fIxcb_request_check\\fP '
2618 'instead, use \\fI%s_checked\\fP. See '
2619 '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
2621 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2622 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2623 'handle errors in the event loop instead, use '
2624 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
2626 (cookie_type, self.c_reply_name, base_func_name))
2627 f.write('.SH ERRORS\n')
2628 if hasattr(self, "doc") and self.doc:
2629 for errtype, errtext in self.doc.errors.items():
2630 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2631 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2632 f.write('%s\n' % (errtext))
2633 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2634 f.write('This request does never generate any errors.\n')
2635 if hasattr(self, "doc") and self.doc and self.doc.example:
2636 f.write('.SH EXAMPLE\n')
2639 lines = self.doc.example.split('\n')
2640 f.write('\n'.join(lines) + '\n')
2642 f.write('.SH SEE ALSO\n')
2643 if hasattr(self, "doc") and self.doc:
2644 see = ['.BR %s (3)' % 'xcb-requests']
2645 if self.doc.example:
2646 see.append('.BR %s (3)' % 'xcb-examples')
2647 for seename, seetype in self.doc.see.items():
2648 if seetype == 'program':
2649 see.append('.BR %s (1)' % seename)
2650 elif seetype == 'event':
2651 see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2652 elif seetype == 'request':
2653 see.append('.BR %s (3)' % _n(('xcb', seename)))
2654 elif seetype == 'function':
2655 see.append('.BR %s (3)' % seename)
2657 see.append('TODO: %s (type %s)' % (seename, seetype))
2658 f.write(',\n'.join(see) + '\n')
2659 f.write('.SH AUTHOR\n')
2660 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2663 def _man_event(self, name):
2665 sys.stdout.write('man/%s.3 ' % self.c_type)
2666 # Our CWD is src/, so this will end up in src/man/
2667 f = open('man/%s.3' % self.c_type, 'w')
2668 f.write('.TH %s 3 %s "XCB" "XCB Events"\n' % (self.c_type, today))
2669 # Left-adjust instead of adjusting to both sides
2671 f.write('.SH NAME\n')
2672 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2673 f.write('%s \\- %s\n' % (self.c_type, brief))
2674 f.write('.SH SYNOPSIS\n')
2675 # Don't split words (hyphenate)
2677 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2680 f.write('.SS Event datastructure\n')
2683 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2687 for field in self.fields:
2688 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2691 struct_fields.append(field)
2693 for field in struct_fields:
2694 length = len(field.c_field_type)
2695 # account for '*' pointer_spec
2696 if not field.type.fixed_size():
2698 maxtypelen = max(maxtypelen, length)
2700 def _c_complex_field(self, field, space=''):
2701 if (field.type.fixed_size() or
2702 # in case of switch with switch children, don't make the field a pointer
2703 # necessary for unserialize to work
2704 (self.is_switch and field.type.is_switch)):
2705 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2706 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2708 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2710 if not self.is_switch:
2711 for field in struct_fields:
2712 _c_complex_field(self, field)
2714 for b in self.bitcases:
2718 for field in b.type.fields:
2719 _c_complex_field(self, field, space)
2721 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2724 f.write('} \\fB%s\\fP;\n' % self.c_type)
2729 # Re-enable hyphenation and adjusting to both sides
2732 # argument reference
2733 f.write('.SH EVENT FIELDS\n')
2734 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2735 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2736 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2737 'to tell events apart from each other.\n') % _n(name).upper())
2738 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2739 f.write('The sequence number of the last request processed by the X11 server.\n')
2741 if not self.is_switch:
2742 for field in struct_fields:
2743 # Skip the fields which every event has, we already documented
2745 if field.c_field_name in ('response_type', 'sequence'):
2747 if isinstance(field.type, PadType):
2749 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2750 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2751 desc = self.doc.fields[field.field_name]
2752 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2753 f.write('%s\n' % desc)
2755 f.write('NOT YET DOCUMENTED.\n')
2758 f.write('.SH DESCRIPTION\n')
2759 if hasattr(self, "doc") and self.doc and self.doc.description:
2760 desc = self.doc.description
2761 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2762 lines = desc.split('\n')
2763 f.write('\n'.join(lines) + '\n')
2765 if hasattr(self, "doc") and self.doc and self.doc.example:
2766 f.write('.SH EXAMPLE\n')
2769 lines = self.doc.example.split('\n')
2770 f.write('\n'.join(lines) + '\n')
2772 f.write('.SH SEE ALSO\n')
2773 if hasattr(self, "doc") and self.doc:
2774 see = ['.BR %s (3)' % 'xcb_generic_event_t']
2775 if self.doc.example:
2776 see.append('.BR %s (3)' % 'xcb-examples')
2777 for seename, seetype in self.doc.see.items():
2778 if seetype == 'program':
2779 see.append('.BR %s (1)' % seename)
2780 elif seetype == 'event':
2781 see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2782 elif seetype == 'request':
2783 see.append('.BR %s (3)' % _n(('xcb', seename)))
2784 elif seetype == 'function':
2785 see.append('.BR %s (3)' % seename)
2787 see.append('TODO: %s (type %s)' % (seename, seetype))
2788 f.write(',\n'.join(see) + '\n')
2789 f.write('.SH AUTHOR\n')
2790 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2794 def c_request(self, name):
2796 Exported function that handles request declarations.
2798 _c_type_setup(self, name, ('request',))
2801 # Cookie type declaration
2802 _c_cookie(self, name)
2805 _c_opcode(name, self.opcode)
2807 # Request structure declaration
2811 _c_type_setup(self.reply, name, ('reply',))
2812 # Reply structure definition
2813 _c_complex(self.reply)
2814 # Request prototypes
2815 _c_request_helper(self, name, self.c_cookie_type, False, True)
2816 _c_request_helper(self, name, self.c_cookie_type, False, False)
2818 _c_request_helper(self, name, self.c_cookie_type, False, True, True)
2819 _c_request_helper(self, name, self.c_cookie_type, False, False, True)
2821 _c_accessors(self.reply, name + ('reply',), name)
2822 _c_reply(self, name)
2824 # Request prototypes
2825 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2826 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2828 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2829 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2831 # We generate the manpage afterwards because _c_type_setup has been called.
2832 # TODO: what about aux helpers?
2833 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2834 _man_request(self, name, cookie_type, not self.reply, False)
2836 def c_event(self, name):
2838 Exported function that handles event declarations.
2840 _c_type_setup(self, name, ('event',))
2843 _c_opcode(name, self.opcodes[name])
2845 if self.name == name:
2846 # Structure definition
2851 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2853 _man_event(self, name)
2855 def c_error(self, name):
2857 Exported function that handles error declarations.
2859 _c_type_setup(self, name, ('error',))
2862 _c_opcode(name, self.opcodes[name])
2864 if self.name == name:
2865 # Structure definition
2870 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2873 # Main routine starts here
2875 # Must create an "output" dictionary before any xcbgen imports.
2876 output = {'open' : c_open,
2878 'simple' : c_simple,
2880 'struct' : c_struct,
2882 'request' : c_request,
2887 # Boilerplate below this point
2889 # Check for the argument that specifies path to the xcbgen python package.
2891 opts, args = getopt.getopt(sys.argv[1:], 'p:m')
2892 except getopt.GetoptError as err:
2894 print('Usage: c_client.py [-p path] file.xml')
2897 for (opt, arg) in opts:
2899 sys.path.insert(1, arg)
2902 sys.stdout.write('man_MANS = ')
2904 # Import the module class
2906 from xcbgen.state import Module
2907 from xcbgen.xtypes import *
2910 Failed to load the xcbgen Python package!
2911 Make sure that xcb/proto installed it on your Python path.
2912 If not, you will need to create a .pth file or define $PYTHONPATH
2914 Refer to the README file in xcb/proto for more info.
2918 # Ensure the man subdirectory exists
2921 except OSError as e:
2922 if e.errno != errno.EEXIST:
2925 today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
2927 # Parse the xml header
2928 module = Module(args[0], output)
2930 # Build type-registry and resolve type dependencies