Commit fdf49ba719b15c5dc830d540bcbf525bfd5ad3a0

Authored by Jarryd Beck
2 parents 1a558d76 4e4e91c3

Merge branch 'default_implicit'

src/cxxopts.hpp
@@ -214,15 +214,36 @@ namespace cxxopts @@ -214,15 +214,36 @@ namespace cxxopts
214 214
215 namespace cxxopts 215 namespace cxxopts
216 { 216 {
217 - class Value 217 + class Value : public std::enable_shared_from_this<Value>
218 { 218 {
219 public: 219 public:
220 220
221 virtual void 221 virtual void
222 parse(const std::string& text) const = 0; 222 parse(const std::string& text) const = 0;
223 223
  224 + virtual void
  225 + parse() const = 0;
  226 +
224 virtual bool 227 virtual bool
225 has_arg() const = 0; 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 class OptionException : public std::exception 249 class OptionException : public std::exception
@@ -375,7 +396,7 @@ namespace cxxopts @@ -375,7 +396,7 @@ namespace cxxopts
375 396
376 inline 397 inline
377 void 398 void
378 - parse_value(const std::string& text, bool& value) 399 + parse_value(const std::string& /*text*/, bool& value)
379 { 400 {
380 //TODO recognise on, off, yes, no, enable, disable 401 //TODO recognise on, off, yes, no, enable, disable
381 //so that we can write --long=yes explicitly 402 //so that we can write --long=yes explicitly
@@ -395,16 +416,16 @@ namespace cxxopts @@ -395,16 +416,16 @@ namespace cxxopts
395 }; 416 };
396 417
397 template <typename T> 418 template <typename T>
398 - class default_value : public Value 419 + class standard_value : public Value
399 { 420 {
400 public: 421 public:
401 - default_value() 422 + standard_value()
402 : m_result(std::make_shared<T>()) 423 : m_result(std::make_shared<T>())
403 , m_store(m_result.get()) 424 , m_store(m_result.get())
404 { 425 {
405 } 426 }
406 427
407 - default_value(T* t) 428 + standard_value(T* t)
408 : m_store(t) 429 : m_store(t)
409 { 430 {
410 } 431 }
@@ -412,7 +433,20 @@ namespace cxxopts @@ -412,7 +433,20 @@ namespace cxxopts
412 void 433 void
413 parse(const std::string& text) const 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 bool 452 bool
@@ -421,6 +455,44 @@ namespace cxxopts @@ -421,6 +455,44 @@ namespace cxxopts
421 return value_has_arg<T>::value; 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 const T& 496 const T&
425 get() const 497 get() const
426 { 498 {
@@ -434,25 +506,28 @@ namespace cxxopts @@ -434,25 +506,28 @@ namespace cxxopts
434 } 506 }
435 } 507 }
436 508
437 - private: 509 + protected:
438 std::shared_ptr<T> m_result; 510 std::shared_ptr<T> m_result;
439 T* m_store; 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 template <typename T> 519 template <typename T>
445 std::shared_ptr<Value> 520 std::shared_ptr<Value>
446 value() 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 template <typename T> 526 template <typename T>
452 std::shared_ptr<Value> 527 std::shared_ptr<Value>
453 value(T& t) 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 class OptionAdder; 533 class OptionAdder;
@@ -490,17 +565,28 @@ namespace cxxopts @@ -490,17 +565,28 @@ namespace cxxopts
490 ++m_count; 565 ++m_count;
491 } 566 }
492 567
  568 + void
  569 + parse_default()
  570 + {
  571 + m_value->parse();
  572 + ++m_count;
  573 + }
  574 +
493 int 575 int
494 count() const 576 count() const
495 { 577 {
496 return m_count; 578 return m_count;
497 } 579 }
498 580
  581 + const Value& value() const {
  582 + return *m_value;
  583 + }
  584 +
499 template <typename T> 585 template <typename T>
500 const T& 586 const T&
501 as() const 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 private: 592 private:
@@ -515,6 +601,10 @@ namespace cxxopts @@ -515,6 +601,10 @@ namespace cxxopts
515 std::string l; 601 std::string l;
516 String desc; 602 String desc;
517 bool has_arg; 603 bool has_arg;
  604 + bool has_default;
  605 + std::string default_value;
  606 + bool has_implicit;
  607 + std::string implicit_value;
518 std::string arg_help; 608 std::string arg_help;
519 }; 609 };
520 610
@@ -622,7 +712,7 @@ namespace cxxopts @@ -622,7 +712,7 @@ namespace cxxopts
622 ( 712 (
623 int argc, 713 int argc,
624 char* argv[], 714 char* argv[],
625 - int argPos, 715 + int& current,
626 std::shared_ptr<OptionDetails> value, 716 std::shared_ptr<OptionDetails> value,
627 const std::string& name 717 const std::string& name
628 ); 718 );
@@ -686,12 +776,12 @@ namespace cxxopts @@ -686,12 +776,12 @@ namespace cxxopts
686 String 776 String
687 format_option 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 String result = " "; 785 String result = " ";
696 786
697 if (s.size() > 0) 787 if (s.size() > 0)
@@ -708,15 +798,17 @@ namespace cxxopts @@ -708,15 +798,17 @@ namespace cxxopts
708 result += " --" + toLocalString(l); 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 else 809 else
718 { 810 {
719 - result += " arg"; 811 + result += " " + arg;
720 } 812 }
721 } 813 }
722 814
@@ -726,20 +818,27 @@ namespace cxxopts @@ -726,20 +818,27 @@ namespace cxxopts
726 String 818 String
727 format_description 819 format_description
728 ( 820 (
729 - const String& text, 821 + const HelpOptionDetails& o,
730 int start, 822 int start,
731 int width 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 String result; 833 String result;
735 834
736 - auto current = std::begin(text); 835 + auto current = std::begin(desc);
737 auto startLine = current; 836 auto startLine = current;
738 auto lastSpace = current; 837 auto lastSpace = current;
739 838
740 int size = 0; 839 int size = 0;
741 840
742 - while (current != std::end(text)) 841 + while (current != std::end(desc))
743 { 842 {
744 if (*current == ' ') 843 if (*current == ' ')
745 { 844 {
@@ -816,7 +915,7 @@ void @@ -816,7 +915,7 @@ void
816 Options::parse_option 915 Options::parse_option
817 ( 916 (
818 std::shared_ptr<OptionDetails> value, 917 std::shared_ptr<OptionDetails> value,
819 - const std::string& name, 918 + const std::string& /*name*/,
820 const std::string& arg 919 const std::string& arg
821 ) 920 )
822 { 921 {
@@ -828,17 +927,34 @@ Options::checked_parse_arg @@ -828,17 +927,34 @@ Options::checked_parse_arg
828 ( 927 (
829 int argc, 928 int argc,
830 char* argv[], 929 char* argv[],
831 - int argPos, 930 + int& current,
832 std::shared_ptr<OptionDetails> value, 931 std::shared_ptr<OptionDetails> value,
833 const std::string& name 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 void 960 void
@@ -909,7 +1025,7 @@ Options::parse(int&amp; argc, char**&amp; argv) @@ -909,7 +1025,7 @@ Options::parse(int&amp; argc, char**&amp; argv)
909 { 1025 {
910 const std::string& s = result[4]; 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 std::string name(1, s[i]); 1030 std::string name(1, s[i]);
915 auto iter = m_options.find(name); 1031 auto iter = m_options.find(name);
@@ -931,8 +1047,11 @@ Options::parse(int&amp; argc, char**&amp; argv) @@ -931,8 +1047,11 @@ Options::parse(int&amp; argc, char**&amp; argv)
931 //it must be the last argument 1047 //it must be the last argument
932 if (i + 1 == s.size()) 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 else 1056 else
938 { 1057 {
@@ -973,9 +1092,7 @@ Options::parse(int&amp; argc, char**&amp; argv) @@ -973,9 +1092,7 @@ Options::parse(int&amp; argc, char**&amp; argv)
973 if (opt->has_arg()) 1092 if (opt->has_arg())
974 { 1093 {
975 //parse the next argument 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 else 1097 else
981 { 1098 {
@@ -990,6 +1107,16 @@ Options::parse(int&amp; argc, char**&amp; argv) @@ -990,6 +1107,16 @@ Options::parse(int&amp; argc, char**&amp; argv)
990 ++current; 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 argc = nextKeep; 1120 argc = nextKeep;
994 } 1121 }
995 1122
@@ -1019,10 +1146,12 @@ Options::add_option @@ -1019,10 +1146,12 @@ Options::add_option
1019 1146
1020 //add the help details 1147 //add the help details
1021 auto& options = m_help[group]; 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 void 1157 void
@@ -1064,7 +1193,7 @@ Options::help_one_group(const std::string&amp; g) const @@ -1064,7 +1193,7 @@ Options::help_one_group(const std::string&amp; g) const
1064 1193
1065 for (const auto& o : group->second.options) 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 longest = std::max(longest, stringLength(s)); 1197 longest = std::max(longest, stringLength(s));
1069 format.push_back(std::make_pair(s, String())); 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,7 +1206,7 @@ Options::help_one_group(const std::string&amp; g) const
1077 auto fiter = format.begin(); 1206 auto fiter = format.begin();
1078 for (const auto& o : group->second.options) 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 result += fiter->first; 1211 result += fiter->first;
1083 if (stringLength(fiter->first) > longest) 1212 if (stringLength(fiter->first) > longest)
src/example.cpp
@@ -38,6 +38,8 @@ int main(int argc, char* argv[]) @@ -38,6 +38,8 @@ int main(int argc, char* argv[])
38 ("a,apple", "an apple", cxxopts::value<bool>(apple)) 38 ("a,apple", "an apple", cxxopts::value<bool>(apple))
39 ("b,bob", "Bob") 39 ("b,bob", "Bob")
40 ("f,file", "File", cxxopts::value<std::vector<std::string>>(), "FILE") 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 ("positional", 43 ("positional",
42 "Positional arguments: these are the arguments that are entered " 44 "Positional arguments: these are the arguments that are entered "
43 "without an option", cxxopts::value<std::string>()) 45 "without an option", cxxopts::value<std::string>())
@@ -92,6 +94,12 @@ int main(int argc, char* argv[]) @@ -92,6 +94,12 @@ int main(int argc, char* argv[])
92 << std::endl; 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 if (options.count("int")) 103 if (options.count("int"))
96 { 104 {
97 std::cout << "int = " << options["int"].as<int>() << std::endl; 105 std::cout << "int = " << options["int"].as<int>() << std::endl;