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