Add argument parser

Add command-line argument parser for the main application. This is built
over the GNU getopt.

Change-Id: Ida6ea6894d4832fd631d8bd1e2b6f4a3fb496023
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/args.cpp b/args.cpp
new file mode 100644
index 0000000..8ec90dd
--- /dev/null
+++ b/args.cpp
@@ -0,0 +1,89 @@
+#include <getopt.h>
+#include <string>
+#include <vector>
+#include <utility>
+#include <iostream>
+#include <sstream>
+#include "args.hpp"
+
+namespace openpower
+{
+namespace vpd
+{
+namespace args
+{
+
+static constexpr auto shortForm = "v:f:o:h";
+static const option longForm[] =
+{
+    { "vpd",     required_argument,  nullptr,  'v' },
+    { "fru",     required_argument,  nullptr,  'f' },
+    { "object",  required_argument,  nullptr,  'o' },
+    { "help",    no_argument,        nullptr,  'h' },
+    { 0, 0, 0, 0},
+};
+
+void usage(char** argv)
+{
+    std::cerr << "\nUsage: " << argv[0] << " args\n";
+    std::cerr << "args:\n";
+    std::cerr << "--vpd=<vpd file> pathname of file containing vpd,";
+    std::cerr << " for eg an eeprom file\n";
+    std::cerr << "--fru=<FRU type>, supported types:\n";
+    std::cerr << "\t" << "bmc\n";
+    std::cerr << "\t" << "ethernet\n";
+    std::cerr << "Specify multiple FRU types via comma-separated list\n";
+    std::cerr << "--object=<FRU object path> for eg,";
+    std::cerr << " chassis/bmc0/planar\n";
+    std::cerr << "Specify multiple object paths via comma-separated list, "
+              "ordered as the FRU types\n";
+    std::cerr << "--help display usage\n";
+}
+
+Args parse(int argc, char** argv)
+{
+    Args args;
+    int option = 0;
+    if (1 == argc)
+    {
+        usage(argv);
+    }
+    while (-1 !=
+           (option = getopt_long(argc, argv, shortForm, longForm, nullptr)))
+    {
+        if (('h' == option) || ('?' == option))
+        {
+            usage(argv);
+        }
+        else
+        {
+            auto which = &longForm[0];
+            // Figure out which option
+            while ((which->val != option) && (which->val != 0))
+            {
+                ++which;
+            }
+            // If option needs an argument, note the argument value
+            if ((no_argument != which->has_arg) && optarg)
+            {
+                using argList = std::vector<std::string>;
+                argList values;
+                // There could be a comma-separated list
+                std::string opts(optarg);
+                std::istringstream stream(std::move(opts));
+                std::string input {};
+                while (std::getline(stream, input, ','))
+                {
+                    values.push_back(std::move(input));
+                }
+                args.emplace(which->name, std::move(values));
+            }
+        }
+    }
+
+    return args;
+}
+
+} // namespace args
+} // namespace vpd
+} // namespace openpower
diff --git a/args.hpp b/args.hpp
new file mode 100644
index 0000000..ee82986
--- /dev/null
+++ b/args.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+namespace openpower
+{
+namespace vpd
+{
+namespace args
+{
+
+using Args = std::unordered_map<std::string,
+      std::vector<std::string>>;
+
+/** @brief Command-line argument parser for openpower-read-vpd
+ *
+ *  @param[in] argc - argument count
+ *  @param[in] argv - argument array
+ *
+ *  @returns map of argument:value
+ */
+Args parse(int argc, char** argv);
+
+/** @brief Display usage of openpower-vpd-read
+ *
+ *  @param[in] argv - argument array
+ */
+void usage(char** argv);
+
+} // namespace args
+} // namespace vpd
+} // namespace openpower