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