Do tmpl substitutions using all properties on path

The current code would substitute the template arguments in the JSON
files, such as $bus, by only looking at the properties of the interface
that passed the probe.

This commit will try to find a substitution using the properties of all
of the interfaces on the same object path as the interface that passed
the probe.  It does this by reading and storing the properties of all
interfaces that came back from the existing GetSubTree call that finds
the paths of the probed interfaces, instead of just limiting it to the
interfaces that were probed.  The template substitutions are then tried
on the properties of all interfaces until one is successful.

This change is being made so that the interface used in the probe
doesn't also need to contain properties for the device details, such as
the bus property, that otherwise wouldn't belong there.  For example,
the com.ibm.ipzvpd.VINI interface, which models EEPROM contents, is
currently used in probes on IBM systems, and with this change the bus
and address properties can now be on a separate interface, such as the
recently proposed xyz.openbmc_project.Inventory.Decorator.I2CDevice.

Tested:  Tested that the $bus template can be successfully filled in
with the Bus property from an interface other than the one the probe was
matched on.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ic6f1539b38f6a4098f131d7f14cad6b6ddff041f
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 45c42e8..a097d06 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -149,6 +149,28 @@
         power::interface, power::property);
 }
 
+// Replaces the template character like the other version of this function,
+// but checks all properties on all interfaces provided to do the substitution
+// with.
+std::optional<std::string> templateCharReplace(
+    nlohmann::json::iterator& keyPair,
+    const boost::container::flat_map<
+        std::string, boost::container::flat_map<std::string, BasicVariantType>>&
+        allInterfaces,
+    const size_t foundDeviceIdx, const std::optional<std::string>& replaceStr)
+{
+    for (const auto& [interface, properties] : allInterfaces)
+    {
+        auto ret = templateCharReplace(keyPair, properties, foundDeviceIdx,
+                                       replaceStr);
+        if (ret)
+        {
+            return ret;
+        }
+    }
+    return std::nullopt;
+}
+
 // finds the template character (currently set to $) and replaces the value with
 // the field found in a dbus object i.e. $ADDRESS would get populated with the
 // ADDRESS field from a object on dbus