sdbus++: common: generate service_names

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I67c3ee58595a49d0104e9b1bc421052f9a405e01
diff --git a/tools/meson.build b/tools/meson.build
index bce5559..943e941 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -10,6 +10,7 @@
   'sdbusplus/path.py',
   'sdbusplus/property.py',
   'sdbusplus/renderer.py',
+  'sdbusplus/servicename.py',
   'sdbusplus/signal.py',
   'sdbusplus/templates/error.cpp.mako',
   'sdbusplus/templates/error.hpp.mako',
diff --git a/tools/sdbusplus/interface.py b/tools/sdbusplus/interface.py
index d6c2bac..933e51f 100644
--- a/tools/sdbusplus/interface.py
+++ b/tools/sdbusplus/interface.py
@@ -8,6 +8,7 @@
 from .path import Path
 from .property import Property
 from .renderer import Renderer
+from .servicename import ServiceName
 from .signal import Signal
 
 
@@ -30,6 +31,9 @@
         self.signals = [Signal(**s) for s in kwargs.pop("signals", [])]
         self.enums = [Enum(**e) for e in kwargs.pop("enumerations", [])]
         self.paths = [Path(**p) for p in kwargs.pop("paths", [])]
+        self.service_names = [
+            ServiceName(**s) for s in kwargs.pop("service_names", [])
+        ]
 
         super(Interface, self).__init__(**kwargs)
 
diff --git a/tools/sdbusplus/servicename.py b/tools/sdbusplus/servicename.py
new file mode 100644
index 0000000..f2690bf
--- /dev/null
+++ b/tools/sdbusplus/servicename.py
@@ -0,0 +1,37 @@
+import re
+import string
+
+from .namedelement import NamedElement
+
+""" Class for parsing 'service_name' definition eleemnts from an interface.
+"""
+
+
+class ServiceName(NamedElement):
+    def __init__(self, **kwargs):
+        if "default" in kwargs:
+            kwargs["name"] = "DefaultService"
+            self.value = kwargs.pop("default")
+        else:
+            self.value = kwargs.pop("value", False)
+
+        # Validate service name format.
+        if len(self.value) == 0:
+            raise ValueError("Invalid empty service-name")
+        for s in self.value.split("."):
+            if len(s) == 0:
+                raise ValueError(
+                    "Service names cannot have consecutive .:"
+                    f" {self.value} {s}"
+                )
+            if re.search("[^a-zA-Z0-9_]", s):
+                raise ValueError(
+                    f"Service name contains illegal characters: {self.value}"
+                )
+            if s[0] in string.digits:
+                raise ValueError(
+                    "Service name segments may not start with a number:"
+                    f" {self.value} {s}"
+                )
+
+        super(ServiceName, self).__init__(**kwargs)
diff --git a/tools/sdbusplus/templates/interface.common.hpp.mako b/tools/sdbusplus/templates/interface.common.hpp.mako
index 6331245..d64090d 100644
--- a/tools/sdbusplus/templates/interface.common.hpp.mako
+++ b/tools/sdbusplus/templates/interface.common.hpp.mako
@@ -44,6 +44,12 @@
     };
         % endif
     % endfor
+    % for s in interface.service_names:
+        % if s.description:
+    /** ${s.description.strip()} */
+        % endif
+    static constexpr auto ${s.snake_case} = "${s.value}";
+    % endfor
 
     % for e in interface.enums:
     /** @brief Convert a string to an appropriate enum value.