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