blob: 61c9b355cf2fca4eb507803c045fae17508c4fc2 [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 Romanick85f0fa32005-01-25 01:20:11 +000093 temp = attrs.get('count', None)
94 if temp == None:
95 self.default_count = 0
96 else:
97 try:
98 c = int(temp)
99 except Exception,e:
100 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
101
102 self.default_count = c
103 return
104
Ian Romanick73f59b02004-05-18 18:33:40 +0000105
Ian Romanick5ff2b942005-01-24 21:29:13 +0000106 def process_attributes(self, attrs):
107 name = attrs.get('name', None)
108
109 temp = attrs.get('count', None)
Ian Romanick85f0fa32005-01-25 01:20:11 +0000110 if temp == None:
111 c = self.default_count
112 else:
113 try:
114 c = int(temp)
115 except Exception,e:
116 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 +0000117
Ian Romanick85f0fa32005-01-25 01:20:11 +0000118 mode_str = attrs.get('mode', "set")
119 if mode_str == "set":
120 mode = 1
121 elif mode_str == "get":
122 mode = 0
123 else:
124 raise RuntimeError("Invalid mode '%s' for function '%s' in enum '%s'." % (mode_str, self.context.name, self.name))
125
126 return [name, c, mode]
Ian Romanick73f59b02004-05-18 18:33:40 +0000127
128
129class glType( glItem ):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000130 """Subclass of glItem for representing GL types."""
131
Ian Romanick73f59b02004-05-18 18:33:40 +0000132 def __init__(self, context, name, attrs):
133 self.size = int(attrs.get('size', "0"))
Ian Romanicka285acb2005-01-07 03:22:56 +0000134 self.glx_name = attrs.get('glx_name', "")
Ian Romanick73f59b02004-05-18 18:33:40 +0000135
136 type_name = "GL" + attrs.get('name', None)
137 glItem.__init__(self, name, type_name, context)
138
139
Ian Romanicka9d033c2004-05-19 23:33:08 +0000140class glParameter( glItem ):
141 """Parameter of a glFunction."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000142 p_type = None
143 p_type_string = ""
Ian Romanick73f59b02004-05-18 18:33:40 +0000144 p_count = 0
145 p_count_parameters = None
146 counter = None
147 is_output = 0
148 is_counter = 0
149 is_pointer = 0
150
Ian Romanicka9d033c2004-05-19 23:33:08 +0000151 def __init__(self, context, name, attrs):
152 p_name = attrs.get('name', None)
153 self.p_type_string = attrs.get('type', None)
154 self.p_count_parameters = attrs.get('variable_param', None)
Ian Romanick73f59b02004-05-18 18:33:40 +0000155
Ian Romanicka9d033c2004-05-19 23:33:08 +0000156 self.p_type = context.context.find_type(self.p_type_string)
157 if self.p_type == None:
158 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
159
160
161 # The count tag can be either a numeric string or the name of
162 # a variable. If it is the name of a variable, the int(c)
163 # statement will throw an exception, and the except block will
164 # take over.
165
166 c = attrs.get('count', "0")
Ian Romanick73f59b02004-05-18 18:33:40 +0000167 try:
168 self.p_count = int(c)
Ian Romanicka9d033c2004-05-19 23:33:08 +0000169 self.counter = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000170 except Exception,e:
171 self.p_count = 0
172 self.counter = c
173
Ian Romanicka9d033c2004-05-19 23:33:08 +0000174 if attrs.get('counter', "false") == "true":
175 self.is_counter = 1
176 else:
177 self.is_counter = 0
178
179 if attrs.get('output', "false") == "true":
Ian Romanick73f59b02004-05-18 18:33:40 +0000180 self.is_output = 1
181 else:
182 self.is_output = 0
183
Ian Romanick5f1f2292005-01-07 02:39:09 +0000184
185 # Pixel data has special parameters.
186
187 self.width = attrs.get('img_width', None)
188 self.height = attrs.get('img_height', None)
189 self.depth = attrs.get('img_depth', None)
190 self.extent = attrs.get('img_extent', None)
191
192 self.img_xoff = attrs.get('img_xoff', None)
193 self.img_yoff = attrs.get('img_yoff', None)
194 self.img_zoff = attrs.get('img_zoff', None)
195 self.img_woff = attrs.get('img_woff', None)
196
197 self.img_format = attrs.get('img_format', None)
198 self.img_type = attrs.get('img_type', None)
199 self.img_target = attrs.get('img_target', None)
200
201 pad = attrs.get('img_pad_dimensions', "false")
202 if pad == "true":
203 self.img_pad_dimensions = 1
204 else:
205 self.img_pad_dimensions = 0
206
207
208 null_flag = attrs.get('img_null_flag', "false")
209 if null_flag == "true":
210 self.img_null_flag = 1
211 else:
212 self.img_null_flag = 0
213
214 send_null = attrs.get('img_send_null', "false")
215 if send_null == "true":
216 self.img_send_null = 1
217 else:
218 self.img_send_null = 0
219
220
221
222 if self.p_count > 0 or self.counter or self.p_count_parameters:
Ian Romanick73f59b02004-05-18 18:33:40 +0000223 has_count = 1
224 else:
225 has_count = 0
226
Ian Romanicka9d033c2004-05-19 23:33:08 +0000227
Ian Romanick73f59b02004-05-18 18:33:40 +0000228 # If there is a * anywhere in the parameter's type, then it
229 # is a pointer.
230
Ian Romanicka9d033c2004-05-19 23:33:08 +0000231 if re.compile("[*]").search(self.p_type_string):
Ian Romanick73f59b02004-05-18 18:33:40 +0000232 # We could do some other validation here. For
233 # example, an output parameter should not be const,
234 # but every non-output parameter should.
235
236 self.is_pointer = 1;
237 else:
238 # If a parameter is not a pointer, then there cannot
239 # be an associated count (either fixed size or
240 # variable) and the parameter cannot be an output.
241
242 if has_count or self.is_output:
243 raise RuntimeError("Non-pointer type has count or is output.")
244 self.is_pointer = 0;
245
Ian Romanicka9d033c2004-05-19 23:33:08 +0000246 glItem.__init__(self, name, p_name, context)
247 return
248
249
Ian Romanick73f59b02004-05-18 18:33:40 +0000250 def is_variable_length_array(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000251 """Determine if a parameter is a variable length array.
252
253 A parameter is considered to be a variable length array if
254 its size depends on the value of another parameter that is
255 an enumerant. The params parameter to glTexEnviv is an
256 example of a variable length array parameter. Arrays whose
257 size depends on a count variable, such as the lists parameter
258 to glCallLists, are not variable length arrays in this
259 sense."""
260
Ian Romanick5f1f2292005-01-07 02:39:09 +0000261 return self.p_count_parameters or self.counter or self.width
Ian Romanick73f59b02004-05-18 18:33:40 +0000262
Ian Romanicka9d033c2004-05-19 23:33:08 +0000263
Ian Romanick73f59b02004-05-18 18:33:40 +0000264 def is_array(self):
265 return self.is_pointer
266
Ian Romanicka9d033c2004-05-19 23:33:08 +0000267
Ian Romanick73f59b02004-05-18 18:33:40 +0000268 def count_string(self):
269 """Return a string representing the number of items
270
271 Returns a string representing the number of items in a
272 parameter. For scalar types this will always be "1". For
273 vector types, it will depend on whether or not it is a
274 fixed length vector (like the parameter of glVertex3fv),
275 a counted length (like the vector parameter of
276 glDeleteTextures), or a general variable length vector."""
277
278 if self.is_array():
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000279 if self.p_count_parameters != None:
Ian Romanick73f59b02004-05-18 18:33:40 +0000280 return "compsize"
281 elif self.counter != None:
282 return self.counter
283 else:
284 return str(self.p_count)
285 else:
286 return "1"
287
Ian Romanicka9d033c2004-05-19 23:33:08 +0000288
Ian Romanick73f59b02004-05-18 18:33:40 +0000289 def size(self):
Ian Romanick5f1f2292005-01-07 02:39:09 +0000290 if self.p_count_parameters or self.counter or self.width or self.is_output:
Ian Romanick73f59b02004-05-18 18:33:40 +0000291 return 0
292 elif self.p_count == 0:
293 return self.p_type.size
294 else:
295 return self.p_type.size * self.p_count
296
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000297 def size_string(self):
298 s = self.size()
299 if s == 0:
300 a_prod = "compsize"
301 b_prod = self.p_type.size
302
303 if self.p_count_parameters == None and self.counter != None:
304 a_prod = self.counter
305 elif self.p_count_parameters != None and self.counter == None:
306 pass
307 elif self.p_count_parameters != None and self.counter != None:
308 b_prod = self.counter
Ian Romanick5f1f2292005-01-07 02:39:09 +0000309 elif self.width:
310 return "compsize"
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000311 else:
312 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
313
314 return "(%s * %s)" % (a_prod, b_prod)
315 else:
316 return str(s)
317
Ian Romanicka9d033c2004-05-19 23:33:08 +0000318
Ian Romanick73f59b02004-05-18 18:33:40 +0000319class glParameterIterator:
Ian Romanicka9d033c2004-05-19 23:33:08 +0000320 """Class to iterate over a list of glParameters.
321
Ian Romanick1d270842004-12-21 21:26:36 +0000322 Objects of this class are returned by the parameterIterator method of
323 the glFunction class. They are used to iterate over the list of
Ian Romanicka9d033c2004-05-19 23:33:08 +0000324 parameters to the function."""
325
Ian Romanick73f59b02004-05-18 18:33:40 +0000326 def __init__(self, data):
327 self.data = data
328 self.index = 0
Ian Romanick1d270842004-12-21 21:26:36 +0000329
330 def __iter__(self):
331 return self
332
Ian Romanick73f59b02004-05-18 18:33:40 +0000333 def next(self):
334 if self.index == len( self.data ):
335 raise StopIteration
336 i = self.index
337 self.index += 1
338 return self.data[i]
339
Ian Romanicka9d033c2004-05-19 23:33:08 +0000340
Ian Romanick73f59b02004-05-18 18:33:40 +0000341class glFunction( glItem ):
342 real_name = ""
343 fn_alias = None
344 fn_offset = -1
345 fn_return_type = "void"
346 fn_parameters = []
347
348 def __init__(self, context, name, attrs):
349 self.fn_alias = attrs.get('alias', None)
350 self.fn_parameters = []
Ian Romanick5f1f2292005-01-07 02:39:09 +0000351 self.image = None
Ian Romanick73f59b02004-05-18 18:33:40 +0000352
353 temp = attrs.get('offset', None)
354 if temp == None or temp == "?":
355 self.fn_offset = -1
356 else:
357 self.fn_offset = int(temp)
358
359 fn_name = attrs.get('name', None)
360 if self.fn_alias != None:
361 self.real_name = self.fn_alias
362 else:
363 self.real_name = fn_name
364
365 glItem.__init__(self, name, fn_name, context)
366 return
367
368
Ian Romanick1d270842004-12-21 21:26:36 +0000369 def parameterIterator(self):
Ian Romanick73f59b02004-05-18 18:33:40 +0000370 return glParameterIterator(self.fn_parameters)
371
372
373 def startElement(self, name, attrs):
374 if name == "param":
Ian Romanick73f59b02004-05-18 18:33:40 +0000375 try:
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000376 self.context.factory.create(self, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000377 except RuntimeError:
378 print "Error with parameter '%s' in function '%s'." \
Ian Romanicka9d033c2004-05-19 23:33:08 +0000379 % (attrs.get('name','(unknown)'), self.name)
Ian Romanick73f59b02004-05-18 18:33:40 +0000380 raise
Ian Romanick73f59b02004-05-18 18:33:40 +0000381 elif name == "return":
382 self.set_return_type(attrs.get('type', None))
383
384
Ian Romanicka9d033c2004-05-19 23:33:08 +0000385 def append(self, tag_name, p):
386 if tag_name != "param":
387 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
388
Ian Romanick5f1f2292005-01-07 02:39:09 +0000389 if p.width:
390 self.image = p
391
Ian Romanick73f59b02004-05-18 18:33:40 +0000392 self.fn_parameters.append(p)
393
Ian Romanicka9d033c2004-05-19 23:33:08 +0000394
Ian Romanick73f59b02004-05-18 18:33:40 +0000395 def set_return_type(self, t):
396 self.fn_return_type = t
397
Ian Romanicka9d033c2004-05-19 23:33:08 +0000398
Ian Romanick73f59b02004-05-18 18:33:40 +0000399 def get_parameter_string(self):
400 arg_string = ""
401 comma = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000402 for p in glFunction.parameterIterator(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000403 arg_string = arg_string + comma + p.p_type_string + " " + p.name
Ian Romanick73f59b02004-05-18 18:33:40 +0000404 comma = ", "
405
406 if arg_string == "":
407 arg_string = "void"
408
409 return arg_string
410
411
412class glItemFactory:
413 """Factory to create objects derived from glItem."""
414
415 def create(self, context, name, attrs):
416 if name == "function":
417 return glFunction(context, name, attrs)
418 elif name == "type":
419 return glType(context, name, attrs)
420 elif name == "enum":
421 return glEnum(context, name, attrs)
Ian Romanick4f0a75e2004-12-01 00:29:48 +0000422 elif name == "param":
423 return glParameter(context, name, attrs)
Ian Romanick73f59b02004-05-18 18:33:40 +0000424 else:
425 return None
426
427
428class FilterGLAPISpecBase(saxutils.XMLFilterBase):
429 name = "a"
430 license = "The license for this file is unspecified."
431 functions = {}
432 next_alias = -2
433 types = {}
434 xref = {}
435 current_object = None
436 factory = None
437 current_category = ""
438
439 def __init__(self):
440 saxutils.XMLFilterBase.__init__(self)
441 self.functions = {}
442 self.types = {}
443 self.xref = {}
444 self.factory = glItemFactory()
445
Ian Romanicka9d033c2004-05-19 23:33:08 +0000446
Ian Romanick73f59b02004-05-18 18:33:40 +0000447 def find_type(self,type_name):
448 for t in self.types:
449 if re.compile(t).search(type_name):
450 return self.types[t]
451 print "Unable to find base type matching \"%s\"." % (type_name)
452 return None
453
Ian Romanicka9d033c2004-05-19 23:33:08 +0000454
Ian Romanick73f59b02004-05-18 18:33:40 +0000455 def find_function(self,function_name):
456 index = self.xref[function_name]
457 return self.functions[index]
458
Ian Romanicka9d033c2004-05-19 23:33:08 +0000459
Ian Romanick73f59b02004-05-18 18:33:40 +0000460 def printFunctions(self):
461 keys = self.functions.keys()
462 keys.sort()
463 prevk = -1
464 for k in keys:
465 if k < 0: continue
466
467 if self.functions[k].fn_alias == None:
468 if k != prevk + 1:
469 #print 'Missing offset %d' % (prevk)
470 pass
471 prevk = int(k)
472 self.printFunction(self.functions[k])
473
474 keys.reverse()
475 for k in keys:
476 if self.functions[k].fn_alias != None:
477 self.printFunction(self.functions[k])
478
479 return
480
Ian Romanicka9d033c2004-05-19 23:33:08 +0000481
Ian Romanick73f59b02004-05-18 18:33:40 +0000482 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000483 """Print the header associated with all files and call the printRealHeader method."""
484
Ian Romanick73f59b02004-05-18 18:33:40 +0000485 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
486 % (self.name)
487 print ''
488 print '/*'
489 print ' * ' + self.license.replace('\n', '\n * ')
490 print ' */'
491 print ''
492 self.printRealHeader();
493 return
494
Ian Romanicka9d033c2004-05-19 23:33:08 +0000495
Ian Romanick73f59b02004-05-18 18:33:40 +0000496 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000497 """Print the header associated with all files and call the printRealFooter method."""
498
Ian Romanick73f59b02004-05-18 18:33:40 +0000499 self.printFunctions()
500 self.printRealFooter()
501
502
503 def get_category_define(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000504 """Convert the category name to the #define that would be found in glext.h"""
505
Ian Romanick73f59b02004-05-18 18:33:40 +0000506 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
507 s = self.current_category
508 return "GL_VERSION_" + s.replace(".", "_")
509 else:
510 return self.current_category
511
512
513 def append(self, object_type, obj):
514 if object_type == "function":
515 # If the function is not an alias and has a negative
516 # offset, then we do not need to track it. These are
517 # functions that don't have an assigned offset
518
519 if obj.fn_offset >= 0 or obj.fn_alias != None:
520 if obj.fn_offset >= 0:
521 index = obj.fn_offset
522 else:
523 index = self.next_alias
524 self.next_alias -= 1
525
526 self.functions[index] = obj
527 self.xref[obj.name] = index
528 elif object_type == "type":
529 self.types[obj.name] = obj
530
531 return
532
533
534 def startElement(self, name, attrs):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000535 """Start a new element in the XML stream.
536
537 Starts a new element. There are three types of elements that
538 are specially handled by this function. When a "category"
539 element is encountered, the name of the category is saved.
540 If an element is encountered and no API object is
541 in-progress, a new object is created using the API factory.
542 Any future elements, until that API object is closed, are
543 passed to the current objects startElement method.
544
545 This paradigm was chosen becuase it allows subclasses of the
546 basic API types (i.e., glFunction, glEnum, etc.) to handle
547 additional XML data, GLX protocol information, that the base
548 classes do not know about."""
549
Ian Romanick73f59b02004-05-18 18:33:40 +0000550 if self.current_object != None:
551 self.current_object.startElement(name, attrs)
552 elif name == "category":
553 self.current_category = attrs.get('name', "")
554 else:
555 self.current_object = self.factory.create(self, name, attrs)
556 return
557
Ian Romanicka9d033c2004-05-19 23:33:08 +0000558
Ian Romanick73f59b02004-05-18 18:33:40 +0000559 def endElement(self, name):
560 if self.current_object != None:
561 if self.current_object.endElement(name):
562 self.current_object = None
563 return
564
Ian Romanicka9d033c2004-05-19 23:33:08 +0000565
Ian Romanick73f59b02004-05-18 18:33:40 +0000566 def printFunction(self,offset):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000567 """Print a single function.
568
569 In the base class, this function is empty. All derived
570 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000571 return
572
Ian Romanicka9d033c2004-05-19 23:33:08 +0000573
Ian Romanick73f59b02004-05-18 18:33:40 +0000574 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000575 """Print the "real" header for the created file.
576
577 In the base class, this function is empty. All derived
578 classes should over-ride this function."""
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 printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000583 """Print the "real" footer for the created file.
584
585 In the base class, this function is empty. All derived
586 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000587 return