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