c_client.py revision 1c7386f4
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.direct_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.c_need_aux = False 309 self.c_need_serialize = False 310 self.c_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.c_var_followed_by_fixed_fields = False 322 323 if self.is_switch: 324 self.c_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.c_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.c_need_aux = True 361 elif not field.type.fixed_size() and not field.type.is_bitcase: 362 self.c_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.c_need_serialize = True 383 self.c_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.c_var_followed_by_fixed_fields: 390 if field.type.fixed_size(): 391 field.prev_varsized_field = None 392 393 if self.c_need_serialize: 394 # when _unserialize() is wanted, create _sizeof() as well for consistency reasons 395 self.c_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.c_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.c_var_followed_by_fixed_fields: 420 _c_serialize('unserialize', self) 421 422 if self.c_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.c_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.c_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.c_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 if field.type.is_pad: 985 # Variable length pad is <pad align= /> 986 code_lines.append('%s xcb_align_to = %d;' % (space, field.type.align)) 987 count += _c_serialize_helper_insert_padding(context, code_lines, space, 988 self.c_var_followed_by_fixed_fields) 989 continue 990 else: 991 # switch/bitcase: always calculate padding before and after variable sized fields 992 if need_padding or is_bitcase: 993 count += _c_serialize_helper_insert_padding(context, code_lines, space, 994 self.c_var_followed_by_fixed_fields) 995 996 value, length = _c_serialize_helper_fields_variable_size(context, self, field, 997 code_lines, temp_vars, 998 space, prefix) 999 prev_field_was_variable = True 1000 1001 # save (un)serialization C code 1002 if '' != value: 1003 code_lines.append('%s%s' % (space, value)) 1004 1005 if field.type.fixed_size(): 1006 if is_bitcase or self.c_var_followed_by_fixed_fields: 1007 # keep track of (un)serialized object's size 1008 code_lines.append('%s xcb_block_len += %s;' % (space, length)) 1009 if context in ('unserialize', 'unpack', 'sizeof'): 1010 code_lines.append('%s xcb_tmp += %s;' % (space, length)) 1011 else: 1012 # variable size objects or bitcase: 1013 # value & length might have been inserted earlier for special cases 1014 if '' != length: 1015 # special case: intermixed fixed and variable size fields 1016 if (not field.type.fixed_size() and 1017 self.c_var_followed_by_fixed_fields and 'unserialize' == context): 1018 temp_vars.append(' int %s_len;' % field.c_field_name) 1019 code_lines.append('%s %s_len = %s;' % (space, field.c_field_name, length)) 1020 code_lines.append('%s xcb_block_len += %s_len;' % (space, field.c_field_name)) 1021 code_lines.append('%s xcb_tmp += %s_len;' % (space, field.c_field_name)) 1022 else: 1023 code_lines.append('%s xcb_block_len += %s;' % (space, length)) 1024 # increase pointer into the byte stream accordingly 1025 if context in ('unserialize', 'sizeof', 'unpack'): 1026 code_lines.append('%s xcb_tmp += xcb_block_len;' % space) 1027 1028 if 'serialize' == context: 1029 if '' != length: 1030 code_lines.append('%s xcb_parts[xcb_parts_idx].iov_len = %s;' % (space, length)) 1031 code_lines.append('%s xcb_parts_idx++;' % space) 1032 count += 1 1033 1034 code_lines.append('%s xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type)) 1035 1036 need_padding = True 1037 if self.c_var_followed_by_fixed_fields: 1038 need_padding = False 1039 1040 return count 1041# _c_serialize_helper_fields() 1042 1043def _c_serialize_helper(context, complex_type, 1044 code_lines, temp_vars, 1045 space='', prefix=[]): 1046 # count tracks the number of fields to serialize 1047 count = 0 1048 1049 if hasattr(complex_type, 'type'): 1050 self = complex_type.type 1051 complex_name = complex_type.name 1052 else: 1053 self = complex_type 1054 if self.c_var_followed_by_fixed_fields and 'unserialize' == context: 1055 complex_name = 'xcb_out' 1056 else: 1057 complex_name = '_aux' 1058 1059 # special case: switch is serialized by evaluating each bitcase separately 1060 if self.is_switch: 1061 count += _c_serialize_helper_switch(context, self, complex_name, 1062 code_lines, temp_vars, 1063 space, prefix) 1064 1065 # all other data types can be evaluated one field a time 1066 else: 1067 # unserialize & fixed size fields: simply cast the buffer to the respective xcb_out type 1068 if context in ('unserialize', 'unpack', 'sizeof') and not self.c_var_followed_by_fixed_fields: 1069 code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type)) 1070 code_lines.append('%s xcb_tmp += xcb_block_len;' % space) 1071 code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space) 1072 code_lines.append('%s xcb_block_len = 0;' % space) 1073 1074 count += _c_serialize_helper_fields(context, self, 1075 code_lines, temp_vars, 1076 space, prefix, False) 1077 # "final padding" 1078 count += _c_serialize_helper_insert_padding(context, code_lines, space, False) 1079 1080 return count 1081# _c_serialize_helper() 1082 1083def _c_serialize(context, self): 1084 """ 1085 depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof() 1086 for the ComplexType variable self 1087 """ 1088 _h_setlevel(1) 1089 _c_setlevel(1) 1090 1091 _hc('') 1092 # _serialize() returns the buffer size 1093 _hc('int') 1094 1095 if self.is_switch and 'unserialize' == context: 1096 context = 'unpack' 1097 1098 cases = { 'serialize' : self.c_serialize_name, 1099 'unserialize' : self.c_unserialize_name, 1100 'unpack' : self.c_unpack_name, 1101 'sizeof' : self.c_sizeof_name } 1102 func_name = cases[context] 1103 1104 param_fields, wire_fields, params = get_serialize_params(context, self) 1105 variable_size_fields = 0 1106 # maximum space required for type definition of function arguments 1107 maxtypelen = 0 1108 1109 # determine N(variable_fields) 1110 for field in param_fields: 1111 # if self.is_switch, treat all fields as if they are variable sized 1112 if not field.type.fixed_size() or self.is_switch: 1113 variable_size_fields += 1 1114 # determine maxtypelen 1115 for p in params: 1116 maxtypelen = max(maxtypelen, len(p[0]) + len(p[1])) 1117 1118 # write to .c/.h 1119 indent = ' '*(len(func_name)+2) 1120 param_str = [] 1121 for p in params: 1122 typespec, pointerspec, field_name = p 1123 spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) 1124 param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)) 1125 # insert function name 1126 param_str[0] = "%s (%s" % (func_name, param_str[0].strip()) 1127 param_str = list(map(lambda x: "%s," % x, param_str)) 1128 for s in param_str[:-1]: 1129 _hc(s) 1130 _h("%s);" % param_str[-1].rstrip(',')) 1131 _c("%s)" % param_str[-1].rstrip(',')) 1132 _c('{') 1133 1134 code_lines = [] 1135 temp_vars = [] 1136 prefix = [] 1137 1138 if 'serialize' == context: 1139 if not self.is_switch and not self.c_var_followed_by_fixed_fields: 1140 _c(' %s *xcb_out = *_buffer;', self.c_type) 1141 _c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type) 1142 _c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type) 1143 _c(' unsigned int xcb_align_to = 0;') 1144 else: 1145 _c(' char *xcb_out = *_buffer;') 1146 _c(' unsigned int xcb_buffer_len = 0;') 1147 _c(' unsigned int xcb_align_to = 0;') 1148 prefix = [('_aux', '->', self)] 1149 aux_ptr = 'xcb_out' 1150 1151 elif context in ('unserialize', 'unpack'): 1152 _c(' char *xcb_tmp = (char *)_buffer;') 1153 if not self.is_switch: 1154 if not self.c_var_followed_by_fixed_fields: 1155 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) 1156 prefix = [('_aux', '->', self)] 1157 else: 1158 _c(' %s xcb_out;', self.c_type) 1159 prefix = [('xcb_out', '.', self)] 1160 else: 1161 aux_var = '_aux' # default for unpack: single pointer 1162 # note: unserialize not generated for switch 1163 if 'unserialize' == context: 1164 aux_var = '(*_aux)' # unserialize: double pointer (!) 1165 prefix = [(aux_var, '->', self)] 1166 aux_ptr = '*_aux' 1167 _c(' unsigned int xcb_buffer_len = 0;') 1168 _c(' unsigned int xcb_block_len = 0;') 1169 _c(' unsigned int xcb_pad = 0;') 1170 _c(' unsigned int xcb_align_to = 0;') 1171 1172 elif 'sizeof' == context: 1173 param_names = [p[2] for p in params] 1174 if self.is_switch: 1175 # switch: call _unpack() 1176 _c(' %s _aux;', self.c_type) 1177 _c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) 1178 _c('}') 1179 return 1180 elif self.c_var_followed_by_fixed_fields: 1181 # special case: call _unserialize() 1182 _c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names)) 1183 _c('}') 1184 return 1185 else: 1186 _c(' char *xcb_tmp = (char *)_buffer;') 1187 prefix = [('_aux', '->', self)] 1188 1189 count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix) 1190 # update variable size fields (only important for context=='serialize' 1191 variable_size_fields = count 1192 if 'serialize' == context: 1193 temp_vars.append(' unsigned int xcb_pad = 0;') 1194 temp_vars.append(' char xcb_pad0[3] = {0, 0, 0};') 1195 temp_vars.append(' struct iovec xcb_parts[%d];' % count) 1196 temp_vars.append(' unsigned int xcb_parts_idx = 0;') 1197 temp_vars.append(' unsigned int xcb_block_len = 0;') 1198 temp_vars.append(' unsigned int i;') 1199 temp_vars.append(' char *xcb_tmp;') 1200 elif 'sizeof' == context: 1201 # neither switch nor intermixed fixed and variable size fields: 1202 # evaluate parameters directly 1203 if not (self.is_switch or self.c_var_followed_by_fixed_fields): 1204 1205 # look if we have to declare an '_aux' variable at all 1206 if len(list(filter(lambda x: x.find('_aux')!=-1, code_lines)))>0: 1207 if not self.c_var_followed_by_fixed_fields: 1208 _c(' const %s *_aux = (%s *)_buffer;', self.c_type, self.c_type) 1209 else: 1210 _c(' %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type) 1211 1212 _c(' unsigned int xcb_buffer_len = 0;') 1213 _c(' unsigned int xcb_block_len = 0;') 1214 _c(' unsigned int xcb_pad = 0;') 1215 _c(' unsigned int xcb_align_to = 0;') 1216 1217 _c('') 1218 for t in temp_vars: 1219 _c(t) 1220 _c('') 1221 for l in code_lines: 1222 _c(l) 1223 1224 # variable sized fields have been collected, now 1225 # allocate memory and copy everything into a continuous memory area 1226 # note: this is not necessary in case of unpack 1227 if context in ('serialize', 'unserialize'): 1228 # unserialize: check for sizeof-only invocation 1229 if 'unserialize' == context: 1230 _c('') 1231 _c(' if (NULL == _aux)') 1232 _c(' return xcb_buffer_len;') 1233 1234 _c('') 1235 _c(' if (NULL == %s) {', aux_ptr) 1236 _c(' /* allocate memory */') 1237 _c(' %s = malloc(xcb_buffer_len);', aux_ptr) 1238 if 'serialize' == context: 1239 _c(' *_buffer = xcb_out;') 1240 _c(' }') 1241 _c('') 1242 1243 # serialize: handle variable size fields in a loop 1244 if 'serialize' == context: 1245 if not self.is_switch and not self.c_var_followed_by_fixed_fields: 1246 if len(wire_fields)>0: 1247 _c(' *xcb_out = *_aux;') 1248 # copy variable size fields into the buffer 1249 if variable_size_fields > 0: 1250 # xcb_out padding 1251 if not self.is_switch and not self.c_var_followed_by_fixed_fields: 1252 _c(' xcb_tmp = (char*)++xcb_out;') 1253 _c(' xcb_tmp += xcb_out_pad;') 1254 else: 1255 _c(' xcb_tmp = xcb_out;') 1256 1257 # variable sized fields 1258 _c(' for(i=0; i<xcb_parts_idx; i++) {') 1259 _c(' if (0 != xcb_parts[i].iov_base && 0 != xcb_parts[i].iov_len)') 1260 _c(' memcpy(xcb_tmp, xcb_parts[i].iov_base, xcb_parts[i].iov_len);') 1261 _c(' if (0 != xcb_parts[i].iov_len)') 1262 _c(' xcb_tmp += xcb_parts[i].iov_len;') 1263 _c(' }') 1264 1265 # unserialize: assign variable size fields individually 1266 if 'unserialize' == context: 1267 _c(' xcb_tmp = ((char *)*_aux)+xcb_buffer_len;') 1268 param_fields.reverse() 1269 for field in param_fields: 1270 if not field.type.fixed_size(): 1271 _c(' xcb_tmp -= %s_len;', field.c_field_name) 1272 _c(' memmove(xcb_tmp, %s, %s_len);', field.c_field_name, field.c_field_name) 1273 _c(' *%s = xcb_out;', aux_ptr) 1274 1275 _c('') 1276 _c(' return xcb_buffer_len;') 1277 _c('}') 1278# _c_serialize() 1279 1280def _c_iterator_get_end(field, accum): 1281 ''' 1282 Figures out what C code is needed to find the end of a variable-length structure field. 1283 For nested structures, recurses into its last variable-sized field. 1284 For lists, calls the end function 1285 ''' 1286 if field.type.is_container: 1287 accum = field.c_accessor_name + '(' + accum + ')' 1288 return _c_iterator_get_end(field.type.last_varsized_field, accum) 1289 if field.type.is_list: 1290 # XXX we can always use the first way 1291 if field.type.member.is_simple: 1292 return field.c_end_name + '(' + accum + ')' 1293 else: 1294 return field.type.member.c_end_name + '(' + field.c_iterator_name + '(' + accum + '))' 1295 1296def _c_iterator(self, name): 1297 ''' 1298 Declares the iterator structure and next/end functions for a given type. 1299 ''' 1300 _h_setlevel(0) 1301 _h('') 1302 _h('/**') 1303 _h(' * @brief %s', self.c_iterator_type) 1304 _h(' **/') 1305 _h('typedef struct %s {', self.c_iterator_type) 1306 _h(' %s *data; /**< */', self.c_type) 1307 _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2)) 1308 _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2)) 1309 _h('} %s;', self.c_iterator_type) 1310 1311 _h_setlevel(1) 1312 _c_setlevel(1) 1313 _h('') 1314 _h('/**') 1315 _h(' * Get the next element of the iterator') 1316 _h(' * @param i Pointer to a %s', self.c_iterator_type) 1317 _h(' *') 1318 _h(' * Get the next element in the iterator. The member rem is') 1319 _h(' * decreased by one. The member data points to the next') 1320 _h(' * element. The member index is increased by sizeof(%s)', self.c_type) 1321 _h(' */') 1322 _c('') 1323 _hc('void') 1324 _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type) 1325 _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type) 1326 _c('{') 1327 1328 if not self.fixed_size(): 1329 _c(' %s *R = i->data;', self.c_type) 1330 1331 if self.is_union: 1332 # FIXME - how to determine the size of a variable size union?? 1333 _c(' /* FIXME - determine the size of the union %s */', self.c_type) 1334 else: 1335 if self.c_need_sizeof: 1336 _c(' xcb_generic_iterator_t child;') 1337 _c(' child.data = (%s *)(((char *)R) + %s(R));', 1338 self.c_type, self.c_sizeof_name) 1339 _c(' i->index = (char *) child.data - (char *) i->data;') 1340 else: 1341 _c(' xcb_generic_iterator_t child = %s;', _c_iterator_get_end(self.last_varsized_field, 'R')) 1342 _c(' i->index = child.index;') 1343 _c(' --i->rem;') 1344 _c(' i->data = (%s *) child.data;', self.c_type) 1345 1346 else: 1347 _c(' --i->rem;') 1348 _c(' ++i->data;') 1349 _c(' i->index += sizeof(%s);', self.c_type) 1350 1351 _c('}') 1352 1353 _h('') 1354 _h('/**') 1355 _h(' * Return the iterator pointing to the last element') 1356 _h(' * @param i An %s', self.c_iterator_type) 1357 _h(' * @return The iterator pointing to the last element') 1358 _h(' *') 1359 _h(' * Set the current element in the iterator to the last element.') 1360 _h(' * The member rem is set to 0. The member data points to the') 1361 _h(' * last element.') 1362 _h(' */') 1363 _c('') 1364 _hc('xcb_generic_iterator_t') 1365 _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type) 1366 _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type) 1367 _c('{') 1368 _c(' xcb_generic_iterator_t ret;') 1369 1370 if self.fixed_size(): 1371 _c(' ret.data = i.data + i.rem;') 1372 _c(' ret.index = i.index + ((char *) ret.data - (char *) i.data);') 1373 _c(' ret.rem = 0;') 1374 else: 1375 _c(' while(i.rem > 0)') 1376 _c(' %s(&i);', self.c_next_name) 1377 _c(' ret.data = i.data;') 1378 _c(' ret.rem = i.rem;') 1379 _c(' ret.index = i.index;') 1380 1381 _c(' return ret;') 1382 _c('}') 1383 1384def _c_accessor_get_length(expr, field_mapping=None): 1385 ''' 1386 Figures out what C code is needed to get a length field. 1387 The field_mapping parameter can be used to change the absolute name of a length field. 1388 For fields that follow a variable-length field, use the accessor. 1389 Otherwise, just reference the structure field directly. 1390 ''' 1391 1392 lenfield_name = expr.lenfield_name 1393 if lenfield_name is not None: 1394 if field_mapping is not None: 1395 lenfield_name = field_mapping[lenfield_name][0] 1396 1397 if expr.lenfield is not None and expr.lenfield.prev_varsized_field is not None: 1398 # special case: variable and fixed size fields are intermixed 1399 # if the lenfield is among the fixed size fields, there is no need 1400 # to call a special accessor function like <expr.lenfield.c_accessor_name + '(' + prefix + ')'> 1401 return field_mapping(expr.lenfield_name) 1402 elif expr.lenfield_name is not None: 1403 return lenfield_name 1404 else: 1405 return str(expr.nmemb) 1406 1407def _c_accessor_get_expr(expr, field_mapping): 1408 ''' 1409 Figures out what C code is needed to get the length of a list field. 1410 The field_mapping parameter can be used to change the absolute name of a length field. 1411 Recurses for math operations. 1412 Returns bitcount for value-mask fields. 1413 Otherwise, uses the value of the length field. 1414 ''' 1415 lenexp = _c_accessor_get_length(expr, field_mapping) 1416 1417 if expr.op == '~': 1418 return '(' + '~' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' 1419 elif expr.op == 'popcount': 1420 return 'xcb_popcount(' + _c_accessor_get_expr(expr.rhs, field_mapping) + ')' 1421 elif expr.op == 'enumref': 1422 enum_name = expr.lenfield_type.name 1423 constant_name = expr.lenfield_name 1424 c_name = _n(enum_name + (constant_name,)).upper() 1425 return c_name 1426 elif expr.op == 'sumof': 1427 # locate the referenced list object 1428 list_obj = expr.lenfield_type 1429 field = None 1430 for f in expr.lenfield_parent.fields: 1431 if f.field_name == expr.lenfield_name: 1432 field = f 1433 break 1434 1435 if field is None: 1436 raise Exception("list field '%s' referenced by sumof not found" % expr.lenfield_name) 1437 list_name = field_mapping[field.c_field_name][0] 1438 c_length_func = "%s(%s)" % (field.c_length_name, list_name) 1439 # note: xcb_sumof() has only been defined for integers 1440 c_length_func = _c_accessor_get_expr(field.type.expr, field_mapping) 1441 return 'xcb_sumof(%s, %s)' % (list_name, c_length_func) 1442 elif expr.op != None: 1443 return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) + 1444 ' ' + expr.op + ' ' + 1445 _c_accessor_get_expr(expr.rhs, field_mapping) + ')') 1446 elif expr.bitfield: 1447 return 'xcb_popcount(' + lenexp + ')' 1448 else: 1449 return lenexp 1450 1451def type_pad_type(type): 1452 if type == 'void': 1453 return 'char' 1454 return type 1455 1456def _c_accessors_field(self, field): 1457 ''' 1458 Declares the accessor functions for a non-list field that follows a variable-length field. 1459 ''' 1460 c_type = self.c_type 1461 1462 # special case: switch 1463 switch_obj = self if self.is_switch else None 1464 if self.is_bitcase: 1465 switch_obj = self.parents[-1] 1466 if switch_obj is not None: 1467 c_type = switch_obj.c_type 1468 1469 if field.type.is_simple: 1470 _hc('') 1471 _hc('%s', field.c_field_type) 1472 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) 1473 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) 1474 _c('{') 1475 if field.prev_varsized_field is None: 1476 _c(' return (%s *) (R + 1);', field.c_field_type) 1477 else: 1478 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1479 _c(' return * (%s *) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 1480 field.c_field_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) 1481 _c('}') 1482 else: 1483 _hc('') 1484 if field.type.is_switch and switch_obj is None: 1485 return_type = 'void *' 1486 else: 1487 return_type = '%s *' % field.c_field_type 1488 1489 _hc(return_type) 1490 _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) 1491 _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) 1492 _c('{') 1493 if field.prev_varsized_field is None: 1494 _c(' return (%s) (R + 1);', return_type) 1495 # note: the special case 'variable fields followed by fixed size fields' 1496 # is not of any consequence here, since the ordering gets 1497 # 'corrected' in the reply function 1498 else: 1499 _c(' xcb_generic_iterator_t prev = %s;', _c_iterator_get_end(field.prev_varsized_field, 'R')) 1500 _c(' return (%s) ((char *) prev.data + XCB_TYPE_PAD(%s, prev.index) + %d);', 1501 return_type, type_pad_type(field.first_field_after_varsized.type.c_type), field.prev_varsized_offset) 1502 _c('}') 1503 1504 1505def _c_accessors_list(self, field): 1506 ''' 1507 Declares the accessor functions for a list field. 1508 Declares a direct-accessor function only if the list members are fixed size. 1509 Declares length and get-iterator functions always. 1510 ''' 1511 1512 def get_align_pad(field): 1513 prev = field.prev_varsized_field 1514 prev_prev = field.prev_varsized_field.prev_varsized_field 1515 1516 if (prev.type.is_pad and prev.type.align > 0 and prev_prev is not None): 1517 return (prev_prev, '((-prev.index) & (%d - 1))' % prev.type.align) 1518 else: 1519 return (prev, None) 1520 1521 1522 list = field.type 1523 c_type = self.c_type 1524 1525 # special case: switch 1526 # in case of switch, 2 params have to be supplied to certain accessor functions: 1527 # 1. the anchestor object (request or reply) 1528 # 2. the (anchestor) switch object 1529 # the reason is that switch is either a child of a request/reply or nested in another switch, 1530 # so whenever we need to access a length field, we might need to refer to some anchestor type 1531 switch_obj = self if self.is_switch else None 1532 if self.is_bitcase: 1533 switch_obj = self.parents[-1] 1534 if switch_obj is not None: 1535 c_type = switch_obj.c_type 1536 1537 params = [] 1538 fields = {} 1539 parents = self.parents if hasattr(self, 'parents') else [self] 1540 # 'R': parents[0] is always the 'toplevel' container type 1541 params.append(('const %s *R' % parents[0].c_type, parents[0])) 1542 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True)) 1543 # auxiliary object for 'R' parameters 1544 R_obj = parents[0] 1545 1546 if switch_obj is not None: 1547 # now look where the fields are defined that are needed to evaluate 1548 # the switch expr, and store the parent objects in accessor_params and 1549 # the fields in switch_fields 1550 1551 # 'S': name for the 'toplevel' switch 1552 toplevel_switch = parents[1] 1553 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch)) 1554 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True)) 1555 1556 # initialize prefix for everything "below" S 1557 prefix_str = '/* %s */ S' % toplevel_switch.name[-1] 1558 prefix = [(prefix_str, '->', toplevel_switch)] 1559 1560 # look for fields in the remaining containers 1561 for p in parents[2:] + [self]: 1562 # the separator between parent and child is always '.' here, 1563 # because of nested switch statements 1564 if not p.is_bitcase or (p.is_bitcase and p.has_name): 1565 prefix.append((p.name[-1], '.', p)) 1566 fields.update(_c_helper_field_mapping(p, prefix, flat=True)) 1567 1568 # auxiliary object for 'S' parameter 1569 S_obj = parents[1] 1570 1571 _h_setlevel(1) 1572 _c_setlevel(1) 1573 if list.member.fixed_size(): 1574 idx = 1 if switch_obj is not None else 0 1575 _hc('') 1576 _hc('%s *', field.c_field_type) 1577 1578 _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0]) 1579 _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0]) 1580 1581 _c('{') 1582 if switch_obj is not None: 1583 _c(' return %s;', fields[field.c_field_name][0]) 1584 elif field.prev_varsized_field is None: 1585 _c(' return (%s *) (R + 1);', field.c_field_type) 1586 else: 1587 (prev_varsized_field, align_pad) = get_align_pad(field) 1588 1589 if align_pad is None: 1590 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' % 1591 type_pad_type(field.first_field_after_varsized.type.c_type)) 1592 1593 _c(' xcb_generic_iterator_t prev = %s;', 1594 _c_iterator_get_end(prev_varsized_field, 'R')) 1595 _c(' return (%s *) ((char *) prev.data + %s + %d);', 1596 field.c_field_type, align_pad, field.prev_varsized_offset) 1597 _c('}') 1598 1599 _hc('') 1600 _hc('int') 1601 if switch_obj is not None: 1602 _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type) 1603 spacing = ' '*(len(field.c_length_name)+2) 1604 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1605 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1606 length = _c_accessor_get_expr(field.type.expr, fields) 1607 else: 1608 _h('%s (const %s *R /**< */);', field.c_length_name, c_type) 1609 _c('%s (const %s *R /**< */)', field.c_length_name, c_type) 1610 length = _c_accessor_get_expr(field.type.expr, fields) 1611 _c('{') 1612 _c(' return %s;', length) 1613 _c('}') 1614 1615 if field.type.member.is_simple: 1616 _hc('') 1617 _hc('xcb_generic_iterator_t') 1618 if switch_obj is not None: 1619 _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type) 1620 spacing = ' '*(len(field.c_end_name)+2) 1621 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1622 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1623 else: 1624 _h('%s (const %s *R /**< */);', field.c_end_name, c_type) 1625 _c('%s (const %s *R /**< */)', field.c_end_name, c_type) 1626 _c('{') 1627 _c(' xcb_generic_iterator_t i;') 1628 1629 param = 'R' if switch_obj is None else 'S' 1630 if switch_obj is not None: 1631 _c(' i.data = %s + %s;', fields[field.c_field_name][0], 1632 _c_accessor_get_expr(field.type.expr, fields)) 1633 elif field.prev_varsized_field == None: 1634 _c(' i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype, 1635 _c_accessor_get_expr(field.type.expr, fields)) 1636 else: 1637 _c(' xcb_generic_iterator_t child = %s;', 1638 _c_iterator_get_end(field.prev_varsized_field, 'R')) 1639 _c(' i.data = ((%s *) child.data) + (%s);', field.type.c_wiretype, 1640 _c_accessor_get_expr(field.type.expr, fields)) 1641 1642 _c(' i.rem = 0;') 1643 _c(' i.index = (char *) i.data - (char *) %s;', param) 1644 _c(' return i;') 1645 _c('}') 1646 1647 else: 1648 _hc('') 1649 _hc('%s', field.c_iterator_type) 1650 if switch_obj is not None: 1651 _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type) 1652 spacing = ' '*(len(field.c_iterator_name)+2) 1653 _h('%sconst %s *S /**< */);', spacing, S_obj.c_type) 1654 _c('%sconst %s *S /**< */)', spacing, S_obj.c_type) 1655 else: 1656 _h('%s (const %s *R /**< */);', field.c_iterator_name, c_type) 1657 _c('%s (const %s *R /**< */)', field.c_iterator_name, c_type) 1658 _c('{') 1659 _c(' %s i;', field.c_iterator_type) 1660 1661 if switch_obj is not None: 1662 _c(' i.data = %s;', fields[field.c_field_name][0]) 1663 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) 1664 elif field.prev_varsized_field == None: 1665 _c(' i.data = (%s *) (R + 1);', field.c_field_type) 1666 else: 1667 (prev_varsized_field, align_pad) = get_align_pad(field) 1668 1669 if align_pad is None: 1670 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' % 1671 type_pad_type(field.c_field_type)) 1672 1673 _c(' xcb_generic_iterator_t prev = %s;', 1674 _c_iterator_get_end(prev_varsized_field, 'R')) 1675 _c(' i.data = (%s *) ((char *) prev.data + %s);', 1676 field.c_field_type, align_pad) 1677 1678 if switch_obj is None: 1679 _c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields)) 1680 _c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' ) 1681 _c(' return i;') 1682 _c('}') 1683 1684def _c_accessors(self, name, base): 1685 ''' 1686 Declares the accessor functions for the fields of a structure. 1687 ''' 1688 # no accessors for switch itself - 1689 # switch always needs to be unpacked explicitly 1690# if self.is_switch: 1691# pass 1692# else: 1693 if True: 1694 for field in self.fields: 1695 if not field.type.is_pad: 1696 if field.type.is_list and not field.type.fixed_size(): 1697 _c_accessors_list(self, field) 1698 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 1699 _c_accessors_field(self, field) 1700 1701def c_simple(self, name): 1702 ''' 1703 Exported function that handles cardinal type declarations. 1704 These are types which are typedef'd to one of the CARDx's, char, float, etc. 1705 ''' 1706 _c_type_setup(self, name, ()) 1707 1708 if (self.name != name): 1709 # Typedef 1710 _h_setlevel(0) 1711 my_name = _t(name) 1712 _h('') 1713 _h('typedef %s %s;', _t(self.name), my_name) 1714 1715 # Iterator 1716 _c_iterator(self, name) 1717 1718def _c_complex(self, force_packed = False): 1719 ''' 1720 Helper function for handling all structure types. 1721 Called for all structs, requests, replies, events, errors. 1722 ''' 1723 _h_setlevel(0) 1724 _h('') 1725 _h('/**') 1726 _h(' * @brief %s', self.c_type) 1727 _h(' **/') 1728 _h('typedef %s %s {', self.c_container, self.c_type) 1729 1730 struct_fields = [] 1731 maxtypelen = 0 1732 1733 varfield = None 1734 for field in self.fields: 1735 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 1736 varfield = field.c_field_name 1737 continue 1738 if field.wire: 1739 struct_fields.append(field) 1740 1741 for field in struct_fields: 1742 length = len(field.c_field_type) 1743 # account for '*' pointer_spec 1744 if not field.type.fixed_size() and not self.is_union: 1745 length += 1 1746 maxtypelen = max(maxtypelen, length) 1747 1748 def _c_complex_field(self, field, space=''): 1749 if (field.type.fixed_size() or self.is_union or 1750 # in case of switch with switch children, don't make the field a pointer 1751 # necessary for unserialize to work 1752 (self.is_switch and field.type.is_switch)): 1753 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 1754 _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 1755 else: 1756 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) 1757 _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 1758 1759 if not self.is_switch: 1760 for field in struct_fields: 1761 _c_complex_field(self, field) 1762 else: 1763 for b in self.bitcases: 1764 space = '' 1765 if b.type.has_name: 1766 _h(' struct _%s {', b.c_field_name) 1767 space = ' ' 1768 for field in b.type.fields: 1769 _c_complex_field(self, field, space) 1770 if b.type.has_name: 1771 _h(' } %s;', b.c_field_name) 1772 1773 _h('} %s%s;', 'XCB_PACKED ' if force_packed else '', self.c_type) 1774 1775def c_struct(self, name): 1776 ''' 1777 Exported function that handles structure declarations. 1778 ''' 1779 _c_type_setup(self, name, ()) 1780 _c_complex(self) 1781 _c_accessors(self, name, name) 1782 _c_iterator(self, name) 1783 1784def c_union(self, name): 1785 ''' 1786 Exported function that handles union declarations. 1787 ''' 1788 _c_type_setup(self, name, ()) 1789 _c_complex(self) 1790 _c_iterator(self, name) 1791 1792def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False): 1793 ''' 1794 Declares a request function. 1795 ''' 1796 1797 # Four stunningly confusing possibilities here: 1798 # 1799 # Void Non-void 1800 # ------------------------------ 1801 # "req" "req" 1802 # 0 flag CHECKED flag Normal Mode 1803 # void_cookie req_cookie 1804 # ------------------------------ 1805 # "req_checked" "req_unchecked" 1806 # CHECKED flag 0 flag Abnormal Mode 1807 # void_cookie req_cookie 1808 # ------------------------------ 1809 1810 1811 # Whether we are _checked or _unchecked 1812 checked = void and not regular 1813 unchecked = not void and not regular 1814 1815 # What kind of cookie we return 1816 func_cookie = 'xcb_void_cookie_t' if void else self.c_cookie_type 1817 1818 # What flag is passed to xcb_request 1819 func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED' 1820 1821 if reply_fds: 1822 if func_flags == '0': 1823 func_flags = 'XCB_REQUEST_REPLY_FDS' 1824 else: 1825 func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS' 1826 1827 # Global extension id variable or NULL for xproto 1828 func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0' 1829 1830 # What our function name is 1831 func_name = self.c_request_name if not aux else self.c_aux_name 1832 if checked: 1833 func_name = self.c_checked_name if not aux else self.c_aux_checked_name 1834 if unchecked: 1835 func_name = self.c_unchecked_name if not aux else self.c_aux_unchecked_name 1836 1837 param_fields = [] 1838 wire_fields = [] 1839 maxtypelen = len('xcb_connection_t') 1840 serial_fields = [] 1841 # special case: list with variable size elements 1842 list_with_var_size_elems = False 1843 1844 for field in self.fields: 1845 if field.visible: 1846 # The field should appear as a call parameter 1847 param_fields.append(field) 1848 if field.wire and not field.auto: 1849 # We need to set the field up in the structure 1850 wire_fields.append(field) 1851 if field.type.c_need_serialize or field.type.c_need_sizeof: 1852 serial_fields.append(field) 1853 1854 for field in param_fields: 1855 c_field_const_type = field.c_field_const_type 1856 if field.type.c_need_serialize and not aux: 1857 c_field_const_type = "const void" 1858 if len(c_field_const_type) > maxtypelen: 1859 maxtypelen = len(c_field_const_type) 1860 if field.type.is_list and not field.type.member.fixed_size(): 1861 list_with_var_size_elems = True 1862 1863 _h_setlevel(1) 1864 _c_setlevel(1) 1865 _h('') 1866 _h('/**') 1867 if hasattr(self, "doc") and self.doc: 1868 if self.doc.brief: 1869 _h(' * @brief ' + self.doc.brief) 1870 else: 1871 _h(' * No brief doc yet') 1872 1873 _h(' *') 1874 _h(' * @param c The connection') 1875 param_names = [f.c_field_name for f in param_fields] 1876 if hasattr(self, "doc") and self.doc: 1877 for field in param_fields: 1878 # XXX: hard-coded until we fix xproto.xml 1879 base_func_name = self.c_request_name if not aux else self.c_aux_name 1880 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask': 1881 field.enum = 'GC' 1882 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask': 1883 field.enum = 'CW' 1884 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask': 1885 field.enum = 'CW' 1886 if field.enum: 1887 # XXX: why the 'xcb' prefix? 1888 key = ('xcb', field.enum) 1889 1890 tname = _t(key) 1891 if namecount[tname] > 1: 1892 tname = _t(key + ('enum',)) 1893 _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname)) 1894 1895 if self.doc and field.field_name in self.doc.fields: 1896 desc = self.doc.fields[field.field_name] 1897 for name in param_names: 1898 desc = desc.replace('`%s`' % name, '\\a %s' % (name)) 1899 desc = desc.split("\n") 1900 desc = [line if line != '' else '\\n' for line in desc] 1901 _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc))) 1902 # If there is no documentation yet, we simply don't generate an 1903 # @param tag. Doxygen will then warn about missing documentation. 1904 1905 _h(' * @return A cookie') 1906 _h(' *') 1907 1908 if hasattr(self, "doc") and self.doc: 1909 if self.doc.description: 1910 desc = self.doc.description 1911 for name in param_names: 1912 desc = desc.replace('`%s`' % name, '\\a %s' % (name)) 1913 desc = desc.split("\n") 1914 _h(' * ' + "\n * ".join(desc)) 1915 else: 1916 _h(' * No description yet') 1917 else: 1918 _h(' * Delivers a request to the X server.') 1919 _h(' *') 1920 if checked: 1921 _h(' * This form can be used only if the request will not cause') 1922 _h(' * a reply to be generated. Any returned error will be') 1923 _h(' * saved for handling by xcb_request_check().') 1924 if unchecked: 1925 _h(' * This form can be used only if the request will cause') 1926 _h(' * a reply to be generated. Any returned error will be') 1927 _h(' * placed in the event queue.') 1928 _h(' */') 1929 _c('') 1930 _hc('%s', cookie_type) 1931 1932 spacing = ' ' * (maxtypelen - len('xcb_connection_t')) 1933 comma = ',' if len(param_fields) else ');' 1934 _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 1935 comma = ',' if len(param_fields) else ')' 1936 _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) 1937 1938 func_spacing = ' ' * (len(func_name) + 2) 1939 count = len(param_fields) 1940 for field in param_fields: 1941 count = count - 1 1942 c_field_const_type = field.c_field_const_type 1943 c_pointer = field.c_pointer 1944 if field.type.c_need_serialize and not aux: 1945 c_field_const_type = "const void" 1946 c_pointer = '*' 1947 spacing = ' ' * (maxtypelen - len(c_field_const_type)) 1948 comma = ',' if count else ');' 1949 _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, 1950 spacing, c_pointer, field.c_field_name, comma) 1951 comma = ',' if count else ')' 1952 _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, 1953 spacing, c_pointer, field.c_field_name, comma) 1954 1955 count = 2 1956 if not self.c_var_followed_by_fixed_fields: 1957 for field in param_fields: 1958 if not field.type.fixed_size(): 1959 count = count + 2 1960 if field.type.c_need_serialize: 1961 # _serialize() keeps track of padding automatically 1962 count -= 1 1963 dimension = count + 2 1964 1965 _c('{') 1966 _c(' static const xcb_protocol_request_t xcb_req = {') 1967 _c(' /* count */ %d,', count) 1968 _c(' /* ext */ %s,', func_ext_global) 1969 _c(' /* opcode */ %s,', self.c_request_name.upper()) 1970 _c(' /* isvoid */ %d', 1 if void else 0) 1971 _c(' };') 1972 _c('') 1973 1974 _c(' struct iovec xcb_parts[%d];', dimension) 1975 _c(' %s xcb_ret;', func_cookie) 1976 _c(' %s xcb_out;', self.c_type) 1977 if self.c_var_followed_by_fixed_fields: 1978 _c(' /* in the protocol description, variable size fields are followed by fixed size fields */') 1979 _c(' void *xcb_aux = 0;') 1980 1981 1982 for idx, f in enumerate(serial_fields): 1983 if aux: 1984 _c(' void *xcb_aux%d = 0;' % (idx)) 1985 if list_with_var_size_elems: 1986 _c(' unsigned int i;') 1987 _c(' unsigned int xcb_tmp_len;') 1988 _c(' char *xcb_tmp;') 1989 _c('') 1990 # simple request call tracing 1991# _c(' printf("in function %s\\n");' % func_name) 1992 1993 # fixed size fields 1994 for field in wire_fields: 1995 if field.type.fixed_size(): 1996 if field.type.is_expr: 1997 _c(' xcb_out.%s = %s;', field.c_field_name, _c_accessor_get_expr(field.type.expr, None)) 1998 elif field.type.is_pad: 1999 if field.type.nmemb == 1: 2000 _c(' xcb_out.%s = 0;', field.c_field_name) 2001 else: 2002 _c(' memset(xcb_out.%s, 0, %d);', field.c_field_name, field.type.nmemb) 2003 else: 2004 if field.type.nmemb == 1: 2005 _c(' xcb_out.%s = %s;', field.c_field_name, field.c_field_name) 2006 else: 2007 _c(' memcpy(xcb_out.%s, %s, %d);', field.c_field_name, field.c_field_name, field.type.nmemb) 2008 2009 def get_serialize_args(type_obj, c_field_name, aux_var, context='serialize'): 2010 serialize_args = get_serialize_params(context, type_obj, 2011 c_field_name, 2012 aux_var)[2] 2013 return reduce(lambda x,y: "%s, %s" % (x,y), [a[2] for a in serialize_args]) 2014 2015 # calls in order to free dyn. all. memory 2016 free_calls = [] 2017 2018 _c('') 2019 if not self.c_var_followed_by_fixed_fields: 2020 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;') 2021 _c(' xcb_parts[2].iov_len = sizeof(xcb_out);') 2022 _c(' xcb_parts[3].iov_base = 0;') 2023 _c(' xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;') 2024 2025 count = 4 2026 2027 for field in param_fields: 2028 if not field.type.fixed_size(): 2029 _c(' /* %s %s */', field.type.c_type, field.c_field_name) 2030 # default: simple cast to char * 2031 if not field.type.c_need_serialize and not field.type.c_need_sizeof: 2032 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) 2033 if field.type.is_list: 2034 if field.type.member.fixed_size(): 2035 _c(' xcb_parts[%d].iov_len = %s * sizeof(%s);', count, 2036 _c_accessor_get_expr(field.type.expr, None), 2037 field.type.member.c_wiretype) 2038 else: 2039 list_length = _c_accessor_get_expr(field.type.expr, None) 2040 2041 length = '' 2042 _c(" xcb_parts[%d].iov_len = 0;" % count) 2043 _c(" xcb_tmp = (char *)%s;", field.c_field_name) 2044 _c(" for(i=0; i<%s; i++) {" % list_length) 2045 _c(" xcb_tmp_len = %s(xcb_tmp);" % 2046 (field.type.c_sizeof_name)) 2047 _c(" xcb_parts[%d].iov_len += xcb_tmp_len;" % count) 2048 _c(" xcb_tmp += xcb_tmp_len;") 2049 _c(" }") 2050 else: 2051 # not supposed to happen 2052 raise Exception("unhandled variable size field %s" % field.c_field_name) 2053 else: 2054 if not aux: 2055 _c(' xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name) 2056 idx = serial_fields.index(field) 2057 aux_var = '&xcb_aux%d' % idx 2058 context = 'serialize' if aux else 'sizeof' 2059 _c(' xcb_parts[%d].iov_len =', count) 2060 if aux: 2061 serialize_args = get_serialize_args(field.type, aux_var, field.c_field_name, context) 2062 _c(' %s (%s);', field.type.c_serialize_name, serialize_args) 2063 _c(' xcb_parts[%d].iov_base = xcb_aux%d;' % (count, idx)) 2064 free_calls.append(' free(xcb_aux%d);' % idx) 2065 else: 2066 serialize_args = get_serialize_args(field.type, field.c_field_name, aux_var, context) 2067 func_name = field.type.c_sizeof_name 2068 _c(' %s (%s);', func_name, serialize_args) 2069 2070 count += 1 2071 if not (field.type.c_need_serialize or field.type.c_need_sizeof): 2072 # the _serialize() function keeps track of padding automatically 2073 _c(' xcb_parts[%d].iov_base = 0;', count) 2074 _c(' xcb_parts[%d].iov_len = -xcb_parts[%d].iov_len & 3;', count, count-1) 2075 count += 1 2076 2077 # elif self.c_var_followed_by_fixed_fields: 2078 else: 2079 _c(' xcb_parts[2].iov_base = (char *) &xcb_out;') 2080 # request header: opcodes + length 2081 _c(' xcb_parts[2].iov_len = 2*sizeof(uint8_t) + sizeof(uint16_t);') 2082 count += 1 2083 # call _serialize() 2084 buffer_var = '&xcb_aux' 2085 serialize_args = get_serialize_args(self, buffer_var, '&xcb_out', 'serialize') 2086 _c(' xcb_parts[%d].iov_len = %s (%s);', count, self.c_serialize_name, serialize_args) 2087 _c(' xcb_parts[%d].iov_base = (char *) xcb_aux;', count) 2088 free_calls.append(' free(xcb_aux);') 2089 # no padding necessary - _serialize() keeps track of padding automatically 2090 2091 _c('') 2092 for field in param_fields: 2093 if field.isfd: 2094 _c(' xcb_send_fd(c, %s);', field.c_field_name) 2095 2096 _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) 2097 2098 # free dyn. all. data, if any 2099 for f in free_calls: 2100 _c(f) 2101 _c(' return xcb_ret;') 2102 _c('}') 2103 2104def _c_reply(self, name): 2105 ''' 2106 Declares the function that returns the reply structure. 2107 ''' 2108 spacing1 = ' ' * (len(self.c_cookie_type) - len('xcb_connection_t')) 2109 spacing2 = ' ' * (len(self.c_cookie_type) - len('xcb_generic_error_t')) 2110 spacing3 = ' ' * (len(self.c_reply_name) + 2) 2111 2112 # check if _unserialize() has to be called for any field 2113 def look_for_special_cases(complex_obj): 2114 unserialize_fields = [] 2115 # no unserialize call in case of switch 2116 if not complex_obj.is_switch: 2117 for field in complex_obj.fields: 2118 # three cases: 1. field with special case 2119 # 2. container that contains special case field 2120 # 3. list with special case elements 2121 if field.type.c_var_followed_by_fixed_fields: 2122 unserialize_fields.append(field) 2123 elif field.type.is_container: 2124 unserialize_fields += look_for_special_cases(field.type) 2125 elif field.type.is_list: 2126 if field.type.member.c_var_followed_by_fixed_fields: 2127 unserialize_fields.append(field) 2128 if field.type.member.is_container: 2129 unserialize_fields += look_for_special_cases(field.type.member) 2130 return unserialize_fields 2131 2132 unserialize_fields = look_for_special_cases(self.reply) 2133 2134 _h('') 2135 _h('/**') 2136 _h(' * Return the reply') 2137 _h(' * @param c The connection') 2138 _h(' * @param cookie The cookie') 2139 _h(' * @param e The xcb_generic_error_t supplied') 2140 _h(' *') 2141 _h(' * Returns the reply of the request asked by') 2142 _h(' *') 2143 _h(' * The parameter @p e supplied to this function must be NULL if') 2144 _h(' * %s(). is used.', self.c_unchecked_name) 2145 _h(' * Otherwise, it stores the error if any.') 2146 _h(' *') 2147 _h(' * The returned value must be freed by the caller using free().') 2148 _h(' */') 2149 _c('') 2150 _hc('%s *', self.c_reply_type) 2151 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1) 2152 _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type) 2153 _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2) 2154 _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2) 2155 _c('{') 2156 2157 if len(unserialize_fields)>0: 2158 # certain variable size fields need to be unserialized explicitly 2159 _c(' %s *reply = (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', 2160 self.c_reply_type, self.c_reply_type) 2161 _c(' int i;') 2162 for field in unserialize_fields: 2163 if field.type.is_list: 2164 _c(' %s %s_iter = %s(reply);', field.c_iterator_type, field.c_field_name, field.c_iterator_name) 2165 _c(' int %s_len = %s(reply);', field.c_field_name, field.c_length_name) 2166 _c(' %s *%s_data;', field.c_field_type, field.c_field_name) 2167 else: 2168 raise Exception('not implemented: call _unserialize() in reply for non-list type %s', field.c_field_type) 2169 # call _unserialize(), using the reply as source and target buffer 2170 _c(' /* special cases: transform parts of the reply to match XCB data structures */') 2171 for field in unserialize_fields: 2172 if field.type.is_list: 2173 _c(' for(i=0; i<%s_len; i++) {', field.c_field_name) 2174 _c(' %s_data = %s_iter.data;', field.c_field_name, field.c_field_name) 2175 _c(' %s((const void *)%s_data, &%s_data);', field.type.c_unserialize_name, 2176 field.c_field_name, field.c_field_name) 2177 _c(' %s(&%s_iter);', field.type.c_next_name, field.c_field_name) 2178 _c(' }') 2179 # return the transformed reply 2180 _c(' return reply;') 2181 2182 else: 2183 _c(' return (%s *) xcb_wait_for_reply(c, cookie.sequence, e);', self.c_reply_type) 2184 2185 _c('}') 2186 2187def _c_reply_has_fds(self): 2188 for field in self.fields: 2189 if field.isfd: 2190 return True 2191 return False 2192 2193def _c_reply_fds(self, name): 2194 ''' 2195 Declares the function that returns fds related to the reply. 2196 ''' 2197 spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t')) 2198 spacing3 = ' ' * (len(self.c_reply_fds_name) + 2) 2199 _h('') 2200 _h('/**') 2201 _h(' * Return the reply fds') 2202 _h(' * @param c The connection') 2203 _h(' * @param reply The reply') 2204 _h(' *') 2205 _h(' * Returns the array of reply fds of the request asked by') 2206 _h(' *') 2207 _h(' * The returned value must be freed by the caller using free().') 2208 _h(' */') 2209 _c('') 2210 _hc('int *') 2211 _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1) 2212 _h('%s%s *reply /**< */);', spacing3, self.c_reply_type) 2213 _c('%s%s *reply /**< */)', spacing3, self.c_reply_type) 2214 _c('{') 2215 2216 _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type) 2217 2218 _c('}') 2219 2220 2221def _c_opcode(name, opcode): 2222 ''' 2223 Declares the opcode define for requests, events, and errors. 2224 ''' 2225 _h_setlevel(0) 2226 _h('') 2227 _h('/** Opcode for %s. */', _n(name)) 2228 _h('#define %s %s', _n(name).upper(), opcode) 2229 2230def _c_cookie(self, name): 2231 ''' 2232 Declares the cookie type for a non-void request. 2233 ''' 2234 _h_setlevel(0) 2235 _h('') 2236 _h('/**') 2237 _h(' * @brief %s', self.c_cookie_type) 2238 _h(' **/') 2239 _h('typedef struct %s {', self.c_cookie_type) 2240 _h(' unsigned int sequence; /**< */') 2241 _h('} %s;', self.c_cookie_type) 2242 2243def _man_request(self, name, cookie_type, void, aux): 2244 param_fields = [f for f in self.fields if f.visible] 2245 2246 func_name = self.c_request_name if not aux else self.c_aux_name 2247 2248 def create_link(linkname): 2249 name = 'man/%s.%s' % (linkname, section) 2250 if manpaths: 2251 sys.stdout.write(name) 2252 f = open(name, 'w') 2253 f.write('.so man%s/%s.%s' % (section, func_name, section)) 2254 f.close() 2255 2256 if manpaths: 2257 sys.stdout.write('man/%s.%s ' % (func_name, section)) 2258 # Our CWD is src/, so this will end up in src/man/ 2259 f = open('man/%s.%s' % (func_name, section), 'w') 2260 f.write('.TH %s %s "%s" "%s" "XCB Requests"\n' % (func_name, section, center_footer, left_footer)) 2261 # Left-adjust instead of adjusting to both sides 2262 f.write('.ad l\n') 2263 f.write('.SH NAME\n') 2264 brief = self.doc.brief if hasattr(self, "doc") and self.doc else '' 2265 f.write('%s \\- %s\n' % (func_name, brief)) 2266 f.write('.SH SYNOPSIS\n') 2267 # Don't split words (hyphenate) 2268 f.write('.hy 0\n') 2269 f.write('.B #include <xcb/%s.h>\n' % _ns.header) 2270 2271 # function prototypes 2272 prototype = '' 2273 count = len(param_fields) 2274 for field in param_fields: 2275 count = count - 1 2276 c_field_const_type = field.c_field_const_type 2277 c_pointer = field.c_pointer 2278 if c_pointer == ' ': 2279 c_pointer = '' 2280 if field.type.c_need_serialize and not aux: 2281 c_field_const_type = "const void" 2282 c_pointer = '*' 2283 comma = ', ' if count else ');' 2284 prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma) 2285 2286 f.write('.SS Request function\n') 2287 f.write('.HP\n') 2288 base_func_name = self.c_request_name if not aux else self.c_aux_name 2289 f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype)) 2290 create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked'))) 2291 if not void: 2292 f.write('.PP\n') 2293 f.write('.SS Reply datastructure\n') 2294 f.write('.nf\n') 2295 f.write('.sp\n') 2296 f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type)) 2297 struct_fields = [] 2298 maxtypelen = 0 2299 2300 for field in self.reply.fields: 2301 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 2302 continue 2303 if field.wire: 2304 struct_fields.append(field) 2305 2306 for field in struct_fields: 2307 length = len(field.c_field_type) 2308 # account for '*' pointer_spec 2309 if not field.type.fixed_size(): 2310 length += 1 2311 maxtypelen = max(maxtypelen, length) 2312 2313 def _c_complex_field(self, field, space=''): 2314 if (field.type.fixed_size() or 2315 # in case of switch with switch children, don't make the field a pointer 2316 # necessary for unserialize to work 2317 (self.is_switch and field.type.is_switch)): 2318 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 2319 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)) 2320 else: 2321 spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) 2322 f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name)) 2323 #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) 2324 2325 if not self.is_switch: 2326 for field in struct_fields: 2327 _c_complex_field(self, field) 2328 else: 2329 for b in self.bitcases: 2330 space = '' 2331 if b.type.has_name: 2332 space = ' ' 2333 for field in b.type.fields: 2334 _c_complex_field(self, field, space) 2335 if b.type.has_name: 2336 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2337 pass 2338 2339 f.write('} \\fB%s\\fP;\n' % self.reply.c_type) 2340 f.write('.fi\n') 2341 2342 f.write('.SS Reply function\n') 2343 f.write('.HP\n') 2344 f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ ' 2345 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') % 2346 (self.c_reply_type, self.c_reply_name, self.c_cookie_type)) 2347 create_link('%s' % self.c_reply_name) 2348 2349 has_accessors = False 2350 for field in self.reply.fields: 2351 if field.type.is_list and not field.type.fixed_size(): 2352 has_accessors = True 2353 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2354 has_accessors = True 2355 2356 if has_accessors: 2357 f.write('.SS Reply accessors\n') 2358 2359 def _c_accessors_field(self, field): 2360 ''' 2361 Declares the accessor functions for a non-list field that follows a variable-length field. 2362 ''' 2363 c_type = self.c_type 2364 2365 # special case: switch 2366 switch_obj = self if self.is_switch else None 2367 if self.is_bitcase: 2368 switch_obj = self.parents[-1] 2369 if switch_obj is not None: 2370 c_type = switch_obj.c_type 2371 2372 if field.type.is_simple: 2373 f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type)) 2374 create_link('%s' % field.c_accessor_name) 2375 else: 2376 f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type)) 2377 create_link('%s' % field.c_accessor_name) 2378 2379 def _c_accessors_list(self, field): 2380 ''' 2381 Declares the accessor functions for a list field. 2382 Declares a direct-accessor function only if the list members are fixed size. 2383 Declares length and get-iterator functions always. 2384 ''' 2385 list = field.type 2386 c_type = self.reply.c_type 2387 2388 # special case: switch 2389 # in case of switch, 2 params have to be supplied to certain accessor functions: 2390 # 1. the anchestor object (request or reply) 2391 # 2. the (anchestor) switch object 2392 # the reason is that switch is either a child of a request/reply or nested in another switch, 2393 # so whenever we need to access a length field, we might need to refer to some anchestor type 2394 switch_obj = self if self.is_switch else None 2395 if self.is_bitcase: 2396 switch_obj = self.parents[-1] 2397 if switch_obj is not None: 2398 c_type = switch_obj.c_type 2399 2400 params = [] 2401 fields = {} 2402 parents = self.parents if hasattr(self, 'parents') else [self] 2403 # 'R': parents[0] is always the 'toplevel' container type 2404 params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0])) 2405 fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True)) 2406 # auxiliary object for 'R' parameters 2407 R_obj = parents[0] 2408 2409 if switch_obj is not None: 2410 # now look where the fields are defined that are needed to evaluate 2411 # the switch expr, and store the parent objects in accessor_params and 2412 # the fields in switch_fields 2413 2414 # 'S': name for the 'toplevel' switch 2415 toplevel_switch = parents[1] 2416 params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch)) 2417 fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True)) 2418 2419 # initialize prefix for everything "below" S 2420 prefix_str = '/* %s */ S' % toplevel_switch.name[-1] 2421 prefix = [(prefix_str, '->', toplevel_switch)] 2422 2423 # look for fields in the remaining containers 2424 for p in parents[2:] + [self]: 2425 # the separator between parent and child is always '.' here, 2426 # because of nested switch statements 2427 if not p.is_bitcase or (p.is_bitcase and p.has_name): 2428 prefix.append((p.name[-1], '.', p)) 2429 fields.update(_c_helper_field_mapping(p, prefix, flat=True)) 2430 2431 # auxiliary object for 'S' parameter 2432 S_obj = parents[1] 2433 2434 if list.member.fixed_size(): 2435 idx = 1 if switch_obj is not None else 0 2436 f.write('.HP\n') 2437 f.write('%s *\\fB%s\\fP(%s);\n' % 2438 (field.c_field_type, field.c_accessor_name, params[idx][0])) 2439 create_link('%s' % field.c_accessor_name) 2440 2441 f.write('.HP\n') 2442 f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2443 (field.c_length_name, c_type)) 2444 create_link('%s' % field.c_length_name) 2445 2446 if field.type.member.is_simple: 2447 f.write('.HP\n') 2448 f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2449 (field.c_end_name, c_type)) 2450 create_link('%s' % field.c_end_name) 2451 else: 2452 f.write('.HP\n') 2453 f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' % 2454 (field.c_iterator_type, field.c_iterator_name, 2455 c_type)) 2456 create_link('%s' % field.c_iterator_name) 2457 2458 for field in self.reply.fields: 2459 if field.type.is_list and not field.type.fixed_size(): 2460 _c_accessors_list(self, field) 2461 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2462 _c_accessors_field(self, field) 2463 2464 2465 f.write('.br\n') 2466 # Re-enable hyphenation and adjusting to both sides 2467 f.write('.hy 1\n') 2468 2469 # argument reference 2470 f.write('.SH REQUEST ARGUMENTS\n') 2471 f.write('.IP \\fI%s\\fP 1i\n' % 'conn') 2472 f.write('The XCB connection to X11.\n') 2473 for field in param_fields: 2474 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2475 printed_enum = False 2476 # XXX: hard-coded until we fix xproto.xml 2477 if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask': 2478 field.enum = 'GC' 2479 elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask': 2480 field.enum = 'CW' 2481 elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask': 2482 field.enum = 'CW' 2483 if hasattr(field, "enum") and field.enum: 2484 # XXX: why the 'xcb' prefix? 2485 key = ('xcb', field.enum) 2486 if key in enums: 2487 f.write('One of the following values:\n') 2488 f.write('.RS 1i\n') 2489 enum = enums[key] 2490 count = len(enum.values) 2491 for (enam, eval) in enum.values: 2492 count = count - 1 2493 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper())) 2494 if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields: 2495 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam]) 2496 f.write('%s\n' % desc) 2497 else: 2498 f.write('TODO: NOT YET DOCUMENTED.\n') 2499 f.write('.RE\n') 2500 f.write('.RS 1i\n') 2501 printed_enum = True 2502 2503 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields: 2504 desc = self.doc.fields[field.field_name] 2505 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2506 if printed_enum: 2507 f.write('\n') 2508 f.write('%s\n' % desc) 2509 else: 2510 f.write('TODO: NOT YET DOCUMENTED.\n') 2511 if printed_enum: 2512 f.write('.RE\n') 2513 2514 # Reply reference 2515 if not void: 2516 f.write('.SH REPLY FIELDS\n') 2517 # These fields are present in every reply: 2518 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type') 2519 f.write(('The type of this reply, in this case \\fI%s\\fP. This field ' 2520 'is also present in the \\fIxcb_generic_reply_t\\fP and can ' 2521 'be used to tell replies apart from each other.\n') % 2522 _n(self.reply.name).upper()) 2523 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence') 2524 f.write('The sequence number of the last request processed by the X11 server.\n') 2525 f.write('.IP \\fI%s\\fP 1i\n' % 'length') 2526 f.write('The length of the reply, in words (a word is 4 bytes).\n') 2527 for field in self.reply.fields: 2528 if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or 2529 field.c_field_name.startswith('pad')): 2530 continue 2531 2532 if field.type.is_list and not field.type.fixed_size(): 2533 continue 2534 elif field.prev_varsized_field is not None or not field.type.fixed_size(): 2535 continue 2536 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2537 printed_enum = False 2538 if hasattr(field, "enum") and field.enum: 2539 # XXX: why the 'xcb' prefix? 2540 key = ('xcb', field.enum) 2541 if key in enums: 2542 f.write('One of the following values:\n') 2543 f.write('.RS 1i\n') 2544 enum = enums[key] 2545 count = len(enum.values) 2546 for (enam, eval) in enum.values: 2547 count = count - 1 2548 f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper())) 2549 if enum.doc and enam in enum.doc.fields: 2550 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam]) 2551 f.write('%s\n' % desc) 2552 else: 2553 f.write('TODO: NOT YET DOCUMENTED.\n') 2554 f.write('.RE\n') 2555 f.write('.RS 1i\n') 2556 printed_enum = True 2557 2558 if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields: 2559 desc = self.reply.doc.fields[field.field_name] 2560 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2561 if printed_enum: 2562 f.write('\n') 2563 f.write('%s\n' % desc) 2564 else: 2565 f.write('TODO: NOT YET DOCUMENTED.\n') 2566 if printed_enum: 2567 f.write('.RE\n') 2568 2569 2570 2571 # text description 2572 f.write('.SH DESCRIPTION\n') 2573 if hasattr(self, "doc") and self.doc and self.doc.description: 2574 desc = self.doc.description 2575 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2576 lines = desc.split('\n') 2577 f.write('\n'.join(lines) + '\n') 2578 2579 f.write('.SH RETURN VALUE\n') 2580 if void: 2581 f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) ' 2582 'have to be handled in the event loop.\n\nIf you want to ' 2583 'handle errors directly with \\fIxcb_request_check\\fP ' 2584 'instead, use \\fI%s_checked\\fP. See ' 2585 '\\fBxcb-requests(%s)\\fP for details.\n') % (base_func_name, section)) 2586 else: 2587 f.write(('Returns an \\fI%s\\fP. Errors have to be handled when ' 2588 'calling the reply function \\fI%s\\fP.\n\nIf you want to ' 2589 'handle errors in the event loop instead, use ' 2590 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(%s)\\fP for ' 2591 'details.\n') % 2592 (cookie_type, self.c_reply_name, base_func_name, section)) 2593 f.write('.SH ERRORS\n') 2594 if hasattr(self, "doc") and self.doc: 2595 for errtype, errtext in sorted(self.doc.errors.items()): 2596 f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error')))) 2597 errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext) 2598 f.write('%s\n' % (errtext)) 2599 if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0: 2600 f.write('This request does never generate any errors.\n') 2601 if hasattr(self, "doc") and self.doc and self.doc.example: 2602 f.write('.SH EXAMPLE\n') 2603 f.write('.nf\n') 2604 f.write('.sp\n') 2605 lines = self.doc.example.split('\n') 2606 f.write('\n'.join(lines) + '\n') 2607 f.write('.fi\n') 2608 f.write('.SH SEE ALSO\n') 2609 if hasattr(self, "doc") and self.doc: 2610 see = ['.BR %s (%s)' % ('xcb-requests', section)] 2611 if self.doc.example: 2612 see.append('.BR %s (%s)' % ('xcb-examples', section)) 2613 for seename, seetype in sorted(self.doc.see.items()): 2614 if seetype == 'program': 2615 see.append('.BR %s (1)' % seename) 2616 elif seetype == 'event': 2617 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section)) 2618 elif seetype == 'request': 2619 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section)) 2620 elif seetype == 'function': 2621 see.append('.BR %s (%s)' % (seename, section)) 2622 else: 2623 see.append('TODO: %s (type %s)' % (seename, seetype)) 2624 f.write(',\n'.join(see) + '\n') 2625 f.write('.SH AUTHOR\n') 2626 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header) 2627 f.close() 2628 2629def _man_event(self, name): 2630 if manpaths: 2631 sys.stdout.write('man/%s.%s ' % (self.c_type, section)) 2632 # Our CWD is src/, so this will end up in src/man/ 2633 f = open('man/%s.%s' % (self.c_type, section), 'w') 2634 f.write('.TH %s %s "%s" "%s" "XCB Events"\n' % (self.c_type, section, center_footer, left_footer)) 2635 # Left-adjust instead of adjusting to both sides 2636 f.write('.ad l\n') 2637 f.write('.SH NAME\n') 2638 brief = self.doc.brief if hasattr(self, "doc") and self.doc else '' 2639 f.write('%s \\- %s\n' % (self.c_type, brief)) 2640 f.write('.SH SYNOPSIS\n') 2641 # Don't split words (hyphenate) 2642 f.write('.hy 0\n') 2643 f.write('.B #include <xcb/%s.h>\n' % _ns.header) 2644 2645 f.write('.PP\n') 2646 f.write('.SS Event datastructure\n') 2647 f.write('.nf\n') 2648 f.write('.sp\n') 2649 f.write('typedef %s %s {\n' % (self.c_container, self.c_type)) 2650 struct_fields = [] 2651 maxtypelen = 0 2652 2653 for field in self.fields: 2654 if not field.type.fixed_size() and not self.is_switch and not self.is_union: 2655 continue 2656 if field.wire: 2657 struct_fields.append(field) 2658 2659 for field in struct_fields: 2660 length = len(field.c_field_type) 2661 # account for '*' pointer_spec 2662 if not field.type.fixed_size(): 2663 length += 1 2664 maxtypelen = max(maxtypelen, length) 2665 2666 def _c_complex_field(self, field, space=''): 2667 if (field.type.fixed_size() or 2668 # in case of switch with switch children, don't make the field a pointer 2669 # necessary for unserialize to work 2670 (self.is_switch and field.type.is_switch)): 2671 spacing = ' ' * (maxtypelen - len(field.c_field_type)) 2672 f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)) 2673 else: 2674 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2675 2676 if not self.is_switch: 2677 for field in struct_fields: 2678 _c_complex_field(self, field) 2679 else: 2680 for b in self.bitcases: 2681 space = '' 2682 if b.type.has_name: 2683 space = ' ' 2684 for field in b.type.fields: 2685 _c_complex_field(self, field, space) 2686 if b.type.has_name: 2687 print >> sys.stderr, 'ERROR: New unhandled documentation case' 2688 pass 2689 2690 f.write('} \\fB%s\\fP;\n' % self.c_type) 2691 f.write('.fi\n') 2692 2693 2694 f.write('.br\n') 2695 # Re-enable hyphenation and adjusting to both sides 2696 f.write('.hy 1\n') 2697 2698 # argument reference 2699 f.write('.SH EVENT FIELDS\n') 2700 f.write('.IP \\fI%s\\fP 1i\n' % 'response_type') 2701 f.write(('The type of this event, in this case \\fI%s\\fP. This field is ' 2702 'also present in the \\fIxcb_generic_event_t\\fP and can be used ' 2703 'to tell events apart from each other.\n') % _n(name).upper()) 2704 f.write('.IP \\fI%s\\fP 1i\n' % 'sequence') 2705 f.write('The sequence number of the last request processed by the X11 server.\n') 2706 2707 if not self.is_switch: 2708 for field in struct_fields: 2709 # Skip the fields which every event has, we already documented 2710 # them (see above). 2711 if field.c_field_name in ('response_type', 'sequence'): 2712 continue 2713 if isinstance(field.type, PadType): 2714 continue 2715 f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name)) 2716 if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields: 2717 desc = self.doc.fields[field.field_name] 2718 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2719 f.write('%s\n' % desc) 2720 else: 2721 f.write('NOT YET DOCUMENTED.\n') 2722 2723 # text description 2724 f.write('.SH DESCRIPTION\n') 2725 if hasattr(self, "doc") and self.doc and self.doc.description: 2726 desc = self.doc.description 2727 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc) 2728 lines = desc.split('\n') 2729 f.write('\n'.join(lines) + '\n') 2730 2731 if hasattr(self, "doc") and self.doc and self.doc.example: 2732 f.write('.SH EXAMPLE\n') 2733 f.write('.nf\n') 2734 f.write('.sp\n') 2735 lines = self.doc.example.split('\n') 2736 f.write('\n'.join(lines) + '\n') 2737 f.write('.fi\n') 2738 f.write('.SH SEE ALSO\n') 2739 if hasattr(self, "doc") and self.doc: 2740 see = ['.BR %s (%s)' % ('xcb_generic_event_t', section)] 2741 if self.doc.example: 2742 see.append('.BR %s (%s)' % ('xcb-examples', section)) 2743 for seename, seetype in sorted(self.doc.see.items()): 2744 if seetype == 'program': 2745 see.append('.BR %s (1)' % seename) 2746 elif seetype == 'event': 2747 see.append('.BR %s (%s)' % (_t(('xcb', seename, 'event')), section)) 2748 elif seetype == 'request': 2749 see.append('.BR %s (%s)' % (_n(('xcb', seename)), section)) 2750 elif seetype == 'function': 2751 see.append('.BR %s (%s)' % (seename, section)) 2752 else: 2753 see.append('TODO: %s (type %s)' % (seename, seetype)) 2754 f.write(',\n'.join(see) + '\n') 2755 f.write('.SH AUTHOR\n') 2756 f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header) 2757 f.close() 2758 2759 2760def c_request(self, name): 2761 ''' 2762 Exported function that handles request declarations. 2763 ''' 2764 _c_type_setup(self, name, ('request',)) 2765 2766 if self.reply: 2767 # Cookie type declaration 2768 _c_cookie(self, name) 2769 2770 # Opcode define 2771 _c_opcode(name, self.opcode) 2772 2773 # Request structure declaration 2774 _c_complex(self) 2775 2776 if self.reply: 2777 _c_type_setup(self.reply, name, ('reply',)) 2778 # Reply structure definition 2779 _c_complex(self.reply) 2780 # Request prototypes 2781 has_fds = _c_reply_has_fds(self.reply) 2782 _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds) 2783 _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds) 2784 if self.c_need_aux: 2785 _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds) 2786 _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds) 2787 # Reply accessors 2788 _c_accessors(self.reply, name + ('reply',), name) 2789 _c_reply(self, name) 2790 if has_fds: 2791 _c_reply_fds(self, name) 2792 else: 2793 # Request prototypes 2794 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False) 2795 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True) 2796 if self.c_need_aux: 2797 _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True) 2798 _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True) 2799 2800 # We generate the manpage afterwards because _c_type_setup has been called. 2801 # TODO: what about aux helpers? 2802 cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t' 2803 _man_request(self, name, cookie_type, not self.reply, False) 2804 2805def c_event(self, name): 2806 ''' 2807 Exported function that handles event declarations. 2808 ''' 2809 2810 # The generic event structure xcb_ge_event_t has the full_sequence field 2811 # at the 32byte boundary. That's why we've to inject this field into GE 2812 # events while generating the structure for them. Otherwise we would read 2813 # garbage (the internal full_sequence) when accessing normal event fields 2814 # there. 2815 force_packed = False 2816 if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name: 2817 event_size = 0 2818 for field in self.fields: 2819 if field.type.size != None and field.type.nmemb != None: 2820 event_size += field.type.size * field.type.nmemb 2821 if event_size == 32: 2822 full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True) 2823 idx = self.fields.index(field) 2824 self.fields.insert(idx + 1, full_sequence) 2825 2826 # If the event contains any 64-bit extended fields, they need 2827 # to remain aligned on a 64-bit boundary. Adding full_sequence 2828 # would normally break that; force the struct to be packed. 2829 force_packed = any(f.type.size == 8 and f.type.is_simple for f in self.fields[(idx+1):]) 2830 break 2831 2832 _c_type_setup(self, name, ('event',)) 2833 2834 # Opcode define 2835 _c_opcode(name, self.opcodes[name]) 2836 2837 if self.name == name: 2838 # Structure definition 2839 _c_complex(self, force_packed) 2840 else: 2841 # Typedef 2842 _h('') 2843 _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',))) 2844 2845 _man_event(self, name) 2846 2847def c_error(self, name): 2848 ''' 2849 Exported function that handles error declarations. 2850 ''' 2851 _c_type_setup(self, name, ('error',)) 2852 2853 # Opcode define 2854 _c_opcode(name, self.opcodes[name]) 2855 2856 if self.name == name: 2857 # Structure definition 2858 _c_complex(self) 2859 else: 2860 # Typedef 2861 _h('') 2862 _h('typedef %s %s;', _t(self.name + ('error',)), _t(name + ('error',))) 2863 2864 2865# Main routine starts here 2866 2867# Must create an "output" dictionary before any xcbgen imports. 2868output = {'open' : c_open, 2869 'close' : c_close, 2870 'simple' : c_simple, 2871 'enum' : c_enum, 2872 'struct' : c_struct, 2873 'union' : c_union, 2874 'request' : c_request, 2875 'event' : c_event, 2876 'error' : c_error, 2877 } 2878 2879# Boilerplate below this point 2880 2881# Check for the argument that specifies path to the xcbgen python package. 2882try: 2883 opts, args = getopt.getopt(sys.argv[1:], 'c:l:s:p:m') 2884except getopt.GetoptError as err: 2885 print(err) 2886 print('Usage: c_client.py -c center_footer -l left_footer -s section [-p path] file.xml') 2887 sys.exit(1) 2888 2889for (opt, arg) in opts: 2890 if opt == '-c': 2891 center_footer=arg 2892 if opt == '-l': 2893 left_footer=arg 2894 if opt == '-s': 2895 section=arg 2896 if opt == '-p': 2897 sys.path.insert(1, arg) 2898 elif opt == '-m': 2899 manpaths = True 2900 sys.stdout.write('man_MANS = ') 2901 2902# Import the module class 2903try: 2904 from xcbgen.state import Module 2905 from xcbgen.xtypes import * 2906except ImportError: 2907 print(''' 2908Failed to load the xcbgen Python package! 2909Make sure that xcb/proto installed it on your Python path. 2910If not, you will need to create a .pth file or define $PYTHONPATH 2911to extend the path. 2912Refer to the README file in xcb/proto for more info. 2913''') 2914 raise 2915 2916# Ensure the man subdirectory exists 2917try: 2918 os.mkdir('man') 2919except OSError as e: 2920 if e.errno != errno.EEXIST: 2921 raise 2922 2923# Parse the xml header 2924module = Module(args[0], output) 2925 2926# Build type-registry and resolve type dependencies 2927module.register() 2928module.resolve() 2929 2930# Output the code 2931module.generate() 2932