main: Add entry point for NamedBufferSubData.
[mesa.git] / src / mapi / glapi / gen / gl_XML.py
1 #!/usr/bin/env python
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 decimal import Decimal
29 import xml.etree.ElementTree as ET
30 import re, sys, string
31 import os.path
32 import typeexpr
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 * ')
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__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) && defined(__ELF__))
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__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
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 "(%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 = 0
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 is_attr_true(element, "static_dispatch", "true"):
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 offset = element.get( "offset" )
688 if offset:
689 try:
690 o = int( offset )
691 self.offset = o
692 except Exception, e:
693 self.offset = -1
694 if offset == "assign":
695 self.assign_offset = 1
696
697
698 if not self.name:
699 self.name = true_name
700 elif self.name != true_name:
701 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
702
703
704 # There are two possible cases. The first time an entry-point
705 # with data is seen, self.initialized will be 0. On that
706 # pass, we just fill in the data. The next time an
707 # entry-point with data is seen, self.initialized will be 1.
708 # On that pass we have to make that the new values match the
709 # valuse from the previous entry-point.
710
711 parameters = []
712 return_type = "void"
713 for child in element.getchildren():
714 if child.tag == "return":
715 return_type = child.get( "type", "void" )
716 elif child.tag == "param":
717 param = self.context.factory.create_parameter(child, self.context)
718 parameters.append( param )
719
720
721 if self.initialized:
722 if self.return_type != return_type:
723 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
724
725 if len(parameters) != len(self.parameters):
726 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
727
728 for j in range(0, len(parameters)):
729 p1 = parameters[j]
730 p2 = self.parameters[j]
731 if not p1.compatible( p2 ):
732 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))
733
734
735 if true_name == name or not self.initialized:
736 self.return_type = return_type
737 self.parameters = parameters
738
739 for param in self.parameters:
740 if param.is_image():
741 self.images.append( param )
742
743 if element.getchildren():
744 self.initialized = 1
745 self.entry_point_parameters[name] = parameters
746 else:
747 self.entry_point_parameters[name] = []
748
749 return
750
751 def filter_entry_points(self, entry_point_list):
752 """Filter out entry points not in entry_point_list."""
753 if not self.initialized:
754 raise RuntimeError('%s is not initialized yet' % self.name)
755
756 entry_points = []
757 for ent in self.entry_points:
758 if ent not in entry_point_list:
759 if ent in self.static_entry_points:
760 self.static_entry_points.remove(ent)
761 self.entry_point_parameters.pop(ent)
762 else:
763 entry_points.append(ent)
764
765 if not entry_points:
766 raise RuntimeError('%s has no entry point after filtering' % self.name)
767
768 self.entry_points = entry_points
769 if self.name not in entry_points:
770 # use the first remaining entry point
771 self.name = entry_points[0]
772 self.parameters = self.entry_point_parameters[entry_points[0]]
773
774 def get_images(self):
775 """Return potentially empty list of input images."""
776 return self.images
777
778
779 def parameterIterator(self, name = None):
780 if name is not None:
781 return self.entry_point_parameters[name].__iter__();
782 else:
783 return self.parameters.__iter__();
784
785
786 def get_parameter_string(self, entrypoint = None):
787 if entrypoint:
788 params = self.entry_point_parameters[ entrypoint ]
789 else:
790 params = self.parameters
791
792 return create_parameter_string( params, 1 )
793
794 def get_called_parameter_string(self):
795 p_string = ""
796 comma = ""
797
798 for p in self.parameterIterator():
799 if p.is_padding:
800 continue
801 p_string = p_string + comma + p.name
802 comma = ", "
803
804 return p_string
805
806
807 def is_abi(self):
808 return (self.offset >= 0 and not self.assign_offset)
809
810 def is_static_entry_point(self, name):
811 return name in self.static_entry_points
812
813 def dispatch_name(self):
814 if self.name in self.static_entry_points:
815 return self.name
816 else:
817 return "_dispatch_stub_%u" % (self.offset)
818
819 def static_name(self, name):
820 if name in self.static_entry_points:
821 return name
822 else:
823 return "_dispatch_stub_%u" % (self.offset)
824
825 def entry_points_for_api_version(self, api, version = None):
826 """Return a list of the entry point names for this function
827 which are supported in the given API (and optionally, version).
828
829 Use the decimal.Decimal type to precisely express non-integer
830 versions.
831 """
832 result = []
833 for entry_point, api_to_ver in self.entry_point_api_map.iteritems():
834 if api not in api_to_ver:
835 continue
836 if version is not None and version < api_to_ver[api]:
837 continue
838 result.append(entry_point)
839 return result
840
841
842 class gl_item_factory(object):
843 """Factory to create objects derived from gl_item."""
844
845 def create_function(self, element, context):
846 return gl_function(element, context)
847
848 def create_type(self, element, context, category):
849 return gl_type(element, context, category)
850
851 def create_enum(self, element, context, category):
852 return gl_enum(element, context, category)
853
854 def create_parameter(self, element, context):
855 return gl_parameter(element, context)
856
857 def create_api(self):
858 return gl_api(self)
859
860
861 class gl_api(object):
862 def __init__(self, factory):
863 self.functions_by_name = {}
864 self.enums_by_name = {}
865 self.types_by_name = {}
866
867 self.category_dict = {}
868 self.categories = [{}, {}, {}, {}]
869
870 self.factory = factory
871
872 self.next_offset = 0
873
874 typeexpr.create_initial_types()
875 return
876
877 def filter_functions(self, entry_point_list):
878 """Filter out entry points not in entry_point_list."""
879 functions_by_name = {}
880 for func in self.functions_by_name.itervalues():
881 entry_points = [ent for ent in func.entry_points if ent in entry_point_list]
882 if entry_points:
883 func.filter_entry_points(entry_points)
884 functions_by_name[func.name] = func
885
886 self.functions_by_name = functions_by_name
887
888 def filter_functions_by_api(self, api, version = None):
889 """Filter out entry points not in the given API (or
890 optionally, not in the given version of the given API).
891 """
892 functions_by_name = {}
893 for func in self.functions_by_name.itervalues():
894 entry_points = func.entry_points_for_api_version(api, version)
895 if entry_points:
896 func.filter_entry_points(entry_points)
897 functions_by_name[func.name] = func
898
899 self.functions_by_name = functions_by_name
900
901
902 def parse_file(self, file_name):
903 doc = ET.parse( file_name )
904 self.process_element(file_name, doc)
905
906
907 def process_element(self, file_name, doc):
908 element = doc.getroot()
909 if element.tag == "OpenGLAPI":
910 self.process_OpenGLAPI(file_name, element)
911 return
912
913
914 def process_OpenGLAPI(self, file_name, element):
915 for child in element.getchildren():
916 if child.tag == "category":
917 self.process_category( child )
918 elif child.tag == "OpenGLAPI":
919 self.process_OpenGLAPI( file_name, child )
920 elif child.tag == '{http://www.w3.org/2001/XInclude}include':
921 href = child.get('href')
922 href = os.path.join(os.path.dirname(file_name), href)
923 self.parse_file(href)
924
925 return
926
927
928 def process_category(self, cat):
929 cat_name = cat.get( "name" )
930 cat_number = cat.get( "number" )
931
932 [cat_type, key] = classify_category(cat_name, cat_number)
933 self.categories[cat_type][key] = [cat_name, cat_number]
934
935 for child in cat.getchildren():
936 if child.tag == "function":
937 func_name = real_function_name( child )
938
939 temp_name = child.get( "name" )
940 self.category_dict[ temp_name ] = [cat_name, cat_number]
941
942 if self.functions_by_name.has_key( func_name ):
943 func = self.functions_by_name[ func_name ]
944 func.process_element( child )
945 else:
946 func = self.factory.create_function( child, self )
947 self.functions_by_name[ func_name ] = func
948
949 if func.offset >= self.next_offset:
950 self.next_offset = func.offset + 1
951
952
953 elif child.tag == "enum":
954 enum = self.factory.create_enum( child, self, cat_name )
955 self.enums_by_name[ enum.name ] = enum
956 elif child.tag == "type":
957 t = self.factory.create_type( child, self, cat_name )
958 self.types_by_name[ "GL" + t.name ] = t
959
960 return
961
962
963 def functionIterateByCategory(self, cat = None):
964 """Iterate over functions by category.
965
966 If cat is None, all known functions are iterated in category
967 order. See classify_category for details of the ordering.
968 Within a category, functions are sorted by name. If cat is
969 not None, then only functions in that category are iterated.
970 """
971 lists = [{}, {}, {}, {}]
972
973 for func in self.functionIterateAll():
974 [cat_name, cat_number] = self.category_dict[func.name]
975
976 if (cat == None) or (cat == cat_name):
977 [func_cat_type, key] = classify_category(cat_name, cat_number)
978
979 if not lists[func_cat_type].has_key(key):
980 lists[func_cat_type][key] = {}
981
982 lists[func_cat_type][key][func.name] = func
983
984
985 functions = []
986 for func_cat_type in range(0,4):
987 keys = lists[func_cat_type].keys()
988 keys.sort()
989
990 for key in keys:
991 names = lists[func_cat_type][key].keys()
992 names.sort()
993
994 for name in names:
995 functions.append(lists[func_cat_type][key][name])
996
997 return functions.__iter__()
998
999
1000 def functionIterateByOffset(self):
1001 max_offset = -1
1002 for func in self.functions_by_name.itervalues():
1003 if func.offset > max_offset:
1004 max_offset = func.offset
1005
1006
1007 temp = [None for i in range(0, max_offset + 1)]
1008 for func in self.functions_by_name.itervalues():
1009 if func.offset != -1:
1010 temp[ func.offset ] = func
1011
1012
1013 list = []
1014 for i in range(0, max_offset + 1):
1015 if temp[i]:
1016 list.append(temp[i])
1017
1018 return list.__iter__();
1019
1020
1021 def functionIterateAll(self):
1022 return self.functions_by_name.itervalues()
1023
1024
1025 def enumIterateByName(self):
1026 keys = self.enums_by_name.keys()
1027 keys.sort()
1028
1029 list = []
1030 for enum in keys:
1031 list.append( self.enums_by_name[ enum ] )
1032
1033 return list.__iter__()
1034
1035
1036 def categoryIterate(self):
1037 """Iterate over categories.
1038
1039 Iterate over all known categories in the order specified by
1040 classify_category. Each iterated value is a tuple of the
1041 name and number (which may be None) of the category.
1042 """
1043
1044 list = []
1045 for cat_type in range(0,4):
1046 keys = self.categories[cat_type].keys()
1047 keys.sort()
1048
1049 for key in keys:
1050 list.append(self.categories[cat_type][key])
1051
1052 return list.__iter__()
1053
1054
1055 def get_category_for_name( self, name ):
1056 if self.category_dict.has_key(name):
1057 return self.category_dict[name]
1058 else:
1059 return ["<unknown category>", None]
1060
1061
1062 def typeIterate(self):
1063 return self.types_by_name.itervalues()
1064
1065
1066 def find_type( self, type_name ):
1067 if type_name in self.types_by_name:
1068 return self.types_by_name[ type_name ].type_expr
1069 else:
1070 print "Unable to find base type matching \"%s\"." % (type_name)
1071 return None