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