c_client.py revision b20a2039
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 == '~': 452 return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix) + ')' 453 elif expr.op != None: 454 return '(' + _c_accessor_get_expr(expr.lhs, prefix) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix) + ')' 455 elif expr.bitfield: 456 return 'xcb_popcount(' + lenexp + ')' 457 else: 458 return lenexp 459 460def _c_accessors_field(self, field): 461 ''' 462 Declares the accessor functions for a non-list field that follows a variable-length field. 463 ''' 464 if field.type.is_simple: 465 _hc('') 466 _hc('') 467 _hc('/*****************************************************************************') 468 _hc(' **') 469 _hc(' ** %s %s', field.c_field_type, field.c_accessor_name) 470 _hc(' ** ') 471 _hc(' ** @param const %s *R', self.c_type) 472 _hc(' ** @returns %s', field.c_field_type) 473 _hc(' **') 474 _hc(' *****************************************************************************/') 475 _hc(' ') 476 _hc('%s', field.c_field_type) 477 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) 478 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) 479 _c('{') 480 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 481 _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) 482 _c('}') 483 else: 484 _hc('') 485 _hc('') 486 _hc('/*****************************************************************************') 487 _hc(' **') 488 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name) 489 _hc(' ** ') 490 _hc(' ** @param const %s *R', self.c_type) 491 _hc(' ** @returns %s *', field.c_field_type) 492 _hc(' **') 493 _hc(' *****************************************************************************/') 494 _hc(' ') 495 _hc('%s *', field.c_field_type) 496 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) 497 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) 498 _c('{') 499 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 500 _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) 501 _c('}') 502 503def _c_accessors_list(self, field): 504 ''' 505 Declares the accessor functions for a list field. 506 Declares a direct-accessor function only if the list members are fixed size. 507 Declares length and get-iterator functions always. 508 ''' 509 list = field.type 510 511 _h_setlevel(1) 512 _c_setlevel(1) 513 if list.member.fixed_size(): 514 _hc('') 515 _hc('') 516 _hc('/*****************************************************************************') 517 _hc(' **') 518 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name) 519 _hc(' ** ') 520 _hc(' ** @param const %s *R', self.c_type) 521 _hc(' ** @returns %s *', field.c_field_type) 522 _hc(' **') 523 _hc(' *****************************************************************************/') 524 _hc(' ') 525 _hc('%s *', field.c_field_type) 526 _h('%s (const %s *R /**< */);', field.c_accessor_name, self.c_type) 527 _c('%s (const %s *R /**< */)', field.c_accessor_name, self.c_type) 528 _c('{') 529 530 if field.prev_varsized_field == None: 531 _c(' return (%s *) (R + 1);', field.c_field_type) 532 else: 533 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 534 _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) 535 536 _c('}') 537 538 _hc('') 539 _hc('') 540 _hc('/*****************************************************************************') 541 _hc(' **') 542 _hc(' ** int %s', field.c_length_name) 543 _hc(' ** ') 544 _hc(' ** @param const %s *R', self.c_type) 545 _hc(' ** @returns int') 546 _hc(' **') 547 _hc(' *****************************************************************************/') 548 _hc(' ') 549 _hc('int') 550 _h('%s (const %s *R /**< */);', field.c_length_name, self.c_type) 551 _c('%s (const %s *R /**< */)', field.c_length_name, self.c_type) 552 _c('{') 553 _c(' return %s;', _c_accessor_get_expr(field.type.expr, 'R')) 554 _c('}') 555 556 if field.type.member.is_simple: 557 _hc('') 558 _hc('') 559 _hc('/*****************************************************************************') 560 _hc(' **') 561 _hc(' ** xcb_generic_iterator_t %s', field.c_end_name) 562 _hc(' ** ') 563 _hc(' ** @param const %s *R', self.c_type) 564 _hc(' ** @returns xcb_generic_iterator_t') 565 _hc(' **') 566 _hc(' *****************************************************************************/') 567 _hc(' ') 568 _hc('xcb_generic_iterator_t') 569 _h('%s (const %s *R /**< */);', field.c_end_name, self.c_type) 570 _c('%s (const %s *R /**< */)', field.c_end_name, self.c_type) 571 _c('{') 572 _c(' xcb_generic_iterator_t i;') 573 574 if field.prev_varsized_field == None: 575 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R')) 576 else: 577 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 578 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, _c_accessor_get_expr(field.type.expr, 'R')) 579 580 _c(' i.rem = 0;') 581 _c(' i.index = (char *) i.data - (char *) R;') 582 _c(' return i;') 583 _c('}') 584 585 else: 586 _hc('') 587 _hc('') 588 _hc('/*****************************************************************************') 589 _hc(' **') 590 _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name) 591 _hc(' ** ') 592 _hc(' ** @param const %s *R', self.c_type) 593 _hc(' ** @returns %s', field.c_iterator_type) 594 _hc(' **') 595 _hc(' *****************************************************************************/') 596 _hc(' ') 597 _hc('%s', field.c_iterator_type) 598 _h('%s (const %s *R /**< */);', field.c_iterator_name, self.c_type) 599 _c('%s (const %s *R /**< */)', field.c_iterator_name, self.c_type) 600 _c('{') 601 _c(' %s i;', field.c_iterator_type) 602 603 if field.prev_varsized_field == None: 604 _c(' i.data = (%s *) (R + 1);', field.c_field_type) 605 else: 606 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 607 _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', field.c_field_type, field.c_field_type) 608 609 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, 'R')) 610 _c(' i.index = (char *) i.data - (char *) R;') 611 _c(' return i;') 612 _c('}') 613 614def _c_accessors(self, name, base): 615 ''' 616 Declares the accessor functions for the fields of a structure. 617 ''' 618 for field in self.fields: 619 if field.type.is_list and not field.type.fixed_size(): 620 _c_accessors_list(self, field) 621 elif field.prev_varsized_field != None: 622 _c_accessors_field(self, field) 623 624def c_simple(self, name): 625 ''' 626 Exported function that handles cardinal type declarations. 627 These are types which are typedef'd to one of the CARDx's, char, float, etc. 628 ''' 629 _c_type_setup(self, name, ()) 630 631 if (self.name != name): 632 # Typedef 633 _h_setlevel(0) 634 my_name = _t(name) 635 _h('') 636 _h('typedef %s %s;', _t(self.name), my_name) 637 638 # Iterator 639 _c_iterator(self, name) 640 641def _c_complex(self): 642 ''' 643 Helper function for handling all structure types. 644 Called for all structs, requests, replies, events, errors. 645 ''' 646 _h_setlevel(0) 647 _h('') 648 _h('/**') 649 _h(' * @brief %s', self.c_type) 650 _h(' **/') 651 _h('typedef %s %s {', self.c_container, self.c_type) 652 653 struct_fields = [] 654 maxtypelen = 0 655 656 varfield = None 657 for field in self.fields: 658 if not field.type.fixed_size(): 659 varfield = field.c_field_name 660 continue 661 if varfield != None and not field.type.is_pad and field.wire: 662 errmsg = '%s: warning: variable field %s followed by fixed field %s\n' % (self.c_type, varfield, field.c_field_name) 663 sys.stderr.write(errmsg) 664 # sys.exit(1) 665 if field.wire: 666 struct_fields.append(field) 667 668 for field in struct_fields: 669 if len(field.c_field_type) > maxtypelen: 670 maxtypelen = len(field.c_field_type) 671 672 for field in struct_fields: 673 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 674 _h(' %s%s %s%s; /**< */', field.c_field_type, spacing, field.c_field_name, field.c_subscript) 675 676 _h('} %s;', self.c_type) 677 678def c_struct(self, name): 679 ''' 680 Exported function that handles structure declarations. 681 ''' 682 _c_type_setup(self, name, ()) 683 _c_complex(self) 684 _c_accessors(self, name, name) 685 _c_iterator(self, name) 686 687def c_union(self, name): 688 ''' 689 Exported function that handles union declarations. 690 ''' 691 _c_type_setup(self, name, ()) 692 _c_complex(self) 693 _c_iterator(self, name) 694 695def _c_request_helper(self, name, cookie_type, void, regular): 696 ''' 697 Declares a request function. 698 ''' 699 700 # Four stunningly confusing possibilities here: 701 # 702 # Void Non-void 703 # ------------------------------ 704 # "req" "req" 705 # 0 flag CHECKED flag Normal Mode 706 # void_cookie req_cookie 707 # ------------------------------ 708 # "req_checked" "req_unchecked" 709 # CHECKED flag 0 flag Abnormal Mode 710 # void_cookie req_cookie 711 # ------------------------------ 712 713 714 # Whether we are _checked or _unchecked 715 checked = void and not regular 716 unchecked = not void and not regular 717 718 # What kind of cookie we return 719 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type 720 721 # What flag is passed to xcb_request 722 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED' 723 724 # Global extension id variable or NULL for xproto 725 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0' 726 727 # What our function name is 728 func_name = self.c_request_name 729 if checked: 730 func_name = self.c_checked_name 731 if unchecked: 732 func_name = self.c_unchecked_name 733 734 param_fields = [] 735 wire_fields = [] 736 maxtypelen = len('xcb_connection_t') 737 738 for field in self.fields: 739 if field.visible: 740 # The field should appear as a call parameter 741 param_fields.append(field) 742 if field.wire and not field.auto: 743 # We need to set the field up in the structure 744 wire_fields.append(field) 745 746 for field in param_fields: 747 if len(field.c_field_const_type) > maxtypelen: 748 maxtypelen = len(field.c_field_const_type) 749 750 _h_setlevel(1) 751 _c_setlevel(1) 752 _h('') 753 _h('/**') 754 _h(' * Delivers a request to the X server') 755 _h(' * @param c The connection') 756 _h(' * @return A cookie') 757 _h(' *') 758 _h(' * Delivers a request to the X server.') 759 _h(' * ') 760 if checked: 761 _h(' * This form can be used only if the request will not cause') 762 _h(' * a reply to be generated. Any returned error will be') 763 _h(' * saved for handling by xcb_request_check().') 764 if unchecked: 765 _h(' * This form can be used only if the request will cause') 766 _h(' * a reply to be generated. Any returned error will be') 767 _h(' * placed in the event queue.') 768 _h(' */') 769 _c('') 770 _hc('') 771 _hc('/*****************************************************************************') 772 _hc(' **') 773 _hc(' ** %s %s', cookie_type, func_name) 774 _hc(' ** ') 775 776 spacing = ' ' * (maxtypelen - len('xcb_connection_t')) 777 _hc(' ** @param xcb_connection_t%s *c', spacing) 778 779 for field in param_fields: 780 spacing = ' ' * (maxtypelen - len(field.c_field_const_type)) 781 _hc(' ** @param %s%s %s%s', field.c_field_const_type, spacing, field.c_pointer, field.c_field_name) 782 783 _hc(' ** @returns %s', cookie_type) 784 _hc(' **') 785 _hc(' *****************************************************************************/') 786 _hc(' ') 787 _hc('%s', cookie_type) 788 789 spacing = ' ' * (maxtypelen - len('xcb_connection_t')) 790 comma = ',' if len(param_fields) else ');' 791 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 792 comma = ',' if len(param_fields) else ')' 793 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 794 795 func_spacing = ' ' * (len(func_name) + 2) 796 count = len(param_fields) 797 for field in param_fields: 798 count = count - 1 799 spacing = ' ' * (maxtypelen - len(field.c_field_const_type)) 800 comma = ',' if count else ');' 801 _h('%s%s%s %s%s /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma) 802 comma = ',' if count else ')' 803 _c('%s%s%s %s%s /**< */%s', func_spacing, field.c_field_const_type, spacing, field.c_pointer, field.c_field_name, comma) 804 805 count = 2 806 for field in param_fields: 807 if not field.type.fixed_size(): 808 count = count + 2 809 810 _c('{') 811 _c(' static const xcb_protocol_request_t xcb_req = {') 812 _c(' /* count */ %d,', count) 813 _c(' /* ext */ %s,', func_ext_global) 814 _c(' /* opcode */ %s,', self.c_request_name.upper()) 815 _c(' /* isvoid */ %d', 1 if void else 0) 816 _c(' };') 817 _c(' ') 818 _c(' struct iovec xcb_parts[%d];', count + 2) 819 _c(' %s xcb_ret;', func_cookie) 820 _c(' %s xcb_out;', self.c_type) 821 _c(' ') 822 823 for field in wire_fields: 824 if field.type.fixed_size(): 825 if field.type.is_expr: 826 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr)) 827 828 elif field.type.is_pad: 829 if field.type.nmemb == 1: 830 _c(' xcb_out.%s = 0;', field.c_field_name) 831 else: 832 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) 833 else: 834 if field.type.nmemb == 1: 835 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) 836 else: 837 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) 838 839 _c(' ') 840 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;') 841 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);') 842 _c(' xcb_parts[3].iov_base = 0;') 843 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') 844 845 count = 4 846 for field in param_fields: 847 if not field.type.fixed_size(): 848 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) 849 if field.type.is_list: 850 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, _c_accessor_get_expr(field.type.expr), field.type.member.c_wiretype) 851 else: 852 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 'Uh oh', field.type.c_wiretype) 853 _c(' xcb_parts[%d].iov_base = 0;', count + 1) 854 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count + 1, count) 855 count = count + 2 856 857 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) 858 _c(' return xcb_ret;') 859 _c('}') 860 861def _c_reply(self, name): 862 ''' 863 Declares the function that returns the reply structure. 864 ''' 865 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t')) 866 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t')) 867 spacing3 = ' ' * (len(self.c_reply_name) + 2) 868 869 _h('') 870 _h('/**') 871 _h(' * Return the reply') 872 _h(' * @param c The connection') 873 _h(' * @param cookie The cookie') 874 _h(' * @param e The xcb_generic_error_t supplied') 875 _h(' *') 876 _h(' * Returns the reply of the request asked by') 877 _h(' * ') 878 _h(' * The parameter @p e supplied to this function must be NULL if') 879 _h(' * %s(). is used.', self.c_unchecked_name) 880 _h(' * Otherwise, it stores the error if any.') 881 _h(' *') 882 _h(' * The returned value must be freed by the caller using free().') 883 _h(' */') 884 _c('') 885 _hc('') 886 _hc('/*****************************************************************************') 887 _hc(' **') 888 _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name) 889 _hc(' ** ') 890 _hc(' ** @param xcb_connection_t%s *c', spacing1) 891 _hc(' ** @param %s cookie', self.c_cookie_type) 892 _hc(' ** @param xcb_generic_error_t%s **e', spacing2) 893 _hc(' ** @returns %s *', self.c_reply_type) 894 _hc(' **') 895 _hc(' *****************************************************************************/') 896 _hc(' ') 897 _hc('%s *', self.c_reply_type) 898 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1) 899 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type) 900 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2) 901 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2) 902 _c('{') 903 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type) 904 _c('}') 905 906def _c_opcode(name, opcode): 907 ''' 908 Declares the opcode define for requests, events, and errors. 909 ''' 910 _h_setlevel(0) 911 _h('') 912 _h('/** Opcode for %s. */', _n(name)) 913 _h('#define %s %s', _n(name).upper(), opcode) 914 915def _c_cookie(self, name): 916 ''' 917 Declares the cookie type for a non-void request. 918 ''' 919 _h_setlevel(0) 920 _h('') 921 _h('/**') 922 _h(' * @brief %s', self.c_cookie_type) 923 _h(' **/') 924 _h('typedef struct %s {', self.c_cookie_type) 925 _h(' unsigned int sequence; /**< */') 926 _h('} %s;', self.c_cookie_type) 927 928def c_request(self, name): 929 ''' 930 Exported function that handles request declarations. 931 ''' 932 _c_type_setup(self, name, ('request',)) 933 934 if self.reply: 935 # Cookie type declaration 936 _c_cookie(self, name) 937 938 # Opcode define 939 _c_opcode(name, self.opcode) 940 941 # Request structure declaration 942 _c_complex(self) 943 944 if self.reply: 945 _c_type_setup(self.reply, name, ('reply',)) 946 # Reply structure definition 947 _c_complex(self.reply) 948 # Request prototypes 949 _c_request_helper(self, name, self.c_cookie_type, False, True) 950 _c_request_helper(self, name, self.c_cookie_type, False, False) 951 # Reply accessors 952 _c_accessors(self.reply, name + ('reply',), name) 953 _c_reply(self, name) 954 else: 955 # Request prototypes 956 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False) 957 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True) 958 959def c_event(self, name): 960 ''' 961 Exported function that handles event declarations. 962 ''' 963 _c_type_setup(self, name, ('event',)) 964 965 # Opcode define 966 _c_opcode(name, self.opcodes[name]) 967 968 if self.name == name: 969 # Structure definition 970 _c_complex(self) 971 else: 972 # Typedef 973 _h('') 974 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',))) 975 976def c_error(self, name): 977 ''' 978 Exported function that handles error declarations. 979 ''' 980 _c_type_setup(self, name, ('error',)) 981 982 # Opcode define 983 _c_opcode(name, self.opcodes[name]) 984 985 if self.name == name: 986 # Structure definition 987 _c_complex(self) 988 else: 989 # Typedef 990 _h('') 991 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',))) 992 993 994# Main routine starts here 995 996# Must create an "output" dictionary before any xcbgen imports. 997output = {'open' : c_open, 998 'close' : c_close, 999 'simple' : c_simple, 1000 'enum' : c_enum, 1001 'struct' : c_struct, 1002 'union' : c_union, 1003 'request' : c_request, 1004 'event' : c_event, 1005 'error' : c_error 1006 } 1007 1008# Boilerplate below this point 1009 1010# Check for the argument that specifies path to the xcbgen python package. 1011try: 1012 opts, args = getopt.getopt(sys.argv[1:], 'p:') 1013except getopt.GetoptError, err: 1014 print str(err) 1015 print 'Usage: c_client.py [-p path] file.xml' 1016 sys.exit(1) 1017 1018for (opt, arg) in opts: 1019 if opt == '-p': 1020 sys.path.append(arg) 1021 1022# Import the module class 1023try: 1024 from xcbgen.state import Module 1025except ImportError: 1026 print '' 1027 print 'Failed to load the xcbgen Python package!' 1028 print 'Make sure that xcb/proto installed it on your Python path.' 1029 print 'If not, you will need to create a .pth file or define $PYTHONPATH' 1030 print 'to extend the path.' 1031 print 'Refer to the README file in xcb/proto for more info.' 1032 print '' 1033 raise 1034 1035# Parse the xml header 1036module = Module(args[0], output) 1037 1038# Build type-registry and resolve type dependencies 1039module.register() 1040module.resolve() 1041 1042# Output the code 1043module.generate() 1044