61 template <
char C,
typename ValueType,
bool Req = false>
68 Argument() : _value(), _valueName(), _help(), _conflicts() { }
73 Argument(
const ValueType & v,
const std::string & valueName =
"",
74 const std::string & help =
"")
75 : _value(v), _valueName(valueName), _help(help), _conflicts()
81 static constexpr char OptChar() {
return _c; }
86 const ValueType & Value()
const {
return _value; }
91 const ValueType & Value(
const ValueType & v)
100 ValueType & Value() {
return _value; }
105 static constexpr bool Required() {
return _required; }
110 static constexpr bool NeedsValue() {
return _needsValue; }
115 const std::string & ValueName()
const {
return _valueName; }
120 const std::string & ValueName(
const std::string & valueName)
122 _valueName = valueName;
129 const std::string & Help()
const {
return _help; }
134 const std::string & Help(
const std::string & help)
143 const std::set<char> & Conflicts()
const {
return _conflicts; }
148 const std::set<char> & Conflicts(
const std::set<char> & conflicts)
150 _conflicts = conflicts;
157 std::string UsageString()
const
176 static std::string IndentedText(
const std::string & s)
180 static const std::set<char> ws({
' ',
'\t',
'\n'});
182 for (
auto i = 0; i < s.size(); ++i) {
183 if (ws.find(s[i]) != ws.end()) {
190 for ( ; (j < s.size()) && (ws.find(s[j]) == ws.end()); ++j) {
192 if ((col + (j - i)) > 76) {
213 std::string HelpText()
const
215 std::string rc(UsageString());
220 rc += IndentedText(_help);
226 std::string _valueName;
228 std::set<char> _conflicts;
230 static constexpr const char _c = C;
231 static constexpr const bool _needsValue =
232 (! std::is_same<bool, ValueType>::value);
233 static constexpr const bool _required = Req;
239 template <
class ...Ts>
246 Arguments(
const char *envVar =
nullptr)
249 LoadFromEnvironment(envVar);
255 Arguments(
const char *envVar, Ts ...args)
258 LoadFromEnvironment(envVar);
264 int Parse(
int argc,
char *argv[])
267 std::string optStr = OptString();
271 while ((optChar = getopt(argc, argv, optStr.c_str())) != -1) {
277 if (ArgNeedsValue(optChar)) {
278 if (Set(optChar, optarg)) { _gotArgs.insert(optChar); }
282 if (Set(optChar,
true)) { _gotArgs.insert(optChar); }
285 KillConflicts(optChar);
289 if ((! erc) && GotRequiredArgs() && (! GotConflictingArgs())) {
300 static constexpr auto Indexes()
308 std::string OptString()
const
311 for (
auto i = 0; i < _indexes.size(); ++i) {
312 if (isprint(_indexes.at(i).first)) {
313 rc += _indexes.at(i).first;
314 if (_indexes.at(i).second) {
325 std::set<std::string> UsageGroups()
const
327 namespace Tuples = Dwm::TupleHelpers;
329 std::set<std::string> rc;
331 std::set<std::pair<bool,std::set<std::string>>> groups;
332 Tuples::ForEach(_args,
333 [&sep,&groups,
this] (
auto e)
335 std::set<std::string> ss;
336 ss.insert(e.UsageString());
337 for (
auto conflict : e.Conflicts()) {
338 ss.insert(UsageString(conflict));
340 groups.insert(std::make_pair(e.Required(), ss));
342 for (
const auto & gr : groups) {
348 for (
const auto & s : gr.second) {
364 std::string UsageString()
const
366 namespace Tuples = Dwm::TupleHelpers;
371 std::set<std::pair<bool,std::set<std::string>>> groups;
372 Tuples::ForEach(_args,
373 [&sep,&rc,&groups,
this] (
auto e)
375 std::set<std::string> ss;
376 ss.insert(e.UsageString());
377 for (
auto conflict : e.Conflicts()) {
378 ss.insert(UsageString(conflict));
380 groups.insert(std::make_pair(e.Required(), ss));
382 for (
const auto & gr : groups) {
387 for (
const auto & s : gr.second) {
403 std::string HelpText()
const
405 namespace Tuples = Dwm::TupleHelpers;
408 Tuples::ForEach(_args,
411 rc += e.HelpText() +
'\n';
412 if (! e.Conflicts().empty()) {
414 rc +=
"\t[conflicts with ";
415 for (auto conflict : e.Conflicts()) {
431 std::string Usage(
const std::string & argv0,
432 const std::string & tailArgs =
"")
const
434 std::ostringstream os;
436 auto groups = PrintableUsageGroups();
437 size_t indent = argv0.size() + std::string(
"Usage: ").size() + 1;
439 os <<
"Usage: " << argv0 <<
' ';
441 for (
const auto & gr : groups) {
442 if (col + gr.size() + 1 > 76) {
443 os <<
'\n' << std::setw(indent) <<
' ';
447 col += gr.size() + 1;
449 if (tailArgs.size() + col > 76) {
450 os <<
'\n' << std::setw(indent) <<
' ';
452 os << tailArgs <<
'\n' <<
'\n';
463 return std::get<Index(C)>(_args).Value();
472 return std::get<Index(C)>(_args).Value();
478 template <
char C,
typename V>
479 void Set(
const V & v)
481 std::get<Index(C)>(_args).Value(v);
489 void SetHelp(
const std::string & help)
491 std::get<Index(C)>(_args).Help(help);
499 std::string GetHelp()
const
501 return std::get<Index(C)>(_args).Help();
508 std::string GetHelpText()
const
510 return std::get<Index(C)>(_args).HelpText();
517 void SetValueName(
const std::string & valueName)
519 std::get<Index(C)>(_args).ValueName(valueName);
526 void SetConflicts(std::vector<std::set<char>> confs)
528 for (
const auto & c : confs) {
537 bool LoadFromEnvironment(
const char *envVar)
541 using std::regex, std::sregex_iterator, std::regex_search,
542 std::smatch, std::regex_match;
543 const char *envVal = getenv(envVar);
546 std::string envStr(envVal);
547 regex rgx(
"[^:]+", regex::ECMAScript|regex::optimize);
548 regex rgx1(
"^[^=]", regex::ECMAScript|regex::optimize);
549 regex rgx2(
"^([^=])[=](.+)$", regex::ECMAScript|regex::optimize);
550 auto vbeg = sregex_iterator(envStr.begin(), envStr.end(), rgx);
551 auto vend = sregex_iterator();
552 for (
auto it = vbeg; it != vend; ++it) {
554 std::string itstr(it->str());
555 if (regex_match(itstr, match, rgx2)) {
556 if (match.size() == 3) {
557 if (! Set(match[0].str()[0], match[2].str())) {
563 else if (regex_match(itstr, match, rgx1)) {
564 if (match.size() == 1) {
565 if (! Set(match[0].str()[0],
true)) {
582 static constexpr const std::array<std::pair<char,bool>, std::tuple_size<std::tuple<Ts...>>::value> _indexes = {std::pair<char,bool>(Ts::OptChar(),Ts::NeedsValue())...};
584 std::tuple<Ts...> _args;
585 std::set<char> _gotArgs;
590 static constexpr int Index(
char c)
592 for (
auto i = 0; i < _indexes.size(); ++i) {
593 if (_indexes.at(i).first == c) {
603 std::string UsageString(
char c)
const
605 namespace Tuples = Dwm::TupleHelpers;
607 std::string usagestr;
608 auto idx = Tuples::FindIf(_args,
610 {
return n.OptChar() == c; });
611 Tuples::Perform(_args, idx,
613 { usagestr = n.UsageString(); });
620 void SetConflicts1(std::set<char> conflicts)
622 namespace Tuples = Dwm::TupleHelpers;
624 for (
const auto conflict : conflicts) {
627 auto idx = Tuples::FindIf(_args,
629 {
return n.OptChar() == conflict; });
630 Tuples::Perform(_args, idx,
631 [&sc] (
auto & n) { n.Conflicts(sc); });
639 constexpr bool ArgNeedsValue(
char c)
const
641 namespace Tuples = Dwm::TupleHelpers;
644 auto idx = Tuples::FindIf(_args,
645 [c] (
auto n) {
return n.OptChar() == c; });
646 Tuples::Perform(_args, idx,
649 if (n.NeedsValue()) {
659 template <
typename U>
660 bool Set(
char c,
const U u)
662 namespace Tuples = Dwm::TupleHelpers;
663 using namespace ArgumentIO;
666 auto idx = Tuples::FindIf(_args,
667 [c] (
auto n) {
return n.OptChar() == c; });
668 Tuples::Perform(_args, idx,
670 std::ostringstream os;
672 std::istringstream is(os.str());
673 if (is >> n.Value()) {
683 bool Set(
char c, std::string s)
685 namespace Tuples = Dwm::TupleHelpers;
686 using namespace ArgumentIO;
688 std::istringstream iss(s);
690 auto idx = Tuples::FindIf(_args,
691 [c] (
auto n) {
return n.OptChar() == c; });
692 Tuples::Perform(_args, idx,
694 if (iss >> n.Value()) {
704 void KillConflicts(
char c)
706 namespace Tuples = Dwm::TupleHelpers;
707 std::set<char> conflicts = GetConflicts(c);
708 for (
auto conflict : conflicts) {
709 if (_gotArgs.find(conflict) == _gotArgs.end()) {
710 auto idx = Tuples::FindIf(_args,
712 {
return n.OptChar() == conflict; });
713 Tuples::Perform(_args, idx,
716 if constexpr (std::is_same<std::remove_reference_t<
decltype(n.Value())>,
bool>::value) {
720 n.Value(std::remove_reference_t<
decltype(n.Value())>());
731 std::set<char> GetConflicts(
char c)
733 namespace Tuples = Dwm::TupleHelpers;
735 auto idx = Tuples::FindIf(_args,
736 [c] (
auto n) {
return n.OptChar() == c; });
737 Tuples::Perform(_args, idx,
747 bool GotRequiredArgs()
749 namespace Tuples = Dwm::TupleHelpers;
751 bool foundConflict =
false;
752 Tuples::ForEach(_args,
753 [&rc, &foundConflict,
this] (
auto e)
755 && (_gotArgs.find(e.OptChar())
756 == _gotArgs.end())) {
757 for (auto c : e.Conflicts()) {
758 if (_gotArgs.find(c) != _gotArgs.end()) {
759 foundConflict = true;
763 if (! foundConflict) {
774 bool GotConflictingArgs()
776 namespace Tuples = Dwm::TupleHelpers;
778 Tuples::ForEach(_args,
781 if (_gotArgs.find(e.OptChar())
783 for (auto c : e.Conflicts()) {
798 std::set<std::string> PrintableUsageGroups()
const
800 namespace Tuples = Dwm::TupleHelpers;
801 std::set<std::string> rc;
803 std::set<std::pair<bool,std::set<std::string>>> groups;
804 Tuples::ForEach(_args,
805 [&sep,&groups,
this] (
auto e)
807 if (isprint(e.OptChar())) {
808 std::set<std::string> ss;
809 ss.insert(e.UsageString());
810 for (auto conflict : e.Conflicts()) {
811 ss.insert(UsageString(conflict));
813 groups.insert(std::make_pair(e.Required(), ss));
816 for (
const auto & gr : groups) {
822 for (
const auto & s : gr.second) {
iostream helpers for Argument values