Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: base/command_line.cc

Issue 1046073002: Add read-only mode to CommandLine that optimizes HasSwitch(const char*). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@whitelisted
Patch Set: Fix tests. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/command_line.h ('k') | base/command_line_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/command_line.h" 5 #include "base/command_line.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cstring>
8 #include <ostream> 9 #include <ostream>
9 10
10 #include "base/basictypes.h" 11 #include "base/basictypes.h"
11 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "build/build_config.h" 17 #include "build/build_config.h"
17 18
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 switch_value); 87 switch_value);
87 #elif defined(OS_POSIX) 88 #elif defined(OS_POSIX)
88 command_line->AppendSwitchNative(switch_string, switch_value); 89 command_line->AppendSwitchNative(switch_string, switch_value);
89 #endif 90 #endif
90 } else { 91 } else {
91 command_line->AppendArgNative(arg); 92 command_line->AppendArgNative(arg);
92 } 93 }
93 } 94 }
94 } 95 }
95 96
97 bool ContainsUpperASCII(const char* string) {
98 for (; *string; ++string) {
99 if (*string >= 'A' && *string <= 'Z')
100 return true;
101 }
102 return false;
103 }
104
96 // Lowercase switches for backwards compatiblity *on Windows*. 105 // Lowercase switches for backwards compatiblity *on Windows*.
97 #if defined(OS_WIN) 106 #if defined(OS_WIN)
98 std::string LowerASCIIOnWindows(const std::string& string) { 107 std::string LowerASCIIOnWindows(const std::string& string) {
99 return StringToLowerASCII(string); 108 return StringToLowerASCII(string);
100 } 109 }
101 #elif defined(OS_POSIX) 110 #elif defined(OS_POSIX)
102 const std::string& LowerASCIIOnWindows(const std::string& string) { 111 const std::string& LowerASCIIOnWindows(const std::string& string) {
103 return string; 112 return string;
104 } 113 }
105 #endif 114 #endif
106 115
116 // Comparator usable by std::lower_bound().
117 bool CompareStringAndCharPtr(const std::string& s, const char* c) {
118 return strcmp(s.c_str(), c) <= 0;
119 }
107 120
108 #if defined(OS_WIN) 121 #if defined(OS_WIN)
109 // Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. 122 // Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
110 string16 QuoteForCommandLineToArgvW(const string16& arg, 123 string16 QuoteForCommandLineToArgvW(const string16& arg,
111 bool quote_placeholders) { 124 bool quote_placeholders) {
112 // We follow the quoting rules of CommandLineToArgvW. 125 // We follow the quoting rules of CommandLineToArgvW.
113 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx 126 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
114 string16 quotable_chars(L" \\\""); 127 string16 quotable_chars(L" \\\"");
115 // We may also be required to quote '%', which is commonly used in a command 128 // We may also be required to quote '%', which is commonly used in a command
116 // line as a placeholder. (It may be substituted for a string with spaces.) 129 // line as a placeholder. (It may be substituted for a string with spaces.)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 } 164 }
152 out.push_back('"'); 165 out.push_back('"');
153 166
154 return out; 167 return out;
155 } 168 }
156 #endif 169 #endif
157 170
158 } // namespace 171 } // namespace
159 172
160 CommandLine::CommandLine(NoProgram no_program) 173 CommandLine::CommandLine(NoProgram no_program)
161 : argv_(1), 174 : argv_(1), begin_args_(1), writeable_(true) {
162 begin_args_(1) {
163 } 175 }
164 176
165 CommandLine::CommandLine(const FilePath& program) 177 CommandLine::CommandLine(const FilePath& program)
166 : argv_(1), 178 : argv_(1), begin_args_(1), writeable_(true) {
167 begin_args_(1) {
168 SetProgram(program); 179 SetProgram(program);
169 } 180 }
170 181
171 CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) 182 CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
172 : argv_(1), 183 : argv_(1), begin_args_(1), writeable_(true) {
173 begin_args_(1) {
174 InitFromArgv(argc, argv); 184 InitFromArgv(argc, argv);
175 } 185 }
176 186
177 CommandLine::CommandLine(const StringVector& argv) 187 CommandLine::CommandLine(const StringVector& argv)
178 : argv_(1), 188 : argv_(1), begin_args_(1), writeable_(true) {
179 begin_args_(1) {
180 InitFromArgv(argv); 189 InitFromArgv(argv);
181 } 190 }
182 191
183 CommandLine::~CommandLine() { 192 CommandLine::~CommandLine() {
184 } 193 }
185 194
186 #if defined(OS_WIN) 195 #if defined(OS_WIN)
187 // static 196 // static
188 void CommandLine::set_slash_is_not_a_switch() { 197 void CommandLine::set_slash_is_not_a_switch() {
189 // The last switch prefix should be slash, so adjust the size to skip it. 198 // The last switch prefix should be slash, so adjust the size to skip it.
(...skipping 10 matching lines...) Expand all
200 // shared libraries. 209 // shared libraries.
201 return false; 210 return false;
202 } 211 }
203 212
204 current_process_commandline_ = new CommandLine(NO_PROGRAM); 213 current_process_commandline_ = new CommandLine(NO_PROGRAM);
205 #if defined(OS_WIN) 214 #if defined(OS_WIN)
206 current_process_commandline_->ParseFromString(::GetCommandLineW()); 215 current_process_commandline_->ParseFromString(::GetCommandLineW());
207 #elif defined(OS_POSIX) 216 #elif defined(OS_POSIX)
208 current_process_commandline_->InitFromArgv(argc, argv); 217 current_process_commandline_->InitFromArgv(argc, argv);
209 #endif 218 #endif
219 current_process_commandline_->MakeReadOnly();
210 220
211 return true; 221 return true;
212 } 222 }
213 223
214 // static 224 // static
215 void CommandLine::Reset() { 225 void CommandLine::Reset() {
216 DCHECK(current_process_commandline_); 226 DCHECK(current_process_commandline_);
217 delete current_process_commandline_; 227 delete current_process_commandline_;
218 current_process_commandline_ = NULL; 228 current_process_commandline_ = NULL;
219 } 229 }
(...skipping 13 matching lines...) Expand all
233 // static 243 // static
234 CommandLine CommandLine::FromString(const string16& command_line) { 244 CommandLine CommandLine::FromString(const string16& command_line) {
235 CommandLine cmd(NO_PROGRAM); 245 CommandLine cmd(NO_PROGRAM);
236 cmd.ParseFromString(command_line); 246 cmd.ParseFromString(command_line);
237 return cmd; 247 return cmd;
238 } 248 }
239 #endif 249 #endif
240 250
241 void CommandLine::InitFromArgv(int argc, 251 void CommandLine::InitFromArgv(int argc,
242 const CommandLine::CharType* const* argv) { 252 const CommandLine::CharType* const* argv) {
253 DCHECK(writeable_);
243 StringVector new_argv; 254 StringVector new_argv;
244 for (int i = 0; i < argc; ++i) 255 for (int i = 0; i < argc; ++i)
245 new_argv.push_back(argv[i]); 256 new_argv.push_back(argv[i]);
246 InitFromArgv(new_argv); 257 InitFromArgv(new_argv);
247 } 258 }
248 259
249 void CommandLine::InitFromArgv(const StringVector& argv) { 260 void CommandLine::InitFromArgv(const StringVector& argv) {
261 DCHECK(writeable_);
250 argv_ = StringVector(1); 262 argv_ = StringVector(1);
251 switches_.clear(); 263 switches_.clear();
252 begin_args_ = 1; 264 begin_args_ = 1;
253 SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); 265 SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
254 AppendSwitchesAndArguments(this, argv); 266 AppendSwitchesAndArguments(this, argv);
255 } 267 }
256 268
257 FilePath CommandLine::GetProgram() const { 269 FilePath CommandLine::GetProgram() const {
258 return FilePath(argv_[0]); 270 return FilePath(argv_[0]);
259 } 271 }
260 272
261 void CommandLine::SetProgram(const FilePath& program) { 273 void CommandLine::SetProgram(const FilePath& program) {
274 DCHECK(writeable_);
262 TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); 275 TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
263 } 276 }
264 277
265 bool CommandLine::HasSwitch(const std::string& switch_string) const { 278 bool CommandLine::HasSwitch(const std::string& switch_string) const {
266 return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end(); 279 #if defined(OS_WIN)
280 if (ContainsUpperASCII(switch_string.c_str()))
281 return switches_.find(LowerASCIIOnWindows(switch_string)) !=
282 switches_.end();
283 #endif
284
285 return switches_.find(switch_string) != switches_.end();
267 } 286 }
268 287
269 bool CommandLine::HasSwitch(const char string_constant[]) const { 288 bool CommandLine::HasSwitch(const char string_constant[]) const {
270 return HasSwitch(std::string(string_constant)); 289 DCHECK(!ContainsUpperASCII(string_constant));
290 return writeable_ ? HasSwitchLowerCase(string_constant)
291 : HasSwitchVector(string_constant);
271 } 292 }
272 293
273 std::string CommandLine::GetSwitchValueASCII( 294 std::string CommandLine::GetSwitchValueASCII(
274 const std::string& switch_string) const { 295 const std::string& switch_string) const {
275 StringType value = GetSwitchValueNative(switch_string); 296 StringType value = GetSwitchValueNative(switch_string);
276 if (!IsStringASCII(value)) { 297 if (!IsStringASCII(value)) {
277 DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII."; 298 DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
278 return std::string(); 299 return std::string();
279 } 300 }
280 #if defined(OS_WIN) 301 #if defined(OS_WIN)
281 return UTF16ToASCII(value); 302 return UTF16ToASCII(value);
282 #else 303 #else
283 return value; 304 return value;
284 #endif 305 #endif
285 } 306 }
286 307
287 FilePath CommandLine::GetSwitchValuePath( 308 FilePath CommandLine::GetSwitchValuePath(
288 const std::string& switch_string) const { 309 const std::string& switch_string) const {
289 return FilePath(GetSwitchValueNative(switch_string)); 310 return FilePath(GetSwitchValueNative(switch_string));
290 } 311 }
291 312
292 CommandLine::StringType CommandLine::GetSwitchValueNative( 313 CommandLine::StringType CommandLine::GetSwitchValueNative(
293 const std::string& switch_string) const { 314 const std::string& switch_string) const {
294 SwitchMap::const_iterator result = 315 #if defined(OS_WIN)
295 switches_.find(LowerASCIIOnWindows(switch_string)); 316 if (ContainsUpperASCII(switch_string.c_str())) {
317 SwitchMap::const_iterator result =
318 switches_.find(LowerASCIIOnWindows(switch_string));
319 return result == switches_.end() ? StringType() : result->second;
320 }
321 #endif
322
323 SwitchMap::const_iterator result = switches_.find(switch_string);
296 return result == switches_.end() ? StringType() : result->second; 324 return result == switches_.end() ? StringType() : result->second;
297 } 325 }
298 326
299 void CommandLine::AppendSwitch(const std::string& switch_string) { 327 void CommandLine::AppendSwitch(const std::string& switch_string) {
300 AppendSwitchNative(switch_string, StringType()); 328 AppendSwitchNative(switch_string, StringType());
301 } 329 }
302 330
303 void CommandLine::AppendSwitchPath(const std::string& switch_string, 331 void CommandLine::AppendSwitchPath(const std::string& switch_string,
304 const FilePath& path) { 332 const FilePath& path) {
305 AppendSwitchNative(switch_string, path.value()); 333 AppendSwitchNative(switch_string, path.value());
306 } 334 }
307 335
308 void CommandLine::AppendSwitchNative(const std::string& switch_string, 336 void CommandLine::AppendSwitchNative(const std::string& switch_string,
309 const CommandLine::StringType& value) { 337 const CommandLine::StringType& value) {
338 DCHECK(writeable_);
310 std::string switch_key(LowerASCIIOnWindows(switch_string)); 339 std::string switch_key(LowerASCIIOnWindows(switch_string));
311 #if defined(OS_WIN) 340 #if defined(OS_WIN)
312 StringType combined_switch_string(ASCIIToUTF16(switch_key)); 341 StringType combined_switch_string(ASCIIToUTF16(switch_key));
313 #elif defined(OS_POSIX) 342 #elif defined(OS_POSIX)
314 StringType combined_switch_string(switch_string); 343 StringType combined_switch_string(switch_string);
315 #endif 344 #endif
316 size_t prefix_length = GetSwitchPrefixLength(combined_switch_string); 345 size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
317 switches_[switch_key.substr(prefix_length)] = value; 346 switches_[switch_key.substr(prefix_length)] = value;
318 // Preserve existing switch prefixes in |argv_|; only append one if necessary. 347 // Preserve existing switch prefixes in |argv_|; only append one if necessary.
319 if (prefix_length == 0) 348 if (prefix_length == 0)
320 combined_switch_string = kSwitchPrefixes[0] + combined_switch_string; 349 combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
321 if (!value.empty()) 350 if (!value.empty())
322 combined_switch_string += kSwitchValueSeparator + value; 351 combined_switch_string += kSwitchValueSeparator + value;
323 // Append the switch and update the switches/arguments divider |begin_args_|. 352 // Append the switch and update the switches/arguments divider |begin_args_|.
324 argv_.insert(argv_.begin() + begin_args_++, combined_switch_string); 353 argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
325 } 354 }
326 355
327 void CommandLine::AppendSwitchASCII(const std::string& switch_string, 356 void CommandLine::AppendSwitchASCII(const std::string& switch_string,
328 const std::string& value_string) { 357 const std::string& value_string) {
358 DCHECK(writeable_);
329 #if defined(OS_WIN) 359 #if defined(OS_WIN)
330 AppendSwitchNative(switch_string, ASCIIToUTF16(value_string)); 360 AppendSwitchNative(switch_string, ASCIIToUTF16(value_string));
331 #elif defined(OS_POSIX) 361 #elif defined(OS_POSIX)
332 AppendSwitchNative(switch_string, value_string); 362 AppendSwitchNative(switch_string, value_string);
333 #endif 363 #endif
334 } 364 }
335 365
336 void CommandLine::CopySwitchesFrom(const CommandLine& source, 366 void CommandLine::CopySwitchesFrom(const CommandLine& source,
337 const char* const switches[], 367 const char* const switches[],
338 size_t count) { 368 size_t count) {
369 DCHECK(writeable_);
339 for (size_t i = 0; i < count; ++i) { 370 for (size_t i = 0; i < count; ++i) {
340 if (source.HasSwitch(switches[i])) 371 if (source.HasSwitch(switches[i]))
341 AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i])); 372 AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
342 } 373 }
343 } 374 }
344 375
345 CommandLine::StringVector CommandLine::GetArgs() const { 376 CommandLine::StringVector CommandLine::GetArgs() const {
346 // Gather all arguments after the last switch (may include kSwitchTerminator). 377 // Gather all arguments after the last switch (may include kSwitchTerminator).
347 StringVector args(argv_.begin() + begin_args_, argv_.end()); 378 StringVector args(argv_.begin() + begin_args_, argv_.end());
348 // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?) 379 // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
(...skipping 11 matching lines...) Expand all
360 #elif defined(OS_POSIX) 391 #elif defined(OS_POSIX)
361 AppendArgNative(value); 392 AppendArgNative(value);
362 #endif 393 #endif
363 } 394 }
364 395
365 void CommandLine::AppendArgPath(const FilePath& path) { 396 void CommandLine::AppendArgPath(const FilePath& path) {
366 AppendArgNative(path.value()); 397 AppendArgNative(path.value());
367 } 398 }
368 399
369 void CommandLine::AppendArgNative(const CommandLine::StringType& value) { 400 void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
401 DCHECK(writeable_);
370 argv_.push_back(value); 402 argv_.push_back(value);
371 } 403 }
372 404
373 void CommandLine::AppendArguments(const CommandLine& other, 405 void CommandLine::AppendArguments(const CommandLine& other,
374 bool include_program) { 406 bool include_program) {
407 DCHECK(writeable_);
375 if (include_program) 408 if (include_program)
376 SetProgram(other.GetProgram()); 409 SetProgram(other.GetProgram());
377 AppendSwitchesAndArguments(this, other.argv()); 410 AppendSwitchesAndArguments(this, other.argv());
378 } 411 }
379 412
380 void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { 413 void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
414 DCHECK(writeable_);
381 if (wrapper.empty()) 415 if (wrapper.empty())
382 return; 416 return;
383 // The wrapper may have embedded arguments (like "gdb --args"). In this case, 417 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
384 // we don't pretend to do anything fancy, we just split on spaces. 418 // we don't pretend to do anything fancy, we just split on spaces.
385 StringVector wrapper_argv; 419 StringVector wrapper_argv;
386 SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv); 420 SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
387 // Prepend the wrapper and update the switches/arguments |begin_args_|. 421 // Prepend the wrapper and update the switches/arguments |begin_args_|.
388 argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end()); 422 argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
389 begin_args_ += wrapper_argv.size(); 423 begin_args_ += wrapper_argv.size();
390 } 424 }
391 425
392 #if defined(OS_WIN) 426 #if defined(OS_WIN)
393 void CommandLine::ParseFromString(const string16& command_line) { 427 void CommandLine::ParseFromString(const string16& command_line) {
428 DCHECK(writeable_);
394 string16 command_line_string; 429 string16 command_line_string;
395 TrimWhitespace(command_line, TRIM_ALL, &command_line_string); 430 TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
396 if (command_line_string.empty()) 431 if (command_line_string.empty())
397 return; 432 return;
398 433
399 int num_args = 0; 434 int num_args = 0;
400 wchar_t** args = NULL; 435 wchar_t** args = NULL;
401 args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args); 436 args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
402 437
403 DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " 438 DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
404 << UTF16ToUTF8(command_line); 439 << UTF16ToUTF8(command_line);
405 InitFromArgv(num_args, args); 440 InitFromArgv(num_args, args);
406 LocalFree(args); 441 LocalFree(args);
407 } 442 }
408 #endif 443 #endif
409 444
445 void CommandLine::MakeReadOnly() {
446 for (const auto& i : switches_)
447 switch_vector_.push_back(i.first);
448 std::sort(switch_vector_.begin(), switch_vector_.end());
449 }
450
410 CommandLine::StringType CommandLine::GetCommandLineStringInternal( 451 CommandLine::StringType CommandLine::GetCommandLineStringInternal(
411 bool quote_placeholders) const { 452 bool quote_placeholders) const {
412 StringType string(argv_[0]); 453 StringType string(argv_[0]);
413 #if defined(OS_WIN) 454 #if defined(OS_WIN)
414 string = QuoteForCommandLineToArgvW(string, quote_placeholders); 455 string = QuoteForCommandLineToArgvW(string, quote_placeholders);
415 #endif 456 #endif
416 StringType params(GetArgumentsStringInternal(quote_placeholders)); 457 StringType params(GetArgumentsStringInternal(quote_placeholders));
417 if (!params.empty()) { 458 if (!params.empty()) {
418 string.append(StringType(FILE_PATH_LITERAL(" "))); 459 string.append(StringType(FILE_PATH_LITERAL(" ")));
419 string.append(params); 460 string.append(params);
(...skipping 25 matching lines...) Expand all
445 } else { 486 } else {
446 #if defined(OS_WIN) 487 #if defined(OS_WIN)
447 arg = QuoteForCommandLineToArgvW(arg, quote_placeholders); 488 arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
448 #endif 489 #endif
449 params.append(arg); 490 params.append(arg);
450 } 491 }
451 } 492 }
452 return params; 493 return params;
453 } 494 }
454 495
496 bool CommandLine::HasSwitchVector(const char string_constant[]) const {
497 DCHECK(!writeable_);
498 auto lb = std::lower_bound(switch_vector_.begin(), switch_vector_.end(),
499 string_constant, CompareStringAndCharPtr);
500 return lb != switch_vector_.end() && !strcmp(lb->c_str(), string_constant);
501 }
502
503 bool CommandLine::HasSwitchLowerCase(const char string_constant[]) const {
504 return switches_.find(std::string(string_constant)) != switches_.end();
505 }
506
455 } // namespace base 507 } // namespace base
OLDNEW
« no previous file with comments | « base/command_line.h ('k') | base/command_line_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698