1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 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 #ifndef PANDA_LIBPANDABASE_UTILS_PANDARGS_H_ 17 #define PANDA_LIBPANDABASE_UTILS_PANDARGS_H_ 18 19 #include <algorithm> 20 #include <array> 21 #include <list> 22 #include <set> 23 #include <map> 24 #include <string> 25 #include <string_view> 26 #include <type_traits> 27 #include <vector> 28 #include <cerrno> 29 #include <optional> 30 #include <utility> 31 32 #include "macros.h" 33 34 namespace panda { 35 using arg_list_t = std::vector<std::string>; 36 using std::enable_if_t; 37 using std::is_same_v; 38 39 enum class PandArgType : uint8_t { STRING, INTEGER, DOUBLE, BOOL, LIST, UINT32, UINT64, NOTYPE }; 40 41 // Base class for panda argument 42 class PandArgBase { 43 public: 44 explicit PandArgBase(std::string name, std::string desc, PandArgType type = PandArgType::NOTYPE) name_(std::move (name))45 : name_(std::move(name)), desc_(std::move(desc)), type_(type) {}; 46 GetType()47 PandArgType GetType() const 48 { 49 return type_; 50 } 51 GetName()52 std::string GetName() const 53 { 54 return name_; 55 } 56 GetDesc()57 std::string GetDesc() const 58 { 59 return desc_; 60 } 61 62 private: 63 std::string name_; 64 std::string desc_; 65 PandArgType type_; 66 }; 67 68 template <typename T, 69 enable_if_t<is_same_v<std::string, T> || is_same_v<double, T> || is_same_v<bool, T> || is_same_v<int, T> || 70 is_same_v<uint32_t, T> || is_same_v<uint64_t, T> || is_same_v<arg_list_t, T>> * = nullptr> 71 class PandArg : public PandArgBase { 72 public: PandArg(const std::string & name,T default_val,const std::string & desc)73 explicit PandArg(const std::string &name, T default_val, const std::string &desc) 74 : PandArgBase(name, desc, this->EvalType()), default_val_(default_val), real_val_(default_val) {}; 75 PandArg(const std::string & name,int default_val,const std::string & desc,T min_val,T max_val)76 explicit PandArg(const std::string &name, int default_val, const std::string &desc, T min_val, T max_val) 77 : PandArgBase(name, desc, this->EvalType()), 78 default_val_(default_val), 79 real_val_(default_val), 80 min_max_val_(std::pair<T, T>(min_val, max_val)) 81 { 82 } 83 PandArg(const std::string & name,const arg_list_t & default_val,const std::string & desc,std::string delimiter)84 explicit PandArg(const std::string &name, const arg_list_t &default_val, const std::string &desc, 85 std::string delimiter) 86 : PandArgBase(name, desc, PandArgType::LIST), 87 default_val_(default_val), 88 real_val_(default_val), 89 delimiter_(std::move(delimiter)) {}; 90 GetValue()91 T GetValue() const 92 { 93 return real_val_; 94 } 95 GetDefaultValue()96 T GetDefaultValue() const 97 { 98 return default_val_; 99 } 100 101 template <bool update_flag = true> SetValue(T val)102 void SetValue(T val) 103 { 104 real_val_ = val; 105 if constexpr (update_flag) { 106 was_set_ = true; 107 } 108 } 109 ResetDefaultValue()110 void ResetDefaultValue() 111 { 112 real_val_ = default_val_; 113 } 114 WasSet()115 bool WasSet() const 116 { 117 return was_set_; 118 } 119 GetDelimiter()120 std::optional<std::string> GetDelimiter() const 121 { 122 return delimiter_; 123 } GetMinMaxVal()124 std::optional<std::pair<T, T>> GetMinMaxVal() 125 { 126 return min_max_val_; 127 } 128 129 private: EvalType()130 constexpr PandArgType EvalType() 131 { 132 // NOLINTNEXTLINE(bugprone-branch-clone) 133 if constexpr (is_same_v<std::string, T>) { // NOLINT(readability-braces-around-statements) 134 return PandArgType::STRING; 135 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 136 } else if constexpr (is_same_v<double, T>) { 137 return PandArgType::DOUBLE; 138 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 139 } else if constexpr (is_same_v<bool, T>) { 140 return PandArgType::BOOL; 141 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 142 } else if constexpr (is_same_v<int, T>) { 143 return PandArgType::INTEGER; 144 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 145 } else if constexpr (is_same_v<uint32_t, T>) { 146 return PandArgType::UINT32; 147 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 148 } else if constexpr (is_same_v<uint64_t, T>) { 149 return PandArgType::UINT64; 150 // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation) 151 } else if constexpr (is_same_v<arg_list_t, T>) { 152 return PandArgType::LIST; 153 } 154 UNREACHABLE(); 155 } 156 157 T default_val_; 158 T real_val_; 159 bool was_set_ {false}; 160 161 // Only for integer arguments with range 162 std::optional<std::pair<T, T>> min_max_val_; 163 164 // Only for strings with delimiter 165 std::optional<std::string> delimiter_; 166 }; 167 168 class PandArgParser { 169 public: Add(PandArgBase * arg)170 bool Add(PandArgBase *arg) 171 { 172 if (arg == nullptr) { 173 errstr_ += "pandargs: Can't add `nullptr` as an argument\n"; 174 return false; 175 } 176 bool success = args_.insert(arg).second; 177 if (!success) { 178 errstr_ += "pandargs: Argument " + arg->GetName() + " has duplicate\n"; 179 } 180 return success; 181 } 182 PushBackTail(PandArgBase * arg)183 bool PushBackTail(PandArgBase *arg) 184 { 185 if (arg == nullptr) { 186 errstr_ += "pandargs: Can't add `nullptr` as a tail argument\n"; 187 return false; 188 } 189 if (std::find(tail_args_.begin(), tail_args_.end(), arg) != tail_args_.end()) { 190 errstr_ += "pandargs: Tail argument " + arg->GetName() + " is already in tail arguments list\n"; 191 return false; 192 } 193 tail_args_.emplace_back(arg); 194 return true; 195 } 196 PopBackTail()197 bool PopBackTail() 198 { 199 if (tail_args_.empty()) { 200 errstr_ += "pandargs: Nothing to pop back from tail arguments\n"; 201 return false; 202 } 203 tail_args_.pop_back(); 204 return true; 205 } 206 EraseTail()207 void EraseTail() 208 { 209 tail_args_.erase(tail_args_.begin(), tail_args_.end()); 210 } 211 Parse(const std::vector<std::string> & argv_vec)212 bool Parse(const std::vector<std::string> &argv_vec) 213 { 214 InitDefault(); 215 std::copy(argv_vec.begin(), argv_vec.end(), std::back_inserter(argv_vec_)); 216 return ParseArgs(); 217 } 218 Parse(int argc,const char * argv[])219 bool Parse(int argc, const char *argv[]) // NOLINT(modernize-avoid-c-arrays, hicpp-avoid-c-arrays) 220 { 221 InitDefault(); 222 for (int i = 1; i < argc; i++) { 223 argv_vec_.emplace_back(argv[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 224 } 225 return ParseArgs(); 226 } 227 228 /** 229 * Parses a string to the option's value. 230 */ ParseSingleArg(PandArgBase * option,const std::string_view & option_value)231 bool ParseSingleArg(PandArgBase *option, const std::string_view &option_value) 232 { 233 ASSERT(option != nullptr); 234 argv_vec_ = {std::string(option_value)}; 235 argv_index_ = 0; 236 ParseNextParam(option); 237 return errstr_.empty(); 238 } 239 240 /** 241 * Parses option's name and returns corresponding pointer. 242 */ GetPandArg(const std::string_view & arg_name)243 PandArgBase *GetPandArg(const std::string_view &arg_name) 244 { 245 auto arg_it = args_.find(arg_name); 246 return (arg_it != args_.end()) ? *arg_it : nullptr; 247 } 248 GetErrorString()249 std::string GetErrorString() const 250 { 251 return errstr_; 252 } 253 EnableTail()254 void EnableTail() 255 { 256 tail_flag_ = true; 257 } 258 DisableTail()259 void DisableTail() 260 { 261 tail_flag_ = false; 262 } 263 IsTailEnabled()264 bool IsTailEnabled() const 265 { 266 return tail_flag_; 267 } 268 GetTailSize()269 std::size_t GetTailSize() const 270 { 271 return tail_args_.size(); 272 } 273 EnableRemainder()274 void EnableRemainder() noexcept 275 { 276 remainder_flag_ = true; 277 } 278 DisableRemainder()279 void DisableRemainder() noexcept 280 { 281 remainder_flag_ = false; 282 } 283 IsRemainderEnabled()284 bool IsRemainderEnabled() const 285 { 286 return remainder_flag_; 287 } 288 GetRemainder()289 arg_list_t GetRemainder() 290 { 291 return remainder_; 292 } 293 IsArgSet(PandArgBase * arg)294 bool IsArgSet(PandArgBase *arg) const 295 { 296 return args_.find(arg) != args_.end(); 297 } 298 IsArgSet(const std::string & arg_name)299 bool IsArgSet(const std::string &arg_name) const 300 { 301 return args_.find(arg_name) != args_.end(); 302 } 303 GetHelpString()304 std::string GetHelpString() const 305 { 306 std::string helpstr; 307 for (auto i : args_) { 308 helpstr += DOUBLE_DASH + i->GetName() + ": " + i->GetDesc() + "\n"; 309 } 310 if (!tail_args_.empty()) { 311 helpstr += "Tail arguments:\n"; 312 for (auto i : tail_args_) { 313 helpstr += i->GetName() + ": " + i->GetDesc() + "\n"; 314 } 315 } 316 return helpstr; 317 } 318 GetRegularArgs()319 std::string GetRegularArgs() 320 { 321 std::string args_str; 322 std::string value; 323 for (auto i : args_) { 324 switch (i->GetType()) { 325 case PandArgType::STRING: 326 value = static_cast<PandArg<std::string> *>(i)->GetValue(); 327 break; 328 case PandArgType::INTEGER: 329 value = std::to_string(static_cast<PandArg<int> *>(i)->GetValue()); 330 break; 331 case PandArgType::DOUBLE: 332 value = std::to_string(static_cast<PandArg<double> *>(i)->GetValue()); 333 break; 334 case PandArgType::BOOL: 335 // NOLINTNEXTLINE(readability-implicit-bool-conversion) 336 value = std::to_string(static_cast<PandArg<bool> *>(i)->GetValue()); 337 break; 338 case PandArgType::UINT32: 339 value = std::to_string(static_cast<PandArg<uint32_t> *>(i)->GetValue()); 340 break; 341 case PandArgType::UINT64: 342 value = std::to_string(static_cast<PandArg<uint64_t> *>(i)->GetValue()); 343 break; 344 case PandArgType::LIST: { 345 value = ""; 346 std::vector<std::string> values_buf = static_cast<PandArg<arg_list_t> *>(i)->GetValue(); 347 for (const auto &j : values_buf) { 348 value += j + ", "; 349 } 350 break; 351 } 352 default: 353 errstr_ += "Invalid argument type \"" + i->GetName() + "\"\n"; 354 break; 355 } 356 args_str += DOUBLE_DASH + i->GetName() + "=" + value + "\n"; 357 } 358 return args_str; 359 } 360 361 private: 362 struct PandArgPtrComparator { 363 using is_transparent = void; operatorPandArgPtrComparator364 bool operator()(const PandArgBase *lhs, const PandArgBase *rhs) const 365 { 366 return lhs->GetName() < rhs->GetName(); 367 } operatorPandArgPtrComparator368 bool operator()(std::string_view lhs, const PandArgBase *rhs) const 369 { 370 return lhs < rhs->GetName(); 371 } operatorPandArgPtrComparator372 bool operator()(const PandArgBase *lhs, std::string_view rhs) const 373 { 374 return lhs->GetName() < rhs; 375 } 376 }; 377 ParseArgs()378 bool ParseArgs() 379 { 380 while (argv_index_ < argv_vec_.size()) { 381 PandArgBase *parsed_arg = ParseNextArg(); 382 if (!errstr_.empty()) { 383 return false; 384 } 385 ParseNextParam(parsed_arg); 386 if (!errstr_.empty()) { 387 return false; 388 } 389 } 390 return true; 391 } 392 InitDefault()393 void InitDefault() 394 { 395 equal_flag_ = false; 396 tail_parsed_flag_ = false; 397 argv_vec_.clear(); 398 argv_index_ = 0; 399 errstr_ = ""; 400 // reset tail 401 for (auto tail_arg : tail_args_) { 402 switch (tail_arg->GetType()) { 403 case PandArgType::STRING: 404 static_cast<PandArg<std::string> *>(tail_arg)->ResetDefaultValue(); 405 break; 406 case PandArgType::INTEGER: 407 static_cast<PandArg<int> *>(tail_arg)->ResetDefaultValue(); 408 break; 409 case PandArgType::DOUBLE: 410 static_cast<PandArg<double> *>(tail_arg)->ResetDefaultValue(); 411 break; 412 case PandArgType::BOOL: 413 static_cast<PandArg<bool> *>(tail_arg)->ResetDefaultValue(); 414 break; 415 case PandArgType::UINT32: 416 static_cast<PandArg<uint32_t> *>(tail_arg)->ResetDefaultValue(); 417 break; 418 case PandArgType::UINT64: 419 static_cast<PandArg<uint64_t> *>(tail_arg)->ResetDefaultValue(); 420 break; 421 case PandArgType::LIST: 422 static_cast<PandArg<arg_list_t> *>(tail_arg)->ResetDefaultValue(); 423 break; 424 default: 425 break; 426 } 427 } 428 // reset remainder 429 remainder_ = arg_list_t(); 430 } 431 ParseNextRegularArg()432 PandArgBase *ParseNextRegularArg() 433 { 434 PandArgBase *arg = nullptr; 435 std::string argstr = argv_vec_[argv_index_]; 436 437 const std::size_t SEP_FOUND = NextSeparator(argstr); 438 std::string arg_name; 439 440 if (SEP_FOUND != std::string::npos) { 441 equal_flag_ = true; 442 argv_vec_[argv_index_] = argstr.substr(SEP_FOUND + 1); 443 arg_name = argstr.substr(DASH_COUNT, SEP_FOUND - DASH_COUNT); 444 } else { 445 arg_name = argstr.substr(DASH_COUNT, SEP_FOUND); 446 // check if there is next argv element to iterate into 447 if (argv_index_ + 1 < argv_vec_.size()) { 448 argv_index_++; 449 } else { 450 argv_vec_[argv_index_] = ""; 451 } 452 } 453 454 auto arg_it = args_.find(arg_name); 455 456 if (arg_it != args_.end()) { 457 arg = *arg_it; 458 } else { 459 errstr_.append("pandargs: Invalid option \""); 460 errstr_.append(arg_name); 461 errstr_.append("\"\n"); 462 return nullptr; 463 } 464 465 return arg; 466 } 467 ParseNextArg()468 PandArgBase *ParseNextArg() 469 { 470 PandArgBase *arg = nullptr; 471 std::string argstr = argv_vec_[argv_index_]; 472 equal_flag_ = false; 473 474 // NOTE: currently we have only double dash argument prefix 475 std::size_t dashes_found = argstr.find(DOUBLE_DASH); 476 if (dashes_found == 0 && argstr.size() > DASH_COUNT) { 477 // regular argument 478 return ParseNextRegularArg(); 479 } 480 481 if (dashes_found == 0 && argstr.size() == DASH_COUNT) { 482 // remainder argument 483 if (!remainder_flag_) { 484 errstr_.append("pandargs: Remainder arguments are not enabled\n"); 485 errstr_.append("pandargs: Remainder found at literal \""); 486 errstr_.append(argstr); 487 errstr_.append("\"\n"); 488 return nullptr; 489 } 490 491 argv_index_++; 492 ParseRemainder(); 493 } else if (dashes_found > 0) { 494 // tail argument, N.B. std::string::npos > 0 495 if (!tail_flag_) { 496 errstr_.append("pandargs: Tail arguments are not enabled\n"); 497 errstr_.append("pandargs: Tail found at literal \""); 498 errstr_.append(argstr); 499 errstr_.append("\"\n"); 500 return nullptr; 501 } 502 if (tail_parsed_flag_) { 503 errstr_.append("pandargs: Too many tail arguments\n"); 504 return nullptr; 505 } 506 ParseTail(); 507 508 if (argv_index_ < argv_vec_.size()) { 509 if (argv_vec_[argv_index_] != DOUBLE_DASH && !remainder_flag_) { 510 errstr_ += "pandargs: Too many tail arguments given\n"; 511 } 512 } 513 514 } else { 515 errstr_.append("pandargs: Invalid option \""); 516 errstr_.append(argstr); 517 errstr_.append("\"\n"); 518 UNREACHABLE(); 519 } 520 return arg; 521 } 522 ParseTail()523 void ParseTail() 524 { 525 for (auto &tail_arg : tail_args_) { 526 switch (tail_arg->GetType()) { 527 case PandArgType::STRING: 528 argv_index_ = ParseStringArgParam(static_cast<PandArg<std::string> *>(tail_arg)); 529 break; 530 case PandArgType::INTEGER: 531 argv_index_ = ParseIntArgParam(static_cast<PandArg<int> *>(tail_arg)); 532 break; 533 case PandArgType::DOUBLE: 534 argv_index_ = ParseDoubleArgParam(static_cast<PandArg<double> *>(tail_arg)); 535 break; 536 case PandArgType::BOOL: 537 argv_index_ = ParseBoolArgParam(static_cast<PandArg<bool> *>(tail_arg), true); 538 break; 539 case PandArgType::UINT32: 540 argv_index_ = ParseUint32ArgParam(static_cast<PandArg<uint32_t> *>(tail_arg)); 541 break; 542 case PandArgType::UINT64: 543 argv_index_ = ParseUint64ArgParam(static_cast<PandArg<uint64_t> *>(tail_arg)); 544 break; 545 case PandArgType::LIST: 546 argv_index_ = ParseListArgParam(static_cast<PandArg<arg_list_t> *>(tail_arg)); 547 break; 548 default: 549 errstr_.append("pandargs: Invalid tail option type: \""); 550 errstr_.append(tail_arg->GetName()); 551 errstr_.append("\"\n"); 552 UNREACHABLE(); 553 break; 554 } 555 if (argv_index_ >= argv_vec_.size() || !errstr_.empty()) { 556 break; 557 } 558 } 559 tail_parsed_flag_ = true; 560 } 561 ParseRemainder()562 void ParseRemainder() 563 { 564 remainder_ = arg_list_t(argv_vec_.begin() + argv_index_, argv_vec_.end()); 565 argv_index_ = argv_vec_.size(); 566 } 567 ParseNextParam(PandArgBase * arg)568 void ParseNextParam(PandArgBase *arg) 569 { 570 if (argv_index_ >= argv_vec_.size() || arg == nullptr) { 571 return; 572 } 573 switch (arg->GetType()) { 574 case PandArgType::STRING: 575 argv_index_ = ParseStringArgParam(static_cast<PandArg<std::string> *>(arg)); 576 break; 577 case PandArgType::INTEGER: 578 argv_index_ = ParseIntArgParam(static_cast<PandArg<int> *>(arg)); 579 break; 580 case PandArgType::DOUBLE: 581 argv_index_ = ParseDoubleArgParam(static_cast<PandArg<double> *>(arg)); 582 break; 583 case PandArgType::BOOL: 584 argv_index_ = ParseBoolArgParam(static_cast<PandArg<bool> *>(arg)); 585 break; 586 case PandArgType::UINT32: 587 argv_index_ = ParseUint32ArgParam(static_cast<PandArg<uint32_t> *>(arg)); 588 break; 589 case PandArgType::UINT64: 590 argv_index_ = ParseUint64ArgParam(static_cast<PandArg<uint64_t> *>(arg)); 591 break; 592 case PandArgType::LIST: 593 argv_index_ = ParseListArgParam(static_cast<PandArg<arg_list_t> *>(arg)); 594 break; 595 case PandArgType::NOTYPE: 596 errstr_.append("pandargs: Invalid option type: \""); 597 errstr_.append(arg->GetName()); 598 errstr_.append("\"\n"); 599 UNREACHABLE(); 600 break; 601 default: 602 UNREACHABLE(); 603 break; 604 } 605 } 606 ParseStringArgParam(PandArg<std::string> * arg)607 std::size_t ParseStringArgParam(PandArg<std::string> *arg) 608 { 609 arg->SetValue(argv_vec_[argv_index_]); 610 return argv_index_ + 1; 611 } 612 ParseIntArgParam(PandArg<int> * arg)613 std::size_t ParseIntArgParam(PandArg<int> *arg) 614 { 615 std::string param_str(argv_vec_[argv_index_]); 616 if (IsIntegerNumber(param_str)) { 617 int num; 618 errno = 0; 619 if (StartsWith(param_str, "0x")) { 620 const int HEX = 16; 621 num = std::stoi(param_str, nullptr, HEX); 622 } else { 623 num = std::stoi(param_str); 624 } 625 626 if (errno == ERANGE) { 627 errstr_ += 628 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 629 } 630 631 if (IsIntegerArgInRange(arg, num)) { 632 arg->SetValue(num); 633 } else { 634 errstr_ += "pandargs: \"" + arg->GetName() + "\" argument has out of range parameter value \"" + 635 param_str + "\"\n"; 636 } 637 } else { 638 errstr_ += "pandargs: \"" + arg->GetName() + "\" argument has out of range parameter value \"" + param_str + 639 "\"\n"; 640 } 641 return argv_index_ + 1; 642 } 643 ParseDoubleArgParam(PandArg<double> * arg)644 std::size_t ParseDoubleArgParam(PandArg<double> *arg) 645 { 646 std::string param_str(argv_vec_[argv_index_]); 647 if (IsRationalNumber(param_str)) { 648 arg->SetValue(std::stod(param_str)); 649 } else { 650 errstr_ += 651 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 652 } 653 return argv_index_ + 1; 654 } 655 656 std::size_t ParseBoolArgParam(PandArg<bool> *arg, bool is_tail_param = false) 657 { 658 std::string param_str(argv_vec_[argv_index_]); 659 660 // if not a tail argument, assume two following cases 661 if (!is_tail_param) { 662 arg->SetValue(true); 663 // bool with no param, next argument comes right after 664 if (StartsWith(param_str, DOUBLE_DASH)) { 665 // check that bool param comes without "=" 666 if (equal_flag_) { 667 SetBoolUnexpectedValueError(arg, param_str); 668 } 669 return argv_index_; 670 } 671 // OR bool arg at the end of arguments line 672 if (param_str.empty()) { 673 // check that bool param comes without "=" 674 if (equal_flag_) { 675 SetBoolUnexpectedValueError(arg, param_str); 676 } 677 return argv_index_ + 1; 678 } 679 } 680 681 constexpr std::array<std::string_view, 3> TRUE_VALUES = {"on", "true", "1"}; 682 constexpr std::array<std::string_view, 3> FALSE_VALUES = {"off", "false", "0"}; 683 684 for (const auto &i : TRUE_VALUES) { 685 if (param_str == i) { 686 arg->SetValue(true); 687 return argv_index_ + 1; 688 } 689 } 690 for (const auto &i : FALSE_VALUES) { 691 if (param_str == i) { 692 arg->SetValue(false); 693 return argv_index_ + 1; 694 } 695 } 696 697 // if it's not a part of tail argument, 698 // assume that it's bool with no param, 699 // preceding tail argument 700 if (!is_tail_param) { 701 // check that bool param came without "=" 702 if (equal_flag_) { 703 SetBoolUnexpectedValueError(arg, param_str); 704 } else { 705 arg->SetValue(true); 706 } 707 } else { 708 errstr_ += 709 "pandargs: Tail argument " + arg->GetName() + " has unexpected parameter value " + param_str + "\n"; 710 arg->ResetDefaultValue(); 711 } 712 713 return argv_index_; 714 } 715 ParseUint64ArgParam(PandArg<uint64_t> * arg)716 std::size_t ParseUint64ArgParam(PandArg<uint64_t> *arg) 717 { 718 std::string param_str(argv_vec_[argv_index_]); 719 if (IsUintNumber(param_str)) { 720 errno = 0; 721 uint64_t num; 722 if (StartsWith(param_str, "0x")) { 723 const int HEX = 16; 724 num = std::strtoull(param_str.c_str(), nullptr, HEX); 725 } else { 726 const int DEC = 10; 727 num = std::strtoull(param_str.c_str(), nullptr, DEC); 728 } 729 if (errno == ERANGE) { 730 errstr_ += 731 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 732 } 733 734 if (IsIntegerArgInRange<uint64_t>(arg, num)) { 735 arg->SetValue(num); 736 } else { 737 errstr_ += "pandargs: \"" + arg->GetName() + "\" argument has out of range parameter value \"" + 738 param_str + "\"\n"; 739 } 740 } else { 741 errstr_ += 742 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 743 } 744 return argv_index_ + 1; 745 } 746 ParseUint32ArgParam(PandArg<uint32_t> * arg)747 std::size_t ParseUint32ArgParam(PandArg<uint32_t> *arg) 748 { 749 std::string param_str(argv_vec_[argv_index_]); 750 if (IsUintNumber(param_str)) { 751 errno = 0; 752 uint32_t num; 753 if (StartsWith(param_str, "0x")) { 754 const int HEX = 16; 755 num = std::strtoull(param_str.c_str(), nullptr, HEX); 756 } else { 757 const int DEC = 10; 758 num = std::strtoull(param_str.c_str(), nullptr, DEC); 759 } 760 if (errno == ERANGE) { 761 errstr_ += 762 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 763 } 764 765 if (IsIntegerArgInRange<uint32_t>(arg, num)) { 766 arg->SetValue(num); 767 } else { 768 errstr_ += "pandargs: \"" + arg->GetName() + "\" argument has out of range parameter value \"" + 769 param_str + "\"\n"; 770 } 771 } else { 772 errstr_ += 773 "pandargs: \"" + arg->GetName() + "\" argument has invalid parameter value \"" + param_str + "\"\n"; 774 } 775 return argv_index_ + 1; 776 } 777 ParseListArgParam(PandArg<arg_list_t> * arg)778 std::size_t ParseListArgParam(PandArg<arg_list_t> *arg) 779 { 780 std::string param_str(argv_vec_[argv_index_]); 781 arg_list_t value; 782 if (arg->WasSet()) { 783 value = arg->GetValue(); 784 } else { 785 value = arg_list_t(); 786 } 787 if (!arg->GetDelimiter().has_value()) { 788 value.push_back(param_str); 789 arg->SetValue(value); 790 return argv_index_ + 1; 791 } 792 std::string delimiter = arg->GetDelimiter().value(); 793 std::size_t param_str_index = 0; 794 std::size_t pos = param_str.find_first_of(delimiter, param_str_index); 795 while (pos < param_str.size()) { 796 value.push_back(param_str.substr(param_str_index, pos - param_str_index)); 797 param_str_index = pos; 798 param_str_index = param_str.find_first_not_of(delimiter, param_str_index); 799 pos = param_str.find_first_of(delimiter, param_str_index); 800 }; 801 802 value.push_back(param_str.substr(param_str_index, pos - param_str_index)); 803 arg->SetValue(value); 804 return argv_index_ + 1; 805 } 806 807 static std::size_t NextSeparator(std::string_view argstr, std::size_t pos = 0, 808 const std::string &separarors = EQ_SEPARATOR) 809 { 810 return argstr.find_first_of(separarors, pos); 811 } 812 IsIntegerNumber(const std::string_view & str)813 static bool IsIntegerNumber(const std::string_view &str) 814 { 815 if (str.empty()) { 816 return false; 817 } 818 std::size_t pos = 0; 819 // look for dash if it's negative one 820 if (str[0] == '-') { 821 pos++; 822 } 823 // look for hex-style integer 824 if (str[0] == '0' && str[1] == 'x') { 825 pos += HEX_PREFIX_WIDTH; 826 } 827 return str.find_first_not_of("0123456789", pos) == std::string::npos; 828 } 829 IsRationalNumber(const std::string_view & str)830 static bool IsRationalNumber(const std::string_view &str) 831 { 832 if (str.empty()) { 833 return false; 834 } 835 std::size_t pos = 0; 836 // look for dash if it's negative one 837 if (str[0] == '-') { 838 pos++; 839 } 840 return str.find_first_not_of(".0123456789", pos) == std::string::npos; 841 } 842 IsUintNumber(const std::string_view & str)843 static bool IsUintNumber(const std::string_view &str) 844 { 845 if (str.empty()) { 846 return false; 847 } 848 849 std::size_t pos = 0; 850 // look for hex-style uint_t integer 851 if (str[0] == '0' && str[1] == 'x') { 852 pos += HEX_PREFIX_WIDTH; 853 } 854 return str.find_first_not_of("0123456789", pos) == std::string::npos; 855 } 856 857 template <typename T, 858 enable_if_t<is_same_v<T, int> || is_same_v<T, uint32_t> || is_same_v<T, uint64_t>> * = nullptr> IsIntegerArgInRange(PandArg<T> * arg,T num)859 bool IsIntegerArgInRange(PandArg<T> *arg, T num) 860 { 861 if (!(arg->GetMinMaxVal().has_value())) { 862 return true; 863 } 864 std::pair<T, T> min_max = arg->GetMinMaxVal().value(); 865 return ((num >= std::get<0>(min_max)) && (num <= std::get<1>(min_max))); 866 } 867 StartsWith(const std::string & haystack,const std::string & needle)868 static bool StartsWith(const std::string &haystack, const std::string &needle) 869 { 870 return std::equal(needle.begin(), needle.end(), haystack.begin()); 871 } 872 SetBoolUnexpectedValueError(PandArg<bool> * arg,const std::string & wrongvalue)873 void SetBoolUnexpectedValueError(PandArg<bool> *arg, const std::string &wrongvalue) 874 { 875 errstr_ += "pandargs: Bool argument " + arg->GetName() + " has unexpected parameter value " + wrongvalue + "\n"; 876 arg->ResetDefaultValue(); 877 } 878 879 constexpr static size_t HEX_PREFIX_WIDTH = 2; 880 constexpr static unsigned int DASH_COUNT = 2; 881 882 std::vector<std::string> argv_vec_; 883 std::size_t argv_index_ = 0; 884 std::string errstr_ = ""; 885 bool tail_flag_ = false; 886 bool remainder_flag_ = false; 887 bool equal_flag_ = false; 888 bool tail_parsed_flag_ = false; 889 static constexpr const char *DOUBLE_DASH = "--"; 890 static constexpr const char *EQ_SEPARATOR = "="; 891 std::set<PandArgBase *, PandArgPtrComparator> args_; 892 std::vector<PandArgBase *> tail_args_; 893 arg_list_t remainder_ = arg_list_t(); 894 }; 895 896 } // namespace panda 897 898 #endif // PANDA_LIBPANDABASE_UTILS_PANDARGS_H_ 899