| 84 | } |
| 85 | |
| 86 | CommandParser::CommandParser(int argc, const char* argv[], |
| 87 | std::initializer_list<std::variant<Fixed, Optional>> options, std::string desc |
| 88 | ) : program(argv[0]){ |
| 89 | |
| 90 | std::queue<Fixed> fixed; |
| 91 | std::unordered_map<std::string, Optional> optmap; |
| 92 | std::unordered_map<std::string, std::string> aliases; |
| 93 | for(auto option : options){ |
| 94 | std::visit(overloaded { |
| 95 | [&](Fixed& opt){ |
| 96 | Fixed& f = fixed.emplace(opt); |
| 97 | if(f.number == 0){ |
| 98 | f.number = 1; |
| 99 | } |
| 100 | }, |
| 101 | [&](Optional& opt){ |
| 102 | optmap[opt.name] = opt; |
| 103 | if(!opt.alias.empty()){ |
| 104 | aliases[opt.alias] = opt.name; |
| 105 | } |
| 106 | } |
| 107 | }, option); |
| 108 | } |
| 109 | |
| 110 | // Consume values for a resolved option name. argi points to the first |
| 111 | // candidate value on entry and is advanced past everything consumed. |
| 112 | auto process_option = [&](const std::string& name, std::optional<std::string> inline_val, int& argi){ |
| 113 | Arg& value = args[name]; |
| 114 | switch(optmap[name].number){ |
| 115 | case 0: |
| 116 | value.emplace<std::monostate>(); |
| 117 | break; |
| 118 | case 1: |
| 119 | if(inline_val){ |
| 120 | value.emplace<std::string>(inline_val.value()); |
| 121 | } else { |
| 122 | if(argi >= argc){ |
| 123 | std::cerr << COLOR_Error ": option '" << name << "' requires an argument" << std::endl; |
| 124 | std::exit(-1); |
| 125 | } |
| 126 | value.emplace<std::string>(argv[argi++]); |
| 127 | } |
| 128 | break; |
| 129 | default:{ |
| 130 | std::vector<std::string>& values = value.emplace<std::vector<std::string>>(); |
| 131 | if(inline_val){ |
| 132 | values.emplace_back(inline_val.value()); |
| 133 | } |
| 134 | for(unsigned remain = optmap[name].number; remain > 0 && argi < argc; --remain, ++argi){ |
| 135 | std::string argstr(argv[argi]); |
| 136 | if(argstr == "--" || optmap.contains(argstr) || aliases.contains(argstr)){ |
| 137 | break; |
| 138 | } |
| 139 | if(argstr == "--help" || argstr == "-h"){ |
| 140 | help(program, desc, options); |
| 141 | std::exit(0); |
| 142 | } |
| 143 | values.emplace_back(argstr); |