-
Notifications
You must be signed in to change notification settings - Fork 3
/
ArgumentParse.h
143 lines (135 loc) · 4.22 KB
/
ArgumentParse.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once
// process command line options
// example of two argument option:
// procFlag("-x", arglist, option1, option2); // arglist=vector<strings), option1= first variable, option2=second variable
// variables may be either strings, ints, doubles, or bools. Bools do not remove an argument but set option variable to true
// other variables are set with converted argument strings which are then removed
#include <vector>
#include <string>
#include <type_traits>
namespace ArgHelp {
static void fixup(const std::string &argcmd, bool& arg) {} // dummy, bool variable set by procFlag(), no arg consumed
static void fixup(const std::string &argcmd, std::string &arg) { arg = argcmd; }
template<class T>
std::enable_if_t<std::is_floating_point<T>::value>
static fixup(const std::string &argcmd, T& arg) { arg = static_cast<T>(stod(argcmd)); }
template<class T>
std::enable_if_t<std::is_integral<T>::value>
static fixup(const std::string &argcmd, T& arg) { arg = stoi(argcmd); }
template<class T>
static void procVal(std::vector<std::string>& arglist, size_t idx, T& arg)
{
fixup(arglist[idx], arg);
arglist.erase(arglist.begin() + idx);
}
static void procVal(std::vector<std::string>&, size_t) {} // nothing more to do, end option search
template<class T, class ...TA>
static void procVal(std::vector<std::string>& arglist, int idx, T& arg, TA&...argv)
{
procVal(arglist, idx, arg); // process an argument
procVal(arglist, idx, argv...); // then process another argument
}
}
template<class T, class ...TA>
static bool procFlag(const char *pc, std::vector<std::string>& arglist, T& arg1, TA&...argv)
{
using namespace ArgHelp;
std::string flag(pc);
if (flag[0] != '-' || flag.length() != 2)
throw std::invalid_argument(flag);
// bools may be concatenated, remove if a match is found
if (std::is_same<bool, T>::value)
{
for (size_t i = 0; i < arglist.size(); i++)
{
if (arglist[i][0] == '-') // may be flag or negative numerical argument
{
for (size_t ii = 1; ii < arglist[i].length(); ii++)
{
if (arglist[i][ii] == flag[1])
{
arg1 = true;
if (arglist[i].length() == 2)
arglist.erase(arglist.begin() + i);
else
arglist[i].erase(ii,1);
return true;
}
}
}
}
}
for (size_t i = 0; i < arglist.size(); i++)
{
if (arglist[i] == flag)
{
arglist.erase(arglist.begin() + i);
procVal(arglist, i, arg1); // process one argument after flag
procVal(arglist, i, argv...); // process more arguments, if any, after flag
return true;
}
}
return false;
}
#if 0
// ArgumentParse Test
bool procFlagTest()
{
int pass = 0;
{
vector<string> args{
"-abc",
"-x", "3.0",
"-de",
"-s", "Hello There",
"-y", "4.5", "4.6",
"-z", "100",
"-f"
};
bool a, b, c, d, e, f;
int z1;
float x1;
double y1, y2;
string s;
procFlag("-a", args, a);
procFlag("-b", args, b);
procFlag("-c", args, c);
procFlag("-d", args, d);
procFlag("-s", args, s);
procFlag("-e", args, e);
procFlag("-x", args, x1);
procFlag("-f", args, f);
procFlag("-y", args, y1, y2);
procFlag("-z", args, z1);
pass++;
}
{
vector<string> args{
"-s", "Hello There",
"-abc",
"-x", "3.0",
"-de",
"-y", "4.5", "4.6",
"-z", "100",
"-f"
};
bool a, b, c, d, e, f;
int z1;
float x1;
double y1, y2;
string s;
procFlag("-y", args, y1, y2);
procFlag("-z", args, z1);
procFlag("-b", args, b);
procFlag("-s", args, s);
procFlag("-c", args, c);
procFlag("-a", args, a);
procFlag("-d", args, d);
procFlag("-e", args, e);
procFlag("-x", args, x1);
procFlag("-f", args, f);
pass++;
}
return true;
}
#endif