14 static bool read(
const char* arg, T& value) {
21 static bool read(
const char* arg,
bool& value) {
22 if (!std::strcmp(arg,
"true") || (arg[0] ==
'1' && arg[1] ==
'\0') || arg[0] ==
'\0') {
24 }
else if (!std::strcmp(arg,
"false") || (arg[0] ==
'0' && arg[1] ==
'\0')) {
36 static bool read(
const char* arg, std::string& value) {
44 static bool read(
const char* arg,
int& value) {
46 value = std::strtol(arg, &tmp, 10);
53 static bool read(
const char* arg,
size_t& value) {
55 value = std::strtoul(arg, &tmp, 10);
62 static bool read(
const char* arg,
float& value) {
64 value = std::strtof(arg, &tmp);
71 static bool read(
const char* arg,
double& value) {
73 value = std::strtod(arg, &tmp);
80 static std::string write(
const T& value) {
81 return std::to_string(value);
87 static std::string write(
const std::string& value) {
93 Option(
const std::string& fn,
94 const std::string& sn,
95 const std::string& dc)
103 virtual std::ostream& print_default(std::ostream& o)
const {
return o; }
104 virtual bool read_value(
const char* arg) = 0;
105 virtual std::string arg_name()
const {
return ""; }
106 virtual bool has_arg()
const {
return false; }
108 std::string full_name;
109 std::string short_name;
113 template <
typename T>
116 const std::string& short_name,
117 const std::string& desc,
118 T& val,
const T& def,
119 const std::string& arg)
120 :
Option(full_name, short_name, desc)
125 value = default_value;
128 std::ostream& print_default(std::ostream& o)
const override {
return o << default_value; }
130 bool read_value(
const char* arg)
override {
134 bool has_arg()
const override {
return true; }
135 std::string arg_name()
const override {
return arg_desc; }
139 std::string arg_desc;
145 const std::string& short_name,
146 const std::string& desc,
147 bool& val,
const bool& def,
149 :
Option(full_name, short_name, desc)
153 value = default_value;
156 bool read_value(
const char* arg)
override {
168 : argc(argc), argv(argv)
170 std::string path(argv[0]);
171 exe_name = path.substr(path.find_last_of(
"\\/") + 1);
175 for (
auto opt : options) {
180 template <
typename T>
181 void add_option(
const std::string& full_name,
182 const std::string& short_name,
183 const std::string& desc,
185 const T& default_value = T(),
186 const std::string& arg_name = std::string()) {
187 options.push_back(
new OptionImpl<T>(full_name, short_name, desc, value, default_value, arg_name));
191 for (
int i = 1; i < argc; i++) {
192 if (argv[i][0] ==
'-') {
194 if (argv[i][1] ==
'-') {
196 const std::string full_opt(argv[i] + 2);
197 auto eq_pos = full_opt.find(
'=');
198 const std::string opt_name = full_opt.substr(0, eq_pos);
199 const std::string opt_arg = (eq_pos != std::string::npos) ? full_opt.substr(eq_pos + 1) : std::string();
201 auto it = std::find_if(options.begin(), options.end(), [
this, opt_name] (
const Option* opt) ->
bool {
202 return opt->full_name == opt_name;
205 if (it == options.end()) {
206 std::cerr <<
"Unknown option : " << opt_name << std::endl;
210 if ((*it)->has_arg()) {
211 if (eq_pos == std::string::npos) {
212 std::cerr <<
"Missing argument for option : " << opt_name << std::endl;
216 if (!(*it)->read_value(opt_arg.c_str())) {
217 std::cerr <<
"Invalid value given to option \'" << opt_name <<
"\' : " << opt_arg << std::endl;
221 if (eq_pos != std::string::npos) {
222 std::cerr <<
"Option \'" << opt_name <<
"\' does not accept any argument" << std::endl;
226 bool ok = (*it)->read_value(opt_arg.c_str());
228 assert(ok &&
"read_value returns false for an option without args");
232 auto it = std::find_if(options.begin(), options.end(), [
this, i] (
const Option* opt) ->
bool {
233 return opt->short_name.compare(argv[i] + 1) == 0;
236 if (it == options.end()) {
237 std::cerr <<
"Unknown option : " << argv[i] + 1 << std::endl;
241 if ((*it)->has_arg()) {
243 std::cerr <<
"Missing argument for option : " << argv[i] + 1 << std::endl;
247 if(!(*it)->read_value(argv[i + 1])) {
248 std::cerr <<
"Invalid value given to option \'" << argv[i] + 1 <<
"\' : " << argv[i + 1] << std::endl;
254 if(!(*it)->read_value(
"")) {
255 std::cerr <<
"Invalid value given to option \'" << argv[i] + 1 << std::endl;
262 args.push_back(argv[i]);
269 std::cout <<
"Usage : " << exe_name <<
" [options] files\n" 270 <<
"Available options :\n";
273 size_t short_offset = 0, full_offset = 0;
274 for (
const auto opt : options) {
275 auto a = opt->has_arg() ? opt->arg_name().length() + 2 : 0;
276 auto s = opt->short_name.length() + a;
277 auto f = opt->full_name.length() + a;
279 if (short_offset < s) short_offset = s;
280 if (full_offset < f) full_offset = f;
283 for (
const auto opt : options) {
284 auto s = opt->short_name.length();
285 auto f = opt->full_name.length();
287 if (opt->has_arg()) {
288 auto a = opt->arg_name().length();
289 std::cout <<
"\t-" << opt->short_name <<
" " << opt->arg_name() << std::string(short_offset - s - a,
' ')
290 <<
"--" << opt->full_name <<
"=" << opt->arg_name() << std::string(full_offset - f - a,
' ')
291 << opt->desc <<
" (defaults to \'";
292 opt->print_default(std::cout) <<
"\').\n";
294 std::cout <<
"\t-" << opt->short_name << std::string(short_offset - s + 1,
' ')
295 <<
"--" << opt->full_name << std::string(full_offset - f + 1,
' ')
296 << opt->desc <<
".\n";
300 std::cout << std::endl;
303 const std::vector<std::string>& arguments()
const {
308 std::vector<Option*> options;
309 std::vector<std::string> args;
310 std::string exe_name;
Command line argument parser with ability to display the program usage.
Definition: options.h:165
Definition: options.h:114