_c_helper_fieldaccess_expr: remove handling for empty sep
[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 is not None and expr.lenfield.prev_varsized_field is not None:
1594         # special case: variable and fixed size fields are intermixed
1595         # if the lenfield is among the fixed size fields, there is no need
1596         # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'>
1597         return field_mapping(expr.lenfield_name)
1598     elif expr.lenfield_name is not None:
1599         return lenfield_name
1600     else:
1601         return str(expr.nmemb)
1602
1603 def _c_accessor_get_expr(expr, field_mapping):
1604     '''
1605     Figures out what C code is needed to get the length of a list field.
1606     The field_mapping parameter can be used to change the absolute name of a length field.
1607     Recurses for math operations.
1608     Returns bitcount for value-mask fields.
1609     Otherwise, uses the value of the length field.
1610     '''
1611     lenexp = _c_accessor_get_length(expr, field_mapping)
1612
1613     if expr.op == '~':
1614         return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1615     elif expr.op == 'popcount':
1616         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')'
1617     elif expr.op == 'enumref':
1618         enum_name = expr.lenfield_type.name
1619         constant_name = expr.lenfield_name
1620         c_name = _n(enum_name + (constant_name,)).upper()
1621         return c_name
1622     elif expr.op == 'sumof':
1623         # locate the referenced list object
1624         list_obj = expr.lenfield_type
1625         field = None
1626         for f in expr.lenfield_parent.fields:
1627             if f.field_name == expr.lenfield_name:
1628                 field = f
1629                 break
1630
1631         if field is None:
1632             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1633         list_name = field_mapping[field.c_field_name][0]
1634         c_length_func = "%s(%s)" % (field.c_length_name, list_name)
1635         c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping)
1636         # create explicit code for computing the sum.
1637         # This works for all C-types which can be added to int64_t with +=
1638         _c_pre.start()
1639         lengthvar = _c_pre.get_tempvarname()
1640         loopvar = _c_pre.get_tempvarname()
1641         sumvar = _c_pre.get_tempvarname()
1642         listvar = _c_pre.get_tempvarname()
1643         _c_pre.tempvar("int %s; /* sumof length */", lengthvar)
1644         _c_pre.tempvar("int %s; /* sumof loop counter */", loopvar)
1645         _c_pre.tempvar("int64_t %s; /* sumof sum */", sumvar)
1646         _c_pre.tempvar("const %s* %s; /* sumof list ptr */", field.c_field_type, listvar)
1647         _c_pre.code("/* sumof start */")
1648         _c_pre.code("%s = %s;", lengthvar, c_length_func)
1649         _c_pre.code("%s = 0;", sumvar)
1650         _c_pre.code("%s = %s;", listvar, list_name)
1651         _c_pre.code("for (%s = 0; %s < %s; %s++) {", loopvar, loopvar, lengthvar, loopvar)
1652         _c_pre.indent()
1653
1654         if expr.rhs is None:
1655             _c_pre.code("%s += *%s;", sumvar, listvar)
1656         else:
1657             # sumof has a nested expression which has to be evaluated in
1658             # the context of this list element
1659
1660             # field mapping for the subexpression needs to include
1661             # the fields of the list-member type
1662             scoped_field_mapping = field_mapping.copy()
1663             scoped_field_mapping.update(
1664                 _c_helper_field_mapping(
1665                     field.type.member,
1666                     [(listvar, '->', field.type.member)]))
1667
1668             # cause pre-code of the subexpression be added right here
1669             _c_pre.end()
1670             # compute the subexpression
1671             rhs_expr_str = _c_accessor_get_expr(expr.rhs, scoped_field_mapping)
1672             # resume with our code
1673             _c_pre.start()
1674             # output the summation expression
1675             _c_pre.code("%s += %s;", sumvar, rhs_expr_str)
1676
1677         _c_pre.code("%s++;", listvar)
1678         _c_pre.pop_indent()
1679         _c_pre.code("}")
1680         _c_pre.code("/* sumof end. Result is in %s */", sumvar)
1681         _c_pre.end()
1682         return sumvar
1683     elif expr.op != None:
1684         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
1685                 ' ' + expr.op + ' ' +
1686                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
1687     elif expr.bitfield:
1688         return 'xcb_popcount(' + lenexp + ')'
1689     else:
1690         return lenexp
1691
1692 def type_pad_type(type):
1693     if type == 'void':
1694         return 'char'
1695     return type
1696
1697 def _c_accessors_field(self, field):
1698     '''
1699     Declares the accessor functions for a non-list field that follows a variable-length field.
1700     '''
1701     c_type = self.c_type
1702
1703     # special case: switch
1704     switch_obj = self if self.is_switch else None
1705     if self.is_case_or_bitcase:
1706         switch_obj = self.parents[-1]
1707     if switch_obj is not None:
1708         c_type = switch_obj.c_type
1709
1710     if field.type.is_simple:
1711         _hc('')
1712         _hc('%s', field.c_field_type)
1713         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1714         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1715         _c('{')
1716         if field.prev_varsized_field is None:
1717             _c('    return (%s *) (R + 1);', field.c_field_type)
1718         else:
1719             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1720             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1721                field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1722         _c('}')
1723     else:
1724         _hc('')
1725         if field.type.is_switch and switch_obj is None:
1726             return_type = 'void *'
1727         else:
1728             return_type = '%s *' % field.c_field_type
1729
1730         _hc(return_type)
1731         _h('%s (const %s *R  /**< */);', field.c_accessor_name, c_type)
1732         _c('%s (const %s *R  /**< */)', field.c_accessor_name, c_type)
1733         _c('{')
1734         if field.prev_varsized_field is None:
1735             _c('    return (%s) (R + 1);', return_type)
1736             # note: the special case 'variable fields followed by fixed size fields'
1737             #       is not of any consequence here, since the ordering gets
1738             #       'corrected' in the reply function
1739         else:
1740             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1741             _c('    return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);',
1742                return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset)
1743         _c('}')
1744
1745
1746 def _c_accessors_list(self, field):
1747     '''
1748     Declares the accessor functions for a list field.
1749     Declares a direct-accessor function only if the list members are fixed size.
1750     Declares length and get-iterator functions always.
1751     '''
1752
1753     def get_align_pad(field):
1754             prev = field.prev_varsized_field
1755             prev_prev = field.prev_varsized_field.prev_varsized_field
1756
1757             if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None):
1758                 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align)
1759             else:
1760                 return (prev, None)
1761
1762
1763     list = field.type
1764     c_type = self.c_type
1765
1766     # special case: switch
1767     # in case of switch, 2 params have to be supplied to certain accessor functions:
1768     #   1. the anchestor object (request or reply)
1769     #   2. the (anchestor) switch object
1770     # the reason is that switch is either a child of a request/reply or nested in another switch,
1771     # so whenever we need to access a length field, we might need to refer to some anchestor type
1772     switch_obj = self if self.is_switch else None
1773     if self.is_case_or_bitcase:
1774         switch_obj = self.parents[-1]
1775     if switch_obj is not None:
1776         c_type = switch_obj.c_type
1777
1778     params = []
1779     fields = {}
1780     parents = self.parents if hasattr(self, 'parents') else [self]
1781     # 'R': parents[0] is always the 'toplevel' container type
1782     params.append(('const %s *R' % parents[0].c_type, parents[0]))
1783     fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
1784     # auxiliary object for 'R' parameters
1785     R_obj = parents[0]
1786
1787     if switch_obj is not None:
1788         # now look where the fields are defined that are needed to evaluate
1789         # the switch expr, and store the parent objects in accessor_params and
1790         # the fields in switch_fields
1791
1792         # 'S': name for the 'toplevel' switch
1793         toplevel_switch = parents[1]
1794         params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
1795         fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
1796
1797         # initialize prefix for everything "below" S
1798         prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
1799         prefix = [(prefix_str, '->', toplevel_switch)]
1800
1801         # look for fields in the remaining containers
1802         for p in parents[2:] + [self]:
1803             # the separator between parent and child is always '.' here,
1804             # because of nested switch statements
1805             if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
1806                 prefix.append((p.name[-1], '.', p))
1807             fields.update(_c_helper_field_mapping(p, prefix, flat=True))
1808
1809         # auxiliary object for 'S' parameter
1810         S_obj = parents[1]
1811
1812     _h_setlevel(1)
1813     _c_setlevel(1)
1814     if list.member.fixed_size():
1815         idx = 1 if switch_obj is not None else 0
1816         _hc('')
1817         _hc('%s *', field.c_field_type)
1818
1819         _h('%s (%s  /**< */);', field.c_accessor_name, params[idx][0])
1820         _c('%s (%s  /**< */)', field.c_accessor_name, params[idx][0])
1821
1822         _c('{')
1823         if switch_obj is not None:
1824             _c('    return %s;', fields[field.c_field_name][0])
1825         elif field.prev_varsized_field is None:
1826             _c('    return (%s *) (R + 1);', field.c_field_type)
1827         else:
1828             (prev_varsized_field, align_pad) = get_align_pad(field)
1829
1830             if align_pad is None:
1831                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1832                     type_pad_type(field.first_field_after_varsized.type.c_type))
1833
1834             _c('    xcb_generic_iterator_t prev = %s;',
1835                 _c_iterator_get_end(prev_varsized_field, 'R'))
1836             _c('    return (%s *) ((char *) prev.data + %s + %d);',
1837                field.c_field_type, align_pad, field.prev_varsized_offset)
1838         _c('}')
1839
1840     _hc('')
1841     _hc('int')
1842     if switch_obj is not None:
1843         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
1844         spacing = ' '*(len(field.c_length_name)+2)
1845         _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1846         _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1847     else:
1848         _h('%s (const %s *R  /**< */);', field.c_length_name, c_type)
1849         _c('%s (const %s *R  /**< */)', field.c_length_name, c_type)
1850     _c('{')
1851     length = _c_accessor_get_expr(field.type.expr, fields)
1852     _c('    return %s;', length)
1853     _c('}')
1854
1855     if field.type.member.is_simple:
1856         _hc('')
1857         _hc('xcb_generic_iterator_t')
1858         if switch_obj is not None:
1859             _hc('%s (const %s *R  /**< */,', field.c_end_name, R_obj.c_type)
1860             spacing = ' '*(len(field.c_end_name)+2)
1861             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1862             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1863         else:
1864             _h('%s (const %s *R  /**< */);', field.c_end_name, c_type)
1865             _c('%s (const %s *R  /**< */)', field.c_end_name, c_type)
1866         _c('{')
1867         _c('    xcb_generic_iterator_t i;')
1868
1869         param = 'R' if switch_obj is None else 'S'
1870         if switch_obj is not None:
1871             _c('    i.data = %s + %s;', fields[field.c_field_name][0],
1872                _c_accessor_get_expr(field.type.expr, fields))
1873         elif field.prev_varsized_field == None:
1874             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
1875                _c_accessor_get_expr(field.type.expr, fields))
1876         else:
1877             _c('    xcb_generic_iterator_t child = %s;',
1878                _c_iterator_get_end(field.prev_varsized_field, 'R'))
1879             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype,
1880                _c_accessor_get_expr(field.type.expr, fields))
1881
1882         _c('    i.rem = 0;')
1883         _c('    i.index = (char *) i.data - (char *) %s;', param)
1884         _c('    return i;')
1885         _c('}')
1886
1887     else:
1888         _hc('')
1889         _hc('%s', field.c_iterator_type)
1890         if switch_obj is not None:
1891             _hc('%s (const %s *R  /**< */,', field.c_iterator_name, R_obj.c_type)
1892             spacing = ' '*(len(field.c_iterator_name)+2)
1893             _h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
1894             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
1895         else:
1896             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
1897             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
1898         _c('{')
1899         _c('    %s i;', field.c_iterator_type)
1900
1901         _c_pre.start()
1902         length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
1903
1904         if switch_obj is not None:
1905             _c_pre.end()
1906             _c('    i.data = %s;', fields[field.c_field_name][0])
1907             _c('    i.rem = %s;', length_expr_str)
1908         elif field.prev_varsized_field == None:
1909             _c_pre.end()
1910             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1911         else:
1912             (prev_varsized_field, align_pad) = get_align_pad(field)
1913
1914             if align_pad is None:
1915                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
1916                     type_pad_type(field.c_field_type))
1917
1918             _c('    xcb_generic_iterator_t prev = %s;',
1919                 _c_iterator_get_end(prev_varsized_field, 'R'))
1920             _c_pre.end()
1921             _c('    i.data = (%s *) ((char *) prev.data + %s);',
1922                 field.c_field_type, align_pad)
1923
1924         if switch_obj is None:
1925             _c('    i.rem = %s;', length_expr_str)
1926         _c('    i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
1927         _c('    return i;')
1928         _c('}')
1929
1930 def _c_accessors(self, name, base):
1931     '''
1932     Declares the accessor functions for the fields of a structure.
1933     '''
1934     # no accessors for switch itself -
1935     # switch always needs to be unpacked explicitly
1936 #    if self.is_switch:
1937 #        pass
1938 #    else:
1939     if True:
1940         for field in self.fields:
1941             if not field.type.is_pad:
1942                 if _c_field_needs_list_accessor(field):
1943                     _c_accessors_list(self, field)
1944                 elif _c_field_needs_field_accessor(field):
1945                     _c_accessors_field(self, field)
1946
1947 def c_simple(self, name):
1948     '''
1949     Exported function that handles cardinal type declarations.
1950     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1951     '''
1952     _c_type_setup(self, name, ())
1953
1954     if (self.name != name):
1955         # Typedef
1956         _h_setlevel(0)
1957         my_name = _t(name)
1958         _h('')
1959         _h('typedef %s %s;', _t(self.name), my_name)
1960
1961         # Iterator
1962         _c_iterator(self, name)
1963
1964 def _c_complex(self, force_packed = False):
1965     '''
1966     Helper function for handling all structure types.
1967     Called for all structs, requests, replies, events, errors.
1968     '''
1969     _h_setlevel(0)
1970     _h('')
1971     _h('/**')
1972     _h(' * @brief %s', self.c_type)
1973     _h(' **/')
1974     _h('typedef %s %s {', self.c_container, self.c_type)
1975
1976     struct_fields = []
1977     maxtypelen = 0
1978
1979     varfield = None
1980     for field in self.fields:
1981         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
1982             varfield = field.c_field_name
1983             continue
1984         if field.wire:
1985             struct_fields.append(field)
1986
1987     for field in struct_fields:
1988         length = len(field.c_field_type)
1989         # account for '*' pointer_spec
1990         if not field.type.fixed_size() and not self.is_union:
1991             length += 1
1992         maxtypelen = max(maxtypelen, length)
1993
1994     def _c_complex_field(self, field, space=''):
1995         if (field.type.fixed_size() or self.is_union or
1996             # in case of switch with switch children, don't make the field a pointer
1997             # necessary for unserialize to work
1998             (self.is_switch and field.type.is_switch)):
1999             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2000             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2001         else:
2002             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2003             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2004
2005     if not self.is_switch:
2006         for field in struct_fields:
2007             _c_complex_field(self, field)
2008     else:
2009         for b in self.bitcases:
2010             space = ''
2011             if b.type.has_name:
2012                 _h('    struct {')
2013                 space = '    '
2014             for field in b.type.fields:
2015                 _c_complex_field(self, field, space)
2016             if b.type.has_name:
2017                 _h('    } %s;', b.c_field_name)
2018
2019     _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type)
2020
2021 def c_struct(self, name):
2022     '''
2023     Exported function that handles structure declarations.
2024     '''
2025     _c_type_setup(self, name, ())
2026     _c_complex(self)
2027     _c_accessors(self, name, name)
2028     _c_iterator(self, name)
2029
2030 def c_union(self, name):
2031     '''
2032     Exported function that handles union declarations.
2033     '''
2034     _c_type_setup(self, name, ())
2035     _c_complex(self)
2036     _c_iterator(self, name)
2037
2038 def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
2039     '''
2040     Declares a request function.
2041     '''
2042
2043     # Four stunningly confusing possibilities here:
2044     #
2045     #   Void            Non-void
2046     # ------------------------------
2047     # "req"            "req"
2048     # 0 flag           CHECKED flag   Normal Mode
2049     # void_cookie      req_cookie
2050     # ------------------------------
2051     # "req_checked"    "req_unchecked"
2052     # CHECKED flag     0 flag         Abnormal Mode
2053     # void_cookie      req_cookie
2054     # ------------------------------
2055
2056
2057     # Whether we are _checked or _unchecked
2058     checked = void and not regular
2059     unchecked = not void and not regular
2060
2061     # What kind of cookie we return
2062     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
2063
2064     # What flag is passed to xcb_request
2065     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
2066
2067     if reply_fds:
2068         if func_flags == '0':
2069             func_flags = 'XCB_REQUEST_REPLY_FDS'
2070         else:
2071             func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
2072
2073     # Global extension id variable or NULL for xproto
2074     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
2075
2076     # What our function name is
2077     func_name = self.c_request_name if not aux else self.c_aux_name
2078     if checked:
2079         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
2080     if unchecked:
2081         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
2082
2083     param_fields = []
2084     wire_fields = []
2085     maxtypelen = len('xcb_connection_t')
2086     serial_fields = []
2087     # special case: list with variable size elements
2088     list_with_var_size_elems = False
2089
2090     for field in self.fields:
2091         if field.visible:
2092             # The field should appear as a call parameter
2093             param_fields.append(field)
2094         if field.wire and not field.auto:
2095             # We need to set the field up in the structure
2096             wire_fields.append(field)
2097         if field.type.c_need_serialize or field.type.c_need_sizeof:
2098             serial_fields.append(field)
2099
2100     for field in param_fields:
2101         c_field_const_type = field.c_field_const_type
2102         if field.type.c_need_serialize and not aux:
2103             c_field_const_type = "const void"
2104         if len(c_field_const_type) > maxtypelen:
2105             maxtypelen = len(c_field_const_type)
2106         if field.type.is_list and not field.type.member.fixed_size():
2107             list_with_var_size_elems = True
2108
2109     _h_setlevel(1)
2110     _c_setlevel(1)
2111     _h('')
2112     _h('/**')
2113     if hasattr(self, "doc") and self.doc:
2114         if self.doc.brief:
2115             _h(' * @brief ' + self.doc.brief)
2116         else:
2117             _h(' * No brief doc yet')
2118
2119     _h(' *')
2120     _h(' * @param c The connection')
2121     param_names = [f.c_field_name for f in param_fields]
2122     if hasattr(self, "doc") and self.doc:
2123         for field in param_fields:
2124             # XXX: hard-coded until we fix xproto.xml
2125             base_func_name = self.c_request_name if not aux else self.c_aux_name
2126             if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2127                 field.enum = 'GC'
2128             elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2129                 field.enum = 'CW'
2130             elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2131                 field.enum = 'CW'
2132             if field.enum:
2133                 # XXX: why the 'xcb' prefix?
2134                 key = ('xcb', field.enum)
2135
2136                 tname = _t(key)
2137                 if namecount[tname] > 1:
2138                     tname = _t(key + ('enum',))
2139                 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
2140
2141             if self.doc and field.field_name in self.doc.fields:
2142                 desc = self.doc.fields[field.field_name]
2143                 for name in param_names:
2144                     desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2145                 desc = desc.split("\n")
2146                 desc = [line if line != '' else '\\n' for line in desc]
2147                 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
2148             # If there is no documentation yet, we simply don't generate an
2149             # @param tag. Doxygen will then warn about missing documentation.
2150
2151     _h(' * @return A cookie')
2152     _h(' *')
2153
2154     if hasattr(self, "doc") and self.doc:
2155         if self.doc.description:
2156             desc = self.doc.description
2157             for name in param_names:
2158                 desc = desc.replace('`%s`' % name, '\\a %s' % (name))
2159             desc = desc.split("\n")
2160             _h(' * ' + "\n * ".join(desc))
2161         else:
2162             _h(' * No description yet')
2163     else:
2164         _h(' * Delivers a request to the X server.')
2165     _h(' *')
2166     if checked:
2167         _h(' * This form can be used only if the request will not cause')
2168         _h(' * a reply to be generated. Any returned error will be')
2169         _h(' * saved for handling by xcb_request_check().')
2170     if unchecked:
2171         _h(' * This form can be used only if the request will cause')
2172         _h(' * a reply to be generated. Any returned error will be')
2173         _h(' * placed in the event queue.')
2174     _h(' */')
2175     _c('')
2176     _hc('%s', cookie_type)
2177
2178     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
2179     comma = ',' if len(param_fields) else ');'
2180     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2181     comma = ',' if len(param_fields) else ')'
2182     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
2183
2184     func_spacing = ' ' * (len(func_name) + 2)
2185     count = len(param_fields)
2186     for field in param_fields:
2187         count = count - 1
2188         c_field_const_type = field.c_field_const_type
2189         c_pointer = field.c_pointer
2190         if field.type.c_need_serialize and not aux:
2191             c_field_const_type = "const void"
2192             c_pointer = '*'
2193         spacing = ' ' * (maxtypelen - len(c_field_const_type))
2194         comma = ',' if count else ');'
2195         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2196            spacing, c_pointer, field.c_field_name, comma)
2197         comma = ',' if count else ')'
2198         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type,
2199            spacing, c_pointer, field.c_field_name, comma)
2200
2201     count = 2
2202     if not self.c_var_followed_by_fixed_fields:
2203         for field in param_fields:
2204             if not field.type.fixed_size():
2205                 count = count + 2
2206                 if field.type.c_need_serialize:
2207                     # _serialize() keeps track of padding automatically
2208                     count -= 1
2209     dimension = count + 2
2210
2211     _c('{')
2212     _c('    static const xcb_protocol_request_t xcb_req = {')
2213     _c('        /* count */ %d,', count)
2214     _c('        /* ext */ %s,', func_ext_global)
2215     _c('        /* opcode */ %s,', self.c_request_name.upper())
2216     _c('        /* isvoid */ %d', 1 if void else 0)
2217     _c('    };')
2218     _c('')
2219
2220     _c('    struct iovec xcb_parts[%d];', dimension)
2221     _c('    %s xcb_ret;', func_cookie)
2222     _c('    %s xcb_out;', self.c_type)
2223     if self.c_var_followed_by_fixed_fields:
2224         _c('    /* in the protocol description, variable size fields are followed by fixed size fields */')
2225         _c('    void *xcb_aux = 0;')
2226
2227
2228     for idx, f in enumerate(serial_fields):
2229         if aux:
2230             _c('    void *xcb_aux%d = 0;' % (idx))
2231     if list_with_var_size_elems:
2232         _c('    unsigned int i;')
2233         _c('    unsigned int xcb_tmp_len;')
2234         _c('    char *xcb_tmp;')
2235     _c('')
2236     # simple request call tracing
2237 #    _c('    printf("in function %s\\n");' % func_name)
2238
2239     # fixed size fields
2240     for field in wire_fields:
2241         if field.type.fixed_size():
2242             if field.type.is_expr:
2243                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None))
2244             elif field.type.is_pad:
2245                 if field.type.nmemb == 1:
2246                     _c('    xcb_out.%s = 0;', field.c_field_name)
2247                 else:
2248                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
2249             else:
2250                 if field.type.nmemb == 1:
2251                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
2252                 else:
2253                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
2254
2255     def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'):
2256         serialize_args = get_serialize_params(context, type_obj,
2257                                               c_field_name,
2258                                               aux_var)[2]
2259         return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
2260
2261     # calls in order to free dyn. all. memory
2262     free_calls = []
2263
2264     _c('')
2265     if not self.c_var_followed_by_fixed_fields:
2266         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2267         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
2268         _c('    xcb_parts[3].iov_base = 0;')
2269         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
2270
2271         count = 4
2272
2273         for field in param_fields:
2274             if not field.type.fixed_size():
2275                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
2276                 # default: simple cast to char *
2277                 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
2278                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2279                     if field.type.is_list:
2280                         if field.type.member.fixed_size():
2281                             _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
2282                                _c_accessor_get_expr(field.type.expr, None),
2283                                field.type.member.c_wiretype)
2284                         else:
2285                             list_length = _c_accessor_get_expr(field.type.expr, None)
2286
2287                             length = ''
2288                             _c("    xcb_parts[%d].iov_len = 0;" % count)
2289                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
2290                             _c("    for(i=0; i<%s; i++) {" % list_length)
2291                             _c("        xcb_tmp_len = %s(xcb_tmp);" %
2292                                               (field.type.c_sizeof_name))
2293                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
2294                             _c("        xcb_tmp += xcb_tmp_len;")
2295                             _c("    }")
2296                     else:
2297                         # not supposed to happen
2298                         raise Exception("unhandled variable size field %s" % field.c_field_name)
2299                 else:
2300                     if not aux:
2301                         _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
2302                     idx = serial_fields.index(field)
2303                     aux_var = '&xcb_aux%d' % idx
2304                     context = 'serialize' if aux else 'sizeof'
2305                     _c('    xcb_parts[%d].iov_len =', count)
2306                     if aux:
2307                         serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context)
2308                         _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
2309                         _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
2310                         free_calls.append('    free(xcb_aux%d);' % idx)
2311                     else:
2312                         serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context)
2313                         func_name = field.type.c_sizeof_name
2314                         _c('      %s (%s);', func_name, serialize_args)
2315
2316                 count += 1
2317                 if not (field.type.c_need_serialize or field.type.c_need_sizeof):
2318                     # the _serialize() function keeps track of padding automatically
2319                     _c('    xcb_parts[%d].iov_base = 0;', count)
2320                     _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
2321                     count += 1
2322
2323     # elif self.c_var_followed_by_fixed_fields:
2324     else:
2325         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
2326         # request header: opcodes + length
2327         _c('    xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);')
2328         count += 1
2329         # call _serialize()
2330         buffer_var = '&xcb_aux'
2331         serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize')
2332         _c('    xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args)
2333         _c('    xcb_parts[%d].iov_base = (char *) xcb_aux;', count)
2334         free_calls.append('    free(xcb_aux);')
2335         # no padding necessary - _serialize() keeps track of padding automatically
2336
2337     _c('')
2338     for field in param_fields:
2339         if field.isfd:
2340             _c('    xcb_send_fd(c, %s);', field.c_field_name)
2341
2342     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
2343
2344     # free dyn. all. data, if any
2345     for f in free_calls:
2346         _c(f)
2347     _c('    return xcb_ret;')
2348     _c('}')
2349
2350 def _c_reply(self, name):
2351     '''
2352     Declares the function that returns the reply structure.
2353     '''
2354     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
2355     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
2356     spacing3 = ' ' * (len(self.c_reply_name) + 2)
2357
2358     # check if _unserialize() has to be called for any field
2359     def look_for_special_cases(complex_obj):
2360         unserialize_fields = []
2361         # no unserialize call in case of switch
2362         if not complex_obj.is_switch:
2363             for field in complex_obj.fields:
2364                 # three cases: 1. field with special case
2365                 #              2. container that contains special case field
2366                 #              3. list with special case elements
2367                 if field.type.c_var_followed_by_fixed_fields:
2368                     unserialize_fields.append(field)
2369                 elif field.type.is_container:
2370                     unserialize_fields += look_for_special_cases(field.type)
2371                 elif field.type.is_list:
2372                     if field.type.member.c_var_followed_by_fixed_fields:
2373                         unserialize_fields.append(field)
2374                     if field.type.member.is_container:
2375                         unserialize_fields += look_for_special_cases(field.type.member)
2376         return unserialize_fields
2377
2378     unserialize_fields = look_for_special_cases(self.reply)
2379
2380     _h('')
2381     _h('/**')
2382     _h(' * Return the reply')
2383     _h(' * @param c      The connection')
2384     _h(' * @param cookie The cookie')
2385     _h(' * @param e      The xcb_generic_error_t supplied')
2386     _h(' *')
2387     _h(' * Returns the reply of the request asked by')
2388     _h(' *')
2389     _h(' * The parameter @p e supplied to this function must be NULL if')
2390     _h(' * %s(). is used.', self.c_unchecked_name)
2391     _h(' * Otherwise, it stores the error if any.')
2392     _h(' *')
2393     _h(' * The returned value must be freed by the caller using free().')
2394     _h(' */')
2395     _c('')
2396     _hc('%s *', self.c_reply_type)
2397     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
2398     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
2399     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
2400     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
2401     _c('{')
2402
2403     if len(unserialize_fields)>0:
2404         # certain variable size fields need to be unserialized explicitly
2405         _c('    %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);',
2406            self.c_reply_type, self.c_reply_type)
2407         _c('    int i;')
2408         for field in unserialize_fields:
2409             if field.type.is_list:
2410                 _c('    %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name)
2411                 _c('    int %s_len = %s(reply);', field.c_field_name, field.c_length_name)
2412                 _c('    %s *%s_data;', field.c_field_type, field.c_field_name)
2413             else:
2414                 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type)
2415         # call _unserialize(), using the reply as source and target buffer
2416         _c('    /* special cases: transform parts of the reply to match XCB data structures */')
2417         for field in unserialize_fields:
2418             if field.type.is_list:
2419                 _c('    for(i=0; i<%s_len; i++) {', field.c_field_name)
2420                 _c('        %s_data = %s_iter.data;', field.c_field_name, field.c_field_name)
2421                 _c('        %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name,
2422                    field.c_field_name, field.c_field_name)
2423                 _c('        %s(&%s_iter);', field.type.c_next_name, field.c_field_name)
2424                 _c('    }')
2425         # return the transformed reply
2426         _c('    return reply;')
2427
2428     else:
2429         _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
2430
2431     _c('}')
2432
2433 def _c_reply_has_fds(self):
2434     for field in self.fields:
2435         if field.isfd:
2436             return True
2437     return False
2438
2439 def _c_reply_fds(self, name):
2440     '''
2441     Declares the function that returns fds related to the reply.
2442     '''
2443     spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
2444     spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
2445     _h('')
2446     _h('/**')
2447     _h(' * Return the reply fds')
2448     _h(' * @param c      The connection')
2449     _h(' * @param reply  The reply')
2450     _h(' *')
2451     _h(' * Returns the array of reply fds of the request asked by')
2452     _h(' *')
2453     _h(' * The returned value must be freed by the caller using free().')
2454     _h(' */')
2455     _c('')
2456     _hc('int *')
2457     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_fds_name, spacing1)
2458     _h('%s%s  *reply  /**< */);', spacing3, self.c_reply_type)
2459     _c('%s%s  *reply  /**< */)', spacing3, self.c_reply_type)
2460     _c('{')
2461
2462     _c('    return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
2463
2464     _c('}')
2465
2466
2467 def _c_opcode(name, opcode):
2468     '''
2469     Declares the opcode define for requests, events, and errors.
2470     '''
2471     _h_setlevel(0)
2472     _h('')
2473     _h('/** Opcode for %s. */', _n(name))
2474     _h('#define %s %s', _n(name).upper(), opcode)
2475
2476 def _c_cookie(self, name):
2477     '''
2478     Declares the cookie type for a non-void request.
2479     '''
2480     _h_setlevel(0)
2481     _h('')
2482     _h('/**')
2483     _h(' * @brief %s', self.c_cookie_type)
2484     _h(' **/')
2485     _h('typedef struct %s {', self.c_cookie_type)
2486     _h('    unsigned int sequence; /**<  */')
2487     _h('} %s;', self.c_cookie_type)
2488
2489 def _man_request(self, name, cookie_type, void, aux):
2490     param_fields = [f for f in self.fields if f.visible]
2491
2492     func_name = self.c_request_name if not aux else self.c_aux_name
2493
2494     def create_link(linkname):
2495         name = 'man/%s.%s' % (linkname, section)
2496         if manpaths:
2497             sys.stdout.write(name)
2498         f = open(name, 'w')
2499         f.write('.so man%s/%s.%s' % (section, func_name, section))
2500         f.close()
2501
2502     if manpaths:
2503         sys.stdout.write('man/%s.%s ' % (func_name, section))
2504     # Our CWD is src/, so this will end up in src/man/
2505     f = open('man/%s.%s' % (func_name, section), 'w')
2506     f.write('.TH %s %s  "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer))
2507     # Left-adjust instead of adjusting to both sides
2508     f.write('.ad l\n')
2509     f.write('.SH NAME\n')
2510     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2511     f.write('%s \\- %s\n' % (func_name, brief))
2512     f.write('.SH SYNOPSIS\n')
2513     # Don't split words (hyphenate)
2514     f.write('.hy 0\n')
2515     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2516
2517     # function prototypes
2518     prototype = ''
2519     count = len(param_fields)
2520     for field in param_fields:
2521         count = count - 1
2522         c_field_const_type = field.c_field_const_type
2523         c_pointer = field.c_pointer
2524         if c_pointer == ' ':
2525             c_pointer = ''
2526         if field.type.c_need_serialize and not aux:
2527             c_field_const_type = "const void"
2528             c_pointer = '*'
2529         comma = ', ' if count else ');'
2530         prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
2531
2532     f.write('.SS Request function\n')
2533     f.write('.HP\n')
2534     base_func_name = self.c_request_name if not aux else self.c_aux_name
2535     f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
2536     create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
2537     if not void:
2538         f.write('.PP\n')
2539         f.write('.SS Reply datastructure\n')
2540         f.write('.nf\n')
2541         f.write('.sp\n')
2542         f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
2543         struct_fields = []
2544         maxtypelen = 0
2545
2546         for field in self.reply.fields:
2547             if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2548                 continue
2549             if field.wire:
2550                 struct_fields.append(field)
2551
2552         for field in struct_fields:
2553             length = len(field.c_field_type)
2554             # account for '*' pointer_spec
2555             if not field.type.fixed_size():
2556                 length += 1
2557             maxtypelen = max(maxtypelen, length)
2558
2559         def _c_complex_field(self, field, space=''):
2560             if (field.type.fixed_size() or
2561                 # in case of switch with switch children, don't make the field a pointer
2562                 # necessary for unserialize to work
2563                 (self.is_switch and field.type.is_switch)):
2564                 spacing = ' ' * (maxtypelen - len(field.c_field_type))
2565                 f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2566             else:
2567                 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
2568                 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
2569                 #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
2570
2571         if not self.is_switch:
2572             for field in struct_fields:
2573                 _c_complex_field(self, field)
2574         else:
2575             for b in self.bitcases:
2576                 space = ''
2577                 if b.type.has_name:
2578                     space = '    '
2579                 for field in b.type.fields:
2580                     _c_complex_field(self, field, space)
2581                 if b.type.has_name:
2582                     print >> sys.stderr, 'ERROR: New unhandled documentation case'
2583                     pass
2584
2585         f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
2586         f.write('.fi\n')
2587
2588         f.write('.SS Reply function\n')
2589         f.write('.HP\n')
2590         f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
2591                  '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
2592                 (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
2593         create_link('%s' % self.c_reply_name)
2594
2595         has_accessors = False
2596         for field in self.reply.fields:
2597             if field.type.is_list and not field.type.fixed_size():
2598                 has_accessors = True
2599             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2600                 has_accessors = True
2601
2602         if has_accessors:
2603             f.write('.SS Reply accessors\n')
2604
2605         def _c_accessors_field(self, field):
2606             '''
2607             Declares the accessor functions for a non-list field that follows a variable-length field.
2608             '''
2609             c_type = self.c_type
2610
2611             # special case: switch
2612             switch_obj = self if self.is_switch else None
2613             if self.is_case_or_bitcase:
2614                 switch_obj = self.parents[-1]
2615             if switch_obj is not None:
2616                 c_type = switch_obj.c_type
2617
2618             if field.type.is_simple:
2619                 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2620                 create_link('%s' % field.c_accessor_name)
2621             else:
2622                 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
2623                 create_link('%s' % field.c_accessor_name)
2624
2625         def _c_accessors_list(self, field):
2626             '''
2627             Declares the accessor functions for a list field.
2628             Declares a direct-accessor function only if the list members are fixed size.
2629             Declares length and get-iterator functions always.
2630             '''
2631             list = field.type
2632             c_type = self.reply.c_type
2633
2634             # special case: switch
2635             # in case of switch, 2 params have to be supplied to certain accessor functions:
2636             #   1. the anchestor object (request or reply)
2637             #   2. the (anchestor) switch object
2638             # the reason is that switch is either a child of a request/reply or nested in another switch,
2639             # so whenever we need to access a length field, we might need to refer to some anchestor type
2640             switch_obj = self if self.is_switch else None
2641             if self.is_case_or_bitcase:
2642                 switch_obj = self.parents[-1]
2643             if switch_obj is not None:
2644                 c_type = switch_obj.c_type
2645
2646             params = []
2647             fields = {}
2648             parents = self.parents if hasattr(self, 'parents') else [self]
2649             # 'R': parents[0] is always the 'toplevel' container type
2650             params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
2651             fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
2652             # auxiliary object for 'R' parameters
2653             R_obj = parents[0]
2654
2655             if switch_obj is not None:
2656                 # now look where the fields are defined that are needed to evaluate
2657                 # the switch expr, and store the parent objects in accessor_params and
2658                 # the fields in switch_fields
2659
2660                 # 'S': name for the 'toplevel' switch
2661                 toplevel_switch = parents[1]
2662                 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
2663                 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
2664
2665                 # initialize prefix for everything "below" S
2666                 prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
2667                 prefix = [(prefix_str, '->', toplevel_switch)]
2668
2669                 # look for fields in the remaining containers
2670                 for p in parents[2:] + [self]:
2671                     # the separator between parent and child is always '.' here,
2672                     # because of nested switch statements
2673                     if not p.is_case_or_bitcase or (p.is_case_or_bitcase and p.has_name):
2674                         prefix.append((p.name[-1], '.', p))
2675                     fields.update(_c_helper_field_mapping(p, prefix, flat=True))
2676
2677                 # auxiliary object for 'S' parameter
2678                 S_obj = parents[1]
2679
2680             if list.member.fixed_size():
2681                 idx = 1 if switch_obj is not None else 0
2682                 f.write('.HP\n')
2683                 f.write('%s *\\fB%s\\fP(%s);\n' %
2684                         (field.c_field_type, field.c_accessor_name, params[idx][0]))
2685                 create_link('%s' % field.c_accessor_name)
2686
2687             f.write('.HP\n')
2688             f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2689                     (field.c_length_name, c_type))
2690             create_link('%s' % field.c_length_name)
2691
2692             if field.type.member.is_simple:
2693                 f.write('.HP\n')
2694                 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2695                         (field.c_end_name, c_type))
2696                 create_link('%s' % field.c_end_name)
2697             else:
2698                 f.write('.HP\n')
2699                 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
2700                         (field.c_iterator_type, field.c_iterator_name,
2701                          c_type))
2702                 create_link('%s' % field.c_iterator_name)
2703
2704         for field in self.reply.fields:
2705             if field.type.is_list and not field.type.fixed_size():
2706                 _c_accessors_list(self, field)
2707             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2708                 _c_accessors_field(self, field)
2709
2710
2711     f.write('.br\n')
2712     # Re-enable hyphenation and adjusting to both sides
2713     f.write('.hy 1\n')
2714
2715     # argument reference
2716     f.write('.SH REQUEST ARGUMENTS\n')
2717     f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
2718     f.write('The XCB connection to X11.\n')
2719     for field in param_fields:
2720         f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2721         printed_enum = False
2722         # XXX: hard-coded until we fix xproto.xml
2723         if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
2724             field.enum = 'GC'
2725         elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
2726             field.enum = 'CW'
2727         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
2728             field.enum = 'CW'
2729         if hasattr(field, "enum") and field.enum:
2730             # XXX: why the 'xcb' prefix?
2731             key = ('xcb', field.enum)
2732             if key in enums:
2733                 f.write('One of the following values:\n')
2734                 f.write('.RS 1i\n')
2735                 enum = enums[key]
2736                 count = len(enum.values)
2737                 for (enam, eval) in enum.values:
2738                     count = count - 1
2739                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2740                     if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
2741                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2742                         f.write('%s\n' % desc)
2743                     else:
2744                         f.write('TODO: NOT YET DOCUMENTED.\n')
2745                 f.write('.RE\n')
2746                 f.write('.RS 1i\n')
2747                 printed_enum = True
2748
2749         if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2750             desc = self.doc.fields[field.field_name]
2751             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2752             if printed_enum:
2753                 f.write('\n')
2754             f.write('%s\n' % desc)
2755         else:
2756             f.write('TODO: NOT YET DOCUMENTED.\n')
2757         if printed_enum:
2758             f.write('.RE\n')
2759
2760     # Reply reference
2761     if not void:
2762         f.write('.SH REPLY FIELDS\n')
2763         # These fields are present in every reply:
2764         f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2765         f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
2766                  'is also present in the \\fIxcb_generic_reply_t\\fP and can '
2767                  'be used to tell replies apart from each other.\n') %
2768                  _n(self.reply.name).upper())
2769         f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2770         f.write('The sequence number of the last request processed by the X11 server.\n')
2771         f.write('.IP \\fI%s\\fP 1i\n' % 'length')
2772         f.write('The length of the reply, in words (a word is 4 bytes).\n')
2773         for field in self.reply.fields:
2774             if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
2775                 field.c_field_name.startswith('pad')):
2776                 continue
2777
2778             if field.type.is_list and not field.type.fixed_size():
2779                 continue
2780             elif field.prev_varsized_field is not None or not field.type.fixed_size():
2781                 continue
2782             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2783             printed_enum = False
2784             if hasattr(field, "enum") and field.enum:
2785                 # XXX: why the 'xcb' prefix?
2786                 key = ('xcb', field.enum)
2787                 if key in enums:
2788                     f.write('One of the following values:\n')
2789                     f.write('.RS 1i\n')
2790                     enum = enums[key]
2791                     count = len(enum.values)
2792                     for (enam, eval) in enum.values:
2793                         count = count - 1
2794                         f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
2795                         if enum.doc and enam in enum.doc.fields:
2796                             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
2797                             f.write('%s\n' % desc)
2798                         else:
2799                             f.write('TODO: NOT YET DOCUMENTED.\n')
2800                     f.write('.RE\n')
2801                     f.write('.RS 1i\n')
2802                     printed_enum = True
2803
2804             if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
2805                 desc = self.reply.doc.fields[field.field_name]
2806                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2807                 if printed_enum:
2808                     f.write('\n')
2809                 f.write('%s\n' % desc)
2810             else:
2811                 f.write('TODO: NOT YET DOCUMENTED.\n')
2812             if printed_enum:
2813                 f.write('.RE\n')
2814
2815
2816
2817     # text description
2818     f.write('.SH DESCRIPTION\n')
2819     if hasattr(self, "doc") and self.doc and self.doc.description:
2820         desc = self.doc.description
2821         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2822         lines = desc.split('\n')
2823         f.write('\n'.join(lines) + '\n')
2824
2825     f.write('.SH RETURN VALUE\n')
2826     if void:
2827         f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
2828                  'have to be handled in the event loop.\n\nIf you want to '
2829                  'handle errors directly with \\fIxcb_request_check\\fP '
2830                  'instead, use \\fI%s_checked\\fP. See '
2831                  '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section))
2832     else:
2833         f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
2834                  'calling the reply function \\fI%s\\fP.\n\nIf you want to '
2835                  'handle errors in the event loop instead, use '
2836                  '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for '
2837                  'details.\n') %
2838                 (cookie_type, self.c_reply_name, base_func_name, section))
2839     f.write('.SH ERRORS\n')
2840     if hasattr(self, "doc") and self.doc:
2841         for errtype, errtext in sorted(self.doc.errors.items()):
2842             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
2843             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
2844             f.write('%s\n' % (errtext))
2845     if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
2846         f.write('This request does never generate any errors.\n')
2847     if hasattr(self, "doc") and self.doc and self.doc.example:
2848         f.write('.SH EXAMPLE\n')
2849         f.write('.nf\n')
2850         f.write('.sp\n')
2851         lines = self.doc.example.split('\n')
2852         f.write('\n'.join(lines) + '\n')
2853         f.write('.fi\n')
2854     f.write('.SH SEE ALSO\n')
2855     if hasattr(self, "doc") and self.doc:
2856         see = ['.BR %s (%s)' % ('xcb-requests', section)]
2857         if self.doc.example:
2858             see.append('.BR %s (%s)' % ('xcb-examples', section))
2859         for seename, seetype in sorted(self.doc.see.items()):
2860             if seetype == 'program':
2861                 see.append('.BR %s (1)' % seename)
2862             elif seetype == 'event':
2863                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2864             elif seetype == 'request':
2865                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2866             elif seetype == 'function':
2867                 see.append('.BR %s (%s)' % (seename, section))
2868             else:
2869                 see.append('TODO: %s (type %s)' % (seename, seetype))
2870         f.write(',\n'.join(see) + '\n')
2871     f.write('.SH AUTHOR\n')
2872     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
2873     f.close()
2874
2875 def _man_event(self, name):
2876     if manpaths:
2877         sys.stdout.write('man/%s.%s ' % (self.c_type, section))
2878     # Our CWD is src/, so this will end up in src/man/
2879     f = open('man/%s.%s' % (self.c_type, section), 'w')
2880     f.write('.TH %s %s  "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer))
2881     # Left-adjust instead of adjusting to both sides
2882     f.write('.ad l\n')
2883     f.write('.SH NAME\n')
2884     brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
2885     f.write('%s \\- %s\n' % (self.c_type, brief))
2886     f.write('.SH SYNOPSIS\n')
2887     # Don't split words (hyphenate)
2888     f.write('.hy 0\n')
2889     f.write('.B #include <xcb/%s.h>\n' % _ns.header)
2890
2891     f.write('.PP\n')
2892     f.write('.SS Event datastructure\n')
2893     f.write('.nf\n')
2894     f.write('.sp\n')
2895     f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
2896     struct_fields = []
2897     maxtypelen = 0
2898
2899     for field in self.fields:
2900         if not field.type.fixed_size() and not self.is_switch and not self.is_union:
2901             continue
2902         if field.wire:
2903             struct_fields.append(field)
2904
2905     for field in struct_fields:
2906         length = len(field.c_field_type)
2907         # account for '*' pointer_spec
2908         if not field.type.fixed_size():
2909             length += 1
2910         maxtypelen = max(maxtypelen, length)
2911
2912     def _c_complex_field(self, field, space=''):
2913         if (field.type.fixed_size() or
2914             # in case of switch with switch children, don't make the field a pointer
2915             # necessary for unserialize to work
2916             (self.is_switch and field.type.is_switch)):
2917             spacing = ' ' * (maxtypelen - len(field.c_field_type))
2918             f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
2919         else:
2920             print >> sys.stderr, 'ERROR: New unhandled documentation case'
2921
2922     if not self.is_switch:
2923         for field in struct_fields:
2924             _c_complex_field(self, field)
2925     else:
2926         for b in self.bitcases:
2927             space = ''
2928             if b.type.has_name:
2929                 space = '    '
2930             for field in b.type.fields:
2931                 _c_complex_field(self, field, space)
2932             if b.type.has_name:
2933                 print >> sys.stderr, 'ERROR: New unhandled documentation case'
2934                 pass
2935
2936     f.write('} \\fB%s\\fP;\n' % self.c_type)
2937     f.write('.fi\n')
2938
2939
2940     f.write('.br\n')
2941     # Re-enable hyphenation and adjusting to both sides
2942     f.write('.hy 1\n')
2943
2944     # argument reference
2945     f.write('.SH EVENT FIELDS\n')
2946     f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
2947     f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
2948              'also present in the \\fIxcb_generic_event_t\\fP and can be used '
2949              'to tell events apart from each other.\n') % _n(name).upper())
2950     f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
2951     f.write('The sequence number of the last request processed by the X11 server.\n')
2952
2953     if not self.is_switch:
2954         for field in struct_fields:
2955             # Skip the fields which every event has, we already documented
2956             # them (see above).
2957             if field.c_field_name in ('response_type', 'sequence'):
2958                 continue
2959             if isinstance(field.type, PadType):
2960                 continue
2961             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
2962             if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
2963                 desc = self.doc.fields[field.field_name]
2964                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2965                 f.write('%s\n' % desc)
2966             else:
2967                 f.write('NOT YET DOCUMENTED.\n')
2968
2969     # text description
2970     f.write('.SH DESCRIPTION\n')
2971     if hasattr(self, "doc") and self.doc and self.doc.description:
2972         desc = self.doc.description
2973         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
2974         lines = desc.split('\n')
2975         f.write('\n'.join(lines) + '\n')
2976
2977     if hasattr(self, "doc") and self.doc and self.doc.example:
2978         f.write('.SH EXAMPLE\n')
2979         f.write('.nf\n')
2980         f.write('.sp\n')
2981         lines = self.doc.example.split('\n')
2982         f.write('\n'.join(lines) + '\n')
2983         f.write('.fi\n')
2984     f.write('.SH SEE ALSO\n')
2985     if hasattr(self, "doc") and self.doc:
2986         see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)]
2987         if self.doc.example:
2988             see.append('.BR %s (%s)' % ('xcb-examples', section))
2989         for seename, seetype in sorted(self.doc.see.items()):
2990             if seetype == 'program':
2991                 see.append('.BR %s (1)' % seename)
2992             elif seetype == 'event':
2993                 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section))
2994             elif seetype == 'request':
2995                 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section))
2996             elif seetype == 'function':
2997                 see.append('.BR %s (%s)' % (seename, section))
2998             else:
2999                 see.append('TODO: %s (type %s)' % (seename, seetype))
3000         f.write(',\n'.join(see) + '\n')
3001     f.write('.SH AUTHOR\n')
3002     f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
3003     f.close()
3004
3005
3006 def c_request(self, name):
3007     '''
3008     Exported function that handles request declarations.
3009     '''
3010     _c_type_setup(self, name, ('request',))
3011
3012     if self.reply:
3013         # Cookie type declaration
3014         _c_cookie(self, name)
3015
3016     # Opcode define
3017     _c_opcode(name, self.opcode)
3018
3019     # Request structure declaration
3020     _c_complex(self)
3021
3022     if self.reply:
3023         _c_type_setup(self.reply, name, ('reply',))
3024         # Reply structure definition
3025         _c_complex(self.reply)
3026         # Request prototypes
3027         has_fds = _c_reply_has_fds(self.reply)
3028         _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
3029         _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
3030         if self.c_need_aux:
3031             _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
3032             _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
3033         # Reply accessors
3034         _c_accessors(self.reply, name + ('reply',), name)
3035         _c_reply(self, name)
3036         if has_fds:
3037             _c_reply_fds(self, name)
3038     else:
3039         # Request prototypes
3040         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
3041         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
3042         if self.c_need_aux:
3043             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
3044             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
3045
3046     # We generate the manpage afterwards because _c_type_setup has been called.
3047     # TODO: what about aux helpers?
3048     cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
3049     _man_request(self, name, cookie_type, not self.reply, False)
3050
3051 def c_event(self, name):
3052     '''
3053     Exported function that handles event declarations.
3054     '''
3055
3056     # The generic event structure xcb_ge_event_t has the full_sequence field
3057     # at the 32byte boundary. That's why we've to inject this field into GE
3058     # events while generating the structure for them. Otherwise we would read
3059     # garbage (the internal full_sequence) when accessing normal event fields
3060     # there.
3061     force_packed = False
3062     if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
3063         event_size = 0
3064         for field in self.fields:
3065             if field.type.size != None and field.type.nmemb != None:
3066                 event_size += field.type.size * field.type.nmemb
3067             if event_size == 32:
3068                 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
3069                 idx = self.fields.index(field)
3070                 self.fields.insert(idx + 1, full_sequence)
3071
3072                 # If the event contains any 64-bit extended fields, they need
3073                 # to remain aligned on a 64-bit boundary.  Adding full_sequence
3074                 # would normally break that; force the struct to be packed.
3075                 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):])
3076                 break
3077
3078     _c_type_setup(self, name, ('event',))
3079
3080     # Opcode define
3081     _c_opcode(name, self.opcodes[name])
3082
3083     if self.name == name:
3084         # Structure definition
3085         _c_complex(self, force_packed)
3086     else:
3087         # Typedef
3088         _h('')
3089         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
3090
3091     _man_event(self, name)
3092
3093 def c_error(self, name):
3094     '''
3095     Exported function that handles error declarations.
3096     '''
3097     _c_type_setup(self, name, ('error',))
3098
3099     # Opcode define
3100     _c_opcode(name, self.opcodes[name])
3101
3102     if self.name == name:
3103         # Structure definition
3104         _c_complex(self)
3105     else:
3106         # Typedef
3107         _h('')
3108         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
3109
3110
3111 # Main routine starts here
3112
3113 # Must create an "output" dictionary before any xcbgen imports.
3114 output = {'open'    : c_open,
3115           'close'   : c_close,
3116           'simple'  : c_simple,
3117           'enum'    : c_enum,
3118           'struct'  : c_struct,
3119           'union'   : c_union,
3120           'request' : c_request,
3121           'event'   : c_event,
3122           'error'   : c_error,
3123           }
3124
3125 # Boilerplate below this point
3126
3127 # Check for the argument that specifies path to the xcbgen python package.
3128 try:
3129     opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m')
3130 except getopt.GetoptError as err:
3131     print(err)
3132     print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml')
3133     sys.exit(1)
3134
3135 for (opt, arg) in opts:
3136     if opt == '-c':
3137         center_footer=arg
3138     if opt == '-l':
3139         left_footer=arg
3140     if opt == '-s':
3141         section=arg
3142     if opt == '-p':
3143         sys.path.insert(1, arg)
3144     elif opt == '-m':
3145         manpaths = True
3146         sys.stdout.write('man_MANS = ')
3147
3148 # Import the module class
3149 try:
3150     from xcbgen.state import Module
3151     from xcbgen.xtypes import *
3152 except ImportError:
3153     print('''
3154 Failed to load the xcbgen Python package!
3155 Make sure that xcb/proto installed it on your Python path.
3156 If not, you will need to create a .pth file or define $PYTHONPATH
3157 to extend the path.
3158 Refer to the README file in xcb/proto for more info.
3159 ''')
3160     raise
3161
3162 # Ensure the man subdirectory exists
3163 try:
3164     os.mkdir('man')
3165 except OSError as e:
3166     if e.errno != errno.EEXIST:
3167         raise
3168
3169 # Parse the xml header
3170 module = Module(args[0], output)
3171
3172 # Build type-registry and resolve type dependencies
3173 module.register()
3174 module.resolve()
3175
3176 # Output the code
3177 module.generate()