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