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