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