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