bug fixes for all kinds of 'special cases'
[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 import getopt
5 import sys
6 import re
7
8 # Jump to the bottom of this file for the main routine
9
10 # Some hacks to make the API more readable, and to keep backwards compability
11 _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
12 _cname_special_cases = {'DECnet':'decnet'}
13
14 _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
15
16 _cplusplus_annoyances = {'class' : '_class',
17                          'new'   : '_new',
18                          'delete': '_delete'}
19 _c_keywords = {'default' : '_default'}
20
21 _hlines = []
22 _hlevel = 0
23 _clines = []
24 _clevel = 0
25 _ns = None
26
27 # global variable to keep track of serializers and switch data types
28 # due to weird dependencies, I see no way to do this more elegant at the moment
29 finished_serializers = []
30 finished_switch = []
31
32 def _h(fmt, *args):
33     '''
34     Writes the given line to the header file.
35     '''
36     _hlines[_hlevel].append(fmt % args)
37     
38 def _c(fmt, *args):
39     '''
40     Writes the given line to the source file.
41     '''
42     _clines[_clevel].append(fmt % args)
43     
44 def _hc(fmt, *args):
45     '''
46     Writes the given line to both the header and source files.
47     '''
48     _h(fmt, *args)
49     _c(fmt, *args)
50
51 # XXX See if this level thing is really necessary.
52 def _h_setlevel(idx):
53     '''
54     Changes the array that header lines are written to.
55     Supports writing different sections of the header file.
56     '''
57     global _hlevel
58     while len(_hlines) <= idx:
59         _hlines.append([])
60     _hlevel = idx
61     
62 def _c_setlevel(idx):
63     '''
64     Changes the array that source lines are written to.
65     Supports writing to different sections of the source file.
66     '''
67     global _clevel
68     while len(_clines) <= idx:
69         _clines.append([])
70     _clevel = idx
71     
72 def _n_item(str):
73     '''
74     Does C-name conversion on a single string fragment.
75     Uses a regexp with some hard-coded special cases.
76     '''
77     if str in _cname_special_cases:
78         return _cname_special_cases[str]
79     else:
80         split = _cname_re.finditer(str)
81         name_parts = [match.group(0) for match in split]
82         return '_'.join(name_parts)
83     
84 def _cpp(str):
85     '''
86     Checks for certain C++ reserved words and fixes them.
87     '''
88     if str in _cplusplus_annoyances:
89         return _cplusplus_annoyances[str]
90     elif str in _c_keywords:
91         return  _c_keywords[str]
92     else:
93         return str
94
95 def _ext(str):
96     '''
97     Does C-name conversion on an extension name.
98     Has some additional special cases on top of _n_item.
99     '''
100     if str in _extension_special_cases:
101         return _n_item(str).lower()
102     else:
103         return str.lower()
104     
105 def _n(list):
106     '''
107     Does C-name conversion on a tuple of strings.
108     Different behavior depending on length of tuple, extension/not extension, etc.
109     Basically C-name converts the individual pieces, then joins with underscores.
110     '''
111     if len(list) == 1:
112         parts = list
113     elif len(list) == 2:
114         parts = [list[0], _n_item(list[1])]
115     elif _ns.is_ext:
116         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]]
117     else:
118         parts = [list[0]] + [_n_item(i) for i in list[1:]]
119     return '_'.join(parts).lower()
120
121 def _t(list):
122     '''
123     Does C-name conversion on a tuple of strings representing a type.
124     Same as _n but adds a "_t" on the end.
125     '''
126     if len(list) == 1:
127         parts = list
128     elif len(list) == 2:
129         parts = [list[0], _n_item(list[1]), 't']
130     elif _ns.is_ext:
131         parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t']
132     else:
133         parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t']
134     return '_'.join(parts).lower()
135         
136
137 def c_open(self):
138     '''
139     Exported function that handles module open.
140     Opens the files and writes out the auto-generated comment, header file includes, etc.
141     '''
142     global _ns
143     _ns = self.namespace
144     _ns.c_ext_global_name = _n(_ns.prefix + ('id',))
145
146     # Build the type-name collision avoidance table used by c_enum
147     build_collision_table()
148
149     _h_setlevel(0)
150     _c_setlevel(0)
151
152     _hc('/*')
153     _hc(' * This file generated automatically from %s by c_client.py.', _ns.file)
154     _hc(' * Edit at your peril.')
155     _hc(' */')
156     _hc('')
157
158     _h('/**')
159     _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name)
160     _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name)
161     _h(' * @{')
162     _h(' **/')
163     _h('')
164     _h('#ifndef __%s_H', _ns.header.upper())
165     _h('#define __%s_H', _ns.header.upper())
166     _h('')
167     _h('#include "xcb.h"')
168
169     _c('#include <stdlib.h>')
170     _c('#include <string.h>')
171     _c('#include <assert.h>')
172     _c('#include "xcbext.h"')
173     _c('#include "%s.h"', _ns.header)
174         
175     if _ns.is_ext:
176         for (n, h) in self.imports:
177             _hc('#include "%s.h"', h)
178
179     _h('')
180     _h('#ifdef __cplusplus')
181     _h('extern "C" {')
182     _h('#endif')
183
184     if _ns.is_ext:
185         _h('')
186         _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version)
187         _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version)
188         _h('  ') #XXX
189         _h('extern xcb_extension_t %s;', _ns.c_ext_global_name)
190
191         _c('')
192         _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname)
193
194 def c_close(self):
195     '''
196     Exported function that handles module close.
197     Writes out all the stored content lines, then closes the files.
198     '''
199     _h_setlevel(2)
200     _c_setlevel(2)
201     _hc('')
202
203     _h('')
204     _h('#ifdef __cplusplus')
205     _h('}')
206     _h('#endif')
207
208     _h('')
209     _h('#endif')
210     _h('')
211     _h('/**')
212     _h(' * @}')
213     _h(' */')
214
215     # Write header file
216     hfile = open('%s.h' % _ns.header, 'w')
217     for list in _hlines:
218         for line in list:
219             hfile.write(line)
220             hfile.write('\n')
221     hfile.close()
222
223     # Write source file
224     cfile = open('%s.c' % _ns.header, 'w')
225     for list in _clines:
226         for line in list:
227             cfile.write(line)
228             cfile.write('\n')
229     cfile.close()
230
231 def build_collision_table():
232     global namecount
233     namecount = {}
234
235     for v in module.types.values():
236         name = _t(v[0])
237         namecount[name] = (namecount.get(name) or 0) + 1
238
239 def c_enum(self, name):
240     '''
241     Exported function that handles enum declarations.
242     '''
243
244     tname = _t(name)
245     if namecount[tname] > 1:
246         tname = _t(name + ('enum',))
247
248     _h_setlevel(0)
249     _h('')
250     _h('typedef enum %s {', tname)
251
252     count = len(self.values)
253
254     for (enam, eval) in self.values:
255         count = count - 1
256         equals = ' = ' if eval != '' else ''
257         comma = ',' if count > 0 else ''
258         _h('    %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
259
260     _h('} %s;', tname)
261
262 def _c_type_setup(self, name, postfix):
263     '''
264     Sets up all the C-related state by adding additional data fields to
265     all Field and Type objects.  Here is where we figure out most of our
266     variable and function names.
267
268     Recurses into child fields and list member types.
269     '''
270     # Do all the various names in advance
271     self.c_type = _t(name + postfix)
272     self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type
273
274     self.c_iterator_type = _t(name + ('iterator',))
275     self.c_next_name = _n(name + ('next',))
276     self.c_end_name = _n(name + ('end',))
277
278     self.c_request_name = _n(name)
279     self.c_checked_name = _n(name + ('checked',))
280     self.c_unchecked_name = _n(name + ('unchecked',))
281     self.c_reply_name = _n(name + ('reply',))
282     self.c_reply_type = _t(name + ('reply',))
283     self.c_cookie_type = _t(name + ('cookie',))
284
285     self.c_aux_name = _n(name + ('aux',))
286     self.c_aux_checked_name = _n(name + ('aux', 'checked'))
287     self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked'))
288     self.c_serialize_name = _n(name + ('serialize',))
289     self.c_unserialize_name = _n(name + ('unserialize',))
290     if hasattr(self, 'reply'):
291         if self.reply is not None:
292             self.c_serialize_name = _n(name + ('reply', 'serialize'))
293             self.c_unserialize_name = _n(name + ('reply', 'unserialize'))
294     # indicates rare structs where variable size fields are followed fixed size fields
295     self.var_followed_by_fixed_fields = False
296
297     # whether a request or reply has a switch field
298     self.need_aux = False
299     self.need_serialize = False
300     if self.is_switch:
301         self.need_serialize = True
302         self.c_container = 'struct'
303         for bitcase in self.bitcases:
304             bitcase.c_field_name = _cpp(bitcase.field_name)
305             _c_type_setup(bitcase.type, bitcase.field_type, ())
306
307     elif self.is_container:
308
309         self.c_container = 'union' if self.is_union else 'struct'
310         prev_varsized_field = None
311         prev_varsized_offset = 0
312         first_field_after_varsized = None
313
314         for field in self.fields:
315             _c_type_setup(field.type, field.field_type, ())
316             if field.type.is_list:
317                 _c_type_setup(field.type.member, field.field_type, ())
318                 # FIXME - structures with variable sized members, sort out when serialize() is needed
319                 if (field.type.nmemb is None): # and not field.type.member.fixed_size():
320                     self.need_serialize = True
321
322             field.c_field_type = _t(field.field_type)
323             field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
324             field.c_field_name = _cpp(field.field_name)
325             field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else ''
326             field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
327             if field.type.is_switch:
328                 field.c_pointer = '*'
329                 field.c_field_const_type = 'const ' + field.c_field_type
330                 self.need_aux = True
331             elif not field.type.fixed_size() and not field.type.is_bitcase:
332                 self.need_serialize = True
333
334             field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
335             field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
336             field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
337             field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
338             # special case - c_field_name ends with _length as well
339             #if field.c_field_name.endswith('length'):
340             #    c_field_name = field.c_field_name.rsplit('length', 1)
341             #    field.c_field_name = c_field_name[0] + "_length"
342             field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
343
344             field.prev_varsized_field = prev_varsized_field
345             field.prev_varsized_offset = prev_varsized_offset
346
347             if prev_varsized_offset == 0:
348                 first_field_after_varsized = field
349             field.first_field_after_varsized = first_field_after_varsized
350
351             if field.type.fixed_size():
352                 prev_varsized_offset += field.type.size
353                 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
354                     if not self.is_union:
355                         self.need_serialize = True
356                         self.var_followed_by_fixed_fields = True
357 #                        print "WARNING (%s): variable size field %s followed by fixed size field %s" % (
358 #                            self.c_type, prev_varsized_field.field_name, field.field_name)
359             else:
360                 self.last_varsized_field = field
361                 prev_varsized_field = field
362                 prev_varsized_offset = 0                    
363
364     # as switch does never appear at toplevel, 
365     # continue here with type construction
366     if self.is_switch:
367         if self.c_type not in finished_switch:
368             finished_switch.append(self.c_type)
369             # special: switch C structs get pointer fields for variable-sized members
370             _c_complex(self)
371             # FIXME: declare switch (un)packing functions
372             _c_accessors(self, name, name)
373
374     # FIXME - in case of request/reply, serialize() is not always needed
375     if self.need_serialize and not self.is_bitcase:
376         if self.c_serialize_name not in finished_serializers:
377             finished_serializers.append(self.c_serialize_name)
378             _c_serialize(self)
379             _c_unserialize(self)
380 # _c_type_setup()
381
382 def get_request_fields(self):
383     param_fields = []
384     wire_fields = []
385
386     for field in self.fields:
387         if field.visible:
388             # the field should appear as a parameter in the function call
389             param_fields.append(field)
390         if field.wire and not field.auto:
391             if field.type.fixed_size() and not self.is_switch:
392                 # field in the xcb_out structure
393                 wire_fields.append(field)
394         # fields like 'pad0' are skipped!
395                     
396     return (param_fields, wire_fields)
397 # get_request_fields()
398
399 def get_expr_fields(self):
400     # get the fields referenced by switch or list expression
401     def get_expr_field_names(expr):
402         if expr.op is None:
403             if expr.lenfield_name is not None:
404                 return [expr.lenfield_name]
405             else:
406                 # constant value expr
407                 return []
408         else:
409             if expr.op == '~':
410                 return get_expr_field_names(expr.rhs)
411             elif expr.op == 'popcount':
412                 return get_expr_field_names(expr.rhs)
413             elif expr.op == 'sumof':
414                 return [expr.lenfield_name]
415             elif expr.op == 'enumref':
416                 return []
417             else:
418                 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs)
419     # get_expr_field_names()
420     
421     # resolve the field names with the parent structure(s)
422     unresolved_fields = get_expr_field_names(self.expr)
423     if unresolved_fields is None:
424         return []
425     expr_fields = dict.fromkeys(unresolved_fields)
426     for p in reversed(self.parent):
427         parent_fields = dict((f.field_name, f) for f in p.fields)
428         for f in parent_fields.keys():
429             if f in unresolved_fields:
430                 expr_fields[f] = parent_fields[f]
431                 unresolved_fields.remove(f)
432         if len(unresolved_fields) == 0:
433             break
434                 
435     if None in expr_fields.values():
436         raise Exception("could not resolve all fields for %s" % self.name)
437
438     params = expr_fields.values()
439     return params
440 # get_expr_fields()
441
442 def resolve_fields(anchestor, complex_obj=None):
443     """find fields referenced by anchestor or descendents with external scope"""
444     expr_fields = []
445     unresolved = []
446     all_fields = []
447     if complex_obj is None:
448         complex_obj = anchestor
449     for field in complex_obj.fields:
450         all_fields.append(field)
451         if field.type.is_switch or field.type.is_list:
452             expr_fields += get_expr_fields(field.type)
453         if field.type.is_container:
454             expr_fields += resolve_fields(anchestor, field.type)
455     # try to resolve expr fields
456     for e in expr_fields:
457         if e not in all_fields:
458             unresolved.append(e)
459     return unresolved
460             
461 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
462     def add_param(params, param):
463         if param not in params:
464             params.append(param)
465
466     param_fields, wire_fields = get_request_fields(self)
467     if self.is_switch:
468         param_fields = get_expr_fields(self)
469
470     # _serialize function parameters
471     # cannot use set() for params, as series is important
472     params = []
473     if  'serialize' == context:
474         params.append(('void', '**', buffer_var))
475     elif 'unserialize' == context:
476         params.append(('const void', '*', buffer_var))
477
478     # look for special cases
479     unresolved_fields = resolve_fields(self)
480     for f in unresolved_fields:
481         add_param(params, (f.c_field_type, '', f.c_field_name))
482
483     # make sure all required length fields are present
484     for p in param_fields:
485         if p.visible and not p.wire and not p.auto:
486             typespec = p.c_field_type
487             pointerspec = ''
488             add_param(params, (typespec, pointerspec, p.c_field_name))
489
490     # parameter fields if any
491     if self.is_switch:
492         for p in get_expr_fields(self):
493             typespec = p.c_field_const_type
494             pointerspec = p.c_pointer 
495             add_param(params, (typespec, pointerspec, p.c_field_name))
496   
497     # aux argument - structure to be serialized
498     if 'serialize' == context:
499         add_param(params, ('const %s' % self.c_type, '*', aux_var))
500     elif 'unserialize' == context and self.is_switch:
501         add_param(params, ('%s' % self.c_type, '*', aux_var))
502     if not self.is_switch and 'serialize' == context:
503         for p in param_fields:
504             if not p.type.fixed_size():
505                 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
506     return (param_fields, wire_fields, params)
507 # get_serialize_params()
508
509 def _c_serialize_helper_prefix(prefix):
510     # prefix is a list of (field_name, anchestor object) tuples
511     # concatenate field names
512     prefix_str = ''
513     for name, obj in prefix:
514         prefix_str += name
515         prefix_str += '.' if (obj.is_bitcase and obj.has_name) else '->'
516     lenfield_prefix = '' if prefix_str.find('_aux')==0 else "_aux"
517     if prefix_str != '':
518         if lenfield_prefix != '':
519             lenfield_prefix += '->' 
520         lenfield_prefix += prefix_str
521     return (prefix_str, lenfield_prefix)
522 # _c_serialize_helper_prefix
523
524 def _c_field_mapping(context, complex_type, prefix):
525     def get_prefix(field, prefix):
526         prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
527         if prefix_str == '':
528             if context in ('serialize', 'unserialize'):
529                 if field.type.fixed_size() or complex_type.is_switch:
530                     prefix_str = '_aux->'
531             else:
532                 raise Exception("unknown context '%s' in c_field_mapping" % context)
533         return prefix_str
534     # get_prefix()
535     def get_field_name(fields, complex_type, prefix):
536         for f in complex_type.fields:
537             prefix_str = get_prefix(f, prefix)
538
539             fname = "%s%s" % (prefix_str, f.c_field_name)
540             if fields.has_key(f.field_name):
541                 continue
542                 # FIXME 
543                 raise Exception("field name %s has been registered before" % f.field_name)
544             fields[f.field_name] = (fname, f)
545             if f.type.is_container:
546                 get_field_name(fields, f.type, prefix+[(f.c_field_name, f.type)])
547     # get_field_name()
548
549     # dict(field_name : (c_field_name, field))
550     fields = {}
551     get_field_name(fields, complex_type, prefix)
552     
553     # switch: get the fields referenced by the switch expr as well
554     #         these may not belong to any structure
555     if complex_type.is_switch:
556         pass
557 #       FIXME: fields += get_serialize_params(context, complex_type)
558
559     return fields
560 # _c_field_mapping()
561
562 def _c_serialize_helper_insert_padding(context, code_lines, space):
563     code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
564     code_lines.append('%s    /* padding */' % space)
565     code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
566     code_lines.append('%s    if (0 != xcb_pad) {' % space)
567
568     if 'serialize' == context:
569         code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
570         code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
571         code_lines.append('%s        xcb_parts_idx++;' % space)
572     elif 'unserialize' == context:
573         code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
574
575     code_lines.append('%s        xcb_buffer_len += xcb_pad;' % space)    
576     code_lines.append('%s        xcb_pad = 0;' % space)
577     code_lines.append('%s    }' % space)
578     code_lines.append('%s    xcb_block_len = 0;' % space)
579     
580     return 1
581 # _c_serialize_helper_insert_padding()
582
583 def _c_serialize_helper_switch(context, self, complex_name, 
584                                code_lines, temp_vars, 
585                                space, prefix):
586     count = 0
587     switch_prefix = prefix + [(complex_name, self)]
588     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(switch_prefix)
589     switch_expr = _c_accessor_get_expr(self.expr)
590     
591     for b in self.bitcases:            
592         bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix_str)
593         code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
594         b_prefix = switch_prefix
595         if b.type.has_name:
596             b_prefix = switch_prefix + [(b.c_field_name, b.type)]
597         _c_serialize_helper_fields(context, b.type, 
598                                    code_lines, temp_vars, 
599                                    "%s    " % space, 
600                                    b_prefix, 
601                                    is_bitcase = True)
602         code_lines.append('    }')
603
604     if 'serialize' == context:
605         count = _c_serialize_helper_insert_padding(context, code_lines, space)
606     if 'unserialize' == context:
607         # padding
608         code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
609         code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
610     
611     return count
612 # _c_serialize_helper_switch
613
614 def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix):
615     # switch is handled by this function as a special case
616     param_fields, wire_fields, params = get_serialize_params(context, self)
617     args = get_expr_fields(field.type)
618     field_mapping = _c_field_mapping(context, self, prefix)
619
620     # determine which params to pass to _unserialize() and their prefixes
621     switch_len_fields = resolve_fields(self, field.type)
622     bitcase_unresolved = resolve_fields(self, self)
623     if len(bitcase_unresolved) != 0:
624         raise Exception('unresolved fields within bitcase is not supported at this point')
625     c_field_names = ''
626     for a in switch_len_fields:
627         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
628     for a in args:
629         c_field_names += "%s, " % field_mapping[a.c_field_name][0]
630 #    switch_field_name = field_mapping[field.field_name][0]
631     # call _unserialize() to determine the actual size
632     length = "%s(xcb_tmp, %s&%s)" % (field.type.c_unserialize_name, 
633                                      c_field_names, c_switch_variable) #switch_field_name)
634     return length
635 # _c_serialize_helper_switch_field()
636
637 def _c_serialize_helper_list_field(context, self, field, 
638                                    code_lines, temp_vars, 
639                                    space, prefix):
640     """
641     helper function for (un)serialize to cope with lists of variable length
642     """
643     expr = field.type.expr
644     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
645     param_fields, wire_fields, params = get_serialize_params('unserialize', self)
646     param_names = [p[2] for p in params]
647
648     # look if the list's lenfield is a struct member or a function argument
649     # special case: if the list has a length field, its name will be returned 
650     # unchanged by calling c_accessor_get_length(expr)
651     if expr.lenfield_name == _c_accessor_get_length(expr):
652         if expr.lenfield_name in param_names:
653             # the length field appears as separate argument in unserialize, 
654             # so no need for a prefix
655             lenfield_prefix = ''
656     sep = '.' if (self.is_bitcase and self.has_name) else '->'
657     list_length = _c_accessor_get_expr(expr, lenfield_prefix, sep)
658
659     # default: list with fixed size elements
660     length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
661     # list with variable-sized elements 
662     if field.type.size is None:
663         length = ''
664         if 'unserialize' == context:
665             int_i = '    unsigned int i;'
666             xcb_tmp_len = '    unsigned int xcb_tmp_len;'
667             if int_i not in temp_vars:
668                 temp_vars.append(int_i)
669             if xcb_tmp_len not in temp_vars:
670                 temp_vars.append(xcb_tmp_len)
671             code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
672             code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp);" % 
673                               (space, field.type.c_unserialize_name))
674             code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
675             code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
676             code_lines.append("%s    }" % space)                        
677         elif 'serialize' == context:
678             code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
679             code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
680             code_lines.append('%s    for(i=0; i<%s; i++) { ' 
681                               % (space, _c_accessor_get_expr(expr, lenfield_prefix, sep)))
682             code_lines.append('%s        xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name))
683             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
684             code_lines.append('%s    }' % space)
685             code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
686             
687     return length
688 # _c_serialize_helper_list_field()
689
690 def _c_serialize_helper_fields_fixed_size(context, self, field, 
691                                           code_lines, temp_vars, 
692                                           space, prefix):
693     code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
694     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
695
696     length = "sizeof(%s)" % field.c_field_type
697
698     if 'unserialize' == context:
699         value = '    %s%s = *(%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) 
700         if field.type.is_pad and field.type.nmemb > 1:
701             value = ''
702             for i in range(field.type.nmemb):
703                 code_lines.append('%s    %s%s[%d] = *(%s *)xcb_tmp;' % 
704                                   (space, prefix_str, field.c_field_name, i, field.c_field_type)) 
705             length += " * %d" % field.type.nmemb
706         # FIXME? - lists
707         if field.type.is_list:
708             raise Exception('list with fixed number of elemens unhandled in _unserialize()')
709     elif 'serialize' == context:
710         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) ' 
711
712         if field.type.is_expr:
713             # need to register a temporary variable for the expression
714             if field.type.c_type is None:
715                 raise Exception("type for field '%s' (expression '%s') unkown" % 
716                                 (field.field_name, _c_accessor_get_expr(field.type.expr)))
717             temp_vars.append('    %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, 
718                                                            _c_accessor_get_expr(field.type.expr, prefix)))
719             value += "&xcb_expr_%s;" % field.field_name 
720
721         elif field.type.is_pad:
722             if field.type.nmemb == 1:
723                 value += "&xcb_pad;"
724             else:
725                 # FIXME - possible segmentation fault!!
726                 value = '    memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb
727                 length += "*%d" % field.type.nmemb
728
729         else:
730             # non-list type with fixed size
731             if field.type.nmemb == 1:
732                 value += "&%s%s;" % (prefix_str, field.c_field_name)
733             # list with nmemb (fixed size) elements
734             else:
735                 value += '%s%s;' % (prefix_str, field.c_field_name)
736                 length = '%d' % field.type.nmemb
737
738     return (value, length)
739 # _c_serialize_helper_fields_fixed_size()
740
741 def _c_serialize_helper_fields_variable_size(context, self, field, 
742                                              code_lines, temp_vars, 
743                                              space, prefix):
744     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
745
746     if 'unserialize' == context:
747         value = ''
748     elif 'serialize' == context:
749         address_of = '&' if (self.is_bitcase and self.has_name) else ''
750         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s%s;' % (address_of, prefix_str, field.c_field_name)
751     length = ''
752
753     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
754     code_lines.append('%s    /* %s */' % (space, field.c_field_name))
755
756     if field.type.is_list:
757         length = _c_serialize_helper_list_field(context, self, field, 
758                                                 code_lines, temp_vars, 
759                                                 space, prefix)
760     elif field.type.is_switch:
761         prev = filter(lambda x: x.find('xcb_switch_field'), temp_vars)
762         var_name = 'xcb_switch_field%d' % len(prev)
763         temp_vars.append('    %s %s;' % (field.type.c_type, var_name))
764         length = _c_serialize_helper_switch_field(context, self, field, var_name, prefix)
765     else:
766         length = "%s(xcb_tmp)" % (field.type.c_unserialize_name)
767
768     return (value, length)
769 # _c_serialize_helper_fields_variable_size
770
771 def _c_serialize_helper_fields(context, self, 
772                                code_lines, temp_vars, 
773                                space, prefix, is_bitcase):
774     count = 0
775     need_padding = False
776
777     for field in self.fields:
778         if not ((field.wire and not field.auto) or field.visible):
779             continue
780
781         # switch/bitcase: fixed size fields must be considered explicitly 
782         if field.type.fixed_size():
783             if self.is_bitcase:
784                 value, length = _c_serialize_helper_fields_fixed_size(context, self, field, 
785                                                                       code_lines, temp_vars, 
786                                                                       space, prefix)
787             else:
788                 continue
789
790         # fields with variable size
791         else:
792             # switch/bitcase: always calculate padding before and after variable sized fields
793             if need_padding or is_bitcase:
794                 _c_serialize_helper_insert_padding(context, code_lines, space)
795
796             value, length = _c_serialize_helper_fields_variable_size(context, self, field, 
797                                                                      code_lines, temp_vars, 
798                                                                      space, prefix)
799                 
800         # save (un)serialization C code
801         if '' != value:
802             code_lines.append('%s%s' % (space, value))
803         if field.type.fixed_size() and is_bitcase:
804             code_lines.append('%s    xcb_block_len += %s;' % (space, length))
805             if 'unserialize' == context:
806                 code_lines.append('%s    xcb_tmp += %s;' % (space, length))
807         else:
808             # padding
809             if '' != length:
810                 code_lines.append('%s    xcb_block_len = %s;' % (space, length))
811                 if 'unserialize' == context:
812                     code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
813         if 'serialize' == context:
814             if '' != length:
815                 code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space)
816             code_lines.append('%s    xcb_parts_idx++;' % space)
817             count += 1
818         need_padding = True
819         
820     return count
821 # _c_serialize_helper_fields()    
822
823 def _c_serialize_helper(context, complex_type, 
824                         code_lines, temp_vars, 
825                         space='', prefix=[]):
826     count = 0
827     if hasattr(complex_type, 'type'):
828         self = complex_type.type
829         complex_name = complex_type.name
830     else:
831         self = complex_type
832         complex_name = '_aux'
833
834     # special case: switch is serialized by evaluating each bitcase separately
835     if self.is_switch:
836         count += _c_serialize_helper_switch(context, self, complex_name, 
837                                             code_lines, temp_vars, 
838                                             space, prefix)
839
840     # all other data types can be evaluated one field a time
841     else: 
842         # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
843         if 'unserialize' == context:
844             code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
845             code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
846             _c_serialize_helper_insert_padding(context, code_lines, space)
847
848         count += _c_serialize_helper_fields(context, self, 
849                                             code_lines, temp_vars, 
850                                             space, prefix, False)
851         # "final padding"
852         count += _c_serialize_helper_insert_padding(context, code_lines, space)
853
854     return count    
855 # _c_serialize_helper()
856
857 def _c_serialize(self):
858     _h_setlevel(1)
859     _c_setlevel(1)
860
861     _hc('')
862     # _serialize() returns the buffer size
863     _hc('int')
864
865     variable_size_fields = 0
866     # maximum space required for type definition of function arguments
867     maxtypelen = 0
868     param_fields, wire_fields, params = get_serialize_params('serialize', self)
869
870     # determine N(variable_fields) 
871     for field in param_fields:
872         # if self.is_switch, treat all fields as if they are variable sized
873         if not field.type.fixed_size() or self.is_switch:
874             variable_size_fields += 1
875     # determine maxtypelen
876     for p in params:
877         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
878
879     # write to .c/.h
880     for idx, p in enumerate(params):
881         line = ""
882         typespec, pointerspec, field_name = p
883         indent = ' '*(len(self.c_serialize_name)+2)
884         # p==0: function declaration
885         if 0==idx:
886             line = "%s (" % self.c_serialize_name
887             indent = ''
888         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
889         line += "%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name)
890         if idx < len(params)-1:
891             _hc("%s," % line)
892         else:
893             _h("%s);" % line)
894             _c("%s)" % line)
895                 
896     _c('{')
897     if not self.is_switch:
898         _c('    %s *xcb_out = *_buffer;', self.c_type)
899         _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
900         _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
901     else:
902         _c('    char *xcb_out = *_buffer;')
903         _c('    unsigned int xcb_buffer_len = 0;')
904     if variable_size_fields > 0:        
905         code_lines = []
906         temp_vars = []
907         count =_c_serialize_helper('serialize', self, 
908                                    code_lines, temp_vars)
909         # update variable size fields 
910         variable_size_fields = count
911         temp_vars.append('    unsigned int xcb_pad = 0;')
912         temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};') 
913         temp_vars.append('    struct iovec xcb_parts[%d];' % (count+1))
914         temp_vars.append('    unsigned int xcb_parts_idx = 0;')
915         temp_vars.append('    unsigned int xcb_block_len = 0;')
916         temp_vars.append('    unsigned int i;')
917         temp_vars.append('    char *xcb_tmp;')
918         for t in temp_vars:
919             _c(t)
920
921     _c('')
922     
923     if variable_size_fields > 0:        
924         for l in code_lines:
925             _c(l)
926     _c('')
927
928     # variable sized fields have been collected, now
929     # allocate memory and copy everything into a continuous memory area
930     _c('    if (NULL == xcb_out) {')
931     _c('        /* allocate memory  */')
932     _c('        *_buffer = malloc(xcb_buffer_len);')
933     _c('        xcb_out = *_buffer;')
934     _c('    }')
935     _c('')
936
937     # fill in struct members
938     if not self.is_switch:
939         if len(wire_fields)>0:
940             _c('    *xcb_out = *_aux;')
941
942     # copy variable size fields into the buffer
943     if variable_size_fields > 0:
944         # xcb_out padding
945         if not self.is_switch:
946             _c('    xcb_tmp = (char*)++xcb_out;')
947             _c('    xcb_tmp += xcb_out_pad;')
948         else:
949             _c('    xcb_tmp = xcb_out;')
950             
951         # variable sized fields
952         _c('    for(i=0; i<xcb_parts_idx; i++) {')
953         _c('        memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
954         _c('        xcb_tmp += xcb_parts[i].iov_len;')
955         _c('    }')
956     _c('')
957     _c('    return xcb_buffer_len;')
958     _c('}')
959 # _c_serialize()
960
961 def _c_unserialize(self):
962     _h_setlevel(1)
963     _c_setlevel(1)
964
965     # _unserialize()
966     _hc('')
967     # _unserialize() returns the buffer size as well
968     _hc('int')
969
970
971     variable_size_fields = 0
972     # maximum space required for type definition of function arguments
973     maxtypelen = 0
974     param_fields, wire_fields, params = get_serialize_params('unserialize', self)
975
976     # determine N(variable_fields) 
977     for field in param_fields:
978         # if self.is_switch, treat all fields as if they are variable sized
979         if not field.type.fixed_size() or self.is_switch:
980             variable_size_fields += 1
981     # determine maxtypelen
982     for p in params:
983         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
984
985     # write to .c/.h
986     for idx, p in enumerate(params):
987         line = ""
988         typespec, pointerspec, field_name = p
989         indent = ' '*(len(self.c_unserialize_name)+2)
990         # p==0: function declaration
991         if 0==idx:
992             line = "%s (" % self.c_unserialize_name
993             indent = ''
994         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
995         line += "%s%s%s %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name)
996         if idx < len(params)-1:
997             _hc("%s," % line)
998         else:
999             _h("%s);" % line)
1000             _c("%s)" % line)
1001                 
1002     _c('{')
1003     _c('    char *xcb_tmp = (char *)_buffer;')
1004     if not self.is_switch:
1005         _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
1006     _c('    unsigned int xcb_buffer_len = 0;')
1007     _c('    unsigned int xcb_block_len = 0;')
1008     _c('    unsigned int xcb_pad = 0;')
1009
1010     code_lines = []
1011     temp_vars = []
1012     _c_serialize_helper('unserialize', self, 
1013                         code_lines, temp_vars)
1014     for t in temp_vars:
1015         _c(t)
1016     _c('')
1017
1018     for l in code_lines:
1019         _c(l)
1020     _c('')
1021     _c('    return xcb_buffer_len;')
1022     _c('}')
1023 # _c_unserialize()
1024
1025 def _c_iterator_get_end(field, accum):
1026     '''
1027     Figures out what C code is needed to find the end of a variable-length structure field.
1028     For nested structures, recurses into its last variable-sized field.
1029     For lists, calls the end function
1030     '''
1031     if field.type.is_container:
1032         accum = field.c_accessor_name + '(' + accum + ')'
1033         if field.type.fixed_size():
1034             print "iterator_get_end()", accum, field.c_field_name
1035         # XXX there could be fixed-length fields at the end
1036         return _c_iterator_get_end(field.type.last_varsized_field, accum)
1037     if field.type.is_list:
1038         # XXX we can always use the first way
1039         if field.type.member.is_simple:
1040             return field.c_end_name + '(' + accum + ')'
1041         else:
1042             return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
1043
1044 def _c_iterator(self, name):
1045     '''
1046     Declares the iterator structure and next/end functions for a given type.
1047     '''
1048     _h_setlevel(0)
1049     _h('')
1050     _h('/**')
1051     _h(' * @brief %s', self.c_iterator_type)
1052     _h(' **/')
1053     _h('typedef struct %s {', self.c_iterator_type)
1054     _h('    %s *data; /**<  */', self.c_type)
1055     _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
1056     _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
1057     _h('} %s;', self.c_iterator_type)
1058
1059     _h_setlevel(1)
1060     _c_setlevel(1)
1061     _h('')
1062     _h('/**')
1063     _h(' * Get the next element of the iterator')
1064     _h(' * @param i Pointer to a %s', self.c_iterator_type)
1065     _h(' *')
1066     _h(' * Get the next element in the iterator. The member rem is')
1067     _h(' * decreased by one. The member data points to the next')
1068     _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
1069     _h(' */')
1070     _c('')
1071     _hc('')
1072     _hc('/*****************************************************************************')
1073     _hc(' **')
1074     _hc(' ** void %s', self.c_next_name)
1075     _hc(' ** ')
1076     _hc(' ** @param %s *i', self.c_iterator_type)
1077     _hc(' ** @returns void')
1078     _hc(' **')
1079     _hc(' *****************************************************************************/')
1080     _hc(' ')
1081     _hc('void')
1082     _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
1083     _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
1084     _c('{')
1085
1086     if not self.fixed_size():
1087         _c('    %s *R = i->data;', self.c_type)
1088         _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
1089         _c('    --i->rem;')
1090         _c('    i->data = (%s *) child.data;', self.c_type)
1091         _c('    i->index = child.index;')
1092     else:
1093         _c('    --i->rem;')
1094         _c('    ++i->data;')
1095         _c('    i->index += sizeof(%s);', self.c_type)
1096
1097     _c('}')
1098
1099     _h('')
1100     _h('/**')
1101     _h(' * Return the iterator pointing to the last element')
1102     _h(' * @param i An %s', self.c_iterator_type)
1103     _h(' * @return  The iterator pointing to the last element')
1104     _h(' *')
1105     _h(' * Set the current element in the iterator to the last element.')
1106     _h(' * The member rem is set to 0. The member data points to the')
1107     _h(' * last element.')
1108     _h(' */')
1109     _c('')
1110     _hc('')
1111     _hc('/*****************************************************************************')
1112     _hc(' **')
1113     _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1114     _hc(' ** ')
1115     _hc(' ** @param %s i', self.c_iterator_type)
1116     _hc(' ** @returns xcb_generic_iterator_t')
1117     _hc(' **')
1118     _hc(' *****************************************************************************/')
1119     _hc(' ')
1120     _hc('xcb_generic_iterator_t')
1121     _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1122     _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1123     _c('{')
1124     _c('    xcb_generic_iterator_t ret;')
1125
1126     if self.fixed_size():
1127         _c('    ret.data = i.data + i.rem;')
1128         _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1129         _c('    ret.rem = 0;')
1130     else:
1131         _c('    while(i.rem > 0)')
1132         _c('        %s(&i);', self.c_next_name)
1133         _c('    ret.data = i.data;')
1134         _c('    ret.rem = i.rem;')
1135         _c('    ret.index = i.index;')
1136
1137     _c('    return ret;')
1138     _c('}')
1139
1140 def _c_accessor_get_length(expr, prefix='', sep='->'):
1141     '''
1142     Figures out what C code is needed to get a length field.
1143     For fields that follow a variable-length field, use the accessor.
1144     Otherwise, just reference the structure field directly.
1145     '''
1146     prefarrow = '' if prefix == '' else prefix + sep
1147     
1148     if expr.lenfield != None and expr.lenfield.prev_varsized_field != None:
1149         # special case: variable and fixed size fields are intermixed
1150         retval = expr.lenfield.c_accessor_name + '(' + prefix + ')'
1151         if prefix in ('', '_aux'):
1152             prefix_str = '' if prefix=='' else '%s' % (prefarrow)
1153             retval = '%s%s' % (prefix_str, expr.lenfield_name)
1154         return retval
1155     elif expr.lenfield_name != None:
1156         if prefix.endswith(sep):
1157             return prefix + expr.lenfield_name
1158         else:
1159             return prefarrow + expr.lenfield_name
1160     else:
1161         return str(expr.nmemb)
1162
1163 def _c_accessor_get_expr(expr, prefix='', sep='->'):
1164     '''
1165     Figures out what C code is needed to get the length of a list field.
1166     Recurses for math operations.
1167     Returns bitcount for value-mask fields.
1168     Otherwise, uses the value of the length field.
1169     '''
1170     lenexp = _c_accessor_get_length(expr, prefix, sep)
1171
1172     if expr.op == '~':
1173         return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1174     elif expr.op == 'popcount':
1175         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1176     elif expr.op == 'enumref':
1177         enum_name = expr.lenfield_type.name
1178         constant_name = expr.lenfield_name
1179         c_name = _n(enum_name + (constant_name,)).upper()
1180         return c_name
1181     elif expr.op == 'sumof':
1182         # 1. locate the referenced list object
1183         list_obj = expr.lenfield_type
1184         field = None
1185         for f in expr.lenfield_parent.fields:
1186             if f.field_name == expr.lenfield_name:
1187                 field = f
1188                 break
1189         if field is None:
1190             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1191         if prefix != '' and not prefix.endswith(sep):
1192             prefix += sep
1193         list_name = "%s%s" % (prefix, field.c_field_name)
1194         c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name)
1195         # FIXME
1196         c_length_func = _c_accessor_get_expr(field.type.expr, prefix='', sep='')
1197         return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1198     elif expr.op != None:
1199         return '(' + _c_accessor_get_expr(expr.lhs, prefix, sep) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix, sep) + ')'
1200     elif expr.bitfield:
1201         return 'xcb_popcount(' + lenexp + ')'
1202     else:
1203         return lenexp + '/* bla */'
1204
1205 def _c_accessors_field(self, field):
1206     '''
1207     Declares the accessor functions for a non-list field that follows a variable-length field.
1208     '''
1209     if field.type.is_simple:
1210         _hc('')
1211         _hc('')
1212         _hc('/*****************************************************************************')
1213         _hc(' **')
1214         _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1215         _hc(' ** ')
1216         _hc(' ** @param const %s *R', self.c_type)
1217         _hc(' ** @returns %s', field.c_field_type)
1218         _hc(' **')
1219         _hc(' *****************************************************************************/')
1220         _hc(' ')
1221         _hc('%s', field.c_field_type)
1222         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1223         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1224         _c('{')
1225         if field.prev_varsized_field is None:
1226             _c('    return (%s *) (R + 1);', field.c_field_type)
1227         else:
1228             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1229             _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1230                field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1231         _c('}')
1232     else:
1233         _hc('')
1234         _hc('')
1235         _hc('/*****************************************************************************')
1236         _hc(' **')
1237         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1238         _hc(' ** ')
1239         _hc(' ** @param const %s *R', self.c_type)
1240         _hc(' ** @returns %s *', field.c_field_type)
1241         _hc(' **')
1242         _hc(' *****************************************************************************/')
1243         _hc(' ')
1244         _hc('%s *', field.c_field_type)
1245         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1246         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1247         _c('{')
1248         if field.prev_varsized_field is None:
1249             _c('    return (%s *) (R + 1);', field.c_field_type)
1250         else:
1251             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1252             _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1253                field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1254         _c('}')
1255     
1256 def _c_accessors_list(self, field):
1257     '''
1258     Declares the accessor functions for a list field.
1259     Declares a direct-accessor function only if the list members are fixed size.
1260     Declares length and get-iterator functions always.
1261     '''
1262     list = field.type
1263
1264     _h_setlevel(1)
1265     _c_setlevel(1)
1266     if list.member.fixed_size():
1267         _hc('')
1268         _hc('')
1269         _hc('/*****************************************************************************')
1270         _hc(' **')
1271         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1272         _hc(' ** ')
1273         _hc(' ** @param const %s *R', self.c_type)
1274         _hc(' ** @returns %s *', field.c_field_type)
1275         _hc(' **')
1276         _hc(' *****************************************************************************/')
1277         _hc(' ')
1278         _hc('%s *', field.c_field_type)
1279         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1280         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1281         _c('{')
1282
1283         if field.prev_varsized_field is None:
1284             _c('    return (%s *) (R + 1);', field.c_field_type)
1285         else:
1286             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1287             _c('    return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1288
1289         _c('}')
1290
1291     _hc('')
1292     _hc('')
1293     _hc('/*****************************************************************************')
1294     _hc(' **')
1295     _hc(' ** int %s', field.c_length_name)
1296     _hc(' ** ')
1297     _hc(' ** @param const %s *R', self.c_type)
1298     _hc(' ** @returns int')
1299     _hc(' **')
1300     _hc(' *****************************************************************************/')
1301     _hc(' ')
1302     _hc('int')
1303     _h('%s (const %s *R  /**< */);', field.c_length_name, self.c_type)
1304     _c('%s (const %s *R  /**< */)', field.c_length_name, self.c_type)
1305     _c('{')
1306     _c('    return %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1307     _c('}')
1308
1309     if field.type.member.is_simple:
1310         _hc('')
1311         _hc('')
1312         _hc('/*****************************************************************************')
1313         _hc(' **')
1314         _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1315         _hc(' ** ')
1316         _hc(' ** @param const %s *R', self.c_type)
1317         _hc(' ** @returns xcb_generic_iterator_t')
1318         _hc(' **')
1319         _hc(' *****************************************************************************/')
1320         _hc(' ')
1321         _hc('xcb_generic_iterator_t')
1322         _h('%s (const %s *R  /**< */);', field.c_end_name, self.c_type)
1323         _c('%s (const %s *R  /**< */)', field.c_end_name, self.c_type)
1324         _c('{')
1325         _c('    xcb_generic_iterator_t i;')
1326
1327         if field.prev_varsized_field == None:
1328             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1329         else:
1330             _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1331             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1332
1333         _c('    i.rem = 0;')
1334         _c('    i.index = (char *) i.data - (char *) R;')
1335         _c('    return i;')
1336         _c('}')
1337
1338     else:
1339         _hc('')
1340         _hc('')
1341         _hc('/*****************************************************************************')
1342         _hc(' **')
1343         _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1344         _hc(' ** ')
1345         _hc(' ** @param const %s *R', self.c_type)
1346         _hc(' ** @returns %s', field.c_iterator_type)
1347         _hc(' **')
1348         _hc(' *****************************************************************************/')
1349         _hc(' ')
1350         _hc('%s', field.c_iterator_type)
1351         _h('%s (const %s *R  /**< */);', field.c_iterator_name, self.c_type)
1352         _c('%s (const %s *R  /**< */)', field.c_iterator_name, self.c_type)
1353         _c('{')
1354         _c('    %s i;', field.c_iterator_type)
1355
1356         if field.prev_varsized_field == None:
1357             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1358         else:
1359             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1360             _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', field.c_field_type, field.c_field_type)
1361
1362         _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1363         _c('    i.index = (char *) i.data - (char *) R;')
1364         _c('    return i;')
1365         _c('}')
1366
1367 def _c_accessors(self, name, base):
1368     '''
1369     Declares the accessor functions for the fields of a structure.
1370     '''
1371     for field in self.fields:
1372         # no accessors for switch - 
1373         # switch always needs to be unserialized explicitly
1374         if self.is_switch:
1375             continue
1376         if field.type.is_list and not field.type.fixed_size():
1377             _c_accessors_list(self, field)
1378         elif field.prev_varsized_field != None or not field.type.fixed_size():
1379             _c_accessors_field(self, field)
1380
1381 def c_simple(self, name):
1382     '''
1383     Exported function that handles cardinal type declarations.
1384     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1385     '''
1386     _c_type_setup(self, name, ())
1387
1388     if (self.name != name):
1389         # Typedef
1390         _h_setlevel(0)
1391         my_name = _t(name)
1392         _h('')
1393         _h('typedef %s %s;', _t(self.name), my_name)
1394
1395         # Iterator
1396         _c_iterator(self, name)
1397
1398 def _c_complex(self):
1399     '''
1400     Helper function for handling all structure types.
1401     Called for all structs, requests, replies, events, errors.
1402     '''
1403     _h_setlevel(0)
1404     _h('')
1405     _h('/**')
1406     _h(' * @brief %s', self.c_type)
1407     _h(' **/')
1408     _h('typedef %s %s {', self.c_container, self.c_type)
1409
1410     struct_fields = []
1411     maxtypelen = 0
1412
1413     varfield = None
1414     for field in self.fields:
1415         if not field.type.fixed_size() and not self.is_switch:
1416             varfield = field.c_field_name
1417             continue
1418         if varfield != None and not field.type.is_pad and field.wire:
1419             errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name)
1420             sys.stderr.write(errmsg)
1421             # sys.exit(1)
1422         if field.wire:
1423             struct_fields.append(field)
1424         
1425     for field in struct_fields:
1426         length = len(field.c_field_type)
1427         # account for '*' pointer_spec
1428         if not field.type.fixed_size():
1429             length += 1
1430         maxtypelen = max(maxtypelen, length)
1431
1432     def _c_complex_field(self, field, space=''):
1433         if (field.type.fixed_size() or 
1434             # in case of switch with switch children, don't make the field a pointer
1435             # necessary for unserialize to work
1436             (self.is_switch and field.type.is_switch)):
1437             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1438             _h('%s    %s%s %s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1439         else:
1440             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1441             _h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1442
1443     if not self.is_switch:
1444         for field in struct_fields:
1445             _c_complex_field(self, field)
1446     else:
1447         for b in self.bitcases:
1448             space = ''
1449             if b.type.has_name:
1450                 _h('    struct _%s {', b.c_field_name)
1451                 space = '    '
1452             for field in b.type.fields:
1453                 _c_complex_field(self, field, space)
1454             if b.type.has_name:
1455                 _h('    } %s;', b.c_field_name)
1456
1457     _h('} %s;', self.c_type)
1458
1459 def c_struct(self, name):
1460     '''
1461     Exported function that handles structure declarations.
1462     '''
1463     _c_type_setup(self, name, ())
1464     _c_complex(self)
1465     _c_accessors(self, name, name)
1466     _c_iterator(self, name)
1467
1468 def c_union(self, name):
1469     '''
1470     Exported function that handles union declarations.
1471     '''
1472     _c_type_setup(self, name, ())
1473     _c_complex(self)
1474     _c_iterator(self, name)
1475
1476 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1477     '''
1478     Declares a request function.
1479     '''
1480
1481     # Four stunningly confusing possibilities here:
1482     #
1483     #   Void            Non-void
1484     # ------------------------------
1485     # "req"            "req"
1486     # 0 flag           CHECKED flag   Normal Mode
1487     # void_cookie      req_cookie
1488     # ------------------------------
1489     # "req_checked"    "req_unchecked"
1490     # CHECKED flag     0 flag         Abnormal Mode
1491     # void_cookie      req_cookie
1492     # ------------------------------
1493
1494
1495     # Whether we are _checked or _unchecked
1496     checked = void and not regular
1497     unchecked = not void and not regular
1498
1499     # What kind of cookie we return
1500     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1501
1502     # What flag is passed to xcb_request
1503     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1504
1505     # Global extension id variable or NULL for xproto
1506     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1507
1508     # What our function name is
1509     func_name = self.c_request_name if not aux else self.c_aux_name
1510     if checked:
1511         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1512     if unchecked:
1513         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1514
1515     param_fields = []
1516     wire_fields = []
1517     maxtypelen = len('xcb_connection_t')
1518     serial_fields = []
1519
1520     for field in self.fields:
1521         if field.visible:
1522             # The field should appear as a call parameter
1523             param_fields.append(field)
1524         if field.wire and not field.auto:
1525             # We need to set the field up in the structure
1526             wire_fields.append(field)
1527         if field.type.need_serialize:
1528             serial_fields.append(field)
1529         
1530     for field in param_fields:
1531         c_field_const_type = field.c_field_const_type 
1532         if field.type.need_serialize and not aux:
1533             c_field_const_type = "const void"
1534         if len(c_field_const_type) > maxtypelen:
1535             maxtypelen = len(c_field_const_type)
1536
1537     _h_setlevel(1)
1538     _c_setlevel(1)
1539     _h('')
1540     _h('/**')
1541     _h(' * Delivers a request to the X server')
1542     _h(' * @param c The connection')
1543     _h(' * @return A cookie')
1544     _h(' *')
1545     _h(' * Delivers a request to the X server.')
1546     _h(' * ')
1547     if checked:
1548         _h(' * This form can be used only if the request will not cause')
1549         _h(' * a reply to be generated. Any returned error will be')
1550         _h(' * saved for handling by xcb_request_check().')
1551     if unchecked:
1552         _h(' * This form can be used only if the request will cause')
1553         _h(' * a reply to be generated. Any returned error will be')
1554         _h(' * placed in the event queue.')
1555     _h(' */')
1556     _c('')
1557     _hc('')
1558     _hc('/*****************************************************************************')
1559     _hc(' **')
1560     _hc(' ** %s %s', cookie_type, func_name)
1561     _hc(' ** ')
1562
1563     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1564     _hc(' ** @param xcb_connection_t%s *c', spacing)
1565
1566     for field in param_fields:
1567         c_field_const_type = field.c_field_const_type 
1568         if field.type.need_serialize and not aux:
1569             c_field_const_type = "const void"
1570         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1571         _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1572
1573     _hc(' ** @returns %s', cookie_type)
1574     _hc(' **')
1575     _hc(' *****************************************************************************/')
1576     _hc(' ')
1577     _hc('%s', cookie_type)
1578
1579     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1580     comma = ',' if len(param_fields) else ');'
1581     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1582     comma = ',' if len(param_fields) else ')'
1583     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1584
1585     func_spacing = ' ' * (len(func_name) + 2)
1586     count = len(param_fields)
1587     for field in param_fields:
1588         count = count - 1
1589         c_field_const_type = field.c_field_const_type 
1590         c_pointer = field.c_pointer
1591         if field.type.need_serialize and not aux:
1592             c_field_const_type = "const void"
1593             c_pointer = '*'
1594         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1595         comma = ',' if count else ');'
1596         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1597            spacing, c_pointer, field.c_field_name, comma)
1598         comma = ',' if count else ')'
1599         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1600            spacing, c_pointer, field.c_field_name, comma)
1601
1602     count = 2
1603     if self.var_followed_by_fixed_fields:
1604         count += len(wire_fields)*2
1605     for field in param_fields:
1606         if not field.type.fixed_size():
1607             count = count + 2
1608             if field.type.need_serialize:
1609                 # _serialize() keeps track of padding automatically
1610                 count -= 1
1611
1612     _c('{')
1613     _c('    static const xcb_protocol_request_t xcb_req = {')
1614     _c('        /* count */ %d,', count)
1615     _c('        /* ext */ %s,', func_ext_global)
1616     _c('        /* opcode */ %s,', self.c_request_name.upper())
1617     _c('        /* isvoid */ %d', 1 if void else 0)
1618     _c('    };')
1619     _c('    ')
1620
1621     _c('    struct iovec xcb_parts[%d];', count + 2)
1622     _c('    %s xcb_ret;', func_cookie)
1623     if not self.var_followed_by_fixed_fields:
1624         _c('    %s xcb_out;', self.c_type)
1625
1626     for idx, f in enumerate(serial_fields):
1627         if not aux:
1628             _c('    %s xcb_aux%d;' % (f.type.c_type, idx))
1629         else:
1630             _c('    void *xcb_aux%d = 0;' % (idx))
1631     _c('    ')
1632 #    _c('    printf("in function %s\\n");' % func_name)     
1633  
1634     # fixed size fields
1635     if not self.var_followed_by_fixed_fields:
1636         for field in wire_fields:
1637             if field.type.fixed_size():
1638                 if field.type.is_expr:
1639                     _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr))
1640                 elif field.type.is_pad:
1641                     if field.type.nmemb == 1:
1642                         _c('    xcb_out.%s = 0;', field.c_field_name)
1643                     else:
1644                         _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
1645                 else:
1646                     if field.type.nmemb == 1:
1647                         _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
1648                     else:
1649                         _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
1650
1651         _c('    ')
1652         _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
1653         _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
1654         _c('    xcb_parts[3].iov_base = 0;')
1655         _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
1656
1657     # calls in order to free dyn. all. memory
1658     free_calls = []
1659     if not self.var_followed_by_fixed_fields:
1660         count = 4
1661     else:
1662         count = 2
1663     var_size_fields = param_fields
1664     if self.var_followed_by_fixed_fields:
1665         var_size_fields = wire_fields + param_fields
1666     for field in var_size_fields:
1667         if field.type.fixed_size and self.var_followed_by_fixed_fields:
1668             _c('    xcb_parts[%d].iov_base = (char *) &%s;', count, field.c_field_name)
1669             _c('    xcb_parts[%d].iov_len = sizeof(%s);', count, field.type.c_type)
1670             count += 1
1671         if not field.type.fixed_size():
1672             # default: simple cast to char *
1673             if not field.type.need_serialize:
1674                 _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1675                 if field.type.is_list:
1676                     _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 
1677                        _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype)
1678                 else:
1679                     # not supposed to happen
1680                     raise Exception("unhandled variable size field %s" % field.c_field_name)
1681                     #_c('/* eeeeeeeeeee */')
1682             else:
1683                 if not aux:
1684                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1685                 idx = serial_fields.index(field)
1686                 if not aux:
1687                     serialize_args = get_serialize_params('unserialize', field.type, 
1688                                                           field.c_field_name, 
1689                                                           '&xcb_aux%d' % idx)[2]
1690                 else:
1691                     serialize_args = get_serialize_params('serialize', field.type, 
1692                                                           '&xcb_aux%d' % idx,
1693                                                           field.c_field_name)[2]
1694                 serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
1695                 _c('    xcb_parts[%d].iov_len = ', count)
1696                 if aux:
1697                     _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
1698                     _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
1699                     free_calls.append('    free(xcb_aux%d);' % idx)
1700                 else:
1701                     _c('      %s (%s);', field.type.c_unserialize_name, serialize_args)
1702
1703             
1704             count += 1
1705             if not field.type.need_serialize:
1706                 # the _serialize() function keeps track of padding automatically
1707                 _c('    xcb_parts[%d].iov_base = 0;', count)
1708                 _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
1709                 count += 1
1710
1711     _c('    ')
1712     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
1713     
1714     # free dyn. all. data, if any
1715     for f in free_calls:
1716         _c(f)
1717     _c('    return xcb_ret;')
1718     _c('}')
1719
1720 def _c_reply(self, name):
1721     '''
1722     Declares the function that returns the reply structure.
1723     '''
1724     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
1725     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
1726     spacing3 = ' ' * (len(self.c_reply_name) + 2)
1727
1728     _h('')
1729     _h('/**')
1730     _h(' * Return the reply')
1731     _h(' * @param c      The connection')
1732     _h(' * @param cookie The cookie')
1733     _h(' * @param e      The xcb_generic_error_t supplied')
1734     _h(' *')
1735     _h(' * Returns the reply of the request asked by')
1736     _h(' * ')
1737     _h(' * The parameter @p e supplied to this function must be NULL if')
1738     _h(' * %s(). is used.', self.c_unchecked_name)
1739     _h(' * Otherwise, it stores the error if any.')
1740     _h(' *')
1741     _h(' * The returned value must be freed by the caller using free().')
1742     _h(' */')
1743     _c('')
1744     _hc('')
1745     _hc('/*****************************************************************************')
1746     _hc(' **')
1747     _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
1748     _hc(' ** ')
1749     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
1750     _hc(' ** @param %s   cookie', self.c_cookie_type)
1751     _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
1752     _hc(' ** @returns %s *', self.c_reply_type)
1753     _hc(' **')
1754     _hc(' *****************************************************************************/')
1755     _hc(' ')
1756     _hc('%s *', self.c_reply_type)
1757     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
1758     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
1759     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
1760     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
1761     _c('{')
1762     _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
1763     _c('}')
1764
1765 def _c_opcode(name, opcode):
1766     '''
1767     Declares the opcode define for requests, events, and errors.
1768     '''
1769     _h_setlevel(0)
1770     _h('')
1771     _h('/** Opcode for %s. */', _n(name))
1772     _h('#define %s %s', _n(name).upper(), opcode)
1773     
1774 def _c_cookie(self, name):
1775     '''
1776     Declares the cookie type for a non-void request.
1777     '''
1778     _h_setlevel(0)
1779     _h('')
1780     _h('/**')
1781     _h(' * @brief %s', self.c_cookie_type)
1782     _h(' **/')
1783     _h('typedef struct %s {', self.c_cookie_type)
1784     _h('    unsigned int sequence; /**<  */')
1785     _h('} %s;', self.c_cookie_type)
1786
1787 def c_request(self, name):
1788     '''
1789     Exported function that handles request declarations.
1790     '''
1791     _c_type_setup(self, name, ('request',))
1792
1793     if self.reply:
1794         # Cookie type declaration
1795         _c_cookie(self, name)
1796
1797     # Opcode define
1798     _c_opcode(name, self.opcode)
1799
1800     # Request structure declaration
1801     _c_complex(self)
1802
1803     if self.reply:
1804         _c_type_setup(self.reply, name, ('reply',))
1805         # Reply structure definition
1806         _c_complex(self.reply)
1807         # Request prototypes
1808         _c_request_helper(self, name, self.c_cookie_type, False, True)
1809         _c_request_helper(self, name, self.c_cookie_type, False, False)
1810         if self.need_aux:
1811             _c_request_helper(self, name, self.c_cookie_type, False, True, True)
1812             _c_request_helper(self, name, self.c_cookie_type, False, False, True)
1813         # Reply accessors
1814         _c_accessors(self.reply, name + ('reply',), name)
1815         _c_reply(self, name)
1816     else:
1817         # Request prototypes
1818         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
1819         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
1820         if self.need_aux:
1821             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
1822             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
1823
1824
1825 def c_event(self, name):
1826     '''
1827     Exported function that handles event declarations.
1828     '''
1829     _c_type_setup(self, name, ('event',))
1830
1831     # Opcode define
1832     _c_opcode(name, self.opcodes[name])
1833
1834     if self.name == name:
1835         # Structure definition
1836         _c_complex(self)
1837     else:
1838         # Typedef
1839         _h('')
1840         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
1841
1842 def c_error(self, name):
1843     '''
1844     Exported function that handles error declarations.
1845     '''
1846     _c_type_setup(self, name, ('error',))
1847
1848     # Opcode define
1849     _c_opcode(name, self.opcodes[name])
1850
1851     if self.name == name:
1852         # Structure definition
1853         _c_complex(self)
1854     else:
1855         # Typedef
1856         _h('')
1857         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
1858
1859
1860 # Main routine starts here
1861
1862 # Must create an "output" dictionary before any xcbgen imports.
1863 output = {'open'    : c_open,
1864           'close'   : c_close,
1865           'simple'  : c_simple,
1866           'enum'    : c_enum,
1867           'struct'  : c_struct,
1868           'union'   : c_union,
1869           'request' : c_request,
1870           'event'   : c_event,
1871           'error'   : c_error, 
1872           }
1873
1874 # Boilerplate below this point
1875
1876 # Check for the argument that specifies path to the xcbgen python package.
1877 try:
1878     opts, args = getopt.getopt(sys.argv[1:], 'p:')
1879 except getopt.GetoptError, err:
1880     print str(err)
1881     print 'Usage: c_client.py [-p path] file.xml'
1882     sys.exit(1)
1883
1884 for (opt, arg) in opts:
1885     if opt == '-p':
1886         sys.path.append(arg)
1887
1888 # Import the module class
1889 try:
1890     from xcbgen.state import Module
1891 except ImportError:
1892     print ''
1893     print 'Failed to load the xcbgen Python package!'
1894     print 'Make sure that xcb/proto installed it on your Python path.'
1895     print 'If not, you will need to create a .pth file or define $PYTHONPATH'
1896     print 'to extend the path.'
1897     print 'Refer to the README file in xcb/proto for more info.'
1898     print ''
1899     raise
1900
1901 # Parse the xml header
1902 module = Module(args[0], output)
1903
1904 # Build type-registry and resolve type dependencies
1905 module.register()
1906 module.resolve()
1907
1908 # Output the code
1909 module.generate()