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 import libxml2
     29 import re, sys, string
     30 import typeexpr
     31 
     32 
     33 def 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 
     58 def 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 
     75 class 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 
    255 def 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 
    265 def 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 
    272 def 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 
    307 def 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 
    325 class 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 
    333 class 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 
    355 class 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 
    404 class 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 
    597 class 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 
    783 class 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 
    801 class 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