From 2426b57daf25a48fcedeb7cb762e0a368a72802d Mon Sep 17 00:00:00 2001
From: Clinton Stimpson <clinton@elemtech.com>
Date: Sat, 7 Dec 2013 14:28:08 -0700
Subject: [PATCH] Encoding: Add support for program arguments argc/argv.

Change-Id: Ifda279df9a68872cf16e580274dff534f6cfd855
---
 Encoding.hxx.in  | 31 ++++++++++++++++
 EncodingCXX.cxx  | 93 ++++++++++++++++++++++++++++++++++++++++++++++++
 testEncoding.cxx | 31 ++++++++++++++++
 3 files changed, 155 insertions(+)

diff --git a/Encoding.hxx.in b/Encoding.hxx.in
index 60a4a8e..aba4175 100644
--- a/Encoding.hxx.in
+++ b/Encoding.hxx.in
@@ -14,6 +14,7 @@
 
 #include <@KWSYS_NAMESPACE@/Configure.hxx>
 #include <@KWSYS_NAMESPACE@/stl/string>
+#include <@KWSYS_NAMESPACE@/stl/vector>
 
 /* Define these macros temporarily to keep the code readable.  */
 #if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
@@ -25,6 +26,36 @@ namespace @KWSYS_NAMESPACE@
 class @KWSYS_NAMESPACE@_EXPORT Encoding
 {
 public:
+
+  // Container class for argc/argv.
+  class CommandLineArguments
+  {
+    public:
+      // On Windows, get the program command line arguments
+      // in this Encoding module's 8 bit encoding.
+      // On other platforms the given argc/argv is used, and
+      // to be consistent, should be the argc/argv from main().
+      static CommandLineArguments Main(int argc, char const* const* argv);
+
+      // Construct CommandLineArguments with the given
+      // argc/argv.  It is assumed that the string is already
+      // in the encoding used by this module.
+      CommandLineArguments(int argc, char const* const* argv);
+
+      // Construct CommandLineArguments with the given
+      // argc and wide argv.  This is useful if wmain() is used.
+      CommandLineArguments(int argc, wchar_t const* const* argv);
+      ~CommandLineArguments();
+      CommandLineArguments(const CommandLineArguments&);
+      CommandLineArguments& operator=(const CommandLineArguments&);
+
+      int argc() const;
+      char const* const* argv() const;
+
+    protected:
+      std::vector<char*> argv_;
+  };
+
   /**
    * Convert between char and wchar_t
    */
diff --git a/EncodingCXX.cxx b/EncodingCXX.cxx
index aebc148..f76deb5 100644
--- a/EncodingCXX.cxx
+++ b/EncodingCXX.cxx
@@ -29,6 +29,7 @@
 #endif
 
 #include <stdlib.h>
+#include <string.h>
 
 #ifdef _MSC_VER
 # pragma warning (disable: 4786)
@@ -42,6 +43,98 @@
 namespace KWSYS_NAMESPACE
 {
 
+Encoding::CommandLineArguments
+Encoding::CommandLineArguments::Main(int argc, char const* const* argv)
+{
+#ifdef _WIN32
+  (void) argc;
+  (void) argv;
+
+  int ac;
+  LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac);
+
+  std::vector<std::string> av1(ac);
+  std::vector<char const*> av2(ac);
+  for(int i=0; i<ac; i++)
+    {
+    av1[i] = ToNarrow(w_av[i]);
+    av2[i] = av1[i].c_str();
+    }
+  LocalFree(w_av);
+  return CommandLineArguments(ac, &av2[0]);
+#else
+  return CommandLineArguments(argc, argv);
+#endif
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+                                                     char const* const* av)
+{
+  this->argv_.resize(ac+1);
+  for(int i=0; i<ac; i++)
+    {
+    this->argv_[i] = strdup(av[i]);
+    }
+  this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+                                                     wchar_t const* const* av)
+{
+  this->argv_.resize(ac+1);
+  for(int i=0; i<ac; i++)
+    {
+    this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]);
+    }
+  this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::~CommandLineArguments()
+{
+  for(size_t i=0; i<this->argv_.size(); i++)
+    {
+    free(argv_[i]);
+    }
+}
+
+Encoding::CommandLineArguments::
+  CommandLineArguments(const CommandLineArguments& other)
+{
+  this->argv_.resize(other.argv_.size());
+  for(size_t i=0; i<this->argv_.size(); i++)
+    {
+    this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+    }
+}
+
+Encoding::CommandLineArguments&
+Encoding::CommandLineArguments::operator=(const CommandLineArguments& other)
+{
+  size_t i;
+  for(i=0; i<this->argv_.size(); i++)
+    {
+    free(this->argv_[i]);
+    }
+
+  this->argv_.resize(other.argv_.size());
+  for(i=0; i<this->argv_.size(); i++)
+    {
+    this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+    }
+
+  return *this;
+}
+
+int Encoding::CommandLineArguments::argc() const
+{
+  return static_cast<int>(this->argv_.size() - 1);
+}
+
+char const* const* Encoding::CommandLineArguments::argv() const
+{
+  return &this->argv_[0];
+}
+
 #if KWSYS_STL_HAS_WSTRING
 
 kwsys_stl::wstring Encoding::ToWide(const kwsys_stl::string& str)
diff --git a/testEncoding.cxx b/testEncoding.cxx
index a65c430..094588c 100644
--- a/testEncoding.cxx
+++ b/testEncoding.cxx
@@ -145,6 +145,36 @@ static int testRobustEncoding()
   return ret;
 }
 
+static int testCommandLineArguments()
+{
+  int status = 0;
+
+  char const* argv[2] = {
+    "./app.exe",
+    (char const*)helloWorldStrings[1]
+  };
+
+  kwsys::Encoding::CommandLineArguments args(2, argv);
+  kwsys::Encoding::CommandLineArguments arg2 =
+    kwsys::Encoding::CommandLineArguments(args);
+
+  char const* const* u8_argv = args.argv();
+  for(int i=0; i<args.argc(); i++)
+  {
+    char const* u8_arg = u8_argv[i];
+    if(strcmp(argv[i], u8_arg) != 0)
+    {
+      std::cout << "argv[" << i << "] " << argv[i] << " != "
+                << u8_arg << std::endl;
+      status++;
+    }
+  }
+
+  kwsys::Encoding::CommandLineArguments args3 =
+    kwsys::Encoding::CommandLineArguments::Main(2, argv);
+
+  return status;
+}
 
 //----------------------------------------------------------------------------
 int testEncoding(int, char*[])
@@ -163,6 +193,7 @@ int testEncoding(int, char*[])
 
   ret |= testHelloWorldEncoding();
   ret |= testRobustEncoding();
+  ret |= testCommandLineArguments();
 
   return ret;
 }
-- 
GitLab