mapi/gen: remove shebang from python scripts
[mesa.git] / src / mapi / glapi / gen / gl_XML.py
1
2 # (C) Copyright IBM Corporation 2004, 2005
3 # All Rights Reserved.
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # on the rights to use, copy, modify, merge, publish, distribute, sub
9 # license, and/or sell copies of the Software, and to permit persons to whom
10 # the Software is furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
14 # Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 # IN THE SOFTWARE.
23 #
24 # Authors:
25 # Ian Romanick <idr@us.ibm.com>
26
27 from decimal import Decimal
28 import xml.etree.ElementTree as ET
29 import re, sys, string
30 import os.path
31 import typeexpr
32 import static_data
33
34
35 def parse_GL_API( file_name, factory = None ):
36
37 if not factory:
38 factory = gl_item_factory()
39
40 api = factory.create_api()
41 api.parse_file( file_name )
42
43 # After the XML has been processed, we need to go back and assign
44 # dispatch offsets to the functions that request that their offsets
45 # be assigned by the scripts. Typically this means all functions
46 # that are not part of the ABI.
47
48 for func in api.functionIterateByCategory():
49 if func.assign_offset:
50 func.offset = api.next_offset;
51 api.next_offset += 1
52
53 return api
54
55
56 def is_attr_true( element, name, default = "false" ):
57 """Read a name value from an element's attributes.
58
59 The value read from the attribute list must be either 'true' or
60 'false'. If the value is 'false', zero will be returned. If the
61 value is 'true', non-zero will be returned. An exception will be
62 raised for any other value."""
63
64 value = element.get( name, default )
65 if value == "true":
66 return 1
67 elif value == "false":
68 return 0
69 else:
70 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
71
72
73 class gl_print_base(object):
74 """Base class of all API pretty-printers.
75
76 In the model-view-controller pattern, this is the view. Any derived
77 class will want to over-ride the printBody, printRealHader, and
78 printRealFooter methods. Some derived classes may want to over-ride
79 printHeader and printFooter, or even Print (though this is unlikely).
80 """
81
82 def __init__(self):
83 # Name of the script that is generating the output file.
84 # Every derived class should set this to the name of its
85 # source file.
86
87 self.name = "a"
88
89
90 # License on the *generated* source file. This may differ
91 # from the license on the script that is generating the file.
92 # Every derived class should set this to some reasonable
93 # value.
94 #
95 # See license.py for an example of a reasonable value.
96
97 self.license = "The license for this file is unspecified."
98
99
100 # The header_tag is the name of the C preprocessor define
101 # used to prevent multiple inclusion. Typically only
102 # generated C header files need this to be set. Setting it
103 # causes code to be generated automatically in printHeader
104 # and printFooter.
105
106 self.header_tag = None
107
108
109 # List of file-private defines that must be undefined at the
110 # end of the file. This can be used in header files to define
111 # names for use in the file, then undefine them at the end of
112 # the header file.
113
114 self.undef_list = []
115 return
116
117
118 def Print(self, api):
119 self.printHeader()
120 self.printBody(api)
121 self.printFooter()
122 return
123
124
125 def printHeader(self):
126 """Print the header associated with all files and call the printRealHeader method."""
127
128 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
129 % (self.name)
130 print ''
131 print '/*'
132 print (' * ' + self.license.replace('\n', '\n * ')).replace(' \n', '\n')
133 print ' */'
134 print ''
135 if self.header_tag:
136 print '#if !defined( %s )' % (self.header_tag)
137 print '# define %s' % (self.header_tag)
138 print ''
139 self.printRealHeader();
140 return
141
142
143 def printFooter(self):
144 """Print the header associated with all files and call the printRealFooter method."""
145
146 self.printRealFooter()
147
148 if self.undef_list:
149 print ''
150 for u in self.undef_list:
151 print "# undef %s" % (u)
152
153 if self.header_tag:
154 print ''
155 print '#endif /* !defined( %s ) */' % (self.header_tag)
156
157
158 def printRealHeader(self):
159 """Print the "real" header for the created file.
160
161 In the base class, this function is empty. All derived
162 classes should over-ride this function."""
163 return
164
165
166 def printRealFooter(self):
167 """Print the "real" footer for the created file.
168
169 In the base class, this function is empty. All derived
170 classes should over-ride this function."""
171 return
172
173
174 def printPure(self):
175 """Conditionally define `PURE' function attribute.
176
177 Conditionally defines a preprocessor macro `PURE' that wraps
178 GCC's `pure' function attribute. The conditional code can be
179 easilly adapted to other compilers that support a similar
180 feature.
181
182 The name is also added to the file's undef_list.
183 """
184 self.undef_list.append("PURE")
185 print """# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
186 # define PURE __attribute__((pure))
187 # else
188 # define PURE
189 # endif"""
190 return
191
192
193 def printFastcall(self):
194 """Conditionally define `FASTCALL' function attribute.
195
196 Conditionally defines a preprocessor macro `FASTCALL' that
197 wraps GCC's `fastcall' function attribute. The conditional
198 code can be easilly adapted to other compilers that support a
199 similar feature.
200
201 The name is also added to the file's undef_list.
202 """
203
204 self.undef_list.append("FASTCALL")
205 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
206 # define FASTCALL __attribute__((fastcall))
207 # else
208 # define FASTCALL
209 # endif"""
210 return
211
212
213 def printVisibility(self, S, s):
214 """Conditionally define visibility function attribute.
215
216 Conditionally defines a preprocessor macro name S that wraps
217 GCC's visibility function attribute. The visibility used is
218 the parameter s. The conditional code can be easilly adapted
219 to other compilers that support a similar feature.
220
221 The name is also added to the file's undef_list.
222 """
223
224 self.undef_list.append(S)
225 print """# if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
226 # define %s __attribute__((visibility("%s")))
227 # else
228 # define %s
229 # endif""" % (S, s, S)
230 return
231
232
233 def printNoinline(self):
234 """Conditionally define `NOINLINE' function attribute.
235
236 Conditionally defines a preprocessor macro `NOINLINE' that
237 wraps GCC's `noinline' function attribute. The conditional
238 code can be easilly adapted to other compilers that support a
239 similar feature.
240
241 The name is also added to the file's undef_list.
242 """
243
244 self.undef_list.append("NOINLINE")
245 print """# if defined(__GNUC__)
246 # define NOINLINE __attribute__((noinline))
247 # else
248 # define NOINLINE
249 # endif"""
250 return
251
252
253 def real_function_name(element):
254 name = element.get( "name" )
255 alias = element.get( "alias" )
256
257 if alias:
258 return alias
259 else:
260 return name
261
262
263 def real_category_name(c):
264 if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
265 return "GL_VERSION_" + c.replace(".", "_")
266 else:
267 return c
268
269
270 def classify_category(name, number):
271 """Based on the category name and number, select a numerical class for it.
272
273 Categories are divided into four classes numbered 0 through 3. The
274 classes are:
275
276 0. Core GL versions, sorted by version number.
277 1. ARB extensions, sorted by extension number.
278 2. Non-ARB extensions, sorted by extension number.
279 3. Un-numbered extensions, sorted by extension name.
280 """
281
282 try:
283 core_version = float(name)
284 except Exception,e:
285 core_version = 0.0
286
287 if core_version > 0.0:
288 cat_type = 0
289 key = name
290 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
291 cat_type = 1
292 key = int(number)
293 else:
294 if number != None:
295 cat_type = 2
296 key = int(number)
297 else:
298 cat_type = 3
299 key = name
300
301
302 return [cat_type, key]
303
304
305 def create_parameter_string(parameters, include_names):
306 """Create a parameter string from a list of gl_parameters."""
307
308 list = []
309 for p in parameters:
310 if p.is_padding:
311 continue
312
313 if include_names:
314 list.append( p.string() )
315 else:
316 list.append( p.type_string() )
317
318 if len(list) == 0: list = ["void"]
319
320 return string.join(list, ", ")
321
322
323 class gl_item(object):
324 def __init__(self, element, context, category):
325 self.context = context
326 self.name = element.get( "name" )
327 self.category = real_category_name( category )
328
329 return
330
331
332 class gl_type( gl_item ):
333 def __init__(self, element, context, category):
334 gl_item.__init__(self, element, context, category)
335 self.size = int( element.get( "size" ), 0 )
336
337 te = typeexpr.type_expression( None )
338 tn = typeexpr.type_node()
339 tn.size = int( element.get( "size" ), 0 )
340 tn.integer = not is_attr_true( element, "float" )
341 tn.unsigned = is_attr_true( element, "unsigned" )
342 tn.pointer = is_attr_true( element, "pointer" )
343 tn.name = "GL" + self.name
344 te.set_base_type_node( tn )
345
346 self.type_expr = te
347 return
348
349
350 def get_type_expression(self):
351 return self.type_expr
352
353
354 class gl_enum( gl_item ):
355 def __init__(self, element, context, category):
356 gl_item.__init__(self, element, context, category)
357 self.value = int( element.get( "value" ), 0 )
358
359 temp = element.get( "count" )
360 if not temp or temp == "?":
361 self.default_count = -1
362 else:
363 try:
364 c = int(temp)
365 except Exception,e:
366 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
367
368 self.default_count = c
369
370 return
371
372
373 def priority(self):
374 """Calculate a 'priority' for this enum name.
375
376 When an enum is looked up by number, there may be many
377 possible names, but only one is the 'prefered' name. The
378 priority is used to select which name is the 'best'.
379
380 Highest precedence is given to core GL name. ARB extension
381 names have the next highest, followed by EXT extension names.
382 Vendor extension names are the lowest.
383 """
384
385 if self.name.endswith( "_BIT" ):
386 bias = 1
387 else:
388 bias = 0
389
390 if self.category.startswith( "GL_VERSION_" ):
391 priority = 0
392 elif self.category.startswith( "GL_ARB_" ):
393 priority = 2
394 elif self.category.startswith( "GL_EXT_" ):
395 priority = 4
396 else:
397 priority = 6
398
399 return priority + bias
400
401
402
403 class gl_parameter(object):
404 def __init__(self, element, context):
405 self.name = element.get( "name" )
406
407 ts = element.get( "type" )
408 self.type_expr = typeexpr.type_expression( ts, context )
409
410 temp = element.get( "variable_param" )
411 if temp:
412 self.count_parameter_list = temp.split( ' ' )
413 else:
414 self.count_parameter_list = []
415
416 # The count tag can be either a numeric string or the name of
417 # a variable. If it is the name of a variable, the int(c)
418 # statement will throw an exception, and the except block will
419 # take over.
420
421 c = element.get( "count" )
422 try:
423 count = int(c)
424 self.count = count
425 self.counter = None
426 except Exception,e:
427 count = 1
428 self.count = 0
429 self.counter = c
430
431 self.count_scale = int(element.get( "count_scale", "1" ))
432
433 elements = (count * self.count_scale)
434 if elements == 1:
435 elements = 0
436
437 #if ts == "GLdouble":
438 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
439 # print '/* # elements = %u */' % (elements)
440 self.type_expr.set_elements( elements )
441 #if ts == "GLdouble":
442 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
443
444 self.is_client_only = is_attr_true( element, 'client_only' )
445 self.is_counter = is_attr_true( element, 'counter' )
446 self.is_output = is_attr_true( element, 'output' )
447
448
449 # Pixel data has special parameters.
450
451 self.width = element.get('img_width')
452 self.height = element.get('img_height')
453 self.depth = element.get('img_depth')
454 self.extent = element.get('img_extent')
455
456 self.img_xoff = element.get('img_xoff')
457 self.img_yoff = element.get('img_yoff')
458 self.img_zoff = element.get('img_zoff')
459 self.img_woff = element.get('img_woff')
460
461 self.img_format = element.get('img_format')
462 self.img_type = element.get('img_type')
463 self.img_target = element.get('img_target')
464
465 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
466 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
467 self.img_send_null = is_attr_true( element, 'img_send_null' )
468
469 self.is_padding = is_attr_true( element, 'padding' )
470 return
471
472
473 def compatible(self, other):
474 return 1
475
476
477 def is_array(self):
478 return self.is_pointer()
479
480
481 def is_pointer(self):
482 return self.type_expr.is_pointer()
483
484
485 def is_image(self):
486 if self.width:
487 return 1
488 else:
489 return 0
490
491
492 def is_variable_length(self):
493 return len(self.count_parameter_list) or self.counter
494
495
496 def is_64_bit(self):
497 count = self.type_expr.get_element_count()
498 if count:
499 if (self.size() / count) == 8:
500 return 1
501 else:
502 if self.size() == 8:
503 return 1
504
505 return 0
506
507
508 def string(self):
509 return self.type_expr.original_string + " " + self.name
510
511
512 def type_string(self):
513 return self.type_expr.original_string
514
515
516 def get_base_type_string(self):
517 return self.type_expr.get_base_name()
518
519
520 def get_dimensions(self):
521 if not self.width:
522 return [ 0, "0", "0", "0", "0" ]
523
524 dim = 1
525 w = self.width
526 h = "1"
527 d = "1"
528 e = "1"
529
530 if self.height:
531 dim = 2
532 h = self.height
533
534 if self.depth:
535 dim = 3
536 d = self.depth
537
538 if self.extent:
539 dim = 4
540 e = self.extent
541
542 return [ dim, w, h, d, e ]
543
544
545 def get_stack_size(self):
546 return self.type_expr.get_stack_size()
547
548
549 def size(self):
550 if self.is_image():
551 return 0
552 else:
553 return self.type_expr.get_element_size()
554
555
556 def get_element_count(self):
557 c = self.type_expr.get_element_count()
558 if c == 0:
559 return 1
560
561 return c
562
563
564 def size_string(self, use_parens = 1):
565 s = self.size()
566 if self.counter or self.count_parameter_list:
567 list = [ "compsize" ]
568
569 if self.counter and self.count_parameter_list:
570 list.append( self.counter )
571 elif self.counter:
572 list = [ self.counter ]
573
574 if s > 1:
575 list.append( str(s) )
576
577 if len(list) > 1 and use_parens :
578 return "safe_mul(%s)" % (string.join(list, ", "))
579 else:
580 return string.join(list, " * ")
581
582 elif self.is_image():
583 return "compsize"
584 else:
585 return str(s)
586
587
588 def format_string(self):
589 if self.type_expr.original_string == "GLenum":
590 return "0x%x"
591 else:
592 return self.type_expr.format_string()
593
594
595 class gl_function( gl_item ):
596 def __init__(self, element, context):
597 self.context = context
598 self.name = None
599
600 self.entry_points = []
601 self.return_type = "void"
602 self.parameters = []
603 self.offset = -1
604 self.initialized = 0
605 self.images = []
606 self.exec_flavor = 'mesa'
607 self.desktop = True
608 self.deprecated = None
609
610 # self.entry_point_api_map[name][api] is a decimal value
611 # indicating the earliest version of the given API in which
612 # each entry point exists. Every entry point is included in
613 # the first level of the map; the second level of the map only
614 # lists APIs which contain the entry point in at least one
615 # version. For example,
616 # self.entry_point_api_map['ClipPlanex'] == { 'es1':
617 # Decimal('1.1') }.
618 self.entry_point_api_map = {}
619
620 # self.api_map[api] is a decimal value indicating the earliest
621 # version of the given API in which ANY alias for the function
622 # exists. The map only lists APIs which contain the function
623 # in at least one version. For example, for the ClipPlanex
624 # function, self.entry_point_api_map == { 'es1':
625 # Decimal('1.1') }.
626 self.api_map = {}
627
628 self.assign_offset = False
629
630 self.static_entry_points = []
631
632 # Track the parameter string (for the function prototype)
633 # for each entry-point. This is done because some functions
634 # change their prototype slightly when promoted from extension
635 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
636 # are good examples of this. Scripts that need to generate
637 # code for these differing aliases need to real prototype
638 # for each entry-point. Otherwise, they may generate code
639 # that won't compile.
640
641 self.entry_point_parameters = {}
642
643 self.process_element( element )
644
645 return
646
647
648 def process_element(self, element):
649 name = element.get( "name" )
650 alias = element.get( "alias" )
651
652 if name in static_data.functions:
653 self.static_entry_points.append(name)
654
655 self.entry_points.append( name )
656
657 self.entry_point_api_map[name] = {}
658 for api in ('es1', 'es2'):
659 version_str = element.get(api, 'none')
660 assert version_str is not None
661 if version_str != 'none':
662 version_decimal = Decimal(version_str)
663 self.entry_point_api_map[name][api] = version_decimal
664 if api not in self.api_map or \
665 version_decimal < self.api_map[api]:
666 self.api_map[api] = version_decimal
667
668 exec_flavor = element.get('exec')
669 if exec_flavor:
670 self.exec_flavor = exec_flavor
671
672 deprecated = element.get('deprecated', 'none')
673 if deprecated != 'none':
674 self.deprecated = Decimal(deprecated)
675
676 if not is_attr_true(element, 'desktop', 'true'):
677 self.desktop = False
678
679 if alias:
680 true_name = alias
681 else:
682 true_name = name
683
684 # Only try to set the offset when a non-alias entry-point
685 # is being processed.
686
687 if name in static_data.offsets:
688 self.offset = static_data.offsets[name]
689 else:
690 self.offset = -1
691 self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions
692
693 if not self.name:
694 self.name = true_name
695 elif self.name != true_name:
696 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
697
698
699 # There are two possible cases. The first time an entry-point
700 # with data is seen, self.initialized will be 0. On that
701 # pass, we just fill in the data. The next time an
702 # entry-point with data is seen, self.initialized will be 1.
703 # On that pass we have to make that the new values match the
704 # valuse from the previous entry-point.
705
706 parameters = []
707 return_type = "void"
708 for child in element.getchildren():
709 if child.tag == "return":
710 return_type = child.get( "type", "void" )
711 elif child.tag == "param":
712 param = self.context.factory.create_parameter(child, self.context)
713 parameters.append( param )
714
715
716 if self.initialized:
717 if self.return_type != return_type:
718 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
719
720 if len(parameters) != len(self.parameters):
721 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
722
723 for j in range(0, len(parameters)):
724 p1 = parameters[j]
725 p2 = self.parameters[j]
726 if not p1.compatible( p2 ):
727 raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string))
728
729
730 if true_name == name or not self.initialized:
731 self.return_type = return_type
732 self.parameters = parameters
733
734 for param in self.parameters:
735 if param.is_image():
736 self.images.append( param )
737
738 if element.getchildren():
739 self.initialized = 1
740 self.entry_point_parameters[name] = parameters
741 else:
742 self.entry_point_parameters[name] = []
743
744 return
745
746 def filter_entry_points(self, entry_point_list):
747 """Filter out entry points not in entry_point_list."""
748 if not self.initialized:
749 raise RuntimeError('%s is not initialized yet' % self.name)
750
751 entry_points = []
752 for ent in self.entry_points:
753 if ent not in entry_point_list:
754 if ent in self.static_entry_points:
755 self.static_entry_points.remove(ent)
756 self.entry_point_parameters.pop(ent)
757 else:
758 entry_points.append(ent)
759
760 if not entry_points:
761 raise RuntimeError('%s has no entry point after filtering' % self.name)
762
763 self.entry_points = entry_points
764 if self.name not in entry_points:
765 # use the first remaining entry point
766 self.name = entry_points[0]
767 self.parameters = self.entry_point_parameters[entry_points[0]]
768
769 def get_images(self):
770 """Return potentially empty list of input images."""
771 return self.images
772
773
774 def parameterIterator(self, name = None):
775 if name is not None:
776 return self.entry_point_parameters[name].__iter__();
777 else:
778 return self.parameters.__iter__();
779
780
781 def get_parameter_string(self, entrypoint = None):
782 if entrypoint:
783 params = self.entry_point_parameters[ entrypoint ]
784 else:
785 params = self.parameters
786
787 return create_parameter_string( params, 1 )
788
789 def get_called_parameter_string(self):
790 p_string = ""
791 comma = ""
792
793 for p in self.parameterIterator():
794 if p.is_padding:
795 continue
796 p_string = p_string + comma + p.name
797 comma = ", "
798
799 return p_string
800
801
802 def is_abi(self):
803 return (self.offset >= 0 and not self.assign_offset)
804
805 def is_static_entry_point(self, name):
806 return name in self.static_entry_points
807
808 def dispatch_name(self):
809 if self.name in self.static_entry_points:
810 return self.name
811 else:
812 return "_dispatch_stub_%u" % (self.offset)
813
814 def static_name(self, name):
815 if name in self.static_entry_points:
816 return name
817 else:
818 return "_dispatch_stub_%u" % (self.offset)
819
820 def entry_points_for_api_version(self, api, version = None):
821 """Return a list of the entry point names for this function
822 which are supported in the given API (and optionally, version).
823
824 Use the decimal.Decimal type to precisely express non-integer
825 versions.
826 """
827 result = []
828 for entry_point, api_to_ver in self.entry_point_api_map.iteritems():
829 if api not in api_to_ver:
830 continue
831 if version is not None and version < api_to_ver[api]:
832 continue
833 result.append(entry_point)
834 return result
835
836
837 class gl_item_factory(object):
838 """Factory to create objects derived from gl_item."""
839
840 def create_function(self, element, context):
841 return gl_function(element, context)
842
843 def create_type(self, element, context, category):
844 return gl_type(element, context, category)
845
846 def create_enum(self, element, context, category):
847 return gl_enum(element, context, category)
848
849 def create_parameter(self, element, context):
850 return gl_parameter(element, context)
851
852 def create_api(self):
853 return gl_api(self)
854
855
856 class gl_api(object):
857 def __init__(self, factory):
858 self.functions_by_name = {}
859 self.enums_by_name = {}
860 self.types_by_name = {}
861
862 self.category_dict = {}
863 self.categories = [{}, {}, {}, {}]
864
865 self.factory = factory
866
867 self.next_offset = 0
868
869 typeexpr.create_initial_types()
870 return
871
872 def filter_functions(self, entry_point_list):
873 """Filter out entry points not in entry_point_list."""
874 functions_by_name = {}
875 for func in self.functions_by_name.itervalues():
876 entry_points = [ent for ent in func.entry_points if ent in entry_point_list]
877 if entry_points:
878 func.filter_entry_points(entry_points)
879 functions_by_name[func.name] = func
880
881 self.functions_by_name = functions_by_name
882
883 def filter_functions_by_api(self, api, version = None):
884 """Filter out entry points not in the given API (or
885 optionally, not in the given version of the given API).
886 """
887 functions_by_name = {}
888 for func in self.functions_by_name.itervalues():
889 entry_points = func.entry_points_for_api_version(api, version)
890 if entry_points:
891 func.filter_entry_points(entry_points)
892 functions_by_name[func.name] = func
893
894 self.functions_by_name = functions_by_name
895
896
897 def parse_file(self, file_name):
898 doc = ET.parse( file_name )
899 self.process_element(file_name, doc)
900
901
902 def process_element(self, file_name, doc):
903 element = doc.getroot()
904 if element.tag == "OpenGLAPI":
905 self.process_OpenGLAPI(file_name, element)
906 return
907
908
909 def process_OpenGLAPI(self, file_name, element):
910 for child in element.getchildren():
911 if child.tag == "category":
912 self.process_category( child )
913 elif child.tag == "OpenGLAPI":
914 self.process_OpenGLAPI( file_name, child )
915 elif child.tag == '{http://www.w3.org/2001/XInclude}include':
916 href = child.get('href')
917 href = os.path.join(os.path.dirname(file_name), href)
918 self.parse_file(href)
919
920 return
921
922
923 def process_category(self, cat):
924 cat_name = cat.get( "name" )
925 cat_number = cat.get( "number" )
926
927 [cat_type, key] = classify_category(cat_name, cat_number)
928 self.categories[cat_type][key] = [cat_name, cat_number]
929
930 for child in cat.getchildren():
931 if child.tag == "function":
932 func_name = real_function_name( child )
933
934 temp_name = child.get( "name" )
935 self.category_dict[ temp_name ] = [cat_name, cat_number]
936
937 if self.functions_by_name.has_key( func_name ):
938 func = self.functions_by_name[ func_name ]
939 func.process_element( child )
940 else:
941 func = self.factory.create_function( child, self )
942 self.functions_by_name[ func_name ] = func
943
944 if func.offset >= self.next_offset:
945 self.next_offset = func.offset + 1
946
947
948 elif child.tag == "enum":
949 enum = self.factory.create_enum( child, self, cat_name )
950 self.enums_by_name[ enum.name ] = enum
951 elif child.tag == "type":
952 t = self.factory.create_type( child, self, cat_name )
953 self.types_by_name[ "GL" + t.name ] = t
954
955 return
956
957
958 def functionIterateByCategory(self, cat = None):
959 """Iterate over functions by category.
960
961 If cat is None, all known functions are iterated in category
962 order. See classify_category for details of the ordering.
963 Within a category, functions are sorted by name. If cat is
964 not None, then only functions in that category are iterated.
965 """
966 lists = [{}, {}, {}, {}]
967
968 for func in self.functionIterateAll():
969 [cat_name, cat_number] = self.category_dict[func.name]
970
971 if (cat == None) or (cat == cat_name):
972 [func_cat_type, key] = classify_category(cat_name, cat_number)
973
974 if not lists[func_cat_type].has_key(key):
975 lists[func_cat_type][key] = {}
976
977 lists[func_cat_type][key][func.name] = func
978
979
980 functions = []
981 for func_cat_type in range(0,4):
982 keys = lists[func_cat_type].keys()
983 keys.sort()
984
985 for key in keys:
986 names = lists[func_cat_type][key].keys()
987 names.sort()
988
989 for name in names:
990 functions.append(lists[func_cat_type][key][name])
991
992 return functions.__iter__()
993
994
995 def functionIterateByOffset(self):
996 max_offset = -1
997 for func in self.functions_by_name.itervalues():
998 if func.offset > max_offset:
999 max_offset = func.offset
1000
1001
1002 temp = [None for i in range(0, max_offset + 1)]
1003 for func in self.functions_by_name.itervalues():
1004 if func.offset != -1:
1005 temp[ func.offset ] = func
1006
1007
1008 list = []
1009 for i in range(0, max_offset + 1):
1010 if temp[i]:
1011 list.append(temp[i])
1012
1013 return list.__iter__();
1014
1015
1016 def functionIterateAll(self):
1017 return self.functions_by_name.itervalues()
1018
1019
1020 def enumIterateByName(self):
1021 keys = self.enums_by_name.keys()
1022 keys.sort()
1023
1024 list = []
1025 for enum in keys:
1026 list.append( self.enums_by_name[ enum ] )
1027
1028 return list.__iter__()
1029
1030
1031 def categoryIterate(self):
1032 """Iterate over categories.
1033
1034 Iterate over all known categories in the order specified by
1035 classify_category. Each iterated value is a tuple of the
1036 name and number (which may be None) of the category.
1037 """
1038
1039 list = []
1040 for cat_type in range(0,4):
1041 keys = self.categories[cat_type].keys()
1042 keys.sort()
1043
1044 for key in keys:
1045 list.append(self.categories[cat_type][key])
1046
1047 return list.__iter__()
1048
1049
1050 def get_category_for_name( self, name ):
1051 if self.category_dict.has_key(name):
1052 return self.category_dict[name]
1053 else:
1054 return ["<unknown category>", None]
1055
1056
1057 def typeIterate(self):
1058 return self.types_by_name.itervalues()
1059
1060
1061 def find_type( self, type_name ):
1062 if type_name in self.types_by_name:
1063 return self.types_by_name[ type_name ].type_expr
1064 else:
1065 print "Unable to find base type matching \"%s\"." % (type_name)
1066 return None