elog-gen.py : order inherited errors

The elog-gen.py script should process errors such that the generated
code has definitions for parent errors before their child errors are
defined.

Change-Id: I035292731346bdba969f549c7e4033066814890f
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/tools/elog-gen.py b/tools/elog-gen.py
index d1acb79..a6fdb1f 100755
--- a/tools/elog-gen.py
+++ b/tools/elog-gen.py
@@ -18,10 +18,40 @@
 import os
 
 
+def order_inherited_errors(i_errors, i_parents):
+    # the ordered list of errors
+    errors = list()
+    has_inheritance = False
+    for error in i_errors:
+        if(i_parents[error] is not None):
+            has_inheritance = True
+            break
+
+    if(has_inheritance):
+        # Order the error codes list such that an error is never placed
+        # before it's parent. This way generated code can ensure parent
+        # definitions preceed child error definitions.
+        while(len(errors) < len(i_errors)):
+            for error in i_errors:
+                if(error in errors):
+                    # already ordererd
+                    continue
+                if((not i_parents[error]) or (i_parents[error] in errors)):
+                    # parent present, or has no parent, either way this error
+                    # can be added
+                    errors.append(error)
+    else:
+        # no inherited errors
+        errors = i_errors
+
+    return errors
+
+
 def check_error_inheritance(i_errors, i_parents):
-    for parent in i_parents:
-        if(parent and (parent not in i_errors)):
-            print parent + " inhertied from, but not defined"
+    for error in i_errors:
+        if(i_parents[error] and (i_parents[error] not in i_errors)):
+            print (error + " inherits " + i_parents[error] +
+                   " but the latter is not defined")
             return False
     return True
 
@@ -72,9 +102,9 @@
     errors = list()  # Main error codes
     error_msg = dict()  # Error msg that corresponds to error code
     error_lvl = dict()  # Error code log level (debug, info, error, ...)
-    meta = list()  # The meta data names associated (ERRNO, FILE_NAME, ...)
+    meta = dict()  # The meta data names associated (ERRNO, FILE_NAME, ...)
     meta_data = dict()  # The meta data info (type, format)
-    parents = list()
+    parents = dict()
 
     error_yamls = get_error_yaml_files(i_yaml_dir)
 
@@ -111,6 +141,8 @@
         print "Error - failed to validate error inheritance"
         exit(1)
 
+    errors = order_inherited_errors(errors, parents)
+
     # Load the mako template and call it with the required data
     yaml_dir = i_yaml_dir.strip("./")
     yaml_dir = yaml_dir.strip("../")
@@ -155,7 +187,7 @@
             # xyz.openbmc.Foo, we need Foo
             # Get 0th inherited error (current support - single inheritance)
             parent = i['inherits'][0].split(".").pop()
-        parents.append(parent)
+        parents[i['name']] = parent
         error_msg[i['name']] = i['description']
         error_lvl[i['name']] = match['level']
         tmp_meta = []
@@ -167,7 +199,7 @@
             meta_data[str_short]['str'] = j['str']
             meta_data[str_short]['str_short'] = str_short
             meta_data[str_short]['type'] = get_cpp_type(j['type'])
-        meta.append(tmp_meta)
+        meta[i['name']] = tmp_meta
 
     # Debug
     # for i in errors: