Use C scalar-type versions of the cryptohome API in cryptohome_library
[chromium-blink-merge.git] / base / command_line.cc
blobfcb229400ebe783c5ba09455069778e4e2c60f7e
1 // Copyright (c) 2011 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 #include <algorithm>
9 #include "base/file_path.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/singleton.h"
13 #include "base/string_split.h"
14 #include "base/string_util.h"
15 #include "base/sys_string_conversions.h"
16 #include "base/utf_string_conversions.h"
17 #include "build/build_config.h"
19 #if defined(OS_WIN)
20 #include <windows.h>
21 #include <shellapi.h>
22 #elif defined(OS_POSIX)
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #endif
28 CommandLine* CommandLine::current_process_commandline_ = NULL;
30 namespace {
31 typedef CommandLine::StringType::value_type CharType;
33 const CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
34 const CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
35 // Since we use a lazy match, make sure that longer versions (like "--") are
36 // listed before shorter versions (like "-") of similar prefixes.
37 #if defined(OS_WIN)
38 const CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
39 #elif defined(OS_POSIX)
40 // Unixes don't use slash as a switch.
41 const CharType* const kSwitchPrefixes[] = {"--", "-"};
42 #endif
44 #if defined(OS_WIN)
45 // Lowercase a string for case-insensitivity of switches.
46 // Is this desirable? It exists for backwards compatibility on Windows.
47 void Lowercase(std::string* arg) {
48 transform(arg->begin(), arg->end(), arg->begin(), tolower);
51 // Quote a string if necessary, such that CommandLineToArgvW() will always
52 // process it as a single argument.
53 std::wstring WindowsStyleQuote(const std::wstring& arg) {
54 // We follow the quoting rules of CommandLineToArgvW.
55 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
56 if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
57 // No quoting necessary.
58 return arg;
61 std::wstring out;
62 out.push_back(L'"');
63 for (size_t i = 0; i < arg.size(); ++i) {
64 if (arg[i] == '\\') {
65 // Find the extent of this run of backslashes.
66 size_t start = i, end = start + 1;
67 for (; end < arg.size() && arg[end] == '\\'; ++end)
68 /* empty */;
69 size_t backslash_count = end - start;
71 // Backslashes are escapes only if the run is followed by a double quote.
72 // Since we also will end the string with a double quote, we escape for
73 // either a double quote or the end of the string.
74 if (end == arg.size() || arg[end] == '"') {
75 // To quote, we need to output 2x as many backslashes.
76 backslash_count *= 2;
78 for (size_t j = 0; j < backslash_count; ++j)
79 out.push_back('\\');
81 // Advance i to one before the end to balance i++ in loop.
82 i = end - 1;
83 } else if (arg[i] == '"') {
84 out.push_back('\\');
85 out.push_back('"');
86 } else {
87 out.push_back(arg[i]);
90 out.push_back('"');
92 return out;
94 #endif
96 // Returns true and fills in |switch_string| and |switch_value| if
97 // |parameter_string| represents a switch.
98 bool IsSwitch(const CommandLine::StringType& parameter_string,
99 std::string* switch_string,
100 CommandLine::StringType* switch_value) {
101 switch_string->clear();
102 switch_value->clear();
104 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
105 CommandLine::StringType prefix(kSwitchPrefixes[i]);
106 if (parameter_string.find(prefix) != 0)
107 continue;
109 const size_t switch_start = prefix.length();
110 const size_t equals_position = parameter_string.find(
111 kSwitchValueSeparator, switch_start);
112 CommandLine::StringType switch_native;
113 if (equals_position == CommandLine::StringType::npos) {
114 switch_native = parameter_string.substr(switch_start);
115 } else {
116 switch_native = parameter_string.substr(
117 switch_start, equals_position - switch_start);
118 *switch_value = parameter_string.substr(equals_position + 1);
120 #if defined(OS_WIN)
121 *switch_string = WideToASCII(switch_native);
122 Lowercase(switch_string);
123 #else
124 *switch_string = switch_native;
125 #endif
127 return true;
130 return false;
133 } // namespace
135 CommandLine::CommandLine(NoProgram no_program) {
136 #if defined(OS_POSIX)
137 // Push an empty argument, because we always assume argv_[0] is a program.
138 argv_.push_back("");
139 #endif
142 CommandLine::CommandLine(const FilePath& program) {
143 #if defined(OS_WIN)
144 if (!program.empty()) {
145 program_ = program.value();
146 // TODO(evanm): proper quoting here.
147 command_line_string_ = L'"' + program.value() + L'"';
149 #elif defined(OS_POSIX)
150 argv_.push_back(program.value());
151 #endif
154 #if defined(OS_POSIX)
155 CommandLine::CommandLine(int argc, const char* const* argv) {
156 InitFromArgv(argc, argv);
159 CommandLine::CommandLine(const StringVector& argv) {
160 InitFromArgv(argv);
162 #endif // OS_POSIX
164 CommandLine::~CommandLine() {
167 // static
168 void CommandLine::Init(int argc, const char* const* argv) {
169 delete current_process_commandline_;
170 current_process_commandline_ = new CommandLine;
171 #if defined(OS_WIN)
172 current_process_commandline_->ParseFromString(::GetCommandLineW());
173 #elif defined(OS_POSIX)
174 current_process_commandline_->InitFromArgv(argc, argv);
175 #endif
178 // static
179 void CommandLine::Reset() {
180 DCHECK(current_process_commandline_);
181 delete current_process_commandline_;
182 current_process_commandline_ = NULL;
185 // static
186 CommandLine* CommandLine::ForCurrentProcess() {
187 DCHECK(current_process_commandline_);
188 return current_process_commandline_;
191 #if defined(OS_WIN)
192 // static
193 CommandLine CommandLine::FromString(const std::wstring& command_line) {
194 CommandLine cmd;
195 cmd.ParseFromString(command_line);
196 return cmd;
198 #endif // OS_WIN
200 #if defined(OS_POSIX)
201 void CommandLine::InitFromArgv(int argc, const char* const* argv) {
202 for (int i = 0; i < argc; ++i)
203 argv_.push_back(argv[i]);
204 InitFromArgv(argv_);
207 void CommandLine::InitFromArgv(const StringVector& argv) {
208 argv_ = argv;
209 bool parse_switches = true;
210 for (size_t i = 1; i < argv_.size(); ++i) {
211 const std::string& arg = argv_[i];
213 if (!parse_switches) {
214 args_.push_back(arg);
215 continue;
218 if (arg == kSwitchTerminator) {
219 parse_switches = false;
220 continue;
223 std::string switch_string;
224 StringType switch_value;
225 if (IsSwitch(arg, &switch_string, &switch_value)) {
226 switches_[switch_string] = switch_value;
227 } else {
228 args_.push_back(arg);
232 #endif // OS_POSIX
234 CommandLine::StringType CommandLine::command_line_string() const {
235 #if defined(OS_WIN)
236 return command_line_string_;
237 #elif defined(OS_POSIX)
238 return JoinString(argv_, ' ');
239 #endif
242 FilePath CommandLine::GetProgram() const {
243 #if defined(OS_WIN)
244 return FilePath(program_);
245 #else
246 DCHECK_GT(argv_.size(), 0U);
247 return FilePath(argv_[0]);
248 #endif
251 bool CommandLine::HasSwitch(const std::string& switch_string) const {
252 std::string lowercased_switch(switch_string);
253 #if defined(OS_WIN)
254 Lowercase(&lowercased_switch);
255 #endif
256 return switches_.find(lowercased_switch) != switches_.end();
259 std::string CommandLine::GetSwitchValueASCII(
260 const std::string& switch_string) const {
261 CommandLine::StringType value = GetSwitchValueNative(switch_string);
262 if (!IsStringASCII(value)) {
263 LOG(WARNING) << "Value of --" << switch_string << " must be ASCII.";
264 return "";
266 #if defined(OS_WIN)
267 return WideToASCII(value);
268 #else
269 return value;
270 #endif
273 FilePath CommandLine::GetSwitchValuePath(
274 const std::string& switch_string) const {
275 return FilePath(GetSwitchValueNative(switch_string));
278 CommandLine::StringType CommandLine::GetSwitchValueNative(
279 const std::string& switch_string) const {
280 std::string lowercased_switch(switch_string);
281 #if defined(OS_WIN)
282 Lowercase(&lowercased_switch);
283 #endif
285 SwitchMap::const_iterator result = switches_.find(lowercased_switch);
287 if (result == switches_.end()) {
288 return CommandLine::StringType();
289 } else {
290 return result->second;
294 size_t CommandLine::GetSwitchCount() const {
295 return switches_.size();
298 void CommandLine::AppendSwitch(const std::string& switch_string) {
299 #if defined(OS_WIN)
300 command_line_string_.append(L" ");
301 command_line_string_.append(kSwitchPrefixes[0] + ASCIIToWide(switch_string));
302 switches_[switch_string] = L"";
303 #elif defined(OS_POSIX)
304 argv_.push_back(kSwitchPrefixes[0] + switch_string);
305 switches_[switch_string] = "";
306 #endif
309 void CommandLine::AppendSwitchPath(const std::string& switch_string,
310 const FilePath& path) {
311 AppendSwitchNative(switch_string, path.value());
314 void CommandLine::AppendSwitchNative(const std::string& switch_string,
315 const CommandLine::StringType& value) {
316 #if defined(OS_WIN)
317 StringType combined_switch_string =
318 kSwitchPrefixes[0] + ASCIIToWide(switch_string);
319 if (!value.empty())
320 combined_switch_string += kSwitchValueSeparator + WindowsStyleQuote(value);
322 command_line_string_.append(L" ");
323 command_line_string_.append(combined_switch_string);
325 switches_[switch_string] = value;
326 #elif defined(OS_POSIX)
327 StringType combined_switch_string = kSwitchPrefixes[0] + switch_string;
328 if (!value.empty())
329 combined_switch_string += kSwitchValueSeparator + value;
330 argv_.push_back(combined_switch_string);
331 switches_[switch_string] = value;
332 #endif
335 void CommandLine::AppendSwitchASCII(const std::string& switch_string,
336 const std::string& value_string) {
337 #if defined(OS_WIN)
338 AppendSwitchNative(switch_string, ASCIIToWide(value_string));
339 #elif defined(OS_POSIX)
340 AppendSwitchNative(switch_string, value_string);
341 #endif
344 void CommandLine::AppendSwitches(const CommandLine& other) {
345 SwitchMap::const_iterator i;
346 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
347 AppendSwitchNative(i->first, i->second);
350 void CommandLine::CopySwitchesFrom(const CommandLine& source,
351 const char* const switches[],
352 size_t count) {
353 for (size_t i = 0; i < count; ++i) {
354 if (source.HasSwitch(switches[i])) {
355 StringType value = source.GetSwitchValueNative(switches[i]);
356 AppendSwitchNative(switches[i], value);
361 void CommandLine::AppendArg(const std::string& value) {
362 #if defined(OS_WIN)
363 DCHECK(IsStringUTF8(value));
364 AppendArgNative(UTF8ToWide(value));
365 #elif defined(OS_POSIX)
366 AppendArgNative(value);
367 #endif
370 void CommandLine::AppendArgPath(const FilePath& path) {
371 AppendArgNative(path.value());
374 void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
375 #if defined(OS_WIN)
376 command_line_string_.append(L" ");
377 command_line_string_.append(WindowsStyleQuote(value));
378 args_.push_back(value);
379 #elif defined(OS_POSIX)
380 DCHECK(IsStringUTF8(value));
381 argv_.push_back(value);
382 #endif
385 void CommandLine::AppendArgs(const CommandLine& other) {
386 if(other.args_.size() <= 0)
387 return;
388 #if defined(OS_WIN)
389 command_line_string_.append(L" --");
390 #endif // OS_WIN
391 StringVector::const_iterator i;
392 for (i = other.args_.begin(); i != other.args_.end(); ++i)
393 AppendArgNative(*i);
396 void CommandLine::AppendArguments(const CommandLine& other,
397 bool include_program) {
398 #if defined(OS_WIN)
399 // Verify include_program is used correctly.
400 DCHECK(!include_program || !other.GetProgram().empty());
401 if (include_program)
402 program_ = other.program_;
404 if (!command_line_string_.empty())
405 command_line_string_ += L' ';
407 command_line_string_ += other.command_line_string_;
408 #elif defined(OS_POSIX)
409 // Verify include_program is used correctly.
410 // Logic could be shorter but this is clearer.
411 DCHECK_EQ(include_program, !other.GetProgram().empty());
413 if (include_program)
414 argv_[0] = other.argv_[0];
416 // Skip the first arg when copying since it's the program but push all
417 // arguments to our arg vector.
418 for (size_t i = 1; i < other.argv_.size(); ++i)
419 argv_.push_back(other.argv_[i]);
420 #endif
422 SwitchMap::const_iterator i;
423 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
424 switches_[i->first] = i->second;
427 void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
428 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
429 // we don't pretend to do anything fancy, we just split on spaces.
430 if (wrapper.empty())
431 return;
432 StringVector wrapper_and_args;
433 #if defined(OS_WIN)
434 base::SplitString(wrapper, ' ', &wrapper_and_args);
435 program_ = wrapper_and_args[0];
436 command_line_string_ = wrapper + L" " + command_line_string_;
437 #elif defined(OS_POSIX)
438 base::SplitString(wrapper, ' ', &wrapper_and_args);
439 argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
440 #endif
443 #if defined(OS_WIN)
444 void CommandLine::ParseFromString(const std::wstring& command_line) {
445 TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
447 if (command_line_string_.empty())
448 return;
450 int num_args = 0;
451 wchar_t** args = NULL;
453 args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
455 // Populate program_ with the trimmed version of the first arg.
456 TrimWhitespace(args[0], TRIM_ALL, &program_);
458 bool parse_switches = true;
459 for (int i = 1; i < num_args; ++i) {
460 std::wstring arg;
461 TrimWhitespace(args[i], TRIM_ALL, &arg);
463 if (!parse_switches) {
464 args_.push_back(arg);
465 continue;
468 if (arg == kSwitchTerminator) {
469 parse_switches = false;
470 continue;
473 std::string switch_string;
474 std::wstring switch_value;
475 if (IsSwitch(arg, &switch_string, &switch_value)) {
476 switches_[switch_string] = switch_value;
477 } else {
478 args_.push_back(arg);
482 if (args)
483 LocalFree(args);
485 #endif
487 CommandLine::CommandLine() {