32#include <unordered_map>
44concept StringType = std::is_class_v<T> &&
requires(T type) {
49 typename T::value_type;
50 typename T::size_type;
51 { type.length() } -> std::same_as<typename T::size_type>;
52 { type[0] } -> std::same_as<typename T::value_type &>;
53 { type += T{} } -> std::same_as<T &>;
54 { type = T{} } -> std::same_as<T &>;
69template <StringType String>
95template <StringType String>
106 std::copy(a.
args.begin(), a.
args.end(), std::back_inserter(
args));
112 args = std::move(a.args);
123template <StringType String>
142template <StringType String>
187 if constexpr(std::is_same<typename String::value_type, char>::value) {
188 for(
int i = 1; i < argc; ++i) {
189 const char *a = argv[i];
195 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
196 for(
int i = 1; i < argc; ++i) {
197 const char *a = argv[i];
199 for(
size_t z = 0; a[z] != 0; ++z) {
200 data +=
static_cast<typename String::value_type
>(a[z]);
227 a.
desc = description;
242 a.
desc = description;
258 a.
desc = description;
275 a.
desc = description;
288 if(i.second.arg_name == value) {
289 return i.second.arg_letter;
304 if(type.length() > 3 && type[0] ==
'-' && type[1] ==
'-') {
306 for(
size_t z = 2; z < type.length(); ++z)
326 if constexpr(std::is_same<typename String::value_type, char>::value) {
333 if constexpr(std::is_same<typename String::value_type, char>::value) {
334 String value =
"Error argument: ";
336 value +=
" switch not found";
339 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
340 String value = L
"Error argument: ";
342 value += L
" switch not found";
346 }
else if(type.length() == 1 && type[0] ==
'-') {
347 if constexpr(std::is_same<typename String::value_type, char>::value) {
350 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
353 }
else if(type.length() > 1 && (type[0] ==
'-')) {
354 const int c{type[
cindex]};
357 if(
cindex >=
static_cast<int>(type.length())) {
362 name_val +=
static_cast<typename String::value_type
>(c);
371 if(s.length() > 1 && s[0] ==
'-' && !(s[1] >=
'0' && s[1] <=
'9')) {
372 if constexpr(std::is_same<typename String::value_type, char>::value) {
375 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
378 }
else if(s.length() == 1 && s[0] ==
'-') {
379 if constexpr(std::is_same<typename String::value_type, char>::value) {
382 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
394 if constexpr(std::is_same<typename String::value_type, char>::value) {
397 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
402 if constexpr(std::is_same<typename String::value_type, char>::value) {
405 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
410 if constexpr(std::is_same<typename String::value_type, char>::value) {
412 value =
"Error argument ";
413 value +=
static_cast<typename String::value_type
>(c);
414 value +=
" switch not found.";
417 if constexpr(std::is_same<typename String::value_type, wchar_t>::value) {
419 value = L
"Error argument ";
420 value +=
static_cast<typename String::value_type
>(c);
421 value += L
" switch not found.";
442 template <
typename T>
444 using char_type =
typename std::decay<decltype(*std::declval<T>().rdbuf())>::type::char_type;
445 std::vector<Argument<String>> v;
446 std::vector<Argument<String>> v2;
449 v.push_back(i.second);
451 v2.push_back(i.second);
453 std::sort(v.begin(), v.end());
454 std::sort(v2.begin(), v2.end());
455 std::vector<Argument<String>> farg;
456 farg.reserve(v.size() + v2.size());
457 std::copy(v.begin(), v.end(), std::back_inserter(farg));
458 std::copy(v2.begin(), v2.end(), std::back_inserter(farg));
459 for(
auto a = farg.begin(); a != farg.end(); ++a) {
461 if constexpr(std::is_same<char_type, char>::value) {
463 item +=
static_cast<char_type
>(a->arg_letter);
464 cout <<
"-" << std::setfill(
' ') << std::setw(9) << std::left << item <<
"\t";
465 cout << std::setfill(
' ') << std::left << std::setw(10) << a->desc;
467 }
else if constexpr(std::is_same<char_type, wchar_t>::value) {
469 item +=
static_cast<char_type
>(a->arg_letter);
470 cout << L
"-" << std::setfill(L
' ') << std::setw(9) << std::left << item << L
"\t";
471 cout << std::setfill(L
' ') << std::setw(10) << a->desc;
475 if constexpr(std::is_same<char_type, char>::value) {
477 cout << std::setfill(
' ') << std::left << std::setw(10) << a->arg_name;
479 cout << std::setw(10) << a->desc;
481 }
else if constexpr(std::is_same<char_type, wchar_t>::value) {
483 cout << std::setfill(L
' ') << std::left << std::setw(10) << a->arg_name;
485 cout << std::setw(10) << std::left << a->desc;
495 std::unordered_map<int, Argument<String>>
arg_info;
536 .addOptionSingleValue(
'p',
"assets path")
537 .addOptionDoubleValue(
'P',
"path",
"assets path")
538 .addOptionSingleValue(
'r',
"Resolution WidthxHeight")
539 .addOptionDoubleValue(
'R',
"resolution",
"Resolution WidthxHeight")
540 .addOptionSingle(
'f',
"fullscreen")
541 .addOptionDouble(
'F',
"fullscreen",
"fullscreen")
542 .addOptionDoubleValue(256,
"filename",
"input filename")
543 .addOptionDoubleValue(257,
"texture",
"texture file (.png or .tex)")
544 .addOptionSingleValue(
'S',
"shader SPV folder path (contains index.txt)")
545 .addOptionDoubleValue(258,
"shader-path",
"shader SPV folder path (contains index.txt)")
551 int tw = 1280, th = 720;
552 bool fullscreen =
false;
553 std::string filename;
555 std::string shaderPath;
557 while((value = parser.
proc(arg)) != -1) {
571 parser.
help(std::cout);
581 if(pos == std::string::npos) {
582 std::cerr <<
"Error invalid resolution use WidthxHeight\n";
586 std::string left, right;
589 tw = atoi(left.c_str());
590 th = atoi(right.c_str());
600 std::cerr <<
"mx: Argument Exception" << e.
text() << std::endl;
608 std::cerr <<
"mx: No path provided trying default current directory.\n";
Arguments proc_args(int &argc, char **argv)
Parse standard libmx2 command-line options from main()'s argv.
ArgType
Discriminator for option kind used inside Argument.
Exception thrown by Argz::proc() on unrecognised or malformed options.
ArgException(const String &s)
Template command-line argument parser.
void help(T &cout)
Print all registered options to any ostream-like object.
std::unordered_map< int, Argument< String > > arg_info
Argz< String > & addOptionSingleValue(const int &c, const String &description)
Register a short option that requires a value argument (e.g.
ArgumentData< String > arg_data
Argz< String > & addOptionDouble(const int &code, const String &value, const String &description)
Register a flag-only long option (e.g.
const size_t count() const
Argz< String > & initArgs(int argc, char **argv)
Ingest argc/argv, converting to the target String type.
Argz< String > & addOptionDoubleValue(const int &code, const String &value, const String &description)
Register a long option that requires a value argument (e.g.
int proc(Argument< String > &a)
Advance the cursor and parse the next argument.
Argz< String > & operator=(Argz< String > &&a)
Argz< String > & addOptionSingle(const int &c, const String &description)
Register a flag-only short option (e.g.
Argz< String > & operator=(const Argz< String > &a)
int lookUpCode(const String &value)
Look up the integer code registered for a long option name.
Argz(const Argz< String > &a)
void reset()
Reset the internal parse cursor to the beginning of argv.
Argz(int argc, char **argv)
Construct and immediately ingest argv.
Models a string-like class with indexing, concatenation, length, and value_type.
Holds the raw argv strings converted to the target String type.
ArgumentData(ArgumentData< String > &&a)
ArgumentData< String > & operator=(ArgumentData< String > &&a)
ArgumentData(const ArgumentData< String > &a)
ArgumentData & operator=(const ArgumentData< String > &a)
std::vector< String > args
Converted argv entries (argv[1] … argv[argc-1]).
int argc
Original argc value.
Describes a single parsed argument entry returned by Argz::proc().
int arg_letter
Short option code (e.g. 'o') or unique integer for long-only options.
Argument & operator=(const Argument< String > &a)
Argument(const Argument &a)
ArgType arg_type
Which ArgType variant this argument represents.
String arg_name
Long option name (e.g. "output").
auto operator<=>(const Argument< String > &a) const
String arg_value
Value string supplied after the option, if any.
String desc
Human-readable description used in help output.
Plain data structure returned by proc_args() with all common libmx2 CLI options.
std::string shaderPath
Optional SPV shader folder path (-S / --shader-path).
bool fullscreen
Whether fullscreen mode was requested.
std::string texture
Optional texture file path (--texture).
int height
Viewport height in pixels (default: 720).
std::string filename
Optional input filename (--filename).
std::string path
Asset search path (default: ".").
int width
Viewport width in pixels (default: 1280).