[go: nahoru, domu]

Pinkerton's port/fix-up of command-line processing to work cross-platform.



git-svn-id: svn://svn.chromium.org/chrome/trunk/src@531 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/command_line.cc b/base/command_line.cc
index 7755578..a142f95 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -27,17 +27,30 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include "base/command_line.h"
+
+#if defined(OS_WIN)
 #include <windows.h>
 #include <shellapi.h>
+#endif
 
 #include <algorithm>
 
-#include "base/command_line.h"
-
 #include "base/logging.h"
 #include "base/singleton.h"
 #include "base/string_util.h"
 
+extern "C" {
+#if defined(OS_MACOSX)
+const char** NXArgv;
+int NXArgc;
+#elif defined(OS_LINUX)
+extern "C" {
+const char** __libc_argv;
+int __libc_argv;
+#endif
+}  // extern "C"
+
 using namespace std;
 
 // Since we use a lazy match, make sure that longer versions (like L"--")
@@ -46,8 +59,15 @@
 
 const wchar_t CommandLine::kSwitchValueSeparator[] = L"=";
 
+// Needed to avoid a typecast on the tolower() function pointer in Lowercase().
+// MSVC accepts it as-is but GCC requires the typecast.
+static int ToLower(int c) {
+  return tolower(c);
+}
+
 static void Lowercase(wstring* parameter) {
-  transform(parameter->begin(), parameter->end(), parameter->begin(), tolower);
+  transform(parameter->begin(), parameter->end(), parameter->begin(), 
+            ToLower);
 }
 
 // CommandLine::Data
@@ -61,13 +81,85 @@
 // Do NOT add any non-const methods to this object.  You have been warned.
 class CommandLine::Data {
  public:
-  Data() {
+#if defined(OS_WIN)
+  Data() { 
     Init(GetCommandLineW());
   }
+#elif defined(OS_MACOSX)
+  Data() {
+    Init(NXArgc, NXArgv);
+  }
+#elif defined(OS_LINUX)
+  Data() {
+    Init(__gnuc_argc, __gnuc_argv);
+  }
+#endif
 
+#if defined(OS_WIN)
   Data(const wstring& command_line) {
     Init(command_line);
   }
+#elif defined(OS_POSIX)
+  Data(const int argc, const char* argv[]) {
+    Init(argc, argv);
+  }
+#endif
+
+#if defined(OS_WIN)
+  // Does the actual parsing of the command line.
+  void Init(const std::wstring& command_line) {
+    TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
+
+    if (command_line_string_.empty())
+      return;
+
+    int num_args = 0;
+    wchar_t** args = NULL;
+
+    args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
+
+    // Populate program_ with the trimmed version of the first arg.
+    TrimWhitespace(args[0], TRIM_ALL, &program_);
+
+    for (int i = 1; i < num_args; ++i) {
+      wstring arg;
+      TrimWhitespace(args[i], TRIM_ALL, &arg);
+
+      wstring switch_string;
+      wstring switch_value;
+      if (IsSwitch(arg, &switch_string, &switch_value)) {
+        switches_[switch_string] = switch_value;
+      } else {
+        loose_values_.push_back(arg);
+      }
+    }
+
+    if (args)
+      LocalFree(args);
+  }
+#elif defined(OS_POSIX)  // Does the actual parsing of the command line.
+  void Init(int argc, const char* argv[]) {
+    if (argc <= 1)
+      return;
+
+    program_ = NativeMBToWide(argv[0]);
+    command_line_string_ = program_;
+
+    for (int i = 1; i < argc; ++i) {
+      std::wstring arg = NativeMBToWide(argv[i]);
+      command_line_string_.append(L" ");
+      command_line_string_.append(arg);
+
+      wstring switch_string;
+      wstring switch_value;
+      if (IsSwitch(arg, &switch_string, &switch_value)) {
+        switches_[switch_string] = switch_value;
+      } else {
+        loose_values_.push_back(arg);
+      }
+    }
+  }
+#endif
 
   const std::wstring& command_line_string() const {
     return command_line_string_;
@@ -119,44 +211,12 @@
     return false;
   }
 
-  // Does the actual parsing of the command line.
-  void Init(const std::wstring& command_line) {
-    TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
-
-    if (command_line_string_.empty())
-      return;
-
-    int num_args = 0;
-    wchar_t** args = NULL;
-
-    args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
-
-    // Populate program_ with the trimmed version of the first arg.
-    TrimWhitespace(args[0], TRIM_ALL, &program_);
-
-    for (int i = 1; i < num_args; ++i) {
-      wstring arg;
-      TrimWhitespace(args[i], TRIM_ALL, &arg);
-
-      wstring switch_string;
-      wstring switch_value;
-      if (IsSwitch(arg, &switch_string, &switch_value)) {
-        switches_[switch_string] = switch_value;
-      } else {
-        loose_values_.push_back(arg);
-      }
-    }
-
-    if (args)
-      LocalFree(args);
-  }
-
   std::wstring command_line_string_;
   std::wstring program_;
   std::map<std::wstring, std::wstring> switches_;
   std::vector<std::wstring> loose_values_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(CommandLine::Data);
+  DISALLOW_EVIL_CONSTRUCTORS(Data);
 };
 
 CommandLine::CommandLine()
@@ -164,10 +224,17 @@
       data_(Singleton<Data>::get()) {
 }
 
+#if defined(OS_WIN)
 CommandLine::CommandLine(const wstring& command_line)
     : we_own_data_(true),
       data_(new Data(command_line)) {
 }
+#elif defined(OS_POSIX)
+CommandLine::CommandLine(const int argc, const char* argv[])
+    : we_own_data_(true),
+      data_(new Data(argc, argv)) {
+}
+#endif
 
 CommandLine::~CommandLine() {
   if (we_own_data_)
diff --git a/base/command_line.h b/base/command_line.h
index f1b7ade..4f24f263 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -50,9 +50,13 @@
   // the current process.
   CommandLine();
 
+#if defined(OS_WIN)
   // Creates a parsed version of the given command-line string.
-  // The program name is assumed to be the first item in the string.
+  // The program name is assumed to be the first item in the string.  
   CommandLine(const std::wstring& command_line);
+#elif defined(OS_POSIX)
+  CommandLine(int argc, const char** argv);
+#endif
 
   ~CommandLine();
 
@@ -112,7 +116,7 @@
 
   // A pointer to the parsed version of the command line.
   Data* data_;
-
+  
   DISALLOW_EVIL_CONSTRUCTORS(CommandLine);
 };
 
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index dbcf06fb..6a0a62c 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -31,6 +31,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/basictypes.h"
 #include "base/logging.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,12 +41,21 @@
 };
 
 TEST(CommandLineTest, CommandLineConstructor) {
+#ifdef OS_WIN
   CommandLine cl(L"program --foo= -bAr  /Spaetzel=pierogi /Baz flim "
                  L"--other-switches=\"--dog=canine --cat=feline\" "
                  L"-spaetzle=Crepe   -=loosevalue  flan "
                  L"--input-translation=\"45\"--output-rotation "
                  L"\"in the time of submarines...\"");
-
+#elif OS_POSIX
+  const char* argv[] = {"program", "--foo=", "-bAr", 
+                         "/Spaetzel=pierogi /Baz flim",
+                         "--other-switches=\"--dog=canine --cat=feline\"",
+                         "-spaetzle=Crepe", "-=loosevalue", "flan",
+                         "--input-translation=\"45\"--output-rotation",
+                         "\"in the time of submarines...\""};
+  CommandLine cl(arraysize(argv), argv);
+#endif
   EXPECT_FALSE(cl.command_line_string().empty());
   EXPECT_FALSE(cl.HasSwitch(L"cruller"));
   EXPECT_FALSE(cl.HasSwitch(L"flim"));
@@ -92,13 +102,21 @@
 
 // Tests behavior with an empty input string.
 TEST(CommandLineTest, EmptyString) {
+#if defined(OS_WIN)
   CommandLine cl(L"");
+#elif defined(OS_POSIX)
+  const char* argv[] = {};
+  CommandLine cl(ARRAYSIZE_UNSAFE(argv), argv);
+#endif
   EXPECT_TRUE(cl.command_line_string().empty());
   EXPECT_TRUE(cl.program().empty());
   EXPECT_EQ(0, cl.GetLooseValueCount());
 }
 
 // Test static functions for appending switches to a command line.
+// TODO(pinkerton): non-windows platforms don't have the requisite ctor here, so
+// we need something that tests AppendSwitches in another way (if even desired).
+#if defined(OS_WIN)
 TEST(CommandLineTest, AppendSwitches) {
   std::wstring cl_string = L"Program";
   std::wstring switch1 = L"switch1";
@@ -123,3 +141,4 @@
   EXPECT_TRUE(cl.HasSwitch(switch2));
   EXPECT_EQ(value4.substr(1, value4.length() - 2), cl.GetSwitchValue(switch4));
 }
+#endif