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