c_client.py revision 1016ad83
1#!/usr/bin/env python 2from xml.etree.cElementTree import * 3from os.path import basename 4from functools import reduce 5import getopt 6import os 7import sys 8import errno 9import time 10import re 11 12# Jump to the bottom of this file for the main routine 13 14# Some hacks to make the API more readable, and to keep backwards compability 15_cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)') 16_cname_special_cases = {'DECnet':'decnet'} 17 18_extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests'] 19 20_cplusplus_annoyances = {'class' : '_class', 21 'new' : '_new', 22 'delete': '_delete'} 23_c_keywords = {'default' : '_default'} 24 25_hlines = [] 26_hlevel = 0 27_clines = [] 28_clevel = 0 29_ns = None 30 31# global variable to keep track of serializers and 32# switch data types due to weird dependencies 33finished_serializers = [] 34finished_sizeof = [] 35finished_switch = [] 36 37# keeps enum objects so that we can refer to them when generating manpages. 38enums = {} 39 40manpaths = False 41 42def _h(fmt, *args): 43 ''' 44 Writes the given line to the header file. 45 ''' 46 _hlines[_hlevel].append(fmt % args) 47 48def _c(fmt, *args): 49 ''' 50 Writes the given line to the source file. 51 ''' 52 _clines[_clevel].append(fmt % args) 53 54def _hc(fmt, *args): 55 ''' 56 Writes the given line to both the header and source files. 57 ''' 58 _h(fmt, *args) 59 _c(fmt, *args) 60 61# XXX See if this level thing is really necessary. 62def _h_setlevel(idx): 63 ''' 64 Changes the array that header lines are written to. 65 Supports writing different sections of the header file. 66 ''' 67 global _hlevel 68 while len(_hlines) <= idx: 69 _hlines.append([]) 70 _hlevel = idx 71 72def _c_setlevel(idx): 73 ''' 74 Changes the array that source lines are written to. 75 Supports writing to different sections of the source file. 76 ''' 77 global _clevel 78 while len(_clines) <= idx: 79 _clines.append([]) 80 _clevel = idx 81 82def _n_item(str): 83 ''' 84 Does C-name conversion on a single string fragment. 85 Uses a regexp with some hard-coded special cases. 86 ''' 87 if str in _cname_special_cases: 88 return _cname_special_cases[str] 89 else: 90 split = _cname_re.finditer(str) 91 name_parts = [match.group(0) for match in split] 92 return '_'.join(name_parts) 93 94def _cpp(str): 95 ''' 96 Checks for certain C++ reserved words and fixes them. 97 ''' 98 if str in _cplusplus_annoyances: 99 return _cplusplus_annoyances[str] 100 elif str in _c_keywords: 101 return _c_keywords[str] 102 else: 103 return str 104 105def _ext(str): 106 ''' 107 Does C-name conversion on an extension name. 108 Has some additional special cases on top of _n_item. 109 ''' 110 if str in _extension_special_cases: 111 return _n_item(str).lower() 112 else: 113 return str.lower() 114 115def _n(list): 116 ''' 117 Does C-name conversion on a tuple of strings. 118 Different behavior depending on length of tuple, extension/not extension, etc. 119 Basically C-name converts the individual pieces, then joins with underscores. 120 ''' 121 if len(list) == 1: 122 parts = list 123 elif len(list) == 2: 124 parts = [list[0], _n_item(list[1])] 125 elif _ns.is_ext: 126 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] 127 else: 128 parts = [list[0]] + [_n_item(i) for i in list[1:]] 129 return '_'.join(parts).lower() 130 131def _t(list): 132 ''' 133 Does C-name conversion on a tuple of strings representing a type. 134 Same as _n but adds a "_t" on the end. 135 ''' 136 if len(list) == 1: 137 parts = list 138 elif len(list) == 2: 139 parts = [list[0], _n_item(list[1]), 't'] 140 elif _ns.is_ext: 141 parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] + ['t'] 142 else: 143 parts = [list[0]] + [_n_item(i) for i in list[1:]] + ['t'] 144 return '_'.join(parts).lower() 145 146 147def c_open(self): 148 ''' 149 Exported function that handles module open. 150 Opens the files and writes out the auto-generated comment, header file includes, etc. 151 ''' 152 global _ns 153 _ns = self.namespace 154 _ns.c_ext_global_name = _n(_ns.prefix + ('id',)) 155 156 # Build the type-name collision avoidance table used by c_enum 157 build_collision_table() 158 159 _h_setlevel(0) 160 _c_setlevel(0) 161 162 _hc('/*') 163 _hc(' * This file generated automatically from %s by c_client.py.', _ns.file) 164 _hc(' * Edit at your peril.') 165 _hc(' */') 166 _hc('') 167 168 _h('/**') 169 _h(' * @defgroup XCB_%s_API XCB %s API', _ns.ext_name, _ns.ext_name) 170 _h(' * @brief %s XCB Protocol Implementation.', _ns.ext_name) 171 _h(' * @{') 172 _h(' **/') 173 _h('') 174 _h('#ifndef __%s_H', _ns.header.upper()) 175 _h('#define __%s_H', _ns.header.upper()) 176 _h('') 177 _h('#include "xcb.h"') 178 179 _c('#ifdef HAVE_CONFIG_H') 180 _c('#include "config.h"') 181 _c('#endif') 182 _c('#include <stdlib.h>') 183 _c('#include <string.h>') 184 _c('#include <assert.h>') 185 _c('#include <stddef.h> /* for offsetof() */') 186 _c('#include "xcbext.h"') 187 _c('#include "%s.h"', _ns.header) 188 189 _c('') 190 _c('#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)') 191 192 if _ns.is_ext: 193 for (n, h) in self.imports: 194 _hc('#include "%s.h"', h) 195 196 _h('') 197 _h('#ifdef __cplusplus') 198 _h('extern "C" {') 199 _h('#endif') 200 201 if _ns.is_ext: 202 _h('') 203 _h('#define XCB_%s_MAJOR_VERSION %s', _ns.ext_name.upper(), _ns.major_version) 204 _h('#define XCB_%s_MINOR_VERSION %s', _ns.ext_name.upper(), _ns.minor_version) 205 _h(' ') #XXX 206 _h('extern xcb_extension_t %s;', _ns.c_ext_global_name) 207 208 _c('') 209 _c('xcb_extension_t %s = { "%s", 0 };', _ns.c_ext_global_name, _ns.ext_xname) 210 211def c_close(self): 212 ''' 213 Exported function that handles module close. 214 Writes out all the stored content lines, then closes the files. 215 ''' 216 _h_setlevel(2) 217 _c_setlevel(2) 218 _hc('') 219 220 _h('') 221 _h('#ifdef __cplusplus') 222 _h('}') 223 _h('#endif') 224 225 _h('') 226 _h('#endif') 227 _h('') 228 _h('/**') 229 _h(' * @}') 230 _h(' */') 231 232 # Write header file 233 hfile = open('%s.h' % _ns.header, 'w') 234 for list in _hlines: 235 for line in list: 236 hfile.write(line) 237 hfile.write('\n') 238 hfile.close() 239 240 # Write source file 241 cfile = open('%s.c' % _ns.header, 'w') 242 for list in _clines: 243 for line in list: 244 cfile.write(line) 245 cfile.write('\n') 246 cfile.close() 247 248def build_collision_table(): 249 global namecount 250 namecount = {} 251 252 for v in module.types.values(): 253 name = _t(v[0]) 254 namecount[name] = (namecount.get(name) or 0) + 1 255 256def c_enum(self, name): 257 ''' 258 Exported function that handles enum declarations. 259 ''' 260 261 enums[name] = self 262 263 tname = _t(name) 264 if namecount[tname] > 1: 265 tname = _t(name + ('enum',)) 266 267 _h_setlevel(0) 268 _h('') 269 _h('typedef enum %s {', tname) 270 271 count = len(self.values) 272 273 for (enam, eval) in self.values: 274 count = count - 1 275 equals = ' = ' if eval != '' else '' 276 comma = ',' if count > 0 else '' 277 doc = '' 278 if hasattr(self, "doc") and self.doc and enam in self.doc.fields: 279 doc = '\n/**< %s */\n' % self.doc.fields[enam] 280 _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc) 281 282 _h('} %s;', tname) 283 284def _c_type_setup(self, name, postfix): 285 ''' 286 Sets up all the C-related state by adding additional data fields to 287 all Field and Type objects. Here is where we figure out most of our 288 variable and function names. 289 290 Recurses into child fields and list member types. 291 ''' 292 # Do all the various names in advance 293 self.c_type = _t(name + postfix) 294 self.c_wiretype = 'char' if self.c_type == 'void' else self.c_type 295 296 self.c_iterator_type = _t(name + ('iterator',)) 297 self.c_next_name = _n(name + ('next',)) 298 self.c_end_name = _n(name + ('end',)) 299 300 self.c_request_name = _n(name) 301 self.c_checked_name = _n(name + ('checked',)) 302 self.c_unchecked_name = _n(name + ('unchecked',)) 303 self.c_reply_name = _n(name + ('reply',)) 304 self.c_reply_type = _t(name + ('reply',)) 305 self.c_cookie_type = _t(name + ('cookie',)) 306 self.c_reply_fds_name = _n(name + ('reply_fds',)) 307 308 self.need_aux = False 309 self.need_serialize = False 310 self.need_sizeof = False 311 312 self.c_aux_name = _n(name + ('aux',)) 313 self.c_aux_checked_name = _n(name + ('aux', 'checked')) 314 self.c_aux_unchecked_name = _n(name + ('aux', 'unchecked')) 315 self.c_serialize_name = _n(name + ('serialize',)) 316 self.c_unserialize_name = _n(name + ('unserialize',)) 317 self.c_unpack_name = _n(name + ('unpack',)) 318 self.c_sizeof_name = _n(name + ('sizeof',)) 319 320 # special case: structs where variable size fields are followed by fixed size fields 321 self.var_followed_by_fixed_fields = False 322 323 if self.is_switch: 324 self.need_serialize = True 325 self.c_container = 'struct' 326 for bitcase in self.bitcases: 327 bitcase.c_field_name = _cpp(bitcase.field_name) 328 bitcase_name = bitcase.field_type if bitcase.type.has_name else name 329 _c_type_setup(bitcase.type, bitcase_name, ()) 330 331 elif self.is_container: 332 333 self.c_container = 'union' if self.is_union else 'struct' 334 prev_varsized_field = None 335 prev_varsized_offset = 0 336 first_field_after_varsized = None 337 338 for field in self.fields: 339 _c_type_setup(field.type, field.field_type, ()) 340 if field.type.is_list: 341 _c_type_setup(field.type.member, field.field_type, ()) 342 if (field.type.nmemb is None): 343 self.need_sizeof = True 344 345 field.c_field_type = _t(field.field_type) 346 field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type 347 field.c_field_name = _cpp(field.field_name) 348 field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else '' 349 field.c_pointer = ' ' if field.type.nmemb == 1 else '*' 350 351 # correct the c_pointer field for variable size non-list types 352 if not field.type.fixed_size() and field.c_pointer == ' ': 353 field.c_pointer = '*' 354 if field.type.is_list and not field.type.member.fixed_size(): 355 field.c_pointer = '*' 356 357 if field.type.is_switch: 358 field.c_pointer = '*' 359 field.c_field_const_type = 'const ' + field.c_field_type 360 self.need_aux = True 361 elif not field.type.fixed_size() and not field.type.is_bitcase: 362 self.need_sizeof = True 363 364 field.c_iterator_type = _t(field.field_type + ('iterator',)) # xcb_fieldtype_iterator_t 365 field.c_iterator_name = _n(name + (field.field_name, 'iterator')) # xcb_container_field_iterator 366 field.c_accessor_name = _n(name + (field.field_name,)) # xcb_container_field 367 field.c_length_name = _n(name + (field.field_name, 'length')) # xcb_container_field_length 368 field.c_end_name = _n(name + (field.field_name, 'end')) # xcb_container_field_end 369 370 field.prev_varsized_field = prev_varsized_field 371 field.prev_varsized_offset = prev_varsized_offset 372 373 if prev_varsized_offset == 0: 374 first_field_after_varsized = field 375 field.first_field_after_varsized = first_field_after_varsized 376 377 if field.type.fixed_size(): 378 prev_varsized_offset += field.type.size 379 # special case: intermixed fixed and variable size fields 380 if prev_varsized_field is not None and not field.type.is_pad and field.wire: 381 if not self.is_union: 382 self.need_serialize = True 383 self.var_followed_by_fixed_fields = True 384 else: 385 self.last_varsized_field = field 386 prev_varsized_field = field 387 prev_varsized_offset = 0 388 389 if self.var_followed_by_fixed_fields: 390 if field.type.fixed_size(): 391 field.prev_varsized_field = None 392 393 if self.need_serialize: 394 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons 395 self.need_sizeof = True 396 397 # as switch does never appear at toplevel, 398 # continue here with type construction 399 if self.is_switch: 400 if self.c_type not in finished_switch: 401 finished_switch.append(self.c_type) 402 # special: switch C structs get pointer fields for variable-sized members 403 _c_complex(self) 404 for bitcase in self.bitcases: 405 bitcase_name = bitcase.type.name if bitcase.type.has_name else name 406 _c_accessors(bitcase.type, bitcase_name, bitcase_name) 407 # no list with switch as element, so no call to 408 # _c_iterator(field.type, field_name) necessary 409 410 if not self.is_bitcase: 411 if self.need_serialize: 412 if self.c_serialize_name not in finished_serializers: 413 finished_serializers.append(self.c_serialize_name) 414 _c_serialize('serialize', self) 415 416 # _unpack() and _unserialize() are only needed for special cases: 417 # switch -> unpack 418 # special cases -> unserialize 419 if self.is_switch or self.var_followed_by_fixed_fields: 420 _c_serialize('unserialize', self) 421 422 if self.need_sizeof: 423 if self.c_sizeof_name not in finished_sizeof: 424 if not module.namespace.is_ext or self.name[:2] == module.namespace.prefix: 425 finished_sizeof.append(self.c_sizeof_name) 426 _c_serialize('sizeof', self) 427# _c_type_setup() 428 429def _c_helper_absolute_name(prefix, field=None): 430 """ 431 turn prefix, which is a list of tuples (name, separator, Type obj) into a string 432 representing a valid name in C (based on the context) 433 if field is not None, append the field name as well 434 """ 435 prefix_str = '' 436 for name, sep, obj in prefix: 437 prefix_str += name 438 if '' == sep: 439 sep = '->' 440 if ((obj.is_bitcase and obj.has_name) or # named bitcase 441 (obj.is_switch and len(obj.parents)>1)): 442 sep = '.' 443 prefix_str += sep 444 if field is not None: 445 prefix_str += _cpp(field.field_name) 446 return prefix_str 447# _c_absolute_name 448 449def _c_helper_field_mapping(complex_type, prefix, flat=False): 450 """ 451 generate absolute names, based on prefix, for all fields starting from complex_type 452 if flat == True, nested complex types are not taken into account 453 """ 454 all_fields = {} 455 if complex_type.is_switch: 456 for b in complex_type.bitcases: 457 if b.type.has_name: 458 switch_name, switch_sep, switch_type = prefix[-1] 459 bitcase_prefix = prefix + [(b.type.name[-1], '.', b.type)] 460 else: 461 bitcase_prefix = prefix 462 463 if (True==flat and not b.type.has_name) or False==flat: 464 all_fields.update(_c_helper_field_mapping(b.type, bitcase_prefix, flat)) 465 else: 466 for f in complex_type.fields: 467 fname = _c_helper_absolute_name(prefix, f) 468 if f.field_name in all_fields: 469 raise Exception("field name %s has been registered before" % f.field_name) 470 471 all_fields[f.field_name] = (fname, f) 472 if f.type.is_container and flat==False: 473 if f.type.is_bitcase and not f.type.has_name: 474 new_prefix = prefix 475 elif f.type.is_switch and len(f.type.parents)>1: 476 # nested switch gets another separator 477 new_prefix = prefix+[(f.c_field_name, '.', f.type)] 478 else: 479 new_prefix = prefix+[(f.c_field_name, '->', f.type)] 480 all_fields.update(_c_helper_field_mapping(f.type, new_prefix, flat)) 481 482 return all_fields 483# _c_field_mapping() 484 485def _c_helper_resolve_field_names (prefix): 486 """ 487 get field names for all objects in the prefix array 488 """ 489 all_fields = {} 490 tmp_prefix = [] 491 # look for fields in the remaining containers 492 for idx, p in enumerate(prefix): 493 name, sep, obj = p 494 if ''==sep: 495 # sep can be preset in prefix, if not, make a sensible guess 496 sep = '.' if (obj.is_switch or obj.is_bitcase) else '->' 497 # exception: 'toplevel' object (switch as well!) always have sep '->' 498 sep = '->' if idx<1 else sep 499 if not obj.is_bitcase or (obj.is_bitcase and obj.has_name): 500 tmp_prefix.append((name, sep, obj)) 501 all_fields.update(_c_helper_field_mapping(obj, tmp_prefix, flat=True)) 502 503 return all_fields 504# _c_helper_resolve_field_names 505 506def get_expr_fields(self): 507 """ 508 get the Fields referenced by switch or list expression 509 """ 510 def get_expr_field_names(expr): 511 if expr.op is None: 512 if expr.lenfield_name is not None: 513 return [expr.lenfield_name] 514 else: 515 # constant value expr 516 return [] 517 else: 518 if expr.op == '~': 519 return get_expr_field_names(expr.rhs) 520 elif expr.op == 'popcount': 521 return get_expr_field_names(expr.rhs) 522 elif expr.op == 'sumof': 523 # sumof expr references another list, 524 # we need that list's length field here 525 field = None 526 for f in expr.lenfield_parent.fields: 527 if f.field_name == expr.lenfield_name: 528 field = f 529 break 530 if field is None: 531 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) 532 # referenced list + its length field 533 return [expr.lenfield_name] + get_expr_field_names(field.type.expr) 534 elif expr.op == 'enumref': 535 return [] 536 else: 537 return get_expr_field_names(expr.lhs) + get_expr_field_names(expr.rhs) 538 # get_expr_field_names() 539 540 # resolve the field names with the parent structure(s) 541 unresolved_fields_names = get_expr_field_names(self.expr) 542 543 # construct prefix from self 544 prefix = [('', '', p) for p in self.parents] 545 if self.is_container: 546 prefix.append(('', '', self)) 547 548 all_fields = _c_helper_resolve_field_names (prefix) 549 resolved_fields_names = list(filter(lambda x: x in all_fields.keys(), unresolved_fields_names)) 550 if len(unresolved_fields_names) != len(resolved_fields_names): 551 raise Exception("could not resolve all fields for %s" % self.name) 552 553 resolved_fields = [all_fields[n][1] for n in resolved_fields_names] 554 return resolved_fields 555# get_expr_fields() 556 557def resolve_expr_fields(complex_obj): 558 """ 559 find expr fields appearing in complex_obj and descendents that cannot be resolved within complex_obj 560 these are normally fields that need to be given as function parameters 561 """ 562 all_fields = [] 563 expr_fields = [] 564 unresolved = [] 565 566 for field in complex_obj.fields: 567 all_fields.append(field) 568 if field.type.is_switch or field.type.is_list: 569 expr_fields += get_expr_fields(field.type) 570 if field.type.is_container: 571 expr_fields += resolve_expr_fields(field.type) 572 573 # try to resolve expr fields 574 for e in expr_fields: 575 if e not in all_fields and e not in unresolved: 576 unresolved.append(e) 577 return unresolved 578# resolve_expr_fields() 579 580def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'): 581 """ 582 functions like _serialize(), _unserialize(), and _unpack() sometimes need additional parameters: 583 E.g. in order to unpack switch, extra parameters might be needed to evaluate the switch 584 expression. This function tries to resolve all fields within a structure, and returns the 585 unresolved fields as the list of external parameters. 586 """ 587 def add_param(params, param): 588 if param not in params: 589 params.append(param) 590 591 # collect all fields into param_fields 592 param_fields = [] 593 wire_fields = [] 594 595 for field in self.fields: 596 if field.visible: 597 # the field should appear as a parameter in the function call 598 param_fields.append(field) 599 if field.wire and not field.auto: 600 if field.type.fixed_size() and not self.is_switch: 601 # field in the xcb_out structure 602 wire_fields.append(field) 603 # fields like 'pad0' are skipped! 604 605 # in case of switch, parameters always contain any fields referenced in the switch expr 606 # we do not need any variable size fields here, as the switch data type contains both 607 # fixed and variable size fields 608 if self.is_switch: 609 param_fields = get_expr_fields(self) 610 611 # _serialize()/_unserialize()/_unpack() function parameters 612 # note: don't use set() for params, it is unsorted 613 params = [] 614 615 # 1. the parameter for the void * buffer 616 if 'serialize' == context: 617 params.append(('void', '**', buffer_var)) 618 elif context in ('unserialize', 'unpack', 'sizeof'): 619 params.append(('const void', '*', buffer_var)) 620 621 # 2. any expr fields that cannot be resolved within self and descendants 622 unresolved_fields = resolve_expr_fields(self) 623 for f in unresolved_fields: 624 add_param(params, (f.c_field_type, '', f.c_field_name)) 625 626 # 3. param_fields contain the fields necessary to evaluate the switch expr or any other fields 627 # that do not appear in the data type struct 628 for p in param_fields: 629 if self.is_switch: 630 typespec = p.c_field_const_type 631 pointerspec = p.c_pointer 632 add_param(params, (typespec, pointerspec, p.c_field_name)) 633 else: 634 if p.visible and not p.wire and not p.auto: 635 typespec = p.c_field_type 636 pointerspec = '' 637 add_param(params, (typespec, pointerspec, p.c_field_name)) 638 639 # 4. aux argument 640 if 'serialize' == context: 641 add_param(params, ('const %s' % self.c_type, '*', aux_var)) 642 elif 'unserialize' == context: 643 add_param(params, ('%s' % self.c_type, '**', aux_var)) 644 elif 'unpack' == context: 645 add_param(params, ('%s' % self.c_type, '*', aux_var)) 646 647 # 5. switch contains all variable size fields as struct members 648 # for other data types though, these have to be supplied separately 649 # this is important for the special case of intermixed fixed and 650 # variable size fields 651 if not self.is_switch and 'serialize' == context: 652 for p in param_fields: 653 if not p.type.fixed_size(): 654 add_param(params, (p.c_field_const_type, '*', p.c_field_name)) 655 656 return (param_fields, wire_fields, params) 657# get_serialize_params() 658 659def _c_serialize_helper_insert_padding(context, code_lines, space, postpone): 660 code_lines.append('%s /* insert padding */' % space) 661 code_lines.append('%s xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space) 662# code_lines.append('%s printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space) 663 code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) 664 665 if not postpone: 666 code_lines.append('%s if (0 != xcb_pad) {' % space) 667 668 if 'serialize' == context: 669 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' % space) 670 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = xcb_pad;' % space) 671 code_lines.append('%s xcb_parts_idx++;' % space) 672 elif context in ('unserialize', 'unpack', 'sizeof'): 673 code_lines.append('%s xcb_tmp += xcb_pad;' % space) 674 675 code_lines.append('%s xcb_pad = 0;' % space) 676 code_lines.append('%s }' % space) 677 678 code_lines.append('%s xcb_block_len = 0;' % space) 679 680 # keep tracking of xcb_parts entries for serialize 681 return 1 682# _c_serialize_helper_insert_padding() 683 684def _c_serialize_helper_switch(context, self, complex_name, 685 code_lines, temp_vars, 686 space, prefix): 687 count = 0 688 switch_expr = _c_accessor_get_expr(self.expr, None) 689 690 for b in self.bitcases: 691 len_expr = len(b.type.expr) 692 for n, expr in enumerate(b.type.expr): 693 bitcase_expr = _c_accessor_get_expr(expr, None) 694 # only one <enumref> in the <bitcase> 695 if len_expr == 1: 696 code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr)) 697 # multiple <enumref> in the <bitcase> 698 elif n == 0: # first 699 code_lines.append(' if((%s & %s) ||' % (switch_expr, bitcase_expr)) 700 elif len_expr == (n + 1): # last 701 code_lines.append(' (%s & %s)) {' % (switch_expr, bitcase_expr)) 702 else: # between first and last 703 code_lines.append(' (%s & %s) ||' % (switch_expr, bitcase_expr)) 704 705 b_prefix = prefix 706 if b.type.has_name: 707 b_prefix = prefix + [(b.c_field_name, '.', b.type)] 708 709 count += _c_serialize_helper_fields(context, b.type, 710 code_lines, temp_vars, 711 "%s " % space, 712 b_prefix, 713 is_bitcase = True) 714 code_lines.append(' }') 715 716# if 'serialize' == context: 717# count += _c_serialize_helper_insert_padding(context, code_lines, space, False) 718# elif context in ('unserialize', 'unpack', 'sizeof'): 719# # padding 720# code_lines.append('%s xcb_pad = -xcb_block_len & 3;' % space) 721# code_lines.append('%s xcb_buffer_len += xcb_block_len + xcb_pad;' % space) 722 723 return count 724# _c_serialize_helper_switch 725 726def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, prefix): 727 """ 728 handle switch by calling _serialize() or _unpack(), depending on context 729 """ 730 # switch is handled by this function as a special case 731 param_fields, wire_fields, params = get_serialize_params(context, self) 732 field_mapping = _c_helper_field_mapping(self, prefix) 733 prefix_str = _c_helper_absolute_name(prefix) 734 735 # find the parameters that need to be passed to _serialize()/_unpack(): 736 # all switch expr fields must be given as parameters 737 args = get_expr_fields(field.type) 738 # length fields for variable size types in switch, normally only some of need 739 # need to be passed as parameters 740 switch_len_fields = resolve_expr_fields(field.type) 741 742 # a switch field at this point _must_ be a bitcase field 743 # we require that bitcases are "self-contiguous" 744 bitcase_unresolved = resolve_expr_fields(self) 745 if len(bitcase_unresolved) != 0: 746 raise Exception('unresolved fields within bitcase is not supported at this point') 747 748 # get the C names for the parameters 749 c_field_names = '' 750 for a in switch_len_fields: 751 c_field_names += "%s, " % field_mapping[a.c_field_name][0] 752 for a in args: 753 c_field_names += "%s, " % field_mapping[a.c_field_name][0] 754 755 # call _serialize()/_unpack() to determine the actual size 756 if 'serialize' == context: 757 length = "%s(&%s, %s&%s%s)" % (field.type.c_serialize_name, c_switch_variable, 758 c_field_names, prefix_str, field.c_field_name) 759 elif context in ('unserialize', 'unpack'): 760 length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name, 761 c_field_names, prefix_str, field.c_field_name) 762 763 return length 764# _c_serialize_helper_switch_field() 765 766def _c_serialize_helper_list_field(context, self, field, 767 code_lines, temp_vars, 768 space, prefix): 769 """ 770 helper function to cope with lists of variable length 771 """ 772 expr = field.type.expr 773 prefix_str = _c_helper_absolute_name(prefix) 774 param_fields, wire_fields, params = get_serialize_params('sizeof', self) 775 param_names = [p[2] for p in params] 776 777 expr_fields_names = [f.field_name for f in get_expr_fields(field.type)] 778 resolved = list(filter(lambda x: x in param_names, expr_fields_names)) 779 unresolved = list(filter(lambda x: x not in param_names, expr_fields_names)) 780 781 field_mapping = {} 782 for r in resolved: 783 field_mapping[r] = (r, None) 784 785 if len(unresolved)>0: 786 tmp_prefix = prefix 787 if len(tmp_prefix)==0: 788 raise Exception("found an empty prefix while resolving expr field names for list %s", 789 field.c_field_name) 790 791 field_mapping.update(_c_helper_resolve_field_names(prefix)) 792 resolved += list(filter(lambda x: x in field_mapping, unresolved)) 793 unresolved = list(filter(lambda x: x not in field_mapping, unresolved)) 794 if len(unresolved)>0: 795 raise Exception('could not resolve the length fields required for list %s' % field.c_field_name) 796 797 list_length = _c_accessor_get_expr(expr, field_mapping) 798 799 # default: list with fixed size elements 800 length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype) 801 802 # list with variable-sized elements 803 if not field.type.member.fixed_size(): 804 length = '' 805 if context in ('unserialize', 'sizeof', 'unpack'): 806 int_i = ' unsigned int i;' 807 xcb_tmp_len = ' unsigned int xcb_tmp_len;' 808 if int_i not in temp_vars: 809 temp_vars.append(int_i) 810 if xcb_tmp_len not in temp_vars: 811 temp_vars.append(xcb_tmp_len) 812 # loop over all list elements and call sizeof repeatedly 813 # this should be a bit faster than using the iterators 814 code_lines.append("%s for(i=0; i<%s; i++) {" % (space, list_length)) 815 code_lines.append("%s xcb_tmp_len = %s(xcb_tmp);" % 816 (space, field.type.c_sizeof_name)) 817 code_lines.append("%s xcb_block_len += xcb_tmp_len;" % space) 818 code_lines.append("%s xcb_tmp += xcb_tmp_len;" % space) 819 code_lines.append("%s }" % space) 820 821 elif 'serialize' == context: 822 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = 0;' % space) 823 code_lines.append('%s xcb_tmp = (char *) %s%s;' % (space, prefix_str, field.c_field_name)) 824 code_lines.append('%s for(i=0; i<%s; i++) { ' % (space, list_length)) 825 code_lines.append('%s xcb_block_len = %s(xcb_tmp);' % (space, field.type.c_sizeof_name)) 826 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len += xcb_block_len;' % space) 827 code_lines.append('%s }' % space) 828 code_lines.append('%s xcb_block_len = xcb_parts[xcb_parts_idx].iov_len;' % space) 829 830 return length 831# _c_serialize_helper_list_field() 832 833def _c_serialize_helper_fields_fixed_size(context, self, field, 834 code_lines, temp_vars, 835 space, prefix): 836 # keep the C code a bit more readable by giving the field name 837 if not self.is_bitcase: 838 code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) 839 else: 840 scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)] 841 typename = reduce(lambda x,y: "%s.%s" % (x, y), scoped_name) 842 code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name)) 843 844 abs_field_name = _c_helper_absolute_name(prefix, field) 845 # default for simple cases: call sizeof() 846 length = "sizeof(%s)" % field.c_field_type 847 848 if context in ('unserialize', 'unpack', 'sizeof'): 849 # default: simple cast 850 value = ' %s = *(%s *)xcb_tmp;' % (abs_field_name, field.c_field_type) 851 852 # padding - we could probably just ignore it 853 if field.type.is_pad and field.type.nmemb > 1: 854 value = '' 855 for i in range(field.type.nmemb): 856 code_lines.append('%s %s[%d] = *(%s *)xcb_tmp;' % 857 (space, abs_field_name, i, field.c_field_type)) 858 # total padding = sizeof(pad0) * nmemb 859 length += " * %d" % field.type.nmemb 860 861 if field.type.is_list: 862 # no such case in the protocol, cannot be tested and therefore ignored for now 863 raise Exception('list with fixed number of elemens unhandled in _unserialize()') 864 865 elif 'serialize' == context: 866 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) ' 867 868 if field.type.is_expr: 869 # need to register a temporary variable for the expression in case we know its type 870 if field.type.c_type is None: 871 raise Exception("type for field '%s' (expression '%s') unkown" % 872 (field.field_name, _c_accessor_get_expr(field.type.expr))) 873 874 temp_vars.append(' %s xcb_expr_%s = %s;' % (field.type.c_type, _cpp(field.field_name), 875 _c_accessor_get_expr(field.type.expr, prefix))) 876 value += "&xcb_expr_%s;" % _cpp(field.field_name) 877 878 elif field.type.is_pad: 879 if field.type.nmemb == 1: 880 value += "&xcb_pad;" 881 else: 882 # we could also set it to 0, see definition of xcb_send_request() 883 value = ' xcb_parts[xcb_parts_idx].iov_base = xcb_pad0;' 884 length += "*%d" % field.type.nmemb 885 886 else: 887 # non-list type with fixed size 888 if field.type.nmemb == 1: 889 value += "&%s;" % (abs_field_name) 890 891 # list with nmemb (fixed size) elements 892 else: 893 value += '%s;' % (abs_field_name) 894 length = '%d' % field.type.nmemb 895 896 return (value, length) 897# _c_serialize_helper_fields_fixed_size() 898 899def _c_serialize_helper_fields_variable_size(context, self, field, 900 code_lines, temp_vars, 901 space, prefix): 902 prefix_str = _c_helper_absolute_name(prefix) 903 904 if context in ('unserialize', 'unpack', 'sizeof'): 905 value = '' 906 var_field_name = 'xcb_tmp' 907 908 # special case: intermixed fixed and variable size fields 909 if self.var_followed_by_fixed_fields and 'unserialize' == context: 910 value = ' %s = (%s *)xcb_tmp;' % (field.c_field_name, field.c_field_type) 911 temp_vars.append(' %s *%s;' % (field.type.c_type, field.c_field_name)) 912 # special case: switch 913 if 'unpack' == context: 914 value = ' %s%s = (%s *)xcb_tmp;' % (prefix_str, field.c_field_name, field.c_field_type) 915 916 elif 'serialize' == context: 917 # variable size fields appear as parameters to _serialize() if the 918 # 'toplevel' container is not a switch 919 prefix_string = prefix_str if prefix[0][2].is_switch else '' 920 var_field_name = "%s%s" % (prefix_string, field.c_field_name) 921 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *) %s;' % var_field_name 922 923 length = '' 924 925 code_lines.append('%s /* %s */' % (space, field.c_field_name)) 926 927 if field.type.is_list: 928 if value != '': 929 # in any context, list is already a pointer, so the default assignment is ok 930 code_lines.append("%s%s" % (space, value)) 931 value = '' 932 length = _c_serialize_helper_list_field(context, self, field, 933 code_lines, temp_vars, 934 space, prefix) 935 936 elif field.type.is_switch: 937 value = '' 938 if context == 'serialize': 939 # the _serialize() function allocates the correct amount memory if given a NULL pointer 940 value = ' xcb_parts[xcb_parts_idx].iov_base = (char *)0;' 941 length = _c_serialize_helper_switch_field(context, self, field, 942 'xcb_parts[xcb_parts_idx].iov_base', 943 prefix) 944 945 else: 946 # in all remaining special cases - call _sizeof() 947 length = "%s(%s)" % (field.type.c_sizeof_name, var_field_name) 948 949 return (value, length) 950# _c_serialize_helper_fields_variable_size 951 952def _c_serialize_helper_fields(context, self, 953 code_lines, temp_vars, 954 space, prefix, is_bitcase): 955 count = 0 956 need_padding = False 957 prev_field_was_variable = False 958 959 for field in self.fields: 960 if not field.visible: 961 if not ((field.wire and not field.auto) or 'unserialize' == context): 962 continue 963 964 # switch/bitcase: fixed size fields must be considered explicitly 965 if field.type.fixed_size(): 966 if self.is_bitcase or self.var_followed_by_fixed_fields: 967 if prev_field_was_variable and need_padding: 968 # insert padding 969# count += _c_serialize_helper_insert_padding(context, code_lines, space, 970# self.var_followed_by_fixed_fields) 971 prev_field_was_variable = False 972 973 # prefix for fixed size fields 974 fixed_prefix = prefix 975 976 value, length = _c_serialize_helper_fields_fixed_size(context, self, field, 977 code_lines, temp_vars, 978 space, fixed_prefix) 979 else: 980 continue 981 982 # fields with variable size 983 else: 984 # switch/bitcase: always calculate padding before and after variable sized fields 985 if need_padding or is_bitcase: 986 count += _c_serialize_helper_insert_padding(context, code_lines, space, 987 self.var_followed_by_fixed_fields) 988 989 value, length = _c_serialize_helper_fields_variable_size(context, self, field, 990 code_lines, temp_vars, 991 space, prefix) 992 prev_field_was_variable = True 993 994 # save (un)serialization C code 995 if '' != value: 996 code_lines.append('%s%s' % (space, value)) 997 998 if field.type.fixed_size(): 999 if is_bitcase or self.var_followed_by_fixed_fields: 1000 # keep track of (un)serialized object's size 1001 code_lines.append('%s xcb_block_len += %s;' % (space, length)) 1002 if context in ('unserialize', 'unpack', 'sizeof'): 1003 code_lines.append('%s xcb_tmp += %s;' % (space, length)) 1004 else: 1005 # variable size objects or bitcase: 1006 # value & length might have been inserted earlier for special cases 1007 if '' != length: 1008 # special case: intermixed fixed and variable size fields 1009 if (not field.type.fixed_size() and 1010 self.var_followed_by_fixed_fields and 'unserialize' == context): 1011 temp_vars.append(' int %s_len;' % field.c_field_name) 1012 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length)) 1013 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name)) 1014 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name)) 1015 else: 1016 code_lines.append('%s xcb_block_len += %s;' % (space, length)) 1017 # increase pointer into the byte stream accordingly 1018 if context in ('unserialize', 'sizeof', 'unpack'): 1019 code_lines.append('%s xcb_tmp += xcb_block_len;' % space) 1020 1021 if 'serialize' == context: 1022 if '' != length: 1023 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length)) 1024 code_lines.append('%s xcb_parts_idx++;' % space) 1025 count += 1 1026 1027 code_lines.append('%s xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type)) 1028 1029 need_padding = True 1030 if self.var_followed_by_fixed_fields: 1031 need_padding = False 1032 1033 return count 1034# _c_serialize_helper_fields() 1035 1036def _c_serialize_helper(context, complex_type, 1037 code_lines, temp_vars, 1038 space='', prefix=[]): 1039 # count tracks the number of fields to serialize 1040 count = 0 1041 1042 if hasattr(complex_type, 'type'): 1043 self = complex_type.type 1044 complex_name = complex_type.name 1045 else: 1046 self = complex_type 1047 if self.var_followed_by_fixed_fields and 'unserialize' == context: 1048 complex_name = 'xcb_out' 1049 else: 1050 complex_name = '_aux' 1051 1052 # special case: switch is serialized by evaluating each bitcase separately 1053 if self.is_switch: 1054 count += _c_serialize_helper_switch(context, self, complex_name, 1055 code_lines, temp_vars, 1056 space, prefix) 1057 1058 # all other data types can be evaluated one field a time 1059 else: 1060 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type 1061 if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields: 1062 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type)) 1063 code_lines.append('%s xcb_tmp += xcb_block_len;' % space) 1064 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) 1065 code_lines.append('%s xcb_block_len = 0;' % space) 1066 1067 count += _c_serialize_helper_fields(context, self, 1068 code_lines, temp_vars, 1069 space, prefix, False) 1070 # "final padding" 1071 count += _c_serialize_helper_insert_padding(context, code_lines, space, False) 1072 1073 return count 1074# _c_serialize_helper() 1075 1076def _c_serialize(context, self): 1077 """ 1078 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof() 1079 for the ComplexType variable self 1080 """ 1081 _h_setlevel(1) 1082 _c_setlevel(1) 1083 1084 _hc('') 1085 # _serialize() returns the buffer size 1086 _hc('int') 1087 1088 if self.is_switch and 'unserialize' == context: 1089 context = 'unpack' 1090 1091 cases = { 'serialize' : self.c_serialize_name, 1092 'unserialize' : self.c_unserialize_name, 1093 'unpack' : self.c_unpack_name, 1094 'sizeof' : self.c_sizeof_name } 1095 func_name = cases[context] 1096 1097 param_fields, wire_fields, params = get_serialize_params(context, self) 1098 variable_size_fields = 0 1099 # maximum space required for type definition of function arguments 1100 maxtypelen = 0 1101 1102 # determine N(variable_fields) 1103 for field in param_fields: 1104 # if self.is_switch, treat all fields as if they are variable sized 1105 if not field.type.fixed_size() or self.is_switch: 1106 variable_size_fields += 1 1107 # determine maxtypelen 1108 for p in params: 1109 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1])) 1110 1111 # write to .c/.h 1112 indent = ' '*(len(func_name)+2) 1113 param_str = [] 1114 for p in params: 1115 typespec, pointerspec, field_name = p 1116 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) 1117 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)) 1118 # insert function name 1119 param_str[0] = "%s (%s" % (func_name, param_str[0].strip()) 1120 param_str = list(map(lambda x: "%s," % x, param_str)) 1121 for s in param_str[:-1]: 1122 _hc(s) 1123 _h("%s);" % param_str[-1].rstrip(',')) 1124 _c("%s)" % param_str[-1].rstrip(',')) 1125 _c('{') 1126 1127 code_lines = [] 1128 temp_vars = [] 1129 prefix = [] 1130 1131 if 'serialize' == context: 1132 if not self.is_switch and not self.var_followed_by_fixed_fields: 1133 _c(' %s *xcb_out = *_buffer;', self.c_type) 1134 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type) 1135 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type) 1136 _c(' unsigned int xcb_align_to = 0;') 1137 else: 1138 _c(' char *xcb_out = *_buffer;') 1139 _c(' unsigned int xcb_buffer_len = 0;') 1140 _c(' unsigned int xcb_align_to = 0;') 1141 prefix = [('_aux', '->', self)] 1142 aux_ptr = 'xcb_out' 1143 1144 elif context in ('unserialize', 'unpack'): 1145 _c(' char *xcb_tmp = (char *)_buffer;') 1146 if not self.is_switch: 1147 if not self.var_followed_by_fixed_fields: 1148 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) 1149 prefix = [('_aux', '->', self)] 1150 else: 1151 _c(' %s xcb_out;', self.c_type) 1152 prefix = [('xcb_out', '.', self)] 1153 else: 1154 aux_var = '_aux' # default for unpack: single pointer 1155 # note: unserialize not generated for switch 1156 if 'unserialize' == context: 1157 aux_var = '(*_aux)' # unserialize: double pointer (!) 1158 prefix = [(aux_var, '->', self)] 1159 aux_ptr = '*_aux' 1160 _c(' unsigned int xcb_buffer_len = 0;') 1161 _c(' unsigned int xcb_block_len = 0;') 1162 _c(' unsigned int xcb_pad = 0;') 1163 _c(' unsigned int xcb_align_to = 0;') 1164 1165 elif 'sizeof' == context: 1166 param_names = [p[2] for p in params] 1167 if self.is_switch: 1168 # switch: call _unpack() 1169 _c(' %s _aux;', self.c_type) 1170 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) 1171 _c('}') 1172 return 1173 elif self.var_followed_by_fixed_fields: 1174 # special case: call _unserialize() 1175 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) 1176 _c('}') 1177 return 1178 else: 1179 _c(' char *xcb_tmp = (char *)_buffer;') 1180 prefix = [('_aux', '->', self)] 1181 1182 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix) 1183 # update variable size fields (only important for context=='serialize' 1184 variable_size_fields = count 1185 if 'serialize' == context: 1186 temp_vars.append(' unsigned int xcb_pad = 0;') 1187 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};') 1188 temp_vars.append(' struct iovec xcb_parts[%d];' % count) 1189 temp_vars.append(' unsigned int xcb_parts_idx = 0;') 1190 temp_vars.append(' unsigned int xcb_block_len = 0;') 1191 temp_vars.append(' unsigned int i;') 1192 temp_vars.append(' char *xcb_tmp;') 1193 elif 'sizeof' == context: 1194 # neither switch nor intermixed fixed and variable size fields: 1195 # evaluate parameters directly 1196 if not (self.is_switch or self.var_followed_by_fixed_fields): 1197 1198 # look if we have to declare an '_aux' variable at all 1199 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0: 1200 if not self.var_followed_by_fixed_fields: 1201 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) 1202 else: 1203 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type) 1204 1205 _c(' unsigned int xcb_buffer_len = 0;') 1206 _c(' unsigned int xcb_block_len = 0;') 1207 _c(' unsigned int xcb_pad = 0;') 1208 _c(' unsigned int xcb_align_to = 0;') 1209 1210 _c('') 1211 for t in temp_vars: 1212 _c(t) 1213 _c('') 1214 for l in code_lines: 1215 _c(l) 1216 1217 # variable sized fields have been collected, now 1218 # allocate memory and copy everything into a continuous memory area 1219 # note: this is not necessary in case of unpack 1220 if context in ('serialize', 'unserialize'): 1221 # unserialize: check for sizeof-only invocation 1222 if 'unserialize' == context: 1223 _c('') 1224 _c(' if (NULL == _aux)') 1225 _c(' return xcb_buffer_len;') 1226 1227 _c('') 1228 _c(' if (NULL == %s) {', aux_ptr) 1229 _c(' /* allocate memory */') 1230 _c(' %s = malloc(xcb_buffer_len);', aux_ptr) 1231 if 'serialize' == context: 1232 _c(' *_buffer = xcb_out;') 1233 _c(' }') 1234 _c('') 1235 1236 # serialize: handle variable size fields in a loop 1237 if 'serialize' == context: 1238 if not self.is_switch and not self.var_followed_by_fixed_fields: 1239 if len(wire_fields)>0: 1240 _c(' *xcb_out = *_aux;') 1241 # copy variable size fields into the buffer 1242 if variable_size_fields > 0: 1243 # xcb_out padding 1244 if not self.is_switch and not self.var_followed_by_fixed_fields: 1245 _c(' xcb_tmp = (char*)++xcb_out;') 1246 _c(' xcb_tmp += xcb_out_pad;') 1247 else: 1248 _c(' xcb_tmp = xcb_out;') 1249 1250 # variable sized fields 1251 _c(' for(i=0; i<xcb_parts_idx; i++) {') 1252 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)') 1253 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);') 1254 _c(' if (0 != xcb_parts[i].iov_len)') 1255 _c(' xcb_tmp += xcb_parts[i].iov_len;') 1256 _c(' }') 1257 1258 # unserialize: assign variable size fields individually 1259 if 'unserialize' == context: 1260 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;') 1261 param_fields.reverse() 1262 for field in param_fields: 1263 if not field.type.fixed_size(): 1264 _c(' xcb_tmp -= %s_len;', field.c_field_name) 1265 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name) 1266 _c(' *%s = xcb_out;', aux_ptr) 1267 1268 _c('') 1269 _c(' return xcb_buffer_len;') 1270 _c('}') 1271# _c_serialize() 1272 1273def _c_iterator_get_end(field, accum): 1274 ''' 1275 Figures out what C code is needed to find the end of a variable-length structure field. 1276 For nested structures, recurses into its last variable-sized field. 1277 For lists, calls the end function 1278 ''' 1279 if field.type.is_container: 1280 accum = field.c_accessor_name + '(' + accum + ')' 1281 return _c_iterator_get_end(field.type.last_varsized_field, accum) 1282 if field.type.is_list: 1283 # XXX we can always use the first way 1284 if field.type.member.is_simple: 1285 return field.c_end_name + '(' + accum + ')' 1286 else: 1287 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))' 1288 1289def _c_iterator(self, name): 1290 ''' 1291 Declares the iterator structure and next/end functions for a given type. 1292 ''' 1293 _h_setlevel(0) 1294 _h('') 1295 _h('/**') 1296 _h(' * @brief %s', self.c_iterator_type) 1297 _h(' **/') 1298 _h('typedef struct %s {', self.c_iterator_type) 1299 _h(' %s *data; /**< */', self.c_type) 1300 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2)) 1301 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2)) 1302 _h('} %s;', self.c_iterator_type) 1303 1304 _h_setlevel(1) 1305 _c_setlevel(1) 1306 _h('') 1307 _h('/**') 1308 _h(' * Get the next element of the iterator') 1309 _h(' * @param i Pointer to a %s', self.c_iterator_type) 1310 _h(' *') 1311 _h(' * Get the next element in the iterator. The member rem is') 1312 _h(' * decreased by one. The member data points to the next') 1313 _h(' * element. The member index is increased by sizeof(%s)', self.c_type) 1314 _h(' */') 1315 _c('') 1316 _hc('') 1317 _hc('/*****************************************************************************') 1318 _hc(' **') 1319 _hc(' ** void %s', self.c_next_name) 1320 _hc(' ** ') 1321 _hc(' ** @param %s *i', self.c_iterator_type) 1322 _hc(' ** @returns void') 1323 _hc(' **') 1324 _hc(' *****************************************************************************/') 1325 _hc(' ') 1326 _hc('void') 1327 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type) 1328 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type) 1329 _c('{') 1330 1331 if not self.fixed_size(): 1332 _c(' %s *R = i->data;', self.c_type) 1333 1334 if self.is_union: 1335 # FIXME - how to determine the size of a variable size union?? 1336 _c(' /* FIXME - determine the size of the union %s */', self.c_type) 1337 else: 1338 if self.need_sizeof: 1339 _c(' xcb_generic_iterator_t child;') 1340 _c(' child.data = (%s *)(((char *)R) + %s(R));', 1341 self.c_type, self.c_sizeof_name) 1342 _c(' i->index = (char *) child.data - (char *) i->data;') 1343 else: 1344 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) 1345 _c(' i->index = child.index;') 1346 _c(' --i->rem;') 1347 _c(' i->data = (%s *) child.data;', self.c_type) 1348 1349 else: 1350 _c(' --i->rem;') 1351 _c(' ++i->data;') 1352 _c(' i->index += sizeof(%s);', self.c_type) 1353 1354 _c('}') 1355 1356 _h('') 1357 _h('/**') 1358 _h(' * Return the iterator pointing to the last element') 1359 _h(' * @param i An %s', self.c_iterator_type) 1360 _h(' * @return The iterator pointing to the last element') 1361 _h(' *') 1362 _h(' * Set the current element in the iterator to the last element.') 1363 _h(' * The member rem is set to 0. The member data points to the') 1364 _h(' * last element.') 1365 _h(' */') 1366 _c('') 1367 _hc('') 1368 _hc('/*****************************************************************************') 1369 _hc(' **') 1370 _hc(' ** xcb_generic_iterator_t %s', self.c_end_name) 1371 _hc(' ** ') 1372 _hc(' ** @param %s i', self.c_iterator_type) 1373 _hc(' ** @returns xcb_generic_iterator_t') 1374 _hc(' **') 1375 _hc(' *****************************************************************************/') 1376 _hc(' ') 1377 _hc('xcb_generic_iterator_t') 1378 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type) 1379 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type) 1380 _c('{') 1381 _c(' xcb_generic_iterator_t ret;') 1382 1383 if self.fixed_size(): 1384 _c(' ret.data = i.data + i.rem;') 1385 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);') 1386 _c(' ret.rem = 0;') 1387 else: 1388 _c(' while(i.rem > 0)') 1389 _c(' %s(&i);', self.c_next_name) 1390 _c(' ret.data = i.data;') 1391 _c(' ret.rem = i.rem;') 1392 _c(' ret.index = i.index;') 1393 1394 _c(' return ret;') 1395 _c('}') 1396 1397def _c_accessor_get_length(expr, field_mapping=None): 1398 ''' 1399 Figures out what C code is needed to get a length field. 1400 The field_mapping parameter can be used to change the absolute name of a length field. 1401 For fields that follow a variable-length field, use the accessor. 1402 Otherwise, just reference the structure field directly. 1403 ''' 1404 1405 lenfield_name = expr.lenfield_name 1406 if lenfield_name is not None: 1407 if field_mapping is not None: 1408 lenfield_name = field_mapping[lenfield_name][0] 1409 1410 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None: 1411 # special case: variable and fixed size fields are intermixed 1412 # if the lenfield is among the fixed size fields, there is no need 1413 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'> 1414 return field_mapping(expr.lenfield_name) 1415 elif expr.lenfield_name is not None: 1416 return lenfield_name 1417 else: 1418 return str(expr.nmemb) 1419 1420def _c_accessor_get_expr(expr, field_mapping): 1421 ''' 1422 Figures out what C code is needed to get the length of a list field. 1423 The field_mapping parameter can be used to change the absolute name of a length field. 1424 Recurses for math operations. 1425 Returns bitcount for value-mask fields. 1426 Otherwise, uses the value of the length field. 1427 ''' 1428 lenexp = _c_accessor_get_length(expr, field_mapping) 1429 1430 if expr.op == '~': 1431 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' 1432 elif expr.op == 'popcount': 1433 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' 1434 elif expr.op == 'enumref': 1435 enum_name = expr.lenfield_type.name 1436 constant_name = expr.lenfield_name 1437 c_name = _n(enum_name + (constant_name,)).upper() 1438 return c_name 1439 elif expr.op == 'sumof': 1440 # locate the referenced list object 1441 list_obj = expr.lenfield_type 1442 field = None 1443 for f in expr.lenfield_parent.fields: 1444 if f.field_name == expr.lenfield_name: 1445 field = f 1446 break 1447 1448 if field is None: 1449 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) 1450 list_name = field_mapping[field.c_field_name][0] 1451 c_length_func = "%s(%s)" % (field.c_length_name, list_name) 1452 # note: xcb_sumof() has only been defined for integers 1453 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping) 1454 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func) 1455 elif expr.op != None: 1456 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) + 1457 ' ' + expr.op + ' ' + 1458 _c_accessor_get_expr(expr.rhs, field_mapping) + ')') 1459 elif expr.bitfield: 1460 return 'xcb_popcount(' + lenexp + ')' 1461 else: 1462 return lenexp 1463 1464def type_pad_type(type): 1465 if type == 'void': 1466 return 'char' 1467 return type 1468 1469def _c_accessors_field(self, field): 1470 ''' 1471 Declares the accessor functions for a non-list field that follows a variable-length field. 1472 ''' 1473 c_type = self.c_type 1474 1475 # special case: switch 1476 switch_obj = self if self.is_switch else None 1477 if self.is_bitcase: 1478 switch_obj = self.parents[-1] 1479 if switch_obj is not None: 1480 c_type = switch_obj.c_type 1481 1482 if field.type.is_simple: 1483 _hc('') 1484 _hc('') 1485 _hc('/*****************************************************************************') 1486 _hc(' ** ') 1487 _hc(' ** %s %s', field.c_field_type, field.c_accessor_name) 1488 _hc(' ** ') 1489 _hc(' ** @param const %s *R', c_type) 1490 _hc(' ** @returns %s', field.c_field_type) 1491 _hc(' **') 1492 _hc(' *****************************************************************************/') 1493 _hc(' ') 1494 _hc('%s', field.c_field_type) 1495 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) 1496 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) 1497 _c('{') 1498 if field.prev_varsized_field is None: 1499 _c(' return (%s *) (R + 1);', field.c_field_type) 1500 else: 1501 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1502 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 1503 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) 1504 _c('}') 1505 else: 1506 _hc('') 1507 _hc('') 1508 _hc('/*****************************************************************************') 1509 _hc(' **') 1510 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name) 1511 _hc(' ** ') 1512 _hc(' ** @param const %s *R', c_type) 1513 _hc(' ** @returns %s *', field.c_field_type) 1514 _hc(' **') 1515 _hc(' *****************************************************************************/') 1516 _hc(' ') 1517 if field.type.is_switch and switch_obj is None: 1518 return_type = 'void *' 1519 else: 1520 return_type = '%s *' % field.c_field_type 1521 1522 _hc(return_type) 1523 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) 1524 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) 1525 _c('{') 1526 if field.prev_varsized_field is None: 1527 _c(' return (%s) (R + 1);', return_type) 1528 # note: the special case 'variable fields followed by fixed size fields' 1529 # is not of any consequence here, since the ordering gets 1530 # 'corrected' in the reply function 1531 else: 1532 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1533 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 1534 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) 1535 _c('}') 1536 1537 1538def _c_accessors_list(self, field): 1539 ''' 1540 Declares the accessor functions for a list field. 1541 Declares a direct-accessor function only if the list members are fixed size. 1542 Declares length and get-iterator functions always. 1543 ''' 1544 list = field.type 1545 c_type = self.c_type 1546 1547 # special case: switch 1548 # in case of switch, 2 params have to be supplied to certain accessor functions: 1549 # 1. the anchestor object (request or reply) 1550 # 2. the (anchestor) switch object 1551 # the reason is that switch is either a child of a request/reply or nested in another switch, 1552 # so whenever we need to access a length field, we might need to refer to some anchestor type 1553 switch_obj = self if self.is_switch else None 1554 if self.is_bitcase: 1555 switch_obj = self.parents[-1] 1556 if switch_obj is not None: 1557 c_type = switch_obj.c_type 1558 1559 params = [] 1560 fields = {} 1561 parents = self.parents if hasattr(self, 'parents') else [self] 1562 # 'R': parents[0] is always the 'toplevel' container type 1563 params.append(('const %s *R' % parents[0].c_type, parents[0])) 1564 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True)) 1565 # auxiliary object for 'R' parameters 1566 R_obj = parents[0] 1567 1568 if switch_obj is not None: 1569 # now look where the fields are defined that are needed to evaluate 1570 # the switch expr, and store the parent objects in accessor_params and 1571 # the fields in switch_fields 1572 1573 # 'S': name for the 'toplevel' switch 1574 toplevel_switch = parents[1] 1575 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch)) 1576 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True)) 1577 1578 # initialize prefix for everything "below" S 1579 prefix_str = '/* %s */ S' % toplevel_switch.name[-1] 1580 prefix = [(prefix_str, '->', toplevel_switch)] 1581 1582 # look for fields in the remaining containers 1583 for p in parents[2:] + [self]: 1584 # the separator between parent and child is always '.' here, 1585 # because of nested switch statements 1586 if not p.is_bitcase or (p.is_bitcase and p.has_name): 1587 prefix.append((p.name[-1], '.', p)) 1588 fields.update(_c_helper_field_mapping(p, prefix, flat=True)) 1589 1590 # auxiliary object for 'S' parameter 1591 S_obj = parents[1] 1592 1593 _h_setlevel(1) 1594 _c_setlevel(1) 1595 if list.member.fixed_size(): 1596 idx = 1 if switch_obj is not None else 0 1597 _hc('') 1598 _hc('') 1599 _hc('/*****************************************************************************') 1600 _hc(' **') 1601 _hc(' ** %s * %s', field.c_field_type, field.c_accessor_name) 1602 _hc(' ** ') 1603 _hc(' ** @param %s', params[idx][0]) 1604 _hc(' ** @returns %s *', field.c_field_type) 1605 _hc(' **') 1606 _hc(' *****************************************************************************/') 1607 _hc(' ') 1608 _hc('%s *', field.c_field_type) 1609 1610 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0]) 1611 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0]) 1612 1613 _c('{') 1614 if switch_obj is not None: 1615 _c(' return %s;', fields[field.c_field_name][0]) 1616 elif field.prev_varsized_field is None: 1617 _c(' return (%s *) (R + 1);', field.c_field_type) 1618 else: 1619 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1620 _c(' return (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 1621 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) 1622 _c('}') 1623 1624 _hc('') 1625 _hc('') 1626 _hc('/*****************************************************************************') 1627 _hc(' **') 1628 _hc(' ** int %s', field.c_length_name) 1629 _hc(' ** ') 1630 _hc(' ** @param const %s *R', c_type) 1631 _hc(' ** @returns int') 1632 _hc(' **') 1633 _hc(' *****************************************************************************/') 1634 _hc(' ') 1635 _hc('int') 1636 if switch_obj is not None: 1637 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type) 1638 spacing = ' '*(len(field.c_length_name)+2) 1639 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1640 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1641 length = _c_accessor_get_expr(field.type.expr, fields) 1642 else: 1643 _h('%s (const %s *R /**< */);', field.c_length_name, c_type) 1644 _c('%s (const %s *R /**< */)', field.c_length_name, c_type) 1645 length = _c_accessor_get_expr(field.type.expr, fields) 1646 _c('{') 1647 _c(' return %s;', length) 1648 _c('}') 1649 1650 if field.type.member.is_simple: 1651 _hc('') 1652 _hc('') 1653 _hc('/*****************************************************************************') 1654 _hc(' **') 1655 _hc(' ** xcb_generic_iterator_t %s', field.c_end_name) 1656 _hc(' ** ') 1657 _hc(' ** @param const %s *R', c_type) 1658 _hc(' ** @returns xcb_generic_iterator_t') 1659 _hc(' **') 1660 _hc(' *****************************************************************************/') 1661 _hc(' ') 1662 _hc('xcb_generic_iterator_t') 1663 if switch_obj is not None: 1664 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type) 1665 spacing = ' '*(len(field.c_end_name)+2) 1666 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1667 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1668 else: 1669 _h('%s (const %s *R /**< */);', field.c_end_name, c_type) 1670 _c('%s (const %s *R /**< */)', field.c_end_name, c_type) 1671 _c('{') 1672 _c(' xcb_generic_iterator_t i;') 1673 1674 param = 'R' if switch_obj is None else 'S' 1675 if switch_obj is not None: 1676 _c(' i.data = %s + %s;', fields[field.c_field_name][0], 1677 _c_accessor_get_expr(field.type.expr, fields)) 1678 elif field.prev_varsized_field == None: 1679 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, 1680 _c_accessor_get_expr(field.type.expr, fields)) 1681 else: 1682 _c(' xcb_generic_iterator_t child = %s;', 1683 _c_iterator_get_end(field.prev_varsized_field, 'R')) 1684 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, 1685 _c_accessor_get_expr(field.type.expr, fields)) 1686 1687 _c(' i.rem = 0;') 1688 _c(' i.index = (char *) i.data - (char *) %s;', param) 1689 _c(' return i;') 1690 _c('}') 1691 1692 else: 1693 _hc('') 1694 _hc('') 1695 _hc('/*****************************************************************************') 1696 _hc(' **') 1697 _hc(' ** %s %s', field.c_iterator_type, field.c_iterator_name) 1698 _hc(' ** ') 1699 _hc(' ** @param const %s *R', c_type) 1700 _hc(' ** @returns %s', field.c_iterator_type) 1701 _hc(' **') 1702 _hc(' *****************************************************************************/') 1703 _hc(' ') 1704 1705 _hc('%s', field.c_iterator_type) 1706 if switch_obj is not None: 1707 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type) 1708 spacing = ' '*(len(field.c_iterator_name)+2) 1709 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1710 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1711 else: 1712 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type) 1713 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type) 1714 _c('{') 1715 _c(' %s i;', field.c_iterator_type) 1716 1717 if switch_obj is not None: 1718 _c(' i.data = %s;', fields[field.c_field_name][0]) 1719 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) 1720 elif field.prev_varsized_field == None: 1721 _c(' i.data = (%s *) (R + 1);', field.c_field_type) 1722 else: 1723 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1724 _c(' i.data = (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index));', 1725 field.c_field_type, type_pad_type(field.c_field_type)) 1726 if switch_obj is None: 1727 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) 1728 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' ) 1729 _c(' return i;') 1730 _c('}') 1731 1732def _c_accessors(self, name, base): 1733 ''' 1734 Declares the accessor functions for the fields of a structure. 1735 ''' 1736 # no accessors for switch itself - 1737 # switch always needs to be unpacked explicitly 1738# if self.is_switch: 1739# pass 1740# else: 1741 if True: 1742 for field in self.fields: 1743 if field.type.is_list and not field.type.fixed_size(): 1744 _c_accessors_list(self, field) 1745 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 1746 _c_accessors_field(self, field) 1747 1748def c_simple(self, name): 1749 ''' 1750 Exported function that handles cardinal type declarations. 1751 These are types which are typedef'd to one of the CARDx's, char, float, etc. 1752 ''' 1753 _c_type_setup(self, name, ()) 1754 1755 if (self.name != name): 1756 # Typedef 1757 _h_setlevel(0) 1758 my_name = _t(name) 1759 _h('') 1760 _h('typedef %s %s;', _t(self.name), my_name) 1761 1762 # Iterator 1763 _c_iterator(self, name) 1764 1765def _c_complex(self): 1766 ''' 1767 Helper function for handling all structure types. 1768 Called for all structs, requests, replies, events, errors. 1769 ''' 1770 _h_setlevel(0) 1771 _h('') 1772 _h('/**') 1773 _h(' * @brief %s', self.c_type) 1774 _h(' **/') 1775 _h('typedef %s %s {', self.c_container, self.c_type) 1776 1777 struct_fields = [] 1778 maxtypelen = 0 1779 1780 varfield = None 1781 for field in self.fields: 1782 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 1783 varfield = field.c_field_name 1784 continue 1785 if field.wire: 1786 struct_fields.append(field) 1787 1788 for field in struct_fields: 1789 length = len(field.c_field_type) 1790 # account for '*' pointer_spec 1791 if not field.type.fixed_size() and not self.is_union: 1792 length += 1 1793 maxtypelen = max(maxtypelen, length) 1794 1795 def _c_complex_field(self, field, space=''): 1796 if (field.type.fixed_size() or self.is_union or 1797 # in case of switch with switch children, don't make the field a pointer 1798 # necessary for unserialize to work 1799 (self.is_switch and field.type.is_switch)): 1800 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 1801 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 1802 else: 1803 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) 1804 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 1805 1806 if not self.is_switch: 1807 for field in struct_fields: 1808 _c_complex_field(self, field) 1809 else: 1810 for b in self.bitcases: 1811 space = '' 1812 if b.type.has_name: 1813 _h(' struct _%s {', b.c_field_name) 1814 space = ' ' 1815 for field in b.type.fields: 1816 _c_complex_field(self, field, space) 1817 if b.type.has_name: 1818 _h(' } %s;', b.c_field_name) 1819 1820 _h('} %s;', self.c_type) 1821 1822def c_struct(self, name): 1823 ''' 1824 Exported function that handles structure declarations. 1825 ''' 1826 _c_type_setup(self, name, ()) 1827 _c_complex(self) 1828 _c_accessors(self, name, name) 1829 _c_iterator(self, name) 1830 1831def c_union(self, name): 1832 ''' 1833 Exported function that handles union declarations. 1834 ''' 1835 _c_type_setup(self, name, ()) 1836 _c_complex(self) 1837 _c_iterator(self, name) 1838 1839def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False): 1840 ''' 1841 Declares a request function. 1842 ''' 1843 1844 # Four stunningly confusing possibilities here: 1845 # 1846 # Void Non-void 1847 # ------------------------------ 1848 # "req" "req" 1849 # 0 flag CHECKED flag Normal Mode 1850 # void_cookie req_cookie 1851 # ------------------------------ 1852 # "req_checked" "req_unchecked" 1853 # CHECKED flag 0 flag Abnormal Mode 1854 # void_cookie req_cookie 1855 # ------------------------------ 1856 1857 1858 # Whether we are _checked or _unchecked 1859 checked = void and not regular 1860 unchecked = not void and not regular 1861 1862 # What kind of cookie we return 1863 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type 1864 1865 # What flag is passed to xcb_request 1866 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED' 1867 1868 if reply_fds: 1869 if func_flags == '0': 1870 func_flags = 'XCB_REQUEST_REPLY_FDS' 1871 else: 1872 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS' 1873 1874 # Global extension id variable or NULL for xproto 1875 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0' 1876 1877 # What our function name is 1878 func_name = self.c_request_name if not aux else self.c_aux_name 1879 if checked: 1880 func_name = self.c_checked_name if not aux else self.c_aux_checked_name 1881 if unchecked: 1882 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name 1883 1884 param_fields = [] 1885 wire_fields = [] 1886 maxtypelen = len('xcb_connection_t') 1887 serial_fields = [] 1888 # special case: list with variable size elements 1889 list_with_var_size_elems = False 1890 1891 for field in self.fields: 1892 if field.visible: 1893 # The field should appear as a call parameter 1894 param_fields.append(field) 1895 if field.wire and not field.auto: 1896 # We need to set the field up in the structure 1897 wire_fields.append(field) 1898 if field.type.need_serialize or field.type.need_sizeof: 1899 serial_fields.append(field) 1900 1901 for field in param_fields: 1902 c_field_const_type = field.c_field_const_type 1903 if field.type.need_serialize and not aux: 1904 c_field_const_type = "const void" 1905 if len(c_field_const_type) > maxtypelen: 1906 maxtypelen = len(c_field_const_type) 1907 if field.type.is_list and not field.type.member.fixed_size(): 1908 list_with_var_size_elems = True 1909 1910 _h_setlevel(1) 1911 _c_setlevel(1) 1912 _h('') 1913 _h('/**') 1914 if hasattr(self, "doc") and self.doc: 1915 if self.doc.brief: 1916 _h(' * @brief ' + self.doc.brief) 1917 else: 1918 _h(' * No brief doc yet') 1919 1920 _h(' *') 1921 _h(' * @param c The connection') 1922 param_names = [f.c_field_name for f in param_fields] 1923 if hasattr(self, "doc") and self.doc: 1924 for field in param_fields: 1925 # XXX: hard-coded until we fix xproto.xml 1926 base_func_name = self.c_request_name if not aux else self.c_aux_name 1927 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask': 1928 field.enum = 'GC' 1929 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask': 1930 field.enum = 'CW' 1931 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask': 1932 field.enum = 'CW' 1933 if field.enum: 1934 # XXX: why the 'xcb' prefix? 1935 key = ('xcb', field.enum) 1936 1937 tname = _t(key) 1938 if namecount[tname] > 1: 1939 tname = _t(key + ('enum',)) 1940 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname)) 1941 1942 if self.doc and field.field_name in self.doc.fields: 1943 desc = self.doc.fields[field.field_name] 1944 for name in param_names: 1945 desc = desc.replace('`%s`' % name, '\\a %s' % (name)) 1946 desc = desc.split("\n") 1947 desc = [line if line != '' else '\\n' for line in desc] 1948 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc))) 1949 # If there is no documentation yet, we simply don't generate an 1950 # @param tag. Doxygen will then warn about missing documentation. 1951 1952 _h(' * @return A cookie') 1953 _h(' *') 1954 1955 if hasattr(self, "doc") and self.doc: 1956 if self.doc.description: 1957 desc = self.doc.description 1958 for name in param_names: 1959 desc = desc.replace('`%s`' % name, '\\a %s' % (name)) 1960 desc = desc.split("\n") 1961 _h(' * ' + "\n * ".join(desc)) 1962 else: 1963 _h(' * No description yet') 1964 else: 1965 _h(' * Delivers a request to the X server.') 1966 _h(' * ') 1967 if checked: 1968 _h(' * This form can be used only if the request will not cause') 1969 _h(' * a reply to be generated. Any returned error will be') 1970 _h(' * saved for handling by xcb_request_check().') 1971 if unchecked: 1972 _h(' * This form can be used only if the request will cause') 1973 _h(' * a reply to be generated. Any returned error will be') 1974 _h(' * placed in the event queue.') 1975 _h(' */') 1976 _c('') 1977 _hc('') 1978 _hc('/*****************************************************************************') 1979 _hc(' **') 1980 _hc(' ** %s %s', cookie_type, func_name) 1981 _hc(' ** ') 1982 1983 spacing = ' ' * (maxtypelen - len('xcb_connection_t')) 1984 _hc(' ** @param xcb_connection_t%s *c', spacing) 1985 1986 for field in param_fields: 1987 c_field_const_type = field.c_field_const_type 1988 if field.type.need_serialize and not aux: 1989 c_field_const_type = "const void" 1990 spacing = ' ' * (maxtypelen - len(c_field_const_type)) 1991 _hc(' ** @param %s%s %s%s', c_field_const_type, spacing, field.c_pointer, field.c_field_name) 1992 1993 _hc(' ** @returns %s', cookie_type) 1994 _hc(' **') 1995 _hc(' *****************************************************************************/') 1996 _hc(' ') 1997 _hc('%s', cookie_type) 1998 1999 spacing = ' ' * (maxtypelen - len('xcb_connection_t')) 2000 comma = ',' if len(param_fields) else ');' 2001 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 2002 comma = ',' if len(param_fields) else ')' 2003 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 2004 2005 func_spacing = ' ' * (len(func_name) + 2) 2006 count = len(param_fields) 2007 for field in param_fields: 2008 count = count - 1 2009 c_field_const_type = field.c_field_const_type 2010 c_pointer = field.c_pointer 2011 if field.type.need_serialize and not aux: 2012 c_field_const_type = "const void" 2013 c_pointer = '*' 2014 spacing = ' ' * (maxtypelen - len(c_field_const_type)) 2015 comma = ',' if count else ');' 2016 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, 2017 spacing, c_pointer, field.c_field_name, comma) 2018 comma = ',' if count else ')' 2019 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, 2020 spacing, c_pointer, field.c_field_name, comma) 2021 2022 count = 2 2023 if not self.var_followed_by_fixed_fields: 2024 for field in param_fields: 2025 if not field.type.fixed_size(): 2026 count = count + 2 2027 if field.type.need_serialize: 2028 # _serialize() keeps track of padding automatically 2029 count -= 1 2030 dimension = count + 2 2031 2032 _c('{') 2033 _c(' static const xcb_protocol_request_t xcb_req = {') 2034 _c(' /* count */ %d,', count) 2035 _c(' /* ext */ %s,', func_ext_global) 2036 _c(' /* opcode */ %s,', self.c_request_name.upper()) 2037 _c(' /* isvoid */ %d', 1 if void else 0) 2038 _c(' };') 2039 _c(' ') 2040 2041 _c(' struct iovec xcb_parts[%d];', dimension) 2042 _c(' %s xcb_ret;', func_cookie) 2043 _c(' %s xcb_out;', self.c_type) 2044 if self.var_followed_by_fixed_fields: 2045 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */') 2046 _c(' void *xcb_aux = 0;') 2047 2048 2049 for idx, f in enumerate(serial_fields): 2050 if aux: 2051 _c(' void *xcb_aux%d = 0;' % (idx)) 2052 if list_with_var_size_elems: 2053 _c(' unsigned int i;') 2054 _c(' unsigned int xcb_tmp_len;') 2055 _c(' char *xcb_tmp;') 2056 _c(' ') 2057 # simple request call tracing 2058# _c(' printf("in function %s\\n");' % func_name) 2059 2060 # fixed size fields 2061 for field in wire_fields: 2062 if field.type.fixed_size(): 2063 if field.type.is_expr: 2064 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None)) 2065 elif field.type.is_pad: 2066 if field.type.nmemb == 1: 2067 _c(' xcb_out.%s = 0;', field.c_field_name) 2068 else: 2069 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) 2070 else: 2071 if field.type.nmemb == 1: 2072 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) 2073 else: 2074 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) 2075 2076 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'): 2077 serialize_args = get_serialize_params(context, type_obj, 2078 c_field_name, 2079 aux_var)[2] 2080 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) 2081 2082 # calls in order to free dyn. all. memory 2083 free_calls = [] 2084 2085 _c(' ') 2086 if not self.var_followed_by_fixed_fields: 2087 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;') 2088 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);') 2089 _c(' xcb_parts[3].iov_base = 0;') 2090 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') 2091 2092 count = 4 2093 2094 for field in param_fields: 2095 if not field.type.fixed_size(): 2096 _c(' /* %s %s */', field.type.c_type, field.c_field_name) 2097 # default: simple cast to char * 2098 if not field.type.need_serialize and not field.type.need_sizeof: 2099 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) 2100 if field.type.is_list: 2101 if field.type.member.fixed_size(): 2102 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 2103 _c_accessor_get_expr(field.type.expr, None), 2104 field.type.member.c_wiretype) 2105 else: 2106 list_length = _c_accessor_get_expr(field.type.expr, None) 2107 2108 length = '' 2109 _c(" xcb_parts[%d].iov_len = 0;" % count) 2110 _c(" xcb_tmp = (char *)%s;", field.c_field_name) 2111 _c(" for(i=0; i<%s; i++) {" % list_length) 2112 _c(" xcb_tmp_len = %s(xcb_tmp);" % 2113 (field.type.c_sizeof_name)) 2114 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count) 2115 _c(" xcb_tmp += xcb_tmp_len;") 2116 _c(" }") 2117 else: 2118 # not supposed to happen 2119 raise Exception("unhandled variable size field %s" % field.c_field_name) 2120 else: 2121 if not aux: 2122 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) 2123 idx = serial_fields.index(field) 2124 aux_var = '&xcb_aux%d' % idx 2125 context = 'serialize' if aux else 'sizeof' 2126 _c(' xcb_parts[%d].iov_len = ', count) 2127 if aux: 2128 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context) 2129 _c(' %s (%s);', field.type.c_serialize_name, serialize_args) 2130 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx)) 2131 free_calls.append(' free(xcb_aux%d);' % idx) 2132 else: 2133 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context) 2134 func_name = field.type.c_sizeof_name 2135 _c(' %s (%s);', func_name, serialize_args) 2136 2137 count += 1 2138 if not (field.type.need_serialize or field.type.need_sizeof): 2139 # the _serialize() function keeps track of padding automatically 2140 _c(' xcb_parts[%d].iov_base = 0;', count) 2141 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1) 2142 count += 1 2143 2144 # elif self.var_followed_by_fixed_fields: 2145 else: 2146 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;') 2147 # request header: opcodes + length 2148 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);') 2149 count += 1 2150 # call _serialize() 2151 buffer_var = '&xcb_aux' 2152 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize') 2153 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args) 2154 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count) 2155 free_calls.append(' free(xcb_aux);') 2156 # no padding necessary - _serialize() keeps track of padding automatically 2157 2158 _c(' ') 2159 for field in param_fields: 2160 if field.isfd: 2161 _c(' xcb_send_fd(c, %s);', field.c_field_name) 2162 2163 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) 2164 2165 # free dyn. all. data, if any 2166 for f in free_calls: 2167 _c(f) 2168 _c(' return xcb_ret;') 2169 _c('}') 2170 2171def _c_reply(self, name): 2172 ''' 2173 Declares the function that returns the reply structure. 2174 ''' 2175 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t')) 2176 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t')) 2177 spacing3 = ' ' * (len(self.c_reply_name) + 2) 2178 2179 # check if _unserialize() has to be called for any field 2180 def look_for_special_cases(complex_obj): 2181 unserialize_fields = [] 2182 # no unserialize call in case of switch 2183 if not complex_obj.is_switch: 2184 for field in complex_obj.fields: 2185 # three cases: 1. field with special case 2186 # 2. container that contains special case field 2187 # 3. list with special case elements 2188 if field.type.var_followed_by_fixed_fields: 2189 unserialize_fields.append(field) 2190 elif field.type.is_container: 2191 unserialize_fields += look_for_special_cases(field.type) 2192 elif field.type.is_list: 2193 if field.type.member.var_followed_by_fixed_fields: 2194 unserialize_fields.append(field) 2195 if field.type.member.is_container: 2196 unserialize_fields += look_for_special_cases(field.type.member) 2197 return unserialize_fields 2198 2199 unserialize_fields = look_for_special_cases(self.reply) 2200 2201 _h('') 2202 _h('/**') 2203 _h(' * Return the reply') 2204 _h(' * @param c The connection') 2205 _h(' * @param cookie The cookie') 2206 _h(' * @param e The xcb_generic_error_t supplied') 2207 _h(' *') 2208 _h(' * Returns the reply of the request asked by') 2209 _h(' * ') 2210 _h(' * The parameter @p e supplied to this function must be NULL if') 2211 _h(' * %s(). is used.', self.c_unchecked_name) 2212 _h(' * Otherwise, it stores the error if any.') 2213 _h(' *') 2214 _h(' * The returned value must be freed by the caller using free().') 2215 _h(' */') 2216 _c('') 2217 _hc('') 2218 _hc('/*****************************************************************************') 2219 _hc(' **') 2220 _hc(' ** %s * %s', self.c_reply_type, self.c_reply_name) 2221 _hc(' ** ') 2222 _hc(' ** @param xcb_connection_t%s *c', spacing1) 2223 _hc(' ** @param %s cookie', self.c_cookie_type) 2224 _hc(' ** @param xcb_generic_error_t%s **e', spacing2) 2225 _hc(' ** @returns %s *', self.c_reply_type) 2226 _hc(' **') 2227 _hc(' *****************************************************************************/') 2228 _hc(' ') 2229 _hc('%s *', self.c_reply_type) 2230 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1) 2231 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type) 2232 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2) 2233 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2) 2234 _c('{') 2235 2236 if len(unserialize_fields)>0: 2237 # certain variable size fields need to be unserialized explicitly 2238 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', 2239 self.c_reply_type, self.c_reply_type) 2240 _c(' int i;') 2241 for field in unserialize_fields: 2242 if field.type.is_list: 2243 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name) 2244 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name) 2245 _c(' %s *%s_data;', field.c_field_type, field.c_field_name) 2246 else: 2247 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type) 2248 # call _unserialize(), using the reply as source and target buffer 2249 _c(' /* special cases: transform parts of the reply to match XCB data structures */') 2250 for field in unserialize_fields: 2251 if field.type.is_list: 2252 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name) 2253 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name) 2254 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name, 2255 field.c_field_name, field.c_field_name) 2256 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name) 2257 _c(' }') 2258 # return the transformed reply 2259 _c(' return reply;') 2260 2261 else: 2262 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type) 2263 2264 _c('}') 2265 2266def _c_reply_has_fds(self): 2267 for field in self.fields: 2268 if field.isfd: 2269 return True 2270 return False 2271 2272def _c_reply_fds(self, name): 2273 ''' 2274 Declares the function that returns fds related to the reply. 2275 ''' 2276 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t')) 2277 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2) 2278 _h('') 2279 _h('/**') 2280 _h(' * Return the reply fds') 2281 _h(' * @param c The connection') 2282 _h(' * @param reply The reply') 2283 _h(' *') 2284 _h(' * Returns the array of reply fds of the request asked by') 2285 _h(' * ') 2286 _h(' * The returned value must be freed by the caller using free().') 2287 _h(' */') 2288 _c('') 2289 _hc('') 2290 _hc('/*****************************************************************************') 2291 _hc(' **') 2292 _hc(' ** int * %s', self.c_reply_fds_name) 2293 _hc(' ** ') 2294 _hc(' ** @param xcb_connection_t%s *c', spacing1) 2295 _hc(' ** @param %s *reply', self.c_reply_type) 2296 _hc(' ** @returns int *') 2297 _hc(' **') 2298 _hc(' *****************************************************************************/') 2299 _hc(' ') 2300 _hc('int *') 2301 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1) 2302 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type) 2303 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type) 2304 _c('{') 2305 2306 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type) 2307 2308 _c('}') 2309 2310 2311def _c_opcode(name, opcode): 2312 ''' 2313 Declares the opcode define for requests, events, and errors. 2314 ''' 2315 _h_setlevel(0) 2316 _h('') 2317 _h('/** Opcode for %s. */', _n(name)) 2318 _h('#define %s %s', _n(name).upper(), opcode) 2319 2320def _c_cookie(self, name): 2321 ''' 2322 Declares the cookie type for a non-void request. 2323 ''' 2324 _h_setlevel(0) 2325 _h('') 2326 _h('/**') 2327 _h(' * @brief %s', self.c_cookie_type) 2328 _h(' **/') 2329 _h('typedef struct %s {', self.c_cookie_type) 2330 _h(' unsigned int sequence; /**< */') 2331 _h('} %s;', self.c_cookie_type) 2332 2333def _man_request(self, name, cookie_type, void, aux): 2334 param_fields = [f for f in self.fields if f.visible] 2335 2336 func_name = self.c_request_name if not aux else self.c_aux_name 2337 2338 def create_link(linkname): 2339 name = 'man/%s.3' % linkname 2340 if manpaths: 2341 sys.stdout.write(name) 2342 f = open(name, 'w') 2343 f.write('.so man3/%s.3' % func_name) 2344 f.close() 2345 2346 if manpaths: 2347 sys.stdout.write('man/%s.3 ' % func_name) 2348 # Our CWD is src/, so this will end up in src/man/ 2349 f = open('man/%s.3' % func_name, 'w') 2350 f.write('.TH %s 3 %s "XCB" "XCB Requests"\n' % (func_name, today)) 2351 # Left-adjust instead of adjusting to both sides 2352 f.write('.ad l\n') 2353 f.write('.SH NAME\n') 2354 brief = self.doc.brief if hasattr(self, "doc") and self.doc else '' 2355 f.write('%s \\- %s\n' % (func_name, brief)) 2356 f.write('.SH SYNOPSIS\n') 2357 # Don't split words (hyphenate) 2358 f.write('.hy 0\n') 2359 f.write('.B #include <xcb/%s.h>\n' % _ns.header) 2360 2361 # function prototypes 2362 prototype = '' 2363 count = len(param_fields) 2364 for field in param_fields: 2365 count = count - 1 2366 c_field_const_type = field.c_field_const_type 2367 c_pointer = field.c_pointer 2368 if c_pointer == ' ': 2369 c_pointer = '' 2370 if field.type.need_serialize and not aux: 2371 c_field_const_type = "const void" 2372 c_pointer = '*' 2373 comma = ', ' if count else ');' 2374 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma) 2375 2376 f.write('.SS Request function\n') 2377 f.write('.HP\n') 2378 base_func_name = self.c_request_name if not aux else self.c_aux_name 2379 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype)) 2380 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked'))) 2381 if not void: 2382 f.write('.PP\n') 2383 f.write('.SS Reply datastructure\n') 2384 f.write('.nf\n') 2385 f.write('.sp\n') 2386 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type)) 2387 struct_fields = [] 2388 maxtypelen = 0 2389 2390 for field in self.reply.fields: 2391 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 2392 continue 2393 if field.wire: 2394 struct_fields.append(field) 2395 2396 for field in struct_fields: 2397 length = len(field.c_field_type) 2398 # account for '*' pointer_spec 2399 if not field.type.fixed_size(): 2400 length += 1 2401 maxtypelen = max(maxtypelen, length) 2402 2403 def _c_complex_field(self, field, space=''): 2404 if (field.type.fixed_size() or 2405 # in case of switch with switch children, don't make the field a pointer 2406 # necessary for unserialize to work 2407 (self.is_switch and field.type.is_switch)): 2408 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 2409 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)) 2410 else: 2411 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) 2412 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name)) 2413 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 2414 2415 if not self.is_switch: 2416 for field in struct_fields: 2417 _c_complex_field(self, field) 2418 else: 2419 for b in self.bitcases: 2420 space = '' 2421 if b.type.has_name: 2422 space = ' ' 2423 for field in b.type.fields: 2424 _c_complex_field(self, field, space) 2425 if b.type.has_name: 2426 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2427 pass 2428 2429 f.write('} \\fB%s\\fP;\n' % self.reply.c_type) 2430 f.write('.fi\n') 2431 2432 f.write('.SS Reply function\n') 2433 f.write('.HP\n') 2434 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ ' 2435 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') % 2436 (self.c_reply_type, self.c_reply_name, self.c_cookie_type)) 2437 create_link('%s' % self.c_reply_name) 2438 2439 has_accessors = False 2440 for field in self.reply.fields: 2441 if field.type.is_list and not field.type.fixed_size(): 2442 has_accessors = True 2443 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2444 has_accessors = True 2445 2446 if has_accessors: 2447 f.write('.SS Reply accessors\n') 2448 2449 def _c_accessors_field(self, field): 2450 ''' 2451 Declares the accessor functions for a non-list field that follows a variable-length field. 2452 ''' 2453 c_type = self.c_type 2454 2455 # special case: switch 2456 switch_obj = self if self.is_switch else None 2457 if self.is_bitcase: 2458 switch_obj = self.parents[-1] 2459 if switch_obj is not None: 2460 c_type = switch_obj.c_type 2461 2462 if field.type.is_simple: 2463 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type)) 2464 create_link('%s' % field.c_accessor_name) 2465 else: 2466 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type)) 2467 create_link('%s' % field.c_accessor_name) 2468 2469 def _c_accessors_list(self, field): 2470 ''' 2471 Declares the accessor functions for a list field. 2472 Declares a direct-accessor function only if the list members are fixed size. 2473 Declares length and get-iterator functions always. 2474 ''' 2475 list = field.type 2476 c_type = self.reply.c_type 2477 2478 # special case: switch 2479 # in case of switch, 2 params have to be supplied to certain accessor functions: 2480 # 1. the anchestor object (request or reply) 2481 # 2. the (anchestor) switch object 2482 # the reason is that switch is either a child of a request/reply or nested in another switch, 2483 # so whenever we need to access a length field, we might need to refer to some anchestor type 2484 switch_obj = self if self.is_switch else None 2485 if self.is_bitcase: 2486 switch_obj = self.parents[-1] 2487 if switch_obj is not None: 2488 c_type = switch_obj.c_type 2489 2490 params = [] 2491 fields = {} 2492 parents = self.parents if hasattr(self, 'parents') else [self] 2493 # 'R': parents[0] is always the 'toplevel' container type 2494 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0])) 2495 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True)) 2496 # auxiliary object for 'R' parameters 2497 R_obj = parents[0] 2498 2499 if switch_obj is not None: 2500 # now look where the fields are defined that are needed to evaluate 2501 # the switch expr, and store the parent objects in accessor_params and 2502 # the fields in switch_fields 2503 2504 # 'S': name for the 'toplevel' switch 2505 toplevel_switch = parents[1] 2506 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch)) 2507 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True)) 2508 2509 # initialize prefix for everything "below" S 2510 prefix_str = '/* %s */ S' % toplevel_switch.name[-1] 2511 prefix = [(prefix_str, '->', toplevel_switch)] 2512 2513 # look for fields in the remaining containers 2514 for p in parents[2:] + [self]: 2515 # the separator between parent and child is always '.' here, 2516 # because of nested switch statements 2517 if not p.is_bitcase or (p.is_bitcase and p.has_name): 2518 prefix.append((p.name[-1], '.', p)) 2519 fields.update(_c_helper_field_mapping(p, prefix, flat=True)) 2520 2521 # auxiliary object for 'S' parameter 2522 S_obj = parents[1] 2523 2524 if list.member.fixed_size(): 2525 idx = 1 if switch_obj is not None else 0 2526 f.write('.HP\n') 2527 f.write('%s *\\fB%s\\fP(%s);\n' % 2528 (field.c_field_type, field.c_accessor_name, params[idx][0])) 2529 create_link('%s' % field.c_accessor_name) 2530 2531 f.write('.HP\n') 2532 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2533 (field.c_length_name, c_type)) 2534 create_link('%s' % field.c_length_name) 2535 2536 if field.type.member.is_simple: 2537 f.write('.HP\n') 2538 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2539 (field.c_end_name, c_type)) 2540 create_link('%s' % field.c_end_name) 2541 else: 2542 f.write('.HP\n') 2543 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2544 (field.c_iterator_type, field.c_iterator_name, 2545 c_type)) 2546 create_link('%s' % field.c_iterator_name) 2547 2548 for field in self.reply.fields: 2549 if field.type.is_list and not field.type.fixed_size(): 2550 _c_accessors_list(self, field) 2551 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2552 _c_accessors_field(self, field) 2553 2554 2555 f.write('.br\n') 2556 # Re-enable hyphenation and adjusting to both sides 2557 f.write('.hy 1\n') 2558 2559 # argument reference 2560 f.write('.SH REQUEST ARGUMENTS\n') 2561 f.write('.IP \\fI%s\\fP 1i\n' % 'conn') 2562 f.write('The XCB connection to X11.\n') 2563 for field in param_fields: 2564 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2565 printed_enum = False 2566 # XXX: hard-coded until we fix xproto.xml 2567 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask': 2568 field.enum = 'GC' 2569 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask': 2570 field.enum = 'CW' 2571 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask': 2572 field.enum = 'CW' 2573 if hasattr(field, "enum") and field.enum: 2574 # XXX: why the 'xcb' prefix? 2575 key = ('xcb', field.enum) 2576 if key in enums: 2577 f.write('One of the following values:\n') 2578 f.write('.RS 1i\n') 2579 enum = enums[key] 2580 count = len(enum.values) 2581 for (enam, eval) in enum.values: 2582 count = count - 1 2583 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper())) 2584 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields: 2585 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam]) 2586 f.write('%s\n' % desc) 2587 else: 2588 f.write('TODO: NOT YET DOCUMENTED.\n') 2589 f.write('.RE\n') 2590 f.write('.RS 1i\n') 2591 printed_enum = True 2592 2593 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields: 2594 desc = self.doc.fields[field.field_name] 2595 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2596 if printed_enum: 2597 f.write('\n') 2598 f.write('%s\n' % desc) 2599 else: 2600 f.write('TODO: NOT YET DOCUMENTED.\n') 2601 if printed_enum: 2602 f.write('.RE\n') 2603 2604 # Reply reference 2605 if not void: 2606 f.write('.SH REPLY FIELDS\n') 2607 # These fields are present in every reply: 2608 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type') 2609 f.write(('The type of this reply, in this case \\fI%s\\fP. This field ' 2610 'is also present in the \\fIxcb_generic_reply_t\\fP and can ' 2611 'be used to tell replies apart from each other.\n') % 2612 _n(self.reply.name).upper()) 2613 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence') 2614 f.write('The sequence number of the last request processed by the X11 server.\n') 2615 f.write('.IP \\fI%s\\fP 1i\n' % 'length') 2616 f.write('The length of the reply, in words (a word is 4 bytes).\n') 2617 for field in self.reply.fields: 2618 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or 2619 field.c_field_name.startswith('pad')): 2620 continue 2621 2622 if field.type.is_list and not field.type.fixed_size(): 2623 continue 2624 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2625 continue 2626 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2627 printed_enum = False 2628 if hasattr(field, "enum") and field.enum: 2629 # XXX: why the 'xcb' prefix? 2630 key = ('xcb', field.enum) 2631 if key in enums: 2632 f.write('One of the following values:\n') 2633 f.write('.RS 1i\n') 2634 enum = enums[key] 2635 count = len(enum.values) 2636 for (enam, eval) in enum.values: 2637 count = count - 1 2638 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper())) 2639 if enum.doc and enam in enum.doc.fields: 2640 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam]) 2641 f.write('%s\n' % desc) 2642 else: 2643 f.write('TODO: NOT YET DOCUMENTED.\n') 2644 f.write('.RE\n') 2645 f.write('.RS 1i\n') 2646 printed_enum = True 2647 2648 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields: 2649 desc = self.reply.doc.fields[field.field_name] 2650 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2651 if printed_enum: 2652 f.write('\n') 2653 f.write('%s\n' % desc) 2654 else: 2655 f.write('TODO: NOT YET DOCUMENTED.\n') 2656 if printed_enum: 2657 f.write('.RE\n') 2658 2659 2660 2661 # text description 2662 f.write('.SH DESCRIPTION\n') 2663 if hasattr(self, "doc") and self.doc and self.doc.description: 2664 desc = self.doc.description 2665 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2666 lines = desc.split('\n') 2667 f.write('\n'.join(lines) + '\n') 2668 2669 f.write('.SH RETURN VALUE\n') 2670 if void: 2671 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) ' 2672 'have to be handled in the event loop.\n\nIf you want to ' 2673 'handle errors directly with \\fIxcb_request_check\\fP ' 2674 'instead, use \\fI%s_checked\\fP. See ' 2675 '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name)) 2676 else: 2677 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when ' 2678 'calling the reply function \\fI%s\\fP.\n\nIf you want to ' 2679 'handle errors in the event loop instead, use ' 2680 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for ' 2681 'details.\n') % 2682 (cookie_type, self.c_reply_name, base_func_name)) 2683 f.write('.SH ERRORS\n') 2684 if hasattr(self, "doc") and self.doc: 2685 for errtype, errtext in self.doc.errors.items(): 2686 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error')))) 2687 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext) 2688 f.write('%s\n' % (errtext)) 2689 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0: 2690 f.write('This request does never generate any errors.\n') 2691 if hasattr(self, "doc") and self.doc and self.doc.example: 2692 f.write('.SH EXAMPLE\n') 2693 f.write('.nf\n') 2694 f.write('.sp\n') 2695 lines = self.doc.example.split('\n') 2696 f.write('\n'.join(lines) + '\n') 2697 f.write('.fi\n') 2698 f.write('.SH SEE ALSO\n') 2699 if hasattr(self, "doc") and self.doc: 2700 see = ['.BR %s (3)' % 'xcb-requests'] 2701 if self.doc.example: 2702 see.append('.BR %s (3)' % 'xcb-examples') 2703 for seename, seetype in self.doc.see.items(): 2704 if seetype == 'program': 2705 see.append('.BR %s (1)' % seename) 2706 elif seetype == 'event': 2707 see.append('.BR %s (3)' % _t(('xcb', seename, 'event'))) 2708 elif seetype == 'request': 2709 see.append('.BR %s (3)' % _n(('xcb', seename))) 2710 elif seetype == 'function': 2711 see.append('.BR %s (3)' % seename) 2712 else: 2713 see.append('TODO: %s (type %s)' % (seename, seetype)) 2714 f.write(',\n'.join(see) + '\n') 2715 f.write('.SH AUTHOR\n') 2716 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header) 2717 f.close() 2718 2719def _man_event(self, name): 2720 if manpaths: 2721 sys.stdout.write('man/%s.3 ' % self.c_type) 2722 # Our CWD is src/, so this will end up in src/man/ 2723 f = open('man/%s.3' % self.c_type, 'w') 2724 f.write('.TH %s 3 %s "XCB" "XCB Events"\n' % (self.c_type, today)) 2725 # Left-adjust instead of adjusting to both sides 2726 f.write('.ad l\n') 2727 f.write('.SH NAME\n') 2728 brief = self.doc.brief if hasattr(self, "doc") and self.doc else '' 2729 f.write('%s \\- %s\n' % (self.c_type, brief)) 2730 f.write('.SH SYNOPSIS\n') 2731 # Don't split words (hyphenate) 2732 f.write('.hy 0\n') 2733 f.write('.B #include <xcb/%s.h>\n' % _ns.header) 2734 2735 f.write('.PP\n') 2736 f.write('.SS Event datastructure\n') 2737 f.write('.nf\n') 2738 f.write('.sp\n') 2739 f.write('typedef %s %s {\n' % (self.c_container, self.c_type)) 2740 struct_fields = [] 2741 maxtypelen = 0 2742 2743 for field in self.fields: 2744 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 2745 continue 2746 if field.wire: 2747 struct_fields.append(field) 2748 2749 for field in struct_fields: 2750 length = len(field.c_field_type) 2751 # account for '*' pointer_spec 2752 if not field.type.fixed_size(): 2753 length += 1 2754 maxtypelen = max(maxtypelen, length) 2755 2756 def _c_complex_field(self, field, space=''): 2757 if (field.type.fixed_size() or 2758 # in case of switch with switch children, don't make the field a pointer 2759 # necessary for unserialize to work 2760 (self.is_switch and field.type.is_switch)): 2761 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 2762 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)) 2763 else: 2764 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2765 2766 if not self.is_switch: 2767 for field in struct_fields: 2768 _c_complex_field(self, field) 2769 else: 2770 for b in self.bitcases: 2771 space = '' 2772 if b.type.has_name: 2773 space = ' ' 2774 for field in b.type.fields: 2775 _c_complex_field(self, field, space) 2776 if b.type.has_name: 2777 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2778 pass 2779 2780 f.write('} \\fB%s\\fP;\n' % self.c_type) 2781 f.write('.fi\n') 2782 2783 2784 f.write('.br\n') 2785 # Re-enable hyphenation and adjusting to both sides 2786 f.write('.hy 1\n') 2787 2788 # argument reference 2789 f.write('.SH EVENT FIELDS\n') 2790 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type') 2791 f.write(('The type of this event, in this case \\fI%s\\fP. This field is ' 2792 'also present in the \\fIxcb_generic_event_t\\fP and can be used ' 2793 'to tell events apart from each other.\n') % _n(name).upper()) 2794 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence') 2795 f.write('The sequence number of the last request processed by the X11 server.\n') 2796 2797 if not self.is_switch: 2798 for field in struct_fields: 2799 # Skip the fields which every event has, we already documented 2800 # them (see above). 2801 if field.c_field_name in ('response_type', 'sequence'): 2802 continue 2803 if isinstance(field.type, PadType): 2804 continue 2805 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2806 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields: 2807 desc = self.doc.fields[field.field_name] 2808 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2809 f.write('%s\n' % desc) 2810 else: 2811 f.write('NOT YET DOCUMENTED.\n') 2812 2813 # text description 2814 f.write('.SH DESCRIPTION\n') 2815 if hasattr(self, "doc") and self.doc and self.doc.description: 2816 desc = self.doc.description 2817 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2818 lines = desc.split('\n') 2819 f.write('\n'.join(lines) + '\n') 2820 2821 if hasattr(self, "doc") and self.doc and self.doc.example: 2822 f.write('.SH EXAMPLE\n') 2823 f.write('.nf\n') 2824 f.write('.sp\n') 2825 lines = self.doc.example.split('\n') 2826 f.write('\n'.join(lines) + '\n') 2827 f.write('.fi\n') 2828 f.write('.SH SEE ALSO\n') 2829 if hasattr(self, "doc") and self.doc: 2830 see = ['.BR %s (3)' % 'xcb_generic_event_t'] 2831 if self.doc.example: 2832 see.append('.BR %s (3)' % 'xcb-examples') 2833 for seename, seetype in self.doc.see.items(): 2834 if seetype == 'program': 2835 see.append('.BR %s (1)' % seename) 2836 elif seetype == 'event': 2837 see.append('.BR %s (3)' % _t(('xcb', seename, 'event'))) 2838 elif seetype == 'request': 2839 see.append('.BR %s (3)' % _n(('xcb', seename))) 2840 elif seetype == 'function': 2841 see.append('.BR %s (3)' % seename) 2842 else: 2843 see.append('TODO: %s (type %s)' % (seename, seetype)) 2844 f.write(',\n'.join(see) + '\n') 2845 f.write('.SH AUTHOR\n') 2846 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header) 2847 f.close() 2848 2849 2850def c_request(self, name): 2851 ''' 2852 Exported function that handles request declarations. 2853 ''' 2854 _c_type_setup(self, name, ('request',)) 2855 2856 if self.reply: 2857 # Cookie type declaration 2858 _c_cookie(self, name) 2859 2860 # Opcode define 2861 _c_opcode(name, self.opcode) 2862 2863 # Request structure declaration 2864 _c_complex(self) 2865 2866 if self.reply: 2867 _c_type_setup(self.reply, name, ('reply',)) 2868 # Reply structure definition 2869 _c_complex(self.reply) 2870 # Request prototypes 2871 has_fds = _c_reply_has_fds(self.reply) 2872 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds) 2873 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds) 2874 if self.need_aux: 2875 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds) 2876 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds) 2877 # Reply accessors 2878 _c_accessors(self.reply, name + ('reply',), name) 2879 _c_reply(self, name) 2880 if has_fds: 2881 _c_reply_fds(self, name) 2882 else: 2883 # Request prototypes 2884 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False) 2885 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True) 2886 if self.need_aux: 2887 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True) 2888 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True) 2889 2890 # We generate the manpage afterwards because _c_type_setup has been called. 2891 # TODO: what about aux helpers? 2892 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t' 2893 _man_request(self, name, cookie_type, not self.reply, False) 2894 2895def c_event(self, name): 2896 ''' 2897 Exported function that handles event declarations. 2898 ''' 2899 2900 # The generic event structure xcb_ge_event_t has the full_sequence field 2901 # at the 32byte boundary. That's why we've to inject this field into GE 2902 # events while generating the structure for them. Otherwise we would read 2903 # garbage (the internal full_sequence) when accessing normal event fields 2904 # there. 2905 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name: 2906 event_size = 0 2907 for field in self.fields: 2908 if field.type.size != None and field.type.nmemb != None: 2909 event_size += field.type.size * field.type.nmemb 2910 if event_size == 32: 2911 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True) 2912 idx = self.fields.index(field) 2913 self.fields.insert(idx + 1, full_sequence) 2914 break 2915 2916 _c_type_setup(self, name, ('event',)) 2917 2918 # Opcode define 2919 _c_opcode(name, self.opcodes[name]) 2920 2921 if self.name == name: 2922 # Structure definition 2923 _c_complex(self) 2924 else: 2925 # Typedef 2926 _h('') 2927 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',))) 2928 2929 _man_event(self, name) 2930 2931def c_error(self, name): 2932 ''' 2933 Exported function that handles error declarations. 2934 ''' 2935 _c_type_setup(self, name, ('error',)) 2936 2937 # Opcode define 2938 _c_opcode(name, self.opcodes[name]) 2939 2940 if self.name == name: 2941 # Structure definition 2942 _c_complex(self) 2943 else: 2944 # Typedef 2945 _h('') 2946 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',))) 2947 2948 2949# Main routine starts here 2950 2951# Must create an "output" dictionary before any xcbgen imports. 2952output = {'open' : c_open, 2953 'close' : c_close, 2954 'simple' : c_simple, 2955 'enum' : c_enum, 2956 'struct' : c_struct, 2957 'union' : c_union, 2958 'request' : c_request, 2959 'event' : c_event, 2960 'error' : c_error, 2961 } 2962 2963# Boilerplate below this point 2964 2965# Check for the argument that specifies path to the xcbgen python package. 2966try: 2967 opts, args = getopt.getopt(sys.argv[1:], 'p:m') 2968except getopt.GetoptError as err: 2969 print(err) 2970 print('Usage: c_client.py [-p path] file.xml') 2971 sys.exit(1) 2972 2973for (opt, arg) in opts: 2974 if opt == '-p': 2975 sys.path.insert(1, arg) 2976 elif opt == '-m': 2977 manpaths = True 2978 sys.stdout.write('man_MANS = ') 2979 2980# Import the module class 2981try: 2982 from xcbgen.state import Module 2983 from xcbgen.xtypes import * 2984except ImportError: 2985 print(''' 2986Failed to load the xcbgen Python package! 2987Make sure that xcb/proto installed it on your Python path. 2988If not, you will need to create a .pth file or define $PYTHONPATH 2989to extend the path. 2990Refer to the README file in xcb/proto for more info. 2991''') 2992 raise 2993 2994# Ensure the man subdirectory exists 2995try: 2996 os.mkdir('man') 2997except OSError as e: 2998 if e.errno != errno.EEXIST: 2999 raise 3000 3001today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0]))) 3002 3003# Parse the xml header 3004module = Module(args[0], output) 3005 3006# Build type-registry and resolve type dependencies 3007module.register() 3008module.resolve() 3009 3010# Output the code 3011module.generate() 3012