Commit fdf49ba719b15c5dc830d540bcbf525bfd5ad3a0

Authored by Jarryd Beck
2 parents 1a558d76 4e4e91c3

Merge branch 'default_implicit'

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&amp; argc, char**&amp; 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&amp; argc, char**&amp; 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&amp; argc, char**&amp; 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&amp; argc, char**&amp; 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&amp; 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&amp; 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;
... ...