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