blob: f984d5f87fb68f3e8fb7b81abf3c20c9de1f805d [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
34class glItem:
35 """Generic class on which all other API entity types are based."""
36
Ian Romanick73f59b02004-05-18 18:33:40 +000037 def __init__(self, tag_name, name, context):
38 self.name = name
39 self.category = context.get_category_define()
40 self.context = context
41 self.tag_name = tag_name
42
43 context.append(tag_name, self)
44 return
45
46 def startElement(self, name, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +000047 """Generic startElement handler.
48
49 The startElement handler is called for all elements except
50 the one that starts the object. For a foo element, the
51 XML "<foo><bar/></foo>" would cause the startElement handler
52 to be called once, but the endElement handler would be called
53 twice."""
Ian Romanick73f59b02004-05-18 18:33:40 +000054 return
55
56 def endElement(self, name):
57 """Generic endElement handler.
58
59 Generic endElement handler. Returns 1 if the tag containing
60 the object is complete. Otherwise 0 is returned. All
61 derived class endElement handlers should call this method. If
62 the name of the ending tag is the same as the tag that
63 started this object, the object is assumed to be complete.
64
65 This fails if a tag can contain another tag with the same
66 name. The XML "<foo><foo/><bar/></foo>" would fail. The
Ian Romanicka9d033c2004-05-19 23:33:08 +000067 object would end before the bar tag was processed.
68
69 The endElement handler is called for every end element
70 associated with an object, even the element that started the
71 object. See the description of startElement an example."""
Ian Romanick73f59b02004-05-18 18:33:40 +000072
73 if name == self.tag_name:
74 return 1
75 else:
76 return 0
Ian Romanick73f59b02004-05-18 18:33:40 +000077
Ian Romanicka9d033c2004-05-19 23:33:08 +000078 def get_category_define(self):
79 return self.category
80
Ian Romanick73f59b02004-05-18 18:33:40 +000081
82class glEnum( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +000083 """Subclass of glItem for representing GL enumerants.
84
85 This class is not complete, and is not really used yet."""
86
Ian Romanick73f59b02004-05-18 18:33:40 +000087 def __init__(self, context, name, attrs):
88 self.value = int(attrs.get('value', "0x0000"), 0)
89 self.functions = {}
90
91 enum_name = "GL_" + attrs.get('name', None)
92 glItem.__init__(self, name, enum_name, context)
93
94 def startElement(self, name, attrs):
95 if name == "size":
96 name = attrs.get('name', None)
97 count = int(attrs.get('count', "0"), 0)
98 self.functions[name] = count
99
100 return
101
102
103class glType( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000104 """Subclass of glItem for representing GL types."""
105
Ian Romanick73f59b02004-05-18 18:33:40 +0000106 def __init__(self, context, name, attrs):
107 self.size = int(attrs.get('size', "0"))
108
109 type_name = "GL" + attrs.get('name', None)
110 glItem.__init__(self, name, type_name, context)
111
112
Ian Romanicka9d033c2004-05-19 23:33:08 +0000113class glParameter( glItem ):
114 """Parameter of a glFunction."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000115 p_type = None
116 p_type_string = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000117 p_count = 0
118 p_count_parameters = None
119 counter = None
120 is_output = 0
121 is_counter = 0
122 is_pointer = 0
123
Ian Romanicka9d033c2004-05-19 23:33:08 +0000124 def __init__(self, context, name, attrs):
125 p_name = attrs.get('name', None)
126 self.p_type_string = attrs.get('type', None)
127 self.p_count_parameters = attrs.get('variable_param', None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000128
Ian Romanicka9d033c2004-05-19 23:33:08 +0000129 self.p_type = context.context.find_type(self.p_type_string)
130 if self.p_type == None:
131 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
132
133
134 # The count tag can be either a numeric string or the name of
135 # a variable. If it is the name of a variable, the int(c)
136 # statement will throw an exception, and the except block will
137 # take over.
138
139 c = attrs.get('count', "0")
Ian Romanick73f59b02004-05-18 18:33:40 +0000140 try:
141 self.p_count = int(c)
Ian Romanicka9d033c2004-05-19 23:33:08 +0000142 self.counter = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000143 except Exception,e:
144 self.p_count = 0
145 self.counter = c
146
Ian Romanicka9d033c2004-05-19 23:33:08 +0000147 if attrs.get('counter', "false") == "true":
148 self.is_counter = 1
149 else:
150 self.is_counter = 0
151
152 if attrs.get('output', "false") == "true":
Ian Romanick73f59b02004-05-18 18:33:40 +0000153 self.is_output = 1
154 else:
155 self.is_output = 0
156
Ian Romanick5f1f2292005-01-07 02:39:09 +0000157
158 # Pixel data has special parameters.
159
160 self.width = attrs.get('img_width', None)
161 self.height = attrs.get('img_height', None)
162 self.depth = attrs.get('img_depth', None)
163 self.extent = attrs.get('img_extent', None)
164
165 self.img_xoff = attrs.get('img_xoff', None)
166 self.img_yoff = attrs.get('img_yoff', None)
167 self.img_zoff = attrs.get('img_zoff', None)
168 self.img_woff = attrs.get('img_woff', None)
169
170 self.img_format = attrs.get('img_format', None)
171 self.img_type = attrs.get('img_type', None)
172 self.img_target = attrs.get('img_target', None)
173
174 pad = attrs.get('img_pad_dimensions', "false")
175 if pad == "true":
176 self.img_pad_dimensions = 1
177 else:
178 self.img_pad_dimensions = 0
179
180
181 null_flag = attrs.get('img_null_flag', "false")
182 if null_flag == "true":
183 self.img_null_flag = 1
184 else:
185 self.img_null_flag = 0
186
187 send_null = attrs.get('img_send_null', "false")
188 if send_null == "true":
189 self.img_send_null = 1
190 else:
191 self.img_send_null = 0
192
193
194
195 if self.p_count > 0 or self.counter or self.p_count_parameters:
Ian Romanick73f59b02004-05-18 18:33:40 +0000196 has_count = 1
197 else:
198 has_count = 0
199
Ian Romanicka9d033c2004-05-19 23:33:08 +0000200
Ian Romanick73f59b02004-05-18 18:33:40 +0000201 # If there is a * anywhere in the parameter's type, then it
202 # is a pointer.
203
Ian Romanicka9d033c2004-05-19 23:33:08 +0000204 if re.compile("[*]").search(self.p_type_string):
Ian Romanick73f59b02004-05-18 18:33:40 +0000205 # We could do some other validation here. For
206 # example, an output parameter should not be const,
207 # but every non-output parameter should.
208
209 self.is_pointer = 1;
210 else:
211 # If a parameter is not a pointer, then there cannot
212 # be an associated count (either fixed size or
213 # variable) and the parameter cannot be an output.
214
215 if has_count or self.is_output:
216 raise RuntimeError("Non-pointer type has count or is output.")
217 self.is_pointer = 0;
218
Ian Romanicka9d033c2004-05-19 23:33:08 +0000219 glItem.__init__(self, name, p_name, context)
220 return
221
222
Ian Romanick73f59b02004-05-18 18:33:40 +0000223 def is_variable_length_array(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000224 """Determine if a parameter is a variable length array.
225
226 A parameter is considered to be a variable length array if
227 its size depends on the value of another parameter that is
228 an enumerant. The params parameter to glTexEnviv is an
229 example of a variable length array parameter. Arrays whose
230 size depends on a count variable, such as the lists parameter
231 to glCallLists, are not variable length arrays in this
232 sense."""
233
Ian Romanick5f1f2292005-01-07 02:39:09 +0000234 return self.p_count_parameters or self.counter or self.width
Ian Romanick73f59b02004-05-18 18:33:40 +0000235
Ian Romanicka9d033c2004-05-19 23:33:08 +0000236
Ian Romanick73f59b02004-05-18 18:33:40 +0000237 def is_array(self):
238 return self.is_pointer
239
Ian Romanicka9d033c2004-05-19 23:33:08 +0000240
Ian Romanick73f59b02004-05-18 18:33:40 +0000241 def count_string(self):
242 """Return a string representing the number of items
243
244 Returns a string representing the number of items in a
245 parameter. For scalar types this will always be "1". For
246 vector types, it will depend on whether or not it is a
247 fixed length vector (like the parameter of glVertex3fv),
248 a counted length (like the vector parameter of
249 glDeleteTextures), or a general variable length vector."""
250
251 if self.is_array():
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000252 if self.p_count_parameters != None:
Ian Romanick73f59b02004-05-18 18:33:40 +0000253 return "compsize"
254 elif self.counter != None:
255 return self.counter
256 else:
257 return str(self.p_count)
258 else:
259 return "1"
260
Ian Romanicka9d033c2004-05-19 23:33:08 +0000261
Ian Romanick73f59b02004-05-18 18:33:40 +0000262 def size(self):
Ian Romanick5f1f2292005-01-07 02:39:09 +0000263 if self.p_count_parameters or self.counter or self.width or self.is_output:
Ian Romanick73f59b02004-05-18 18:33:40 +0000264 return 0
265 elif self.p_count == 0:
266 return self.p_type.size
267 else:
268 return self.p_type.size * self.p_count
269
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000270 def size_string(self):
271 s = self.size()
272 if s == 0:
273 a_prod = "compsize"
274 b_prod = self.p_type.size
275
276 if self.p_count_parameters == None and self.counter != None:
277 a_prod = self.counter
278 elif self.p_count_parameters != None and self.counter == None:
279 pass
280 elif self.p_count_parameters != None and self.counter != None:
281 b_prod = self.counter
Ian Romanick5f1f2292005-01-07 02:39:09 +0000282 elif self.width:
283 return "compsize"
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000284 else:
285 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
286
287 return "(%s * %s)" % (a_prod, b_prod)
288 else:
289 return str(s)
290
Ian Romanicka9d033c2004-05-19 23:33:08 +0000291
Ian Romanick73f59b02004-05-18 18:33:40 +0000292class glParameterIterator:
Ian Romanicka9d033c2004-05-19 23:33:08 +0000293 """Class to iterate over a list of glParameters.
294
Ian Romanick1d270842004-12-21 21:26:36 +0000295 Objects of this class are returned by the parameterIterator method of
296 the glFunction class. They are used to iterate over the list of
Ian Romanicka9d033c2004-05-19 23:33:08 +0000297 parameters to the function."""
298
Ian Romanick73f59b02004-05-18 18:33:40 +0000299 def __init__(self, data):
300 self.data = data
301 self.index = 0
Ian Romanick1d270842004-12-21 21:26:36 +0000302
303 def __iter__(self):
304 return self
305
Ian Romanick73f59b02004-05-18 18:33:40 +0000306 def next(self):
307 if self.index == len( self.data ):
308 raise StopIteration
309 i = self.index
310 self.index += 1
311 return self.data[i]
312
Ian Romanicka9d033c2004-05-19 23:33:08 +0000313
Ian Romanick73f59b02004-05-18 18:33:40 +0000314class glFunction( glItem ):
315 real_name = ""
316 fn_alias = None
317 fn_offset = -1
318 fn_return_type = "void"
319 fn_parameters = []
320
321 def __init__(self, context, name, attrs):
322 self.fn_alias = attrs.get('alias', None)
323 self.fn_parameters = []
Ian Romanick5f1f2292005-01-07 02:39:09 +0000324 self.image = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000325
326 temp = attrs.get('offset', None)
327 if temp == None or temp == "?":
328 self.fn_offset = -1
329 else:
330 self.fn_offset = int(temp)
331
332 fn_name = attrs.get('name', None)
333 if self.fn_alias != None:
334 self.real_name = self.fn_alias
335 else:
336 self.real_name = fn_name
337
338 glItem.__init__(self, name, fn_name, context)
339 return
340
341
Ian Romanick1d270842004-12-21 21:26:36 +0000342 def parameterIterator(self):
Ian Romanick73f59b02004-05-18 18:33:40 +0000343 return glParameterIterator(self.fn_parameters)
344
345
346 def startElement(self, name, attrs):
347 if name == "param":
Ian Romanick73f59b02004-05-18 18:33:40 +0000348 try:
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000349 self.context.factory.create(self, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000350 except RuntimeError:
351 print "Error with parameter '%s' in function '%s'." \
Ian Romanicka9d033c2004-05-19 23:33:08 +0000352 % (attrs.get('name','(unknown)'), self.name)
Ian Romanick73f59b02004-05-18 18:33:40 +0000353 raise
Ian Romanick73f59b02004-05-18 18:33:40 +0000354 elif name == "return":
355 self.set_return_type(attrs.get('type', None))
356
357
Ian Romanicka9d033c2004-05-19 23:33:08 +0000358 def append(self, tag_name, p):
359 if tag_name != "param":
360 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
361
Ian Romanick5f1f2292005-01-07 02:39:09 +0000362 if p.width:
363 self.image = p
364
Ian Romanick73f59b02004-05-18 18:33:40 +0000365 self.fn_parameters.append(p)
366
Ian Romanicka9d033c2004-05-19 23:33:08 +0000367
Ian Romanick73f59b02004-05-18 18:33:40 +0000368 def set_return_type(self, t):
369 self.fn_return_type = t
370
Ian Romanicka9d033c2004-05-19 23:33:08 +0000371
Ian Romanick73f59b02004-05-18 18:33:40 +0000372 def get_parameter_string(self):
373 arg_string = ""
374 comma = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000375 for p in glFunction.parameterIterator(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000376 arg_string = arg_string + comma + p.p_type_string + " " + p.name
Ian Romanick73f59b02004-05-18 18:33:40 +0000377 comma = ", "
378
379 if arg_string == "":
380 arg_string = "void"
381
382 return arg_string
383
384
385class glItemFactory:
386 """Factory to create objects derived from glItem."""
387
388 def create(self, context, name, attrs):
389 if name == "function":
390 return glFunction(context, name, attrs)
391 elif name == "type":
392 return glType(context, name, attrs)
393 elif name == "enum":
394 return glEnum(context, name, attrs)
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000395 elif name == "param":
396 return glParameter(context, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000397 else:
398 return None
399
400
401class FilterGLAPISpecBase(saxutils.XMLFilterBase):
402 name = "a"
403 license = "The license for this file is unspecified."
404 functions = {}
405 next_alias = -2
406 types = {}
407 xref = {}
408 current_object = None
409 factory = None
410 current_category = ""
411
412 def __init__(self):
413 saxutils.XMLFilterBase.__init__(self)
414 self.functions = {}
415 self.types = {}
416 self.xref = {}
417 self.factory = glItemFactory()
418
Ian Romanicka9d033c2004-05-19 23:33:08 +0000419
Ian Romanick73f59b02004-05-18 18:33:40 +0000420 def find_type(self,type_name):
421 for t in self.types:
422 if re.compile(t).search(type_name):
423 return self.types[t]
424 print "Unable to find base type matching \"%s\"." % (type_name)
425 return None
426
Ian Romanicka9d033c2004-05-19 23:33:08 +0000427
Ian Romanick73f59b02004-05-18 18:33:40 +0000428 def find_function(self,function_name):
429 index = self.xref[function_name]
430 return self.functions[index]
431
Ian Romanicka9d033c2004-05-19 23:33:08 +0000432
Ian Romanick73f59b02004-05-18 18:33:40 +0000433 def printFunctions(self):
434 keys = self.functions.keys()
435 keys.sort()
436 prevk = -1
437 for k in keys:
438 if k < 0: continue
439
440 if self.functions[k].fn_alias == None:
441 if k != prevk + 1:
442 #print 'Missing offset %d' % (prevk)
443 pass
444 prevk = int(k)
445 self.printFunction(self.functions[k])
446
447 keys.reverse()
448 for k in keys:
449 if self.functions[k].fn_alias != None:
450 self.printFunction(self.functions[k])
451
452 return
453
Ian Romanicka9d033c2004-05-19 23:33:08 +0000454
Ian Romanick73f59b02004-05-18 18:33:40 +0000455 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000456 """Print the header associated with all files and call the printRealHeader method."""
457
Ian Romanick73f59b02004-05-18 18:33:40 +0000458 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
459 % (self.name)
460 print ''
461 print '/*'
462 print ' * ' + self.license.replace('\n', '\n * ')
463 print ' */'
464 print ''
465 self.printRealHeader();
466 return
467
Ian Romanicka9d033c2004-05-19 23:33:08 +0000468
Ian Romanick73f59b02004-05-18 18:33:40 +0000469 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000470 """Print the header associated with all files and call the printRealFooter method."""
471
Ian Romanick73f59b02004-05-18 18:33:40 +0000472 self.printFunctions()
473 self.printRealFooter()
474
475
476 def get_category_define(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000477 """Convert the category name to the #define that would be found in glext.h"""
478
Ian Romanick73f59b02004-05-18 18:33:40 +0000479 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
480 s = self.current_category
481 return "GL_VERSION_" + s.replace(".", "_")
482 else:
483 return self.current_category
484
485
486 def append(self, object_type, obj):
487 if object_type == "function":
488 # If the function is not an alias and has a negative
489 # offset, then we do not need to track it. These are
490 # functions that don't have an assigned offset
491
492 if obj.fn_offset >= 0 or obj.fn_alias != None:
493 if obj.fn_offset >= 0:
494 index = obj.fn_offset
495 else:
496 index = self.next_alias
497 self.next_alias -= 1
498
499 self.functions[index] = obj
500 self.xref[obj.name] = index
501 elif object_type == "type":
502 self.types[obj.name] = obj
503
504 return
505
506
507 def startElement(self, name, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000508 """Start a new element in the XML stream.
509
510 Starts a new element. There are three types of elements that
511 are specially handled by this function. When a "category"
512 element is encountered, the name of the category is saved.
513 If an element is encountered and no API object is
514 in-progress, a new object is created using the API factory.
515 Any future elements, until that API object is closed, are
516 passed to the current objects startElement method.
517
518 This paradigm was chosen becuase it allows subclasses of the
519 basic API types (i.e., glFunction, glEnum, etc.) to handle
520 additional XML data, GLX protocol information, that the base
521 classes do not know about."""
522
Ian Romanick73f59b02004-05-18 18:33:40 +0000523 if self.current_object != None:
524 self.current_object.startElement(name, attrs)
525 elif name == "category":
526 self.current_category = attrs.get('name', "")
527 else:
528 self.current_object = self.factory.create(self, name, attrs)
529 return
530
Ian Romanicka9d033c2004-05-19 23:33:08 +0000531
Ian Romanick73f59b02004-05-18 18:33:40 +0000532 def endElement(self, name):
533 if self.current_object != None:
534 if self.current_object.endElement(name):
535 self.current_object = None
536 return
537
Ian Romanicka9d033c2004-05-19 23:33:08 +0000538
Ian Romanick73f59b02004-05-18 18:33:40 +0000539 def printFunction(self,offset):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000540 """Print a single function.
541
542 In the base class, this function is empty. All derived
543 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000544 return
545
Ian Romanicka9d033c2004-05-19 23:33:08 +0000546
Ian Romanick73f59b02004-05-18 18:33:40 +0000547 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000548 """Print the "real" header for the created file.
549
550 In the base class, this function is empty. All derived
551 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000552 return
553
Ian Romanicka9d033c2004-05-19 23:33:08 +0000554
Ian Romanick73f59b02004-05-18 18:33:40 +0000555 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000556 """Print the "real" footer for the created file.
557
558 In the base class, this function is empty. All derived
559 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000560 return