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