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