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