glthread: don't prefix variable_data with const
[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.count_scale = int(element.get( "count_scale", "1" ))
435
436 elements = (count * self.count_scale)
437 if elements == 1:
438 elements = 0
439
440 #if ts == "GLdouble":
441 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
442 # print '/* # elements = %u */' % (elements)
443 self.type_expr.set_elements( elements )
444 #if ts == "GLdouble":
445 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
446
447 self.is_client_only = is_attr_true( element, 'client_only' )
448 self.is_counter = is_attr_true( element, 'counter' )
449 self.is_output = is_attr_true( element, 'output' )
450
451
452 # Pixel data has special parameters.
453
454 self.width = element.get('img_width')
455 self.height = element.get('img_height')
456 self.depth = element.get('img_depth')
457 self.extent = element.get('img_extent')
458
459 self.img_xoff = element.get('img_xoff')
460 self.img_yoff = element.get('img_yoff')
461 self.img_zoff = element.get('img_zoff')
462 self.img_woff = element.get('img_woff')
463
464 self.img_format = element.get('img_format')
465 self.img_type = element.get('img_type')
466 self.img_target = element.get('img_target')
467
468 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
469 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
470 self.img_send_null = is_attr_true( element, 'img_send_null' )
471
472 self.is_padding = is_attr_true( element, 'padding' )
473 return
474
475
476 def compatible(self, other):
477 return 1
478
479
480 def is_array(self):
481 return self.is_pointer()
482
483
484 def is_pointer(self):
485 return self.type_expr.is_pointer()
486
487
488 def is_image(self):
489 if self.width:
490 return 1
491 else:
492 return 0
493
494
495 def is_variable_length(self):
496 return len(self.count_parameter_list) or self.counter
497
498
499 def is_64_bit(self):
500 count = self.type_expr.get_element_count()
501 if count:
502 if (self.size() / count) == 8:
503 return 1
504 else:
505 if self.size() == 8:
506 return 1
507
508 return 0
509
510
511 def string(self):
512 return self.type_expr.original_string + " " + self.name
513
514
515 def type_string(self):
516 return self.type_expr.original_string
517
518
519 def get_base_type_string(self):
520 return self.type_expr.get_base_name()
521
522
523 def get_dimensions(self):
524 if not self.width:
525 return [ 0, "0", "0", "0", "0" ]
526
527 dim = 1
528 w = self.width
529 h = "1"
530 d = "1"
531 e = "1"
532
533 if self.height:
534 dim = 2
535 h = self.height
536
537 if self.depth:
538 dim = 3
539 d = self.depth
540
541 if self.extent:
542 dim = 4
543 e = self.extent
544
545 return [ dim, w, h, d, e ]
546
547
548 def get_stack_size(self):
549 return self.type_expr.get_stack_size()
550
551
552 def size(self):
553 if self.is_image():
554 return 0
555 else:
556 return self.type_expr.get_element_size()
557
558
559 def get_element_count(self):
560 c = self.type_expr.get_element_count()
561 if c == 0:
562 return 1
563
564 return c
565
566
567 def size_string(self, use_parens = 1):
568 base_size_str = ""
569
570 count = self.get_element_count()
571 if count:
572 base_size_str = "%d * " % count
573
574 base_size_str += "sizeof(%s)" % ( self.get_base_type_string() )
575
576 if self.counter or self.count_parameter_list:
577 list = [ "compsize" ]
578
579 if self.counter and self.count_parameter_list:
580 list.append( self.counter )
581 elif self.counter:
582 list = [ self.counter ]
583
584 if self.size() > 1:
585 list.append( base_size_str )
586
587 if len(list) > 1 and use_parens :
588 return "safe_mul(%s)" % ", ".join(list)
589 else:
590 return " * ".join(list)
591
592 elif self.is_image():
593 return "compsize"
594 else:
595 return base_size_str
596
597
598 def format_string(self):
599 if self.type_expr.original_string == "GLenum":
600 return "0x%x"
601 else:
602 return self.type_expr.format_string()
603
604
605 class gl_function( gl_item ):
606 def __init__(self, element, context):
607 self.context = context
608 self.name = None
609
610 self.entry_points = []
611 self.return_type = "void"
612 self.parameters = []
613 self.offset = -1
614 self.initialized = 0
615 self.images = []
616 self.exec_flavor = 'mesa'
617 self.desktop = True
618 self.deprecated = None
619 self.has_no_error_variant = False
620
621 # self.api_map[api] is a decimal value indicating the earliest
622 # version of the given API in which ANY alias for the function
623 # exists. The map only lists APIs which contain the function
624 # in at least one version. For example, for the ClipPlanex
625 # function, self.api_map == { 'es1':
626 # Decimal('1.1') }.
627 self.api_map = {}
628
629 self.assign_offset = False
630
631 self.static_entry_points = []
632
633 # Track the parameter string (for the function prototype)
634 # for each entry-point. This is done because some functions
635 # change their prototype slightly when promoted from extension
636 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
637 # are good examples of this. Scripts that need to generate
638 # code for these differing aliases need to real prototype
639 # for each entry-point. Otherwise, they may generate code
640 # that won't compile.
641
642 self.entry_point_parameters = {}
643
644 self.process_element( element )
645
646 return
647
648
649 def process_element(self, element):
650 name = element.get( "name" )
651 alias = element.get( "alias" )
652
653 if name in static_data.functions:
654 self.static_entry_points.append(name)
655
656 self.entry_points.append( name )
657
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 if api not in self.api_map or \
664 version_decimal < self.api_map[api]:
665 self.api_map[api] = version_decimal
666
667 exec_flavor = element.get('exec')
668 if exec_flavor:
669 self.exec_flavor = exec_flavor
670
671 deprecated = element.get('deprecated', 'none')
672 if deprecated != 'none':
673 self.deprecated = Decimal(deprecated)
674
675 if not is_attr_true(element, 'desktop', 'true'):
676 self.desktop = False
677
678 if self.has_no_error_variant or is_attr_true(element, 'no_error'):
679 self.has_no_error_variant = True
680 else:
681 self.has_no_error_variant = False
682
683 if alias:
684 true_name = alias
685 else:
686 true_name = name
687
688 # Only try to set the offset when a non-alias entry-point
689 # is being processed.
690
691 if name in static_data.offsets and static_data.offsets[name] <= static_data.MAX_OFFSETS:
692 self.offset = static_data.offsets[name]
693 elif name in static_data.offsets and static_data.offsets[name] > static_data.MAX_OFFSETS:
694 self.offset = static_data.offsets[name]
695 self.assign_offset = True
696 else:
697 if self.exec_flavor != "skip":
698 raise RuntimeError("Entry-point %s is missing offset in static_data.py. Add one at the bottom of the list." % (name))
699 self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions
700
701 if not self.name:
702 self.name = true_name
703 elif self.name != true_name:
704 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
705
706
707 # There are two possible cases. The first time an entry-point
708 # with data is seen, self.initialized will be 0. On that
709 # pass, we just fill in the data. The next time an
710 # entry-point with data is seen, self.initialized will be 1.
711 # On that pass we have to make that the new values match the
712 # valuse from the previous entry-point.
713
714 parameters = []
715 return_type = "void"
716 for child in element.getchildren():
717 if child.tag == "return":
718 return_type = child.get( "type", "void" )
719 elif child.tag == "param":
720 param = self.context.factory.create_parameter(child, self.context)
721 parameters.append( param )
722
723
724 if self.initialized:
725 if self.return_type != return_type:
726 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
727
728 if len(parameters) != len(self.parameters):
729 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
730
731 for j in range(0, len(parameters)):
732 p1 = parameters[j]
733 p2 = self.parameters[j]
734 if not p1.compatible( p2 ):
735 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))
736
737
738 if true_name == name or not self.initialized:
739 self.return_type = return_type
740 self.parameters = parameters
741
742 for param in self.parameters:
743 if param.is_image():
744 self.images.append( param )
745
746 if element.getchildren():
747 self.initialized = 1
748 self.entry_point_parameters[name] = parameters
749 else:
750 self.entry_point_parameters[name] = []
751
752 return
753
754 def filter_entry_points(self, entry_point_list):
755 """Filter out entry points not in entry_point_list."""
756 if not self.initialized:
757 raise RuntimeError('%s is not initialized yet' % self.name)
758
759 entry_points = []
760 for ent in self.entry_points:
761 if ent not in entry_point_list:
762 if ent in self.static_entry_points:
763 self.static_entry_points.remove(ent)
764 self.entry_point_parameters.pop(ent)
765 else:
766 entry_points.append(ent)
767
768 if not entry_points:
769 raise RuntimeError('%s has no entry point after filtering' % self.name)
770
771 self.entry_points = entry_points
772 if self.name not in entry_points:
773 # use the first remaining entry point
774 self.name = entry_points[0]
775 self.parameters = self.entry_point_parameters[entry_points[0]]
776
777 def get_images(self):
778 """Return potentially empty list of input images."""
779 return self.images
780
781
782 def parameterIterator(self, name = None):
783 if name is not None:
784 return iter(self.entry_point_parameters[name]);
785 else:
786 return iter(self.parameters);
787
788
789 def get_parameter_string(self, entrypoint = None):
790 if entrypoint:
791 params = self.entry_point_parameters[ entrypoint ]
792 else:
793 params = self.parameters
794
795 return create_parameter_string( params, 1 )
796
797 def get_called_parameter_string(self):
798 p_string = ""
799 comma = ""
800
801 for p in self.parameterIterator():
802 if p.is_padding:
803 continue
804 p_string = p_string + comma + p.name
805 comma = ", "
806
807 return p_string
808
809
810 def is_abi(self):
811 return (self.offset >= 0 and not self.assign_offset)
812
813 def is_static_entry_point(self, name):
814 return name in self.static_entry_points
815
816 def dispatch_name(self):
817 if self.name in self.static_entry_points:
818 return self.name
819 else:
820 return "_dispatch_stub_%u" % (self.offset)
821
822 def static_name(self, name):
823 if name in self.static_entry_points:
824 return name
825 else:
826 return "_dispatch_stub_%u" % (self.offset)
827
828 class gl_item_factory(object):
829 """Factory to create objects derived from gl_item."""
830
831 def create_function(self, element, context):
832 return gl_function(element, context)
833
834 def create_type(self, element, context, category):
835 return gl_type(element, context, category)
836
837 def create_enum(self, element, context, category):
838 return gl_enum(element, context, category)
839
840 def create_parameter(self, element, context):
841 return gl_parameter(element, context)
842
843 def create_api(self):
844 return gl_api(self)
845
846
847 class gl_api(object):
848 def __init__(self, factory):
849 self.functions_by_name = OrderedDict()
850 self.enums_by_name = {}
851 self.types_by_name = {}
852
853 self.category_dict = {}
854 self.categories = [{}, {}, {}, {}]
855
856 self.factory = factory
857
858 self.next_offset = 0
859
860 typeexpr.create_initial_types()
861 return
862
863 def parse_file(self, file_name):
864 doc = ET.parse( file_name )
865 self.process_element(file_name, doc)
866
867
868 def process_element(self, file_name, doc):
869 element = doc.getroot()
870 if element.tag == "OpenGLAPI":
871 self.process_OpenGLAPI(file_name, element)
872 return
873
874
875 def process_OpenGLAPI(self, file_name, element):
876 for child in element.getchildren():
877 if child.tag == "category":
878 self.process_category( child )
879 elif child.tag == "OpenGLAPI":
880 self.process_OpenGLAPI( file_name, child )
881 elif child.tag == '{http://www.w3.org/2001/XInclude}include':
882 href = child.get('href')
883 href = os.path.join(os.path.dirname(file_name), href)
884 self.parse_file(href)
885
886 return
887
888
889 def process_category(self, cat):
890 cat_name = cat.get( "name" )
891 cat_number = cat.get( "number" )
892
893 [cat_type, key] = classify_category(cat_name, cat_number)
894 self.categories[cat_type][key] = [cat_name, cat_number]
895
896 for child in cat.getchildren():
897 if child.tag == "function":
898 func_name = real_function_name( child )
899
900 temp_name = child.get( "name" )
901 self.category_dict[ temp_name ] = [cat_name, cat_number]
902
903 if func_name in self.functions_by_name:
904 func = self.functions_by_name[ func_name ]
905 func.process_element( child )
906 else:
907 func = self.factory.create_function( child, self )
908 self.functions_by_name[ func_name ] = func
909
910 if func.offset >= self.next_offset:
911 self.next_offset = func.offset + 1
912
913
914 elif child.tag == "enum":
915 enum = self.factory.create_enum( child, self, cat_name )
916 self.enums_by_name[ enum.name ] = enum
917 elif child.tag == "type":
918 t = self.factory.create_type( child, self, cat_name )
919 self.types_by_name[ "GL" + t.name ] = t
920
921 return
922
923
924 def functionIterateByCategory(self, cat = None):
925 """Iterate over functions by category.
926
927 If cat is None, all known functions are iterated in category
928 order. See classify_category for details of the ordering.
929 Within a category, functions are sorted by name. If cat is
930 not None, then only functions in that category are iterated.
931 """
932 lists = [{}, {}, {}, {}]
933
934 for func in self.functionIterateAll():
935 [cat_name, cat_number] = self.category_dict[func.name]
936
937 if (cat == None) or (cat == cat_name):
938 [func_cat_type, key] = classify_category(cat_name, cat_number)
939
940 if key not in lists[func_cat_type]:
941 lists[func_cat_type][key] = {}
942
943 lists[func_cat_type][key][func.name] = func
944
945
946 functions = []
947 for func_cat_type in range(0,4):
948 keys = sorted(lists[func_cat_type].keys())
949
950 for key in keys:
951 names = sorted(lists[func_cat_type][key].keys())
952
953 for name in names:
954 functions.append(lists[func_cat_type][key][name])
955
956 return iter(functions)
957
958
959 def functionIterateByOffset(self):
960 max_offset = -1
961 for func in self.functions_by_name.values():
962 if func.offset > max_offset:
963 max_offset = func.offset
964
965
966 temp = [None for i in range(0, max_offset + 1)]
967 for func in self.functions_by_name.values():
968 if func.offset != -1:
969 temp[ func.offset ] = func
970
971
972 list = []
973 for i in range(0, max_offset + 1):
974 if temp[i]:
975 list.append(temp[i])
976
977 return iter(list);
978
979
980 def functionIterateAll(self):
981 return self.functions_by_name.values()
982
983
984 def enumIterateByName(self):
985 keys = sorted(self.enums_by_name.keys())
986
987 list = []
988 for enum in keys:
989 list.append( self.enums_by_name[ enum ] )
990
991 return iter(list)
992
993
994 def categoryIterate(self):
995 """Iterate over categories.
996
997 Iterate over all known categories in the order specified by
998 classify_category. Each iterated value is a tuple of the
999 name and number (which may be None) of the category.
1000 """
1001
1002 list = []
1003 for cat_type in range(0,4):
1004 keys = sorted(self.categories[cat_type].keys())
1005
1006 for key in keys:
1007 list.append(self.categories[cat_type][key])
1008
1009 return iter(list)
1010
1011
1012 def get_category_for_name( self, name ):
1013 if name in self.category_dict:
1014 return self.category_dict[name]
1015 else:
1016 return ["<unknown category>", None]
1017
1018
1019 def typeIterate(self):
1020 return self.types_by_name.values()
1021
1022
1023 def find_type( self, type_name ):
1024 if type_name in self.types_by_name:
1025 return self.types_by_name[ type_name ].type_expr
1026 else:
1027 print("Unable to find base type matching \"%s\"." % (type_name))
1028 return None