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"
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"
22 #elif defined(OS_POSIX)
28 CommandLine
* CommandLine::current_process_commandline_
= NULL
;
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.
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
[] = {"--", "-"};
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.
63 for (size_t i
= 0; i
< arg
.size(); ++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
)
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.
78 for (size_t j
= 0; j
< backslash_count
; ++j
)
81 // Advance i to one before the end to balance i++ in loop.
83 } else if (arg
[i
] == '"') {
87 out
.push_back(arg
[i
]);
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)
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
);
116 switch_native
= parameter_string
.substr(
117 switch_start
, equals_position
- switch_start
);
118 *switch_value
= parameter_string
.substr(equals_position
+ 1);
121 *switch_string
= WideToASCII(switch_native
);
122 Lowercase(switch_string
);
124 *switch_string
= switch_native
;
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.
142 CommandLine::CommandLine(const FilePath
& program
) {
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());
154 #if defined(OS_POSIX)
155 CommandLine::CommandLine(int argc
, const char* const* argv
) {
156 InitFromArgv(argc
, argv
);
159 CommandLine::CommandLine(const StringVector
& argv
) {
164 CommandLine::~CommandLine() {
168 void CommandLine::Init(int argc
, const char* const* argv
) {
169 delete current_process_commandline_
;
170 current_process_commandline_
= new CommandLine
;
172 current_process_commandline_
->ParseFromString(::GetCommandLineW());
173 #elif defined(OS_POSIX)
174 current_process_commandline_
->InitFromArgv(argc
, argv
);
179 void CommandLine::Reset() {
180 DCHECK(current_process_commandline_
);
181 delete current_process_commandline_
;
182 current_process_commandline_
= NULL
;
186 CommandLine
* CommandLine::ForCurrentProcess() {
187 DCHECK(current_process_commandline_
);
188 return current_process_commandline_
;
193 CommandLine
CommandLine::FromString(const std::wstring
& command_line
) {
195 cmd
.ParseFromString(command_line
);
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
]);
207 void CommandLine::InitFromArgv(const StringVector
& 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
);
218 if (arg
== kSwitchTerminator
) {
219 parse_switches
= false;
223 std::string switch_string
;
224 StringType switch_value
;
225 if (IsSwitch(arg
, &switch_string
, &switch_value
)) {
226 switches_
[switch_string
] = switch_value
;
228 args_
.push_back(arg
);
234 CommandLine::StringType
CommandLine::command_line_string() const {
236 return command_line_string_
;
237 #elif defined(OS_POSIX)
238 return JoinString(argv_
, ' ');
242 FilePath
CommandLine::GetProgram() const {
244 return FilePath(program_
);
246 DCHECK_GT(argv_
.size(), 0U);
247 return FilePath(argv_
[0]);
251 bool CommandLine::HasSwitch(const std::string
& switch_string
) const {
252 std::string
lowercased_switch(switch_string
);
254 Lowercase(&lowercased_switch
);
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.";
267 return WideToASCII(value
);
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
);
282 Lowercase(&lowercased_switch
);
285 SwitchMap::const_iterator result
= switches_
.find(lowercased_switch
);
287 if (result
== switches_
.end()) {
288 return CommandLine::StringType();
290 return result
->second
;
294 size_t CommandLine::GetSwitchCount() const {
295 return switches_
.size();
298 void CommandLine::AppendSwitch(const std::string
& switch_string
) {
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
] = "";
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
) {
317 StringType combined_switch_string
=
318 kSwitchPrefixes
[0] + ASCIIToWide(switch_string
);
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
;
329 combined_switch_string
+= kSwitchValueSeparator
+ value
;
330 argv_
.push_back(combined_switch_string
);
331 switches_
[switch_string
] = value
;
335 void CommandLine::AppendSwitchASCII(const std::string
& switch_string
,
336 const std::string
& value_string
) {
338 AppendSwitchNative(switch_string
, ASCIIToWide(value_string
));
339 #elif defined(OS_POSIX)
340 AppendSwitchNative(switch_string
, value_string
);
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
[],
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
) {
363 DCHECK(IsStringUTF8(value
));
364 AppendArgNative(UTF8ToWide(value
));
365 #elif defined(OS_POSIX)
366 AppendArgNative(value
);
370 void CommandLine::AppendArgPath(const FilePath
& path
) {
371 AppendArgNative(path
.value());
374 void CommandLine::AppendArgNative(const CommandLine::StringType
& value
) {
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
);
385 void CommandLine::AppendArgs(const CommandLine
& other
) {
386 if(other
.args_
.size() <= 0)
389 command_line_string_
.append(L
" --");
391 StringVector::const_iterator i
;
392 for (i
= other
.args_
.begin(); i
!= other
.args_
.end(); ++i
)
396 void CommandLine::AppendArguments(const CommandLine
& other
,
397 bool include_program
) {
399 // Verify include_program is used correctly.
400 DCHECK(!include_program
|| !other
.GetProgram().empty());
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());
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
]);
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.
432 StringVector wrapper_and_args
;
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());
444 void CommandLine::ParseFromString(const std::wstring
& command_line
) {
445 TrimWhitespace(command_line
, TRIM_ALL
, &command_line_string_
);
447 if (command_line_string_
.empty())
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
) {
461 TrimWhitespace(args
[i
], TRIM_ALL
, &arg
);
463 if (!parse_switches
) {
464 args_
.push_back(arg
);
468 if (arg
== kSwitchTerminator
) {
469 parse_switches
= false;
473 std::string switch_string
;
474 std::wstring switch_value
;
475 if (IsSwitch(arg
, &switch_string
, &switch_value
)) {
476 switches_
[switch_string
] = switch_value
;
478 args_
.push_back(arg
);
487 CommandLine::CommandLine() {