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