Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
michael@0 | 2 | // Use of this source code is governed by a BSD-style license that can be |
michael@0 | 3 | // found in the LICENSE file. |
michael@0 | 4 | |
michael@0 | 5 | #include "base/command_line.h" |
michael@0 | 6 | |
michael@0 | 7 | #if defined(OS_WIN) |
michael@0 | 8 | #include <windows.h> |
michael@0 | 9 | #include <shellapi.h> |
michael@0 | 10 | #endif |
michael@0 | 11 | |
michael@0 | 12 | #include <algorithm> |
michael@0 | 13 | |
michael@0 | 14 | #include "base/logging.h" |
michael@0 | 15 | #include "base/singleton.h" |
michael@0 | 16 | #include "base/string_piece.h" |
michael@0 | 17 | #include "base/string_util.h" |
michael@0 | 18 | #include "base/sys_string_conversions.h" |
michael@0 | 19 | |
michael@0 | 20 | CommandLine* CommandLine::current_process_commandline_ = NULL; |
michael@0 | 21 | |
michael@0 | 22 | // Since we use a lazy match, make sure that longer versions (like L"--") |
michael@0 | 23 | // are listed before shorter versions (like L"-") of similar prefixes. |
michael@0 | 24 | #if defined(OS_WIN) |
michael@0 | 25 | const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; |
michael@0 | 26 | const wchar_t kSwitchTerminator[] = L"--"; |
michael@0 | 27 | const wchar_t kSwitchValueSeparator[] = L"="; |
michael@0 | 28 | #elif defined(OS_POSIX) |
michael@0 | 29 | // Unixes don't use slash as a switch. |
michael@0 | 30 | const char* const kSwitchPrefixes[] = {"--", "-"}; |
michael@0 | 31 | const char kSwitchTerminator[] = "--"; |
michael@0 | 32 | const char kSwitchValueSeparator[] = "="; |
michael@0 | 33 | #endif |
michael@0 | 34 | |
michael@0 | 35 | #if defined(OS_WIN) |
michael@0 | 36 | // Lowercase a string. This is used to lowercase switch names. |
michael@0 | 37 | // Is this what we really want? It seems crazy to me. I've left it in |
michael@0 | 38 | // for backwards compatibility on Windows. |
michael@0 | 39 | static void Lowercase(std::wstring* parameter) { |
michael@0 | 40 | transform(parameter->begin(), parameter->end(), parameter->begin(), |
michael@0 | 41 | tolower); |
michael@0 | 42 | } |
michael@0 | 43 | #endif |
michael@0 | 44 | |
michael@0 | 45 | #if defined(OS_WIN) |
michael@0 | 46 | void CommandLine::ParseFromString(const std::wstring& command_line) { |
michael@0 | 47 | TrimWhitespace(command_line, TRIM_ALL, &command_line_string_); |
michael@0 | 48 | |
michael@0 | 49 | if (command_line_string_.empty()) |
michael@0 | 50 | return; |
michael@0 | 51 | |
michael@0 | 52 | int num_args = 0; |
michael@0 | 53 | wchar_t** args = NULL; |
michael@0 | 54 | |
michael@0 | 55 | args = CommandLineToArgvW(command_line_string_.c_str(), &num_args); |
michael@0 | 56 | |
michael@0 | 57 | // Populate program_ with the trimmed version of the first arg. |
michael@0 | 58 | TrimWhitespace(args[0], TRIM_ALL, &program_); |
michael@0 | 59 | |
michael@0 | 60 | bool parse_switches = true; |
michael@0 | 61 | for (int i = 1; i < num_args; ++i) { |
michael@0 | 62 | std::wstring arg; |
michael@0 | 63 | TrimWhitespace(args[i], TRIM_ALL, &arg); |
michael@0 | 64 | |
michael@0 | 65 | if (!parse_switches) { |
michael@0 | 66 | loose_values_.push_back(arg); |
michael@0 | 67 | continue; |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | if (arg == kSwitchTerminator) { |
michael@0 | 71 | parse_switches = false; |
michael@0 | 72 | continue; |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | std::string switch_string; |
michael@0 | 76 | std::wstring switch_value; |
michael@0 | 77 | if (IsSwitch(arg, &switch_string, &switch_value)) { |
michael@0 | 78 | switches_[switch_string] = switch_value; |
michael@0 | 79 | } else { |
michael@0 | 80 | loose_values_.push_back(arg); |
michael@0 | 81 | } |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | if (args) |
michael@0 | 85 | LocalFree(args); |
michael@0 | 86 | } |
michael@0 | 87 | CommandLine::CommandLine(const std::wstring& program) { |
michael@0 | 88 | if (!program.empty()) { |
michael@0 | 89 | program_ = program; |
michael@0 | 90 | command_line_string_ = L'"' + program + L'"'; |
michael@0 | 91 | } |
michael@0 | 92 | } |
michael@0 | 93 | #elif defined(OS_POSIX) |
michael@0 | 94 | CommandLine::CommandLine(int argc, const char* const* argv) { |
michael@0 | 95 | for (int i = 0; i < argc; ++i) |
michael@0 | 96 | argv_.push_back(argv[i]); |
michael@0 | 97 | InitFromArgv(); |
michael@0 | 98 | } |
michael@0 | 99 | CommandLine::CommandLine(const std::vector<std::string>& argv) { |
michael@0 | 100 | argv_ = argv; |
michael@0 | 101 | InitFromArgv(); |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | void CommandLine::InitFromArgv() { |
michael@0 | 105 | bool parse_switches = true; |
michael@0 | 106 | for (size_t i = 1; i < argv_.size(); ++i) { |
michael@0 | 107 | const std::string& arg = argv_[i]; |
michael@0 | 108 | |
michael@0 | 109 | if (!parse_switches) { |
michael@0 | 110 | loose_values_.push_back(arg); |
michael@0 | 111 | continue; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | if (arg == kSwitchTerminator) { |
michael@0 | 115 | parse_switches = false; |
michael@0 | 116 | continue; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | std::string switch_string; |
michael@0 | 120 | std::string switch_value; |
michael@0 | 121 | if (IsSwitch(arg, &switch_string, &switch_value)) { |
michael@0 | 122 | switches_[switch_string] = switch_value; |
michael@0 | 123 | } else { |
michael@0 | 124 | loose_values_.push_back(arg); |
michael@0 | 125 | } |
michael@0 | 126 | } |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | CommandLine::CommandLine(const std::wstring& program) { |
michael@0 | 130 | argv_.push_back(WideToASCII(program)); |
michael@0 | 131 | } |
michael@0 | 132 | #endif |
michael@0 | 133 | |
michael@0 | 134 | // static |
michael@0 | 135 | bool CommandLine::IsSwitch(const StringType& parameter_string, |
michael@0 | 136 | std::string* switch_string, |
michael@0 | 137 | StringType* switch_value) { |
michael@0 | 138 | switch_string->clear(); |
michael@0 | 139 | switch_value->clear(); |
michael@0 | 140 | |
michael@0 | 141 | for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { |
michael@0 | 142 | StringType prefix(kSwitchPrefixes[i]); |
michael@0 | 143 | if (parameter_string.find(prefix) != 0) |
michael@0 | 144 | continue; |
michael@0 | 145 | |
michael@0 | 146 | const size_t switch_start = prefix.length(); |
michael@0 | 147 | const size_t equals_position = parameter_string.find( |
michael@0 | 148 | kSwitchValueSeparator, switch_start); |
michael@0 | 149 | StringType switch_native; |
michael@0 | 150 | if (equals_position == StringType::npos) { |
michael@0 | 151 | switch_native = parameter_string.substr(switch_start); |
michael@0 | 152 | } else { |
michael@0 | 153 | switch_native = parameter_string.substr( |
michael@0 | 154 | switch_start, equals_position - switch_start); |
michael@0 | 155 | *switch_value = parameter_string.substr(equals_position + 1); |
michael@0 | 156 | } |
michael@0 | 157 | #if defined(OS_WIN) |
michael@0 | 158 | Lowercase(&switch_native); |
michael@0 | 159 | *switch_string = WideToASCII(switch_native); |
michael@0 | 160 | #else |
michael@0 | 161 | *switch_string = switch_native; |
michael@0 | 162 | #endif |
michael@0 | 163 | |
michael@0 | 164 | return true; |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | return false; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | // static |
michael@0 | 171 | void CommandLine::Init(int argc, const char* const* argv) { |
michael@0 | 172 | DCHECK(current_process_commandline_ == NULL); |
michael@0 | 173 | #if defined(OS_WIN) |
michael@0 | 174 | current_process_commandline_ = new CommandLine; |
michael@0 | 175 | current_process_commandline_->ParseFromString(::GetCommandLineW()); |
michael@0 | 176 | #elif defined(OS_POSIX) |
michael@0 | 177 | current_process_commandline_ = new CommandLine(argc, argv); |
michael@0 | 178 | #endif |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | void CommandLine::Terminate() { |
michael@0 | 182 | DCHECK(current_process_commandline_ != NULL); |
michael@0 | 183 | delete current_process_commandline_; |
michael@0 | 184 | current_process_commandline_ = NULL; |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | bool CommandLine::HasSwitch(const std::wstring& switch_string) const { |
michael@0 | 188 | std::wstring lowercased_switch(switch_string); |
michael@0 | 189 | #if defined(OS_WIN) |
michael@0 | 190 | Lowercase(&lowercased_switch); |
michael@0 | 191 | #endif |
michael@0 | 192 | return switches_.find(WideToASCII(lowercased_switch)) != switches_.end(); |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | std::wstring CommandLine::GetSwitchValue( |
michael@0 | 196 | const std::wstring& switch_string) const { |
michael@0 | 197 | std::wstring lowercased_switch(switch_string); |
michael@0 | 198 | #if defined(OS_WIN) |
michael@0 | 199 | Lowercase(&lowercased_switch); |
michael@0 | 200 | #endif |
michael@0 | 201 | |
michael@0 | 202 | std::map<std::string, StringType>::const_iterator result = |
michael@0 | 203 | switches_.find(WideToASCII(lowercased_switch)); |
michael@0 | 204 | |
michael@0 | 205 | if (result == switches_.end()) { |
michael@0 | 206 | return L""; |
michael@0 | 207 | } else { |
michael@0 | 208 | #if defined(OS_WIN) |
michael@0 | 209 | return result->second; |
michael@0 | 210 | #else |
michael@0 | 211 | return ASCIIToWide(result->second); |
michael@0 | 212 | #endif |
michael@0 | 213 | } |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | #if defined(OS_WIN) |
michael@0 | 217 | std::vector<std::wstring> CommandLine::GetLooseValues() const { |
michael@0 | 218 | return loose_values_; |
michael@0 | 219 | } |
michael@0 | 220 | std::wstring CommandLine::program() const { |
michael@0 | 221 | return program_; |
michael@0 | 222 | } |
michael@0 | 223 | #else |
michael@0 | 224 | std::vector<std::wstring> CommandLine::GetLooseValues() const { |
michael@0 | 225 | std::vector<std::wstring> values; |
michael@0 | 226 | for (size_t i = 0; i < loose_values_.size(); ++i) |
michael@0 | 227 | values.push_back(ASCIIToWide(loose_values_[i])); |
michael@0 | 228 | return values; |
michael@0 | 229 | } |
michael@0 | 230 | std::wstring CommandLine::program() const { |
michael@0 | 231 | DCHECK(argv_.size() > 0); |
michael@0 | 232 | return ASCIIToWide(argv_[0]); |
michael@0 | 233 | } |
michael@0 | 234 | #endif |
michael@0 | 235 | |
michael@0 | 236 | |
michael@0 | 237 | // static |
michael@0 | 238 | std::wstring CommandLine::PrefixedSwitchString( |
michael@0 | 239 | const std::wstring& switch_string) { |
michael@0 | 240 | return StringPrintf(L"%ls%ls", |
michael@0 | 241 | kSwitchPrefixes[0], |
michael@0 | 242 | switch_string.c_str()); |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | // static |
michael@0 | 246 | std::wstring CommandLine::PrefixedSwitchStringWithValue( |
michael@0 | 247 | const std::wstring& switch_string, const std::wstring& value_string) { |
michael@0 | 248 | if (value_string.empty()) { |
michael@0 | 249 | return PrefixedSwitchString(switch_string); |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | return StringPrintf(L"%ls%ls%ls%ls", |
michael@0 | 253 | kSwitchPrefixes[0], |
michael@0 | 254 | switch_string.c_str(), |
michael@0 | 255 | kSwitchValueSeparator, |
michael@0 | 256 | value_string.c_str()); |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | #if defined(OS_WIN) |
michael@0 | 260 | void CommandLine::AppendSwitch(const std::wstring& switch_string) { |
michael@0 | 261 | std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string); |
michael@0 | 262 | command_line_string_.append(L" "); |
michael@0 | 263 | command_line_string_.append(prefixed_switch_string); |
michael@0 | 264 | switches_[WideToASCII(switch_string)] = L""; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | // Quote a string if necessary, such that CommandLineToArgvW() will |
michael@0 | 268 | // always process it as a single argument. |
michael@0 | 269 | static std::wstring WindowsStyleQuote(const std::wstring& arg) { |
michael@0 | 270 | // We follow the quoting rules of CommandLineToArgvW. |
michael@0 | 271 | // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx |
michael@0 | 272 | if (arg.find_first_of(L" \\\"\t") == std::wstring::npos) { |
michael@0 | 273 | // No quoting necessary. |
michael@0 | 274 | return arg; |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | std::wstring out; |
michael@0 | 278 | out.push_back(L'"'); |
michael@0 | 279 | for (size_t i = 0; i < arg.size(); ++i) { |
michael@0 | 280 | if (arg[i] == '\\') { |
michael@0 | 281 | // Find the extent of this run of backslashes. |
michael@0 | 282 | size_t start = i, end = start + 1; |
michael@0 | 283 | for (; end < arg.size() && arg[end] == '\\'; ++end) |
michael@0 | 284 | /* empty */; |
michael@0 | 285 | size_t backslash_count = end - start; |
michael@0 | 286 | |
michael@0 | 287 | // Backslashes are escapes only if the run is followed by a double quote. |
michael@0 | 288 | // Since we also will end the string with a double quote, we escape for |
michael@0 | 289 | // either a double quote or the end of the string. |
michael@0 | 290 | if (end == arg.size() || arg[end] == '"') { |
michael@0 | 291 | // To quote, we need to output 2x as many backslashes. |
michael@0 | 292 | backslash_count *= 2; |
michael@0 | 293 | } |
michael@0 | 294 | for (size_t j = 0; j < backslash_count; ++j) |
michael@0 | 295 | out.push_back('\\'); |
michael@0 | 296 | |
michael@0 | 297 | // Advance i to one before the end to balance i++ in loop. |
michael@0 | 298 | i = end - 1; |
michael@0 | 299 | } else if (arg[i] == '"') { |
michael@0 | 300 | out.push_back('\\'); |
michael@0 | 301 | out.push_back('"'); |
michael@0 | 302 | } else { |
michael@0 | 303 | out.push_back(arg[i]); |
michael@0 | 304 | } |
michael@0 | 305 | } |
michael@0 | 306 | out.push_back('"'); |
michael@0 | 307 | |
michael@0 | 308 | return out; |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string, |
michael@0 | 312 | const std::wstring& value_string) { |
michael@0 | 313 | std::wstring quoted_value_string = WindowsStyleQuote(value_string); |
michael@0 | 314 | std::wstring combined_switch_string = |
michael@0 | 315 | PrefixedSwitchStringWithValue(switch_string, quoted_value_string); |
michael@0 | 316 | |
michael@0 | 317 | command_line_string_.append(L" "); |
michael@0 | 318 | command_line_string_.append(combined_switch_string); |
michael@0 | 319 | |
michael@0 | 320 | switches_[WideToASCII(switch_string)] = value_string; |
michael@0 | 321 | } |
michael@0 | 322 | |
michael@0 | 323 | void CommandLine::AppendLooseValue(const std::wstring& value) { |
michael@0 | 324 | command_line_string_.append(L" "); |
michael@0 | 325 | command_line_string_.append(WindowsStyleQuote(value)); |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | void CommandLine::AppendArguments(const CommandLine& other, |
michael@0 | 329 | bool include_program) { |
michael@0 | 330 | // Verify include_program is used correctly. |
michael@0 | 331 | // Logic could be shorter but this is clearer. |
michael@0 | 332 | DCHECK(include_program ? !other.program().empty() : other.program().empty()); |
michael@0 | 333 | command_line_string_ += L" " + other.command_line_string_; |
michael@0 | 334 | std::map<std::string, StringType>::const_iterator i; |
michael@0 | 335 | for (i = other.switches_.begin(); i != other.switches_.end(); ++i) |
michael@0 | 336 | switches_[i->first] = i->second; |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | void CommandLine::PrependWrapper(const std::wstring& wrapper) { |
michael@0 | 340 | // The wrapper may have embedded arguments (like "gdb --args"). In this case, |
michael@0 | 341 | // we don't pretend to do anything fancy, we just split on spaces. |
michael@0 | 342 | std::vector<std::wstring> wrapper_and_args; |
michael@0 | 343 | SplitString(wrapper, ' ', &wrapper_and_args); |
michael@0 | 344 | program_ = wrapper_and_args[0]; |
michael@0 | 345 | command_line_string_ = wrapper + L" " + command_line_string_; |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | #elif defined(OS_POSIX) |
michael@0 | 349 | void CommandLine::AppendSwitch(const std::wstring& switch_string) { |
michael@0 | 350 | std::string ascii_switch = WideToASCII(switch_string); |
michael@0 | 351 | argv_.push_back(kSwitchPrefixes[0] + ascii_switch); |
michael@0 | 352 | switches_[ascii_switch] = ""; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string, |
michael@0 | 356 | const std::wstring& value_string) { |
michael@0 | 357 | std::string ascii_switch = WideToASCII(switch_string); |
michael@0 | 358 | std::string ascii_value = WideToASCII(value_string); |
michael@0 | 359 | |
michael@0 | 360 | argv_.push_back(kSwitchPrefixes[0] + ascii_switch + |
michael@0 | 361 | kSwitchValueSeparator + ascii_value); |
michael@0 | 362 | switches_[ascii_switch] = ascii_value; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | void CommandLine::AppendLooseValue(const std::wstring& value) { |
michael@0 | 366 | argv_.push_back(WideToASCII(value)); |
michael@0 | 367 | } |
michael@0 | 368 | |
michael@0 | 369 | void CommandLine::AppendArguments(const CommandLine& other, |
michael@0 | 370 | bool include_program) { |
michael@0 | 371 | // Verify include_program is used correctly. |
michael@0 | 372 | // Logic could be shorter but this is clearer. |
michael@0 | 373 | DCHECK(include_program ? !other.program().empty() : other.program().empty()); |
michael@0 | 374 | |
michael@0 | 375 | size_t first_arg = include_program ? 0 : 1; |
michael@0 | 376 | for (size_t i = first_arg; i < other.argv_.size(); ++i) |
michael@0 | 377 | argv_.push_back(other.argv_[i]); |
michael@0 | 378 | std::map<std::string, StringType>::const_iterator i; |
michael@0 | 379 | for (i = other.switches_.begin(); i != other.switches_.end(); ++i) |
michael@0 | 380 | switches_[i->first] = i->second; |
michael@0 | 381 | } |
michael@0 | 382 | |
michael@0 | 383 | void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) { |
michael@0 | 384 | // The wrapper may have embedded arguments (like "gdb --args"). In this case, |
michael@0 | 385 | // we don't pretend to do anything fancy, we just split on spaces. |
michael@0 | 386 | const std::string wrapper = WideToASCII(wrapper_wide); |
michael@0 | 387 | std::vector<std::string> wrapper_and_args; |
michael@0 | 388 | SplitString(wrapper, ' ', &wrapper_and_args); |
michael@0 | 389 | argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end()); |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | #endif |