2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
12 # Jump to the bottom of this file for the main routine
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
20 _cplusplus_annoyances = {'class' : '_class',
23 _c_keywords = {'default' : '_default'}
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
37 # keeps enum objects so that we can refer to them when generating manpages.
44 Writes the given line to the header file.
46 _hlines[_hlevel].append(fmt % args)
50 Writes the given line to the source file.
52 _clines[_clevel].append(fmt % args)
56 Writes the given line to both the header and source files.
61 # XXX See if this level thing is really necessary.
64 Changes the array that header lines are written to.
65 Supports writing different sections of the header file.
68 while len(_hlines) <= idx:
74 Changes the array that source lines are written to.
75 Supports writing to different sections of the source file.
78 while len(_clines) <= idx:
84 Does C-name conversion on a single string fragment.
85 Uses a regexp with some hard-coded special cases.
87 if str in _cname_special_cases:
88 return _cname_special_cases[str]
90 split = _cname_re.finditer(str)
91 name_parts = [match.group(0) for match in split]
92 return '_'.join(name_parts)
96 Checks for certain C++ reserved words and fixes them.
98 if str in _cplusplus_annoyances:
99 return _cplusplus_annoyances[str]
100 elif str in _c_keywords:
101 return _c_keywords[str]
107 Does C-name conversion on an extension name.
108 Has some additional special cases on top of _n_item.
110 if str in _extension_special_cases:
111 return _n_item(str).lower()
117 Does C-name conversion on a tuple of strings.
118 Different behavior depending on length of tuple, extension/not extension, etc.
119 Basically C-name converts the individual pieces, then joins with underscores.
124 parts = [list[0], _n_item(list[1])]
126 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
128 parts = [list[0]] + [_n_item(i) for i in list[1:]]
129 return '_'.join(parts).lower()
133 Does C-name conversion on a tuple of strings representing a type.
134 Same as _n but adds a "_t" on the end.
139 parts = [list[0], _n_item(list[1]), 't']
141 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
143 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
144 return '_'.join(parts).lower()
149 Exported function that handles module open.
150 Opens the files and writes out the auto-generated comment, header file includes, etc.
154 _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
156 # Build the type-name collision avoidance table used by c_enum
157 build_collision_table()
163 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
164 _hc(' * Edit at your peril.')
169 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
170 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
174 _h('#ifndef __%s_H', _ns.header.upper())
175 _h('#define __%s_H', _ns.header.upper())
177 _h('#include "xcb.h"')
179 _c('#ifdef HAVE_CONFIG_H')
180 _c('#include "config.h"')
182 _c('#include <stdlib.h>')
183 _c('#include <string.h>')
184 _c('#include <assert.h>')
185 _c('#include <stddef.h> /* for offsetof() */')
186 _c('#include "xcbext.h"')
187 _c('#include "%s.h"', _ns.header)
190 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
193 for (n, h) in self.direct_imports:
194 _hc('#include "%s.h"', h)
197 _h('#ifdef __cplusplus')
203 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
204 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
206 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
209 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
213 Exported function that handles module close.
214 Writes out all the stored content lines, then closes the files.
221 _h('#ifdef __cplusplus')
233 hfile = open('%s.h' % _ns.header, 'w')
241 cfile = open('%s.c' % _ns.header, 'w')
248 def build_collision_table():
252 for v in module.types.values():
254 namecount[name] = (namecount.get(name) or 0) + 1
256 def c_enum(self, name):
258 Exported function that handles enum declarations.
264 if namecount[tname] > 1:
265 tname = _t(name + ('enum',))
269 _h('typedef enum %s {', tname)
271 count = len(self.values)
273 for (enam, eval) in self.values:
275 equals = ' = ' if eval != '' else ''
276 comma = ',' if count > 0 else ''
278 if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
279 doc = '\n/**< %s */\n' % self.doc.fields[enam]
280 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
284 def _c_type_setup(self, name, postfix):
286 Sets up all the C-related state by adding additional data fields to
287 all Field and Type objects. Here is where we figure out most of our
288 variable and function names.
290 Recurses into child fields and list member types.
292 # Do all the various names in advance
293 self.c_type = _t(name + postfix)
294 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
296 self.c_iterator_type = _t(name + ('iterator',))
297 self.c_next_name = _n(name + ('next',))
298 self.c_end_name = _n(name + ('end',))
300 self.c_request_name = _n(name)
301 self.c_checked_name = _n(name + ('checked',))
302 self.c_unchecked_name = _n(name + ('unchecked',))
303 self.c_reply_name = _n(name + ('reply',))
304 self.c_reply_type = _t(name + ('reply',))
305 self.c_cookie_type = _t(name + ('cookie',))
306 self.c_reply_fds_name = _n(name + ('reply_fds',))
308 self.c_need_aux = False
309 self.c_need_serialize = False
310 self.c_need_sizeof = False
312 self.c_aux_name = _n(name + ('aux',))
313 self.c_aux_checked_name = _n(name + ('aux', 'checked'))
314 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
315 self.c_serialize_name = _n(name + ('serialize',))
316 self.c_unserialize_name = _n(name + ('unserialize',))
317 self.c_unpack_name = _n(name + ('unpack',))
318 self.c_sizeof_name = _n(name + ('sizeof',))
320 # special case: structs where variable size fields are followed by fixed size fields
321 self.c_var_followed_by_fixed_fields = False
324 self.c_need_serialize = True
325 self.c_container = 'struct'
326 for bitcase in self.bitcases:
327 bitcase.c_field_name = _cpp(bitcase.field_name)
328 bitcase_name = bitcase.field_type if bitcase.type.has_name else name
329 _c_type_setup(bitcase.type, bitcase_name, ())
331 elif self.is_container:
333 self.c_container = 'union' if self.is_union else 'struct'
334 prev_varsized_field = None
335 prev_varsized_offset = 0
336 first_field_after_varsized = None
338 for field in self.fields:
339 _c_type_setup(field.type, field.field_type, ())
340 if field.type.is_list:
341 _c_type_setup(field.type.member, field.field_type, ())
342 if (field.type.nmemb is None):
343 self.c_need_sizeof = True
345 field.c_field_type = _t(field.field_type)
346 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
347 field.c_field_name = _cpp(field.field_name)
348 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
349 field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
351 # correct the c_pointer field for variable size non-list types
352 if not field.type.fixed_size() and field.c_pointer == ' ':
353 field.c_pointer = '*'
354 if field.type.is_list and not field.type.member.fixed_size():
355 field.c_pointer = '*'
357 if field.type.is_switch:
358 field.c_pointer = '*'
359 field.c_field_const_type = 'const ' + field.c_field_type
360 self.c_need_aux = True
362 if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
363 self.c_need_sizeof = True
365 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t
366 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
367 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field
368 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length
369 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end
371 field.prev_varsized_field = prev_varsized_field
372 field.prev_varsized_offset = prev_varsized_offset
374 if prev_varsized_offset == 0:
375 first_field_after_varsized = field
376 field.first_field_after_varsized = first_field_after_varsized
378 if field.type.fixed_size():
379 prev_varsized_offset += field.type.size
380 # special case: intermixed fixed and variable size fields
381 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
382 if not self.is_union:
383 self.c_need_serialize = True
384 self.c_var_followed_by_fixed_fields = True
386 self.last_varsized_field = field
387 prev_varsized_field = field
388 prev_varsized_offset = 0
390 if self.c_var_followed_by_fixed_fields:
391 if field.type.fixed_size():
392 field.prev_varsized_field = None
394 if self.c_need_serialize:
395 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
396 self.c_need_sizeof = True
398 # as switch does never appear at toplevel,
399 # continue here with type construction
401 if self.c_type not in finished_switch:
402 finished_switch.append(self.c_type)
403 # special: switch C structs get pointer fields for variable-sized members
405 for bitcase in self.bitcases:
406 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
407 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
408 # no list with switch as element, so no call to
409 # _c_iterator(field.type, field_name) necessary
411 if not self.is_case_or_bitcase:
412 if self.c_need_serialize:
413 if self.c_serialize_name not in finished_serializers:
414 finished_serializers.append(self.c_serialize_name)
415 _c_serialize('serialize', self)
417 # _unpack() and _unserialize() are only needed for special cases:
419 # special cases -> unserialize
420 if self.is_switch or self.c_var_followed_by_fixed_fields:
421 _c_serialize('unserialize', self)
423 if self.c_need_sizeof:
424 if self.c_sizeof_name not in finished_sizeof:
425 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
426 finished_sizeof.append(self.c_sizeof_name)
427 _c_serialize('sizeof', self)
430 def _c_helper_absolute_name(prefix, field=None):
432 turn prefix, which is a list of tuples (name, separator, Type obj) into a string
433 representing a valid name in C (based on the context)
434 if field is not None, append the field name as well
437 for name, sep, obj in prefix:
441 if ((obj.is_case_or_bitcase and obj.has_name) or # named bitcase
442 (obj.is_switch and len(obj.parents)>1)):
445 if field is not None:
446 prefix_str += _cpp(field.field_name)
450 def _c_helper_field_mapping(complex_type, prefix, flat=False):
452 generate absolute names, based on prefix, for all fields starting from complex_type
453 if flat == True, nested complex types are not taken into account
456 if complex_type.is_switch:
457 for b in complex_type.bitcases:
459 switch_name, switch_sep, switch_type = prefix[-1]
460 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
462 bitcase_prefix = prefix
464 if (True==flat and not b.type.has_name) or False==flat:
465 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
467 for f in complex_type.fields:
468 fname = _c_helper_absolute_name(prefix, f)
469 if f.field_name in all_fields:
470 raise Exception("field name %s has been registered before" % f.field_name)
472 all_fields[f.field_name] = (fname, f)
473 if f.type.is_container and flat==False:
474 if f.type.is_case_or_bitcase and not f.type.has_name:
476 elif f.type.is_switch and len(f.type.parents)>1:
477 # nested switch gets another separator
478 new_prefix = prefix+[(f.c_field_name, '.', f.type)]
480 new_prefix = prefix+[(f.c_field_name, '->', f.type)]
481 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
486 def _c_helper_resolve_field_names (prefix):
488 get field names for all objects in the prefix array
492 # look for fields in the remaining containers
493 for idx, p in enumerate(prefix):
496 # sep can be preset in prefix, if not, make a sensible guess
497 sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
498 # exception: 'toplevel' object (switch as well!) always have sep '->'
499 sep = '->' if idx<1 else sep
500 if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
501 tmp_prefix.append((name, sep, obj))
502 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
505 # _c_helper_resolve_field_names
507 def get_expr_fields(self):
509 get the Fields referenced by switch or list expression
511 def get_expr_field_names(expr):
513 if expr.lenfield_name is not None:
514 return [expr.lenfield_name]
516 # constant value expr
520 return get_expr_field_names(expr.rhs)
521 elif expr.op == 'popcount':
522 return get_expr_field_names(expr.rhs)
523 elif expr.op == 'sumof':
524 # sumof expr references another list,
525 # we need that list's length field here
527 for f in expr.lenfield_parent.fields:
528 if f.field_name == expr.lenfield_name:
532 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
533 # referenced list + its length field
534 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
535 elif expr.op == 'enumref':
538 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
539 # get_expr_field_names()
541 # resolve the field names with the parent structure(s)
542 unresolved_fields_names = get_expr_field_names(self.expr)
544 # construct prefix from self
545 prefix = [('', '', p) for p in self.parents]
546 if self.is_container:
547 prefix.append(('', '', self))
549 all_fields = _c_helper_resolve_field_names (prefix)
550 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
551 if len(unresolved_fields_names) != len(resolved_fields_names):
552 raise Exception("could not resolve all fields for %s" % self.name)
554 resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
555 return resolved_fields
558 def resolve_expr_fields(complex_obj):
560 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
561 these are normally fields that need to be given as function parameters
567 for field in complex_obj.fields:
568 all_fields.append(field)
569 if field.type.is_switch or field.type.is_list:
570 expr_fields += get_expr_fields(field.type)
571 if field.type.is_container:
572 expr_fields += resolve_expr_fields(field.type)
574 # try to resolve expr fields
575 for e in expr_fields:
576 if e not in all_fields and e not in unresolved:
579 # resolve_expr_fields()
581 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
583 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
584 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
585 expression. This function tries to resolve all fields within a structure, and returns the
586 unresolved fields as the list of external parameters.
588 def add_param(params, param):
589 if param not in params:
592 # collect all fields into param_fields
596 for field in self.fields:
598 # the field should appear as a parameter in the function call
599 param_fields.append(field)
600 if field.wire and not field.auto:
601 if field.type.fixed_size() and not self.is_switch:
602 # field in the xcb_out structure
603 wire_fields.append(field)
604 # fields like 'pad0' are skipped!
606 # in case of switch, parameters always contain any fields referenced in the switch expr
607 # we do not need any variable size fields here, as the switch data type contains both
608 # fixed and variable size fields
610 param_fields = get_expr_fields(self)
612 # _serialize()/_unserialize()/_unpack() function parameters
613 # note: don't use set() for params, it is unsorted
616 # 1. the parameter for the void * buffer
617 if 'serialize' == context:
618 params.append(('void', '**', buffer_var))
619 elif context in ('unserialize', 'unpack', 'sizeof'):
620 params.append(('const void', '*', buffer_var))
622 # 2. any expr fields that cannot be resolved within self and descendants
623 unresolved_fields = resolve_expr_fields(self)
624 for f in unresolved_fields:
625 add_param(params, (f.c_field_type, '', f.c_field_name))
627 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
628 # that do not appear in the data type struct
629 for p in param_fields:
631 typespec = p.c_field_const_type
632 pointerspec = p.c_pointer
633 add_param(params, (typespec, pointerspec, p.c_field_name))
635 if p.visible and not p.wire and not p.auto:
636 typespec = p.c_field_type
638 add_param(params, (typespec, pointerspec, p.c_field_name))
641 if 'serialize' == context:
642 add_param(params, ('const %s' % self.c_type, '*', aux_var))
643 elif 'unserialize' == context:
644 add_param(params, ('%s' % self.c_type, '**', aux_var))
645 elif 'unpack' == context:
646 add_param(params, ('%s' % self.c_type, '*', aux_var))
648 # 5. switch contains all variable size fields as struct members
649 # for other data types though, these have to be supplied separately
650 # this is important for the special case of intermixed fixed and
651 # variable size fields
652 if not self.is_switch and 'serialize' == context:
653 for p in param_fields:
654 if not p.type.fixed_size():
655 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
657 return (param_fields, wire_fields, params)
658 # get_serialize_params()
660 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
661 code_lines.append('%s /* insert padding */' % space)
662 if is_case_or_bitcase:
664 '%s xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
668 '%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
669 # code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
670 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
673 code_lines.append('%s if (0 != xcb_pad) {' % space)
675 if 'serialize' == context:
676 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
677 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
678 code_lines.append('%s xcb_parts_idx++;' % space)
679 elif context in ('unserialize', 'unpack', 'sizeof'):
680 code_lines.append('%s xcb_tmp += xcb_pad;' % space)
682 code_lines.append('%s xcb_pad = 0;' % space)
683 code_lines.append('%s }' % space)
685 code_lines.append('%s xcb_block_len = 0;' % space)
686 if is_case_or_bitcase:
687 code_lines.append('%s xcb_padding_offset = 0;' % space)
689 # keep tracking of xcb_parts entries for serialize
691 # _c_serialize_helper_insert_padding()
693 def _c_serialize_helper_switch(context, self, complex_name,
694 code_lines, temp_vars,
697 switch_expr = _c_accessor_get_expr(self.expr, None)
699 for b in self.bitcases:
700 len_expr = len(b.type.expr)
702 compare_operator = '&'
704 compare_operator = '=='
706 compare_operator = '&'
708 for n, expr in enumerate(b.type.expr):
709 bitcase_expr = _c_accessor_get_expr(expr, None)
710 # only one <enumref> in the <bitcase>
713 ' if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
714 # multiple <enumref> in the <bitcase>
717 ' if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
718 elif len_expr == (n + 1): # last
720 ' (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
721 else: # between first and last
723 ' (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
727 b_prefix = prefix + [(b.c_field_name, '.', b.type)]
729 count += _c_serialize_helper_fields(context, b.type,
730 code_lines, temp_vars,
733 is_case_or_bitcase = True)
734 code_lines.append(' }')
736 # if 'serialize' == context:
737 # count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
738 # elif context in ('unserialize', 'unpack', 'sizeof'):
740 # code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space)
741 # code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
744 # _c_serialize_helper_switch
746 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
748 handle switch by calling _serialize() or _unpack(), depending on context
750 # switch is handled by this function as a special case
751 param_fields, wire_fields, params = get_serialize_params(context, self)
752 field_mapping = _c_helper_field_mapping(self, prefix)
753 prefix_str = _c_helper_absolute_name(prefix)
755 # find the parameters that need to be passed to _serialize()/_unpack():
756 # all switch expr fields must be given as parameters
757 args = get_expr_fields(field.type)
758 # length fields for variable size types in switch, normally only some of need
759 # need to be passed as parameters
760 switch_len_fields = resolve_expr_fields(field.type)
762 # a switch field at this point _must_ be a bitcase field
763 # we require that bitcases are "self-contiguous"
764 bitcase_unresolved = resolve_expr_fields(self)
765 if len(bitcase_unresolved) != 0:
766 raise Exception('unresolved fields within bitcase is not supported at this point')
768 # get the C names for the parameters
770 for a in switch_len_fields:
771 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
773 c_field_names += "%s, " % field_mapping[a.c_field_name][0]
775 # call _serialize()/_unpack() to determine the actual size
776 if 'serialize' == context:
777 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
778 c_field_names, prefix_str, field.c_field_name)
779 elif context in ('unserialize', 'unpack'):
780 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
781 c_field_names, prefix_str, field.c_field_name)
782 elif 'sizeof' == context:
783 # remove trailing ", " from c_field_names because it will be used at end of arglist
784 my_c_field_names = c_field_names[:-2]
785 length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
788 # _c_serialize_helper_switch_field()
790 def _c_serialize_helper_list_field(context, self, field,
791 code_lines, temp_vars,
794 helper function to cope with lists of variable length
796 expr = field.type.expr
797 prefix_str = _c_helper_absolute_name(prefix)
798 param_fields, wire_fields, params = get_serialize_params('sizeof', self)
799 param_names = [p[2] for p in params]
801 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
802 resolved = list(filter(lambda x: x in param_names, expr_fields_names))
803 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
807 field_mapping[r] = (r, None)
809 if len(unresolved)>0:
811 if len(tmp_prefix)==0:
812 raise Exception("found an empty prefix while resolving expr field names for list %s",
815 field_mapping.update(_c_helper_resolve_field_names(prefix))
816 resolved += list(filter(lambda x: x in field_mapping, unresolved))
817 unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
818 if len(unresolved)>0:
819 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
821 list_length = _c_accessor_get_expr(expr, field_mapping)
823 # default: list with fixed size elements
824 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
826 # list with variable-sized elements
827 if not field.type.member.fixed_size():
829 if context in ('unserialize', 'sizeof', 'unpack'):
830 int_i = ' unsigned int i;'
831 xcb_tmp_len = ' unsigned int xcb_tmp_len;'
832 if int_i not in temp_vars:
833 temp_vars.append(int_i)
834 if xcb_tmp_len not in temp_vars:
835 temp_vars.append(xcb_tmp_len)
836 # loop over all list elements and call sizeof repeatedly
837 # this should be a bit faster than using the iterators
838 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length))
839 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" %
840 (space, field.type.c_sizeof_name))
841 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space)
842 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space)
843 code_lines.append("%s }" % space)
845 elif 'serialize' == context:
846 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
847 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
848 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length))
849 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
850 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
851 code_lines.append('%s }' % space)
852 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
855 # _c_serialize_helper_list_field()
857 def _c_serialize_helper_fields_fixed_size(context, self, field,
858 code_lines, temp_vars,
860 # keep the C code a bit more readable by giving the field name
861 if not self.is_case_or_bitcase:
862 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name))
864 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
865 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
866 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name))
868 abs_field_name = _c_helper_absolute_name(prefix, field)
869 # default for simple cases: call sizeof()
870 length = "sizeof(%s)" % field.c_field_type
872 if context in ('unserialize', 'unpack', 'sizeof'):
873 # default: simple cast
874 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
876 # padding - we could probably just ignore it
877 if field.type.is_pad and field.type.nmemb > 1:
879 for i in range(field.type.nmemb):
880 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' %
881 (space, abs_field_name, i, field.c_field_type))
882 # total padding = sizeof(pad0) * nmemb
883 length += " * %d" % field.type.nmemb
885 elif field.type.is_list:
886 # list with fixed number of elements
887 # length of array = sizeof(arrayElementType) * nmemb
888 length += " * %d" % field.type.nmemb
889 # use memcpy because C cannot assign whole arrays with operator=
890 value = ' memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
893 elif 'serialize' == context:
894 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) '
896 if field.type.is_expr:
897 # need to register a temporary variable for the expression in case we know its type
898 if field.type.c_type is None:
899 raise Exception("type for field '%s' (expression '%s') unkown" %
900 (field.field_name, _c_accessor_get_expr(field.type.expr)))
902 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
903 _c_accessor_get_expr(field.type.expr, prefix)))
904 value += "&xcb_expr_%s;" % _cpp(field.field_name)
906 elif field.type.is_pad:
907 if field.type.nmemb == 1:
910 # we could also set it to 0, see definition of xcb_send_request()
911 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
912 length += "*%d" % field.type.nmemb
915 # non-list type with fixed size
916 if field.type.nmemb == 1:
917 value += "&%s;" % (abs_field_name)
919 # list with nmemb (fixed size) elements
921 value += '%s;' % (abs_field_name)
922 length = '%d' % field.type.nmemb
924 return (value, length)
925 # _c_serialize_helper_fields_fixed_size()
927 def _c_serialize_helper_fields_variable_size(context, self, field,
928 code_lines, temp_vars,
930 prefix_str = _c_helper_absolute_name(prefix)
932 if context in ('unserialize', 'unpack', 'sizeof'):
934 var_field_name = 'xcb_tmp'
936 # special case: intermixed fixed and variable size fields
937 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
938 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
939 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name))
940 # special case: switch
941 if 'unpack' == context:
942 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
944 elif 'serialize' == context:
945 # variable size fields appear as parameters to _serialize() if the
946 # 'toplevel' container is not a switch
947 prefix_string = prefix_str if prefix[0][2].is_switch else ''
948 var_field_name = "%s%s" % (prefix_string, field.c_field_name)
949 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
953 code_lines.append('%s /* %s */' % (space, field.c_field_name))
955 if field.type.is_list:
957 # in any context, list is already a pointer, so the default assignment is ok
958 code_lines.append("%s%s" % (space, value))
960 length = _c_serialize_helper_list_field(context, self, field,
961 code_lines, temp_vars,
964 elif field.type.is_switch:
966 if context == 'serialize':
967 # the _serialize() function allocates the correct amount memory if given a NULL pointer
968 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
969 length = _c_serialize_helper_switch_field(context, self, field,
970 'xcb_parts[xcb_parts_idx].iov_base',
974 # in all remaining special cases - call _sizeof()
975 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
977 return (value, length)
978 # _c_serialize_helper_fields_variable_size
980 def _c_serialize_helper_fields(context, self,
981 code_lines, temp_vars,
982 space, prefix, is_case_or_bitcase):
985 prev_field_was_variable = False
987 for field in self.fields:
988 if not field.visible:
989 if not ((field.wire and not field.auto) or 'unserialize' == context):
992 # switch/bitcase: fixed size fields must be considered explicitly
993 if field.type.fixed_size():
994 if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
995 if prev_field_was_variable and need_padding:
997 # count += _c_serialize_helper_insert_padding(context, code_lines, space,
998 # self.c_var_followed_by_fixed_fields)
999 prev_field_was_variable = False
1001 # prefix for fixed size fields
1002 fixed_prefix = prefix
1004 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1005 code_lines, temp_vars,
1006 space, fixed_prefix)
1010 # fields with variable size
1012 if field.type.is_pad:
1013 # Variable length pad is <pad align= />
1014 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align))
1015 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1016 self.c_var_followed_by_fixed_fields,
1020 # switch/bitcase: always calculate padding before and after variable sized fields
1021 if need_padding or is_case_or_bitcase:
1022 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1023 self.c_var_followed_by_fixed_fields,
1026 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1027 code_lines, temp_vars,
1029 prev_field_was_variable = True
1031 # save (un)serialization C code
1033 code_lines.append('%s%s' % (space, value))
1035 if field.type.fixed_size():
1036 if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1037 # keep track of (un)serialized object's size
1038 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1039 if context in ('unserialize', 'unpack', 'sizeof'):
1040 code_lines.append('%s xcb_tmp += %s;' % (space, length))
1042 # variable size objects or bitcase:
1043 # value & length might have been inserted earlier for special cases
1045 # special case: intermixed fixed and variable size fields
1046 if (not field.type.fixed_size() and
1047 self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1048 temp_vars.append(' int %s_len;' % field.c_field_name)
1049 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length))
1050 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name))
1051 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name))
1053 code_lines.append('%s xcb_block_len += %s;' % (space, length))
1054 # increase pointer into the byte stream accordingly
1055 if context in ('unserialize', 'sizeof', 'unpack'):
1056 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1058 if 'serialize' == context:
1060 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1061 code_lines.append('%s xcb_parts_idx++;' % space)
1065 '%s xcb_align_to = ALIGNOF(%s);'
1068 if field.c_field_type == 'void' or field.type.is_switch
1069 else field.c_field_type))
1072 if self.c_var_followed_by_fixed_fields:
1073 need_padding = False
1076 # _c_serialize_helper_fields()
1078 def _c_serialize_helper(context, complex_type,
1079 code_lines, temp_vars,
1080 space='', prefix=[]):
1081 # count tracks the number of fields to serialize
1084 if hasattr(complex_type, 'type'):
1085 self = complex_type.type
1086 complex_name = complex_type.name
1089 if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1090 complex_name = 'xcb_out'
1092 complex_name = '_aux'
1094 # special case: switch is serialized by evaluating each bitcase separately
1096 count += _c_serialize_helper_switch(context, self, complex_name,
1097 code_lines, temp_vars,
1100 # all other data types can be evaluated one field a time
1102 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1103 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1104 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
1105 code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
1106 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
1107 code_lines.append('%s xcb_block_len = 0;' % space)
1109 count += _c_serialize_helper_fields(context, self,
1110 code_lines, temp_vars,
1111 space, prefix, False)
1113 count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1116 # _c_serialize_helper()
1118 def _c_serialize(context, self):
1120 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1121 for the ComplexType variable self
1127 # _serialize() returns the buffer size
1130 if self.is_switch and 'unserialize' == context:
1133 cases = { 'serialize' : self.c_serialize_name,
1134 'unserialize' : self.c_unserialize_name,
1135 'unpack' : self.c_unpack_name,
1136 'sizeof' : self.c_sizeof_name }
1137 func_name = cases[context]
1139 param_fields, wire_fields, params = get_serialize_params(context, self)
1140 variable_size_fields = 0
1141 # maximum space required for type definition of function arguments
1144 # determine N(variable_fields)
1145 for field in param_fields:
1146 # if self.is_switch, treat all fields as if they are variable sized
1147 if not field.type.fixed_size() or self.is_switch:
1148 variable_size_fields += 1
1149 # determine maxtypelen
1151 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1154 indent = ' '*(len(func_name)+2)
1157 typespec, pointerspec, field_name = p
1158 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1159 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1160 # insert function name
1161 param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1162 param_str = list(map(lambda x: "%s," % x, param_str))
1163 for s in param_str[:-1]:
1165 _h("%s);" % param_str[-1].rstrip(','))
1166 _c("%s)" % param_str[-1].rstrip(','))
1173 if 'serialize' == context:
1174 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1175 _c(' %s *xcb_out = *_buffer;', self.c_type)
1176 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1177 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1178 _c(' unsigned int xcb_align_to = 0;')
1180 _c(' char *xcb_out = *_buffer;')
1181 _c(' unsigned int xcb_buffer_len = 0;')
1182 _c(' unsigned int xcb_align_to = 0;')
1184 _c(' unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1185 prefix = [('_aux', '->', self)]
1188 elif context in ('unserialize', 'unpack'):
1189 _c(' char *xcb_tmp = (char *)_buffer;')
1190 if not self.is_switch:
1191 if not self.c_var_followed_by_fixed_fields:
1192 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1193 prefix = [('_aux', '->', self)]
1195 _c(' %s xcb_out;', self.c_type)
1196 prefix = [('xcb_out', '.', self)]
1198 aux_var = '_aux' # default for unpack: single pointer
1199 # note: unserialize not generated for switch
1200 if 'unserialize' == context:
1201 aux_var = '(*_aux)' # unserialize: double pointer (!)
1202 prefix = [(aux_var, '->', self)]
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 = 0;')
1209 _c(' unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1211 elif 'sizeof' == context:
1212 param_names = [p[2] for p in params]
1214 # switch: call _unpack()
1215 _c(' %s _aux;', self.c_type)
1216 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1219 elif self.c_var_followed_by_fixed_fields:
1220 # special case: call _unserialize()
1221 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1225 _c(' char *xcb_tmp = (char *)_buffer;')
1226 prefix = [('_aux', '->', self)]
1228 _c(' unsigned int xcb_padding_offset = 0;')
1230 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1231 # update variable size fields (only important for context=='serialize'
1232 variable_size_fields = count
1233 if 'serialize' == context:
1234 temp_vars.append(' unsigned int xcb_pad = 0;')
1235 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};')
1236 temp_vars.append(' struct iovec xcb_parts[%d];' % count)
1237 temp_vars.append(' unsigned int xcb_parts_idx = 0;')
1238 temp_vars.append(' unsigned int xcb_block_len = 0;')
1239 temp_vars.append(' unsigned int i;')
1240 temp_vars.append(' char *xcb_tmp;')
1241 elif 'sizeof' == context:
1242 # neither switch nor intermixed fixed and variable size fields:
1243 # evaluate parameters directly
1244 if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1246 # look if we have to declare an '_aux' variable at all
1247 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1248 if not self.c_var_followed_by_fixed_fields:
1249 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1251 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1253 _c(' unsigned int xcb_buffer_len = 0;')
1254 _c(' unsigned int xcb_block_len = 0;')
1255 _c(' unsigned int xcb_pad = 0;')
1256 _c(' unsigned int xcb_align_to = 0;')
1262 for l in code_lines:
1265 # variable sized fields have been collected, now
1266 # allocate memory and copy everything into a continuous memory area
1267 # note: this is not necessary in case of unpack
1268 if context in ('serialize', 'unserialize'):
1269 # unserialize: check for sizeof-only invocation
1270 if 'unserialize' == context:
1272 _c(' if (NULL == _aux)')
1273 _c(' return xcb_buffer_len;')
1276 _c(' if (NULL == %s) {', aux_ptr)
1277 _c(' /* allocate memory */')
1278 _c(' %s = malloc(xcb_buffer_len);', aux_ptr)
1279 if 'serialize' == context:
1280 _c(' *_buffer = xcb_out;')
1284 # serialize: handle variable size fields in a loop
1285 if 'serialize' == context:
1286 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1287 if len(wire_fields)>0:
1288 _c(' *xcb_out = *_aux;')
1289 # copy variable size fields into the buffer
1290 if variable_size_fields > 0:
1292 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1293 _c(' xcb_tmp = (char*)++xcb_out;')
1294 _c(' xcb_tmp += xcb_out_pad;')
1296 _c(' xcb_tmp = xcb_out;')
1298 # variable sized fields
1299 _c(' for(i=0; i<xcb_parts_idx; i++) {')
1300 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1301 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1302 _c(' if (0 != xcb_parts[i].iov_len)')
1303 _c(' xcb_tmp += xcb_parts[i].iov_len;')
1306 # unserialize: assign variable size fields individually
1307 if 'unserialize' == context:
1308 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1309 param_fields.reverse()
1310 for field in param_fields:
1311 if not field.type.fixed_size():
1312 _c(' xcb_tmp -= %s_len;', field.c_field_name)
1313 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1314 _c(' *%s = xcb_out;', aux_ptr)
1317 _c(' return xcb_buffer_len;')
1321 def _c_iterator_get_end(field, accum):
1323 Figures out what C code is needed to find the end of a variable-length structure field.
1324 For nested structures, recurses into its last variable-sized field.
1325 For lists, calls the end function
1327 if field.type.is_container:
1328 accum = field.c_accessor_name + '(' + accum + ')'
1329 return _c_iterator_get_end(field.type.last_varsized_field, accum)
1330 if field.type.is_list:
1331 # XXX we can always use the first way
1332 if field.type.member.is_simple:
1333 return field.c_end_name + '(' + accum + ')'
1335 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1337 def _c_iterator(self, name):
1339 Declares the iterator structure and next/end functions for a given type.
1344 _h(' * @brief %s', self.c_iterator_type)
1346 _h('typedef struct %s {', self.c_iterator_type)
1347 _h(' %s *data; /**< */', self.c_type)
1348 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2))
1349 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2))
1350 _h('} %s;', self.c_iterator_type)
1356 _h(' * Get the next element of the iterator')
1357 _h(' * @param i Pointer to a %s', self.c_iterator_type)
1359 _h(' * Get the next element in the iterator. The member rem is')
1360 _h(' * decreased by one. The member data points to the next')
1361 _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1365 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type)
1366 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type)
1369 if not self.fixed_size():
1370 _c(' %s *R = i->data;', self.c_type)
1373 # FIXME - how to determine the size of a variable size union??
1374 _c(' /* FIXME - determine the size of the union %s */', self.c_type)
1376 if self.c_need_sizeof:
1377 _c(' xcb_generic_iterator_t child;')
1378 _c(' child.data = (%s *)(((char *)R) + %s(R));',
1379 self.c_type, self.c_sizeof_name)
1380 _c(' i->index = (char *) child.data - (char *) i->data;')
1382 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1383 _c(' i->index = child.index;')
1385 _c(' i->data = (%s *) child.data;', self.c_type)
1390 _c(' i->index += sizeof(%s);', self.c_type)
1396 _h(' * Return the iterator pointing to the last element')
1397 _h(' * @param i An %s', self.c_iterator_type)
1398 _h(' * @return The iterator pointing to the last element')
1400 _h(' * Set the current element in the iterator to the last element.')
1401 _h(' * The member rem is set to 0. The member data points to the')
1402 _h(' * last element.')
1405 _hc('xcb_generic_iterator_t')
1406 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type)
1407 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type)
1409 _c(' xcb_generic_iterator_t ret;')
1411 if self.fixed_size():
1412 _c(' ret.data = i.data + i.rem;')
1413 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1416 _c(' while(i.rem > 0)')
1417 _c(' %s(&i);', self.c_next_name)
1418 _c(' ret.data = i.data;')
1419 _c(' ret.rem = i.rem;')
1420 _c(' ret.index = i.index;')
1425 def _c_accessor_get_length(expr, field_mapping=None):
1427 Figures out what C code is needed to get a length field.
1428 The field_mapping parameter can be used to change the absolute name of a length field.
1429 For fields that follow a variable-length field, use the accessor.
1430 Otherwise, just reference the structure field directly.
1433 lenfield_name = expr.lenfield_name
1434 if lenfield_name is not None:
1435 if field_mapping is not None:
1436 lenfield_name = field_mapping[lenfield_name][0]
1438 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1439 # special case: variable and fixed size fields are intermixed
1440 # if the lenfield is among the fixed size fields, there is no need
1441 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1442 return field_mapping(expr.lenfield_name)
1443 elif expr.lenfield_name is not None:
1444 return lenfield_name
1446 return str(expr.nmemb)
1448 def _c_accessor_get_expr(expr, field_mapping):
1450 Figures out what C code is needed to get the length of a list field.
1451 The field_mapping parameter can be used to change the absolute name of a length field.
1452 Recurses for math operations.
1453 Returns bitcount for value-mask fields.
1454 Otherwise, uses the value of the length field.
1456 lenexp = _c_accessor_get_length(expr, field_mapping)
1459 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1460 elif expr.op == 'popcount':
1461 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1462 elif expr.op == 'enumref':
1463 enum_name = expr.lenfield_type.name
1464 constant_name = expr.lenfield_name
1465 c_name = _n(enum_name + (constant_name,)).upper()
1467 elif expr.op == 'sumof':
1468 # locate the referenced list object
1469 list_obj = expr.lenfield_type
1471 for f in expr.lenfield_parent.fields:
1472 if f.field_name == expr.lenfield_name:
1477 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1478 list_name = field_mapping[field.c_field_name][0]
1479 c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1480 # note: xcb_sumof() has only been defined for integers
1481 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1482 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1483 elif expr.op != None:
1484 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1485 ' ' + expr.op + ' ' +
1486 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1488 return 'xcb_popcount(' + lenexp + ')'
1492 def type_pad_type(type):
1497 def _c_accessors_field(self, field):
1499 Declares the accessor functions for a non-list field that follows a variable-length field.
1501 c_type = self.c_type
1503 # special case: switch
1504 switch_obj = self if self.is_switch else None
1505 if self.is_case_or_bitcase:
1506 switch_obj = self.parents[-1]
1507 if switch_obj is not None:
1508 c_type = switch_obj.c_type
1510 if field.type.is_simple:
1512 _hc('%s', field.c_field_type)
1513 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1514 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1516 if field.prev_varsized_field is None:
1517 _c(' return (%s *) (R + 1);', field.c_field_type)
1519 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1520 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1521 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1525 if field.type.is_switch and switch_obj is None:
1526 return_type = 'void *'
1528 return_type = '%s *' % field.c_field_type
1531 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type)
1532 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type)
1534 if field.prev_varsized_field is None:
1535 _c(' return (%s) (R + 1);', return_type)
1536 # note: the special case 'variable fields followed by fixed size fields'
1537 # is not of any consequence here, since the ordering gets
1538 # 'corrected' in the reply function
1540 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1541 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1542 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1546 def _c_accessors_list(self, field):
1548 Declares the accessor functions for a list field.
1549 Declares a direct-accessor function only if the list members are fixed size.
1550 Declares length and get-iterator functions always.
1553 def get_align_pad(field):
1554 prev = field.prev_varsized_field
1555 prev_prev = field.prev_varsized_field.prev_varsized_field
1557 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1558 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1564 c_type = self.c_type
1566 # special case: switch
1567 # in case of switch, 2 params have to be supplied to certain accessor functions:
1568 # 1. the anchestor object (request or reply)
1569 # 2. the (anchestor) switch object
1570 # the reason is that switch is either a child of a request/reply or nested in another switch,
1571 # so whenever we need to access a length field, we might need to refer to some anchestor type
1572 switch_obj = self if self.is_switch else None
1573 if self.is_case_or_bitcase:
1574 switch_obj = self.parents[-1]
1575 if switch_obj is not None:
1576 c_type = switch_obj.c_type
1580 parents = self.parents if hasattr(self, 'parents') else [self]
1581 # 'R': parents[0] is always the 'toplevel' container type
1582 params.append(('const %s *R' % parents[0].c_type, parents[0]))
1583 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1584 # auxiliary object for 'R' parameters
1587 if switch_obj is not None:
1588 # now look where the fields are defined that are needed to evaluate
1589 # the switch expr, and store the parent objects in accessor_params and
1590 # the fields in switch_fields
1592 # 'S': name for the 'toplevel' switch
1593 toplevel_switch = parents[1]
1594 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1595 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1597 # initialize prefix for everything "below" S
1598 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1599 prefix = [(prefix_str, '->', toplevel_switch)]
1601 # look for fields in the remaining containers
1602 for p in parents[2:] + [self]:
1603 # the separator between parent and child is always '.' here,
1604 # because of nested switch statements
1605 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1606 prefix.append((p.name[-1], '.', p))
1607 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1609 # auxiliary object for 'S' parameter
1614 if list.member.fixed_size():
1615 idx = 1 if switch_obj is not None else 0
1617 _hc('%s *', field.c_field_type)
1619 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0])
1620 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0])
1623 if switch_obj is not None:
1624 _c(' return %s;', fields[field.c_field_name][0])
1625 elif field.prev_varsized_field is None:
1626 _c(' return (%s *) (R + 1);', field.c_field_type)
1628 (prev_varsized_field, align_pad) = get_align_pad(field)
1630 if align_pad is None:
1631 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1632 type_pad_type(field.first_field_after_varsized.type.c_type))
1634 _c(' xcb_generic_iterator_t prev = %s;',
1635 _c_iterator_get_end(prev_varsized_field, 'R'))
1636 _c(' return (%s *) ((char *) prev.data + %s + %d);',
1637 field.c_field_type, align_pad, field.prev_varsized_offset)
1642 if switch_obj is not None:
1643 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type)
1644 spacing = ' '*(len(field.c_length_name)+2)
1645 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1646 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1647 length = _c_accessor_get_expr(field.type.expr, fields)
1649 _h('%s (const %s *R /**< */);', field.c_length_name, c_type)
1650 _c('%s (const %s *R /**< */)', field.c_length_name, c_type)
1651 length = _c_accessor_get_expr(field.type.expr, fields)
1653 _c(' return %s;', length)
1656 if field.type.member.is_simple:
1658 _hc('xcb_generic_iterator_t')
1659 if switch_obj is not None:
1660 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type)
1661 spacing = ' '*(len(field.c_end_name)+2)
1662 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1663 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1665 _h('%s (const %s *R /**< */);', field.c_end_name, c_type)
1666 _c('%s (const %s *R /**< */)', field.c_end_name, c_type)
1668 _c(' xcb_generic_iterator_t i;')
1670 param = 'R' if switch_obj is None else 'S'
1671 if switch_obj is not None:
1672 _c(' i.data = %s + %s;', fields[field.c_field_name][0],
1673 _c_accessor_get_expr(field.type.expr, fields))
1674 elif field.prev_varsized_field == None:
1675 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1676 _c_accessor_get_expr(field.type.expr, fields))
1678 _c(' xcb_generic_iterator_t child = %s;',
1679 _c_iterator_get_end(field.prev_varsized_field, 'R'))
1680 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1681 _c_accessor_get_expr(field.type.expr, fields))
1684 _c(' i.index = (char *) i.data - (char *) %s;', param)
1690 _hc('%s', field.c_iterator_type)
1691 if switch_obj is not None:
1692 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type)
1693 spacing = ' '*(len(field.c_iterator_name)+2)
1694 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1695 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
1697 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type)
1698 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type)
1700 _c(' %s i;', field.c_iterator_type)
1702 if switch_obj is not None:
1703 _c(' i.data = %s;', fields[field.c_field_name][0])
1704 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1705 elif field.prev_varsized_field == None:
1706 _c(' i.data = (%s *) (R + 1);', field.c_field_type)
1708 (prev_varsized_field, align_pad) = get_align_pad(field)
1710 if align_pad is None:
1711 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1712 type_pad_type(field.c_field_type))
1714 _c(' xcb_generic_iterator_t prev = %s;',
1715 _c_iterator_get_end(prev_varsized_field, 'R'))
1716 _c(' i.data = (%s *) ((char *) prev.data + %s);',
1717 field.c_field_type, align_pad)
1719 if switch_obj is None:
1720 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1721 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1725 def _c_accessors(self, name, base):
1727 Declares the accessor functions for the fields of a structure.
1729 # no accessors for switch itself -
1730 # switch always needs to be unpacked explicitly
1731 # if self.is_switch:
1735 for field in self.fields:
1736 if not field.type.is_pad:
1737 if field.type.is_list and not field.type.fixed_size():
1738 _c_accessors_list(self, field)
1739 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1740 _c_accessors_field(self, field)
1742 def c_simple(self, name):
1744 Exported function that handles cardinal type declarations.
1745 These are types which are typedef'd to one of the CARDx's, char, float, etc.
1747 _c_type_setup(self, name, ())
1749 if (self.name != name):
1754 _h('typedef %s %s;', _t(self.name), my_name)
1757 _c_iterator(self, name)
1759 def _c_complex(self, force_packed = False):
1761 Helper function for handling all structure types.
1762 Called for all structs, requests, replies, events, errors.
1767 _h(' * @brief %s', self.c_type)
1769 _h('typedef %s %s {', self.c_container, self.c_type)
1775 for field in self.fields:
1776 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1777 varfield = field.c_field_name
1780 struct_fields.append(field)
1782 for field in struct_fields:
1783 length = len(field.c_field_type)
1784 # account for '*' pointer_spec
1785 if not field.type.fixed_size() and not self.is_union:
1787 maxtypelen = max(maxtypelen, length)
1789 def _c_complex_field(self, field, space=''):
1790 if (field.type.fixed_size() or self.is_union or
1791 # in case of switch with switch children, don't make the field a pointer
1792 # necessary for unserialize to work
1793 (self.is_switch and field.type.is_switch)):
1794 spacing = ' ' * (maxtypelen - len(field.c_field_type))
1795 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1797 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1798 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1800 if not self.is_switch:
1801 for field in struct_fields:
1802 _c_complex_field(self, field)
1804 for b in self.bitcases:
1807 _h(' struct _%s {', b.c_field_name)
1809 for field in b.type.fields:
1810 _c_complex_field(self, field, space)
1812 _h(' } %s;', b.c_field_name)
1814 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1816 def c_struct(self, name):
1818 Exported function that handles structure declarations.
1820 _c_type_setup(self, name, ())
1822 _c_accessors(self, name, name)
1823 _c_iterator(self, name)
1825 def c_union(self, name):
1827 Exported function that handles union declarations.
1829 _c_type_setup(self, name, ())
1831 _c_iterator(self, name)
1833 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1835 Declares a request function.
1838 # Four stunningly confusing possibilities here:
1841 # ------------------------------
1843 # 0 flag CHECKED flag Normal Mode
1844 # void_cookie req_cookie
1845 # ------------------------------
1846 # "req_checked" "req_unchecked"
1847 # CHECKED flag 0 flag Abnormal Mode
1848 # void_cookie req_cookie
1849 # ------------------------------
1852 # Whether we are _checked or _unchecked
1853 checked = void and not regular
1854 unchecked = not void and not regular
1856 # What kind of cookie we return
1857 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1859 # What flag is passed to xcb_request
1860 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1863 if func_flags == '0':
1864 func_flags = 'XCB_REQUEST_REPLY_FDS'
1866 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1868 # Global extension id variable or NULL for xproto
1869 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1871 # What our function name is
1872 func_name = self.c_request_name if not aux else self.c_aux_name
1874 func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1876 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1880 maxtypelen = len('xcb_connection_t')
1882 # special case: list with variable size elements
1883 list_with_var_size_elems = False
1885 for field in self.fields:
1887 # The field should appear as a call parameter
1888 param_fields.append(field)
1889 if field.wire and not field.auto:
1890 # We need to set the field up in the structure
1891 wire_fields.append(field)
1892 if field.type.c_need_serialize or field.type.c_need_sizeof:
1893 serial_fields.append(field)
1895 for field in param_fields:
1896 c_field_const_type = field.c_field_const_type
1897 if field.type.c_need_serialize and not aux:
1898 c_field_const_type = "const void"
1899 if len(c_field_const_type) > maxtypelen:
1900 maxtypelen = len(c_field_const_type)
1901 if field.type.is_list and not field.type.member.fixed_size():
1902 list_with_var_size_elems = True
1908 if hasattr(self, "doc") and self.doc:
1910 _h(' * @brief ' + self.doc.brief)
1912 _h(' * No brief doc yet')
1915 _h(' * @param c The connection')
1916 param_names = [f.c_field_name for f in param_fields]
1917 if hasattr(self, "doc") and self.doc:
1918 for field in param_fields:
1919 # XXX: hard-coded until we fix xproto.xml
1920 base_func_name = self.c_request_name if not aux else self.c_aux_name
1921 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1923 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1925 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1928 # XXX: why the 'xcb' prefix?
1929 key = ('xcb', field.enum)
1932 if namecount[tname] > 1:
1933 tname = _t(key + ('enum',))
1934 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1936 if self.doc and field.field_name in self.doc.fields:
1937 desc = self.doc.fields[field.field_name]
1938 for name in param_names:
1939 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1940 desc = desc.split("\n")
1941 desc = [line if line != '' else '\\n' for line in desc]
1942 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1943 # If there is no documentation yet, we simply don't generate an
1944 # @param tag. Doxygen will then warn about missing documentation.
1946 _h(' * @return A cookie')
1949 if hasattr(self, "doc") and self.doc:
1950 if self.doc.description:
1951 desc = self.doc.description
1952 for name in param_names:
1953 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1954 desc = desc.split("\n")
1955 _h(' * ' + "\n * ".join(desc))
1957 _h(' * No description yet')
1959 _h(' * Delivers a request to the X server.')
1962 _h(' * This form can be used only if the request will not cause')
1963 _h(' * a reply to be generated. Any returned error will be')
1964 _h(' * saved for handling by xcb_request_check().')
1966 _h(' * This form can be used only if the request will cause')
1967 _h(' * a reply to be generated. Any returned error will be')
1968 _h(' * placed in the event queue.')
1971 _hc('%s', cookie_type)
1973 spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1974 comma = ',' if len(param_fields) else ');'
1975 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1976 comma = ',' if len(param_fields) else ')'
1977 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma)
1979 func_spacing = ' ' * (len(func_name) + 2)
1980 count = len(param_fields)
1981 for field in param_fields:
1983 c_field_const_type = field.c_field_const_type
1984 c_pointer = field.c_pointer
1985 if field.type.c_need_serialize and not aux:
1986 c_field_const_type = "const void"
1988 spacing = ' ' * (maxtypelen - len(c_field_const_type))
1989 comma = ',' if count else ');'
1990 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1991 spacing, c_pointer, field.c_field_name, comma)
1992 comma = ',' if count else ')'
1993 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type,
1994 spacing, c_pointer, field.c_field_name, comma)
1997 if not self.c_var_followed_by_fixed_fields:
1998 for field in param_fields:
1999 if not field.type.fixed_size():
2001 if field.type.c_need_serialize:
2002 # _serialize() keeps track of padding automatically
2004 dimension = count + 2
2007 _c(' static const xcb_protocol_request_t xcb_req = {')
2008 _c(' /* count */ %d,', count)
2009 _c(' /* ext */ %s,', func_ext_global)
2010 _c(' /* opcode */ %s,', self.c_request_name.upper())
2011 _c(' /* isvoid */ %d', 1 if void else 0)
2015 _c(' struct iovec xcb_parts[%d];', dimension)
2016 _c(' %s xcb_ret;', func_cookie)
2017 _c(' %s xcb_out;', self.c_type)
2018 if self.c_var_followed_by_fixed_fields:
2019 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */')
2020 _c(' void *xcb_aux = 0;')
2023 for idx, f in enumerate(serial_fields):
2025 _c(' void *xcb_aux%d = 0;' % (idx))
2026 if list_with_var_size_elems:
2027 _c(' unsigned int i;')
2028 _c(' unsigned int xcb_tmp_len;')
2029 _c(' char *xcb_tmp;')
2031 # simple request call tracing
2032 # _c(' printf("in function %s\\n");' % func_name)
2035 for field in wire_fields:
2036 if field.type.fixed_size():
2037 if field.type.is_expr:
2038 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2039 elif field.type.is_pad:
2040 if field.type.nmemb == 1:
2041 _c(' xcb_out.%s = 0;', field.c_field_name)
2043 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2045 if field.type.nmemb == 1:
2046 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2048 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2050 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2051 serialize_args = get_serialize_params(context, type_obj,
2054 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2056 # calls in order to free dyn. all. memory
2060 if not self.c_var_followed_by_fixed_fields:
2061 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2062 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);')
2063 _c(' xcb_parts[3].iov_base = 0;')
2064 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2068 for field in param_fields:
2069 if not field.type.fixed_size():
2070 _c(' /* %s %s */', field.type.c_type, field.c_field_name)
2071 # default: simple cast to char *
2072 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2073 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2074 if field.type.is_list:
2075 if field.type.member.fixed_size():
2076 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2077 _c_accessor_get_expr(field.type.expr, None),
2078 field.type.member.c_wiretype)
2080 list_length = _c_accessor_get_expr(field.type.expr, None)
2083 _c(" xcb_parts[%d].iov_len = 0;" % count)
2084 _c(" xcb_tmp = (char *)%s;", field.c_field_name)
2085 _c(" for(i=0; i<%s; i++) {" % list_length)
2086 _c(" xcb_tmp_len = %s(xcb_tmp);" %
2087 (field.type.c_sizeof_name))
2088 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2089 _c(" xcb_tmp += xcb_tmp_len;")
2092 # not supposed to happen
2093 raise Exception("unhandled variable size field %s" % field.c_field_name)
2096 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2097 idx = serial_fields.index(field)
2098 aux_var = '&xcb_aux%d' % idx
2099 context = 'serialize' if aux else 'sizeof'
2100 _c(' xcb_parts[%d].iov_len =', count)
2102 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2103 _c(' %s (%s);', field.type.c_serialize_name, serialize_args)
2104 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2105 free_calls.append(' free(xcb_aux%d);' % idx)
2107 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2108 func_name = field.type.c_sizeof_name
2109 _c(' %s (%s);', func_name, serialize_args)
2112 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2113 # the _serialize() function keeps track of padding automatically
2114 _c(' xcb_parts[%d].iov_base = 0;', count)
2115 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2118 # elif self.c_var_followed_by_fixed_fields:
2120 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;')
2121 # request header: opcodes + length
2122 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2125 buffer_var = '&xcb_aux'
2126 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2127 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2128 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2129 free_calls.append(' free(xcb_aux);')
2130 # no padding necessary - _serialize() keeps track of padding automatically
2133 for field in param_fields:
2135 _c(' xcb_send_fd(c, %s);', field.c_field_name)
2137 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2139 # free dyn. all. data, if any
2140 for f in free_calls:
2142 _c(' return xcb_ret;')
2145 def _c_reply(self, name):
2147 Declares the function that returns the reply structure.
2149 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2150 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2151 spacing3 = ' ' * (len(self.c_reply_name) + 2)
2153 # check if _unserialize() has to be called for any field
2154 def look_for_special_cases(complex_obj):
2155 unserialize_fields = []
2156 # no unserialize call in case of switch
2157 if not complex_obj.is_switch:
2158 for field in complex_obj.fields:
2159 # three cases: 1. field with special case
2160 # 2. container that contains special case field
2161 # 3. list with special case elements
2162 if field.type.c_var_followed_by_fixed_fields:
2163 unserialize_fields.append(field)
2164 elif field.type.is_container:
2165 unserialize_fields += look_for_special_cases(field.type)
2166 elif field.type.is_list:
2167 if field.type.member.c_var_followed_by_fixed_fields:
2168 unserialize_fields.append(field)
2169 if field.type.member.is_container:
2170 unserialize_fields += look_for_special_cases(field.type.member)
2171 return unserialize_fields
2173 unserialize_fields = look_for_special_cases(self.reply)
2177 _h(' * Return the reply')
2178 _h(' * @param c The connection')
2179 _h(' * @param cookie The cookie')
2180 _h(' * @param e The xcb_generic_error_t supplied')
2182 _h(' * Returns the reply of the request asked by')
2184 _h(' * The parameter @p e supplied to this function must be NULL if')
2185 _h(' * %s(). is used.', self.c_unchecked_name)
2186 _h(' * Otherwise, it stores the error if any.')
2188 _h(' * The returned value must be freed by the caller using free().')
2191 _hc('%s *', self.c_reply_type)
2192 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1)
2193 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type)
2194 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2)
2195 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2)
2198 if len(unserialize_fields)>0:
2199 # certain variable size fields need to be unserialized explicitly
2200 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2201 self.c_reply_type, self.c_reply_type)
2203 for field in unserialize_fields:
2204 if field.type.is_list:
2205 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2206 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2207 _c(' %s *%s_data;', field.c_field_type, field.c_field_name)
2209 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2210 # call _unserialize(), using the reply as source and target buffer
2211 _c(' /* special cases: transform parts of the reply to match XCB data structures */')
2212 for field in unserialize_fields:
2213 if field.type.is_list:
2214 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name)
2215 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2216 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2217 field.c_field_name, field.c_field_name)
2218 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2220 # return the transformed reply
2221 _c(' return reply;')
2224 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2228 def _c_reply_has_fds(self):
2229 for field in self.fields:
2234 def _c_reply_fds(self, name):
2236 Declares the function that returns fds related to the reply.
2238 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2239 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2242 _h(' * Return the reply fds')
2243 _h(' * @param c The connection')
2244 _h(' * @param reply The reply')
2246 _h(' * Returns the array of reply fds of the request asked by')
2248 _h(' * The returned value must be freed by the caller using free().')
2252 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
2253 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
2254 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
2257 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2262 def _c_opcode(name, opcode):
2264 Declares the opcode define for requests, events, and errors.
2268 _h('/** Opcode for %s. */', _n(name))
2269 _h('#define %s %s', _n(name).upper(), opcode)
2271 def _c_cookie(self, name):
2273 Declares the cookie type for a non-void request.
2278 _h(' * @brief %s', self.c_cookie_type)
2280 _h('typedef struct %s {', self.c_cookie_type)
2281 _h(' unsigned int sequence; /**< */')
2282 _h('} %s;', self.c_cookie_type)
2284 def _man_request(self, name, cookie_type, void, aux):
2285 param_fields = [f for f in self.fields if f.visible]
2287 func_name = self.c_request_name if not aux else self.c_aux_name
2289 def create_link(linkname):
2290 name = 'man/%s.%s' % (linkname, section)
2292 sys.stdout.write(name)
2294 f.write('.so man%s/%s.%s' % (section, func_name, section))
2298 sys.stdout.write('man/%s.%s ' % (func_name, section))
2299 # Our CWD is src/, so this will end up in src/man/
2300 f = open('man/%s.%s' % (func_name, section), 'w')
2301 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2302 # Left-adjust instead of adjusting to both sides
2304 f.write('.SH NAME\n')
2305 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2306 f.write('%s \\- %s\n' % (func_name, brief))
2307 f.write('.SH SYNOPSIS\n')
2308 # Don't split words (hyphenate)
2310 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2312 # function prototypes
2314 count = len(param_fields)
2315 for field in param_fields:
2317 c_field_const_type = field.c_field_const_type
2318 c_pointer = field.c_pointer
2319 if c_pointer == ' ':
2321 if field.type.c_need_serialize and not aux:
2322 c_field_const_type = "const void"
2324 comma = ', ' if count else ');'
2325 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2327 f.write('.SS Request function\n')
2329 base_func_name = self.c_request_name if not aux else self.c_aux_name
2330 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2331 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2334 f.write('.SS Reply datastructure\n')
2337 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2341 for field in self.reply.fields:
2342 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2345 struct_fields.append(field)
2347 for field in struct_fields:
2348 length = len(field.c_field_type)
2349 # account for '*' pointer_spec
2350 if not field.type.fixed_size():
2352 maxtypelen = max(maxtypelen, length)
2354 def _c_complex_field(self, field, space=''):
2355 if (field.type.fixed_size() or
2356 # in case of switch with switch children, don't make the field a pointer
2357 # necessary for unserialize to work
2358 (self.is_switch and field.type.is_switch)):
2359 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2360 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2362 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2363 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2364 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2366 if not self.is_switch:
2367 for field in struct_fields:
2368 _c_complex_field(self, field)
2370 for b in self.bitcases:
2374 for field in b.type.fields:
2375 _c_complex_field(self, field, space)
2377 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2380 f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2383 f.write('.SS Reply function\n')
2385 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2386 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2387 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2388 create_link('%s' % self.c_reply_name)
2390 has_accessors = False
2391 for field in self.reply.fields:
2392 if field.type.is_list and not field.type.fixed_size():
2393 has_accessors = True
2394 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2395 has_accessors = True
2398 f.write('.SS Reply accessors\n')
2400 def _c_accessors_field(self, field):
2402 Declares the accessor functions for a non-list field that follows a variable-length field.
2404 c_type = self.c_type
2406 # special case: switch
2407 switch_obj = self if self.is_switch else None
2408 if self.is_case_or_bitcase:
2409 switch_obj = self.parents[-1]
2410 if switch_obj is not None:
2411 c_type = switch_obj.c_type
2413 if field.type.is_simple:
2414 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2415 create_link('%s' % field.c_accessor_name)
2417 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2418 create_link('%s' % field.c_accessor_name)
2420 def _c_accessors_list(self, field):
2422 Declares the accessor functions for a list field.
2423 Declares a direct-accessor function only if the list members are fixed size.
2424 Declares length and get-iterator functions always.
2427 c_type = self.reply.c_type
2429 # special case: switch
2430 # in case of switch, 2 params have to be supplied to certain accessor functions:
2431 # 1. the anchestor object (request or reply)
2432 # 2. the (anchestor) switch object
2433 # the reason is that switch is either a child of a request/reply or nested in another switch,
2434 # so whenever we need to access a length field, we might need to refer to some anchestor type
2435 switch_obj = self if self.is_switch else None
2436 if self.is_case_or_bitcase:
2437 switch_obj = self.parents[-1]
2438 if switch_obj is not None:
2439 c_type = switch_obj.c_type
2443 parents = self.parents if hasattr(self, 'parents') else [self]
2444 # 'R': parents[0] is always the 'toplevel' container type
2445 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2446 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2447 # auxiliary object for 'R' parameters
2450 if switch_obj is not None:
2451 # now look where the fields are defined that are needed to evaluate
2452 # the switch expr, and store the parent objects in accessor_params and
2453 # the fields in switch_fields
2455 # 'S': name for the 'toplevel' switch
2456 toplevel_switch = parents[1]
2457 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2458 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2460 # initialize prefix for everything "below" S
2461 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2462 prefix = [(prefix_str, '->', toplevel_switch)]
2464 # look for fields in the remaining containers
2465 for p in parents[2:] + [self]:
2466 # the separator between parent and child is always '.' here,
2467 # because of nested switch statements
2468 if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2469 prefix.append((p.name[-1], '.', p))
2470 fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2472 # auxiliary object for 'S' parameter
2475 if list.member.fixed_size():
2476 idx = 1 if switch_obj is not None else 0
2478 f.write('%s *\\fB%s\\fP(%s);\n' %
2479 (field.c_field_type, field.c_accessor_name, params[idx][0]))
2480 create_link('%s' % field.c_accessor_name)
2483 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2484 (field.c_length_name, c_type))
2485 create_link('%s' % field.c_length_name)
2487 if field.type.member.is_simple:
2489 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2490 (field.c_end_name, c_type))
2491 create_link('%s' % field.c_end_name)
2494 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2495 (field.c_iterator_type, field.c_iterator_name,
2497 create_link('%s' % field.c_iterator_name)
2499 for field in self.reply.fields:
2500 if field.type.is_list and not field.type.fixed_size():
2501 _c_accessors_list(self, field)
2502 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2503 _c_accessors_field(self, field)
2507 # Re-enable hyphenation and adjusting to both sides
2510 # argument reference
2511 f.write('.SH REQUEST ARGUMENTS\n')
2512 f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2513 f.write('The XCB connection to X11.\n')
2514 for field in param_fields:
2515 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2516 printed_enum = False
2517 # XXX: hard-coded until we fix xproto.xml
2518 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2520 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2522 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2524 if hasattr(field, "enum") and field.enum:
2525 # XXX: why the 'xcb' prefix?
2526 key = ('xcb', field.enum)
2528 f.write('One of the following values:\n')
2531 count = len(enum.values)
2532 for (enam, eval) in enum.values:
2534 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2535 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2536 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2537 f.write('%s\n' % desc)
2539 f.write('TODO: NOT YET DOCUMENTED.\n')
2544 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2545 desc = self.doc.fields[field.field_name]
2546 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2549 f.write('%s\n' % desc)
2551 f.write('TODO: NOT YET DOCUMENTED.\n')
2557 f.write('.SH REPLY FIELDS\n')
2558 # These fields are present in every reply:
2559 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2560 f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2561 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2562 'be used to tell replies apart from each other.\n') %
2563 _n(self.reply.name).upper())
2564 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2565 f.write('The sequence number of the last request processed by the X11 server.\n')
2566 f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2567 f.write('The length of the reply, in words (a word is 4 bytes).\n')
2568 for field in self.reply.fields:
2569 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2570 field.c_field_name.startswith('pad')):
2573 if field.type.is_list and not field.type.fixed_size():
2575 elif field.prev_varsized_field is not None or not field.type.fixed_size():
2577 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2578 printed_enum = False
2579 if hasattr(field, "enum") and field.enum:
2580 # XXX: why the 'xcb' prefix?
2581 key = ('xcb', field.enum)
2583 f.write('One of the following values:\n')
2586 count = len(enum.values)
2587 for (enam, eval) in enum.values:
2589 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2590 if enum.doc and enam in enum.doc.fields:
2591 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2592 f.write('%s\n' % desc)
2594 f.write('TODO: NOT YET DOCUMENTED.\n')
2599 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2600 desc = self.reply.doc.fields[field.field_name]
2601 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2604 f.write('%s\n' % desc)
2606 f.write('TODO: NOT YET DOCUMENTED.\n')
2613 f.write('.SH DESCRIPTION\n')
2614 if hasattr(self, "doc") and self.doc and self.doc.description:
2615 desc = self.doc.description
2616 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2617 lines = desc.split('\n')
2618 f.write('\n'.join(lines) + '\n')
2620 f.write('.SH RETURN VALUE\n')
2622 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2623 'have to be handled in the event loop.\n\nIf you want to '
2624 'handle errors directly with \\fIxcb_request_check\\fP '
2625 'instead, use \\fI%s_checked\\fP. See '
2626 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2628 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2629 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2630 'handle errors in the event loop instead, use '
2631 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2633 (cookie_type, self.c_reply_name, base_func_name, section))
2634 f.write('.SH ERRORS\n')
2635 if hasattr(self, "doc") and self.doc:
2636 for errtype, errtext in sorted(self.doc.errors.items()):
2637 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2638 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2639 f.write('%s\n' % (errtext))
2640 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2641 f.write('This request does never generate any errors.\n')
2642 if hasattr(self, "doc") and self.doc and self.doc.example:
2643 f.write('.SH EXAMPLE\n')
2646 lines = self.doc.example.split('\n')
2647 f.write('\n'.join(lines) + '\n')
2649 f.write('.SH SEE ALSO\n')
2650 if hasattr(self, "doc") and self.doc:
2651 see = ['.BR %s (%s)' % ('xcb-requests', section)]
2652 if self.doc.example:
2653 see.append('.BR %s (%s)' % ('xcb-examples', section))
2654 for seename, seetype in sorted(self.doc.see.items()):
2655 if seetype == 'program':
2656 see.append('.BR %s (1)' % seename)
2657 elif seetype == 'event':
2658 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2659 elif seetype == 'request':
2660 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2661 elif seetype == 'function':
2662 see.append('.BR %s (%s)' % (seename, section))
2664 see.append('TODO: %s (type %s)' % (seename, seetype))
2665 f.write(',\n'.join(see) + '\n')
2666 f.write('.SH AUTHOR\n')
2667 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2670 def _man_event(self, name):
2672 sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2673 # Our CWD is src/, so this will end up in src/man/
2674 f = open('man/%s.%s' % (self.c_type, section), 'w')
2675 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2676 # Left-adjust instead of adjusting to both sides
2678 f.write('.SH NAME\n')
2679 brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2680 f.write('%s \\- %s\n' % (self.c_type, brief))
2681 f.write('.SH SYNOPSIS\n')
2682 # Don't split words (hyphenate)
2684 f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2687 f.write('.SS Event datastructure\n')
2690 f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2694 for field in self.fields:
2695 if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2698 struct_fields.append(field)
2700 for field in struct_fields:
2701 length = len(field.c_field_type)
2702 # account for '*' pointer_spec
2703 if not field.type.fixed_size():
2705 maxtypelen = max(maxtypelen, length)
2707 def _c_complex_field(self, field, space=''):
2708 if (field.type.fixed_size() or
2709 # in case of switch with switch children, don't make the field a pointer
2710 # necessary for unserialize to work
2711 (self.is_switch and field.type.is_switch)):
2712 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2713 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2715 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2717 if not self.is_switch:
2718 for field in struct_fields:
2719 _c_complex_field(self, field)
2721 for b in self.bitcases:
2725 for field in b.type.fields:
2726 _c_complex_field(self, field, space)
2728 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2731 f.write('} \\fB%s\\fP;\n' % self.c_type)
2736 # Re-enable hyphenation and adjusting to both sides
2739 # argument reference
2740 f.write('.SH EVENT FIELDS\n')
2741 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2742 f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2743 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2744 'to tell events apart from each other.\n') % _n(name).upper())
2745 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2746 f.write('The sequence number of the last request processed by the X11 server.\n')
2748 if not self.is_switch:
2749 for field in struct_fields:
2750 # Skip the fields which every event has, we already documented
2752 if field.c_field_name in ('response_type', 'sequence'):
2754 if isinstance(field.type, PadType):
2756 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2757 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2758 desc = self.doc.fields[field.field_name]
2759 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2760 f.write('%s\n' % desc)
2762 f.write('NOT YET DOCUMENTED.\n')
2765 f.write('.SH DESCRIPTION\n')
2766 if hasattr(self, "doc") and self.doc and self.doc.description:
2767 desc = self.doc.description
2768 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2769 lines = desc.split('\n')
2770 f.write('\n'.join(lines) + '\n')
2772 if hasattr(self, "doc") and self.doc and self.doc.example:
2773 f.write('.SH EXAMPLE\n')
2776 lines = self.doc.example.split('\n')
2777 f.write('\n'.join(lines) + '\n')
2779 f.write('.SH SEE ALSO\n')
2780 if hasattr(self, "doc") and self.doc:
2781 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2782 if self.doc.example:
2783 see.append('.BR %s (%s)' % ('xcb-examples', section))
2784 for seename, seetype in sorted(self.doc.see.items()):
2785 if seetype == 'program':
2786 see.append('.BR %s (1)' % seename)
2787 elif seetype == 'event':
2788 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2789 elif seetype == 'request':
2790 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2791 elif seetype == 'function':
2792 see.append('.BR %s (%s)' % (seename, section))
2794 see.append('TODO: %s (type %s)' % (seename, seetype))
2795 f.write(',\n'.join(see) + '\n')
2796 f.write('.SH AUTHOR\n')
2797 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2801 def c_request(self, name):
2803 Exported function that handles request declarations.
2805 _c_type_setup(self, name, ('request',))
2808 # Cookie type declaration
2809 _c_cookie(self, name)
2812 _c_opcode(name, self.opcode)
2814 # Request structure declaration
2818 _c_type_setup(self.reply, name, ('reply',))
2819 # Reply structure definition
2820 _c_complex(self.reply)
2821 # Request prototypes
2822 has_fds = _c_reply_has_fds(self.reply)
2823 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2824 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2826 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2827 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2829 _c_accessors(self.reply, name + ('reply',), name)
2830 _c_reply(self, name)
2832 _c_reply_fds(self, name)
2834 # Request prototypes
2835 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2836 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2838 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2839 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2841 # We generate the manpage afterwards because _c_type_setup has been called.
2842 # TODO: what about aux helpers?
2843 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2844 _man_request(self, name, cookie_type, not self.reply, False)
2846 def c_event(self, name):
2848 Exported function that handles event declarations.
2851 # The generic event structure xcb_ge_event_t has the full_sequence field
2852 # at the 32byte boundary. That's why we've to inject this field into GE
2853 # events while generating the structure for them. Otherwise we would read
2854 # garbage (the internal full_sequence) when accessing normal event fields
2856 force_packed = False
2857 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2859 for field in self.fields:
2860 if field.type.size != None and field.type.nmemb != None:
2861 event_size += field.type.size * field.type.nmemb
2862 if event_size == 32:
2863 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2864 idx = self.fields.index(field)
2865 self.fields.insert(idx + 1, full_sequence)
2867 # If the event contains any 64-bit extended fields, they need
2868 # to remain aligned on a 64-bit boundary. Adding full_sequence
2869 # would normally break that; force the struct to be packed.
2870 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
2873 _c_type_setup(self, name, ('event',))
2876 _c_opcode(name, self.opcodes[name])
2878 if self.name == name:
2879 # Structure definition
2880 _c_complex(self, force_packed)
2884 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2886 _man_event(self, name)
2888 def c_error(self, name):
2890 Exported function that handles error declarations.
2892 _c_type_setup(self, name, ('error',))
2895 _c_opcode(name, self.opcodes[name])
2897 if self.name == name:
2898 # Structure definition
2903 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2906 # Main routine starts here
2908 # Must create an "output" dictionary before any xcbgen imports.
2909 output = {'open' : c_open,
2911 'simple' : c_simple,
2913 'struct' : c_struct,
2915 'request' : c_request,
2920 # Boilerplate below this point
2922 # Check for the argument that specifies path to the xcbgen python package.
2924 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
2925 except getopt.GetoptError as err:
2927 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
2930 for (opt, arg) in opts:
2938 sys.path.insert(1, arg)
2941 sys.stdout.write('man_MANS = ')
2943 # Import the module class
2945 from xcbgen.state import Module
2946 from xcbgen.xtypes import *
2949 Failed to load the xcbgen Python package!
2950 Make sure that xcb/proto installed it on your Python path.
2951 If not, you will need to create a .pth file or define $PYTHONPATH
2953 Refer to the README file in xcb/proto for more info.
2957 # Ensure the man subdirectory exists
2960 except OSError as e:
2961 if e.errno != errno.EEXIST:
2964 # Parse the xml header
2965 module = Module(args[0], output)
2967 # Build type-registry and resolve type dependencies