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