function _c_helper_fieldaccess_expr: improve description
[free-sw/xcb/libxcb] / src / c_client.py
1 #!/usr/bin/env python
2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
5 import getopt
6 import os
7 import sys
8 import errno
9 import time
10 import re
11
12 # Jump to the bottom of this file for the main routine
13
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'}
17
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
19
20 _cplusplus_annoyances = {'class' : '_class',
21                          'new'   : '_new',
22                          'delete': '_delete'}
23 _c_keywords = {'default' : '_default'}
24
25 _hlines = []
26 _hlevel = 0
27 _clines = []
28 _clevel = 0
29 _ns = None
30
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
34 finished_sizeof = []
35 finished_switch = []
36
37 # keeps enum objects so that we can refer to them when generating manpages.
38 enums = {}
39
40 manpaths = False
41
42 def _h(fmt, *args):
43     '''
44     Writes the given line to the header file.
45     '''
46     _hlines[_hlevel].append(fmt % args)
47
48 def _c(fmt, *args):
49     '''
50     Writes the given line to the source file.
51     '''
52     _clines[_clevel].append(fmt % args)
53
54 def _hc(fmt, *args):
55     '''
56     Writes the given line to both the header and source files.
57     '''
58     _h(fmt, *args)
59     _c(fmt, *args)
60
61 def _c_wr_stringlist(indent, strlist):
62     '''
63     Writes the given list of strings to the source file.
64     Each line is prepended by the indent string
65     '''
66     for str in strlist:
67         _c("%s%s", indent, str)
68
69
70 class PreCode(object):
71     '''
72     For pre-code generated by expression generation
73     (for example, the for-loop of a sumof)
74     This has to account for recursiveness of the expression
75     generation, i.e., there may be pre-code for pre-code.
76     Therefore this is implemented as a stack of lists of lines.
77
78     If redirection is switched on, then all output is collected in
79     self.redirect_code and self.redirect_tempvars instead of
80     being sent to the output via _h und _c.
81     '''
82     def __init__(self):
83         self.nesting_level = 0
84         self.tempvars = []
85         self.codelines = []
86         self.redirect_code = None
87         self.redirect_tempvars = None
88         self.indent_str = '    '
89         self.indent_stack = []
90         self.tempvar_num = 0
91
92
93     # start and end of pre-code blocks
94     def start(self):
95         self.nesting_level += 1
96
97     def end(self):
98         self.nesting_level -= 1
99         if self.nesting_level == 0:
100             # lowest pre-code level is finished -> output to source
101             if self.redirect_tempvars is None:
102                 _c_wr_stringlist('', self.tempvars)
103                 self.tempvars = []
104             else:
105                 self.redirect_tempvars.extend(self.tempvars)
106                 self.tempvars = []
107             if self.redirect_code == None:
108                 _c_wr_stringlist('', self.codelines)
109                 self.codelines = []
110             else:
111                 self.redirect_code.extend(self.codelines)
112                 self.codelines = []
113
114
115     def output_tempvars(self):
116         if self.redirect_code == None:
117             _c_wr_stringlist('', self.tempvars)
118             self.tempvars = []
119
120     # output to precode
121     def code(self, fmt, *args):
122         self.codelines.append(self.indent_str + fmt % args)
123
124     def tempvar(self, fmt, *args):
125         self.tempvars.append('    ' + (fmt % args))
126
127     # get a unique name for a temporary variable
128     def get_tempvarname(self):
129         self.tempvar_num += 1
130         return "xcb_pre_tmp_%d" % self.tempvar_num
131
132     # indentation
133
134     def push_indent(self, indentstr):
135         self.indent_stack.append(self.indent_str)
136         self.indent_str = indentstr
137
138     def push_addindent(self, indent_add_str):
139         self.push_indent(self.indent_str + indent_add_str)
140
141     def indent(self):
142         self.push_addindent('    ')
143
144     def pop_indent(self):
145         self.indent_str = self.indent_stack.pop()
146
147     # redirection to lists
148     def redirect_start(self, redirect_code, redirect_tempvars=None):
149         self.redirect_code = redirect_code
150         self.redirect_tempvars = redirect_tempvars
151         if redirect_tempvars is not None:
152             self.tempvar_num = 0
153
154     def redirect_end(self):
155         self.redirect_code = None
156         self.redirect_tempvars = None
157
158 # global PreCode handler
159 _c_pre = PreCode()
160
161
162 # XXX See if this level thing is really necessary.
163 def _h_setlevel(idx):
164     '''
165     Changes the array that header lines are written to.
166     Supports writing different sections of the header file.
167     '''
168     global _hlevel
169     while len(_hlines) <= idx:
170         _hlines.append([])
171     _hlevel = idx
172
173 def _c_setlevel(idx):
174     '''
175     Changes the array that source lines are written to.
176     Supports writing to different sections of the source file.
177     '''
178     global _clevel
179     while len(_clines) <= idx:
180         _clines.append([])
181     _clevel = idx
182
183 def _n_item(str):
184     '''
185     Does C-name conversion on a single string fragment.
186     Uses a regexp with some hard-coded special cases.
187     '''
188     if str in _cname_special_cases:
189         return _cname_special_cases[str]
190     else:
191         split = _cname_re.finditer(str)
192         name_parts = [match.group(0) for match in split]
193         return '_'.join(name_parts)
194
195 def _cpp(str):
196     '''
197     Checks for certain C++ reserved words and fixes them.
198     '''
199     if str in _cplusplus_annoyances:
200         return _cplusplus_annoyances[str]
201     elif str in _c_keywords:
202         return  _c_keywords[str]
203     else:
204         return str
205
206 def _ext(str):
207     '''
208     Does C-name conversion on an extension name.
209     Has some additional special cases on top of _n_item.
210     '''
211     if str in _extension_special_cases:
212         return _n_item(str).lower()
213     else:
214         return str.lower()
215
216 def _n(list):
217     '''
218     Does C-name conversion on a tuple of strings.
219     Different behavior depending on length of tuple, extension/not extension, etc.
220     Basically C-name converts the individual pieces, then joins with underscores.
221     '''
222     if len(list) == 1:
223         parts = list
224     elif len(list) == 2:
225         parts = [list[0], _n_item(list[1])]
226     elif _ns.is_ext:
227         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
228     else:
229         parts = [list[0]] + [_n_item(i) for i in list[1:]]
230     return '_'.join(parts).lower()
231
232 def _t(list):
233     '''
234     Does C-name conversion on a tuple of strings representing a type.
235     Same as _n but adds a "_t" on the end.
236     '''
237     if len(list) == 1:
238         parts = list
239     elif len(list) == 2:
240         parts = [list[0], _n_item(list[1]), 't']
241     elif _ns.is_ext:
242         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
243     else:
244         parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
245     return '_'.join(parts).lower()
246
247
248 def c_open(self):
249     '''
250     Exported function that handles module open.
251     Opens the files and writes out the auto-generated comment, header file includes, etc.
252     '''
253     global _ns
254     _ns = self.namespace
255     _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
256
257     # Build the type-name collision avoidance table used by c_enum
258     build_collision_table()
259
260     _h_setlevel(0)
261     _c_setlevel(0)
262
263     _hc('/*')
264     _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
265     _hc(' * Edit at your peril.')
266     _hc(' */')
267     _hc('')
268
269     _h('/**')
270     _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
271     _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
272     _h(' * @{')
273     _h(' **/')
274     _h('')
275     _h('#ifndef __%s_H', _ns.header.upper())
276     _h('#define __%s_H', _ns.header.upper())
277     _h('')
278     _h('#include "xcb.h"')
279
280     _c('#ifdef HAVE_CONFIG_H')
281     _c('#include "config.h"')
282     _c('#endif')
283     _c('#include <stdlib.h>')
284     _c('#include <string.h>')
285     _c('#include <assert.h>')
286     _c('#include <stddef.h>  /* for offsetof() */')
287     _c('#include "xcbext.h"')
288     _c('#include "%s.h"', _ns.header)
289
290     _c('')
291     _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
292
293     if _ns.is_ext:
294         for (n, h) in self.direct_imports:
295             _hc('#include "%s.h"', h)
296
297     _h('')
298     _h('#ifdef __cplusplus')
299     _h('extern "C" {')
300     _h('#endif')
301
302     if _ns.is_ext:
303         _h('')
304         _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
305         _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
306         _h('') #XXX
307         _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
308
309         _c('')
310         _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
311
312 def c_close(self):
313     '''
314     Exported function that handles module close.
315     Writes out all the stored content lines, then closes the files.
316     '''
317     _h_setlevel(2)
318     _c_setlevel(2)
319     _hc('')
320
321     _h('')
322     _h('#ifdef __cplusplus')
323     _h('}')
324     _h('#endif')
325
326     _h('')
327     _h('#endif')
328     _h('')
329     _h('/**')
330     _h(' * @}')
331     _h(' */')
332
333     # Write header file
334     hfile = open('%s.h' % _ns.header, 'w')
335     for list in _hlines:
336         for line in list:
337             hfile.write(line)
338             hfile.write('\n')
339     hfile.close()
340
341     # Write source file
342     cfile = open('%s.c' % _ns.header, 'w')
343     for list in _clines:
344         for line in list:
345             cfile.write(line)
346             cfile.write('\n')
347     cfile.close()
348
349 def build_collision_table():
350     global namecount
351     namecount = {}
352
353     for v in module.types.values():
354         name = _t(v[0])
355         namecount[name] = (namecount.get(name) or 0) + 1
356
357 def c_enum(self, name):
358     '''
359     Exported function that handles enum declarations.
360     '''
361
362     enums[name] = self
363
364     tname = _t(name)
365     if namecount[tname] > 1:
366         tname = _t(name + ('enum',))
367
368     _h_setlevel(0)
369     _h('')
370     _h('typedef enum %s {', tname)
371
372     count = len(self.values)
373
374     for (enam, eval) in self.values:
375         count = count - 1
376         equals = ' = ' if eval != '' else ''
377         comma = ',' if count > 0 else ''
378         doc = ''
379         if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
380             doc = '\n/**< %s */\n' % self.doc.fields[enam]
381         _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
382
383     _h('} %s;', tname)
384
385 def _c_type_setup(self, name, postfix):
386     '''
387     Sets up all the C-related state by adding additional data fields to
388     all Field and Type objects.  Here is where we figure out most of our
389     variable and function names.
390
391     Recurses into child fields and list member types.
392     '''
393     # Do all the various names in advance
394     self.c_type = _t(name + postfix)
395     self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
396
397     self.c_iterator_type = _t(name + ('iterator',))
398     self.c_next_name = _n(name + ('next',))
399     self.c_end_name = _n(name + ('end',))
400
401     self.c_request_name = _n(name)
402     self.c_checked_name = _n(name + ('checked',))
403     self.c_unchecked_name = _n(name + ('unchecked',))
404     self.c_reply_name = _n(name + ('reply',))
405     self.c_reply_type = _t(name + ('reply',))
406     self.c_cookie_type = _t(name + ('cookie',))
407     self.c_reply_fds_name = _n(name + ('reply_fds',))
408
409     self.c_need_aux = False
410     self.c_need_serialize = False
411     self.c_need_sizeof = False
412
413     self.c_aux_name = _n(name + ('aux',))
414     self.c_aux_checked_name = _n(name + ('aux', 'checked'))
415     self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
416     self.c_serialize_name = _n(name + ('serialize',))
417     self.c_unserialize_name = _n(name + ('unserialize',))
418     self.c_unpack_name = _n(name + ('unpack',))
419     self.c_sizeof_name = _n(name + ('sizeof',))
420
421     # special case: structs where variable size fields are followed by fixed size fields
422     self.c_var_followed_by_fixed_fields = False
423
424     if self.is_switch:
425         self.c_need_serialize = True
426         self.c_container = 'struct'
427         for bitcase in self.bitcases:
428             bitcase.c_field_name = _cpp(bitcase.field_name)
429             bitcase_name = bitcase.field_type if bitcase.type.has_name else name
430             _c_type_setup(bitcase.type, bitcase_name, ())
431
432     elif self.is_container:
433
434         self.c_container = 'union' if self.is_union else 'struct'
435         prev_varsized_field = None
436         prev_varsized_offset = 0
437         first_field_after_varsized = None
438
439         for field in self.fields:
440             field.c_field_type = _t(field.field_type)
441             field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
442             field.c_field_name = _cpp(field.field_name)
443             field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
444             field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
445
446             # correct the c_pointer field for variable size non-list types
447             if not field.type.fixed_size() and field.c_pointer == ' ':
448                 field.c_pointer = '*'
449             if field.type.is_list and not field.type.member.fixed_size():
450                 field.c_pointer = '*'
451
452             if field.type.is_switch:
453                 field.c_pointer = '*'
454                 field.c_field_const_type = 'const ' + field.c_field_type
455                 self.c_need_aux = True
456
457             if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
458                 self.c_need_sizeof = True
459
460             field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
461             field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
462             field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
463             field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
464             field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
465
466             field.prev_varsized_field = prev_varsized_field
467             field.prev_varsized_offset = prev_varsized_offset
468
469             if prev_varsized_offset == 0:
470                 first_field_after_varsized = field
471             field.first_field_after_varsized = first_field_after_varsized
472
473             if field.type.fixed_size():
474                 prev_varsized_offset += field.type.size
475                 # special case: intermixed fixed and variable size fields
476                 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
477                     if not self.is_union:
478                         self.c_need_serialize = True
479                         self.c_var_followed_by_fixed_fields = True
480             else:
481                 self.last_varsized_field = field
482                 prev_varsized_field = field
483                 prev_varsized_offset = 0
484
485             if self.c_var_followed_by_fixed_fields:
486                 if field.type.fixed_size():
487                     field.prev_varsized_field = None
488
489             # recurse into this field this has to be done here, i.e.,
490             # after the field has been set up. Otherwise the function
491             # _c_helper_fieldaccess_expr will produce garbage or crash
492             _c_type_setup(field.type, field.field_type, ())
493             if field.type.is_list:
494                 _c_type_setup(field.type.member, field.field_type, ())
495                 if (field.type.nmemb is None):
496                     self.c_need_sizeof = True
497
498     if self.c_need_serialize:
499         # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
500         self.c_need_sizeof = True
501
502     # as switch does never appear at toplevel,
503     # continue here with type construction
504     if self.is_switch:
505         if self.c_type not in finished_switch:
506             finished_switch.append(self.c_type)
507             # special: switch C structs get pointer fields for variable-sized members
508             _c_complex(self)
509             for bitcase in self.bitcases:
510                 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
511                 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
512                 # no list with switch as element, so no call to
513                 # _c_iterator(field.type, field_name) necessary
514
515     if not self.is_case_or_bitcase:
516         if self.c_need_serialize:
517             if self.c_serialize_name not in finished_serializers:
518                 finished_serializers.append(self.c_serialize_name)
519                 _c_serialize('serialize', self)
520
521                 # _unpack() and _unserialize() are only needed for special cases:
522                 #   switch -> unpack
523                 #   special cases -> unserialize
524                 if self.is_switch or self.c_var_followed_by_fixed_fields:
525                     _c_serialize('unserialize', self)
526
527         if self.c_need_sizeof:
528             if self.c_sizeof_name not in finished_sizeof:
529                 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
530                     finished_sizeof.append(self.c_sizeof_name)
531                     _c_serialize('sizeof', self)
532 # _c_type_setup()
533
534 # Functions for querying field properties
535 def _c_field_needs_list_accessor(field):
536     return field.type.is_list and not field.type.fixed_size()
537
538 def _c_field_needs_field_accessor(field):
539     if field.type.is_list:
540         return False
541     else:
542         return (field.prev_varsized_field is not None or
543                 not field.type.fixed_size())
544
545 def _c_field_needs_accessor(field):
546     return (_c_field_needs_list_accessor(field) or
547             _c_field_needs_field_accessor(field))
548
549 def _c_field_is_member_of_case_or_bitcase(field):
550     return field.parent and field.parent.is_case_or_bitcase
551
552 def _c_helper_fieldaccess_expr(prefix, field=None):
553     """
554     turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555     representing a valid field-access-expression in C (based on the context)
556     if field is not None, append access to the field as well.
557
558     "separator" is one of the C-operators "." or "->".
559
560     A field access expression can consist of the following components:
561     * struct/union member access from a value with the "."-operator
562     * struct/union member access from a pointer with "->"-operator
563     * function-call of an accessor function:
564       This is used when a xcb-field is not contained in a struct.
565       This can, e.g., happen for fields after var-sized fields, etc.
566     """
567     prefix_str = ''
568     last_sep =''
569     for name, sep, obj in prefix:
570         prefix_str += last_sep + name
571         if '' == sep:
572             sep = '->'
573             if ((obj.is_case_or_bitcase and obj.has_name) or     # named bitcase
574                 (obj.is_switch and len(obj.parents)>1)):
575                 sep = '.'
576         last_sep = sep
577
578     if field is None:
579         # add separator for access to a yet unknown field
580         prefix_str += last_sep
581     else:
582         if _c_field_needs_accessor(field):
583             if _c_field_is_member_of_case_or_bitcase(field):
584                 # case members are available in the deserialized struct,
585                 # so there is no need to use the accessor function
586                 # (also, their accessor function needs a different arglist
587                 # so this would require special treatment here)
588                 # Therefore: Access as struct member
589                 prefix_str += last_sep + _cpp(field.field_name)
590             else:
591                 # Access with the accessor function
592                 prefix_str = field.c_accessor_name + "(" + prefix_str + ")"
593         else:
594             # Access as struct member
595             prefix_str += last_sep + _cpp(field.field_name)
596
597     return prefix_str
598 # _c_absolute_name
599
600 def _c_helper_field_mapping(complex_type, prefix, flat=False):
601     """
602     generate absolute names, based on prefix, for all fields starting from complex_type
603     if flat == True, nested complex types are not taken into account
604     """
605     all_fields = {}
606     if complex_type.is_switch:
607         for b in complex_type.bitcases:
608             if b.type.has_name:
609                 switch_name, switch_sep, switch_type = prefix[-1]
610                 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
611             else:
612                 bitcase_prefix = prefix
613
614             if (True==flat and not b.type.has_name) or False==flat:
615                 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
616     else:
617         for f in complex_type.fields:
618             fname = _c_helper_fieldaccess_expr(prefix, f)
619             if f.field_name in all_fields:
620                 raise Exception("field name %s has been registered before" % f.field_name)
621
622             all_fields[f.field_name] = (fname, f)
623             if f.type.is_container and flat==False:
624                 if f.type.is_case_or_bitcase and not f.type.has_name:
625                     new_prefix = prefix
626                 elif f.type.is_switch and len(f.type.parents)>1:
627                     # nested switch gets another separator
628                     new_prefix = prefix+[(f.c_field_name, '.', f.type)]
629                 else:
630                     new_prefix = prefix+[(f.c_field_name, '->', f.type)]
631                 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
632
633     return all_fields
634 # _c_field_mapping()
635
636 def _c_helper_resolve_field_names (prefix):
637     """
638     get field names for all objects in the prefix array
639     """
640     all_fields = {}
641     tmp_prefix = []
642     # look for fields in the remaining containers
643     for idx, p in enumerate(prefix):
644         name, sep, obj = p
645         if ''==sep:
646             # sep can be preset in prefix, if not, make a sensible guess
647             sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->'
648             # exception: 'toplevel' object (switch as well!) always have sep '->'
649             sep = '->' if idx<1 else sep
650         if not obj.is_case_or_bitcase or (obj.is_case_or_bitcase and obj.has_name):
651             tmp_prefix.append((name, sep, obj))
652         all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
653
654     return all_fields
655 # _c_helper_resolve_field_names
656
657 def get_expr_fields(self):
658     """
659     get the Fields referenced by switch or list expression
660     """
661     def get_expr_field_names(expr):
662         if expr.op is None:
663             if expr.lenfield_name is not None:
664                 return [expr.lenfield_name]
665             else:
666                 # constant value expr
667                 return []
668         else:
669             if expr.op == '~':
670                 return get_expr_field_names(expr.rhs)
671             elif expr.op == 'popcount':
672                 return get_expr_field_names(expr.rhs)
673             elif expr.op == 'sumof':
674                 # sumof expr references another list,
675                 # we need that list's length field here
676                 field = None
677                 for f in expr.lenfield_parent.fields:
678                     if f.field_name == expr.lenfield_name:
679                         field = f
680                         break
681                 if field is None:
682                     raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
683                 # referenced list + its length field
684                 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
685             elif expr.op == 'enumref':
686                 return []
687             else:
688                 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
689     # get_expr_field_names()
690
691     # resolve the field names with the parent structure(s)
692     unresolved_fields_names = get_expr_field_names(self.expr)
693
694     # construct prefix from self
695     prefix = [('', '', p) for p in self.parents]
696     if self.is_container:
697         prefix.append(('', '', self))
698
699     all_fields = _c_helper_resolve_field_names (prefix)
700     resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
701     if len(unresolved_fields_names) != len(resolved_fields_names):
702         raise Exception("could not resolve all fields for %s" % self.name)
703
704     resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
705     return resolved_fields
706 # get_expr_fields()
707
708 def resolve_expr_fields(complex_obj):
709     """
710     find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
711     these are normally fields that need to be given as function parameters
712     """
713     all_fields = []
714     expr_fields = []
715     unresolved = []
716
717     for field in complex_obj.fields:
718         all_fields.append(field)
719         if field.type.is_switch or field.type.is_list:
720             expr_fields += get_expr_fields(field.type)
721         if field.type.is_container:
722             expr_fields += resolve_expr_fields(field.type)
723
724     # try to resolve expr fields
725     for e in expr_fields:
726         if e not in all_fields and e not in unresolved:
727             unresolved.append(e)
728     return unresolved
729 # resolve_expr_fields()
730
731 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
732     """
733     functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
734     E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch
735     expression. This function tries to resolve all fields within a structure, and returns the
736     unresolved fields as the list of external parameters.
737     """
738     def add_param(params, param):
739         if param not in params:
740             params.append(param)
741
742     # collect all fields into param_fields
743     param_fields = []
744     wire_fields = []
745
746     for field in self.fields:
747         if field.visible:
748             # the field should appear as a parameter in the function call
749             param_fields.append(field)
750         if field.wire and not field.auto:
751             if field.type.fixed_size() and not self.is_switch:
752                 # field in the xcb_out structure
753                 wire_fields.append(field)
754         # fields like 'pad0' are skipped!
755
756     # in case of switch, parameters always contain any fields referenced in the switch expr
757     # we do not need any variable size fields here, as the switch data type contains both
758     # fixed and variable size fields
759     if self.is_switch:
760         param_fields = get_expr_fields(self)
761
762     # _serialize()/_unserialize()/_unpack() function parameters
763     # note: don't use set() for params, it is unsorted
764     params = []
765
766     # 1. the parameter for the void * buffer
767     if  'serialize' == context:
768         params.append(('void', '**', buffer_var))
769     elif context in ('unserialize', 'unpack', 'sizeof'):
770         params.append(('const void', '*', buffer_var))
771
772     # 2. any expr fields that cannot be resolved within self and descendants
773     unresolved_fields = resolve_expr_fields(self)
774     for f in unresolved_fields:
775         add_param(params, (f.c_field_type, '', f.c_field_name))
776
777     # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
778     #    that do not appear in the data type struct
779     for p in param_fields:
780         if self.is_switch:
781             typespec = p.c_field_const_type
782             pointerspec = p.c_pointer
783             add_param(params, (typespec, pointerspec, p.c_field_name))
784         else:
785             if p.visible and not p.wire and not p.auto:
786                 typespec = p.c_field_type
787                 pointerspec = ''
788                 add_param(params, (typespec, pointerspec, p.c_field_name))
789
790     # 4. aux argument
791     if 'serialize' == context:
792         add_param(params, ('const %s' % self.c_type, '*', aux_var))
793     elif 'unserialize' == context:
794         add_param(params, ('%s' % self.c_type, '**', aux_var))
795     elif 'unpack' == context:
796         add_param(params, ('%s' % self.c_type, '*', aux_var))
797
798     # 5. switch contains all variable size fields as struct members
799     #    for other data types though, these have to be supplied separately
800     #    this is important for the special case of intermixed fixed and
801     #    variable size fields
802     if not self.is_switch and 'serialize' == context:
803         for p in param_fields:
804             if not p.type.fixed_size():
805                 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
806
807     return (param_fields, wire_fields, params)
808 # get_serialize_params()
809
810 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
811     code_lines.append('%s    /* insert padding */' % space)
812     if is_case_or_bitcase:
813         code_lines.append(
814             '%s    xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
815             % space)
816     else:
817         code_lines.append(
818             '%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
819 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
820     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
821
822     if not postpone:
823         code_lines.append('%s    if (0 != xcb_pad) {' % space)
824
825         if 'serialize' == context:
826             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
827             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
828             code_lines.append('%s        xcb_parts_idx++;' % space)
829         elif context in ('unserialize', 'unpack', 'sizeof'):
830             code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
831
832         code_lines.append('%s        xcb_pad = 0;' % space)
833         code_lines.append('%s    }' % space)
834
835     code_lines.append('%s    xcb_block_len = 0;' % space)
836     if is_case_or_bitcase:
837         code_lines.append('%s    xcb_padding_offset = 0;' % space)
838
839     # keep tracking of xcb_parts entries for serialize
840     return 1
841 # _c_serialize_helper_insert_padding()
842
843 def _c_serialize_helper_switch(context, self, complex_name,
844                                code_lines, temp_vars,
845                                space, prefix):
846     count = 0
847     switch_expr = _c_accessor_get_expr(self.expr, None)
848
849     for b in self.bitcases:
850         len_expr = len(b.type.expr)
851
852         compare_operator = '&'
853         if b.type.is_case:
854             compare_operator = '=='
855         else:
856             compare_operator = '&'
857
858         for n, expr in enumerate(b.type.expr):
859             bitcase_expr = _c_accessor_get_expr(expr, None)
860             # only one <enumref> in the <bitcase>
861             if len_expr == 1:
862                 code_lines.append(
863                     '    if(%s %s %s) {' % (switch_expr, compare_operator, bitcase_expr))
864             # multiple <enumref> in the <bitcase>
865             elif n == 0: # first
866                 code_lines.append(
867                     '    if((%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
868             elif len_expr == (n + 1): # last
869                 code_lines.append(
870                     '       (%s %s %s)) {' % (switch_expr, compare_operator, bitcase_expr))
871             else: # between first and last
872                 code_lines.append(
873                     '       (%s %s %s) ||' % (switch_expr, compare_operator, bitcase_expr))
874
875         b_prefix = prefix
876         if b.type.has_name:
877             b_prefix = prefix + [(b.c_field_name, '.', b.type)]
878
879         count += _c_serialize_helper_fields(context, b.type,
880                                             code_lines, temp_vars,
881                                             "%s    " % space,
882                                             b_prefix,
883                                             is_case_or_bitcase = True)
884         code_lines.append('    }')
885
886 #    if 'serialize' == context:
887 #        count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
888 #    elif context in ('unserialize', 'unpack', 'sizeof'):
889 #        # padding
890 #        code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
891 #        code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
892
893     return count
894 # _c_serialize_helper_switch
895
896 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
897     """
898     handle switch by calling _serialize() or _unpack(), depending on context
899     """
900     # switch is handled by this function as a special case
901     param_fields, wire_fields, params = get_serialize_params(context, self)
902     field_mapping = _c_helper_field_mapping(self, prefix)
903     prefix_str = _c_helper_fieldaccess_expr(prefix)
904
905     # find the parameters that need to be passed to _serialize()/_unpack():
906     # all switch expr fields must be given as parameters
907     args = get_expr_fields(field.type)
908     # length fields for variable size types in switch, normally only some of need
909     # need to be passed as parameters
910     switch_len_fields = resolve_expr_fields(field.type)
911
912     # a switch field at this point _must_ be a bitcase field
913     # we require that bitcases are "self-contiguous"
914     bitcase_unresolved = resolve_expr_fields(self)
915     if len(bitcase_unresolved) != 0:
916         raise Exception('unresolved fields within bitcase is not supported at this point')
917
918     # get the C names for the parameters
919     c_field_names = ''
920     for a in switch_len_fields:
921         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
922     for a in args:
923         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
924
925     # call _serialize()/_unpack() to determine the actual size
926     if 'serialize' == context:
927         length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
928                                        c_field_names, prefix_str, field.c_field_name)
929     elif context in ('unserialize', 'unpack'):
930         length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
931                                            c_field_names, prefix_str, field.c_field_name)
932     elif 'sizeof' == context:
933         # remove trailing ", " from c_field_names because it will be used at end of arglist
934         my_c_field_names = c_field_names[:-2]
935         length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
936
937     return length
938 # _c_serialize_helper_switch_field()
939
940 def _c_serialize_helper_list_field(context, self, field,
941                                    code_lines, temp_vars,
942                                    space, prefix):
943     """
944     helper function to cope with lists of variable length
945     """
946     expr = field.type.expr
947     prefix_str = _c_helper_fieldaccess_expr(prefix)
948     param_fields, wire_fields, params = get_serialize_params('sizeof', self)
949     param_names = [p[2] for p in params]
950
951     expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
952     resolved = list(filter(lambda x: x in param_names, expr_fields_names))
953     unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
954
955     field_mapping = {}
956     for r in resolved:
957         field_mapping[r] = (r, None)
958
959     if len(unresolved)>0:
960         tmp_prefix = prefix
961         if len(tmp_prefix)==0:
962             raise Exception("found an empty prefix while resolving expr field names for list %s",
963                             field.c_field_name)
964
965         field_mapping.update(_c_helper_resolve_field_names(prefix))
966         resolved += list(filter(lambda x: x in field_mapping, unresolved))
967         unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
968         if len(unresolved)>0:
969             raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
970
971     list_length = _c_accessor_get_expr(expr, field_mapping)
972
973     # default: list with fixed size elements
974     length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
975
976     # list with variable-sized elements
977     if not field.type.member.fixed_size():
978         length = ''
979         if context in ('unserialize', 'sizeof', 'unpack'):
980             int_i = '    unsigned int i;'
981             xcb_tmp_len = '    unsigned int xcb_tmp_len;'
982             if int_i not in temp_vars:
983                 temp_vars.append(int_i)
984             if xcb_tmp_len not in temp_vars:
985                 temp_vars.append(xcb_tmp_len)
986             # loop over all list elements and call sizeof repeatedly
987             # this should be a bit faster than using the iterators
988             code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
989             code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp);" %
990                               (space, field.type.c_sizeof_name))
991             code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
992             code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
993             code_lines.append("%s    }" % space)
994
995         elif 'serialize' == context:
996             code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
997             code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
998             code_lines.append('%s    for(i=0; i<%s; i++) { ' % (space, list_length))
999             code_lines.append('%s        xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
1000             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
1001             code_lines.append('%s    }' % space)
1002             code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
1003
1004     return length
1005 # _c_serialize_helper_list_field()
1006
1007 def _c_serialize_helper_fields_fixed_size(context, self, field,
1008                                           code_lines, temp_vars,
1009                                           space, prefix):
1010     # keep the C code a bit more readable by giving the field name
1011     if not self.is_case_or_bitcase:
1012         code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
1013     else:
1014         scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
1015         typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
1016         code_lines.append('%s    /* %s.%s */' % (space, typename, field.c_field_name))
1017
1018     abs_field_name = _c_helper_fieldaccess_expr(prefix, field)
1019     # default for simple cases: call sizeof()
1020     length = "sizeof(%s)" % field.c_field_type
1021
1022     if context in ('unserialize', 'unpack', 'sizeof'):
1023         # default: simple cast
1024         value = '    %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type)
1025
1026         # padding - we could probably just ignore it
1027         if field.type.is_pad and field.type.nmemb > 1:
1028             value = ''
1029             for i in range(field.type.nmemb):
1030                 code_lines.append('%s    %s[%d] = *(%s *)xcb_tmp;' %
1031                                   (space, abs_field_name, i, field.c_field_type))
1032             # total padding = sizeof(pad0) * nmemb
1033             length += " * %d" % field.type.nmemb
1034
1035         elif field.type.is_list:
1036             # list with fixed number of elements
1037             # length of array = sizeof(arrayElementType) * nmemb
1038             length += " * %d" % field.type.nmemb
1039             # use memcpy because C cannot assign whole arrays with operator=
1040             value = '    memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
1041
1042
1043     elif 'serialize' == context:
1044         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) '
1045
1046         if field.type.is_expr:
1047             # need to register a temporary variable for the expression in case we know its type
1048             if field.type.c_type is None:
1049                 raise Exception("type for field '%s' (expression '%s') unkown" %
1050                                 (field.field_name, _c_accessor_get_expr(field.type.expr)))
1051
1052             temp_vars.append('    %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name),
1053                                                            _c_accessor_get_expr(field.type.expr, prefix)))
1054             value += "&xcb_expr_%s;" % _cpp(field.field_name)
1055
1056         elif field.type.is_pad:
1057             if field.type.nmemb == 1:
1058                 value += "&xcb_pad;"
1059             else:
1060                 # we could also set it to 0, see definition of xcb_send_request()
1061                 value = '    xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
1062                 length += "*%d" % field.type.nmemb
1063
1064         else:
1065             # non-list type with fixed size
1066             if field.type.nmemb == 1:
1067                 value += "&%s;" % (abs_field_name)
1068
1069             # list with nmemb (fixed size) elements
1070             else:
1071                 value += '%s;' % (abs_field_name)
1072                 length = '%d' % field.type.nmemb
1073
1074     return (value, length)
1075 # _c_serialize_helper_fields_fixed_size()
1076
1077 def _c_serialize_helper_fields_variable_size(context, self, field,
1078                                              code_lines, temp_vars,
1079                                              space, prefix):
1080     prefix_str = _c_helper_fieldaccess_expr(prefix)
1081
1082     if context in ('unserialize', 'unpack', 'sizeof'):
1083         value = ''
1084         var_field_name = 'xcb_tmp'
1085
1086         # special case: intermixed fixed and variable size fields
1087         if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1088             value = '    %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
1089             temp_vars.append('    %s *%s;' % (field.type.c_type, field.c_field_name))
1090         # special case: switch
1091         if 'unpack' == context:
1092             value = '    %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
1093
1094     elif 'serialize' == context:
1095         # variable size fields appear as parameters to _serialize() if the
1096         # 'toplevel' container is not a switch
1097         prefix_string = prefix_str if prefix[0][2].is_switch else ''
1098         var_field_name = "%s%s" % (prefix_string, field.c_field_name)
1099         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
1100
1101     length = ''
1102
1103     code_lines.append('%s    /* %s */' % (space, field.c_field_name))
1104
1105     if field.type.is_list:
1106         if value != '':
1107             # in any context, list is already a pointer, so the default assignment is ok
1108             code_lines.append("%s%s" % (space, value))
1109             value = ''
1110         length = _c_serialize_helper_list_field(context, self, field,
1111                                                 code_lines, temp_vars,
1112                                                 space, prefix)
1113
1114     elif field.type.is_switch:
1115         value = ''
1116         if context == 'serialize':
1117             # the _serialize() function allocates the correct amount memory if given a NULL pointer
1118             value = '    xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
1119         length = _c_serialize_helper_switch_field(context, self, field,
1120                                                   'xcb_parts[xcb_parts_idx].iov_base',
1121                                                   prefix)
1122
1123     else:
1124         # in all remaining special cases - call _sizeof()
1125         length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
1126
1127     return (value, length)
1128 # _c_serialize_helper_fields_variable_size
1129
1130 def _c_serialize_helper_fields(context, self,
1131                                code_lines, temp_vars,
1132                                space, prefix, is_case_or_bitcase):
1133     count = 0
1134     need_padding = False
1135     prev_field_was_variable = False
1136
1137     _c_pre.push_indent(space + '    ')
1138
1139     for field in self.fields:
1140         if not field.visible:
1141             if not ((field.wire and not field.auto) or 'unserialize' == context):
1142                 continue
1143
1144         # switch/bitcase: fixed size fields must be considered explicitly
1145         if field.type.fixed_size():
1146             if self.is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1147                 if prev_field_was_variable and need_padding:
1148                     # insert padding
1149 #                    count += _c_serialize_helper_insert_padding(context, code_lines, space,
1150 #                                                                self.c_var_followed_by_fixed_fields)
1151                     prev_field_was_variable = False
1152
1153                 # prefix for fixed size fields
1154                 fixed_prefix = prefix
1155
1156                 value, length = _c_serialize_helper_fields_fixed_size(context, self, field,
1157                                                                       code_lines, temp_vars,
1158                                                                       space, fixed_prefix)
1159             else:
1160                 continue
1161
1162         # fields with variable size
1163         else:
1164             if field.type.is_pad:
1165                 # Variable length pad is <pad align= />
1166                 code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
1167                 count += _c_serialize_helper_insert_padding(context, code_lines, space,
1168                                                             self.c_var_followed_by_fixed_fields,
1169                                                             is_case_or_bitcase)
1170                 continue
1171             else:
1172                 # switch/bitcase: always calculate padding before and after variable sized fields
1173                 if need_padding or is_case_or_bitcase:
1174                     count += _c_serialize_helper_insert_padding(context, code_lines, space,
1175                                                                 self.c_var_followed_by_fixed_fields,
1176                                                                 is_case_or_bitcase)
1177
1178                 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
1179                                                                          code_lines, temp_vars,
1180                                                                          space, prefix)
1181                 prev_field_was_variable = True
1182
1183         # save (un)serialization C code
1184         if '' != value:
1185             code_lines.append('%s%s' % (space, value))
1186
1187         if field.type.fixed_size():
1188             if is_case_or_bitcase or self.c_var_followed_by_fixed_fields:
1189                 # keep track of (un)serialized object's size
1190                 code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1191                 if context in ('unserialize', 'unpack', 'sizeof'):
1192                     code_lines.append('%s    xcb_tmp += %s;' % (space, length))
1193         else:
1194             # variable size objects or bitcase:
1195             #   value & length might have been inserted earlier for special cases
1196             if '' != length:
1197                 # special case: intermixed fixed and variable size fields
1198                 if (not field.type.fixed_size() and
1199                     self.c_var_followed_by_fixed_fields and 'unserialize' == context):
1200                     temp_vars.append('    int %s_len;' % field.c_field_name)
1201                     code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
1202                     code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
1203                     code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
1204                 else:
1205                     code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1206                     # increase pointer into the byte stream accordingly
1207                     if context in ('unserialize', 'sizeof', 'unpack'):
1208                         code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1209
1210         if 'serialize' == context:
1211             if '' != length:
1212                 code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1213             code_lines.append('%s    xcb_parts_idx++;' % space)
1214             count += 1
1215
1216         code_lines.append(
1217             '%s    xcb_align_to = ALIGNOF(%s);'
1218              % (space,
1219                  'char'
1220                   if field.c_field_type == 'void' or field.type.is_switch
1221                   else field.c_field_type))
1222
1223         need_padding = True
1224         if self.c_var_followed_by_fixed_fields:
1225             need_padding = False
1226
1227     _c_pre.pop_indent()
1228
1229     return count
1230 # _c_serialize_helper_fields()
1231
1232 def _c_serialize_helper(context, complex_type,
1233                         code_lines, temp_vars,
1234                         space='', prefix=[]):
1235     # count tracks the number of fields to serialize
1236     count = 0
1237
1238     if hasattr(complex_type, 'type'):
1239         self = complex_type.type
1240         complex_name = complex_type.name
1241     else:
1242         self = complex_type
1243         if self.c_var_followed_by_fixed_fields and 'unserialize' == context:
1244             complex_name = 'xcb_out'
1245         else:
1246             complex_name = '_aux'
1247
1248     # special case: switch is serialized by evaluating each bitcase separately
1249     if self.is_switch:
1250         count += _c_serialize_helper_switch(context, self, complex_name,
1251                                             code_lines, temp_vars,
1252                                             space, prefix)
1253
1254     # all other data types can be evaluated one field a time
1255     else:
1256         # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1257         if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields:
1258             code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
1259             code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1260             code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
1261             code_lines.append('%s    xcb_block_len = 0;' % space)
1262
1263         count += _c_serialize_helper_fields(context, self,
1264                                             code_lines, temp_vars,
1265                                             space, prefix, False)
1266     # "final padding"
1267     count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
1268
1269     return count
1270 # _c_serialize_helper()
1271
1272 def _c_serialize(context, self):
1273     """
1274     depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
1275     for the ComplexType variable self
1276     """
1277     _h_setlevel(1)
1278     _c_setlevel(1)
1279
1280     _hc('')
1281     # _serialize() returns the buffer size
1282     _hc('int')
1283
1284     if self.is_switch and 'unserialize' == context:
1285         context = 'unpack'
1286
1287     cases = { 'serialize'   : self.c_serialize_name,
1288               'unserialize' : self.c_unserialize_name,
1289               'unpack'      : self.c_unpack_name,
1290               'sizeof'      : self.c_sizeof_name }
1291     func_name = cases[context]
1292
1293     param_fields, wire_fields, params = get_serialize_params(context, self)
1294     variable_size_fields = 0
1295     # maximum space required for type definition of function arguments
1296     maxtypelen = 0
1297
1298     # determine N(variable_fields)
1299     for field in param_fields:
1300         # if self.is_switch, treat all fields as if they are variable sized
1301         if not field.type.fixed_size() or self.is_switch:
1302             variable_size_fields += 1
1303     # determine maxtypelen
1304     for p in params:
1305         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))
1306
1307     # write to .c/.h
1308     indent = ' '*(len(func_name)+2)
1309     param_str = []
1310     for p in params:
1311         typespec, pointerspec, field_name = p
1312         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1313         param_str.append("%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1314     # insert function name
1315     param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1316     param_str = list(map(lambda x: "%s," % x, param_str))
1317     for s in param_str[:-1]:
1318         _hc(s)
1319     _h("%s);" % param_str[-1].rstrip(','))
1320     _c("%s)" % param_str[-1].rstrip(','))
1321     _c('{')
1322
1323     code_lines = []
1324     temp_vars = []
1325     prefix = []
1326
1327     _c_pre.redirect_start(code_lines, temp_vars)
1328
1329     if 'serialize' == context:
1330         if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1331             _c('    %s *xcb_out = *_buffer;', self.c_type)
1332             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1333             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1334             _c('    unsigned int xcb_align_to = 0;')
1335         else:
1336             _c('    char *xcb_out = *_buffer;')
1337             _c('    unsigned int xcb_buffer_len = 0;')
1338             _c('    unsigned int xcb_align_to = 0;')
1339         if self.is_switch:
1340             _c('    unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
1341         prefix = [('_aux', '->', self)]
1342         aux_ptr = 'xcb_out'
1343
1344     elif context in ('unserialize', 'unpack'):
1345         _c('    char *xcb_tmp = (char *)_buffer;')
1346         if not self.is_switch:
1347             if not self.c_var_followed_by_fixed_fields:
1348                 _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1349                 prefix = [('_aux', '->', self)]
1350             else:
1351                 _c('    %s xcb_out;', self.c_type)
1352                 prefix = [('xcb_out', '.', self)]
1353         else:
1354             aux_var = '_aux' # default for unpack: single pointer
1355             # note: unserialize not generated for switch
1356             if 'unserialize' == context:
1357                 aux_var = '(*_aux)' # unserialize: double pointer (!)
1358             prefix = [(aux_var, '->', self)]
1359         aux_ptr = '*_aux'
1360         _c('    unsigned int xcb_buffer_len = 0;')
1361         _c('    unsigned int xcb_block_len = 0;')
1362         _c('    unsigned int xcb_pad = 0;')
1363         _c('    unsigned int xcb_align_to = 0;')
1364         if self.is_switch:
1365             _c('    unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
1366
1367     elif 'sizeof' == context:
1368         param_names = [p[2] for p in params]
1369         if self.is_switch:
1370             # switch: call _unpack()
1371             _c('    %s _aux;', self.c_type)
1372             _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1373             _c('}')
1374             _c_pre.redirect_end()
1375             return
1376         elif self.c_var_followed_by_fixed_fields:
1377             # special case: call _unserialize()
1378             _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1379             _c('}')
1380             _c_pre.redirect_end()
1381             return
1382         else:
1383             _c('    char *xcb_tmp = (char *)_buffer;')
1384             prefix = [('_aux', '->', self)]
1385             if self.is_switch:
1386                 _c('    unsigned int xcb_padding_offset = 0;')
1387
1388     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1389     # update variable size fields (only important for context=='serialize'
1390     variable_size_fields = count
1391     if 'serialize' == context:
1392         temp_vars.append('    unsigned int xcb_pad = 0;')
1393         temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};')
1394         temp_vars.append('    struct iovec xcb_parts[%d];' % count)
1395         temp_vars.append('    unsigned int xcb_parts_idx = 0;')
1396         temp_vars.append('    unsigned int xcb_block_len = 0;')
1397         temp_vars.append('    unsigned int i;')
1398         temp_vars.append('    char *xcb_tmp;')
1399     elif 'sizeof' == context:
1400         # neither switch nor intermixed fixed and variable size fields:
1401         # evaluate parameters directly
1402         if not (self.is_switch or self.c_var_followed_by_fixed_fields):
1403
1404             # look if we have to declare an '_aux' variable at all
1405             if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1406                 if not self.c_var_followed_by_fixed_fields:
1407                     _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1408                 else:
1409                     _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1410
1411             _c('    unsigned int xcb_buffer_len = 0;')
1412             _c('    unsigned int xcb_block_len = 0;')
1413             _c('    unsigned int xcb_pad = 0;')
1414             _c('    unsigned int xcb_align_to = 0;')
1415
1416     _c_pre.redirect_end()
1417
1418     _c('')
1419     for t in temp_vars:
1420         _c(t)
1421     _c('')
1422     for l in code_lines:
1423         _c(l)
1424
1425     # variable sized fields have been collected, now
1426     # allocate memory and copy everything into a continuous memory area
1427     # note: this is not necessary in case of unpack
1428     if context in ('serialize', 'unserialize'):
1429         # unserialize: check for sizeof-only invocation
1430         if 'unserialize' == context:
1431             _c('')
1432             _c('    if (NULL == _aux)')
1433             _c('        return xcb_buffer_len;')
1434
1435         _c('')
1436         _c('    if (NULL == %s) {', aux_ptr)
1437         _c('        /* allocate memory */')
1438         _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
1439         if 'serialize' == context:
1440             _c('        *_buffer = xcb_out;')
1441         _c('    }')
1442         _c('')
1443
1444         # serialize: handle variable size fields in a loop
1445         if 'serialize' == context:
1446             if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1447                 if len(wire_fields)>0:
1448                     _c('    *xcb_out = *_aux;')
1449             # copy variable size fields into the buffer
1450             if variable_size_fields > 0:
1451                 # xcb_out padding
1452                 if not self.is_switch and not self.c_var_followed_by_fixed_fields:
1453                     _c('    xcb_tmp = (char*)++xcb_out;')
1454                     _c('    xcb_tmp += xcb_out_pad;')
1455                 else:
1456                     _c('    xcb_tmp = xcb_out;')
1457
1458                 # variable sized fields
1459                 _c('    for(i=0; i<xcb_parts_idx; i++) {')
1460                 _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1461                 _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1462                 _c('        if (0 != xcb_parts[i].iov_len)')
1463                 _c('            xcb_tmp += xcb_parts[i].iov_len;')
1464                 _c('    }')
1465
1466         # unserialize: assign variable size fields individually
1467         if 'unserialize' == context:
1468             _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1469             param_fields.reverse()
1470             for field in param_fields:
1471                 if not field.type.fixed_size():
1472                     _c('    xcb_tmp -= %s_len;', field.c_field_name)
1473                     _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1474             _c('    *%s = xcb_out;', aux_ptr)
1475
1476     _c('')
1477     _c('    return xcb_buffer_len;')
1478     _c('}')
1479 # _c_serialize()
1480
1481 def _c_iterator_get_end(field, accum):
1482     '''
1483     Figures out what C code is needed to find the end of a variable-length structure field.
1484     For nested structures, recurses into its last variable-sized field.
1485     For lists, calls the end function
1486     '''
1487     if field.type.is_container:
1488         accum = field.c_accessor_name + '(' + accum + ')'
1489         return _c_iterator_get_end(field.type.last_varsized_field, accum)
1490     if field.type.is_list:
1491         # XXX we can always use the first way
1492         if field.type.member.is_simple:
1493             return field.c_end_name + '(' + accum + ')'
1494         else:
1495             return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1496
1497 def _c_iterator(self, name):
1498     '''
1499     Declares the iterator structure and next/end functions for a given type.
1500     '''
1501     _h_setlevel(0)
1502     _h('')
1503     _h('/**')
1504     _h(' * @brief %s', self.c_iterator_type)
1505     _h(' **/')
1506     _h('typedef struct %s {', self.c_iterator_type)
1507     _h('    %s *data; /**<  */', self.c_type)
1508     _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1509     _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1510     _h('} %s;', self.c_iterator_type)
1511
1512     _h_setlevel(1)
1513     _c_setlevel(1)
1514     _h('')
1515     _h('/**')
1516     _h(' * Get the next element of the iterator')
1517     _h(' * @param i Pointer to a %s', self.c_iterator_type)
1518     _h(' *')
1519     _h(' * Get the next element in the iterator. The member rem is')
1520     _h(' * decreased by one. The member data points to the next')
1521     _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1522     _h(' */')
1523     _c('')
1524     _hc('void')
1525     _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1526     _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1527     _c('{')
1528
1529     if not self.fixed_size():
1530         _c('    %s *R = i->data;', self.c_type)
1531
1532         if self.is_union:
1533             # FIXME - how to determine the size of a variable size union??
1534             _c('    /* FIXME - determine the size of the union %s */', self.c_type)
1535         else:
1536             if self.c_need_sizeof:
1537                 _c('    xcb_generic_iterator_t child;')
1538                 _c('    child.data = (%s *)(((char *)R) + %s(R));',
1539                    self.c_type, self.c_sizeof_name)
1540                 _c('    i->index = (char *) child.data - (char *) i->data;')
1541             else:
1542                 _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1543                 _c('    i->index = child.index;')
1544             _c('    --i->rem;')
1545             _c('    i->data = (%s *) child.data;', self.c_type)
1546
1547     else:
1548         _c('    --i->rem;')
1549         _c('    ++i->data;')
1550         _c('    i->index += sizeof(%s);', self.c_type)
1551
1552     _c('}')
1553
1554     _h('')
1555     _h('/**')
1556     _h(' * Return the iterator pointing to the last element')
1557     _h(' * @param i An %s', self.c_iterator_type)
1558     _h(' * @return  The iterator pointing to the last element')
1559     _h(' *')
1560     _h(' * Set the current element in the iterator to the last element.')
1561     _h(' * The member rem is set to 0. The member data points to the')
1562     _h(' * last element.')
1563     _h(' */')
1564     _c('')
1565     _hc('xcb_generic_iterator_t')
1566     _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1567     _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1568     _c('{')
1569     _c('    xcb_generic_iterator_t ret;')
1570
1571     if self.fixed_size():
1572         _c('    ret.data = i.data + i.rem;')
1573         _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1574         _c('    ret.rem = 0;')
1575     else:
1576         _c('    while(i.rem > 0)')
1577         _c('        %s(&i);', self.c_next_name)
1578         _c('    ret.data = i.data;')
1579         _c('    ret.rem = i.rem;')
1580         _c('    ret.index = i.index;')
1581
1582     _c('    return ret;')
1583     _c('}')
1584
1585 def _c_accessor_get_length(expr, field_mapping=None):
1586     '''
1587     Figures out what C code is needed to get a length field.
1588     The field_mapping parameter can be used to change the absolute name of a length field.
1589     For fields that follow a variable-length field, use the accessor.
1590     Otherwise, just reference the structure field directly.
1591     '''
1592
1593     lenfield_name = expr.lenfield_name
1594     if lenfield_name is not None:
1595         if field_mapping is not None:
1596             lenfield_name = field_mapping[lenfield_name][0]
1597
1598     if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1599         # special case: variable and fixed size fields are intermixed
1600         # if the lenfield is among the fixed size fields, there is no need
1601         # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1602         return field_mapping(expr.lenfield_name)
1603     elif expr.lenfield_name is not None:
1604         return lenfield_name
1605     else:
1606         return str(expr.nmemb)
1607
1608 def _c_accessor_get_expr(expr, field_mapping):
1609     '''
1610     Figures out what C code is needed to get the length of a list field.
1611     The field_mapping parameter can be used to change the absolute name of a length field.
1612     Recurses for math operations.
1613     Returns bitcount for value-mask fields.
1614     Otherwise, uses the value of the length field.
1615     '''
1616     lenexp = _c_accessor_get_length(expr, field_mapping)
1617
1618     if expr.op == '~':
1619         return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1620     elif expr.op == 'popcount':
1621         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1622     elif expr.op == 'enumref':
1623         enum_name = expr.lenfield_type.name
1624         constant_name = expr.lenfield_name
1625         c_name = _n(enum_name + (constant_name,)).upper()
1626         return c_name
1627     elif expr.op == 'sumof':
1628         # locate the referenced list object
1629         list_obj = expr.lenfield_type
1630         field = None
1631         for f in expr.lenfield_parent.fields:
1632             if f.field_name == expr.lenfield_name:
1633                 field = f
1634                 break
1635
1636         if field is None:
1637             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1638         list_name = field_mapping[field.c_field_name][0]
1639         c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1640         c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1641         # create explicit code for computing the sum.
1642         # This works for all C-types which can be added to int64_t with +=
1643         _c_pre.start()
1644         lengthvar = _c_pre.get_tempvarname()
1645         loopvar = _c_pre.get_tempvarname()
1646         sumvar = _c_pre.get_tempvarname()
1647         listvar = _c_pre.get_tempvarname()
1648         _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1649         _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1650         _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1651         _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1652         _c_pre.code("/* sumof start */")
1653         _c_pre.code("%s = %s;", lengthvar, c_length_func)
1654         _c_pre.code("%s = 0;", sumvar)
1655         _c_pre.code("%s = %s;", listvar, list_name)
1656         _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1657         _c_pre.indent()
1658
1659         if expr.rhs is None:
1660             _c_pre.code("%s += *%s;", sumvar, listvar)
1661         else:
1662             # sumof has a nested expression which has to be evaluated in
1663             # the context of this list element
1664
1665             # field mapping for the subexpression needs to include
1666             # the fields of the list-member type
1667             scoped_field_mapping = field_mapping.copy()
1668             scoped_field_mapping.update(
1669                 _c_helper_field_mapping(
1670                     field.type.member,
1671                     [(listvar, '->', field.type.member)]))
1672
1673             # cause pre-code of the subexpression be added right here
1674             _c_pre.end()
1675             # compute the subexpression
1676             rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1677             # resume with our code
1678             _c_pre.start()
1679             # output the summation expression
1680             _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1681
1682         _c_pre.code("%s++;", listvar)
1683         _c_pre.pop_indent()
1684         _c_pre.code("}")
1685         _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1686         _c_pre.end()
1687         return sumvar
1688     elif expr.op != None:
1689         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1690                 ' ' + expr.op + ' ' +
1691                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1692     elif expr.bitfield:
1693         return 'xcb_popcount(' + lenexp + ')'
1694     else:
1695         return lenexp
1696
1697 def type_pad_type(type):
1698     if type == 'void':
1699         return 'char'
1700     return type
1701
1702 def _c_accessors_field(self, field):
1703     '''
1704     Declares the accessor functions for a non-list field that follows a variable-length field.
1705     '''
1706     c_type = self.c_type
1707
1708     # special case: switch
1709     switch_obj = self if self.is_switch else None
1710     if self.is_case_or_bitcase:
1711         switch_obj = self.parents[-1]
1712     if switch_obj is not None:
1713         c_type = switch_obj.c_type
1714
1715     if field.type.is_simple:
1716         _hc('')
1717         _hc('%s', field.c_field_type)
1718         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1719         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1720         _c('{')
1721         if field.prev_varsized_field is None:
1722             _c('    return (%s *) (R + 1);', field.c_field_type)
1723         else:
1724             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1725             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1726                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1727         _c('}')
1728     else:
1729         _hc('')
1730         if field.type.is_switch and switch_obj is None:
1731             return_type = 'void *'
1732         else:
1733             return_type = '%s *' % field.c_field_type
1734
1735         _hc(return_type)
1736         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1737         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1738         _c('{')
1739         if field.prev_varsized_field is None:
1740             _c('    return (%s) (R + 1);', return_type)
1741             # note: the special case 'variable fields followed by fixed size fields'
1742             #       is not of any consequence here, since the ordering gets
1743             #       'corrected' in the reply function
1744         else:
1745             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1746             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1747                return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1748         _c('}')
1749
1750
1751 def _c_accessors_list(self, field):
1752     '''
1753     Declares the accessor functions for a list field.
1754     Declares a direct-accessor function only if the list members are fixed size.
1755     Declares length and get-iterator functions always.
1756     '''
1757
1758     def get_align_pad(field):
1759             prev = field.prev_varsized_field
1760             prev_prev = field.prev_varsized_field.prev_varsized_field
1761
1762             if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1763                 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1764             else:
1765                 return (prev, None)
1766
1767
1768     list = field.type
1769     c_type = self.c_type
1770
1771     # special case: switch
1772     # in case of switch, 2 params have to be supplied to certain accessor functions:
1773     #   1. the anchestor object (request or reply)
1774     #   2. the (anchestor) switch object
1775     # the reason is that switch is either a child of a request/reply or nested in another switch,
1776     # so whenever we need to access a length field, we might need to refer to some anchestor type
1777     switch_obj = self if self.is_switch else None
1778     if self.is_case_or_bitcase:
1779         switch_obj = self.parents[-1]
1780     if switch_obj is not None:
1781         c_type = switch_obj.c_type
1782
1783     params = []
1784     fields = {}
1785     parents = self.parents if hasattr(self, 'parents') else [self]
1786     # 'R': parents[0] is always the 'toplevel' container type
1787     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1788     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1789     # auxiliary object for 'R' parameters
1790     R_obj = parents[0]
1791
1792     if switch_obj is not None:
1793         # now look where the fields are defined that are needed to evaluate
1794         # the switch expr, and store the parent objects in accessor_params and
1795         # the fields in switch_fields
1796
1797         # 'S': name for the 'toplevel' switch
1798         toplevel_switch = parents[1]
1799         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1800         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1801
1802         # initialize prefix for everything "below" S
1803         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1804         prefix = [(prefix_str, '->', toplevel_switch)]
1805
1806         # look for fields in the remaining containers
1807         for p in parents[2:] + [self]:
1808             # the separator between parent and child is always '.' here,
1809             # because of nested switch statements
1810             if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1811                 prefix.append((p.name[-1], '.', p))
1812             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1813
1814         # auxiliary object for 'S' parameter
1815         S_obj = parents[1]
1816
1817     _h_setlevel(1)
1818     _c_setlevel(1)
1819     if list.member.fixed_size():
1820         idx = 1 if switch_obj is not None else 0
1821         _hc('')
1822         _hc('%s *', field.c_field_type)
1823
1824         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1825         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1826
1827         _c('{')
1828         if switch_obj is not None:
1829             _c('    return %s;', fields[field.c_field_name][0])
1830         elif field.prev_varsized_field is None:
1831             _c('    return (%s *) (R + 1);', field.c_field_type)
1832         else:
1833             (prev_varsized_field, align_pad) = get_align_pad(field)
1834
1835             if align_pad is None:
1836                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1837                     type_pad_type(field.first_field_after_varsized.type.c_type))
1838
1839             _c('    xcb_generic_iterator_t prev = %s;',
1840                 _c_iterator_get_end(prev_varsized_field, 'R'))
1841             _c('    return (%s *) ((char *) prev.data + %s + %d);',
1842                field.c_field_type, align_pad, field.prev_varsized_offset)
1843         _c('}')
1844
1845     _hc('')
1846     _hc('int')
1847     if switch_obj is not None:
1848         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1849         spacing = ' '*(len(field.c_length_name)+2)
1850         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1851         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1852     else:
1853         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1854         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1855     _c('{')
1856     length = _c_accessor_get_expr(field.type.expr, fields)
1857     _c('    return %s;', length)
1858     _c('}')
1859
1860     if field.type.member.is_simple:
1861         _hc('')
1862         _hc('xcb_generic_iterator_t')
1863         if switch_obj is not None:
1864             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1865             spacing = ' '*(len(field.c_end_name)+2)
1866             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1867             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1868         else:
1869             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1870             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1871         _c('{')
1872         _c('    xcb_generic_iterator_t i;')
1873
1874         param = 'R' if switch_obj is None else 'S'
1875         if switch_obj is not None:
1876             _c('    i.data = %s + %s;', fields[field.c_field_name][0],
1877                _c_accessor_get_expr(field.type.expr, fields))
1878         elif field.prev_varsized_field == None:
1879             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1880                _c_accessor_get_expr(field.type.expr, fields))
1881         else:
1882             _c('    xcb_generic_iterator_t child = %s;',
1883                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1884             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1885                _c_accessor_get_expr(field.type.expr, fields))
1886
1887         _c('    i.rem = 0;')
1888         _c('    i.index = (char *) i.data - (char *) %s;', param)
1889         _c('    return i;')
1890         _c('}')
1891
1892     else:
1893         _hc('')
1894         _hc('%s', field.c_iterator_type)
1895         if switch_obj is not None:
1896             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1897             spacing = ' '*(len(field.c_iterator_name)+2)
1898             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1899             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1900         else:
1901             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1902             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1903         _c('{')
1904         _c('    %s i;', field.c_iterator_type)
1905
1906         _c_pre.start()
1907         length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1908
1909         if switch_obj is not None:
1910             _c_pre.end()
1911             _c('    i.data = %s;', fields[field.c_field_name][0])
1912             _c('    i.rem = %s;', length_expr_str)
1913         elif field.prev_varsized_field == None:
1914             _c_pre.end()
1915             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1916         else:
1917             (prev_varsized_field, align_pad) = get_align_pad(field)
1918
1919             if align_pad is None:
1920                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1921                     type_pad_type(field.c_field_type))
1922
1923             _c('    xcb_generic_iterator_t prev = %s;',
1924                 _c_iterator_get_end(prev_varsized_field, 'R'))
1925             _c_pre.end()
1926             _c('    i.data = (%s *) ((char *) prev.data + %s);',
1927                 field.c_field_type, align_pad)
1928
1929         if switch_obj is None:
1930             _c('    i.rem = %s;', length_expr_str)
1931         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1932         _c('    return i;')
1933         _c('}')
1934
1935 def _c_accessors(self, name, base):
1936     '''
1937     Declares the accessor functions for the fields of a structure.
1938     '''
1939     # no accessors for switch itself -
1940     # switch always needs to be unpacked explicitly
1941 #    if self.is_switch:
1942 #        pass
1943 #    else:
1944     if True:
1945         for field in self.fields:
1946             if not field.type.is_pad:
1947                 if _c_field_needs_list_accessor(field):
1948                     _c_accessors_list(self, field)
1949                 elif _c_field_needs_field_accessor(field):
1950                     _c_accessors_field(self, field)
1951
1952 def c_simple(self, name):
1953     '''
1954     Exported function that handles cardinal type declarations.
1955     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1956     '''
1957     _c_type_setup(self, name, ())
1958
1959     if (self.name != name):
1960         # Typedef
1961         _h_setlevel(0)
1962         my_name = _t(name)
1963         _h('')
1964         _h('typedef %s %s;', _t(self.name), my_name)
1965
1966         # Iterator
1967         _c_iterator(self, name)
1968
1969 def _c_complex(self, force_packed = False):
1970     '''
1971     Helper function for handling all structure types.
1972     Called for all structs, requests, replies, events, errors.
1973     '''
1974     _h_setlevel(0)
1975     _h('')
1976     _h('/**')
1977     _h(' * @brief %s', self.c_type)
1978     _h(' **/')
1979     _h('typedef %s %s {', self.c_container, self.c_type)
1980
1981     struct_fields = []
1982     maxtypelen = 0
1983
1984     varfield = None
1985     for field in self.fields:
1986         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1987             varfield = field.c_field_name
1988             continue
1989         if field.wire:
1990             struct_fields.append(field)
1991
1992     for field in struct_fields:
1993         length = len(field.c_field_type)
1994         # account for '*' pointer_spec
1995         if not field.type.fixed_size() and not self.is_union:
1996             length += 1
1997         maxtypelen = max(maxtypelen, length)
1998
1999     def _c_complex_field(self, field, space=''):
2000         if (field.type.fixed_size() or self.is_union or
2001             # in case of switch with switch children, don't make the field a pointer
2002             # necessary for unserialize to work
2003             (self.is_switch and field.type.is_switch)):
2004             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2005             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2006         else:
2007             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2008             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2009
2010     if not self.is_switch:
2011         for field in struct_fields:
2012             _c_complex_field(self, field)
2013     else:
2014         for b in self.bitcases:
2015             space = ''
2016             if b.type.has_name:
2017                 _h('    struct {')
2018                 space = '    '
2019             for field in b.type.fields:
2020                 _c_complex_field(self, field, space)
2021             if b.type.has_name:
2022                 _h('    } %s;', b.c_field_name)
2023
2024     _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2025
2026 def c_struct(self, name):
2027     '''
2028     Exported function that handles structure declarations.
2029     '''
2030     _c_type_setup(self, name, ())
2031     _c_complex(self)
2032     _c_accessors(self, name, name)
2033     _c_iterator(self, name)
2034
2035 def c_union(self, name):
2036     '''
2037     Exported function that handles union declarations.
2038     '''
2039     _c_type_setup(self, name, ())
2040     _c_complex(self)
2041     _c_iterator(self, name)
2042
2043 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2044     '''
2045     Declares a request function.
2046     '''
2047
2048     # Four stunningly confusing possibilities here:
2049     #
2050     #   Void            Non-void
2051     # ------------------------------
2052     # "req"            "req"
2053     # 0 flag           CHECKED flag   Normal Mode
2054     # void_cookie      req_cookie
2055     # ------------------------------
2056     # "req_checked"    "req_unchecked"
2057     # CHECKED flag     0 flag         Abnormal Mode
2058     # void_cookie      req_cookie
2059     # ------------------------------
2060
2061
2062     # Whether we are _checked or _unchecked
2063     checked = void and not regular
2064     unchecked = not void and not regular
2065
2066     # What kind of cookie we return
2067     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2068
2069     # What flag is passed to xcb_request
2070     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2071
2072     if reply_fds:
2073         if func_flags == '0':
2074             func_flags = 'XCB_REQUEST_REPLY_FDS'
2075         else:
2076             func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2077
2078     # Global extension id variable or NULL for xproto
2079     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2080
2081     # What our function name is
2082     func_name = self.c_request_name if not aux else self.c_aux_name
2083     if checked:
2084         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2085     if unchecked:
2086         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2087
2088     param_fields = []
2089     wire_fields = []
2090     maxtypelen = len('xcb_connection_t')
2091     serial_fields = []
2092     # special case: list with variable size elements
2093     list_with_var_size_elems = False
2094
2095     for field in self.fields:
2096         if field.visible:
2097             # The field should appear as a call parameter
2098             param_fields.append(field)
2099         if field.wire and not field.auto:
2100             # We need to set the field up in the structure
2101             wire_fields.append(field)
2102         if field.type.c_need_serialize or field.type.c_need_sizeof:
2103             serial_fields.append(field)
2104
2105     for field in param_fields:
2106         c_field_const_type = field.c_field_const_type
2107         if field.type.c_need_serialize and not aux:
2108             c_field_const_type = "const void"
2109         if len(c_field_const_type) > maxtypelen:
2110             maxtypelen = len(c_field_const_type)
2111         if field.type.is_list and not field.type.member.fixed_size():
2112             list_with_var_size_elems = True
2113
2114     _h_setlevel(1)
2115     _c_setlevel(1)
2116     _h('')
2117     _h('/**')
2118     if hasattr(self, "doc") and self.doc:
2119         if self.doc.brief:
2120             _h(' * @brief ' + self.doc.brief)
2121         else:
2122             _h(' * No brief doc yet')
2123
2124     _h(' *')
2125     _h(' * @param c The connection')
2126     param_names = [f.c_field_name for f in param_fields]
2127     if hasattr(self, "doc") and self.doc:
2128         for field in param_fields:
2129             # XXX: hard-coded until we fix xproto.xml
2130             base_func_name = self.c_request_name if not aux else self.c_aux_name
2131             if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2132                 field.enum = 'GC'
2133             elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2134                 field.enum = 'CW'
2135             elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2136                 field.enum = 'CW'
2137             if field.enum:
2138                 # XXX: why the 'xcb' prefix?
2139                 key = ('xcb', field.enum)
2140
2141                 tname = _t(key)
2142                 if namecount[tname] > 1:
2143                     tname = _t(key + ('enum',))
2144                 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2145
2146             if self.doc and field.field_name in self.doc.fields:
2147                 desc = self.doc.fields[field.field_name]
2148                 for name in param_names:
2149                     desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2150                 desc = desc.split("\n")
2151                 desc = [line if line != '' else '\\n' for line in desc]
2152                 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2153             # If there is no documentation yet, we simply don't generate an
2154             # @param tag. Doxygen will then warn about missing documentation.
2155
2156     _h(' * @return A cookie')
2157     _h(' *')
2158
2159     if hasattr(self, "doc") and self.doc:
2160         if self.doc.description:
2161             desc = self.doc.description
2162             for name in param_names:
2163                 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2164             desc = desc.split("\n")
2165             _h(' * ' + "\n * ".join(desc))
2166         else:
2167             _h(' * No description yet')
2168     else:
2169         _h(' * Delivers a request to the X server.')
2170     _h(' *')
2171     if checked:
2172         _h(' * This form can be used only if the request will not cause')
2173         _h(' * a reply to be generated. Any returned error will be')
2174         _h(' * saved for handling by xcb_request_check().')
2175     if unchecked:
2176         _h(' * This form can be used only if the request will cause')
2177         _h(' * a reply to be generated. Any returned error will be')
2178         _h(' * placed in the event queue.')
2179     _h(' */')
2180     _c('')
2181     _hc('%s', cookie_type)
2182
2183     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2184     comma = ',' if len(param_fields) else ');'
2185     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2186     comma = ',' if len(param_fields) else ')'
2187     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2188
2189     func_spacing = ' ' * (len(func_name) + 2)
2190     count = len(param_fields)
2191     for field in param_fields:
2192         count = count - 1
2193         c_field_const_type = field.c_field_const_type
2194         c_pointer = field.c_pointer
2195         if field.type.c_need_serialize and not aux:
2196             c_field_const_type = "const void"
2197             c_pointer = '*'
2198         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2199         comma = ',' if count else ');'
2200         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2201            spacing, c_pointer, field.c_field_name, comma)
2202         comma = ',' if count else ')'
2203         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2204            spacing, c_pointer, field.c_field_name, comma)
2205
2206     count = 2
2207     if not self.c_var_followed_by_fixed_fields:
2208         for field in param_fields:
2209             if not field.type.fixed_size():
2210                 count = count + 2
2211                 if field.type.c_need_serialize:
2212                     # _serialize() keeps track of padding automatically
2213                     count -= 1
2214     dimension = count + 2
2215
2216     _c('{')
2217     _c('    static const xcb_protocol_request_t xcb_req = {')
2218     _c('        /* count */ %d,', count)
2219     _c('        /* ext */ %s,', func_ext_global)
2220     _c('        /* opcode */ %s,', self.c_request_name.upper())
2221     _c('        /* isvoid */ %d', 1 if void else 0)
2222     _c('    };')
2223     _c('')
2224
2225     _c('    struct iovec xcb_parts[%d];', dimension)
2226     _c('    %s xcb_ret;', func_cookie)
2227     _c('    %s xcb_out;', self.c_type)
2228     if self.c_var_followed_by_fixed_fields:
2229         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2230         _c('    void *xcb_aux = 0;')
2231
2232
2233     for idx, f in enumerate(serial_fields):
2234         if aux:
2235             _c('    void *xcb_aux%d = 0;' % (idx))
2236     if list_with_var_size_elems:
2237         _c('    unsigned int i;')
2238         _c('    unsigned int xcb_tmp_len;')
2239         _c('    char *xcb_tmp;')
2240     _c('')
2241     # simple request call tracing
2242 #    _c('    printf("in function %s\\n");' % func_name)
2243
2244     # fixed size fields
2245     for field in wire_fields:
2246         if field.type.fixed_size():
2247             if field.type.is_expr:
2248                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2249             elif field.type.is_pad:
2250                 if field.type.nmemb == 1:
2251                     _c('    xcb_out.%s = 0;', field.c_field_name)
2252                 else:
2253                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2254             else:
2255                 if field.type.nmemb == 1:
2256                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2257                 else:
2258                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2259
2260     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2261         serialize_args = get_serialize_params(context, type_obj,
2262                                               c_field_name,
2263                                               aux_var)[2]
2264         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2265
2266     # calls in order to free dyn. all. memory
2267     free_calls = []
2268
2269     _c('')
2270     if not self.c_var_followed_by_fixed_fields:
2271         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2272         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2273         _c('    xcb_parts[3].iov_base = 0;')
2274         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2275
2276         count = 4
2277
2278         for field in param_fields:
2279             if not field.type.fixed_size():
2280                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2281                 # default: simple cast to char *
2282                 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2283                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2284                     if field.type.is_list:
2285                         if field.type.member.fixed_size():
2286                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2287                                _c_accessor_get_expr(field.type.expr, None),
2288                                field.type.member.c_wiretype)
2289                         else:
2290                             list_length = _c_accessor_get_expr(field.type.expr, None)
2291
2292                             length = ''
2293                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2294                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2295                             _c("    for(i=0; i<%s; i++) {" % list_length)
2296                             _c("        xcb_tmp_len = %s(xcb_tmp);" %
2297                                               (field.type.c_sizeof_name))
2298                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2299                             _c("        xcb_tmp += xcb_tmp_len;")
2300                             _c("    }")
2301                     else:
2302                         # not supposed to happen
2303                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2304                 else:
2305                     if not aux:
2306                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2307                     idx = serial_fields.index(field)
2308                     aux_var = '&xcb_aux%d' % idx
2309                     context = 'serialize' if aux else 'sizeof'
2310                     _c('    xcb_parts[%d].iov_len =', count)
2311                     if aux:
2312                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2313                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2314                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2315                         free_calls.append('    free(xcb_aux%d);' % idx)
2316                     else:
2317                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2318                         func_name = field.type.c_sizeof_name
2319                         _c('      %s (%s);', func_name, serialize_args)
2320
2321                 count += 1
2322                 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2323                     # the _serialize() function keeps track of padding automatically
2324                     _c('    xcb_parts[%d].iov_base = 0;', count)
2325                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2326                     count += 1
2327
2328     # elif self.c_var_followed_by_fixed_fields:
2329     else:
2330         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2331         # request header: opcodes + length
2332         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2333         count += 1
2334         # call _serialize()
2335         buffer_var = '&xcb_aux'
2336         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2337         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2338         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2339         free_calls.append('    free(xcb_aux);')
2340         # no padding necessary - _serialize() keeps track of padding automatically
2341
2342     _c('')
2343     for field in param_fields:
2344         if field.isfd:
2345             _c('    xcb_send_fd(c, %s);', field.c_field_name)
2346
2347     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2348
2349     # free dyn. all. data, if any
2350     for f in free_calls:
2351         _c(f)
2352     _c('    return xcb_ret;')
2353     _c('}')
2354
2355 def _c_reply(self, name):
2356     '''
2357     Declares the function that returns the reply structure.
2358     '''
2359     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2360     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2361     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2362
2363     # check if _unserialize() has to be called for any field
2364     def look_for_special_cases(complex_obj):
2365         unserialize_fields = []
2366         # no unserialize call in case of switch
2367         if not complex_obj.is_switch:
2368             for field in complex_obj.fields:
2369                 # three cases: 1. field with special case
2370                 #              2. container that contains special case field
2371                 #              3. list with special case elements
2372                 if field.type.c_var_followed_by_fixed_fields:
2373                     unserialize_fields.append(field)
2374                 elif field.type.is_container:
2375                     unserialize_fields += look_for_special_cases(field.type)
2376                 elif field.type.is_list:
2377                     if field.type.member.c_var_followed_by_fixed_fields:
2378                         unserialize_fields.append(field)
2379                     if field.type.member.is_container:
2380                         unserialize_fields += look_for_special_cases(field.type.member)
2381         return unserialize_fields
2382
2383     unserialize_fields = look_for_special_cases(self.reply)
2384
2385     _h('')
2386     _h('/**')
2387     _h(' * Return the reply')
2388     _h(' * @param c      The connection')
2389     _h(' * @param cookie The cookie')
2390     _h(' * @param e      The xcb_generic_error_t supplied')
2391     _h(' *')
2392     _h(' * Returns the reply of the request asked by')
2393     _h(' *')
2394     _h(' * The parameter @p e supplied to this function must be NULL if')
2395     _h(' * %s(). is used.', self.c_unchecked_name)
2396     _h(' * Otherwise, it stores the error if any.')
2397     _h(' *')
2398     _h(' * The returned value must be freed by the caller using free().')
2399     _h(' */')
2400     _c('')
2401     _hc('%s *', self.c_reply_type)
2402     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2403     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2404     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2405     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2406     _c('{')
2407
2408     if len(unserialize_fields)>0:
2409         # certain variable size fields need to be unserialized explicitly
2410         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2411            self.c_reply_type, self.c_reply_type)
2412         _c('    int i;')
2413         for field in unserialize_fields:
2414             if field.type.is_list:
2415                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2416                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2417                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2418             else:
2419                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2420         # call _unserialize(), using the reply as source and target buffer
2421         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2422         for field in unserialize_fields:
2423             if field.type.is_list:
2424                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2425                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2426                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2427                    field.c_field_name, field.c_field_name)
2428                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2429                 _c('    }')
2430         # return the transformed reply
2431         _c('    return reply;')
2432
2433     else:
2434         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2435
2436     _c('}')
2437
2438 def _c_reply_has_fds(self):
2439     for field in self.fields:
2440         if field.isfd:
2441             return True
2442     return False
2443
2444 def _c_reply_fds(self, name):
2445     '''
2446     Declares the function that returns fds related to the reply.
2447     '''
2448     spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2449     spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2450     _h('')
2451     _h('/**')
2452     _h(' * Return the reply fds')
2453     _h(' * @param c      The connection')
2454     _h(' * @param reply  The reply')
2455     _h(' *')
2456     _h(' * Returns the array of reply fds of the request asked by')
2457     _h(' *')
2458     _h(' * The returned value must be freed by the caller using free().')
2459     _h(' */')
2460     _c('')
2461     _hc('int *')
2462     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2463     _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2464     _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2465     _c('{')
2466
2467     _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2468
2469     _c('}')
2470
2471
2472 def _c_opcode(name, opcode):
2473     '''
2474     Declares the opcode define for requests, events, and errors.
2475     '''
2476     _h_setlevel(0)
2477     _h('')
2478     _h('/** Opcode for %s. */', _n(name))
2479     _h('#define %s %s', _n(name).upper(), opcode)
2480
2481 def _c_cookie(self, name):
2482     '''
2483     Declares the cookie type for a non-void request.
2484     '''
2485     _h_setlevel(0)
2486     _h('')
2487     _h('/**')
2488     _h(' * @brief %s', self.c_cookie_type)
2489     _h(' **/')
2490     _h('typedef struct %s {', self.c_cookie_type)
2491     _h('    unsigned int sequence; /**<  */')
2492     _h('} %s;', self.c_cookie_type)
2493
2494 def _man_request(self, name, cookie_type, void, aux):
2495     param_fields = [f for f in self.fields if f.visible]
2496
2497     func_name = self.c_request_name if not aux else self.c_aux_name
2498
2499     def create_link(linkname):
2500         name = 'man/%s.%s' % (linkname, section)
2501         if manpaths:
2502             sys.stdout.write(name)
2503         f = open(name, 'w')
2504         f.write('.so man%s/%s.%s' % (section, func_name, section))
2505         f.close()
2506
2507     if manpaths:
2508         sys.stdout.write('man/%s.%s ' % (func_name, section))
2509     # Our CWD is src/, so this will end up in src/man/
2510     f = open('man/%s.%s' % (func_name, section), 'w')
2511     f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2512     # Left-adjust instead of adjusting to both sides
2513     f.write('.ad l\n')
2514     f.write('.SH NAME\n')
2515     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2516     f.write('%s \\- %s\n' % (func_name, brief))
2517     f.write('.SH SYNOPSIS\n')
2518     # Don't split words (hyphenate)
2519     f.write('.hy 0\n')
2520     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2521
2522     # function prototypes
2523     prototype = ''
2524     count = len(param_fields)
2525     for field in param_fields:
2526         count = count - 1
2527         c_field_const_type = field.c_field_const_type
2528         c_pointer = field.c_pointer
2529         if c_pointer == ' ':
2530             c_pointer = ''
2531         if field.type.c_need_serialize and not aux:
2532             c_field_const_type = "const void"
2533             c_pointer = '*'
2534         comma = ', ' if count else ');'
2535         prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2536
2537     f.write('.SS Request function\n')
2538     f.write('.HP\n')
2539     base_func_name = self.c_request_name if not aux else self.c_aux_name
2540     f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2541     create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2542     if not void:
2543         f.write('.PP\n')
2544         f.write('.SS Reply datastructure\n')
2545         f.write('.nf\n')
2546         f.write('.sp\n')
2547         f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2548         struct_fields = []
2549         maxtypelen = 0
2550
2551         for field in self.reply.fields:
2552             if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2553                 continue
2554             if field.wire:
2555                 struct_fields.append(field)
2556
2557         for field in struct_fields:
2558             length = len(field.c_field_type)
2559             # account for '*' pointer_spec
2560             if not field.type.fixed_size():
2561                 length += 1
2562             maxtypelen = max(maxtypelen, length)
2563
2564         def _c_complex_field(self, field, space=''):
2565             if (field.type.fixed_size() or
2566                 # in case of switch with switch children, don't make the field a pointer
2567                 # necessary for unserialize to work
2568                 (self.is_switch and field.type.is_switch)):
2569                 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2570                 f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2571             else:
2572                 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2573                 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2574                 #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2575
2576         if not self.is_switch:
2577             for field in struct_fields:
2578                 _c_complex_field(self, field)
2579         else:
2580             for b in self.bitcases:
2581                 space = ''
2582                 if b.type.has_name:
2583                     space = '    '
2584                 for field in b.type.fields:
2585                     _c_complex_field(self, field, space)
2586                 if b.type.has_name:
2587                     print >> sys.stderr, 'ERROR: New unhandled documentation case'
2588                     pass
2589
2590         f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2591         f.write('.fi\n')
2592
2593         f.write('.SS Reply function\n')
2594         f.write('.HP\n')
2595         f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2596                  '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2597                 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2598         create_link('%s' % self.c_reply_name)
2599
2600         has_accessors = False
2601         for field in self.reply.fields:
2602             if field.type.is_list and not field.type.fixed_size():
2603                 has_accessors = True
2604             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2605                 has_accessors = True
2606
2607         if has_accessors:
2608             f.write('.SS Reply accessors\n')
2609
2610         def _c_accessors_field(self, field):
2611             '''
2612             Declares the accessor functions for a non-list field that follows a variable-length field.
2613             '''
2614             c_type = self.c_type
2615
2616             # special case: switch
2617             switch_obj = self if self.is_switch else None
2618             if self.is_case_or_bitcase:
2619                 switch_obj = self.parents[-1]
2620             if switch_obj is not None:
2621                 c_type = switch_obj.c_type
2622
2623             if field.type.is_simple:
2624                 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2625                 create_link('%s' % field.c_accessor_name)
2626             else:
2627                 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2628                 create_link('%s' % field.c_accessor_name)
2629
2630         def _c_accessors_list(self, field):
2631             '''
2632             Declares the accessor functions for a list field.
2633             Declares a direct-accessor function only if the list members are fixed size.
2634             Declares length and get-iterator functions always.
2635             '''
2636             list = field.type
2637             c_type = self.reply.c_type
2638
2639             # special case: switch
2640             # in case of switch, 2 params have to be supplied to certain accessor functions:
2641             #   1. the anchestor object (request or reply)
2642             #   2. the (anchestor) switch object
2643             # the reason is that switch is either a child of a request/reply or nested in another switch,
2644             # so whenever we need to access a length field, we might need to refer to some anchestor type
2645             switch_obj = self if self.is_switch else None
2646             if self.is_case_or_bitcase:
2647                 switch_obj = self.parents[-1]
2648             if switch_obj is not None:
2649                 c_type = switch_obj.c_type
2650
2651             params = []
2652             fields = {}
2653             parents = self.parents if hasattr(self, 'parents') else [self]
2654             # 'R': parents[0] is always the 'toplevel' container type
2655             params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2656             fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2657             # auxiliary object for 'R' parameters
2658             R_obj = parents[0]
2659
2660             if switch_obj is not None:
2661                 # now look where the fields are defined that are needed to evaluate
2662                 # the switch expr, and store the parent objects in accessor_params and
2663                 # the fields in switch_fields
2664
2665                 # 'S': name for the 'toplevel' switch
2666                 toplevel_switch = parents[1]
2667                 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2668                 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2669
2670                 # initialize prefix for everything "below" S
2671                 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2672                 prefix = [(prefix_str, '->', toplevel_switch)]
2673
2674                 # look for fields in the remaining containers
2675                 for p in parents[2:] + [self]:
2676                     # the separator between parent and child is always '.' here,
2677                     # because of nested switch statements
2678                     if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2679                         prefix.append((p.name[-1], '.', p))
2680                     fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2681
2682                 # auxiliary object for 'S' parameter
2683                 S_obj = parents[1]
2684
2685             if list.member.fixed_size():
2686                 idx = 1 if switch_obj is not None else 0
2687                 f.write('.HP\n')
2688                 f.write('%s *\\fB%s\\fP(%s);\n' %
2689                         (field.c_field_type, field.c_accessor_name, params[idx][0]))
2690                 create_link('%s' % field.c_accessor_name)
2691
2692             f.write('.HP\n')
2693             f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2694                     (field.c_length_name, c_type))
2695             create_link('%s' % field.c_length_name)
2696
2697             if field.type.member.is_simple:
2698                 f.write('.HP\n')
2699                 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2700                         (field.c_end_name, c_type))
2701                 create_link('%s' % field.c_end_name)
2702             else:
2703                 f.write('.HP\n')
2704                 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2705                         (field.c_iterator_type, field.c_iterator_name,
2706                          c_type))
2707                 create_link('%s' % field.c_iterator_name)
2708
2709         for field in self.reply.fields:
2710             if field.type.is_list and not field.type.fixed_size():
2711                 _c_accessors_list(self, field)
2712             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2713                 _c_accessors_field(self, field)
2714
2715
2716     f.write('.br\n')
2717     # Re-enable hyphenation and adjusting to both sides
2718     f.write('.hy 1\n')
2719
2720     # argument reference
2721     f.write('.SH REQUEST ARGUMENTS\n')
2722     f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2723     f.write('The XCB connection to X11.\n')
2724     for field in param_fields:
2725         f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2726         printed_enum = False
2727         # XXX: hard-coded until we fix xproto.xml
2728         if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2729             field.enum = 'GC'
2730         elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2731             field.enum = 'CW'
2732         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2733             field.enum = 'CW'
2734         if hasattr(field, "enum") and field.enum:
2735             # XXX: why the 'xcb' prefix?
2736             key = ('xcb', field.enum)
2737             if key in enums:
2738                 f.write('One of the following values:\n')
2739                 f.write('.RS 1i\n')
2740                 enum = enums[key]
2741                 count = len(enum.values)
2742                 for (enam, eval) in enum.values:
2743                     count = count - 1
2744                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2745                     if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2746                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2747                         f.write('%s\n' % desc)
2748                     else:
2749                         f.write('TODO: NOT YET DOCUMENTED.\n')
2750                 f.write('.RE\n')
2751                 f.write('.RS 1i\n')
2752                 printed_enum = True
2753
2754         if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2755             desc = self.doc.fields[field.field_name]
2756             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2757             if printed_enum:
2758                 f.write('\n')
2759             f.write('%s\n' % desc)
2760         else:
2761             f.write('TODO: NOT YET DOCUMENTED.\n')
2762         if printed_enum:
2763             f.write('.RE\n')
2764
2765     # Reply reference
2766     if not void:
2767         f.write('.SH REPLY FIELDS\n')
2768         # These fields are present in every reply:
2769         f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2770         f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2771                  'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2772                  'be used to tell replies apart from each other.\n') %
2773                  _n(self.reply.name).upper())
2774         f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2775         f.write('The sequence number of the last request processed by the X11 server.\n')
2776         f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2777         f.write('The length of the reply, in words (a word is 4 bytes).\n')
2778         for field in self.reply.fields:
2779             if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2780                 field.c_field_name.startswith('pad')):
2781                 continue
2782
2783             if field.type.is_list and not field.type.fixed_size():
2784                 continue
2785             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2786                 continue
2787             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2788             printed_enum = False
2789             if hasattr(field, "enum") and field.enum:
2790                 # XXX: why the 'xcb' prefix?
2791                 key = ('xcb', field.enum)
2792                 if key in enums:
2793                     f.write('One of the following values:\n')
2794                     f.write('.RS 1i\n')
2795                     enum = enums[key]
2796                     count = len(enum.values)
2797                     for (enam, eval) in enum.values:
2798                         count = count - 1
2799                         f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2800                         if enum.doc and enam in enum.doc.fields:
2801                             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2802                             f.write('%s\n' % desc)
2803                         else:
2804                             f.write('TODO: NOT YET DOCUMENTED.\n')
2805                     f.write('.RE\n')
2806                     f.write('.RS 1i\n')
2807                     printed_enum = True
2808
2809             if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2810                 desc = self.reply.doc.fields[field.field_name]
2811                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2812                 if printed_enum:
2813                     f.write('\n')
2814                 f.write('%s\n' % desc)
2815             else:
2816                 f.write('TODO: NOT YET DOCUMENTED.\n')
2817             if printed_enum:
2818                 f.write('.RE\n')
2819
2820
2821
2822     # text description
2823     f.write('.SH DESCRIPTION\n')
2824     if hasattr(self, "doc") and self.doc and self.doc.description:
2825         desc = self.doc.description
2826         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2827         lines = desc.split('\n')
2828         f.write('\n'.join(lines) + '\n')
2829
2830     f.write('.SH RETURN VALUE\n')
2831     if void:
2832         f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2833                  'have to be handled in the event loop.\n\nIf you want to '
2834                  'handle errors directly with \\fIxcb_request_check\\fP '
2835                  'instead, use \\fI%s_checked\\fP. See '
2836                  '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2837     else:
2838         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2839                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2840                  'handle errors in the event loop instead, use '
2841                  '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2842                  'details.\n') %
2843                 (cookie_type, self.c_reply_name, base_func_name, section))
2844     f.write('.SH ERRORS\n')
2845     if hasattr(self, "doc") and self.doc:
2846         for errtype, errtext in sorted(self.doc.errors.items()):
2847             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2848             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2849             f.write('%s\n' % (errtext))
2850     if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2851         f.write('This request does never generate any errors.\n')
2852     if hasattr(self, "doc") and self.doc and self.doc.example:
2853         f.write('.SH EXAMPLE\n')
2854         f.write('.nf\n')
2855         f.write('.sp\n')
2856         lines = self.doc.example.split('\n')
2857         f.write('\n'.join(lines) + '\n')
2858         f.write('.fi\n')
2859     f.write('.SH SEE ALSO\n')
2860     if hasattr(self, "doc") and self.doc:
2861         see = ['.BR %s (%s)' % ('xcb-requests', section)]
2862         if self.doc.example:
2863             see.append('.BR %s (%s)' % ('xcb-examples', section))
2864         for seename, seetype in sorted(self.doc.see.items()):
2865             if seetype == 'program':
2866                 see.append('.BR %s (1)' % seename)
2867             elif seetype == 'event':
2868                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2869             elif seetype == 'request':
2870                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2871             elif seetype == 'function':
2872                 see.append('.BR %s (%s)' % (seename, section))
2873             else:
2874                 see.append('TODO: %s (type %s)' % (seename, seetype))
2875         f.write(',\n'.join(see) + '\n')
2876     f.write('.SH AUTHOR\n')
2877     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2878     f.close()
2879
2880 def _man_event(self, name):
2881     if manpaths:
2882         sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2883     # Our CWD is src/, so this will end up in src/man/
2884     f = open('man/%s.%s' % (self.c_type, section), 'w')
2885     f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2886     # Left-adjust instead of adjusting to both sides
2887     f.write('.ad l\n')
2888     f.write('.SH NAME\n')
2889     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2890     f.write('%s \\- %s\n' % (self.c_type, brief))
2891     f.write('.SH SYNOPSIS\n')
2892     # Don't split words (hyphenate)
2893     f.write('.hy 0\n')
2894     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2895
2896     f.write('.PP\n')
2897     f.write('.SS Event datastructure\n')
2898     f.write('.nf\n')
2899     f.write('.sp\n')
2900     f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2901     struct_fields = []
2902     maxtypelen = 0
2903
2904     for field in self.fields:
2905         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2906             continue
2907         if field.wire:
2908             struct_fields.append(field)
2909
2910     for field in struct_fields:
2911         length = len(field.c_field_type)
2912         # account for '*' pointer_spec
2913         if not field.type.fixed_size():
2914             length += 1
2915         maxtypelen = max(maxtypelen, length)
2916
2917     def _c_complex_field(self, field, space=''):
2918         if (field.type.fixed_size() or
2919             # in case of switch with switch children, don't make the field a pointer
2920             # necessary for unserialize to work
2921             (self.is_switch and field.type.is_switch)):
2922             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2923             f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2924         else:
2925             print >> sys.stderr, 'ERROR: New unhandled documentation case'
2926
2927     if not self.is_switch:
2928         for field in struct_fields:
2929             _c_complex_field(self, field)
2930     else:
2931         for b in self.bitcases:
2932             space = ''
2933             if b.type.has_name:
2934                 space = '    '
2935             for field in b.type.fields:
2936                 _c_complex_field(self, field, space)
2937             if b.type.has_name:
2938                 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2939                 pass
2940
2941     f.write('} \\fB%s\\fP;\n' % self.c_type)
2942     f.write('.fi\n')
2943
2944
2945     f.write('.br\n')
2946     # Re-enable hyphenation and adjusting to both sides
2947     f.write('.hy 1\n')
2948
2949     # argument reference
2950     f.write('.SH EVENT FIELDS\n')
2951     f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2952     f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2953              'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2954              'to tell events apart from each other.\n') % _n(name).upper())
2955     f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2956     f.write('The sequence number of the last request processed by the X11 server.\n')
2957
2958     if not self.is_switch:
2959         for field in struct_fields:
2960             # Skip the fields which every event has, we already documented
2961             # them (see above).
2962             if field.c_field_name in ('response_type', 'sequence'):
2963                 continue
2964             if isinstance(field.type, PadType):
2965                 continue
2966             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2967             if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2968                 desc = self.doc.fields[field.field_name]
2969                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2970                 f.write('%s\n' % desc)
2971             else:
2972                 f.write('NOT YET DOCUMENTED.\n')
2973
2974     # text description
2975     f.write('.SH DESCRIPTION\n')
2976     if hasattr(self, "doc") and self.doc and self.doc.description:
2977         desc = self.doc.description
2978         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2979         lines = desc.split('\n')
2980         f.write('\n'.join(lines) + '\n')
2981
2982     if hasattr(self, "doc") and self.doc and self.doc.example:
2983         f.write('.SH EXAMPLE\n')
2984         f.write('.nf\n')
2985         f.write('.sp\n')
2986         lines = self.doc.example.split('\n')
2987         f.write('\n'.join(lines) + '\n')
2988         f.write('.fi\n')
2989     f.write('.SH SEE ALSO\n')
2990     if hasattr(self, "doc") and self.doc:
2991         see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2992         if self.doc.example:
2993             see.append('.BR %s (%s)' % ('xcb-examples', section))
2994         for seename, seetype in sorted(self.doc.see.items()):
2995             if seetype == 'program':
2996                 see.append('.BR %s (1)' % seename)
2997             elif seetype == 'event':
2998                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2999             elif seetype == 'request':
3000                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
3001             elif seetype == 'function':
3002                 see.append('.BR %s (%s)' % (seename, section))
3003             else:
3004                 see.append('TODO: %s (type %s)' % (seename, seetype))
3005         f.write(',\n'.join(see) + '\n')
3006     f.write('.SH AUTHOR\n')
3007     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3008     f.close()
3009
3010
3011 def c_request(self, name):
3012     '''
3013     Exported function that handles request declarations.
3014     '''
3015     _c_type_setup(self, name, ('request',))
3016
3017     if self.reply:
3018         # Cookie type declaration
3019         _c_cookie(self, name)
3020
3021     # Opcode define
3022     _c_opcode(name, self.opcode)
3023
3024     # Request structure declaration
3025     _c_complex(self)
3026
3027     if self.reply:
3028         _c_type_setup(self.reply, name, ('reply',))
3029         # Reply structure definition
3030         _c_complex(self.reply)
3031         # Request prototypes
3032         has_fds = _c_reply_has_fds(self.reply)
3033         _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3034         _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3035         if self.c_need_aux:
3036             _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3037             _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3038         # Reply accessors
3039         _c_accessors(self.reply, name + ('reply',), name)
3040         _c_reply(self, name)
3041         if has_fds:
3042             _c_reply_fds(self, name)
3043     else:
3044         # Request prototypes
3045         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3046         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3047         if self.c_need_aux:
3048             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3049             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3050
3051     # We generate the manpage afterwards because _c_type_setup has been called.
3052     # TODO: what about aux helpers?
3053     cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3054     _man_request(self, name, cookie_type, not self.reply, False)
3055
3056 def c_event(self, name):
3057     '''
3058     Exported function that handles event declarations.
3059     '''
3060
3061     # The generic event structure xcb_ge_event_t has the full_sequence field
3062     # at the 32byte boundary. That's why we've to inject this field into GE
3063     # events while generating the structure for them. Otherwise we would read
3064     # garbage (the internal full_sequence) when accessing normal event fields
3065     # there.
3066     force_packed = False
3067     if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3068         event_size = 0
3069         for field in self.fields:
3070             if field.type.size != None and field.type.nmemb != None:
3071                 event_size += field.type.size * field.type.nmemb
3072             if event_size == 32:
3073                 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3074                 idx = self.fields.index(field)
3075                 self.fields.insert(idx + 1, full_sequence)
3076
3077                 # If the event contains any 64-bit extended fields, they need
3078                 # to remain aligned on a 64-bit boundary.  Adding full_sequence
3079                 # would normally break that; force the struct to be packed.
3080                 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3081                 break
3082
3083     _c_type_setup(self, name, ('event',))
3084
3085     # Opcode define
3086     _c_opcode(name, self.opcodes[name])
3087
3088     if self.name == name:
3089         # Structure definition
3090         _c_complex(self, force_packed)
3091     else:
3092         # Typedef
3093         _h('')
3094         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3095
3096     _man_event(self, name)
3097
3098 def c_error(self, name):
3099     '''
3100     Exported function that handles error declarations.
3101     '''
3102     _c_type_setup(self, name, ('error',))
3103
3104     # Opcode define
3105     _c_opcode(name, self.opcodes[name])
3106
3107     if self.name == name:
3108         # Structure definition
3109         _c_complex(self)
3110     else:
3111         # Typedef
3112         _h('')
3113         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3114
3115
3116 # Main routine starts here
3117
3118 # Must create an "output" dictionary before any xcbgen imports.
3119 output = {'open'    : c_open,
3120           'close'   : c_close,
3121           'simple'  : c_simple,
3122           'enum'    : c_enum,
3123           'struct'  : c_struct,
3124           'union'   : c_union,
3125           'request' : c_request,
3126           'event'   : c_event,
3127           'error'   : c_error,
3128           }
3129
3130 # Boilerplate below this point
3131
3132 # Check for the argument that specifies path to the xcbgen python package.
3133 try:
3134     opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3135 except getopt.GetoptError as err:
3136     print(err)
3137     print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3138     sys.exit(1)
3139
3140 for (opt, arg) in opts:
3141     if opt == '-c':
3142         center_footer=arg
3143     if opt == '-l':
3144         left_footer=arg
3145     if opt == '-s':
3146         section=arg
3147     if opt == '-p':
3148         sys.path.insert(1, arg)
3149     elif opt == '-m':
3150         manpaths = True
3151         sys.stdout.write('man_MANS = ')
3152
3153 # Import the module class
3154 try:
3155     from xcbgen.state import Module
3156     from xcbgen.xtypes import *
3157 except ImportError:
3158     print('''
3159 Failed to load the xcbgen Python package!
3160 Make sure that xcb/proto installed it on your Python path.
3161 If not, you will need to create a .pth file or define $PYTHONPATH
3162 to extend the path.
3163 Refer to the README file in xcb/proto for more info.
3164 ''')
3165     raise
3166
3167 # Ensure the man subdirectory exists
3168 try:
3169     os.mkdir('man')
3170 except OSError as e:
3171     if e.errno != errno.EEXIST:
3172         raise
3173
3174 # Parse the xml header
3175 module = Module(args[0], output)
3176
3177 # Build type-registry and resolve type dependencies
3178 module.register()
3179 module.resolve()
3180
3181 # Output the code
3182 module.generate()