partial rewrite of serialize helper functions completed;
[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         # special: switch C structs get pointer fields for variable-sized members
348         _c_complex(self)
349         # FIXME: declare switch (un)packing functions
350         _c_accessors(self, name, name)
351
352     # FIXME - in case of request/reply, serialize() is not always needed
353     if self.need_serialize and not self.is_bitcase:
354         if self.c_serialize_name not in finished_serializers:
355             _c_serialize(self)
356             _c_unserialize(self)
357             finished_serializers.append(self.c_serialize_name)
358 # _c_type_setup()
359
360 def get_request_fields(self):
361     param_fields = []
362     wire_fields = []
363
364     for field in self.fields:
365         if field.visible:
366             # the field should appear as a parameter in the function call
367             param_fields.append(field)
368         if field.wire and not field.auto:
369             if field.type.fixed_size() and not self.is_switch:
370                 # field in the xcb_out structure
371                 wire_fields.append(field)
372         # fields like 'pad0' are skipped!
373                     
374     return (param_fields, wire_fields)
375 # get_request_fields()
376
377 def get_switch_expr_fields(self):
378     # get the fields referenced by the switch expression
379     def get_expr_fields(expr):
380         if expr.op is None:
381             if expr.lenfield_name is not None:
382                 return [expr.lenfield_name]
383         else:
384             if expr.op == '~':
385                 return get_expr_fields(expr.rhs)
386             elif expr.op == 'popcount':
387                 return get_expr_fields(expr.rhs)
388             elif expr.op == 'sumof':
389                 return [expr.lenfield_name]
390             elif expr.op == 'enumref':
391                 return []
392             else: 
393                 return get_expr_fields(expr.lhs) + get_expr_fields(expr.rhs)
394     # get_expr_fields()
395     
396     # resolve the field names with the parent structure(s)
397     unresolved_fields = get_expr_fields(self.expr)
398     expr_fields = dict.fromkeys(unresolved_fields)
399     for p in reversed(self.parent):
400         parent_fields = dict((f.field_name, f) for f in p.fields)
401         for f in parent_fields.keys():
402             if f in unresolved_fields:
403                 expr_fields[f] = parent_fields[f]
404                 unresolved_fields.remove(f)
405         if len(unresolved_fields) == 0:
406             break
407                 
408     if None in expr_fields.values():
409         raise Exception("could not resolve all fields for <switch> %s" % self.name)
410
411     params = expr_fields.values()
412     return params
413 # get_switch_expr_fields()
414
415 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
416     param_fields, wire_fields = get_request_fields(self)
417     if self.is_switch:
418         param_fields = get_switch_expr_fields(self)
419
420     # _serialize function parameters
421     if  'serialize' == context:
422         params = [('void', '**', buffer_var)]
423     elif 'unserialize' == context:
424         params = [('const void', '*', buffer_var)]
425
426     # make sure all required length fields are present
427     for p in param_fields:
428         if p.visible and not p.wire and not p.auto:
429             typespec = p.c_field_type
430             pointerspec = ''
431             params.append((typespec, pointerspec, p.c_field_name))
432
433     # parameter fields if any
434     if self.is_switch:
435         for p in get_switch_expr_fields(self):
436             typespec = p.c_field_const_type
437             pointerspec = p.c_pointer
438             params.append((typespec, pointerspec, p.c_field_name))
439   
440     # aux argument - structure to be serialized
441     if 'serialize' == context:
442         params.append(('const %s' % self.c_type, '*', aux_var))
443     elif 'unserialize' == context and self.is_switch:
444         params.append(('%s' % self.c_type, '*', aux_var))
445     if not self.is_switch and 'serialize' == context:
446         for p in param_fields:
447             if not p.type.fixed_size():
448                 params.append((p.c_field_const_type, p.c_pointer, p.c_field_name))
449     return (param_fields, wire_fields, params)
450 # get_serialize_params()
451
452 def _c_field_mapping(context, complex_type):
453     def get_prefix(field):
454         prefix = ''
455         if context in ('serialize', 'unserialize'):
456             if field.type.fixed_size() or complex_type.is_switch:
457                 prefix = '_aux->'
458         else:
459             raise Exception("unknown context '%s' in c_field_mapping" % context)
460         return prefix
461     # get_prefix()
462     def get_field_name(fields, complex_type, prefix=''):
463         for f in complex_type.fields:
464             if '' == prefix:
465                 prefix = get_prefix(f)
466
467             fname = "%s%s" % (prefix, f.c_field_name)
468             if fields.has_key(f.field_name):
469                 continue
470                 raise Exception("field name %s has been registered before" % f.field_name)
471             fields[f.field_name] = (fname, f)
472             if f.type.is_container:
473                 new_prefix = "%s%s" % (prefix, f.c_field_name)
474                 new_prefix += "." if f.type.is_switch else "->"
475                 get_field_name(fields, f.type, new_prefix)
476     # get_field_name()
477
478     # dict(field_name : (c_field_name, field))
479     fields = {}
480     get_field_name(fields, complex_type)
481     
482     # switch: get the fields referenced by the switch expr as well
483     #         these may not belong to any structure
484     if complex_type.is_switch:
485         pass
486 #       FIXME: fields += get_serialize_params(context, complex_type)
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):
501     code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
502     code_lines.append('%s    /* padding */' % space)
503     code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
504     code_lines.append('%s    if (0 != xcb_pad) {' % space)
505
506     if 'serialize' == context:
507         code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space)
508         code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space)
509         code_lines.append('%s        xcb_parts_idx++;' % space)
510     elif 'unserialize' == context:
511         code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
512
513     code_lines.append('%s        xcb_buffer_len += xcb_pad;' % space)    
514     code_lines.append('%s        xcb_pad = 0;' % space)
515     code_lines.append('%s    }' % space)
516     code_lines.append('%s    xcb_block_len = 0;' % space)
517     
518     return 1
519 # _c_serialize_helper_insert_padding()
520
521 def _c_serialize_helper_switch(context, self, complex_name, 
522                                code_lines, temp_vars, 
523                                space, prefix):
524     count = 0
525     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
526     switch_expr = _c_accessor_get_expr(self.expr)
527
528     for b in self.bitcases:            
529         bitcase_expr = _c_accessor_get_expr(b.type.expr, prefix)
530         code_lines.append('    if(%s & %s) {' % (switch_expr, bitcase_expr))
531
532         _c_serialize_helper_fields(context, b.type, 
533                                    code_lines, temp_vars, 
534                                    space="%s    " % space, 
535                                    prefix="%s%s" % (prefix_str, complex_name), 
536                                    is_bitcase = True)
537         code_lines.append('    }')
538
539     if 'serialize' == context:
540         count = _c_serialize_helper_insert_padding(context, code_lines, space)
541     if 'unserialize' == context:
542         # padding
543         code_lines.append('%s    xcb_pad = -xcb_block_len & 3;' % space)
544         code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
545     
546     return count
547 # _c_serialize_helper_switch
548
549 def _c_serialize_helper_switch_field(self, field):
550     # switch is handled by this function as a special case
551     args = get_switch_expr_fields(field.type)
552     field_mapping = _c_field_mapping('unserialize', self)
553     c_field_names = ''
554     for a in args:
555         c_field_names += "%s, " % field_mapping[a.field_name][0]
556     switch_field_name = field_mapping[field.field_name][0]
557     length = "%s(xcb_tmp, %s&%s)" % (field.type.c_unserialize_name, 
558                                      c_field_names, switch_field_name)
559     return length
560 # _c_serialize_helper_switch_field()
561
562 def _c_serialize_helper_list_field(context, self, field, 
563                                    code_lines, temp_vars, 
564                                    space, prefix):
565     """
566     helper function for (un)serialize to cope with lists of variable length
567     """
568     expr = field.type.expr
569     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
570     param_fields, wire_fields, params = get_serialize_params('unserialize', self)
571     param_names = [p[2] for p in params]
572
573     # look if the list's lenfield is a struct member or a function argument
574     # special case: if the list has a length field, its name will returned 
575     # unchanged by calling c_accessor_get_length(expr)
576     if expr.lenfield_name == _c_accessor_get_length(expr):
577         if expr.lenfield_name in param_names:
578             # the length field appears as separate argument in unserialize, 
579             # so no need for a prefix
580             lenfield_prefix = ''
581     list_length = _c_accessor_get_expr(expr, lenfield_prefix)
582
583     # default: list with fixed size elements
584     length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
585     # list with variable-sized elements 
586     if field.type.size is None:
587         length = ''
588         if 'unserialize' == context:
589             temp_vars.add('    unsigned int i;')
590             temp_vars.add('    unsigned int xcb_tmp_len;')
591             code_lines.append("%s    for(i=0; i<%s; i++) {" % (space, list_length))
592             code_lines.append("%s        xcb_tmp_len = %s(xcb_tmp);" % 
593                               (space, field.type.c_unserialize_name))
594             code_lines.append("%s        xcb_block_len += xcb_tmp_len;" % space)
595             code_lines.append("%s        xcb_tmp += xcb_tmp_len;" % space)
596             code_lines.append("%s    }" % space)                        
597         elif 'serialize' == context:
598             code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = 0;' % space)
599             code_lines.append('%s    xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name))
600             code_lines.append('%s    for(i=0; i<%s; i++) {' 
601                               % (space, _c_accessor_get_expr(expr, lenfield_prefix)))
602             code_lines.append('%s        xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_unserialize_name))
603             code_lines.append('%s        xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space)
604             code_lines.append('%s    }' % space)
605             code_lines.append('%s    xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space)
606             
607     return length
608 # _c_serialize_helper_list_field()
609
610 def _c_serialize_helper_fields_fixed_size(context, self, field, 
611                                           code_lines, temp_vars, 
612                                           space, prefix):
613     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
614     code_lines.append('%s    /* %s.%s */' % (space, self.c_type, field.c_field_name))
615
616     length = "sizeof(%s)" % field.c_field_type
617
618     if 'unserialize' == context:
619         value = '    _aux->%s = *(%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type) 
620         # FIXME? - lists
621         if field.type.is_list:
622             raise Exception('list with fixed number of elemens unhandled in _unserialize()')
623     elif 'serialize' == context:
624         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) ' 
625
626         if field.type.is_expr:
627             # need to register a temporary variable for the expression
628             if field.type.c_type is None:
629                 raise Exception("type for field '%s' (expression '%s') unkown" % 
630                                 (field.field_name, _c_accessor_get_expr(field.type.expr)))
631             temp_vars.add('    %s xcb_expr_%s = %s;' % (field.type.c_type, field.field_name, 
632                                                         _c_accessor_get_expr(field.type.expr, prefix)))
633             value += "&xcb_expr_%s;" % field.field_name 
634
635         elif field.type.is_pad:
636             if field.type.nmemb == 1:
637                 value += "&xcb_pad;"
638             else:
639                 value = '    memset(xcb_parts[xcb_parts_idx].iov_base, 0, %d);' % field.type.nmemb
640                 length += "*%d" % field.type.nmemb
641
642         else:
643             # non-list type with fixed size
644             if field.type.nmemb == 1:
645                 value += "&%s%s;" % (prefix_str, field.c_field_name)
646             # list with nmemb (fixed size) elements
647             else:
648                 value += '%s%s;' % (prefix_str, field.c_field_name)
649                 length = '%d' % field.type.nmemb
650
651     return (value, length)
652 # _c_serialize_helper_fields_fixed_size()
653
654 def _c_serialize_helper_fields_variable_size(context, self, field, 
655                                              code_lines, temp_vars, 
656                                              space, prefix):
657     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
658
659     if 'unserialize' == context:
660         value = ''
661     elif 'serialize' == context:
662         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) %s%s;' % (prefix_str, field.c_field_name)
663     length = ''
664
665     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
666     code_lines.append('%s    /* %s */' % (space, field.c_field_name))
667
668     if field.type.is_list:
669         length = _c_serialize_helper_list_field(context, self, field, 
670                                                 code_lines, temp_vars, 
671                                                 space, prefix)
672     elif field.type.is_switch:
673         length = _c_serialize_helper_switch_field(self, field)
674     else:
675         length = "%s(xcb_tmp)" % (field.type.c_unserialize_name)
676
677     return (value, length)
678 # _c_serialize_helper_fields_variable_size
679
680 def _c_serialize_helper_fields(context, self, 
681                                code_lines, temp_vars, 
682                                space, prefix, is_bitcase):
683     count = 0
684     need_padding = False
685     prefix_str, lenfield_prefix = _c_serialize_helper_prefix(prefix)
686
687     for field in self.fields:
688         if not ((field.wire and not field.auto) or field.visible):
689             continue
690
691         # switch/bitcase: fixed size fields must be considered explicitly 
692         if field.type.fixed_size():
693             if is_bitcase:
694                 value, length = _c_serialize_helper_fields_fixed_size(context, self, field, 
695                                                                       code_lines, temp_vars, 
696                                                                       space, prefix)
697             else:
698                 continue
699
700         # fields with variable size
701         else:
702             # switch/bitcase: always calculate padding before and after variable sized fields
703             if need_padding or is_bitcase:
704                 _c_serialize_helper_insert_padding(context, code_lines, space)
705
706             value, length = _c_serialize_helper_fields_variable_size(context, self, field, 
707                                                                      code_lines, temp_vars, 
708                                                                      space, prefix)
709                 
710         # save (un)serialization C code
711         if '' != value:
712             code_lines.append('%s%s' % (space, value))
713         if field.type.fixed_size() and is_bitcase:
714             code_lines.append('%s    xcb_block_len += %s;' % (space, length))
715             if 'unserialize' == context:
716                 code_lines.append('%s    xcb_tmp += %s;' % (space, length))
717         else:
718             # padding
719             if '' != length:
720                 code_lines.append('%s    xcb_block_len = %s;' % (space, length))
721                 if 'unserialize' == context:
722                     code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
723         if 'serialize' == context:
724             if '' != length:
725                 code_lines.append('%s    xcb_parts[xcb_parts_idx].iov_len = xcb_block_len;' % space)
726             code_lines.append('%s    xcb_parts_idx++;' % space)
727             count += 1
728         need_padding = True
729         
730     return count
731 # _c_serialize_helper_fields()    
732
733 def _c_serialize_helper(context, complex_type, 
734                         code_lines, temp_vars, 
735                         space='', prefix=''):
736     count = 0
737     if hasattr(complex_type, 'type'):
738         self = complex_type.type
739         complex_name = complex_type.name
740     else:
741         self = complex_type
742         complex_name = '_aux'
743
744     # special case: switch is serialized by evaluating each bitcase separately
745     if self.is_switch:
746         count += _c_serialize_helper_switch(context, self, complex_name, 
747                                             code_lines, temp_vars, 
748                                             space, prefix)
749
750     # all other data types can be evaluated one field a time
751     else: 
752         # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type
753         if 'unserialize' == context:
754             code_lines.append('%s    xcb_block_len += sizeof(%s);' % (space, self.c_type))
755             code_lines.append('%s    xcb_tmp += xcb_block_len;' % space)
756             _c_serialize_helper_insert_padding(context, code_lines, space)
757
758         count += _c_serialize_helper_fields(context, self, 
759                                             code_lines, temp_vars, 
760                                             space, prefix, False)
761         # "final padding"
762         count += _c_serialize_helper_insert_padding(context, code_lines, space)
763
764     return count    
765 # _c_serialize_helper()
766
767 def _c_serialize(self):
768     _h_setlevel(1)
769     _c_setlevel(1)
770
771     _hc('')
772     # _serialize() returns the buffer size
773     _hc('int')
774
775     variable_size_fields = 0
776     # maximum space required for type definition of function arguments
777     maxtypelen = 0
778     param_fields, wire_fields, params = get_serialize_params('serialize', self)
779
780     # determine N(variable_fields) 
781     for field in param_fields:
782         # if self.is_switch, treat all fields as if they are variable sized
783         if not field.type.fixed_size() or self.is_switch:
784             variable_size_fields += 1
785     # determine maxtypelen
786     for p in params:
787         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
788
789     # write to .c/.h
790     for p in range(len(params)):
791         line = ""
792         typespec, pointerspec, field_name = params[p]
793         indent = ' '*(len(self.c_serialize_name)+2)
794         # p==0: function declaration
795         if 0==p:
796             line = "%s (" % self.c_serialize_name
797             indent = ''
798         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
799         line += "%s%s%s  %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name)
800         if p < len(params)-1:
801             _hc("%s," % line)
802         else:
803             _h("%s);" % line)
804             _c("%s)" % line)
805                 
806     _c('{')
807     if not self.is_switch:
808         _c('    %s *xcb_out = *_buffer;', self.c_type)
809         _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
810         _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
811     else:
812         _c('    char *xcb_out = *_buffer;')
813         _c('    unsigned int xcb_buffer_len = 0;')
814     if variable_size_fields > 0:        
815         code_lines = []
816         temp_vars = set()
817         count =_c_serialize_helper('serialize', self, 
818                                    code_lines, temp_vars)
819         # update variable size fields 
820         variable_size_fields = count
821         temp_vars.add('    unsigned int xcb_pad = 0;')
822         temp_vars.add('    char xcb_pad0[3] = {0, 0, 0};') 
823         temp_vars.add('    struct iovec xcb_parts[%d];' % (count+1))
824         temp_vars.add('    unsigned int xcb_parts_idx = 0;')
825         temp_vars.add('    unsigned int xcb_block_len = 0;')
826         temp_vars.add('    unsigned int i;')
827         temp_vars.add('    char *xcb_tmp;')
828         for t in temp_vars:
829             _c(t)
830
831     _c('')
832     
833     if variable_size_fields > 0:        
834         for l in code_lines:
835             _c(l)
836     _c('')
837
838     # variable sized fields have been collected, now
839     # allocate memory and copy everything into a continuous memory area
840     _c('    if (NULL == xcb_out) {')
841     _c('        /* allocate memory  */')
842     _c('        *_buffer = malloc(xcb_buffer_len);')
843     _c('        xcb_out = *_buffer;')
844     _c('    }')
845     _c('')
846
847     # fill in struct members
848     if not self.is_switch:
849         if len(wire_fields)>0:
850             _c('    *xcb_out = *_aux;')
851
852     # copy variable size fields into the buffer
853     if variable_size_fields > 0:
854         # xcb_out padding
855         if not self.is_switch:
856             _c('    xcb_tmp = (char*)++xcb_out;')
857             _c('    xcb_tmp += xcb_out_pad;')
858         else:
859             _c('    xcb_tmp = xcb_out;')
860             
861         # variable sized fields
862         _c('    for(i=0; i<xcb_parts_idx; i++) {')
863         _c('        memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);')
864         _c('        xcb_tmp += xcb_parts[i].iov_len;')
865         _c('    }')
866     _c('')
867     _c('    return xcb_buffer_len;')
868     _c('}')
869 # _c_serialize()
870
871 def _c_unserialize(self):
872     _h_setlevel(1)
873     _c_setlevel(1)
874
875     # _unserialize()
876     _hc('')
877     # _unserialize() returns the buffer size as well
878     _hc('int')
879
880
881     variable_size_fields = 0
882     # maximum space required for type definition of function arguments
883     maxtypelen = 0
884     param_fields, wire_fields, params = get_serialize_params('unserialize', self)
885
886     # determine N(variable_fields) 
887     for field in param_fields:
888         # if self.is_switch, treat all fields as if they are variable sized
889         if not field.type.fixed_size() or self.is_switch:
890             variable_size_fields += 1
891     # determine maxtypelen
892     for p in params:
893         maxtypelen = max(maxtypelen, len(p[0]) + len(p[1]))    
894
895     # write to .c/.h
896     for p in range(len(params)):
897         line = ""
898         typespec, pointerspec, field_name = params[p]
899         indent = ' '*(len(self.c_unserialize_name)+2)
900         # p==0: function declaration
901         if 0==p:
902             line = "%s (" % self.c_unserialize_name
903             indent = ''
904         spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec))
905         line += "%s%s%s %s%s  /**< */" % (indent, typespec, spacing, pointerspec, field_name)
906         if p < len(params)-1:
907             _hc("%s," % line)
908         else:
909             _h("%s);" % line)
910             _c("%s)" % line)
911                 
912     _c('{')
913     _c('    char *xcb_tmp = (char *)_buffer;')
914     if not self.is_switch:
915         _c('    const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type)
916     _c('    unsigned int xcb_buffer_len = 0;')
917     _c('    unsigned int xcb_block_len = 0;')
918     _c('    unsigned int xcb_pad = 0;')
919
920     code_lines = []
921     temp_vars = set()
922     _c_serialize_helper('unserialize', self, 
923                         code_lines, temp_vars)
924     for t in temp_vars:
925         _c(t)
926     _c('')
927
928     for l in code_lines:
929         _c(l)
930     _c('')
931     _c('    return xcb_buffer_len;')
932     _c('}')
933 # _c_unserialize()
934
935 def _c_iterator_get_end(field, accum):
936     '''
937     Figures out what C code is needed to find the end of a variable-length structure field.
938     For nested structures, recurses into its last variable-sized field.
939     For lists, calls the end function
940     '''
941     if field.type.is_container:
942         accum = field.c_accessor_name + '(' + accum + ')'
943         # XXX there could be fixed-length fields at the end
944         return _c_iterator_get_end(field.type.last_varsized_field, accum)
945     if field.type.is_list:
946         # XXX we can always use the first way
947         if field.type.member.is_simple:
948             return field.c_end_name + '(' + accum + ')'
949         else:
950             return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
951
952 def _c_iterator(self, name):
953     '''
954     Declares the iterator structure and next/end functions for a given type.
955     '''
956     _h_setlevel(0)
957     _h('')
958     _h('/**')
959     _h(' * @brief %s', self.c_iterator_type)
960     _h(' **/')
961     _h('typedef struct %s {', self.c_iterator_type)
962     _h('    %s *data; /**<  */', self.c_type)
963     _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
964     _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
965     _h('} %s;', self.c_iterator_type)
966
967     _h_setlevel(1)
968     _c_setlevel(1)
969     _h('')
970     _h('/**')
971     _h(' * Get the next element of the iterator')
972     _h(' * @param i Pointer to a %s', self.c_iterator_type)
973     _h(' *')
974     _h(' * Get the next element in the iterator. The member rem is')
975     _h(' * decreased by one. The member data points to the next')
976     _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
977     _h(' */')
978     _c('')
979     _hc('')
980     _hc('/*****************************************************************************')
981     _hc(' **')
982     _hc(' ** void %s', self.c_next_name)
983     _hc(' ** ')
984     _hc(' ** @param %s *i', self.c_iterator_type)
985     _hc(' ** @returns void')
986     _hc(' **')
987     _hc(' *****************************************************************************/')
988     _hc(' ')
989     _hc('void')
990     _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
991     _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
992     _c('{')
993
994     if not self.fixed_size():
995         _c('    %s *R = i->data;', self.c_type)
996         _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
997         _c('    --i->rem;')
998         _c('    i->data = (%s *) child.data;', self.c_type)
999         _c('    i->index = child.index;')
1000     else:
1001         _c('    --i->rem;')
1002         _c('    ++i->data;')
1003         _c('    i->index += sizeof(%s);', self.c_type)
1004
1005     _c('}')
1006
1007     _h('')
1008     _h('/**')
1009     _h(' * Return the iterator pointing to the last element')
1010     _h(' * @param i An %s', self.c_iterator_type)
1011     _h(' * @return  The iterator pointing to the last element')
1012     _h(' *')
1013     _h(' * Set the current element in the iterator to the last element.')
1014     _h(' * The member rem is set to 0. The member data points to the')
1015     _h(' * last element.')
1016     _h(' */')
1017     _c('')
1018     _hc('')
1019     _hc('/*****************************************************************************')
1020     _hc(' **')
1021     _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
1022     _hc(' ** ')
1023     _hc(' ** @param %s i', self.c_iterator_type)
1024     _hc(' ** @returns xcb_generic_iterator_t')
1025     _hc(' **')
1026     _hc(' *****************************************************************************/')
1027     _hc(' ')
1028     _hc('xcb_generic_iterator_t')
1029     _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
1030     _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
1031     _c('{')
1032     _c('    xcb_generic_iterator_t ret;')
1033
1034     if self.fixed_size():
1035         _c('    ret.data = i.data + i.rem;')
1036         _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
1037         _c('    ret.rem = 0;')
1038     else:
1039         _c('    while(i.rem > 0)')
1040         _c('        %s(&i);', self.c_next_name)
1041         _c('    ret.data = i.data;')
1042         _c('    ret.rem = i.rem;')
1043         _c('    ret.index = i.index;')
1044
1045     _c('    return ret;')
1046     _c('}')
1047
1048 def _c_accessor_get_length(expr, prefix=''):
1049     '''
1050     Figures out what C code is needed to get a length field.
1051     For fields that follow a variable-length field, use the accessor.
1052     Otherwise, just reference the structure field directly.
1053     '''
1054     prefarrow = '' if prefix == '' else prefix + '->'
1055
1056     if expr.lenfield != None and expr.lenfield.prev_varsized_field != None:
1057         return expr.lenfield.c_accessor_name + '(' + prefix + ')'
1058     elif expr.lenfield_name != None:
1059         return prefarrow + expr.lenfield_name
1060     else:
1061         return str(expr.nmemb)
1062
1063 def _c_accessor_get_expr(expr, prefix=''):
1064     '''
1065     Figures out what C code is needed to get the length of a list field.
1066     Recurses for math operations.
1067     Returns bitcount for value-mask fields.
1068     Otherwise, uses the value of the length field.
1069     '''
1070     lenexp = _c_accessor_get_length(expr, prefix)
1071
1072     if expr.op == '~':
1073         return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
1074     elif expr.op == 'popcount':
1075         return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
1076     elif expr.op == 'enumref':
1077         enum_name = expr.lenfield_type.name
1078         constant_name = expr.lenfield_name
1079         c_name = _n(enum_name + (constant_name,)).upper()
1080         return c_name
1081     elif expr.op == 'sumof':
1082         # 1. locate the referenced list object
1083         list_obj = expr.lenfield_type
1084         field = None
1085         for f in expr.lenfield_parent.fields:
1086             if f.field_name == expr.lenfield_name:
1087                 field = f
1088                 break
1089         if field is None:
1090             raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name)
1091         if prefix != '':
1092             prefix = "%s->" % prefix
1093         list_name = "%s%s" % (prefix, field.c_field_name)
1094         c_length_func = "%s(%s%s)" % (field.c_length_name, prefix, field.c_field_name)
1095         return 'xcb_sumof(%s, %s)' % (list_name, c_length_func)
1096     elif expr.op != None:
1097         return '(' + _c_accessor_get_expr(expr.lhs, prefix) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
1098     elif expr.bitfield:
1099         return 'xcb_popcount(' + lenexp + ')'
1100     else:
1101         return lenexp
1102
1103 def _c_accessors_field(self, field):
1104     '''
1105     Declares the accessor functions for a non-list field that follows a variable-length field.
1106     '''
1107     if field.type.is_simple:
1108         _hc('')
1109         _hc('')
1110         _hc('/*****************************************************************************')
1111         _hc(' **')
1112         _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
1113         _hc(' ** ')
1114         _hc(' ** @param const %s *R', self.c_type)
1115         _hc(' ** @returns %s', field.c_field_type)
1116         _hc(' **')
1117         _hc(' *****************************************************************************/')
1118         _hc(' ')
1119         _hc('%s', field.c_field_type)
1120         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1121         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1122         _c('{')
1123         _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1124         _c('    return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 
1125            field.c_field_type, field.first_field_after_varsized.type.c_type, field.prev_varsized_offset)
1126         _c('}')
1127     else:
1128         _hc('')
1129         _hc('')
1130         _hc('/*****************************************************************************')
1131         _hc(' **')
1132         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1133         _hc(' ** ')
1134         _hc(' ** @param const %s *R', self.c_type)
1135         _hc(' ** @returns %s *', field.c_field_type)
1136         _hc(' **')
1137         _hc(' *****************************************************************************/')
1138         _hc(' ')
1139         _hc('%s *', field.c_field_type)
1140         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1141         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1142         _c('{')
1143         _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1144         _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)
1145         _c('}')
1146     
1147 def _c_accessors_list(self, field):
1148     '''
1149     Declares the accessor functions for a list field.
1150     Declares a direct-accessor function only if the list members are fixed size.
1151     Declares length and get-iterator functions always.
1152     '''
1153     list = field.type
1154
1155     _h_setlevel(1)
1156     _c_setlevel(1)
1157     if list.member.fixed_size():
1158         _hc('')
1159         _hc('')
1160         _hc('/*****************************************************************************')
1161         _hc(' **')
1162         _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
1163         _hc(' ** ')
1164         _hc(' ** @param const %s *R', self.c_type)
1165         _hc(' ** @returns %s *', field.c_field_type)
1166         _hc(' **')
1167         _hc(' *****************************************************************************/')
1168         _hc(' ')
1169         _hc('%s *', field.c_field_type)
1170         _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
1171         _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
1172         _c('{')
1173
1174         if field.prev_varsized_field == None:
1175             _c('    return (%s *) (R + 1);', field.c_field_type)
1176         else:
1177             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1178             _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)
1179
1180         _c('}')
1181
1182     _hc('')
1183     _hc('')
1184     _hc('/*****************************************************************************')
1185     _hc(' **')
1186     _hc(' ** int %s', field.c_length_name)
1187     _hc(' ** ')
1188     _hc(' ** @param const %s *R', self.c_type)
1189     _hc(' ** @returns int')
1190     _hc(' **')
1191     _hc(' *****************************************************************************/')
1192     _hc(' ')
1193     _hc('int')
1194     _h('%s (const %s *R  /**< */);', field.c_length_name, self.c_type)
1195     _c('%s (const %s *R  /**< */)', field.c_length_name, self.c_type)
1196     _c('{')
1197     _c('    return %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1198     _c('}')
1199
1200     if field.type.member.is_simple:
1201         _hc('')
1202         _hc('')
1203         _hc('/*****************************************************************************')
1204         _hc(' **')
1205         _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
1206         _hc(' ** ')
1207         _hc(' ** @param const %s *R', self.c_type)
1208         _hc(' ** @returns xcb_generic_iterator_t')
1209         _hc(' **')
1210         _hc(' *****************************************************************************/')
1211         _hc(' ')
1212         _hc('xcb_generic_iterator_t')
1213         _h('%s (const %s *R  /**< */);', field.c_end_name, self.c_type)
1214         _c('%s (const %s *R  /**< */)', field.c_end_name, self.c_type)
1215         _c('{')
1216         _c('    xcb_generic_iterator_t i;')
1217
1218         if field.prev_varsized_field == None:
1219             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1220         else:
1221             _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1222             _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
1223
1224         _c('    i.rem = 0;')
1225         _c('    i.index = (char *) i.data - (char *) R;')
1226         _c('    return i;')
1227         _c('}')
1228
1229     else:
1230         _hc('')
1231         _hc('')
1232         _hc('/*****************************************************************************')
1233         _hc(' **')
1234         _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
1235         _hc(' ** ')
1236         _hc(' ** @param const %s *R', self.c_type)
1237         _hc(' ** @returns %s', field.c_iterator_type)
1238         _hc(' **')
1239         _hc(' *****************************************************************************/')
1240         _hc(' ')
1241         _hc('%s', field.c_iterator_type)
1242         _h('%s (const %s *R  /**< */);', field.c_iterator_name, self.c_type)
1243         _c('%s (const %s *R  /**< */)', field.c_iterator_name, self.c_type)
1244         _c('{')
1245         _c('    %s i;', field.c_iterator_type)
1246
1247         if field.prev_varsized_field == None:
1248             _c('    i.data = (%s *) (R + 1);', field.c_field_type)
1249         else:
1250             _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
1251             _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', field.c_field_type, field.c_field_type)
1252
1253         _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R'))
1254         _c('    i.index = (char *) i.data - (char *) R;')
1255         _c('    return i;')
1256         _c('}')
1257
1258 def _c_accessors(self, name, base):
1259     '''
1260     Declares the accessor functions for the fields of a structure.
1261     '''
1262     for field in self.fields:
1263         if field.type.is_list and not field.type.fixed_size():
1264             _c_accessors_list(self, field)
1265         elif field.prev_varsized_field != None:
1266             _c_accessors_field(self, field)
1267
1268 def c_simple(self, name):
1269     '''
1270     Exported function that handles cardinal type declarations.
1271     These are types which are typedef'd to one of the CARDx's, char, float, etc.
1272     '''
1273     _c_type_setup(self, name, ())
1274
1275     if (self.name != name):
1276         # Typedef
1277         _h_setlevel(0)
1278         my_name = _t(name)
1279         _h('')
1280         _h('typedef %s %s;', _t(self.name), my_name)
1281
1282         # Iterator
1283         _c_iterator(self, name)
1284
1285 def _c_complex(self):
1286     '''
1287     Helper function for handling all structure types.
1288     Called for all structs, requests, replies, events, errors.
1289     '''
1290     _h_setlevel(0)
1291     _h('')
1292     _h('/**')
1293     _h(' * @brief %s', self.c_type)
1294     _h(' **/')
1295     _h('typedef %s %s {', self.c_container, self.c_type)
1296
1297     struct_fields = []
1298     maxtypelen = 0
1299
1300     varfield = None
1301     for field in self.fields:
1302         if not field.type.fixed_size() and not self.is_switch:
1303             varfield = field.c_field_name
1304             continue
1305         if varfield != None and not field.type.is_pad and field.wire:
1306             errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name)
1307             sys.stderr.write(errmsg)
1308             # sys.exit(1)
1309         if field.wire:
1310             struct_fields.append(field)
1311         
1312     for field in struct_fields:
1313         length = len(field.c_field_type)
1314         # account for '*' pointer_spec
1315         if not field.type.fixed_size():
1316             length += 1
1317         maxtypelen = max(maxtypelen, length)
1318
1319     for field in struct_fields:
1320         if (field.type.fixed_size() or 
1321             # in case of switch with switch children, don't make the field a pointer
1322             # necessary for unserialize to work
1323             (self.is_switch and field.type.is_switch)):
1324             spacing = ' ' * (maxtypelen - len(field.c_field_type))
1325             _h('    %s%s %s%s; /**<  */', field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1326         
1327         else:
1328             spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
1329             _h('    %s%s *%s%s; /**<  */', field.c_field_type, spacing, field.c_field_name, field.c_subscript)
1330
1331     _h('} %s;', self.c_type)
1332
1333 def c_struct(self, name):
1334     '''
1335     Exported function that handles structure declarations.
1336     '''
1337     _c_type_setup(self, name, ())
1338     _c_complex(self)
1339     _c_accessors(self, name, name)
1340     _c_iterator(self, name)
1341
1342 def c_union(self, name):
1343     '''
1344     Exported function that handles union declarations.
1345     '''
1346     _c_type_setup(self, name, ())
1347     _c_complex(self)
1348     _c_iterator(self, name)
1349
1350 def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
1351     '''
1352     Declares a request function.
1353     '''
1354
1355     # Four stunningly confusing possibilities here:
1356     #
1357     #   Void            Non-void
1358     # ------------------------------
1359     # "req"            "req"
1360     # 0 flag           CHECKED flag   Normal Mode
1361     # void_cookie      req_cookie
1362     # ------------------------------
1363     # "req_checked"    "req_unchecked"
1364     # CHECKED flag     0 flag         Abnormal Mode
1365     # void_cookie      req_cookie
1366     # ------------------------------
1367
1368
1369     # Whether we are _checked or _unchecked
1370     checked = void and not regular
1371     unchecked = not void and not regular
1372
1373     # What kind of cookie we return
1374     func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
1375
1376     # What flag is passed to xcb_request
1377     func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
1378
1379     # Global extension id variable or NULL for xproto
1380     func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
1381
1382     # What our function name is
1383     func_name = self.c_request_name if not aux else self.c_aux_name
1384     if checked:
1385         func_name = self.c_checked_name if not aux else self.c_aux_checked_name
1386     if unchecked:
1387         func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name
1388
1389     param_fields = []
1390     wire_fields = []
1391     maxtypelen = len('xcb_connection_t')
1392     serial_fields = []
1393
1394     for field in self.fields:
1395         if field.visible:
1396             # The field should appear as a call parameter
1397             param_fields.append(field)
1398         if field.wire and not field.auto:
1399             # We need to set the field up in the structure
1400             wire_fields.append(field)
1401         if field.type.need_serialize:
1402             serial_fields.append(field)
1403         
1404     for field in param_fields:
1405         c_field_const_type = field.c_field_const_type 
1406         if field.type.need_serialize and not aux:
1407             c_field_const_type = "const void"
1408         if len(c_field_const_type) > maxtypelen:
1409             maxtypelen = len(c_field_const_type)
1410
1411     _h_setlevel(1)
1412     _c_setlevel(1)
1413     _h('')
1414     _h('/**')
1415     _h(' * Delivers a request to the X server')
1416     _h(' * @param c The connection')
1417     _h(' * @return A cookie')
1418     _h(' *')
1419     _h(' * Delivers a request to the X server.')
1420     _h(' * ')
1421     if checked:
1422         _h(' * This form can be used only if the request will not cause')
1423         _h(' * a reply to be generated. Any returned error will be')
1424         _h(' * saved for handling by xcb_request_check().')
1425     if unchecked:
1426         _h(' * This form can be used only if the request will cause')
1427         _h(' * a reply to be generated. Any returned error will be')
1428         _h(' * placed in the event queue.')
1429     _h(' */')
1430     _c('')
1431     _hc('')
1432     _hc('/*****************************************************************************')
1433     _hc(' **')
1434     _hc(' ** %s %s', cookie_type, func_name)
1435     _hc(' ** ')
1436
1437     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1438     _hc(' ** @param xcb_connection_t%s *c', spacing)
1439
1440     for field in param_fields:
1441         c_field_const_type = field.c_field_const_type 
1442         if field.type.need_serialize and not aux:
1443             c_field_const_type = "const void"
1444         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1445         _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name)
1446
1447     _hc(' ** @returns %s', cookie_type)
1448     _hc(' **')
1449     _hc(' *****************************************************************************/')
1450     _hc(' ')
1451     _hc('%s', cookie_type)
1452
1453     spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
1454     comma = ',' if len(param_fields) else ');'
1455     _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1456     comma = ',' if len(param_fields) else ')'
1457     _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
1458
1459     func_spacing = ' ' * (len(func_name) + 2)
1460     count = len(param_fields)
1461     for field in param_fields:
1462         count = count - 1
1463         c_field_const_type = field.c_field_const_type 
1464         if field.type.need_serialize and not aux:
1465             c_field_const_type = "const void"
1466         spacing = ' ' * (maxtypelen - len(c_field_const_type))
1467         comma = ',' if count else ');'
1468         _h('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1469            spacing, field.c_pointer, field.c_field_name, comma)
1470         comma = ',' if count else ')'
1471         _c('%s%s%s %s%s  /**< */%s', func_spacing, c_field_const_type, 
1472            spacing, field.c_pointer, field.c_field_name, comma)
1473
1474     count = 2
1475     for field in param_fields:
1476         if not field.type.fixed_size():
1477             count = count + 2
1478             if field.type.need_serialize:
1479                 # _serialize() keeps track of padding automatically
1480                 count -= 1
1481
1482     _c('{')
1483     _c('    static const xcb_protocol_request_t xcb_req = {')
1484     _c('        /* count */ %d,', count)
1485     _c('        /* ext */ %s,', func_ext_global)
1486     _c('        /* opcode */ %s,', self.c_request_name.upper())
1487     _c('        /* isvoid */ %d', 1 if void else 0)
1488     _c('    };')
1489     _c('    ')
1490
1491     _c('    struct iovec xcb_parts[%d];', count + 2)
1492     _c('    %s xcb_ret;', func_cookie)
1493     _c('    %s xcb_out;', self.c_type)
1494     for idx, f in enumerate(serial_fields):
1495         if not aux:
1496             _c('    %s xcb_aux%d;' % (f.type.c_type, idx))
1497         else:
1498             _c('    void *xcb_aux%d = 0;' % (idx))
1499     _c('    ')
1500     _c('    printf("in function %s\\n");' % func_name)     
1501  
1502     # fixed size fields
1503     for field in wire_fields:
1504         if field.type.fixed_size():
1505             if field.type.is_expr:
1506                 _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr))
1507             elif field.type.is_pad:
1508                 if field.type.nmemb == 1:
1509                     _c('    xcb_out.%s = 0;', field.c_field_name)
1510                 else:
1511                     _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
1512             else:
1513                 if field.type.nmemb == 1:
1514                     _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
1515                 else:
1516                     _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
1517
1518     _c('    ')
1519     _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
1520     _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
1521     _c('    xcb_parts[3].iov_base = 0;')
1522     _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
1523
1524     # calls in order to free dyn. all. memory
1525     free_calls = []
1526     count = 4
1527     for field in param_fields:
1528         if not field.type.fixed_size():
1529             if not field.type.need_serialize:
1530                 _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1531             else:
1532                 if not aux:
1533                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
1534                 idx = serial_fields.index(field)
1535                 if not aux:
1536                     serialize_args = get_serialize_params('unserialize', field.type, 
1537                                                           field.c_field_name, 
1538                                                           '&xcb_aux%d' % idx)[2]
1539                 else:
1540                     serialize_args = get_serialize_params('serialize', field.type, 
1541                                                           '&xcb_aux%d' % idx,
1542                                                           field.c_field_name)[2]
1543                 serialize_args = reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args])
1544                 _c('    xcb_parts[%d].iov_len = ', count)
1545                 if aux:
1546                     _c('      %s (%s);', field.type.c_serialize_name, serialize_args)
1547                     _c('    xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx))
1548                     free_calls.append('    free(xcb_aux%d);' % idx)
1549                 else:
1550                     _c('      %s (%s);', field.type.c_unserialize_name, serialize_args)
1551             if field.type.is_list:
1552                 _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 
1553                    _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype)
1554             elif not field.type.need_serialize:
1555                 # FIXME - _serialize()
1556                 _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', 
1557                    count, 'Uh oh', field.type.c_wiretype)
1558             
1559             count += 1
1560             if not field.type.need_serialize:
1561                 # the _serialize() function keeps track of padding automatically
1562                 _c('    xcb_parts[%d].iov_base = 0;', count)
1563                 _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1)
1564                 count += 1
1565
1566     _c('    ')
1567     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
1568     
1569     # free dyn. all. data, if any
1570     for f in free_calls:
1571         _c(f)
1572     _c('    return xcb_ret;')
1573     _c('}')
1574
1575 def _c_reply(self, name):
1576     '''
1577     Declares the function that returns the reply structure.
1578     '''
1579     spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
1580     spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
1581     spacing3 = ' ' * (len(self.c_reply_name) + 2)
1582
1583     _h('')
1584     _h('/**')
1585     _h(' * Return the reply')
1586     _h(' * @param c      The connection')
1587     _h(' * @param cookie The cookie')
1588     _h(' * @param e      The xcb_generic_error_t supplied')
1589     _h(' *')
1590     _h(' * Returns the reply of the request asked by')
1591     _h(' * ')
1592     _h(' * The parameter @p e supplied to this function must be NULL if')
1593     _h(' * %s(). is used.', self.c_unchecked_name)
1594     _h(' * Otherwise, it stores the error if any.')
1595     _h(' *')
1596     _h(' * The returned value must be freed by the caller using free().')
1597     _h(' */')
1598     _c('')
1599     _hc('')
1600     _hc('/*****************************************************************************')
1601     _hc(' **')
1602     _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
1603     _hc(' ** ')
1604     _hc(' ** @param xcb_connection_t%s  *c', spacing1)
1605     _hc(' ** @param %s   cookie', self.c_cookie_type)
1606     _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
1607     _hc(' ** @returns %s *', self.c_reply_type)
1608     _hc(' **')
1609     _hc(' *****************************************************************************/')
1610     _hc(' ')
1611     _hc('%s *', self.c_reply_type)
1612     _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
1613     _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
1614     _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
1615     _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
1616     _c('{')
1617     _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
1618     _c('}')
1619
1620 def _c_opcode(name, opcode):
1621     '''
1622     Declares the opcode define for requests, events, and errors.
1623     '''
1624     _h_setlevel(0)
1625     _h('')
1626     _h('/** Opcode for %s. */', _n(name))
1627     _h('#define %s %s', _n(name).upper(), opcode)
1628     
1629 def _c_cookie(self, name):
1630     '''
1631     Declares the cookie type for a non-void request.
1632     '''
1633     _h_setlevel(0)
1634     _h('')
1635     _h('/**')
1636     _h(' * @brief %s', self.c_cookie_type)
1637     _h(' **/')
1638     _h('typedef struct %s {', self.c_cookie_type)
1639     _h('    unsigned int sequence; /**<  */')
1640     _h('} %s;', self.c_cookie_type)
1641
1642 def c_request(self, name):
1643     '''
1644     Exported function that handles request declarations.
1645     '''
1646     _c_type_setup(self, name, ('request',))
1647
1648     if self.reply:
1649         # Cookie type declaration
1650         _c_cookie(self, name)
1651
1652     # Opcode define
1653     _c_opcode(name, self.opcode)
1654
1655     # Request structure declaration
1656     _c_complex(self)
1657
1658     if self.reply:
1659         _c_type_setup(self.reply, name, ('reply',))
1660         # Reply structure definition
1661         _c_complex(self.reply)
1662         # Request prototypes
1663         _c_request_helper(self, name, self.c_cookie_type, False, True)
1664         _c_request_helper(self, name, self.c_cookie_type, False, False)
1665         if self.need_aux:
1666             _c_request_helper(self, name, self.c_cookie_type, False, True, True)
1667             _c_request_helper(self, name, self.c_cookie_type, False, False, True)
1668         # Reply accessors
1669         _c_accessors(self.reply, name + ('reply',), name)
1670         _c_reply(self, name)
1671     else:
1672         # Request prototypes
1673         _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
1674         _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
1675         if self.need_aux:
1676             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
1677             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
1678
1679
1680 def c_event(self, name):
1681     '''
1682     Exported function that handles event declarations.
1683     '''
1684     _c_type_setup(self, name, ('event',))
1685
1686     # Opcode define
1687     _c_opcode(name, self.opcodes[name])
1688
1689     if self.name == name:
1690         # Structure definition
1691         _c_complex(self)
1692     else:
1693         # Typedef
1694         _h('')
1695         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
1696
1697 def c_error(self, name):
1698     '''
1699     Exported function that handles error declarations.
1700     '''
1701     _c_type_setup(self, name, ('error',))
1702
1703     # Opcode define
1704     _c_opcode(name, self.opcodes[name])
1705
1706     if self.name == name:
1707         # Structure definition
1708         _c_complex(self)
1709     else:
1710         # Typedef
1711         _h('')
1712         _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
1713
1714
1715 # Main routine starts here
1716
1717 # Must create an "output" dictionary before any xcbgen imports.
1718 output = {'open'    : c_open,
1719           'close'   : c_close,
1720           'simple'  : c_simple,
1721           'enum'    : c_enum,
1722           'struct'  : c_struct,
1723           'union'   : c_union,
1724           'request' : c_request,
1725           'event'   : c_event,
1726           'error'   : c_error, 
1727           }
1728
1729 # Boilerplate below this point
1730
1731 # Check for the argument that specifies path to the xcbgen python package.
1732 try:
1733     opts, args = getopt.getopt(sys.argv[1:], 'p:')
1734 except getopt.GetoptError, err:
1735     print str(err)
1736     print 'Usage: c_client.py [-p path] file.xml'
1737     sys.exit(1)
1738
1739 for (opt, arg) in opts:
1740     if opt == '-p':
1741         sys.path.append(arg)
1742
1743 # Import the module class
1744 try:
1745     from xcbgen.state import Module
1746 except ImportError:
1747     print ''
1748     print 'Failed to load the xcbgen Python package!'
1749     print 'Make sure that xcb/proto installed it on your Python path.'
1750     print 'If not, you will need to create a .pth file or define $PYTHONPATH'
1751     print 'to extend the path.'
1752     print 'Refer to the README file in xcb/proto for more info.'
1753     print ''
1754     raise
1755
1756 # Parse the xml header
1757 module = Module(args[0], output)
1758
1759 # Build type-registry and resolve type dependencies
1760 module.register()
1761 module.resolve()
1762
1763 # Output the code
1764 module.generate()