Commit fdf49ba719b15c5dc830d540bcbf525bfd5ad3a0
Merge branch 'default_implicit'
Showing
2 changed files
with
178 additions
and
41 deletions
src/cxxopts.hpp
| ... | ... | @@ -214,15 +214,36 @@ namespace cxxopts |
| 214 | 214 | |
| 215 | 215 | namespace cxxopts |
| 216 | 216 | { |
| 217 | - class Value | |
| 217 | + class Value : public std::enable_shared_from_this<Value> | |
| 218 | 218 | { |
| 219 | 219 | public: |
| 220 | 220 | |
| 221 | 221 | virtual void |
| 222 | 222 | parse(const std::string& text) const = 0; |
| 223 | 223 | |
| 224 | + virtual void | |
| 225 | + parse() const = 0; | |
| 226 | + | |
| 224 | 227 | virtual bool |
| 225 | 228 | has_arg() const = 0; |
| 229 | + | |
| 230 | + virtual bool | |
| 231 | + has_default() const = 0; | |
| 232 | + | |
| 233 | + virtual bool | |
| 234 | + has_implicit() const = 0; | |
| 235 | + | |
| 236 | + virtual std::string | |
| 237 | + get_default_value() const = 0; | |
| 238 | + | |
| 239 | + virtual std::string | |
| 240 | + get_implicit_value() const = 0; | |
| 241 | + | |
| 242 | + virtual std::shared_ptr<Value> | |
| 243 | + default_value(const std::string& value) = 0; | |
| 244 | + | |
| 245 | + virtual std::shared_ptr<Value> | |
| 246 | + implicit_value(const std::string& value) = 0; | |
| 226 | 247 | }; |
| 227 | 248 | |
| 228 | 249 | class OptionException : public std::exception |
| ... | ... | @@ -375,7 +396,7 @@ namespace cxxopts |
| 375 | 396 | |
| 376 | 397 | inline |
| 377 | 398 | void |
| 378 | - parse_value(const std::string& text, bool& value) | |
| 399 | + parse_value(const std::string& /*text*/, bool& value) | |
| 379 | 400 | { |
| 380 | 401 | //TODO recognise on, off, yes, no, enable, disable |
| 381 | 402 | //so that we can write --long=yes explicitly |
| ... | ... | @@ -395,16 +416,16 @@ namespace cxxopts |
| 395 | 416 | }; |
| 396 | 417 | |
| 397 | 418 | template <typename T> |
| 398 | - class default_value : public Value | |
| 419 | + class standard_value : public Value | |
| 399 | 420 | { |
| 400 | 421 | public: |
| 401 | - default_value() | |
| 422 | + standard_value() | |
| 402 | 423 | : m_result(std::make_shared<T>()) |
| 403 | 424 | , m_store(m_result.get()) |
| 404 | 425 | { |
| 405 | 426 | } |
| 406 | 427 | |
| 407 | - default_value(T* t) | |
| 428 | + standard_value(T* t) | |
| 408 | 429 | : m_store(t) |
| 409 | 430 | { |
| 410 | 431 | } |
| ... | ... | @@ -412,7 +433,20 @@ namespace cxxopts |
| 412 | 433 | void |
| 413 | 434 | parse(const std::string& text) const |
| 414 | 435 | { |
| 415 | - parse_value(text, *m_store); | |
| 436 | + if (m_implicit && text.empty()) | |
| 437 | + { | |
| 438 | + parse_value(m_implicit_value, *m_store); | |
| 439 | + } | |
| 440 | + else | |
| 441 | + { | |
| 442 | + parse_value(text, *m_store); | |
| 443 | + } | |
| 444 | + } | |
| 445 | + | |
| 446 | + void | |
| 447 | + parse() const | |
| 448 | + { | |
| 449 | + parse_value(m_default_value, *m_store); | |
| 416 | 450 | } |
| 417 | 451 | |
| 418 | 452 | bool |
| ... | ... | @@ -421,6 +455,44 @@ namespace cxxopts |
| 421 | 455 | return value_has_arg<T>::value; |
| 422 | 456 | } |
| 423 | 457 | |
| 458 | + bool | |
| 459 | + has_default() const | |
| 460 | + { | |
| 461 | + return m_default; | |
| 462 | + } | |
| 463 | + | |
| 464 | + bool | |
| 465 | + has_implicit() const | |
| 466 | + { | |
| 467 | + return m_implicit; | |
| 468 | + } | |
| 469 | + | |
| 470 | + virtual std::shared_ptr<Value> | |
| 471 | + default_value(const std::string& value){ | |
| 472 | + m_default = true; | |
| 473 | + m_default_value = value; | |
| 474 | + return shared_from_this(); | |
| 475 | + } | |
| 476 | + | |
| 477 | + virtual std::shared_ptr<Value> | |
| 478 | + implicit_value(const std::string& value){ | |
| 479 | + m_implicit = true; | |
| 480 | + m_implicit_value = value; | |
| 481 | + return shared_from_this(); | |
| 482 | + } | |
| 483 | + | |
| 484 | + std::string | |
| 485 | + get_default_value() const | |
| 486 | + { | |
| 487 | + return m_default_value; | |
| 488 | + } | |
| 489 | + | |
| 490 | + std::string | |
| 491 | + get_implicit_value() const | |
| 492 | + { | |
| 493 | + return m_implicit_value; | |
| 494 | + } | |
| 495 | + | |
| 424 | 496 | const T& |
| 425 | 497 | get() const |
| 426 | 498 | { |
| ... | ... | @@ -434,25 +506,28 @@ namespace cxxopts |
| 434 | 506 | } |
| 435 | 507 | } |
| 436 | 508 | |
| 437 | - private: | |
| 509 | + protected: | |
| 438 | 510 | std::shared_ptr<T> m_result; |
| 439 | 511 | T* m_store; |
| 512 | + bool m_default = false; | |
| 513 | + std::string m_default_value; | |
| 514 | + bool m_implicit = false; | |
| 515 | + std::string m_implicit_value; | |
| 440 | 516 | }; |
| 441 | - | |
| 442 | 517 | } |
| 443 | 518 | |
| 444 | 519 | template <typename T> |
| 445 | 520 | std::shared_ptr<Value> |
| 446 | 521 | value() |
| 447 | 522 | { |
| 448 | - return std::make_shared<values::default_value<T>>(); | |
| 523 | + return std::make_shared<values::standard_value<T>>(); | |
| 449 | 524 | } |
| 450 | 525 | |
| 451 | 526 | template <typename T> |
| 452 | 527 | std::shared_ptr<Value> |
| 453 | 528 | value(T& t) |
| 454 | 529 | { |
| 455 | - return std::make_shared<values::default_value<T>>(&t); | |
| 530 | + return std::make_shared<values::standard_value<T>>(&t); | |
| 456 | 531 | } |
| 457 | 532 | |
| 458 | 533 | class OptionAdder; |
| ... | ... | @@ -490,17 +565,28 @@ namespace cxxopts |
| 490 | 565 | ++m_count; |
| 491 | 566 | } |
| 492 | 567 | |
| 568 | + void | |
| 569 | + parse_default() | |
| 570 | + { | |
| 571 | + m_value->parse(); | |
| 572 | + ++m_count; | |
| 573 | + } | |
| 574 | + | |
| 493 | 575 | int |
| 494 | 576 | count() const |
| 495 | 577 | { |
| 496 | 578 | return m_count; |
| 497 | 579 | } |
| 498 | 580 | |
| 581 | + const Value& value() const { | |
| 582 | + return *m_value; | |
| 583 | + } | |
| 584 | + | |
| 499 | 585 | template <typename T> |
| 500 | 586 | const T& |
| 501 | 587 | as() const |
| 502 | 588 | { |
| 503 | - return dynamic_cast<const values::default_value<T>&>(*m_value).get(); | |
| 589 | + return dynamic_cast<const values::standard_value<T>&>(*m_value).get(); | |
| 504 | 590 | } |
| 505 | 591 | |
| 506 | 592 | private: |
| ... | ... | @@ -515,6 +601,10 @@ namespace cxxopts |
| 515 | 601 | std::string l; |
| 516 | 602 | String desc; |
| 517 | 603 | bool has_arg; |
| 604 | + bool has_default; | |
| 605 | + std::string default_value; | |
| 606 | + bool has_implicit; | |
| 607 | + std::string implicit_value; | |
| 518 | 608 | std::string arg_help; |
| 519 | 609 | }; |
| 520 | 610 | |
| ... | ... | @@ -622,7 +712,7 @@ namespace cxxopts |
| 622 | 712 | ( |
| 623 | 713 | int argc, |
| 624 | 714 | char* argv[], |
| 625 | - int argPos, | |
| 715 | + int& current, | |
| 626 | 716 | std::shared_ptr<OptionDetails> value, |
| 627 | 717 | const std::string& name |
| 628 | 718 | ); |
| ... | ... | @@ -686,12 +776,12 @@ namespace cxxopts |
| 686 | 776 | String |
| 687 | 777 | format_option |
| 688 | 778 | ( |
| 689 | - const std::string& s, | |
| 690 | - const std::string& l, | |
| 691 | - bool has_arg, | |
| 692 | - const std::string& arg_help | |
| 779 | + const HelpOptionDetails& o | |
| 693 | 780 | ) |
| 694 | 781 | { |
| 782 | + auto& s = o.s; | |
| 783 | + auto& l = o.l; | |
| 784 | + | |
| 695 | 785 | String result = " "; |
| 696 | 786 | |
| 697 | 787 | if (s.size() > 0) |
| ... | ... | @@ -708,15 +798,17 @@ namespace cxxopts |
| 708 | 798 | result += " --" + toLocalString(l); |
| 709 | 799 | } |
| 710 | 800 | |
| 711 | - if (has_arg) | |
| 801 | + if (o.has_arg) | |
| 712 | 802 | { |
| 713 | - if (arg_help.size() != 0) | |
| 803 | + auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; | |
| 804 | + | |
| 805 | + if (o.has_implicit) | |
| 714 | 806 | { |
| 715 | - result += " " + toLocalString(arg_help); | |
| 807 | + result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]"; | |
| 716 | 808 | } |
| 717 | 809 | else |
| 718 | 810 | { |
| 719 | - result += " arg"; | |
| 811 | + result += " " + arg; | |
| 720 | 812 | } |
| 721 | 813 | } |
| 722 | 814 | |
| ... | ... | @@ -726,20 +818,27 @@ namespace cxxopts |
| 726 | 818 | String |
| 727 | 819 | format_description |
| 728 | 820 | ( |
| 729 | - const String& text, | |
| 821 | + const HelpOptionDetails& o, | |
| 730 | 822 | int start, |
| 731 | 823 | int width |
| 732 | 824 | ) |
| 733 | 825 | { |
| 826 | + auto desc = o.desc; | |
| 827 | + | |
| 828 | + if (o.has_default) | |
| 829 | + { | |
| 830 | + desc += toLocalString(" (default:" + o.default_value + ")"); | |
| 831 | + } | |
| 832 | + | |
| 734 | 833 | String result; |
| 735 | 834 | |
| 736 | - auto current = std::begin(text); | |
| 835 | + auto current = std::begin(desc); | |
| 737 | 836 | auto startLine = current; |
| 738 | 837 | auto lastSpace = current; |
| 739 | 838 | |
| 740 | 839 | int size = 0; |
| 741 | 840 | |
| 742 | - while (current != std::end(text)) | |
| 841 | + while (current != std::end(desc)) | |
| 743 | 842 | { |
| 744 | 843 | if (*current == ' ') |
| 745 | 844 | { |
| ... | ... | @@ -816,7 +915,7 @@ void |
| 816 | 915 | Options::parse_option |
| 817 | 916 | ( |
| 818 | 917 | std::shared_ptr<OptionDetails> value, |
| 819 | - const std::string& name, | |
| 918 | + const std::string& /*name*/, | |
| 820 | 919 | const std::string& arg |
| 821 | 920 | ) |
| 822 | 921 | { |
| ... | ... | @@ -828,17 +927,34 @@ Options::checked_parse_arg |
| 828 | 927 | ( |
| 829 | 928 | int argc, |
| 830 | 929 | char* argv[], |
| 831 | - int argPos, | |
| 930 | + int& current, | |
| 832 | 931 | std::shared_ptr<OptionDetails> value, |
| 833 | 932 | const std::string& name |
| 834 | 933 | ) |
| 835 | 934 | { |
| 836 | - if (argPos >= argc) | |
| 935 | + if (current + 1 >= argc) | |
| 837 | 936 | { |
| 838 | - throw missing_argument_exception(name); | |
| 937 | + if (value->value().has_implicit()) | |
| 938 | + { | |
| 939 | + parse_option(value, name, ""); | |
| 940 | + } | |
| 941 | + else | |
| 942 | + { | |
| 943 | + throw missing_argument_exception(name); | |
| 944 | + } | |
| 945 | + } | |
| 946 | + else | |
| 947 | + { | |
| 948 | + if (argv[current + 1][0] == '-' && value->value().has_implicit()) | |
| 949 | + { | |
| 950 | + parse_option(value, name, ""); | |
| 951 | + } | |
| 952 | + else | |
| 953 | + { | |
| 954 | + parse_option(value, name, argv[current + 1]); | |
| 955 | + ++current; | |
| 956 | + } | |
| 839 | 957 | } |
| 840 | - | |
| 841 | - parse_option(value, name, argv[argPos]); | |
| 842 | 958 | } |
| 843 | 959 | |
| 844 | 960 | void |
| ... | ... | @@ -909,7 +1025,7 @@ Options::parse(int& argc, char**& argv) |
| 909 | 1025 | { |
| 910 | 1026 | const std::string& s = result[4]; |
| 911 | 1027 | |
| 912 | - for (int i = 0; i != s.size(); ++i) | |
| 1028 | + for (std::size_t i = 0; i != s.size(); ++i) | |
| 913 | 1029 | { |
| 914 | 1030 | std::string name(1, s[i]); |
| 915 | 1031 | auto iter = m_options.find(name); |
| ... | ... | @@ -931,8 +1047,11 @@ Options::parse(int& argc, char**& argv) |
| 931 | 1047 | //it must be the last argument |
| 932 | 1048 | if (i + 1 == s.size()) |
| 933 | 1049 | { |
| 934 | - checked_parse_arg(argc, argv, current+1, value, name); | |
| 935 | - ++current; | |
| 1050 | + checked_parse_arg(argc, argv, current, value, name); | |
| 1051 | + } | |
| 1052 | + else if (value->value().has_implicit()) | |
| 1053 | + { | |
| 1054 | + parse_option(value, name, ""); | |
| 936 | 1055 | } |
| 937 | 1056 | else |
| 938 | 1057 | { |
| ... | ... | @@ -973,9 +1092,7 @@ Options::parse(int& argc, char**& argv) |
| 973 | 1092 | if (opt->has_arg()) |
| 974 | 1093 | { |
| 975 | 1094 | //parse the next argument |
| 976 | - checked_parse_arg(argc, argv, current + 1, opt, name); | |
| 977 | - | |
| 978 | - ++current; | |
| 1095 | + checked_parse_arg(argc, argv, current, opt, name); | |
| 979 | 1096 | } |
| 980 | 1097 | else |
| 981 | 1098 | { |
| ... | ... | @@ -990,6 +1107,16 @@ Options::parse(int& argc, char**& argv) |
| 990 | 1107 | ++current; |
| 991 | 1108 | } |
| 992 | 1109 | |
| 1110 | + for (auto& opt : m_options) | |
| 1111 | + { | |
| 1112 | + auto& detail = opt.second; | |
| 1113 | + auto& value = detail->value(); | |
| 1114 | + | |
| 1115 | + if(!detail->count() && value.has_default()){ | |
| 1116 | + detail->parse_default(); | |
| 1117 | + } | |
| 1118 | + } | |
| 1119 | + | |
| 993 | 1120 | argc = nextKeep; |
| 994 | 1121 | } |
| 995 | 1122 | |
| ... | ... | @@ -1019,10 +1146,12 @@ Options::add_option |
| 1019 | 1146 | |
| 1020 | 1147 | //add the help details |
| 1021 | 1148 | auto& options = m_help[group]; |
| 1022 | - options.options. | |
| 1023 | - emplace_back(HelpOptionDetails{s, l, stringDesc, value->has_arg(), | |
| 1024 | - std::move(arg_help)} | |
| 1025 | - ); | |
| 1149 | + | |
| 1150 | + options.options.emplace_back(HelpOptionDetails{s, l, stringDesc, | |
| 1151 | + value->has_arg(), | |
| 1152 | + value->has_default(), value->get_default_value(), | |
| 1153 | + value->has_implicit(), value->get_implicit_value(), | |
| 1154 | + std::move(arg_help)}); | |
| 1026 | 1155 | } |
| 1027 | 1156 | |
| 1028 | 1157 | void |
| ... | ... | @@ -1064,7 +1193,7 @@ Options::help_one_group(const std::string& g) const |
| 1064 | 1193 | |
| 1065 | 1194 | for (const auto& o : group->second.options) |
| 1066 | 1195 | { |
| 1067 | - auto s = format_option(o.s, o.l, o.has_arg, o.arg_help); | |
| 1196 | + auto s = format_option(o); | |
| 1068 | 1197 | longest = std::max(longest, stringLength(s)); |
| 1069 | 1198 | format.push_back(std::make_pair(s, String())); |
| 1070 | 1199 | } |
| ... | ... | @@ -1077,7 +1206,7 @@ Options::help_one_group(const std::string& g) const |
| 1077 | 1206 | auto fiter = format.begin(); |
| 1078 | 1207 | for (const auto& o : group->second.options) |
| 1079 | 1208 | { |
| 1080 | - auto d = format_description(o.desc, longest + OPTION_DESC_GAP, allowed); | |
| 1209 | + auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); | |
| 1081 | 1210 | |
| 1082 | 1211 | result += fiter->first; |
| 1083 | 1212 | if (stringLength(fiter->first) > longest) | ... | ... |
src/example.cpp
| ... | ... | @@ -38,6 +38,8 @@ int main(int argc, char* argv[]) |
| 38 | 38 | ("a,apple", "an apple", cxxopts::value<bool>(apple)) |
| 39 | 39 | ("b,bob", "Bob") |
| 40 | 40 | ("f,file", "File", cxxopts::value<std::vector<std::string>>(), "FILE") |
| 41 | + ("o,output", "Output file", cxxopts::value<std::string>() | |
| 42 | + ->default_value("a.out")->implicit_value("b.def"), "BIN") | |
| 41 | 43 | ("positional", |
| 42 | 44 | "Positional arguments: these are the arguments that are entered " |
| 43 | 45 | "without an option", cxxopts::value<std::string>()) |
| ... | ... | @@ -92,6 +94,12 @@ int main(int argc, char* argv[]) |
| 92 | 94 | << std::endl; |
| 93 | 95 | } |
| 94 | 96 | |
| 97 | + if (options.count("output")) | |
| 98 | + { | |
| 99 | + std::cout << "Output = " << options["output"].as<std::string>() | |
| 100 | + << std::endl; | |
| 101 | + } | |
| 102 | + | |
| 95 | 103 | if (options.count("int")) |
| 96 | 104 | { |
| 97 | 105 | std::cout << "int = " << options["int"].as<int>() << std::endl; | ... | ... |