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