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