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