409054b12e470d89bd1e9bfd691940d78bef6030
[free-sw/xcb/libxcb] / src / c_client.py
1 #!/usr/bin/env python
2 from xml.etree.cElementTree import *
3 from os.path import basename
4 from functools import reduce
5 import getopt
6 import os
7 import sys
8 import errno
9 import time
10 import re
11
12 # Jump to the bottom of this file for the main routine
13
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
17
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
19
20 _cplusplus_annoyances = {'class' : '_class',
21                          'new'   : '_new',
22                          'delete': '_delete'}
23 _c_keywords = {'default' : '_default'}
24
25 _hlines = []
26 _hlevel = 0
27 _clines = []
28 _clevel = 0
29 _ns = None
30
31 # global variable to keep track of serializers and
32 # switch data types due to weird dependencies
33 finished_serializers = []
34 finished_sizeof = []
35 finished_switch = []
36
37 # keeps enum objects so that we can refer to them when generating manpages.
38 enums = {}
39
40 manpaths = False
41
42 def _h(fmt, *args):
43     '''
44     Writes the given line to the header file.
45     '''
46     _hlines[_hlevel].append(fmt % args)
47
48 def _c(fmt, *args):
49     '''
50     Writes the given line to the source file.
51     '''
52     _clines[_clevel].append(fmt % args)
53
54 def _hc(fmt, *args):
55     '''
56     Writes the given line to both the header and source files.
57     '''
58     _h(fmt, *args)
59     _c(fmt, *args)
60
61 def _c_wr_stringlist(indent, strlist):
62     '''
63     Writes the given list of strings to the source file.
64     Each line is prepended by the indent string
65     '''
66     for str in strlist:
67         _c("%s%s", indent, str)
68
69
70 class PreCode(object):
71     '''
72     For pre-code generated by expression generation
73     (for example, the for-loop of a sumof)
74     This has to account for recursiveness of the expression
75     generation, i.e., there may be pre-code for pre-code.
76     Therefore this is implemented as a stack of lists of lines.
77
78     If redirection is switched on, then all output is collected in
79     self.redirect_code and self.redirect_tempvars instead of
80     being sent to the output via _h und _c.
81     '''
82     def __init__(self):
83         self.nesting_level = 0
84         self.tempvars = []
85         self.codelines = []
86         self.redirect_code = None
87         self.redirect_tempvars = None
88         self.indent_str = '    '
89         self.indent_stack = []
90         self.tempvar_num = 0
91
92
93     # start and end of pre-code blocks
94     def start(self):
95         self.nesting_level += 1
96
97     def end(self):
98         self.nesting_level -= 1
99         if self.nesting_level == 0:
100             # lowest pre-code level is finished -> output to source
101             if self.redirect_tempvars is None:
102                 _c_wr_stringlist('', self.tempvars)
103                 self.tempvars = []
104             else:
105                 self.redirect_tempvars.extend(self.tempvars)
106                 self.tempvars = []
107             if self.redirect_code == None:
108                 _c_wr_stringlist('', self.codelines)
109                 self.codelines = []
110             else:
111                 self.redirect_code.extend(self.codelines)
112                 self.codelines = []
113
114
115     def output_tempvars(self):
116         if self.redirect_code == None:
117             _c_wr_stringlist('', self.tempvars)
118             self.tempvars = []
119
120     # output to precode
121     def code(self, fmt, *args):
122         self.codelines.append(self.indent_str + fmt % args)
123
124     def tempvar(self, fmt, *args):
125         self.tempvars.append('    ' + (fmt % args))
126
127     # get a unique name for a temporary variable
128     def get_tempvarname(self):
129         self.tempvar_num += 1
130         return "xcb_pre_tmp_%d" % self.tempvar_num
131
132     # indentation
133
134     def push_indent(self, indentstr):
135         self.indent_stack.append(self.indent_str)
136         self.indent_str = indentstr
137
138     def push_addindent(self, indent_add_str):
139         self.push_indent(self.indent_str + indent_add_str)
140
141     def indent(self):
142         self.push_addindent('    ')
143
144     def pop_indent(self):
145         self.indent_str = self.indent_stack.pop()
146
147     # redirection to lists
148     def redirect_start(self, redirect_code, redirect_tempvars=None):
149         self.redirect_code = redirect_code
150         self.redirect_tempvars = redirect_tempvars
151         if redirect_tempvars is not None:
152             self.tempvar_num = 0
153
154     def redirect_end(self):
155         self.redirect_code = None
156         self.redirect_tempvars = None
157
158 # global PreCode handler
159 _c_pre = PreCode()
160
161
162 # XXX See if this level thing is really necessary.
163 def _h_setlevel(idx):
164     '''
165     Changes the array that header lines are written to.
166     Supports writing different sections of the header file.
167     '''
168     global _hlevel
169     while len(_hlines) <= idx:
170         _hlines.append([])
171     _hlevel = idx
172
173 def _c_setlevel(idx):
174     '''
175     Changes the array that source lines are written to.
176     Supports writing to different sections of the source file.
177     '''
178     global _clevel
179     while len(_clines) <= idx:
180         _clines.append([])
181     _clevel = idx
182
183 def _n_item(str):
184     '''
185     Does C-name conversion on a single string fragment.
186     Uses a regexp with some hard-coded special cases.
187     '''
188     if str in _cname_special_cases:
189         return _cname_special_cases[str]
190     else:
191         split = _cname_re.finditer(str)
192         name_parts = [match.group(0) for match in split]
193         return '_'.join(name_parts)
194
195 def _cpp(str):
196     '''
197     Checks for certain C++ reserved words and fixes them.
198     '''
199     if str in _cplusplus_annoyances:
200         return _cplusplus_annoyances[str]
201     elif str in _c_keywords:
202         return  _c_keywords[str]
203     else:
204         return str
205
206 def _ext(str):
207     '''
208     Does C-name conversion on an extension name.
209     Has some additional special cases on top of _n_item.
210     '''
211     if str in _extension_special_cases:
212         return _n_item(str).lower()
213     else:
214         return str.lower()
215
216 def _n(list):
217     '''
218     Does C-name conversion on a tuple of strings.
219     Different behavior depending on length of tuple, extension/not extension, etc.
220     Basically C-name converts the individual pieces, then joins with underscores.
221     '''
222     if len(list) == 1:
223         parts = list
224     elif len(list) == 2:
225         parts = [list[0], _n_item(list[1])]
226     elif _ns.is_ext:
227         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
228     else:
229         parts = [list[0]] + [_n_item(i) for i in list[1:]]
230     return '_'.join(parts).lower()
231
232 def _t(list):
233     '''
234     Does C-name conversion on a tuple of strings representing a type.
235     Same as _n but adds a "_t" on the end.
236     '''
237     if len(list) == 1:
238         parts = list
239     elif len(list) == 2:
240         parts = [list[0], _n_item(list[1]), 't']
241     elif _ns.is_ext:
242         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
243     else:
244         parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
245     return '_'.join(parts).lower()
246
247
248 def c_open(self):
249     '''
250     Exported function that handles module open.
251     Opens the files and writes out the auto-generated comment, header file includes, etc.
252     '''
253     global _ns
254     _ns = self.namespace
255     _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
256
257     # Build the type-name collision avoidance table used by c_enum
258     build_collision_table()
259
260     _h_setlevel(0)
261     _c_setlevel(0)
262
263     _hc('/*')
264     _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
265     _hc(' * Edit at your peril.')
266     _hc(' */')
267     _hc('')
268
269     _h('/**')
270     _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
271     _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
272     _h(' * @{')
273     _h(' **/')
274     _h('')
275     _h('#ifndef __%s_H', _ns.header.upper())
276     _h('#define __%s_H', _ns.header.upper())
277     _h('')
278     _h('#include "xcb.h"')
279
280     _c('#ifdef HAVE_CONFIG_H')
281     _c('#include "config.h"')
282     _c('#endif')
283     _c('#include <stdlib.h>')
284     _c('#include <string.h>')
285     _c('#include <assert.h>')
286     _c('#include <stddef.h>  /* for offsetof() */')
287     _c('#include "xcbext.h"')
288     _c('#include "%s.h"', _ns.header)
289
290     _c('')
291     _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
292
293     if _ns.is_ext:
294         for (n, h) in self.direct_imports:
295             _hc('#include "%s.h"', h)
296
297     _h('')
298     _h('#ifdef __cplusplus')
299     _h('extern "C" {')
300     _h('#endif')
301
302     if _ns.is_ext:
303         _h('')
304         _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
305         _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
306         _h('') #XXX
307         _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
308
309         _c('')
310         _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
311
312 def c_close(self):
313     '''
314     Exported function that handles module close.
315     Writes out all the stored content lines, then closes the files.
316     '''
317     _h_setlevel(2)
318     _c_setlevel(2)
319     _hc('')
320
321     _h('')
322     _h('#ifdef __cplusplus')
323     _h('}')
324     _h('#endif')
325
326     _h('')
327     _h('#endif')
328     _h('')
329     _h('/**')
330     _h(' * @}')
331     _h(' */')
332
333     # Write header file
334     hfile = open('%s.h' % _ns.header, 'w')
335     for list in _hlines:
336         for line in list:
337             hfile.write(line)
338             hfile.write('\n')
339     hfile.close()
340
341     # Write source file
342     cfile = open('%s.c' % _ns.header, 'w')
343     for list in _clines:
344         for line in list:
345             cfile.write(line)
346             cfile.write('\n')
347     cfile.close()
348
349 def build_collision_table():
350     global namecount
351     namecount = {}
352
353     for v in module.types.values():
354         name = _t(v[0])
355         namecount[name] = (namecount.get(name) or 0) + 1
356
357 def c_enum(self, name):
358     '''
359     Exported function that handles enum declarations.
360     '''
361
362     enums[name] = self
363
364     tname = _t(name)
365     if namecount[tname] > 1:
366         tname = _t(name + ('enum',))
367
368     _h_setlevel(0)
369     _h('')
370     _h('typedef enum %s {', tname)
371
372     count = len(self.values)
373
374     for (enam, eval) in self.values:
375         count = count - 1
376         equals = ' = ' if eval != '' else ''
377         comma = ',' if count > 0 else ''
378         doc = ''
379         if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
380             doc = '\n/**< %s */\n' % self.doc.fields[enam]
381         _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
382
383     _h('} %s;', tname)
384
385 def _c_type_setup(self, name, postfix):
386     '''
387     Sets up all the C-related state by adding additional data fields to
388     all Field and Type objects.  Here is where we figure out most of our
389     variable and function names.
390
391     Recurses into child fields and list member types.
392     '''
393     # Do all the various names in advance
394     self.c_type = _t(name + postfix)
395     self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
396
397     self.c_iterator_type = _t(name + ('iterator',))
398     self.c_next_name = _n(name + ('next',))
399     self.c_end_name = _n(name + ('end',))
400
401     self.c_request_name = _n(name)
402     self.c_checked_name = _n(name + ('checked',))
403     self.c_unchecked_name = _n(name + ('unchecked',))
404     self.c_reply_name = _n(name + ('reply',))
405     self.c_reply_type = _t(name + ('reply',))
406     self.c_cookie_type = _t(name + ('cookie',))
407     self.c_reply_fds_name = _n(name + ('reply_fds',))
408
409     self.c_need_aux = False
410     self.c_need_serialize = False
411     self.c_need_sizeof = False
412
413     self.c_aux_name = _n(name + ('aux',))
414     self.c_aux_checked_name = _n(name + ('aux', 'checked'))
415     self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
416     self.c_serialize_name = _n(name + ('serialize',))
417     self.c_unserialize_name = _n(name + ('unserialize',))
418     self.c_unpack_name = _n(name + ('unpack',))
419     self.c_sizeof_name = _n(name + ('sizeof',))
420
421     # special case: structs where variable size fields are followed by fixed size fields
422     self.c_var_followed_by_fixed_fields = False
423
424     if self.is_switch:
425         self.c_need_serialize = True
426         self.c_container = 'struct'
427         for bitcase in self.bitcases:
428             bitcase.c_field_name = _cpp(bitcase.field_name)
429             bitcase_name = bitcase.field_type if bitcase.type.has_name else name
430             _c_type_setup(bitcase.type, bitcase_name, ())
431
432     elif self.is_container:
433
434         self.c_container = 'union' if self.is_union else 'struct'
435         prev_varsized_field = None
436         prev_varsized_offset = 0
437         first_field_after_varsized = None
438
439         for field in self.fields:
440             field.c_field_type = _t(field.field_type)
441             field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
442             field.c_field_name = _cpp(field.field_name)
443             field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
444             field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
445
446             # correct the c_pointer field for variable size non-list types
447             if not field.type.fixed_size() and field.c_pointer == ' ':
448                 field.c_pointer = '*'
449             if field.type.is_list and not field.type.member.fixed_size():
450                 field.c_pointer = '*'
451
452             if field.type.is_switch:
453                 field.c_pointer = '*'
454                 field.c_field_const_type = 'const ' + field.c_field_type
455                 self.c_need_aux = True
456
457             if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
458                 self.c_need_sizeof = True
459
460             field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
461             field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
462             field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
463             field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
464             field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
465
466             field.prev_varsized_field = prev_varsized_field
467             field.prev_varsized_offset = prev_varsized_offset
468
469             if prev_varsized_offset == 0:
470                 first_field_after_varsized = field
471             field.first_field_after_varsized = first_field_after_varsized
472
473             if field.type.fixed_size():
474                 prev_varsized_offset += field.type.size
475                 # special case: intermixed fixed and variable size fields
476                 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
477                     if not self.is_union:
478                         self.c_need_serialize = True
479                         self.c_var_followed_by_fixed_fields = True
480             else:
481                 self.last_varsized_field = field
482                 prev_varsized_field = field
483                 prev_varsized_offset = 0
484
485             if self.c_var_followed_by_fixed_fields:
486                 if field.type.fixed_size():
487                     field.prev_varsized_field = None
488
489             # recurse into this field this has to be done here, i.e.,
490             # after the field has been set up. Otherwise the function
491             # _c_helper_fieldaccess_expr will produce garbage or crash
492             _c_type_setup(field.type, field.field_type, ())
493             if field.type.is_list:
494                 _c_type_setup(field.type.member, field.field_type, ())
495                 if (field.type.nmemb is None):
496                     self.c_need_sizeof = True
497
498     if self.c_need_serialize:
499         # when _unserialize() is wanted, create _sizeof() as well for consistency reasons
500         self.c_need_sizeof = True
501
502     # as switch does never appear at toplevel,
503     # continue here with type construction
504     if self.is_switch:
505         if self.c_type not in finished_switch:
506             finished_switch.append(self.c_type)
507             # special: switch C structs get pointer fields for variable-sized members
508             _c_complex(self)
509             for bitcase in self.bitcases:
510                 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
511                 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
512                 # no list with switch as element, so no call to
513                 # _c_iterator(field.type, field_name) necessary
514
515     if not self.is_case_or_bitcase:
516         if self.c_need_serialize:
517             if self.c_serialize_name not in finished_serializers:
518                 finished_serializers.append(self.c_serialize_name)
519                 _c_serialize('serialize', self)
520
521                 # _unpack() and _unserialize() are only needed for special cases:
522                 #   switch -> unpack
523                 #   special cases -> unserialize
524                 if self.is_switch or self.c_var_followed_by_fixed_fields:
525                     _c_serialize('unserialize', self)
526
527         if self.c_need_sizeof:
528             if self.c_sizeof_name not in finished_sizeof:
529                 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
530                     finished_sizeof.append(self.c_sizeof_name)
531                     _c_serialize('sizeof', self)
532 # _c_type_setup()
533
534 # Functions for querying field properties
535 def _c_field_needs_list_accessor(field):
536     return field.type.is_list and not field.type.fixed_size()
537
538 def _c_field_needs_field_accessor(field):
539     if field.type.is_list:
540         return False
541     else:
542         return (field.prev_varsized_field is not None or
543                 not field.type.fixed_size())
544
545 def _c_field_needs_accessor(field):
546     return (_c_field_needs_list_accessor(field) or
547             _c_field_needs_field_accessor(field))
548
549 def _c_field_is_member_of_case_or_bitcase(field):
550     return field.parent and field.parent.is_case_or_bitcase
551
552 def _c_helper_fieldaccess_expr(prefix, field=None):
553     """
554     turn prefix, which is a list of tuples (name, separator, Type obj) into a string
555     representing a valid 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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(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_fieldaccess_expr(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         c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1632         # create explicit code for computing the sum.
1633         # This works for all C-types which can be added to int64_t with +=
1634         _c_pre.start()
1635         lengthvar = _c_pre.get_tempvarname()
1636         loopvar = _c_pre.get_tempvarname()
1637         sumvar = _c_pre.get_tempvarname()
1638         listvar = _c_pre.get_tempvarname()
1639         _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1640         _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1641         _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1642         _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1643         _c_pre.code("/* sumof start */")
1644         _c_pre.code("%s = %s;", lengthvar, c_length_func)
1645         _c_pre.code("%s = 0;", sumvar)
1646         _c_pre.code("%s = %s;", listvar, list_name)
1647         _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1648         _c_pre.indent()
1649
1650         if expr.rhs is None:
1651             _c_pre.code("%s += *%s;", sumvar, listvar)
1652         else:
1653             # sumof has a nested expression which has to be evaluated in
1654             # the context of this list element
1655
1656             # field mapping for the subexpression needs to include
1657             # the fields of the list-member type
1658             scoped_field_mapping = field_mapping.copy()
1659             scoped_field_mapping.update(
1660                 _c_helper_field_mapping(
1661                     field.type.member,
1662                     [(listvar, '->', field.type.member)]))
1663
1664             # cause pre-code of the subexpression be added right here
1665             _c_pre.end()
1666             # compute the subexpression
1667             rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1668             # resume with our code
1669             _c_pre.start()
1670             # output the summation expression
1671             _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1672
1673         _c_pre.code("%s++;", listvar)
1674         _c_pre.pop_indent()
1675         _c_pre.code("}")
1676         _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1677         _c_pre.end()
1678         return sumvar
1679     elif expr.op != None:
1680         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1681                 ' ' + expr.op + ' ' +
1682                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1683     elif expr.bitfield:
1684         return 'xcb_popcount(' + lenexp + ')'
1685     else:
1686         return lenexp
1687
1688 def type_pad_type(type):
1689     if type == 'void':
1690         return 'char'
1691     return type
1692
1693 def _c_accessors_field(self, field):
1694     '''
1695     Declares the accessor functions for a non-list field that follows a variable-length field.
1696     '''
1697     c_type = self.c_type
1698
1699     # special case: switch
1700     switch_obj = self if self.is_switch else None
1701     if self.is_case_or_bitcase:
1702         switch_obj = self.parents[-1]
1703     if switch_obj is not None:
1704         c_type = switch_obj.c_type
1705
1706     if field.type.is_simple:
1707         _hc('')
1708         _hc('%s', field.c_field_type)
1709         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1710         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1711         _c('{')
1712         if field.prev_varsized_field is None:
1713             _c('    return (%s *) (R + 1);', field.c_field_type)
1714         else:
1715             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1716             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1717                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1718         _c('}')
1719     else:
1720         _hc('')
1721         if field.type.is_switch and switch_obj is None:
1722             return_type = 'void *'
1723         else:
1724             return_type = '%s *' % field.c_field_type
1725
1726         _hc(return_type)
1727         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1728         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1729         _c('{')
1730         if field.prev_varsized_field is None:
1731             _c('    return (%s) (R + 1);', return_type)
1732             # note: the special case 'variable fields followed by fixed size fields'
1733             #       is not of any consequence here, since the ordering gets
1734             #       'corrected' in the reply function
1735         else:
1736             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1737             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1738                return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1739         _c('}')
1740
1741
1742 def _c_accessors_list(self, field):
1743     '''
1744     Declares the accessor functions for a list field.
1745     Declares a direct-accessor function only if the list members are fixed size.
1746     Declares length and get-iterator functions always.
1747     '''
1748
1749     def get_align_pad(field):
1750             prev = field.prev_varsized_field
1751             prev_prev = field.prev_varsized_field.prev_varsized_field
1752
1753             if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1754                 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1755             else:
1756                 return (prev, None)
1757
1758
1759     list = field.type
1760     c_type = self.c_type
1761
1762     # special case: switch
1763     # in case of switch, 2 params have to be supplied to certain accessor functions:
1764     #   1. the anchestor object (request or reply)
1765     #   2. the (anchestor) switch object
1766     # the reason is that switch is either a child of a request/reply or nested in another switch,
1767     # so whenever we need to access a length field, we might need to refer to some anchestor type
1768     switch_obj = self if self.is_switch else None
1769     if self.is_case_or_bitcase:
1770         switch_obj = self.parents[-1]
1771     if switch_obj is not None:
1772         c_type = switch_obj.c_type
1773
1774     params = []
1775     fields = {}
1776     parents = self.parents if hasattr(self, 'parents') else [self]
1777     # 'R': parents[0] is always the 'toplevel' container type
1778     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1779     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1780     # auxiliary object for 'R' parameters
1781     R_obj = parents[0]
1782
1783     if switch_obj is not None:
1784         # now look where the fields are defined that are needed to evaluate
1785         # the switch expr, and store the parent objects in accessor_params and
1786         # the fields in switch_fields
1787
1788         # 'S': name for the 'toplevel' switch
1789         toplevel_switch = parents[1]
1790         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1791         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1792
1793         # initialize prefix for everything "below" S
1794         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1795         prefix = [(prefix_str, '->', toplevel_switch)]
1796
1797         # look for fields in the remaining containers
1798         for p in parents[2:] + [self]:
1799             # the separator between parent and child is always '.' here,
1800             # because of nested switch statements
1801             if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1802                 prefix.append((p.name[-1], '.', p))
1803             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1804
1805         # auxiliary object for 'S' parameter
1806         S_obj = parents[1]
1807
1808     _h_setlevel(1)
1809     _c_setlevel(1)
1810     if list.member.fixed_size():
1811         idx = 1 if switch_obj is not None else 0
1812         _hc('')
1813         _hc('%s *', field.c_field_type)
1814
1815         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1816         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1817
1818         _c('{')
1819         if switch_obj is not None:
1820             _c('    return %s;', fields[field.c_field_name][0])
1821         elif field.prev_varsized_field is None:
1822             _c('    return (%s *) (R + 1);', field.c_field_type)
1823         else:
1824             (prev_varsized_field, align_pad) = get_align_pad(field)
1825
1826             if align_pad is None:
1827                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1828                     type_pad_type(field.first_field_after_varsized.type.c_type))
1829
1830             _c('    xcb_generic_iterator_t prev = %s;',
1831                 _c_iterator_get_end(prev_varsized_field, 'R'))
1832             _c('    return (%s *) ((char *) prev.data + %s + %d);',
1833                field.c_field_type, align_pad, field.prev_varsized_offset)
1834         _c('}')
1835
1836     _hc('')
1837     _hc('int')
1838     if switch_obj is not None:
1839         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1840         spacing = ' '*(len(field.c_length_name)+2)
1841         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1842         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1843     else:
1844         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1845         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1846     _c('{')
1847     length = _c_accessor_get_expr(field.type.expr, fields)
1848     _c('    return %s;', length)
1849     _c('}')
1850
1851     if field.type.member.is_simple:
1852         _hc('')
1853         _hc('xcb_generic_iterator_t')
1854         if switch_obj is not None:
1855             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1856             spacing = ' '*(len(field.c_end_name)+2)
1857             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1858             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1859         else:
1860             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1861             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1862         _c('{')
1863         _c('    xcb_generic_iterator_t i;')
1864
1865         param = 'R' if switch_obj is None else 'S'
1866         if switch_obj is not None:
1867             _c('    i.data = %s + %s;', fields[field.c_field_name][0],
1868                _c_accessor_get_expr(field.type.expr, fields))
1869         elif field.prev_varsized_field == None:
1870             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1871                _c_accessor_get_expr(field.type.expr, fields))
1872         else:
1873             _c('    xcb_generic_iterator_t child = %s;',
1874                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1875             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1876                _c_accessor_get_expr(field.type.expr, fields))
1877
1878         _c('    i.rem = 0;')
1879         _c('    i.index = (char *) i.data - (char *) %s;', param)
1880         _c('    return i;')
1881         _c('}')
1882
1883     else:
1884         _hc('')
1885         _hc('%s', field.c_iterator_type)
1886         if switch_obj is not None:
1887             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1888             spacing = ' '*(len(field.c_iterator_name)+2)
1889             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1890             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1891         else:
1892             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1893             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1894         _c('{')
1895         _c('    %s i;', field.c_iterator_type)
1896
1897         _c_pre.start()
1898         length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1899
1900         if switch_obj is not None:
1901             _c_pre.end()
1902             _c('    i.data = %s;', fields[field.c_field_name][0])
1903             _c('    i.rem = %s;', length_expr_str)
1904         elif field.prev_varsized_field == None:
1905             _c_pre.end()
1906             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1907         else:
1908             (prev_varsized_field, align_pad) = get_align_pad(field)
1909
1910             if align_pad is None:
1911                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1912                     type_pad_type(field.c_field_type))
1913
1914             _c('    xcb_generic_iterator_t prev = %s;',
1915                 _c_iterator_get_end(prev_varsized_field, 'R'))
1916             _c_pre.end()
1917             _c('    i.data = (%s *) ((char *) prev.data + %s);',
1918                 field.c_field_type, align_pad)
1919
1920         if switch_obj is None:
1921             _c('    i.rem = %s;', length_expr_str)
1922         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1923         _c('    return i;')
1924         _c('}')
1925
1926 def _c_accessors(self, name, base):
1927     '''
1928     Declares the accessor functions for the fields of a structure.
1929     '''
1930     # no accessors for switch itself -
1931     # switch always needs to be unpacked explicitly
1932 #    if self.is_switch:
1933 #        pass
1934 #    else:
1935     if True:
1936         for field in self.fields:
1937             if not field.type.is_pad:
1938                 if _c_field_needs_list_accessor(field):
1939                     _c_accessors_list(self, field)
1940                 elif _c_field_needs_field_accessor(field):
1941                     _c_accessors_field(self, field)
1942
1943 def c_simple(self, name):
1944     '''
1945     Exported function that handles cardinal type declarations.
1946     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1947     '''
1948     _c_type_setup(self, name, ())
1949
1950     if (self.name != name):
1951         # Typedef
1952         _h_setlevel(0)
1953         my_name = _t(name)
1954         _h('')
1955         _h('typedef %s %s;', _t(self.name), my_name)
1956
1957         # Iterator
1958         _c_iterator(self, name)
1959
1960 def _c_complex(self, force_packed = False):
1961     '''
1962     Helper function for handling all structure types.
1963     Called for all structs, requests, replies, events, errors.
1964     '''
1965     _h_setlevel(0)
1966     _h('')
1967     _h('/**')
1968     _h(' * @brief %s', self.c_type)
1969     _h(' **/')
1970     _h('typedef %s %s {', self.c_container, self.c_type)
1971
1972     struct_fields = []
1973     maxtypelen = 0
1974
1975     varfield = None
1976     for field in self.fields:
1977         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1978             varfield = field.c_field_name
1979             continue
1980         if field.wire:
1981             struct_fields.append(field)
1982
1983     for field in struct_fields:
1984         length = len(field.c_field_type)
1985         # account for '*' pointer_spec
1986         if not field.type.fixed_size() and not self.is_union:
1987             length += 1
1988         maxtypelen = max(maxtypelen, length)
1989
1990     def _c_complex_field(self, field, space=''):
1991         if (field.type.fixed_size() or self.is_union or
1992             # in case of switch with switch children, don't make the field a pointer
1993             # necessary for unserialize to work
1994             (self.is_switch and field.type.is_switch)):
1995             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1996             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1997         else:
1998             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1999             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2000
2001     if not self.is_switch:
2002         for field in struct_fields:
2003             _c_complex_field(self, field)
2004     else:
2005         for b in self.bitcases:
2006             space = ''
2007             if b.type.has_name:
2008                 _h('    struct {')
2009                 space = '    '
2010             for field in b.type.fields:
2011                 _c_complex_field(self, field, space)
2012             if b.type.has_name:
2013                 _h('    } %s;', b.c_field_name)
2014
2015     _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2016
2017 def c_struct(self, name):
2018     '''
2019     Exported function that handles structure declarations.
2020     '''
2021     _c_type_setup(self, name, ())
2022     _c_complex(self)
2023     _c_accessors(self, name, name)
2024     _c_iterator(self, name)
2025
2026 def c_union(self, name):
2027     '''
2028     Exported function that handles union declarations.
2029     '''
2030     _c_type_setup(self, name, ())
2031     _c_complex(self)
2032     _c_iterator(self, name)
2033
2034 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2035     '''
2036     Declares a request function.
2037     '''
2038
2039     # Four stunningly confusing possibilities here:
2040     #
2041     #   Void            Non-void
2042     # ------------------------------
2043     # "req"            "req"
2044     # 0 flag           CHECKED flag   Normal Mode
2045     # void_cookie      req_cookie
2046     # ------------------------------
2047     # "req_checked"    "req_unchecked"
2048     # CHECKED flag     0 flag         Abnormal Mode
2049     # void_cookie      req_cookie
2050     # ------------------------------
2051
2052
2053     # Whether we are _checked or _unchecked
2054     checked = void and not regular
2055     unchecked = not void and not regular
2056
2057     # What kind of cookie we return
2058     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2059
2060     # What flag is passed to xcb_request
2061     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2062
2063     if reply_fds:
2064         if func_flags == '0':
2065             func_flags = 'XCB_REQUEST_REPLY_FDS'
2066         else:
2067             func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2068
2069     # Global extension id variable or NULL for xproto
2070     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2071
2072     # What our function name is
2073     func_name = self.c_request_name if not aux else self.c_aux_name
2074     if checked:
2075         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2076     if unchecked:
2077         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2078
2079     param_fields = []
2080     wire_fields = []
2081     maxtypelen = len('xcb_connection_t')
2082     serial_fields = []
2083     # special case: list with variable size elements
2084     list_with_var_size_elems = False
2085
2086     for field in self.fields:
2087         if field.visible:
2088             # The field should appear as a call parameter
2089             param_fields.append(field)
2090         if field.wire and not field.auto:
2091             # We need to set the field up in the structure
2092             wire_fields.append(field)
2093         if field.type.c_need_serialize or field.type.c_need_sizeof:
2094             serial_fields.append(field)
2095
2096     for field in param_fields:
2097         c_field_const_type = field.c_field_const_type
2098         if field.type.c_need_serialize and not aux:
2099             c_field_const_type = "const void"
2100         if len(c_field_const_type) > maxtypelen:
2101             maxtypelen = len(c_field_const_type)
2102         if field.type.is_list and not field.type.member.fixed_size():
2103             list_with_var_size_elems = True
2104
2105     _h_setlevel(1)
2106     _c_setlevel(1)
2107     _h('')
2108     _h('/**')
2109     if hasattr(self, "doc") and self.doc:
2110         if self.doc.brief:
2111             _h(' * @brief ' + self.doc.brief)
2112         else:
2113             _h(' * No brief doc yet')
2114
2115     _h(' *')
2116     _h(' * @param c The connection')
2117     param_names = [f.c_field_name for f in param_fields]
2118     if hasattr(self, "doc") and self.doc:
2119         for field in param_fields:
2120             # XXX: hard-coded until we fix xproto.xml
2121             base_func_name = self.c_request_name if not aux else self.c_aux_name
2122             if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2123                 field.enum = 'GC'
2124             elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2125                 field.enum = 'CW'
2126             elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2127                 field.enum = 'CW'
2128             if field.enum:
2129                 # XXX: why the 'xcb' prefix?
2130                 key = ('xcb', field.enum)
2131
2132                 tname = _t(key)
2133                 if namecount[tname] > 1:
2134                     tname = _t(key + ('enum',))
2135                 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2136
2137             if self.doc and field.field_name in self.doc.fields:
2138                 desc = self.doc.fields[field.field_name]
2139                 for name in param_names:
2140                     desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2141                 desc = desc.split("\n")
2142                 desc = [line if line != '' else '\\n' for line in desc]
2143                 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2144             # If there is no documentation yet, we simply don't generate an
2145             # @param tag. Doxygen will then warn about missing documentation.
2146
2147     _h(' * @return A cookie')
2148     _h(' *')
2149
2150     if hasattr(self, "doc") and self.doc:
2151         if self.doc.description:
2152             desc = self.doc.description
2153             for name in param_names:
2154                 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2155             desc = desc.split("\n")
2156             _h(' * ' + "\n * ".join(desc))
2157         else:
2158             _h(' * No description yet')
2159     else:
2160         _h(' * Delivers a request to the X server.')
2161     _h(' *')
2162     if checked:
2163         _h(' * This form can be used only if the request will not cause')
2164         _h(' * a reply to be generated. Any returned error will be')
2165         _h(' * saved for handling by xcb_request_check().')
2166     if unchecked:
2167         _h(' * This form can be used only if the request will cause')
2168         _h(' * a reply to be generated. Any returned error will be')
2169         _h(' * placed in the event queue.')
2170     _h(' */')
2171     _c('')
2172     _hc('%s', cookie_type)
2173
2174     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2175     comma = ',' if len(param_fields) else ');'
2176     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2177     comma = ',' if len(param_fields) else ')'
2178     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2179
2180     func_spacing = ' ' * (len(func_name) + 2)
2181     count = len(param_fields)
2182     for field in param_fields:
2183         count = count - 1
2184         c_field_const_type = field.c_field_const_type
2185         c_pointer = field.c_pointer
2186         if field.type.c_need_serialize and not aux:
2187             c_field_const_type = "const void"
2188             c_pointer = '*'
2189         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2190         comma = ',' if count else ');'
2191         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2192            spacing, c_pointer, field.c_field_name, comma)
2193         comma = ',' if count else ')'
2194         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2195            spacing, c_pointer, field.c_field_name, comma)
2196
2197     count = 2
2198     if not self.c_var_followed_by_fixed_fields:
2199         for field in param_fields:
2200             if not field.type.fixed_size():
2201                 count = count + 2
2202                 if field.type.c_need_serialize:
2203                     # _serialize() keeps track of padding automatically
2204                     count -= 1
2205     dimension = count + 2
2206
2207     _c('{')
2208     _c('    static const xcb_protocol_request_t xcb_req = {')
2209     _c('        /* count */ %d,', count)
2210     _c('        /* ext */ %s,', func_ext_global)
2211     _c('        /* opcode */ %s,', self.c_request_name.upper())
2212     _c('        /* isvoid */ %d', 1 if void else 0)
2213     _c('    };')
2214     _c('')
2215
2216     _c('    struct iovec xcb_parts[%d];', dimension)
2217     _c('    %s xcb_ret;', func_cookie)
2218     _c('    %s xcb_out;', self.c_type)
2219     if self.c_var_followed_by_fixed_fields:
2220         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2221         _c('    void *xcb_aux = 0;')
2222
2223
2224     for idx, f in enumerate(serial_fields):
2225         if aux:
2226             _c('    void *xcb_aux%d = 0;' % (idx))
2227     if list_with_var_size_elems:
2228         _c('    unsigned int i;')
2229         _c('    unsigned int xcb_tmp_len;')
2230         _c('    char *xcb_tmp;')
2231     _c('')
2232     # simple request call tracing
2233 #    _c('    printf("in function %s\\n");' % func_name)
2234
2235     # fixed size fields
2236     for field in wire_fields:
2237         if field.type.fixed_size():
2238             if field.type.is_expr:
2239                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2240             elif field.type.is_pad:
2241                 if field.type.nmemb == 1:
2242                     _c('    xcb_out.%s = 0;', field.c_field_name)
2243                 else:
2244                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2245             else:
2246                 if field.type.nmemb == 1:
2247                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2248                 else:
2249                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2250
2251     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2252         serialize_args = get_serialize_params(context, type_obj,
2253                                               c_field_name,
2254                                               aux_var)[2]
2255         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2256
2257     # calls in order to free dyn. all. memory
2258     free_calls = []
2259
2260     _c('')
2261     if not self.c_var_followed_by_fixed_fields:
2262         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2263         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2264         _c('    xcb_parts[3].iov_base = 0;')
2265         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2266
2267         count = 4
2268
2269         for field in param_fields:
2270             if not field.type.fixed_size():
2271                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2272                 # default: simple cast to char *
2273                 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2274                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2275                     if field.type.is_list:
2276                         if field.type.member.fixed_size():
2277                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2278                                _c_accessor_get_expr(field.type.expr, None),
2279                                field.type.member.c_wiretype)
2280                         else:
2281                             list_length = _c_accessor_get_expr(field.type.expr, None)
2282
2283                             length = ''
2284                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2285                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2286                             _c("    for(i=0; i<%s; i++) {" % list_length)
2287                             _c("        xcb_tmp_len = %s(xcb_tmp);" %
2288                                               (field.type.c_sizeof_name))
2289                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2290                             _c("        xcb_tmp += xcb_tmp_len;")
2291                             _c("    }")
2292                     else:
2293                         # not supposed to happen
2294                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2295                 else:
2296                     if not aux:
2297                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2298                     idx = serial_fields.index(field)
2299                     aux_var = '&xcb_aux%d' % idx
2300                     context = 'serialize' if aux else 'sizeof'
2301                     _c('    xcb_parts[%d].iov_len =', count)
2302                     if aux:
2303                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2304                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2305                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2306                         free_calls.append('    free(xcb_aux%d);' % idx)
2307                     else:
2308                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2309                         func_name = field.type.c_sizeof_name
2310                         _c('      %s (%s);', func_name, serialize_args)
2311
2312                 count += 1
2313                 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2314                     # the _serialize() function keeps track of padding automatically
2315                     _c('    xcb_parts[%d].iov_base = 0;', count)
2316                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2317                     count += 1
2318
2319     # elif self.c_var_followed_by_fixed_fields:
2320     else:
2321         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2322         # request header: opcodes + length
2323         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2324         count += 1
2325         # call _serialize()
2326         buffer_var = '&xcb_aux'
2327         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2328         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2329         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2330         free_calls.append('    free(xcb_aux);')
2331         # no padding necessary - _serialize() keeps track of padding automatically
2332
2333     _c('')
2334     for field in param_fields:
2335         if field.isfd:
2336             _c('    xcb_send_fd(c, %s);', field.c_field_name)
2337
2338     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2339
2340     # free dyn. all. data, if any
2341     for f in free_calls:
2342         _c(f)
2343     _c('    return xcb_ret;')
2344     _c('}')
2345
2346 def _c_reply(self, name):
2347     '''
2348     Declares the function that returns the reply structure.
2349     '''
2350     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2351     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2352     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2353
2354     # check if _unserialize() has to be called for any field
2355     def look_for_special_cases(complex_obj):
2356         unserialize_fields = []
2357         # no unserialize call in case of switch
2358         if not complex_obj.is_switch:
2359             for field in complex_obj.fields:
2360                 # three cases: 1. field with special case
2361                 #              2. container that contains special case field
2362                 #              3. list with special case elements
2363                 if field.type.c_var_followed_by_fixed_fields:
2364                     unserialize_fields.append(field)
2365                 elif field.type.is_container:
2366                     unserialize_fields += look_for_special_cases(field.type)
2367                 elif field.type.is_list:
2368                     if field.type.member.c_var_followed_by_fixed_fields:
2369                         unserialize_fields.append(field)
2370                     if field.type.member.is_container:
2371                         unserialize_fields += look_for_special_cases(field.type.member)
2372         return unserialize_fields
2373
2374     unserialize_fields = look_for_special_cases(self.reply)
2375
2376     _h('')
2377     _h('/**')
2378     _h(' * Return the reply')
2379     _h(' * @param c      The connection')
2380     _h(' * @param cookie The cookie')
2381     _h(' * @param e      The xcb_generic_error_t supplied')
2382     _h(' *')
2383     _h(' * Returns the reply of the request asked by')
2384     _h(' *')
2385     _h(' * The parameter @p e supplied to this function must be NULL if')
2386     _h(' * %s(). is used.', self.c_unchecked_name)
2387     _h(' * Otherwise, it stores the error if any.')
2388     _h(' *')
2389     _h(' * The returned value must be freed by the caller using free().')
2390     _h(' */')
2391     _c('')
2392     _hc('%s *', self.c_reply_type)
2393     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2394     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2395     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2396     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2397     _c('{')
2398
2399     if len(unserialize_fields)>0:
2400         # certain variable size fields need to be unserialized explicitly
2401         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2402            self.c_reply_type, self.c_reply_type)
2403         _c('    int i;')
2404         for field in unserialize_fields:
2405             if field.type.is_list:
2406                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2407                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2408                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2409             else:
2410                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2411         # call _unserialize(), using the reply as source and target buffer
2412         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2413         for field in unserialize_fields:
2414             if field.type.is_list:
2415                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2416                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2417                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2418                    field.c_field_name, field.c_field_name)
2419                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2420                 _c('    }')
2421         # return the transformed reply
2422         _c('    return reply;')
2423
2424     else:
2425         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2426
2427     _c('}')
2428
2429 def _c_reply_has_fds(self):
2430     for field in self.fields:
2431         if field.isfd:
2432             return True
2433     return False
2434
2435 def _c_reply_fds(self, name):
2436     '''
2437     Declares the function that returns fds related to the reply.
2438     '''
2439     spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2440     spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2441     _h('')
2442     _h('/**')
2443     _h(' * Return the reply fds')
2444     _h(' * @param c      The connection')
2445     _h(' * @param reply  The reply')
2446     _h(' *')
2447     _h(' * Returns the array of reply fds of the request asked by')
2448     _h(' *')
2449     _h(' * The returned value must be freed by the caller using free().')
2450     _h(' */')
2451     _c('')
2452     _hc('int *')
2453     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2454     _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2455     _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2456     _c('{')
2457
2458     _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2459
2460     _c('}')
2461
2462
2463 def _c_opcode(name, opcode):
2464     '''
2465     Declares the opcode define for requests, events, and errors.
2466     '''
2467     _h_setlevel(0)
2468     _h('')
2469     _h('/** Opcode for %s. */', _n(name))
2470     _h('#define %s %s', _n(name).upper(), opcode)
2471
2472 def _c_cookie(self, name):
2473     '''
2474     Declares the cookie type for a non-void request.
2475     '''
2476     _h_setlevel(0)
2477     _h('')
2478     _h('/**')
2479     _h(' * @brief %s', self.c_cookie_type)
2480     _h(' **/')
2481     _h('typedef struct %s {', self.c_cookie_type)
2482     _h('    unsigned int sequence; /**<  */')
2483     _h('} %s;', self.c_cookie_type)
2484
2485 def _man_request(self, name, cookie_type, void, aux):
2486     param_fields = [f for f in self.fields if f.visible]
2487
2488     func_name = self.c_request_name if not aux else self.c_aux_name
2489
2490     def create_link(linkname):
2491         name = 'man/%s.%s' % (linkname, section)
2492         if manpaths:
2493             sys.stdout.write(name)
2494         f = open(name, 'w')
2495         f.write('.so man%s/%s.%s' % (section, func_name, section))
2496         f.close()
2497
2498     if manpaths:
2499         sys.stdout.write('man/%s.%s ' % (func_name, section))
2500     # Our CWD is src/, so this will end up in src/man/
2501     f = open('man/%s.%s' % (func_name, section), 'w')
2502     f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2503     # Left-adjust instead of adjusting to both sides
2504     f.write('.ad l\n')
2505     f.write('.SH NAME\n')
2506     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2507     f.write('%s \\- %s\n' % (func_name, brief))
2508     f.write('.SH SYNOPSIS\n')
2509     # Don't split words (hyphenate)
2510     f.write('.hy 0\n')
2511     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2512
2513     # function prototypes
2514     prototype = ''
2515     count = len(param_fields)
2516     for field in param_fields:
2517         count = count - 1
2518         c_field_const_type = field.c_field_const_type
2519         c_pointer = field.c_pointer
2520         if c_pointer == ' ':
2521             c_pointer = ''
2522         if field.type.c_need_serialize and not aux:
2523             c_field_const_type = "const void"
2524             c_pointer = '*'
2525         comma = ', ' if count else ');'
2526         prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2527
2528     f.write('.SS Request function\n')
2529     f.write('.HP\n')
2530     base_func_name = self.c_request_name if not aux else self.c_aux_name
2531     f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2532     create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2533     if not void:
2534         f.write('.PP\n')
2535         f.write('.SS Reply datastructure\n')
2536         f.write('.nf\n')
2537         f.write('.sp\n')
2538         f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2539         struct_fields = []
2540         maxtypelen = 0
2541
2542         for field in self.reply.fields:
2543             if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2544                 continue
2545             if field.wire:
2546                 struct_fields.append(field)
2547
2548         for field in struct_fields:
2549             length = len(field.c_field_type)
2550             # account for '*' pointer_spec
2551             if not field.type.fixed_size():
2552                 length += 1
2553             maxtypelen = max(maxtypelen, length)
2554
2555         def _c_complex_field(self, field, space=''):
2556             if (field.type.fixed_size() or
2557                 # in case of switch with switch children, don't make the field a pointer
2558                 # necessary for unserialize to work
2559                 (self.is_switch and field.type.is_switch)):
2560                 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2561                 f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2562             else:
2563                 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2564                 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2565                 #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2566
2567         if not self.is_switch:
2568             for field in struct_fields:
2569                 _c_complex_field(self, field)
2570         else:
2571             for b in self.bitcases:
2572                 space = ''
2573                 if b.type.has_name:
2574                     space = '    '
2575                 for field in b.type.fields:
2576                     _c_complex_field(self, field, space)
2577                 if b.type.has_name:
2578                     print >> sys.stderr, 'ERROR: New unhandled documentation case'
2579                     pass
2580
2581         f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2582         f.write('.fi\n')
2583
2584         f.write('.SS Reply function\n')
2585         f.write('.HP\n')
2586         f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2587                  '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2588                 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2589         create_link('%s' % self.c_reply_name)
2590
2591         has_accessors = False
2592         for field in self.reply.fields:
2593             if field.type.is_list and not field.type.fixed_size():
2594                 has_accessors = True
2595             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2596                 has_accessors = True
2597
2598         if has_accessors:
2599             f.write('.SS Reply accessors\n')
2600
2601         def _c_accessors_field(self, field):
2602             '''
2603             Declares the accessor functions for a non-list field that follows a variable-length field.
2604             '''
2605             c_type = self.c_type
2606
2607             # special case: switch
2608             switch_obj = self if self.is_switch else None
2609             if self.is_case_or_bitcase:
2610                 switch_obj = self.parents[-1]
2611             if switch_obj is not None:
2612                 c_type = switch_obj.c_type
2613
2614             if field.type.is_simple:
2615                 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2616                 create_link('%s' % field.c_accessor_name)
2617             else:
2618                 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2619                 create_link('%s' % field.c_accessor_name)
2620
2621         def _c_accessors_list(self, field):
2622             '''
2623             Declares the accessor functions for a list field.
2624             Declares a direct-accessor function only if the list members are fixed size.
2625             Declares length and get-iterator functions always.
2626             '''
2627             list = field.type
2628             c_type = self.reply.c_type
2629
2630             # special case: switch
2631             # in case of switch, 2 params have to be supplied to certain accessor functions:
2632             #   1. the anchestor object (request or reply)
2633             #   2. the (anchestor) switch object
2634             # the reason is that switch is either a child of a request/reply or nested in another switch,
2635             # so whenever we need to access a length field, we might need to refer to some anchestor type
2636             switch_obj = self if self.is_switch else None
2637             if self.is_case_or_bitcase:
2638                 switch_obj = self.parents[-1]
2639             if switch_obj is not None:
2640                 c_type = switch_obj.c_type
2641
2642             params = []
2643             fields = {}
2644             parents = self.parents if hasattr(self, 'parents') else [self]
2645             # 'R': parents[0] is always the 'toplevel' container type
2646             params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2647             fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2648             # auxiliary object for 'R' parameters
2649             R_obj = parents[0]
2650
2651             if switch_obj is not None:
2652                 # now look where the fields are defined that are needed to evaluate
2653                 # the switch expr, and store the parent objects in accessor_params and
2654                 # the fields in switch_fields
2655
2656                 # 'S': name for the 'toplevel' switch
2657                 toplevel_switch = parents[1]
2658                 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2659                 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2660
2661                 # initialize prefix for everything "below" S
2662                 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2663                 prefix = [(prefix_str, '->', toplevel_switch)]
2664
2665                 # look for fields in the remaining containers
2666                 for p in parents[2:] + [self]:
2667                     # the separator between parent and child is always '.' here,
2668                     # because of nested switch statements
2669                     if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2670                         prefix.append((p.name[-1], '.', p))
2671                     fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2672
2673                 # auxiliary object for 'S' parameter
2674                 S_obj = parents[1]
2675
2676             if list.member.fixed_size():
2677                 idx = 1 if switch_obj is not None else 0
2678                 f.write('.HP\n')
2679                 f.write('%s *\\fB%s\\fP(%s);\n' %
2680                         (field.c_field_type, field.c_accessor_name, params[idx][0]))
2681                 create_link('%s' % field.c_accessor_name)
2682
2683             f.write('.HP\n')
2684             f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2685                     (field.c_length_name, c_type))
2686             create_link('%s' % field.c_length_name)
2687
2688             if field.type.member.is_simple:
2689                 f.write('.HP\n')
2690                 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2691                         (field.c_end_name, c_type))
2692                 create_link('%s' % field.c_end_name)
2693             else:
2694                 f.write('.HP\n')
2695                 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2696                         (field.c_iterator_type, field.c_iterator_name,
2697                          c_type))
2698                 create_link('%s' % field.c_iterator_name)
2699
2700         for field in self.reply.fields:
2701             if field.type.is_list and not field.type.fixed_size():
2702                 _c_accessors_list(self, field)
2703             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2704                 _c_accessors_field(self, field)
2705
2706
2707     f.write('.br\n')
2708     # Re-enable hyphenation and adjusting to both sides
2709     f.write('.hy 1\n')
2710
2711     # argument reference
2712     f.write('.SH REQUEST ARGUMENTS\n')
2713     f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2714     f.write('The XCB connection to X11.\n')
2715     for field in param_fields:
2716         f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2717         printed_enum = False
2718         # XXX: hard-coded until we fix xproto.xml
2719         if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2720             field.enum = 'GC'
2721         elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2722             field.enum = 'CW'
2723         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2724             field.enum = 'CW'
2725         if hasattr(field, "enum") and field.enum:
2726             # XXX: why the 'xcb' prefix?
2727             key = ('xcb', field.enum)
2728             if key in enums:
2729                 f.write('One of the following values:\n')
2730                 f.write('.RS 1i\n')
2731                 enum = enums[key]
2732                 count = len(enum.values)
2733                 for (enam, eval) in enum.values:
2734                     count = count - 1
2735                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2736                     if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2737                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2738                         f.write('%s\n' % desc)
2739                     else:
2740                         f.write('TODO: NOT YET DOCUMENTED.\n')
2741                 f.write('.RE\n')
2742                 f.write('.RS 1i\n')
2743                 printed_enum = True
2744
2745         if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2746             desc = self.doc.fields[field.field_name]
2747             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2748             if printed_enum:
2749                 f.write('\n')
2750             f.write('%s\n' % desc)
2751         else:
2752             f.write('TODO: NOT YET DOCUMENTED.\n')
2753         if printed_enum:
2754             f.write('.RE\n')
2755
2756     # Reply reference
2757     if not void:
2758         f.write('.SH REPLY FIELDS\n')
2759         # These fields are present in every reply:
2760         f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2761         f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2762                  'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2763                  'be used to tell replies apart from each other.\n') %
2764                  _n(self.reply.name).upper())
2765         f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2766         f.write('The sequence number of the last request processed by the X11 server.\n')
2767         f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2768         f.write('The length of the reply, in words (a word is 4 bytes).\n')
2769         for field in self.reply.fields:
2770             if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2771                 field.c_field_name.startswith('pad')):
2772                 continue
2773
2774             if field.type.is_list and not field.type.fixed_size():
2775                 continue
2776             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2777                 continue
2778             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2779             printed_enum = False
2780             if hasattr(field, "enum") and field.enum:
2781                 # XXX: why the 'xcb' prefix?
2782                 key = ('xcb', field.enum)
2783                 if key in enums:
2784                     f.write('One of the following values:\n')
2785                     f.write('.RS 1i\n')
2786                     enum = enums[key]
2787                     count = len(enum.values)
2788                     for (enam, eval) in enum.values:
2789                         count = count - 1
2790                         f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2791                         if enum.doc and enam in enum.doc.fields:
2792                             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2793                             f.write('%s\n' % desc)
2794                         else:
2795                             f.write('TODO: NOT YET DOCUMENTED.\n')
2796                     f.write('.RE\n')
2797                     f.write('.RS 1i\n')
2798                     printed_enum = True
2799
2800             if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2801                 desc = self.reply.doc.fields[field.field_name]
2802                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2803                 if printed_enum:
2804                     f.write('\n')
2805                 f.write('%s\n' % desc)
2806             else:
2807                 f.write('TODO: NOT YET DOCUMENTED.\n')
2808             if printed_enum:
2809                 f.write('.RE\n')
2810
2811
2812
2813     # text description
2814     f.write('.SH DESCRIPTION\n')
2815     if hasattr(self, "doc") and self.doc and self.doc.description:
2816         desc = self.doc.description
2817         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2818         lines = desc.split('\n')
2819         f.write('\n'.join(lines) + '\n')
2820
2821     f.write('.SH RETURN VALUE\n')
2822     if void:
2823         f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2824                  'have to be handled in the event loop.\n\nIf you want to '
2825                  'handle errors directly with \\fIxcb_request_check\\fP '
2826                  'instead, use \\fI%s_checked\\fP. See '
2827                  '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2828     else:
2829         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2830                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2831                  'handle errors in the event loop instead, use '
2832                  '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2833                  'details.\n') %
2834                 (cookie_type, self.c_reply_name, base_func_name, section))
2835     f.write('.SH ERRORS\n')
2836     if hasattr(self, "doc") and self.doc:
2837         for errtype, errtext in sorted(self.doc.errors.items()):
2838             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2839             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2840             f.write('%s\n' % (errtext))
2841     if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2842         f.write('This request does never generate any errors.\n')
2843     if hasattr(self, "doc") and self.doc and self.doc.example:
2844         f.write('.SH EXAMPLE\n')
2845         f.write('.nf\n')
2846         f.write('.sp\n')
2847         lines = self.doc.example.split('\n')
2848         f.write('\n'.join(lines) + '\n')
2849         f.write('.fi\n')
2850     f.write('.SH SEE ALSO\n')
2851     if hasattr(self, "doc") and self.doc:
2852         see = ['.BR %s (%s)' % ('xcb-requests', section)]
2853         if self.doc.example:
2854             see.append('.BR %s (%s)' % ('xcb-examples', section))
2855         for seename, seetype in sorted(self.doc.see.items()):
2856             if seetype == 'program':
2857                 see.append('.BR %s (1)' % seename)
2858             elif seetype == 'event':
2859                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2860             elif seetype == 'request':
2861                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2862             elif seetype == 'function':
2863                 see.append('.BR %s (%s)' % (seename, section))
2864             else:
2865                 see.append('TODO: %s (type %s)' % (seename, seetype))
2866         f.write(',\n'.join(see) + '\n')
2867     f.write('.SH AUTHOR\n')
2868     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2869     f.close()
2870
2871 def _man_event(self, name):
2872     if manpaths:
2873         sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2874     # Our CWD is src/, so this will end up in src/man/
2875     f = open('man/%s.%s' % (self.c_type, section), 'w')
2876     f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2877     # Left-adjust instead of adjusting to both sides
2878     f.write('.ad l\n')
2879     f.write('.SH NAME\n')
2880     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2881     f.write('%s \\- %s\n' % (self.c_type, brief))
2882     f.write('.SH SYNOPSIS\n')
2883     # Don't split words (hyphenate)
2884     f.write('.hy 0\n')
2885     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2886
2887     f.write('.PP\n')
2888     f.write('.SS Event datastructure\n')
2889     f.write('.nf\n')
2890     f.write('.sp\n')
2891     f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2892     struct_fields = []
2893     maxtypelen = 0
2894
2895     for field in self.fields:
2896         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2897             continue
2898         if field.wire:
2899             struct_fields.append(field)
2900
2901     for field in struct_fields:
2902         length = len(field.c_field_type)
2903         # account for '*' pointer_spec
2904         if not field.type.fixed_size():
2905             length += 1
2906         maxtypelen = max(maxtypelen, length)
2907
2908     def _c_complex_field(self, field, space=''):
2909         if (field.type.fixed_size() or
2910             # in case of switch with switch children, don't make the field a pointer
2911             # necessary for unserialize to work
2912             (self.is_switch and field.type.is_switch)):
2913             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2914             f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2915         else:
2916             print >> sys.stderr, 'ERROR: New unhandled documentation case'
2917
2918     if not self.is_switch:
2919         for field in struct_fields:
2920             _c_complex_field(self, field)
2921     else:
2922         for b in self.bitcases:
2923             space = ''
2924             if b.type.has_name:
2925                 space = '    '
2926             for field in b.type.fields:
2927                 _c_complex_field(self, field, space)
2928             if b.type.has_name:
2929                 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2930                 pass
2931
2932     f.write('} \\fB%s\\fP;\n' % self.c_type)
2933     f.write('.fi\n')
2934
2935
2936     f.write('.br\n')
2937     # Re-enable hyphenation and adjusting to both sides
2938     f.write('.hy 1\n')
2939
2940     # argument reference
2941     f.write('.SH EVENT FIELDS\n')
2942     f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2943     f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2944              'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2945              'to tell events apart from each other.\n') % _n(name).upper())
2946     f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2947     f.write('The sequence number of the last request processed by the X11 server.\n')
2948
2949     if not self.is_switch:
2950         for field in struct_fields:
2951             # Skip the fields which every event has, we already documented
2952             # them (see above).
2953             if field.c_field_name in ('response_type', 'sequence'):
2954                 continue
2955             if isinstance(field.type, PadType):
2956                 continue
2957             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2958             if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2959                 desc = self.doc.fields[field.field_name]
2960                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2961                 f.write('%s\n' % desc)
2962             else:
2963                 f.write('NOT YET DOCUMENTED.\n')
2964
2965     # text description
2966     f.write('.SH DESCRIPTION\n')
2967     if hasattr(self, "doc") and self.doc and self.doc.description:
2968         desc = self.doc.description
2969         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2970         lines = desc.split('\n')
2971         f.write('\n'.join(lines) + '\n')
2972
2973     if hasattr(self, "doc") and self.doc and self.doc.example:
2974         f.write('.SH EXAMPLE\n')
2975         f.write('.nf\n')
2976         f.write('.sp\n')
2977         lines = self.doc.example.split('\n')
2978         f.write('\n'.join(lines) + '\n')
2979         f.write('.fi\n')
2980     f.write('.SH SEE ALSO\n')
2981     if hasattr(self, "doc") and self.doc:
2982         see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2983         if self.doc.example:
2984             see.append('.BR %s (%s)' % ('xcb-examples', section))
2985         for seename, seetype in sorted(self.doc.see.items()):
2986             if seetype == 'program':
2987                 see.append('.BR %s (1)' % seename)
2988             elif seetype == 'event':
2989                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2990             elif seetype == 'request':
2991                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2992             elif seetype == 'function':
2993                 see.append('.BR %s (%s)' % (seename, section))
2994             else:
2995                 see.append('TODO: %s (type %s)' % (seename, seetype))
2996         f.write(',\n'.join(see) + '\n')
2997     f.write('.SH AUTHOR\n')
2998     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2999     f.close()
3000
3001
3002 def c_request(self, name):
3003     '''
3004     Exported function that handles request declarations.
3005     '''
3006     _c_type_setup(self, name, ('request',))
3007
3008     if self.reply:
3009         # Cookie type declaration
3010         _c_cookie(self, name)
3011
3012     # Opcode define
3013     _c_opcode(name, self.opcode)
3014
3015     # Request structure declaration
3016     _c_complex(self)
3017
3018     if self.reply:
3019         _c_type_setup(self.reply, name, ('reply',))
3020         # Reply structure definition
3021         _c_complex(self.reply)
3022         # Request prototypes
3023         has_fds = _c_reply_has_fds(self.reply)
3024         _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3025         _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3026         if self.c_need_aux:
3027             _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3028             _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3029         # Reply accessors
3030         _c_accessors(self.reply, name + ('reply',), name)
3031         _c_reply(self, name)
3032         if has_fds:
3033             _c_reply_fds(self, name)
3034     else:
3035         # Request prototypes
3036         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3037         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3038         if self.c_need_aux:
3039             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3040             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3041
3042     # We generate the manpage afterwards because _c_type_setup has been called.
3043     # TODO: what about aux helpers?
3044     cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3045     _man_request(self, name, cookie_type, not self.reply, False)
3046
3047 def c_event(self, name):
3048     '''
3049     Exported function that handles event declarations.
3050     '''
3051
3052     # The generic event structure xcb_ge_event_t has the full_sequence field
3053     # at the 32byte boundary. That's why we've to inject this field into GE
3054     # events while generating the structure for them. Otherwise we would read
3055     # garbage (the internal full_sequence) when accessing normal event fields
3056     # there.
3057     force_packed = False
3058     if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3059         event_size = 0
3060         for field in self.fields:
3061             if field.type.size != None and field.type.nmemb != None:
3062                 event_size += field.type.size * field.type.nmemb
3063             if event_size == 32:
3064                 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3065                 idx = self.fields.index(field)
3066                 self.fields.insert(idx + 1, full_sequence)
3067
3068                 # If the event contains any 64-bit extended fields, they need
3069                 # to remain aligned on a 64-bit boundary.  Adding full_sequence
3070                 # would normally break that; force the struct to be packed.
3071                 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3072                 break
3073
3074     _c_type_setup(self, name, ('event',))
3075
3076     # Opcode define
3077     _c_opcode(name, self.opcodes[name])
3078
3079     if self.name == name:
3080         # Structure definition
3081         _c_complex(self, force_packed)
3082     else:
3083         # Typedef
3084         _h('')
3085         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3086
3087     _man_event(self, name)
3088
3089 def c_error(self, name):
3090     '''
3091     Exported function that handles error declarations.
3092     '''
3093     _c_type_setup(self, name, ('error',))
3094
3095     # Opcode define
3096     _c_opcode(name, self.opcodes[name])
3097
3098     if self.name == name:
3099         # Structure definition
3100         _c_complex(self)
3101     else:
3102         # Typedef
3103         _h('')
3104         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3105
3106
3107 # Main routine starts here
3108
3109 # Must create an "output" dictionary before any xcbgen imports.
3110 output = {'open'    : c_open,
3111           'close'   : c_close,
3112           'simple'  : c_simple,
3113           'enum'    : c_enum,
3114           'struct'  : c_struct,
3115           'union'   : c_union,
3116           'request' : c_request,
3117           'event'   : c_event,
3118           'error'   : c_error,
3119           }
3120
3121 # Boilerplate below this point
3122
3123 # Check for the argument that specifies path to the xcbgen python package.
3124 try:
3125     opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3126 except getopt.GetoptError as err:
3127     print(err)
3128     print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3129     sys.exit(1)
3130
3131 for (opt, arg) in opts:
3132     if opt == '-c':
3133         center_footer=arg
3134     if opt == '-l':
3135         left_footer=arg
3136     if opt == '-s':
3137         section=arg
3138     if opt == '-p':
3139         sys.path.insert(1, arg)
3140     elif opt == '-m':
3141         manpaths = True
3142         sys.stdout.write('man_MANS = ')
3143
3144 # Import the module class
3145 try:
3146     from xcbgen.state import Module
3147     from xcbgen.xtypes import *
3148 except ImportError:
3149     print('''
3150 Failed to load the xcbgen Python package!
3151 Make sure that xcb/proto installed it on your Python path.
3152 If not, you will need to create a .pth file or define $PYTHONPATH
3153 to extend the path.
3154 Refer to the README file in xcb/proto for more info.
3155 ''')
3156     raise
3157
3158 # Ensure the man subdirectory exists
3159 try:
3160     os.mkdir('man')
3161 except OSError as e:
3162     if e.errno != errno.EEXIST:
3163         raise
3164
3165 # Parse the xml header
3166 module = Module(args[0], output)
3167
3168 # Build type-registry and resolve type dependencies
3169 module.register()
3170 module.resolve()
3171
3172 # Output the code
3173 module.generate()