PIDUINO
Loading...
Searching...
No Matches
popl.h
1/***
2 ____ __ ____ __
3 ( _ \ / \‍( _ \‍( )
4 ) __/( O )) __// (_/\
5 (__) \__/(__) \____/
6 version 1.2.0
7 https://github.com/badaix/popl
8
9 This file is part of popl (program options parser lib)
10 Copyright (C) 2015-2018 Johannes Pohl
11
12 This software may be modified and distributed under the terms
13 of the MIT license. See the 3rdparty/popl/LICENSE file for details.
14***/
15
18#pragma once
19
20#ifndef NOMINMAX
21#define NOMINMAX
22#endif // NOMINMAX
23
24#include <algorithm>
25#include <cstdio>
26#include <cstring>
27#include <iostream>
28#include <memory>
29#include <sstream>
30#include <stdexcept>
31#include <vector>
32
33
34namespace Piduino {
35
36#define POPL_VERSION "1.2.0"
37
38
40
45 enum class Argument {
46 no = 0, // option never takes an argument
47 required, // option always requires an argument
48 optional // option may take an argument
49 };
50
51
53
61 enum class Attribute {
62 inactive = 0,
63 hidden = 1,
64 required = 2,
65 optional = 3,
66 advanced = 4,
67 expert = 5
68 };
69
70
72
77 enum class OptionName {
81 };
82
83
85
90 class Option {
91 friend class OptionParser;
92 public:
97 Option (const std::string& short_name, const std::string& long_name, std::string description);
98
100 virtual ~Option() = default;
101
103 Option (const Option&) = default;
104
106 Option (Option &&) = default;
107
109 Option& operator= (const Option&) = default;
110
112 Option& operator= (Option &&) = default;
113
116 char short_name() const;
117
120 std::string long_name() const;
121
126 std::string name (OptionName what_name, bool with_hypen = false) const;
127
130 std::string description() const;
131
135 virtual bool get_default (std::ostream& out) const = 0;
136
139 void set_attribute (const Attribute& attribute);
140
143 Attribute attribute() const;
144
147 virtual Argument argument_type() const = 0;
148
151 virtual size_t count() const = 0;
152
155 virtual bool is_set() const = 0;
156
157 protected:
161 virtual void parse (OptionName what_name, const char* value) = 0;
162
164 virtual void clear() = 0;
165
166 std::string short_name_;
167 std::string long_name_;
168 std::string description_;
170 };
171
172
173
174
176
180 template<class T>
181 class Value : public Option {
182 public:
187 Value (const std::string& short_name, const std::string& long_name, const std::string& description);
188
195 Value (const std::string& short_name, const std::string& long_name, const std::string& description, const T& default_val, T* assign_to = nullptr);
196
197 size_t count() const override;
198 bool is_set() const override;
199
202 void assign_to (T* var);
203
206 void set_value (const T& value);
207
211 T value (size_t idx = 0) const;
212
215 void set_default (const T& value);
216
219 bool has_default() const;
220
223 T get_default() const;
224 bool get_default (std::ostream& out) const override;
225
226 Argument argument_type() const override;
227
228 protected:
229 void parse (OptionName what_name, const char* value) override;
230 std::unique_ptr<T> default_;
231
232 virtual void update_reference();
233 virtual void add_value (const T& value);
234 void clear() override;
235
237 std::vector<T> values_;
238 };
239
240
241
242
244
250 template<class T>
251 class Implicit : public Value<T> {
252 public:
253 Implicit (const std::string& short_name, const std::string& long_name, const std::string& description, const T& implicit_val, T* assign_to = nullptr);
254
255 Argument argument_type() const override;
256
257 protected:
258 void parse (OptionName what_name, const char* value) override;
259 };
260
261
262
263
265
270 class Switch : public Value<bool> {
271 public:
272 Switch (const std::string& short_name, const std::string& long_name, const std::string& description, bool* assign_to = nullptr);
273
274 void set_default (const bool& value) = delete;
275 Argument argument_type() const override;
276
277 protected:
278 void parse (OptionName what_name, const char* value) override;
279 };
280
281
282
283
284 using Option_ptr = std::shared_ptr<Option>;
285
287
294 public:
297 explicit OptionParser (std::string description = "");
298
300 virtual ~OptionParser() = default;
301
306 template<typename T, Attribute attribute, typename... Ts>
307 std::shared_ptr<T> add (Ts && ... params);
308
312 template<typename T, typename... Ts>
313 std::shared_ptr<T> add (Ts && ... params);
314
318 void parse (int argc, const char * const argv[]);
319
323 std::string help (const Attribute& max_attribute = Attribute::optional) const;
324
327 std::string description() const;
328
331 const std::vector<Option_ptr>& options() const;
332
337 const std::vector<std::string>& non_option_args() const;
338
342 const std::vector<std::string>& unknown_options() const;
343
347 template<typename T>
348 std::shared_ptr<T> get_option (const std::string& long_name) const;
349
353 template<typename T>
354 std::shared_ptr<T> get_option (char short_name) const;
355
356 protected:
357 std::vector<Option_ptr> options_;
358 std::string description_;
359 std::vector<std::string> non_option_args_;
360 std::vector<std::string> unknown_options_;
361
362 Option_ptr find_option (const std::string& long_name) const;
363 Option_ptr find_option (char short_name) const;
364 };
365
366
367
368 class invalid_option : public std::invalid_argument {
369 public:
376
377 invalid_option (const Option* option, invalid_option::Error error, OptionName what_name, std::string value, const std::string& text) :
378 std::invalid_argument (text.c_str()), option_ (option), error_ (error), what_name_ (what_name), value_ (std::move (value)) {
379 }
380
381 invalid_option (const Option* option, invalid_option::Error error, const std::string& text) :
383 }
384
385 const Option* option() const {
386 return option_;
387 }
388
389 Error error() const {
390 return error_;
391 }
392
394 return what_name_;
395 }
396
397 std::string value() const {
398 return value_;
399 }
400
401 private:
405 std::string value_;
406 };
407
408
409
411
415 public:
418 explicit OptionPrinter (const OptionParser* option_parser) : option_parser_ (option_parser) {
419 }
420
422 virtual ~OptionPrinter() = default;
423
427 virtual std::string print (const Attribute& max_attribute = Attribute::optional) const = 0;
428
429 protected:
431 };
432
433
434
435
437
442 public:
443 explicit ConsoleOptionPrinter (const OptionParser* option_parser);
444 ~ConsoleOptionPrinter() override = default;
445
446 std::string print (const Attribute& max_attribute = Attribute::optional) const override;
447
448 private:
449 std::string to_string (Option_ptr option) const;
450 };
451
452
453
454
456
460 public:
461 explicit GroffOptionPrinter (const OptionParser* option_parser);
462 ~GroffOptionPrinter() override = default;
463
464 std::string print (const Attribute& max_attribute = Attribute::optional) const override;
465
466 private:
467 std::string to_string (Option_ptr option) const;
468 };
469
470
471
472
474
478 public:
479 BashCompletionOptionPrinter (const OptionParser* option_parser, std::string program_name);
480 ~BashCompletionOptionPrinter() override = default;
481
482 std::string print (const Attribute& max_attribute = Attribute::optional) const override;
483
484 private:
485 std::string program_name_;
486 };
487
488
489
490
492
493 inline Option::Option (const std::string& short_name, const std::string& long_name, std::string description) :
494 short_name_ (short_name),
495 long_name_ (long_name),
496 description_ (std::move (description)),
497 attribute_ (Attribute::optional) {
498 if (short_name.size() > 1) {
499 throw std::invalid_argument ("length of short name must be <= 1: '" + short_name + "'");
500 }
501
502 if (short_name.empty() && long_name.empty()) {
503 throw std::invalid_argument ("short and long name are empty");
504 }
505 }
506
507
508 inline char Option::short_name() const {
509 if (!short_name_.empty()) {
510 return short_name_[0];
511 }
512 return 0;
513 }
514
515
516 inline std::string Option::long_name() const {
517 return long_name_;
518 }
519
520
521 inline std::string Option::name (OptionName what_name, bool with_hypen) const {
522 if (what_name == OptionName::short_name) {
523 return short_name_.empty() ? "" : ( (with_hypen ? "-" : "") + short_name_);
524 }
525 if (what_name == OptionName::long_name) {
526 return long_name_.empty() ? "" : ( (with_hypen ? "--" : "") + long_name_);
527 }
528 return "";
529 }
530
531
532 inline std::string Option::description() const {
533 return description_;
534 }
535
536
537 inline void Option::set_attribute (const Attribute& attribute) {
539 }
540
541
543 return attribute_;
544 }
545
546
547
548
550
551 template<class T>
552 inline Value<T>::Value (const std::string& short_name, const std::string& long_name, const std::string& description) :
553 Option (short_name, long_name, description),
554 assign_to_ (nullptr) {
555 }
556
557
558 template<class T>
559 inline Value<T>::Value (const std::string& short_name, const std::string& long_name, const std::string& description, const T& default_val, T* assign_to) :
560 Value<T> (short_name, long_name, description) {
562 set_default (default_val);
563 }
564
565
566 template<class T>
567 inline size_t Value<T>::count() const {
568 return values_.size();
569 }
570
571
572 template<class T>
573 inline bool Value<T>::is_set() const {
574 return !values_.empty();
575 }
576
577
578 template<class T>
579 inline void Value<T>::assign_to (T* var) {
580 assign_to_ = var;
581 update_reference();
582 }
583
584
585 template<class T>
586 inline void Value<T>::set_value (const T& value) {
587 clear();
588 add_value (value);
589 }
590
591
592 template<class T>
593 inline T Value<T>::value (size_t idx) const {
594 if (!this->is_set() && default_) {
595 return *default_;
596 }
597
598 if (!is_set() || (idx >= count())) {
599 std::stringstream optionStr;
600 if (!is_set()) {
601 optionStr << "option not set: \"";
602 }
603 else {
604 optionStr << "index out of range (" << idx << ") for \"";
605 }
606
607 if (short_name() != 0) {
608 optionStr << "-" << short_name();
609 }
610 else {
611 optionStr << "--" << long_name();
612 }
613
614 optionStr << "\"";
615 throw std::out_of_range (optionStr.str());
616 }
617
618 return values_[idx];
619 }
620
621
622
623 template<class T>
624 inline void Value<T>::set_default (const T& value) {
625 this->default_.reset (new T);
626 *this->default_ = value;
627 update_reference();
628 }
629
630
631 template<class T>
632 inline bool Value<T>::has_default() const {
633 return (this->default_ != nullptr);
634 }
635
636
637 template<class T>
638 inline T Value<T>::get_default() const {
639 if (!has_default()) {
640 throw std::runtime_error ("no default value set");
641 }
642 return *this->default_;
643 }
644
645
646 template<class T>
647 inline bool Value<T>::get_default (std::ostream& out) const {
648 if (!has_default()) {
649 return false;
650 }
651 out << *this->default_;
652 return true;
653 }
654
655
656 template<class T>
658 return Argument::required;
659 }
660
661
662 template<>
663 inline void Value<std::string>::parse (OptionName what_name, const char* value) {
664 if (strlen (value) == 0) {
665 throw invalid_option (this, invalid_option::Error::missing_argument, what_name, value, "missing argument for " + name (what_name, true));
666 }
667
668 add_value (value);
669 }
670
671
672 template<class T>
673 inline void Value<T>::parse (OptionName what_name, const char* value) {
674 T parsed_value;
675 std::string strValue;
676 if (value != nullptr) {
677 strValue = value;
678 }
679
680 std::istringstream is (strValue);
681 int valuesRead = 0;
682 while (is.good()) {
683 if (is.peek() != EOF) {
684 is >> parsed_value;
685 }
686 else {
687 break;
688 }
689
690 valuesRead++;
691 }
692
693 if (is.fail()) {
694 throw invalid_option (this, invalid_option::Error::invalid_argument, what_name, value, "invalid argument for " + name (what_name, true) + ": '" + strValue + "'");
695 }
696
697 if (valuesRead > 1) {
698 throw invalid_option (this, invalid_option::Error::too_many_arguments, what_name, value, "too many arguments for " + name (what_name, true) + ": '" + strValue + "'");
699 }
700
701 if (strValue.empty()) {
702 throw invalid_option (this, invalid_option::Error::missing_argument, what_name, "", "missing argument for " + name (what_name, true));
703 }
704
705 this->add_value (parsed_value);
706 }
707
708
709 template<class T>
711 if (this->assign_to_) {
712 if (this->is_set() || default_) {
713 *this->assign_to_ = value();
714 }
715 }
716 }
717
718
719 template<class T>
720 inline void Value<T>::add_value (const T& value) {
721 values_.push_back (value);
722 update_reference();
723 }
724
725
726 template<class T>
727 inline void Value<T>::clear() {
728 values_.clear();
729 update_reference();
730 }
731
732
733
735
736 template<class T>
737 inline Implicit<T>::Implicit (const std::string& short_name, const std::string& long_name, const std::string& description, const T& implicit_val, T* assign_to) :
738 Value<T> (short_name, long_name, description, implicit_val, assign_to) {
739 }
740
741
742 template<class T>
744 return Argument::optional;
745 }
746
747
748 template<class T>
749 inline void Implicit<T>::parse (OptionName what_name, const char* value) {
750 if ( (value != nullptr) && (strlen (value) > 0)) {
751 Value<T>::parse (what_name, value);
752 }
753 else {
754 this->add_value (*this->default_);
755 }
756 }
757
758
759
760
762
763 inline Switch::Switch (const std::string& short_name, const std::string& long_name, const std::string& description, bool* assign_to) :
764 Value<bool> (short_name, long_name, description, false, assign_to) {
765 }
766
767
768 inline void Switch::parse (OptionName /*what_name*/, const char* /*value*/) {
769 add_value (true);
770 }
771
772
774 return Argument::no;
775 }
776
777
778
779
781
782 inline OptionParser::OptionParser (std::string description) : description_ (std::move (description)) {
783 }
784
785
786 template<typename T, typename... Ts>
787 inline std::shared_ptr<T> OptionParser::add (Ts && ... params) {
788 return add<T, Attribute::optional> (std::forward<Ts> (params)...);
789 }
790
791
792 template<typename T, Attribute attribute, typename... Ts>
793 inline std::shared_ptr<T> OptionParser::add (Ts && ... params) {
794 static_assert (
795 std::is_base_of<Option, typename std::decay<T>::type>::value,
796 "type T must be Switch, Value or Implicit"
797 );
798 std::shared_ptr<T> option = std::make_shared<T> (std::forward<Ts> (params)...);
799
800 for (const auto & o : options_) {
801 if ( (option->short_name() != 0) && (option->short_name() == o->short_name())) {
802 throw std::invalid_argument ("duplicate short option name '-" + std::string (1, option->short_name()) + "'");
803 }
804 if (!option->long_name().empty() && (option->long_name() == (o->long_name()))) {
805 throw std::invalid_argument ("duplicate long option name '--" + option->long_name() + "'");
806 }
807 }
808 option->set_attribute (attribute);
809 options_.push_back (option);
810 return option;
811 }
812
813
814 inline std::string OptionParser::description() const {
815 return description_;
816 }
817
818
819 inline const std::vector<Option_ptr>& OptionParser::options() const {
820 return options_;
821 }
822
823
824 inline const std::vector<std::string>& OptionParser::non_option_args() const {
825 return non_option_args_;
826 }
827
828
829 inline const std::vector<std::string>& OptionParser::unknown_options() const {
830 return unknown_options_;
831 }
832
833
834 inline Option_ptr OptionParser::find_option (const std::string& long_name) const {
835 for (const auto & option : options_)
836 if (option->long_name() == long_name) {
837 return option;
838 }
839 return nullptr;
840 }
841
842
844 for (const auto & option : options_)
845 if (option->short_name() == short_name) {
846 return option;
847 }
848 return nullptr;
849 }
850
851
852 template<typename T>
853 inline std::shared_ptr<T> OptionParser::get_option (const std::string& long_name) const {
855 if (!option) {
856 throw std::invalid_argument ("option not found: " + long_name);
857 }
858 auto result = std::dynamic_pointer_cast<T> (option);
859 if (!result) {
860 throw std::invalid_argument ("cannot cast option to T: " + long_name);
861 }
862 return result;
863 }
864
865
866 template<typename T>
867 inline std::shared_ptr<T> OptionParser::get_option (char short_name) const {
869 if (!option) {
870 throw std::invalid_argument ("option not found: " + std::string (1, short_name));
871 }
872 auto result = std::dynamic_pointer_cast<T> (option);
873 if (!result) {
874 throw std::invalid_argument ("cannot cast option to T: " + std::string (1, short_name));
875 }
876 return result;
877 }
878
879
880 inline void OptionParser::parse (int argc, const char * const argv[]) {
881 unknown_options_.clear();
882 non_option_args_.clear();
883 for (auto & opt : options_) {
884 opt->clear();
885 }
886
887 for (int n = 1; n < argc; ++n) {
888 const std::string arg (argv[n]);
889 if (arg == "--") {
891 for (int m = n + 1; m < argc; ++m) {
892 non_option_args_.emplace_back (argv[m]);
893 }
894 }
895 else if (arg.find ("--") == 0) {
897 std::string opt = arg.substr (2);
898 std::string optarg;
899 size_t equalIdx = opt.find ('=');
900 if (equalIdx != std::string::npos) {
901 optarg = opt.substr (equalIdx + 1);
902 opt.resize (equalIdx);
903 }
904
905 Option_ptr option = find_option (opt);
906 if (option && (option->attribute() == Attribute::inactive)) {
907 option = nullptr;
908 }
909 if (option) {
910 if (option->argument_type() == Argument::no) {
911 if (!optarg.empty()) {
912 option = nullptr;
913 }
914 }
915 else if (option->argument_type() == Argument::required) {
916 if (optarg.empty() && n < argc - 1) {
917 optarg = argv[++n];
918 }
919 }
920 }
921
922 if (option) {
923 option->parse (OptionName::long_name, optarg.c_str());
924 }
925 else {
926 unknown_options_.push_back (arg);
927 }
928 }
929 else if (arg.find ('-') == 0) {
931 std::string opt = arg.substr (1);
932 bool unknown = false;
933 for (size_t m = 0; m < opt.size(); ++m) {
934 char c = opt[m];
935 std::string optarg;
936
937 Option_ptr option = find_option (c);
938 if (option && (option->attribute() == Attribute::inactive)) {
939 option = nullptr;
940 }
941 if (option) {
942 if (option->argument_type() == Argument::required) {
944 optarg = opt.substr (m + 1);
946 if (optarg.empty() && n < argc - 1) {
947 optarg = argv[++n];
948 }
949 m = opt.size();
950 }
951 else if (option->argument_type() == Argument::optional) {
953 optarg = opt.substr (m + 1);
954 m = opt.size();
955 }
956 }
957
958 if (option) {
959 option->parse (OptionName::short_name, optarg.c_str());
960 }
961 else {
962 unknown = true;
963 }
964 }
965 if (unknown) {
966 unknown_options_.push_back (arg);
967 }
968 }
969 else {
970 non_option_args_.push_back (arg);
971 }
972 }
973
974 for (auto & opt : options_) {
975 if ( (opt->attribute() == Attribute::required) && !opt->is_set()) {
976 std::string option = opt->long_name().empty() ? std::string (1, opt->short_name()) : opt->long_name();
977 throw invalid_option (opt.get(), invalid_option::Error::missing_option, "option \"" + option + "\" is required");
978 }
979 }
980 }
981
982
983 inline std::string OptionParser::help (const Attribute& max_attribute) const {
984 ConsoleOptionPrinter option_printer (this);
985 return option_printer.print (max_attribute);
986 }
987
988
989
990
992
993 inline ConsoleOptionPrinter::ConsoleOptionPrinter (const OptionParser* option_parser) : OptionPrinter (option_parser) {
994 }
995
996
997 inline std::string ConsoleOptionPrinter::to_string (Option_ptr option) const {
998 std::stringstream line;
999 if (option->short_name() != 0) {
1000 line << " -" << option->short_name();
1001 if (!option->long_name().empty()) {
1002 line << ", ";
1003 }
1004 }
1005 else {
1006 line << " ";
1007 }
1008 if (!option->long_name().empty()) {
1009 line << "--" << option->long_name();
1010 }
1011
1012 if (option->argument_type() == Argument::required) {
1013 line << " arg";
1014 std::stringstream defaultStr;
1015 if (option->get_default (defaultStr)) {
1016 if (!defaultStr.str().empty()) {
1017 line << " (=" << defaultStr.str() << ")";
1018 }
1019 }
1020 }
1021 else if (option->argument_type() == Argument::optional) {
1022 std::stringstream defaultStr;
1023 if (option->get_default (defaultStr)) {
1024 line << " [=arg(=" << defaultStr.str() << ")]";
1025 }
1026 }
1027
1028 return line.str();
1029 }
1030
1031
1032 inline std::string ConsoleOptionPrinter::print (const Attribute& max_attribute) const {
1033 if (option_parser_ == nullptr) {
1034 return "";
1035 }
1036
1037 if (max_attribute < Attribute::optional) {
1038 throw std::invalid_argument ("attribute must be 'optional', 'advanced', or 'default'");
1039 }
1040
1041 std::stringstream s;
1042 if (!option_parser_->description().empty()) {
1043 s << option_parser_->description() << ":\n";
1044 }
1045
1046 size_t optionRightMargin (20);
1047 const size_t maxDescriptionLeftMargin (40);
1048 // const size_t descriptionRightMargin(80);
1049
1050 for (const auto & option : option_parser_->options()) {
1051 optionRightMargin = std::max (optionRightMargin, to_string (option).size() + 2);
1052 }
1053 optionRightMargin = std::min (maxDescriptionLeftMargin - 2, optionRightMargin);
1054
1055 for (const auto & option : option_parser_->options()) {
1056 if ( (option->attribute() <= Attribute::hidden) ||
1057 (option->attribute() > max_attribute)) {
1058 continue;
1059 }
1060 std::string optionStr = to_string (option);
1061 if (optionStr.size() < optionRightMargin) {
1062 optionStr.resize (optionRightMargin, ' ');
1063 }
1064 else {
1065 optionStr += "\n" + std::string (optionRightMargin, ' ');
1066 }
1067 s << optionStr;
1068
1069 std::string line;
1070 std::vector<std::string> lines;
1071 std::stringstream description (option->description());
1072 while (std::getline (description, line, '\n')) {
1073 lines.push_back (line);
1074 }
1075
1076 std::string empty (optionRightMargin, ' ');
1077 for (size_t n = 0; n < lines.size(); ++n) {
1078 if (n > 0) {
1079 s << "\n" << empty;
1080 }
1081 s << lines[n];
1082 }
1083 s << "\n";
1084 }
1085
1086 return s.str();
1087 }
1088
1089
1090
1091
1093
1094 inline GroffOptionPrinter::GroffOptionPrinter (const OptionParser* option_parser) : OptionPrinter (option_parser) {
1095 }
1096
1097
1098 inline std::string GroffOptionPrinter::to_string (Option_ptr option) const {
1099 std::stringstream line;
1100 if (option->short_name() != 0) {
1101 line << "-" << option->short_name();
1102 if (!option->long_name().empty()) {
1103 line << ", ";
1104 }
1105 }
1106 if (!option->long_name().empty()) {
1107 line << "--" << option->long_name();
1108 }
1109
1110 if (option->argument_type() == Argument::required) {
1111 line << " arg";
1112 std::stringstream defaultStr;
1113 if (option->get_default (defaultStr)) {
1114 if (!defaultStr.str().empty()) {
1115 line << " (=" << defaultStr.str() << ")";
1116 }
1117 }
1118 }
1119 else if (option->argument_type() == Argument::optional) {
1120 std::stringstream defaultStr;
1121 if (option->get_default (defaultStr)) {
1122 line << " [=arg(=" << defaultStr.str() << ")]";
1123 }
1124 }
1125
1126 return line.str();
1127 }
1128
1129
1130 inline std::string GroffOptionPrinter::print (const Attribute& max_attribute) const {
1131 if (option_parser_ == nullptr) {
1132 return "";
1133 }
1134
1135 if (max_attribute < Attribute::optional) {
1136 throw std::invalid_argument ("attribute must be 'optional', 'advanced', or 'default'");
1137 }
1138
1139 std::stringstream s;
1140 if (!option_parser_->description().empty()) {
1141 s << ".SS " << option_parser_->description() << ":\n";
1142 }
1143
1144 for (const auto & option : option_parser_->options()) {
1145 if ( (option->attribute() <= Attribute::hidden) ||
1146 (option->attribute() > max_attribute)) {
1147 continue;
1148 }
1149 s << ".TP\n\\fB" << to_string (option) << "\\fR\n";
1150 if (!option->description().empty()) {
1151 s << option->description() << "\n";
1152 }
1153 }
1154
1155 return s.str();
1156 }
1157
1158
1159
1160
1162
1163 inline BashCompletionOptionPrinter::BashCompletionOptionPrinter (const OptionParser* option_parser, std::string program_name) : OptionPrinter (option_parser), program_name_ (std::move (program_name)) {
1164 }
1165
1166
1167 inline std::string BashCompletionOptionPrinter::print (const Attribute& /*max_attribute*/) const {
1168 if (option_parser_ == nullptr) {
1169 return "";
1170 }
1171
1172 std::stringstream s;
1173 s << "_" << program_name_ << "()\n";
1174 s << R"({
1175 local cur prev opts
1176 COMPREPLY=()
1177 cur="$ {COMP_WORDS[COMP_CWORD]}"
1178 prev="$ {COMP_WORDS[COMP_CWORD - 1]}"
1179 opts=") ";
1180
1181 for (const auto& option: option_parser_->options())
1182 {
1183 if (option->attribute() > Attribute::hidden)
1184 {
1185 if (option->short_name() != 0)
1186 s << " - " << option->short_name() << " ";
1187 if (!option->long_name().empty())
1188 s << "--" << option->long_name() << " ";
1189 }
1190 }
1191
1192 s << R" ("
1193 if [[ ${cur} == -* ]] ; then
1194 COMPREPLY=( $(compgen -W "$ {opts}" -- ${cur}) )
1195 return 0
1196 fi
1197 }
1198 complete -F )";
1199 s << "_" << program_name_ << " " << program_name_ << "\n";
1200
1201 return s.str();
1202 }
1203
1204
1205
1206
1207 static inline std::ostream& operator<< (std::ostream& out, const OptionParser& op) {
1208 return out << op.help();
1209 }
1210
1211
1212} // namespace Popl
Option printer for bash completion.
Definition popl.h:477
~BashCompletionOptionPrinter() override=default
std::string print(const Attribute &max_attribute=Attribute::optional) const override
Definition popl.h:1167
BashCompletionOptionPrinter(const OptionParser *option_parser, std::string program_name)
BashCompletionOptionPrinter implementation /////////////////////////////////.
Definition popl.h:1163
Option printer for the console.
Definition popl.h:441
std::string print(const Attribute &max_attribute=Attribute::optional) const override
Definition popl.h:1032
~ConsoleOptionPrinter() override=default
ConsoleOptionPrinter(const OptionParser *option_parser)
ConsoleOptionPrinter implementation /////////////////////////////////.
Definition popl.h:993
std::string to_string(Option_ptr option) const
Definition popl.h:997
Option printer for man pages.
Definition popl.h:459
~GroffOptionPrinter() override=default
std::string to_string(Option_ptr option) const
Definition popl.h:1098
GroffOptionPrinter(const OptionParser *option_parser)
GroffOptionPrinter implementation /////////////////////////////////.
Definition popl.h:1094
std::string print(const Attribute &max_attribute=Attribute::optional) const override
Definition popl.h:1130
Value option with implicit default value.
Definition popl.h:251
Implicit(const std::string &short_name, const std::string &long_name, const std::string &description, const T &implicit_val, T *assign_to=nullptr)
Implicit implementation /////////////////////////////////.
Definition popl.h:737
Argument argument_type() const override
Definition popl.h:743
void parse(OptionName what_name, const char *value) override
Definition popl.h:749
Abstract Base class for Options.
Definition popl.h:90
Option(const Option &)=default
default copy constructor
Attribute attribute() const
Definition popl.h:542
std::string description() const
Definition popl.h:532
virtual ~Option()=default
Destructor.
virtual Argument argument_type() const =0
virtual bool get_default(std::ostream &out) const =0
Option & operator=(const Option &)=default
default assignement operator
Attribute attribute_
Definition popl.h:169
std::string short_name_
Definition popl.h:166
Option(Option &&)=default
default move constructor
virtual bool is_set() const =0
Option(const std::string &short_name, const std::string &long_name, std::string description)
Option implementation /////////////////////////////////.
Definition popl.h:493
virtual void parse(OptionName what_name, const char *value)=0
virtual size_t count() const =0
char short_name() const
Definition popl.h:508
std::string long_name() const
Definition popl.h:516
virtual void clear()=0
Clear the internal data structure.
std::string name(OptionName what_name, bool with_hypen=false) const
Definition popl.h:521
std::string long_name_
Definition popl.h:167
void set_attribute(const Attribute &attribute)
Definition popl.h:537
std::string description_
Definition popl.h:168
OptionParser manages all Options.
Definition popl.h:293
Option_ptr find_option(const std::string &long_name) const
Definition popl.h:834
std::shared_ptr< T > add(Ts &&... params)
Definition popl.h:793
virtual ~OptionParser()=default
Destructor.
std::vector< Option_ptr > options_
Definition popl.h:357
std::string description() const
Definition popl.h:814
std::string description_
Definition popl.h:358
const std::vector< Option_ptr > & options() const
Definition popl.h:819
std::string help(const Attribute &max_attribute=Attribute::optional) const
Definition popl.h:983
std::vector< std::string > non_option_args_
Definition popl.h:359
const std::vector< std::string > & unknown_options() const
Definition popl.h:829
const std::vector< std::string > & non_option_args() const
Definition popl.h:824
std::shared_ptr< T > get_option(const std::string &long_name) const
Definition popl.h:853
std::vector< std::string > unknown_options_
Definition popl.h:360
void parse(int argc, const char *const argv[])
Definition popl.h:880
OptionParser(std::string description="")
OptionParser implementation /////////////////////////////////.
Definition popl.h:782
Base class for an OptionPrinter.
Definition popl.h:414
const OptionParser * option_parser_
Definition popl.h:430
virtual ~OptionPrinter()=default
Destructor.
virtual std::string print(const Attribute &max_attribute=Attribute::optional) const =0
OptionPrinter(const OptionParser *option_parser)
Definition popl.h:418
Value option without value.
Definition popl.h:270
void set_default(const bool &value)=delete
Switch(const std::string &short_name, const std::string &long_name, const std::string &description, bool *assign_to=nullptr)
Switch implementation /////////////////////////////////.
Definition popl.h:763
Argument argument_type() const override
Definition popl.h:773
void parse(OptionName what_name, const char *value) override
Definition popl.h:768
Value option with optional default value.
Definition popl.h:181
virtual void update_reference()
Definition popl.h:710
bool is_set() const override
Definition popl.h:573
Value(const std::string &short_name, const std::string &long_name, const std::string &description, const T &default_val, T *assign_to=nullptr)
Definition popl.h:559
void assign_to(T *var)
Definition popl.h:579
std::vector< T > values_
Definition popl.h:237
Argument argument_type() const override
Definition popl.h:657
T value(size_t idx=0) const
Definition popl.h:593
bool has_default() const
Definition popl.h:632
T * assign_to_
Definition popl.h:236
void set_default(const T &value)
Definition popl.h:624
void clear() override
Clear the internal data structure.
Definition popl.h:727
size_t count() const override
Definition popl.h:567
Value(const std::string &short_name, const std::string &long_name, const std::string &description)
Value implementation /////////////////////////////////.
Definition popl.h:552
virtual void add_value(const T &value)
Definition popl.h:720
T get_default() const
Definition popl.h:638
bool get_default(std::ostream &out) const override
Definition popl.h:647
void set_value(const T &value)
Definition popl.h:586
std::unique_ptr< T > default_
Definition popl.h:230
void parse(OptionName what_name, const char *value) override
Definition popl.h:673
OptionName what_name() const
Definition popl.h:393
Error error() const
Definition popl.h:389
const Option * option_
Definition popl.h:402
OptionName what_name_
Definition popl.h:404
const Option * option() const
Definition popl.h:385
invalid_option(const Option *option, invalid_option::Error error, const std::string &text)
Definition popl.h:381
std::string value_
Definition popl.h:405
invalid_option(const Option *option, invalid_option::Error error, OptionName what_name, std::string value, const std::string &text)
Definition popl.h:377
std::string value() const
Definition popl.h:397
Global namespace for Piduino.
Definition board.h:28
Attribute
Option's attribute.
Definition popl.h:61
Argument
Option's argument type.
Definition popl.h:45
OptionName
Option name type. Used in invalid_option exception.
Definition popl.h:77
std::shared_ptr< Option > Option_ptr
Definition popl.h:284
static std::ostream & operator<<(std::ostream &out, const OptionParser &op)
Definition popl.h:1183
STL namespace.