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