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