Index: base/command_line.cc |
diff --git a/base/command_line.cc b/base/command_line.cc |
index 6e02e1d8aa9d14ea0f2db1fabf3ece63630b815f..cf3e36f444691068824108633290a7c9583109b4 100644 |
--- a/base/command_line.cc |
+++ b/base/command_line.cc |
@@ -17,302 +17,228 @@ |
#include "base/string_util.h" |
#include "base/sys_string_conversions.h" |
-using namespace std; |
+CommandLine* CommandLine::current_process_commandline_ = NULL; |
// Since we use a lazy match, make sure that longer versions (like L"--") |
// are listed before shorter versions (like L"-") of similar prefixes. |
#if defined(OS_WIN) |
-const wchar_t* const CommandLine::kSwitchPrefixes[] = {L"--", L"-", L"/"}; |
+const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; |
+const wchar_t kSwitchTerminator[] = L"--"; |
+const wchar_t kSwitchValueSeparator[] = L"="; |
#elif defined(OS_POSIX) |
// Unixes don't use slash as a switch. |
-const wchar_t* const CommandLine::kSwitchPrefixes[] = {L"--", L"-"}; |
+const char* const kSwitchPrefixes[] = {"--", "-"}; |
+const char kSwitchTerminator[] = "--"; |
+const char kSwitchValueSeparator[] = "="; |
#endif |
-const wchar_t CommandLine::kSwitchValueSeparator[] = L"="; |
-const wchar_t CommandLine::kSwitchTerminator[] = 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); |
+#if defined(OS_WIN) |
+// Lowercase a string. This is used to lowercase switch names. |
+// Is this what we really want? It seems crazy to me. I've left it in |
+// for backwards compatibility on Windows. |
+static void Lowercase(std::wstring* parameter) { |
+ transform(parameter->begin(), parameter->end(), parameter->begin(), |
+ tolower); |
} |
+#endif |
-// CommandLine::Data |
-// |
-// This object holds the parsed data for a command line. We hold this in a |
-// separate object from |CommandLine| so that we can share the parsed data |
-// across multiple |CommandLine| objects. When we share |Data|, we might be |
-// accessing this object on multiple threads. To ensure thread safety, the |
-// public interface of this object is const only. |
-// |
-// Do NOT add any non-const methods to this object. You have been warned. |
-class CommandLine::Data { |
- public: |
#if defined(OS_WIN) |
- Data() { |
- Init(GetCommandLineW()); |
- } |
+void CommandLine::ParseFromString(const std::wstring& command_line) { |
+ TrimWhitespace(command_line, TRIM_ALL, &command_line_string_); |
- Data(const wstring& command_line) { |
- Init(command_line); |
- } |
-#elif defined(OS_POSIX) |
- Data() { |
- // Owner must call Init(). |
- } |
+ if (command_line_string_.empty()) |
+ return; |
- Data(int argc, const char* const* argv) { |
- Init(argc, argv); |
- } |
-#endif // defined(OS_POSIX) |
+ int num_args = 0; |
+ wchar_t** args = NULL; |
-#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_); |
- |
- bool parse_switches = true; |
- for (int i = 1; i < num_args; ++i) { |
- wstring arg; |
- TrimWhitespace(args[i], TRIM_ALL, &arg); |
- |
- if (!parse_switches) { |
- loose_values_.push_back(arg); |
- continue; |
- } |
- |
- if (arg == kSwitchTerminator) { |
- parse_switches = false; |
- continue; |
- } |
- |
- wstring switch_string; |
- wstring switch_value; |
- if (IsSwitch(arg, &switch_string, &switch_value)) { |
- switches_[switch_string] = switch_value; |
- } else { |
- loose_values_.push_back(arg); |
- } |
- } |
+ args = CommandLineToArgvW(command_line_string_.c_str(), &num_args); |
- if (args) |
- LocalFree(args); |
- } |
-#elif defined(OS_POSIX) |
- // Does the actual parsing of the command line. |
- void Init(int argc, const char* const* argv) { |
- if (argc < 1) |
- return; |
- program_ = base::SysNativeMBToWide(argv[0]); |
- argv_.push_back(std::string(argv[0])); |
- command_line_string_ = program_; |
- |
- bool parse_switches = true; |
- for (int i = 1; i < argc; ++i) { |
- std::wstring arg = base::SysNativeMBToWide(argv[i]); |
- argv_.push_back(argv[i]); |
- command_line_string_.append(L" "); |
- command_line_string_.append(arg); |
- |
- if (!parse_switches) { |
- loose_values_.push_back(arg); |
- continue; |
- } |
- |
- if (arg == kSwitchTerminator) { |
- parse_switches = false; |
- continue; |
- } |
- |
- wstring switch_string; |
- wstring switch_value; |
- if (IsSwitch(arg, &switch_string, &switch_value)) { |
- switches_[switch_string] = switch_value; |
- } else { |
- loose_values_.push_back(arg); |
- } |
+ // Populate program_ with the trimmed version of the first arg. |
+ TrimWhitespace(args[0], TRIM_ALL, &program_); |
+ |
+ bool parse_switches = true; |
+ for (int i = 1; i < num_args; ++i) { |
+ std::wstring arg; |
+ TrimWhitespace(args[i], TRIM_ALL, &arg); |
+ |
+ if (!parse_switches) { |
+ loose_values_.push_back(arg); |
+ continue; |
} |
- } |
-#endif |
- const std::wstring& command_line_string() const { |
- return command_line_string_; |
- } |
+ if (arg == kSwitchTerminator) { |
+ parse_switches = false; |
+ continue; |
+ } |
- const std::wstring& program() const { |
- return program_; |
+ std::string switch_string; |
+ std::wstring switch_value; |
+ if (IsSwitch(arg, &switch_string, &switch_value)) { |
+ switches_[switch_string] = switch_value; |
+ } else { |
+ loose_values_.push_back(arg); |
+ } |
} |
- const std::map<std::wstring, std::wstring>& switches() const { |
- return switches_; |
+ if (args) |
+ LocalFree(args); |
+} |
+CommandLine::CommandLine(const std::wstring& program) { |
+ if (!program.empty()) { |
+ program_ = program; |
+ command_line_string_ = L'"' + program + L'"'; |
} |
+} |
+#elif defined(OS_POSIX) |
+CommandLine::CommandLine(int argc, const char* const* argv) { |
+ for (int i = 0; i < argc; ++i) |
+ argv_.push_back(argv[i]); |
+ InitFromArgv(); |
+} |
+CommandLine::CommandLine(const std::vector<std::string>& argv) { |
+ argv_ = argv; |
+ InitFromArgv(); |
+} |
- const std::vector<std::wstring>& loose_values() const { |
- return loose_values_; |
- } |
+void CommandLine::InitFromArgv() { |
+ bool parse_switches = true; |
+ for (size_t i = 1; i < argv_.size(); ++i) { |
+ const std::string& arg = argv_[i]; |
-#if defined(OS_POSIX) |
- const std::vector<std::string>& argv() const { |
- return argv_; |
- } |
-#endif |
+ if (!parse_switches) { |
+ loose_values_.push_back(arg); |
+ continue; |
+ } |
- private: |
- // Returns true if parameter_string represents a switch. If true, |
- // switch_string and switch_value are set. (If false, both are |
- // set to the empty string.) |
- static bool IsSwitch(const wstring& parameter_string, |
- wstring* switch_string, |
- wstring* switch_value) { |
- |
- *switch_string = L""; |
- *switch_value = L""; |
- |
- for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { |
- std::wstring prefix(kSwitchPrefixes[i]); |
- if (parameter_string.find(prefix) != 0) // check prefix |
- continue; |
- |
- const size_t switch_start = prefix.length(); |
- const size_t equals_position = parameter_string.find( |
- kSwitchValueSeparator, switch_start); |
- if (equals_position == wstring::npos) { |
- *switch_string = parameter_string.substr(switch_start); |
- } else { |
- *switch_string = parameter_string.substr( |
- switch_start, equals_position - switch_start); |
- *switch_value = parameter_string.substr(equals_position + 1); |
- } |
- Lowercase(switch_string); |
- |
- return true; |
+ if (arg == kSwitchTerminator) { |
+ parse_switches = false; |
+ continue; |
} |
- return false; |
+ std::string switch_string; |
+ std::string switch_value; |
+ if (IsSwitch(arg, &switch_string, &switch_value)) { |
+ switches_[switch_string] = switch_value; |
+ } else { |
+ loose_values_.push_back(arg); |
+ } |
} |
+} |
- std::wstring command_line_string_; |
- std::wstring program_; |
- std::map<std::wstring, std::wstring> switches_; |
- std::vector<std::wstring> loose_values_; |
- std::vector<std::string> argv_; |
- |
- DISALLOW_EVIL_CONSTRUCTORS(Data); |
-}; |
- |
-CommandLine::CommandLine() |
- : we_own_data_(false), // The Singleton class will manage it for us. |
- data_(Singleton<Data>::get()) { |
- DCHECK(!data_->command_line_string().empty()) << |
- "You must call CommandLine::SetArgcArgv before making any CommandLine " |
- "calls."; |
+CommandLine::CommandLine(const std::wstring& program) { |
+ argv_.push_back(WideToASCII(program)); |
} |
+#endif |
+// static |
+bool CommandLine::IsSwitch(const StringType& parameter_string, |
+ std::string* switch_string, |
+ StringType* switch_value) { |
+ switch_string->clear(); |
+ switch_value->clear(); |
+ |
+ for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { |
+ StringType prefix(kSwitchPrefixes[i]); |
+ if (parameter_string.find(prefix) != 0) |
+ continue; |
+ |
+ const size_t switch_start = prefix.length(); |
+ const size_t equals_position = parameter_string.find( |
+ kSwitchValueSeparator, switch_start); |
+ StringType switch_native; |
+ if (equals_position == StringType::npos) { |
+ switch_native = parameter_string.substr(switch_start); |
+ } else { |
+ switch_native = parameter_string.substr( |
+ switch_start, equals_position - switch_start); |
+ *switch_value = parameter_string.substr(equals_position + 1); |
+ } |
#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* const* argv) |
- : we_own_data_(true), |
- data_(new Data(argc, argv)) { |
-} |
+ Lowercase(&switch_native); |
+ *switch_string = WideToASCII(switch_native); |
+#else |
+ *switch_string = switch_native; |
+#endif |
-CommandLine::CommandLine(const std::vector<std::string>& argv) |
- : we_own_data_(true) { |
- const char* argv_copy[argv.size()]; |
- for (size_t i = 0; i < argv.size(); i++) { |
- argv_copy[i] = argv[i].c_str(); |
+ return true; |
} |
- data_ = new Data(argv.size(), argv_copy); |
-} |
-#endif |
-CommandLine::~CommandLine() { |
- if (we_own_data_) |
- delete data_; |
+ return false; |
} |
// static |
-void CommandLine::SetArgcArgv(int argc, const char* const* argv) { |
-#if !defined(OS_WIN) |
- Singleton<Data>::get()->Init(argc, argv); |
+void CommandLine::Init(int argc, const char* const* argv) { |
+ DCHECK(current_process_commandline_ == NULL); |
+#if defined(OS_WIN) |
+ current_process_commandline_ = new CommandLine; |
+ current_process_commandline_->ParseFromString(::GetCommandLineW()); |
+#elif defined(OS_POSIX) |
+ current_process_commandline_ = new CommandLine(argc, argv); |
#endif |
} |
-bool CommandLine::HasSwitch(const wstring& switch_string) const { |
- wstring lowercased_switch(switch_string); |
+bool CommandLine::HasSwitch(const std::wstring& switch_string) const { |
+ std::wstring lowercased_switch(switch_string); |
+#if defined(OS_WIN) |
Lowercase(&lowercased_switch); |
- return data_->switches().find(lowercased_switch) != data_->switches().end(); |
+#endif |
+ return switches_.find(WideToASCII(lowercased_switch)) != switches_.end(); |
} |
-wstring CommandLine::GetSwitchValue(const wstring& switch_string) const { |
- wstring lowercased_switch(switch_string); |
+std::wstring CommandLine::GetSwitchValue( |
+ const std::wstring& switch_string) const { |
+ std::wstring lowercased_switch(switch_string); |
+#if defined(OS_WIN) |
Lowercase(&lowercased_switch); |
+#endif |
- const map<wstring, wstring>::const_iterator result = |
- data_->switches().find(lowercased_switch); |
+ std::map<std::string, StringType>::const_iterator result = |
+ switches_.find(WideToASCII(lowercased_switch)); |
- if (result == data_->switches().end()) { |
+ if (result == switches_.end()) { |
return L""; |
} else { |
+#if defined(OS_WIN) |
return result->second; |
+#else |
+ return ASCIIToWide(result->second); |
+#endif |
} |
} |
-size_t CommandLine::GetLooseValueCount() const { |
- return data_->loose_values().size(); |
-} |
- |
-CommandLine::LooseValueIterator CommandLine::GetLooseValuesBegin() const { |
- return data_->loose_values().begin(); |
+#if defined(OS_WIN) |
+std::vector<std::wstring> CommandLine::GetLooseValues() const { |
+ return loose_values_; |
} |
- |
-CommandLine::LooseValueIterator CommandLine::GetLooseValuesEnd() const { |
- return data_->loose_values().end(); |
+std::wstring CommandLine::program() const { |
+ return program_; |
} |
- |
-std::wstring CommandLine::command_line_string() const { |
- return data_->command_line_string(); |
+#else |
+std::vector<std::wstring> CommandLine::GetLooseValues() const { |
+ std::vector<std::wstring> values; |
+ for (size_t i = 0; i < loose_values_.size(); ++i) |
+ values.push_back(ASCIIToWide(loose_values_[i])); |
+ return values; |
} |
- |
-#if defined(OS_POSIX) |
-const std::vector<std::string>& CommandLine::argv() const { |
- return data_->argv(); |
+std::wstring CommandLine::program() const { |
+ DCHECK(argv_.size() > 0); |
+ return ASCIIToWide(argv_[0]); |
} |
#endif |
-std::wstring CommandLine::program() const { |
- return data_->program(); |
-} |
// static |
-wstring CommandLine::PrefixedSwitchString(const wstring& switch_string) { |
+std::wstring CommandLine::PrefixedSwitchString( |
+ const std::wstring& switch_string) { |
return StringPrintf(L"%ls%ls", |
kSwitchPrefixes[0], |
switch_string.c_str()); |
} |
// static |
-wstring CommandLine::PrefixedSwitchStringWithValue( |
- const wstring& switch_string, const wstring& value_string) { |
+std::wstring CommandLine::PrefixedSwitchStringWithValue( |
+ const std::wstring& switch_string, const std::wstring& value_string) { |
if (value_string.empty()) { |
return PrefixedSwitchString(switch_string); |
} |
@@ -324,20 +250,17 @@ wstring CommandLine::PrefixedSwitchStringWithValue( |
value_string.c_str()); |
} |
-// static |
-void CommandLine::AppendSwitch(wstring* command_line_string, |
- const wstring& switch_string) { |
- DCHECK(command_line_string); |
- wstring prefixed_switch_string = PrefixedSwitchString(switch_string); |
- command_line_string->append(L" "); |
- command_line_string->append(prefixed_switch_string); |
+#if defined(OS_WIN) |
+void CommandLine::AppendSwitch(const std::wstring& switch_string) { |
+ std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string); |
+ command_line_string_.append(L" "); |
+ command_line_string_.append(prefixed_switch_string); |
+ switches_[WideToASCII(switch_string)] = L""; |
} |
-// static |
-void CommandLine::AppendSwitchWithValue(wstring* command_line_string, |
- const wstring& switch_string, |
- const wstring& value_string) { |
- wstring value_string_edit; |
+void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string, |
+ const std::wstring& value_string) { |
+ std::wstring value_string_edit; |
// NOTE(jhughes): If the value contains a quotation mark at one |
// end but not both, you may get unusable output. |
@@ -351,10 +274,65 @@ void CommandLine::AppendSwitchWithValue(wstring* command_line_string, |
value_string_edit = value_string; |
} |
- wstring combined_switch_string = |
+ std::wstring combined_switch_string = |
PrefixedSwitchStringWithValue(switch_string, value_string_edit); |
- command_line_string->append(L" "); |
- command_line_string->append(combined_switch_string); |
+ command_line_string_.append(L" "); |
+ command_line_string_.append(combined_switch_string); |
+ |
+ switches_[WideToASCII(switch_string)] = value_string; |
+} |
+ |
+void CommandLine::AppendLooseValue(const std::wstring& value) { |
+ // TODO(evan): quoting? |
+ command_line_string_.append(L" "); |
+ command_line_string_.append(value); |
+} |
+ |
+void CommandLine::AppendArguments(const CommandLine& other, |
+ bool include_program) { |
+ // Verify include_program is used correctly. |
+ // Logic could be shorter but this is clearer. |
+ DCHECK(include_program ? !other.program().empty() : other.program().empty()); |
+ command_line_string_ += L" " + other.command_line_string_; |
+ std::map<std::string, StringType>::const_iterator i; |
+ for (i = other.switches_.begin(); i != other.switches_.end(); ++i) |
+ switches_[i->first] = i->second; |
} |
+#elif defined(OS_POSIX) |
+void CommandLine::AppendSwitch(const std::wstring& switch_string) { |
+ std::string ascii_switch = WideToASCII(switch_string); |
+ argv_.push_back(kSwitchPrefixes[0] + ascii_switch); |
+ switches_[ascii_switch] = ""; |
+} |
+ |
+void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string, |
+ const std::wstring& value_string) { |
+ std::string ascii_switch = WideToASCII(switch_string); |
+ std::string ascii_value = WideToASCII(value_string); |
+ |
+ argv_.push_back(kSwitchPrefixes[0] + ascii_switch + |
+ kSwitchValueSeparator + ascii_value); |
+ switches_[ascii_switch] = ascii_value; |
+} |
+ |
+void CommandLine::AppendLooseValue(const std::wstring& value) { |
+ argv_.push_back(WideToASCII(value)); |
+} |
+ |
+void CommandLine::AppendArguments(const CommandLine& other, |
+ bool include_program) { |
+ // Verify include_program is used correctly. |
+ // Logic could be shorter but this is clearer. |
+ DCHECK(include_program ? !other.program().empty() : other.program().empty()); |
+ |
+ size_t first_arg = include_program ? 0 : 1; |
+ for (size_t i = first_arg; i < other.argv_.size(); ++i) |
+ argv_.push_back(other.argv_[i]); |
+ std::map<std::string, StringType>::const_iterator i; |
+ for (i = other.switches_.begin(); i != other.switches_.end(); ++i) |
+ switches_[i->first] = i->second; |
+} |
+#endif |
+ |