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