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