c_client.py: remove useless 'today' variable
[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.direct_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             if field.type.is_pad:
985                 # Variable length pad is <pad align= />
986                 code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
987                 count += _c_serialize_helper_insert_padding(context, code_lines, space, 
988                                                         self.var_followed_by_fixed_fields)
989                 continue
990             else:
991                 # switch/bitcase: always calculate padding before and after variable sized fields
992                 if need_padding or is_bitcase:
993                     count += _c_serialize_helper_insert_padding(context, code_lines, space,
994                                                             self.var_followed_by_fixed_fields)
995
996                 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
997                                                                          code_lines, temp_vars,
998                                                                          space, prefix)
999                 prev_field_was_variable = True
1000         
1001         # save (un)serialization C code
1002         if '' != value:
1003             code_lines.append('%s%s' % (space, value))    
1004         
1005         if field.type.fixed_size():
1006             if is_bitcase or self.var_followed_by_fixed_fields:
1007                 # keep track of (un)serialized object's size
1008                 code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1009                 if context in ('unserialize', 'unpack', 'sizeof'):
1010                     code_lines.append('%s    xcb_tmp += %s;' % (space, length))
1011         else: 
1012             # variable size objects or bitcase:
1013             #   value & length might have been inserted earlier for special cases
1014             if '' != length:
1015                 # special case: intermixed fixed and variable size fields
1016                 if (not field.type.fixed_size() and 
1017                     self.var_followed_by_fixed_fields and 'unserialize' == context):
1018                     temp_vars.append('    int %s_len;' % field.c_field_name)
1019                     code_lines.append('%s    %s_len = %s;' % (space, field.c_field_name, length))
1020                     code_lines.append('%s    xcb_block_len += %s_len;' % (space, field.c_field_name))
1021                     code_lines.append('%s    xcb_tmp += %s_len;' % (space, field.c_field_name))
1022                 else:
1023                     code_lines.append('%s    xcb_block_len += %s;' % (space, length))
1024                     # increase pointer into the byte stream accordingly
1025                     if context in ('unserialize', 'sizeof', 'unpack'):
1026                         code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1027                         
1028         if 'serialize' == context:
1029             if '' != length:
1030                 code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length))
1031             code_lines.append('%s    xcb_parts_idx++;' % space)
1032             count += 1
1033
1034         code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
1035
1036         need_padding = True
1037         if self.var_followed_by_fixed_fields:
1038             need_padding = False
1039         
1040     return count
1041 # _c_serialize_helper_fields()    
1042
1043 def _c_serialize_helper(context, complex_type, 
1044                         code_lines, temp_vars, 
1045                         space='', prefix=[]):
1046     # count tracks the number of fields to serialize
1047     count = 0
1048
1049     if hasattr(complex_type, 'type'):
1050         self = complex_type.type
1051         complex_name = complex_type.name
1052     else:
1053         self = complex_type
1054         if self.var_followed_by_fixed_fields and 'unserialize' == context:
1055             complex_name = 'xcb_out'
1056         else:
1057             complex_name = '_aux'
1058     
1059     # special case: switch is serialized by evaluating each bitcase separately
1060     if self.is_switch:
1061         count += _c_serialize_helper_switch(context, self, complex_name, 
1062                                             code_lines, temp_vars, 
1063                                             space, prefix)
1064
1065     # all other data types can be evaluated one field a time
1066     else: 
1067         # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
1068         if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
1069             code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
1070             code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
1071             code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
1072             code_lines.append('%s    xcb_block_len = 0;' % space)
1073
1074         count += _c_serialize_helper_fields(context, self, 
1075                                             code_lines, temp_vars, 
1076                                             space, prefix, False)
1077     # "final padding"
1078     count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
1079
1080     return count    
1081 # _c_serialize_helper()
1082
1083 def _c_serialize(context, self):
1084     """
1085     depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof() 
1086     for the ComplexType variable self
1087     """
1088     _h_setlevel(1)
1089     _c_setlevel(1)
1090
1091     _hc('')
1092     # _serialize() returns the buffer size
1093     _hc('int')
1094
1095     if self.is_switch and 'unserialize' == context:
1096         context = 'unpack'
1097
1098     cases = { 'serialize'   : self.c_serialize_name, 
1099               'unserialize' : self.c_unserialize_name, 
1100               'unpack'      : self.c_unpack_name, 
1101               'sizeof'      : self.c_sizeof_name }
1102     func_name = cases[context]
1103             
1104     param_fields, wire_fields, params = get_serialize_params(context, self)
1105     variable_size_fields = 0
1106     # maximum space required for type definition of function arguments
1107     maxtypelen = 0
1108
1109     # determine N(variable_fields) 
1110     for field in param_fields:
1111         # if self.is_switch, treat all fields as if they are variable sized
1112         if not field.type.fixed_size() or self.is_switch:
1113             variable_size_fields += 1
1114     # determine maxtypelen
1115     for p in params:
1116         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
1117
1118     # write to .c/.h
1119     indent = ' '*(len(func_name)+2)
1120     param_str = []
1121     for p in params:
1122         typespec, pointerspec, field_name = p
1123         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
1124         param_str.append("%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name))
1125     # insert function name
1126     param_str[0] = "%s (%s" % (func_name, param_str[0].strip())
1127     param_str = list(map(lambda x: "%s," % x, param_str))
1128     for s in param_str[:-1]:
1129         _hc(s)
1130     _h("%s);" % param_str[-1].rstrip(','))
1131     _c("%s)" % param_str[-1].rstrip(','))
1132     _c('{')
1133
1134     code_lines = []
1135     temp_vars = []
1136     prefix = []
1137
1138     if 'serialize' == context:
1139         if not self.is_switch and not self.var_followed_by_fixed_fields:
1140             _c('    %s *xcb_out = *_buffer;', self.c_type)
1141             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
1142             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
1143             _c('    unsigned int xcb_align_to = 0;')
1144         else:
1145             _c('    char *xcb_out = *_buffer;')
1146             _c('    unsigned int xcb_buffer_len = 0;')
1147             _c('    unsigned int xcb_align_to = 0;')
1148         prefix = [('_aux', '->', self)]
1149         aux_ptr = 'xcb_out'
1150
1151     elif context in ('unserialize', 'unpack'):
1152         _c('    char *xcb_tmp = (char *)_buffer;')
1153         if not self.is_switch:
1154             if not self.var_followed_by_fixed_fields:
1155                 _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1156                 prefix = [('_aux', '->', self)]
1157             else:
1158                 _c('    %s xcb_out;', self.c_type)
1159                 prefix = [('xcb_out', '.', self)]
1160         else:
1161             aux_var = '_aux' # default for unpack: single pointer
1162             # note: unserialize not generated for switch
1163             if 'unserialize' == context:
1164                 aux_var = '(*_aux)' # unserialize: double pointer (!)
1165             prefix = [(aux_var, '->', self)]
1166         aux_ptr = '*_aux'
1167         _c('    unsigned int xcb_buffer_len = 0;')
1168         _c('    unsigned int xcb_block_len = 0;')
1169         _c('    unsigned int xcb_pad = 0;')
1170         _c('    unsigned int xcb_align_to = 0;')
1171
1172     elif 'sizeof' == context:
1173         param_names = [p[2] for p in params]
1174         if self.is_switch:
1175             # switch: call _unpack()
1176             _c('    %s _aux;', self.c_type)
1177             _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1178             _c('}')
1179             return
1180         elif self.var_followed_by_fixed_fields:
1181             # special case: call _unserialize()
1182             _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
1183             _c('}')
1184             return
1185         else:
1186             _c('    char *xcb_tmp = (char *)_buffer;')
1187             prefix = [('_aux', '->', self)]
1188
1189     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
1190     # update variable size fields (only important for context=='serialize'
1191     variable_size_fields = count
1192     if 'serialize' == context:
1193         temp_vars.append('    unsigned int xcb_pad = 0;')
1194         temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};') 
1195         temp_vars.append('    struct iovec xcb_parts[%d];' % count)
1196         temp_vars.append('    unsigned int xcb_parts_idx = 0;')
1197         temp_vars.append('    unsigned int xcb_block_len = 0;')
1198         temp_vars.append('    unsigned int i;')
1199         temp_vars.append('    char *xcb_tmp;')
1200     elif 'sizeof' == context:
1201         # neither switch nor intermixed fixed and variable size fields:
1202         # evaluate parameters directly
1203         if not (self.is_switch or self.var_followed_by_fixed_fields):
1204
1205             # look if we have to declare an '_aux' variable at all
1206             if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0:
1207                 if not self.var_followed_by_fixed_fields:
1208                     _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1209                 else:
1210                     _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
1211
1212             _c('    unsigned int xcb_buffer_len = 0;')
1213             _c('    unsigned int xcb_block_len = 0;')
1214             _c('    unsigned int xcb_pad = 0;')        
1215             _c('    unsigned int xcb_align_to = 0;')
1216
1217     _c('')
1218     for t in temp_vars:
1219         _c(t)
1220     _c('')
1221     for l in code_lines:
1222         _c(l)
1223
1224     # variable sized fields have been collected, now
1225     # allocate memory and copy everything into a continuous memory area 
1226     # note: this is not necessary in case of unpack
1227     if context in ('serialize', 'unserialize'):
1228         # unserialize: check for sizeof-only invocation
1229         if 'unserialize' == context:
1230             _c('')
1231             _c('    if (NULL == _aux)')
1232             _c('        return xcb_buffer_len;')
1233
1234         _c('')
1235         _c('    if (NULL == %s) {', aux_ptr)
1236         _c('        /* allocate memory */')
1237         _c('        %s = malloc(xcb_buffer_len);', aux_ptr)
1238         if 'serialize' == context:
1239             _c('        *_buffer = xcb_out;')
1240         _c('    }')
1241         _c('')
1242
1243         # serialize: handle variable size fields in a loop
1244         if 'serialize' == context:
1245             if not self.is_switch and not self.var_followed_by_fixed_fields:
1246                 if len(wire_fields)>0:
1247                     _c('    *xcb_out = *_aux;')
1248             # copy variable size fields into the buffer
1249             if variable_size_fields > 0:
1250                 # xcb_out padding
1251                 if not self.is_switch and not self.var_followed_by_fixed_fields:
1252                     _c('    xcb_tmp = (char*)++xcb_out;')
1253                     _c('    xcb_tmp += xcb_out_pad;')
1254                 else:
1255                     _c('    xcb_tmp = xcb_out;')
1256
1257                 # variable sized fields
1258                 _c('    for(i=0; i<xcb_parts_idx; i++) {')
1259                 _c('        if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)')
1260                 _c('            memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
1261                 _c('        if (0 != xcb_parts[i].iov_len)')
1262                 _c('            xcb_tmp += xcb_parts[i].iov_len;')
1263                 _c('    }')
1264             
1265         # unserialize: assign variable size fields individually
1266         if 'unserialize' == context:
1267             _c('    xcb_tmp = ((char *)*_aux)+xcb_buffer_len;')
1268             param_fields.reverse()
1269             for field in param_fields:
1270                 if not field.type.fixed_size():
1271                     _c('    xcb_tmp -= %s_len;', field.c_field_name)
1272                     _c('    memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name)
1273             _c('    *%s = xcb_out;', aux_ptr)
1274  
1275     _c('')
1276     _c('    return xcb_buffer_len;')
1277     _c('}')
1278 # _c_serialize()
1279
1280 def _c_iterator_get_end(field, accum):
1281     '''
1282     Figures out what C code is needed to find the end of a variable-length structure field.
1283     For nested structures, recurses into its last variable-sized field.
1284     For lists, calls the end function
1285     '''
1286     if field.type.is_container:
1287         accum = field.c_accessor_name + '(' + accum + ')'
1288         return _c_iterator_get_end(field.type.last_varsized_field, accum)
1289     if field.type.is_list:
1290         # XXX we can always use the first way
1291         if field.type.member.is_simple:
1292             return field.c_end_name + '(' + accum + ')'
1293         else:
1294             return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1295
1296 def _c_iterator(self, name):
1297     '''
1298     Declares the iterator structure and next/end functions for a given type.
1299     '''
1300     _h_setlevel(0)
1301     _h('')
1302     _h('/**')
1303     _h(' * @brief %s', self.c_iterator_type)
1304     _h(' **/')
1305     _h('typedef struct %s {', self.c_iterator_type)
1306     _h('    %s *data; /**<  */', self.c_type)
1307     _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1308     _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1309     _h('} %s;', self.c_iterator_type)
1310
1311     _h_setlevel(1)
1312     _c_setlevel(1)
1313     _h('')
1314     _h('/**')
1315     _h(' * Get the next element of the iterator')
1316     _h(' * @param i Pointer to a %s', self.c_iterator_type)
1317     _h(' *')
1318     _h(' * Get the next element in the iterator. The member rem is')
1319     _h(' * decreased by one. The member data points to the next')
1320     _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1321     _h(' */')
1322     _c('')
1323     _hc('')
1324     _hc('/*****************************************************************************')
1325     _hc(' **')
1326     _hc(' ** void %s', self.c_next_name)
1327     _hc(' ** ')
1328     _hc(' ** @param %s *i', self.c_iterator_type)
1329     _hc(' ** @returns void')
1330     _hc(' **')
1331     _hc(' *****************************************************************************/')
1332     _hc(' ')
1333     _hc('void')
1334     _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1335     _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1336     _c('{')
1337
1338     if not self.fixed_size():
1339         _c('    %s *R = i->data;', self.c_type)
1340
1341         if self.is_union:
1342             # FIXME - how to determine the size of a variable size union??
1343             _c('    /* FIXME - determine the size of the union %s */', self.c_type)            
1344         else:
1345             if self.need_sizeof:
1346                 _c('    xcb_generic_iterator_t child;')
1347                 _c('    child.data = (%s *)(((char *)R) + %s(R));', 
1348                    self.c_type, self.c_sizeof_name)
1349                 _c('    i->index = (char *) child.data - (char *) i->data;')
1350             else:
1351                 _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1352                 _c('    i->index = child.index;')
1353             _c('    --i->rem;')
1354             _c('    i->data = (%s *) child.data;', self.c_type)
1355
1356     else:
1357         _c('    --i->rem;')
1358         _c('    ++i->data;')
1359         _c('    i->index += sizeof(%s);', self.c_type)
1360
1361     _c('}')
1362
1363     _h('')
1364     _h('/**')
1365     _h(' * Return the iterator pointing to the last element')
1366     _h(' * @param i An %s', self.c_iterator_type)
1367     _h(' * @return  The iterator pointing to the last element')
1368     _h(' *')
1369     _h(' * Set the current element in the iterator to the last element.')
1370     _h(' * The member rem is set to 0. The member data points to the')
1371     _h(' * last element.')
1372     _h(' */')
1373     _c('')
1374     _hc('')
1375     _hc('/*****************************************************************************')
1376     _hc(' **')
1377     _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1378     _hc(' ** ')
1379     _hc(' ** @param %s i', self.c_iterator_type)
1380     _hc(' ** @returns xcb_generic_iterator_t')
1381     _hc(' **')
1382     _hc(' *****************************************************************************/')
1383     _hc(' ')
1384     _hc('xcb_generic_iterator_t')
1385     _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1386     _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1387     _c('{')
1388     _c('    xcb_generic_iterator_t ret;')
1389
1390     if self.fixed_size():
1391         _c('    ret.data = i.data + i.rem;')
1392         _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1393         _c('    ret.rem = 0;')
1394     else:
1395         _c('    while(i.rem > 0)')
1396         _c('        %s(&i);', self.c_next_name)
1397         _c('    ret.data = i.data;')
1398         _c('    ret.rem = i.rem;')
1399         _c('    ret.index = i.index;')
1400
1401     _c('    return ret;')
1402     _c('}')
1403
1404 def _c_accessor_get_length(expr, field_mapping=None):
1405     '''
1406     Figures out what C code is needed to get a length field.
1407     The field_mapping parameter can be used to change the absolute name of a length field. 
1408     For fields that follow a variable-length field, use the accessor.
1409     Otherwise, just reference the structure field directly.
1410     '''
1411
1412     lenfield_name = expr.lenfield_name
1413     if lenfield_name is not None:
1414         if field_mapping is not None:
1415             lenfield_name = field_mapping[lenfield_name][0]
1416  
1417     if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None:
1418         # special case: variable and fixed size fields are intermixed
1419         # if the lenfield is among the fixed size fields, there is no need
1420         # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1421         return field_mapping(expr.lenfield_name)
1422     elif expr.lenfield_name is not None:
1423         return lenfield_name
1424     else:
1425         return str(expr.nmemb)
1426
1427 def _c_accessor_get_expr(expr, field_mapping):
1428     '''
1429     Figures out what C code is needed to get the length of a list field.
1430     The field_mapping parameter can be used to change the absolute name of a length field. 
1431     Recurses for math operations.
1432     Returns bitcount for value-mask fields.
1433     Otherwise, uses the value of the length field.
1434     '''
1435     lenexp = _c_accessor_get_length(expr, field_mapping)
1436
1437     if expr.op == '~':
1438         return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1439     elif expr.op == 'popcount':
1440         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1441     elif expr.op == 'enumref':
1442         enum_name = expr.lenfield_type.name
1443         constant_name = expr.lenfield_name
1444         c_name = _n(enum_name + (constant_name,)).upper()
1445         return c_name
1446     elif expr.op == 'sumof':
1447         # locate the referenced list object
1448         list_obj = expr.lenfield_type
1449         field = None
1450         for f in expr.lenfield_parent.fields:
1451             if f.field_name == expr.lenfield_name:
1452                 field = f
1453                 break
1454
1455         if field is None:
1456             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1457         list_name = field_mapping[field.c_field_name][0]
1458         c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1459         # note: xcb_sumof() has only been defined for integers
1460         c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1461         return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1462     elif expr.op != None:
1463         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) + 
1464                 ' ' + expr.op + ' ' + 
1465                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1466     elif expr.bitfield:
1467         return 'xcb_popcount(' + lenexp + ')'
1468     else:
1469         return lenexp
1470
1471 def type_pad_type(type):
1472     if type == 'void':
1473         return 'char'
1474     return type
1475
1476 def _c_accessors_field(self, field):
1477     '''
1478     Declares the accessor functions for a non-list field that follows a variable-length field.
1479     '''
1480     c_type = self.c_type
1481
1482     # special case: switch
1483     switch_obj = self if self.is_switch else None
1484     if self.is_bitcase:
1485         switch_obj = self.parents[-1]
1486     if switch_obj is not None:
1487         c_type = switch_obj.c_type
1488
1489     if field.type.is_simple:
1490         _hc('')
1491         _hc('')
1492         _hc('/*****************************************************************************')
1493         _hc(' ** ')
1494         _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1495         _hc(' ** ')
1496         _hc(' ** @param const %s *R', c_type)
1497         _hc(' ** @returns %s', field.c_field_type)
1498         _hc(' **')
1499         _hc(' *****************************************************************************/')
1500         _hc(' ')
1501         _hc('%s', field.c_field_type)
1502         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1503         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1504         _c('{')
1505         if field.prev_varsized_field is None:
1506             _c('    return (%s *) (R + 1);', field.c_field_type)
1507         else:
1508             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1509             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1510                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1511         _c('}')
1512     else:
1513         _hc('')
1514         _hc('')
1515         _hc('/*****************************************************************************')
1516         _hc(' **')
1517         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1518         _hc(' ** ')
1519         _hc(' ** @param const %s *R', c_type)
1520         _hc(' ** @returns %s *', field.c_field_type)
1521         _hc(' **')
1522         _hc(' *****************************************************************************/')
1523         _hc(' ')
1524         if field.type.is_switch and switch_obj is None:
1525             return_type = 'void *'
1526         else:
1527             return_type = '%s *' % field.c_field_type
1528
1529         _hc(return_type)
1530         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1531         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1532         _c('{')
1533         if field.prev_varsized_field is None:
1534             _c('    return (%s) (R + 1);', return_type)
1535             # note: the special case 'variable fields followed by fixed size fields'
1536             #       is not of any consequence here, since the ordering gets 
1537             #       'corrected' in the reply function
1538         else:
1539             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1540             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1541                return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1542         _c('}')
1543
1544     
1545 def _c_accessors_list(self, field):
1546     '''
1547     Declares the accessor functions for a list field.
1548     Declares a direct-accessor function only if the list members are fixed size.
1549     Declares length and get-iterator functions always.
1550     '''
1551
1552     def get_align_pad(field):
1553             prev = field.prev_varsized_field
1554             prev_prev = field.prev_varsized_field.prev_varsized_field
1555
1556             if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1557                 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1558             else:
1559                 return (prev, None)
1560
1561
1562     list = field.type
1563     c_type = self.c_type
1564
1565     # special case: switch
1566     # in case of switch, 2 params have to be supplied to certain accessor functions:
1567     #   1. the anchestor object (request or reply)
1568     #   2. the (anchestor) switch object
1569     # the reason is that switch is either a child of a request/reply or nested in another switch, 
1570     # so whenever we need to access a length field, we might need to refer to some anchestor type
1571     switch_obj = self if self.is_switch else None
1572     if self.is_bitcase:
1573         switch_obj = self.parents[-1]
1574     if switch_obj is not None:
1575         c_type = switch_obj.c_type
1576
1577     params = []
1578     fields = {}
1579     parents = self.parents if hasattr(self, 'parents') else [self]
1580     # 'R': parents[0] is always the 'toplevel' container type 
1581     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1582     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1583     # auxiliary object for 'R' parameters
1584     R_obj = parents[0]
1585
1586     if switch_obj is not None:
1587         # now look where the fields are defined that are needed to evaluate 
1588         # the switch expr, and store the parent objects in accessor_params and
1589         # the fields in switch_fields
1590
1591         # 'S': name for the 'toplevel' switch
1592         toplevel_switch = parents[1]
1593         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1594         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1595
1596         # initialize prefix for everything "below" S
1597         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1598         prefix = [(prefix_str, '->', toplevel_switch)]
1599
1600         # look for fields in the remaining containers
1601         for p in parents[2:] + [self]:
1602             # the separator between parent and child is always '.' here, 
1603             # because of nested switch statements
1604             if not p.is_bitcase or (p.is_bitcase and p.has_name):
1605                 prefix.append((p.name[-1], '.', p))
1606             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1607
1608         # auxiliary object for 'S' parameter
1609         S_obj = parents[1]
1610
1611     _h_setlevel(1)
1612     _c_setlevel(1)
1613     if list.member.fixed_size():
1614         idx = 1 if switch_obj is not None else 0
1615         _hc('')
1616         _hc('')
1617         _hc('/*****************************************************************************')
1618         _hc(' **')
1619         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1620         _hc(' ** ')
1621         _hc(' ** @param %s', params[idx][0])
1622         _hc(' ** @returns %s *', field.c_field_type)
1623         _hc(' **')
1624         _hc(' *****************************************************************************/')
1625         _hc(' ')
1626         _hc('%s *', field.c_field_type)
1627
1628         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1629         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1630
1631         _c('{')
1632         if switch_obj is not None:
1633             _c('    return %s;', fields[field.c_field_name][0])
1634         elif field.prev_varsized_field is None:
1635             _c('    return (%s *) (R + 1);', field.c_field_type)
1636         else:
1637             (prev_varsized_field, align_pad) = get_align_pad(field)
1638
1639             if align_pad is None:
1640                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1641                     type_pad_type(field.first_field_after_varsized.type.c_type))
1642
1643             _c('    xcb_generic_iterator_t prev = %s;',
1644                 _c_iterator_get_end(prev_varsized_field, 'R'))
1645             _c('    return (%s *) ((char *) prev.data + %s + %d);',
1646                field.c_field_type, align_pad, field.prev_varsized_offset)
1647         _c('}')
1648
1649     _hc('')
1650     _hc('')
1651     _hc('/*****************************************************************************')
1652     _hc(' **')
1653     _hc(' ** int %s', field.c_length_name)
1654     _hc(' ** ')
1655     _hc(' ** @param const %s *R', c_type)
1656     _hc(' ** @returns int')
1657     _hc(' **')
1658     _hc(' *****************************************************************************/')
1659     _hc(' ')
1660     _hc('int')
1661     if switch_obj is not None:
1662         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1663         spacing = ' '*(len(field.c_length_name)+2)
1664         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1665         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1666         length = _c_accessor_get_expr(field.type.expr, fields)
1667     else:
1668         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1669         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1670         length = _c_accessor_get_expr(field.type.expr, fields)
1671     _c('{')
1672     _c('    return %s;', length)
1673     _c('}')
1674
1675     if field.type.member.is_simple:
1676         _hc('')
1677         _hc('')
1678         _hc('/*****************************************************************************')
1679         _hc(' **')
1680         _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1681         _hc(' ** ')
1682         _hc(' ** @param const %s *R', c_type)
1683         _hc(' ** @returns xcb_generic_iterator_t')
1684         _hc(' **')
1685         _hc(' *****************************************************************************/')
1686         _hc(' ')
1687         _hc('xcb_generic_iterator_t')
1688         if switch_obj is not None:
1689             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1690             spacing = ' '*(len(field.c_end_name)+2)
1691             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1692             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1693         else:
1694             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1695             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1696         _c('{')
1697         _c('    xcb_generic_iterator_t i;')
1698         
1699         param = 'R' if switch_obj is None else 'S'
1700         if switch_obj is not None:
1701             _c('    i.data = %s + %s;', fields[field.c_field_name][0], 
1702                _c_accessor_get_expr(field.type.expr, fields))
1703         elif field.prev_varsized_field == None:
1704             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, 
1705                _c_accessor_get_expr(field.type.expr, fields))
1706         else:
1707             _c('    xcb_generic_iterator_t child = %s;', 
1708                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1709             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, 
1710                _c_accessor_get_expr(field.type.expr, fields))
1711
1712         _c('    i.rem = 0;')
1713         _c('    i.index = (char *) i.data - (char *) %s;', param)
1714         _c('    return i;')
1715         _c('}')
1716
1717     else:
1718         _hc('')
1719         _hc('')
1720         _hc('/*****************************************************************************')
1721         _hc(' **')
1722         _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1723         _hc(' ** ')
1724         _hc(' ** @param const %s *R', c_type)
1725         _hc(' ** @returns %s', field.c_iterator_type)
1726         _hc(' **')
1727         _hc(' *****************************************************************************/')
1728         _hc(' ')
1729
1730         _hc('%s', field.c_iterator_type)
1731         if switch_obj is not None:
1732             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1733             spacing = ' '*(len(field.c_iterator_name)+2)
1734             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1735             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1736         else:
1737             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1738             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1739         _c('{')
1740         _c('    %s i;', field.c_iterator_type)
1741
1742         if switch_obj is not None:
1743             _c('    i.data = %s;', fields[field.c_field_name][0])
1744             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1745         elif field.prev_varsized_field == None:
1746             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1747         else:
1748             (prev_varsized_field, align_pad) = get_align_pad(field)
1749
1750             if align_pad is None:
1751                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1752                     type_pad_type(field.c_field_type))
1753
1754             _c('    xcb_generic_iterator_t prev = %s;',
1755                 _c_iterator_get_end(prev_varsized_field, 'R'))
1756             _c('    i.data = (%s *) ((char *) prev.data + %s);',
1757                 field.c_field_type, align_pad)
1758
1759         if switch_obj is None:
1760             _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
1761         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1762         _c('    return i;')
1763         _c('}')
1764
1765 def _c_accessors(self, name, base):
1766     '''
1767     Declares the accessor functions for the fields of a structure.
1768     '''
1769     # no accessors for switch itself - 
1770     # switch always needs to be unpacked explicitly
1771 #    if self.is_switch:
1772 #        pass
1773 #    else:
1774     if True:
1775         for field in self.fields:
1776             if not field.type.is_pad:
1777                 if field.type.is_list and not field.type.fixed_size():
1778                     _c_accessors_list(self, field)
1779                 elif field.prev_varsized_field is not None or not field.type.fixed_size():
1780                     _c_accessors_field(self, field)
1781
1782 def c_simple(self, name):
1783     '''
1784     Exported function that handles cardinal type declarations.
1785     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1786     '''
1787     _c_type_setup(self, name, ())
1788
1789     if (self.name != name):
1790         # Typedef
1791         _h_setlevel(0)
1792         my_name = _t(name)
1793         _h('')
1794         _h('typedef %s %s;', _t(self.name), my_name)
1795
1796         # Iterator
1797         _c_iterator(self, name)
1798
1799 def _c_complex(self, force_packed = False):
1800     '''
1801     Helper function for handling all structure types.
1802     Called for all structs, requests, replies, events, errors.
1803     '''
1804     _h_setlevel(0)
1805     _h('')
1806     _h('/**')
1807     _h(' * @brief %s', self.c_type)
1808     _h(' **/')
1809     _h('typedef %s %s {', self.c_container, self.c_type)
1810
1811     struct_fields = []
1812     maxtypelen = 0
1813
1814     varfield = None
1815     for field in self.fields:
1816         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1817             varfield = field.c_field_name
1818             continue
1819         if field.wire:
1820             struct_fields.append(field)
1821     
1822     for field in struct_fields:
1823         length = len(field.c_field_type)
1824         # account for '*' pointer_spec
1825         if not field.type.fixed_size() and not self.is_union:
1826             length += 1
1827         maxtypelen = max(maxtypelen, length)
1828
1829     def _c_complex_field(self, field, space=''):
1830         if (field.type.fixed_size() or self.is_union or
1831             # in case of switch with switch children, don't make the field a pointer
1832             # necessary for unserialize to work
1833             (self.is_switch and field.type.is_switch)):
1834             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1835             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1836         else:
1837             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1838             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1839
1840     if not self.is_switch:
1841         for field in struct_fields:
1842             _c_complex_field(self, field)
1843     else:
1844         for b in self.bitcases:
1845             space = ''
1846             if b.type.has_name:
1847                 _h('    struct _%s {', b.c_field_name)
1848                 space = '    '
1849             for field in b.type.fields:
1850                 _c_complex_field(self, field, space)
1851             if b.type.has_name:
1852                 _h('    } %s;', b.c_field_name)
1853
1854     _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
1855
1856 def c_struct(self, name):
1857     '''
1858     Exported function that handles structure declarations.
1859     '''
1860     _c_type_setup(self, name, ())
1861     _c_complex(self)
1862     _c_accessors(self, name, name)
1863     _c_iterator(self, name)
1864
1865 def c_union(self, name):
1866     '''
1867     Exported function that handles union declarations.
1868     '''
1869     _c_type_setup(self, name, ())
1870     _c_complex(self)
1871     _c_iterator(self, name)
1872
1873 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
1874     '''
1875     Declares a request function.
1876     '''
1877
1878     # Four stunningly confusing possibilities here:
1879     #
1880     #   Void            Non-void
1881     # ------------------------------
1882     # "req"            "req"
1883     # 0 flag           CHECKED flag   Normal Mode
1884     # void_cookie      req_cookie
1885     # ------------------------------
1886     # "req_checked"    "req_unchecked"
1887     # CHECKED flag     0 flag         Abnormal Mode
1888     # void_cookie      req_cookie
1889     # ------------------------------
1890
1891
1892     # Whether we are _checked or _unchecked
1893     checked = void and not regular
1894     unchecked = not void and not regular
1895
1896     # What kind of cookie we return
1897     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1898
1899     # What flag is passed to xcb_request
1900     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1901
1902     if reply_fds:
1903         if func_flags == '0':
1904             func_flags = 'XCB_REQUEST_REPLY_FDS'
1905         else:
1906             func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
1907
1908     # Global extension id variable or NULL for xproto
1909     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1910
1911     # What our function name is
1912     func_name = self.c_request_name if not aux else self.c_aux_name
1913     if checked:
1914         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1915     if unchecked:
1916         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1917
1918     param_fields = []
1919     wire_fields = []
1920     maxtypelen = len('xcb_connection_t')
1921     serial_fields = []
1922     # special case: list with variable size elements
1923     list_with_var_size_elems = False
1924
1925     for field in self.fields:
1926         if field.visible:
1927             # The field should appear as a call parameter
1928             param_fields.append(field)
1929         if field.wire and not field.auto:
1930             # We need to set the field up in the structure
1931             wire_fields.append(field)
1932         if field.type.need_serialize or field.type.need_sizeof:
1933             serial_fields.append(field)
1934         
1935     for field in param_fields:
1936         c_field_const_type = field.c_field_const_type 
1937         if field.type.need_serialize and not aux:
1938             c_field_const_type = "const void"
1939         if len(c_field_const_type) > maxtypelen:
1940             maxtypelen = len(c_field_const_type)
1941         if field.type.is_list and not field.type.member.fixed_size():
1942             list_with_var_size_elems = True
1943
1944     _h_setlevel(1)
1945     _c_setlevel(1)
1946     _h('')
1947     _h('/**')
1948     if hasattr(self, "doc") and self.doc:
1949         if self.doc.brief:
1950             _h(' * @brief ' + self.doc.brief)
1951         else:
1952             _h(' * No brief doc yet')
1953
1954     _h(' *')
1955     _h(' * @param c The connection')
1956     param_names = [f.c_field_name for f in param_fields]
1957     if hasattr(self, "doc") and self.doc:
1958         for field in param_fields:
1959             # XXX: hard-coded until we fix xproto.xml
1960             base_func_name = self.c_request_name if not aux else self.c_aux_name
1961             if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
1962                 field.enum = 'GC'
1963             elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
1964                 field.enum = 'CW'
1965             elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
1966                 field.enum = 'CW'
1967             if field.enum:
1968                 # XXX: why the 'xcb' prefix?
1969                 key = ('xcb', field.enum)
1970
1971                 tname = _t(key)
1972                 if namecount[tname] > 1:
1973                     tname = _t(key + ('enum',))
1974                 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
1975
1976             if self.doc and field.field_name in self.doc.fields:
1977                 desc = self.doc.fields[field.field_name]
1978                 for name in param_names:
1979                     desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1980                 desc = desc.split("\n")
1981                 desc = [line if line != '' else '\\n' for line in desc]
1982                 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
1983             # If there is no documentation yet, we simply don't generate an
1984             # @param tag. Doxygen will then warn about missing documentation.
1985
1986     _h(' * @return A cookie')
1987     _h(' *')
1988
1989     if hasattr(self, "doc") and self.doc:
1990         if self.doc.description:
1991             desc = self.doc.description
1992             for name in param_names:
1993                 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
1994             desc = desc.split("\n")
1995             _h(' * ' + "\n * ".join(desc))
1996         else:
1997             _h(' * No description yet')
1998     else:
1999         _h(' * Delivers a request to the X server.')
2000     _h(' * ')
2001     if checked:
2002         _h(' * This form can be used only if the request will not cause')
2003         _h(' * a reply to be generated. Any returned error will be')
2004         _h(' * saved for handling by xcb_request_check().')
2005     if unchecked:
2006         _h(' * This form can be used only if the request will cause')
2007         _h(' * a reply to be generated. Any returned error will be')
2008         _h(' * placed in the event queue.')
2009     _h(' */')
2010     _c('')
2011     _hc('')
2012     _hc('/*****************************************************************************')
2013     _hc(' **')
2014     _hc(' ** %s %s', cookie_type, func_name)
2015     _hc(' ** ')
2016
2017     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2018     _hc(' ** @param xcb_connection_t%s *c', spacing)
2019
2020     for field in param_fields:
2021         c_field_const_type = field.c_field_const_type 
2022         if field.type.need_serialize and not aux:
2023             c_field_const_type = "const void"
2024         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2025         _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
2026
2027     _hc(' ** @returns %s', cookie_type)
2028     _hc(' **')
2029     _hc(' *****************************************************************************/')
2030     _hc(' ')
2031     _hc('%s', cookie_type)
2032
2033     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2034     comma = ',' if len(param_fields) else ');'
2035     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2036     comma = ',' if len(param_fields) else ')'
2037     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2038
2039     func_spacing = ' ' * (len(func_name) + 2)
2040     count = len(param_fields)
2041     for field in param_fields:
2042         count = count - 1
2043         c_field_const_type = field.c_field_const_type 
2044         c_pointer = field.c_pointer
2045         if field.type.need_serialize and not aux:
2046             c_field_const_type = "const void"
2047             c_pointer = '*'
2048         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2049         comma = ',' if count else ');'
2050         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
2051            spacing, c_pointer, field.c_field_name, comma)
2052         comma = ',' if count else ')'
2053         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
2054            spacing, c_pointer, field.c_field_name, comma)
2055
2056     count = 2
2057     if not self.var_followed_by_fixed_fields:
2058         for field in param_fields:
2059             if not field.type.fixed_size():
2060                 count = count + 2
2061                 if field.type.need_serialize:
2062                     # _serialize() keeps track of padding automatically
2063                     count -= 1
2064     dimension = count + 2
2065
2066     _c('{')
2067     _c('    static const xcb_protocol_request_t xcb_req = {')
2068     _c('        /* count */ %d,', count)
2069     _c('        /* ext */ %s,', func_ext_global)
2070     _c('        /* opcode */ %s,', self.c_request_name.upper())
2071     _c('        /* isvoid */ %d', 1 if void else 0)
2072     _c('    };')
2073     _c('    ')
2074
2075     _c('    struct iovec xcb_parts[%d];', dimension)
2076     _c('    %s xcb_ret;', func_cookie)
2077     _c('    %s xcb_out;', self.c_type)
2078     if self.var_followed_by_fixed_fields:
2079         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2080         _c('    void *xcb_aux = 0;')
2081         
2082
2083     for idx, f in enumerate(serial_fields):
2084         if aux:
2085             _c('    void *xcb_aux%d = 0;' % (idx))
2086     if list_with_var_size_elems:
2087         _c('    unsigned int i;')
2088         _c('    unsigned int xcb_tmp_len;')
2089         _c('    char *xcb_tmp;')
2090     _c('    ')
2091     # simple request call tracing
2092 #    _c('    printf("in function %s\\n");' % func_name)     
2093  
2094     # fixed size fields
2095     for field in wire_fields:
2096         if field.type.fixed_size():
2097             if field.type.is_expr:
2098                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2099             elif field.type.is_pad:
2100                 if field.type.nmemb == 1:
2101                     _c('    xcb_out.%s = 0;', field.c_field_name)
2102                 else:
2103                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2104             else:
2105                 if field.type.nmemb == 1:
2106                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2107                 else:
2108                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2109
2110     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2111         serialize_args = get_serialize_params(context, type_obj, 
2112                                               c_field_name, 
2113                                               aux_var)[2]
2114         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2115
2116     # calls in order to free dyn. all. memory
2117     free_calls = []
2118
2119     _c('    ')
2120     if not self.var_followed_by_fixed_fields:
2121         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2122         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2123         _c('    xcb_parts[3].iov_base = 0;')
2124         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2125
2126         count = 4
2127
2128         for field in param_fields:
2129             if not field.type.fixed_size():
2130                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2131                 # default: simple cast to char *
2132                 if not field.type.need_serialize and not field.type.need_sizeof:
2133                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2134                     if field.type.is_list:
2135                         if field.type.member.fixed_size():
2136                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 
2137                                _c_accessor_get_expr(field.type.expr, None), 
2138                                field.type.member.c_wiretype)
2139                         else:
2140                             list_length = _c_accessor_get_expr(field.type.expr, None)
2141     
2142                             length = ''
2143                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2144                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2145                             _c("    for(i=0; i<%s; i++) {" % list_length)
2146                             _c("        xcb_tmp_len = %s(xcb_tmp);" % 
2147                                               (field.type.c_sizeof_name))
2148                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2149                             _c("        xcb_tmp += xcb_tmp_len;")
2150                             _c("    }")                        
2151                     else:
2152                         # not supposed to happen
2153                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2154                 else:
2155                     if not aux:
2156                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2157                     idx = serial_fields.index(field)
2158                     aux_var = '&xcb_aux%d' % idx
2159                     context = 'serialize' if aux else 'sizeof'
2160                     _c('    xcb_parts[%d].iov_len = ', count)
2161                     if aux:
2162                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2163                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2164                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2165                         free_calls.append('    free(xcb_aux%d);' % idx)
2166                     else:
2167                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2168                         func_name = field.type.c_sizeof_name
2169                         _c('      %s (%s);', func_name, serialize_args)
2170
2171                 count += 1
2172                 if not (field.type.need_serialize or field.type.need_sizeof):
2173                     # the _serialize() function keeps track of padding automatically
2174                     _c('    xcb_parts[%d].iov_base = 0;', count)
2175                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2176                     count += 1
2177
2178     # elif self.var_followed_by_fixed_fields:
2179     else:
2180         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2181         # request header: opcodes + length
2182         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);') 
2183         count += 1
2184         # call _serialize()
2185         buffer_var = '&xcb_aux'
2186         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2187         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2188         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2189         free_calls.append('    free(xcb_aux);')
2190         # no padding necessary - _serialize() keeps track of padding automatically
2191
2192     _c('    ')
2193     for field in param_fields:
2194         if field.isfd:
2195             _c('    xcb_send_fd(c, %s);', field.c_field_name)
2196     
2197     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2198     
2199     # free dyn. all. data, if any
2200     for f in free_calls:
2201         _c(f)
2202     _c('    return xcb_ret;')
2203     _c('}')
2204
2205 def _c_reply(self, name):
2206     '''
2207     Declares the function that returns the reply structure.
2208     '''
2209     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2210     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2211     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2212     
2213     # check if _unserialize() has to be called for any field
2214     def look_for_special_cases(complex_obj):
2215         unserialize_fields = []
2216         # no unserialize call in case of switch
2217         if not complex_obj.is_switch:
2218             for field in complex_obj.fields:
2219                 # three cases: 1. field with special case
2220                 #              2. container that contains special case field
2221                 #              3. list with special case elements
2222                 if field.type.var_followed_by_fixed_fields:
2223                     unserialize_fields.append(field)
2224                 elif field.type.is_container:
2225                     unserialize_fields += look_for_special_cases(field.type)
2226                 elif field.type.is_list:
2227                     if field.type.member.var_followed_by_fixed_fields:
2228                         unserialize_fields.append(field)
2229                     if field.type.member.is_container:
2230                         unserialize_fields += look_for_special_cases(field.type.member)
2231         return unserialize_fields
2232     
2233     unserialize_fields = look_for_special_cases(self.reply)
2234     
2235     _h('')
2236     _h('/**')
2237     _h(' * Return the reply')
2238     _h(' * @param c      The connection')
2239     _h(' * @param cookie The cookie')
2240     _h(' * @param e      The xcb_generic_error_t supplied')
2241     _h(' *')
2242     _h(' * Returns the reply of the request asked by')
2243     _h(' * ')
2244     _h(' * The parameter @p e supplied to this function must be NULL if')
2245     _h(' * %s(). is used.', self.c_unchecked_name)
2246     _h(' * Otherwise, it stores the error if any.')
2247     _h(' *')
2248     _h(' * The returned value must be freed by the caller using free().')
2249     _h(' */')
2250     _c('')
2251     _hc('')
2252     _hc('/*****************************************************************************')
2253     _hc(' **')
2254     _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
2255     _hc(' ** ')
2256     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2257     _hc(' ** @param %s   cookie', self.c_cookie_type)
2258     _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
2259     _hc(' ** @returns %s *', self.c_reply_type)
2260     _hc(' **')
2261     _hc(' *****************************************************************************/')
2262     _hc(' ')
2263     _hc('%s *', self.c_reply_type)
2264     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2265     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2266     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2267     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2268     _c('{')
2269     
2270     if len(unserialize_fields)>0:
2271         # certain variable size fields need to be unserialized explicitly
2272         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', 
2273            self.c_reply_type, self.c_reply_type)
2274         _c('    int i;')
2275         for field in unserialize_fields:
2276             if field.type.is_list:
2277                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2278                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2279                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2280             else:
2281                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2282         # call _unserialize(), using the reply as source and target buffer
2283         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2284         for field in unserialize_fields:
2285             if field.type.is_list:
2286                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2287                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2288                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name, 
2289                    field.c_field_name, field.c_field_name)
2290                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2291                 _c('    }')
2292         # return the transformed reply
2293         _c('    return reply;')
2294     
2295     else:
2296         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2297
2298     _c('}')
2299
2300 def _c_reply_has_fds(self):
2301     for field in self.fields:
2302         if field.isfd:
2303             return True
2304     return False
2305
2306 def _c_reply_fds(self, name):
2307     '''
2308     Declares the function that returns fds related to the reply.
2309     '''
2310     spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2311     spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2312     _h('')
2313     _h('/**')
2314     _h(' * Return the reply fds')
2315     _h(' * @param c      The connection')
2316     _h(' * @param reply  The reply')
2317     _h(' *')
2318     _h(' * Returns the array of reply fds of the request asked by')
2319     _h(' * ')
2320     _h(' * The returned value must be freed by the caller using free().')
2321     _h(' */')
2322     _c('')
2323     _hc('')
2324     _hc('/*****************************************************************************')
2325     _hc(' **')
2326     _hc(' ** int * %s', self.c_reply_fds_name)
2327     _hc(' ** ')
2328     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
2329     _hc(' ** @param %s  *reply', self.c_reply_type)
2330     _hc(' ** @returns int *')
2331     _hc(' **')
2332     _hc(' *****************************************************************************/')
2333     _hc(' ')
2334     _hc('int *')
2335     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2336     _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2337     _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2338     _c('{')
2339     
2340     _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2341
2342     _c('}')
2343     
2344
2345 def _c_opcode(name, opcode):
2346     '''
2347     Declares the opcode define for requests, events, and errors.
2348     '''
2349     _h_setlevel(0)
2350     _h('')
2351     _h('/** Opcode for %s. */', _n(name))
2352     _h('#define %s %s', _n(name).upper(), opcode)
2353     
2354 def _c_cookie(self, name):
2355     '''
2356     Declares the cookie type for a non-void request.
2357     '''
2358     _h_setlevel(0)
2359     _h('')
2360     _h('/**')
2361     _h(' * @brief %s', self.c_cookie_type)
2362     _h(' **/')
2363     _h('typedef struct %s {', self.c_cookie_type)
2364     _h('    unsigned int sequence; /**<  */')
2365     _h('} %s;', self.c_cookie_type)
2366
2367 def _man_request(self, name, cookie_type, void, aux):
2368     param_fields = [f for f in self.fields if f.visible]
2369
2370     func_name = self.c_request_name if not aux else self.c_aux_name
2371
2372     def create_link(linkname):
2373         name = 'man/%s.%s' % (linkname, section)
2374         if manpaths:
2375             sys.stdout.write(name)
2376         f = open(name, 'w')
2377         f.write('.so man%s/%s.%s' % (section, func_name, section))
2378         f.close()
2379
2380     if manpaths:
2381         sys.stdout.write('man/%s.%s ' % (func_name, section))
2382     # Our CWD is src/, so this will end up in src/man/
2383     f = open('man/%s.%s' % (func_name, section), 'w')
2384     f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2385     # Left-adjust instead of adjusting to both sides
2386     f.write('.ad l\n')
2387     f.write('.SH NAME\n')
2388     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2389     f.write('%s \\- %s\n' % (func_name, brief))
2390     f.write('.SH SYNOPSIS\n')
2391     # Don't split words (hyphenate)
2392     f.write('.hy 0\n')
2393     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2394
2395     # function prototypes
2396     prototype = ''
2397     count = len(param_fields)
2398     for field in param_fields:
2399         count = count - 1
2400         c_field_const_type = field.c_field_const_type
2401         c_pointer = field.c_pointer
2402         if c_pointer == ' ':
2403             c_pointer = ''
2404         if field.type.need_serialize and not aux:
2405             c_field_const_type = "const void"
2406             c_pointer = '*'
2407         comma = ', ' if count else ');'
2408         prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2409
2410     f.write('.SS Request function\n')
2411     f.write('.HP\n')
2412     base_func_name = self.c_request_name if not aux else self.c_aux_name
2413     f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2414     create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2415     if not void:
2416         f.write('.PP\n')
2417         f.write('.SS Reply datastructure\n')
2418         f.write('.nf\n')
2419         f.write('.sp\n')
2420         f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2421         struct_fields = []
2422         maxtypelen = 0
2423
2424         for field in self.reply.fields:
2425             if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2426                 continue
2427             if field.wire:
2428                 struct_fields.append(field)
2429
2430         for field in struct_fields:
2431             length = len(field.c_field_type)
2432             # account for '*' pointer_spec
2433             if not field.type.fixed_size():
2434                 length += 1
2435             maxtypelen = max(maxtypelen, length)
2436
2437         def _c_complex_field(self, field, space=''):
2438             if (field.type.fixed_size() or
2439                 # in case of switch with switch children, don't make the field a pointer
2440                 # necessary for unserialize to work
2441                 (self.is_switch and field.type.is_switch)):
2442                 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2443                 f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2444             else:
2445                 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2446                 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2447                 #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2448
2449         if not self.is_switch:
2450             for field in struct_fields:
2451                 _c_complex_field(self, field)
2452         else:
2453             for b in self.bitcases:
2454                 space = ''
2455                 if b.type.has_name:
2456                     space = '    '
2457                 for field in b.type.fields:
2458                     _c_complex_field(self, field, space)
2459                 if b.type.has_name:
2460                     print >> sys.stderr, 'ERROR: New unhandled documentation case'
2461                     pass
2462
2463         f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2464         f.write('.fi\n')
2465
2466         f.write('.SS Reply function\n')
2467         f.write('.HP\n')
2468         f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2469                  '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2470                 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2471         create_link('%s' % self.c_reply_name)
2472
2473         has_accessors = False
2474         for field in self.reply.fields:
2475             if field.type.is_list and not field.type.fixed_size():
2476                 has_accessors = True
2477             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2478                 has_accessors = True
2479
2480         if has_accessors:
2481             f.write('.SS Reply accessors\n')
2482
2483         def _c_accessors_field(self, field):
2484             '''
2485             Declares the accessor functions for a non-list field that follows a variable-length field.
2486             '''
2487             c_type = self.c_type
2488
2489             # special case: switch
2490             switch_obj = self if self.is_switch else None
2491             if self.is_bitcase:
2492                 switch_obj = self.parents[-1]
2493             if switch_obj is not None:
2494                 c_type = switch_obj.c_type
2495
2496             if field.type.is_simple:
2497                 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2498                 create_link('%s' % field.c_accessor_name)
2499             else:
2500                 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2501                 create_link('%s' % field.c_accessor_name)
2502
2503         def _c_accessors_list(self, field):
2504             '''
2505             Declares the accessor functions for a list field.
2506             Declares a direct-accessor function only if the list members are fixed size.
2507             Declares length and get-iterator functions always.
2508             '''
2509             list = field.type
2510             c_type = self.reply.c_type
2511
2512             # special case: switch
2513             # in case of switch, 2 params have to be supplied to certain accessor functions:
2514             #   1. the anchestor object (request or reply)
2515             #   2. the (anchestor) switch object
2516             # the reason is that switch is either a child of a request/reply or nested in another switch,
2517             # so whenever we need to access a length field, we might need to refer to some anchestor type
2518             switch_obj = self if self.is_switch else None
2519             if self.is_bitcase:
2520                 switch_obj = self.parents[-1]
2521             if switch_obj is not None:
2522                 c_type = switch_obj.c_type
2523
2524             params = []
2525             fields = {}
2526             parents = self.parents if hasattr(self, 'parents') else [self]
2527             # 'R': parents[0] is always the 'toplevel' container type
2528             params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2529             fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2530             # auxiliary object for 'R' parameters
2531             R_obj = parents[0]
2532
2533             if switch_obj is not None:
2534                 # now look where the fields are defined that are needed to evaluate
2535                 # the switch expr, and store the parent objects in accessor_params and
2536                 # the fields in switch_fields
2537
2538                 # 'S': name for the 'toplevel' switch
2539                 toplevel_switch = parents[1]
2540                 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2541                 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2542
2543                 # initialize prefix for everything "below" S
2544                 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2545                 prefix = [(prefix_str, '->', toplevel_switch)]
2546
2547                 # look for fields in the remaining containers
2548                 for p in parents[2:] + [self]:
2549                     # the separator between parent and child is always '.' here,
2550                     # because of nested switch statements
2551                     if not p.is_bitcase or (p.is_bitcase and p.has_name):
2552                         prefix.append((p.name[-1], '.', p))
2553                     fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2554
2555                 # auxiliary object for 'S' parameter
2556                 S_obj = parents[1]
2557
2558             if list.member.fixed_size():
2559                 idx = 1 if switch_obj is not None else 0
2560                 f.write('.HP\n')
2561                 f.write('%s *\\fB%s\\fP(%s);\n' %
2562                         (field.c_field_type, field.c_accessor_name, params[idx][0]))
2563                 create_link('%s' % field.c_accessor_name)
2564
2565             f.write('.HP\n')
2566             f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2567                     (field.c_length_name, c_type))
2568             create_link('%s' % field.c_length_name)
2569
2570             if field.type.member.is_simple:
2571                 f.write('.HP\n')
2572                 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2573                         (field.c_end_name, c_type))
2574                 create_link('%s' % field.c_end_name)
2575             else:
2576                 f.write('.HP\n')
2577                 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2578                         (field.c_iterator_type, field.c_iterator_name,
2579                          c_type))
2580                 create_link('%s' % field.c_iterator_name)
2581
2582         for field in self.reply.fields:
2583             if field.type.is_list and not field.type.fixed_size():
2584                 _c_accessors_list(self, field)
2585             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2586                 _c_accessors_field(self, field)
2587
2588
2589     f.write('.br\n')
2590     # Re-enable hyphenation and adjusting to both sides
2591     f.write('.hy 1\n')
2592
2593     # argument reference
2594     f.write('.SH REQUEST ARGUMENTS\n')
2595     f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2596     f.write('The XCB connection to X11.\n')
2597     for field in param_fields:
2598         f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2599         printed_enum = False
2600         # XXX: hard-coded until we fix xproto.xml
2601         if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2602             field.enum = 'GC'
2603         elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2604             field.enum = 'CW'
2605         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2606             field.enum = 'CW'
2607         if hasattr(field, "enum") and field.enum:
2608             # XXX: why the 'xcb' prefix?
2609             key = ('xcb', field.enum)
2610             if key in enums:
2611                 f.write('One of the following values:\n')
2612                 f.write('.RS 1i\n')
2613                 enum = enums[key]
2614                 count = len(enum.values)
2615                 for (enam, eval) in enum.values:
2616                     count = count - 1
2617                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2618                     if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2619                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2620                         f.write('%s\n' % desc)
2621                     else:
2622                         f.write('TODO: NOT YET DOCUMENTED.\n')
2623                 f.write('.RE\n')
2624                 f.write('.RS 1i\n')
2625                 printed_enum = True
2626
2627         if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2628             desc = self.doc.fields[field.field_name]
2629             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2630             if printed_enum:
2631                 f.write('\n')
2632             f.write('%s\n' % desc)
2633         else:
2634             f.write('TODO: NOT YET DOCUMENTED.\n')
2635         if printed_enum:
2636             f.write('.RE\n')
2637
2638     # Reply reference
2639     if not void:
2640         f.write('.SH REPLY FIELDS\n')
2641         # These fields are present in every reply:
2642         f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2643         f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2644                  'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2645                  'be used to tell replies apart from each other.\n') %
2646                  _n(self.reply.name).upper())
2647         f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2648         f.write('The sequence number of the last request processed by the X11 server.\n')
2649         f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2650         f.write('The length of the reply, in words (a word is 4 bytes).\n')
2651         for field in self.reply.fields:
2652             if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2653                 field.c_field_name.startswith('pad')):
2654                 continue
2655
2656             if field.type.is_list and not field.type.fixed_size():
2657                 continue
2658             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2659                 continue
2660             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2661             printed_enum = False
2662             if hasattr(field, "enum") and field.enum:
2663                 # XXX: why the 'xcb' prefix?
2664                 key = ('xcb', field.enum)
2665                 if key in enums:
2666                     f.write('One of the following values:\n')
2667                     f.write('.RS 1i\n')
2668                     enum = enums[key]
2669                     count = len(enum.values)
2670                     for (enam, eval) in enum.values:
2671                         count = count - 1
2672                         f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2673                         if enum.doc and enam in enum.doc.fields:
2674                             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2675                             f.write('%s\n' % desc)
2676                         else:
2677                             f.write('TODO: NOT YET DOCUMENTED.\n')
2678                     f.write('.RE\n')
2679                     f.write('.RS 1i\n')
2680                     printed_enum = True
2681
2682             if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2683                 desc = self.reply.doc.fields[field.field_name]
2684                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2685                 if printed_enum:
2686                     f.write('\n')
2687                 f.write('%s\n' % desc)
2688             else:
2689                 f.write('TODO: NOT YET DOCUMENTED.\n')
2690             if printed_enum:
2691                 f.write('.RE\n')
2692
2693
2694
2695     # text description
2696     f.write('.SH DESCRIPTION\n')
2697     if hasattr(self, "doc") and self.doc and self.doc.description:
2698         desc = self.doc.description
2699         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2700         lines = desc.split('\n')
2701         f.write('\n'.join(lines) + '\n')
2702
2703     f.write('.SH RETURN VALUE\n')
2704     if void:
2705         f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2706                  'have to be handled in the event loop.\n\nIf you want to '
2707                  'handle errors directly with \\fIxcb_request_check\\fP '
2708                  'instead, use \\fI%s_checked\\fP. See '
2709                  '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2710     else:
2711         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2712                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2713                  'handle errors in the event loop instead, use '
2714                  '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2715                  'details.\n') %
2716                 (cookie_type, self.c_reply_name, base_func_name, section))
2717     f.write('.SH ERRORS\n')
2718     if hasattr(self, "doc") and self.doc:
2719         for errtype, errtext in self.doc.errors.items():
2720             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2721             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2722             f.write('%s\n' % (errtext))
2723     if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2724         f.write('This request does never generate any errors.\n')
2725     if hasattr(self, "doc") and self.doc and self.doc.example:
2726         f.write('.SH EXAMPLE\n')
2727         f.write('.nf\n')
2728         f.write('.sp\n')
2729         lines = self.doc.example.split('\n')
2730         f.write('\n'.join(lines) + '\n')
2731         f.write('.fi\n')
2732     f.write('.SH SEE ALSO\n')
2733     if hasattr(self, "doc") and self.doc:
2734         see = ['.BR %s (%s)' % ('xcb-requests', section)]
2735         if self.doc.example:
2736             see.append('.BR %s (%s)' % ('xcb-examples', section))
2737         for seename, seetype in self.doc.see.items():
2738             if seetype == 'program':
2739                 see.append('.BR %s (1)' % seename)
2740             elif seetype == 'event':
2741                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2742             elif seetype == 'request':
2743                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2744             elif seetype == 'function':
2745                 see.append('.BR %s (%s)' % (seename, section))
2746             else:
2747                 see.append('TODO: %s (type %s)' % (seename, seetype))
2748         f.write(',\n'.join(see) + '\n')
2749     f.write('.SH AUTHOR\n')
2750     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2751     f.close()
2752
2753 def _man_event(self, name):
2754     if manpaths:
2755         sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2756     # Our CWD is src/, so this will end up in src/man/
2757     f = open('man/%s.%s' % (self.c_type, section), 'w')
2758     f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2759     # Left-adjust instead of adjusting to both sides
2760     f.write('.ad l\n')
2761     f.write('.SH NAME\n')
2762     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2763     f.write('%s \\- %s\n' % (self.c_type, brief))
2764     f.write('.SH SYNOPSIS\n')
2765     # Don't split words (hyphenate)
2766     f.write('.hy 0\n')
2767     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2768
2769     f.write('.PP\n')
2770     f.write('.SS Event datastructure\n')
2771     f.write('.nf\n')
2772     f.write('.sp\n')
2773     f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2774     struct_fields = []
2775     maxtypelen = 0
2776
2777     for field in self.fields:
2778         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2779             continue
2780         if field.wire:
2781             struct_fields.append(field)
2782
2783     for field in struct_fields:
2784         length = len(field.c_field_type)
2785         # account for '*' pointer_spec
2786         if not field.type.fixed_size():
2787             length += 1
2788         maxtypelen = max(maxtypelen, length)
2789
2790     def _c_complex_field(self, field, space=''):
2791         if (field.type.fixed_size() or
2792             # in case of switch with switch children, don't make the field a pointer
2793             # necessary for unserialize to work
2794             (self.is_switch and field.type.is_switch)):
2795             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2796             f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2797         else:
2798             print >> sys.stderr, 'ERROR: New unhandled documentation case'
2799
2800     if not self.is_switch:
2801         for field in struct_fields:
2802             _c_complex_field(self, field)
2803     else:
2804         for b in self.bitcases:
2805             space = ''
2806             if b.type.has_name:
2807                 space = '    '
2808             for field in b.type.fields:
2809                 _c_complex_field(self, field, space)
2810             if b.type.has_name:
2811                 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2812                 pass
2813
2814     f.write('} \\fB%s\\fP;\n' % self.c_type)
2815     f.write('.fi\n')
2816
2817
2818     f.write('.br\n')
2819     # Re-enable hyphenation and adjusting to both sides
2820     f.write('.hy 1\n')
2821
2822     # argument reference
2823     f.write('.SH EVENT FIELDS\n')
2824     f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2825     f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2826              'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2827              'to tell events apart from each other.\n') % _n(name).upper())
2828     f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2829     f.write('The sequence number of the last request processed by the X11 server.\n')
2830
2831     if not self.is_switch:
2832         for field in struct_fields:
2833             # Skip the fields which every event has, we already documented
2834             # them (see above).
2835             if field.c_field_name in ('response_type', 'sequence'):
2836                 continue
2837             if isinstance(field.type, PadType):
2838                 continue
2839             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2840             if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2841                 desc = self.doc.fields[field.field_name]
2842                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2843                 f.write('%s\n' % desc)
2844             else:
2845                 f.write('NOT YET DOCUMENTED.\n')
2846
2847     # text description
2848     f.write('.SH DESCRIPTION\n')
2849     if hasattr(self, "doc") and self.doc and self.doc.description:
2850         desc = self.doc.description
2851         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2852         lines = desc.split('\n')
2853         f.write('\n'.join(lines) + '\n')
2854
2855     if hasattr(self, "doc") and self.doc and self.doc.example:
2856         f.write('.SH EXAMPLE\n')
2857         f.write('.nf\n')
2858         f.write('.sp\n')
2859         lines = self.doc.example.split('\n')
2860         f.write('\n'.join(lines) + '\n')
2861         f.write('.fi\n')
2862     f.write('.SH SEE ALSO\n')
2863     if hasattr(self, "doc") and self.doc:
2864         see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2865         if self.doc.example:
2866             see.append('.BR %s (%s)' % ('xcb-examples', section))
2867         for seename, seetype in self.doc.see.items():
2868             if seetype == 'program':
2869                 see.append('.BR %s (1)' % seename)
2870             elif seetype == 'event':
2871                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2872             elif seetype == 'request':
2873                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2874             elif seetype == 'function':
2875                 see.append('.BR %s (%s)' % (seename, section))
2876             else:
2877                 see.append('TODO: %s (type %s)' % (seename, seetype))
2878         f.write(',\n'.join(see) + '\n')
2879     f.write('.SH AUTHOR\n')
2880     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2881     f.close()
2882
2883
2884 def c_request(self, name):
2885     '''
2886     Exported function that handles request declarations.
2887     '''
2888     _c_type_setup(self, name, ('request',))
2889
2890     if self.reply:
2891         # Cookie type declaration
2892         _c_cookie(self, name)
2893
2894     # Opcode define
2895     _c_opcode(name, self.opcode)
2896
2897     # Request structure declaration
2898     _c_complex(self)
2899
2900     if self.reply:
2901         _c_type_setup(self.reply, name, ('reply',))
2902         # Reply structure definition
2903         _c_complex(self.reply)
2904         # Request prototypes
2905         has_fds = _c_reply_has_fds(self.reply)
2906         _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
2907         _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
2908         if self.need_aux:
2909             _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
2910             _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
2911         # Reply accessors
2912         _c_accessors(self.reply, name + ('reply',), name)
2913         _c_reply(self, name)
2914         if has_fds:
2915             _c_reply_fds(self, name)
2916     else:
2917         # Request prototypes
2918         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
2919         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
2920         if self.need_aux:
2921             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
2922             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
2923
2924     # We generate the manpage afterwards because _c_type_setup has been called.
2925     # TODO: what about aux helpers?
2926     cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
2927     _man_request(self, name, cookie_type, not self.reply, False)
2928
2929 def c_event(self, name):
2930     '''
2931     Exported function that handles event declarations.
2932     '''
2933
2934     # The generic event structure xcb_ge_event_t has the full_sequence field
2935     # at the 32byte boundary. That's why we've to inject this field into GE
2936     # events while generating the structure for them. Otherwise we would read
2937     # garbage (the internal full_sequence) when accessing normal event fields
2938     # there.
2939     force_packed = False
2940     if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
2941         event_size = 0
2942         for field in self.fields:
2943             if field.type.size != None and field.type.nmemb != None:
2944                 event_size += field.type.size * field.type.nmemb
2945             if event_size == 32:
2946                 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
2947                 idx = self.fields.index(field)
2948                 self.fields.insert(idx + 1, full_sequence)
2949
2950                 # If the event contains any 64-bit extended fields, they need
2951                 # to remain aligned on a 64-bit boundary.  Adding full_sequence
2952                 # would normally break that; force the struct to be packed.
2953                 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
2954                 break
2955
2956     _c_type_setup(self, name, ('event',))
2957
2958     # Opcode define
2959     _c_opcode(name, self.opcodes[name])
2960
2961     if self.name == name:
2962         # Structure definition
2963         _c_complex(self, force_packed)
2964     else:
2965         # Typedef
2966         _h('')
2967         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
2968
2969     _man_event(self, name)
2970
2971 def c_error(self, name):
2972     '''
2973     Exported function that handles error declarations.
2974     '''
2975     _c_type_setup(self, name, ('error',))
2976
2977     # Opcode define
2978     _c_opcode(name, self.opcodes[name])
2979
2980     if self.name == name:
2981         # Structure definition
2982         _c_complex(self)
2983     else:
2984         # Typedef
2985         _h('')
2986         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
2987
2988
2989 # Main routine starts here
2990
2991 # Must create an "output" dictionary before any xcbgen imports.
2992 output = {'open'    : c_open,
2993           'close'   : c_close,
2994           'simple'  : c_simple,
2995           'enum'    : c_enum,
2996           'struct'  : c_struct,
2997           'union'   : c_union,
2998           'request' : c_request,
2999           'event'   : c_event,
3000           'error'   : c_error, 
3001           }
3002
3003 # Boilerplate below this point
3004
3005 # Check for the argument that specifies path to the xcbgen python package.
3006 try:
3007     opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3008 except getopt.GetoptError as err:
3009     print(err)
3010     print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3011     sys.exit(1)
3012
3013 for (opt, arg) in opts:
3014     if opt == '-c':
3015         center_footer=arg
3016     if opt == '-l':
3017         left_footer=arg
3018     if opt == '-s':
3019         section=arg
3020     if opt == '-p':
3021         sys.path.insert(1, arg)
3022     elif opt == '-m':
3023         manpaths = True
3024         sys.stdout.write('man_MANS = ')
3025
3026 # Import the module class
3027 try:
3028     from xcbgen.state import Module
3029     from xcbgen.xtypes import *
3030 except ImportError:
3031     print('''
3032 Failed to load the xcbgen Python package!
3033 Make sure that xcb/proto installed it on your Python path.
3034 If not, you will need to create a .pth file or define $PYTHONPATH
3035 to extend the path.
3036 Refer to the README file in xcb/proto for more info.
3037 ''')
3038     raise
3039
3040 # Ensure the man subdirectory exists
3041 try:
3042     os.mkdir('man')
3043 except OSError as e:
3044     if e.errno != errno.EEXIST:
3045         raise
3046
3047 # Parse the xml header
3048 module = Module(args[0], output)
3049
3050 # Build type-registry and resolve type dependencies
3051 module.register()
3052 module.resolve()
3053
3054 # Output the code
3055 module.generate()