app: Change argument parsing and error handling

This modifies the way the application parses arguments and performs
error handling when invalid options are passed. There is no functional
change to the application aside from the error message that is printed
when incorrect options are passed.

If you do not pass a VPD file:

$ openpower-read-vpd --fru BMC --object /system/chassis/motherboard/bmc
VPD file required (--vpd=<filename>)

If you pass a VPD but no --object or --fru options:

$ openpower-read-vpd --vpd vpdfile
No task to perform

  Update FRU: --fru <type> --object <path>
              --fru <type1>,<type2> --object <path1>,<path2>

Signed-off-by: Joel Stanley <joel@jms.id.au>
Change-Id: I4d41b55d37516bbc0557127fcb441f6fd29698bf
diff --git a/app.cpp b/app.cpp
index 96c9ee4..e38936d 100644
--- a/app.cpp
+++ b/app.cpp
@@ -17,23 +17,37 @@
     try
     {
         using namespace openpower::vpd;
-
         args::Args arguments = args::parse(argc, argv);
 
-        // We need vpd file, FRU type and object path
-        if ((arguments.end() != arguments.find("vpd")) &&
-            (arguments.end() != arguments.find("fru")) &&
-            (arguments.end() != arguments.find("object")))
+        bool haveVpd = arguments.count("vpd");
+        bool doFru = arguments.count("fru") && arguments.count("object");
+
+        if (!haveVpd)
         {
-            // Read binary VPD file
-            auto file = arguments.at("vpd")[0];
-            std::ifstream vpdFile(file, std::ios::binary);
-            Binary vpd((std::istreambuf_iterator<char>(vpdFile)),
-                       std::istreambuf_iterator<char>());
+            std::cerr << "VPD file required (--vpd=<filename>)\n";
+            return -1;
+        }
 
-            // Parse vpd
-            auto vpdStore = parse(std::move(vpd));
+        if (!doFru)
+        {
+            std::cerr << "No task to perform\n\n";
+            std::cerr << "  Update FRU: --fru <type> --object <path>\n";
+            std::cerr << "              --fru <t1>,<t2> --object <p1>,<p2>\n\n";
+            return -1;
+        }
 
+        // Read binary VPD file
+        auto file = arguments.at("vpd")[0];
+        std::ifstream vpdFile(file, std::ios::binary);
+        Binary vpd((std::istreambuf_iterator<char>(vpdFile)),
+                   std::istreambuf_iterator<char>());
+
+        // Parse VPD
+        auto vpdStore = parse(std::move(vpd));
+
+        // Set FRU based on FRU type and object path
+        if (doFru)
+        {
             using argList = std::vector<std::string>;
             argList frus = std::move(arguments.at("fru"));
             argList objects = std::move(arguments.at("object"));
@@ -53,11 +67,6 @@
                 }
             }
         }
-        else
-        {
-            std::cerr << "Need VPD file, FRU type and object path\n";
-            rc = -1;
-        }
     }
     catch (std::exception& e)
     {