diff options
-rw-r--r-- | base/command_line.cc | 417 | ||||
-rw-r--r-- | base/command_line.h | 70 | ||||
-rw-r--r-- | base/command_line_unittest.cc | 202 | ||||
-rw-r--r-- | chrome/browser/browser_main_win.cc | 3 | ||||
-rw-r--r-- | chrome/browser/process_info_snapshot_mac.cc | 81 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/safe_browsing_test.cc | 5 | ||||
-rw-r--r-- | chrome/browser/ui/browser_init.cc | 2 | ||||
-rw-r--r-- | chrome/common/switch_utils_unittest.cc | 37 | ||||
-rw-r--r-- | chrome/installer/util/install_util.cc | 19 | ||||
-rw-r--r-- | chrome/installer/util/install_util.h | 4 | ||||
-rw-r--r-- | chrome/installer/util/product_state_unittest.cc | 19 | ||||
-rw-r--r-- | chrome/test/live_sync/live_sync_test.cc | 8 | ||||
-rw-r--r-- | chrome/test/ui/ui_test.cc | 20 | ||||
-rw-r--r-- | chrome/test/ui_test_utils.cc | 23 | ||||
-rw-r--r-- | net/test/test_server.cc | 25 | ||||
-rw-r--r-- | net/test/test_server_posix.cc | 5 | ||||
-rw-r--r-- | net/test/test_server_win.cc | 3 |
17 files changed, 473 insertions, 470 deletions
diff --git a/base/command_line.cc b/base/command_line.cc index b027d2a..b3a79eb 100644 --- a/base/command_line.cc +++ b/base/command_line.cc @@ -23,29 +23,79 @@ CommandLine* CommandLine::current_process_commandline_ = NULL; namespace { -typedef CommandLine::StringType::value_type CharType; - -const CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--"); -const CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("="); +const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--"); +const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("="); // Since we use a lazy match, make sure that longer versions (like "--") are // listed before shorter versions (like "-") of similar prefixes. #if defined(OS_WIN) -const CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; +const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; #elif defined(OS_POSIX) // Unixes don't use slash as a switch. -const CharType* const kSwitchPrefixes[] = {"--", "-"}; +const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"}; #endif +size_t GetSwitchPrefixLength(const CommandLine::StringType& string) { + for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { + CommandLine::StringType prefix(kSwitchPrefixes[i]); + if (string.find(prefix) == 0) + return prefix.length(); + } + return 0; +} + +// Fills in |switch_string| and |switch_value| if |string| is a switch. +// This will preserve the input switch prefix in the output |switch_string|. +bool IsSwitch(const CommandLine::StringType& string, + CommandLine::StringType* switch_string, + CommandLine::StringType* switch_value) { + switch_string->clear(); + switch_value->clear(); + if (GetSwitchPrefixLength(string) == 0) + return false; + + const size_t equals_position = string.find(kSwitchValueSeparator); + *switch_string = string.substr(0, equals_position); + if (equals_position != CommandLine::StringType::npos) + *switch_value = string.substr(equals_position + 1); + return true; +} + +// Append switches and arguments, keeping switches before arguments. +void AppendSwitchesAndArguments(CommandLine& command_line, + const CommandLine::StringVector& argv) { + bool parse_switches = true; + for (size_t i = 1; i < argv.size(); ++i) { + CommandLine::StringType arg = argv[i]; + TrimWhitespace(arg, TRIM_ALL, &arg); + + CommandLine::StringType switch_string; + CommandLine::StringType switch_value; + parse_switches &= (arg != kSwitchTerminator); + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { #if defined(OS_WIN) -// Lowercase a string for case-insensitivity of switches. -// Is this desirable? It exists for backwards compatibility on Windows. -void Lowercase(std::string* arg) { - transform(arg->begin(), arg->end(), arg->begin(), tolower); + command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value); +#elif defined(OS_POSIX) + command_line.AppendSwitchNative(switch_string, switch_value); +#endif + } else { + command_line.AppendArgNative(arg); + } + } +} + +// Lowercase switches for backwards compatiblity *on Windows*. +std::string LowerASCIIOnWindows(const std::string& string) { +#if defined(OS_WIN) + return StringToLowerASCII(string); +#elif defined(OS_POSIX) + return string; +#endif } -// Quote a string if necessary, such that CommandLineToArgvW() will always -// process it as a single argument. -std::wstring WindowsStyleQuote(const std::wstring& arg) { + +#if defined(OS_WIN) +// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. +std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) { // We follow the quoting rules of CommandLineToArgvW. // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx if (arg.find_first_of(L" \\\"") == std::wstring::npos) { @@ -88,73 +138,30 @@ std::wstring WindowsStyleQuote(const std::wstring& arg) { } #endif -// Returns true and fills in |switch_string| and |switch_value| if -// |parameter_string| represents a switch. -bool IsSwitch(const CommandLine::StringType& parameter_string, - std::string* switch_string, - CommandLine::StringType* switch_value) { - switch_string->clear(); - switch_value->clear(); - - for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { - CommandLine::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); - CommandLine::StringType switch_native; - if (equals_position == CommandLine::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) - *switch_string = WideToASCII(switch_native); - Lowercase(switch_string); -#else - *switch_string = switch_native; -#endif - - return true; - } - - return false; -} - } // namespace -CommandLine::CommandLine(NoProgram no_program) { -#if defined(OS_POSIX) - // Push an empty argument, because we always assume argv_[0] is a program. - argv_.push_back(""); -#endif +CommandLine::CommandLine(NoProgram no_program) + : argv_(1), + begin_args_(1) { } -CommandLine::CommandLine(const FilePath& program) { -#if defined(OS_WIN) - if (!program.empty()) { - program_ = program.value(); - // TODO(evanm): proper quoting here. - command_line_string_ = L'"' + program.value() + L'"'; - } -#elif defined(OS_POSIX) - argv_.push_back(program.value()); -#endif +CommandLine::CommandLine(const FilePath& program) + : argv_(1), + begin_args_(1) { + SetProgram(program); } -#if defined(OS_POSIX) -CommandLine::CommandLine(int argc, const char* const* argv) { +CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) + : argv_(1), + begin_args_(1) { InitFromArgv(argc, argv); } -CommandLine::CommandLine(const StringVector& argv) { +CommandLine::CommandLine(const StringVector& argv) + : argv_(1), + begin_args_(1) { InitFromArgv(argv); } -#endif // OS_POSIX CommandLine::~CommandLine() { } @@ -162,7 +169,7 @@ CommandLine::~CommandLine() { // static void CommandLine::Init(int argc, const char* const* argv) { delete current_process_commandline_; - current_process_commandline_ = new CommandLine; + current_process_commandline_ = new CommandLine(NO_PROGRAM); #if defined(OS_WIN) current_process_commandline_->ParseFromString(::GetCommandLineW()); #elif defined(OS_POSIX) @@ -186,76 +193,76 @@ CommandLine* CommandLine::ForCurrentProcess() { #if defined(OS_WIN) // static CommandLine CommandLine::FromString(const std::wstring& command_line) { - CommandLine cmd; + CommandLine cmd(NO_PROGRAM); cmd.ParseFromString(command_line); return cmd; } -#endif // OS_WIN +#endif -#if defined(OS_POSIX) -void CommandLine::InitFromArgv(int argc, const char* const* argv) { +void CommandLine::InitFromArgv(int argc, + const CommandLine::CharType* const* argv) { + StringVector new_argv; for (int i = 0; i < argc; ++i) - argv_.push_back(argv[i]); - InitFromArgv(argv_); + new_argv.push_back(argv[i]); + InitFromArgv(new_argv); } void CommandLine::InitFromArgv(const StringVector& argv) { - argv_ = argv; - bool parse_switches = true; - for (size_t i = 1; i < argv_.size(); ++i) { - const std::string& arg = argv_[i]; - - if (!parse_switches) { - args_.push_back(arg); - continue; - } - - if (arg == kSwitchTerminator) { - parse_switches = false; - continue; - } - - std::string switch_string; - StringType switch_value; - if (IsSwitch(arg, &switch_string, &switch_value)) { - switches_[switch_string] = switch_value; - } else { - args_.push_back(arg); - } - } + argv_ = StringVector(1); + begin_args_ = 1; + SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); + AppendSwitchesAndArguments(*this, argv); } -#endif // OS_POSIX CommandLine::StringType CommandLine::command_line_string() const { + StringType string(argv_[0]); #if defined(OS_WIN) - return command_line_string_; -#elif defined(OS_POSIX) - return JoinString(argv_, ' '); + string = QuoteForCommandLineToArgvW(string); +#endif + // Append switches and arguments. + bool parse_switches = true; + for (size_t i = 1; i < argv_.size(); ++i) { + CommandLine::StringType arg = argv_[i]; + CommandLine::StringType switch_string; + CommandLine::StringType switch_value; + parse_switches &= arg != kSwitchTerminator; + string.append(StringType(FILE_PATH_LITERAL(" "))); + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { + string.append(switch_string); + if (!switch_value.empty()) { +#if defined(OS_WIN) + switch_value = QuoteForCommandLineToArgvW(switch_value); +#endif + string.append(kSwitchValueSeparator + switch_value); + } + } + else { +#if defined(OS_WIN) + arg = QuoteForCommandLineToArgvW(arg); #endif + string.append(arg); + } + } + return string; } FilePath CommandLine::GetProgram() const { -#if defined(OS_WIN) - return FilePath(program_); -#else - DCHECK_GT(argv_.size(), 0U); return FilePath(argv_[0]); -#endif +} + +void CommandLine::SetProgram(const FilePath& program) { + TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); } bool CommandLine::HasSwitch(const std::string& switch_string) const { - std::string lowercased_switch(switch_string); -#if defined(OS_WIN) - Lowercase(&lowercased_switch); -#endif - return switches_.find(lowercased_switch) != switches_.end(); + return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end(); } std::string CommandLine::GetSwitchValueASCII( const std::string& switch_string) const { - CommandLine::StringType value = GetSwitchValueNative(switch_string); + StringType value = GetSwitchValueNative(switch_string); if (!IsStringASCII(value)) { - LOG(WARNING) << "Value of --" << switch_string << " must be ASCII."; + LOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII."; return ""; } #if defined(OS_WIN) @@ -272,18 +279,9 @@ FilePath CommandLine::GetSwitchValuePath( CommandLine::StringType CommandLine::GetSwitchValueNative( const std::string& switch_string) const { - std::string lowercased_switch(switch_string); -#if defined(OS_WIN) - Lowercase(&lowercased_switch); -#endif - - SwitchMap::const_iterator result = switches_.find(lowercased_switch); - - if (result == switches_.end()) { - return CommandLine::StringType(); - } else { - return result->second; - } + SwitchMap::const_iterator result = switches_.end(); + result = switches_.find(LowerASCIIOnWindows(switch_string)); + return result == switches_.end() ? StringType() : result->second; } size_t CommandLine::GetSwitchCount() const { @@ -291,14 +289,7 @@ size_t CommandLine::GetSwitchCount() const { } void CommandLine::AppendSwitch(const std::string& switch_string) { -#if defined(OS_WIN) - command_line_string_.append(L" "); - command_line_string_.append(kSwitchPrefixes[0] + ASCIIToWide(switch_string)); - switches_[switch_string] = L""; -#elif defined(OS_POSIX) - argv_.push_back(kSwitchPrefixes[0] + switch_string); - switches_[switch_string] = ""; -#endif + AppendSwitchNative(switch_string, StringType()); } void CommandLine::AppendSwitchPath(const std::string& switch_string, @@ -308,23 +299,21 @@ void CommandLine::AppendSwitchPath(const std::string& switch_string, void CommandLine::AppendSwitchNative(const std::string& switch_string, const CommandLine::StringType& value) { + std::string switch_key(LowerASCIIOnWindows(switch_string)); #if defined(OS_WIN) - StringType combined_switch_string = - kSwitchPrefixes[0] + ASCIIToWide(switch_string); - if (!value.empty()) - combined_switch_string += kSwitchValueSeparator + WindowsStyleQuote(value); - - command_line_string_.append(L" "); - command_line_string_.append(combined_switch_string); - - switches_[switch_string] = value; + StringType combined_switch_string(ASCIIToWide(switch_key)); #elif defined(OS_POSIX) - StringType combined_switch_string = kSwitchPrefixes[0] + switch_string; + StringType combined_switch_string(switch_string); +#endif + size_t prefix_length = GetSwitchPrefixLength(combined_switch_string); + switches_[switch_key.substr(prefix_length)] = value; + // Preserve existing switch prefixes in |argv_|; only append one if necessary. + if (prefix_length == 0) + combined_switch_string = kSwitchPrefixes[0] + combined_switch_string; if (!value.empty()) combined_switch_string += kSwitchValueSeparator + value; - argv_.push_back(combined_switch_string); - switches_[switch_string] = value; -#endif + // Append the switch and update the switches/arguments divider |begin_args_|. + argv_.insert(argv_.begin() + begin_args_++, combined_switch_string); } void CommandLine::AppendSwitchASCII(const std::string& switch_string, @@ -336,23 +325,26 @@ void CommandLine::AppendSwitchASCII(const std::string& switch_string, #endif } -void CommandLine::AppendSwitches(const CommandLine& other) { - SwitchMap::const_iterator i; - for (i = other.switches_.begin(); i != other.switches_.end(); ++i) - AppendSwitchNative(i->first, i->second); -} - void CommandLine::CopySwitchesFrom(const CommandLine& source, const char* const switches[], size_t count) { for (size_t i = 0; i < count; ++i) { - if (source.HasSwitch(switches[i])) { - StringType value = source.GetSwitchValueNative(switches[i]); - AppendSwitchNative(switches[i], value); - } + if (source.HasSwitch(switches[i])) + AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i])); } } +CommandLine::StringVector CommandLine::args() const { + // Gather all arguments after the last switch (may include kSwitchTerminator). + StringVector args(argv_.begin() + begin_args_, argv_.end()); + // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?) + StringVector::iterator switch_terminator = + std::find(args.begin(), args.end(), kSwitchTerminator); + if (switch_terminator != args.end()) + args.erase(switch_terminator); + return args; +} + void CommandLine::AppendArg(const std::string& value) { #if defined(OS_WIN) DCHECK(IsStringUTF8(value)); @@ -367,117 +359,42 @@ void CommandLine::AppendArgPath(const FilePath& path) { } void CommandLine::AppendArgNative(const CommandLine::StringType& value) { -#if defined(OS_WIN) - command_line_string_.append(L" "); - command_line_string_.append(WindowsStyleQuote(value)); - args_.push_back(value); -#elif defined(OS_POSIX) - DCHECK(IsStringUTF8(value)); argv_.push_back(value); -#endif -} - -void CommandLine::AppendArgs(const CommandLine& other) { - if(other.args_.size() <= 0) - return; -#if defined(OS_WIN) - command_line_string_.append(L" --"); -#endif // OS_WIN - StringVector::const_iterator i; - for (i = other.args_.begin(); i != other.args_.end(); ++i) - AppendArgNative(*i); } void CommandLine::AppendArguments(const CommandLine& other, bool include_program) { -#if defined(OS_WIN) - // Verify include_program is used correctly. - DCHECK(!include_program || !other.GetProgram().empty()); if (include_program) - program_ = other.program_; - - if (!command_line_string_.empty()) - command_line_string_ += L' '; - - command_line_string_ += other.command_line_string_; -#elif defined(OS_POSIX) - // Verify include_program is used correctly. - // Logic could be shorter but this is clearer. - DCHECK_EQ(include_program, !other.GetProgram().empty()); - - if (include_program) - argv_[0] = other.argv_[0]; - - // Skip the first arg when copying since it's the program but push all - // arguments to our arg vector. - for (size_t i = 1; i < other.argv_.size(); ++i) - argv_.push_back(other.argv_[i]); -#endif - - SwitchMap::const_iterator i; - for (i = other.switches_.begin(); i != other.switches_.end(); ++i) - switches_[i->first] = i->second; + SetProgram(other.GetProgram()); + AppendSwitchesAndArguments(*this, other.argv()); } void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { - // The wrapper may have embedded arguments (like "gdb --args"). In this case, - // we don't pretend to do anything fancy, we just split on spaces. if (wrapper.empty()) return; - StringVector wrapper_and_args; -#if defined(OS_WIN) - base::SplitString(wrapper, ' ', &wrapper_and_args); - program_ = wrapper_and_args[0]; - command_line_string_ = wrapper + L" " + command_line_string_; -#elif defined(OS_POSIX) - base::SplitString(wrapper, ' ', &wrapper_and_args); - argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end()); -#endif + // The wrapper may have embedded arguments (like "gdb --args"). In this case, + // we don't pretend to do anything fancy, we just split on spaces. + StringVector wrapper_argv; + base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv); + // Prepend the wrapper and update the switches/arguments |begin_args_|. + argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end()); + begin_args_ += wrapper_argv.size(); } #if defined(OS_WIN) void CommandLine::ParseFromString(const std::wstring& command_line) { - TrimWhitespace(command_line, TRIM_ALL, &command_line_string_); - - if (command_line_string_.empty()) + std::wstring command_line_string; + 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); - 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) { - std::wstring arg; - TrimWhitespace(args[i], TRIM_ALL, &arg); - - if (!parse_switches) { - args_.push_back(arg); - continue; - } - - if (arg == kSwitchTerminator) { - parse_switches = false; - continue; - } - - std::string switch_string; - std::wstring switch_value; - if (IsSwitch(arg, &switch_string, &switch_value)) { - switches_[switch_string] = switch_value; - } else { - args_.push_back(arg); - } - } - - if (args) - LocalFree(args); + PLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " << + command_line; + InitFromArgv(num_args, args); + LocalFree(args); } #endif - -CommandLine::CommandLine() { -} diff --git a/base/command_line.h b/base/command_line.h index 970e4a7..d9f3138 100644 --- a/base/command_line.h +++ b/base/command_line.h @@ -3,10 +3,11 @@ // found in the LICENSE file. // This class works with command lines: building and parsing. -// Switches can optionally have a value attached using an equals sign, as in -// "-switch=value". Arguments that aren't prefixed with a switch prefix are -// saved as extra arguments. An argument of "--" will terminate switch parsing, -// causing everything after to be considered as extra arguments. +// Arguments with prefixes ('--', '-', and on Windows, '/') are switches. +// Switches will precede all other arguments without switch prefixes. +// Switches can optionally have values, delimited by '=', e.g., "-switch=value". +// An argument of "--" will terminate switch parsing during initialization, +// interpreting subsequent tokens as non-switch arguments, regardless of prefix. // There is a singleton read-only CommandLine that represents the command line // that the current process was started with. It must be initialized in main(). @@ -34,8 +35,8 @@ class BASE_API CommandLine { typedef std::string StringType; #endif + typedef StringType::value_type CharType; typedef std::vector<StringType> StringVector; - // The type of map for parsed-out switch key and values. typedef std::map<std::string, StringType> SwitchMap; // A constructor for CommandLines that only carry switches and arguments. @@ -45,10 +46,9 @@ class BASE_API CommandLine { // Construct a new command line with |program| as argv[0]. explicit CommandLine(const FilePath& program); -#if defined(OS_POSIX) - CommandLine(int argc, const char* const* argv); + // Construct a new command line from an argument list. + CommandLine(int argc, const CharType* const* argv); explicit CommandLine(const StringVector& argv); -#endif ~CommandLine(); @@ -73,23 +73,21 @@ class BASE_API CommandLine { static CommandLine FromString(const std::wstring& command_line); #endif -#if defined(OS_POSIX) // Initialize from an argv vector. - void InitFromArgv(int argc, const char* const* argv); + void InitFromArgv(int argc, const CharType* const* argv); void InitFromArgv(const StringVector& argv); -#endif - // Returns the represented command line string. + // Constructs and returns the represented command line string. // CAUTION! This should be avoided because quoting behavior is unclear. + // TODO(msw): Rename GetCommandLineString. StringType command_line_string() const; -#if defined(OS_POSIX) // Returns the original command line string as a vector of strings. const StringVector& argv() const { return argv_; } -#endif - // Returns the program part of the command line string (the first item). + // Get and Set the program part of the command line string (the first item). FilePath GetProgram() const; + void SetProgram(const FilePath& program); // Returns true if this command line contains the given switch. // (Switch names are case-insensitive). @@ -109,35 +107,35 @@ class BASE_API CommandLine { const SwitchMap& GetSwitches() const { return switches_; } // Append a switch [with optional value] to the command line. - // CAUTION! Appending a switch after the "--" switch terminator is futile! + // Note: Switches will precede arguments regardless of appending order. void AppendSwitch(const std::string& switch_string); void AppendSwitchPath(const std::string& switch_string, const FilePath& path); void AppendSwitchNative(const std::string& switch_string, const StringType& value); void AppendSwitchASCII(const std::string& switch_string, const std::string& value); - void AppendSwitches(const CommandLine& other); // Copy a set of switches (and any values) from another command line. // Commonly used when launching a subprocess. - void CopySwitchesFrom(const CommandLine& source, const char* const switches[], + void CopySwitchesFrom(const CommandLine& source, + const char* const switches[], size_t count); // Get the remaining arguments to the command. - const StringVector& args() const { return args_; } + // TODO(msw): Rename GetArgs. + StringVector args() const; // Append an argument to the command line. Note that the argument is quoted // properly such that it is interpreted as one argument to the target command. // AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8. + // Note: Switches will precede arguments regardless of appending order. void AppendArg(const std::string& value); void AppendArgPath(const FilePath& value); void AppendArgNative(const StringType& value); - void AppendArgs(const CommandLine& other); - // Append the arguments from another command line to this one. + // Append the switches and arguments from another command line to this one. // If |include_program| is true, include |other|'s program as well. - void AppendArguments(const CommandLine& other, - bool include_program); + void AppendArguments(const CommandLine& other, bool include_program); // Insert a command before the current command. // Common for debuggers, like "valgrind" or "gdb --args". @@ -150,34 +148,24 @@ class BASE_API CommandLine { #endif private: - // Disallow public default construction; a program name must be specified. + // Disallow default constructor; a program name must be explicitly specified. CommandLine(); + // Allow the copy constructor. A common pattern is to copy of the current + // process's command line and then add some flags to it. For example: + // CommandLine cl(*CommandLine::ForCurrentProcess()); + // cl.AppendSwitch(...); // The singleton CommandLine representing the current process's command line. static CommandLine* current_process_commandline_; - // We store a platform-native version of the command line, used when building - // up a new command line to be executed. This ifdef delimits that code. -#if defined(OS_WIN) - // The quoted, space-separated command line string. - StringType command_line_string_; - // The name of the program. - StringType program_; -#elif defined(OS_POSIX) - // The argv array, with the program name in argv_[0]. + // The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* } StringVector argv_; -#endif // Parsed-out switch keys and values. SwitchMap switches_; - // Non-switch command line arguments. - StringVector args_; - - // Allow the copy constructor. A common pattern is to copy the current - // process's command line and then add some flags to it. For example: - // CommandLine cl(*CommandLine::ForCurrentProcess()); - // cl.AppendSwitch(...); + // The index after the program and switches, any arguments start here. + size_t begin_args_; }; #endif // BASE_COMMAND_LINE_H_ diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc index 5ce6911..a8d1eed 100644 --- a/base/command_line_unittest.cc +++ b/base/command_line_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,32 +15,34 @@ // and quotes. // Consider the command-line argument: q\"bs1\bs2\\bs3q\\\" // Here it is with C-style escapes. -#define TRICKY_QUOTED L"q\\\"bs1\\bs2\\\\bs3q\\\\\\\"" +static const CommandLine::StringType kTrickyQuoted = + FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\""); // It should be parsed by Windows as: q"bs1\bs2\\bs3q\" // Here that is with C-style escapes. -#define TRICKY L"q\"bs1\\bs2\\\\bs3q\\\"" +static const CommandLine::StringType kTricky = + FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\""); TEST(CommandLineTest, CommandLineConstructor) { -#if defined(OS_WIN) - CommandLine cl = CommandLine::FromString( - 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"--quotes=" TRICKY_QUOTED L" " - L"-- -- --not-a-switch " - L"\"in the time of submarines...\""); - EXPECT_FALSE(cl.command_line_string().empty()); -#elif defined(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", - "--", "--", "--not-a-switch", - "in the time of submarines..."}; + const CommandLine::CharType* argv[] = { + FILE_PATH_LITERAL("program"), + FILE_PATH_LITERAL("--foo="), + FILE_PATH_LITERAL("-bAr"), + FILE_PATH_LITERAL("-spaetzel=pierogi"), + FILE_PATH_LITERAL("-baz"), + FILE_PATH_LITERAL("flim"), + FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"), + FILE_PATH_LITERAL("-spaetzle=Crepe"), + FILE_PATH_LITERAL("-=loosevalue"), + FILE_PATH_LITERAL("FLAN"), + FILE_PATH_LITERAL("--input-translation=45--output-rotation"), + FILE_PATH_LITERAL("--"), + FILE_PATH_LITERAL("--"), + FILE_PATH_LITERAL("--not-a-switch"), + FILE_PATH_LITERAL("\"in the time of submarines...\""), + FILE_PATH_LITERAL("unquoted arg-with-space")}; CommandLine cl(arraysize(argv), argv); -#endif + + EXPECT_FALSE(cl.command_line_string().empty()); EXPECT_FALSE(cl.HasSwitch("cruller")); EXPECT_FALSE(cl.HasSwitch("flim")); EXPECT_FALSE(cl.HasSwitch("program")); @@ -54,7 +56,7 @@ TEST(CommandLineTest, CommandLineConstructor) { cl.GetProgram().value()); EXPECT_TRUE(cl.HasSwitch("foo")); - EXPECT_TRUE(cl.HasSwitch("bar")); + EXPECT_TRUE(cl.HasSwitch("bAr")); EXPECT_TRUE(cl.HasSwitch("baz")); EXPECT_TRUE(cl.HasSwitch("spaetzle")); #if defined(OS_WIN) @@ -62,9 +64,66 @@ TEST(CommandLineTest, CommandLineConstructor) { #endif EXPECT_TRUE(cl.HasSwitch("other-switches")); EXPECT_TRUE(cl.HasSwitch("input-translation")); + + EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); + EXPECT_EQ("", cl.GetSwitchValueASCII("Foo")); + EXPECT_EQ("", cl.GetSwitchValueASCII("bar")); + EXPECT_EQ("", cl.GetSwitchValueASCII("cruller")); + EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( + "other-switches")); + EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); + + const std::vector<CommandLine::StringType>& args = cl.args(); + ASSERT_EQ(6U, args.size()); + + std::vector<CommandLine::StringType>::const_iterator iter = args.begin(); + EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); + ++iter; + EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); + ++iter; + EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); + ++iter; + EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter); + ++iter; + EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter); + ++iter; + EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter); + ++iter; + EXPECT_TRUE(iter == args.end()); +} + +TEST(CommandLineTest, CommandLineFromString) { #if defined(OS_WIN) + CommandLine cl = CommandLine::FromString( + 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"--quotes=" + kTrickyQuoted + L" " + L"-- -- --not-a-switch " + L"\"in the time of submarines...\""); + + EXPECT_FALSE(cl.command_line_string().empty()); + EXPECT_FALSE(cl.HasSwitch("cruller")); + EXPECT_FALSE(cl.HasSwitch("flim")); + EXPECT_FALSE(cl.HasSwitch("program")); + EXPECT_FALSE(cl.HasSwitch("dog")); + EXPECT_FALSE(cl.HasSwitch("cat")); + EXPECT_FALSE(cl.HasSwitch("output-rotation")); + EXPECT_FALSE(cl.HasSwitch("not-a-switch")); + EXPECT_FALSE(cl.HasSwitch("--")); + + EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(), + cl.GetProgram().value()); + + EXPECT_TRUE(cl.HasSwitch("foo")); + EXPECT_TRUE(cl.HasSwitch("bar")); + EXPECT_TRUE(cl.HasSwitch("baz")); + EXPECT_TRUE(cl.HasSwitch("spaetzle")); + EXPECT_TRUE(cl.HasSwitch("SPAETZLE")); + EXPECT_TRUE(cl.HasSwitch("other-switches")); + EXPECT_TRUE(cl.HasSwitch("input-translation")); EXPECT_TRUE(cl.HasSwitch("quotes")); -#endif EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); EXPECT_EQ("", cl.GetSwitchValueASCII("Foo")); @@ -73,9 +132,7 @@ TEST(CommandLineTest, CommandLineConstructor) { EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( "other-switches")); EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); -#if defined(OS_WIN) - EXPECT_EQ(TRICKY, cl.GetSwitchValueNative("quotes")); -#endif + EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes")); const std::vector<CommandLine::StringType>& args = cl.args(); ASSERT_EQ(5U, args.size()); @@ -83,7 +140,7 @@ TEST(CommandLineTest, CommandLineConstructor) { std::vector<CommandLine::StringType>::const_iterator iter = args.begin(); EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("flan"), *iter); + EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); ++iter; EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); ++iter; @@ -92,69 +149,92 @@ TEST(CommandLineTest, CommandLineConstructor) { EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter); ++iter; EXPECT_TRUE(iter == args.end()); -#if defined(OS_POSIX) - const std::vector<std::string>& argvec = cl.argv(); - for (size_t i = 0; i < argvec.size(); i++) { - EXPECT_EQ(0, argvec[i].compare(argv[i])); - } + // Check that a generated string produces an equivalent command line. + CommandLine cl_duplicate = CommandLine::FromString(cl.command_line_string()); + EXPECT_EQ(cl.command_line_string(), cl_duplicate.command_line_string()); #endif } // Tests behavior with an empty input string. TEST(CommandLineTest, EmptyString) { #if defined(OS_WIN) - CommandLine cl = CommandLine::FromString(L""); - EXPECT_TRUE(cl.command_line_string().empty()); - EXPECT_TRUE(cl.GetProgram().empty()); -#elif defined(OS_POSIX) - CommandLine cl(0, NULL); - EXPECT_TRUE(cl.argv().empty()); + CommandLine cl_from_string = CommandLine::FromString(L""); + EXPECT_TRUE(cl_from_string.command_line_string().empty()); + EXPECT_TRUE(cl_from_string.GetProgram().empty()); + EXPECT_EQ(1U, cl_from_string.argv().size()); + EXPECT_TRUE(cl_from_string.args().empty()); #endif - EXPECT_TRUE(cl.args().empty()); + CommandLine cl_from_argv(0, NULL); + EXPECT_TRUE(cl_from_argv.command_line_string().empty()); + EXPECT_TRUE(cl_from_argv.GetProgram().empty()); + EXPECT_EQ(1U, cl_from_argv.argv().size()); + EXPECT_TRUE(cl_from_argv.args().empty()); } // Test methods for appending switches to a command line. TEST(CommandLineTest, AppendSwitches) { std::string switch1 = "switch1"; std::string switch2 = "switch2"; - std::string value = "value"; + std::string value2 = "value"; std::string switch3 = "switch3"; std::string value3 = "a value with spaces"; std::string switch4 = "switch4"; std::string value4 = "\"a value with quotes\""; std::string switch5 = "quotes"; - std::string value5 = WideToUTF8(TRICKY); + CommandLine::StringType value5 = kTricky; CommandLine cl(FilePath(FILE_PATH_LITERAL("Program"))); cl.AppendSwitch(switch1); - cl.AppendSwitchASCII(switch2, value); + cl.AppendSwitchASCII(switch2, value2); cl.AppendSwitchASCII(switch3, value3); cl.AppendSwitchASCII(switch4, value4); - cl.AppendSwitchASCII(switch5, value5); + cl.AppendSwitchNative(switch5, value5); EXPECT_TRUE(cl.HasSwitch(switch1)); EXPECT_TRUE(cl.HasSwitch(switch2)); - EXPECT_EQ(value, cl.GetSwitchValueASCII(switch2)); + EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2)); EXPECT_TRUE(cl.HasSwitch(switch3)); EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3)); EXPECT_TRUE(cl.HasSwitch(switch4)); EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4)); EXPECT_TRUE(cl.HasSwitch(switch5)); - EXPECT_EQ(value5, cl.GetSwitchValueASCII(switch5)); + EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5)); #if defined(OS_WIN) - EXPECT_EQ(L"\"Program\" " + EXPECT_EQ(L"Program " L"--switch1 " L"--switch2=value " L"--switch3=\"a value with spaces\" " L"--switch4=\"\\\"a value with quotes\\\"\" " - L"--quotes=\"" TRICKY_QUOTED L"\"", + L"--quotes=\"" + kTrickyQuoted + L"\"", cl.command_line_string()); #endif } +TEST(CommandLineTest, AppendSwitchesDashDash) { + const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"), + FILE_PATH_LITERAL("--"), + FILE_PATH_LITERAL("--arg1") }; + CommandLine cl(arraysize(raw_argv), raw_argv); + + cl.AppendSwitch("switch1"); + cl.AppendSwitchASCII("switch2", "foo"); + + cl.AppendArg("--arg2"); + + EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"), + cl.command_line_string()); + CommandLine::StringVector cl_argv = cl.argv(); + EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]); + EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]); + EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]); + EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]); + EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]); + EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]); +} + // Tests that when AppendArguments is called that the program is set correctly // on the target CommandLine object and the switches from the source // CommandLine are added to the target. @@ -180,21 +260,27 @@ TEST(CommandLineTest, AppendArguments) { } #if defined(OS_WIN) -// Make sure that the program part of a command line is always quoted. +// Make sure that program paths of command_line_string are quoted as necessary. // This only makes sense on Windows and the test is basically here to guard // against regressions. TEST(CommandLineTest, ProgramQuotes) { + // Check that quotes are not added for paths without spaces. const FilePath kProgram(L"Program"); + CommandLine cl_program(kProgram); + EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value()); + EXPECT_EQ(kProgram.value(), cl_program.command_line_string()); + + const FilePath kProgramPath(L"Program Path"); // Check that quotes are not returned from GetProgram(). - CommandLine cl(kProgram); - EXPECT_EQ(kProgram.value(), cl.GetProgram().value()); - - // Verify that in the command line string, the program part is always quoted. - CommandLine::StringType cmd(cl.command_line_string()); - CommandLine::StringType program(cl.GetProgram().value()); - EXPECT_EQ('"', cmd[0]); - EXPECT_EQ(program, cmd.substr(1, program.length())); - EXPECT_EQ('"', cmd[program.length() + 1]); + CommandLine cl_program_path(kProgramPath); + EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value()); + + // Check that quotes are added to command line string paths containing spaces. + CommandLine::StringType cmd_string(cl_program_path.command_line_string()); + CommandLine::StringType program_string(cl_program_path.GetProgram().value()); + EXPECT_EQ('"', cmd_string[0]); + EXPECT_EQ(program_string, cmd_string.substr(1, program_string.length())); + EXPECT_EQ('"', cmd_string[program_string.length() + 1]); } #endif diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc index 6ecea52..ad74709 100644 --- a/chrome/browser/browser_main_win.cc +++ b/chrome/browser/browser_main_win.cc @@ -230,8 +230,7 @@ bool RegisterApplicationRestart(const CommandLine& parsed_command_line) { // The Windows Restart Manager expects a string of command line flags only, // without the program. CommandLine command_line(CommandLine::NO_PROGRAM); - command_line.AppendSwitches(parsed_command_line); - command_line.AppendArgs(parsed_command_line); + command_line.AppendArguments(parsed_command_line, false); // Ensure restore last session is set. if (!command_line.HasSwitch(switches::kRestoreLastSession)) command_line.AppendSwitch(switches::kRestoreLastSession); diff --git a/chrome/browser/process_info_snapshot_mac.cc b/chrome/browser/process_info_snapshot_mac.cc index 10fc77b..d0387b0 100644 --- a/chrome/browser/process_info_snapshot_mac.cc +++ b/chrome/browser/process_info_snapshot_mac.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -127,25 +127,23 @@ static bool ConvertByteUnitToScale(char unit, uint64_t* out_scale) { static bool GetProcessMemoryInfoUsingPS( const std::vector<base::ProcessId>& pid_list, std::map<int,ProcessInfoSnapshot::ProcInfoEntry>& proc_info_entries) { - const char kPsPathName[] = "/bin/ps"; - std::vector<std::string> argv; - argv.push_back(kPsPathName); + const FilePath kProgram("/bin/ps"); + CommandLine command_line(kProgram); // Get resident set size, virtual memory size. - argv.push_back("-o"); - argv.push_back("pid=,rss=,vsz="); + command_line.AppendArg("-o"); + command_line.AppendArg("pid=,rss=,vsz="); // Only display the specified PIDs. for (std::vector<base::ProcessId>::const_iterator it = pid_list.begin(); - it != pid_list.end(); ++it) { - argv.push_back("-p"); - argv.push_back(base::Int64ToString(static_cast<int64>(*it))); + it != pid_list.end(); ++it) { + command_line.AppendArg("-p"); + command_line.AppendArg(base::Int64ToString(static_cast<int64>(*it))); } std::string output; - CommandLine command_line(argv); // Limit output read to a megabyte for safety. if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) { - LOG(ERROR) << "Failure running " << kPsPathName << " to acquire data."; + LOG(ERROR) << "Failure running " << kProgram.value() << " to acquire data."; return false; } @@ -172,12 +170,12 @@ static bool GetProcessMemoryInfoUsingPS( in.ignore(1, ' '); // Eat the space. std::getline(in, proc_info.command); // Get the rest of the line. if (!in.good()) { - LOG(ERROR) << "Error parsing output from " << kPsPathName << "."; + LOG(ERROR) << "Error parsing output from " << kProgram.value() << "."; return false; } if (!proc_info.pid || ! proc_info.vsize) { - LOG(WARNING) << "Invalid data from " << kPsPathName << "."; + LOG(WARNING) << "Invalid data from " << kProgram.value() << "."; return false; } @@ -190,29 +188,27 @@ static bool GetProcessMemoryInfoUsingPS( static bool GetProcessMemoryInfoUsingTop( std::map<int,ProcessInfoSnapshot::ProcInfoEntry>& proc_info_entries) { - const char kTopPathName[] = "/usr/bin/top"; - std::vector<std::string> argv; - argv.push_back(kTopPathName); + const FilePath kProgram("/usr/bin/top"); + CommandLine command_line(kProgram); // -stats tells top to print just the given fields as ordered. - argv.push_back("-stats"); - argv.push_back("pid," // Process ID - "rsize," // Resident memory - "rshrd," // Resident shared memory - "rprvt," // Resident private memory - "vsize"); // Total virtual memory + command_line.AppendArg("-stats"); + command_line.AppendArg("pid," // Process ID + "rsize," // Resident memory + "rshrd," // Resident shared memory + "rprvt," // Resident private memory + "vsize"); // Total virtual memory // Run top in logging (non-interactive) mode. - argv.push_back("-l"); - argv.push_back("1"); + command_line.AppendArg("-l"); + command_line.AppendArg("1"); // Set the delay between updates to 0. - argv.push_back("-s"); - argv.push_back("0"); + command_line.AppendArg("-s"); + command_line.AppendArg("0"); std::string output; - CommandLine command_line(argv); // Limit output read to a megabyte for safety. if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) { - LOG(ERROR) << "Failure running " << kTopPathName << " to acquire data."; + LOG(ERROR) << "Failure running " << kProgram.value() << " to acquire data."; return false; } @@ -274,29 +270,28 @@ static bool GetProcessMemoryInfoUsingTop( static bool GetProcessMemoryInfoUsingTop_10_5( std::map<int,ProcessInfoSnapshot::ProcInfoEntry>& proc_info_entries) { - const char kTopPathName[] = "/usr/bin/top"; - std::vector<std::string> argv; - argv.push_back(kTopPathName); + const FilePath kProgram("/usr/bin/top"); + CommandLine command_line(kProgram); // -p tells top to print just the given fields as ordered. - argv.push_back("-p"); - argv.push_back("^aaaaaaaaaaaaaaaaaaaa " // Process ID (PID) - "^jjjjjjjjjjjjjjjjjjjj " // Resident memory (RSIZE) - "^iiiiiiiiiiiiiiiiiiii " // Resident shared memory (RSHRD) - "^hhhhhhhhhhhhhhhhhhhh " // Resident private memory (RPRVT) - "^llllllllllllllllllll"); // Total virtual memory (VSIZE) + command_line.AppendArg("-p"); + command_line.AppendArg( + "^aaaaaaaaaaaaaaaaaaaa " // Process ID (PID) + "^jjjjjjjjjjjjjjjjjjjj " // Resident memory (RSIZE) + "^iiiiiiiiiiiiiiiiiiii " // Resident shared memory (RSHRD) + "^hhhhhhhhhhhhhhhhhhhh " // Resident private memory (RPRVT) + "^llllllllllllllllllll"); // Total virtual memory (VSIZE) // Run top in logging (non-interactive) mode. - argv.push_back("-l"); - argv.push_back("1"); + command_line.AppendArg("-l"); + command_line.AppendArg("1"); // Set the delay between updates to 0. - argv.push_back("-s"); - argv.push_back("0"); + command_line.AppendArg("-s"); + command_line.AppendArg("0"); std::string output; - CommandLine command_line(argv); // Limit output read to a megabyte for safety. if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) { - LOG(ERROR) << "Failure running " << kTopPathName << " to acquire data."; + LOG(ERROR) << "Failure running " << kProgram.value() << " to acquire data."; return false; } diff --git a/chrome/browser/safe_browsing/safe_browsing_test.cc b/chrome/browser/safe_browsing/safe_browsing_test.cc index 3c8a0aa2..a13d2f4 100644 --- a/chrome/browser/safe_browsing/safe_browsing_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_test.cc @@ -141,8 +141,9 @@ class SafeBrowsingTestServer { CommandLine cmd_line(python_runtime); FilePath datafile = testserver_path.Append(datafile_); cmd_line.AppendArgPath(testserver); - cmd_line.AppendSwitchASCII("port", base::StringPrintf("%d", kPort_)); - cmd_line.AppendSwitchPath("datafile", datafile); + cmd_line.AppendArg(base::StringPrintf("--port=%d", kPort_)); + cmd_line.AppendArgNative(FILE_PATH_LITERAL("--datafile=") + + datafile.value()); if (!base::LaunchApp(cmd_line, false, true, &server_handle_)) { LOG(ERROR) << "Failed to launch server: " diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc index a01a4ae..3a72032 100644 --- a/chrome/browser/ui/browser_init.cc +++ b/chrome/browser/ui/browser_init.cc @@ -1204,7 +1204,7 @@ std::vector<GURL> BrowserInit::GetURLsFromCommandLine( const FilePath& cur_dir, Profile* profile) { std::vector<GURL> urls; - const std::vector<CommandLine::StringType>& params = command_line.args(); + CommandLine::StringVector params = command_line.args(); for (size_t i = 0; i < params.size(); ++i) { FilePath param = FilePath(params[i]); diff --git a/chrome/common/switch_utils_unittest.cc b/chrome/common/switch_utils_unittest.cc index 528030e..49f2c38 100644 --- a/chrome/common/switch_utils_unittest.cc +++ b/chrome/common/switch_utils_unittest.cc @@ -6,10 +6,34 @@ #include "base/basictypes.h" #include "base/command_line.h" +#include "base/file_path.h" #include "testing/gtest/include/gtest/gtest.h" TEST(SwitchUtilsTest, RemoveSwitches) { + const CommandLine::CharType* argv[] = { + FILE_PATH_LITERAL("program"), + FILE_PATH_LITERAL("--app=http://www.google.com/"), + FILE_PATH_LITERAL("--first-run"), + FILE_PATH_LITERAL("--import"), + FILE_PATH_LITERAL("--import-from-file=c:\\test.html"), + FILE_PATH_LITERAL("--make-default-browser"), + FILE_PATH_LITERAL("--foo"), + FILE_PATH_LITERAL("--bar")}; + CommandLine cmd_line(arraysize(argv), argv); + EXPECT_FALSE(cmd_line.command_line_string().empty()); + + std::map<std::string, CommandLine::StringType> switches = + cmd_line.GetSwitches(); + EXPECT_EQ(7U, switches.size()); + + switches::RemoveSwitchesForAutostart(&switches); + EXPECT_EQ(2U, switches.size()); + EXPECT_TRUE(cmd_line.HasSwitch("foo")); + EXPECT_TRUE(cmd_line.HasSwitch("bar")); +} + #if defined(OS_WIN) +TEST(SwitchUtilsTest, RemoveSwitchesFromString) { // All these command line args (except foo and bar) will // be removed after RemoveSwitchesForAutostart: CommandLine cmd_line = CommandLine::FromString( @@ -22,18 +46,6 @@ TEST(SwitchUtilsTest, RemoveSwitches) { L" --foo" L" --bar"); EXPECT_FALSE(cmd_line.command_line_string().empty()); -#elif defined(OS_POSIX) - const char* argv[] = { - "program", - "--app=http://www.google.com/", - "--first-run", - "--import", - "--import-from-file=c:\\test.html", - "--make-default-browser", - "--foo", - "--bar"}; - CommandLine cmd_line(arraysize(argv), argv); -#endif std::map<std::string, CommandLine::StringType> switches = cmd_line.GetSwitches(); @@ -44,3 +56,4 @@ TEST(SwitchUtilsTest, RemoveSwitches) { EXPECT_TRUE(cmd_line.HasSwitch("foo")); EXPECT_TRUE(cmd_line.HasSwitch("bar")); } +#endif diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 480e5df..6724ca2 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -356,25 +356,10 @@ int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) { } // static -void InstallUtil::MakeUninstallCommand(const std::wstring& exe_path, +void InstallUtil::MakeUninstallCommand(const std::wstring& program, const std::wstring& arguments, CommandLine* command_line) { - const bool no_program = exe_path.empty(); - - // Return a bunch of nothingness. - if (no_program && arguments.empty()) { - *command_line = CommandLine(CommandLine::NO_PROGRAM); - } else { - // Form a full command line string. - std::wstring command; - command.append(1, L'"') - .append(no_program ? L"" : exe_path) - .append(L"\" ") - .append(arguments); - - // If we have a program name, return this complete command line. - *command_line = CommandLine::FromString(command); - } + *command_line = CommandLine::FromString(L"\"" + program + L"\" " + arguments); } std::wstring InstallUtil::GetCurrentDate() { diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 5592b40..9fa9576 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h @@ -151,8 +151,8 @@ class InstallUtil { // Returns zero on install success, or an InstallStatus value otherwise. static int GetInstallReturnCode(installer::InstallStatus install_status); - // Composes |exe_path| and |arguments| into |command_line|. - static void MakeUninstallCommand(const std::wstring& exe_path, + // Composes |program| and |arguments| into |command_line|. + static void MakeUninstallCommand(const std::wstring& program, const std::wstring& arguments, CommandLine* command_line); diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc index c6031359..b6c228f 100644 --- a/chrome/installer/util/product_state_unittest.cc +++ b/chrome/installer/util/product_state_unittest.cc @@ -303,8 +303,7 @@ TEST_F(ProductStateTest, InitializeUninstallCommand) { ApplyUninstallCommand(NULL, L"--uninstall"); EXPECT_TRUE(state.Initialize(system_install_, dist_)); EXPECT_TRUE(state.GetSetupPath().empty()); - EXPECT_EQ(L"\"\" --uninstall", - state.uninstall_command().command_line_string()); + EXPECT_EQ(L" --uninstall", state.uninstall_command().command_line_string()); EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount()); } @@ -314,8 +313,18 @@ TEST_F(ProductStateTest, InitializeUninstallCommand) { ApplyUninstallCommand(L"setup.exe", NULL); EXPECT_TRUE(state.Initialize(system_install_, dist_)); EXPECT_EQ(L"setup.exe", state.GetSetupPath().value()); - EXPECT_EQ(L"\"setup.exe\"", - state.uninstall_command().command_line_string()); + EXPECT_EQ(L"setup.exe", state.uninstall_command().command_line_string()); + EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount()); + } + + // Uninstall command with exe that requires quoting. + { + ProductState state; + ApplyUninstallCommand(L"set up.exe", NULL); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ(L"set up.exe", state.GetSetupPath().value()); + EXPECT_EQ(L"\"set up.exe\"", + state.uninstall_command().command_line_string()); EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount()); } @@ -325,7 +334,7 @@ TEST_F(ProductStateTest, InitializeUninstallCommand) { ApplyUninstallCommand(L"setup.exe", L"--uninstall"); EXPECT_TRUE(state.Initialize(system_install_, dist_)); EXPECT_EQ(L"setup.exe", state.GetSetupPath().value()); - EXPECT_EQ(L"\"setup.exe\" --uninstall", + EXPECT_EQ(L"setup.exe --uninstall", state.uninstall_command().command_line_string()); EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount()); } diff --git a/chrome/test/live_sync/live_sync_test.cc b/chrome/test/live_sync/live_sync_test.cc index 2372f73..4bfc981 100644 --- a/chrome/test/live_sync/live_sync_test.cc +++ b/chrome/test/live_sync/live_sync_test.cc @@ -401,14 +401,10 @@ bool LiveSyncTest::SetUpLocalTestServer() { CommandLine* cl = CommandLine::ForCurrentProcess(); CommandLine::StringType server_cmdline_string = cl->GetSwitchValueNative( switches::kSyncServerCommandLine); -#if defined(OS_WIN) - CommandLine server_cmdline = CommandLine::FromString(server_cmdline_string); -#else - std::vector<std::string> server_cmdline_vector; - std::string delimiters(" "); + CommandLine::StringVector server_cmdline_vector; + CommandLine::StringType delimiters(FILE_PATH_LITERAL(" ")); Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector); CommandLine server_cmdline(server_cmdline_vector); -#endif if (!base::LaunchApp(server_cmdline, false, true, &test_server_handle_)) LOG(ERROR) << "Could not launch local test server."; diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc index f30fdc1..0eca725 100644 --- a/chrome/test/ui/ui_test.cc +++ b/chrome/test/ui/ui_test.cc @@ -521,6 +521,8 @@ ProxyLauncher* UITest::CreateProxyLauncher() { } static CommandLine* CreatePythonCommandLine() { + // Note: Python's first argument must be the script; do not append CommandLine + // switches, as they would precede the script path and break this CommandLine. return new CommandLine(FilePath(FILE_PATH_LITERAL("python"))); } @@ -547,11 +549,13 @@ void UITest::StartHttpServer(const FilePath& root_directory) { void UITest::StartHttpServerWithPort(const FilePath& root_directory, int port) { + // Append CommandLine arguments after the server script, switches won't work. scoped_ptr<CommandLine> cmd_line(CreateHttpServerCommandLine()); ASSERT_TRUE(cmd_line.get()); - cmd_line->AppendSwitchASCII("server", "start"); - cmd_line->AppendSwitch("register_cygwin"); - cmd_line->AppendSwitchPath("root", root_directory); + cmd_line->AppendArg("--server=start"); + cmd_line->AppendArg("--register_cygwin"); + cmd_line->AppendArgNative(FILE_PATH_LITERAL("--root=") + + root_directory.value()); FilePath layout_tests_dir; PathService::Get(base::DIR_SOURCE_ROOT, &layout_tests_dir); @@ -560,18 +564,19 @@ void UITest::StartHttpServerWithPort(const FilePath& root_directory, .AppendASCII("data") .AppendASCII("layout_tests") .AppendASCII("LayoutTests"); - cmd_line->AppendSwitchPath("layout_tests_dir", layout_tests_dir); + cmd_line->AppendArgNative(FILE_PATH_LITERAL("--layout_tests_dir=") + + layout_tests_dir.value()); // For Windows 7, if we start the lighttpd server on the foreground mode, // it will mess up with the command window and cause conhost.exe to crash. To // work around this, we start the http server on the background mode. #if defined(OS_WIN) if (base::win::GetVersion() >= base::win::VERSION_WIN7) - cmd_line->AppendSwitch("run_background"); + cmd_line->AppendArg("--run_background"); #endif if (port) - cmd_line->AppendSwitchASCII("port", base::IntToString(port)); + cmd_line->AppendArg("--port=" + base::IntToString(port)); #if defined(OS_WIN) // TODO(phajdan.jr): is this needed? @@ -585,9 +590,10 @@ void UITest::StartHttpServerWithPort(const FilePath& root_directory, } void UITest::StopHttpServer() { + // Append CommandLine arguments after the server script, switches won't work. scoped_ptr<CommandLine> cmd_line(CreateHttpServerCommandLine()); ASSERT_TRUE(cmd_line.get()); - cmd_line->AppendSwitchASCII("server", "stop"); + cmd_line->AppendArg("--server=stop"); #if defined(OS_WIN) // TODO(phajdan.jr): is this needed? diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc index e7c84aa..77ce4ff 100644 --- a/chrome/test/ui_test_utils.cc +++ b/chrome/test/ui_test_utils.cc @@ -750,17 +750,20 @@ TestWebSocketServer::TestWebSocketServer() : started_(false) { bool TestWebSocketServer::Start(const FilePath& root_directory) { if (started_) return true; + // Append CommandLine arguments after the server script, switches won't work. scoped_ptr<CommandLine> cmd_line(CreateWebSocketServerCommandLine()); - cmd_line->AppendSwitchASCII("server", "start"); - cmd_line->AppendSwitch("chromium"); - cmd_line->AppendSwitch("register_cygwin"); - cmd_line->AppendSwitchPath("root", root_directory); + cmd_line->AppendArg("--server=start"); + cmd_line->AppendArg("--chromium"); + cmd_line->AppendArg("--register_cygwin"); + cmd_line->AppendArgNative(FILE_PATH_LITERAL("--root=") + + root_directory.value()); if (!temp_dir_.CreateUniqueTempDir()) { LOG(ERROR) << "Unable to create a temporary directory."; return false; } websocket_pid_file_ = temp_dir_.path().AppendASCII("websocket.pid"); - cmd_line->AppendSwitchPath("pidfile", websocket_pid_file_); + cmd_line->AppendArgNative(FILE_PATH_LITERAL("--pidfile=") + + websocket_pid_file_.value()); SetPythonPath(); if (!base::LaunchApp(*cmd_line.get(), true, false, NULL)) { LOG(ERROR) << "Unable to launch websocket server."; @@ -771,6 +774,8 @@ bool TestWebSocketServer::Start(const FilePath& root_directory) { } CommandLine* TestWebSocketServer::CreatePythonCommandLine() { + // Note: Python's first argument must be the script; do not append CommandLine + // switches, as they would precede the script path and break this CommandLine. return new CommandLine(FilePath(FILE_PATH_LITERAL("python"))); } @@ -806,10 +811,12 @@ CommandLine* TestWebSocketServer::CreateWebSocketServerCommandLine() { TestWebSocketServer::~TestWebSocketServer() { if (!started_) return; + // Append CommandLine arguments after the server script, switches won't work. scoped_ptr<CommandLine> cmd_line(CreateWebSocketServerCommandLine()); - cmd_line->AppendSwitchASCII("server", "stop"); - cmd_line->AppendSwitch("chromium"); - cmd_line->AppendSwitchPath("pidfile", websocket_pid_file_); + cmd_line->AppendArg("--server=stop"); + cmd_line->AppendArg("--chromium"); + cmd_line->AppendArgNative(FILE_PATH_LITERAL("--pidfile=") + + websocket_pid_file_.value()); base::LaunchApp(*cmd_line.get(), true, false, NULL); } diff --git a/net/test/test_server.cc b/net/test/test_server.cc index 528d08e..bd24f73 100644 --- a/net/test/test_server.cc +++ b/net/test/test_server.cc @@ -342,9 +342,10 @@ bool TestServer::LoadTestRootCert() { } bool TestServer::AddCommandLineArguments(CommandLine* command_line) const { - command_line->AppendSwitchASCII("port", - base::IntToString(host_port_pair_.port())); - command_line->AppendSwitchPath("data-dir", document_root_); + command_line->AppendArg("--port=" + + base::IntToString(host_port_pair_.port())); + command_line->AppendArgNative(FILE_PATH_LITERAL("--data-dir=") + + document_root_.value()); if (logging::GetMinLogLevel() == logging::LOG_VERBOSE) { command_line->AppendArg("--log-to-console"); @@ -363,10 +364,11 @@ bool TestServer::AddCommandLineArguments(CommandLine* command_line) const { << " doesn't exist. Can't launch https server."; return false; } - command_line->AppendSwitchPath("https", certificate_path); + command_line->AppendArgNative(FILE_PATH_LITERAL("--https=") + + certificate_path.value()); if (https_options_.request_client_certificate) - command_line->AppendSwitch("ssl-client-auth"); + command_line->AppendArg("--ssl-client-auth"); for (std::vector<FilePath>::const_iterator it = https_options_.client_authorities.begin(); @@ -377,18 +379,19 @@ bool TestServer::AddCommandLineArguments(CommandLine* command_line) const { return false; } - command_line->AppendSwitchPath("ssl-client-ca", *it); + command_line->AppendArgNative(FILE_PATH_LITERAL("--ssl-client-ca=") + + it->value()); } - const char kBulkCipherSwitch[] = "ssl-bulk-cipher"; + const std::string kBulkCipherSwitch("--ssl-bulk-cipher"); if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_RC4) - command_line->AppendSwitchASCII(kBulkCipherSwitch, "rc4"); + command_line->AppendArg(kBulkCipherSwitch + "=rc4"); if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES128) - command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes128"); + command_line->AppendArg(kBulkCipherSwitch + "=aes128"); if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES256) - command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes256"); + command_line->AppendArg(kBulkCipherSwitch + "=aes256"); if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_3DES) - command_line->AppendSwitchASCII(kBulkCipherSwitch, "3des"); + command_line->AppendArg(kBulkCipherSwitch + "=3des"); } return true; diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc index de42fb3..10e5b8b 100644 --- a/net/test/test_server_posix.cc +++ b/net/test/test_server_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -112,8 +112,7 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { base::file_handle_mapping_vector map_write_fd; map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1])); - python_command.AppendSwitchASCII("startup-pipe", - base::IntToString(pipefd[1])); + python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1])); // Try to kill any orphaned testserver processes that may be running. OrphanedTestServerFilter filter(testserver_path.value(), diff --git a/net/test/test_server_win.cc b/net/test/test_server_win.cc index 9fc13cd..96c899e 100644 --- a/net/test/test_server_win.cc +++ b/net/test/test_server_win.cc @@ -176,8 +176,7 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { // safe to truncate the handle (when passing it from 64-bit to // 32-bit) or sign-extend the handle (when passing it from 32-bit to // 64-bit)." - python_command.AppendSwitchASCII( - "startup-pipe", + python_command.AppendArg("--startup-pipe=" + base::IntToString(reinterpret_cast<uintptr_t>(child_write))); if (!LaunchTestServerAsJob(python_command, |