Fix _unserialize of reply headers
[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 _c_accessors_field(self, field):
1427     '''
1428     Declares the accessor functions for a non-list field that follows a variable-length field.
1429     '''
1430     c_type = self.c_type
1431
1432     # special case: switch
1433     switch_obj = self if self.is_switch else None
1434     if self.is_bitcase:
1435         switch_obj = self.parents[-1]
1436     if switch_obj is not None:
1437         c_type = switch_obj.c_type
1438
1439     if field.type.is_simple:
1440         _hc('')
1441         _hc('')
1442         _hc('/*****************************************************************************')
1443         _hc(' ** ')
1444         _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1445         _hc(' ** ')
1446         _hc(' ** @param const %s *R', c_type)
1447         _hc(' ** @returns %s', field.c_field_type)
1448         _hc(' **')
1449         _hc(' *****************************************************************************/')
1450         _hc(' ')
1451         _hc('%s', field.c_field_type)
1452         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1453         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1454         _c('{')
1455         if field.prev_varsized_field is None:
1456             _c('    return (%s *) (R + 1);', field.c_field_type)
1457         else:
1458             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1459             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1460                field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1461         _c('}')
1462     else:
1463         _hc('')
1464         _hc('')
1465         _hc('/*****************************************************************************')
1466         _hc(' **')
1467         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1468         _hc(' ** ')
1469         _hc(' ** @param const %s *R', c_type)
1470         _hc(' ** @returns %s *', field.c_field_type)
1471         _hc(' **')
1472         _hc(' *****************************************************************************/')
1473         _hc(' ')
1474         if field.type.is_switch and switch_obj is None:
1475             return_type = 'void *'
1476         else:
1477             return_type = '%s *' % field.c_field_type
1478
1479         _hc(return_type)
1480         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1481         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1482         _c('{')
1483         if field.prev_varsized_field is None:
1484             _c('    return (%s) (R + 1);', return_type)
1485             # note: the special case 'variable fields followed by fixed size fields'
1486             #       is not of any consequence here, since the ordering gets 
1487             #       'corrected' in the reply function
1488         else:
1489             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1490             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1491                return_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1492         _c('}')
1493
1494     
1495 def _c_accessors_list(self, field):
1496     '''
1497     Declares the accessor functions for a list field.
1498     Declares a direct-accessor function only if the list members are fixed size.
1499     Declares length and get-iterator functions always.
1500     '''
1501     list = field.type
1502     c_type = self.c_type
1503
1504     # special case: switch
1505     # in case of switch, 2 params have to be supplied to certain accessor functions:
1506     #   1. the anchestor object (request or reply)
1507     #   2. the (anchestor) switch object
1508     # the reason is that switch is either a child of a request/reply or nested in another switch, 
1509     # so whenever we need to access a length field, we might need to refer to some anchestor type
1510     switch_obj = self if self.is_switch else None
1511     if self.is_bitcase:
1512         switch_obj = self.parents[-1]
1513     if switch_obj is not None:
1514         c_type = switch_obj.c_type
1515
1516     params = []
1517     fields = {}
1518     parents = self.parents if hasattr(self, 'parents') else [self]
1519     # 'R': parents[0] is always the 'toplevel' container type 
1520     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1521     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1522     # auxiliary object for 'R' parameters
1523     R_obj = parents[0]
1524
1525     if switch_obj is not None:
1526         # now look where the fields are defined that are needed to evaluate 
1527         # the switch expr, and store the parent objects in accessor_params and
1528         # the fields in switch_fields
1529
1530         # 'S': name for the 'toplevel' switch
1531         toplevel_switch = parents[1]
1532         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1533         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1534
1535         # initialize prefix for everything "below" S
1536         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1537         prefix = [(prefix_str, '->', toplevel_switch)]
1538
1539         # look for fields in the remaining containers
1540         for p in parents[2:] + [self]:
1541             # the separator between parent and child is always '.' here, 
1542             # because of nested switch statements
1543             if not p.is_bitcase or (p.is_bitcase and p.has_name):
1544                 prefix.append((p.name[-1], '.', p))
1545             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1546
1547         # auxiliary object for 'S' parameter
1548         S_obj = parents[1]
1549
1550     _h_setlevel(1)
1551     _c_setlevel(1)
1552     if list.member.fixed_size():
1553         idx = 1 if switch_obj is not None else 0
1554         _hc('')
1555         _hc('')
1556         _hc('/*****************************************************************************')
1557         _hc(' **')
1558         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1559         _hc(' ** ')
1560         _hc(' ** @param %s', params[idx][0])
1561         _hc(' ** @returns %s *', field.c_field_type)
1562         _hc(' **')
1563         _hc(' *****************************************************************************/')
1564         _hc(' ')
1565         _hc('%s *', field.c_field_type)
1566
1567         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1568         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1569
1570         _c('{')
1571         if switch_obj is not None:
1572             _c('    return %s;', fields[field.c_field_name][0])
1573         elif field.prev_varsized_field is None:
1574             _c('    return (%s *) (R + 1);', field.c_field_type)
1575         else:
1576             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1577             _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1578                field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1579         _c('}')
1580
1581     _hc('')
1582     _hc('')
1583     _hc('/*****************************************************************************')
1584     _hc(' **')
1585     _hc(' ** int %s', field.c_length_name)
1586     _hc(' ** ')
1587     _hc(' ** @param const %s *R', c_type)
1588     _hc(' ** @returns int')
1589     _hc(' **')
1590     _hc(' *****************************************************************************/')
1591     _hc(' ')
1592     _hc('int')
1593     if switch_obj is not None:
1594         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1595         spacing = ' '*(len(field.c_length_name)+2)
1596         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1597         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1598         length = _c_accessor_get_expr(field.type.expr, fields)
1599     else:
1600         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1601         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1602         length = _c_accessor_get_expr(field.type.expr, fields)
1603     _c('{')
1604     _c('    return %s;', length)
1605     _c('}')
1606
1607     if field.type.member.is_simple:
1608         _hc('')
1609         _hc('')
1610         _hc('/*****************************************************************************')
1611         _hc(' **')
1612         _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1613         _hc(' ** ')
1614         _hc(' ** @param const %s *R', c_type)
1615         _hc(' ** @returns xcb_generic_iterator_t')
1616         _hc(' **')
1617         _hc(' *****************************************************************************/')
1618         _hc(' ')
1619         _hc('xcb_generic_iterator_t')
1620         if switch_obj is not None:
1621             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1622             spacing = ' '*(len(field.c_end_name)+2)
1623             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1624             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1625         else:
1626             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1627             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1628         _c('{')
1629         _c('    xcb_generic_iterator_t i;')
1630         
1631         param = 'R' if switch_obj is None else 'S'
1632         if switch_obj is not None:
1633             _c('    i.data = %s + %s;', fields[field.c_field_name][0], 
1634                _c_accessor_get_expr(field.type.expr, fields))
1635         elif field.prev_varsized_field == None:
1636             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, 
1637                _c_accessor_get_expr(field.type.expr, fields))
1638         else:
1639             _c('    xcb_generic_iterator_t child = %s;', 
1640                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1641             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, 
1642                _c_accessor_get_expr(field.type.expr, fields))
1643
1644         _c('    i.rem = 0;')
1645         _c('    i.index = (char *) i.data - (char *) %s;', param)
1646         _c('    return i;')
1647         _c('}')
1648
1649     else:
1650         _hc('')
1651         _hc('')
1652         _hc('/*****************************************************************************')
1653         _hc(' **')
1654         _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1655         _hc(' ** ')
1656         _hc(' ** @param const %s *R', c_type)
1657         _hc(' ** @returns %s', field.c_iterator_type)
1658         _hc(' **')
1659         _hc(' *****************************************************************************/')
1660         _hc(' ')
1661
1662         _hc('%s', field.c_iterator_type)
1663         if switch_obj is not None:
1664             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1665             spacing = ' '*(len(field.c_iterator_name)+2)
1666             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1667             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1668         else:
1669             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1670             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1671         _c('{')
1672         _c('    %s i;', field.c_iterator_type)
1673
1674         if switch_obj is not None:
1675             _c('    i.data = %s;', fields[field.c_field_name][0])
1676             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1677         elif field.prev_varsized_field == None:
1678             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1679         else:
1680             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1681             _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', 
1682                field.c_field_type, field.c_field_type)
1683         if switch_obj is None:
1684             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1685         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1686         _c('    return i;')
1687         _c('}')
1688
1689 def _c_accessors(self, name, base):
1690     '''
1691     Declares the accessor functions for the fields of a structure.
1692     '''
1693     # no accessors for switch itself - 
1694     # switch always needs to be unpacked explicitly
1695 #    if self.is_switch:
1696 #        pass
1697 #    else:
1698     if True:
1699         for field in self.fields:
1700             if field.type.is_list and not field.type.fixed_size():
1701                 _c_accessors_list(self, field)
1702             elif field.prev_varsized_field is not None or not field.type.fixed_size():
1703                 _c_accessors_field(self, field)
1704
1705 def c_simple(self, name):
1706     '''
1707     Exported function that handles cardinal type declarations.
1708     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1709     '''
1710     _c_type_setup(self, name, ())
1711
1712     if (self.name != name):
1713         # Typedef
1714         _h_setlevel(0)
1715         my_name = _t(name)
1716         _h('')
1717         _h('typedef %s %s;', _t(self.name), my_name)
1718
1719         # Iterator
1720         _c_iterator(self, name)
1721
1722 def _c_complex(self):
1723     '''
1724     Helper function for handling all structure types.
1725     Called for all structs, requests, replies, events, errors.
1726     '''
1727     _h_setlevel(0)
1728     _h('')
1729     _h('/**')
1730     _h(' * @brief %s', self.c_type)
1731     _h(' **/')
1732     _h('typedef %s %s {', self.c_container, self.c_type)
1733
1734     struct_fields = []
1735     maxtypelen = 0
1736
1737     varfield = None
1738     for field in self.fields:
1739         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1740             varfield = field.c_field_name
1741             continue
1742         if field.wire:
1743             struct_fields.append(field)
1744     
1745     for field in struct_fields:
1746         length = len(field.c_field_type)
1747         # account for '*' pointer_spec
1748         if not field.type.fixed_size():
1749             length += 1
1750         maxtypelen = max(maxtypelen, length)
1751
1752     def _c_complex_field(self, field, space=''):
1753         if (field.type.fixed_size() or 
1754             # in case of switch with switch children, don't make the field a pointer
1755             # necessary for unserialize to work
1756             (self.is_switch and field.type.is_switch)):
1757             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1758             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1759         else:
1760             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1761             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1762
1763     if not self.is_switch:
1764         for field in struct_fields:
1765             _c_complex_field(self, field)
1766     else:
1767         for b in self.bitcases:
1768             space = ''
1769             if b.type.has_name:
1770                 _h('    struct _%s {', b.c_field_name)
1771                 space = '    '
1772             for field in b.type.fields:
1773                 _c_complex_field(self, field, space)
1774             if b.type.has_name:
1775                 _h('    } %s;', b.c_field_name)
1776
1777     _h('} %s;', self.c_type)
1778
1779 def c_struct(self, name):
1780     '''
1781     Exported function that handles structure declarations.
1782     '''
1783     _c_type_setup(self, name, ())
1784     _c_complex(self)
1785     _c_accessors(self, name, name)
1786     _c_iterator(self, name)
1787
1788 def c_union(self, name):
1789     '''
1790     Exported function that handles union declarations.
1791     '''
1792     _c_type_setup(self, name, ())
1793     _c_complex(self)
1794     _c_iterator(self, name)
1795
1796 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1797     '''
1798     Declares a request function.
1799     '''
1800
1801     # Four stunningly confusing possibilities here:
1802     #
1803     #   Void            Non-void
1804     # ------------------------------
1805     # "req"            "req"
1806     # 0 flag           CHECKED flag   Normal Mode
1807     # void_cookie      req_cookie
1808     # ------------------------------
1809     # "req_checked"    "req_unchecked"
1810     # CHECKED flag     0 flag         Abnormal Mode
1811     # void_cookie      req_cookie
1812     # ------------------------------
1813
1814
1815     # Whether we are _checked or _unchecked
1816     checked = void and not regular
1817     unchecked = not void and not regular
1818
1819     # What kind of cookie we return
1820     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1821
1822     # What flag is passed to xcb_request
1823     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1824
1825     # Global extension id variable or NULL for xproto
1826     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1827
1828     # What our function name is
1829     func_name = self.c_request_name if not aux else self.c_aux_name
1830     if checked:
1831         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1832     if unchecked:
1833         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1834
1835     param_fields = []
1836     wire_fields = []
1837     maxtypelen = len('xcb_connection_t')
1838     serial_fields = []
1839     # special case: list with variable size elements
1840     list_with_var_size_elems = False
1841
1842     for field in self.fields:
1843         if field.visible:
1844             # The field should appear as a call parameter
1845             param_fields.append(field)
1846         if field.wire and not field.auto:
1847             # We need to set the field up in the structure
1848             wire_fields.append(field)
1849         if field.type.need_serialize or field.type.need_sizeof:
1850             serial_fields.append(field)
1851         
1852     for field in param_fields:
1853         c_field_const_type = field.c_field_const_type 
1854         if field.type.need_serialize and not aux:
1855             c_field_const_type = "const void"
1856         if len(c_field_const_type) > maxtypelen:
1857             maxtypelen = len(c_field_const_type)
1858         if field.type.is_list and not field.type.member.fixed_size():
1859             list_with_var_size_elems = True
1860
1861     _h_setlevel(1)
1862     _c_setlevel(1)
1863     _h('')
1864     _h('/**')
1865     _h(' * Delivers a request to the X server')
1866     _h(' * @param c The connection')
1867     _h(' * @return A cookie')
1868     _h(' *')
1869     _h(' * Delivers a request to the X server.')
1870     _h(' * ')
1871     if checked:
1872         _h(' * This form can be used only if the request will not cause')
1873         _h(' * a reply to be generated. Any returned error will be')
1874         _h(' * saved for handling by xcb_request_check().')
1875     if unchecked:
1876         _h(' * This form can be used only if the request will cause')
1877         _h(' * a reply to be generated. Any returned error will be')
1878         _h(' * placed in the event queue.')
1879     _h(' */')
1880     _c('')
1881     _hc('')
1882     _hc('/*****************************************************************************')
1883     _hc(' **')
1884     _hc(' ** %s %s', cookie_type, func_name)
1885     _hc(' ** ')
1886
1887     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1888     _hc(' ** @param xcb_connection_t%s *c', spacing)
1889
1890     for field in param_fields:
1891         c_field_const_type = field.c_field_const_type 
1892         if field.type.need_serialize and not aux:
1893             c_field_const_type = "const void"
1894         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1895         _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1896
1897     _hc(' ** @returns %s', cookie_type)
1898     _hc(' **')
1899     _hc(' *****************************************************************************/')
1900     _hc(' ')
1901     _hc('%s', cookie_type)
1902
1903     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1904     comma = ',' if len(param_fields) else ');'
1905     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1906     comma = ',' if len(param_fields) else ')'
1907     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1908
1909     func_spacing = ' ' * (len(func_name) + 2)
1910     count = len(param_fields)
1911     for field in param_fields:
1912         count = count - 1
1913         c_field_const_type = field.c_field_const_type 
1914         c_pointer = field.c_pointer
1915         if field.type.need_serialize and not aux:
1916             c_field_const_type = "const void"
1917             c_pointer = '*'
1918         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1919         comma = ',' if count else ');'
1920         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1921            spacing, c_pointer, field.c_field_name, comma)
1922         comma = ',' if count else ')'
1923         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1924            spacing, c_pointer, field.c_field_name, comma)
1925
1926     count = 2
1927     if not self.var_followed_by_fixed_fields:
1928         for field in param_fields:
1929             if not field.type.fixed_size():
1930                 count = count + 2
1931                 if field.type.need_serialize:
1932                     # _serialize() keeps track of padding automatically
1933                     count -= 1
1934     dimension = count + 2
1935
1936     _c('{')
1937     _c('    static const xcb_protocol_request_t xcb_req = {')
1938     _c('        /* count */ %d,', count)
1939     _c('        /* ext */ %s,', func_ext_global)
1940     _c('        /* opcode */ %s,', self.c_request_name.upper())
1941     _c('        /* isvoid */ %d', 1 if void else 0)
1942     _c('    };')
1943     _c('    ')
1944
1945     _c('    struct iovec xcb_parts[%d];', dimension)
1946     _c('    %s xcb_ret;', func_cookie)
1947     _c('    %s xcb_out;', self.c_type)
1948     if self.var_followed_by_fixed_fields:
1949         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
1950         _c('    void *xcb_aux = 0;')
1951         
1952
1953     for idx, f in enumerate(serial_fields):
1954         if aux:
1955             _c('    void *xcb_aux%d = 0;' % (idx))
1956     if list_with_var_size_elems:
1957         _c('    unsigned int i;')
1958         _c('    unsigned int xcb_tmp_len;')
1959         _c('    char *xcb_tmp;')
1960     _c('    ')
1961     # simple request call tracing
1962 #    _c('    printf("in function %s\\n");' % func_name)     
1963  
1964     # fixed size fields
1965     for field in wire_fields:
1966         if field.type.fixed_size():
1967             if field.type.is_expr:
1968                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
1969             elif field.type.is_pad:
1970                 if field.type.nmemb == 1:
1971                     _c('    xcb_out.%s = 0;', field.c_field_name)
1972                 else:
1973                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
1974             else:
1975                 if field.type.nmemb == 1:
1976                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
1977                 else:
1978                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
1979
1980     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
1981         serialize_args = get_serialize_params(context, type_obj, 
1982                                               c_field_name, 
1983                                               aux_var)[2]
1984         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
1985
1986     # calls in order to free dyn. all. memory
1987     free_calls = []
1988
1989     _c('    ')
1990     if not self.var_followed_by_fixed_fields:
1991         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
1992         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
1993         _c('    xcb_parts[3].iov_base = 0;')
1994         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
1995
1996         count = 4
1997
1998         for field in param_fields:
1999             if not field.type.fixed_size():
2000                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2001                 # default: simple cast to char *
2002                 if not field.type.need_serialize and not field.type.need_sizeof:
2003                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2004                     if field.type.is_list:
2005                         if field.type.member.fixed_size():
2006                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 
2007                                _c_accessor_get_expr(field.type.expr, None), 
2008                                field.type.member.c_wiretype)
2009                         else:
2010                             list_length = _c_accessor_get_expr(field.type.expr, None)
2011     
2012                             length = ''
2013                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2014                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2015                             _c("    for(i=0; i<%s; i++) {" % list_length)
2016                             _c("        xcb_tmp_len = %s(xcb_tmp);" % 
2017                                               (field.type.c_sizeof_name))
2018                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2019                             _c("        xcb_tmp += xcb_tmp_len;")
2020                             _c("    }")                        
2021                     else:
2022                         # not supposed to happen
2023                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2024                 else:
2025                     if not aux:
2026                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2027                     idx = serial_fields.index(field)
2028                     aux_var = '&xcb_aux%d' % idx
2029                     context = 'serialize' if aux else 'sizeof'
2030                     _c('    xcb_parts[%d].iov_len = ', count)
2031                     if aux:
2032                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2033                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2034                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2035                         free_calls.append('    free(xcb_aux%d);' % idx)
2036                     else:
2037                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2038                         func_name = field.type.c_sizeof_name
2039                         _c('      %s (%s);', func_name, serialize_args)
2040
2041                 count += 1
2042                 if not (field.type.need_serialize or field.type.need_sizeof):
2043                     # the _serialize() function keeps track of padding automatically
2044                     _c('    xcb_parts[%d].iov_base = 0;', count)
2045                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2046                     count += 1
2047
2048     # elif self.var_followed_by_fixed_fields:
2049     else:
2050         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2051         # request header: opcodes + length
2052         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);') 
2053         count += 1
2054         # call _serialize()
2055         buffer_var = '&xcb_aux'
2056         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2057         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2058         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2059         free_calls.append('    free(xcb_aux);')
2060         # no padding necessary - _serialize() keeps track of padding automatically
2061
2062     _c('    ')
2063     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2064     
2065     # free dyn. all. data, if any
2066     for f in free_calls:
2067         _c(f)
2068     _c('    return xcb_ret;')
2069     _c('}')
2070
2071 def _c_reply(self, name):
2072     '''
2073     Declares the function that returns the reply structure.
2074     '''
2075     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2076     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2077     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2078     
2079     # check if _unserialize() has to be called for any field
2080     def look_for_special_cases(complex_obj):
2081         unserialize_fields = []
2082         # no unserialize call in case of switch
2083         if not complex_obj.is_switch:
2084             for field in complex_obj.fields:
2085                 # three cases: 1. field with special case
2086                 #              2. container that contains special case field
2087                 #              3. list with special case elements
2088                 if field.type.var_followed_by_fixed_fields:
2089                     unserialize_fields.append(field)
2090                 elif field.type.is_container:
2091                     unserialize_fields += look_for_special_cases(field.type)
2092                 elif field.type.is_list:
2093                     if field.type.member.var_followed_by_fixed_fields:
2094                         unserialize_fields.append(field)
2095                     if field.type.member.is_container:
2096                         unserialize_fields += look_for_special_cases(field.type.member)
2097         return unserialize_fields
2098     
2099     unserialize_fields = look_for_special_cases(self.reply)
2100     
2101     _h('')
2102     _h('/**')
2103     _h(' * Return the reply')
2104     _h(' * @param c      The connection')
2105     _h(' * @param cookie The cookie')
2106     _h(' * @param e      The xcb_generic_error_t supplied')
2107     _h(' *')
2108     _h(' * Returns the reply of the request asked by')
2109     _h(' * ')
2110     _h(' * The parameter @p e supplied to this function must be NULL if')
2111     _h(' * %s(). is used.', self.c_unchecked_name)
2112     _h(' * Otherwise, it stores the error if any.')
2113     _h(' *')
2114     _h(' * The returned value must be freed by the caller using free().')
2115     _h(' */')
2116     _c('')
2117     _hc('')
2118     _hc('/*****************************************************************************')
2119     _hc(' **')
2120     _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2121     _hc(' ** ')
2122     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2123     _hc(' ** @param %s   cookie', self.c_cookie_type)
2124     _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2125     _hc(' ** @returns %s *', self.c_reply_type)
2126     _hc(' **')
2127     _hc(' *****************************************************************************/')
2128     _hc(' ')
2129     _hc('%s *', self.c_reply_type)
2130     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2131     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2132     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2133     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2134     _c('{')
2135     
2136     if len(unserialize_fields)>0:
2137         # certain variable size fields need to be unserialized explicitly
2138         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', 
2139            self.c_reply_type, self.c_reply_type)
2140         _c('    int i;')
2141         for field in unserialize_fields:
2142             if field.type.is_list:
2143                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2144                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2145                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2146             else:
2147                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2148         # call _unserialize(), using the reply as source and target buffer
2149         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2150         for field in unserialize_fields:
2151             if field.type.is_list:
2152                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2153                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2154                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name, 
2155                    field.c_field_name, field.c_field_name)
2156                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2157                 _c('    }')
2158         # return the transformed reply
2159         _c('    return reply;')
2160     
2161     else:
2162         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2163
2164     _c('}')
2165
2166 def _c_opcode(name, opcode):
2167     '''
2168     Declares the opcode define for requests, events, and errors.
2169     '''
2170     _h_setlevel(0)
2171     _h('')
2172     _h('/** Opcode for %s. */', _n(name))
2173     _h('#define %s %s', _n(name).upper(), opcode)
2174     
2175 def _c_cookie(self, name):
2176     '''
2177     Declares the cookie type for a non-void request.
2178     '''
2179     _h_setlevel(0)
2180     _h('')
2181     _h('/**')
2182     _h(' * @brief %s', self.c_cookie_type)
2183     _h(' **/')
2184     _h('typedef struct %s {', self.c_cookie_type)
2185     _h('    unsigned int sequence; /**<  */')
2186     _h('} %s;', self.c_cookie_type)
2187
2188 def c_request(self, name):
2189     '''
2190     Exported function that handles request declarations.
2191     '''
2192     _c_type_setup(self, name, ('request',))
2193
2194     if self.reply:
2195         # Cookie type declaration
2196         _c_cookie(self, name)
2197
2198     # Opcode define
2199     _c_opcode(name, self.opcode)
2200
2201     # Request structure declaration
2202     _c_complex(self)
2203
2204     if self.reply:
2205         _c_type_setup(self.reply, name, ('reply',))
2206         # Reply structure definition
2207         _c_complex(self.reply)
2208         # Request prototypes
2209         _c_request_helper(self, name, self.c_cookie_type, False, True)
2210         _c_request_helper(self, name, self.c_cookie_type, False, False)
2211         if self.need_aux:
2212             _c_request_helper(self, name, self.c_cookie_type, False, True, True)
2213             _c_request_helper(self, name, self.c_cookie_type, False, False, True)
2214         # Reply accessors
2215         _c_accessors(self.reply, name + ('reply',), name)
2216         _c_reply(self, name)
2217     else:
2218         # Request prototypes
2219         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2220         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2221         if self.need_aux:
2222             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2223             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2224
2225
2226 def c_event(self, name):
2227     '''
2228     Exported function that handles event declarations.
2229     '''
2230     _c_type_setup(self, name, ('event',))
2231
2232     # Opcode define
2233     _c_opcode(name, self.opcodes[name])
2234
2235     if self.name == name:
2236         # Structure definition
2237         _c_complex(self)
2238     else:
2239         # Typedef
2240         _h('')
2241         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2242
2243 def c_error(self, name):
2244     '''
2245     Exported function that handles error declarations.
2246     '''
2247     _c_type_setup(self, name, ('error',))
2248
2249     # Opcode define
2250     _c_opcode(name, self.opcodes[name])
2251
2252     if self.name == name:
2253         # Structure definition
2254         _c_complex(self)
2255     else:
2256         # Typedef
2257         _h('')
2258         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2259
2260
2261 # Main routine starts here
2262
2263 # Must create an "output" dictionary before any xcbgen imports.
2264 output = {'open'    : c_open,
2265           'close'   : c_close,
2266           'simple'  : c_simple,
2267           'enum'    : c_enum,
2268           'struct'  : c_struct,
2269           'union'   : c_union,
2270           'request' : c_request,
2271           'event'   : c_event,
2272           'error'   : c_error, 
2273           }
2274
2275 # Boilerplate below this point
2276
2277 # Check for the argument that specifies path to the xcbgen python package.
2278 try:
2279     opts, args = getopt.getopt(sys.argv[1:], 'p:')
2280 except getopt.GetoptError, err:
2281     print str(err)
2282     print 'Usage: c_client.py [-p path] file.xml'
2283     sys.exit(1)
2284
2285 for (opt, arg) in opts:
2286     if opt == '-p':
2287         sys.path.append(arg)
2288
2289 # Import the module class
2290 try:
2291     from xcbgen.state import Module
2292 except ImportError:
2293     print ''
2294     print 'Failed to load the xcbgen Python package!'
2295     print 'Make sure that xcb/proto installed it on your Python path.'
2296     print 'If not, you will need to create a .pth file or define $PYTHONPATH'
2297     print 'to extend the path.'
2298     print 'Refer to the README file in xcb/proto for more info.'
2299     print ''
2300     raise
2301
2302 # Parse the xml header
2303 module = Module(args[0], output)
2304
2305 # Build type-registry and resolve type dependencies
2306 module.register()
2307 module.resolve()
2308
2309 # Output the code
2310 module.generate()