-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcommandline.cpp
214 lines (200 loc) · 7.67 KB
/
commandline.cpp
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//
// Created by nbollom on 30/05/16.
//
#include "commandline.hpp"
#include "commandlineexeptions.hpp"
#include <iostream>
#include <utility>
inline unsigned long max(const unsigned long &a, const unsigned long &b) {
if (a > b) {
return a;
}
return b;
}
inline std::string pad(const unsigned long length) {
return std::string(length, ' ');
}
CommandLineProcessor::CommandLineProcessor(string program_name, string program_description, string program_version)
: name(std::move(program_name)), description(std::move(program_description)), version(std::move(program_version)) {
options.push_back(make_shared<Option>('h', "help", "Shows this help screen", false, "", false, ""));
options.push_back(make_shared<Option>('v', "version", "prints the version", false, "", false, ""));
}
void CommandLineProcessor::AddOption(const char shortName, const string& longName, const string& description, const bool hasValue, const string& valueDescription, const string& defaultValue) {
const auto option = make_shared<Option>(shortName, longName, description, hasValue, valueDescription, false, defaultValue);
for (const auto& existingOption : options) {
if (option->shortName == existingOption->shortName || option->longName == existingOption->longName) {
throw OptionExistsException(option, existingOption);
}
}
options.push_back(option);
}
void CommandLineProcessor::AddValueOnlyOption(const string& name, const string& description, const string& defaultValue) {
const auto option = make_shared<ValueOption>(name, description, defaultValue);
for (const auto& existingOption : values) {
if (option->name == existingOption->name) {
throw ValueOptionExistsException(option, existingOption);
}
}
values.push_back(option);
}
bool CommandLineProcessor::Parse(const int argc, const char *const *argv) {
const string executable = argv[0];
bool parsingValueOptions = false;
auto currentValueOption = values.begin();
for (int i = 1; i < argc; ++i) {
string val = argv[i];
if (!parsingValueOptions && val.front() == '-') {
if (val.length() < 2) {
throw InvalidArgumentException(val);
}
shared_ptr<Option> option;
string option_str;
if (val[1] == '-') { //long option
option_str = val.substr(2);
option = GetOptionByLongName(option_str);
}
else { // short option
option_str = val.substr(1);
option = GetOptionByShortName(option_str[0]);
}
if (option == nullptr) {
throw UnknownArgumentException(option_str);
}
option->found = true;
if (option->shortName == 'h') {
std::cout << name << "(" << version << ")\n";
std::cout << description << "\n";
options.sort([](const shared_ptr<Option>& a, const shared_ptr<Option>& b){
return a->shortName < b->shortName;
});
std::string usage_str;
std::string option_usage_str;
unsigned long longest_name = 0;
for (const auto &op : options) {
if (op->hasValue) {
option_usage_str += " -";
option_usage_str += op->shortName;
option_usage_str += " <";
option_usage_str += op->longName;
option_usage_str += ">";
}
else {
usage_str += op->shortName;
}
longest_name = max(longest_name, op->longName.length());
}
std::string value_usage_str;
for (const auto &op: values) {
if (!value_usage_str.empty()) {
value_usage_str += " ";
}
value_usage_str += "[" + op->name + "]";
}
std::cout << "Usage: " << executable << " [-" << usage_str << option_usage_str << "] " + value_usage_str + "\n\n";
for (const auto &op : options) {
std::cout << "\t-" << op->shortName << "\t--" << op->longName << pad(longest_name - op->longName.length()) << "\t" << op->description << "\n";
if (op->hasValue) {
std::cout << "\t\t" << pad(longest_name + 2) << "\t" << op->valueDescription;
if (!op->value.empty()) {
std::cout << " (Default: " << op->value << ")\n";
}
else {
std::cout << "\n";
}
}
}
std::cout << "\n";
for (const auto &op : values) {
std::cout << "\t" << op->name << "\t\t" << op->description << "\n";
}
std::cout << "\n";
return false;
}
if (option->shortName == 'v') {
std::cout << name << "\n";
std::cout << "Version: " << version << "\n";
return false;
}
if (option->hasValue) {
if (++i < argc) { // not the end of the parameters yet
string optionValue = argv[i];
if (optionValue.front() == '-') {
throw MissingValueException(option_str, option);
}
else {
option->value = optionValue;
}
}
else {
throw MissingValueException(option_str, option);
}
}
}
else {
parsingValueOptions = true;
if (currentValueOption == values.end()) {
throw UnknownArgumentException(val);
}
(*currentValueOption)->value = val;
++currentValueOption;
}
}
return true;
}
bool CommandLineProcessor::IsSet(const char shortName) {
const auto option = GetOptionByShortName(shortName);
if (option == nullptr) {
return false;
}
return option->found;
}
bool CommandLineProcessor::IsSet(const string &longName) {
const auto option = GetOptionByLongName(longName);
if (option == nullptr) {
return false;
}
return option->found;
}
string CommandLineProcessor::GetOptionValue(const char shortName) {
const auto option = GetOptionByShortName(shortName);
if (option == nullptr) {
return "";
}
return option->value;
}
string CommandLineProcessor::GetOptionValue(const string &longName) {
const auto option = GetOptionByLongName(longName);
if (option == nullptr) {
return "";
}
return option->value;
}
string CommandLineProcessor::GetValueOnlyOptionValue(const string& name) const {
shared_ptr<ValueOption> option = nullptr;
for (const auto & value : values) {
if (value->name == name) {
option = value;
break;
}
}
if (option == nullptr) {
return "";
}
return option->value;
}
shared_ptr<Option> CommandLineProcessor::GetOptionByShortName(const char shortName) {
for (auto &option : options) {
if (option->shortName == shortName) {
return option;
}
}
return nullptr;
}
shared_ptr<Option> CommandLineProcessor::GetOptionByLongName(const string& longName) {
for (auto &option : options) {
if (option->longName == longName) {
return option;
}
}
return nullptr;
}