gpio-presence: Pass drivers in to application

With the optional --drivers argument, pass in the
path/device pairs to bind/unbind.  That string will be parsed,
and then passed into the Presence class.

Change-Id: I1ac0e005de673a679dcb45e93bcac35fddf24d01
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/presence/argument.cpp b/presence/argument.cpp
index 0fa94d0..a4b664e 100644
--- a/presence/argument.cpp
+++ b/presence/argument.cpp
@@ -29,13 +29,14 @@
 const std::string ArgumentParser::trueString = "true"s;
 const std::string ArgumentParser::emptyString = ""s;
 
-const char* ArgumentParser::optionStr = "p:k:n:i:?h";
+const char* ArgumentParser::optionStr = "p:k:n:i:d:?h";
 const option ArgumentParser::options[] =
 {
     { "path",      required_argument,  nullptr,   'p' },
     { "key",       required_argument,  nullptr,   'k' },
     { "name",      required_argument,  nullptr,   'n' },
     { "inventory", required_argument,  nullptr,   'i' },
+    { "drivers",   required_argument,  nullptr,   'd' },
     { "help",      no_argument,        nullptr,   'h' },
     { 0, 0, 0, 0},
 };
@@ -90,6 +91,12 @@
     std::cerr << "  --key=<key>             Input GPIO key number\n";
     std::cerr << "  --name=<name>           Pretty name of the inventory"
               " item\n";
+    std::cerr << "  --drivers=<drivers>     List of drivers to bind when card"
+              " is added and unbind when card is removed\n";
+    std::cerr << "                          Format is a space separated list"
+              " of path,device pairs.  For example:\n";
+    std::cerr << "                          "
+                 "/sys/bus/i2c/drivers/some-driver,3-0068\n";
     std::cerr << std::flush;
     exit(-1);
 }
diff --git a/presence/main.cpp b/presence/main.cpp
index 5808c34..0d25081 100644
--- a/presence/main.cpp
+++ b/presence/main.cpp
@@ -8,6 +8,52 @@
 using namespace phosphor::gpio;
 using namespace phosphor::gpio::presence;
 
+/**
+ * Pulls out the path,device pairs from the string
+ * passed in
+ *
+ * @param[in] driverString - space separated path,device pairs
+ * @param[out] drivers - vector of device,path tuples filled in
+ *                       from driverString
+ *
+ * @return int - 0 if successful, < 0 else
+ */
+static int getDrivers(const std::string driverString,
+                      std::vector<Driver>& drivers)
+{
+    std::istringstream stream{driverString};
+
+    while (true)
+    {
+        std::string entry;
+
+        //Extract each path,device pair
+        stream >> entry;
+
+        if (entry.empty())
+        {
+            break;
+        }
+
+        //Extract the path and device and save them
+        auto pos = entry.rfind(',');
+        if (pos != std::string::npos)
+        {
+            auto path = entry.substr(0, pos);
+            auto device = entry.substr(pos + 1);
+
+            drivers.emplace_back(device, path);
+        }
+        else
+        {
+            std::cerr << "Invalid path,device combination: " << entry << "\n";
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 int main(int argc, char* argv[])
 {
     auto options = ArgumentParser(argc, argv);
@@ -15,6 +61,7 @@
     auto inventory = options["inventory"];
     auto key = options["key"];
     auto path = options["path"];
+    auto drivers = options["drivers"];
     if (argc < 4)
     {
         std::cerr << "Too few arguments\n";
@@ -41,7 +88,14 @@
 
     std::vector<Driver> driverList;
 
-    //TODO: next commit, fill in driverList
+    //Driver list is optional
+    if (drivers != ArgumentParser::emptyString)
+    {
+        if (getDrivers(drivers, driverList) < 0)
+        {
+            options.usage(argv);
+        }
+    }
 
     auto bus = sdbusplus::bus::new_default();
     auto rc = 0;