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

Side by Side Diff: base/command_line_parser.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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_parser.h ('k') | base/command_line_parser_internal.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2008-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/base/command_line_parser.h"
17 #include "omaha/base/command_line_parser_internal.h"
18 #include <shellapi.h>
19 #include "omaha/base/debug.h"
20 #include "omaha/base/error.h"
21 #include "omaha/base/logging.h"
22 #include "omaha/base/path.h"
23
24 namespace omaha {
25
26 namespace internal {
27
28 void CommandLineParserArgs::Reset() {
29 switch_arguments_.clear();
30 }
31
32 // Assumes switch_name is already lower case.
33 HRESULT CommandLineParserArgs::AddSwitch(const CString& switch_name) {
34 ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);
35 if (switch_arguments_.find(switch_name) != switch_arguments_.end()) {
36 return E_INVALIDARG;
37 }
38
39 StringVector string_vector;
40 switch_arguments_[switch_name] = string_vector;
41 return S_OK;
42 }
43
44 // Assumes switch_name is already lower case.
45 HRESULT CommandLineParserArgs::AddSwitchArgument(const CString& switch_name,
46 const CString& value) {
47 ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);
48 ASSERT1(!switch_name.IsEmpty());
49 if (switch_name.IsEmpty()) {
50 // We don't have a switch yet, so this is just a base argument.
51 // Example command line: "foo.exe myarg /someswitch"
52 // Here, myarg would be a base argument.
53 // TODO(omaha): base_args_.push_back(switch_name_str);
54 return E_INVALIDARG;
55 }
56
57 SwitchAndArgumentsMap::iterator iter = switch_arguments_.find(switch_name);
58 if (iter == switch_arguments_.end()) {
59 return E_UNEXPECTED;
60 }
61 (*iter).second.push_back(value);
62
63 return S_OK;
64 }
65
66 int CommandLineParserArgs::GetSwitchCount() const {
67 return switch_arguments_.size();
68 }
69
70 bool CommandLineParserArgs::HasSwitch(const CString& switch_name) const {
71 CString switch_name_lower = switch_name;
72 switch_name_lower.MakeLower();
73 return switch_arguments_.find(switch_name_lower) != switch_arguments_.end();
74 }
75
76 // The value at a particular index may change if switch_names are added
77 // since we're using a map underneath. But this keeps us from having to write
78 // an interator and expose it externally.
79 HRESULT CommandLineParserArgs::GetSwitchNameAtIndex(int index,
80 CString* name) const {
81 ASSERT1(name);
82
83 if (index >= static_cast<int>(switch_arguments_.size())) {
84 return E_INVALIDARG;
85 }
86
87 SwitchAndArgumentsMapIter iter = switch_arguments_.begin();
88 for (int i = 0; i < index; ++i) {
89 ++iter;
90 }
91
92 *name = (*iter).first;
93
94 return S_OK;
95 }
96
97 HRESULT CommandLineParserArgs::GetSwitchArgumentCount(
98 const CString& switch_name,
99 int* count) const {
100 ASSERT1(count);
101
102 CString switch_name_lower = switch_name;
103 switch_name_lower.MakeLower();
104
105 SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);
106 if (iter == switch_arguments_.end()) {
107 return E_INVALIDARG;
108 }
109
110 *count = (*iter).second.size();
111 return S_OK;
112 }
113
114 HRESULT CommandLineParserArgs::GetSwitchArgumentValue(
115 const CString& switch_name,
116 int argument_index,
117 CString* argument_value) const {
118 ASSERT1(argument_value);
119
120 CString switch_name_lower = switch_name;
121 switch_name_lower.MakeLower();
122
123 int count = 0;
124 HRESULT hr = GetSwitchArgumentCount(switch_name_lower, &count);
125 if (FAILED(hr)) {
126 return hr;
127 }
128
129 if (argument_index >= count) {
130 return E_INVALIDARG;
131 }
132
133 SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);
134 if (iter == switch_arguments_.end()) {
135 return E_INVALIDARG;
136 }
137
138 *argument_value = (*iter).second[argument_index];
139 return S_OK;
140 }
141
142 } // namespace internal
143
144 CommandLineParser::CommandLineParser() {
145 required_args_.reset(new internal::CommandLineParserArgs);
146 optional_args_.reset(new internal::CommandLineParserArgs);
147 }
148
149 CommandLineParser::~CommandLineParser() {
150 }
151
152 HRESULT CommandLineParser::ParseFromString(const wchar_t* command_line) {
153 CString command_line_str(command_line);
154 command_line_str.Trim(_T(" "));
155
156 if (command_line_str.IsEmpty()) {
157 // If the first arg to CommandLineToArgvW "is an empty string the function
158 // returns the path to the current executable file." However, it does not
159 // correctly handle the case when the path contains spaces - it breaks the
160 // path up into separate argv elements. To avoid issues while maintaining
161 // the expected behavior, manually get the command line in the empty case.
162 // See http://msdn.microsoft.com/en-us/library/bb776391.aspx.
163 VERIFY1(::GetModuleFileName(NULL,
164 CStrBuf(command_line_str, MAX_PATH),
165 MAX_PATH));
166 EnclosePath(&command_line_str);
167 }
168
169 int argc = 0;
170 wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);
171 if (!argv) {
172 return HRESULTFromLastError();
173 }
174
175 HRESULT hr = ParseFromArgv(argc, argv);
176 ::LocalFree(argv);
177 return hr;
178 }
179
180 // TODO(Omaha): Move the rule parser into a separate class.
181 // TODO(Omaha): Fail the regular command parser if [/ switch is passed.
182 // ParseFromArgv parses either a rule or a command line.
183 //
184 // Rules have required and optional parameters. An example of a rule is:
185 // "gu.exe /install <extraargs> [/oem [/appargs <appargs> [/silent"
186 // This creates a rule for a command line that requires "/install" for the rule
187 // to match. The other parameters are optional, indicated by prefixes of "[/".
188 //
189 // Command lines do not use "[/", and use "/" for all parameters.
190 // A command line that looks like this:
191 // "gu.exe /install <extraargs> /oem /appargs <appargs>"
192 // will match the rule above.
193 HRESULT CommandLineParser::ParseFromArgv(int argc, wchar_t** argv) {
194 if (argc == 0 || !argv) {
195 return E_INVALIDARG;
196 }
197
198 Reset();
199
200 if (argc == 1) {
201 // We only have the program name. So, we're done parsing.
202 ASSERT1(!IsSwitch(argv[0]));
203 return S_OK;
204 }
205
206 CString current_switch_name;
207 bool is_optional_switch = false;
208
209 // Start parsing at the first argument after the program name (index 1).
210 for (int i = 1; i < argc; ++i) {
211 HRESULT hr = S_OK;
212 CString token = argv[i];
213 token.Trim(_T(" "));
214 if (IsSwitch(token)) {
215 hr = StripSwitchNameFromArgv(token, &current_switch_name);
216 if (FAILED(hr)) {
217 return hr;
218 }
219 hr = AddSwitch(current_switch_name);
220 if (FAILED(hr)) {
221 CORE_LOG(LE, (_T("[AddSwitch failed][%s][0x%x]"),
222 current_switch_name, hr));
223 return hr;
224 }
225 is_optional_switch = false;
226 } else if (IsOptionalSwitch(token)) {
227 hr = StripOptionalSwitchNameFromArgv(token, &current_switch_name);
228 if (FAILED(hr)) {
229 return hr;
230 }
231 hr = AddOptionalSwitch(current_switch_name);
232 if (FAILED(hr)) {
233 CORE_LOG(LE, (_T("[AddOptionalSwitch failed][%s][0x%x]"),
234 current_switch_name, hr));
235 return hr;
236 }
237 is_optional_switch = true;
238 } else {
239 hr = is_optional_switch ?
240 AddOptionalSwitchArgument(current_switch_name, token) :
241 AddSwitchArgument(current_switch_name, token);
242
243 if (FAILED(hr)) {
244 CORE_LOG(LE, (_T("[Adding switch argument failed][%d][%s][%s][0x%x]"),
245 is_optional_switch, current_switch_name, token, hr));
246 return hr;
247 }
248 }
249 }
250
251 return S_OK;
252 }
253
254 bool CommandLineParser::IsSwitch(const CString& param) const {
255 // Switches must have a prefix (/) or (-), and at least one character.
256 if (param.GetLength() < 2) {
257 return false;
258 }
259
260 // All switches must start with / or -, and not contain any spaces.
261 // Since the argv parser strips out the enclosing quotes around an argument,
262 // we need to handle the following cases properly:
263 // * foo.exe /switch arg -- /switch is a switch, arg is an arg
264 // * foo.exe /switch "/x y" -- /switch is a switch, '/x y' is an arg and it
265 // will get here _without_ the quotes.
266 // If param_str starts with / and contains no spaces, then it's a switch.
267 return ((param[0] == _T('/')) || (param[0] == _T('-'))) &&
268 (param.Find(_T(" ")) == -1) &&
269 (param.Find(_T("%20")) == -1);
270 }
271
272 bool CommandLineParser::IsOptionalSwitch(const CString& param) const {
273 // Optional switches must have a prefix ([/) or ([-), and at least one
274 // character.
275 return param[0] == _T('[') && IsSwitch(param.Right(param.GetLength() - 1));
276 }
277
278 HRESULT CommandLineParser::StripSwitchNameFromArgv(const CString& param,
279 CString* switch_name) {
280 ASSERT1(switch_name);
281
282 if (!IsSwitch(param)) {
283 return E_INVALIDARG;
284 }
285
286 *switch_name = param.Right(param.GetLength() - 1);
287 switch_name->Trim(_T(" "));
288 switch_name->MakeLower();
289 return S_OK;
290 }
291
292 HRESULT CommandLineParser::StripOptionalSwitchNameFromArgv(const CString& param,
293 CString* name) {
294 ASSERT1(name);
295
296 if (!IsOptionalSwitch(param)) {
297 return E_INVALIDARG;
298 }
299
300 return StripSwitchNameFromArgv(param.Right(param.GetLength() - 1), name);
301 }
302
303 void CommandLineParser::Reset() {
304 required_args_->Reset();
305 optional_args_->Reset();
306 }
307
308 HRESULT CommandLineParser::AddSwitch(const CString& switch_name) {
309 ASSERT1(switch_name == CString(switch_name).MakeLower());
310 return required_args_->AddSwitch(switch_name);
311 }
312
313 HRESULT CommandLineParser::AddSwitchArgument(const CString& switch_name,
314 const CString& argument_value) {
315 ASSERT1(switch_name == CString(switch_name).MakeLower());
316 return required_args_->AddSwitchArgument(switch_name, argument_value);
317 }
318
319 int CommandLineParser::GetSwitchCount() const {
320 return required_args_->GetSwitchCount();
321 }
322
323 bool CommandLineParser::HasSwitch(const CString& switch_name) const {
324 return required_args_->HasSwitch(switch_name);
325 }
326
327 // The value at a particular index may change if switch_names are added
328 // since we're using a map underneath. But this keeps us from having to write
329 // an interator and expose it externally.
330 HRESULT CommandLineParser::GetSwitchNameAtIndex(int index,
331 CString* switch_name) const {
332 return required_args_->GetSwitchNameAtIndex(index, switch_name);
333 }
334
335 HRESULT CommandLineParser::GetSwitchArgumentCount(const CString& switch_name,
336 int* count) const {
337 return required_args_->GetSwitchArgumentCount(switch_name, count);
338 }
339
340 HRESULT CommandLineParser::GetSwitchArgumentValue(
341 const CString& switch_name,
342 int argument_index,
343 CString* argument_value) const {
344 return required_args_->GetSwitchArgumentValue(switch_name,
345 argument_index,
346 argument_value);
347 }
348
349 HRESULT CommandLineParser::AddOptionalSwitch(const CString& switch_name) {
350 ASSERT1(switch_name == CString(switch_name).MakeLower());
351 return optional_args_->AddSwitch(switch_name);
352 }
353
354 HRESULT CommandLineParser::AddOptionalSwitchArgument(const CString& switch_name,
355 const CString& value) {
356 ASSERT1(switch_name == CString(switch_name).MakeLower());
357 return optional_args_->AddSwitchArgument(switch_name, value);
358 }
359
360 int CommandLineParser::GetOptionalSwitchCount() const {
361 return optional_args_->GetSwitchCount();
362 }
363
364 bool CommandLineParser::HasOptionalSwitch(const CString& switch_name) const {
365 return optional_args_->HasSwitch(switch_name);
366 }
367
368 // The value at a particular index may change if switch_names are added
369 // since we're using a map underneath. But this keeps us from having to write
370 // an interator and expose it externally.
371 HRESULT CommandLineParser::GetOptionalSwitchNameAtIndex(int index,
372 CString* name) const {
373 return optional_args_->GetSwitchNameAtIndex(index, name);
374 }
375
376 HRESULT CommandLineParser::GetOptionalSwitchArgumentCount(const CString& name,
377 int* count) const {
378 return optional_args_->GetSwitchArgumentCount(name, count);
379 }
380
381 HRESULT CommandLineParser::GetOptionalSwitchArgumentValue(const CString& name,
382 int argument_index,
383 CString* val) const {
384 return optional_args_->GetSwitchArgumentValue(name,
385 argument_index,
386 val);
387 }
388
389 } // namespace omaha
OLDNEW
« no previous file with comments | « base/command_line_parser.h ('k') | base/command_line_parser_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698