gl_XML.py revision 3464ebd5
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.name = "GL" + self.name
344		te.set_base_type_node( tn )
345
346		self.type_expr = te
347		return
348
349
350	def get_type_expression(self):
351		return self.type_expr
352
353
354class gl_enum( gl_item ):
355	def __init__(self, element, context):
356		gl_item.__init__(self, element, context)
357		self.value = int( element.nsProp( "value", None ), 0 )
358
359		temp = element.nsProp( "count", None )
360		if not temp or temp == "?":
361			self.default_count = -1
362		else:
363			try:
364				c = int(temp)
365			except Exception,e:
366				raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
367
368			self.default_count = c
369
370		return
371
372
373	def priority(self):
374		"""Calculate a 'priority' for this enum name.
375
376		When an enum is looked up by number, there may be many
377		possible names, but only one is the 'prefered' name.  The
378		priority is used to select which name is the 'best'.
379
380		Highest precedence is given to core GL name.  ARB extension
381		names have the next highest, followed by EXT extension names.
382		Vendor extension names are the lowest.
383		"""
384
385		if self.name.endswith( "_BIT" ):
386			bias = 1
387		else:
388			bias = 0
389
390		if self.category.startswith( "GL_VERSION_" ):
391			priority = 0
392		elif self.category.startswith( "GL_ARB_" ):
393			priority = 2
394		elif self.category.startswith( "GL_EXT_" ):
395			priority = 4
396		else:
397			priority = 6
398
399		return priority + bias
400
401
402
403class gl_parameter:
404	def __init__(self, element, context):
405		self.name = element.nsProp( "name", None )
406
407		ts = element.nsProp( "type", None )
408		self.type_expr = typeexpr.type_expression( ts, context )
409
410		temp = element.nsProp( "variable_param", None )
411		if temp:
412			self.count_parameter_list = temp.split( ' ' )
413		else:
414			self.count_parameter_list = []
415
416		# The count tag can be either a numeric string or the name of
417		# a variable.  If it is the name of a variable, the int(c)
418		# statement will throw an exception, and the except block will
419		# take over.
420
421		c = element.nsProp( "count", None )
422		try:
423			count = int(c)
424			self.count = count
425			self.counter = None
426		except Exception,e:
427			count = 1
428			self.count = 0
429			self.counter = c
430
431		self.count_scale = int(element.nsProp( "count_scale", None ))
432
433		elements = (count * self.count_scale)
434		if elements == 1:
435			elements = 0
436
437		#if ts == "GLdouble":
438		#	print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
439		#	print '/* # elements = %u */' % (elements)
440		self.type_expr.set_elements( elements )
441		#if ts == "GLdouble":
442		#	print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
443
444		self.is_client_only = is_attr_true( element, 'client_only' )
445		self.is_counter     = is_attr_true( element, 'counter' )
446		self.is_output      = is_attr_true( element, 'output' )
447
448
449		# Pixel data has special parameters.
450
451		self.width      = element.nsProp('img_width',  None)
452		self.height     = element.nsProp('img_height', None)
453		self.depth      = element.nsProp('img_depth',  None)
454		self.extent     = element.nsProp('img_extent', None)
455
456		self.img_xoff   = element.nsProp('img_xoff',   None)
457		self.img_yoff   = element.nsProp('img_yoff',   None)
458		self.img_zoff   = element.nsProp('img_zoff',   None)
459		self.img_woff   = element.nsProp('img_woff',   None)
460
461		self.img_format = element.nsProp('img_format', None)
462		self.img_type   = element.nsProp('img_type',   None)
463		self.img_target = element.nsProp('img_target', None)
464
465		self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
466		self.img_null_flag      = is_attr_true( element, 'img_null_flag' )
467		self.img_send_null      = is_attr_true( element, 'img_send_null' )
468
469		self.is_padding = is_attr_true( element, 'padding' )
470		return
471
472
473	def compatible(self, other):
474		return 1
475
476
477	def is_array(self):
478		return self.is_pointer()
479
480
481	def is_pointer(self):
482		return self.type_expr.is_pointer()
483
484
485	def is_image(self):
486		if self.width:
487			return 1
488		else:
489			return 0
490
491
492	def is_variable_length(self):
493		return len(self.count_parameter_list) or self.counter
494
495
496	def is_64_bit(self):
497		count = self.type_expr.get_element_count()
498		if count:
499			if (self.size() / count) == 8:
500				return 1
501		else:
502			if self.size() == 8:
503				return 1
504
505		return 0
506
507
508	def string(self):
509		return self.type_expr.original_string + " " + self.name
510
511
512	def type_string(self):
513		return self.type_expr.original_string
514
515
516	def get_base_type_string(self):
517		return self.type_expr.get_base_name()
518
519
520	def get_dimensions(self):
521		if not self.width:
522			return [ 0, "0", "0", "0", "0" ]
523
524		dim = 1
525		w = self.width
526		h = "1"
527		d = "1"
528		e = "1"
529
530		if self.height:
531			dim = 2
532			h = self.height
533
534		if self.depth:
535			dim = 3
536			d = self.depth
537
538		if self.extent:
539			dim = 4
540			e = self.extent
541
542		return [ dim, w, h, d, e ]
543
544
545	def get_stack_size(self):
546		return self.type_expr.get_stack_size()
547
548
549	def size(self):
550		if self.is_image():
551			return 0
552		else:
553			return self.type_expr.get_element_size()
554
555
556	def get_element_count(self):
557		c = self.type_expr.get_element_count()
558		if c == 0:
559			return 1
560
561		return c
562
563
564	def size_string(self, use_parens = 1):
565		s = self.size()
566		if self.counter or self.count_parameter_list:
567			list = [ "compsize" ]
568
569			if self.counter and self.count_parameter_list:
570				list.append( self.counter )
571			elif self.counter:
572				list = [ self.counter ]
573
574			if s > 1:
575				list.append( str(s) )
576
577			if len(list) > 1 and use_parens :
578				return "(%s)" % (string.join(list, " * "))
579			else:
580				return string.join(list, " * ")
581
582		elif self.is_image():
583			return "compsize"
584		else:
585			return str(s)
586
587
588	def format_string(self):
589		if self.type_expr.original_string == "GLenum":
590			return "0x%x"
591		else:
592			return self.type_expr.format_string()
593
594
595
596class 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
608		self.assign_offset = 0
609
610		self.static_entry_points = []
611
612		# Track the parameter string (for the function prototype)
613		# for each entry-point.  This is done because some functions
614		# change their prototype slightly when promoted from extension
615		# to ARB extension to core.  glTexImage3DEXT and glTexImage3D
616		# are good examples of this.  Scripts that need to generate
617		# code for these differing aliases need to real prototype
618		# for each entry-point.  Otherwise, they may generate code
619		# that won't compile.
620
621		self.parameter_strings = {}
622
623		self.process_element( element )
624
625		return
626
627
628	def process_element(self, element):
629		name = element.nsProp( "name", None )
630		alias = element.nsProp( "alias", None )
631
632		if is_attr_true(element, "static_dispatch"):
633			self.static_entry_points.append(name)
634
635		self.entry_points.append( name )
636		if alias:
637			true_name = alias
638		else:
639			true_name = name
640
641			# Only try to set the offset when a non-alias
642			# entry-point is being processes.
643
644			offset = element.nsProp( "offset", None )
645			if offset:
646				try:
647					o = int( offset )
648					self.offset = o
649				except Exception, e:
650					self.offset = -1
651					if offset == "assign":
652						self.assign_offset = 1
653
654
655		if not self.name:
656			self.name = true_name
657		elif self.name != true_name:
658			raise RuntimeError("Function true name redefined.  Was %s, now %s." % (self.name, true_name))
659
660
661		# There are two possible cases.  The first time an entry-point
662		# with data is seen, self.initialized will be 0.  On that
663		# pass, we just fill in the data.  The next time an
664		# entry-point with data is seen, self.initialized will be 1.
665		# On that pass we have to make that the new values match the
666		# valuse from the previous entry-point.
667
668		parameters = []
669		return_type = "void"
670		child = element.children
671		while child:
672			if child.type == "element":
673				if child.name == "return":
674					return_type = child.nsProp( "type", None )
675				elif child.name == "param":
676					param = self.context.factory.create_item( "parameter", child, self.context)
677					parameters.append( param )
678
679			child = child.next
680
681
682		if self.initialized:
683			if self.return_type != return_type:
684				raise RuntimeError( "Return type changed in %s.  Was %s, now %s." % (name, self.return_type, return_type))
685
686			if len(parameters) != len(self.parameters):
687				raise RuntimeError( "Parameter count mismatch in %s.  Was %d, now %d." % (name, len(self.parameters), len(parameters)))
688
689			for j in range(0, len(parameters)):
690				p1 = parameters[j]
691				p2 = self.parameters[j]
692				if not p1.compatible( p2 ):
693					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))
694
695
696		if true_name == name or not self.initialized:
697			self.return_type = return_type
698			self.parameters = parameters
699
700			for param in self.parameters:
701				if param.is_image():
702					self.images.append( param )
703
704		if element.children:
705			self.initialized = 1
706			self.parameter_strings[name] = create_parameter_string(parameters, 1)
707		else:
708			self.parameter_strings[name] = None
709
710		return
711
712
713	def get_images(self):
714		"""Return potentially empty list of input images."""
715		return self.images
716
717
718	def parameterIterator(self):
719		return self.parameters.__iter__();
720
721
722	def get_parameter_string(self, entrypoint = None):
723		if entrypoint:
724			s = self.parameter_strings[ entrypoint ]
725			if s:
726				return s
727
728		return create_parameter_string( self.parameters, 1 )
729
730	def get_called_parameter_string(self):
731		p_string = ""
732		comma = ""
733
734		for p in self.parameterIterator():
735			p_string = p_string + comma + p.name
736			comma = ", "
737
738		return p_string
739
740
741	def is_abi(self):
742		return (self.offset >= 0 and not self.assign_offset)
743
744	def is_static_entry_point(self, name):
745		return name in self.static_entry_points
746
747	def dispatch_name(self):
748		if self.name in self.static_entry_points:
749			return self.name
750		else:
751			return "_dispatch_stub_%u" % (self.offset)
752
753	def static_name(self, name):
754		if name in self.static_entry_points:
755			return name
756		else:
757			return "_dispatch_stub_%u" % (self.offset)
758
759
760class gl_item_factory:
761	"""Factory to create objects derived from gl_item."""
762
763	def create_item(self, item_name, element, context):
764		if item_name == "function":
765			return gl_function(element, context)
766		if item_name == "type":
767			return gl_type(element, context)
768		elif item_name == "enum":
769			return gl_enum(element, context)
770		elif item_name == "parameter":
771			return gl_parameter(element, context)
772		elif item_name == "api":
773			return gl_api(self)
774		else:
775			return None
776
777
778class gl_api:
779	def __init__(self, factory):
780		self.functions_by_name = {}
781		self.enums_by_name = {}
782		self.types_by_name = {}
783
784		self.category_dict = {}
785		self.categories = [{}, {}, {}, {}]
786
787		self.factory = factory
788
789		self.next_offset = 0
790
791		typeexpr.create_initial_types()
792		return
793
794
795	def process_element(self, doc):
796		element = doc.children
797		while element.type != "element" or element.name != "OpenGLAPI":
798			element = element.next
799
800		if element:
801			self.process_OpenGLAPI(element)
802		return
803
804
805	def process_OpenGLAPI(self, element):
806		child = element.children
807		while child:
808			if child.type == "element":
809				if child.name == "category":
810					self.process_category( child )
811				elif child.name == "OpenGLAPI":
812					self.process_OpenGLAPI( child )
813
814			child = child.next
815
816		return
817
818
819	def process_category(self, cat):
820		cat_name = cat.nsProp( "name", None )
821		cat_number = cat.nsProp( "number", None )
822
823		[cat_type, key] = classify_category(cat_name, cat_number)
824		self.categories[cat_type][key] = [cat_name, cat_number]
825
826		child = cat.children
827		while child:
828			if child.type == "element":
829				if child.name == "function":
830					func_name = real_function_name( child )
831
832					temp_name = child.nsProp( "name", None )
833					self.category_dict[ temp_name ] = [cat_name, cat_number]
834
835					if self.functions_by_name.has_key( func_name ):
836						func = self.functions_by_name[ func_name ]
837						func.process_element( child )
838					else:
839						func = self.factory.create_item( "function", child, self )
840						self.functions_by_name[ func_name ] = func
841
842					if func.offset >= self.next_offset:
843						self.next_offset = func.offset + 1
844
845
846				elif child.name == "enum":
847					enum = self.factory.create_item( "enum", child, self )
848					self.enums_by_name[ enum.name ] = enum
849				elif child.name == "type":
850					t = self.factory.create_item( "type", child, self )
851					self.types_by_name[ "GL" + t.name ] = t
852
853
854			child = child.next
855
856		return
857
858
859	def functionIterateByCategory(self, cat = None):
860		"""Iterate over functions by category.
861
862		If cat is None, all known functions are iterated in category
863		order.  See classify_category for details of the ordering.
864		Within a category, functions are sorted by name.  If cat is
865		not None, then only functions in that category are iterated.
866		"""
867		lists = [{}, {}, {}, {}]
868
869		for func in self.functionIterateAll():
870			[cat_name, cat_number] = self.category_dict[func.name]
871
872			if (cat == None) or (cat == cat_name):
873				[func_cat_type, key] = classify_category(cat_name, cat_number)
874
875				if not lists[func_cat_type].has_key(key):
876					lists[func_cat_type][key] = {}
877
878				lists[func_cat_type][key][func.name] = func
879
880
881		functions = []
882		for func_cat_type in range(0,4):
883			keys = lists[func_cat_type].keys()
884			keys.sort()
885
886			for key in keys:
887				names = lists[func_cat_type][key].keys()
888				names.sort()
889
890				for name in names:
891					functions.append(lists[func_cat_type][key][name])
892
893		return functions.__iter__()
894
895
896	def functionIterateByOffset(self):
897		max_offset = -1
898		for func in self.functions_by_name.itervalues():
899			if func.offset > max_offset:
900				max_offset = func.offset
901
902
903		temp = [None for i in range(0, max_offset + 1)]
904		for func in self.functions_by_name.itervalues():
905			if func.offset != -1:
906				temp[ func.offset ] = func
907
908
909		list = []
910		for i in range(0, max_offset + 1):
911			if temp[i]:
912				list.append(temp[i])
913
914		return list.__iter__();
915
916
917	def functionIterateAll(self):
918		return self.functions_by_name.itervalues()
919
920
921	def enumIterateByName(self):
922		keys = self.enums_by_name.keys()
923		keys.sort()
924
925		list = []
926		for enum in keys:
927			list.append( self.enums_by_name[ enum ] )
928
929		return list.__iter__()
930
931
932	def categoryIterate(self):
933		"""Iterate over categories.
934
935		Iterate over all known categories in the order specified by
936		classify_category.  Each iterated value is a tuple of the
937		name and number (which may be None) of the category.
938		"""
939
940		list = []
941		for cat_type in range(0,4):
942			keys = self.categories[cat_type].keys()
943			keys.sort()
944
945			for key in keys:
946				list.append(self.categories[cat_type][key])
947
948		return list.__iter__()
949
950
951	def get_category_for_name( self, name ):
952		if self.category_dict.has_key(name):
953			return self.category_dict[name]
954		else:
955			return ["<unknown category>", None]
956
957
958	def typeIterate(self):
959		return self.types_by_name.itervalues()
960
961
962	def find_type( self, type_name ):
963		if type_name in self.types_by_name:
964			return self.types_by_name[ type_name ].type_expr
965		else:
966			print "Unable to find base type matching \"%s\"." % (type_name)
967			return None
968