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