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