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