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