blob: 64422be913d6c783a4ddcbeaa06a4b520a63856b [file] [log] [blame]
Ian Romanick73f59b02004-05-18 18:33:40 +00001#!/usr/bin/python2
2
Ian Romanick5f1f2292005-01-07 02:39:09 +00003# (C) Copyright IBM Corporation 2004, 2005
Ian Romanick73f59b02004-05-18 18:33:40 +00004# 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
28from xml.sax import saxutils
29from xml.sax import make_parser
30from xml.sax.handler import feature_namespaces
31
Brian Paul98fa2bf2004-10-28 21:11:02 +000032import re
Ian Romanick73f59b02004-05-18 18:33:40 +000033
Ian Romanick73b4c1b2005-04-14 23:00:34 +000034def is_attr_true( attrs, name ):
35 """Read a name value from an element's attributes.
36
37 The value read from the attribute list must be either 'true' or
38 'false'. If the value is 'false', zero will be returned. If the
39 value is 'true', non-zero will be returned. An exception will be
40 raised for any other value."""
41
Ian Romanick2510ba62005-04-18 19:16:07 +000042 value = attrs.get((None, name), "false")
Ian Romanick73b4c1b2005-04-14 23:00:34 +000043 if value == "true":
44 return 1
45 elif value == "false":
46 return 0
47 else:
48 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
49
50
Ian Romanick93d2d542005-04-18 19:42:23 +000051def parse_GL_API( handler, file_name ):
52 """Boiler-plate code to create an XML parser and use it.
53
54 Creates an XML parser and uses that parser with the application
55 supplied SAX callback, which should be derived from
56 FilterGLAPISpecBase.
57 """
58 parser = make_parser()
59 parser.setFeature(feature_namespaces, 1)
60 parser.setContentHandler( handler )
61
62 handler.printHeader()
63 parser.parse( file_name )
64
65 handler.printFooter()
66 return
67
68
Ian Romanick73f59b02004-05-18 18:33:40 +000069class glItem:
70 """Generic class on which all other API entity types are based."""
71
Ian Romanick73f59b02004-05-18 18:33:40 +000072 def __init__(self, tag_name, name, context):
73 self.name = name
74 self.category = context.get_category_define()
75 self.context = context
76 self.tag_name = tag_name
77
78 context.append(tag_name, self)
79 return
80
Ian Romanick2510ba62005-04-18 19:16:07 +000081 def startElementNS(self, name, qname, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +000082 """Generic startElement handler.
83
84 The startElement handler is called for all elements except
85 the one that starts the object. For a foo element, the
86 XML "<foo><bar/></foo>" would cause the startElement handler
87 to be called once, but the endElement handler would be called
88 twice."""
Ian Romanick73f59b02004-05-18 18:33:40 +000089 return
90
Ian Romanick2510ba62005-04-18 19:16:07 +000091 def endElementNS(self, name, qname):
Ian Romanick73f59b02004-05-18 18:33:40 +000092 """Generic endElement handler.
93
94 Generic endElement handler. Returns 1 if the tag containing
95 the object is complete. Otherwise 0 is returned. All
96 derived class endElement handlers should call this method. If
97 the name of the ending tag is the same as the tag that
98 started this object, the object is assumed to be complete.
99
100 This fails if a tag can contain another tag with the same
101 name. The XML "<foo><foo/><bar/></foo>" would fail. The
Ian Romanicka9d033c2004-05-19 23:33:08 +0000102 object would end before the bar tag was processed.
103
104 The endElement handler is called for every end element
105 associated with an object, even the element that started the
106 object. See the description of startElement an example."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000107
Ian Romanick2510ba62005-04-18 19:16:07 +0000108 if name == (None, self.tag_name):
Ian Romanick73f59b02004-05-18 18:33:40 +0000109 return 1
110 else:
111 return 0
Ian Romanick73f59b02004-05-18 18:33:40 +0000112
Ian Romanicka9d033c2004-05-19 23:33:08 +0000113 def get_category_define(self):
114 return self.category
115
Ian Romanick73f59b02004-05-18 18:33:40 +0000116
117class glEnum( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000118 """Subclass of glItem for representing GL enumerants.
119
120 This class is not complete, and is not really used yet."""
121
Ian Romanick73f59b02004-05-18 18:33:40 +0000122 def __init__(self, context, name, attrs):
Ian Romanick2510ba62005-04-18 19:16:07 +0000123 self.value = int(attrs.get((None, 'value'), "0x0000"), 0)
Ian Romanick73f59b02004-05-18 18:33:40 +0000124
Ian Romanick2510ba62005-04-18 19:16:07 +0000125 enum_name = "GL_" + attrs.get((None, 'name'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000126 glItem.__init__(self, name, enum_name, context)
127
Ian Romanick2510ba62005-04-18 19:16:07 +0000128 temp = attrs.get((None, 'count'), None)
Ian Romanick80a939c2005-03-17 21:48:37 +0000129 self.default_count = 0
130 if temp == "?":
131 self.default_count = -1
132 elif temp:
Ian Romanick85f0fa32005-01-25 01:20:11 +0000133 try:
134 c = int(temp)
135 except Exception,e:
136 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
137
138 self.default_count = c
139 return
140
Ian Romanick73f59b02004-05-18 18:33:40 +0000141
Ian Romanick5ff2b942005-01-24 21:29:13 +0000142 def process_attributes(self, attrs):
Ian Romanick2510ba62005-04-18 19:16:07 +0000143 name = attrs.get((None, 'name'), None)
Ian Romanick5ff2b942005-01-24 21:29:13 +0000144
Ian Romanick2510ba62005-04-18 19:16:07 +0000145 temp = attrs.get((None, 'count'), None)
Ian Romanick85f0fa32005-01-25 01:20:11 +0000146 if temp == None:
147 c = self.default_count
148 else:
149 try:
150 c = int(temp)
151 except Exception,e:
152 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
Ian Romanick5ff2b942005-01-24 21:29:13 +0000153
Ian Romanick2510ba62005-04-18 19:16:07 +0000154 mode_str = attrs.get((None, 'mode'), "set")
Ian Romanick85f0fa32005-01-25 01:20:11 +0000155 if mode_str == "set":
156 mode = 1
157 elif mode_str == "get":
158 mode = 0
159 else:
160 raise RuntimeError("Invalid mode '%s' for function '%s' in enum '%s'." % (mode_str, self.context.name, self.name))
161
162 return [name, c, mode]
Ian Romanick73f59b02004-05-18 18:33:40 +0000163
164
165class glType( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000166 """Subclass of glItem for representing GL types."""
167
Ian Romanick73f59b02004-05-18 18:33:40 +0000168 def __init__(self, context, name, attrs):
Ian Romanick2510ba62005-04-18 19:16:07 +0000169 self.size = int(attrs.get((None, 'size'), "0"))
170 self.glx_name = attrs.get((None, 'glx_name'), "")
Ian Romanick73f59b02004-05-18 18:33:40 +0000171
Ian Romanick2510ba62005-04-18 19:16:07 +0000172 type_name = "GL" + attrs.get((None, 'name'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000173 glItem.__init__(self, name, type_name, context)
174
175
Ian Romanicka9d033c2004-05-19 23:33:08 +0000176class glParameter( glItem ):
177 """Parameter of a glFunction."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000178 p_type = None
179 p_type_string = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000180 p_count = 0
Ian Romanick73f59b02004-05-18 18:33:40 +0000181 counter = None
182 is_output = 0
183 is_counter = 0
184 is_pointer = 0
185
Ian Romanicka9d033c2004-05-19 23:33:08 +0000186 def __init__(self, context, name, attrs):
Ian Romanick2510ba62005-04-18 19:16:07 +0000187 p_name = attrs.get((None, 'name'), None)
188 self.p_type_string = attrs.get((None, 'type'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000189
Ian Romanick2510ba62005-04-18 19:16:07 +0000190 temp = attrs.get((None, 'variable_param'), None)
Ian Romanick3fec8c22005-02-02 00:54:45 +0000191 if temp:
Ian Romanick067e7882005-04-14 23:03:44 +0000192 self.count_parameter_list = temp.split( ' ' )
Ian Romanickba09c192005-02-01 00:13:04 +0000193 else:
194 self.count_parameter_list = []
195
Ian Romanicka9d033c2004-05-19 23:33:08 +0000196 self.p_type = context.context.find_type(self.p_type_string)
197 if self.p_type == None:
198 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
199
200
201 # The count tag can be either a numeric string or the name of
202 # a variable. If it is the name of a variable, the int(c)
203 # statement will throw an exception, and the except block will
204 # take over.
205
Ian Romanick2510ba62005-04-18 19:16:07 +0000206 c = attrs.get((None, 'count'), "0")
Ian Romanick73f59b02004-05-18 18:33:40 +0000207 try:
208 self.p_count = int(c)
Ian Romanicka9d033c2004-05-19 23:33:08 +0000209 self.counter = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000210 except Exception,e:
211 self.p_count = 0
212 self.counter = c
213
Ian Romanick2510ba62005-04-18 19:16:07 +0000214 self.count_scale = int(attrs.get((None, 'count_scale'), "1"))
215
Ian Romanick73b4c1b2005-04-14 23:00:34 +0000216 self.is_counter = is_attr_true( attrs, 'counter' )
217 self.is_output = is_attr_true( attrs, 'output' )
Ian Romanicka9d033c2004-05-19 23:33:08 +0000218
Ian Romanick73f59b02004-05-18 18:33:40 +0000219
Ian Romanick5f1f2292005-01-07 02:39:09 +0000220 # Pixel data has special parameters.
221
Ian Romanick2510ba62005-04-18 19:16:07 +0000222 self.width = attrs.get((None, 'img_width'), None)
223 self.height = attrs.get((None, 'img_height'), None)
224 self.depth = attrs.get((None, 'img_depth'), None)
225 self.extent = attrs.get((None, 'img_extent'), None)
Ian Romanick5f1f2292005-01-07 02:39:09 +0000226
Ian Romanick2510ba62005-04-18 19:16:07 +0000227 self.img_xoff = attrs.get((None, 'img_xoff'), None)
228 self.img_yoff = attrs.get((None, 'img_yoff'), None)
229 self.img_zoff = attrs.get((None, 'img_zoff'), None)
230 self.img_woff = attrs.get((None, 'img_woff'), None)
Ian Romanick5f1f2292005-01-07 02:39:09 +0000231
Ian Romanick2510ba62005-04-18 19:16:07 +0000232 self.img_format = attrs.get((None, 'img_format'), None)
233 self.img_type = attrs.get((None, 'img_type'), None)
234 self.img_target = attrs.get((None, 'img_target'), None)
Ian Romanick5f1f2292005-01-07 02:39:09 +0000235
Ian Romanick73b4c1b2005-04-14 23:00:34 +0000236 self.img_pad_dimensions = is_attr_true( attrs, 'img_pad_dimensions' )
237 self.img_null_flag = is_attr_true( attrs, 'img_null_flag' )
238 self.img_send_null = is_attr_true( attrs, 'img_send_null' )
Ian Romanick5f1f2292005-01-07 02:39:09 +0000239
Ian Romanick3fec8c22005-02-02 00:54:45 +0000240 if self.p_count > 0 or self.counter or self.count_parameter_list:
Ian Romanick73f59b02004-05-18 18:33:40 +0000241 has_count = 1
242 else:
243 has_count = 0
244
Ian Romanicka9d033c2004-05-19 23:33:08 +0000245
Ian Romanick73f59b02004-05-18 18:33:40 +0000246 # If there is a * anywhere in the parameter's type, then it
247 # is a pointer.
248
Ian Romanicka9d033c2004-05-19 23:33:08 +0000249 if re.compile("[*]").search(self.p_type_string):
Ian Romanick73f59b02004-05-18 18:33:40 +0000250 # We could do some other validation here. For
251 # example, an output parameter should not be const,
252 # but every non-output parameter should.
253
254 self.is_pointer = 1;
255 else:
256 # If a parameter is not a pointer, then there cannot
257 # be an associated count (either fixed size or
258 # variable) and the parameter cannot be an output.
259
260 if has_count or self.is_output:
261 raise RuntimeError("Non-pointer type has count or is output.")
262 self.is_pointer = 0;
263
Ian Romanicka9d033c2004-05-19 23:33:08 +0000264 glItem.__init__(self, name, p_name, context)
265 return
266
267
Ian Romanick73f59b02004-05-18 18:33:40 +0000268 def is_variable_length_array(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000269 """Determine if a parameter is a variable length array.
270
271 A parameter is considered to be a variable length array if
272 its size depends on the value of another parameter that is
273 an enumerant. The params parameter to glTexEnviv is an
274 example of a variable length array parameter. Arrays whose
275 size depends on a count variable, such as the lists parameter
276 to glCallLists, are not variable length arrays in this
277 sense."""
278
Ian Romanick3fec8c22005-02-02 00:54:45 +0000279 return self.count_parameter_list or self.counter or self.width
Ian Romanick73f59b02004-05-18 18:33:40 +0000280
Ian Romanicka9d033c2004-05-19 23:33:08 +0000281
Ian Romanick73f59b02004-05-18 18:33:40 +0000282 def is_array(self):
283 return self.is_pointer
284
Ian Romanicka9d033c2004-05-19 23:33:08 +0000285
Ian Romanick73f59b02004-05-18 18:33:40 +0000286 def count_string(self):
287 """Return a string representing the number of items
288
289 Returns a string representing the number of items in a
290 parameter. For scalar types this will always be "1". For
291 vector types, it will depend on whether or not it is a
292 fixed length vector (like the parameter of glVertex3fv),
293 a counted length (like the vector parameter of
294 glDeleteTextures), or a general variable length vector."""
295
296 if self.is_array():
Ian Romanick3fec8c22005-02-02 00:54:45 +0000297 if self.count_parameter_list:
Ian Romanick73f59b02004-05-18 18:33:40 +0000298 return "compsize"
299 elif self.counter != None:
300 return self.counter
301 else:
302 return str(self.p_count)
303 else:
304 return "1"
305
Ian Romanicka9d033c2004-05-19 23:33:08 +0000306
Ian Romanick73f59b02004-05-18 18:33:40 +0000307 def size(self):
Ian Romanick3fec8c22005-02-02 00:54:45 +0000308 if self.count_parameter_list or self.counter or self.width or self.is_output:
Ian Romanick73f59b02004-05-18 18:33:40 +0000309 return 0
310 elif self.p_count == 0:
311 return self.p_type.size
312 else:
Ian Romanick0bd53732005-03-06 08:55:39 +0000313 return self.p_type.size * self.p_count * self.count_scale
Ian Romanick73f59b02004-05-18 18:33:40 +0000314
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000315 def size_string(self):
316 s = self.size()
317 if s == 0:
318 a_prod = "compsize"
319 b_prod = self.p_type.size
320
Ian Romanickba09c192005-02-01 00:13:04 +0000321 # Handle functions like glCompressedTexImage2D that
322 # have a counted 'void *' parameter.
323
324 if b_prod == 0: b_prod = 1
325
Ian Romanick3fec8c22005-02-02 00:54:45 +0000326 if not self.count_parameter_list and self.counter != None:
Ian Romanick0bd53732005-03-06 08:55:39 +0000327 if self.count_scale > 1:
328 a_prod = '(%s * %u)' % (self.counter, self.count_scale)
329 else:
330 a_prod = self.counter
Ian Romanick3fec8c22005-02-02 00:54:45 +0000331 elif self.count_parameter_list and self.counter == None:
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000332 pass
Ian Romanick3fec8c22005-02-02 00:54:45 +0000333 elif self.count_parameter_list and self.counter != None:
Ian Romanick0bd53732005-03-06 08:55:39 +0000334 if self.count_scale > 1:
335 b_prod = '(%s * %u)' % (self.counter, self.count_scale)
336 else:
337 b_prod = self.counter
Ian Romanick5f1f2292005-01-07 02:39:09 +0000338 elif self.width:
339 return "compsize"
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000340 else:
341 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
342
343 return "(%s * %s)" % (a_prod, b_prod)
344 else:
345 return str(s)
346
Ian Romanicka9d033c2004-05-19 23:33:08 +0000347
Ian Romanick73f59b02004-05-18 18:33:40 +0000348class glParameterIterator:
Ian Romanicka9d033c2004-05-19 23:33:08 +0000349 """Class to iterate over a list of glParameters.
350
Ian Romanick1d270842004-12-21 21:26:36 +0000351 Objects of this class are returned by the parameterIterator method of
352 the glFunction class. They are used to iterate over the list of
Ian Romanicka9d033c2004-05-19 23:33:08 +0000353 parameters to the function."""
354
Ian Romanick73f59b02004-05-18 18:33:40 +0000355 def __init__(self, data):
356 self.data = data
357 self.index = 0
Ian Romanick1d270842004-12-21 21:26:36 +0000358
359 def __iter__(self):
360 return self
361
Ian Romanick73f59b02004-05-18 18:33:40 +0000362 def next(self):
363 if self.index == len( self.data ):
364 raise StopIteration
365 i = self.index
366 self.index += 1
367 return self.data[i]
368
Ian Romanicka9d033c2004-05-19 23:33:08 +0000369
Ian Romanick73f59b02004-05-18 18:33:40 +0000370class glFunction( glItem ):
Ian Romanick73f59b02004-05-18 18:33:40 +0000371 def __init__(self, context, name, attrs):
Ian Romanick2510ba62005-04-18 19:16:07 +0000372 self.fn_alias = attrs.get((None, 'alias'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000373 self.fn_parameters = []
Ian Romanick5f1f2292005-01-07 02:39:09 +0000374 self.image = None
Ian Romanickba09c192005-02-01 00:13:04 +0000375 self.count_parameter_list = []
Ian Romanick3fec8c22005-02-02 00:54:45 +0000376 self.fn_return_type = "void"
Ian Romanick73f59b02004-05-18 18:33:40 +0000377
Ian Romanick2510ba62005-04-18 19:16:07 +0000378 temp = attrs.get((None, 'offset'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000379 if temp == None or temp == "?":
380 self.fn_offset = -1
381 else:
382 self.fn_offset = int(temp)
383
Ian Romanick2510ba62005-04-18 19:16:07 +0000384 fn_name = attrs.get((None, 'name'), None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000385 if self.fn_alias != None:
386 self.real_name = self.fn_alias
387 else:
388 self.real_name = fn_name
389
Ian Romanickce77d372005-03-03 21:21:59 +0000390 self.parameters_by_name = {}
391 self.variable_length_parameters = []
392
Ian Romanick73f59b02004-05-18 18:33:40 +0000393 glItem.__init__(self, name, fn_name, context)
394 return
395
396
Ian Romanick1d270842004-12-21 21:26:36 +0000397 def parameterIterator(self):
Ian Romanick73f59b02004-05-18 18:33:40 +0000398 return glParameterIterator(self.fn_parameters)
399
400
Ian Romanick2510ba62005-04-18 19:16:07 +0000401 def startElementNS(self, name, qname, attrs):
402 [uri, true_name] = name
403 if true_name == "param":
Ian Romanick73f59b02004-05-18 18:33:40 +0000404 try:
Ian Romanick2510ba62005-04-18 19:16:07 +0000405 self.context.factory.create(self, true_name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000406 except RuntimeError:
407 print "Error with parameter '%s' in function '%s'." \
Ian Romanick2510ba62005-04-18 19:16:07 +0000408 % (attrs.get((None, 'name'),'(unknown)'), self.name)
Ian Romanick73f59b02004-05-18 18:33:40 +0000409 raise
Ian Romanick2510ba62005-04-18 19:16:07 +0000410 elif true_name == "return":
411 self.set_return_type(attrs.get((None, 'type'), None))
Ian Romanick73f59b02004-05-18 18:33:40 +0000412
413
Ian Romanick2510ba62005-04-18 19:16:07 +0000414 def endElementNS(self, name, qname):
Ian Romanickce77d372005-03-03 21:21:59 +0000415 """Handle the end of a <function> element.
416
417 At the end of a <function> element, there is some semantic
418 checking that can be done. This prevents some possible
419 exceptions from being thrown elsewhere in the code.
420 """
421
Ian Romanick2510ba62005-04-18 19:16:07 +0000422 [uri, true_name] = name
423 if true_name == "function":
Ian Romanickce77d372005-03-03 21:21:59 +0000424 for p in self.variable_length_parameters:
425 if p.counter:
426 counter = self.parameters_by_name[ p.counter ]
427 if not self.parameters_by_name.has_key( p.counter ):
428 raise RuntimeError("Parameter '%s' of function '%s' has counter '%s', but function has no such parameter." % (p.name, self.name, p.counter))
429 elif not self.parameters_by_name[ p.counter ].is_counter:
430 raise RuntimeError("Parameter '%s' of function '%s' has counter '%s', but '%s' is not marked as a counter." % (p.name, self.name, p.counter, p.counter))
431
432 for n in p.count_parameter_list:
433 if not self.parameters_by_name.has_key( n ):
434 raise RuntimeError("Parameter '%s' of function '%s' has size parameter '%s', but function has no such parameter." % (p.name, self.name, n))
435
436 return 1
437 else:
438 return 0
439
440
Ian Romanicka9d033c2004-05-19 23:33:08 +0000441 def append(self, tag_name, p):
442 if tag_name != "param":
443 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
444
Ian Romanick5f1f2292005-01-07 02:39:09 +0000445 if p.width:
446 self.image = p
447
Ian Romanick73f59b02004-05-18 18:33:40 +0000448 self.fn_parameters.append(p)
Ian Romanickba09c192005-02-01 00:13:04 +0000449 if p.count_parameter_list != []:
450 self.count_parameter_list.extend( p.count_parameter_list )
Ian Romanick73f59b02004-05-18 18:33:40 +0000451
Ian Romanickce77d372005-03-03 21:21:59 +0000452 if p.is_variable_length_array():
453 self.variable_length_parameters.append(p)
454
455 self.parameters_by_name[ p.name ] = p
456
Ian Romanicka9d033c2004-05-19 23:33:08 +0000457
Ian Romanick73f59b02004-05-18 18:33:40 +0000458 def set_return_type(self, t):
459 self.fn_return_type = t
460
Ian Romanicka9d033c2004-05-19 23:33:08 +0000461
Ian Romanick73f59b02004-05-18 18:33:40 +0000462 def get_parameter_string(self):
463 arg_string = ""
464 comma = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000465 for p in glFunction.parameterIterator(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000466 arg_string = arg_string + comma + p.p_type_string + " " + p.name
Ian Romanick73f59b02004-05-18 18:33:40 +0000467 comma = ", "
468
469 if arg_string == "":
470 arg_string = "void"
471
472 return arg_string
473
474
475class glItemFactory:
476 """Factory to create objects derived from glItem."""
477
478 def create(self, context, name, attrs):
479 if name == "function":
480 return glFunction(context, name, attrs)
481 elif name == "type":
482 return glType(context, name, attrs)
483 elif name == "enum":
484 return glEnum(context, name, attrs)
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000485 elif name == "param":
486 return glParameter(context, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000487 else:
488 return None
489
490
Ian Romanick38e6e092005-01-25 23:53:13 +0000491class glFunctionIterator:
492 """Class to iterate over a list of glFunctions
493
494 Objects of this classare returned by
495 FilterGLAPISpecBase::functionIterator. This default version
496 iterates over the functions in order of dispatch table offset. All
497 of the "true" functions are iterated first, followed by the alias
498 functions."""
499
500 def __init__(self, context):
501 self.context = context
502 self.keys = context.functions.keys()
503 self.keys.sort()
504
505 self.prevk = -1
506 self.direction = 1
507
508 for self.index in range(0, len(self.keys)):
509 if self.keys[ self.index ] >= 0: break
510
511 if self.index == len(self.keys):
512 self.direction = -1
513 self.index -= 1
514
515 self.split = self.index - 1
516 return
517
518
519 def __iter__(self):
520 return self
521
522
523 def next(self):
524 if self.index < 0:
525 raise StopIteration
526
527 k = self.keys[ self.index ]
528
529 #if self.context.functions[k].fn_alias == None:
530 # if k != self.prevk + 1:
531 # print 'Missing offset %d' % (prevk)
532 # self.prevk = int(k)
533
534 self.index += self.direction
535
536 if self.index == len(self.keys):
537 self.index = self.split
538 self.direction = -1
539
540 return self.context.functions[k]
541
542
Ian Romanick73f59b02004-05-18 18:33:40 +0000543class FilterGLAPISpecBase(saxutils.XMLFilterBase):
544 name = "a"
545 license = "The license for this file is unspecified."
Ian Romanick73f59b02004-05-18 18:33:40 +0000546 next_alias = -2
Ian Romanick73f59b02004-05-18 18:33:40 +0000547 current_object = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000548
549 def __init__(self):
550 saxutils.XMLFilterBase.__init__(self)
551 self.functions = {}
552 self.types = {}
Ian Romanick6af6a692005-03-17 20:56:13 +0000553 self.functions_by_name = {}
Ian Romanick73f59b02004-05-18 18:33:40 +0000554 self.factory = glItemFactory()
Ian Romanick16c3c742005-01-28 19:00:54 +0000555 self.header_tag = None
Ian Romanickc2803582005-02-01 00:28:47 +0000556 self.undef_list = []
Ian Romanick6af6a692005-03-17 20:56:13 +0000557 self.current_category = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000558
Ian Romanicka9d033c2004-05-19 23:33:08 +0000559
Ian Romanick73f59b02004-05-18 18:33:40 +0000560 def find_type(self,type_name):
561 for t in self.types:
562 if re.compile(t).search(type_name):
563 return self.types[t]
564 print "Unable to find base type matching \"%s\"." % (type_name)
565 return None
566
Ian Romanicka9d033c2004-05-19 23:33:08 +0000567
Ian Romanick73f59b02004-05-18 18:33:40 +0000568 def find_function(self,function_name):
Ian Romanick6af6a692005-03-17 20:56:13 +0000569 return self.functions_by_name[function_name]
Ian Romanick73f59b02004-05-18 18:33:40 +0000570
Ian Romanicka9d033c2004-05-19 23:33:08 +0000571
Ian Romanick38e6e092005-01-25 23:53:13 +0000572 def functionIterator(self):
573 return glFunctionIterator(self)
574
575
Ian Romanick73f59b02004-05-18 18:33:40 +0000576 def printFunctions(self):
Ian Romanick38e6e092005-01-25 23:53:13 +0000577 for f in self.functionIterator():
578 self.printFunction(f)
Ian Romanick73f59b02004-05-18 18:33:40 +0000579 return
580
Ian Romanicka9d033c2004-05-19 23:33:08 +0000581
Ian Romanick73f59b02004-05-18 18:33:40 +0000582 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000583 """Print the header associated with all files and call the printRealHeader method."""
584
Ian Romanick73f59b02004-05-18 18:33:40 +0000585 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
586 % (self.name)
587 print ''
588 print '/*'
589 print ' * ' + self.license.replace('\n', '\n * ')
590 print ' */'
591 print ''
Ian Romanick16c3c742005-01-28 19:00:54 +0000592 if self.header_tag:
593 print '#if !defined( %s )' % (self.header_tag)
594 print '# define %s' % (self.header_tag)
595 print ''
Ian Romanick73f59b02004-05-18 18:33:40 +0000596 self.printRealHeader();
597 return
598
Ian Romanicka9d033c2004-05-19 23:33:08 +0000599
Ian Romanick73f59b02004-05-18 18:33:40 +0000600 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000601 """Print the header associated with all files and call the printRealFooter method."""
602
Ian Romanick73f59b02004-05-18 18:33:40 +0000603 self.printFunctions()
604 self.printRealFooter()
Ian Romanick16c3c742005-01-28 19:00:54 +0000605 if self.header_tag:
Ian Romanickc2803582005-02-01 00:28:47 +0000606 if self.undef_list:
607 print ''
608 for u in self.undef_list:
609 print "# undef %s" % (u)
610 print ''
611 print '#endif /* !defined( %s ) */' % (self.header_tag)
Ian Romanick73f59b02004-05-18 18:33:40 +0000612
613
614 def get_category_define(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000615 """Convert the category name to the #define that would be found in glext.h"""
616
Ian Romanick73f59b02004-05-18 18:33:40 +0000617 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
618 s = self.current_category
619 return "GL_VERSION_" + s.replace(".", "_")
620 else:
621 return self.current_category
622
623
624 def append(self, object_type, obj):
625 if object_type == "function":
626 # If the function is not an alias and has a negative
627 # offset, then we do not need to track it. These are
628 # functions that don't have an assigned offset
629
Ian Romanick2510ba62005-04-18 19:16:07 +0000630 if not self.functions_by_name.has_key(obj.name):
631 self.functions_by_name[obj.name] = obj
Ian Romanick73f59b02004-05-18 18:33:40 +0000632
Ian Romanick2510ba62005-04-18 19:16:07 +0000633 if obj.fn_offset >= 0 or obj.fn_alias != None:
634 if obj.fn_offset >= 0:
635 index = obj.fn_offset
636 else:
637 index = self.next_alias
638 self.next_alias -= 1
Ian Romanick6af6a692005-03-17 20:56:13 +0000639
Ian Romanick2510ba62005-04-18 19:16:07 +0000640 self.functions[index] = obj
641 else:
642 # We should do some checking here to make
643 # sure the functions are an identical match.
644 pass
Ian Romanick6af6a692005-03-17 20:56:13 +0000645
Ian Romanick73f59b02004-05-18 18:33:40 +0000646 elif object_type == "type":
647 self.types[obj.name] = obj
648
649 return
650
651
Ian Romanick2510ba62005-04-18 19:16:07 +0000652 def startElementNS(self, name, qname, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000653 """Start a new element in the XML stream.
654
655 Starts a new element. There are three types of elements that
656 are specially handled by this function. When a "category"
657 element is encountered, the name of the category is saved.
658 If an element is encountered and no API object is
659 in-progress, a new object is created using the API factory.
660 Any future elements, until that API object is closed, are
661 passed to the current objects startElement method.
662
663 This paradigm was chosen becuase it allows subclasses of the
664 basic API types (i.e., glFunction, glEnum, etc.) to handle
665 additional XML data, GLX protocol information, that the base
666 classes do not know about."""
667
Ian Romanick2510ba62005-04-18 19:16:07 +0000668 [uri, true_name] = name
669 if uri is None:
670 if self.current_object != None:
671 self.current_object.startElementNS(name, qname, attrs)
672 elif true_name == "category":
673 self.current_category = attrs.get((None, 'name'), "")
674 elif true_name == "include":
675 self.next_include = attrs.get((None, 'name'), "")
676 else:
677 self.current_object = self.factory.create(self, true_name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000678 return
679
Ian Romanicka9d033c2004-05-19 23:33:08 +0000680
Ian Romanick2510ba62005-04-18 19:16:07 +0000681 def endElementNS(self, name, qname):
Ian Romanick73f59b02004-05-18 18:33:40 +0000682 if self.current_object != None:
Ian Romanick2510ba62005-04-18 19:16:07 +0000683 if self.current_object.endElementNS(name, qname):
Ian Romanick73f59b02004-05-18 18:33:40 +0000684 self.current_object = None
Ian Romanick6cfd4f72005-02-08 02:11:14 +0000685 elif name == "include":
686 parser = make_parser()
Ian Romanick2510ba62005-04-18 19:16:07 +0000687 parser.setFeature(feature_namespaces, 1)
Ian Romanick6cfd4f72005-02-08 02:11:14 +0000688 parser.setContentHandler(self)
689
690 f = open(self.next_include)
691 parser.parse(f)
692
Ian Romanick73f59b02004-05-18 18:33:40 +0000693 return
694
Ian Romanicka9d033c2004-05-19 23:33:08 +0000695
Ian Romanickc2803582005-02-01 00:28:47 +0000696 def printPure(self):
697 self.undef_list.append("PURE")
698 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
699# define PURE __attribute__((pure))
700# else
701# define PURE
702# endif"""
703
704 def printFastcall(self):
705 self.undef_list.append("FASTCALL")
706 print """# if defined(__i386__) && defined(__GNUC__)
707# define FASTCALL __attribute__((fastcall))
708# else
709# define FASTCALL
710# endif"""
711
712 def printVisibility(self, S, s):
713 self.undef_list.append(S)
714 print """# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
715# define %s __attribute__((visibility("%s")))
716# else
717# define %s
718# endif""" % (S, s, S)
719
720 def printNoinline(self):
721 self.undef_list.append("NOINLINE")
722 print """# if defined(__GNUC__)
723# define NOINLINE __attribute__((noinline))
724# else
725# define NOINLINE
726# endif"""
727
728 def printHaveAlias(self):
729 self.undef_list.append("HAVE_ALIAS")
730 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
731# define HAVE_ALIAS
732# endif"""
733
Ian Romanick73f59b02004-05-18 18:33:40 +0000734 def printFunction(self,offset):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000735 """Print a single function.
736
737 In the base class, this function is empty. All derived
738 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000739 return
740
Ian Romanicka9d033c2004-05-19 23:33:08 +0000741
Ian Romanick73f59b02004-05-18 18:33:40 +0000742 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000743 """Print the "real" header for the created file.
744
745 In the base class, this function is empty. All derived
746 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000747 return
748
Ian Romanicka9d033c2004-05-19 23:33:08 +0000749
Ian Romanick73f59b02004-05-18 18:33:40 +0000750 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000751 """Print the "real" footer for the created file.
752
753 In the base class, this function is empty. All derived
754 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000755 return