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