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