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