Refactor the code to emit multiple-inclusion protection to
[profile/ivi/mesa.git] / src / mesa / glapi / gl_XML.py
1 #!/usr/bin/python2
2
3 # (C) Copyright IBM Corporation 2004, 2005
4 # 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
28 from xml.sax import saxutils
29 from xml.sax import make_parser
30 from xml.sax.handler import feature_namespaces
31
32 import re
33
34 class glItem:
35         """Generic class on which all other API entity types are based."""
36
37         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):
47                 """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."""
54                 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
67                 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."""
72
73                 if name == self.tag_name:
74                         return 1
75                 else:
76                         return 0
77
78         def get_category_define(self):
79                 return self.category
80
81
82 class glEnum( glItem ):
83         """Subclass of glItem for representing GL enumerants.
84         
85         This class is not complete, and is not really used yet."""
86
87         def __init__(self, context, name, attrs):
88                 self.value = int(attrs.get('value', "0x0000"), 0)
89
90                 enum_name = "GL_" + attrs.get('name', None)
91                 glItem.__init__(self, name, enum_name, context)
92
93                 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
105
106         def process_attributes(self, attrs):
107                 name = attrs.get('name', None)
108
109                 temp = attrs.get('count', None)
110                 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))
117
118                 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]
127
128
129 class glType( glItem ):
130         """Subclass of glItem for representing GL types."""
131
132         def __init__(self, context, name, attrs):
133                 self.size = int(attrs.get('size', "0"))
134                 self.glx_name = attrs.get('glx_name', "")
135
136                 type_name = "GL" + attrs.get('name', None)
137                 glItem.__init__(self, name, type_name, context)
138
139
140 class glParameter( glItem ):
141         """Parameter of a glFunction."""
142         p_type = None
143         p_type_string = ""
144         p_count = 0
145         p_count_parameters = None
146         counter = None
147         is_output = 0
148         is_counter = 0
149         is_pointer = 0
150
151         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)
155
156                 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")
167                 try: 
168                         self.p_count = int(c)
169                         self.counter = None
170                 except Exception,e:
171                         self.p_count = 0
172                         self.counter = c
173
174                 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":
180                         self.is_output = 1
181                 else:
182                         self.is_output = 0
183
184                         
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:
223                         has_count = 1
224                 else:
225                         has_count = 0
226
227
228                 # If there is a * anywhere in the parameter's type, then it
229                 # is a pointer.
230
231                 if re.compile("[*]").search(self.p_type_string):
232                         # 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
246                 glItem.__init__(self, name, p_name, context)
247                 return
248
249
250         def is_variable_length_array(self):
251                 """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
261                 return self.p_count_parameters or self.counter or self.width
262
263
264         def is_array(self):
265                 return self.is_pointer
266
267
268         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():
279                         if self.p_count_parameters != None:
280                                 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
288
289         def size(self):
290                 if self.p_count_parameters or self.counter or self.width or self.is_output:
291                         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
297         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
309                         elif self.width:
310                                 return "compsize"
311                         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
318
319 class glParameterIterator:
320         """Class to iterate over a list of glParameters.
321         
322         Objects of this class are returned by the parameterIterator method of
323         the glFunction class.  They are used to iterate over the list of
324         parameters to the function."""
325
326         def __init__(self, data):
327                 self.data = data
328                 self.index = 0
329
330         def __iter__(self):
331                 return self
332
333         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
340
341 class 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 = []
351                 self.image = None
352
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
369         def parameterIterator(self):
370                 return glParameterIterator(self.fn_parameters)
371
372
373         def startElement(self, name, attrs):
374                 if name == "param":
375                         try:
376                                 self.context.factory.create(self, name, attrs)
377                         except RuntimeError:
378                                 print "Error with parameter '%s' in function '%s'." \
379                                         % (attrs.get('name','(unknown)'), self.name)
380                                 raise
381                 elif name == "return":
382                         self.set_return_type(attrs.get('type', None))
383
384
385         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
389                 if p.width:
390                         self.image = p
391
392                 self.fn_parameters.append(p)
393
394
395         def set_return_type(self, t):
396                 self.fn_return_type = t
397
398
399         def get_parameter_string(self):
400                 arg_string = ""
401                 comma = ""
402                 for p in glFunction.parameterIterator(self):
403                         arg_string = arg_string + comma + p.p_type_string + " " + p.name
404                         comma = ", "
405
406                 if arg_string == "":
407                         arg_string = "void"
408
409                 return arg_string
410
411
412 class 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)
422                 elif name == "param":
423                         return glParameter(context, name, attrs)
424                 else:
425                         return None
426
427
428 class glFunctionIterator:
429         """Class to iterate over a list of glFunctions
430
431         Objects of this classare returned by
432         FilterGLAPISpecBase::functionIterator.  This default version
433         iterates over the functions in order of dispatch table offset.  All
434         of the "true" functions are iterated first, followed by the alias
435         functions."""
436
437         def __init__(self, context):
438                 self.context = context
439                 self.keys = context.functions.keys()
440                 self.keys.sort()
441
442                 self.prevk = -1
443                 self.direction = 1
444
445                 for self.index in range(0, len(self.keys)):
446                         if self.keys[ self.index ] >= 0: break
447
448                 if self.index == len(self.keys):
449                         self.direction = -1
450                         self.index -= 1
451
452                 self.split = self.index - 1
453                 return
454
455
456         def __iter__(self):
457                 return self
458
459
460         def next(self):
461                 if self.index < 0:
462                         raise StopIteration
463
464                 k = self.keys[ self.index ]
465
466                 #if self.context.functions[k].fn_alias == None:
467                 #       if k != self.prevk + 1:
468                 #               print 'Missing offset %d' % (prevk)
469                 #       self.prevk = int(k)
470
471                 self.index += self.direction
472
473                 if self.index == len(self.keys):
474                         self.index = self.split
475                         self.direction = -1
476
477                 return self.context.functions[k]
478
479
480 class FilterGLAPISpecBase(saxutils.XMLFilterBase):
481         name = "a"
482         license = "The license for this file is unspecified."
483         functions = {}
484         next_alias = -2
485         types = {}
486         xref = {}
487         current_object = None
488         factory = None
489         current_category = ""
490
491         def __init__(self):
492                 saxutils.XMLFilterBase.__init__(self)
493                 self.functions = {}
494                 self.types = {}
495                 self.xref = {}
496                 self.factory = glItemFactory()
497                 self.header_tag = None
498
499
500         def find_type(self,type_name):
501                 for t in self.types:
502                         if re.compile(t).search(type_name):
503                                 return self.types[t]
504                 print "Unable to find base type matching \"%s\"." % (type_name)
505                 return None
506
507
508         def find_function(self,function_name):
509                 index = self.xref[function_name]
510                 return self.functions[index]
511
512
513         def functionIterator(self):
514                 return glFunctionIterator(self)
515
516
517         def printFunctions(self):
518                 for f in self.functionIterator():
519                         self.printFunction(f)
520                 return
521
522
523         def printHeader(self):
524                 """Print the header associated with all files and call the printRealHeader method."""
525
526                 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
527                         % (self.name)
528                 print ''
529                 print '/*'
530                 print ' * ' + self.license.replace('\n', '\n * ')
531                 print ' */'
532                 print ''
533                 if self.header_tag:
534                     print '#if !defined( %s )' % (self.header_tag)
535                     print '#  define %s' % (self.header_tag)
536                     print ''
537                 self.printRealHeader();
538                 return
539
540
541         def printFooter(self):
542                 """Print the header associated with all files and call the printRealFooter method."""
543
544                 self.printFunctions()
545                 self.printRealFooter()
546                 if self.header_tag:
547                     print ''
548                     print '#endif /* !defined( %s ) */' % (self.header_tag)
549
550
551         def get_category_define(self):
552                 """Convert the category name to the #define that would be found in glext.h"""
553
554                 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
555                         s = self.current_category
556                         return "GL_VERSION_" + s.replace(".", "_")
557                 else:
558                         return self.current_category
559
560
561         def append(self, object_type, obj):
562                 if object_type == "function":
563                         # If the function is not an alias and has a negative
564                         # offset, then we do not need to track it.  These are
565                         # functions that don't have an assigned offset
566
567                         if obj.fn_offset >= 0 or obj.fn_alias != None:
568                                 if obj.fn_offset >= 0:
569                                         index = obj.fn_offset
570                                 else:
571                                         index = self.next_alias
572                                         self.next_alias -= 1
573
574                                 self.functions[index] = obj
575                                 self.xref[obj.name] = index
576                 elif object_type == "type":
577                         self.types[obj.name] = obj
578
579                 return
580
581
582         def startElement(self, name, attrs):
583                 """Start a new element in the XML stream.
584                 
585                 Starts a new element.  There are three types of elements that
586                 are specially handled by this function.  When a "category"
587                 element is encountered, the name of the category is saved.
588                 If an element is encountered and no API object is
589                 in-progress, a new object is created using the API factory.
590                 Any future elements, until that API object is closed, are
591                 passed to the current objects startElement method.
592         
593                 This paradigm was chosen becuase it allows subclasses of the
594                 basic API types (i.e., glFunction, glEnum, etc.) to handle
595                 additional XML data, GLX protocol information,  that the base
596                 classes do not know about."""
597
598                 if self.current_object != None:
599                         self.current_object.startElement(name, attrs)
600                 elif name == "category":
601                         self.current_category = attrs.get('name', "")
602                 else:
603                         self.current_object = self.factory.create(self, name, attrs)
604                 return
605
606
607         def endElement(self, name):
608                 if self.current_object != None:
609                         if self.current_object.endElement(name):
610                                 self.current_object = None
611                 return
612
613
614         def printFunction(self,offset):
615                 """Print a single function.
616
617                 In the base class, this function is empty.  All derived
618                 classes should over-ride this function."""
619                 return
620     
621
622         def printRealHeader(self):
623                 """Print the "real" header for the created file.
624
625                 In the base class, this function is empty.  All derived
626                 classes should over-ride this function."""
627                 return
628
629
630         def printRealFooter(self):
631                 """Print the "real" footer for the created file.
632
633                 In the base class, this function is empty.  All derived
634                 classes should over-ride this function."""
635                 return