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

Side by Side Diff: base/command_line.cc

Issue 6526040: CommandLine refactoring and cleanup. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Test Created 9 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 8
9 #include "base/file_path.h" 9 #include "base/file_path.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/singleton.h" 12 #include "base/singleton.h"
13 #include "base/string_split.h" 13 #include "base/string_split.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "base/sys_string_conversions.h" 15 #include "base/sys_string_conversions.h"
16 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
17 #include "build/build_config.h" 17 #include "build/build_config.h"
18 18
19 #if defined(OS_WIN) 19 #if defined(OS_WIN)
20 #include <windows.h> 20 #include <windows.h>
21 #include <shellapi.h> 21 #include <shellapi.h>
22 #elif defined(OS_POSIX) 22 #elif defined(OS_POSIX)
23 #include <limits.h> 23 #include <limits.h>
24 #include <stdlib.h> 24 #include <stdlib.h>
25 #include <unistd.h> 25 #include <unistd.h>
26 #endif 26 #endif
27 27
28 CommandLine* CommandLine::current_process_commandline_ = NULL; 28 CommandLine* CommandLine::current_process_commandline_ = NULL;
29 29
30 // Since we use a lazy match, make sure that longer versions (like L"--") 30 namespace {
31 // are listed before shorter versions (like L"-") of similar prefixes. 31 const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
32 const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
33 // Since we use a lazy match, make sure that longer versions (like "--")
34 // are listed before shorter versions (like "-") of similar prefixes.
32 #if defined(OS_WIN) 35 #if defined(OS_WIN)
33 const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; 36 const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
34 const wchar_t kSwitchTerminator[] = L"--";
35 const wchar_t kSwitchValueSeparator[] = L"=";
36 #elif defined(OS_POSIX) 37 #elif defined(OS_POSIX)
37 // Unixes don't use slash as a switch. 38 // Unixes don't use slash as a switch.
38 const char* const kSwitchPrefixes[] = {"--", "-"}; 39 const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"};
39 const char kSwitchTerminator[] = "--";
40 const char kSwitchValueSeparator[] = "=";
41 #endif 40 #endif
42 41
43 #if defined(OS_WIN) 42 void Lowercase(string* arg);
44 // Lowercase a string. This is used to lowercase switch names.
45 // Is this what we really want? It seems crazy to me. I've left it in
46 // for backwards compatibility on Windows.
47 static void Lowercase(std::string* parameter) {
48 transform(parameter->begin(), parameter->end(), parameter->begin(),
49 tolower);
50 }
51 #endif
52 43
53 CommandLine::~CommandLine() { 44 // Returns true and fills in |switch_string| and |switch_value| if
54 } 45 // |parameter_string| represents a switch.
55 46 bool IsSwitch(const CommandLine::StringType& parameter_string,
56 #if defined(OS_WIN) 47 string* switch_string,
57 CommandLine::CommandLine(NoProgram no_program) { 48 CommandLine::StringType* switch_value) {
58 }
59
60 void CommandLine::ParseFromString(const std::wstring& command_line) {
61 TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
62
63 if (command_line_string_.empty())
64 return;
65
66 int num_args = 0;
67 wchar_t** args = NULL;
68
69 args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
70
71 // Populate program_ with the trimmed version of the first arg.
72 TrimWhitespace(args[0], TRIM_ALL, &program_);
73
74 bool parse_switches = true;
75 for (int i = 1; i < num_args; ++i) {
76 std::wstring arg;
77 TrimWhitespace(args[i], TRIM_ALL, &arg);
78
79 if (!parse_switches) {
80 args_.push_back(arg);
81 continue;
82 }
83
evanm 2011/02/24 01:01:05 It's hard to follow what's gone on in this file.
msw 2011/05/10 23:18:43 Done (move was r76339, this change is cleaner).
84 if (arg == kSwitchTerminator) {
85 parse_switches = false;
86 continue;
87 }
88
89 std::string switch_string;
90 std::wstring switch_value;
91 if (IsSwitch(arg, &switch_string, &switch_value)) {
92 switches_[switch_string] = switch_value;
93 } else {
94 args_.push_back(arg);
95 }
96 }
97
98 if (args)
99 LocalFree(args);
100 }
101
102 // static
103 CommandLine CommandLine::FromString(const std::wstring& command_line) {
104 CommandLine cmd;
105 cmd.ParseFromString(command_line);
106 return cmd;
107 }
108
109 CommandLine::CommandLine(const FilePath& program) {
110 if (!program.empty()) {
111 program_ = program.value();
112 // TODO(evanm): proper quoting here.
113 command_line_string_ = L'"' + program.value() + L'"';
114 }
115 }
116
117 #elif defined(OS_POSIX)
118 CommandLine::CommandLine(NoProgram no_program) {
119 // Push an empty argument, because we always assume argv_[0] is a program.
120 argv_.push_back("");
121 }
122
123 CommandLine::CommandLine(int argc, const char* const* argv) {
124 InitFromArgv(argc, argv);
125 }
126
127 CommandLine::CommandLine(const std::vector<std::string>& argv) {
128 InitFromArgv(argv);
129 }
130
131 void CommandLine::InitFromArgv(int argc, const char* const* argv) {
132 for (int i = 0; i < argc; ++i)
133 argv_.push_back(argv[i]);
134 InitFromArgv(argv_);
135 }
136
137 void CommandLine::InitFromArgv(const std::vector<std::string>& argv) {
138 argv_ = argv;
139 bool parse_switches = true;
140 for (size_t i = 1; i < argv_.size(); ++i) {
141 const std::string& arg = argv_[i];
142
143 if (!parse_switches) {
144 args_.push_back(arg);
145 continue;
146 }
147
148 if (arg == kSwitchTerminator) {
149 parse_switches = false;
150 continue;
151 }
152
153 std::string switch_string;
154 std::string switch_value;
155 if (IsSwitch(arg, &switch_string, &switch_value)) {
156 switches_[switch_string] = switch_value;
157 } else {
158 args_.push_back(arg);
159 }
160 }
161 }
162
163 CommandLine::CommandLine(const FilePath& program) {
164 argv_.push_back(program.value());
165 }
166
167 #endif
168
169 // static
170 bool CommandLine::IsSwitch(const StringType& parameter_string,
171 std::string* switch_string,
172 StringType* switch_value) {
173 switch_string->clear(); 49 switch_string->clear();
174 switch_value->clear(); 50 switch_value->clear();
175 51
176 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { 52 for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
177 StringType prefix(kSwitchPrefixes[i]); 53 CommandLine::StringType prefix(kSwitchPrefixes[i]);
178 if (parameter_string.find(prefix) != 0) 54 if (parameter_string.find(prefix) != 0)
179 continue; 55 continue;
180 56
181 const size_t switch_start = prefix.length(); 57 const size_t switch_start = prefix.length();
182 const size_t equals_position = parameter_string.find( 58 const size_t equals_position = parameter_string.find(
183 kSwitchValueSeparator, switch_start); 59 kSwitchValueSeparator, switch_start);
184 StringType switch_native; 60 CommandLine::StringType switch_native;
185 if (equals_position == StringType::npos) { 61 if (equals_position == CommandLine::StringType::npos) {
186 switch_native = parameter_string.substr(switch_start); 62 switch_native = parameter_string.substr(switch_start);
187 } else { 63 } else {
188 switch_native = parameter_string.substr( 64 switch_native = parameter_string.substr(
189 switch_start, equals_position - switch_start); 65 switch_start, equals_position - switch_start);
190 *switch_value = parameter_string.substr(equals_position + 1); 66 *switch_value = parameter_string.substr(equals_position + 1);
191 } 67 }
192 #if defined(OS_WIN) 68 #if defined(OS_WIN)
193 *switch_string = WideToASCII(switch_native); 69 *switch_string = WideToASCII(switch_native);
194 Lowercase(switch_string);
195 #else 70 #else
196 *switch_string = switch_native; 71 *switch_string = switch_native;
197 #endif 72 #endif
73 Lowercase(switch_string);
198 74
199 return true; 75 return true;
200 } 76 }
201 77
202 return false; 78 return false;
203 } 79 }
204 80
81 #if defined(OS_WIN)
82 // Lowercase a string for case-insensitivity of switches *on Windows*.
83 // Is this desirable? It exists for backwards compatibility on Windows.
84 void Lowercase(string* arg) {
85 transform(arg->begin(), arg->end(), arg->begin(), tolower);
86 }
87
88 CommandLine::StringType Native(const string& string) {
89 return ASCIIToWide(string);
90 }
91
92 CommandLine::StringType Native(const std::wstring& string) { return string; }
93
94 // Quote a string if necessary *on Windows*, such that CommandLineToArgvW() will
95 // always process it as a single argument.
96 CommandLine::StringType Quote(const CommandLine::StringType& arg) {
97 // We follow the quoting rules of CommandLineToArgvW.
98 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
99 if (arg.find_first_of(L" \\\"") == CommandLine::StringType::npos) {
100 // No quoting necessary.
101 return arg;
102 }
103
104 std::wstring out;
105 out.push_back(L'"');
106 for (size_t i = 0; i < arg.size(); ++i) {
107 if (arg[i] == '\\') {
108 // Find the extent of this run of backslashes.
109 size_t start = i, end = start + 1;
110 for (; end < arg.size() && arg[end] == '\\'; ++end)
111 /* empty */;
112 size_t backslash_count = end - start;
113
114 // Backslashes are escapes only if the run is followed by a double quote.
115 // Since we also will end the string with a double quote, we escape for
116 // either a double quote or the end of the string.
117 if (end == arg.size() || arg[end] == '"') {
118 // To quote, we need to output 2x as many backslashes.
119 backslash_count *= 2;
120 }
121 for (size_t j = 0; j < backslash_count; ++j)
122 out.push_back('\\');
123
124 // Advance i to one before the end to balance i++ in loop.
125 i = end - 1;
126 } else if (arg[i] == '"') {
127 out.push_back('\\');
128 out.push_back('"');
129 } else {
130 out.push_back(arg[i]);
131 }
132 }
133 out.push_back('"');
134
135 return out;
136 }
137 #elif defined(OS_POSIX)
138 void Lowercase(string* arg) {}
139
140 CommandLine::StringType Native(const string& string) { return string; }
141
142 CommandLine::StringType Native(const std::wstring& string) {
143 return WideToASCII(string);
144 }
145
146 CommandLine::StringType Quote(const CommandLine::StringType& string) {
147 return string;
148 }
149 #endif
150 } // namespace
151
152 CommandLine::CommandLine(NoProgram no_program) {
153 SetProgram(StringType());
154 }
155
156 CommandLine::CommandLine(const FilePath& program) {
157 SetProgram(program.value());
158 }
159
160 CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) {
161 InitFromArgv(argc, argv);
162 }
163
164 CommandLine::CommandLine(const StringVector& argv) {
165 InitFromArgv(argv);
166 }
167
205 // static 168 // static
206 void CommandLine::Init(int argc, const char* const* argv) { 169 void CommandLine::Init(int argc, const char* const* argv) {
207 delete current_process_commandline_; 170 delete current_process_commandline_;
208 current_process_commandline_ = new CommandLine; 171 current_process_commandline_ = new CommandLine;
209 #if defined(OS_WIN) 172 #if defined(OS_WIN)
210 current_process_commandline_->ParseFromString(::GetCommandLineW()); 173 current_process_commandline_->ParseFromString(::GetCommandLineW());
211 #elif defined(OS_POSIX) 174 #elif defined(OS_POSIX)
212 current_process_commandline_->InitFromArgv(argc, argv); 175 current_process_commandline_->InitFromArgv(argc, argv);
213 #endif 176 #endif
214 } 177 }
215 178
179 // static
216 void CommandLine::Reset() { 180 void CommandLine::Reset() {
217 DCHECK(current_process_commandline_ != NULL); 181 DCHECK(current_process_commandline_);
218 delete current_process_commandline_; 182 delete current_process_commandline_;
219 current_process_commandline_ = NULL; 183 current_process_commandline_ = NULL;
220 } 184 }
221 185
222 // static 186 // static
223 CommandLine* CommandLine::ForCurrentProcess() { 187 CommandLine* CommandLine::ForCurrentProcess() {
224 DCHECK(current_process_commandline_); 188 DCHECK(current_process_commandline_);
225 return current_process_commandline_; 189 return current_process_commandline_;
226 } 190 }
227 191
228 bool CommandLine::HasSwitch(const std::string& switch_string) const { 192 #if defined(OS_WIN)
193 // static
194 CommandLine CommandLine::FromString(
195 const CommandLine::StringType& command_line) {
196 CommandLine cmd;
197 cmd.ParseFromString(command_line);
198 return cmd;
199 }
200 #endif
201
202 void CommandLine::InitFromArgv(int argc,
203 const CommandLine::CharType* const* argv) {
204 StringVector new_argv;
205 for (int i = 0; i < argc; ++i)
206 new_argv.push_back(Native(argv[i]));
207 InitFromArgv(new_argv);
208 }
209
210 void CommandLine::InitFromArgv(const StringVector argv) {
211 argv_.clear();
212 divider_ = 0;
213 if (argv.size() <= 0)
214 return;
215
216 // Initialize the first program argument.
217 SetProgram(argv[0]);
218
219 // Copy switches/arguments to our vector, keeping switches before arguments.
220 bool seen_kSwitchTerminator = false;
221 for (size_t i = 1; i < argv.size(); ++i) {
222 StringType arg = argv[i];
223 TrimWhitespace(arg, TRIM_ALL, &arg);
224
225 string switch_string;
226 StringType switch_value;
227 seen_kSwitchTerminator |= arg == kSwitchTerminator;
228 if (!seen_kSwitchTerminator && IsSwitch(arg, &switch_string, &switch_value))
229 AppendSwitchNative(switch_string, switch_value);
230 else
231 AppendArgNative(arg);
232 }
233 }
234
235 bool CommandLine::HasSwitch(const string& switch_string) const {
229 std::string lowercased_switch(switch_string); 236 std::string lowercased_switch(switch_string);
230 #if defined(OS_WIN)
231 Lowercase(&lowercased_switch); 237 Lowercase(&lowercased_switch);
232 #endif
233 return switches_.find(lowercased_switch) != switches_.end(); 238 return switches_.find(lowercased_switch) != switches_.end();
234 } 239 }
235 240
236 std::string CommandLine::GetSwitchValueASCII( 241 string CommandLine::GetSwitchValueASCII(const string& switch_string) const {
237 const std::string& switch_string) const { 242 StringType value = GetSwitchValueNative(switch_string);
238 CommandLine::StringType value = GetSwitchValueNative(switch_string);
239 if (!IsStringASCII(value)) { 243 if (!IsStringASCII(value)) {
240 LOG(WARNING) << "Value of --" << switch_string << " must be ASCII."; 244 LOG(WARNING) << "Value of --" << switch_string << " must be ASCII.";
241 return ""; 245 return "";
242 } 246 }
243 #if defined(OS_WIN) 247 #if defined(OS_WIN)
244 return WideToASCII(value); 248 return WideToASCII(value);
245 #else 249 #else
246 return value; 250 return value;
247 #endif 251 #endif
248 } 252 }
249 253
250 FilePath CommandLine::GetSwitchValuePath( 254 FilePath CommandLine::GetSwitchValuePath(const string& switch_string) const {
251 const std::string& switch_string) const {
252 return FilePath(GetSwitchValueNative(switch_string)); 255 return FilePath(GetSwitchValueNative(switch_string));
253 } 256 }
254 257
255 CommandLine::StringType CommandLine::GetSwitchValueNative( 258 CommandLine::StringType CommandLine::GetSwitchValueNative(
256 const std::string& switch_string) const { 259 const string& switch_string) const {
257 std::string lowercased_switch(switch_string); 260 std::string lowercased_switch(switch_string);
258 #if defined(OS_WIN)
259 Lowercase(&lowercased_switch); 261 Lowercase(&lowercased_switch);
260 #endif 262 SwitchMap::const_iterator result = switches_.find(lowercased_switch);
263 return result == switches_.end() ? StringType() : result->second;
264 }
261 265
262 std::map<std::string, StringType>::const_iterator result = 266 size_t CommandLine::GetSwitchCount() const {
263 switches_.find(lowercased_switch); 267 return switches_.size();
268 }
264 269
265 if (result == switches_.end()) { 270 CommandLine::StringVector CommandLine::args() const {
266 return CommandLine::StringType(); 271 // Gather all arguments after the last switch (may include kSwitchTerminator).
267 } else { 272 StringVector args(argv_.begin() + divider_, argv_.end());
268 return result->second; 273
269 } 274 // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
275 StringVector::iterator it = args.begin();
276 for (; it < args.end() && *it != kSwitchTerminator; ++it)
277 /* empty */;
278 if (it != args.end())
279 args.erase(it);
280
281 return args;
282 }
283
284 CommandLine::StringType CommandLine::command_line_string() const {
285 return JoinString(argv_, FILE_PATH_LITERAL(' '));
270 } 286 }
271 287
272 FilePath CommandLine::GetProgram() const { 288 FilePath CommandLine::GetProgram() const {
273 #if defined(OS_WIN) 289 #if defined(OS_WIN)
274 return FilePath(program_); 290 // Ensure that quotes are not returned from GetProgram().
275 #else 291 // TODO(evanm): proper quoting/handling here.
276 DCHECK_GT(argv_.size(), 0U); 292 return FilePath(argv_.size() > 0 ? argv_[0].substr(1, argv_[0].size() - 2) :
277 return FilePath(argv_[0]); 293 StringType());
294 #endif
295 return FilePath(argv_.size() > 0 ? argv_[0] : StringType());
296 }
297
298 void CommandLine::SetProgram(const CommandLine::StringType& program) {
299 CommandLine::StringType program_string(program);
300 TrimWhitespace(program_string, TRIM_ALL, &program_string);
301
302 #if defined(OS_WIN)
303 // TODO(evanm): proper quoting here.
304 if (!program_string.empty())
305 program_string = L'"' + program + L'"';
306 #endif
307
308 if (argv_.size() > 0){
309 argv_[0] = program_string;
310 } else {
311 argv_.push_back(program_string);
312 divider_ = 1;
313 }
314 }
315
316 void CommandLine::AppendSwitch(const string& switch_string) {
317 AppendSwitchNative(switch_string, CommandLine::StringType());
318 }
319
320 void CommandLine::AppendSwitchPath(const string& switch_string,
321 const FilePath& path) {
322 AppendSwitchNative(switch_string, path.value());
323 }
324
325 void CommandLine::AppendSwitchNative(const string& switch_string,
326 const CommandLine::StringType& value) {
327 CommandLine::StringType combined = kSwitchPrefixes[0] + Native(switch_string);
328 if (!value.empty())
329 combined += kSwitchValueSeparator + Quote(value);
330 // Append the switch and update the switches/arguments |divider_|.
331 argv_.insert(argv_.begin() + divider_++, combined);
332 switches_[switch_string] = value;
333 }
334
335 void CommandLine::AppendSwitchASCII(const string& switch_string,
336 const string& value_string) {
337 AppendSwitchNative(switch_string, Native(value_string));
338 }
339
340 void CommandLine::AppendSwitches(const CommandLine& other) {
341 SwitchMap::const_iterator i;
342 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
343 AppendSwitchNative(i->first, i->second);
344 }
345
346 void CommandLine::AppendArg(const string& value) {
347 #if defined(OS_WIN)
348 DCHECK(IsStringUTF8(value));
349 AppendArgNative(UTF8ToWide(value));
350 #elif defined(OS_POSIX)
351 AppendArgNative(value);
278 #endif 352 #endif
279 } 353 }
280 354
281 #if defined(OS_POSIX) 355 void CommandLine::AppendArgPath(const FilePath& path) {
282 std::string CommandLine::command_line_string() const { 356 AppendArgNative(path.value());
283 return JoinString(argv_, ' ');
284 }
285 #endif
286
287 #if defined(OS_WIN)
288 void CommandLine::AppendSwitch(const std::string& switch_string) {
289 command_line_string_.append(L" ");
290 command_line_string_.append(kSwitchPrefixes[0] + ASCIIToWide(switch_string));
291 switches_[switch_string] = L"";
292 } 357 }
293 358
294 void CommandLine::AppendSwitchASCII(const std::string& switch_string, 359 void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
295 const std::string& value_string) { 360 #if defined(OS_POSIX)
296 AppendSwitchNative(switch_string, ASCIIToWide(value_string));
297 }
298
299 // Quote a string if necessary, such that CommandLineToArgvW() will
300 // always process it as a single argument.
301 static std::wstring WindowsStyleQuote(const std::wstring& arg) {
302 // We follow the quoting rules of CommandLineToArgvW.
303 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
304 if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
305 // No quoting necessary.
306 return arg;
307 }
308
309 std::wstring out;
310 out.push_back(L'"');
311 for (size_t i = 0; i < arg.size(); ++i) {
312 if (arg[i] == '\\') {
313 // Find the extent of this run of backslashes.
314 size_t start = i, end = start + 1;
315 for (; end < arg.size() && arg[end] == '\\'; ++end)
316 /* empty */;
317 size_t backslash_count = end - start;
318
319 // Backslashes are escapes only if the run is followed by a double quote.
320 // Since we also will end the string with a double quote, we escape for
321 // either a double quote or the end of the string.
322 if (end == arg.size() || arg[end] == '"') {
323 // To quote, we need to output 2x as many backslashes.
324 backslash_count *= 2;
325 }
326 for (size_t j = 0; j < backslash_count; ++j)
327 out.push_back('\\');
328
329 // Advance i to one before the end to balance i++ in loop.
330 i = end - 1;
331 } else if (arg[i] == '"') {
332 out.push_back('\\');
333 out.push_back('"');
334 } else {
335 out.push_back(arg[i]);
336 }
337 }
338 out.push_back('"');
339
340 return out;
341 }
342
343 void CommandLine::AppendSwitchNative(const std::string& switch_string,
344 const std::wstring& value) {
345 std::wstring combined_switch_string =
346 kSwitchPrefixes[0] + ASCIIToWide(switch_string);
347 if (!value.empty())
348 combined_switch_string += kSwitchValueSeparator + WindowsStyleQuote(value);
349
350 command_line_string_.append(L" ");
351 command_line_string_.append(combined_switch_string);
352
353 switches_[switch_string] = value;
354 }
355
356 void CommandLine::AppendArg(const std::string& value) {
357 DCHECK(IsStringUTF8(value)); 361 DCHECK(IsStringUTF8(value));
358 AppendArgNative(UTF8ToWide(value)); 362 #endif
359 } 363 argv_.push_back(Quote(value));
360
361 void CommandLine::AppendArgNative(const std::wstring& value) {
362 command_line_string_.append(L" ");
363 command_line_string_.append(WindowsStyleQuote(value));
364 args_.push_back(value);
365 } 364 }
366 365
367 void CommandLine::AppendArguments(const CommandLine& other, 366 void CommandLine::AppendArguments(const CommandLine& other,
368 bool include_program) { 367 bool include_program) {
369 // Verify include_program is used correctly. 368 // Verify include_program is used correctly.
370 // Logic could be shorter but this is clearer. 369 DCHECK(!include_program || other.argv_.size() > 0);
371 DCHECK_EQ(include_program, !other.GetProgram().empty());
372 if (include_program) 370 if (include_program)
373 program_ = other.program_; 371 SetProgram(other.GetProgram().value());
374 372
375 if (!command_line_string_.empty()) 373 // Copy switches/arguments to our vector, keeping switches before arguments.
376 command_line_string_ += L' '; 374 bool seen_kSwitchTerminator = false;
375 for (size_t i = 1; i < other.argv_.size(); ++i) {
376 StringType arg = other.argv_[i];
377 TrimWhitespace(arg, TRIM_ALL, &arg);
377 378
378 command_line_string_ += other.command_line_string_; 379 string switch_string;
379 380 StringType switch_value;
380 std::map<std::string, StringType>::const_iterator i; 381 seen_kSwitchTerminator |= arg == kSwitchTerminator;
381 for (i = other.switches_.begin(); i != other.switches_.end(); ++i) 382 if (!seen_kSwitchTerminator && IsSwitch(arg, &switch_string, &switch_value))
382 switches_[i->first] = i->second; 383 AppendSwitchNative(switch_string, switch_value);
384 else
385 AppendArgNative(arg);
386 }
383 } 387 }
384 388
385 void CommandLine::PrependWrapper(const std::wstring& wrapper) { 389 void CommandLine::PrependWrapper(const StringType& wrapper) {
386 if (wrapper.empty()) 390 if (wrapper.empty())
387 return; 391 return;
388 // The wrapper may have embedded arguments (like "gdb --args"). In this case, 392 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
389 // we don't pretend to do anything fancy, we just split on spaces. 393 // we don't pretend to do anything fancy, we just split on spaces.
390 std::vector<std::wstring> wrapper_and_args; 394 StringVector prefix;
391 base::SplitString(wrapper, ' ', &wrapper_and_args); 395 base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &prefix);
392 program_ = wrapper_and_args[0]; 396 // Prepend the wrapper and update the switches/arguments |divider_|.
393 command_line_string_ = wrapper + L" " + command_line_string_; 397 argv_.insert(argv_.begin(), prefix.begin(), prefix.end());
394 } 398 divider_ += prefix.size();
395
396 #elif defined(OS_POSIX)
397 void CommandLine::AppendSwitch(const std::string& switch_string) {
398 argv_.push_back(kSwitchPrefixes[0] + switch_string);
399 switches_[switch_string] = "";
400 }
401
402 void CommandLine::AppendSwitchNative(const std::string& switch_string,
403 const std::string& value) {
404 std::string combined_switch_string = kSwitchPrefixes[0] + switch_string;
405 if (!value.empty())
406 combined_switch_string += kSwitchValueSeparator + value;
407 argv_.push_back(combined_switch_string);
408 switches_[switch_string] = value;
409 }
410
411 void CommandLine::AppendSwitchASCII(const std::string& switch_string,
412 const std::string& value_string) {
413 AppendSwitchNative(switch_string, value_string);
414 }
415
416 void CommandLine::AppendArg(const std::string& value) {
417 AppendArgNative(value);
418 }
419
420 void CommandLine::AppendArgNative(const std::string& value) {
421 DCHECK(IsStringUTF8(value));
422 argv_.push_back(value);
423 }
424
425 void CommandLine::AppendArguments(const CommandLine& other,
426 bool include_program) {
427 // Verify include_program is used correctly.
428 // Logic could be shorter but this is clearer.
429 DCHECK_EQ(include_program, !other.GetProgram().empty());
430
431 if (include_program)
432 argv_[0] = other.argv_[0];
433
434 // Skip the first arg when copying since it's the program but push all
435 // arguments to our arg vector.
436 for (size_t i = 1; i < other.argv_.size(); ++i)
437 argv_.push_back(other.argv_[i]);
438
439 std::map<std::string, StringType>::const_iterator i;
440 for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
441 switches_[i->first] = i->second;
442 }
443
444 void CommandLine::PrependWrapper(const std::string& wrapper) {
445 // The wrapper may have embedded arguments (like "gdb --args"). In this case,
446 // we don't pretend to do anything fancy, we just split on spaces.
447 std::vector<std::string> wrapper_and_args;
448 base::SplitString(wrapper, ' ', &wrapper_and_args);
449 argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
450 }
451
452 #endif
453
454 void CommandLine::AppendArgPath(const FilePath& path) {
455 AppendArgNative(path.value());
456 }
457
458 void CommandLine::AppendSwitchPath(const std::string& switch_string,
459 const FilePath& path) {
460 AppendSwitchNative(switch_string, path.value());
461 } 399 }
462 400
463 void CommandLine::CopySwitchesFrom(const CommandLine& source, 401 void CommandLine::CopySwitchesFrom(const CommandLine& source,
464 const char* const switches[], 402 const char* const switches[],
465 size_t count) { 403 size_t count) {
466 for (size_t i = 0; i < count; ++i) { 404 for (size_t i = 0; i < count; ++i) {
467 if (source.HasSwitch(switches[i])) { 405 if (source.HasSwitch(switches[i])) {
468 StringType value = source.GetSwitchValueNative(switches[i]); 406 StringType value = source.GetSwitchValueNative(switches[i]);
469 AppendSwitchNative(switches[i], value); 407 AppendSwitchNative(switches[i], value);
470 } 408 }
471 } 409 }
472 } 410 }
473 411
474 // private 412 #if defined(OS_WIN)
475 CommandLine::CommandLine() { 413 void CommandLine::ParseFromString(const CommandLine::StringType& command_line) {
414 StringType command_line_string;
415 TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
416 if (command_line_string.empty())
417 return;
418
419 int argc = 0;
420 wchar_t** argv = NULL;
421 argv = ::CommandLineToArgvW(command_line_string.c_str(), &argc);
422
423 CHECK(argv);
424 InitFromArgv(argc, argv);
425 LocalFree(argv);
476 } 426 }
477 427 #endif
478 // static
479 CommandLine* CommandLine::ForCurrentProcessMutable() {
480 DCHECK(current_process_commandline_);
481 return current_process_commandline_;
482 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698