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