Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 7491285cd14c9b0bdf18279191d5dc91f41e9e50 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
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
Peter Kasting025a94252025-01-29 21:28:377#include <algorithm>
Arthur Sonzogni6718b702025-01-09 10:49:108#include <array>
[email protected]2edc2862011-04-04 18:04:379#include <ostream>
Helmut Januschka6e9d8fc2024-04-04 16:09:5510#include <string_view>
initial.commitd7cae122008-07-26 21:49:3811
David Dorwin3f503b82022-04-20 04:07:0312#include "base/check_op.h"
Tom Sepez8dce0f0f2025-02-14 20:37:0313#include "base/compiler_specific.h"
Lei Zhangc0f9fc52021-05-22 08:00:5314#include "base/containers/contains.h"
jdoerrie5c4dc4e2019-02-01 18:02:3315#include "base/containers/span.h"
Will Harrisee9f0a22023-03-02 21:38:5816#include "base/debug/debugging_buildflags.h"
[email protected]57999812013-02-24 05:40:5217#include "base/files/file_path.h"
initial.commitd7cae122008-07-26 21:49:3818#include "base/logging.h"
Hans Wennborgafeb3902020-06-17 14:42:2919#include "base/notreached.h"
Peter Kastingde85e742022-06-01 17:41:5420#include "base/numerics/checked_math.h"
Jan Wilken Dörriebd953ac2020-07-10 23:28:5421#include "base/strings/strcat.h"
[email protected]5ae0b763e2013-02-07 23:01:3922#include "base/strings/string_split.h"
skyostild851aa12017-03-29 17:38:3523#include "base/strings/string_tokenizer.h"
[email protected]251cd6e52013-06-11 13:36:3724#include "base/strings/string_util.h"
[email protected]a4ea1f12013-06-07 18:37:0725#include "base/strings/utf_string_conversions.h"
[email protected]74e9fa22010-12-29 21:06:4326#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3827
Xiaohan Wang38e4ebb2022-01-19 06:57:4328#if BUILDFLAG(IS_WIN)
[email protected]74e9fa22010-12-29 21:06:4329#include <windows.h>
Bruce Dawsona1e1cfcb2022-11-22 20:04:3530
[email protected]74e9fa22010-12-29 21:06:4331#include <shellapi.h>
Jan Wilken Dörrieb630aca2019-12-04 10:59:1132
33#include "base/strings/string_util_win.h"
Xiaohan Wang38e4ebb2022-01-19 06:57:4334#endif // BUILDFLAG(IS_WIN)
[email protected]7f113f32009-09-10 18:02:1735
[email protected]2f3b1cc2014-03-17 23:07:1536namespace base {
[email protected]04af979a2013-02-16 04:12:2637
Ivan Kotenkova16212a52017-11-08 12:37:3338CommandLine* CommandLine::current_process_commandline_ = nullptr;
initial.commitd7cae122008-07-26 21:49:3839
[email protected]06cc083a2011-03-01 02:28:4240namespace {
[email protected]2f3b1cc2014-03-17 23:07:1541
Greg Gutermane6051192021-10-15 21:14:3642DuplicateSwitchHandler* g_duplicate_switch_handler = nullptr;
43
Jan Wilken Dörrieda77fd432019-10-24 21:40:3444constexpr CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
45constexpr CommandLine::CharType kSwitchValueSeparator[] =
46 FILE_PATH_LITERAL("=");
[email protected]bf98a0e12013-09-25 23:36:0047
[email protected]06cc083a2011-03-01 02:28:4248// Since we use a lazy match, make sure that longer versions (like "--") are
49// listed before shorter versions (like "-") of similar prefixes.
Xiaohan Wang38e4ebb2022-01-19 06:57:4350#if BUILDFLAG(IS_WIN)
[email protected]bf98a0e12013-09-25 23:36:0051// By putting slash last, we can control whether it is treaded as a switch
52// value by changing the value of switch_prefix_count to be one less than
53// the array size.
Arthur Sonzogni6718b702025-01-09 10:49:1054constexpr auto kSwitchPrefixes = std::to_array<CommandLine::StringViewType>({
55 L"--",
56 L"-",
57 L"/",
58});
Xiaohan Wang38e4ebb2022-01-19 06:57:4359#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
[email protected]1a48f312008-08-12 01:14:3760// Unixes don't use slash as a switch.
Arthur Sonzogni6718b702025-01-09 10:49:1061constexpr auto kSwitchPrefixes = std::to_array<CommandLine::StringViewType>({
62 "--",
63 "-",
64});
[email protected]5d426332008-08-08 20:46:2165#endif
Daniel Chengf45f47602022-02-28 22:38:3266size_t switch_prefix_count = std::size(kSwitchPrefixes);
initial.commitd7cae122008-07-26 21:49:3867
Lei Zhanga562bca2024-12-09 23:42:4168bool IsSwitchNameValid(std::string_view switch_name) {
69 return ToLowerASCII(switch_name) == switch_name;
70}
71
Xiaohan Wang38e4ebb2022-01-19 06:57:4372#if BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:1773// Switch string that specifies the single argument to the command line.
74// If present, everything after this switch is interpreted as a single
75// argument regardless of whitespace, quotes, etc. Used for launches from the
76// Windows shell, which may have arguments with unencoded quotes that could
77// otherwise unexpectedly be split into multiple arguments
78// (https://crbug.com/937179).
79constexpr CommandLine::CharType kSingleArgument[] =
80 FILE_PATH_LITERAL("single-argument");
Xiaohan Wang38e4ebb2022-01-19 06:57:4381#endif // BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:1782
Lei Zhangd6388122024-07-30 20:39:1983size_t GetSwitchPrefixLength(CommandLine::StringViewType string) {
[email protected]bf98a0e12013-09-25 23:36:0084 for (size_t i = 0; i < switch_prefix_count; ++i) {
[email protected]a40ca4302011-05-14 01:10:2485 CommandLine::StringType prefix(kSwitchPrefixes[i]);
Peter Kasting134ef9af2024-12-28 02:30:0986 if (string.substr(0, prefix.length()) == prefix) {
[email protected]a40ca4302011-05-14 01:10:2487 return prefix.length();
Peter Kasting134ef9af2024-12-28 02:30:0988 }
[email protected]a40ca4302011-05-14 01:10:2489 }
90 return 0;
initial.commitd7cae122008-07-26 21:49:3891}
[email protected]0fd23af2011-02-20 06:33:0492
[email protected]a40ca4302011-05-14 01:10:2493// Fills in |switch_string| and |switch_value| if |string| is a switch.
94// This will preserve the input switch prefix in the output |switch_string|.
95bool IsSwitch(const CommandLine::StringType& string,
96 CommandLine::StringType* switch_string,
97 CommandLine::StringType* switch_value) {
98 switch_string->clear();
99 switch_value->clear();
[email protected]21e342f2012-10-19 06:19:59100 size_t prefix_length = GetSwitchPrefixLength(string);
Peter Kasting134ef9af2024-12-28 02:30:09101 if (prefix_length == 0 || prefix_length == string.length()) {
[email protected]a40ca4302011-05-14 01:10:24102 return false;
Peter Kasting134ef9af2024-12-28 02:30:09103 }
[email protected]a40ca4302011-05-14 01:10:24104
105 const size_t equals_position = string.find(kSwitchValueSeparator);
106 *switch_string = string.substr(0, equals_position);
Peter Kasting134ef9af2024-12-28 02:30:09107 if (equals_position != CommandLine::StringType::npos) {
[email protected]a40ca4302011-05-14 01:10:24108 *switch_value = string.substr(equals_position + 1);
Peter Kasting134ef9af2024-12-28 02:30:09109 }
[email protected]a40ca4302011-05-14 01:10:24110 return true;
111}
112
Pavol Markobf16b812019-06-14 00:53:12113// Returns true iff |string| represents a switch with key
114// |switch_key_without_prefix|, regardless of value.
Lei Zhangd6388122024-07-30 20:39:19115bool IsSwitchWithKey(CommandLine::StringViewType string,
116 CommandLine::StringViewType switch_key_without_prefix) {
Pavol Markobf16b812019-06-14 00:53:12117 size_t prefix_length = GetSwitchPrefixLength(string);
Peter Kasting134ef9af2024-12-28 02:30:09118 if (prefix_length == 0 || prefix_length == string.length()) {
Pavol Markobf16b812019-06-14 00:53:12119 return false;
Peter Kasting134ef9af2024-12-28 02:30:09120 }
Pavol Markobf16b812019-06-14 00:53:12121
122 const size_t equals_position = string.find(kSwitchValueSeparator);
123 return string.substr(prefix_length, equals_position - prefix_length) ==
124 switch_key_without_prefix;
125}
126
Xiaohan Wang38e4ebb2022-01-19 06:57:43127#if BUILDFLAG(IS_WIN)
S. Ganeshf2c7cb732022-12-16 22:54:42128// Quotes a string as necessary for CommandLineToArgvW compatibility *on
Jesse McKenna036150c2020-07-17 21:11:17129// Windows*.
S. Ganeshf2c7cb732022-12-16 22:54:42130// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx#parsing-c-command-line-arguments.
131std::wstring QuoteForCommandLineToArgvWInternal(
132 const std::wstring& arg,
133 bool allow_unsafe_insert_sequences) {
134 // Ensures that GetCommandLineString isn't used to generate command-line
Jesse McKenna185ceda22021-03-10 06:47:55135 // strings for the Windows shell by checking for Windows insert sequences like
Jesse McKenna036150c2020-07-17 21:11:17136 // "%1". GetCommandLineStringForShell should be used instead to get a string
137 // with the correct placeholder format for the shell.
Jesse McKenna185ceda22021-03-10 06:47:55138 DCHECK(arg.size() != 2 || arg[0] != L'%' || allow_unsafe_insert_sequences);
[email protected]a40ca4302011-05-14 01:10:24139
S. Ganeshf2c7cb732022-12-16 22:54:42140 constexpr wchar_t kQuotableCharacters[] = L" \t\\\"";
141 if (arg.find_first_of(kQuotableCharacters) == std::wstring::npos) {
[email protected]0fd23af2011-02-20 06:33:04142 return arg;
143 }
144
S. Ganeshf2c7cb732022-12-16 22:54:42145 std::wstring out(1, L'"');
[email protected]0fd23af2011-02-20 06:33:04146 for (size_t i = 0; i < arg.size(); ++i) {
S. Ganeshf2c7cb732022-12-16 22:54:42147 if (arg[i] == L'\\') {
148 // Finds the extent of this run of backslashes.
149 size_t end = i + 1;
150 while (end < arg.size() && arg[end] == L'\\') {
151 ++end;
152 }
[email protected]0fd23af2011-02-20 06:33:04153
S. Ganeshf2c7cb732022-12-16 22:54:42154 const size_t backslash_count = end - i;
155
156 // Backslashes are escaped only if the run is followed by a double quote.
[email protected]0fd23af2011-02-20 06:33:04157 // Since we also will end the string with a double quote, we escape for
158 // either a double quote or the end of the string.
S. Ganeshf2c7cb732022-12-16 22:54:42159 const size_t backslash_multiplier =
160 (end == arg.size() || arg[end] == L'"') ? 2 : 1;
[email protected]0fd23af2011-02-20 06:33:04161
S. Ganeshf2c7cb732022-12-16 22:54:42162 out.append(std::wstring(backslash_count * backslash_multiplier, L'\\'));
163
164 // Advances `i` to one before `end` to balance `++i` in loop.
[email protected]0fd23af2011-02-20 06:33:04165 i = end - 1;
S. Ganeshf2c7cb732022-12-16 22:54:42166 } else if (arg[i] == L'"') {
167 out.append(LR"(\")");
[email protected]0fd23af2011-02-20 06:33:04168 } else {
169 out.push_back(arg[i]);
170 }
171 }
S. Ganeshf2c7cb732022-12-16 22:54:42172
173 out.push_back(L'"');
[email protected]0fd23af2011-02-20 06:33:04174
175 return out;
176}
Xiaohan Wang38e4ebb2022-01-19 06:57:43177#endif // BUILDFLAG(IS_WIN)
initial.commitd7cae122008-07-26 21:49:38178
[email protected]06cc083a2011-03-01 02:28:42179} // namespace
180
Greg Gutermane6051192021-10-15 21:14:36181// static
182void CommandLine::SetDuplicateSwitchHandler(
183 std::unique_ptr<DuplicateSwitchHandler> new_duplicate_switch_handler) {
184 delete g_duplicate_switch_handler;
185 g_duplicate_switch_handler = new_duplicate_switch_handler.release();
186}
187
Greg Gutermanfe16560d2021-10-07 19:58:15188CommandLine::CommandLine(NoProgram no_program) : argv_(1), begin_args_(1) {}
[email protected]06cc083a2011-03-01 02:28:42189
Peter Kasting134ef9af2024-12-28 02:30:09190CommandLine::CommandLine(const FilePath& program) : argv_(1), begin_args_(1) {
[email protected]a40ca4302011-05-14 01:10:24191 SetProgram(program);
[email protected]06cc083a2011-03-01 02:28:42192}
193
[email protected]a40ca4302011-05-14 01:10:24194CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
Greg Gutermanfe16560d2021-10-07 19:58:15195 : argv_(1), begin_args_(1) {
Tom Sepez8dce0f0f2025-02-14 20:37:03196 // SAFETY: required from caller.
197 UNSAFE_BUFFERS(InitFromArgv(argc, argv));
[email protected]06cc083a2011-03-01 02:28:42198}
199
Peter Kasting134ef9af2024-12-28 02:30:09200CommandLine::CommandLine(const StringVector& argv) : argv_(1), begin_args_(1) {
[email protected]06cc083a2011-03-01 02:28:42201 InitFromArgv(argv);
202}
[email protected]06cc083a2011-03-01 02:28:42203
Chris Watkinsbb7211c2017-11-29 07:16:38204CommandLine::CommandLine(const CommandLine& other) = default;
Greg Thompson809a1c02024-02-22 16:28:55205CommandLine::CommandLine(CommandLine&& other) noexcept
206 :
207#if BUILDFLAG(IS_WIN)
208 raw_command_line_string_(
Lei Zhangd6388122024-07-30 20:39:19209 std::exchange(other.raw_command_line_string_, StringViewType())),
Greg Thompson809a1c02024-02-22 16:28:55210 has_single_argument_switch_(
211 std::exchange(other.has_single_argument_switch_, false)),
212#endif // BUILDFLAG(IS_WIN)
213 argv_(std::exchange(other.argv_, StringVector(1))),
214 switches_(std::move(other.switches_)),
215 begin_args_(std::exchange(other.begin_args_, 1)) {
216#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
217 other.sequence_checker_.Detach();
218#endif
219}
Chris Watkinsbb7211c2017-11-29 07:16:38220CommandLine& CommandLine::operator=(const CommandLine& other) = default;
Greg Thompson809a1c02024-02-22 16:28:55221CommandLine& CommandLine::operator=(CommandLine&& other) noexcept {
222#if BUILDFLAG(IS_WIN)
223 raw_command_line_string_ =
Lei Zhangd6388122024-07-30 20:39:19224 std::exchange(other.raw_command_line_string_, StringViewType());
Greg Thompson809a1c02024-02-22 16:28:55225 has_single_argument_switch_ =
226 std::exchange(other.has_single_argument_switch_, false);
227#endif // BUILDFLAG(IS_WIN)
228 argv_ = std::exchange(other.argv_, StringVector(1));
229 switches_ = std::move(other.switches_);
230 begin_args_ = std::exchange(other.begin_args_, 1);
231#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
232 other.sequence_checker_.Detach();
233#endif
234 return *this;
235}
Chris Watkinsbb7211c2017-11-29 07:16:38236CommandLine::~CommandLine() = default;
[email protected]acbeb3d2011-03-01 20:47:58237
Xiaohan Wang38e4ebb2022-01-19 06:57:43238#if BUILDFLAG(IS_WIN)
[email protected]bf98a0e12013-09-25 23:36:00239// static
240void CommandLine::set_slash_is_not_a_switch() {
241 // The last switch prefix should be slash, so adjust the size to skip it.
Peter Kasting0e042762024-11-13 22:54:55242 static_assert(base::span(kSwitchPrefixes).back() == L"/",
Jan Wilken Dörrieda77fd432019-10-24 21:40:34243 "Error: Last switch prefix is not a slash.");
Daniel Chengf45f47602022-02-28 22:38:32244 switch_prefix_count = std::size(kSwitchPrefixes) - 1;
[email protected]bf98a0e12013-09-25 23:36:00245}
anantad936bc12016-06-22 21:40:31246
247// static
248void CommandLine::InitUsingArgvForTesting(int argc, const char* const* argv) {
249 DCHECK(!current_process_commandline_);
250 current_process_commandline_ = new CommandLine(NO_PROGRAM);
Jan Wilken Dörrieda77fd432019-10-24 21:40:34251 // On Windows we need to convert the command line arguments to std::wstring.
jdoerrie5c4dc4e2019-02-01 18:02:33252 CommandLine::StringVector argv_vector;
Peter Kasting134ef9af2024-12-28 02:30:09253 for (int i = 0; i < argc; ++i) {
Tom Sepez8dce0f0f2025-02-14 20:37:03254 // SAFETY: required from caller.
255 argv_vector.push_back(UTF8ToWide(UNSAFE_BUFFERS(argv[i])));
Peter Kasting134ef9af2024-12-28 02:30:09256 }
anantad936bc12016-06-22 21:40:31257 current_process_commandline_->InitFromArgv(argv_vector);
258}
Xiaohan Wang38e4ebb2022-01-19 06:57:43259#endif // BUILDFLAG(IS_WIN)
[email protected]bf98a0e12013-09-25 23:36:00260
[email protected]06cc083a2011-03-01 02:28:42261// static
[email protected]72e2e2422012-02-27 18:38:12262bool CommandLine::Init(int argc, const char* const* argv) {
[email protected]f96fe2c42011-07-13 18:03:34263 if (current_process_commandline_) {
264 // If this is intentional, Reset() must be called first. If we are using
265 // the shared build mode, we have to share a single object across multiple
266 // shared libraries.
[email protected]72e2e2422012-02-27 18:38:12267 return false;
[email protected]f96fe2c42011-07-13 18:03:34268 }
269
[email protected]a40ca4302011-05-14 01:10:24270 current_process_commandline_ = new CommandLine(NO_PROGRAM);
Xiaohan Wang38e4ebb2022-01-19 06:57:43271#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34272 current_process_commandline_->ParseFromString(::GetCommandLineW());
Xiaohan Wang38e4ebb2022-01-19 06:57:43273#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Tom Sepez8dce0f0f2025-02-14 20:37:03274 // SAFETY: required from caller.
275 UNSAFE_BUFFERS(current_process_commandline_->InitFromArgv(argc, argv));
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39276#else
277#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42278#endif
[email protected]72e2e2422012-02-27 18:38:12279
280 return true;
[email protected]06cc083a2011-03-01 02:28:42281}
282
283// static
284void CommandLine::Reset() {
285 DCHECK(current_process_commandline_);
286 delete current_process_commandline_;
Ivan Kotenkova16212a52017-11-08 12:37:33287 current_process_commandline_ = nullptr;
[email protected]06cc083a2011-03-01 02:28:42288}
289
290// static
291CommandLine* CommandLine::ForCurrentProcess() {
292 DCHECK(current_process_commandline_);
293 return current_process_commandline_;
[email protected]3a3d47472010-07-15 21:03:54294}
295
[email protected]2bf64a92013-07-11 23:10:40296// static
297bool CommandLine::InitializedForCurrentProcess() {
298 return !!current_process_commandline_;
299}
300
mayuko aibafa08692f2024-01-12 03:58:38301// static
302CommandLine CommandLine::FromArgvWithoutProgram(const StringVector& argv) {
303 CommandLine cmd(NO_PROGRAM);
304 cmd.AppendSwitchesAndArguments(argv);
305 return cmd;
306}
307
Xiaohan Wang38e4ebb2022-01-19 06:57:43308#if BUILDFLAG(IS_WIN)
[email protected]06cc083a2011-03-01 02:28:42309// static
Lei Zhangd6388122024-07-30 20:39:19310CommandLine CommandLine::FromString(StringViewType command_line) {
[email protected]a40ca4302011-05-14 01:10:24311 CommandLine cmd(NO_PROGRAM);
[email protected]06cc083a2011-03-01 02:28:42312 cmd.ParseFromString(command_line);
313 return cmd;
314}
Xiaohan Wang38e4ebb2022-01-19 06:57:43315#endif // BUILDFLAG(IS_WIN)
[email protected]06cc083a2011-03-01 02:28:42316
[email protected]a40ca4302011-05-14 01:10:24317void CommandLine::InitFromArgv(int argc,
318 const CommandLine::CharType* const* argv) {
319 StringVector new_argv;
Peter Kasting134ef9af2024-12-28 02:30:09320 for (int i = 0; i < argc; ++i) {
Tom Sepez8dce0f0f2025-02-14 20:37:03321 // SAFETY: required from caller.
322 new_argv.push_back(UNSAFE_BUFFERS(argv[i]));
Peter Kasting134ef9af2024-12-28 02:30:09323 }
[email protected]a40ca4302011-05-14 01:10:24324 InitFromArgv(new_argv);
[email protected]51343d5a2009-10-26 22:39:33325}
326
[email protected]06cc083a2011-03-01 02:28:42327void CommandLine::InitFromArgv(const StringVector& argv) {
[email protected]a40ca4302011-05-14 01:10:24328 argv_ = StringVector(1);
[email protected]93660ab32013-06-18 08:19:18329 switches_.clear();
[email protected]a40ca4302011-05-14 01:10:24330 begin_args_ = 1;
331 SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
mayuko aibafa08692f2024-01-12 03:58:38332 if (!argv.empty()) {
Peter Kasting654bb6252024-11-16 02:29:08333 AppendSwitchesAndArguments(span(argv).subspan<1>());
mayuko aibafa08692f2024-01-12 03:58:38334 }
[email protected]06cc083a2011-03-01 02:28:42335}
[email protected]06cc083a2011-03-01 02:28:42336
[email protected]06cc083a2011-03-01 02:28:42337FilePath CommandLine::GetProgram() const {
[email protected]06cc083a2011-03-01 02:28:42338 return FilePath(argv_[0]);
[email protected]a40ca4302011-05-14 01:10:24339}
340
341void CommandLine::SetProgram(const FilePath& program) {
Will Harrisee9f0a22023-03-02 21:38:58342#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
343 sequence_checker_.Check();
344#endif
Xiaohan Wang38e4ebb2022-01-19 06:57:43345#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieb630aca2019-12-04 10:59:11346 argv_[0] = StringType(TrimWhitespace(program.value(), TRIM_ALL));
Xiaohan Wang38e4ebb2022-01-19 06:57:43347#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
tfarina023b1dcc2015-12-06 13:25:41348 TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39349#else
350#error Unsupported platform
tfarina023b1dcc2015-12-06 13:25:41351#endif
[email protected]06cc083a2011-03-01 02:28:42352}
353
Helmut Januschka6e9d8fc2024-04-04 16:09:55354bool CommandLine::HasSwitch(std::string_view switch_string) const {
Daniel Chenge3835812025-05-26 23:01:39355 CHECK(IsSwitchNameValid(switch_string));
Jan Wilken Dörrief61e74c2019-06-07 08:20:02356 return Contains(switches_, switch_string);
[email protected]06cc083a2011-03-01 02:28:42357}
358
jackhou1bd9da92015-05-21 04:48:00359bool CommandLine::HasSwitch(const char switch_constant[]) const {
Helmut Januschka6e9d8fc2024-04-04 16:09:55360 return HasSwitch(std::string_view(switch_constant));
tapted009a1dc82015-03-30 03:57:10361}
362
Helmut Januschka6e9d8fc2024-04-04 16:09:55363std::string CommandLine::GetSwitchValueASCII(
364 std::string_view switch_string) const {
[email protected]a40ca4302011-05-14 01:10:24365 StringType value = GetSwitchValueNative(switch_string);
Xiaohan Wang38e4ebb2022-01-19 06:57:43366#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34367 if (!IsStringASCII(base::AsStringPiece16(value))) {
Xiaohan Wang38e4ebb2022-01-19 06:57:43368#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
[email protected]bd6fc2fb2014-03-17 23:55:43369 if (!IsStringASCII(value)) {
Jan Wilken Dörrieda77fd432019-10-24 21:40:34370#endif
[email protected]a42d4632011-10-26 21:48:00371 DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
372 return std::string();
[email protected]06cc083a2011-03-01 02:28:42373 }
Xiaohan Wang38e4ebb2022-01-19 06:57:43374#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34375 return WideToUTF8(value);
Xiaohan Wang38e4ebb2022-01-19 06:57:43376#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42377 return value;
378#endif
379}
380
S. Ganeshe484e292025-02-13 20:43:14381std::string CommandLine::GetSwitchValueUTF8(
382 std::string_view switch_string) const {
383 StringType value = GetSwitchValueNative(switch_string);
384
385#if BUILDFLAG(IS_WIN)
386 const std::string maybe_utf8_value = WideToUTF8(value);
387#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
388 const std::string maybe_utf8_value = value;
389#endif
390
391 if (!IsStringUTF8(maybe_utf8_value)) {
392 DLOG(WARNING) << "Value of switch (" << switch_string << ") is not UTF8.";
393 return {};
394 }
395 return maybe_utf8_value;
396}
397
Helmut Januschka6e9d8fc2024-04-04 16:09:55398FilePath CommandLine::GetSwitchValuePath(std::string_view switch_string) const {
[email protected]06cc083a2011-03-01 02:28:42399 return FilePath(GetSwitchValueNative(switch_string));
400}
401
402CommandLine::StringType CommandLine::GetSwitchValueNative(
Helmut Januschka6e9d8fc2024-04-04 16:09:55403 std::string_view switch_string) const {
Daniel Chenge3835812025-05-26 23:01:39404 CHECK(IsSwitchNameValid(switch_string));
Lei Zhanga562bca2024-12-09 23:42:41405
Jeremy Roman863386d2017-10-31 19:25:38406 auto result = switches_.find(switch_string);
407 return result == switches_.end() ? StringType() : result->second;
[email protected]06cc083a2011-03-01 02:28:42408}
409
Helmut Januschka6e9d8fc2024-04-04 16:09:55410void CommandLine::AppendSwitch(std::string_view switch_string) {
[email protected]a40ca4302011-05-14 01:10:24411 AppendSwitchNative(switch_string, StringType());
[email protected]06cc083a2011-03-01 02:28:42412}
413
Helmut Januschka6e9d8fc2024-04-04 16:09:55414void CommandLine::AppendSwitchPath(std::string_view switch_string,
[email protected]06cc083a2011-03-01 02:28:42415 const FilePath& path) {
416 AppendSwitchNative(switch_string, path.value());
417}
418
Helmut Januschka6e9d8fc2024-04-04 16:09:55419void CommandLine::AppendSwitchNative(std::string_view switch_string,
Lei Zhangd6388122024-07-30 20:39:19420 CommandLine::StringViewType value) {
Will Harrisee9f0a22023-03-02 21:38:58421#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
422 sequence_checker_.Check();
423#endif
Xiaohan Wang38e4ebb2022-01-19 06:57:43424#if BUILDFLAG(IS_WIN)
brettwfce8d192015-08-10 19:07:51425 const std::string switch_key = ToLowerASCII(switch_string);
Jan Wilken Dörrieda77fd432019-10-24 21:40:34426 StringType combined_switch_string(UTF8ToWide(switch_key));
Xiaohan Wang38e4ebb2022-01-19 06:57:43427#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Helmut Januschka6e9d8fc2024-04-04 16:09:55428 std::string_view switch_key = switch_string;
jackhou1bd9da92015-05-21 04:48:00429 StringType combined_switch_string(switch_key);
[email protected]a40ca4302011-05-14 01:10:24430#endif
431 size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
Greg Gutermanfe16560d2021-10-07 19:58:15432 auto key = switch_key.substr(prefix_length);
Greg Gutermane6051192021-10-15 21:14:36433 if (g_duplicate_switch_handler) {
434 g_duplicate_switch_handler->ResolveDuplicate(key, value,
435 switches_[std::string(key)]);
Greg Gutermanfe16560d2021-10-07 19:58:15436 } else {
Daniel Chenga371b4c2022-01-14 18:24:27437 switches_[std::string(key)] = StringType(value);
Greg Gutermanfe16560d2021-10-07 19:58:15438 }
439
[email protected]a40ca4302011-05-14 01:10:24440 // Preserve existing switch prefixes in |argv_|; only append one if necessary.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34441 if (prefix_length == 0) {
442 combined_switch_string.insert(0, kSwitchPrefixes[0].data(),
443 kSwitchPrefixes[0].size());
444 }
Peter Kasting134ef9af2024-12-28 02:30:09445 if (!value.empty()) {
Jan Wilken Dörriebd953ac2020-07-10 23:28:54446 base::StrAppend(&combined_switch_string, {kSwitchValueSeparator, value});
Peter Kasting134ef9af2024-12-28 02:30:09447 }
[email protected]a40ca4302011-05-14 01:10:24448 // Append the switch and update the switches/arguments divider |begin_args_|.
Peter Kastingde85e742022-06-01 17:41:54449 argv_.insert(argv_.begin() + begin_args_, combined_switch_string);
450 begin_args_ = (CheckedNumeric(begin_args_) + 1).ValueOrDie();
[email protected]06cc083a2011-03-01 02:28:42451}
452
Helmut Januschka6e9d8fc2024-04-04 16:09:55453void CommandLine::AppendSwitchASCII(std::string_view switch_string,
454 std::string_view value_string) {
S. Ganeshe484e292025-02-13 20:43:14455 AppendSwitchUTF8(switch_string, value_string);
456}
457
458void CommandLine::AppendSwitchUTF8(std::string_view switch_string,
459 std::string_view value_string) {
S. Ganesh36c9c55f2025-02-14 05:20:51460 DCHECK(IsStringUTF8(value_string))
461 << "Switch (" << switch_string << ") value (" << value_string
462 << ") is not UTF8.";
Xiaohan Wang38e4ebb2022-01-19 06:57:43463#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34464 AppendSwitchNative(switch_string, UTF8ToWide(value_string));
Xiaohan Wang38e4ebb2022-01-19 06:57:43465#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42466 AppendSwitchNative(switch_string, value_string);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39467#else
468#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42469#endif
470}
471
Helmut Januschka6e9d8fc2024-04-04 16:09:55472void CommandLine::RemoveSwitch(std::string_view switch_key_without_prefix) {
Will Harrisee9f0a22023-03-02 21:38:58473#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
474 sequence_checker_.Check();
475#endif
Daniel Chenge3835812025-05-26 23:01:39476 CHECK(IsSwitchNameValid(switch_key_without_prefix));
Lei Zhanga562bca2024-12-09 23:42:41477
Xiaohan Wang38e4ebb2022-01-19 06:57:43478#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrieda77fd432019-10-24 21:40:34479 StringType switch_key_native = UTF8ToWide(switch_key_without_prefix);
Xiaohan Wang38e4ebb2022-01-19 06:57:43480#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Jan Wilken Dörrie5db50ac2021-02-15 11:43:16481 StringType switch_key_native(switch_key_without_prefix);
Pavol Markobf16b812019-06-14 00:53:12482#endif
483
Pavol Markobf16b812019-06-14 00:53:12484 DCHECK_EQ(0u, GetSwitchPrefixLength(switch_key_native));
Jan Wilken Dörrie5db50ac2021-02-15 11:43:16485 auto it = switches_.find(switch_key_without_prefix);
Peter Kasting134ef9af2024-12-28 02:30:09486 if (it == switches_.end()) {
Pavol Markobf16b812019-06-14 00:53:12487 return;
Peter Kasting134ef9af2024-12-28 02:30:09488 }
Jan Wilken Dörrie5db50ac2021-02-15 11:43:16489 switches_.erase(it);
Pavol Markobf16b812019-06-14 00:53:12490 // Also erase from the switches section of |argv_| and update |begin_args_|
491 // accordingly.
492 // Switches in |argv_| have indices [1, begin_args_).
493 auto argv_switches_begin = argv_.begin() + 1;
494 auto argv_switches_end = argv_.begin() + begin_args_;
495 DCHECK(argv_switches_begin <= argv_switches_end);
496 DCHECK(argv_switches_end <= argv_.end());
Andrei Polushin2ec89bc2019-07-30 20:47:17497 auto expell = std::remove_if(argv_switches_begin, argv_switches_end,
Pavol Markobf16b812019-06-14 00:53:12498 [&switch_key_native](const StringType& arg) {
499 return IsSwitchWithKey(arg, switch_key_native);
500 });
Andrei Polushin2ec89bc2019-07-30 20:47:17501 if (expell == argv_switches_end) {
Peter Boströmde573332024-08-26 20:42:45502 NOTREACHED();
Pavol Markobf16b812019-06-14 00:53:12503 }
Andrei Polushin2ec89bc2019-07-30 20:47:17504 begin_args_ -= argv_switches_end - expell;
505 argv_.erase(expell, argv_switches_end);
Avi Drissman1aa6cb92019-01-23 15:58:38506}
507
[email protected]06cc083a2011-03-01 02:28:42508void CommandLine::CopySwitchesFrom(const CommandLine& source,
Lei Zhang24dcd3e2023-07-07 20:08:36509 span<const char* const> switches) {
510 for (const char* entry : switches) {
511 if (source.HasSwitch(entry)) {
512 AppendSwitchNative(entry, source.GetSwitchValueNative(entry));
513 }
514 }
515}
516
[email protected]75f1c782011-07-13 23:41:22517CommandLine::StringVector CommandLine::GetArgs() const {
[email protected]a40ca4302011-05-14 01:10:24518 // Gather all arguments after the last switch (may include kSwitchTerminator).
519 StringVector args(argv_.begin() + begin_args_, argv_.end());
520 // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
Peter Kasting025a94252025-01-29 21:28:37521 auto switch_terminator = std::ranges::find(args, kSwitchTerminator);
Peter Kasting134ef9af2024-12-28 02:30:09522 if (switch_terminator != args.end()) {
[email protected]a40ca4302011-05-14 01:10:24523 args.erase(switch_terminator);
Peter Kasting134ef9af2024-12-28 02:30:09524 }
[email protected]a40ca4302011-05-14 01:10:24525 return args;
526}
527
Helmut Januschka6e9d8fc2024-04-04 16:09:55528void CommandLine::AppendArg(std::string_view value) {
Xiaohan Wang38e4ebb2022-01-19 06:57:43529#if BUILDFLAG(IS_WIN)
[email protected]bd6fc2fb2014-03-17 23:55:43530 DCHECK(IsStringUTF8(value));
Jan Wilken Dörrieda77fd432019-10-24 21:40:34531 AppendArgNative(UTF8ToWide(value));
Xiaohan Wang38e4ebb2022-01-19 06:57:43532#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
[email protected]06cc083a2011-03-01 02:28:42533 AppendArgNative(value);
Fabrice de Gans-Riberi306871de2018-05-16 19:38:39534#else
535#error Unsupported platform
[email protected]06cc083a2011-03-01 02:28:42536#endif
537}
538
539void CommandLine::AppendArgPath(const FilePath& path) {
540 AppendArgNative(path.value());
541}
542
Lei Zhangd6388122024-07-30 20:39:19543void CommandLine::AppendArgNative(StringViewType value) {
Will Harrisee9f0a22023-03-02 21:38:58544#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
545 sequence_checker_.Check();
546#endif
Peter Kasting811504a72025-01-09 03:18:50547 argv_.emplace_back(value);
[email protected]06cc083a2011-03-01 02:28:42548}
549
550void CommandLine::AppendArguments(const CommandLine& other,
551 bool include_program) {
Peter Kasting134ef9af2024-12-28 02:30:09552 if (include_program) {
[email protected]a40ca4302011-05-14 01:10:24553 SetProgram(other.GetProgram());
Peter Kasting134ef9af2024-12-28 02:30:09554 }
mayuko aibafa08692f2024-01-12 03:58:38555 if (!other.argv().empty()) {
Peter Kasting654bb6252024-11-16 02:29:08556 AppendSwitchesAndArguments(span(other.argv()).subspan<1>());
mayuko aibafa08692f2024-01-12 03:58:38557 }
[email protected]06cc083a2011-03-01 02:28:42558}
559
Lei Zhangd6388122024-07-30 20:39:19560void CommandLine::PrependWrapper(StringViewType wrapper) {
Will Harrisee9f0a22023-03-02 21:38:58561#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
562 sequence_checker_.Check();
563#endif
Peter Kasting134ef9af2024-12-28 02:30:09564 if (wrapper.empty()) {
[email protected]06cc083a2011-03-01 02:28:42565 return;
Peter Kasting134ef9af2024-12-28 02:30:09566 }
skyostild851aa12017-03-29 17:38:35567 // Split the wrapper command based on whitespace (with quoting).
Lei Zhangd6388122024-07-30 20:39:19568 // StringViewType does not currently work directly with StringTokenizerT.
skyostild851aa12017-03-29 17:38:35569 using CommandLineTokenizer =
570 StringTokenizerT<StringType, StringType::const_iterator>;
Wez65018d02021-05-20 15:47:45571 StringType wrapper_string(wrapper);
572 CommandLineTokenizer tokenizer(wrapper_string, FILE_PATH_LITERAL(" "));
skyostild851aa12017-03-29 17:38:35573 tokenizer.set_quote_chars(FILE_PATH_LITERAL("'\""));
574 std::vector<StringType> wrapper_argv;
Lei Zhang09b218e52024-09-12 19:21:55575 while (std::optional<StringViewType> token = tokenizer.GetNextTokenView()) {
576 wrapper_argv.emplace_back(token.value());
577 }
skyostild851aa12017-03-29 17:38:35578
[email protected]a40ca4302011-05-14 01:10:24579 // Prepend the wrapper and update the switches/arguments |begin_args_|.
580 argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
581 begin_args_ += wrapper_argv.size();
[email protected]06cc083a2011-03-01 02:28:42582}
583
Xiaohan Wang38e4ebb2022-01-19 06:57:43584#if BUILDFLAG(IS_WIN)
Lei Zhangd6388122024-07-30 20:39:19585void CommandLine::ParseFromString(StringViewType command_line) {
jdoerrie90787012019-02-07 16:22:02586 command_line = TrimWhitespace(command_line, TRIM_ALL);
Peter Kasting134ef9af2024-12-28 02:30:09587 if (command_line.empty()) {
[email protected]bb975362009-01-21 01:00:22588 return;
Peter Kasting134ef9af2024-12-28 02:30:09589 }
Jesse McKenna036150c2020-07-17 21:11:17590 raw_command_line_string_ = command_line;
[email protected]bb975362009-01-21 01:00:22591
592 int num_args = 0;
593 wchar_t** args = NULL;
Cliff Smolinskyc5c52102019-05-03 20:51:54594 // When calling CommandLineToArgvW, use the apiset if available.
David Bienvenu2c020692023-02-27 19:14:51595 // Doing so will bypass loading shell32.dll on Windows.
Cliff Smolinskyc5c52102019-05-03 20:51:54596 HMODULE downlevel_shell32_dll =
597 ::LoadLibraryEx(L"api-ms-win-downlevel-shell32-l1-1-0.dll", nullptr,
598 LOAD_LIBRARY_SEARCH_SYSTEM32);
599 if (downlevel_shell32_dll) {
600 auto command_line_to_argv_w_proc =
601 reinterpret_cast<decltype(::CommandLineToArgvW)*>(
602 ::GetProcAddress(downlevel_shell32_dll, "CommandLineToArgvW"));
Peter Kasting134ef9af2024-12-28 02:30:09603 if (command_line_to_argv_w_proc) {
Jan Wilken Dörrieda77fd432019-10-24 21:40:34604 args = command_line_to_argv_w_proc(command_line.data(), &num_args);
Peter Kasting134ef9af2024-12-28 02:30:09605 }
Cliff Smolinskyc5c52102019-05-03 20:51:54606 } else {
607 // Since the apiset is not available, allow the delayload of shell32.dll
608 // to take place.
Jan Wilken Dörrieda77fd432019-10-24 21:40:34609 args = ::CommandLineToArgvW(command_line.data(), &num_args);
Cliff Smolinskyc5c52102019-05-03 20:51:54610 }
[email protected]bb975362009-01-21 01:00:22611
[email protected]a42d4632011-10-26 21:48:00612 DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
Jan Wilken Dörrieda77fd432019-10-24 21:40:34613 << command_line;
Tom Sepez8dce0f0f2025-02-14 20:37:03614 StringVector argv(args, UNSAFE_TODO(args + num_args));
jdoerrie5c4dc4e2019-02-01 18:02:33615 InitFromArgv(argv);
Lei Zhangd6388122024-07-30 20:39:19616 raw_command_line_string_ = StringViewType();
[email protected]a40ca4302011-05-14 01:10:24617 LocalFree(args);
Chris Davisa36cb122020-01-21 05:34:00618
Peter Kasting134ef9af2024-12-28 02:30:09619 if (downlevel_shell32_dll) {
Chris Davisa36cb122020-01-21 05:34:00620 ::FreeLibrary(downlevel_shell32_dll);
Peter Kasting134ef9af2024-12-28 02:30:09621 }
[email protected]bb975362009-01-21 01:00:22622}
David Bienvenuedbb4ce2022-09-28 16:02:16623
Xiaohan Wang38e4ebb2022-01-19 06:57:43624#endif // BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17625
mayuko aibafa08692f2024-01-12 03:58:38626void CommandLine::AppendSwitchesAndArguments(span<const StringType> argv) {
Jesse McKenna036150c2020-07-17 21:11:17627 bool parse_switches = true;
Xiaohan Wang38e4ebb2022-01-19 06:57:43628#if BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17629 const bool is_parsed_from_string = !raw_command_line_string_.empty();
630#endif
mayuko aibafa08692f2024-01-12 03:58:38631 for (StringType arg : argv) {
Xiaohan Wang38e4ebb2022-01-19 06:57:43632#if BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17633 arg = CommandLine::StringType(TrimWhitespace(arg, TRIM_ALL));
Xiaohan Wang38e4ebb2022-01-19 06:57:43634#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Jesse McKenna036150c2020-07-17 21:11:17635 TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
[email protected]f3adb5c2008-08-07 20:07:32636#endif
[email protected]2f3b1cc2014-03-17 23:07:15637
Jesse McKenna036150c2020-07-17 21:11:17638 CommandLine::StringType switch_string;
639 CommandLine::StringType switch_value;
640 parse_switches &= (arg != kSwitchTerminator);
641 if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
Xiaohan Wang38e4ebb2022-01-19 06:57:43642#if BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17643 if (is_parsed_from_string &&
644 IsSwitchWithKey(switch_string, kSingleArgument)) {
645 ParseAsSingleArgument(switch_string);
646 return;
647 }
648 AppendSwitchNative(WideToUTF8(switch_string), switch_value);
Xiaohan Wang38e4ebb2022-01-19 06:57:43649#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Jesse McKenna036150c2020-07-17 21:11:17650 AppendSwitchNative(switch_string, switch_value);
651#else
652#error Unsupported platform
653#endif
654 } else {
655 AppendArgNative(arg);
656 }
657 }
658}
659
Jesse McKenna185ceda22021-03-10 06:47:55660CommandLine::StringType CommandLine::GetArgumentsStringInternal(
661 bool allow_unsafe_insert_sequences) const {
662 StringType params;
663 // Append switches and arguments.
664 bool parse_switches = true;
David Bienvenu6d3c35fe22022-11-22 00:25:48665#if BUILDFLAG(IS_WIN)
666 bool appended_single_argument_switch = false;
667#endif
668
Jesse McKenna185ceda22021-03-10 06:47:55669 for (size_t i = 1; i < argv_.size(); ++i) {
670 StringType arg = argv_[i];
671 StringType switch_string;
672 StringType switch_value;
673 parse_switches &= arg != kSwitchTerminator;
Peter Kasting134ef9af2024-12-28 02:30:09674 if (i > 1) {
Jesse McKenna185ceda22021-03-10 06:47:55675 params.append(FILE_PATH_LITERAL(" "));
Peter Kasting134ef9af2024-12-28 02:30:09676 }
Jesse McKenna185ceda22021-03-10 06:47:55677 if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
678 params.append(switch_string);
679 if (!switch_value.empty()) {
Xiaohan Wang38e4ebb2022-01-19 06:57:43680#if BUILDFLAG(IS_WIN)
S. Ganeshf2c7cb732022-12-16 22:54:42681 switch_value = QuoteForCommandLineToArgvWInternal(
Jesse McKenna185ceda22021-03-10 06:47:55682 switch_value, allow_unsafe_insert_sequences);
683#endif
684 params.append(kSwitchValueSeparator + switch_value);
685 }
686 } else {
Xiaohan Wang38e4ebb2022-01-19 06:57:43687#if BUILDFLAG(IS_WIN)
David Bienvenu6d3c35fe22022-11-22 00:25:48688 if (has_single_argument_switch_) {
689 // Check that we don't have multiple arguments when
690 // `has_single_argument_switch_` is true.
691 DCHECK(!appended_single_argument_switch);
692 appended_single_argument_switch = true;
693 params.append(base::StrCat(
694 {kSwitchPrefixes[0], kSingleArgument, FILE_PATH_LITERAL(" ")}));
695 } else {
S. Ganeshf2c7cb732022-12-16 22:54:42696 arg = QuoteForCommandLineToArgvWInternal(arg,
697 allow_unsafe_insert_sequences);
David Bienvenu6d3c35fe22022-11-22 00:25:48698 }
Jesse McKenna185ceda22021-03-10 06:47:55699#endif
700 params.append(arg);
701 }
702 }
703 return params;
704}
705
Jesse McKenna036150c2020-07-17 21:11:17706CommandLine::StringType CommandLine::GetCommandLineString() const {
mgiucac974d5102014-10-01 09:24:51707 StringType string(argv_[0]);
Xiaohan Wang38e4ebb2022-01-19 06:57:43708#if BUILDFLAG(IS_WIN)
S. Ganeshf2c7cb732022-12-16 22:54:42709 string = QuoteForCommandLineToArgvWInternal(
710 string,
711 /*allow_unsafe_insert_sequences=*/false);
mgiucac974d5102014-10-01 09:24:51712#endif
Jesse McKenna036150c2020-07-17 21:11:17713 StringType params(GetArgumentsString());
mgiucac974d5102014-10-01 09:24:51714 if (!params.empty()) {
Jan Wilken Dörrieda77fd432019-10-24 21:40:34715 string.append(FILE_PATH_LITERAL(" "));
mgiucac974d5102014-10-01 09:24:51716 string.append(params);
717 }
718 return string;
719}
720
Xiaohan Wang38e4ebb2022-01-19 06:57:43721#if BUILDFLAG(IS_WIN)
S. Ganeshf2c7cb732022-12-16 22:54:42722// static
723std::wstring CommandLine::QuoteForCommandLineToArgvW(const std::wstring& arg) {
724 return QuoteForCommandLineToArgvWInternal(
725 arg, /*allow_unsafe_insert_sequences=*/false);
726}
727
Jesse McKenna036150c2020-07-17 21:11:17728// NOTE: this function is used to set Chrome's open command in the registry
729// during update. Any change to the syntax must be compatible with the prior
730// version (i.e., any new syntax must be understood by older browsers expecting
731// the old syntax, and the new browser must still handle the old syntax), as
732// old versions are likely to persist, e.g., immediately after background
733// update, when parsing command lines for other channels, when uninstalling web
734// applications installed using the old syntax, etc.
735CommandLine::StringType CommandLine::GetCommandLineStringForShell() const {
736 DCHECK(GetArgs().empty());
737 StringType command_line_string = GetCommandLineString();
738 return command_line_string + FILE_PATH_LITERAL(" ") +
Jan Wilken Dörrie4aa966b2020-08-24 18:20:29739 StringType(kSwitchPrefixes[0]) + kSingleArgument +
Jesse McKenna036150c2020-07-17 21:11:17740 FILE_PATH_LITERAL(" %1");
741}
Jesse McKenna185ceda22021-03-10 06:47:55742
743CommandLine::StringType
744CommandLine::GetCommandLineStringWithUnsafeInsertSequences() const {
745 StringType string(argv_[0]);
S. Ganeshf2c7cb732022-12-16 22:54:42746 string = QuoteForCommandLineToArgvWInternal(
747 string,
748 /*allow_unsafe_insert_sequences=*/true);
Jesse McKenna185ceda22021-03-10 06:47:55749 StringType params(
750 GetArgumentsStringInternal(/*allow_unsafe_insert_sequences=*/true));
751 if (!params.empty()) {
752 string.append(FILE_PATH_LITERAL(" "));
753 string.append(params);
754 }
755 return string;
756}
Xiaohan Wang38e4ebb2022-01-19 06:57:43757#endif // BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17758
759CommandLine::StringType CommandLine::GetArgumentsString() const {
Jesse McKenna185ceda22021-03-10 06:47:55760 return GetArgumentsStringInternal(/*allow_unsafe_insert_sequences=*/false);
mgiucac974d5102014-10-01 09:24:51761}
762
Xiaohan Wang38e4ebb2022-01-19 06:57:43763#if BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17764void CommandLine::ParseAsSingleArgument(
765 const CommandLine::StringType& single_arg_switch) {
766 DCHECK(!raw_command_line_string_.empty());
767
768 // Remove any previously parsed arguments.
Peter Kastingde85e742022-06-01 17:41:54769 argv_.resize(static_cast<size_t>(begin_args_));
Jesse McKenna036150c2020-07-17 21:11:17770
771 // Locate "--single-argument" in the process's raw command line. Results are
772 // unpredictable if "--single-argument" appears as part of a previous
773 // argument or switch.
774 const size_t single_arg_switch_position =
775 raw_command_line_string_.find(single_arg_switch);
776 DCHECK_NE(single_arg_switch_position, StringType::npos);
777
778 // Append the portion of the raw command line that starts one character past
779 // "--single-argument" as the one and only argument, or return if no
780 // argument is present.
781 const size_t arg_position =
782 single_arg_switch_position + single_arg_switch.length() + 1;
Peter Kasting134ef9af2024-12-28 02:30:09783 if (arg_position >= raw_command_line_string_.length()) {
Jesse McKenna036150c2020-07-17 21:11:17784 return;
Peter Kasting134ef9af2024-12-28 02:30:09785 }
David Bienvenuedbb4ce2022-09-28 16:02:16786 has_single_argument_switch_ = true;
Lei Zhangd6388122024-07-30 20:39:19787 const StringViewType arg = raw_command_line_string_.substr(arg_position);
Jesse McKenna036150c2020-07-17 21:11:17788 if (!arg.empty()) {
Wez65018d02021-05-20 15:47:45789 AppendArgNative(arg);
Jesse McKenna036150c2020-07-17 21:11:17790 }
791}
Xiaohan Wang38e4ebb2022-01-19 06:57:43792#endif // BUILDFLAG(IS_WIN)
Jesse McKenna036150c2020-07-17 21:11:17793
Will Harrisee9f0a22023-03-02 21:38:58794void CommandLine::DetachFromCurrentSequence() {
795#if BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
796 sequence_checker_.Detach();
797#endif // BUILDFLAG(ENABLE_COMMANDLINE_SEQUENCE_CHECKS)
798}
799
[email protected]2f3b1cc2014-03-17 23:07:15800} // namespace base