Add configure option to enable or disable fd passing with sendmsg
[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 os
7 import sys
8 import errno
9 import time
10 import re
11
12 # Jump to the bottom of this file for the main routine
13
14 # Some hacks to make the API more readable, and to keep backwards compability
15 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
16 _cname_special_cases = {'DECnet':'decnet'}
17
18 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
19
20 _cplusplus_annoyances = {'class' : '_class',
21                          'new'   : '_new',
22                          'delete': '_delete'}
23 _c_keywords = {'default' : '_default'}
24
25 _hlines = []
26 _hlevel = 0
27 _clines = []
28 _clevel = 0
29 _ns = None
30
31 # global variable to keep track of serializers and 
32 # switch data types due to weird dependencies
33 finished_serializers = []
34 finished_sizeof = []
35 finished_switch = []
36
37 # keeps enum objects so that we can refer to them when generating manpages.
38 enums = {}
39
40 manpaths = False
41
42 def _h(fmt, *args):
43     '''
44     Writes the given line to the header file.
45     '''
46     _hlines[_hlevel].append(fmt % args)
47     
48 def _c(fmt, *args):
49     '''
50     Writes the given line to the source file.
51     '''
52     _clines[_clevel].append(fmt % args)
53     
54 def _hc(fmt, *args):
55     '''
56     Writes the given line to both the header and source files.
57     '''
58     _h(fmt, *args)
59     _c(fmt, *args)
60
61 # XXX See if this level thing is really necessary.
62 def _h_setlevel(idx):
63     '''
64     Changes the array that header lines are written to.
65     Supports writing different sections of the header file.
66     '''
67     global _hlevel
68     while len(_hlines) <= idx:
69         _hlines.append([])
70     _hlevel = idx
71     
72 def _c_setlevel(idx):
73     '''
74     Changes the array that source lines are written to.
75     Supports writing to different sections of the source file.
76     '''
77     global _clevel
78     while len(_clines) <= idx:
79         _clines.append([])
80     _clevel = idx
81     
82 def _n_item(str):
83     '''
84     Does C-name conversion on a single string fragment.
85     Uses a regexp with some hard-coded special cases.
86     '''
87     if str in _cname_special_cases:
88         return _cname_special_cases[str]
89     else:
90         split = _cname_re.finditer(str)
91         name_parts = [match.group(0) for match in split]
92         return '_'.join(name_parts)
93     
94 def _cpp(str):
95     '''
96     Checks for certain C++ reserved words and fixes them.
97     '''
98     if str in _cplusplus_annoyances:
99         return _cplusplus_annoyances[str]
100     elif str in _c_keywords:
101         return  _c_keywords[str]
102     else:
103         return str
104
105 def _ext(str):
106     '''
107     Does C-name conversion on an extension name.
108     Has some additional special cases on top of _n_item.
109     '''
110     if str in _extension_special_cases:
111         return _n_item(str).lower()
112     else:
113         return str.lower()
114     
115 def _n(list):
116     '''
117     Does C-name conversion on a tuple of strings.
118     Different behavior depending on length of tuple, extension/not extension, etc.
119     Basically C-name converts the individual pieces, then joins with underscores.
120     '''
121     if len(list) == 1:
122         parts = list
123     elif len(list) == 2:
124         parts = [list[0], _n_item(list[1])]
125     elif _ns.is_ext:
126         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
127     else:
128         parts = [list[0]] + [_n_item(i) for i in list[1:]]
129     return '_'.join(parts).lower()
130
131 def _t(list):
132     '''
133     Does C-name conversion on a tuple of strings representing a type.
134     Same as _n but adds a "_t" on the end.
135     '''
136     if len(list) == 1:
137         parts = list
138     elif len(list) == 2:
139         parts = [list[0], _n_item(list[1]), 't']
140     elif _ns.is_ext:
141         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
142     else:
143         parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
144     return '_'.join(parts).lower()
145         
146
147 def c_open(self):
148     '''
149     Exported function that handles module open.
150     Opens the files and writes out the auto-generated comment, header file includes, etc.
151     '''
152     global _ns
153     _ns = self.namespace
154     _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
155
156     # Build the type-name collision avoidance table used by c_enum
157     build_collision_table()
158
159     _h_setlevel(0)
160     _c_setlevel(0)
161
162     _hc('/*')
163     _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
164     _hc(' * Edit at your peril.')
165     _hc(' */')
166     _hc('')
167
168     _h('/**')
169     _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
170     _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
171     _h(' * @{')
172     _h(' **/')
173     _h('')
174     _h('#ifndef __%s_H', _ns.header.upper())
175     _h('#define __%s_H', _ns.header.upper())
176     _h('')
177     _h('#include "xcb.h"')
178
179     _c('#ifdef HAVE_CONFIG_H')
180     _c('#include "config.h"')
181     _c('#endif')
182     _c('#include <stdlib.h>')
183     _c('#include <string.h>')
184     _c('#include <assert.h>')
185     _c('#include <stddef.h>  /* for offsetof() */')
186     _c('#include "xcbext.h"')
187     _c('#include "%s.h"', _ns.header)
188         
189     _c('')
190     _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)')
191
192     if _ns.is_ext:
193         for (n, h) in self.imports:
194             _hc('#include "%s.h"', h)
195
196     _h('')
197     _h('#ifdef __cplusplus')
198     _h('extern "C" {')
199     _h('#endif')
200
201     if _ns.is_ext:
202         _h('')
203         _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
204         _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
205         _h('  ') #XXX
206         _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
207
208         _c('')
209         _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
210
211 def c_close(self):
212     '''
213     Exported function that handles module close.
214     Writes out all the stored content lines, then closes the files.
215     '''
216     _h_setlevel(2)
217     _c_setlevel(2)
218     _hc('')
219
220     _h('')
221     _h('#ifdef __cplusplus')
222     _h('}')
223     _h('#endif')
224
225     _h('')
226     _h('#endif')
227     _h('')
228     _h('/**')
229     _h(' * @}')
230     _h(' */')
231
232     # Write header file
233     hfile = open('%s.h' % _ns.header, 'w')
234     for list in _hlines:
235         for line in list:
236             hfile.write(line)
237             hfile.write('\n')
238     hfile.close()
239
240     # Write source file
241     cfile = open('%s.c' % _ns.header, 'w')
242     for list in _clines:
243         for line in list:
244             cfile.write(line)
245             cfile.write('\n')
246     cfile.close()
247
248 def build_collision_table():
249     global namecount
250     namecount = {}
251
252     for v in module.types.values():
253         name = _t(v[0])
254         namecount[name] = (namecount.get(name) or 0) + 1
255
256 def c_enum(self, name):
257     '''
258     Exported function that handles enum declarations.
259     '''
260
261     enums[name] = self
262
263     tname = _t(name)
264     if namecount[tname] > 1:
265         tname = _t(name + ('enum',))
266
267     _h_setlevel(0)
268     _h('')
269     _h('typedef enum %s {', tname)
270
271     count = len(self.values)
272
273     for (enam, eval) in self.values:
274         count = count - 1
275         equals = ' = ' if eval != '' else ''
276         comma = ',' if count > 0 else ''
277         doc = ''
278         if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
279             doc = '\n/**< %s */\n' % self.doc.fields[enam]
280         _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
281
282     _h('} %s;', tname)
283
284 def _c_type_setup(self, name, postfix):
285     '''
286     Sets up all the C-related state by adding additional data fields to
287     all Field and Type objects.  Here is where we figure out most of our
288     variable and function names.
289
290     Recurses into child fields and list member types.
291     '''
292     # Do all the various names in advance
293     self.c_type = _t(name + postfix)
294     self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
295
296     self.c_iterator_type = _t(name + ('iterator',))
297     self.c_next_name = _n(name + ('next',))
298     self.c_end_name = _n(name + ('end',))
299
300     self.c_request_name = _n(name)
301     self.c_checked_name = _n(name + ('checked',))
302     self.c_unchecked_name = _n(name + ('unchecked',))
303     self.c_reply_name = _n(name + ('reply',))
304     self.c_reply_type = _t(name + ('reply',))
305     self.c_cookie_type = _t(name + ('cookie',))
306     self.c_reply_fds_name = _n(name + ('reply_fds',))
307
308     self.need_aux = False
309     self.need_serialize = False
310     self.need_sizeof = False
311
312     self.c_aux_name = _n(name + ('aux',))
313     self.c_aux_checked_name = _n(name + ('aux', 'checked'))
314     self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
315     self.c_serialize_name = _n(name + ('serialize',))
316     self.c_unserialize_name = _n(name + ('unserialize',))
317     self.c_unpack_name = _n(name + ('unpack',))
318     self.c_sizeof_name = _n(name + ('sizeof',))
319
320     # special case: structs where variable size fields are followed by fixed size fields
321     self.var_followed_by_fixed_fields = False
322
323     if self.is_switch:
324         self.need_serialize = True
325         self.c_container = 'struct'
326         for bitcase in self.bitcases:
327             bitcase.c_field_name = _cpp(bitcase.field_name)
328             bitcase_name = bitcase.field_type if bitcase.type.has_name else name
329             _c_type_setup(bitcase.type, bitcase_name, ())
330
331     elif self.is_container:
332
333         self.c_container = 'union' if self.is_union else 'struct'
334         prev_varsized_field = None
335         prev_varsized_offset = 0
336         first_field_after_varsized = None
337
338         for field in self.fields:
339             _c_type_setup(field.type, field.field_type, ())
340             if field.type.is_list:
341                 _c_type_setup(field.type.member, field.field_type, ())
342                 if (field.type.nmemb is None): 
343                     self.need_sizeof = True
344
345             field.c_field_type = _t(field.field_type)
346             field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
347             field.c_field_name = _cpp(field.field_name)
348             field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
349             field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
350
351             # correct the c_pointer field for variable size non-list types
352             if not field.type.fixed_size() and field.c_pointer == ' ':
353                 field.c_pointer = '*'
354             if field.type.is_list and not field.type.member.fixed_size():
355                 field.c_pointer = '*'
356
357             if field.type.is_switch:
358                 field.c_pointer = '*'
359                 field.c_field_const_type = 'const ' + field.c_field_type
360                 self.need_aux = True
361             elif not field.type.fixed_size() and not field.type.is_bitcase:
362                 self.need_sizeof = True
363
364             field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
365             field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
366             field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
367             field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
368             field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
369
370             field.prev_varsized_field = prev_varsized_field
371             field.prev_varsized_offset = prev_varsized_offset
372
373             if prev_varsized_offset == 0:
374                 first_field_after_varsized = field
375             field.first_field_after_varsized = first_field_after_varsized
376
377             if field.type.fixed_size():
378                 prev_varsized_offset += field.type.size
379                 # special case: intermixed fixed and variable size fields
380                 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
381                     if not self.is_union:
382                         self.need_serialize = True
383                         self.var_followed_by_fixed_fields = True
384             else:
385                 self.last_varsized_field = field
386                 prev_varsized_field = field
387                 prev_varsized_offset = 0                    
388
389             if self.var_followed_by_fixed_fields:
390                 if field.type.fixed_size():
391                     field.prev_varsized_field = None
392                             
393     if self.need_serialize:
394         # when _unserialize() is wanted, create _sizeof() as well for consistency reasons 
395         self.need_sizeof = True
396
397     # as switch does never appear at toplevel, 
398     # continue here with type construction
399     if self.is_switch:
400         if self.c_type not in finished_switch:
401             finished_switch.append(self.c_type)
402             # special: switch C structs get pointer fields for variable-sized members
403             _c_complex(self)
404             for bitcase in self.bitcases:
405                 bitcase_name = bitcase.type.name if bitcase.type.has_name else name
406                 _c_accessors(bitcase.type, bitcase_name, bitcase_name)
407                 # no list with switch as element, so no call to 
408                 # _c_iterator(field.type, field_name) necessary
409
410     if not self.is_bitcase:
411         if self.need_serialize:
412             if self.c_serialize_name not in finished_serializers:
413                 finished_serializers.append(self.c_serialize_name)
414                 _c_serialize('serialize', self)
415
416                 # _unpack() and _unserialize() are only needed for special cases:
417                 #   switch -> unpack
418                 #   special cases -> unserialize
419                 if self.is_switch or self.var_followed_by_fixed_fields:
420                     _c_serialize('unserialize', self)
421                     
422         if self.need_sizeof:
423             if self.c_sizeof_name not in finished_sizeof:
424                 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix:
425                     finished_sizeof.append(self.c_sizeof_name)
426                     _c_serialize('sizeof', self)
427 # _c_type_setup()
428
429 def _c_helper_absolute_name(prefix, field=None):
430     """
431     turn prefix, which is a list of tuples (name, separator, Type obj) into a string
432     representing a valid name in C (based on the context)
433     if field is not None, append the field name as well
434     """
435     prefix_str = ''
436     for name, sep, obj in prefix:
437         prefix_str += name
438         if '' == sep:
439             sep = '->'
440             if ((obj.is_bitcase and obj.has_name) or     # named bitcase
441                 (obj.is_switch and len(obj.parents)>1)):
442                 sep = '.'
443         prefix_str += sep
444     if field is not None:
445         prefix_str += _cpp(field.field_name)
446     return prefix_str
447 # _c_absolute_name
448     
449 def _c_helper_field_mapping(complex_type, prefix, flat=False):
450     """
451     generate absolute names, based on prefix, for all fields starting from complex_type
452     if flat == True, nested complex types are not taken into account
453     """
454     all_fields = {}
455     if complex_type.is_switch:
456         for b in complex_type.bitcases:
457             if b.type.has_name:
458                 switch_name, switch_sep, switch_type = prefix[-1]
459                 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)]
460             else:
461                 bitcase_prefix = prefix 
462
463             if (True==flat and not b.type.has_name) or False==flat:
464                 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat))
465     else:
466         for f in complex_type.fields:
467             fname = _c_helper_absolute_name(prefix, f)
468             if f.field_name in all_fields:
469                 raise Exception("field name %s has been registered before" % f.field_name)
470
471             all_fields[f.field_name] = (fname, f)
472             if f.type.is_container and flat==False:
473                 if f.type.is_bitcase and not f.type.has_name:
474                     new_prefix = prefix
475                 elif f.type.is_switch and len(f.type.parents)>1:
476                     # nested switch gets another separator
477                     new_prefix = prefix+[(f.c_field_name, '.', f.type)]
478                 else:
479                     new_prefix = prefix+[(f.c_field_name, '->', f.type)]
480                 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat))
481
482     return all_fields
483 # _c_field_mapping()
484
485 def _c_helper_resolve_field_names (prefix):
486     """
487     get field names for all objects in the prefix array
488     """
489     all_fields = {}
490     tmp_prefix = []
491     # look for fields in the remaining containers
492     for idx, p in enumerate(prefix):
493         name, sep, obj = p
494         if ''==sep:
495             # sep can be preset in prefix, if not, make a sensible guess
496             sep = '.' if (obj.is_switch or obj.is_bitcase) else '->'
497             # exception: 'toplevel' object (switch as well!) always have sep '->'
498             sep = '->' if idx<1 else sep
499         if not obj.is_bitcase or (obj.is_bitcase and obj.has_name):
500             tmp_prefix.append((name, sep, obj))
501         all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True))
502
503     return all_fields
504 # _c_helper_resolve_field_names
505
506 def get_expr_fields(self):
507     """
508     get the Fields referenced by switch or list expression 
509     """
510     def get_expr_field_names(expr):
511         if expr.op is None:
512             if expr.lenfield_name is not None:
513                 return [expr.lenfield_name]
514             else:
515                 # constant value expr
516                 return []
517         else:
518             if expr.op == '~':
519                 return get_expr_field_names(expr.rhs)
520             elif expr.op == 'popcount':
521                 return get_expr_field_names(expr.rhs)
522             elif expr.op == 'sumof':
523                 # sumof expr references another list, 
524                 # we need that list's length field here
525                 field = None
526                 for f in expr.lenfield_parent.fields:
527                     if f.field_name == expr.lenfield_name:
528                         field = f
529                         break
530                 if field is None:
531                     raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
532                 # referenced list + its length field
533                 return [expr.lenfield_name] + get_expr_field_names(field.type.expr)
534             elif expr.op == 'enumref':
535                 return []
536             else:
537                 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
538     # get_expr_field_names()
539     
540     # resolve the field names with the parent structure(s)
541     unresolved_fields_names = get_expr_field_names(self.expr)
542
543     # construct prefix from self
544     prefix = [('', '', p) for p in self.parents]
545     if self.is_container:
546         prefix.append(('', '', self))
547
548     all_fields = _c_helper_resolve_field_names (prefix)
549     resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names))
550     if len(unresolved_fields_names) != len(resolved_fields_names):
551         raise Exception("could not resolve all fields for %s" % self.name)
552     
553     resolved_fields = [all_fields[n][1] for n in resolved_fields_names]
554     return resolved_fields
555 # get_expr_fields()
556
557 def resolve_expr_fields(complex_obj):
558     """
559     find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj
560     these are normally fields that need to be given as function parameters
561     """
562     all_fields = []
563     expr_fields = []
564     unresolved = []
565
566     for field in complex_obj.fields:
567         all_fields.append(field)
568         if field.type.is_switch or field.type.is_list:
569             expr_fields += get_expr_fields(field.type)
570         if field.type.is_container:
571             expr_fields += resolve_expr_fields(field.type)
572
573     # try to resolve expr fields
574     for e in expr_fields:
575         if e not in all_fields and e not in unresolved:
576             unresolved.append(e)
577     return unresolved
578 # resolve_expr_fields()
579             
580 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
581     """
582     functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters:
583     E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch 
584     expression. This function tries to resolve all fields within a structure, and returns the 
585     unresolved fields as the list of external parameters. 
586     """
587     def add_param(params, param):
588         if param not in params:
589             params.append(param)
590
591     # collect all fields into param_fields
592     param_fields = []
593     wire_fields = []
594
595     for field in self.fields:
596         if field.visible:
597             # the field should appear as a parameter in the function call
598             param_fields.append(field)
599         if field.wire and not field.auto:
600             if field.type.fixed_size() and not self.is_switch:
601                 # field in the xcb_out structure
602                 wire_fields.append(field)
603         # fields like 'pad0' are skipped!
604                
605     # in case of switch, parameters always contain any fields referenced in the switch expr
606     # we do not need any variable size fields here, as the switch data type contains both 
607     # fixed and variable size fields
608     if self.is_switch:
609         param_fields = get_expr_fields(self)
610
611     # _serialize()/_unserialize()/_unpack() function parameters
612     # note: don't use set() for params, it is unsorted
613     params = []
614     
615     # 1. the parameter for the void * buffer
616     if  'serialize' == context:
617         params.append(('void', '**', buffer_var))
618     elif context in ('unserialize', 'unpack', 'sizeof'):
619         params.append(('const void', '*', buffer_var))
620
621     # 2. any expr fields that cannot be resolved within self and descendants
622     unresolved_fields = resolve_expr_fields(self)
623     for f in unresolved_fields:
624         add_param(params, (f.c_field_type, '', f.c_field_name))
625
626     # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields
627     #    that do not appear in the data type struct
628     for p in param_fields:
629         if self.is_switch:
630             typespec = p.c_field_const_type
631             pointerspec = p.c_pointer 
632             add_param(params, (typespec, pointerspec, p.c_field_name))
633         else:
634             if p.visible and not p.wire and not p.auto:
635                 typespec = p.c_field_type
636                 pointerspec = ''
637                 add_param(params, (typespec, pointerspec, p.c_field_name))
638   
639     # 4. aux argument
640     if 'serialize' == context:
641         add_param(params, ('const %s' % self.c_type, '*', aux_var))
642     elif 'unserialize' == context: 
643         add_param(params, ('%s' % self.c_type, '**', aux_var))
644     elif 'unpack' == context:
645         add_param(params, ('%s' % self.c_type, '*', aux_var))
646
647     # 5. switch contains all variable size fields as struct members
648     #    for other data types though, these have to be supplied separately
649     #    this is important for the special case of intermixed fixed and 
650     #    variable size fields
651     if not self.is_switch and 'serialize' == context:
652         for p in param_fields:
653             if not p.type.fixed_size():
654                 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
655
656     return (param_fields, wire_fields, params)
657 # get_serialize_params()
658
659 def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
660     code_lines.append('%s    /* insert padding */' % space)
661     code_lines.append('%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
662 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
663     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
664
665     if not postpone:
666         code_lines.append('%s    if (0 != xcb_pad) {' % space)
667
668         if 'serialize' == context:
669             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
670             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
671             code_lines.append('%s        xcb_parts_idx++;' % space)
672         elif context in ('unserialize', 'unpack', 'sizeof'):
673             code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
674
675         code_lines.append('%s        xcb_pad = 0;' % space)
676         code_lines.append('%s    }' % space)
677         
678     code_lines.append('%s    xcb_block_len = 0;' % space)
679
680     # keep tracking of xcb_parts entries for serialize
681     return 1
682 # _c_serialize_helper_insert_padding()
683
684 def _c_serialize_helper_switch(context, self, complex_name, 
685                                code_lines, temp_vars, 
686                                space, prefix):
687     count = 0
688     switch_expr = _c_accessor_get_expr(self.expr, None)
689
690     for b in self.bitcases:            
691         len_expr = len(b.type.expr)
692         for n, expr in enumerate(b.type.expr):
693             bitcase_expr = _c_accessor_get_expr(expr, None)
694             # only one <enumref> in the <bitcase>
695             if len_expr == 1:
696                 code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
697             # multiple <enumref> in the <bitcase>
698             elif n == 0: # first
699                 code_lines.append('    if((%s & %s) ||' % (switch_expr, bitcase_expr))
700             elif len_expr == (n + 1): # last
701                 code_lines.append('       (%s & %s)) {' % (switch_expr, bitcase_expr))
702             else: # between first and last
703                 code_lines.append('       (%s & %s) ||' % (switch_expr, bitcase_expr))
704
705         b_prefix = prefix
706         if b.type.has_name:
707             b_prefix = prefix + [(b.c_field_name, '.', b.type)]
708             
709         count += _c_serialize_helper_fields(context, b.type, 
710                                             code_lines, temp_vars, 
711                                             "%s    " % space, 
712                                             b_prefix, 
713                                             is_bitcase = True)
714         code_lines.append('    }')
715
716 #    if 'serialize' == context:
717 #        count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
718 #    elif context in ('unserialize', 'unpack', 'sizeof'):
719 #        # padding
720 #        code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
721 #        code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
722    
723     return count
724 # _c_serialize_helper_switch
725
726 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
727     """
728     handle switch by calling _serialize() or _unpack(), depending on context
729     """
730     # switch is handled by this function as a special case
731     param_fields, wire_fields, params = get_serialize_params(context, self)
732     field_mapping = _c_helper_field_mapping(self, prefix)
733     prefix_str = _c_helper_absolute_name(prefix)
734
735     # find the parameters that need to be passed to _serialize()/_unpack():
736     # all switch expr fields must be given as parameters
737     args = get_expr_fields(field.type)
738     # length fields for variable size types in switch, normally only some of need 
739     # need to be passed as parameters
740     switch_len_fields = resolve_expr_fields(field.type)
741
742     # a switch field at this point _must_ be a bitcase field
743     # we require that bitcases are "self-contiguous"
744     bitcase_unresolved = resolve_expr_fields(self)
745     if len(bitcase_unresolved) != 0:
746         raise Exception('unresolved fields within bitcase is not supported at this point')
747
748     # get the C names for the parameters  
749     c_field_names = ''
750     for a in switch_len_fields:
751         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
752     for a in args:
753         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
754
755     # call _serialize()/_unpack() to determine the actual size
756     if 'serialize' == context:
757         length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable,
758                                        c_field_names, prefix_str, field.c_field_name) 
759     elif context in ('unserialize', 'unpack'):
760         length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name, 
761                                            c_field_names, prefix_str, field.c_field_name)
762
763     return length
764 # _c_serialize_helper_switch_field()
765
766 def _c_serialize_helper_list_field(context, self, field, 
767                                    code_lines, temp_vars, 
768                                    space, prefix):
769     """
770     helper function to cope with lists of variable length
771     """
772     expr = field.type.expr
773     prefix_str = _c_helper_absolute_name(prefix)
774     param_fields, wire_fields, params = get_serialize_params('sizeof', self)
775     param_names = [p[2] for p in params]
776     
777     expr_fields_names = [f.field_name for f in get_expr_fields(field.type)]
778     resolved = list(filter(lambda x: x in param_names, expr_fields_names))
779     unresolved = list(filter(lambda x: x not in param_names, expr_fields_names))
780     
781     field_mapping = {}
782     for r in resolved:
783         field_mapping[r] = (r, None)
784     
785     if len(unresolved)>0:
786         tmp_prefix = prefix
787         if len(tmp_prefix)==0:
788             raise Exception("found an empty prefix while resolving expr field names for list %s", 
789                             field.c_field_name)        
790         
791         field_mapping.update(_c_helper_resolve_field_names(prefix))
792         resolved += list(filter(lambda x: x in field_mapping, unresolved))
793         unresolved = list(filter(lambda x: x not in field_mapping, unresolved))
794         if len(unresolved)>0:
795             raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
796
797     list_length = _c_accessor_get_expr(expr, field_mapping)
798
799     # default: list with fixed size elements
800     length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
801
802     # list with variable-sized elements 
803     if not field.type.member.fixed_size():
804         length = ''
805         if context in ('unserialize', 'sizeof', 'unpack'):
806             int_i = '    unsigned int i;'
807             xcb_tmp_len = '    unsigned int xcb_tmp_len;'
808             if int_i not in temp_vars:
809                 temp_vars.append(int_i)
810             if xcb_tmp_len not in temp_vars:
811                 temp_vars.append(xcb_tmp_len)
812             # loop over all list elements and call sizeof repeatedly
813             # this should be a bit faster than using the iterators
814             code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
815             code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp);" % 
816                               (space, field.type.c_sizeof_name))
817             code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
818             code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
819             code_lines.append("%s    }" % space)                  
820       
821         elif 'serialize' == context:
822             code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
823             code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
824             code_lines.append('%s    for(i=0; i<%s; i++) { ' % (space, list_length))
825             code_lines.append('%s        xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name))
826             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
827             code_lines.append('%s    }' % space)
828             code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
829             
830     return length
831 # _c_serialize_helper_list_field()
832
833 def _c_serialize_helper_fields_fixed_size(context, self, field, 
834                                           code_lines, temp_vars, 
835                                           space, prefix):
836     # keep the C code a bit more readable by giving the field name
837     if not self.is_bitcase:
838         code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
839     else:
840         scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)]
841         typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name)
842         code_lines.append('%s    /* %s.%s */' % (space, typename, field.c_field_name))
843
844     abs_field_name = _c_helper_absolute_name(prefix, field)
845     # default for simple cases: call sizeof()
846     length = "sizeof(%s)" % field.c_field_type
847
848     if context in ('unserialize', 'unpack', 'sizeof'):
849         # default: simple cast
850         value = '    %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type) 
851         
852         # padding - we could probably just ignore it
853         if field.type.is_pad and field.type.nmemb > 1:
854             value = ''
855             for i in range(field.type.nmemb):
856                 code_lines.append('%s    %s[%d] = *(%s *)xcb_tmp;' % 
857                                   (space, abs_field_name, i, field.c_field_type)) 
858             # total padding = sizeof(pad0) * nmemb
859             length += " * %d" % field.type.nmemb
860
861         if field.type.is_list:
862             # no such case in the protocol, cannot be tested and therefore ignored for now
863             raise Exception('list with fixed number of elemens unhandled in _unserialize()')
864
865     elif 'serialize' == context:
866         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) ' 
867
868         if field.type.is_expr:
869             # need to register a temporary variable for the expression in case we know its type
870             if field.type.c_type is None:
871                 raise Exception("type for field '%s' (expression '%s') unkown" % 
872                                 (field.field_name, _c_accessor_get_expr(field.type.expr)))
873             
874             temp_vars.append('    %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name), 
875                                                            _c_accessor_get_expr(field.type.expr, prefix)))
876             value += "&xcb_expr_%s;" % _cpp(field.field_name)
877
878         elif field.type.is_pad:
879             if field.type.nmemb == 1:
880                 value += "&xcb_pad;"
881             else:
882                 # we could also set it to 0, see definition of xcb_send_request()
883                 value = '    xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;'
884                 length += "*%d" % field.type.nmemb
885
886         else:
887             # non-list type with fixed size
888             if field.type.nmemb == 1:
889                 value += "&%s;" % (abs_field_name)
890
891             # list with nmemb (fixed size) elements
892             else:
893                 value += '%s;' % (abs_field_name)
894                 length = '%d' % field.type.nmemb
895
896     return (value, length)
897 # _c_serialize_helper_fields_fixed_size()
898
899 def _c_serialize_helper_fields_variable_size(context, self, field, 
900                                              code_lines, temp_vars, 
901                                              space, prefix):
902     prefix_str = _c_helper_absolute_name(prefix)
903
904     if context in ('unserialize', 'unpack', 'sizeof'):
905         value = ''
906         var_field_name = 'xcb_tmp'
907         
908         # special case: intermixed fixed and variable size fields
909         if self.var_followed_by_fixed_fields and 'unserialize' == context:
910             value = '    %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type)
911             temp_vars.append('    %s *%s;' % (field.type.c_type, field.c_field_name))
912         # special case: switch
913         if 'unpack' == context:
914             value = '    %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type)
915             
916     elif 'serialize' == context:
917         # variable size fields appear as parameters to _serialize() if the 
918         # 'toplevel' container is not a switch
919         prefix_string = prefix_str if prefix[0][2].is_switch else ''
920         var_field_name = "%s%s" % (prefix_string, field.c_field_name)
921         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name
922
923     length = ''
924
925     code_lines.append('%s    /* %s */' % (space, field.c_field_name))
926
927     if field.type.is_list:
928         if value != '':
929             # in any context, list is already a pointer, so the default assignment is ok
930             code_lines.append("%s%s" % (space, value))
931             value = ''
932         length = _c_serialize_helper_list_field(context, self, field, 
933                                                 code_lines, temp_vars, 
934                                                 space, prefix)
935         
936     elif field.type.is_switch:
937         value = ''
938         if context == 'serialize':
939             # the _serialize() function allocates the correct amount memory if given a NULL pointer
940             value = '    xcb_parts[xcb_parts_idx].iov_base = (char *)0;'
941         length = _c_serialize_helper_switch_field(context, self, field, 
942                                                   'xcb_parts[xcb_parts_idx].iov_base', 
943                                                   prefix)
944         
945     else:
946         # in all remaining special cases - call _sizeof()
947         length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name)
948
949     return (value, length)
950 # _c_serialize_helper_fields_variable_size
951
952 def _c_serialize_helper_fields(context, self, 
953                                code_lines, temp_vars, 
954                                space, prefix, is_bitcase):
955     count = 0
956     need_padding = False
957     prev_field_was_variable = False
958
959     for field in self.fields:
960         if not field.visible:
961             if not ((field.wire and not field.auto) or 'unserialize' == context):
962                 continue
963
964         # switch/bitcase: fixed size fields must be considered explicitly 
965         if field.type.fixed_size():
966             if self.is_bitcase or self.var_followed_by_fixed_fields:
967                 if prev_field_was_variable and need_padding:
968                     # insert padding
969 #                    count += _c_serialize_helper_insert_padding(context, code_lines, space, 
970 #                                                                self.var_followed_by_fixed_fields)
971                     prev_field_was_variable = False
972
973                 # prefix for fixed size fields
974                 fixed_prefix = prefix
975
976                 value, length = _c_serialize_helper_fields_fixed_size(context, self, field, 
977                                                                       code_lines, temp_vars, 
978                                                                       space, fixed_prefix)
979             else:
980                 continue
981
982         # fields with variable size
983         else:
984             # switch/bitcase: always calculate padding before and after variable sized fields
985             if need_padding or is_bitcase:
986                 count += _c_serialize_helper_insert_padding(context, code_lines, space, 
987                                                             self.var_followed_by_fixed_fields)
988
989             value, length = _c_serialize_helper_fields_variable_size(context, self, field, 
990                                                                      code_lines, temp_vars, 
991                                                                      space, prefix)
992             prev_field_was_variable = True
993         
994         # save (un)serialization C code
995         if '' != value:
996             code_lines.append('%s%s' % (space, value))    
997         
998         if field.type.fixed_size():
999             if is_bitcase or self.var_followed_by_fixed_fields:
1000                 # keep track of (un)serialized object's size
1001                 code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1002                 if context in ('unserialize', 'unpack', 'sizeof'):
1003                     code_lines.append('%s    xcb_tmp += %s;' % (space, length))
1004         else: 
1005             # variable size objects or bitcase:
1006             #   value & length might have been inserted earlier for special cases
1007             if '' != length:
1008                 # special case: intermixed fixed and variable size fields
1009                 if (not field.type.fixed_size() and 
1010                     self.var_followed_by_fixed_fields and 'unserialize' == context):
1011                     temp_vars.append('    int %s_len;' % field.c_field_name)
1012                     code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
1013                     code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
1014                     code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
1015                 else:
1016                     code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1017                     # increase pointer into the byte stream accordingly
1018                     if context in ('unserialize', 'sizeof', 'unpack'):
1019                         code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1020                         
1021         if 'serialize' == context:
1022             if '' != length:
1023                 code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1024             code_lines.append('%s    xcb_parts_idx++;' % space)
1025             count += 1
1026
1027         code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1028
1029         need_padding = True
1030         if self.var_followed_by_fixed_fields:
1031             need_padding = False
1032         
1033     return count
1034 # _c_serialize_helper_fields()    
1035
1036 def _c_serialize_helper(context, complex_type, 
1037                         code_lines, temp_vars, 
1038                         space='', prefix=[]):
1039     # count tracks the number of fields to serialize
1040     count = 0
1041
1042     if hasattr(complex_type, 'type'):
1043         self = complex_type.type
1044         complex_name = complex_type.name
1045     else:
1046         self = complex_type
1047         if self.var_followed_by_fixed_fields and 'unserialize' == context:
1048             complex_name = 'xcb_out'
1049         else:
1050             complex_name = '_aux'
1051     
1052     # special case: switch is serialized by evaluating each bitcase separately
1053     if self.is_switch:
1054         count += _c_serialize_helper_switch(context, self, complex_name, 
1055                                             code_lines, temp_vars, 
1056                                             space, prefix)
1057
1058     # all other data types can be evaluated one field a time
1059     else: 
1060         # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1061         if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
1062             code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
1063             code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1064             # probably not needed
1065             #_c_serialize_helper_insert_padding(context, code_lines, space, False)
1066
1067         count += _c_serialize_helper_fields(context, self, 
1068                                             code_lines, temp_vars, 
1069                                             space, prefix, False)
1070     # "final padding"
1071     count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1072
1073     return count    
1074 # _c_serialize_helper()
1075
1076 def _c_serialize(context, self):
1077     """
1078     depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof() 
1079     for the ComplexType variable self
1080     """
1081     _h_setlevel(1)
1082     _c_setlevel(1)
1083
1084     _hc('')
1085     # _serialize() returns the buffer size
1086     _hc('int')
1087
1088     if self.is_switch and 'unserialize' == context:
1089         context = 'unpack'
1090
1091     cases = { 'serialize'   : self.c_serialize_name, 
1092               'unserialize' : self.c_unserialize_name, 
1093               'unpack'      : self.c_unpack_name, 
1094               'sizeof'      : self.c_sizeof_name }
1095     func_name = cases[context]
1096             
1097     param_fields, wire_fields, params = get_serialize_params(context, self)
1098     variable_size_fields = 0
1099     # maximum space required for type definition of function arguments
1100     maxtypelen = 0
1101
1102     # determine N(variable_fields) 
1103     for field in param_fields:
1104         # if self.is_switch, treat all fields as if they are variable sized
1105         if not field.type.fixed_size() or self.is_switch:
1106             variable_size_fields += 1
1107     # determine maxtypelen
1108     for p in params:
1109         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
1110
1111     # write to .c/.h
1112     indent = ' '*(len(func_name)+2)
1113     param_str = []
1114     for p in params:
1115         typespec, pointerspec, field_name = p
1116         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1117         param_str.append("%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1118     # insert function name
1119     param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1120     param_str = list(map(lambda x: "%s," % x, param_str))
1121     for s in param_str[:-1]:
1122         _hc(s)
1123     _h("%s);" % param_str[-1].rstrip(','))
1124     _c("%s)" % param_str[-1].rstrip(','))
1125     _c('{')
1126
1127     code_lines = []
1128     temp_vars = []
1129     prefix = []
1130
1131     if 'serialize' == context:
1132         if not self.is_switch and not self.var_followed_by_fixed_fields:
1133             _c('    %s *xcb_out = *_buffer;', self.c_type)
1134             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1135             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1136             _c('    unsigned int xcb_align_to = 0;')
1137         else:
1138             _c('    char *xcb_out = *_buffer;')
1139             _c('    unsigned int xcb_buffer_len = 0;')
1140             _c('    unsigned int xcb_align_to = 0;')
1141         prefix = [('_aux', '->', self)]
1142         aux_ptr = 'xcb_out'
1143
1144     elif context in ('unserialize', 'unpack'):
1145         _c('    char *xcb_tmp = (char *)_buffer;')
1146         if not self.is_switch:
1147             if not self.var_followed_by_fixed_fields:
1148                 _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1149                 prefix = [('_aux', '->', self)]
1150             else:
1151                 _c('    %s xcb_out;', self.c_type)
1152                 prefix = [('xcb_out', '.', self)]
1153         else:
1154             aux_var = '_aux' # default for unpack: single pointer
1155             # note: unserialize not generated for switch
1156             if 'unserialize' == context:
1157                 aux_var = '(*_aux)' # unserialize: double pointer (!)
1158             prefix = [(aux_var, '->', self)]
1159         aux_ptr = '*_aux'
1160         _c('    unsigned int xcb_buffer_len = 0;')
1161         _c('    unsigned int xcb_block_len = 0;')
1162         _c('    unsigned int xcb_pad = 0;')
1163         _c('    unsigned int xcb_align_to = 0;')
1164
1165     elif 'sizeof' == context:
1166         param_names = [p[2] for p in params]
1167         if self.is_switch:
1168             # switch: call _unpack()
1169             _c('    %s _aux;', self.c_type)
1170             _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1171             _c('}')
1172             return
1173         elif self.var_followed_by_fixed_fields:
1174             # special case: call _unserialize()
1175             _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1176             _c('}')
1177             return
1178         else:
1179             _c('    char *xcb_tmp = (char *)_buffer;')
1180             prefix = [('_aux', '->', self)]
1181
1182     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1183     # update variable size fields (only important for context=='serialize'
1184     variable_size_fields = count
1185     if 'serialize' == context:
1186         temp_vars.append('    unsigned int xcb_pad = 0;')
1187         temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};') 
1188         temp_vars.append('    struct iovec xcb_parts[%d];' % count)
1189         temp_vars.append('    unsigned int xcb_parts_idx = 0;')
1190         temp_vars.append('    unsigned int xcb_block_len = 0;')
1191         temp_vars.append('    unsigned int i;')
1192         temp_vars.append('    char *xcb_tmp;')
1193     elif 'sizeof' == context:
1194         # neither switch nor intermixed fixed and variable size fields:
1195         # evaluate parameters directly
1196         if not (self.is_switch or self.var_followed_by_fixed_fields):
1197
1198             # look if we have to declare an '_aux' variable at all
1199             if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1200                 if not self.var_followed_by_fixed_fields:
1201                     _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1202                 else:
1203                     _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1204
1205             _c('    unsigned int xcb_buffer_len = 0;')
1206             _c('    unsigned int xcb_block_len = 0;')
1207             _c('    unsigned int xcb_pad = 0;')        
1208             _c('    unsigned int xcb_align_to = 0;')
1209
1210     _c('')
1211     for t in temp_vars:
1212         _c(t)
1213     _c('')
1214     for l in code_lines:
1215         _c(l)
1216
1217     # variable sized fields have been collected, now
1218     # allocate memory and copy everything into a continuous memory area 
1219     # note: this is not necessary in case of unpack
1220     if context in ('serialize', 'unserialize'):
1221         # unserialize: check for sizeof-only invocation
1222         if 'unserialize' == context:
1223             _c('')
1224             _c('    if (NULL == _aux)')
1225             _c('        return xcb_buffer_len;')
1226
1227         _c('')
1228         _c('    if (NULL == %s) {', aux_ptr)
1229         _c('        /* allocate memory */')
1230         _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
1231         if 'serialize' == context:
1232             _c('        *_buffer = xcb_out;')
1233         _c('    }')
1234         _c('')
1235
1236         # serialize: handle variable size fields in a loop
1237         if 'serialize' == context:
1238             if not self.is_switch and not self.var_followed_by_fixed_fields:
1239                 if len(wire_fields)>0:
1240                     _c('    *xcb_out = *_aux;')
1241             # copy variable size fields into the buffer
1242             if variable_size_fields > 0:
1243                 # xcb_out padding
1244                 if not self.is_switch and not self.var_followed_by_fixed_fields:
1245                     _c('    xcb_tmp = (char*)++xcb_out;')
1246                     _c('    xcb_tmp += xcb_out_pad;')
1247                 else:
1248                     _c('    xcb_tmp = xcb_out;')
1249
1250                 # variable sized fields
1251                 _c('    for(i=0; i<xcb_parts_idx; i++) {')
1252                 _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1253                 _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1254                 _c('        if (0 != xcb_parts[i].iov_len)')
1255                 _c('            xcb_tmp += xcb_parts[i].iov_len;')
1256                 _c('    }')
1257             
1258         # unserialize: assign variable size fields individually
1259         if 'unserialize' == context:
1260             _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1261             param_fields.reverse()
1262             for field in param_fields:
1263                 if not field.type.fixed_size():
1264                     _c('    xcb_tmp -= %s_len;', field.c_field_name)
1265                     _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1266             _c('    *%s = xcb_out;', aux_ptr)
1267  
1268     _c('')
1269     _c('    return xcb_buffer_len;')
1270     _c('}')
1271 # _c_serialize()
1272
1273 def _c_iterator_get_end(field, accum):
1274     '''
1275     Figures out what C code is needed to find the end of a variable-length structure field.
1276     For nested structures, recurses into its last variable-sized field.
1277     For lists, calls the end function
1278     '''
1279     if field.type.is_container:
1280         accum = field.c_accessor_name + '(' + accum + ')'
1281         return _c_iterator_get_end(field.type.last_varsized_field, accum)
1282     if field.type.is_list:
1283         # XXX we can always use the first way
1284         if field.type.member.is_simple:
1285             return field.c_end_name + '(' + accum + ')'
1286         else:
1287             return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1288
1289 def _c_iterator(self, name):
1290     '''
1291     Declares the iterator structure and next/end functions for a given type.
1292     '''
1293     _h_setlevel(0)
1294     _h('')
1295     _h('/**')
1296     _h(' * @brief %s', self.c_iterator_type)
1297     _h(' **/')
1298     _h('typedef struct %s {', self.c_iterator_type)
1299     _h('    %s *data; /**<  */', self.c_type)
1300     _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1301     _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1302     _h('} %s;', self.c_iterator_type)
1303
1304     _h_setlevel(1)
1305     _c_setlevel(1)
1306     _h('')
1307     _h('/**')
1308     _h(' * Get the next element of the iterator')
1309     _h(' * @param i Pointer to a %s', self.c_iterator_type)
1310     _h(' *')
1311     _h(' * Get the next element in the iterator. The member rem is')
1312     _h(' * decreased by one. The member data points to the next')
1313     _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1314     _h(' */')
1315     _c('')
1316     _hc('')
1317     _hc('/*****************************************************************************')
1318     _hc(' **')
1319     _hc(' ** void %s', self.c_next_name)
1320     _hc(' ** ')
1321     _hc(' ** @param %s *i', self.c_iterator_type)
1322     _hc(' ** @returns void')
1323     _hc(' **')
1324     _hc(' *****************************************************************************/')
1325     _hc(' ')
1326     _hc('void')
1327     _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1328     _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1329     _c('{')
1330
1331     if not self.fixed_size():
1332         _c('    %s *R = i->data;', self.c_type)
1333
1334         if self.is_union:
1335             # FIXME - how to determine the size of a variable size union??
1336             _c('    /* FIXME - determine the size of the union %s */', self.c_type)            
1337         else:
1338             if self.need_sizeof:
1339                 _c('    xcb_generic_iterator_t child;')
1340                 _c('    child.data = (%s *)(((char *)R) + %s(R));', 
1341                    self.c_type, self.c_sizeof_name)
1342                 _c('    i->index = (char *) child.data - (char *) i->data;')
1343             else:
1344                 _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1345                 _c('    i->index = child.index;')
1346             _c('    --i->rem;')
1347             _c('    i->data = (%s *) child.data;', self.c_type)
1348
1349     else:
1350         _c('    --i->rem;')
1351         _c('    ++i->data;')
1352         _c('    i->index += sizeof(%s);', self.c_type)
1353
1354     _c('}')
1355
1356     _h('')
1357     _h('/**')
1358     _h(' * Return the iterator pointing to the last element')
1359     _h(' * @param i An %s', self.c_iterator_type)
1360     _h(' * @return  The iterator pointing to the last element')
1361     _h(' *')
1362     _h(' * Set the current element in the iterator to the last element.')
1363     _h(' * The member rem is set to 0. The member data points to the')
1364     _h(' * last element.')
1365     _h(' */')
1366     _c('')
1367     _hc('')
1368     _hc('/*****************************************************************************')
1369     _hc(' **')
1370     _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1371     _hc(' ** ')
1372     _hc(' ** @param %s i', self.c_iterator_type)
1373     _hc(' ** @returns xcb_generic_iterator_t')
1374     _hc(' **')
1375     _hc(' *****************************************************************************/')
1376     _hc(' ')
1377     _hc('xcb_generic_iterator_t')
1378     _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1379     _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1380     _c('{')
1381     _c('    xcb_generic_iterator_t ret;')
1382
1383     if self.fixed_size():
1384         _c('    ret.data = i.data + i.rem;')
1385         _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1386         _c('    ret.rem = 0;')
1387     else:
1388         _c('    while(i.rem > 0)')
1389         _c('        %s(&i);', self.c_next_name)
1390         _c('    ret.data = i.data;')
1391         _c('    ret.rem = i.rem;')
1392         _c('    ret.index = i.index;')
1393
1394     _c('    return ret;')
1395     _c('}')
1396
1397 def _c_accessor_get_length(expr, field_mapping=None):
1398     '''
1399     Figures out what C code is needed to get a length field.
1400     The field_mapping parameter can be used to change the absolute name of a length field. 
1401     For fields that follow a variable-length field, use the accessor.
1402     Otherwise, just reference the structure field directly.
1403     '''
1404
1405     lenfield_name = expr.lenfield_name
1406     if lenfield_name is not None:
1407         if field_mapping is not None:
1408             lenfield_name = field_mapping[lenfield_name][0]
1409  
1410     if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1411         # special case: variable and fixed size fields are intermixed
1412         # if the lenfield is among the fixed size fields, there is no need
1413         # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1414         return field_mapping(expr.lenfield_name)
1415     elif expr.lenfield_name is not None:
1416         return lenfield_name
1417     else:
1418         return str(expr.nmemb)
1419
1420 def _c_accessor_get_expr(expr, field_mapping):
1421     '''
1422     Figures out what C code is needed to get the length of a list field.
1423     The field_mapping parameter can be used to change the absolute name of a length field. 
1424     Recurses for math operations.
1425     Returns bitcount for value-mask fields.
1426     Otherwise, uses the value of the length field.
1427     '''
1428     lenexp = _c_accessor_get_length(expr, field_mapping)
1429
1430     if expr.op == '~':
1431         return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1432     elif expr.op == 'popcount':
1433         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1434     elif expr.op == 'enumref':
1435         enum_name = expr.lenfield_type.name
1436         constant_name = expr.lenfield_name
1437         c_name = _n(enum_name + (constant_name,)).upper()
1438         return c_name
1439     elif expr.op == 'sumof':
1440         # locate the referenced list object
1441         list_obj = expr.lenfield_type
1442         field = None
1443         for f in expr.lenfield_parent.fields:
1444             if f.field_name == expr.lenfield_name:
1445                 field = f
1446                 break
1447
1448         if field is None:
1449             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1450         list_name = field_mapping[field.c_field_name][0]
1451         c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1452         # note: xcb_sumof() has only been defined for integers
1453         c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1454         return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1455     elif expr.op != None:
1456         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) + 
1457                 ' ' + expr.op + ' ' + 
1458                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1459     elif expr.bitfield:
1460         return 'xcb_popcount(' + lenexp + ')'
1461     else:
1462         return lenexp
1463
1464 def type_pad_type(type):
1465     if type == 'void':
1466         return 'char'
1467     return type
1468
1469 def _c_accessors_field(self, field):
1470     '''
1471     Declares the accessor functions for a non-list field that follows a variable-length field.
1472     '''
1473     c_type = self.c_type
1474
1475     # special case: switch
1476     switch_obj = self if self.is_switch else None
1477     if self.is_bitcase:
1478         switch_obj = self.parents[-1]
1479     if switch_obj is not None:
1480         c_type = switch_obj.c_type
1481
1482     if field.type.is_simple:
1483         _hc('')
1484         _hc('')
1485         _hc('/*****************************************************************************')
1486         _hc(' ** ')
1487         _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1488         _hc(' ** ')
1489         _hc(' ** @param const %s *R', c_type)
1490         _hc(' ** @returns %s', field.c_field_type)
1491         _hc(' **')
1492         _hc(' *****************************************************************************/')
1493         _hc(' ')
1494         _hc('%s', field.c_field_type)
1495         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1496         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1497         _c('{')
1498         if field.prev_varsized_field is None:
1499             _c('    return (%s *) (R + 1);', field.c_field_type)
1500         else:
1501             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1502             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1503                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1504         _c('}')
1505     else:
1506         _hc('')
1507         _hc('')
1508         _hc('/*****************************************************************************')
1509         _hc(' **')
1510         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1511         _hc(' ** ')
1512         _hc(' ** @param const %s *R', c_type)
1513         _hc(' ** @returns %s *', field.c_field_type)
1514         _hc(' **')
1515         _hc(' *****************************************************************************/')
1516         _hc(' ')
1517         if field.type.is_switch and switch_obj is None:
1518             return_type = 'void *'
1519         else:
1520             return_type = '%s *' % field.c_field_type
1521
1522         _hc(return_type)
1523         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1524         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1525         _c('{')
1526         if field.prev_varsized_field is None:
1527             _c('    return (%s) (R + 1);', return_type)
1528             # note: the special case 'variable fields followed by fixed size fields'
1529             #       is not of any consequence here, since the ordering gets 
1530             #       'corrected' in the reply function
1531         else:
1532             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1533             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1534                return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1535         _c('}')
1536
1537     
1538 def _c_accessors_list(self, field):
1539     '''
1540     Declares the accessor functions for a list field.
1541     Declares a direct-accessor function only if the list members are fixed size.
1542     Declares length and get-iterator functions always.
1543     '''
1544     list = field.type
1545     c_type = self.c_type
1546
1547     # special case: switch
1548     # in case of switch, 2 params have to be supplied to certain accessor functions:
1549     #   1. the anchestor object (request or reply)
1550     #   2. the (anchestor) switch object
1551     # the reason is that switch is either a child of a request/reply or nested in another switch, 
1552     # so whenever we need to access a length field, we might need to refer to some anchestor type
1553     switch_obj = self if self.is_switch else None
1554     if self.is_bitcase:
1555         switch_obj = self.parents[-1]
1556     if switch_obj is not None:
1557         c_type = switch_obj.c_type
1558
1559     params = []
1560     fields = {}
1561     parents = self.parents if hasattr(self, 'parents') else [self]
1562     # 'R': parents[0] is always the 'toplevel' container type 
1563     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1564     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1565     # auxiliary object for 'R' parameters
1566     R_obj = parents[0]
1567
1568     if switch_obj is not None:
1569         # now look where the fields are defined that are needed to evaluate 
1570         # the switch expr, and store the parent objects in accessor_params and
1571         # the fields in switch_fields
1572
1573         # 'S': name for the 'toplevel' switch
1574         toplevel_switch = parents[1]
1575         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1576         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1577
1578         # initialize prefix for everything "below" S
1579         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1580         prefix = [(prefix_str, '->', toplevel_switch)]
1581
1582         # look for fields in the remaining containers
1583         for p in parents[2:] + [self]:
1584             # the separator between parent and child is always '.' here, 
1585             # because of nested switch statements
1586             if not p.is_bitcase or (p.is_bitcase and p.has_name):
1587                 prefix.append((p.name[-1], '.', p))
1588             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1589
1590         # auxiliary object for 'S' parameter
1591         S_obj = parents[1]
1592
1593     _h_setlevel(1)
1594     _c_setlevel(1)
1595     if list.member.fixed_size():
1596         idx = 1 if switch_obj is not None else 0
1597         _hc('')
1598         _hc('')
1599         _hc('/*****************************************************************************')
1600         _hc(' **')
1601         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1602         _hc(' ** ')
1603         _hc(' ** @param %s', params[idx][0])
1604         _hc(' ** @returns %s *', field.c_field_type)
1605         _hc(' **')
1606         _hc(' *****************************************************************************/')
1607         _hc(' ')
1608         _hc('%s *', field.c_field_type)
1609
1610         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1611         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1612
1613         _c('{')
1614         if switch_obj is not None:
1615             _c('    return %s;', fields[field.c_field_name][0])
1616         elif field.prev_varsized_field is None:
1617             _c('    return (%s *) (R + 1);', field.c_field_type)
1618         else:
1619             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1620             _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1621                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1622         _c('}')
1623
1624     _hc('')
1625     _hc('')
1626     _hc('/*****************************************************************************')
1627     _hc(' **')
1628     _hc(' ** int %s', field.c_length_name)
1629     _hc(' ** ')
1630     _hc(' ** @param const %s *R', c_type)
1631     _hc(' ** @returns int')
1632     _hc(' **')
1633     _hc(' *****************************************************************************/')
1634     _hc(' ')
1635     _hc('int')
1636     if switch_obj is not None:
1637         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1638         spacing = ' '*(len(field.c_length_name)+2)
1639         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1640         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1641         length = _c_accessor_get_expr(field.type.expr, fields)
1642     else:
1643         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1644         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1645         length = _c_accessor_get_expr(field.type.expr, fields)
1646     _c('{')
1647     _c('    return %s;', length)
1648     _c('}')
1649
1650     if field.type.member.is_simple:
1651         _hc('')
1652         _hc('')
1653         _hc('/*****************************************************************************')
1654         _hc(' **')
1655         _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1656         _hc(' ** ')
1657         _hc(' ** @param const %s *R', c_type)
1658         _hc(' ** @returns xcb_generic_iterator_t')
1659         _hc(' **')
1660         _hc(' *****************************************************************************/')
1661         _hc(' ')
1662         _hc('xcb_generic_iterator_t')
1663         if switch_obj is not None:
1664             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1665             spacing = ' '*(len(field.c_end_name)+2)
1666             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1667             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1668         else:
1669             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1670             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1671         _c('{')
1672         _c('    xcb_generic_iterator_t i;')
1673         
1674         param = 'R' if switch_obj is None else 'S'
1675         if switch_obj is not None:
1676             _c('    i.data = %s + %s;', fields[field.c_field_name][0], 
1677                _c_accessor_get_expr(field.type.expr, fields))
1678         elif field.prev_varsized_field == None:
1679             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, 
1680                _c_accessor_get_expr(field.type.expr, fields))
1681         else:
1682             _c('    xcb_generic_iterator_t child = %s;', 
1683                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1684             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, 
1685                _c_accessor_get_expr(field.type.expr, fields))
1686
1687         _c('    i.rem = 0;')
1688         _c('    i.index = (char *) i.data - (char *) %s;', param)
1689         _c('    return i;')
1690         _c('}')
1691
1692     else:
1693         _hc('')
1694         _hc('')
1695         _hc('/*****************************************************************************')
1696         _hc(' **')
1697         _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1698         _hc(' ** ')
1699         _hc(' ** @param const %s *R', c_type)
1700         _hc(' ** @returns %s', field.c_iterator_type)
1701         _hc(' **')
1702         _hc(' *****************************************************************************/')
1703         _hc(' ')
1704
1705         _hc('%s', field.c_iterator_type)
1706         if switch_obj is not None:
1707             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1708             spacing = ' '*(len(field.c_iterator_name)+2)
1709             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1710             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1711         else:
1712             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1713             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1714         _c('{')
1715         _c('    %s i;', field.c_iterator_type)
1716
1717         if switch_obj is not None:
1718             _c('    i.data = %s;', fields[field.c_field_name][0])
1719             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1720         elif field.prev_varsized_field == None:
1721             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1722         else:
1723             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1724             _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', 
1725                field.c_field_type, type_pad_type(field.c_field_type))
1726         if switch_obj is None:
1727             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1728         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1729         _c('    return i;')
1730         _c('}')
1731
1732 def _c_accessors(self, name, base):
1733     '''
1734     Declares the accessor functions for the fields of a structure.
1735     '''
1736     # no accessors for switch itself - 
1737     # switch always needs to be unpacked explicitly
1738 #    if self.is_switch:
1739 #        pass
1740 #    else:
1741     if True:
1742         for field in self.fields:
1743             if field.type.is_list and not field.type.fixed_size():
1744                 _c_accessors_list(self, field)
1745             elif field.prev_varsized_field is not None or not field.type.fixed_size():
1746                 _c_accessors_field(self, field)
1747
1748 def c_simple(self, name):
1749     '''
1750     Exported function that handles cardinal type declarations.
1751     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1752     '''
1753     _c_type_setup(self, name, ())
1754
1755     if (self.name != name):
1756         # Typedef
1757         _h_setlevel(0)
1758         my_name = _t(name)
1759         _h('')
1760         _h('typedef %s %s;', _t(self.name), my_name)
1761
1762         # Iterator
1763         _c_iterator(self, name)
1764
1765 def _c_complex(self):
1766     '''
1767     Helper function for handling all structure types.
1768     Called for all structs, requests, replies, events, errors.
1769     '''
1770     _h_setlevel(0)
1771     _h('')
1772     _h('/**')
1773     _h(' * @brief %s', self.c_type)
1774     _h(' **/')
1775     _h('typedef %s %s {', self.c_container, self.c_type)
1776
1777     struct_fields = []
1778     maxtypelen = 0
1779
1780     varfield = None
1781     for field in self.fields:
1782         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1783             varfield = field.c_field_name
1784             continue
1785         if field.wire:
1786             struct_fields.append(field)
1787     
1788     for field in struct_fields:
1789         length = len(field.c_field_type)
1790         # account for '*' pointer_spec
1791         if not field.type.fixed_size() and not self.is_union:
1792             length += 1
1793         maxtypelen = max(maxtypelen, length)
1794
1795     def _c_complex_field(self, field, space=''):
1796         if (field.type.fixed_size() or self.is_union or
1797             # in case of switch with switch children, don't make the field a pointer
1798             # necessary for unserialize to work
1799             (self.is_switch and field.type.is_switch)):
1800             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1801             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1802         else:
1803             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1804             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1805
1806     if not self.is_switch:
1807         for field in struct_fields:
1808             _c_complex_field(self, field)
1809     else:
1810         for b in self.bitcases:
1811             space = ''
1812             if b.type.has_name:
1813                 _h('    struct _%s {', b.c_field_name)
1814                 space = '    '
1815             for field in b.type.fields:
1816                 _c_complex_field(self, field, space)
1817             if b.type.has_name:
1818                 _h('    } %s;', b.c_field_name)
1819
1820     _h('} %s;', self.c_type)
1821
1822 def c_struct(self, name):
1823     '''
1824     Exported function that handles structure declarations.
1825     '''
1826     _c_type_setup(self, name, ())
1827     _c_complex(self)
1828     _c_accessors(self, name, name)
1829     _c_iterator(self, name)
1830
1831 def c_union(self, name):
1832     '''
1833     Exported function that handles union declarations.
1834     '''
1835     _c_type_setup(self, name, ())
1836     _c_complex(self)
1837     _c_iterator(self, name)
1838
1839 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1840     '''
1841     Declares a request function.
1842     '''
1843
1844     # Four stunningly confusing possibilities here:
1845     #
1846     #   Void            Non-void
1847     # ------------------------------
1848     # "req"            "req"
1849     # 0 flag           CHECKED flag   Normal Mode
1850     # void_cookie      req_cookie
1851     # ------------------------------
1852     # "req_checked"    "req_unchecked"
1853     # CHECKED flag     0 flag         Abnormal Mode
1854     # void_cookie      req_cookie
1855     # ------------------------------
1856
1857
1858     # Whether we are _checked or _unchecked
1859     checked = void and not regular
1860     unchecked = not void and not regular
1861
1862     # What kind of cookie we return
1863     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1864
1865     # What flag is passed to xcb_request
1866     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1867
1868     if reply_fds:
1869         if func_flags == '0':
1870             func_flags = 'XCB_REQUEST_REPLY_FDS'
1871         else:
1872             func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1873
1874     # Global extension id variable or NULL for xproto
1875     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1876
1877     # What our function name is
1878     func_name = self.c_request_name if not aux else self.c_aux_name
1879     if checked:
1880         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1881     if unchecked:
1882         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1883
1884     param_fields = []
1885     wire_fields = []
1886     maxtypelen = len('xcb_connection_t')
1887     serial_fields = []
1888     # special case: list with variable size elements
1889     list_with_var_size_elems = False
1890
1891     for field in self.fields:
1892         if field.visible:
1893             # The field should appear as a call parameter
1894             param_fields.append(field)
1895         if field.wire and not field.auto:
1896             # We need to set the field up in the structure
1897             wire_fields.append(field)
1898         if field.type.need_serialize or field.type.need_sizeof:
1899             serial_fields.append(field)
1900         
1901     for field in param_fields:
1902         c_field_const_type = field.c_field_const_type 
1903         if field.type.need_serialize and not aux:
1904             c_field_const_type = "const void"
1905         if len(c_field_const_type) > maxtypelen:
1906             maxtypelen = len(c_field_const_type)
1907         if field.type.is_list and not field.type.member.fixed_size():
1908             list_with_var_size_elems = True
1909
1910     _h_setlevel(1)
1911     _c_setlevel(1)
1912     _h('')
1913     _h('/**')
1914     if hasattr(self, "doc") and self.doc:
1915         if self.doc.brief:
1916             _h(' * @brief ' + self.doc.brief)
1917         else:
1918             _h(' * No brief doc yet')
1919
1920     _h(' *')
1921     _h(' * @param c The connection')
1922     param_names = [f.c_field_name for f in param_fields]
1923     if hasattr(self, "doc") and self.doc:
1924         for field in param_fields:
1925             # XXX: hard-coded until we fix xproto.xml
1926             base_func_name = self.c_request_name if not aux else self.c_aux_name
1927             if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1928                 field.enum = 'GC'
1929             elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1930                 field.enum = 'CW'
1931             elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1932                 field.enum = 'CW'
1933             if field.enum:
1934                 # XXX: why the 'xcb' prefix?
1935                 key = ('xcb', field.enum)
1936
1937                 tname = _t(key)
1938                 if namecount[tname] > 1:
1939                     tname = _t(key + ('enum',))
1940                 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1941
1942             if self.doc and field.field_name in self.doc.fields:
1943                 desc = self.doc.fields[field.field_name]
1944                 for name in param_names:
1945                     desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1946                 desc = desc.split("\n")
1947                 desc = [line if line != '' else '\\n' for line in desc]
1948                 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1949             # If there is no documentation yet, we simply don't generate an
1950             # @param tag. Doxygen will then warn about missing documentation.
1951
1952     _h(' * @return A cookie')
1953     _h(' *')
1954
1955     if hasattr(self, "doc") and self.doc:
1956         if self.doc.description:
1957             desc = self.doc.description
1958             for name in param_names:
1959                 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1960             desc = desc.split("\n")
1961             _h(' * ' + "\n * ".join(desc))
1962         else:
1963             _h(' * No description yet')
1964     else:
1965         _h(' * Delivers a request to the X server.')
1966     _h(' * ')
1967     if checked:
1968         _h(' * This form can be used only if the request will not cause')
1969         _h(' * a reply to be generated. Any returned error will be')
1970         _h(' * saved for handling by xcb_request_check().')
1971     if unchecked:
1972         _h(' * This form can be used only if the request will cause')
1973         _h(' * a reply to be generated. Any returned error will be')
1974         _h(' * placed in the event queue.')
1975     _h(' */')
1976     _c('')
1977     _hc('')
1978     _hc('/*****************************************************************************')
1979     _hc(' **')
1980     _hc(' ** %s %s', cookie_type, func_name)
1981     _hc(' ** ')
1982
1983     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1984     _hc(' ** @param xcb_connection_t%s *c', spacing)
1985
1986     for field in param_fields:
1987         c_field_const_type = field.c_field_const_type 
1988         if field.type.need_serialize and not aux:
1989             c_field_const_type = "const void"
1990         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1991         _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1992
1993     _hc(' ** @returns %s', cookie_type)
1994     _hc(' **')
1995     _hc(' *****************************************************************************/')
1996     _hc(' ')
1997     _hc('%s', cookie_type)
1998
1999     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2000     comma = ',' if len(param_fields) else ');'
2001     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2002     comma = ',' if len(param_fields) else ')'
2003     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2004
2005     func_spacing = ' ' * (len(func_name) + 2)
2006     count = len(param_fields)
2007     for field in param_fields:
2008         count = count - 1
2009         c_field_const_type = field.c_field_const_type 
2010         c_pointer = field.c_pointer
2011         if field.type.need_serialize and not aux:
2012             c_field_const_type = "const void"
2013             c_pointer = '*'
2014         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2015         comma = ',' if count else ');'
2016         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
2017            spacing, c_pointer, field.c_field_name, comma)
2018         comma = ',' if count else ')'
2019         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
2020            spacing, c_pointer, field.c_field_name, comma)
2021
2022     count = 2
2023     if not self.var_followed_by_fixed_fields:
2024         for field in param_fields:
2025             if not field.type.fixed_size():
2026                 count = count + 2
2027                 if field.type.need_serialize:
2028                     # _serialize() keeps track of padding automatically
2029                     count -= 1
2030     dimension = count + 2
2031
2032     _c('{')
2033     _c('    static const xcb_protocol_request_t xcb_req = {')
2034     _c('        /* count */ %d,', count)
2035     _c('        /* ext */ %s,', func_ext_global)
2036     _c('        /* opcode */ %s,', self.c_request_name.upper())
2037     _c('        /* isvoid */ %d', 1 if void else 0)
2038     _c('    };')
2039     _c('    ')
2040
2041     _c('    struct iovec xcb_parts[%d];', dimension)
2042     _c('    %s xcb_ret;', func_cookie)
2043     _c('    %s xcb_out;', self.c_type)
2044     if self.var_followed_by_fixed_fields:
2045         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2046         _c('    void *xcb_aux = 0;')
2047         
2048
2049     for idx, f in enumerate(serial_fields):
2050         if aux:
2051             _c('    void *xcb_aux%d = 0;' % (idx))
2052     if list_with_var_size_elems:
2053         _c('    unsigned int i;')
2054         _c('    unsigned int xcb_tmp_len;')
2055         _c('    char *xcb_tmp;')
2056     _c('    ')
2057     # simple request call tracing
2058 #    _c('    printf("in function %s\\n");' % func_name)     
2059  
2060     # fixed size fields
2061     for field in wire_fields:
2062         if field.type.fixed_size():
2063             if field.type.is_expr:
2064                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2065             elif field.type.is_pad:
2066                 if field.type.nmemb == 1:
2067                     _c('    xcb_out.%s = 0;', field.c_field_name)
2068                 else:
2069                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2070             else:
2071                 if field.type.nmemb == 1:
2072                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2073                 else:
2074                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2075
2076     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2077         serialize_args = get_serialize_params(context, type_obj, 
2078                                               c_field_name, 
2079                                               aux_var)[2]
2080         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2081
2082     # calls in order to free dyn. all. memory
2083     free_calls = []
2084
2085     _c('    ')
2086     if not self.var_followed_by_fixed_fields:
2087         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2088         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2089         _c('    xcb_parts[3].iov_base = 0;')
2090         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2091
2092         count = 4
2093
2094         for field in param_fields:
2095             if not field.type.fixed_size():
2096                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2097                 # default: simple cast to char *
2098                 if not field.type.need_serialize and not field.type.need_sizeof:
2099                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2100                     if field.type.is_list:
2101                         if field.type.member.fixed_size():
2102                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 
2103                                _c_accessor_get_expr(field.type.expr, None), 
2104                                field.type.member.c_wiretype)
2105                         else:
2106                             list_length = _c_accessor_get_expr(field.type.expr, None)
2107     
2108                             length = ''
2109                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2110                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2111                             _c("    for(i=0; i<%s; i++) {" % list_length)
2112                             _c("        xcb_tmp_len = %s(xcb_tmp);" % 
2113                                               (field.type.c_sizeof_name))
2114                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2115                             _c("        xcb_tmp += xcb_tmp_len;")
2116                             _c("    }")                        
2117                     else:
2118                         # not supposed to happen
2119                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2120                 else:
2121                     if not aux:
2122                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2123                     idx = serial_fields.index(field)
2124                     aux_var = '&xcb_aux%d' % idx
2125                     context = 'serialize' if aux else 'sizeof'
2126                     _c('    xcb_parts[%d].iov_len = ', count)
2127                     if aux:
2128                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2129                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2130                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2131                         free_calls.append('    free(xcb_aux%d);' % idx)
2132                     else:
2133                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2134                         func_name = field.type.c_sizeof_name
2135                         _c('      %s (%s);', func_name, serialize_args)
2136
2137                 count += 1
2138                 if not (field.type.need_serialize or field.type.need_sizeof):
2139                     # the _serialize() function keeps track of padding automatically
2140                     _c('    xcb_parts[%d].iov_base = 0;', count)
2141                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2142                     count += 1
2143
2144     # elif self.var_followed_by_fixed_fields:
2145     else:
2146         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2147         # request header: opcodes + length
2148         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);') 
2149         count += 1
2150         # call _serialize()
2151         buffer_var = '&xcb_aux'
2152         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2153         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2154         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2155         free_calls.append('    free(xcb_aux);')
2156         # no padding necessary - _serialize() keeps track of padding automatically
2157
2158     _c('    ')
2159     for field in param_fields:
2160         if field.isfd:
2161             _c('    xcb_send_fd(c, %s);', field.c_field_name)
2162     
2163     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2164     
2165     # free dyn. all. data, if any
2166     for f in free_calls:
2167         _c(f)
2168     _c('    return xcb_ret;')
2169     _c('}')
2170
2171 def _c_reply(self, name):
2172     '''
2173     Declares the function that returns the reply structure.
2174     '''
2175     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2176     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2177     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2178     
2179     # check if _unserialize() has to be called for any field
2180     def look_for_special_cases(complex_obj):
2181         unserialize_fields = []
2182         # no unserialize call in case of switch
2183         if not complex_obj.is_switch:
2184             for field in complex_obj.fields:
2185                 # three cases: 1. field with special case
2186                 #              2. container that contains special case field
2187                 #              3. list with special case elements
2188                 if field.type.var_followed_by_fixed_fields:
2189                     unserialize_fields.append(field)
2190                 elif field.type.is_container:
2191                     unserialize_fields += look_for_special_cases(field.type)
2192                 elif field.type.is_list:
2193                     if field.type.member.var_followed_by_fixed_fields:
2194                         unserialize_fields.append(field)
2195                     if field.type.member.is_container:
2196                         unserialize_fields += look_for_special_cases(field.type.member)
2197         return unserialize_fields
2198     
2199     unserialize_fields = look_for_special_cases(self.reply)
2200     
2201     _h('')
2202     _h('/**')
2203     _h(' * Return the reply')
2204     _h(' * @param c      The connection')
2205     _h(' * @param cookie The cookie')
2206     _h(' * @param e      The xcb_generic_error_t supplied')
2207     _h(' *')
2208     _h(' * Returns the reply of the request asked by')
2209     _h(' * ')
2210     _h(' * The parameter @p e supplied to this function must be NULL if')
2211     _h(' * %s(). is used.', self.c_unchecked_name)
2212     _h(' * Otherwise, it stores the error if any.')
2213     _h(' *')
2214     _h(' * The returned value must be freed by the caller using free().')
2215     _h(' */')
2216     _c('')
2217     _hc('')
2218     _hc('/*****************************************************************************')
2219     _hc(' **')
2220     _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2221     _hc(' ** ')
2222     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2223     _hc(' ** @param %s   cookie', self.c_cookie_type)
2224     _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2225     _hc(' ** @returns %s *', self.c_reply_type)
2226     _hc(' **')
2227     _hc(' *****************************************************************************/')
2228     _hc(' ')
2229     _hc('%s *', self.c_reply_type)
2230     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2231     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2232     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2233     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2234     _c('{')
2235     
2236     if len(unserialize_fields)>0:
2237         # certain variable size fields need to be unserialized explicitly
2238         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', 
2239            self.c_reply_type, self.c_reply_type)
2240         _c('    int i;')
2241         for field in unserialize_fields:
2242             if field.type.is_list:
2243                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2244                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2245                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2246             else:
2247                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2248         # call _unserialize(), using the reply as source and target buffer
2249         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2250         for field in unserialize_fields:
2251             if field.type.is_list:
2252                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2253                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2254                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name, 
2255                    field.c_field_name, field.c_field_name)
2256                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2257                 _c('    }')
2258         # return the transformed reply
2259         _c('    return reply;')
2260     
2261     else:
2262         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2263
2264     _c('}')
2265
2266 def _c_reply_has_fds(self):
2267     for field in self.fields:
2268         if field.isfd:
2269             return True
2270     return False
2271
2272 def _c_reply_fds(self, name):
2273     '''
2274     Declares the function that returns fds related to the reply.
2275     '''
2276     spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2277     spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2278     _h('')
2279     _h('/**')
2280     _h(' * Return the reply fds')
2281     _h(' * @param c      The connection')
2282     _h(' * @param reply  The reply')
2283     _h(' *')
2284     _h(' * Returns the array of reply fds of the request asked by')
2285     _h(' * ')
2286     _h(' * The returned value must be freed by the caller using free().')
2287     _h(' */')
2288     _c('')
2289     _hc('')
2290     _hc('/*****************************************************************************')
2291     _hc(' **')
2292     _hc(' ** int * %s', self.c_reply_fds_name)
2293     _hc(' ** ')
2294     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2295     _hc(' ** @param %s  *reply', self.c_reply_type)
2296     _hc(' ** @returns int *')
2297     _hc(' **')
2298     _hc(' *****************************************************************************/')
2299     _hc(' ')
2300     _hc('int *')
2301     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2302     _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2303     _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2304     _c('{')
2305     
2306     _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2307
2308     _c('}')
2309     
2310
2311 def _c_opcode(name, opcode):
2312     '''
2313     Declares the opcode define for requests, events, and errors.
2314     '''
2315     _h_setlevel(0)
2316     _h('')
2317     _h('/** Opcode for %s. */', _n(name))
2318     _h('#define %s %s', _n(name).upper(), opcode)
2319     
2320 def _c_cookie(self, name):
2321     '''
2322     Declares the cookie type for a non-void request.
2323     '''
2324     _h_setlevel(0)
2325     _h('')
2326     _h('/**')
2327     _h(' * @brief %s', self.c_cookie_type)
2328     _h(' **/')
2329     _h('typedef struct %s {', self.c_cookie_type)
2330     _h('    unsigned int sequence; /**<  */')
2331     _h('} %s;', self.c_cookie_type)
2332
2333 def _man_request(self, name, cookie_type, void, aux):
2334     param_fields = [f for f in self.fields if f.visible]
2335
2336     func_name = self.c_request_name if not aux else self.c_aux_name
2337
2338     def create_link(linkname):
2339         name = 'man/%s.3' % linkname
2340         if manpaths:
2341             sys.stdout.write(name)
2342         f = open(name, 'w')
2343         f.write('.so man3/%s.3' % func_name)
2344         f.close()
2345
2346     if manpaths:
2347         sys.stdout.write('man/%s.3 ' % func_name)
2348     # Our CWD is src/, so this will end up in src/man/
2349     f = open('man/%s.3' % func_name, 'w')
2350     f.write('.TH %s 3  %s "XCB" "XCB Requests"\n' % (func_name, today))
2351     # Left-adjust instead of adjusting to both sides
2352     f.write('.ad l\n')
2353     f.write('.SH NAME\n')
2354     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2355     f.write('%s \\- %s\n' % (func_name, brief))
2356     f.write('.SH SYNOPSIS\n')
2357     # Don't split words (hyphenate)
2358     f.write('.hy 0\n')
2359     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2360
2361     # function prototypes
2362     prototype = ''
2363     count = len(param_fields)
2364     for field in param_fields:
2365         count = count - 1
2366         c_field_const_type = field.c_field_const_type
2367         c_pointer = field.c_pointer
2368         if c_pointer == ' ':
2369             c_pointer = ''
2370         if field.type.need_serialize and not aux:
2371             c_field_const_type = "const void"
2372             c_pointer = '*'
2373         comma = ', ' if count else ');'
2374         prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2375
2376     f.write('.SS Request function\n')
2377     f.write('.HP\n')
2378     base_func_name = self.c_request_name if not aux else self.c_aux_name
2379     f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2380     create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2381     if not void:
2382         f.write('.PP\n')
2383         f.write('.SS Reply datastructure\n')
2384         f.write('.nf\n')
2385         f.write('.sp\n')
2386         f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2387         struct_fields = []
2388         maxtypelen = 0
2389
2390         for field in self.reply.fields:
2391             if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2392                 continue
2393             if field.wire:
2394                 struct_fields.append(field)
2395
2396         for field in struct_fields:
2397             length = len(field.c_field_type)
2398             # account for '*' pointer_spec
2399             if not field.type.fixed_size():
2400                 length += 1
2401             maxtypelen = max(maxtypelen, length)
2402
2403         def _c_complex_field(self, field, space=''):
2404             if (field.type.fixed_size() or
2405                 # in case of switch with switch children, don't make the field a pointer
2406                 # necessary for unserialize to work
2407                 (self.is_switch and field.type.is_switch)):
2408                 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2409                 f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2410             else:
2411                 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2412                 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2413                 #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2414
2415         if not self.is_switch:
2416             for field in struct_fields:
2417                 _c_complex_field(self, field)
2418         else:
2419             for b in self.bitcases:
2420                 space = ''
2421                 if b.type.has_name:
2422                     space = '    '
2423                 for field in b.type.fields:
2424                     _c_complex_field(self, field, space)
2425                 if b.type.has_name:
2426                     print >> sys.stderr, 'ERROR: New unhandled documentation case'
2427                     pass
2428
2429         f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2430         f.write('.fi\n')
2431
2432         f.write('.SS Reply function\n')
2433         f.write('.HP\n')
2434         f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2435                  '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2436                 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2437         create_link('%s' % self.c_reply_name)
2438
2439         has_accessors = False
2440         for field in self.reply.fields:
2441             if field.type.is_list and not field.type.fixed_size():
2442                 has_accessors = True
2443             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2444                 has_accessors = True
2445
2446         if has_accessors:
2447             f.write('.SS Reply accessors\n')
2448
2449         def _c_accessors_field(self, field):
2450             '''
2451             Declares the accessor functions for a non-list field that follows a variable-length field.
2452             '''
2453             c_type = self.c_type
2454
2455             # special case: switch
2456             switch_obj = self if self.is_switch else None
2457             if self.is_bitcase:
2458                 switch_obj = self.parents[-1]
2459             if switch_obj is not None:
2460                 c_type = switch_obj.c_type
2461
2462             if field.type.is_simple:
2463                 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2464                 create_link('%s' % field.c_accessor_name)
2465             else:
2466                 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2467                 create_link('%s' % field.c_accessor_name)
2468
2469         def _c_accessors_list(self, field):
2470             '''
2471             Declares the accessor functions for a list field.
2472             Declares a direct-accessor function only if the list members are fixed size.
2473             Declares length and get-iterator functions always.
2474             '''
2475             list = field.type
2476             c_type = self.reply.c_type
2477
2478             # special case: switch
2479             # in case of switch, 2 params have to be supplied to certain accessor functions:
2480             #   1. the anchestor object (request or reply)
2481             #   2. the (anchestor) switch object
2482             # the reason is that switch is either a child of a request/reply or nested in another switch,
2483             # so whenever we need to access a length field, we might need to refer to some anchestor type
2484             switch_obj = self if self.is_switch else None
2485             if self.is_bitcase:
2486                 switch_obj = self.parents[-1]
2487             if switch_obj is not None:
2488                 c_type = switch_obj.c_type
2489
2490             params = []
2491             fields = {}
2492             parents = self.parents if hasattr(self, 'parents') else [self]
2493             # 'R': parents[0] is always the 'toplevel' container type
2494             params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2495             fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2496             # auxiliary object for 'R' parameters
2497             R_obj = parents[0]
2498
2499             if switch_obj is not None:
2500                 # now look where the fields are defined that are needed to evaluate
2501                 # the switch expr, and store the parent objects in accessor_params and
2502                 # the fields in switch_fields
2503
2504                 # 'S': name for the 'toplevel' switch
2505                 toplevel_switch = parents[1]
2506                 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2507                 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2508
2509                 # initialize prefix for everything "below" S
2510                 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2511                 prefix = [(prefix_str, '->', toplevel_switch)]
2512
2513                 # look for fields in the remaining containers
2514                 for p in parents[2:] + [self]:
2515                     # the separator between parent and child is always '.' here,
2516                     # because of nested switch statements
2517                     if not p.is_bitcase or (p.is_bitcase and p.has_name):
2518                         prefix.append((p.name[-1], '.', p))
2519                     fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2520
2521                 # auxiliary object for 'S' parameter
2522                 S_obj = parents[1]
2523
2524             if list.member.fixed_size():
2525                 idx = 1 if switch_obj is not None else 0
2526                 f.write('.HP\n')
2527                 f.write('%s *\\fB%s\\fP(%s);\n' %
2528                         (field.c_field_type, field.c_accessor_name, params[idx][0]))
2529                 create_link('%s' % field.c_accessor_name)
2530
2531             f.write('.HP\n')
2532             f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2533                     (field.c_length_name, c_type))
2534             create_link('%s' % field.c_length_name)
2535
2536             if field.type.member.is_simple:
2537                 f.write('.HP\n')
2538                 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2539                         (field.c_end_name, c_type))
2540                 create_link('%s' % field.c_end_name)
2541             else:
2542                 f.write('.HP\n')
2543                 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2544                         (field.c_iterator_type, field.c_iterator_name,
2545                          c_type))
2546                 create_link('%s' % field.c_iterator_name)
2547
2548         for field in self.reply.fields:
2549             if field.type.is_list and not field.type.fixed_size():
2550                 _c_accessors_list(self, field)
2551             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2552                 _c_accessors_field(self, field)
2553
2554
2555     f.write('.br\n')
2556     # Re-enable hyphenation and adjusting to both sides
2557     f.write('.hy 1\n')
2558
2559     # argument reference
2560     f.write('.SH REQUEST ARGUMENTS\n')
2561     f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2562     f.write('The XCB connection to X11.\n')
2563     for field in param_fields:
2564         f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2565         printed_enum = False
2566         # XXX: hard-coded until we fix xproto.xml
2567         if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2568             field.enum = 'GC'
2569         elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2570             field.enum = 'CW'
2571         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2572             field.enum = 'CW'
2573         if hasattr(field, "enum") and field.enum:
2574             # XXX: why the 'xcb' prefix?
2575             key = ('xcb', field.enum)
2576             if key in enums:
2577                 f.write('One of the following values:\n')
2578                 f.write('.RS 1i\n')
2579                 enum = enums[key]
2580                 count = len(enum.values)
2581                 for (enam, eval) in enum.values:
2582                     count = count - 1
2583                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2584                     if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2585                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2586                         f.write('%s\n' % desc)
2587                     else:
2588                         f.write('TODO: NOT YET DOCUMENTED.\n')
2589                 f.write('.RE\n')
2590                 f.write('.RS 1i\n')
2591                 printed_enum = True
2592
2593         if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2594             desc = self.doc.fields[field.field_name]
2595             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2596             if printed_enum:
2597                 f.write('\n')
2598             f.write('%s\n' % desc)
2599         else:
2600             f.write('TODO: NOT YET DOCUMENTED.\n')
2601         if printed_enum:
2602             f.write('.RE\n')
2603
2604     # Reply reference
2605     if not void:
2606         f.write('.SH REPLY FIELDS\n')
2607         # These fields are present in every reply:
2608         f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2609         f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2610                  'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2611                  'be used to tell replies apart from each other.\n') %
2612                  _n(self.reply.name).upper())
2613         f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2614         f.write('The sequence number of the last request processed by the X11 server.\n')
2615         f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2616         f.write('The length of the reply, in words (a word is 4 bytes).\n')
2617         for field in self.reply.fields:
2618             if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2619                 field.c_field_name.startswith('pad')):
2620                 continue
2621
2622             if field.type.is_list and not field.type.fixed_size():
2623                 continue
2624             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2625                 continue
2626             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2627             printed_enum = False
2628             if hasattr(field, "enum") and field.enum:
2629                 # XXX: why the 'xcb' prefix?
2630                 key = ('xcb', field.enum)
2631                 if key in enums:
2632                     f.write('One of the following values:\n')
2633                     f.write('.RS 1i\n')
2634                     enum = enums[key]
2635                     count = len(enum.values)
2636                     for (enam, eval) in enum.values:
2637                         count = count - 1
2638                         f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2639                         if enum.doc and enam in enum.doc.fields:
2640                             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2641                             f.write('%s\n' % desc)
2642                         else:
2643                             f.write('TODO: NOT YET DOCUMENTED.\n')
2644                     f.write('.RE\n')
2645                     f.write('.RS 1i\n')
2646                     printed_enum = True
2647
2648             if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2649                 desc = self.reply.doc.fields[field.field_name]
2650                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2651                 if printed_enum:
2652                     f.write('\n')
2653                 f.write('%s\n' % desc)
2654             else:
2655                 f.write('TODO: NOT YET DOCUMENTED.\n')
2656             if printed_enum:
2657                 f.write('.RE\n')
2658
2659
2660
2661     # text description
2662     f.write('.SH DESCRIPTION\n')
2663     if hasattr(self, "doc") and self.doc and self.doc.description:
2664         desc = self.doc.description
2665         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2666         lines = desc.split('\n')
2667         f.write('\n'.join(lines) + '\n')
2668
2669     f.write('.SH RETURN VALUE\n')
2670     if void:
2671         f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2672                  'have to be handled in the event loop.\n\nIf you want to '
2673                  'handle errors directly with \\fIxcb_request_check\\fP '
2674                  'instead, use \\fI%s_checked\\fP. See '
2675                  '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
2676     else:
2677         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2678                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2679                  'handle errors in the event loop instead, use '
2680                  '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
2681                  'details.\n') %
2682                 (cookie_type, self.c_reply_name, base_func_name))
2683     f.write('.SH ERRORS\n')
2684     if hasattr(self, "doc") and self.doc:
2685         for errtype, errtext in self.doc.errors.items():
2686             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2687             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2688             f.write('%s\n' % (errtext))
2689     if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2690         f.write('This request does never generate any errors.\n')
2691     if hasattr(self, "doc") and self.doc and self.doc.example:
2692         f.write('.SH EXAMPLE\n')
2693         f.write('.nf\n')
2694         f.write('.sp\n')
2695         lines = self.doc.example.split('\n')
2696         f.write('\n'.join(lines) + '\n')
2697         f.write('.fi\n')
2698     f.write('.SH SEE ALSO\n')
2699     if hasattr(self, "doc") and self.doc:
2700         see = ['.BR %s (3)' % 'xcb-requests']
2701         if self.doc.example:
2702             see.append('.BR %s (3)' % 'xcb-examples')
2703         for seename, seetype in self.doc.see.items():
2704             if seetype == 'program':
2705                 see.append('.BR %s (1)' % seename)
2706             elif seetype == 'event':
2707                 see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2708             elif seetype == 'request':
2709                 see.append('.BR %s (3)' % _n(('xcb', seename)))
2710             elif seetype == 'function':
2711                 see.append('.BR %s (3)' % seename)
2712             else:
2713                 see.append('TODO: %s (type %s)' % (seename, seetype))
2714         f.write(',\n'.join(see) + '\n')
2715     f.write('.SH AUTHOR\n')
2716     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2717     f.close()
2718
2719 def _man_event(self, name):
2720     if manpaths:
2721         sys.stdout.write('man/%s.3 ' % self.c_type)
2722     # Our CWD is src/, so this will end up in src/man/
2723     f = open('man/%s.3' % self.c_type, 'w')
2724     f.write('.TH %s 3  %s "XCB" "XCB Events"\n' % (self.c_type, today))
2725     # Left-adjust instead of adjusting to both sides
2726     f.write('.ad l\n')
2727     f.write('.SH NAME\n')
2728     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2729     f.write('%s \\- %s\n' % (self.c_type, brief))
2730     f.write('.SH SYNOPSIS\n')
2731     # Don't split words (hyphenate)
2732     f.write('.hy 0\n')
2733     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2734
2735     f.write('.PP\n')
2736     f.write('.SS Event datastructure\n')
2737     f.write('.nf\n')
2738     f.write('.sp\n')
2739     f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2740     struct_fields = []
2741     maxtypelen = 0
2742
2743     for field in self.fields:
2744         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2745             continue
2746         if field.wire:
2747             struct_fields.append(field)
2748
2749     for field in struct_fields:
2750         length = len(field.c_field_type)
2751         # account for '*' pointer_spec
2752         if not field.type.fixed_size():
2753             length += 1
2754         maxtypelen = max(maxtypelen, length)
2755
2756     def _c_complex_field(self, field, space=''):
2757         if (field.type.fixed_size() or
2758             # in case of switch with switch children, don't make the field a pointer
2759             # necessary for unserialize to work
2760             (self.is_switch and field.type.is_switch)):
2761             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2762             f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2763         else:
2764             print >> sys.stderr, 'ERROR: New unhandled documentation case'
2765
2766     if not self.is_switch:
2767         for field in struct_fields:
2768             _c_complex_field(self, field)
2769     else:
2770         for b in self.bitcases:
2771             space = ''
2772             if b.type.has_name:
2773                 space = '    '
2774             for field in b.type.fields:
2775                 _c_complex_field(self, field, space)
2776             if b.type.has_name:
2777                 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2778                 pass
2779
2780     f.write('} \\fB%s\\fP;\n' % self.c_type)
2781     f.write('.fi\n')
2782
2783
2784     f.write('.br\n')
2785     # Re-enable hyphenation and adjusting to both sides
2786     f.write('.hy 1\n')
2787
2788     # argument reference
2789     f.write('.SH EVENT FIELDS\n')
2790     f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2791     f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2792              'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2793              'to tell events apart from each other.\n') % _n(name).upper())
2794     f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2795     f.write('The sequence number of the last request processed by the X11 server.\n')
2796
2797     if not self.is_switch:
2798         for field in struct_fields:
2799             # Skip the fields which every event has, we already documented
2800             # them (see above).
2801             if field.c_field_name in ('response_type', 'sequence'):
2802                 continue
2803             if isinstance(field.type, PadType):
2804                 continue
2805             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2806             if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2807                 desc = self.doc.fields[field.field_name]
2808                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2809                 f.write('%s\n' % desc)
2810             else:
2811                 f.write('NOT YET DOCUMENTED.\n')
2812
2813     # text description
2814     f.write('.SH DESCRIPTION\n')
2815     if hasattr(self, "doc") and self.doc and self.doc.description:
2816         desc = self.doc.description
2817         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2818         lines = desc.split('\n')
2819         f.write('\n'.join(lines) + '\n')
2820
2821     if hasattr(self, "doc") and self.doc and self.doc.example:
2822         f.write('.SH EXAMPLE\n')
2823         f.write('.nf\n')
2824         f.write('.sp\n')
2825         lines = self.doc.example.split('\n')
2826         f.write('\n'.join(lines) + '\n')
2827         f.write('.fi\n')
2828     f.write('.SH SEE ALSO\n')
2829     if hasattr(self, "doc") and self.doc:
2830         see = ['.BR %s (3)' % 'xcb_generic_event_t']
2831         if self.doc.example:
2832             see.append('.BR %s (3)' % 'xcb-examples')
2833         for seename, seetype in self.doc.see.items():
2834             if seetype == 'program':
2835                 see.append('.BR %s (1)' % seename)
2836             elif seetype == 'event':
2837                 see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
2838             elif seetype == 'request':
2839                 see.append('.BR %s (3)' % _n(('xcb', seename)))
2840             elif seetype == 'function':
2841                 see.append('.BR %s (3)' % seename)
2842             else:
2843                 see.append('TODO: %s (type %s)' % (seename, seetype))
2844         f.write(',\n'.join(see) + '\n')
2845     f.write('.SH AUTHOR\n')
2846     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2847     f.close()
2848
2849
2850 def c_request(self, name):
2851     '''
2852     Exported function that handles request declarations.
2853     '''
2854     _c_type_setup(self, name, ('request',))
2855
2856     if self.reply:
2857         # Cookie type declaration
2858         _c_cookie(self, name)
2859
2860     # Opcode define
2861     _c_opcode(name, self.opcode)
2862
2863     # Request structure declaration
2864     _c_complex(self)
2865
2866     if self.reply:
2867         _c_type_setup(self.reply, name, ('reply',))
2868         # Reply structure definition
2869         _c_complex(self.reply)
2870         # Request prototypes
2871         has_fds = _c_reply_has_fds(self.reply)
2872         _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2873         _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2874         if self.need_aux:
2875             _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2876             _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2877         # Reply accessors
2878         _c_accessors(self.reply, name + ('reply',), name)
2879         _c_reply(self, name)
2880         if has_fds:
2881             _c_reply_fds(self, name)
2882     else:
2883         # Request prototypes
2884         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2885         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2886         if self.need_aux:
2887             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2888             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2889
2890     # We generate the manpage afterwards because _c_type_setup has been called.
2891     # TODO: what about aux helpers?
2892     cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2893     _man_request(self, name, cookie_type, not self.reply, False)
2894
2895 def c_event(self, name):
2896     '''
2897     Exported function that handles event declarations.
2898     '''
2899
2900     # The generic event structure xcb_ge_event_t has the full_sequence field
2901     # at the 32byte boundary. That's why we've to inject this field into GE
2902     # events while generating the structure for them. Otherwise we would read
2903     # garbage (the internal full_sequence) when accessing normal event fields
2904     # there.
2905     if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2906         event_size = 0
2907         for field in self.fields:
2908             if field.type.size != None and field.type.nmemb != None:
2909                 event_size += field.type.size * field.type.nmemb
2910             if event_size == 32:
2911                 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2912                 idx = self.fields.index(field)
2913                 self.fields.insert(idx + 1, full_sequence)
2914                 break
2915
2916     _c_type_setup(self, name, ('event',))
2917
2918     # Opcode define
2919     _c_opcode(name, self.opcodes[name])
2920
2921     if self.name == name:
2922         # Structure definition
2923         _c_complex(self)
2924     else:
2925         # Typedef
2926         _h('')
2927         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2928
2929     _man_event(self, name)
2930
2931 def c_error(self, name):
2932     '''
2933     Exported function that handles error declarations.
2934     '''
2935     _c_type_setup(self, name, ('error',))
2936
2937     # Opcode define
2938     _c_opcode(name, self.opcodes[name])
2939
2940     if self.name == name:
2941         # Structure definition
2942         _c_complex(self)
2943     else:
2944         # Typedef
2945         _h('')
2946         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2947
2948
2949 # Main routine starts here
2950
2951 # Must create an "output" dictionary before any xcbgen imports.
2952 output = {'open'    : c_open,
2953           'close'   : c_close,
2954           'simple'  : c_simple,
2955           'enum'    : c_enum,
2956           'struct'  : c_struct,
2957           'union'   : c_union,
2958           'request' : c_request,
2959           'event'   : c_event,
2960           'error'   : c_error, 
2961           }
2962
2963 # Boilerplate below this point
2964
2965 # Check for the argument that specifies path to the xcbgen python package.
2966 try:
2967     opts, args = getopt.getopt(sys.argv[1:], 'p:m')
2968 except getopt.GetoptError as err:
2969     print(err)
2970     print('Usage: c_client.py [-p path] file.xml')
2971     sys.exit(1)
2972
2973 for (opt, arg) in opts:
2974     if opt == '-p':
2975         sys.path.insert(1, arg)
2976     elif opt == '-m':
2977         manpaths = True
2978         sys.stdout.write('man_MANS = ')
2979
2980 # Import the module class
2981 try:
2982     from xcbgen.state import Module
2983     from xcbgen.xtypes import *
2984 except ImportError:
2985     print('''
2986 Failed to load the xcbgen Python package!
2987 Make sure that xcb/proto installed it on your Python path.
2988 If not, you will need to create a .pth file or define $PYTHONPATH
2989 to extend the path.
2990 Refer to the README file in xcb/proto for more info.
2991 ''')
2992     raise
2993
2994 # Ensure the man subdirectory exists
2995 try:
2996     os.mkdir('man')
2997 except OSError as e:
2998     if e.errno != errno.EEXIST:
2999         raise
3000
3001 today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
3002
3003 # Parse the xml header
3004 module = Module(args[0], output)
3005
3006 # Build type-registry and resolve type dependencies
3007 module.register()
3008 module.resolve()
3009
3010 # Output the code
3011 module.generate()