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