blob: 0104f3b55ac64cb9b5a704f01287b11b34a01f34 [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
[email protected]8f681e42009-10-09 20:37:5617#include "base/file_path.h"
initial.commitd7cae122008-07-26 21:49:3818#include "base/logging.h"
19#include "base/singleton.h"
[email protected]4bdaceb42008-08-19 13:19:2420#include "base/string_piece.h"
initial.commitd7cae122008-07-26 21:49:3821#include "base/string_util.h"
[email protected]05b5d792008-08-07 22:28:2422#include "base/sys_string_conversions.h"
initial.commitd7cae122008-07-26 21:49:3823
[email protected]7f113f32009-09-10 18:02:1724#if defined(OS_LINUX)
25// Linux/glibc doesn't natively have setproctitle().
26#include "base/setproctitle_linux.h"
27#endif
28
[email protected]bb975362009-01-21 01:00:2229CommandLine* CommandLine::current_process_commandline_ = NULL;
initial.commitd7cae122008-07-26 21:49:3830
31// Since we use a lazy match, make sure that longer versions (like L"--")
32// are listed before shorter versions (like L"-") of similar prefixes.
[email protected]5d426332008-08-08 20:46:2133#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2234const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
35const wchar_t kSwitchTerminator[] = L"--";
36const wchar_t kSwitchValueSeparator[] = L"=";
[email protected]5d426332008-08-08 20:46:2137#elif defined(OS_POSIX)
[email protected]1a48f312008-08-12 01:14:3738// Unixes don't use slash as a switch.
[email protected]bb975362009-01-21 01:00:2239const char* const kSwitchPrefixes[] = {"--", "-"};
40const char kSwitchTerminator[] = "--";
41const char kSwitchValueSeparator[] = "=";
[email protected]5d426332008-08-08 20:46:2142#endif
initial.commitd7cae122008-07-26 21:49:3843
[email protected]f3adb5c2008-08-07 20:07:3244#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2245// Lowercase a string. This is used to lowercase switch names.
46// Is this what we really want? It seems crazy to me. I've left it in
47// for backwards compatibility on Windows.
48static void Lowercase(std::wstring* parameter) {
49 transform(parameter->begin(), parameter->end(), parameter->begin(),
50 tolower);
initial.commitd7cae122008-07-26 21:49:3851}
[email protected]bb975362009-01-21 01:00:2252#endif
initial.commitd7cae122008-07-26 21:49:3853
[email protected]f3adb5c2008-08-07 20:07:3254#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:2255void CommandLine::ParseFromString(const std::wstring& command_line) {
56 TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
57
58 if (command_line_string_.empty())
59 return;
60
61 int num_args = 0;
62 wchar_t** args = NULL;
63
64 args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
65
66 // Populate program_ with the trimmed version of the first arg.
67 TrimWhitespace(args[0], TRIM_ALL, &program_);
68
69 bool parse_switches = true;
70 for (int i = 1; i < num_args; ++i) {
71 std::wstring arg;
72 TrimWhitespace(args[i], TRIM_ALL, &arg);
73
74 if (!parse_switches) {
75 loose_values_.push_back(arg);
76 continue;
77 }
78
79 if (arg == kSwitchTerminator) {
80 parse_switches = false;
81 continue;
82 }
83
84 std::string switch_string;
85 std::wstring switch_value;
86 if (IsSwitch(arg, &switch_string, &switch_value)) {
87 switches_[switch_string] = switch_value;
88 } else {
89 loose_values_.push_back(arg);
90 }
91 }
92
93 if (args)
94 LocalFree(args);
95}
[email protected]8f681e42009-10-09 20:37:5696
97CommandLine::CommandLine(const FilePath& program) {
98 if (!program.empty()) {
99 program_ = program.value();
100 command_line_string_ = L'"' + program.value() + L'"';
101 }
102}
103
104// Deprecated version
[email protected]bb975362009-01-21 01:00:22105CommandLine::CommandLine(const std::wstring& program) {
106 if (!program.empty()) {
107 program_ = program;
108 command_line_string_ = L'"' + program + L'"';
109 }
initial.commitd7cae122008-07-26 21:49:38110}
[email protected]f3adb5c2008-08-07 20:07:32111#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:22112CommandLine::CommandLine(int argc, const char* const* argv) {
113 for (int i = 0; i < argc; ++i)
114 argv_.push_back(argv[i]);
115 InitFromArgv();
116}
117CommandLine::CommandLine(const std::vector<std::string>& argv) {
118 argv_ = argv;
119 InitFromArgv();
[email protected]f3adb5c2008-08-07 20:07:32120}
[email protected]10e42bf2008-10-15 21:59:08121
[email protected]bb975362009-01-21 01:00:22122void CommandLine::InitFromArgv() {
123 bool parse_switches = true;
124 for (size_t i = 1; i < argv_.size(); ++i) {
125 const std::string& arg = argv_[i];
126
127 if (!parse_switches) {
128 loose_values_.push_back(arg);
129 continue;
130 }
131
132 if (arg == kSwitchTerminator) {
133 parse_switches = false;
134 continue;
135 }
136
137 std::string switch_string;
138 std::string switch_value;
139 if (IsSwitch(arg, &switch_string, &switch_value)) {
140 switches_[switch_string] = switch_value;
141 } else {
142 loose_values_.push_back(arg);
143 }
[email protected]10e42bf2008-10-15 21:59:08144 }
[email protected]bb975362009-01-21 01:00:22145}
146
[email protected]8f681e42009-10-09 20:37:56147CommandLine::CommandLine(const FilePath& program) {
148 argv_.push_back(program.value());
149}
150
151// Deprecated version
[email protected]bb975362009-01-21 01:00:22152CommandLine::CommandLine(const std::wstring& program) {
[email protected]b44bd3032009-08-26 03:58:53153 argv_.push_back(base::SysWideToNativeMB(program));
[email protected]10e42bf2008-10-15 21:59:08154}
[email protected]f3adb5c2008-08-07 20:07:32155#endif
initial.commitd7cae122008-07-26 21:49:38156
[email protected]bb975362009-01-21 01:00:22157// static
158bool CommandLine::IsSwitch(const StringType& parameter_string,
159 std::string* switch_string,
160 StringType* switch_value) {
161 switch_string->clear();
162 switch_value->clear();
163
164 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
165 StringType prefix(kSwitchPrefixes[i]);
166 if (parameter_string.find(prefix) != 0)
167 continue;
168
169 const size_t switch_start = prefix.length();
170 const size_t equals_position = parameter_string.find(
171 kSwitchValueSeparator, switch_start);
172 StringType switch_native;
173 if (equals_position == StringType::npos) {
174 switch_native = parameter_string.substr(switch_start);
175 } else {
176 switch_native = parameter_string.substr(
177 switch_start, equals_position - switch_start);
178 *switch_value = parameter_string.substr(equals_position + 1);
179 }
180#if defined(OS_WIN)
181 Lowercase(&switch_native);
182 *switch_string = WideToASCII(switch_native);
183#else
184 *switch_string = switch_native;
185#endif
186
187 return true;
188 }
189
190 return false;
initial.commitd7cae122008-07-26 21:49:38191}
192
[email protected]1a48f312008-08-12 01:14:37193// static
[email protected]cc8f1462009-06-12 17:36:55194void CommandLine::Reset() {
195 delete current_process_commandline_;
196 current_process_commandline_ = NULL;
197}
198
199// static
[email protected]bb975362009-01-21 01:00:22200void CommandLine::Init(int argc, const char* const* argv) {
[email protected]bb975362009-01-21 01:00:22201#if defined(OS_WIN)
202 current_process_commandline_ = new CommandLine;
203 current_process_commandline_->ParseFromString(::GetCommandLineW());
204#elif defined(OS_POSIX)
205 current_process_commandline_ = new CommandLine(argc, argv);
[email protected]54d5b042008-08-12 01:27:35206#endif
[email protected]1a48f312008-08-12 01:14:37207}
208
[email protected]4883a4e2009-06-06 19:59:36209// static
210void CommandLine::Init(const std::vector<std::string>& argv) {
211 DCHECK(current_process_commandline_ == NULL);
212#if defined(OS_WIN)
213 current_process_commandline_ = new CommandLine;
214 current_process_commandline_->ParseFromString(::GetCommandLineW());
215#elif defined(OS_POSIX)
216 current_process_commandline_ = new CommandLine(argv);
217#endif
218}
219
[email protected]7f113f32009-09-10 18:02:17220#if defined(OS_LINUX) || defined(OS_FREEBSD)
221// static
222void CommandLine::SetProcTitle() {
223 // Build a single string which consists of all the arguments separated
224 // by spaces. We can't actually keep them separate due to the way the
225 // setproctitle() function works.
226 std::string title;
227 for (size_t i = 1; i < current_process_commandline_->argv_.size(); ++i) {
228 if (!title.empty())
229 title += " ";
230 title += current_process_commandline_->argv_[i];
231 }
232 setproctitle("%s", title.c_str());
233}
234
235// static
236void CommandLine::SetTrueArgv(char** argv) {
237#if defined(OS_LINUX)
238 setproctitle_init(argv);
239#endif
240}
241#endif
242
[email protected]a2318cda2009-02-25 21:13:53243void CommandLine::Terminate() {
244 DCHECK(current_process_commandline_ != NULL);
245 delete current_process_commandline_;
246 current_process_commandline_ = NULL;
247}
248
[email protected]bb975362009-01-21 01:00:22249bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
250 std::wstring lowercased_switch(switch_string);
251#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38252 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22253#endif
254 return switches_.find(WideToASCII(lowercased_switch)) != switches_.end();
initial.commitd7cae122008-07-26 21:49:38255}
256
[email protected]bb975362009-01-21 01:00:22257std::wstring CommandLine::GetSwitchValue(
258 const std::wstring& switch_string) const {
259 std::wstring lowercased_switch(switch_string);
260#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38261 Lowercase(&lowercased_switch);
[email protected]bb975362009-01-21 01:00:22262#endif
initial.commitd7cae122008-07-26 21:49:38263
[email protected]bb975362009-01-21 01:00:22264 std::map<std::string, StringType>::const_iterator result =
265 switches_.find(WideToASCII(lowercased_switch));
initial.commitd7cae122008-07-26 21:49:38266
[email protected]bb975362009-01-21 01:00:22267 if (result == switches_.end()) {
initial.commitd7cae122008-07-26 21:49:38268 return L"";
269 } else {
[email protected]bb975362009-01-21 01:00:22270#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38271 return result->second;
[email protected]bb975362009-01-21 01:00:22272#else
[email protected]b44bd3032009-08-26 03:58:53273 return base::SysNativeMBToWide(result->second);
[email protected]bb975362009-01-21 01:00:22274#endif
initial.commitd7cae122008-07-26 21:49:38275 }
276}
277
[email protected]bb975362009-01-21 01:00:22278#if defined(OS_WIN)
279std::vector<std::wstring> CommandLine::GetLooseValues() const {
280 return loose_values_;
initial.commitd7cae122008-07-26 21:49:38281}
[email protected]bb975362009-01-21 01:00:22282std::wstring CommandLine::program() const {
283 return program_;
initial.commitd7cae122008-07-26 21:49:38284}
[email protected]bb975362009-01-21 01:00:22285#else
286std::vector<std::wstring> CommandLine::GetLooseValues() const {
287 std::vector<std::wstring> values;
288 for (size_t i = 0; i < loose_values_.size(); ++i)
[email protected]b44bd3032009-08-26 03:58:53289 values.push_back(base::SysNativeMBToWide(loose_values_[i]));
[email protected]bb975362009-01-21 01:00:22290 return values;
initial.commitd7cae122008-07-26 21:49:38291}
[email protected]bb975362009-01-21 01:00:22292std::wstring CommandLine::program() const {
[email protected]8f681e42009-10-09 20:37:56293 DCHECK_GT(argv_.size(), 0U);
[email protected]b44bd3032009-08-26 03:58:53294 return base::SysNativeMBToWide(argv_[0]);
[email protected]10e42bf2008-10-15 21:59:08295}
296#endif
297
initial.commitd7cae122008-07-26 21:49:38298
299// static
[email protected]bb975362009-01-21 01:00:22300std::wstring CommandLine::PrefixedSwitchString(
301 const std::wstring& switch_string) {
[email protected]10e42bf2008-10-15 21:59:08302 return StringPrintf(L"%ls%ls",
303 kSwitchPrefixes[0],
304 switch_string.c_str());
305}
306
307// static
[email protected]bb975362009-01-21 01:00:22308std::wstring CommandLine::PrefixedSwitchStringWithValue(
309 const std::wstring& switch_string, const std::wstring& value_string) {
[email protected]10e42bf2008-10-15 21:59:08310 if (value_string.empty()) {
311 return PrefixedSwitchString(switch_string);
312 }
313
314 return StringPrintf(L"%ls%ls%ls%ls",
315 kSwitchPrefixes[0],
316 switch_string.c_str(),
317 kSwitchValueSeparator,
318 value_string.c_str());
319}
320
[email protected]bb975362009-01-21 01:00:22321#if defined(OS_WIN)
322void CommandLine::AppendSwitch(const std::wstring& switch_string) {
323 std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string);
324 command_line_string_.append(L" ");
325 command_line_string_.append(prefixed_switch_string);
326 switches_[WideToASCII(switch_string)] = L"";
initial.commitd7cae122008-07-26 21:49:38327}
328
[email protected]bb975362009-01-21 01:00:22329void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
330 const std::wstring& value_string) {
331 std::wstring value_string_edit;
initial.commitd7cae122008-07-26 21:49:38332
initial.commitd7cae122008-07-26 21:49:38333 // NOTE(jhughes): If the value contains a quotation mark at one
334 // end but not both, you may get unusable output.
[email protected]10e42bf2008-10-15 21:59:08335 if (!value_string.empty() &&
336 (value_string.find(L" ") != std::wstring::npos) &&
initial.commitd7cae122008-07-26 21:49:38337 (value_string[0] != L'"') &&
338 (value_string[value_string.length() - 1] != L'"')) {
339 // need to provide quotes
[email protected]10e42bf2008-10-15 21:59:08340 value_string_edit = StringPrintf(L"\"%ls\"", value_string.c_str());
initial.commitd7cae122008-07-26 21:49:38341 } else {
[email protected]10e42bf2008-10-15 21:59:08342 value_string_edit = value_string;
initial.commitd7cae122008-07-26 21:49:38343 }
[email protected]10e42bf2008-10-15 21:59:08344
[email protected]bb975362009-01-21 01:00:22345 std::wstring combined_switch_string =
[email protected]10e42bf2008-10-15 21:59:08346 PrefixedSwitchStringWithValue(switch_string, value_string_edit);
347
[email protected]bb975362009-01-21 01:00:22348 command_line_string_.append(L" ");
349 command_line_string_.append(combined_switch_string);
350
351 switches_[WideToASCII(switch_string)] = value_string;
initial.commitd7cae122008-07-26 21:49:38352}
license.botbf09a502008-08-24 00:55:55353
[email protected]bb975362009-01-21 01:00:22354void CommandLine::AppendLooseValue(const std::wstring& value) {
355 // TODO(evan): quoting?
356 command_line_string_.append(L" ");
357 command_line_string_.append(value);
358}
359
360void CommandLine::AppendArguments(const CommandLine& other,
361 bool include_program) {
362 // Verify include_program is used correctly.
363 // Logic could be shorter but this is clearer.
364 DCHECK(include_program ? !other.program().empty() : other.program().empty());
365 command_line_string_ += L" " + other.command_line_string_;
366 std::map<std::string, StringType>::const_iterator i;
367 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
368 switches_[i->first] = i->second;
369}
370
[email protected]e5e19c32009-04-20 22:10:02371void CommandLine::PrependWrapper(const std::wstring& wrapper) {
372 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
373 // we don't pretend to do anything fancy, we just split on spaces.
374 std::vector<std::wstring> wrapper_and_args;
375 SplitString(wrapper, ' ', &wrapper_and_args);
376 program_ = wrapper_and_args[0];
377 command_line_string_ = wrapper + L" " + command_line_string_;
378}
379
[email protected]bb975362009-01-21 01:00:22380#elif defined(OS_POSIX)
381void CommandLine::AppendSwitch(const std::wstring& switch_string) {
382 std::string ascii_switch = WideToASCII(switch_string);
383 argv_.push_back(kSwitchPrefixes[0] + ascii_switch);
384 switches_[ascii_switch] = "";
385}
386
387void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
388 const std::wstring& value_string) {
389 std::string ascii_switch = WideToASCII(switch_string);
[email protected]b44bd3032009-08-26 03:58:53390 std::string mb_value = base::SysWideToNativeMB(value_string);
[email protected]bb975362009-01-21 01:00:22391
392 argv_.push_back(kSwitchPrefixes[0] + ascii_switch +
[email protected]b44bd3032009-08-26 03:58:53393 kSwitchValueSeparator + mb_value);
394 switches_[ascii_switch] = mb_value;
[email protected]bb975362009-01-21 01:00:22395}
396
397void CommandLine::AppendLooseValue(const std::wstring& value) {
[email protected]b44bd3032009-08-26 03:58:53398 argv_.push_back(base::SysWideToNativeMB(value));
[email protected]bb975362009-01-21 01:00:22399}
400
401void CommandLine::AppendArguments(const CommandLine& other,
402 bool include_program) {
403 // Verify include_program is used correctly.
404 // Logic could be shorter but this is clearer.
405 DCHECK(include_program ? !other.program().empty() : other.program().empty());
406
407 size_t first_arg = include_program ? 0 : 1;
408 for (size_t i = first_arg; i < other.argv_.size(); ++i)
409 argv_.push_back(other.argv_[i]);
410 std::map<std::string, StringType>::const_iterator i;
411 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
412 switches_[i->first] = i->second;
413}
[email protected]052f1d482009-02-10 00:52:14414
415void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
416 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
417 // we don't pretend to do anything fancy, we just split on spaces.
[email protected]b44bd3032009-08-26 03:58:53418 const std::string wrapper = base::SysWideToNativeMB(wrapper_wide);
[email protected]052f1d482009-02-10 00:52:14419 std::vector<std::string> wrapper_and_args;
420 SplitString(wrapper, ' ', &wrapper_and_args);
421 argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
422}
423
[email protected]bb975362009-01-21 01:00:22424#endif