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