scripts:Update database file w/ api column

This adds two columns to the error database file.
The first is the Vulkan api call that the error is related to.
The second is a free txt field for "notes" as the last column.

The spec.py script in this commit is a slightly hacky version that
was used to generate the updated database file. In follow-on commit
I'll update the spec.py file to correctly handle the updated database
file format.
diff --git a/layers/spec.py b/layers/spec.py
index ec266c5..b30869c 100644
--- a/layers/spec.py
+++ b/layers/spec.py
@@ -25,7 +25,10 @@
 #
 # TODO:
 #  1. Improve string matching to add more automation for figuring out which messages are changed vs. completely new
-#
+# Temp hack path:
+#  1. Read in spec w/ API info
+#  2. Read in database file
+#  3. Write out updated DB file w/ API/Notes columns
 #
 #############################
 
@@ -63,7 +66,7 @@
 class Specification:
     def __init__(self):
         self.tree   = None
-        self.val_error_dict = {} # string for enum is key that references text for output message
+        self.val_error_dict = {} # string for enum is key that references 'error_msg' and 'api'
         self.error_db_dict = {} # dict of previous error values read in from database file
         self.delimiter = '~^~' # delimiter for db file
         self.copyright = """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
@@ -119,6 +122,7 @@
         #print "ROOT: %s" % self.root
         prev_heading = '' # Last seen section heading or sub-heading
         prev_link = '' # Last seen link id within the spec
+        api_function = '' # API call that a check appears under
         error_strings = set() # Flag any exact duplicate error strings and skip them
         for tag in self.root.iter(): # iterate down tree
             # Grab most recent section heading and link
@@ -136,6 +140,13 @@
                 if tag.get('id') != None:
                     prev_link = tag.get('id')
                     #print "Updated prev link to %s" % (prev_link)
+            elif tag.tag == '{http://www.w3.org/1999/xhtml}pre' and tag.get('class') == 'programlisting':
+                # Check and see if this is API function
+                code_text = "".join(tag.itertext()).replace('\n', '')
+                code_text_list = code_text.split()
+                if len(code_text_list) > 1 and code_text_list[1].startswith('vk'):
+                    api_function = code_text_list[1].strip('(')
+                    print "Found API function: %s" % (api_function)
             elif tag.tag == '{http://www.w3.org/1999/xhtml}div' and tag.get('class') == 'sidebar':
                 # parse down sidebar to check for valid usage cases
                 valid_usage = False
@@ -152,7 +163,9 @@
                             error_strings.add(error_msg_str)
                             enum_str = "%s%05d" % (validation_error_enum_name, unique_enum_id)
                             # TODO : '\' chars in spec error messages are most likely bad spec txt that needs to be updated
-                            self.val_error_dict[enum_str] = error_msg_str.encode("ascii", "ignore").replace("\\", "/")
+                            self.val_error_dict[enum_str] = {}
+                            self.val_error_dict[enum_str]['error_msg'] = error_msg_str.encode("ascii", "ignore").replace("\\", "/")
+                            self.val_error_dict[enum_str]['api'] = api_function
                             unique_enum_id = unique_enum_id + 1
         #print "Validation Error Dict has a total of %d unique errors and contents are:\n%s" % (unique_enum_id, self.val_error_dict)
     def genHeader(self, header_file):
@@ -171,10 +184,10 @@
         for enum in sorted(self.val_error_dict):
             #print "Header enum is %s" % (enum)
             enum_decl.append('    %s = %d,' % (enum, int(enum.split('_')[-1])))
-            error_string_map.append('    {%s, "%s"},' % (enum, self.val_error_dict[enum]))
+            error_string_map.append('    {%s, "%s"},' % (enum, self.val_error_dict[enum]['error_msg']))
         enum_decl.append('    %sMAX_ENUM = %d,' % (validation_error_enum_name, int(enum.split('_')[-1]) + 1))
         enum_decl.append('};')
-        error_string_map.append('};')
+        error_string_map.append('};\n')
         file_contents.extend(enum_decl)
         file_contents.append('\n// Mapping from unique validation error enum to the corresponding error message')
         file_contents.append('// The error message should be appended to the end of a custom error message that is passed')
@@ -189,7 +202,7 @@
         str_count_dict = {}
         unique_id_count = 0
         for enum in self.val_error_dict:
-            err_str = self.val_error_dict[enum]
+            err_str = self.val_error_dict[enum]['error_msg']
             if err_str in str_count_dict:
                 print "Found repeat error string"
                 str_count_dict[err_str] = str_count_dict[err_str] + 1
@@ -210,11 +223,13 @@
         db_lines.append("# This is a database file with validation error check information")
         db_lines.append("# Comments are denoted with '#' char")
         db_lines.append("# The format of the lines is:")
-        db_lines.append("# <error_enum>%s<check_implemented>%s<testname>%s<errormsg>" % (self.delimiter, self.delimiter, self.delimiter))
+        db_lines.append("# <error_enum>%s<check_implemented>%s<testname>%s<api>%s<errormsg>%s<note>" % (self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter))
         db_lines.append("# error_enum: Unique error enum for this check of format %s<uniqueid>" % validation_error_enum_name)
         db_lines.append("# check_implemented: 'Y' if check has been implemented in layers, 'U' for unknown, or 'N' for not implemented")
         db_lines.append("# testname: Name of validation test for this check, 'Unknown' for unknown, or 'None' if not implmented")
+        db_lines.append("# api: Vulkan API function that this check is related to")
         db_lines.append("# errormsg: The unique error message for this check that includes spec language and link")
+        db_lines.append("# note: Free txt field with any custom notes related to the check in question")
         for enum in sorted(self.val_error_dict):
             # Default to unknown if check or test are implemented, then update below if appropriate
             implemented = 'U'
@@ -225,10 +240,11 @@
                 testname = self.error_db_dict[enum]['testname']
             #print "delimiter: %s, id: %s, str: %s" % (self.delimiter, enum, self.val_error_dict[enum])
             # No existing entry so default to N for implemented and None for testname
-            db_lines.append("%s%s%s%s%s%s%s" % (enum, self.delimiter, implemented, self.delimiter, testname, self.delimiter, self.val_error_dict[enum]))
+            db_lines.append("%s%s%s%s%s%s%s%s%s%s" % (enum, self.delimiter, implemented, self.delimiter, testname, self.delimiter, self.val_error_dict[enum]['api'], self.delimiter, self.val_error_dict[enum]['error_msg'], self.delimiter))
         print "Generating database file %s" % (db_file)
         with open(db_file, "w") as outfile:
             outfile.write("\n".join(db_lines))
+            outfile.write("\n")
     def readDB(self, db_file):
         """Read a db file into a dict, format of each line is <enum><implemented Y|N?><testname><errormsg>"""
         db_dict = {} # This is a simple db of just enum->errormsg, the same as is created from spec
@@ -262,72 +278,78 @@
     # 4. If new id in original, but error strings don't match then:
     #   4a. If error string has exact match in original, update new to use original
     #   4b. If error string not in original, may be updated error message, manually address
-    def compareDB(self, orig_db_dict, max_id):
+    def compareDB(self, orig_error_msg_dict, max_id):
         """Compare orig database dict to new dict, report out findings, and return potential new dict for parsed spec"""
         # First create reverse dicts of err_strings to IDs
         next_id = max_id + 1
         orig_err_to_id_dict = {}
         # Create an updated dict in-place that will be assigned to self.val_error_dict when done
         updated_val_error_dict = {}
-        for enum in orig_db_dict:
-            orig_err_to_id_dict[orig_db_dict[enum]] = enum
+        for enum in orig_error_msg_dict:
+            orig_err_to_id_dict[orig_error_msg_dict[enum]] = enum
         new_err_to_id_dict = {}
         for enum in self.val_error_dict:
-            new_err_to_id_dict[self.val_error_dict[enum]] = enum
+            new_err_to_id_dict[self.val_error_dict[enum]['error_msg']] = enum
         ids_parsed = 0
+        # Values to be used for the update dict
+        update_enum = ''
+        update_msg = ''
+        update_api = ''
         # Now parse through new dict and figure out what to do with non-matching things
         for enum in sorted(self.val_error_dict):
             ids_parsed = ids_parsed + 1
             enum_list = enum.split('_') # grab sections of enum for use below
+            # Default update values to be the same
+            update_enum = enum
+            update_msg = self.val_error_dict[enum]['error_msg']
+            update_api = self.val_error_dict[enum]['api']
             # Any user-forced remap takes precendence
             if enum_list[-1] in remap_dict:
                 enum_list[-1] = remap_dict[enum_list[-1]]
                 new_enum = "_".join(enum_list)
                 print "NOTE: Using user-supplied remap to force %s to be %s" % (enum, new_enum)
-                updated_val_error_dict[new_enum] = self.val_error_dict[enum]
-            elif enum in orig_db_dict:
-                if self.val_error_dict[enum] == orig_db_dict[enum]:
+                update_enum = new_enum
+            elif enum in orig_error_msg_dict:
+                if self.val_error_dict[enum]['error_msg'] == orig_error_msg_dict[enum]:
                     print "Exact match for enum %s" % (enum)
                     # Nothing to see here
                     if enum in updated_val_error_dict:
                         print "ERROR: About to overwrite entry for %s" % (enum)
-                    updated_val_error_dict[enum] = self.val_error_dict[enum]
-                elif self.val_error_dict[enum] in orig_err_to_id_dict:
+                elif self.val_error_dict[enum]['error_msg'] in orig_err_to_id_dict:
                     # Same value w/ different error id, need to anchor to original id
-                    print "Need to switch new id %s to original id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]])
+                    print "Need to switch new id %s to original id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']])
                     # Update id at end of new enum to be same id from original enum
-                    enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]].split('_')[-1]
+                    enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']].split('_')[-1]
                     new_enum = "_".join(enum_list)
                     if new_enum in updated_val_error_dict:
                         print "ERROR: About to overwrite entry for %s" % (new_enum)
-                    updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+                    update_enum = new_enum
                 else:
                     # No error match:
                     #  First check if only link has changed, in which case keep ID but update message
-                    orig_msg_list = orig_db_dict[enum].split('(', 1)
-                    new_msg_list = self.val_error_dict[enum].split('(', 1)
+                    orig_msg_list = orig_error_msg_dict[enum].split('(', 1)
+                    new_msg_list = self.val_error_dict[enum]['error_msg'].split('(', 1)
                     if orig_msg_list[0] == new_msg_list[0]: # Msg is same bug link has changed, keep enum & update msg
                         print "NOTE: Found that only spec link changed for %s so keeping same id w/ new link" % (enum)
-                        updated_val_error_dict[enum] = self.val_error_dict[enum]
                     #  This seems to be a new error so need to pick it up from end of original unique ids & flag for review
                     else:
                         enum_list[-1] = "%05d" % (next_id)
                         new_enum = "_".join(enum_list)
                         next_id = next_id + 1
                         print "MANUALLY VERIFY: Updated new enum %s to be unique %s. Make sure new error msg is actually unique and not just changed" % (enum, new_enum)
-                        print "   New error string: %s" % (self.val_error_dict[enum])
+                        print "   New error string: %s" % (self.val_error_dict[enum]['error_msg'])
                         if new_enum in updated_val_error_dict:
                             print "ERROR: About to overwrite entry for %s" % (new_enum)
-                        updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+                        update_enum = new_enum
             else: # new enum is not in orig db
-                if self.val_error_dict[enum] in orig_err_to_id_dict:
-                    print "New enum %s not in orig dict, but exact error message matches original unique id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]])
+                if self.val_error_dict[enum]['error_msg'] in orig_err_to_id_dict:
+                    print "New enum %s not in orig dict, but exact error message matches original unique id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']])
                     # Update new unique_id to use original
-                    enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]].split('_')[-1]
+                    enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']].split('_')[-1]
                     new_enum = "_".join(enum_list)
                     if new_enum in updated_val_error_dict:
                         print "ERROR: About to overwrite entry for %s" % (new_enum)
-                    updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+                    update_enum = new_enum
                 else:
                     enum_list[-1] = "%05d" % (next_id)
                     new_enum = "_".join(enum_list)
@@ -335,7 +357,10 @@
                     print "Completely new id and error code, update new id from %s to unique %s" % (enum, new_enum)
                     if new_enum in updated_val_error_dict:
                         print "ERROR: About to overwrite entry for %s" % (new_enum)
-                    updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+                    update_enum = new_enum
+            updated_val_error_dict[update_enum] = {}
+            updated_val_error_dict[update_enum]['error_msg'] = update_msg
+            updated_val_error_dict[update_enum]['api'] = update_api
         # Assign parsed dict to be the udpated dict based on db compare
         print "In compareDB parsed %d entries" % (ids_parsed)
         return updated_val_error_dict
@@ -417,9 +442,9 @@
     spec.analyze()
     if (spec_compare):
         # Read in old spec info from db file
-        (orig_db_dict, max_id) = spec.readDB(db_filename)
+        (orig_err_msg_dict, max_id) = spec.readDB(db_filename)
         # New spec data should already be read into self.val_error_dict
-        updated_dict = spec.compareDB(orig_db_dict, max_id)
+        updated_dict = spec.compareDB(orig_err_msg_dict, max_id)
         update_valid = spec.validateUpdateDict(updated_dict)
         if update_valid:
             spec.updateDict(updated_dict)