1 2# (C) Copyright IBM Corporation 2004, 2005 3# All Rights Reserved. 4# 5# Permission is hereby granted, free of charge, to any person obtaining a 6# copy of this software and associated documentation files (the "Software"), 7# to deal in the Software without restriction, including without limitation 8# on the rights to use, copy, modify, merge, publish, distribute, sub 9# license, and/or sell copies of the Software, and to permit persons to whom 10# the Software is furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice (including the next 13# paragraph) shall be included in all copies or substantial portions of the 14# Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22# IN THE SOFTWARE. 23# 24# Authors: 25# Ian Romanick <idr@us.ibm.com> 26 27from decimal import Decimal 28import xml.etree.ElementTree as ET 29import re, sys, string 30import os.path 31import typeexpr 32import static_data 33 34 35def parse_GL_API( file_name, factory = None ): 36 37 if not factory: 38 factory = gl_item_factory() 39 40 api = factory.create_api() 41 api.parse_file( file_name ) 42 43 # After the XML has been processed, we need to go back and assign 44 # dispatch offsets to the functions that request that their offsets 45 # be assigned by the scripts. Typically this means all functions 46 # that are not part of the ABI. 47 48 for func in api.functionIterateByCategory(): 49 if func.assign_offset: 50 func.offset = api.next_offset; 51 api.next_offset += 1 52 53 return api 54 55 56def is_attr_true( element, name, default = "false" ): 57 """Read a name value from an element's attributes. 58 59 The value read from the attribute list must be either 'true' or 60 'false'. If the value is 'false', zero will be returned. If the 61 value is 'true', non-zero will be returned. An exception will be 62 raised for any other value.""" 63 64 value = element.get( name, default ) 65 if value == "true": 66 return 1 67 elif value == "false": 68 return 0 69 else: 70 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name)) 71 72 73class gl_print_base(object): 74 """Base class of all API pretty-printers. 75 76 In the model-view-controller pattern, this is the view. Any derived 77 class will want to over-ride the printBody, printRealHader, and 78 printRealFooter methods. Some derived classes may want to over-ride 79 printHeader and printFooter, or even Print (though this is unlikely). 80 """ 81 82 def __init__(self): 83 # Name of the script that is generating the output file. 84 # Every derived class should set this to the name of its 85 # source file. 86 87 self.name = "a" 88 89 90 # License on the *generated* source file. This may differ 91 # from the license on the script that is generating the file. 92 # Every derived class should set this to some reasonable 93 # value. 94 # 95 # See license.py for an example of a reasonable value. 96 97 self.license = "The license for this file is unspecified." 98 99 100 # The header_tag is the name of the C preprocessor define 101 # used to prevent multiple inclusion. Typically only 102 # generated C header files need this to be set. Setting it 103 # causes code to be generated automatically in printHeader 104 # and printFooter. 105 106 self.header_tag = None 107 108 109 # List of file-private defines that must be undefined at the 110 # end of the file. This can be used in header files to define 111 # names for use in the file, then undefine them at the end of 112 # the header file. 113 114 self.undef_list = [] 115 return 116 117 118 def Print(self, api): 119 self.printHeader() 120 self.printBody(api) 121 self.printFooter() 122 return 123 124 125 def printHeader(self): 126 """Print the header associated with all files and call the printRealHeader method.""" 127 128 print '/* DO NOT EDIT - This file generated automatically by %s script */' \ 129 % (self.name) 130 print '' 131 print '/*' 132 print (' * ' + self.license.replace('\n', '\n * ')).replace(' \n', '\n') 133 print ' */' 134 print '' 135 if self.header_tag: 136 print '#if !defined( %s )' % (self.header_tag) 137 print '# define %s' % (self.header_tag) 138 print '' 139 self.printRealHeader(); 140 return 141 142 143 def printFooter(self): 144 """Print the header associated with all files and call the printRealFooter method.""" 145 146 self.printRealFooter() 147 148 if self.undef_list: 149 print '' 150 for u in self.undef_list: 151 print "# undef %s" % (u) 152 153 if self.header_tag: 154 print '' 155 print '#endif /* !defined( %s ) */' % (self.header_tag) 156 157 158 def printRealHeader(self): 159 """Print the "real" header for the created file. 160 161 In the base class, this function is empty. All derived 162 classes should over-ride this function.""" 163 return 164 165 166 def printRealFooter(self): 167 """Print the "real" footer for the created file. 168 169 In the base class, this function is empty. All derived 170 classes should over-ride this function.""" 171 return 172 173 174 def printPure(self): 175 """Conditionally define `PURE' function attribute. 176 177 Conditionally defines a preprocessor macro `PURE' that wraps 178 GCC's `pure' function attribute. The conditional code can be 179 easilly adapted to other compilers that support a similar 180 feature. 181 182 The name is also added to the file's undef_list. 183 """ 184 self.undef_list.append("PURE") 185 print """# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) 186# define PURE __attribute__((pure)) 187# else 188# define PURE 189# endif""" 190 return 191 192 193 def printFastcall(self): 194 """Conditionally define `FASTCALL' function attribute. 195 196 Conditionally defines a preprocessor macro `FASTCALL' that 197 wraps GCC's `fastcall' function attribute. The conditional 198 code can be easilly adapted to other compilers that support a 199 similar feature. 200 201 The name is also added to the file's undef_list. 202 """ 203 204 self.undef_list.append("FASTCALL") 205 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 206# define FASTCALL __attribute__((fastcall)) 207# else 208# define FASTCALL 209# endif""" 210 return 211 212 213 def printVisibility(self, S, s): 214 """Conditionally define visibility function attribute. 215 216 Conditionally defines a preprocessor macro name S that wraps 217 GCC's visibility function attribute. The visibility used is 218 the parameter s. The conditional code can be easilly adapted 219 to other compilers that support a similar feature. 220 221 The name is also added to the file's undef_list. 222 """ 223 224 self.undef_list.append(S) 225 print """# if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 226# define %s __attribute__((visibility("%s"))) 227# else 228# define %s 229# endif""" % (S, s, S) 230 return 231 232 233 def printNoinline(self): 234 """Conditionally define `NOINLINE' function attribute. 235 236 Conditionally defines a preprocessor macro `NOINLINE' that 237 wraps GCC's `noinline' function attribute. The conditional 238 code can be easilly adapted to other compilers that support a 239 similar feature. 240 241 The name is also added to the file's undef_list. 242 """ 243 244 self.undef_list.append("NOINLINE") 245 print """# if defined(__GNUC__) 246# define NOINLINE __attribute__((noinline)) 247# else 248# define NOINLINE 249# endif""" 250 return 251 252 253def real_function_name(element): 254 name = element.get( "name" ) 255 alias = element.get( "alias" ) 256 257 if alias: 258 return alias 259 else: 260 return name 261 262 263def real_category_name(c): 264 if re.compile("[1-9][0-9]*[.][0-9]+").match(c): 265 return "GL_VERSION_" + c.replace(".", "_") 266 else: 267 return c 268 269 270def classify_category(name, number): 271 """Based on the category name and number, select a numerical class for it. 272 273 Categories are divided into four classes numbered 0 through 3. The 274 classes are: 275 276 0. Core GL versions, sorted by version number. 277 1. ARB extensions, sorted by extension number. 278 2. Non-ARB extensions, sorted by extension number. 279 3. Un-numbered extensions, sorted by extension name. 280 """ 281 282 try: 283 core_version = float(name) 284 except Exception,e: 285 core_version = 0.0 286 287 if core_version > 0.0: 288 cat_type = 0 289 key = name 290 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"): 291 cat_type = 1 292 key = int(number) 293 else: 294 if number != None: 295 cat_type = 2 296 key = int(number) 297 else: 298 cat_type = 3 299 key = name 300 301 302 return [cat_type, key] 303 304 305def create_parameter_string(parameters, include_names): 306 """Create a parameter string from a list of gl_parameters.""" 307 308 list = [] 309 for p in parameters: 310 if p.is_padding: 311 continue 312 313 if include_names: 314 list.append( p.string() ) 315 else: 316 list.append( p.type_string() ) 317 318 if len(list) == 0: list = ["void"] 319 320 return string.join(list, ", ") 321 322 323class gl_item(object): 324 def __init__(self, element, context, category): 325 self.context = context 326 self.name = element.get( "name" ) 327 self.category = real_category_name( category ) 328 329 return 330 331 332class gl_type( gl_item ): 333 def __init__(self, element, context, category): 334 gl_item.__init__(self, element, context, category) 335 self.size = int( element.get( "size" ), 0 ) 336 337 te = typeexpr.type_expression( None ) 338 tn = typeexpr.type_node() 339 tn.size = int( element.get( "size" ), 0 ) 340 tn.integer = not is_attr_true( element, "float" ) 341 tn.unsigned = is_attr_true( element, "unsigned" ) 342 tn.pointer = is_attr_true( element, "pointer" ) 343 tn.name = "GL" + self.name 344 te.set_base_type_node( tn ) 345 346 self.type_expr = te 347 return 348 349 350 def get_type_expression(self): 351 return self.type_expr 352 353 354class gl_enum( gl_item ): 355 def __init__(self, element, context, category): 356 gl_item.__init__(self, element, context, category) 357 self.value = int( element.get( "value" ), 0 ) 358 359 temp = element.get( "count" ) 360 if not temp or temp == "?": 361 self.default_count = -1 362 else: 363 try: 364 c = int(temp) 365 except Exception,e: 366 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n)) 367 368 self.default_count = c 369 370 return 371 372 373 def priority(self): 374 """Calculate a 'priority' for this enum name. 375 376 When an enum is looked up by number, there may be many 377 possible names, but only one is the 'prefered' name. The 378 priority is used to select which name is the 'best'. 379 380 Highest precedence is given to core GL name. ARB extension 381 names have the next highest, followed by EXT extension names. 382 Vendor extension names are the lowest. 383 """ 384 385 if self.name.endswith( "_BIT" ): 386 bias = 1 387 else: 388 bias = 0 389 390 if self.category.startswith( "GL_VERSION_" ): 391 priority = 0 392 elif self.category.startswith( "GL_ARB_" ): 393 priority = 2 394 elif self.category.startswith( "GL_EXT_" ): 395 priority = 4 396 else: 397 priority = 6 398 399 return priority + bias 400 401 402 403class gl_parameter(object): 404 def __init__(self, element, context): 405 self.name = element.get( "name" ) 406 407 ts = element.get( "type" ) 408 self.type_expr = typeexpr.type_expression( ts, context ) 409 410 temp = element.get( "variable_param" ) 411 if temp: 412 self.count_parameter_list = temp.split( ' ' ) 413 else: 414 self.count_parameter_list = [] 415 416 # The count tag can be either a numeric string or the name of 417 # a variable. If it is the name of a variable, the int(c) 418 # statement will throw an exception, and the except block will 419 # take over. 420 421 c = element.get( "count" ) 422 try: 423 count = int(c) 424 self.count = count 425 self.counter = None 426 except Exception,e: 427 count = 1 428 self.count = 0 429 self.counter = c 430 431 self.count_scale = int(element.get( "count_scale", "1" )) 432 433 elements = (count * self.count_scale) 434 if elements == 1: 435 elements = 0 436 437 #if ts == "GLdouble": 438 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size()) 439 # print '/* # elements = %u */' % (elements) 440 self.type_expr.set_elements( elements ) 441 #if ts == "GLdouble": 442 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size()) 443 444 self.is_client_only = is_attr_true( element, 'client_only' ) 445 self.is_counter = is_attr_true( element, 'counter' ) 446 self.is_output = is_attr_true( element, 'output' ) 447 448 449 # Pixel data has special parameters. 450 451 self.width = element.get('img_width') 452 self.height = element.get('img_height') 453 self.depth = element.get('img_depth') 454 self.extent = element.get('img_extent') 455 456 self.img_xoff = element.get('img_xoff') 457 self.img_yoff = element.get('img_yoff') 458 self.img_zoff = element.get('img_zoff') 459 self.img_woff = element.get('img_woff') 460 461 self.img_format = element.get('img_format') 462 self.img_type = element.get('img_type') 463 self.img_target = element.get('img_target') 464 465 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' ) 466 self.img_null_flag = is_attr_true( element, 'img_null_flag' ) 467 self.img_send_null = is_attr_true( element, 'img_send_null' ) 468 469 self.is_padding = is_attr_true( element, 'padding' ) 470 return 471 472 473 def compatible(self, other): 474 return 1 475 476 477 def is_array(self): 478 return self.is_pointer() 479 480 481 def is_pointer(self): 482 return self.type_expr.is_pointer() 483 484 485 def is_image(self): 486 if self.width: 487 return 1 488 else: 489 return 0 490 491 492 def is_variable_length(self): 493 return len(self.count_parameter_list) or self.counter 494 495 496 def is_64_bit(self): 497 count = self.type_expr.get_element_count() 498 if count: 499 if (self.size() / count) == 8: 500 return 1 501 else: 502 if self.size() == 8: 503 return 1 504 505 return 0 506 507 508 def string(self): 509 return self.type_expr.original_string + " " + self.name 510 511 512 def type_string(self): 513 return self.type_expr.original_string 514 515 516 def get_base_type_string(self): 517 return self.type_expr.get_base_name() 518 519 520 def get_dimensions(self): 521 if not self.width: 522 return [ 0, "0", "0", "0", "0" ] 523 524 dim = 1 525 w = self.width 526 h = "1" 527 d = "1" 528 e = "1" 529 530 if self.height: 531 dim = 2 532 h = self.height 533 534 if self.depth: 535 dim = 3 536 d = self.depth 537 538 if self.extent: 539 dim = 4 540 e = self.extent 541 542 return [ dim, w, h, d, e ] 543 544 545 def get_stack_size(self): 546 return self.type_expr.get_stack_size() 547 548 549 def size(self): 550 if self.is_image(): 551 return 0 552 else: 553 return self.type_expr.get_element_size() 554 555 556 def get_element_count(self): 557 c = self.type_expr.get_element_count() 558 if c == 0: 559 return 1 560 561 return c 562 563 564 def size_string(self, use_parens = 1): 565 s = self.size() 566 if self.counter or self.count_parameter_list: 567 list = [ "compsize" ] 568 569 if self.counter and self.count_parameter_list: 570 list.append( self.counter ) 571 elif self.counter: 572 list = [ self.counter ] 573 574 if s > 1: 575 list.append( str(s) ) 576 577 if len(list) > 1 and use_parens : 578 return "safe_mul(%s)" % (string.join(list, ", ")) 579 else: 580 return string.join(list, " * ") 581 582 elif self.is_image(): 583 return "compsize" 584 else: 585 return str(s) 586 587 588 def format_string(self): 589 if self.type_expr.original_string == "GLenum": 590 return "0x%x" 591 else: 592 return self.type_expr.format_string() 593 594 595class gl_function( gl_item ): 596 def __init__(self, element, context): 597 self.context = context 598 self.name = None 599 600 self.entry_points = [] 601 self.return_type = "void" 602 self.parameters = [] 603 self.offset = -1 604 self.initialized = 0 605 self.images = [] 606 self.exec_flavor = 'mesa' 607 self.desktop = True 608 self.deprecated = None 609 self.has_no_error_variant = False 610 611 # self.entry_point_api_map[name][api] is a decimal value 612 # indicating the earliest version of the given API in which 613 # each entry point exists. Every entry point is included in 614 # the first level of the map; the second level of the map only 615 # lists APIs which contain the entry point in at least one 616 # version. For example, 617 # self.entry_point_api_map['ClipPlanex'] == { 'es1': 618 # Decimal('1.1') }. 619 self.entry_point_api_map = {} 620 621 # self.api_map[api] is a decimal value indicating the earliest 622 # version of the given API in which ANY alias for the function 623 # exists. The map only lists APIs which contain the function 624 # in at least one version. For example, for the ClipPlanex 625 # function, self.entry_point_api_map == { 'es1': 626 # Decimal('1.1') }. 627 self.api_map = {} 628 629 self.assign_offset = False 630 631 self.static_entry_points = [] 632 633 # Track the parameter string (for the function prototype) 634 # for each entry-point. This is done because some functions 635 # change their prototype slightly when promoted from extension 636 # to ARB extension to core. glTexImage3DEXT and glTexImage3D 637 # are good examples of this. Scripts that need to generate 638 # code for these differing aliases need to real prototype 639 # for each entry-point. Otherwise, they may generate code 640 # that won't compile. 641 642 self.entry_point_parameters = {} 643 644 self.process_element( element ) 645 646 return 647 648 649 def process_element(self, element): 650 name = element.get( "name" ) 651 alias = element.get( "alias" ) 652 653 if name in static_data.functions: 654 self.static_entry_points.append(name) 655 656 self.entry_points.append( name ) 657 658 self.entry_point_api_map[name] = {} 659 for api in ('es1', 'es2'): 660 version_str = element.get(api, 'none') 661 assert version_str is not None 662 if version_str != 'none': 663 version_decimal = Decimal(version_str) 664 self.entry_point_api_map[name][api] = version_decimal 665 if api not in self.api_map or \ 666 version_decimal < self.api_map[api]: 667 self.api_map[api] = version_decimal 668 669 exec_flavor = element.get('exec') 670 if exec_flavor: 671 self.exec_flavor = exec_flavor 672 673 deprecated = element.get('deprecated', 'none') 674 if deprecated != 'none': 675 self.deprecated = Decimal(deprecated) 676 677 if not is_attr_true(element, 'desktop', 'true'): 678 self.desktop = False 679 680 if self.has_no_error_variant or is_attr_true(element, 'no_error'): 681 self.has_no_error_variant = True 682 else: 683 self.has_no_error_variant = False 684 685 if alias: 686 true_name = alias 687 else: 688 true_name = name 689 690 # Only try to set the offset when a non-alias entry-point 691 # is being processed. 692 693 if name in static_data.offsets: 694 self.offset = static_data.offsets[name] 695 else: 696 self.offset = -1 697 self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions 698 699 if not self.name: 700 self.name = true_name 701 elif self.name != true_name: 702 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name)) 703 704 705 # There are two possible cases. The first time an entry-point 706 # with data is seen, self.initialized will be 0. On that 707 # pass, we just fill in the data. The next time an 708 # entry-point with data is seen, self.initialized will be 1. 709 # On that pass we have to make that the new values match the 710 # valuse from the previous entry-point. 711 712 parameters = [] 713 return_type = "void" 714 for child in element.getchildren(): 715 if child.tag == "return": 716 return_type = child.get( "type", "void" ) 717 elif child.tag == "param": 718 param = self.context.factory.create_parameter(child, self.context) 719 parameters.append( param ) 720 721 722 if self.initialized: 723 if self.return_type != return_type: 724 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type)) 725 726 if len(parameters) != len(self.parameters): 727 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters))) 728 729 for j in range(0, len(parameters)): 730 p1 = parameters[j] 731 p2 = self.parameters[j] 732 if not p1.compatible( p2 ): 733 raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string)) 734 735 736 if true_name == name or not self.initialized: 737 self.return_type = return_type 738 self.parameters = parameters 739 740 for param in self.parameters: 741 if param.is_image(): 742 self.images.append( param ) 743 744 if element.getchildren(): 745 self.initialized = 1 746 self.entry_point_parameters[name] = parameters 747 else: 748 self.entry_point_parameters[name] = [] 749 750 return 751 752 def filter_entry_points(self, entry_point_list): 753 """Filter out entry points not in entry_point_list.""" 754 if not self.initialized: 755 raise RuntimeError('%s is not initialized yet' % self.name) 756 757 entry_points = [] 758 for ent in self.entry_points: 759 if ent not in entry_point_list: 760 if ent in self.static_entry_points: 761 self.static_entry_points.remove(ent) 762 self.entry_point_parameters.pop(ent) 763 else: 764 entry_points.append(ent) 765 766 if not entry_points: 767 raise RuntimeError('%s has no entry point after filtering' % self.name) 768 769 self.entry_points = entry_points 770 if self.name not in entry_points: 771 # use the first remaining entry point 772 self.name = entry_points[0] 773 self.parameters = self.entry_point_parameters[entry_points[0]] 774 775 def get_images(self): 776 """Return potentially empty list of input images.""" 777 return self.images 778 779 780 def parameterIterator(self, name = None): 781 if name is not None: 782 return self.entry_point_parameters[name].__iter__(); 783 else: 784 return self.parameters.__iter__(); 785 786 787 def get_parameter_string(self, entrypoint = None): 788 if entrypoint: 789 params = self.entry_point_parameters[ entrypoint ] 790 else: 791 params = self.parameters 792 793 return create_parameter_string( params, 1 ) 794 795 def get_called_parameter_string(self): 796 p_string = "" 797 comma = "" 798 799 for p in self.parameterIterator(): 800 if p.is_padding: 801 continue 802 p_string = p_string + comma + p.name 803 comma = ", " 804 805 return p_string 806 807 808 def is_abi(self): 809 return (self.offset >= 0 and not self.assign_offset) 810 811 def is_static_entry_point(self, name): 812 return name in self.static_entry_points 813 814 def dispatch_name(self): 815 if self.name in self.static_entry_points: 816 return self.name 817 else: 818 return "_dispatch_stub_%u" % (self.offset) 819 820 def static_name(self, name): 821 if name in self.static_entry_points: 822 return name 823 else: 824 return "_dispatch_stub_%u" % (self.offset) 825 826 def entry_points_for_api_version(self, api, version = None): 827 """Return a list of the entry point names for this function 828 which are supported in the given API (and optionally, version). 829 830 Use the decimal.Decimal type to precisely express non-integer 831 versions. 832 """ 833 result = [] 834 for entry_point, api_to_ver in self.entry_point_api_map.iteritems(): 835 if api not in api_to_ver: 836 continue 837 if version is not None and version < api_to_ver[api]: 838 continue 839 result.append(entry_point) 840 return result 841 842 843class gl_item_factory(object): 844 """Factory to create objects derived from gl_item.""" 845 846 def create_function(self, element, context): 847 return gl_function(element, context) 848 849 def create_type(self, element, context, category): 850 return gl_type(element, context, category) 851 852 def create_enum(self, element, context, category): 853 return gl_enum(element, context, category) 854 855 def create_parameter(self, element, context): 856 return gl_parameter(element, context) 857 858 def create_api(self): 859 return gl_api(self) 860 861 862class gl_api(object): 863 def __init__(self, factory): 864 self.functions_by_name = {} 865 self.enums_by_name = {} 866 self.types_by_name = {} 867 868 self.category_dict = {} 869 self.categories = [{}, {}, {}, {}] 870 871 self.factory = factory 872 873 self.next_offset = 0 874 875 typeexpr.create_initial_types() 876 return 877 878 def filter_functions(self, entry_point_list): 879 """Filter out entry points not in entry_point_list.""" 880 functions_by_name = {} 881 for func in self.functions_by_name.itervalues(): 882 entry_points = [ent for ent in func.entry_points if ent in entry_point_list] 883 if entry_points: 884 func.filter_entry_points(entry_points) 885 functions_by_name[func.name] = func 886 887 self.functions_by_name = functions_by_name 888 889 def filter_functions_by_api(self, api, version = None): 890 """Filter out entry points not in the given API (or 891 optionally, not in the given version of the given API). 892 """ 893 functions_by_name = {} 894 for func in self.functions_by_name.itervalues(): 895 entry_points = func.entry_points_for_api_version(api, version) 896 if entry_points: 897 func.filter_entry_points(entry_points) 898 functions_by_name[func.name] = func 899 900 self.functions_by_name = functions_by_name 901 902 903 def parse_file(self, file_name): 904 doc = ET.parse( file_name ) 905 self.process_element(file_name, doc) 906 907 908 def process_element(self, file_name, doc): 909 element = doc.getroot() 910 if element.tag == "OpenGLAPI": 911 self.process_OpenGLAPI(file_name, element) 912 return 913 914 915 def process_OpenGLAPI(self, file_name, element): 916 for child in element.getchildren(): 917 if child.tag == "category": 918 self.process_category( child ) 919 elif child.tag == "OpenGLAPI": 920 self.process_OpenGLAPI( file_name, child ) 921 elif child.tag == '{http://www.w3.org/2001/XInclude}include': 922 href = child.get('href') 923 href = os.path.join(os.path.dirname(file_name), href) 924 self.parse_file(href) 925 926 return 927 928 929 def process_category(self, cat): 930 cat_name = cat.get( "name" ) 931 cat_number = cat.get( "number" ) 932 933 [cat_type, key] = classify_category(cat_name, cat_number) 934 self.categories[cat_type][key] = [cat_name, cat_number] 935 936 for child in cat.getchildren(): 937 if child.tag == "function": 938 func_name = real_function_name( child ) 939 940 temp_name = child.get( "name" ) 941 self.category_dict[ temp_name ] = [cat_name, cat_number] 942 943 if self.functions_by_name.has_key( func_name ): 944 func = self.functions_by_name[ func_name ] 945 func.process_element( child ) 946 else: 947 func = self.factory.create_function( child, self ) 948 self.functions_by_name[ func_name ] = func 949 950 if func.offset >= self.next_offset: 951 self.next_offset = func.offset + 1 952 953 954 elif child.tag == "enum": 955 enum = self.factory.create_enum( child, self, cat_name ) 956 self.enums_by_name[ enum.name ] = enum 957 elif child.tag == "type": 958 t = self.factory.create_type( child, self, cat_name ) 959 self.types_by_name[ "GL" + t.name ] = t 960 961 return 962 963 964 def functionIterateByCategory(self, cat = None): 965 """Iterate over functions by category. 966 967 If cat is None, all known functions are iterated in category 968 order. See classify_category for details of the ordering. 969 Within a category, functions are sorted by name. If cat is 970 not None, then only functions in that category are iterated. 971 """ 972 lists = [{}, {}, {}, {}] 973 974 for func in self.functionIterateAll(): 975 [cat_name, cat_number] = self.category_dict[func.name] 976 977 if (cat == None) or (cat == cat_name): 978 [func_cat_type, key] = classify_category(cat_name, cat_number) 979 980 if not lists[func_cat_type].has_key(key): 981 lists[func_cat_type][key] = {} 982 983 lists[func_cat_type][key][func.name] = func 984 985 986 functions = [] 987 for func_cat_type in range(0,4): 988 keys = lists[func_cat_type].keys() 989 keys.sort() 990 991 for key in keys: 992 names = lists[func_cat_type][key].keys() 993 names.sort() 994 995 for name in names: 996 functions.append(lists[func_cat_type][key][name]) 997 998 return functions.__iter__() 999 1000 1001 def functionIterateByOffset(self): 1002 max_offset = -1 1003 for func in self.functions_by_name.itervalues(): 1004 if func.offset > max_offset: 1005 max_offset = func.offset 1006 1007 1008 temp = [None for i in range(0, max_offset + 1)] 1009 for func in self.functions_by_name.itervalues(): 1010 if func.offset != -1: 1011 temp[ func.offset ] = func 1012 1013 1014 list = [] 1015 for i in range(0, max_offset + 1): 1016 if temp[i]: 1017 list.append(temp[i]) 1018 1019 return list.__iter__(); 1020 1021 1022 def functionIterateAll(self): 1023 return self.functions_by_name.itervalues() 1024 1025 1026 def enumIterateByName(self): 1027 keys = self.enums_by_name.keys() 1028 keys.sort() 1029 1030 list = [] 1031 for enum in keys: 1032 list.append( self.enums_by_name[ enum ] ) 1033 1034 return list.__iter__() 1035 1036 1037 def categoryIterate(self): 1038 """Iterate over categories. 1039 1040 Iterate over all known categories in the order specified by 1041 classify_category. Each iterated value is a tuple of the 1042 name and number (which may be None) of the category. 1043 """ 1044 1045 list = [] 1046 for cat_type in range(0,4): 1047 keys = self.categories[cat_type].keys() 1048 keys.sort() 1049 1050 for key in keys: 1051 list.append(self.categories[cat_type][key]) 1052 1053 return list.__iter__() 1054 1055 1056 def get_category_for_name( self, name ): 1057 if self.category_dict.has_key(name): 1058 return self.category_dict[name] 1059 else: 1060 return ["<unknown category>", None] 1061 1062 1063 def typeIterate(self): 1064 return self.types_by_name.itervalues() 1065 1066 1067 def find_type( self, type_name ): 1068 if type_name in self.types_by_name: 1069 return self.types_by_name[ type_name ].type_expr 1070 else: 1071 print "Unable to find base type matching \"%s\"." % (type_name) 1072 return None 1073