blob: 5df5a5296ceab84ce98a2eaff741b70c5e64dd2d [file] [log] [blame]
[email protected]72e2e2422012-02-27 18:38:121// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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
initial.commitd7cae122008-07-26 21:49:387#include <algorithm>
[email protected]2edc2862011-04-04 18:04:378#include <ostream>
initial.commitd7cae122008-07-26 21:49:389
jdoerrie5c4dc4e2019-02-01 18:02:3310#include "base/containers/span.h"
[email protected]57999812013-02-24 05:40:5211#include "base/files/file_path.h"
initial.commitd7cae122008-07-26 21:49:3812#include "base/logging.h"
Jeremy Roman863386d2017-10-31 19:25:3813#include "base/stl_util.h"
[email protected]5ae0b763e2013-02-07 23:01:3914#include "base/strings/string_split.h"
skyostild851aa12017-03-29 17:38:3515#include "base/strings/string_tokenizer.h"
[email protected]251cd6e52013-06-11 13:36:3716#include "base/strings/string_util.h"
[email protected]a4ea1f12013-06-07 18:37:0717#include "base/strings/utf_string_conversions.h"
[email protected]74e9fa22010-12-29 21:06:4318#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3819
[email protected]74e9fa22010-12-29 21:06:4320#if defined(OS_WIN)
21#include <windows.h>
22#include <shellapi.h>
Jan Wilken Dörrieb630aca2019-12-04 10:59:1123
24#include "base/strings/string_util_win.h"
[email protected]7f113f32009-09-10 18:02:1725#endif
26
[email protected]2f3b1cc2014-03-17 23:07:1527namespace base {
[email protected]04af979a2013-02-16 04:12:2628
Ivan Kotenkova16212a52017-11-08 12:37:3329CommandLine* CommandLine::current_process_commandline_ = nullptr;
initial.commitd7cae122008-07-26 21:49:3830
[email protected]06cc083a2011-03-01 02:28:4231namespace {
[email protected]2f3b1cc2014-03-17 23:07:1532
Jan Wilken Dörrieda77fd432019-10-24 21:40:3433constexpr CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
34constexpr CommandLine::CharType kSwitchValueSeparator[] =
35 FILE_PATH_LITERAL("=");
[email protected]bf98a0e12013-09-25 23:36:0036
[email protected]06cc083a2011-03-01 02:28:4237// Since we use a lazy match, make sure that longer versions (like "--") are
38// listed before shorter versions (like "-") of similar prefixes.
[email protected]5d426332008-08-08 20:46:2139#if defined(OS_WIN)
[email protected]bf98a0e12013-09-25 23:36:0040// By putting slash last, we can control whether it is treaded as a switch
41// value by changing the value of switch_prefix_count to be one less than
42// the array size.
Jan Wilken Dörrieda77fd432019-10-24 21:40:3443constexpr CommandLine::StringPieceType kSwitchPrefixes[] = {L"--", L"-", L"/"};
Fabrice de Gans-Riberi306871de2018-05-16 19:38:3944#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]1a48f312008-08-12 01:14:3745// Unixes don't use slash as a switch.
Jan Wilken Dörrieda77fd432019-10-24 21:40:3446constexpr CommandLine::StringPieceType kSwitchPrefixes[] = {"--", "-"};
[email protected]5d426332008-08-08 20:46:2147#endif
deepak1556bb31c182019-10-29 23:15:5848size_t switch_prefix_count = base::size(kSwitchPrefixes);
initial.commitd7cae122008-07-26 21:49:3849
Pavol Markobf16b812019-06-14 00:53:1250size_t GetSwitchPrefixLength(CommandLine::StringPieceType string) {
[email protected]bf98a0e12013-09-25 23:36:0051 for (size_t i = 0; i < switch_prefix_count; ++i) {
[email protected]a40ca4302011-05-14 01:10:2452 CommandLine::StringType prefix(kSwitchPrefixes[i]);
Pavol Markobf16b812019-06-14 00:53:1253 if (string.substr(0, prefix.length()) == prefix)
[email protected]a40ca4302011-05-14 01:10:2454 return prefix.length();
55 }
56 return 0;
initial.commitd7cae122008-07-26 21:49:3857}
[email protected]0fd23af2011-02-20 06:33:0458
[email protected]a40ca4302011-05-14 01:10:2459// Fills in |switch_string| and |switch_value| if |string| is a switch.
60// This will preserve the input switch prefix in the output |switch_string|.
61bool IsSwitch(const CommandLine::StringType& string,
62 CommandLine::StringType* switch_string,
63 CommandLine::StringType* switch_value) {
64 switch_string->clear();
65 switch_value->clear();
[email protected]21e342f2012-10-19 06:19:5966 size_t prefix_length = GetSwitchPrefixLength(string);
67 if (prefix_length == 0 || prefix_length == string.length())
[email protected]a40ca4302011-05-14 01:10:2468 return false;
69
70 const size_t equals_position = string.find(kSwitchValueSeparator);
71 *switch_string = string.substr(0, equals_position);
72 if (equals_position != CommandLine::StringType::npos)
73 *switch_value = string.substr(equals_position + 1);
74 return true;
75}
76
Pavol Markobf16b812019-06-14 00:53:1277// Returns true iff |string| represents a switch with key
78// |switch_key_without_prefix|, regardless of value.
79bool IsSwitchWithKey(CommandLine::StringPieceType string,
80 CommandLine::StringPieceType switch_key_without_prefix) {
81 size_t prefix_length = GetSwitchPrefixLength(string);
82 if (prefix_length == 0 || prefix_length == string.length())
83 return false;
84
85 const size_t equals_position = string.find(kSwitchValueSeparator);
86 return string.substr(prefix_length, equals_position - prefix_length) ==
87 switch_key_without_prefix;
88}
89
[email protected]a40ca4302011-05-14 01:10:2490// Append switches and arguments, keeping switches before arguments.
thestig8badc792014-12-04 22:14:2291void AppendSwitchesAndArguments(CommandLine* command_line,
[email protected]a40ca4302011-05-14 01:10:2492 const CommandLine::StringVector& argv) {
93 bool parse_switches = true;
94 for (size_t i = 1; i < argv.size(); ++i) {
95 CommandLine::StringType arg = argv[i];
tfarina023b1dcc2015-12-06 13:25:4196#if defined(OS_WIN)
Jan Wilken Dörrieb630aca2019-12-04 10:59:1197 arg = CommandLine::StringType(TrimWhitespace(arg, TRIM_ALL));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:3998#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
tfarina023b1dcc2015-12-06 13:25:4199 TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
100#endif
[email protected]a40ca4302011-05-14 01:10:24101
102 CommandLine::StringType switch_string;
103 CommandLine::StringType switch_value;
104 parse_switches &= (arg != kSwitchTerminator);
105 if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
106#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34107 command_line->AppendSwitchNative(WideToUTF8(switch_string), switch_value);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39108#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
thestig8badc792014-12-04 22:14:22109 command_line->AppendSwitchNative(switch_string, switch_value);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39110#else
111#error Unsupported platform
[email protected]a40ca4302011-05-14 01:10:24112#endif
113 } else {
thestig8badc792014-12-04 22:14:22114 command_line->AppendArgNative(arg);
[email protected]a40ca4302011-05-14 01:10:24115 }
116 }
117}
118
[email protected]a40ca4302011-05-14 01:10:24119#if defined(OS_WIN)
120// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34121std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg,
122 bool quote_placeholders) {
[email protected]0fd23af2011-02-20 06:33:04123 // We follow the quoting rules of CommandLineToArgvW.
124 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
Jan Wilken Dörrieda77fd432019-10-24 21:40:34125 std::wstring quotable_chars(L" \\\"");
mgiucac974d5102014-10-01 09:24:51126 // We may also be required to quote '%', which is commonly used in a command
127 // line as a placeholder. (It may be substituted for a string with spaces.)
128 if (quote_placeholders)
jdoerrie5c4dc4e2019-02-01 18:02:33129 quotable_chars.push_back('%');
Jan Wilken Dörrieda77fd432019-10-24 21:40:34130 if (arg.find_first_of(quotable_chars) == std::wstring::npos) {
[email protected]0fd23af2011-02-20 06:33:04131 // No quoting necessary.
132 return arg;
133 }
134
Jan Wilken Dörrieda77fd432019-10-24 21:40:34135 std::wstring out;
jdoerrie5c4dc4e2019-02-01 18:02:33136 out.push_back('"');
[email protected]0fd23af2011-02-20 06:33:04137 for (size_t i = 0; i < arg.size(); ++i) {
138 if (arg[i] == '\\') {
139 // Find the extent of this run of backslashes.
140 size_t start = i, end = start + 1;
thestig8badc792014-12-04 22:14:22141 for (; end < arg.size() && arg[end] == '\\'; ++end) {}
[email protected]0fd23af2011-02-20 06:33:04142 size_t backslash_count = end - start;
143
144 // Backslashes are escapes only if the run is followed by a double quote.
145 // Since we also will end the string with a double quote, we escape for
146 // either a double quote or the end of the string.
147 if (end == arg.size() || arg[end] == '"') {
148 // To quote, we need to output 2x as many backslashes.
149 backslash_count *= 2;
150 }
151 for (size_t j = 0; j < backslash_count; ++j)
152 out.push_back('\\');
153
154 // Advance i to one before the end to balance i++ in loop.
155 i = end - 1;
156 } else if (arg[i] == '"') {
157 out.push_back('\\');
158 out.push_back('"');
159 } else {
160 out.push_back(arg[i]);
161 }
162 }
163 out.push_back('"');
164
165 return out;
166}
[email protected]bb975362009-01-21 01:00:22167#endif
initial.commitd7cae122008-07-26 21:49:38168
[email protected]06cc083a2011-03-01 02:28:42169} // namespace
170
[email protected]a40ca4302011-05-14 01:10:24171CommandLine::CommandLine(NoProgram no_program)
172 : argv_(1),
173 begin_args_(1) {
[email protected]06cc083a2011-03-01 02:28:42174}
175
[email protected]a40ca4302011-05-14 01:10:24176CommandLine::CommandLine(const FilePath& program)
177 : argv_(1),
178 begin_args_(1) {
179 SetProgram(program);
[email protected]06cc083a2011-03-01 02:28:42180}
181
[email protected]a40ca4302011-05-14 01:10:24182CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
183 : argv_(1),
184 begin_args_(1) {
[email protected]06cc083a2011-03-01 02:28:42185 InitFromArgv(argc, argv);
186}
187
[email protected]a40ca4302011-05-14 01:10:24188CommandLine::CommandLine(const StringVector& argv)
189 : argv_(1),
190 begin_args_(1) {
[email protected]06cc083a2011-03-01 02:28:42191 InitFromArgv(argv);
192}
[email protected]06cc083a2011-03-01 02:28:42193
Chris Watkinsbb7211c2017-11-29 07:16:38194CommandLine::CommandLine(const CommandLine& other) = default;
jackhou1bd9da92015-05-21 04:48:00195
Chris Watkinsbb7211c2017-11-29 07:16:38196CommandLine& CommandLine::operator=(const CommandLine& other) = default;
jackhou1bd9da92015-05-21 04:48:00197
Chris Watkinsbb7211c2017-11-29 07:16:38198CommandLine::~CommandLine() = default;
[email protected]acbeb3d2011-03-01 20:47:58199
[email protected]bf98a0e12013-09-25 23:36:00200#if defined(OS_WIN)
201// static
202void CommandLine::set_slash_is_not_a_switch() {
203 // The last switch prefix should be slash, so adjust the size to skip it.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34204 static_assert(base::make_span(kSwitchPrefixes).back() == L"/",
205 "Error: Last switch prefix is not a slash.");
deepak1556bb31c182019-10-29 23:15:58206 switch_prefix_count = base::size(kSwitchPrefixes) - 1;
[email protected]bf98a0e12013-09-25 23:36:00207}
anantad936bc12016-06-22 21:40:31208
209// static
210void CommandLine::InitUsingArgvForTesting(int argc, const char* const* argv) {
211 DCHECK(!current_process_commandline_);
212 current_process_commandline_ = new CommandLine(NO_PROGRAM);
Jan Wilken Dörrieda77fd432019-10-24 21:40:34213 // On Windows we need to convert the command line arguments to std::wstring.
jdoerrie5c4dc4e2019-02-01 18:02:33214 CommandLine::StringVector argv_vector;
anantad936bc12016-06-22 21:40:31215 for (int i = 0; i < argc; ++i)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34216 argv_vector.push_back(UTF8ToWide(argv[i]));
anantad936bc12016-06-22 21:40:31217 current_process_commandline_->InitFromArgv(argv_vector);
218}
[email protected]bf98a0e12013-09-25 23:36:00219#endif
220
[email protected]06cc083a2011-03-01 02:28:42221// static
[email protected]72e2e2422012-02-27 18:38:12222bool CommandLine::Init(int argc, const char* const* argv) {
[email protected]f96fe2c42011-07-13 18:03:34223 if (current_process_commandline_) {
224 // If this is intentional, Reset() must be called first. If we are using
225 // the shared build mode, we have to share a single object across multiple
226 // shared libraries.
[email protected]72e2e2422012-02-27 18:38:12227 return false;
[email protected]f96fe2c42011-07-13 18:03:34228 }
229
[email protected]a40ca4302011-05-14 01:10:24230 current_process_commandline_ = new CommandLine(NO_PROGRAM);
[email protected]06cc083a2011-03-01 02:28:42231#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34232 current_process_commandline_->ParseFromString(::GetCommandLineW());
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39233#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42234 current_process_commandline_->InitFromArgv(argc, argv);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39235#else
236#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42237#endif
[email protected]72e2e2422012-02-27 18:38:12238
239 return true;
[email protected]06cc083a2011-03-01 02:28:42240}
241
242// static
243void CommandLine::Reset() {
244 DCHECK(current_process_commandline_);
245 delete current_process_commandline_;
Ivan Kotenkova16212a52017-11-08 12:37:33246 current_process_commandline_ = nullptr;
[email protected]06cc083a2011-03-01 02:28:42247}
248
249// static
250CommandLine* CommandLine::ForCurrentProcess() {
251 DCHECK(current_process_commandline_);
252 return current_process_commandline_;
[email protected]3a3d47472010-07-15 21:03:54253}
254
[email protected]2bf64a92013-07-11 23:10:40255// static
256bool CommandLine::InitializedForCurrentProcess() {
257 return !!current_process_commandline_;
258}
259
[email protected]f3adb5c2008-08-07 20:07:32260#if defined(OS_WIN)
[email protected]06cc083a2011-03-01 02:28:42261// static
Jan Wilken Dörrieda77fd432019-10-24 21:40:34262CommandLine CommandLine::FromString(StringPieceType command_line) {
[email protected]a40ca4302011-05-14 01:10:24263 CommandLine cmd(NO_PROGRAM);
[email protected]06cc083a2011-03-01 02:28:42264 cmd.ParseFromString(command_line);
265 return cmd;
266}
[email protected]a40ca4302011-05-14 01:10:24267#endif
[email protected]06cc083a2011-03-01 02:28:42268
[email protected]a40ca4302011-05-14 01:10:24269void CommandLine::InitFromArgv(int argc,
270 const CommandLine::CharType* const* argv) {
271 StringVector new_argv;
[email protected]06cc083a2011-03-01 02:28:42272 for (int i = 0; i < argc; ++i)
[email protected]a40ca4302011-05-14 01:10:24273 new_argv.push_back(argv[i]);
274 InitFromArgv(new_argv);
[email protected]51343d5a2009-10-26 22:39:33275}
276
[email protected]06cc083a2011-03-01 02:28:42277void CommandLine::InitFromArgv(const StringVector& argv) {
[email protected]a40ca4302011-05-14 01:10:24278 argv_ = StringVector(1);
[email protected]93660ab32013-06-18 08:19:18279 switches_.clear();
[email protected]a40ca4302011-05-14 01:10:24280 begin_args_ = 1;
281 SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
thestig8badc792014-12-04 22:14:22282 AppendSwitchesAndArguments(this, argv);
[email protected]06cc083a2011-03-01 02:28:42283}
[email protected]06cc083a2011-03-01 02:28:42284
[email protected]06cc083a2011-03-01 02:28:42285FilePath CommandLine::GetProgram() const {
[email protected]06cc083a2011-03-01 02:28:42286 return FilePath(argv_[0]);
[email protected]a40ca4302011-05-14 01:10:24287}
288
289void CommandLine::SetProgram(const FilePath& program) {
tfarina023b1dcc2015-12-06 13:25:41290#if defined(OS_WIN)
Jan Wilken Dörrieb630aca2019-12-04 10:59:11291 argv_[0] = StringType(TrimWhitespace(program.value(), TRIM_ALL));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39292#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
tfarina023b1dcc2015-12-06 13:25:41293 TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39294#else
295#error Unsupported platform
tfarina023b1dcc2015-12-06 13:25:41296#endif
[email protected]06cc083a2011-03-01 02:28:42297}
298
jdoerrie5c4dc4e2019-02-01 18:02:33299bool CommandLine::HasSwitch(const StringPiece& switch_string) const {
brettwfce8d192015-08-10 19:07:51300 DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
Jan Wilken Dörrief61e74c2019-06-07 08:20:02301 return Contains(switches_, switch_string);
[email protected]06cc083a2011-03-01 02:28:42302}
303
jackhou1bd9da92015-05-21 04:48:00304bool CommandLine::HasSwitch(const char switch_constant[]) const {
jdoerrie5c4dc4e2019-02-01 18:02:33305 return HasSwitch(StringPiece(switch_constant));
tapted009a1dc82015-03-30 03:57:10306}
307
[email protected]06cc083a2011-03-01 02:28:42308std::string CommandLine::GetSwitchValueASCII(
jdoerrie5c4dc4e2019-02-01 18:02:33309 const StringPiece& switch_string) const {
[email protected]a40ca4302011-05-14 01:10:24310 StringType value = GetSwitchValueNative(switch_string);
Jan Wilken Dörrieda77fd432019-10-24 21:40:34311#if defined(OS_WIN)
312 if (!IsStringASCII(base::AsStringPiece16(value))) {
313#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]bd6fc2f2014-03-17 23:55:43314 if (!IsStringASCII(value)) {
Jan Wilken Dörrieda77fd432019-10-24 21:40:34315#endif
[email protected]a42d4632011-10-26 21:48:00316 DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
317 return std::string();
[email protected]06cc083a2011-03-01 02:28:42318 }
319#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34320 return WideToUTF8(value);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39321#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42322 return value;
323#endif
324}
325
326FilePath CommandLine::GetSwitchValuePath(
jdoerrie5c4dc4e2019-02-01 18:02:33327 const StringPiece& switch_string) const {
[email protected]06cc083a2011-03-01 02:28:42328 return FilePath(GetSwitchValueNative(switch_string));
329}
330
331CommandLine::StringType CommandLine::GetSwitchValueNative(
jdoerrie5c4dc4e2019-02-01 18:02:33332 const StringPiece& switch_string) const {
brettwfce8d192015-08-10 19:07:51333 DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
Jeremy Roman863386d2017-10-31 19:25:38334 auto result = switches_.find(switch_string);
335 return result == switches_.end() ? StringType() : result->second;
[email protected]06cc083a2011-03-01 02:28:42336}
337
[email protected]06cc083a2011-03-01 02:28:42338void CommandLine::AppendSwitch(const std::string& switch_string) {
[email protected]a40ca4302011-05-14 01:10:24339 AppendSwitchNative(switch_string, StringType());
[email protected]06cc083a2011-03-01 02:28:42340}
341
342void CommandLine::AppendSwitchPath(const std::string& switch_string,
343 const FilePath& path) {
344 AppendSwitchNative(switch_string, path.value());
345}
346
347void CommandLine::AppendSwitchNative(const std::string& switch_string,
348 const CommandLine::StringType& value) {
349#if defined(OS_WIN)
brettwfce8d192015-08-10 19:07:51350 const std::string switch_key = ToLowerASCII(switch_string);
Jan Wilken Dörrieda77fd432019-10-24 21:40:34351 StringType combined_switch_string(UTF8ToWide(switch_key));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39352#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
jackhou1bd9da92015-05-21 04:48:00353 const std::string& switch_key = switch_string;
354 StringType combined_switch_string(switch_key);
[email protected]a40ca4302011-05-14 01:10:24355#endif
356 size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
jackhou1bd9da92015-05-21 04:48:00357 auto insertion =
358 switches_.insert(make_pair(switch_key.substr(prefix_length), value));
359 if (!insertion.second)
360 insertion.first->second = value;
[email protected]a40ca4302011-05-14 01:10:24361 // Preserve existing switch prefixes in |argv_|; only append one if necessary.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34362 if (prefix_length == 0) {
363 combined_switch_string.insert(0, kSwitchPrefixes[0].data(),
364 kSwitchPrefixes[0].size());
365 }
[email protected]06cc083a2011-03-01 02:28:42366 if (!value.empty())
367 combined_switch_string += kSwitchValueSeparator + value;
[email protected]a40ca4302011-05-14 01:10:24368 // Append the switch and update the switches/arguments divider |begin_args_|.
369 argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
[email protected]06cc083a2011-03-01 02:28:42370}
371
372void CommandLine::AppendSwitchASCII(const std::string& switch_string,
373 const std::string& value_string) {
374#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34375 AppendSwitchNative(switch_string, UTF8ToWide(value_string));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39376#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42377 AppendSwitchNative(switch_string, value_string);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39378#else
379#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42380#endif
381}
382
Pavol Markobf16b812019-06-14 00:53:12383void CommandLine::RemoveSwitch(base::StringPiece switch_key_without_prefix) {
384#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34385 StringType switch_key_native = UTF8ToWide(switch_key_without_prefix);
Pavol Markobf16b812019-06-14 00:53:12386#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
387 StringType switch_key_native = switch_key_without_prefix.as_string();
388#endif
389
390 DCHECK_EQ(ToLowerASCII(switch_key_without_prefix), switch_key_without_prefix);
391 DCHECK_EQ(0u, GetSwitchPrefixLength(switch_key_native));
392 size_t erased_from_switches =
393 switches_.erase(switch_key_without_prefix.as_string());
394 DCHECK(erased_from_switches <= 1);
395 if (!erased_from_switches)
396 return;
397
398 // Also erase from the switches section of |argv_| and update |begin_args_|
399 // accordingly.
400 // Switches in |argv_| have indices [1, begin_args_).
401 auto argv_switches_begin = argv_.begin() + 1;
402 auto argv_switches_end = argv_.begin() + begin_args_;
403 DCHECK(argv_switches_begin <= argv_switches_end);
404 DCHECK(argv_switches_end <= argv_.end());
Andrei Polushin2ec89bc2019-07-30 20:47:17405 auto expell = std::remove_if(argv_switches_begin, argv_switches_end,
Pavol Markobf16b812019-06-14 00:53:12406 [&switch_key_native](const StringType& arg) {
407 return IsSwitchWithKey(arg, switch_key_native);
408 });
Andrei Polushin2ec89bc2019-07-30 20:47:17409 if (expell == argv_switches_end) {
Pavol Markobf16b812019-06-14 00:53:12410 NOTREACHED();
411 return;
412 }
Andrei Polushin2ec89bc2019-07-30 20:47:17413 begin_args_ -= argv_switches_end - expell;
414 argv_.erase(expell, argv_switches_end);
Avi Drissman1aa6cb92019-01-23 15:58:38415}
416
[email protected]06cc083a2011-03-01 02:28:42417void CommandLine::CopySwitchesFrom(const CommandLine& source,
418 const char* const switches[],
419 size_t count) {
420 for (size_t i = 0; i < count; ++i) {
[email protected]a40ca4302011-05-14 01:10:24421 if (source.HasSwitch(switches[i]))
422 AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
[email protected]06cc083a2011-03-01 02:28:42423 }
424}
425
[email protected]75f1c782011-07-13 23:41:22426CommandLine::StringVector CommandLine::GetArgs() const {
[email protected]a40ca4302011-05-14 01:10:24427 // Gather all arguments after the last switch (may include kSwitchTerminator).
428 StringVector args(argv_.begin() + begin_args_, argv_.end());
429 // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
jdoerrie1c4b8ff2018-10-03 00:10:57430 auto switch_terminator =
[email protected]a40ca4302011-05-14 01:10:24431 std::find(args.begin(), args.end(), kSwitchTerminator);
432 if (switch_terminator != args.end())
433 args.erase(switch_terminator);
434 return args;
435}
436
[email protected]06cc083a2011-03-01 02:28:42437void CommandLine::AppendArg(const std::string& value) {
438#if defined(OS_WIN)
[email protected]bd6fc2f2014-03-17 23:55:43439 DCHECK(IsStringUTF8(value));
Jan Wilken Dörrieda77fd432019-10-24 21:40:34440 AppendArgNative(UTF8ToWide(value));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39441#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42442 AppendArgNative(value);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39443#else
444#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42445#endif
446}
447
448void CommandLine::AppendArgPath(const FilePath& path) {
449 AppendArgNative(path.value());
450}
451
452void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
[email protected]06cc083a2011-03-01 02:28:42453 argv_.push_back(value);
[email protected]06cc083a2011-03-01 02:28:42454}
455
456void CommandLine::AppendArguments(const CommandLine& other,
457 bool include_program) {
[email protected]06cc083a2011-03-01 02:28:42458 if (include_program)
[email protected]a40ca4302011-05-14 01:10:24459 SetProgram(other.GetProgram());
thestig8badc792014-12-04 22:14:22460 AppendSwitchesAndArguments(this, other.argv());
[email protected]06cc083a2011-03-01 02:28:42461}
462
463void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
[email protected]06cc083a2011-03-01 02:28:42464 if (wrapper.empty())
465 return;
skyostild851aa12017-03-29 17:38:35466 // Split the wrapper command based on whitespace (with quoting).
467 using CommandLineTokenizer =
468 StringTokenizerT<StringType, StringType::const_iterator>;
469 CommandLineTokenizer tokenizer(wrapper, FILE_PATH_LITERAL(" "));
470 tokenizer.set_quote_chars(FILE_PATH_LITERAL("'\""));
471 std::vector<StringType> wrapper_argv;
472 while (tokenizer.GetNext())
473 wrapper_argv.emplace_back(tokenizer.token());
474
[email protected]a40ca4302011-05-14 01:10:24475 // Prepend the wrapper and update the switches/arguments |begin_args_|.
476 argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
477 begin_args_ += wrapper_argv.size();
[email protected]06cc083a2011-03-01 02:28:42478}
479
480#if defined(OS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34481void CommandLine::ParseFromString(StringPieceType command_line) {
jdoerrie90787012019-02-07 16:22:02482 command_line = TrimWhitespace(command_line, TRIM_ALL);
483 if (command_line.empty())
[email protected]bb975362009-01-21 01:00:22484 return;
485
486 int num_args = 0;
487 wchar_t** args = NULL;
Cliff Smolinskyc5c52102019-05-03 20:51:54488 // When calling CommandLineToArgvW, use the apiset if available.
489 // Doing so will bypass loading shell32.dll on Win8+.
490 HMODULE downlevel_shell32_dll =
491 ::LoadLibraryEx(L"api-ms-win-downlevel-shell32-l1-1-0.dll", nullptr,
492 LOAD_LIBRARY_SEARCH_SYSTEM32);
493 if (downlevel_shell32_dll) {
494 auto command_line_to_argv_w_proc =
495 reinterpret_cast<decltype(::CommandLineToArgvW)*>(
496 ::GetProcAddress(downlevel_shell32_dll, "CommandLineToArgvW"));
497 if (command_line_to_argv_w_proc)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34498 args = command_line_to_argv_w_proc(command_line.data(), &num_args);
Cliff Smolinskyc5c52102019-05-03 20:51:54499 ::FreeLibrary(downlevel_shell32_dll);
500 } else {
501 // Since the apiset is not available, allow the delayload of shell32.dll
502 // to take place.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34503 args = ::CommandLineToArgvW(command_line.data(), &num_args);
Cliff Smolinskyc5c52102019-05-03 20:51:54504 }
[email protected]bb975362009-01-21 01:00:22505
[email protected]a42d4632011-10-26 21:48:00506 DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
Jan Wilken Dörrieda77fd432019-10-24 21:40:34507 << command_line;
508 StringVector argv(args, args + num_args);
jdoerrie5c4dc4e2019-02-01 18:02:33509 InitFromArgv(argv);
[email protected]a40ca4302011-05-14 01:10:24510 LocalFree(args);
[email protected]bb975362009-01-21 01:00:22511}
[email protected]f3adb5c2008-08-07 20:07:32512#endif
[email protected]2f3b1cc2014-03-17 23:07:15513
mgiucac974d5102014-10-01 09:24:51514CommandLine::StringType CommandLine::GetCommandLineStringInternal(
515 bool quote_placeholders) const {
516 StringType string(argv_[0]);
517#if defined(OS_WIN)
518 string = QuoteForCommandLineToArgvW(string, quote_placeholders);
519#endif
520 StringType params(GetArgumentsStringInternal(quote_placeholders));
521 if (!params.empty()) {
Jan Wilken Dörrieda77fd432019-10-24 21:40:34522 string.append(FILE_PATH_LITERAL(" "));
mgiucac974d5102014-10-01 09:24:51523 string.append(params);
524 }
525 return string;
526}
527
528CommandLine::StringType CommandLine::GetArgumentsStringInternal(
529 bool quote_placeholders) const {
530 StringType params;
531 // Append switches and arguments.
532 bool parse_switches = true;
533 for (size_t i = 1; i < argv_.size(); ++i) {
534 StringType arg = argv_[i];
535 StringType switch_string;
536 StringType switch_value;
537 parse_switches &= arg != kSwitchTerminator;
538 if (i > 1)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34539 params.append(FILE_PATH_LITERAL(" "));
mgiucac974d5102014-10-01 09:24:51540 if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
541 params.append(switch_string);
542 if (!switch_value.empty()) {
543#if defined(OS_WIN)
544 switch_value =
545 QuoteForCommandLineToArgvW(switch_value, quote_placeholders);
546#endif
547 params.append(kSwitchValueSeparator + switch_value);
548 }
thestig8badc792014-12-04 22:14:22549 } else {
mgiucac974d5102014-10-01 09:24:51550#if defined(OS_WIN)
551 arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
552#endif
553 params.append(arg);
554 }
555 }
556 return params;
557}
558
[email protected]2f3b1cc2014-03-17 23:07:15559} // namespace base