gl_XML.py revision 848b8605
1#!/usr/bin/env python 2 3# (C) Copyright IBM Corporation 2004, 2005 4# All Rights Reserved. 5# 6# Permission is hereby granted, free of charge, to any person obtaining a 7# copy of this software and associated documentation files (the "Software"), 8# to deal in the Software without restriction, including without limitation 9# on the rights to use, copy, modify, merge, publish, distribute, sub 10# license, and/or sell copies of the Software, and to permit persons to whom 11# the Software is furnished to do so, subject to the following conditions: 12# 13# The above copyright notice and this permission notice (including the next 14# paragraph) shall be included in all copies or substantial portions of the 15# Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23# IN THE SOFTWARE. 24# 25# Authors: 26# Ian Romanick <idr@us.ibm.com> 27 28from decimal import Decimal 29import xml.etree.ElementTree as ET 30import re, sys, string 31import os.path 32import typeexpr 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 * ') 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__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) && defined(__ELF__)) 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__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) 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 "(%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 610 # self.entry_point_api_map[name][api] is a decimal value 611 # indicating the earliest version of the given API in which 612 # each entry point exists. Every entry point is included in 613 # the first level of the map; the second level of the map only 614 # lists APIs which contain the entry point in at least one 615 # version. For example, 616 # self.entry_point_api_map['ClipPlanex'] == { 'es1': 617 # Decimal('1.1') }. 618 self.entry_point_api_map = {} 619 620 # self.api_map[api] is a decimal value indicating the earliest 621 # version of the given API in which ANY alias for the function 622 # exists. The map only lists APIs which contain the function 623 # in at least one version. For example, for the ClipPlanex 624 # function, self.entry_point_api_map == { 'es1': 625 # Decimal('1.1') }. 626 self.api_map = {} 627 628 self.assign_offset = 0 629 630 self.static_entry_points = [] 631 632 # Track the parameter string (for the function prototype) 633 # for each entry-point. This is done because some functions 634 # change their prototype slightly when promoted from extension 635 # to ARB extension to core. glTexImage3DEXT and glTexImage3D 636 # are good examples of this. Scripts that need to generate 637 # code for these differing aliases need to real prototype 638 # for each entry-point. Otherwise, they may generate code 639 # that won't compile. 640 641 self.entry_point_parameters = {} 642 643 self.process_element( element ) 644 645 return 646 647 648 def process_element(self, element): 649 name = element.get( "name" ) 650 alias = element.get( "alias" ) 651 652 if is_attr_true(element, "static_dispatch", "true"): 653 self.static_entry_points.append(name) 654 655 self.entry_points.append( name ) 656 657 self.entry_point_api_map[name] = {} 658 for api in ('es1', 'es2'): 659 version_str = element.get(api, 'none') 660 assert version_str is not None 661 if version_str != 'none': 662 version_decimal = Decimal(version_str) 663 self.entry_point_api_map[name][api] = version_decimal 664 if api not in self.api_map or \ 665 version_decimal < self.api_map[api]: 666 self.api_map[api] = version_decimal 667 668 exec_flavor = element.get('exec') 669 if exec_flavor: 670 self.exec_flavor = exec_flavor 671 672 deprecated = element.get('deprecated', 'none') 673 if deprecated != 'none': 674 self.deprecated = Decimal(deprecated) 675 676 if not is_attr_true(element, 'desktop', 'true'): 677 self.desktop = False 678 679 if alias: 680 true_name = alias 681 else: 682 true_name = name 683 684 # Only try to set the offset when a non-alias entry-point 685 # is being processed. 686 687 offset = element.get( "offset" ) 688 if offset: 689 try: 690 o = int( offset ) 691 self.offset = o 692 except Exception, e: 693 self.offset = -1 694 if offset == "assign": 695 self.assign_offset = 1 696 697 698 if not self.name: 699 self.name = true_name 700 elif self.name != true_name: 701 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name)) 702 703 704 # There are two possible cases. The first time an entry-point 705 # with data is seen, self.initialized will be 0. On that 706 # pass, we just fill in the data. The next time an 707 # entry-point with data is seen, self.initialized will be 1. 708 # On that pass we have to make that the new values match the 709 # valuse from the previous entry-point. 710 711 parameters = [] 712 return_type = "void" 713 for child in element.getchildren(): 714 if child.tag == "return": 715 return_type = child.get( "type", "void" ) 716 elif child.tag == "param": 717 param = self.context.factory.create_parameter(child, self.context) 718 parameters.append( param ) 719 720 721 if self.initialized: 722 if self.return_type != return_type: 723 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type)) 724 725 if len(parameters) != len(self.parameters): 726 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters))) 727 728 for j in range(0, len(parameters)): 729 p1 = parameters[j] 730 p2 = self.parameters[j] 731 if not p1.compatible( p2 ): 732 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)) 733 734 735 if true_name == name or not self.initialized: 736 self.return_type = return_type 737 self.parameters = parameters 738 739 for param in self.parameters: 740 if param.is_image(): 741 self.images.append( param ) 742 743 if element.getchildren(): 744 self.initialized = 1 745 self.entry_point_parameters[name] = parameters 746 else: 747 self.entry_point_parameters[name] = [] 748 749 return 750 751 def filter_entry_points(self, entry_point_list): 752 """Filter out entry points not in entry_point_list.""" 753 if not self.initialized: 754 raise RuntimeError('%s is not initialized yet' % self.name) 755 756 entry_points = [] 757 for ent in self.entry_points: 758 if ent not in entry_point_list: 759 if ent in self.static_entry_points: 760 self.static_entry_points.remove(ent) 761 self.entry_point_parameters.pop(ent) 762 else: 763 entry_points.append(ent) 764 765 if not entry_points: 766 raise RuntimeError('%s has no entry point after filtering' % self.name) 767 768 self.entry_points = entry_points 769 if self.name not in entry_points: 770 # use the first remaining entry point 771 self.name = entry_points[0] 772 self.parameters = self.entry_point_parameters[entry_points[0]] 773 774 def get_images(self): 775 """Return potentially empty list of input images.""" 776 return self.images 777 778 779 def parameterIterator(self, name = None): 780 if name is not None: 781 return self.entry_point_parameters[name].__iter__(); 782 else: 783 return self.parameters.__iter__(); 784 785 786 def get_parameter_string(self, entrypoint = None): 787 if entrypoint: 788 params = self.entry_point_parameters[ entrypoint ] 789 else: 790 params = self.parameters 791 792 return create_parameter_string( params, 1 ) 793 794 def get_called_parameter_string(self): 795 p_string = "" 796 comma = "" 797 798 for p in self.parameterIterator(): 799 if p.is_padding: 800 continue 801 p_string = p_string + comma + p.name 802 comma = ", " 803 804 return p_string 805 806 807 def is_abi(self): 808 return (self.offset >= 0 and not self.assign_offset) 809 810 def is_static_entry_point(self, name): 811 return name in self.static_entry_points 812 813 def dispatch_name(self): 814 if self.name in self.static_entry_points: 815 return self.name 816 else: 817 return "_dispatch_stub_%u" % (self.offset) 818 819 def static_name(self, name): 820 if name in self.static_entry_points: 821 return name 822 else: 823 return "_dispatch_stub_%u" % (self.offset) 824 825 def entry_points_for_api_version(self, api, version = None): 826 """Return a list of the entry point names for this function 827 which are supported in the given API (and optionally, version). 828 829 Use the decimal.Decimal type to precisely express non-integer 830 versions. 831 """ 832 result = [] 833 for entry_point, api_to_ver in self.entry_point_api_map.iteritems(): 834 if api not in api_to_ver: 835 continue 836 if version is not None and version < api_to_ver[api]: 837 continue 838 result.append(entry_point) 839 return result 840 841 842class gl_item_factory(object): 843 """Factory to create objects derived from gl_item.""" 844 845 def create_function(self, element, context): 846 return gl_function(element, context) 847 848 def create_type(self, element, context, category): 849 return gl_type(element, context, category) 850 851 def create_enum(self, element, context, category): 852 return gl_enum(element, context, category) 853 854 def create_parameter(self, element, context): 855 return gl_parameter(element, context) 856 857 def create_api(self): 858 return gl_api(self) 859 860 861class gl_api(object): 862 def __init__(self, factory): 863 self.functions_by_name = {} 864 self.enums_by_name = {} 865 self.types_by_name = {} 866 867 self.category_dict = {} 868 self.categories = [{}, {}, {}, {}] 869 870 self.factory = factory 871 872 self.next_offset = 0 873 874 typeexpr.create_initial_types() 875 return 876 877 def filter_functions(self, entry_point_list): 878 """Filter out entry points not in entry_point_list.""" 879 functions_by_name = {} 880 for func in self.functions_by_name.itervalues(): 881 entry_points = [ent for ent in func.entry_points if ent in entry_point_list] 882 if entry_points: 883 func.filter_entry_points(entry_points) 884 functions_by_name[func.name] = func 885 886 self.functions_by_name = functions_by_name 887 888 def filter_functions_by_api(self, api, version = None): 889 """Filter out entry points not in the given API (or 890 optionally, not in the given version of the given API). 891 """ 892 functions_by_name = {} 893 for func in self.functions_by_name.itervalues(): 894 entry_points = func.entry_points_for_api_version(api, version) 895 if entry_points: 896 func.filter_entry_points(entry_points) 897 functions_by_name[func.name] = func 898 899 self.functions_by_name = functions_by_name 900 901 902 def parse_file(self, file_name): 903 doc = ET.parse( file_name ) 904 self.process_element(file_name, doc) 905 906 907 def process_element(self, file_name, doc): 908 element = doc.getroot() 909 if element.tag == "OpenGLAPI": 910 self.process_OpenGLAPI(file_name, element) 911 return 912 913 914 def process_OpenGLAPI(self, file_name, element): 915 for child in element.getchildren(): 916 if child.tag == "category": 917 self.process_category( child ) 918 elif child.tag == "OpenGLAPI": 919 self.process_OpenGLAPI( file_name, child ) 920 elif child.tag == '{http://www.w3.org/2001/XInclude}include': 921 href = child.get('href') 922 href = os.path.join(os.path.dirname(file_name), href) 923 self.parse_file(href) 924 925 return 926 927 928 def process_category(self, cat): 929 cat_name = cat.get( "name" ) 930 cat_number = cat.get( "number" ) 931 932 [cat_type, key] = classify_category(cat_name, cat_number) 933 self.categories[cat_type][key] = [cat_name, cat_number] 934 935 for child in cat.getchildren(): 936 if child.tag == "function": 937 func_name = real_function_name( child ) 938 939 temp_name = child.get( "name" ) 940 self.category_dict[ temp_name ] = [cat_name, cat_number] 941 942 if self.functions_by_name.has_key( func_name ): 943 func = self.functions_by_name[ func_name ] 944 func.process_element( child ) 945 else: 946 func = self.factory.create_function( child, self ) 947 self.functions_by_name[ func_name ] = func 948 949 if func.offset >= self.next_offset: 950 self.next_offset = func.offset + 1 951 952 953 elif child.tag == "enum": 954 enum = self.factory.create_enum( child, self, cat_name ) 955 self.enums_by_name[ enum.name ] = enum 956 elif child.tag == "type": 957 t = self.factory.create_type( child, self, cat_name ) 958 self.types_by_name[ "GL" + t.name ] = t 959 960 return 961 962 963 def functionIterateByCategory(self, cat = None): 964 """Iterate over functions by category. 965 966 If cat is None, all known functions are iterated in category 967 order. See classify_category for details of the ordering. 968 Within a category, functions are sorted by name. If cat is 969 not None, then only functions in that category are iterated. 970 """ 971 lists = [{}, {}, {}, {}] 972 973 for func in self.functionIterateAll(): 974 [cat_name, cat_number] = self.category_dict[func.name] 975 976 if (cat == None) or (cat == cat_name): 977 [func_cat_type, key] = classify_category(cat_name, cat_number) 978 979 if not lists[func_cat_type].has_key(key): 980 lists[func_cat_type][key] = {} 981 982 lists[func_cat_type][key][func.name] = func 983 984 985 functions = [] 986 for func_cat_type in range(0,4): 987 keys = lists[func_cat_type].keys() 988 keys.sort() 989 990 for key in keys: 991 names = lists[func_cat_type][key].keys() 992 names.sort() 993 994 for name in names: 995 functions.append(lists[func_cat_type][key][name]) 996 997 return functions.__iter__() 998 999 1000 def functionIterateByOffset(self): 1001 max_offset = -1 1002 for func in self.functions_by_name.itervalues(): 1003 if func.offset > max_offset: 1004 max_offset = func.offset 1005 1006 1007 temp = [None for i in range(0, max_offset + 1)] 1008 for func in self.functions_by_name.itervalues(): 1009 if func.offset != -1: 1010 temp[ func.offset ] = func 1011 1012 1013 list = [] 1014 for i in range(0, max_offset + 1): 1015 if temp[i]: 1016 list.append(temp[i]) 1017 1018 return list.__iter__(); 1019 1020 1021 def functionIterateAll(self): 1022 return self.functions_by_name.itervalues() 1023 1024 1025 def enumIterateByName(self): 1026 keys = self.enums_by_name.keys() 1027 keys.sort() 1028 1029 list = [] 1030 for enum in keys: 1031 list.append( self.enums_by_name[ enum ] ) 1032 1033 return list.__iter__() 1034 1035 1036 def categoryIterate(self): 1037 """Iterate over categories. 1038 1039 Iterate over all known categories in the order specified by 1040 classify_category. Each iterated value is a tuple of the 1041 name and number (which may be None) of the category. 1042 """ 1043 1044 list = [] 1045 for cat_type in range(0,4): 1046 keys = self.categories[cat_type].keys() 1047 keys.sort() 1048 1049 for key in keys: 1050 list.append(self.categories[cat_type][key]) 1051 1052 return list.__iter__() 1053 1054 1055 def get_category_for_name( self, name ): 1056 if self.category_dict.has_key(name): 1057 return self.category_dict[name] 1058 else: 1059 return ["<unknown category>", None] 1060 1061 1062 def typeIterate(self): 1063 return self.types_by_name.itervalues() 1064 1065 1066 def find_type( self, type_name ): 1067 if type_name in self.types_by_name: 1068 return self.types_by_name[ type_name ].type_expr 1069 else: 1070 print "Unable to find base type matching \"%s\"." % (type_name) 1071 return None 1072