blob: bc7d27befe3d6dd45365d7515d2403d0e1c27931 [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)
Ian Romanick73f59b02004-05-18 18:33:40 +000089
90 enum_name = "GL_" + attrs.get('name', None)
91 glItem.__init__(self, name, enum_name, context)
92
Ian Romanick73f59b02004-05-18 18:33:40 +000093
Ian Romanick5ff2b942005-01-24 21:29:13 +000094 def process_attributes(self, attrs):
95 name = attrs.get('name', None)
96
97 temp = attrs.get('count', None)
98 try:
99 c = int(temp)
100 except Exception,e:
101 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
102
103 return [name, c]
Ian Romanick73f59b02004-05-18 18:33:40 +0000104
105
106class glType( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000107 """Subclass of glItem for representing GL types."""
108
Ian Romanick73f59b02004-05-18 18:33:40 +0000109 def __init__(self, context, name, attrs):
110 self.size = int(attrs.get('size', "0"))
Ian Romanicka285acb2005-01-07 03:22:56 +0000111 self.glx_name = attrs.get('glx_name', "")
Ian Romanick73f59b02004-05-18 18:33:40 +0000112
113 type_name = "GL" + attrs.get('name', None)
114 glItem.__init__(self, name, type_name, context)
115
116
Ian Romanicka9d033c2004-05-19 23:33:08 +0000117class glParameter( glItem ):
118 """Parameter of a glFunction."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000119 p_type = None
120 p_type_string = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000121 p_count = 0
122 p_count_parameters = None
123 counter = None
124 is_output = 0
125 is_counter = 0
126 is_pointer = 0
127
Ian Romanicka9d033c2004-05-19 23:33:08 +0000128 def __init__(self, context, name, attrs):
129 p_name = attrs.get('name', None)
130 self.p_type_string = attrs.get('type', None)
131 self.p_count_parameters = attrs.get('variable_param', None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000132
Ian Romanicka9d033c2004-05-19 23:33:08 +0000133 self.p_type = context.context.find_type(self.p_type_string)
134 if self.p_type == None:
135 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
136
137
138 # The count tag can be either a numeric string or the name of
139 # a variable. If it is the name of a variable, the int(c)
140 # statement will throw an exception, and the except block will
141 # take over.
142
143 c = attrs.get('count', "0")
Ian Romanick73f59b02004-05-18 18:33:40 +0000144 try:
145 self.p_count = int(c)
Ian Romanicka9d033c2004-05-19 23:33:08 +0000146 self.counter = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000147 except Exception,e:
148 self.p_count = 0
149 self.counter = c
150
Ian Romanicka9d033c2004-05-19 23:33:08 +0000151 if attrs.get('counter', "false") == "true":
152 self.is_counter = 1
153 else:
154 self.is_counter = 0
155
156 if attrs.get('output', "false") == "true":
Ian Romanick73f59b02004-05-18 18:33:40 +0000157 self.is_output = 1
158 else:
159 self.is_output = 0
160
Ian Romanick5f1f2292005-01-07 02:39:09 +0000161
162 # Pixel data has special parameters.
163
164 self.width = attrs.get('img_width', None)
165 self.height = attrs.get('img_height', None)
166 self.depth = attrs.get('img_depth', None)
167 self.extent = attrs.get('img_extent', None)
168
169 self.img_xoff = attrs.get('img_xoff', None)
170 self.img_yoff = attrs.get('img_yoff', None)
171 self.img_zoff = attrs.get('img_zoff', None)
172 self.img_woff = attrs.get('img_woff', None)
173
174 self.img_format = attrs.get('img_format', None)
175 self.img_type = attrs.get('img_type', None)
176 self.img_target = attrs.get('img_target', None)
177
178 pad = attrs.get('img_pad_dimensions', "false")
179 if pad == "true":
180 self.img_pad_dimensions = 1
181 else:
182 self.img_pad_dimensions = 0
183
184
185 null_flag = attrs.get('img_null_flag', "false")
186 if null_flag == "true":
187 self.img_null_flag = 1
188 else:
189 self.img_null_flag = 0
190
191 send_null = attrs.get('img_send_null', "false")
192 if send_null == "true":
193 self.img_send_null = 1
194 else:
195 self.img_send_null = 0
196
197
198
199 if self.p_count > 0 or self.counter or self.p_count_parameters:
Ian Romanick73f59b02004-05-18 18:33:40 +0000200 has_count = 1
201 else:
202 has_count = 0
203
Ian Romanicka9d033c2004-05-19 23:33:08 +0000204
Ian Romanick73f59b02004-05-18 18:33:40 +0000205 # If there is a * anywhere in the parameter's type, then it
206 # is a pointer.
207
Ian Romanicka9d033c2004-05-19 23:33:08 +0000208 if re.compile("[*]").search(self.p_type_string):
Ian Romanick73f59b02004-05-18 18:33:40 +0000209 # We could do some other validation here. For
210 # example, an output parameter should not be const,
211 # but every non-output parameter should.
212
213 self.is_pointer = 1;
214 else:
215 # If a parameter is not a pointer, then there cannot
216 # be an associated count (either fixed size or
217 # variable) and the parameter cannot be an output.
218
219 if has_count or self.is_output:
220 raise RuntimeError("Non-pointer type has count or is output.")
221 self.is_pointer = 0;
222
Ian Romanicka9d033c2004-05-19 23:33:08 +0000223 glItem.__init__(self, name, p_name, context)
224 return
225
226
Ian Romanick73f59b02004-05-18 18:33:40 +0000227 def is_variable_length_array(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000228 """Determine if a parameter is a variable length array.
229
230 A parameter is considered to be a variable length array if
231 its size depends on the value of another parameter that is
232 an enumerant. The params parameter to glTexEnviv is an
233 example of a variable length array parameter. Arrays whose
234 size depends on a count variable, such as the lists parameter
235 to glCallLists, are not variable length arrays in this
236 sense."""
237
Ian Romanick5f1f2292005-01-07 02:39:09 +0000238 return self.p_count_parameters or self.counter or self.width
Ian Romanick73f59b02004-05-18 18:33:40 +0000239
Ian Romanicka9d033c2004-05-19 23:33:08 +0000240
Ian Romanick73f59b02004-05-18 18:33:40 +0000241 def is_array(self):
242 return self.is_pointer
243
Ian Romanicka9d033c2004-05-19 23:33:08 +0000244
Ian Romanick73f59b02004-05-18 18:33:40 +0000245 def count_string(self):
246 """Return a string representing the number of items
247
248 Returns a string representing the number of items in a
249 parameter. For scalar types this will always be "1". For
250 vector types, it will depend on whether or not it is a
251 fixed length vector (like the parameter of glVertex3fv),
252 a counted length (like the vector parameter of
253 glDeleteTextures), or a general variable length vector."""
254
255 if self.is_array():
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000256 if self.p_count_parameters != None:
Ian Romanick73f59b02004-05-18 18:33:40 +0000257 return "compsize"
258 elif self.counter != None:
259 return self.counter
260 else:
261 return str(self.p_count)
262 else:
263 return "1"
264
Ian Romanicka9d033c2004-05-19 23:33:08 +0000265
Ian Romanick73f59b02004-05-18 18:33:40 +0000266 def size(self):
Ian Romanick5f1f2292005-01-07 02:39:09 +0000267 if self.p_count_parameters or self.counter or self.width or self.is_output:
Ian Romanick73f59b02004-05-18 18:33:40 +0000268 return 0
269 elif self.p_count == 0:
270 return self.p_type.size
271 else:
272 return self.p_type.size * self.p_count
273
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000274 def size_string(self):
275 s = self.size()
276 if s == 0:
277 a_prod = "compsize"
278 b_prod = self.p_type.size
279
280 if self.p_count_parameters == None and self.counter != None:
281 a_prod = self.counter
282 elif self.p_count_parameters != None and self.counter == None:
283 pass
284 elif self.p_count_parameters != None and self.counter != None:
285 b_prod = self.counter
Ian Romanick5f1f2292005-01-07 02:39:09 +0000286 elif self.width:
287 return "compsize"
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000288 else:
289 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
290
291 return "(%s * %s)" % (a_prod, b_prod)
292 else:
293 return str(s)
294
Ian Romanicka9d033c2004-05-19 23:33:08 +0000295
Ian Romanick73f59b02004-05-18 18:33:40 +0000296class glParameterIterator:
Ian Romanicka9d033c2004-05-19 23:33:08 +0000297 """Class to iterate over a list of glParameters.
298
Ian Romanick1d270842004-12-21 21:26:36 +0000299 Objects of this class are returned by the parameterIterator method of
300 the glFunction class. They are used to iterate over the list of
Ian Romanicka9d033c2004-05-19 23:33:08 +0000301 parameters to the function."""
302
Ian Romanick73f59b02004-05-18 18:33:40 +0000303 def __init__(self, data):
304 self.data = data
305 self.index = 0
Ian Romanick1d270842004-12-21 21:26:36 +0000306
307 def __iter__(self):
308 return self
309
Ian Romanick73f59b02004-05-18 18:33:40 +0000310 def next(self):
311 if self.index == len( self.data ):
312 raise StopIteration
313 i = self.index
314 self.index += 1
315 return self.data[i]
316
Ian Romanicka9d033c2004-05-19 23:33:08 +0000317
Ian Romanick73f59b02004-05-18 18:33:40 +0000318class glFunction( glItem ):
319 real_name = ""
320 fn_alias = None
321 fn_offset = -1
322 fn_return_type = "void"
323 fn_parameters = []
324
325 def __init__(self, context, name, attrs):
326 self.fn_alias = attrs.get('alias', None)
327 self.fn_parameters = []
Ian Romanick5f1f2292005-01-07 02:39:09 +0000328 self.image = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000329
330 temp = attrs.get('offset', None)
331 if temp == None or temp == "?":
332 self.fn_offset = -1
333 else:
334 self.fn_offset = int(temp)
335
336 fn_name = attrs.get('name', None)
337 if self.fn_alias != None:
338 self.real_name = self.fn_alias
339 else:
340 self.real_name = fn_name
341
342 glItem.__init__(self, name, fn_name, context)
343 return
344
345
Ian Romanick1d270842004-12-21 21:26:36 +0000346 def parameterIterator(self):
Ian Romanick73f59b02004-05-18 18:33:40 +0000347 return glParameterIterator(self.fn_parameters)
348
349
350 def startElement(self, name, attrs):
351 if name == "param":
Ian Romanick73f59b02004-05-18 18:33:40 +0000352 try:
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000353 self.context.factory.create(self, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000354 except RuntimeError:
355 print "Error with parameter '%s' in function '%s'." \
Ian Romanicka9d033c2004-05-19 23:33:08 +0000356 % (attrs.get('name','(unknown)'), self.name)
Ian Romanick73f59b02004-05-18 18:33:40 +0000357 raise
Ian Romanick73f59b02004-05-18 18:33:40 +0000358 elif name == "return":
359 self.set_return_type(attrs.get('type', None))
360
361
Ian Romanicka9d033c2004-05-19 23:33:08 +0000362 def append(self, tag_name, p):
363 if tag_name != "param":
364 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
365
Ian Romanick5f1f2292005-01-07 02:39:09 +0000366 if p.width:
367 self.image = p
368
Ian Romanick73f59b02004-05-18 18:33:40 +0000369 self.fn_parameters.append(p)
370
Ian Romanicka9d033c2004-05-19 23:33:08 +0000371
Ian Romanick73f59b02004-05-18 18:33:40 +0000372 def set_return_type(self, t):
373 self.fn_return_type = t
374
Ian Romanicka9d033c2004-05-19 23:33:08 +0000375
Ian Romanick73f59b02004-05-18 18:33:40 +0000376 def get_parameter_string(self):
377 arg_string = ""
378 comma = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000379 for p in glFunction.parameterIterator(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000380 arg_string = arg_string + comma + p.p_type_string + " " + p.name
Ian Romanick73f59b02004-05-18 18:33:40 +0000381 comma = ", "
382
383 if arg_string == "":
384 arg_string = "void"
385
386 return arg_string
387
388
389class glItemFactory:
390 """Factory to create objects derived from glItem."""
391
392 def create(self, context, name, attrs):
393 if name == "function":
394 return glFunction(context, name, attrs)
395 elif name == "type":
396 return glType(context, name, attrs)
397 elif name == "enum":
398 return glEnum(context, name, attrs)
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000399 elif name == "param":
400 return glParameter(context, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000401 else:
402 return None
403
404
405class FilterGLAPISpecBase(saxutils.XMLFilterBase):
406 name = "a"
407 license = "The license for this file is unspecified."
408 functions = {}
409 next_alias = -2
410 types = {}
411 xref = {}
412 current_object = None
413 factory = None
414 current_category = ""
415
416 def __init__(self):
417 saxutils.XMLFilterBase.__init__(self)
418 self.functions = {}
419 self.types = {}
420 self.xref = {}
421 self.factory = glItemFactory()
422
Ian Romanicka9d033c2004-05-19 23:33:08 +0000423
Ian Romanick73f59b02004-05-18 18:33:40 +0000424 def find_type(self,type_name):
425 for t in self.types:
426 if re.compile(t).search(type_name):
427 return self.types[t]
428 print "Unable to find base type matching \"%s\"." % (type_name)
429 return None
430
Ian Romanicka9d033c2004-05-19 23:33:08 +0000431
Ian Romanick73f59b02004-05-18 18:33:40 +0000432 def find_function(self,function_name):
433 index = self.xref[function_name]
434 return self.functions[index]
435
Ian Romanicka9d033c2004-05-19 23:33:08 +0000436
Ian Romanick73f59b02004-05-18 18:33:40 +0000437 def printFunctions(self):
438 keys = self.functions.keys()
439 keys.sort()
440 prevk = -1
441 for k in keys:
442 if k < 0: continue
443
444 if self.functions[k].fn_alias == None:
445 if k != prevk + 1:
446 #print 'Missing offset %d' % (prevk)
447 pass
448 prevk = int(k)
449 self.printFunction(self.functions[k])
450
451 keys.reverse()
452 for k in keys:
453 if self.functions[k].fn_alias != None:
454 self.printFunction(self.functions[k])
455
456 return
457
Ian Romanicka9d033c2004-05-19 23:33:08 +0000458
Ian Romanick73f59b02004-05-18 18:33:40 +0000459 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000460 """Print the header associated with all files and call the printRealHeader method."""
461
Ian Romanick73f59b02004-05-18 18:33:40 +0000462 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
463 % (self.name)
464 print ''
465 print '/*'
466 print ' * ' + self.license.replace('\n', '\n * ')
467 print ' */'
468 print ''
469 self.printRealHeader();
470 return
471
Ian Romanicka9d033c2004-05-19 23:33:08 +0000472
Ian Romanick73f59b02004-05-18 18:33:40 +0000473 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000474 """Print the header associated with all files and call the printRealFooter method."""
475
Ian Romanick73f59b02004-05-18 18:33:40 +0000476 self.printFunctions()
477 self.printRealFooter()
478
479
480 def get_category_define(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000481 """Convert the category name to the #define that would be found in glext.h"""
482
Ian Romanick73f59b02004-05-18 18:33:40 +0000483 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
484 s = self.current_category
485 return "GL_VERSION_" + s.replace(".", "_")
486 else:
487 return self.current_category
488
489
490 def append(self, object_type, obj):
491 if object_type == "function":
492 # If the function is not an alias and has a negative
493 # offset, then we do not need to track it. These are
494 # functions that don't have an assigned offset
495
496 if obj.fn_offset >= 0 or obj.fn_alias != None:
497 if obj.fn_offset >= 0:
498 index = obj.fn_offset
499 else:
500 index = self.next_alias
501 self.next_alias -= 1
502
503 self.functions[index] = obj
504 self.xref[obj.name] = index
505 elif object_type == "type":
506 self.types[obj.name] = obj
507
508 return
509
510
511 def startElement(self, name, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000512 """Start a new element in the XML stream.
513
514 Starts a new element. There are three types of elements that
515 are specially handled by this function. When a "category"
516 element is encountered, the name of the category is saved.
517 If an element is encountered and no API object is
518 in-progress, a new object is created using the API factory.
519 Any future elements, until that API object is closed, are
520 passed to the current objects startElement method.
521
522 This paradigm was chosen becuase it allows subclasses of the
523 basic API types (i.e., glFunction, glEnum, etc.) to handle
524 additional XML data, GLX protocol information, that the base
525 classes do not know about."""
526
Ian Romanick73f59b02004-05-18 18:33:40 +0000527 if self.current_object != None:
528 self.current_object.startElement(name, attrs)
529 elif name == "category":
530 self.current_category = attrs.get('name', "")
531 else:
532 self.current_object = self.factory.create(self, name, attrs)
533 return
534
Ian Romanicka9d033c2004-05-19 23:33:08 +0000535
Ian Romanick73f59b02004-05-18 18:33:40 +0000536 def endElement(self, name):
537 if self.current_object != None:
538 if self.current_object.endElement(name):
539 self.current_object = None
540 return
541
Ian Romanicka9d033c2004-05-19 23:33:08 +0000542
Ian Romanick73f59b02004-05-18 18:33:40 +0000543 def printFunction(self,offset):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000544 """Print a single function.
545
546 In the base class, this function is empty. All derived
547 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000548 return
549
Ian Romanicka9d033c2004-05-19 23:33:08 +0000550
Ian Romanick73f59b02004-05-18 18:33:40 +0000551 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000552 """Print the "real" header for the created file.
553
554 In the base class, this function is empty. All derived
555 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000556 return
557
Ian Romanicka9d033c2004-05-19 23:33:08 +0000558
Ian Romanick73f59b02004-05-18 18:33:40 +0000559 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000560 """Print the "real" footer for the created file.
561
562 In the base class, this function is empty. All derived
563 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000564 return