Home | History | Annotate | Download | only in gen
      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 (at] us.ibm.com>
     27 
     28 from decimal import Decimal
     29 import xml.etree.ElementTree as ET
     30 import re, sys, string
     31 import os.path
     32 import typeexpr
     33 import static_data
     34 
     35 
     36 def 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:
     51             func.offset = api.next_offset;
     52             api.next_offset += 1
     53 
     54     return api
     55 
     56 
     57 def 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 
     74 class 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 
    254 def 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 
    264 def 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 
    271 def 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,e:
    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 
    306 def 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 string.join(list, ", ")
    322 
    323 
    324 class 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 
    333 class 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 
    355 class 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,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 
    404 class 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,e:
    428             count = 1
    429             self.count = 0
    430             self.counter = c
    431 
    432         self.count_scale = int(element.get( "count_scale", "1" ))
    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.get('img_width')
    453         self.height     = element.get('img_height')
    454         self.depth      = element.get('img_depth')
    455         self.extent     = element.get('img_extent')
    456 
    457         self.img_xoff   = element.get('img_xoff')
    458         self.img_yoff   = element.get('img_yoff')
    459         self.img_zoff   = element.get('img_zoff')
    460         self.img_woff   = element.get('img_woff')
    461 
    462         self.img_format = element.get('img_format')
    463         self.img_type   = element.get('img_type')
    464         self.img_target = element.get('img_target')
    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 "safe_mul(%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 class gl_function( gl_item ):
    597     def __init__(self, element, context):
    598         self.context = context
    599         self.name = None
    600 
    601         self.entry_points = []
    602         self.return_type = "void"
    603         self.parameters = []
    604         self.offset = -1
    605         self.initialized = 0
    606         self.images = []
    607         self.exec_flavor = 'mesa'
    608         self.desktop = True
    609         self.deprecated = None
    610 
    611         # self.entry_point_api_map[name][api] is a decimal value
    612         # indicating the earliest version of the given API in which
    613         # each entry point exists.  Every entry point is included in
    614         # the first level of the map; the second level of the map only
    615         # lists APIs which contain the entry point in at least one
    616         # version.  For example,
    617         # self.entry_point_api_map['ClipPlanex'] == { 'es1':
    618         # Decimal('1.1') }.
    619         self.entry_point_api_map = {}
    620 
    621         # self.api_map[api] is a decimal value indicating the earliest
    622         # version of the given API in which ANY alias for the function
    623         # exists.  The map only lists APIs which contain the function
    624         # in at least one version.  For example, for the ClipPlanex
    625         # function, self.entry_point_api_map == { 'es1':
    626         # Decimal('1.1') }.
    627         self.api_map = {}
    628 
    629         self.assign_offset = False
    630 
    631         self.static_entry_points = []
    632 
    633         # Track the parameter string (for the function prototype)
    634         # for each entry-point.  This is done because some functions
    635         # change their prototype slightly when promoted from extension
    636         # to ARB extension to core.  glTexImage3DEXT and glTexImage3D
    637         # are good examples of this.  Scripts that need to generate
    638         # code for these differing aliases need to real prototype
    639         # for each entry-point.  Otherwise, they may generate code
    640         # that won't compile.
    641 
    642         self.entry_point_parameters = {}
    643 
    644         self.process_element( element )
    645 
    646         return
    647 
    648 
    649     def process_element(self, element):
    650         name = element.get( "name" )
    651         alias = element.get( "alias" )
    652 
    653         if name in static_data.functions:
    654             self.static_entry_points.append(name)
    655 
    656         self.entry_points.append( name )
    657 
    658         self.entry_point_api_map[name] = {}
    659         for api in ('es1', 'es2'):
    660             version_str = element.get(api, 'none')
    661             assert version_str is not None
    662             if version_str != 'none':
    663                 version_decimal = Decimal(version_str)
    664                 self.entry_point_api_map[name][api] = version_decimal
    665                 if api not in self.api_map or \
    666                         version_decimal < self.api_map[api]:
    667                     self.api_map[api] = version_decimal
    668 
    669         exec_flavor = element.get('exec')
    670         if exec_flavor:
    671             self.exec_flavor = exec_flavor
    672 
    673         deprecated = element.get('deprecated', 'none')
    674         if deprecated != 'none':
    675             self.deprecated = Decimal(deprecated)
    676 
    677         if not is_attr_true(element, 'desktop', 'true'):
    678             self.desktop = False
    679 
    680         if alias:
    681             true_name = alias
    682         else:
    683             true_name = name
    684 
    685             # Only try to set the offset when a non-alias entry-point
    686             # is being processed.
    687 
    688             if name in static_data.offsets:
    689                 self.offset = static_data.offsets[name]
    690             else:
    691                 self.offset = -1
    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 self.entry_point_parameters[name].__iter__();
    778         else:
    779             return self.parameters.__iter__();
    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 
    821     def entry_points_for_api_version(self, api, version = None):
    822         """Return a list of the entry point names for this function
    823         which are supported in the given API (and optionally, version).
    824 
    825         Use the decimal.Decimal type to precisely express non-integer
    826         versions.
    827         """
    828         result = []
    829         for entry_point, api_to_ver in self.entry_point_api_map.iteritems():
    830             if api not in api_to_ver:
    831                 continue
    832             if version is not None and version < api_to_ver[api]:
    833                 continue
    834             result.append(entry_point)
    835         return result
    836 
    837 
    838 class gl_item_factory(object):
    839     """Factory to create objects derived from gl_item."""
    840 
    841     def create_function(self, element, context):
    842         return gl_function(element, context)
    843 
    844     def create_type(self, element, context, category):
    845         return gl_type(element, context, category)
    846 
    847     def create_enum(self, element, context, category):
    848         return gl_enum(element, context, category)
    849 
    850     def create_parameter(self, element, context):
    851         return gl_parameter(element, context)
    852 
    853     def create_api(self):
    854         return gl_api(self)
    855 
    856 
    857 class gl_api(object):
    858     def __init__(self, factory):
    859         self.functions_by_name = {}
    860         self.enums_by_name = {}
    861         self.types_by_name = {}
    862 
    863         self.category_dict = {}
    864         self.categories = [{}, {}, {}, {}]
    865 
    866         self.factory = factory
    867 
    868         self.next_offset = 0
    869 
    870         typeexpr.create_initial_types()
    871         return
    872 
    873     def filter_functions(self, entry_point_list):
    874         """Filter out entry points not in entry_point_list."""
    875         functions_by_name = {}
    876         for func in self.functions_by_name.itervalues():
    877             entry_points = [ent for ent in func.entry_points if ent in entry_point_list]
    878             if entry_points:
    879                 func.filter_entry_points(entry_points)
    880                 functions_by_name[func.name] = func
    881 
    882         self.functions_by_name = functions_by_name
    883 
    884     def filter_functions_by_api(self, api, version = None):
    885         """Filter out entry points not in the given API (or
    886         optionally, not in the given version of the given API).
    887         """
    888         functions_by_name = {}
    889         for func in self.functions_by_name.itervalues():
    890             entry_points = func.entry_points_for_api_version(api, version)
    891             if entry_points:
    892                 func.filter_entry_points(entry_points)
    893                 functions_by_name[func.name] = func
    894 
    895         self.functions_by_name = functions_by_name
    896 
    897 
    898     def parse_file(self, file_name):
    899         doc = ET.parse( file_name )
    900         self.process_element(file_name, doc)
    901 
    902 
    903     def process_element(self, file_name, doc):
    904         element = doc.getroot()
    905         if element.tag == "OpenGLAPI":
    906             self.process_OpenGLAPI(file_name, element)
    907         return
    908 
    909 
    910     def process_OpenGLAPI(self, file_name, element):
    911         for child in element.getchildren():
    912             if child.tag == "category":
    913                 self.process_category( child )
    914             elif child.tag == "OpenGLAPI":
    915                 self.process_OpenGLAPI( file_name, child )
    916             elif child.tag == '{http://www.w3.org/2001/XInclude}include':
    917                 href = child.get('href')
    918                 href = os.path.join(os.path.dirname(file_name), href)
    919                 self.parse_file(href)
    920 
    921         return
    922 
    923 
    924     def process_category(self, cat):
    925         cat_name = cat.get( "name" )
    926         cat_number = cat.get( "number" )
    927 
    928         [cat_type, key] = classify_category(cat_name, cat_number)
    929         self.categories[cat_type][key] = [cat_name, cat_number]
    930 
    931         for child in cat.getchildren():
    932             if child.tag == "function":
    933                 func_name = real_function_name( child )
    934 
    935                 temp_name = child.get( "name" )
    936                 self.category_dict[ temp_name ] = [cat_name, cat_number]
    937 
    938                 if self.functions_by_name.has_key( func_name ):
    939                     func = self.functions_by_name[ func_name ]
    940                     func.process_element( child )
    941                 else:
    942                     func = self.factory.create_function( child, self )
    943                     self.functions_by_name[ func_name ] = func
    944 
    945                 if func.offset >= self.next_offset:
    946                     self.next_offset = func.offset + 1
    947 
    948 
    949             elif child.tag == "enum":
    950                 enum = self.factory.create_enum( child, self, cat_name )
    951                 self.enums_by_name[ enum.name ] = enum
    952             elif child.tag == "type":
    953                 t = self.factory.create_type( child, self, cat_name )
    954                 self.types_by_name[ "GL" + t.name ] = t
    955 
    956         return
    957 
    958 
    959     def functionIterateByCategory(self, cat = None):
    960         """Iterate over functions by category.
    961 
    962         If cat is None, all known functions are iterated in category
    963         order.  See classify_category for details of the ordering.
    964         Within a category, functions are sorted by name.  If cat is
    965         not None, then only functions in that category are iterated.
    966         """
    967         lists = [{}, {}, {}, {}]
    968 
    969         for func in self.functionIterateAll():
    970             [cat_name, cat_number] = self.category_dict[func.name]
    971 
    972             if (cat == None) or (cat == cat_name):
    973                 [func_cat_type, key] = classify_category(cat_name, cat_number)
    974 
    975                 if not lists[func_cat_type].has_key(key):
    976                     lists[func_cat_type][key] = {}
    977 
    978                 lists[func_cat_type][key][func.name] = func
    979 
    980 
    981         functions = []
    982         for func_cat_type in range(0,4):
    983             keys = lists[func_cat_type].keys()
    984             keys.sort()
    985 
    986             for key in keys:
    987                 names = lists[func_cat_type][key].keys()
    988                 names.sort()
    989 
    990                 for name in names:
    991                     functions.append(lists[func_cat_type][key][name])
    992 
    993         return functions.__iter__()
    994 
    995 
    996     def functionIterateByOffset(self):
    997         max_offset = -1
    998         for func in self.functions_by_name.itervalues():
    999             if func.offset > max_offset:
   1000                 max_offset = func.offset
   1001 
   1002 
   1003         temp = [None for i in range(0, max_offset + 1)]
   1004         for func in self.functions_by_name.itervalues():
   1005             if func.offset != -1:
   1006                 temp[ func.offset ] = func
   1007 
   1008 
   1009         list = []
   1010         for i in range(0, max_offset + 1):
   1011             if temp[i]:
   1012                 list.append(temp[i])
   1013 
   1014         return list.__iter__();
   1015 
   1016 
   1017     def functionIterateAll(self):
   1018         return self.functions_by_name.itervalues()
   1019 
   1020 
   1021     def enumIterateByName(self):
   1022         keys = self.enums_by_name.keys()
   1023         keys.sort()
   1024 
   1025         list = []
   1026         for enum in keys:
   1027             list.append( self.enums_by_name[ enum ] )
   1028 
   1029         return list.__iter__()
   1030 
   1031 
   1032     def categoryIterate(self):
   1033         """Iterate over categories.
   1034 
   1035         Iterate over all known categories in the order specified by
   1036         classify_category.  Each iterated value is a tuple of the
   1037         name and number (which may be None) of the category.
   1038         """
   1039 
   1040         list = []
   1041         for cat_type in range(0,4):
   1042             keys = self.categories[cat_type].keys()
   1043             keys.sort()
   1044 
   1045             for key in keys:
   1046                 list.append(self.categories[cat_type][key])
   1047 
   1048         return list.__iter__()
   1049 
   1050 
   1051     def get_category_for_name( self, name ):
   1052         if self.category_dict.has_key(name):
   1053             return self.category_dict[name]
   1054         else:
   1055             return ["<unknown category>", None]
   1056 
   1057 
   1058     def typeIterate(self):
   1059         return self.types_by_name.itervalues()
   1060 
   1061 
   1062     def find_type( self, type_name ):
   1063         if type_name in self.types_by_name:
   1064             return self.types_by_name[ type_name ].type_expr
   1065         else:
   1066             print "Unable to find base type matching \"%s\"." % (type_name)
   1067             return None
   1068