diff options
-rw-r--r-- | base/command_line.cc | 141 | ||||
-rw-r--r-- | base/command_line.h | 8 | ||||
-rw-r--r-- | base/command_line_unittest.cc | 21 |
3 files changed, 130 insertions, 40 deletions
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* const CommandLine::kSwitchPrefixes[] = {L"--", L"-", L"/"}; 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 @@ static void Lowercase(wstring* parameter) { // 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 @@ class CommandLine::Data { 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 @@ CommandLine::CommandLine() 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..4f24f26 100644 --- a/base/command_line.h +++ b/base/command_line.h @@ -50,9 +50,13 @@ class CommandLine { // 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 @@ class CommandLine { // 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 dbcf06f..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 @@ namespace { }; 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 @@ TEST(CommandLineTest, DefaultConstructor) { // 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 @@ TEST(CommandLineTest, AppendSwitches) { EXPECT_TRUE(cl.HasSwitch(switch2)); EXPECT_EQ(value4.substr(1, value4.length() - 2), cl.GetSwitchValue(switch4)); } +#endif |