ipc/chromium/src/base/command_line.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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

mercurial