mesa|mapi: replace _mesa_[v]snprintf with [v]snprintf
[mesa.git] / src / mapi / glapi / gen / gl_enums.py
index f45782df85f168d83898af2cacd37bead386733f..255b1adfbeddb6ad813205f8eb36e4dd94220eac 100644 (file)
@@ -1,8 +1,7 @@
-#!/usr/bin/python2
-# -*- Mode: Python; py-indent-offset: 8 -*-
 
-# (C) Copyright Zack Rusin 2005
-# All Rights Reserved.
+# (C) Copyright Zack Rusin 2005. All Rights Reserved.
+# Copyright (C) 2015 Intel Corporation
+# Copyright (C) 2015 Broadcom Corporation
 # 
 # Permission is hereby granted, free of charge, to any person obtaining a
 # copy of this software and associated documentation files (the "Software"),
 # Authors:
 #    Zack Rusin <zack@kde.org>
 
+from __future__ import print_function
+
+import argparse
+
 import license
 import gl_XML
+import xml.etree.ElementTree as ET
 import sys, getopt
+import re
 
 class PrintGlEnums(gl_XML.gl_print_base):
 
@@ -38,24 +43,28 @@ class PrintGlEnums(gl_XML.gl_print_base):
         self.name = "gl_enums.py (from Mesa)"
         self.license = license.bsd_license_template % ( \
 """Copyright (C) 1999-2005 Brian Paul All Rights Reserved.""", "BRIAN PAUL")
+        # Mapping from enum value to (name, priority) tuples.
         self.enum_table = {}
+        # Mapping from enum name to value
+        self.string_to_int = {}
 
 
     def printRealHeader(self):
-        print '#include "main/glheader.h"'
-        print '#include "main/enums.h"'
-        print '#include "main/imports.h"'
-        print '#include "main/mtypes.h"'
-        print ''
-        print 'typedef struct PACKED {'
-        print '   uint16_t offset;'
-        print '   int n;'
-        print '} enum_elt;'
-        print ''
+        print('#include <stdio.h>')
+        print('#include "main/glheader.h"')
+        print('#include "main/enums.h"')
+        print('#include "util/imports.h"')
+        print('#include "main/mtypes.h"')
+        print('')
+        print('typedef struct PACKED {')
+        print('   uint32_t offset;')
+        print('   int n;')
+        print('} enum_elt;')
+        print('')
         return
 
     def print_code(self):
-        print """
+        print("""
 typedef int (*cfunc)(const void *, const void *);
 
 /**
@@ -76,12 +85,15 @@ static int compar_nr( const int *a, enum_elt *b )
 
 static char token_tmp[20];
 
-const char *_mesa_lookup_enum_by_nr( int nr )
+/**
+ * This function always returns a string. If the number is a valid enum, it
+ * returns the enum name. Otherwise, it returns a numeric string.
+ */
+const char *
+_mesa_enum_to_string(int nr)
 {
    enum_elt *elt;
 
-   STATIC_ASSERT(sizeof(enum_string_table) < (1 << 16));
-
    elt = bsearch(& nr, enum_string_table_offsets,
                  ARRAY_SIZE(enum_string_table_offsets),
                  sizeof(enum_string_table_offsets[0]),
@@ -92,7 +104,7 @@ const char *_mesa_lookup_enum_by_nr( int nr )
    }
    else {
       /* this is not re-entrant safe, no big deal here */
-      _mesa_snprintf(token_tmp, sizeof(token_tmp) - 1, "0x%x", nr);
+      snprintf(token_tmp, sizeof(token_tmp) - 1, "0x%x", nr);
       token_tmp[sizeof(token_tmp) - 1] = '\\0';
       return token_tmp;
    }
@@ -116,6 +128,7 @@ static const char *prim_names[PRIM_MAX+3] = {
    "GL_LINE_STRIP_ADJACENCY",
    "GL_TRIANGLES_ADJACENCY",
    "GL_TRIANGLE_STRIP_ADJACENCY",
+   "GL_PATCHES",
    "outside begin/end",
    "unknown state"
 };
@@ -134,88 +147,148 @@ _mesa_lookup_prim_by_nr(GLuint nr)
 }
 
 
-"""
+""")
         return
 
 
-    def printBody(self, api_list):
-        self.enum_table = {}
-        for api in api_list:
-            self.process_enums( api )
-
-        enum_table = []
-
-        for enum in sorted(self.enum_table.keys()):
-            low_pri = 9
-            best_name = ''
-            for [name, pri] in self.enum_table[ enum ]:
-                if pri < low_pri:
-                    low_pri = pri
-                    best_name = name
-
-            enum_table.append((enum, best_name))
+    def printBody(self, xml):
+        self.process_enums(xml)
 
+        sorted_enum_values = sorted(self.enum_table.keys())
         string_offsets = {}
         i = 0;
-        print '#if defined(__GNUC__)'
-        print '# define LONGSTRING __extension__'
-        print '#else'
-        print '# define LONGSTRING'
-        print '#endif'
-        print ''
-        print 'LONGSTRING static const char enum_string_table[] = '
-        for enum, name in enum_table:
-            print '   "%s\\0"' % (name)
+        print('#if defined(__GNUC__)')
+        print('# define LONGSTRING __extension__')
+        print('#else')
+        print('# define LONGSTRING')
+        print('#endif')
+        print('')
+        print('LONGSTRING static const char enum_string_table[] = {')
+        # We express the very long concatenation of enum strings as an array
+        # of characters rather than as a string literal to work-around MSVC's
+        # 65535 character limit.
+        for enum in sorted_enum_values:
+            (name, pri) = self.enum_table[enum]
+            print("  ", end=' ')
+            for ch in name:
+                print("'%c'," % ch, end=' ')
+            print("'\\0',")
+
             string_offsets[ enum ] = i
             i += len(name) + 1
 
-        print '   ;'
-        print ''
+        print('};')
+        print('')
 
 
-        print 'static const enum_elt enum_string_table_offsets[%u] =' % (len(enum_table))
-        print '{'
-        for enum, name in enum_table:
-            print '   { %5u, 0x%08X }, /* %s */' % (string_offsets[enum], enum, name)
-        print '};'
-        print ''
+        print('static const enum_elt enum_string_table_offsets[%u] =' % (len(self.enum_table)))
+        print('{')
+        for enum in sorted_enum_values:
+            (name, pri) = self.enum_table[enum]
+            print('   { %5u, 0x%08X }, /* %s */' % (string_offsets[enum], enum, name))
+        print('};')
+        print('')
 
         self.print_code()
         return
 
+    def add_enum_provider(self, name, priority):
+        value = self.string_to_int[name]
+
+        # We don't want the weird GL_SKIP_COMPONENTS1_NV enums.
+        if value < 0:
+            return
+        # We don't want the 64-bit GL_TIMEOUT_IGNORED "enums"
+        if value > 0xffffffff:
+            return
+
+        # We don't want bitfields in the enum-to-string table --
+        # individual bits have so many names, it's pointless.  Note
+        # that we check for power-of-two, since some getters have
+        # "_BITS" in their name, but none have a power-of-two enum
+        # number.
+        if not (value & (value - 1)) and '_BIT' in name:
+            return
+
+        # Also drop the GL_*_ATTRIB_BITS bitmasks.
+        if value == 0xffffffff:
+                return
+
+        if value in self.enum_table:
+            (n, p) = self.enum_table[value]
+            if priority < p:
+                self.enum_table[value] = (name, priority)
+        else:
+            self.enum_table[value] = (name, priority)
+
+    def process_extension(self, extension):
+        if extension.get('name').startswith('GL_ARB_'):
+            extension_prio = 400
+        elif extension.get('name').startswith('GL_EXT_'):
+            extension_prio = 600
+        else:
+            extension_prio = 800
+
+        for enum in extension.findall('require/enum'):
+            self.add_enum_provider(enum.get('name'), extension_prio)
+
+    def process_enums(self, xml):
+        # First, process the XML entries that define the hex values
+        # for all of the enum names.
+        for enum in xml.findall('enums/enum'):
+            name = enum.get('name')
+            value = int(enum.get('value'), base=16)
+
+            # If the same name ever maps to multiple values, that can
+            # confuse us.  GL_ACTIVE_PROGRAM_EXT is OK to lose because
+            # we choose GL_ACTIVE PROGRAM instead.
+            if name in self.string_to_int and name != "GL_ACTIVE_PROGRAM_EXT":
+                print("#error Renumbering {0} from {1} to {2}".format(name, self.string_to_int[name], value))
+
+            self.string_to_int[name] = value
+
+        # Now, process all of the API versions and extensions that
+        # provide enums, so we can decide what name to call any hex
+        # value.
+        for feature in xml.findall('feature'):
+            feature_name = feature.get('name')
+
+            # When an enum gets renamed in a newer version (generally
+            # because of some generalization of the functionality),
+            # prefer the newer name.  Also, prefer desktop GL names to
+            # ES.
+            m = re.match('GL_VERSION_([0-9])_([0-9])', feature_name)
+            if m:
+                feature_prio = 100 - int(m.group(1) + m.group(2))
+            else:
+                m = re.match('GL_ES_VERSION_([0-9])_([0-9])', feature_name)
+                if m:
+                    feature_prio = 200 - int(m.group(1) + m.group(2))
+                else:
+                    feature_prio = 200
+
+            for enum in feature.findall('require/enum'):
+                self.add_enum_provider(enum.get('name'), feature_prio)
+
+        for extension in xml.findall('extensions/extension'):
+            self.process_extension(extension)
+
+
+def _parser():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-f', '--input_file',
+                        required=True,
+                        help="Choose an xml file to parse.")
+    return parser.parse_args()
+
+
+def main():
+    args = _parser()
+    xml = ET.parse(args.input_file)
 
-    def process_enums(self, api):
-        for obj in api.enumIterateByName():
-            if obj.value not in self.enum_table:
-                self.enum_table[ obj.value ] = []
-
-
-            enum = self.enum_table[ obj.value ]
-            name = "GL_" + obj.name
-            priority = obj.priority()
-            already_in = False;
-            for n, p in enum:
-                if n == name:
-                    already_in = True
-            if not already_in:
-                enum.append( [name, priority] )
-
+    printer = PrintGlEnums()
+    printer.Print(xml)
 
-def show_usage():
-    print "Usage: %s [-f input_file_name]" % sys.argv[0]
-    sys.exit(1)
 
 if __name__ == '__main__':
-    try:
-        (args, trail) = getopt.getopt(sys.argv[1:], "f:")
-    except Exception,e:
-        show_usage()
-
-    api_list = []
-    for (arg,val) in args:
-        if arg == "-f":
-            api = gl_XML.parse_GL_API( val )
-            api_list.append(api);
-
-    printer = PrintGlEnums()
-    printer.Print( api_list )
+    main()