registries: make registration dynamic

Rather than having to manually hook code for registries, add a small
registration function to the registry header and use this registration
results throughout the registry interactions.

Tested:

Confirmed registries have same behavior.

```
$ curl -s -k https://localhost:18080/redfish/v1/Registries/ | jq '.Members | map(."@odata.id")'
[
  "/redfish/v1/Registries/Base",
  "/redfish/v1/Registries/HeartbeatEvent",
  "/redfish/v1/Registries/OpenBMC",
  "/redfish/v1/Registries/ResourceEvent",
  "/redfish/v1/Registries/TaskEvent",
  "/redfish/v1/Registries/Telemetry"
]
```

```
$ curl -s -k https://localhost:18080/redfish/v1/Registries/TaskEvent/TaskEvent | jq ".Messages | keys"
[
  "TaskAborted",
  "TaskCancelled",
  "TaskCompletedOK",
  "TaskCompletedWarning",
  "TaskPaused",
  "TaskProgressChanged",
  "TaskRemoved",
  "TaskResumed",
  "TaskStarted"
]
```

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Iaa355420736a2587d9da4e995208d579443ca9b8
diff --git a/scripts/parse_registries.py b/scripts/parse_registries.py
index a557f65..d60e523 100755
--- a/scripts/parse_registries.py
+++ b/scripts/parse_registries.py
@@ -36,7 +36,9 @@
 
 // clang-format off
 
-namespace redfish::registries::{}
+namespace redfish::registries
+{{
+struct {}
 {{
 """
 
@@ -96,11 +98,12 @@
         with open(file, "w") as registry:
             version_split = json_dict["RegistryVersion"].split(".")
 
-            registry.write(REGISTRY_HEADER.format(namespace))
+            struct_name = to_pascal_case(namespace)
+            registry.write(REGISTRY_HEADER.format(struct_name))
             # Parse the Registry header info
             description = json_dict.get("Description", "")
             registry.write(
-                "const Header header = {{\n"
+                "static constexpr Header header = {{\n"
                 '    "{json_dict[@Redfish.Copyright]}",\n'
                 '    "{json_dict[@odata.type]}",\n'
                 "    {version_split[0]},\n"
@@ -112,10 +115,11 @@
                 '    "{json_dict[RegistryPrefix]}",\n'
                 '    "{json_dict[OwningEntity]}",\n'
                 "}};\n"
-                "constexpr const char* url =\n"
+                "\n"
+                "static constexpr const char* url =\n"
                 '    "{url}";\n'
                 "\n"
-                "constexpr std::array registry =\n"
+                "static constexpr std::array registry =\n"
                 "{{\n".format(
                     json_dict=json_dict,
                     url=url,
@@ -157,11 +161,21 @@
             for index, (messageId, message) in enumerate(messages_sorted):
                 messageId = messageId[0].lower() + messageId[1:]
                 registry.write("    {} = {},\n".format(messageId, index))
+            registry.write("};\n")
+            registry.write("}}; // struct {}\n".format(namespace))
+            registry.write("\n")
             registry.write(
-                "}};\n}} // namespace redfish::registries::{}\n".format(
-                    namespace
+                "[[gnu::constructor]] inline void register{}()\n".format(
+                    to_pascal_case(namespace)
                 )
             )
+            registry.write(
+                "{{ registerRegistry<{}>(); }}\n".format(
+                    to_pascal_case(namespace)
+                )
+            )
+            registry.write("\n")
+            registry.write("} // namespace redfish::registries\n")
 
 
 def get_privilege_string_from_list(
@@ -267,6 +281,7 @@
     registry_name: str,
     namespace_name: str,
 ) -> str:
+    struct_name = to_pascal_case(namespace_name)
     arg_nonstring_types = {
         "const boost::urls::url_view_base&": {
             "AccessDenied": [1],
@@ -351,7 +366,7 @@
                     outargs.append(f"arg{index}")
             argstring = ", ".join(outargs)
             arg_param = f"std::to_array{to_array_type}({{{argstring}}})"
-        out += f"    return getLog(redfish::registries::{namespace_name}::Index::{function_name}, {arg_param});"
+        out += f"    return getLog(redfish::registries::{struct_name}::Index::{function_name}, {arg_param});"
         out += "\n}\n\n"
     if registry_name == "Base":
         args.insert(0, "crow::Response& res")
@@ -422,6 +437,7 @@
 ) -> None:
     file, json_dict, namespace, url = registry_info
     base_filename = filename + "_messages"
+    struct_name = to_pascal_case(namespace_name)
 
     error_messages_hpp = os.path.join(
         SCRIPT_DIR, "..", "redfish-core", "include", f"{base_filename}.hpp"
@@ -541,20 +557,20 @@
         )
         out.write(
             """
-static nlohmann::json getLog(redfish::registries::{namespace_name}::Index name,
+static nlohmann::json getLog(redfish::registries::{struct_name}::Index name,
                              std::span<const std::string_view> args)
 {{
     size_t index = static_cast<size_t>(name);
-    if (index >= redfish::registries::{namespace_name}::registry.size())
+    if (index >= redfish::registries::{struct_name}::registry.size())
     {{
         return {{}};
     }}
-    return getLogFromRegistry(redfish::registries::{namespace_name}::header,
-                              redfish::registries::{namespace_name}::registry, index, args);
+    return getLogFromRegistry(redfish::registries::{struct_name}::header,
+                              redfish::registries::{struct_name}::registry, index, args);
 }}
 
 """.format(
-                namespace_name=namespace_name
+                struct_name=struct_name
             )
         )
         for entry_id, entry in messages.items():