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