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