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

Side by Side Diff: base/commands.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/commands.h ('k') | base/commands_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
(Empty)
1 // Copyright 2005-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 // Parse command-line options
17
18 #include "omaha/base/commands.h"
19 #include <cstdlib>
20 #include "base/scoped_ptr.h"
21 #include "omaha/base/cgi.h"
22 #include "omaha/base/debug.h"
23 #include "omaha/base/error.h"
24 #include "omaha/base/file.h"
25 #include "omaha/base/logging.h"
26 #include "omaha/base/string.h"
27 #include "omaha/base/utils.h"
28
29 namespace omaha {
30
31 #define kNameValueChar _T('=')
32 #define kTrueValue _T("true")
33 #define kFalseValue _T("false")
34 #define kOnValue _T("on")
35 #define kOffValue _T("off")
36
37
38 //
39 // Helper functions
40 //
41
42 template<class T>
43 HRESULT ConvertValue(const TCHAR* str_value, T* value);
44
45 // Convert the three-valued value from the string representation
46 template<>
47 HRESULT ConvertValue<ThreeValue>(const TCHAR* str_value, ThreeValue* value) {
48 ASSERT1(value);
49
50 *value = VALUE_NOT_SET;
51 if (str_value && *str_value) {
52 if (String_StrNCmp(str_value,
53 kTrueValue,
54 TSTR_SIZE(kTrueValue) + 1,
55 true) == 0 ||
56 String_StrNCmp(str_value,
57 kOnValue,
58 TSTR_SIZE(kOnValue) + 1,
59 true) == 0) {
60 *value = TRUE_VALUE;
61 } else if (String_StrNCmp(str_value,
62 kFalseValue,
63 TSTR_SIZE(kFalseValue) + 1,
64 true) == 0 ||
65 String_StrNCmp(str_value,
66 kOffValue,
67 TSTR_SIZE(kOffValue) + 1,
68 true) == 0) {
69 *value = FALSE_VALUE;
70 } else {
71 return CI_E_INVALID_ARG;
72 }
73 }
74 return S_OK;
75 }
76
77 // Convert the int value from the string representation
78 template<>
79 HRESULT ConvertValue<int>(const TCHAR* str_value, int* value) {
80 ASSERT1(str_value && *str_value);
81 ASSERT1(value);
82
83 if (_set_errno(0)) {
84 return E_FAIL;
85 }
86
87 *value = _tcstol(str_value, NULL, 0);
88 if (errno == ERANGE) {
89 return CI_E_INVALID_ARG;
90 }
91 return S_OK;
92 }
93
94 // Convert the unsigned int value from the string representation
95 template<>
96 HRESULT ConvertValue<uint32>(const TCHAR* str_value, uint32* value) {
97 ASSERT1(str_value && *str_value);
98 ASSERT1(value);
99
100 if (_set_errno(0)) {
101 return E_FAIL;
102 }
103
104 *value = _tcstoul(str_value, NULL, 0);
105 if (errno == ERANGE) {
106 return CI_E_INVALID_ARG;
107 }
108 return S_OK;
109 }
110
111 // Convert the string value from the string representation
112 HRESULT ConvertValue(const TCHAR* str_value, CString* value, bool to_unescape) {
113 ASSERT1(str_value && *str_value);
114 ASSERT1(value);
115
116 *value = str_value;
117
118 if (to_unescape) {
119 int length = value->GetLength();
120 scoped_array<TCHAR> unescaped_value(new TCHAR[length + 1]);
121 RET_IF_FALSE(CGI::UnescapeString(*value, length, unescaped_value.get(),
122 length + 1), CI_E_INVALID_ARG);
123 *value = unescaped_value.get();
124 }
125
126 return S_OK;
127 }
128
129 //
130 // Struct CommandOption
131 //
132 void CommandOption::Init(const TCHAR* name, CommandOptionType type,
133 void* value, int max_value_len) {
134 this->name = name;
135 this->type = type;
136 this->value = value;
137 this->max_value_len = max_value_len;
138 }
139
140 void CommandOption::Copy(const CommandOption& option) {
141 Init(option.name, option.type, option.value, option.max_value_len);
142 }
143
144 //
145 // Class CommandParsingSimple
146 //
147
148 // Constructor
149 CommandParsingSimple::CommandParsingSimple()
150 : separator_(_T(' ')) {
151 }
152
153 // Constructor
154 CommandParsingSimple::CommandParsingSimple(TCHAR separator)
155 : separator_(separator) {
156 }
157
158 // Parse a command line string into args
159 HRESULT CommandParsingSimple::ParseSimple(const TCHAR* cmd_line) {
160 ASSERT1(cmd_line);
161
162 UTIL_LOG(L3, (_T("[CommandParsingSimple::ParseSimple][%s]"), cmd_line));
163
164 args_.clear();
165
166 // Split command line string into list of arguments
167 for (const TCHAR* s = cmd_line; *s; ++s) {
168 // Handle separator
169 if (*s == separator_) {
170 continue;
171 }
172
173 // Handle single/double quote
174 if (*s == _T('"') || *s == _T('\'')) {
175 int right_quote = String_FindChar(s + 1, *s);
176 if (right_quote == -1) {
177 UTIL_LOG(LE, (_T("[CommandParsingSimple::ParseSimple]")
178 _T("[single/double quote mismatches]")));
179 return CI_E_INVALID_ARG;
180 }
181 args_.push_back(CString(s + 1, right_quote));
182 s += right_quote + 1;
183 continue;
184 }
185
186 // Handle all other char
187 int next_space = String_FindChar(s + 1, separator_);
188 if (next_space == -1) {
189 args_.push_back(CString(s));
190 break;
191 } else {
192 args_.push_back(CString(s, next_space + 1));
193 s += next_space + 1;
194 }
195 }
196
197 return S_OK;
198 }
199
200 // Get the arg at specified position from the command line
201 HRESULT CommandParsingSimple::GetAt(uint32 position, CString* arg) {
202 ASSERT1(arg);
203 ASSERT1(position < args_.size());
204
205 if (!arg || position >= args_.size()) {
206 return E_INVALIDARG;
207 }
208
209 *arg = args_[position];
210 return S_OK;
211 }
212
213 // Remove the arg at specified position from the command line
214 HRESULT CommandParsingSimple::RemoveAt(uint32 position) {
215 ASSERT1(position < args_.size());
216
217 if (position >= args_.size()) {
218 return E_INVALIDARG;
219 }
220
221 uint32 i = 0;
222 std::vector<CString>::iterator it(args_.begin());
223 for (; i < position; ++it, ++i) {
224 ASSERT1(it != args_.end());
225 }
226 args_.erase(it);
227 return S_OK;
228 }
229
230 // Converted to the string
231 HRESULT CommandParsingSimple::ToString(CString* cmd_line) {
232 ASSERT1(cmd_line);
233
234 bool is_first = true;
235 cmd_line->Empty();
236 for (std::vector<CString>::const_iterator it(args_.begin());
237 it != args_.end();
238 ++it) {
239 if (is_first) {
240 is_first = false;
241 } else {
242 cmd_line->AppendChar(separator_);
243 }
244 const TCHAR* arg = it->GetString();
245 if (String_FindChar(arg, separator_) != -1) {
246 cmd_line->AppendChar(_T('"'));
247 cmd_line->Append(arg);
248 cmd_line->AppendChar(_T('"'));
249 } else {
250 cmd_line->Append(arg);
251 }
252 }
253
254 return S_OK;
255 }
256
257 // Static Helper function that splits a command line
258 // string into executable and any arguments
259 HRESULT CommandParsingSimple::SplitExeAndArgs(const TCHAR* cmd_line,
260 CString* exe,
261 CString* args) {
262 ASSERT1(cmd_line);
263 ASSERT1(exe);
264 ASSERT1(args);
265
266 // Do the parsing
267 CommandParsingSimple cmd_parsing_simple;
268
269 RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));
270 RET_IF_FAILED(cmd_parsing_simple.GetAt(0, exe));
271 exe->Trim();
272 RET_IF_FAILED(cmd_parsing_simple.RemoveAt(0));
273 return (cmd_parsing_simple.ToString(args));
274 }
275
276 HRESULT CommandParsingSimple::SplitExeAndArgsGuess(const TCHAR* cmd_line,
277 CString* exe,
278 CString* args) {
279 ASSERT1(cmd_line);
280 ASSERT1(exe);
281 ASSERT1(args);
282
283 if (File::Exists(cmd_line)) {
284 // Optimization for the single executable case.
285 // Fill the [out] parameters and return.
286 *exe = cmd_line;
287 exe->Trim();
288 args->Empty();
289 return S_OK;
290 }
291
292 CString command_line(cmd_line);
293 // Check if the command line is properly enclosed, or that it does not have
294 // spaces
295 if (command_line.GetAt(0) != _T('"') && command_line.Find(_T(' ')) != -1) {
296 // File::Exists() does not handle leading spaces so remove it.
297 command_line.Trim();
298
299 // If not, need to find the executable, and if valid, enclose it in
300 // double quotes
301 const TCHAR* index_dot_exe = stristrW(command_line.GetString(), _T(".EXE"));
302
303 if (index_dot_exe != NULL) {
304 int dot_exe_end = (index_dot_exe - command_line.GetString())
305 + arraysize(_T(".EXE")) - 1;
306 if (File::Exists(CString(command_line, dot_exe_end))) {
307 // Enclose the EXE in double quotes
308 command_line.Insert(dot_exe_end, _T('"'));
309 command_line.Insert(0, _T('"'));
310 } else {
311 UTIL_LOG(L1, (_T("[CommandParsing::SplitExeAndArgsGuess]")
312 _T("[Could not guess the Executable file within [%s]. ")
313 _T("Passing on to SplitExeAndArgs as-is."),
314 command_line));
315 }
316 }
317 }
318
319 // Do the parsing
320 return SplitExeAndArgs(command_line, exe, args);
321 }
322
323
324 // Static Helper function that returns the number of arguments
325 // in the passed in cmd_line
326 HRESULT CommandParsingSimple::GetNumberOfArgs(const TCHAR* cmd_line,
327 uint32* number_of_args) {
328 ASSERT1(cmd_line);
329 ASSERT1(number_of_args);
330
331 // Do the parsing
332 CommandParsingSimple cmd_parsing_simple;
333
334 RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));
335 *number_of_args = cmd_parsing_simple.args_.size();
336 return S_OK;
337 }
338
339
340 //
341 // Class CommandParsing
342 //
343
344 // Constructor
345 CommandParsing::CommandParsing(CommandOption* options, int options_count)
346 : CommandParsingSimple(),
347 options_(options),
348 options_count_(options_count),
349 as_name_value_pair_(false) {
350 }
351
352 // Constructor
353 CommandParsing::CommandParsing(CommandOption* options, int options_count,
354 TCHAR separator, bool as_name_value_pair)
355 : CommandParsingSimple(separator),
356 options_(options),
357 options_count_(options_count),
358 as_name_value_pair_(as_name_value_pair) {
359 }
360
361 // Parse a command line string
362 HRESULT CommandParsing::Parse(const TCHAR* cmd_line, bool ignore_unknown_args) {
363 ASSERT1(cmd_line);
364
365 UTIL_LOG(L3, (_T("[CommandParsing::Parse][%s][%d]"),
366 cmd_line, ignore_unknown_args));
367
368 // Parse into args_ vector
369 RET_IF_FAILED(ParseSimple(cmd_line));
370
371 // Do the internal parsing
372 return InternalParse(ignore_unknown_args);
373 }
374
375 // Parse a list of command line arguments
376 HRESULT CommandParsing::ParseArguments(int argc, TCHAR* argv[]) {
377 if (argc <= 1) {
378 return S_OK;
379 }
380
381 // Push each argument
382 args_.clear();
383 for (int i = 1; i < argc; ++i) {
384 args_.push_back(CString(argv[i]));
385 }
386
387 // Do the internal parsing
388 return InternalParse(false);
389 }
390
391 // Internal parsing
392 HRESULT CommandParsing::InternalParse(bool ignore_unknown_args) {
393 CString name, value;
394 for (std::vector<CString>::const_iterator it(args_.begin());
395 it != args_.end();
396 ++it) {
397 RET_IF_FAILED(ExtractName(&name, &it));
398
399 int i = FindOption(name);
400 if (i == -1) {
401 if (ignore_unknown_args) {
402 UTIL_LOG(L3, (_T("[CommandParsing::Parse][unknown arg %s]"), name));
403 continue;
404 } else {
405 UTIL_LOG(LE, (_T("[CommandParsing::Parse][invalid arg %s]"), name));
406 return CI_E_INVALID_ARG;
407 }
408 }
409
410 if (options_[i].type != COMMAND_OPTION_BOOL) {
411 RET_IF_FAILED(ExtractValue(options_[i], &value, &it, args_.end()));
412 }
413
414 switch (options_[i].type & COMMAND_OPTION_FLAGS_MASK) {
415 case COMMAND_OPTION_BOOL: {
416 bool bool_value = true;
417 SetParsedValue(options_[i], bool_value);
418 break;
419 }
420
421 case COMMAND_OPTION_THREE: {
422 ThreeValue three_value = VALUE_NOT_SET;
423 RET_IF_FAILED(ConvertValue(value, &three_value));
424 SetParsedValue(options_[i], three_value);
425 break;
426 }
427
428 case COMMAND_OPTION_INT: {
429 int int_value = 0;
430 RET_IF_FAILED(ConvertValue(value, &int_value));
431 SetParsedValue(options_[i], int_value);
432 break;
433 }
434
435 case COMMAND_OPTION_UINT: {
436 int uint_value = 0;
437 RET_IF_FAILED(ConvertValue(value, &uint_value));
438 SetParsedValue(options_[i], uint_value);
439 break;
440 }
441
442 case COMMAND_OPTION_STRING: {
443 CString str_value;
444 bool is_unescape = (options_[i].type & COMMAND_OPTION_UNESCAPE) != 0;
445 RET_IF_FAILED(ConvertValue(value, &str_value, is_unescape));
446 SetParsedValue(options_[i], str_value);
447 break;
448 }
449
450 default:
451 ASSERT1(false);
452 break;
453 }
454 }
455
456 return S_OK;
457 }
458
459 // Extract the name
460 HRESULT CommandParsing::ExtractName(CString* name,
461 std::vector<CString>::const_iterator* it) {
462 ASSERT1(name);
463 ASSERT1(it);
464
465 if (as_name_value_pair_) {
466 int idx = (*it)->Find(kNameValueChar);
467 if (idx == -1) {
468 return CI_E_INVALID_ARG;
469 } else {
470 *name = (*it)->Left(idx);
471 }
472 } else {
473 *name = (*it)->GetString();
474 }
475 return S_OK;
476 }
477
478 // Extract the value
479 // Also validate the value length if necessary
480 HRESULT CommandParsing::ExtractValue(
481 const CommandOption& option,
482 CString* value,
483 std::vector<CString>::const_iterator* it,
484 const std::vector<CString>::const_iterator& end) {
485 ASSERT1(value);
486 ASSERT1(it);
487
488 if (as_name_value_pair_) {
489 int idx = (*it)->Find(kNameValueChar);
490 if (idx == -1) {
491 return CI_E_INVALID_ARG;
492 } else {
493 *value = (*it)->Right((*it)->GetLength() - idx - 1);
494 }
495 } else {
496 ++(*it);
497 if (*it == end) {
498 UTIL_LOG(LE, (_T("[CommandParsing::ExtractValue]")
499 _T("[argument %s missing value]"), option.name));
500 return CI_E_INVALID_ARG;
501 }
502 *value = (*it)->GetString();
503 }
504
505 if (option.max_value_len >= 0) {
506 if (value->GetLength() > option.max_value_len) {
507 return CI_E_INVALID_ARG;
508 }
509 }
510
511 return S_OK;
512 }
513
514 // Set the parsed value
515 template<class T>
516 void CommandParsing::SetParsedValue(const CommandOption& option,
517 const T& value) {
518 if (option.type & COMMAND_OPTION_MULTIPLE) {
519 ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_BOOL,
520 (_T("COMMAND_OPTION_BOOL can't be used with COMMAND_OPTION_MULTIPLE")));
521 ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_THREE,
522 (_T("COMMAND_OPTION_THREE can't be used with COMMAND_OPTION_MULTIPLE")));
523
524 std::vector<T>* ptr = reinterpret_cast<std::vector<T>*>(option.value);
525 ptr->push_back(value);
526 } else {
527 T* ptr = reinterpret_cast<T*>(option.value);
528 *ptr = value;
529 }
530 }
531
532 // Helper function to find an option in the CommandOption list
533 int CommandParsing::FindOption(const TCHAR* option_name) {
534 ASSERT1(option_name);
535
536 for (int i = 0; i < options_count_; ++i) {
537 if (String_StrNCmp(option_name,
538 options_[i].name,
539 options_[i].name.GetLength() + 1,
540 false) == 0) {
541 return i;
542 }
543 }
544
545 return -1;
546 }
547
548 // Remove an option from the command line
549 HRESULT CommandParsing::Remove(const TCHAR* option_name) {
550 ASSERT1(option_name);
551
552 for (std::vector<CString>::iterator it(args_.begin());
553 it != args_.end();
554 ++it) {
555 if (*it == option_name) {
556 int i = FindOption(option_name);
557 if (i == -1) {
558 return E_FAIL;
559 }
560 args_.erase(it);
561 if (!as_name_value_pair_) {
562 if (options_[i].type != COMMAND_OPTION_BOOL) {
563 if (it == args_.end()) {
564 return E_FAIL;
565 }
566 args_.erase(it);
567 }
568 }
569
570 return S_OK;
571 }
572 }
573
574 return E_FAIL;
575 }
576
577 } // namespace omaha
578
OLDNEW
« no previous file with comments | « base/commands.h ('k') | base/commands_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698