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