c_client.py revision 602e473d
1#!/usr/bin/env python
2from xml.etree.cElementTree import *
3from os.path import basename
4import getopt
5import sys
6import 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
26def _h(fmt, *args):
27    '''
28    Writes the given line to the header file.
29    '''
30    _hlines[_hlevel].append(fmt % args)
31
32def _c(fmt, *args):
33    '''
34    Writes the given line to the source file.
35    '''
36    _clines[_clevel].append(fmt % args)
37
38def _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.
46def _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
56def _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
66def _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
78def _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
87def _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
97def _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
113def _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
129def 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
185def 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
222def 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
230def 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
253def _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    if self.is_container:
277
278        self.c_container = 'union' if self.is_union else 'struct'
279        prev_varsized_field = None
280        prev_varsized_offset = 0
281        first_field_after_varsized = None
282
283        for field in self.fields:
284            _c_type_setup(field.type, field.field_type, ())
285            if field.type.is_list:
286                _c_type_setup(field.type.member, field.field_type, ())
287
288            field.c_field_type = _t(field.field_type)
289            field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
290            field.c_field_name = _cpp(field.field_name)
291            field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb > 1) else ''
292            field.c_pointer = ' ' if field.type.nmemb == 1 else '*'
293
294            field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
295            field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator
296            field.c_accessor_name = _n(name + (field.field_name,))            # xcb_container_field
297            field.c_length_name = _n(name + (field.field_name, 'length'))     # xcb_container_field_length
298            field.c_end_name = _n(name + (field.field_name, 'end'))           # xcb_container_field_end
299
300            field.prev_varsized_field = prev_varsized_field
301            field.prev_varsized_offset = prev_varsized_offset
302
303            if prev_varsized_offset == 0:
304                first_field_after_varsized = field
305            field.first_field_after_varsized = first_field_after_varsized
306
307            if field.type.fixed_size():
308                prev_varsized_offset += field.type.size
309            else:
310                self.last_varsized_field = field
311                prev_varsized_field = field
312                prev_varsized_offset = 0
313
314def _c_iterator_get_end(field, accum):
315    '''
316    Figures out what C code is needed to find the end of a variable-length structure field.
317    For nested structures, recurses into its last variable-sized field.
318    For lists, calls the end function
319    '''
320    if field.type.is_container:
321        accum = field.c_accessor_name + '(' + accum + ')'
322        # XXX there could be fixed-length fields at the end
323        return _c_iterator_get_end(field.type.last_varsized_field, accum)
324    if field.type.is_list:
325        # XXX we can always use the first way
326        if field.type.member.is_simple:
327            return field.c_end_name + '(' + accum + ')'
328        else:
329            return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))'
330
331def _c_iterator(self, name):
332    '''
333    Declares the iterator structure and next/end functions for a given type.
334    '''
335    _h_setlevel(0)
336    _h('')
337    _h('/**')
338    _h(' * @brief %s', self.c_iterator_type)
339    _h(' **/')
340    _h('typedef struct %s {', self.c_iterator_type)
341    _h('    %s *data; /**<  */', self.c_type)
342    _h('    int%s rem; /**<  */', ' ' * (len(self.c_type) - 2))
343    _h('    int%s index; /**<  */', ' ' * (len(self.c_type) - 2))
344    _h('} %s;', self.c_iterator_type)
345
346    _h_setlevel(1)
347    _c_setlevel(1)
348    _h('')
349    _h('/**')
350    _h(' * Get the next element of the iterator')
351    _h(' * @param i Pointer to a %s', self.c_iterator_type)
352    _h(' *')
353    _h(' * Get the next element in the iterator. The member rem is')
354    _h(' * decreased by one. The member data points to the next')
355    _h(' * element. The member index is increased by sizeof(%s)', self.c_type)
356    _h(' */')
357    _c('')
358    _hc('')
359    _hc('/*****************************************************************************')
360    _hc(' **')
361    _hc(' ** void %s', self.c_next_name)
362    _hc(' ** ')
363    _hc(' ** @param %s *i', self.c_iterator_type)
364    _hc(' ** @returns void')
365    _hc(' **')
366    _hc(' *****************************************************************************/')
367    _hc(' ')
368    _hc('void')
369    _h('%s (%s *i  /**< */);', self.c_next_name, self.c_iterator_type)
370    _c('%s (%s *i  /**< */)', self.c_next_name, self.c_iterator_type)
371    _c('{')
372
373    if not self.fixed_size():
374        _c('    %s *R = i->data;', self.c_type)
375        _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R'))
376        _c('    --i->rem;')
377        _c('    i->data = (%s *) child.data;', self.c_type)
378        _c('    i->index = child.index;')
379    else:
380        _c('    --i->rem;')
381        _c('    ++i->data;')
382        _c('    i->index += sizeof(%s);', self.c_type)
383
384    _c('}')
385
386    _h('')
387    _h('/**')
388    _h(' * Return the iterator pointing to the last element')
389    _h(' * @param i An %s', self.c_iterator_type)
390    _h(' * @return  The iterator pointing to the last element')
391    _h(' *')
392    _h(' * Set the current element in the iterator to the last element.')
393    _h(' * The member rem is set to 0. The member data points to the')
394    _h(' * last element.')
395    _h(' */')
396    _c('')
397    _hc('')
398    _hc('/*****************************************************************************')
399    _hc(' **')
400    _hc(' ** xcb_generic_iterator_t %s', self.c_end_name)
401    _hc(' ** ')
402    _hc(' ** @param %s i', self.c_iterator_type)
403    _hc(' ** @returns xcb_generic_iterator_t')
404    _hc(' **')
405    _hc(' *****************************************************************************/')
406    _hc(' ')
407    _hc('xcb_generic_iterator_t')
408    _h('%s (%s i  /**< */);', self.c_end_name, self.c_iterator_type)
409    _c('%s (%s i  /**< */)', self.c_end_name, self.c_iterator_type)
410    _c('{')
411    _c('    xcb_generic_iterator_t ret;')
412
413    if self.fixed_size():
414        _c('    ret.data = i.data + i.rem;')
415        _c('    ret.index = i.index + ((char *) ret.data - (char *) i.data);')
416        _c('    ret.rem = 0;')
417    else:
418        _c('    while(i.rem > 0)')
419        _c('        %s(&i);', self.c_next_name)
420        _c('    ret.data = i.data;')
421        _c('    ret.rem = i.rem;')
422        _c('    ret.index = i.index;')
423
424    _c('    return ret;')
425    _c('}')
426
427def _c_accessor_get_length(expr, prefix=''):
428    '''
429    Figures out what C code is needed to get a length field.
430    For fields that follow a variable-length field, use the accessor.
431    Otherwise, just reference the structure field directly.
432    '''
433    prefarrow = '' if prefix == '' else prefix + '->'
434
435    if expr.lenfield != None and expr.lenfield.prev_varsized_field != None:
436        return expr.lenfield.c_accessor_name + '(' + prefix + ')'
437    elif expr.lenfield_name != None:
438        return prefarrow + expr.lenfield_name
439    else:
440        return str(expr.nmemb)
441
442def _c_accessor_get_expr(expr, prefix=''):
443    '''
444    Figures out what C code is needed to get the length of a list field.
445    Recurses for math operations.
446    Returns bitcount for value-mask fields.
447    Otherwise, uses the value of the length field.
448    '''
449    lenexp = _c_accessor_get_length(expr, prefix)
450
451    if expr.op != None:
452        return '(' + _c_accessor_get_expr(expr.lhs, prefix) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
453    elif expr.bitfield:
454        return 'xcb_popcount(' + lenexp + ')'
455    else:
456        return lenexp
457
458def _c_accessors_field(self, field):
459    '''
460    Declares the accessor functions for a non-list field that follows a variable-length field.
461    '''
462    if field.type.is_simple:
463        _hc('')
464        _hc('')
465        _hc('/*****************************************************************************')
466        _hc(' **')
467        _hc(' ** %s %s', field.c_field_type, field.c_accessor_name)
468        _hc(' ** ')
469        _hc(' ** @param const %s *R', self.c_type)
470        _hc(' ** @returns %s', field.c_field_type)
471        _hc(' **')
472        _hc(' *****************************************************************************/')
473        _hc(' ')
474        _hc('%s', field.c_field_type)
475        _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
476        _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
477        _c('{')
478        _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
479        _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)
480        _c('}')
481    else:
482        _hc('')
483        _hc('')
484        _hc('/*****************************************************************************')
485        _hc(' **')
486        _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
487        _hc(' ** ')
488        _hc(' ** @param const %s *R', self.c_type)
489        _hc(' ** @returns %s *', field.c_field_type)
490        _hc(' **')
491        _hc(' *****************************************************************************/')
492        _hc(' ')
493        _hc('%s *', field.c_field_type)
494        _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
495        _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
496        _c('{')
497        _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
498        _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)
499        _c('}')
500
501def _c_accessors_list(self, field):
502    '''
503    Declares the accessor functions for a list field.
504    Declares a direct-accessor function only if the list members are fixed size.
505    Declares length and get-iterator functions always.
506    '''
507    list = field.type
508
509    _h_setlevel(1)
510    _c_setlevel(1)
511    if list.member.fixed_size():
512        _hc('')
513        _hc('')
514        _hc('/*****************************************************************************')
515        _hc(' **')
516        _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name)
517        _hc(' ** ')
518        _hc(' ** @param const %s *R', self.c_type)
519        _hc(' ** @returns %s *', field.c_field_type)
520        _hc(' **')
521        _hc(' *****************************************************************************/')
522        _hc(' ')
523        _hc('%s *', field.c_field_type)
524        _h('%s (const %s *R  /**< */);', field.c_accessor_name, self.c_type)
525        _c('%s (const %s *R  /**< */)', field.c_accessor_name, self.c_type)
526        _c('{')
527
528        if field.prev_varsized_field == None:
529            _c('    return (%s *) (R + 1);', field.c_field_type)
530        else:
531            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
532            _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)
533
534        _c('}')
535
536    _hc('')
537    _hc('')
538    _hc('/*****************************************************************************')
539    _hc(' **')
540    _hc(' ** int %s', field.c_length_name)
541    _hc(' ** ')
542    _hc(' ** @param const %s *R', self.c_type)
543    _hc(' ** @returns int')
544    _hc(' **')
545    _hc(' *****************************************************************************/')
546    _hc(' ')
547    _hc('int')
548    _h('%s (const %s *R  /**< */);', field.c_length_name, self.c_type)
549    _c('%s (const %s *R  /**< */)', field.c_length_name, self.c_type)
550    _c('{')
551    _c('    return %s;', _c_accessor_get_expr(field.type.expr, 'R'))
552    _c('}')
553
554    if field.type.member.is_simple:
555        _hc('')
556        _hc('')
557        _hc('/*****************************************************************************')
558        _hc(' **')
559        _hc(' ** xcb_generic_iterator_t %s', field.c_end_name)
560        _hc(' ** ')
561        _hc(' ** @param const %s *R', self.c_type)
562        _hc(' ** @returns xcb_generic_iterator_t')
563        _hc(' **')
564        _hc(' *****************************************************************************/')
565        _hc(' ')
566        _hc('xcb_generic_iterator_t')
567        _h('%s (const %s *R  /**< */);', field.c_end_name, self.c_type)
568        _c('%s (const %s *R  /**< */)', field.c_end_name, self.c_type)
569        _c('{')
570        _c('    xcb_generic_iterator_t i;')
571
572        if field.prev_varsized_field == None:
573            _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
574        else:
575            _c('    xcb_generic_iterator_t child = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
576            _c('    i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R'))
577
578        _c('    i.rem = 0;')
579        _c('    i.index = (char *) i.data - (char *) R;')
580        _c('    return i;')
581        _c('}')
582
583    else:
584        _hc('')
585        _hc('')
586        _hc('/*****************************************************************************')
587        _hc(' **')
588        _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name)
589        _hc(' ** ')
590        _hc(' ** @param const %s *R', self.c_type)
591        _hc(' ** @returns %s', field.c_iterator_type)
592        _hc(' **')
593        _hc(' *****************************************************************************/')
594        _hc(' ')
595        _hc('%s', field.c_iterator_type)
596        _h('%s (const %s *R  /**< */);', field.c_iterator_name, self.c_type)
597        _c('%s (const %s *R  /**< */)', field.c_iterator_name, self.c_type)
598        _c('{')
599        _c('    %s i;', field.c_iterator_type)
600
601        if field.prev_varsized_field == None:
602            _c('    i.data = (%s *) (R + 1);', field.c_field_type)
603        else:
604            _c('    xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R'))
605            _c('    i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', field.c_field_type, field.c_field_type)
606
607        _c('    i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R'))
608        _c('    i.index = (char *) i.data - (char *) R;')
609        _c('    return i;')
610        _c('}')
611
612def _c_accessors(self, name, base):
613    '''
614    Declares the accessor functions for the fields of a structure.
615    '''
616    for field in self.fields:
617        if field.type.is_list and not field.type.fixed_size():
618            _c_accessors_list(self, field)
619        elif field.prev_varsized_field != None:
620            _c_accessors_field(self, field)
621
622def c_simple(self, name):
623    '''
624    Exported function that handles cardinal type declarations.
625    These are types which are typedef'd to one of the CARDx's, char, float, etc.
626    '''
627    _c_type_setup(self, name, ())
628
629    if (self.name != name):
630        # Typedef
631        _h_setlevel(0)
632        my_name = _t(name)
633        _h('')
634        _h('typedef %s %s;', _t(self.name), my_name)
635
636        # Iterator
637        _c_iterator(self, name)
638
639def _c_complex(self):
640    '''
641    Helper function for handling all structure types.
642    Called for all structs, requests, replies, events, errors.
643    '''
644    _h_setlevel(0)
645    _h('')
646    _h('/**')
647    _h(' * @brief %s', self.c_type)
648    _h(' **/')
649    _h('typedef %s %s {', self.c_container, self.c_type)
650
651    struct_fields = []
652    maxtypelen = 0
653
654    varfield = None
655    for field in self.fields:
656        if not field.type.fixed_size():
657            varfield = field.c_field_name
658            continue
659        if varfield != None and not field.type.is_pad and field.wire:
660            errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name)
661            sys.stderr.write(errmsg)
662            # sys.exit(1)
663        if field.wire:
664            struct_fields.append(field)
665
666    for field in struct_fields:
667        if len(field.c_field_type) > maxtypelen:
668            maxtypelen = len(field.c_field_type)
669
670    for field in struct_fields:
671        spacing = ' ' * (maxtypelen - len(field.c_field_type))
672        _h('    %s%s %s%s; /**<  */', field.c_field_type, spacing, field.c_field_name, field.c_subscript)
673
674    _h('} %s;', self.c_type)
675
676def c_struct(self, name):
677    '''
678    Exported function that handles structure declarations.
679    '''
680    _c_type_setup(self, name, ())
681    _c_complex(self)
682    _c_accessors(self, name, name)
683    _c_iterator(self, name)
684
685def c_union(self, name):
686    '''
687    Exported function that handles union declarations.
688    '''
689    _c_type_setup(self, name, ())
690    _c_complex(self)
691    _c_iterator(self, name)
692
693def _c_request_helper(self, name, cookie_type, void, regular):
694    '''
695    Declares a request function.
696    '''
697
698    # Four stunningly confusing possibilities here:
699    #
700    #   Void            Non-void
701    # ------------------------------
702    # "req"            "req"
703    # 0 flag           CHECKED flag   Normal Mode
704    # void_cookie      req_cookie
705    # ------------------------------
706    # "req_checked"    "req_unchecked"
707    # CHECKED flag     0 flag         Abnormal Mode
708    # void_cookie      req_cookie
709    # ------------------------------
710
711
712    # Whether we are _checked or _unchecked
713    checked = void and not regular
714    unchecked = not void and not regular
715
716    # What kind of cookie we return
717    func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type
718
719    # What flag is passed to xcb_request
720    func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
721
722    # Global extension id variable or NULL for xproto
723    func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
724
725    # What our function name is
726    func_name = self.c_request_name
727    if checked:
728        func_name = self.c_checked_name
729    if unchecked:
730        func_name = self.c_unchecked_name
731
732    param_fields = []
733    wire_fields = []
734    maxtypelen = len('xcb_connection_t')
735
736    for field in self.fields:
737        if field.visible:
738            # The field should appear as a call parameter
739            param_fields.append(field)
740        if field.wire and not field.auto:
741            # We need to set the field up in the structure
742            wire_fields.append(field)
743
744    for field in param_fields:
745        if len(field.c_field_const_type) > maxtypelen:
746            maxtypelen = len(field.c_field_const_type)
747
748    _h_setlevel(1)
749    _c_setlevel(1)
750    _h('')
751    _h('/**')
752    _h(' * Delivers a request to the X server')
753    _h(' * @param c The connection')
754    _h(' * @return A cookie')
755    _h(' *')
756    _h(' * Delivers a request to the X server.')
757    _h(' * ')
758    if checked:
759        _h(' * This form can be used only if the request will not cause')
760        _h(' * a reply to be generated. Any returned error will be')
761        _h(' * saved for handling by xcb_request_check().')
762    if unchecked:
763        _h(' * This form can be used only if the request will cause')
764        _h(' * a reply to be generated. Any returned error will be')
765        _h(' * placed in the event queue.')
766    _h(' */')
767    _c('')
768    _hc('')
769    _hc('/*****************************************************************************')
770    _hc(' **')
771    _hc(' ** %s %s', cookie_type, func_name)
772    _hc(' ** ')
773
774    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
775    _hc(' ** @param xcb_connection_t%s *c', spacing)
776
777    for field in param_fields:
778        spacing = ' ' * (maxtypelen - len(field.c_field_const_type))
779        _hc(' ** @param %s%s %s%s', field.c_field_const_type, spacing, field.c_pointer, field.c_field_name)
780
781    _hc(' ** @returns %s', cookie_type)
782    _hc(' **')
783    _hc(' *****************************************************************************/')
784    _hc(' ')
785    _hc('%s', cookie_type)
786
787    spacing = ' ' * (maxtypelen - len('xcb_connection_t'))
788    comma = ',' if len(param_fields) else ');'
789    _h('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
790    comma = ',' if len(param_fields) else ')'
791    _c('%s (xcb_connection_t%s *c  /**< */%s', func_name, spacing, comma)
792
793    func_spacing = ' ' * (len(func_name) + 2)
794    count = len(param_fields)
795    for field in param_fields:
796        count = count - 1
797        spacing = ' ' * (maxtypelen - len(field.c_field_const_type))
798        comma = ',' if count else ');'
799        _h('%s%s%s %s%s  /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma)
800        comma = ',' if count else ')'
801        _c('%s%s%s %s%s  /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma)
802
803    count = 2
804    for field in param_fields:
805        if not field.type.fixed_size():
806            count = count + 2
807
808    _c('{')
809    _c('    static const xcb_protocol_request_t xcb_req = {')
810    _c('        /* count */ %d,', count)
811    _c('        /* ext */ %s,', func_ext_global)
812    _c('        /* opcode */ %s,', self.c_request_name.upper())
813    _c('        /* isvoid */ %d', 1 if void else 0)
814    _c('    };')
815    _c('    ')
816    _c('    struct iovec xcb_parts[%d];', count + 2)
817    _c('    %s xcb_ret;', func_cookie)
818    _c('    %s xcb_out;', self.c_type)
819    _c('    ')
820
821    for field in wire_fields:
822        if field.type.fixed_size():
823            if field.type.is_expr:
824                _c('    xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr))
825
826            elif field.type.is_pad:
827                if field.type.nmemb == 1:
828                    _c('    xcb_out.%s = 0;', field.c_field_name)
829                else:
830                    _c('    memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb)
831            else:
832                if field.type.nmemb == 1:
833                    _c('    xcb_out.%s = %s;', field.c_field_name, field.c_field_name)
834                else:
835                    _c('    memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb)
836
837    _c('    ')
838    _c('    xcb_parts[2].iov_base = (char *) &xcb_out;')
839    _c('    xcb_parts[2].iov_len = sizeof(xcb_out);')
840    _c('    xcb_parts[3].iov_base = 0;')
841    _c('    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;')
842
843    count = 4
844    for field in param_fields:
845        if not field.type.fixed_size():
846            _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
847            if field.type.is_list:
848                _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype)
849            else:
850                _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 'Uh oh', field.type.c_wiretype)
851            _c('    xcb_parts[%d].iov_base = 0;', count + 1)
852            _c('    xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count + 1, count)
853            count = count + 2
854
855    _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
856    _c('    return xcb_ret;')
857    _c('}')
858
859def _c_reply(self, name):
860    '''
861    Declares the function that returns the reply structure.
862    '''
863    spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t'))
864    spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t'))
865    spacing3 = ' ' * (len(self.c_reply_name) + 2)
866
867    _h('')
868    _h('/**')
869    _h(' * Return the reply')
870    _h(' * @param c      The connection')
871    _h(' * @param cookie The cookie')
872    _h(' * @param e      The xcb_generic_error_t supplied')
873    _h(' *')
874    _h(' * Returns the reply of the request asked by')
875    _h(' * ')
876    _h(' * The parameter @p e supplied to this function must be NULL if')
877    _h(' * %s(). is used.', self.c_unchecked_name)
878    _h(' * Otherwise, it stores the error if any.')
879    _h(' *')
880    _h(' * The returned value must be freed by the caller using free().')
881    _h(' */')
882    _c('')
883    _hc('')
884    _hc('/*****************************************************************************')
885    _hc(' **')
886    _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name)
887    _hc(' ** ')
888    _hc(' ** @param xcb_connection_t%s  *c', spacing1)
889    _hc(' ** @param %s   cookie', self.c_cookie_type)
890    _hc(' ** @param xcb_generic_error_t%s **e', spacing2)
891    _hc(' ** @returns %s *', self.c_reply_type)
892    _hc(' **')
893    _hc(' *****************************************************************************/')
894    _hc(' ')
895    _hc('%s *', self.c_reply_type)
896    _hc('%s (xcb_connection_t%s  *c  /**< */,', self.c_reply_name, spacing1)
897    _hc('%s%s   cookie  /**< */,', spacing3, self.c_cookie_type)
898    _h('%sxcb_generic_error_t%s **e  /**< */);', spacing3, spacing2)
899    _c('%sxcb_generic_error_t%s **e  /**< */)', spacing3, spacing2)
900    _c('{')
901    _c('    return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type)
902    _c('}')
903
904def _c_opcode(name, opcode):
905    '''
906    Declares the opcode define for requests, events, and errors.
907    '''
908    _h_setlevel(0)
909    _h('')
910    _h('/** Opcode for %s. */', _n(name))
911    _h('#define %s %s', _n(name).upper(), opcode)
912
913def _c_cookie(self, name):
914    '''
915    Declares the cookie type for a non-void request.
916    '''
917    _h_setlevel(0)
918    _h('')
919    _h('/**')
920    _h(' * @brief %s', self.c_cookie_type)
921    _h(' **/')
922    _h('typedef struct %s {', self.c_cookie_type)
923    _h('    unsigned int sequence; /**<  */')
924    _h('} %s;', self.c_cookie_type)
925
926def c_request(self, name):
927    '''
928    Exported function that handles request declarations.
929    '''
930    _c_type_setup(self, name, ('request',))
931
932    if self.reply:
933        # Cookie type declaration
934        _c_cookie(self, name)
935
936    # Opcode define
937    _c_opcode(name, self.opcode)
938
939    # Request structure declaration
940    _c_complex(self)
941
942    if self.reply:
943        _c_type_setup(self.reply, name, ('reply',))
944        # Reply structure definition
945        _c_complex(self.reply)
946        # Request prototypes
947        _c_request_helper(self, name, self.c_cookie_type, False, True)
948        _c_request_helper(self, name, self.c_cookie_type, False, False)
949        # Reply accessors
950        _c_accessors(self.reply, name + ('reply',), name)
951        _c_reply(self, name)
952    else:
953        # Request prototypes
954        _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
955        _c_request_helper(self, name, 'xcb_void_cookie_t', True, True)
956
957def c_event(self, name):
958    '''
959    Exported function that handles event declarations.
960    '''
961    _c_type_setup(self, name, ('event',))
962
963    # Opcode define
964    _c_opcode(name, self.opcodes[name])
965
966    if self.name == name:
967        # Structure definition
968        _c_complex(self)
969    else:
970        # Typedef
971        _h('')
972        _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
973
974def c_error(self, name):
975    '''
976    Exported function that handles error declarations.
977    '''
978    _c_type_setup(self, name, ('error',))
979
980    # Opcode define
981    _c_opcode(name, self.opcodes[name])
982
983    if self.name == name:
984        # Structure definition
985        _c_complex(self)
986    else:
987        # Typedef
988        _h('')
989        _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',)))
990
991
992# Main routine starts here
993
994# Must create an "output" dictionary before any xcbgen imports.
995output = {'open'    : c_open,
996          'close'   : c_close,
997          'simple'  : c_simple,
998          'enum'    : c_enum,
999          'struct'  : c_struct,
1000          'union'   : c_union,
1001          'request' : c_request,
1002          'event'   : c_event,
1003          'error'   : c_error
1004          }
1005
1006# Boilerplate below this point
1007
1008# Check for the argument that specifies path to the xcbgen python package.
1009try:
1010    opts, args = getopt.getopt(sys.argv[1:], 'p:')
1011except getopt.GetoptError, err:
1012    print str(err)
1013    print 'Usage: c_client.py [-p path] file.xml'
1014    sys.exit(1)
1015
1016for (opt, arg) in opts:
1017    if opt == '-p':
1018        sys.path.append(arg)
1019
1020# Import the module class
1021try:
1022    from xcbgen.state import Module
1023except ImportError:
1024    print ''
1025    print 'Failed to load the xcbgen Python package!'
1026    print 'Make sure that xcb/proto installed it on your Python path.'
1027    print 'If not, you will need to create a .pth file or define $PYTHONPATH'
1028    print 'to extend the path.'
1029    print 'Refer to the README file in xcb/proto for more info.'
1030    print ''
1031    raise
1032
1033# Parse the xml header
1034module = Module(args[0], output)
1035
1036# Build type-registry and resolve type dependencies
1037module.register()
1038module.resolve()
1039
1040# Output the code
1041module.generate()
1042