diff options
Diffstat (limited to 'base/command_line.cc')
-rw-r--r-- | base/command_line.cc | 468 |
1 files changed, 223 insertions, 245 deletions
diff --git a/base/command_line.cc b/base/command_line.cc index 6e02e1d..cf3e36f 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 + |