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