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