blob: 538756ea0c2d2d8f1b333feda26bd3e1e9fb16cd [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"))
Ian Romanicka285acb2005-01-07 03:22:56 +0000108 self.glx_name = attrs.get('glx_name', "")
Ian Romanick73f59b02004-05-18 18:33:40 +0000109
110 type_name = "GL" + attrs.get('name', None)
111 glItem.__init__(self, name, type_name, context)
112
113
Ian Romanicka9d033c2004-05-19 23:33:08 +0000114class glParameter( glItem ):
115 """Parameter of a glFunction."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000116 p_type = None
117 p_type_string = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000118 p_count = 0
119 p_count_parameters = None
120 counter = None
121 is_output = 0
122 is_counter = 0
123 is_pointer = 0
124
Ian Romanicka9d033c2004-05-19 23:33:08 +0000125 def __init__(self, context, name, attrs):
126 p_name = attrs.get('name', None)
127 self.p_type_string = attrs.get('type', None)
128 self.p_count_parameters = attrs.get('variable_param', None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000129
Ian Romanicka9d033c2004-05-19 23:33:08 +0000130 self.p_type = context.context.find_type(self.p_type_string)
131 if self.p_type == None:
132 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
133
134
135 # The count tag can be either a numeric string or the name of
136 # a variable. If it is the name of a variable, the int(c)
137 # statement will throw an exception, and the except block will
138 # take over.
139
140 c = attrs.get('count', "0")
Ian Romanick73f59b02004-05-18 18:33:40 +0000141 try:
142 self.p_count = int(c)
Ian Romanicka9d033c2004-05-19 23:33:08 +0000143 self.counter = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000144 except Exception,e:
145 self.p_count = 0
146 self.counter = c
147
Ian Romanicka9d033c2004-05-19 23:33:08 +0000148 if attrs.get('counter', "false") == "true":
149 self.is_counter = 1
150 else:
151 self.is_counter = 0
152
153 if attrs.get('output', "false") == "true":
Ian Romanick73f59b02004-05-18 18:33:40 +0000154 self.is_output = 1
155 else:
156 self.is_output = 0
157
Ian Romanick5f1f2292005-01-07 02:39:09 +0000158
159 # Pixel data has special parameters.
160
161 self.width = attrs.get('img_width', None)
162 self.height = attrs.get('img_height', None)
163 self.depth = attrs.get('img_depth', None)
164 self.extent = attrs.get('img_extent', None)
165
166 self.img_xoff = attrs.get('img_xoff', None)
167 self.img_yoff = attrs.get('img_yoff', None)
168 self.img_zoff = attrs.get('img_zoff', None)
169 self.img_woff = attrs.get('img_woff', None)
170
171 self.img_format = attrs.get('img_format', None)
172 self.img_type = attrs.get('img_type', None)
173 self.img_target = attrs.get('img_target', None)
174
175 pad = attrs.get('img_pad_dimensions', "false")
176 if pad == "true":
177 self.img_pad_dimensions = 1
178 else:
179 self.img_pad_dimensions = 0
180
181
182 null_flag = attrs.get('img_null_flag', "false")
183 if null_flag == "true":
184 self.img_null_flag = 1
185 else:
186 self.img_null_flag = 0
187
188 send_null = attrs.get('img_send_null', "false")
189 if send_null == "true":
190 self.img_send_null = 1
191 else:
192 self.img_send_null = 0
193
194
195
196 if self.p_count > 0 or self.counter or self.p_count_parameters:
Ian Romanick73f59b02004-05-18 18:33:40 +0000197 has_count = 1
198 else:
199 has_count = 0
200
Ian Romanicka9d033c2004-05-19 23:33:08 +0000201
Ian Romanick73f59b02004-05-18 18:33:40 +0000202 # If there is a * anywhere in the parameter's type, then it
203 # is a pointer.
204
Ian Romanicka9d033c2004-05-19 23:33:08 +0000205 if re.compile("[*]").search(self.p_type_string):
Ian Romanick73f59b02004-05-18 18:33:40 +0000206 # We could do some other validation here. For
207 # example, an output parameter should not be const,
208 # but every non-output parameter should.
209
210 self.is_pointer = 1;
211 else:
212 # If a parameter is not a pointer, then there cannot
213 # be an associated count (either fixed size or
214 # variable) and the parameter cannot be an output.
215
216 if has_count or self.is_output:
217 raise RuntimeError("Non-pointer type has count or is output.")
218 self.is_pointer = 0;
219
Ian Romanicka9d033c2004-05-19 23:33:08 +0000220 glItem.__init__(self, name, p_name, context)
221 return
222
223
Ian Romanick73f59b02004-05-18 18:33:40 +0000224 def is_variable_length_array(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000225 """Determine if a parameter is a variable length array.
226
227 A parameter is considered to be a variable length array if
228 its size depends on the value of another parameter that is
229 an enumerant. The params parameter to glTexEnviv is an
230 example of a variable length array parameter. Arrays whose
231 size depends on a count variable, such as the lists parameter
232 to glCallLists, are not variable length arrays in this
233 sense."""
234
Ian Romanick5f1f2292005-01-07 02:39:09 +0000235 return self.p_count_parameters or self.counter or self.width
Ian Romanick73f59b02004-05-18 18:33:40 +0000236
Ian Romanicka9d033c2004-05-19 23:33:08 +0000237
Ian Romanick73f59b02004-05-18 18:33:40 +0000238 def is_array(self):
239 return self.is_pointer
240
Ian Romanicka9d033c2004-05-19 23:33:08 +0000241
Ian Romanick73f59b02004-05-18 18:33:40 +0000242 def count_string(self):
243 """Return a string representing the number of items
244
245 Returns a string representing the number of items in a
246 parameter. For scalar types this will always be "1". For
247 vector types, it will depend on whether or not it is a
248 fixed length vector (like the parameter of glVertex3fv),
249 a counted length (like the vector parameter of
250 glDeleteTextures), or a general variable length vector."""
251
252 if self.is_array():
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000253 if self.p_count_parameters != None:
Ian Romanick73f59b02004-05-18 18:33:40 +0000254 return "compsize"
255 elif self.counter != None:
256 return self.counter
257 else:
258 return str(self.p_count)
259 else:
260 return "1"
261
Ian Romanicka9d033c2004-05-19 23:33:08 +0000262
Ian Romanick73f59b02004-05-18 18:33:40 +0000263 def size(self):
Ian Romanick5f1f2292005-01-07 02:39:09 +0000264 if self.p_count_parameters or self.counter or self.width or self.is_output:
Ian Romanick73f59b02004-05-18 18:33:40 +0000265 return 0
266 elif self.p_count == 0:
267 return self.p_type.size
268 else:
269 return self.p_type.size * self.p_count
270
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000271 def size_string(self):
272 s = self.size()
273 if s == 0:
274 a_prod = "compsize"
275 b_prod = self.p_type.size
276
277 if self.p_count_parameters == None and self.counter != None:
278 a_prod = self.counter
279 elif self.p_count_parameters != None and self.counter == None:
280 pass
281 elif self.p_count_parameters != None and self.counter != None:
282 b_prod = self.counter
Ian Romanick5f1f2292005-01-07 02:39:09 +0000283 elif self.width:
284 return "compsize"
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000285 else:
286 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
287
288 return "(%s * %s)" % (a_prod, b_prod)
289 else:
290 return str(s)
291
Ian Romanicka9d033c2004-05-19 23:33:08 +0000292
Ian Romanick73f59b02004-05-18 18:33:40 +0000293class glParameterIterator:
Ian Romanicka9d033c2004-05-19 23:33:08 +0000294 """Class to iterate over a list of glParameters.
295
Ian Romanick1d270842004-12-21 21:26:36 +0000296 Objects of this class are returned by the parameterIterator method of
297 the glFunction class. They are used to iterate over the list of
Ian Romanicka9d033c2004-05-19 23:33:08 +0000298 parameters to the function."""
299
Ian Romanick73f59b02004-05-18 18:33:40 +0000300 def __init__(self, data):
301 self.data = data
302 self.index = 0
Ian Romanick1d270842004-12-21 21:26:36 +0000303
304 def __iter__(self):
305 return self
306
Ian Romanick73f59b02004-05-18 18:33:40 +0000307 def next(self):
308 if self.index == len( self.data ):
309 raise StopIteration
310 i = self.index
311 self.index += 1
312 return self.data[i]
313
Ian Romanicka9d033c2004-05-19 23:33:08 +0000314
Ian Romanick73f59b02004-05-18 18:33:40 +0000315class glFunction( glItem ):
316 real_name = ""
317 fn_alias = None
318 fn_offset = -1
319 fn_return_type = "void"
320 fn_parameters = []
321
322 def __init__(self, context, name, attrs):
323 self.fn_alias = attrs.get('alias', None)
324 self.fn_parameters = []
Ian Romanick5f1f2292005-01-07 02:39:09 +0000325 self.image = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000326
327 temp = attrs.get('offset', None)
328 if temp == None or temp == "?":
329 self.fn_offset = -1
330 else:
331 self.fn_offset = int(temp)
332
333 fn_name = attrs.get('name', None)
334 if self.fn_alias != None:
335 self.real_name = self.fn_alias
336 else:
337 self.real_name = fn_name
338
339 glItem.__init__(self, name, fn_name, context)
340 return
341
342
Ian Romanick1d270842004-12-21 21:26:36 +0000343 def parameterIterator(self):
Ian Romanick73f59b02004-05-18 18:33:40 +0000344 return glParameterIterator(self.fn_parameters)
345
346
347 def startElement(self, name, attrs):
348 if name == "param":
Ian Romanick73f59b02004-05-18 18:33:40 +0000349 try:
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000350 self.context.factory.create(self, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000351 except RuntimeError:
352 print "Error with parameter '%s' in function '%s'." \
Ian Romanicka9d033c2004-05-19 23:33:08 +0000353 % (attrs.get('name','(unknown)'), self.name)
Ian Romanick73f59b02004-05-18 18:33:40 +0000354 raise
Ian Romanick73f59b02004-05-18 18:33:40 +0000355 elif name == "return":
356 self.set_return_type(attrs.get('type', None))
357
358
Ian Romanicka9d033c2004-05-19 23:33:08 +0000359 def append(self, tag_name, p):
360 if tag_name != "param":
361 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
362
Ian Romanick5f1f2292005-01-07 02:39:09 +0000363 if p.width:
364 self.image = p
365
Ian Romanick73f59b02004-05-18 18:33:40 +0000366 self.fn_parameters.append(p)
367
Ian Romanicka9d033c2004-05-19 23:33:08 +0000368
Ian Romanick73f59b02004-05-18 18:33:40 +0000369 def set_return_type(self, t):
370 self.fn_return_type = t
371
Ian Romanicka9d033c2004-05-19 23:33:08 +0000372
Ian Romanick73f59b02004-05-18 18:33:40 +0000373 def get_parameter_string(self):
374 arg_string = ""
375 comma = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000376 for p in glFunction.parameterIterator(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000377 arg_string = arg_string + comma + p.p_type_string + " " + p.name
Ian Romanick73f59b02004-05-18 18:33:40 +0000378 comma = ", "
379
380 if arg_string == "":
381 arg_string = "void"
382
383 return arg_string
384
385
386class glItemFactory:
387 """Factory to create objects derived from glItem."""
388
389 def create(self, context, name, attrs):
390 if name == "function":
391 return glFunction(context, name, attrs)
392 elif name == "type":
393 return glType(context, name, attrs)
394 elif name == "enum":
395 return glEnum(context, name, attrs)
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000396 elif name == "param":
397 return glParameter(context, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000398 else:
399 return None
400
401
402class FilterGLAPISpecBase(saxutils.XMLFilterBase):
403 name = "a"
404 license = "The license for this file is unspecified."
405 functions = {}
406 next_alias = -2
407 types = {}
408 xref = {}
409 current_object = None
410 factory = None
411 current_category = ""
412
413 def __init__(self):
414 saxutils.XMLFilterBase.__init__(self)
415 self.functions = {}
416 self.types = {}
417 self.xref = {}
418 self.factory = glItemFactory()
419
Ian Romanicka9d033c2004-05-19 23:33:08 +0000420
Ian Romanick73f59b02004-05-18 18:33:40 +0000421 def find_type(self,type_name):
422 for t in self.types:
423 if re.compile(t).search(type_name):
424 return self.types[t]
425 print "Unable to find base type matching \"%s\"." % (type_name)
426 return None
427
Ian Romanicka9d033c2004-05-19 23:33:08 +0000428
Ian Romanick73f59b02004-05-18 18:33:40 +0000429 def find_function(self,function_name):
430 index = self.xref[function_name]
431 return self.functions[index]
432
Ian Romanicka9d033c2004-05-19 23:33:08 +0000433
Ian Romanick73f59b02004-05-18 18:33:40 +0000434 def printFunctions(self):
435 keys = self.functions.keys()
436 keys.sort()
437 prevk = -1
438 for k in keys:
439 if k < 0: continue
440
441 if self.functions[k].fn_alias == None:
442 if k != prevk + 1:
443 #print 'Missing offset %d' % (prevk)
444 pass
445 prevk = int(k)
446 self.printFunction(self.functions[k])
447
448 keys.reverse()
449 for k in keys:
450 if self.functions[k].fn_alias != None:
451 self.printFunction(self.functions[k])
452
453 return
454
Ian Romanicka9d033c2004-05-19 23:33:08 +0000455
Ian Romanick73f59b02004-05-18 18:33:40 +0000456 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000457 """Print the header associated with all files and call the printRealHeader method."""
458
Ian Romanick73f59b02004-05-18 18:33:40 +0000459 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
460 % (self.name)
461 print ''
462 print '/*'
463 print ' * ' + self.license.replace('\n', '\n * ')
464 print ' */'
465 print ''
466 self.printRealHeader();
467 return
468
Ian Romanicka9d033c2004-05-19 23:33:08 +0000469
Ian Romanick73f59b02004-05-18 18:33:40 +0000470 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000471 """Print the header associated with all files and call the printRealFooter method."""
472
Ian Romanick73f59b02004-05-18 18:33:40 +0000473 self.printFunctions()
474 self.printRealFooter()
475
476
477 def get_category_define(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000478 """Convert the category name to the #define that would be found in glext.h"""
479
Ian Romanick73f59b02004-05-18 18:33:40 +0000480 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
481 s = self.current_category
482 return "GL_VERSION_" + s.replace(".", "_")
483 else:
484 return self.current_category
485
486
487 def append(self, object_type, obj):
488 if object_type == "function":
489 # If the function is not an alias and has a negative
490 # offset, then we do not need to track it. These are
491 # functions that don't have an assigned offset
492
493 if obj.fn_offset >= 0 or obj.fn_alias != None:
494 if obj.fn_offset >= 0:
495 index = obj.fn_offset
496 else:
497 index = self.next_alias
498 self.next_alias -= 1
499
500 self.functions[index] = obj
501 self.xref[obj.name] = index
502 elif object_type == "type":
503 self.types[obj.name] = obj
504
505 return
506
507
508 def startElement(self, name, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000509 """Start a new element in the XML stream.
510
511 Starts a new element. There are three types of elements that
512 are specially handled by this function. When a "category"
513 element is encountered, the name of the category is saved.
514 If an element is encountered and no API object is
515 in-progress, a new object is created using the API factory.
516 Any future elements, until that API object is closed, are
517 passed to the current objects startElement method.
518
519 This paradigm was chosen becuase it allows subclasses of the
520 basic API types (i.e., glFunction, glEnum, etc.) to handle
521 additional XML data, GLX protocol information, that the base
522 classes do not know about."""
523
Ian Romanick73f59b02004-05-18 18:33:40 +0000524 if self.current_object != None:
525 self.current_object.startElement(name, attrs)
526 elif name == "category":
527 self.current_category = attrs.get('name', "")
528 else:
529 self.current_object = self.factory.create(self, name, attrs)
530 return
531
Ian Romanicka9d033c2004-05-19 23:33:08 +0000532
Ian Romanick73f59b02004-05-18 18:33:40 +0000533 def endElement(self, name):
534 if self.current_object != None:
535 if self.current_object.endElement(name):
536 self.current_object = None
537 return
538
Ian Romanicka9d033c2004-05-19 23:33:08 +0000539
Ian Romanick73f59b02004-05-18 18:33:40 +0000540 def printFunction(self,offset):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000541 """Print a single function.
542
543 In the base class, this function is empty. All derived
544 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000545 return
546
Ian Romanicka9d033c2004-05-19 23:33:08 +0000547
Ian Romanick73f59b02004-05-18 18:33:40 +0000548 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000549 """Print the "real" header for the created file.
550
551 In the base class, this function is empty. All derived
552 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000553 return
554
Ian Romanicka9d033c2004-05-19 23:33:08 +0000555
Ian Romanick73f59b02004-05-18 18:33:40 +0000556 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000557 """Print the "real" footer for the created file.
558
559 In the base class, this function is empty. All derived
560 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000561 return