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