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