blob: 04c1ece6ab762909463e00efb8ced55743638ec3 [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]7f113f32009-09-10 18:02:1710#elif defined(OS_FREEBSD)
11#include <stdlib.h>
12#include <unistd.h>
[email protected]f3adb5c2008-08-07 20:07:3213#endif
initial.commitd7cae122008-07-26 21:49:3814
15#include <algorithm>
16
initial.commitd7cae122008-07-26 21:49:3817#include "base/logging.h"
18#include "base/singleton.h"
[email protected]4bdaceb42008-08-19 13:19:2419#include "base/string_piece.h"
initial.commitd7cae122008-07-26 21:49:3820#include "base/string_util.h"
[email protected]05b5d792008-08-07 22:28:2421#include "base/sys_string_conversions.h"
initial.commitd7cae122008-07-26 21:49:3822
[email protected]7f113f32009-09-10 18:02:1723#if defined(OS_LINUX)
24// Linux/glibc doesn't natively have setproctitle().
25#include "base/setproctitle_linux.h"
26#endif
27
[email protected]bb975362009-01-21 01:00:2228CommandLine* CommandLine::current_process_commandline_ = NULL;
initial.commitd7cae122008-07-26 21:49:3829
30// Since we use a lazy match, make sure that longer versions (like L"--")
31// are listed before shorter versions (like L"-") of similar prefixes.
[email protected]5d426332008-08-08 20:46:2132#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2233const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
34const wchar_t kSwitchTerminator[] = L"--";
35const wchar_t kSwitchValueSeparator[] = L"=";
[email protected]5d426332008-08-08 20:46:2136#elif defined(OS_POSIX)
[email protected]1a48f312008-08-12 01:14:3737// Unixes don't use slash as a switch.
[email protected]bb975362009-01-21 01:00:2238const char* const kSwitchPrefixes[] = {"--", "-"};
39const char kSwitchTerminator[] = "--";
40const char kSwitchValueSeparator[] = "=";
[email protected]5d426332008-08-08 20:46:2141#endif
initial.commitd7cae122008-07-26 21:49:3842
[email protected]f3adb5c2008-08-07 20:07:3243#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2244// Lowercase a string. This is used to lowercase switch names.
45// Is this what we really want? It seems crazy to me. I've left it in
46// for backwards compatibility on Windows.
47static void Lowercase(std::wstring* parameter) {
48 transform(parameter->begin(), parameter->end(), parameter->begin(),
49 tolower);
initial.commitd7cae122008-07-26 21:49:3850}
[email protected]bb975362009-01-21 01:00:2251#endif
initial.commitd7cae122008-07-26 21:49:3852
[email protected]f3adb5c2008-08-07 20:07:3253#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2254void CommandLine::ParseFromString(const std::wstring& command_line) {
55 TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
56
57 if (command_line_string_.empty())
58 return;
59
60 int num_args = 0;
61 wchar_t** args = NULL;
62
63 args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
64
65 // Populate program_ with the trimmed version of the first arg.
66 TrimWhitespace(args[0], TRIM_ALL, &program_);
67
68 bool parse_switches = true;
69 for (int i = 1; i < num_args; ++i) {
70 std::wstring arg;
71 TrimWhitespace(args[i], TRIM_ALL, &arg);
72
73 if (!parse_switches) {
74 loose_values_.push_back(arg);
75 continue;
76 }
77
78 if (arg == kSwitchTerminator) {
79 parse_switches = false;
80 continue;
81 }
82
83 std::string switch_string;
84 std::wstring switch_value;
85 if (IsSwitch(arg, &switch_string, &switch_value)) {
86 switches_[switch_string] = switch_value;
87 } else {
88 loose_values_.push_back(arg);
89 }
90 }
91
92 if (args)
93 LocalFree(args);
94}
95CommandLine::CommandLine(const std::wstring& program) {
96 if (!program.empty()) {
97 program_ = program;
98 command_line_string_ = L'"' + program + L'"';
99 }
initial.commitd7cae122008-07-26 21:49:38100}
[email protected]f3adb5c2008-08-07 20:07:32101#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:22102CommandLine::CommandLine(int argc, const char* const* argv) {
103 for (int i = 0; i < argc; ++i)
104 argv_.push_back(argv[i]);
105 InitFromArgv();
106}
107CommandLine::CommandLine(const std::vector<std::string>& argv) {
108 argv_ = argv;
109 InitFromArgv();
[email protected]f3adb5c2008-08-07 20:07:32110}
[email protected]10e42bf2008-10-15 21:59:08111
[email protected]bb975362009-01-21 01:00:22112void CommandLine::InitFromArgv() {
113 bool parse_switches = true;
114 for (size_t i = 1; i < argv_.size(); ++i) {
115 const std::string& arg = argv_[i];
116
117 if (!parse_switches) {
118 loose_values_.push_back(arg);
119 continue;
120 }
121
122 if (arg == kSwitchTerminator) {
123 parse_switches = false;
124 continue;
125 }
126
127 std::string switch_string;
128 std::string switch_value;
129 if (IsSwitch(arg, &switch_string, &switch_value)) {
130 switches_[switch_string] = switch_value;
131 } else {
132 loose_values_.push_back(arg);
133 }
[email protected]10e42bf2008-10-15 21:59:08134 }
[email protected]bb975362009-01-21 01:00:22135}
136
137CommandLine::CommandLine(const std::wstring& program) {
[email protected]b44bd3032009-08-26 03:58:53138 argv_.push_back(base::SysWideToNativeMB(program));
[email protected]10e42bf2008-10-15 21:59:08139}
[email protected]f3adb5c2008-08-07 20:07:32140#endif
initial.commitd7cae122008-07-26 21:49:38141
[email protected]bb975362009-01-21 01:00:22142// static
143bool CommandLine::IsSwitch(const StringType& parameter_string,
144 std::string* switch_string,
145 StringType* switch_value) {
146 switch_string->clear();
147 switch_value->clear();
148
149 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
150 StringType prefix(kSwitchPrefixes[i]);
151 if (parameter_string.find(prefix) != 0)
152 continue;
153
154 const size_t switch_start = prefix.length();
155 const size_t equals_position = parameter_string.find(
156 kSwitchValueSeparator, switch_start);
157 StringType switch_native;
158 if (equals_position == StringType::npos) {
159 switch_native = parameter_string.substr(switch_start);
160 } else {
161 switch_native = parameter_string.substr(
162 switch_start, equals_position - switch_start);
163 *switch_value = parameter_string.substr(equals_position + 1);
164 }
165#if defined(OS_WIN)
166 Lowercase(&switch_native);
167 *switch_string = WideToASCII(switch_native);
168#else
169 *switch_string = switch_native;
170#endif
171
172 return true;
173 }
174
175 return false;
initial.commitd7cae122008-07-26 21:49:38176}
177
[email protected]1a48f312008-08-12 01:14:37178// static
[email protected]cc8f1462009-06-12 17:36:55179void CommandLine::Reset() {
180 delete current_process_commandline_;
181 current_process_commandline_ = NULL;
182}
183
184// static
[email protected]bb975362009-01-21 01:00:22185void CommandLine::Init(int argc, const char* const* argv) {
[email protected]bb975362009-01-21 01:00:22186#if defined(OS_WIN)
187 current_process_commandline_ = new CommandLine;
188 current_process_commandline_->ParseFromString(::GetCommandLineW());
189#elif defined(OS_POSIX)
190 current_process_commandline_ = new CommandLine(argc, argv);
[email protected]54d5b042008-08-12 01:27:35191#endif
[email protected]1a48f312008-08-12 01:14:37192}
193
[email protected]4883a4e2009-06-06 19:59:36194// static
195void CommandLine::Init(const std::vector<std::string>& argv) {
196 DCHECK(current_process_commandline_ == NULL);
197#if defined(OS_WIN)
198 current_process_commandline_ = new CommandLine;
199 current_process_commandline_->ParseFromString(::GetCommandLineW());
200#elif defined(OS_POSIX)
201 current_process_commandline_ = new CommandLine(argv);
202#endif
203}
204
[email protected]7f113f32009-09-10 18:02:17205#if defined(OS_LINUX) || defined(OS_FREEBSD)
206// static
207void CommandLine::SetProcTitle() {
208 // Build a single string which consists of all the arguments separated
209 // by spaces. We can't actually keep them separate due to the way the
210 // setproctitle() function works.
211 std::string title;
212 for (size_t i = 1; i < current_process_commandline_->argv_.size(); ++i) {
213 if (!title.empty())
214 title += " ";
215 title += current_process_commandline_->argv_[i];
216 }
217 setproctitle("%s", title.c_str());
218}
219
220// static
221void CommandLine::SetTrueArgv(char** argv) {
222#if defined(OS_LINUX)
223 setproctitle_init(argv);
224#endif
225}
226#endif
227
[email protected]a2318cda2009-02-25 21:13:53228void CommandLine::Terminate() {
229 DCHECK(current_process_commandline_ != NULL);
230 delete current_process_commandline_;
231 current_process_commandline_ = NULL;
232}
233
[email protected]bb975362009-01-21 01:00:22234bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
235 std::wstring lowercased_switch(switch_string);
236#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38237 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22238#endif
239 return switches_.find(WideToASCII(lowercased_switch)) != switches_.end();
initial.commitd7cae122008-07-26 21:49:38240}
241
[email protected]bb975362009-01-21 01:00:22242std::wstring CommandLine::GetSwitchValue(
243 const std::wstring& switch_string) const {
244 std::wstring lowercased_switch(switch_string);
245#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38246 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22247#endif
initial.commitd7cae122008-07-26 21:49:38248
[email protected]bb975362009-01-21 01:00:22249 std::map<std::string, StringType>::const_iterator result =
250 switches_.find(WideToASCII(lowercased_switch));
initial.commitd7cae122008-07-26 21:49:38251
[email protected]bb975362009-01-21 01:00:22252 if (result == switches_.end()) {
initial.commitd7cae122008-07-26 21:49:38253 return L"";
254 } else {
[email protected]bb975362009-01-21 01:00:22255#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38256 return result->second;
[email protected]bb975362009-01-21 01:00:22257#else
[email protected]b44bd3032009-08-26 03:58:53258 return base::SysNativeMBToWide(result->second);
[email protected]bb975362009-01-21 01:00:22259#endif
initial.commitd7cae122008-07-26 21:49:38260 }
261}
262
[email protected]bb975362009-01-21 01:00:22263#if defined(OS_WIN)
264std::vector<std::wstring> CommandLine::GetLooseValues() const {
265 return loose_values_;
initial.commitd7cae122008-07-26 21:49:38266}
[email protected]bb975362009-01-21 01:00:22267std::wstring CommandLine::program() const {
268 return program_;
initial.commitd7cae122008-07-26 21:49:38269}
[email protected]bb975362009-01-21 01:00:22270#else
271std::vector<std::wstring> CommandLine::GetLooseValues() const {
272 std::vector<std::wstring> values;
273 for (size_t i = 0; i < loose_values_.size(); ++i)
[email protected]b44bd3032009-08-26 03:58:53274 values.push_back(base::SysNativeMBToWide(loose_values_[i]));
[email protected]bb975362009-01-21 01:00:22275 return values;
initial.commitd7cae122008-07-26 21:49:38276}
[email protected]bb975362009-01-21 01:00:22277std::wstring CommandLine::program() const {
278 DCHECK(argv_.size() > 0);
[email protected]b44bd3032009-08-26 03:58:53279 return base::SysNativeMBToWide(argv_[0]);
[email protected]10e42bf2008-10-15 21:59:08280}
281#endif
282
initial.commitd7cae122008-07-26 21:49:38283
284// static
[email protected]bb975362009-01-21 01:00:22285std::wstring CommandLine::PrefixedSwitchString(
286 const std::wstring& switch_string) {
[email protected]10e42bf2008-10-15 21:59:08287 return StringPrintf(L"%ls%ls",
288 kSwitchPrefixes[0],
289 switch_string.c_str());
290}
291
292// static
[email protected]bb975362009-01-21 01:00:22293std::wstring CommandLine::PrefixedSwitchStringWithValue(
294 const std::wstring& switch_string, const std::wstring& value_string) {
[email protected]10e42bf2008-10-15 21:59:08295 if (value_string.empty()) {
296 return PrefixedSwitchString(switch_string);
297 }
298
299 return StringPrintf(L"%ls%ls%ls%ls",
300 kSwitchPrefixes[0],
301 switch_string.c_str(),
302 kSwitchValueSeparator,
303 value_string.c_str());
304}
305
[email protected]bb975362009-01-21 01:00:22306#if defined(OS_WIN)
307void CommandLine::AppendSwitch(const std::wstring& switch_string) {
308 std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string);
309 command_line_string_.append(L" ");
310 command_line_string_.append(prefixed_switch_string);
311 switches_[WideToASCII(switch_string)] = L"";
initial.commitd7cae122008-07-26 21:49:38312}
313
[email protected]bb975362009-01-21 01:00:22314void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
315 const std::wstring& value_string) {
316 std::wstring value_string_edit;
initial.commitd7cae122008-07-26 21:49:38317
initial.commitd7cae122008-07-26 21:49:38318 // NOTE(jhughes): If the value contains a quotation mark at one
319 // end but not both, you may get unusable output.
[email protected]10e42bf2008-10-15 21:59:08320 if (!value_string.empty() &&
321 (value_string.find(L" ") != std::wstring::npos) &&
initial.commitd7cae122008-07-26 21:49:38322 (value_string[0] != L'"') &&
323 (value_string[value_string.length() - 1] != L'"')) {
324 // need to provide quotes
[email protected]10e42bf2008-10-15 21:59:08325 value_string_edit = StringPrintf(L"\"%ls\"", value_string.c_str());
initial.commitd7cae122008-07-26 21:49:38326 } else {
[email protected]10e42bf2008-10-15 21:59:08327 value_string_edit = value_string;
initial.commitd7cae122008-07-26 21:49:38328 }
[email protected]10e42bf2008-10-15 21:59:08329
[email protected]bb975362009-01-21 01:00:22330 std::wstring combined_switch_string =
[email protected]10e42bf2008-10-15 21:59:08331 PrefixedSwitchStringWithValue(switch_string, value_string_edit);
332
[email protected]bb975362009-01-21 01:00:22333 command_line_string_.append(L" ");
334 command_line_string_.append(combined_switch_string);
335
336 switches_[WideToASCII(switch_string)] = value_string;
initial.commitd7cae122008-07-26 21:49:38337}
license.botbf09a502008-08-24 00:55:55338
[email protected]bb975362009-01-21 01:00:22339void CommandLine::AppendLooseValue(const std::wstring& value) {
340 // TODO(evan): quoting?
341 command_line_string_.append(L" ");
342 command_line_string_.append(value);
343}
344
345void CommandLine::AppendArguments(const CommandLine& other,
346 bool include_program) {
347 // Verify include_program is used correctly.
348 // Logic could be shorter but this is clearer.
349 DCHECK(include_program ? !other.program().empty() : other.program().empty());
350 command_line_string_ += L" " + other.command_line_string_;
351 std::map<std::string, StringType>::const_iterator i;
352 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
353 switches_[i->first] = i->second;
354}
355
[email protected]e5e19c32009-04-20 22:10:02356void CommandLine::PrependWrapper(const std::wstring& wrapper) {
357 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
358 // we don't pretend to do anything fancy, we just split on spaces.
359 std::vector<std::wstring> wrapper_and_args;
360 SplitString(wrapper, ' ', &wrapper_and_args);
361 program_ = wrapper_and_args[0];
362 command_line_string_ = wrapper + L" " + command_line_string_;
363}
364
[email protected]bb975362009-01-21 01:00:22365#elif defined(OS_POSIX)
366void CommandLine::AppendSwitch(const std::wstring& switch_string) {
367 std::string ascii_switch = WideToASCII(switch_string);
368 argv_.push_back(kSwitchPrefixes[0] + ascii_switch);
369 switches_[ascii_switch] = "";
370}
371
372void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
373 const std::wstring& value_string) {
374 std::string ascii_switch = WideToASCII(switch_string);
[email protected]b44bd3032009-08-26 03:58:53375 std::string mb_value = base::SysWideToNativeMB(value_string);
[email protected]bb975362009-01-21 01:00:22376
377 argv_.push_back(kSwitchPrefixes[0] + ascii_switch +
[email protected]b44bd3032009-08-26 03:58:53378 kSwitchValueSeparator + mb_value);
379 switches_[ascii_switch] = mb_value;
[email protected]bb975362009-01-21 01:00:22380}
381
382void CommandLine::AppendLooseValue(const std::wstring& value) {
[email protected]b44bd3032009-08-26 03:58:53383 argv_.push_back(base::SysWideToNativeMB(value));
[email protected]bb975362009-01-21 01:00:22384}
385
386void CommandLine::AppendArguments(const CommandLine& other,
387 bool include_program) {
388 // Verify include_program is used correctly.
389 // Logic could be shorter but this is clearer.
390 DCHECK(include_program ? !other.program().empty() : other.program().empty());
391
392 size_t first_arg = include_program ? 0 : 1;
393 for (size_t i = first_arg; i < other.argv_.size(); ++i)
394 argv_.push_back(other.argv_[i]);
395 std::map<std::string, StringType>::const_iterator i;
396 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
397 switches_[i->first] = i->second;
398}
[email protected]052f1d482009-02-10 00:52:14399
400void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
401 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
402 // we don't pretend to do anything fancy, we just split on spaces.
[email protected]b44bd3032009-08-26 03:58:53403 const std::string wrapper = base::SysWideToNativeMB(wrapper_wide);
[email protected]052f1d482009-02-10 00:52:14404 std::vector<std::string> wrapper_and_args;
405 SplitString(wrapper, ' ', &wrapper_and_args);
406 argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
407}
408
[email protected]bb975362009-01-21 01:00:22409#endif