blob: e49254f497cd2cf6070f0ecaf3c8ac0097521a32 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.
initial.commitd7cae122008-07-26 21:49:384
[email protected]f3adb5c2008-08-07 20:07:325#include "base/command_line.h"
6
7#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:388#include <windows.h>
9#include <shellapi.h>
[email protected]f3adb5c2008-08-07 20:07:3210#endif
initial.commitd7cae122008-07-26 21:49:3811
12#include <algorithm>
13
initial.commitd7cae122008-07-26 21:49:3814#include "base/logging.h"
15#include "base/singleton.h"
[email protected]4bdaceb42008-08-19 13:19:2416#include "base/string_piece.h"
initial.commitd7cae122008-07-26 21:49:3817#include "base/string_util.h"
[email protected]05b5d792008-08-07 22:28:2418#include "base/sys_string_conversions.h"
initial.commitd7cae122008-07-26 21:49:3819
[email protected]bb975362009-01-21 01:00:2220CommandLine* CommandLine::current_process_commandline_ = NULL;
initial.commitd7cae122008-07-26 21:49:3821
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.
[email protected]5d426332008-08-08 20:46:2124#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2225const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
26const wchar_t kSwitchTerminator[] = L"--";
27const wchar_t kSwitchValueSeparator[] = L"=";
[email protected]5d426332008-08-08 20:46:2128#elif defined(OS_POSIX)
[email protected]1a48f312008-08-12 01:14:3729// Unixes don't use slash as a switch.
[email protected]bb975362009-01-21 01:00:2230const char* const kSwitchPrefixes[] = {"--", "-"};
31const char kSwitchTerminator[] = "--";
32const char kSwitchValueSeparator[] = "=";
[email protected]5d426332008-08-08 20:46:2133#endif
initial.commitd7cae122008-07-26 21:49:3834
[email protected]f3adb5c2008-08-07 20:07:3235#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2236// 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.
39static void Lowercase(std::wstring* parameter) {
40 transform(parameter->begin(), parameter->end(), parameter->begin(),
41 tolower);
initial.commitd7cae122008-07-26 21:49:3842}
[email protected]bb975362009-01-21 01:00:2243#endif
initial.commitd7cae122008-07-26 21:49:3844
[email protected]f3adb5c2008-08-07 20:07:3245#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2246void CommandLine::ParseFromString(const std::wstring& command_line) {
47 TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
48
49 if (command_line_string_.empty())
50 return;
51
52 int num_args = 0;
53 wchar_t** args = NULL;
54
55 args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
56
57 // Populate program_ with the trimmed version of the first arg.
58 TrimWhitespace(args[0], TRIM_ALL, &program_);
59
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);
64
65 if (!parse_switches) {
66 loose_values_.push_back(arg);
67 continue;
68 }
69
70 if (arg == kSwitchTerminator) {
71 parse_switches = false;
72 continue;
73 }
74
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 }
83
84 if (args)
85 LocalFree(args);
86}
87CommandLine::CommandLine(const std::wstring& program) {
88 if (!program.empty()) {
89 program_ = program;
90 command_line_string_ = L'"' + program + L'"';
91 }
initial.commitd7cae122008-07-26 21:49:3892}
[email protected]f3adb5c2008-08-07 20:07:3293#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:2294CommandLine::CommandLine(int argc, const char* const* argv) {
95 for (int i = 0; i < argc; ++i)
96 argv_.push_back(argv[i]);
97 InitFromArgv();
98}
99CommandLine::CommandLine(const std::vector<std::string>& argv) {
100 argv_ = argv;
101 InitFromArgv();
[email protected]f3adb5c2008-08-07 20:07:32102}
[email protected]10e42bf2008-10-15 21:59:08103
[email protected]bb975362009-01-21 01:00:22104void CommandLine::InitFromArgv() {
105 bool parse_switches = true;
106 for (size_t i = 1; i < argv_.size(); ++i) {
107 const std::string& arg = argv_[i];
108
109 if (!parse_switches) {
110 loose_values_.push_back(arg);
111 continue;
112 }
113
114 if (arg == kSwitchTerminator) {
115 parse_switches = false;
116 continue;
117 }
118
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 }
[email protected]10e42bf2008-10-15 21:59:08126 }
[email protected]bb975362009-01-21 01:00:22127}
128
129CommandLine::CommandLine(const std::wstring& program) {
130 argv_.push_back(WideToASCII(program));
[email protected]10e42bf2008-10-15 21:59:08131}
[email protected]f3adb5c2008-08-07 20:07:32132#endif
initial.commitd7cae122008-07-26 21:49:38133
[email protected]bb975362009-01-21 01:00:22134// static
135bool CommandLine::IsSwitch(const StringType& parameter_string,
136 std::string* switch_string,
137 StringType* switch_value) {
138 switch_string->clear();
139 switch_value->clear();
140
141 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
142 StringType prefix(kSwitchPrefixes[i]);
143 if (parameter_string.find(prefix) != 0)
144 continue;
145
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
163
164 return true;
165 }
166
167 return false;
initial.commitd7cae122008-07-26 21:49:38168}
169
[email protected]1a48f312008-08-12 01:14:37170// static
[email protected]bb975362009-01-21 01:00:22171void 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);
[email protected]54d5b042008-08-12 01:27:35178#endif
[email protected]1a48f312008-08-12 01:14:37179}
180
[email protected]a2318cda2009-02-25 21:13:53181void CommandLine::Terminate() {
182 DCHECK(current_process_commandline_ != NULL);
183 delete current_process_commandline_;
184 current_process_commandline_ = NULL;
185}
186
[email protected]bb975362009-01-21 01:00:22187bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
188 std::wstring lowercased_switch(switch_string);
189#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38190 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22191#endif
192 return switches_.find(WideToASCII(lowercased_switch)) != switches_.end();
initial.commitd7cae122008-07-26 21:49:38193}
194
[email protected]bb975362009-01-21 01:00:22195std::wstring CommandLine::GetSwitchValue(
196 const std::wstring& switch_string) const {
197 std::wstring lowercased_switch(switch_string);
198#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38199 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22200#endif
initial.commitd7cae122008-07-26 21:49:38201
[email protected]bb975362009-01-21 01:00:22202 std::map<std::string, StringType>::const_iterator result =
203 switches_.find(WideToASCII(lowercased_switch));
initial.commitd7cae122008-07-26 21:49:38204
[email protected]bb975362009-01-21 01:00:22205 if (result == switches_.end()) {
initial.commitd7cae122008-07-26 21:49:38206 return L"";
207 } else {
[email protected]bb975362009-01-21 01:00:22208#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38209 return result->second;
[email protected]bb975362009-01-21 01:00:22210#else
211 return ASCIIToWide(result->second);
212#endif
initial.commitd7cae122008-07-26 21:49:38213 }
214}
215
[email protected]bb975362009-01-21 01:00:22216#if defined(OS_WIN)
217std::vector<std::wstring> CommandLine::GetLooseValues() const {
218 return loose_values_;
initial.commitd7cae122008-07-26 21:49:38219}
[email protected]bb975362009-01-21 01:00:22220std::wstring CommandLine::program() const {
221 return program_;
initial.commitd7cae122008-07-26 21:49:38222}
[email protected]bb975362009-01-21 01:00:22223#else
224std::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;
initial.commitd7cae122008-07-26 21:49:38229}
[email protected]bb975362009-01-21 01:00:22230std::wstring CommandLine::program() const {
231 DCHECK(argv_.size() > 0);
232 return ASCIIToWide(argv_[0]);
[email protected]10e42bf2008-10-15 21:59:08233}
234#endif
235
initial.commitd7cae122008-07-26 21:49:38236
237// static
[email protected]bb975362009-01-21 01:00:22238std::wstring CommandLine::PrefixedSwitchString(
239 const std::wstring& switch_string) {
[email protected]10e42bf2008-10-15 21:59:08240 return StringPrintf(L"%ls%ls",
241 kSwitchPrefixes[0],
242 switch_string.c_str());
243}
244
245// static
[email protected]bb975362009-01-21 01:00:22246std::wstring CommandLine::PrefixedSwitchStringWithValue(
247 const std::wstring& switch_string, const std::wstring& value_string) {
[email protected]10e42bf2008-10-15 21:59:08248 if (value_string.empty()) {
249 return PrefixedSwitchString(switch_string);
250 }
251
252 return StringPrintf(L"%ls%ls%ls%ls",
253 kSwitchPrefixes[0],
254 switch_string.c_str(),
255 kSwitchValueSeparator,
256 value_string.c_str());
257}
258
[email protected]bb975362009-01-21 01:00:22259#if defined(OS_WIN)
260void 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"";
initial.commitd7cae122008-07-26 21:49:38265}
266
[email protected]bb975362009-01-21 01:00:22267void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
268 const std::wstring& value_string) {
269 std::wstring value_string_edit;
initial.commitd7cae122008-07-26 21:49:38270
initial.commitd7cae122008-07-26 21:49:38271 // NOTE(jhughes): If the value contains a quotation mark at one
272 // end but not both, you may get unusable output.
[email protected]10e42bf2008-10-15 21:59:08273 if (!value_string.empty() &&
274 (value_string.find(L" ") != std::wstring::npos) &&
initial.commitd7cae122008-07-26 21:49:38275 (value_string[0] != L'"') &&
276 (value_string[value_string.length() - 1] != L'"')) {
277 // need to provide quotes
[email protected]10e42bf2008-10-15 21:59:08278 value_string_edit = StringPrintf(L"\"%ls\"", value_string.c_str());
initial.commitd7cae122008-07-26 21:49:38279 } else {
[email protected]10e42bf2008-10-15 21:59:08280 value_string_edit = value_string;
initial.commitd7cae122008-07-26 21:49:38281 }
[email protected]10e42bf2008-10-15 21:59:08282
[email protected]bb975362009-01-21 01:00:22283 std::wstring combined_switch_string =
[email protected]10e42bf2008-10-15 21:59:08284 PrefixedSwitchStringWithValue(switch_string, value_string_edit);
285
[email protected]bb975362009-01-21 01:00:22286 command_line_string_.append(L" ");
287 command_line_string_.append(combined_switch_string);
288
289 switches_[WideToASCII(switch_string)] = value_string;
initial.commitd7cae122008-07-26 21:49:38290}
license.botbf09a502008-08-24 00:55:55291
[email protected]bb975362009-01-21 01:00:22292void CommandLine::AppendLooseValue(const std::wstring& value) {
293 // TODO(evan): quoting?
294 command_line_string_.append(L" ");
295 command_line_string_.append(value);
296}
297
298void CommandLine::AppendArguments(const CommandLine& other,
299 bool include_program) {
300 // Verify include_program is used correctly.
301 // Logic could be shorter but this is clearer.
302 DCHECK(include_program ? !other.program().empty() : other.program().empty());
303 command_line_string_ += L" " + other.command_line_string_;
304 std::map<std::string, StringType>::const_iterator i;
305 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
306 switches_[i->first] = i->second;
307}
308
309#elif defined(OS_POSIX)
310void CommandLine::AppendSwitch(const std::wstring& switch_string) {
311 std::string ascii_switch = WideToASCII(switch_string);
312 argv_.push_back(kSwitchPrefixes[0] + ascii_switch);
313 switches_[ascii_switch] = "";
314}
315
316void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
317 const std::wstring& value_string) {
318 std::string ascii_switch = WideToASCII(switch_string);
319 std::string ascii_value = WideToASCII(value_string);
320
321 argv_.push_back(kSwitchPrefixes[0] + ascii_switch +
322 kSwitchValueSeparator + ascii_value);
323 switches_[ascii_switch] = ascii_value;
324}
325
326void CommandLine::AppendLooseValue(const std::wstring& value) {
327 argv_.push_back(WideToASCII(value));
328}
329
330void CommandLine::AppendArguments(const CommandLine& other,
331 bool include_program) {
332 // Verify include_program is used correctly.
333 // Logic could be shorter but this is clearer.
334 DCHECK(include_program ? !other.program().empty() : other.program().empty());
335
336 size_t first_arg = include_program ? 0 : 1;
337 for (size_t i = first_arg; i < other.argv_.size(); ++i)
338 argv_.push_back(other.argv_[i]);
339 std::map<std::string, StringType>::const_iterator i;
340 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
341 switches_[i->first] = i->second;
342}
[email protected]052f1d482009-02-10 00:52:14343
344void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
345 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
346 // we don't pretend to do anything fancy, we just split on spaces.
347 const std::string wrapper = WideToASCII(wrapper_wide);
348 std::vector<std::string> wrapper_and_args;
349 SplitString(wrapper, ' ', &wrapper_and_args);
350 argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
351}
352
[email protected]bb975362009-01-21 01:00:22353#endif