1 |
|
|
/*************************************** |
2 |
|
|
Auteur : Pierre Aubert |
3 |
|
|
Mail : pierre.aubert@lapp.in2p3.fr |
4 |
|
|
Licence : CeCILL-C |
5 |
|
|
****************************************/ |
6 |
|
|
|
7 |
|
|
#include "string_utils.h" |
8 |
|
|
#include "Option.h" |
9 |
|
|
|
10 |
|
|
///Default constructor of Option |
11 |
|
|
/** @param longName : long name of the option |
12 |
|
|
* @param shortName : long name of the option |
13 |
|
|
* @param docString : documentation string of the Option |
14 |
|
|
*/ |
15 |
|
51 |
Option::Option(const std::string & longName, const std::string & shortName, const std::string & docString) |
16 |
✓✓✓✓
|
51 |
:p_longName(longName), p_shortName(shortName), p_value(""), p_isRequired(false), p_docString(docString) |
17 |
|
|
{ |
18 |
✓ |
51 |
initialisationOption(); |
19 |
|
51 |
} |
20 |
|
|
|
21 |
|
|
///Constructor of Option |
22 |
|
|
/** @param longName : long name of the option |
23 |
|
|
* @param shortName : long name of the option |
24 |
|
|
* @param value : value of the Option |
25 |
|
|
* @param docString : documentation string of the Option |
26 |
|
|
*/ |
27 |
|
|
Option::Option(const std::string & longName, const std::string & shortName, const OptionValue & value, const std::string & docString) |
28 |
|
|
:p_longName(longName), p_shortName(shortName), p_value(value), p_isRequired(false), p_docString(docString) |
29 |
|
|
{ |
30 |
|
|
initialisationOption(); |
31 |
|
|
} |
32 |
|
|
|
33 |
|
|
///Constructor of Option |
34 |
|
|
/** @param longName : long name of the option |
35 |
|
|
* @param shortName : long name of the option |
36 |
|
|
* @param value : value of the Option |
37 |
|
|
* @param isRequired : true if the option is required, false if it is optionnal |
38 |
|
|
* @param docString : documentation string of the Option |
39 |
|
|
*/ |
40 |
|
183 |
Option::Option(const std::string & longName, const std::string & shortName, const OptionValue & value, bool isRequired, const std::string & docString) |
41 |
✓✓✓ |
183 |
:p_longName(longName), p_shortName(shortName), p_value(value), p_isRequired(isRequired), p_docString(docString) |
42 |
|
|
{ |
43 |
✓ |
183 |
initialisationOption(); |
44 |
|
183 |
} |
45 |
|
|
|
46 |
|
|
///Constructor of Option |
47 |
|
|
/** @param longName : long name of the option |
48 |
|
|
* @param shortName : long name of the option |
49 |
|
|
* @param isRequired : true if the option is required, false if it is optionnal |
50 |
|
|
* @param docString : documentation string of the Option |
51 |
|
|
*/ |
52 |
|
2 |
Option::Option(const std::string & longName, const std::string & shortName, bool isRequired, const std::string & docString) |
53 |
✓✓✓ |
2 |
:p_longName(longName), p_shortName(shortName), p_isRequired(isRequired), p_docString(docString) |
54 |
|
|
{ |
55 |
✓ |
2 |
initialisationOption(); |
56 |
|
2 |
} |
57 |
|
|
|
58 |
|
|
///Copy constructor of Option |
59 |
|
|
/** @param other : class to copy |
60 |
|
|
*/ |
61 |
✓ |
419 |
Option::Option(const Option & other){ |
62 |
✓ |
419 |
copyOption(other); |
63 |
|
419 |
} |
64 |
|
|
|
65 |
|
|
///Destructeur of Option |
66 |
|
1114 |
Option::~Option(){ |
67 |
|
|
|
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
///Definition of equal operator of Option |
71 |
|
|
/** @param other : class to copy |
72 |
|
|
* @return copied class |
73 |
|
|
*/ |
74 |
|
50 |
Option & Option::operator = (const Option & other){ |
75 |
|
50 |
copyOption(other); |
76 |
|
50 |
return *this; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
///Parse the current option with the given parser |
80 |
|
|
/** @param[out] parser : parser of the given arguments to the program |
81 |
|
|
* @return true on success, false otherwise |
82 |
|
|
*/ |
83 |
|
69 |
bool Option::parseOption(ArgParser & parser){ |
84 |
✓✓✓✓
|
73 |
if(parsePartOption(parser, "--", p_longName)){return true;} |
85 |
✓✓✓✓
|
47 |
else if(parsePartOption(parser, "-", p_shortName)){return true;} |
86 |
|
22 |
return false; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
///Print a vector of value |
90 |
|
|
/** @param vecValue : vector of value to be ploted |
91 |
|
|
*/ |
92 |
|
9 |
void printVecString(const VecValue & vecValue){ |
93 |
✗✓ |
9 |
if(vecValue.size() == 0lu){return;} |
94 |
|
9 |
VecValue::const_iterator it(vecValue.begin()); |
95 |
✓ |
9 |
std::cout << *it; |
96 |
|
9 |
++it; |
97 |
✗✓ |
9 |
while(it != vecValue.end()){ |
98 |
|
|
std::cout << ", " << *it; |
99 |
|
|
++it; |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
|
103 |
|
|
///Print an option |
104 |
|
|
/** @param indentation : indentation to print the option |
105 |
|
|
*/ |
106 |
|
38 |
void Option::print(const std::string & indentation) const{ |
107 |
|
38 |
OptionType::OptionType type(p_value.getType()); |
108 |
|
38 |
std::cout << indentation; |
109 |
✓✗ |
38 |
if(p_longName != ""){ |
110 |
|
38 |
std::cout << "--" << p_longName; |
111 |
✓✓ |
38 |
if(type != OptionType::NONE){ |
112 |
✓ |
37 |
std::cout << "=" << convertOptionTypeToString(type); |
113 |
|
|
} |
114 |
|
|
} |
115 |
✓✗ |
38 |
if(p_shortName != ""){ |
116 |
✓✗ |
38 |
if(p_longName != ""){std::cout << " , ";} |
117 |
|
38 |
std::cout << "-" << p_shortName; |
118 |
✓✓ |
38 |
if(type != OptionType::NONE){ |
119 |
✓ |
37 |
std::cout << " " << convertOptionTypeToString(type); |
120 |
|
|
} |
121 |
|
|
} |
122 |
✓✗ |
38 |
if(p_docString != ""){ |
123 |
|
38 |
std::cout << " : " << p_docString; |
124 |
|
|
} |
125 |
|
38 |
std::cout << std::endl; |
126 |
|
38 |
const VecValue & vecDefaultValue = p_value.getDefaultValue(); |
127 |
✓✓ |
38 |
if(vecDefaultValue.size()){ |
128 |
|
9 |
std::cout << indentation << "\tDefault value : '"; |
129 |
|
9 |
printVecString(vecDefaultValue); |
130 |
|
9 |
std::cout << "'" << std::endl; |
131 |
|
|
} |
132 |
|
38 |
const VecValue & vecPossibleValue = p_value.getPossibleValue(); |
133 |
✗✓ |
38 |
if(vecPossibleValue.size()){ |
134 |
|
|
std::cout << indentation << "\tPossible values : "; |
135 |
|
|
printVecString(vecPossibleValue); |
136 |
|
|
std::cout << std::endl; |
137 |
|
|
} |
138 |
✗✓ |
38 |
if(p_isRequired){std::cout << indentation << "\tThis argument has to be set" << std::endl;} |
139 |
|
38 |
else{std::cout << indentation << "\tThis argument is optional" << std::endl;} |
140 |
✗✓ |
38 |
if(p_isAllowEmpty){std::cout << indentation << "\tThis argument can have an empty value" << std::endl;} |
141 |
|
38 |
else{std::cout << indentation << "\tThis argument cannot have an empty value" << std::endl;} |
142 |
|
38 |
} |
143 |
|
|
|
144 |
|
|
///Set the long name of the option |
145 |
|
|
/** @param longName : long name of the option |
146 |
|
|
*/ |
147 |
|
1 |
void Option::setLongName(const std::string & longName){p_longName = longName;} |
148 |
|
|
|
149 |
|
|
///Set the short name of the option |
150 |
|
|
/** @param shortName : short name of the option |
151 |
|
|
*/ |
152 |
|
1 |
void Option::setShortName(const std::string & shortName){p_shortName = shortName;} |
153 |
|
|
|
154 |
|
|
///Set the value of the option |
155 |
|
|
/** @param value : value name of the option |
156 |
|
|
*/ |
157 |
|
1 |
void Option::setValue(const OptionValue & value){p_value = value;} |
158 |
|
|
|
159 |
|
|
///Set if the option is required |
160 |
|
|
/** @param isRequired : true if the Option is required, false if it is optionnal |
161 |
|
|
*/ |
162 |
|
1 |
void Option::setIsRequired(bool isRequired){p_isRequired = isRequired;} |
163 |
|
|
|
164 |
|
|
///Set the documentation string of the Option |
165 |
|
|
/** @param docString : documentation string of the Option |
166 |
|
|
*/ |
167 |
|
1 |
void Option::setDocString(const std::string & docString){p_docString = docString;} |
168 |
|
|
|
169 |
|
|
///Say if the Option has been parsed or not |
170 |
|
|
/** @param isParsed : true if the Option has been parsed, false if not |
171 |
|
|
*/ |
172 |
|
1 |
void Option::setIsParsed(bool isParsed){p_isParsed = isParsed;} |
173 |
|
|
|
174 |
|
|
///Say if the option can be empty or not |
175 |
|
|
/** @param isAllowEmpty : true if the option can be empty, false otherwise |
176 |
|
|
*/ |
177 |
|
130 |
void Option::setIsAllowEmpty(bool isAllowEmpty){p_isAllowEmpty = isAllowEmpty;} |
178 |
|
|
|
179 |
|
|
///Get the long name of the Option |
180 |
|
|
/** @return long name of the Option |
181 |
|
|
*/ |
182 |
|
197 |
const std::string & Option::getLongName() const{return p_longName;} |
183 |
|
|
|
184 |
|
|
///Get the long name of the Option |
185 |
|
|
/** @return long name of the Option |
186 |
|
|
*/ |
187 |
|
1 |
std::string & Option::getLongName(){return p_longName;} |
188 |
|
|
|
189 |
|
|
///Get the short name of the Option |
190 |
|
|
/** @return short name of the Option |
191 |
|
|
*/ |
192 |
|
103 |
const std::string & Option::getShortName() const{return p_shortName;} |
193 |
|
|
|
194 |
|
|
///Get the short name of the Option |
195 |
|
|
/** @return short name of the Option |
196 |
|
|
*/ |
197 |
|
1 |
std::string & Option::getShortName(){return p_shortName;} |
198 |
|
|
|
199 |
|
|
///Get the value of the Option |
200 |
|
|
/** @return value of the Option |
201 |
|
|
*/ |
202 |
|
3 |
const OptionValue & Option::getValue() const{return p_value;} |
203 |
|
|
|
204 |
|
|
///Get the value of the Option |
205 |
|
|
/** @return value of the Option |
206 |
|
|
*/ |
207 |
|
51 |
OptionValue & Option::getValue(){return p_value;} |
208 |
|
|
|
209 |
|
|
///Get if the option is required |
210 |
|
|
/** @return true if the Option is required, false if it is optionnal |
211 |
|
|
*/ |
212 |
|
3 |
bool Option::isRequired() const{return p_isRequired;} |
213 |
|
|
|
214 |
|
|
///Get if the option is required |
215 |
|
|
/** @return true if the Option is required, false if it is optionnal |
216 |
|
|
*/ |
217 |
|
19 |
bool & Option::isRequired(){return p_isRequired;} |
218 |
|
|
|
219 |
|
|
///Get if the option value can be empty |
220 |
|
|
/** @return true if the option value can be empty, false otherwise |
221 |
|
|
*/ |
222 |
|
3 |
bool Option::isAllowEmpty() const{return p_isAllowEmpty;} |
223 |
|
|
|
224 |
|
|
///Get if the option value can be empty |
225 |
|
|
/** @return true if the option value can be empty, false otherwise |
226 |
|
|
*/ |
227 |
|
1 |
bool & Option::isAllowEmpty(){return p_isAllowEmpty;} |
228 |
|
|
|
229 |
|
|
///Get the documentation string of the Option |
230 |
|
|
/** @return documentation string of the Option |
231 |
|
|
*/ |
232 |
|
3 |
const std::string & Option::getDocString() const{return p_docString;} |
233 |
|
|
|
234 |
|
|
///Get the documentation string of the Option |
235 |
|
|
/** @return documentation string of the Option |
236 |
|
|
*/ |
237 |
|
1 |
std::string & Option::getDocString(){return p_docString;} |
238 |
|
|
|
239 |
|
|
///Say if the Option has been parsed or not |
240 |
|
|
/** @return true if the Option has been parsed, false if not |
241 |
|
|
*/ |
242 |
|
5 |
bool Option::isParsed() const{return p_isParsed;} |
243 |
|
|
|
244 |
|
|
///Say if the Option has been parsed or not |
245 |
|
|
/** @return true if the Option has been parsed, false if not |
246 |
|
|
*/ |
247 |
|
100 |
bool & Option::isParsed(){return p_isParsed;} |
248 |
|
|
|
249 |
|
|
///Check the argument of the parser |
250 |
|
|
/** @return true if the arguments is required and is set, false otherwise |
251 |
|
|
*/ |
252 |
|
66 |
bool Option::checkArgument() const{ |
253 |
✗✓ |
66 |
if(p_isRequired){ |
254 |
|
|
if(!p_isParsed){ |
255 |
|
|
OptionType::OptionType type(p_value.getType()); |
256 |
|
|
std::cerr << termRed() << "Missing arguement "; |
257 |
|
|
if(p_longName != ""){ |
258 |
|
|
std::cerr << "--" << p_longName; |
259 |
|
|
if(type != OptionType::NONE){ |
260 |
|
|
std::cout << "=" << convertOptionTypeToString(type); |
261 |
|
|
} |
262 |
|
|
} |
263 |
|
|
if(p_shortName != ""){ |
264 |
|
|
if(p_longName != ""){std::cerr << " , ";} |
265 |
|
|
std::cerr << "-" << p_shortName; |
266 |
|
|
if(type != OptionType::NONE){ |
267 |
|
|
std::cout << " " << convertOptionTypeToString(type); |
268 |
|
|
} |
269 |
|
|
} |
270 |
|
|
std::cerr << termDefault() << std::endl; |
271 |
|
|
} |
272 |
|
|
return p_isParsed; |
273 |
|
66 |
}else{return true;} |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
///Get the possible options for the bash completion |
277 |
|
|
/** @param[out] possibleOption : possible options for the bash completion |
278 |
|
|
* @param cursorOption : option of the cursor which is currently completed |
279 |
|
|
*/ |
280 |
|
27 |
void Option::getPossibleOption(std::string & possibleOption, const std::string & cursorOption) const{ |
281 |
✓✓ |
27 |
if(p_isParsed){return;} |
282 |
✓✗ |
23 |
if(p_longName != ""){ |
283 |
✓ |
46 |
std::string longOption("--" + p_longName); |
284 |
✓✓ |
23 |
if(cursorOption == ""){ |
285 |
✓✓ |
5 |
possibleOption += longOption + " "; |
286 |
|
|
}else{ |
287 |
✓✓✓ |
18 |
if(isSameBegining(longOption, cursorOption)){ |
288 |
✓✓ |
16 |
possibleOption += longOption + " "; |
289 |
|
|
} |
290 |
|
|
} |
291 |
|
|
} |
292 |
✓✗ |
23 |
if(p_shortName != ""){ |
293 |
✓ |
46 |
std::string shortOption("-" + p_shortName); |
294 |
✓✓ |
23 |
if(cursorOption == ""){ |
295 |
✓✓ |
5 |
possibleOption += shortOption + " "; |
296 |
|
|
}else{ |
297 |
✓✓✓ |
18 |
if(isSameBegining(shortOption, cursorOption)){ |
298 |
✓✓ |
4 |
possibleOption += shortOption + " "; |
299 |
|
|
} |
300 |
|
|
} |
301 |
|
|
} |
302 |
|
|
} |
303 |
|
|
|
304 |
|
|
///Complete the possible values of the Option |
305 |
|
|
/** @param[out] possibleValue : possible value of the option |
306 |
|
|
* @param cursorOption : option of the cursor which is currently completed |
307 |
|
|
*/ |
308 |
|
8 |
void Option::getPossibleValue(std::string & possibleValue, const std::string & cursorOption) const{ |
309 |
|
8 |
p_value.bashCompletionValue(possibleValue, cursorOption); |
310 |
|
8 |
} |
311 |
|
|
|
312 |
|
|
///Copy function of Option |
313 |
|
|
/** @param other : class to copy |
314 |
|
|
*/ |
315 |
|
469 |
void Option::copyOption(const Option & other){ |
316 |
|
469 |
p_longName = other.p_longName; |
317 |
|
469 |
p_shortName = other.p_shortName; |
318 |
|
469 |
p_value = other.p_value; |
319 |
|
469 |
p_isRequired = other.p_isRequired; |
320 |
|
469 |
p_docString = other.p_docString; |
321 |
|
469 |
p_isParsed = other.p_isParsed; |
322 |
|
469 |
p_firstPartParsedOption = other.p_firstPartParsedOption; |
323 |
|
469 |
p_isAllowEmpty = other.p_isAllowEmpty; |
324 |
|
469 |
} |
325 |
|
|
|
326 |
|
|
///Initialisation function of the class Option |
327 |
|
236 |
void Option::initialisationOption(){ |
328 |
|
236 |
p_isParsed = false; |
329 |
|
236 |
p_isRequired = false; |
330 |
|
236 |
p_firstPartParsedOption = ""; |
331 |
|
236 |
p_isAllowEmpty = false; |
332 |
|
236 |
} |
333 |
|
|
|
334 |
|
|
///Parse the given option with the parser |
335 |
|
|
/** @param[out] parser : parser to be used |
336 |
|
|
* @param prefix : option prefix (- or -- or nothing) |
337 |
|
|
* @param optionName : name of hte option to be parsed |
338 |
|
|
* @return true on success, false otherwise |
339 |
|
|
*/ |
340 |
|
116 |
bool Option::parsePartOption(ArgParser & parser, const std::string & prefix, const std::string & optionName){ |
341 |
✓✗✓ |
116 |
if(parser.isEndOfOption()){return true;} |
342 |
✗✓ |
116 |
if(optionName == ""){return false;} |
343 |
✓ |
116 |
std::string & currentOption = parser.getCurrentOption(); |
344 |
✓ |
232 |
std::string longOption(prefix + optionName); |
345 |
|
116 |
size_t sizeLongOption(longOption.size()); |
346 |
✓ |
116 |
OptionType::OptionType optionType = p_value.getType(); |
347 |
✓✓ |
116 |
if(currentOption == longOption){ |
348 |
✓ |
34 |
checkAlreadyParsed(longOption); |
349 |
|
34 |
p_isParsed = true; |
350 |
✓✓ |
34 |
if(optionType == OptionType::NONE){ //No value expected |
351 |
✓ |
2 |
parser.getNextOption(); |
352 |
|
2 |
return true; //Option found |
353 |
|
|
} |
354 |
|
32 |
bool valueOk(true), isInitialised(false); |
355 |
✓ |
32 |
parser.getNextOption(); |
356 |
✓✓✓✓ ✓✓✓ |
72 |
while(!parser.isEndOfOption() && valueOk){ |
357 |
✓ |
40 |
std::string & currentOption = parser.getCurrentOption(); |
358 |
✓✓ |
40 |
if(currentOption == ""){ |
359 |
✓✗ |
1 |
if(optionType == OptionType::STRING){ |
360 |
✓✓ |
1 |
p_value.addValue(""); |
361 |
✓ |
1 |
parser.getNextOption(); |
362 |
|
1 |
valueOk = true; |
363 |
|
1 |
isInitialised = true; |
364 |
|
|
}else{ |
365 |
|
|
throw std::runtime_error("Option::parsePartOption : pass empty value to option '" + longOption + "' which does not expect STRING"); |
366 |
|
|
} |
367 |
|
|
}else{ |
368 |
✓✓✓ |
39 |
if(currentOption[0] == '-'){ |
369 |
|
4 |
valueOk = false; |
370 |
|
|
}else{ |
371 |
✓ |
35 |
p_value.addValue(currentOption); |
372 |
✓ |
35 |
parser.getNextOption(); |
373 |
|
35 |
valueOk = true; |
374 |
|
35 |
isInitialised = true; |
375 |
|
|
} |
376 |
|
|
} |
377 |
|
|
} |
378 |
✓✓✓✗
|
32 |
if(!isInitialised && !p_isAllowEmpty){ |
379 |
✓✓✓ |
2 |
throw std::runtime_error("Option::parsePartOption : expect value after option '" + longOption + "'"); |
380 |
|
|
} |
381 |
✗✓✗✗
|
30 |
return isInitialised || p_isAllowEmpty; |
382 |
✓✓✓ |
82 |
}else if(isSameBegining(currentOption, longOption)){ |
383 |
✓✓✗ |
13 |
if(currentOption[sizeLongOption] == '='){ |
384 |
✗✓ |
13 |
if(optionType == OptionType::NONE){ //No value expected |
385 |
|
|
throw std::runtime_error("Option::parsePartOption : the option '"+currentOption+"' does not have value"); |
386 |
|
|
} |
387 |
✗✓ |
13 |
if(currentOption.size() == sizeLongOption + 1lu){ |
388 |
|
|
p_firstPartParsedOption = longOption + "="; |
389 |
|
|
throw std::runtime_error("Option::parsePartOption : problem with the option '"+currentOption+"' because it ends with a '=' and not a value"); |
390 |
|
|
//Ici il faut un mode qui renvoie quand même les valeurs possibles quand on a --option=... |
391 |
|
|
} |
392 |
✓ |
13 |
checkAlreadyParsed(longOption); |
393 |
✓ |
13 |
std::string value(currentOption.substr(sizeLongOption + 1lu)); |
394 |
✓ |
13 |
p_value.addValue(value); |
395 |
|
13 |
p_isParsed = true; |
396 |
✓ |
13 |
parser.getNextOption(); |
397 |
|
13 |
return true; |
398 |
|
|
}else{ |
399 |
|
|
return false; //It is an option with a longer name |
400 |
|
|
} |
401 |
|
|
} |
402 |
|
69 |
return false; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
///Check if the Option has been already parsed |
406 |
|
|
/** @param longOption : used option |
407 |
|
|
*/ |
408 |
|
47 |
void Option::checkAlreadyParsed(const std::string & longOption){ |
409 |
✗✓ |
47 |
if(p_isParsed){ //The option has already been parsed, there is a mistake |
410 |
|
|
throw std::runtime_error("Option::checkAlreadyParsed : option '" + longOption + "' already exists"); |
411 |
|
|
} |
412 |
|
47 |
} |
413 |
|
|
|
414 |
|
|
|
415 |
|
|
|
416 |
|
|
|