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 |
|
|
using namespace std; |
11 |
|
|
|
12 |
|
|
///Default constructor of Option |
13 |
|
|
/** @param longName : long name of the option |
14 |
|
|
* @param shortName : long name of the option |
15 |
|
|
* @param docString : documentation string of the Option |
16 |
|
|
*/ |
17 |
|
63 |
Option::Option(const std::string & longName, const std::string & shortName, const std::string & docString) |
18 |
✓✓✓✓
|
63 |
:p_longName(longName), p_shortName(shortName), p_value(""), p_isRequired(false), p_docString(docString) |
19 |
|
|
{ |
20 |
✓ |
63 |
initialisationOption(); |
21 |
|
63 |
} |
22 |
|
|
|
23 |
|
|
///Constructor of Option |
24 |
|
|
/** @param longName : long name of the option |
25 |
|
|
* @param shortName : long name of the option |
26 |
|
|
* @param value : value of the Option |
27 |
|
|
* @param docString : documentation string of the Option |
28 |
|
|
*/ |
29 |
|
|
Option::Option(const std::string & longName, const std::string & shortName, const OptionValue & value, const std::string & docString) |
30 |
|
|
:p_longName(longName), p_shortName(shortName), p_value(value), p_isRequired(false), p_docString(docString) |
31 |
|
|
{ |
32 |
|
|
initialisationOption(); |
33 |
|
|
} |
34 |
|
|
|
35 |
|
|
///Constructor of Option |
36 |
|
|
/** @param longName : long name of the option |
37 |
|
|
* @param shortName : long name of the option |
38 |
|
|
* @param value : value of the Option |
39 |
|
|
* @param isRequired : true if the option is required, false if it is optionnal |
40 |
|
|
* @param docString : documentation string of the Option |
41 |
|
|
*/ |
42 |
|
197 |
Option::Option(const std::string & longName, const std::string & shortName, const OptionValue & value, bool isRequired, const std::string & docString) |
43 |
✓✓✓ |
197 |
:p_longName(longName), p_shortName(shortName), p_value(value), p_isRequired(isRequired), p_docString(docString) |
44 |
|
|
{ |
45 |
✓ |
197 |
initialisationOption(); |
46 |
|
197 |
} |
47 |
|
|
|
48 |
|
|
///Constructor of Option |
49 |
|
|
/** @param longName : long name of the option |
50 |
|
|
* @param shortName : long name of the option |
51 |
|
|
* @param isRequired : true if the option is required, false if it is optionnal |
52 |
|
|
* @param docString : documentation string of the Option |
53 |
|
|
*/ |
54 |
|
2 |
Option::Option(const std::string & longName, const std::string & shortName, bool isRequired, const std::string & docString) |
55 |
✓✓✓ |
2 |
:p_longName(longName), p_shortName(shortName), p_isRequired(isRequired), p_docString(docString) |
56 |
|
|
{ |
57 |
✓ |
2 |
initialisationOption(); |
58 |
|
2 |
} |
59 |
|
|
|
60 |
|
|
///Copy constructor of Option |
61 |
|
|
/** @param other : class to copy |
62 |
|
|
*/ |
63 |
✓ |
463 |
Option::Option(const Option & other){ |
64 |
✓ |
463 |
copyOption(other); |
65 |
|
463 |
} |
66 |
|
|
|
67 |
|
|
///Destructeur of Option |
68 |
|
1262 |
Option::~Option(){ |
69 |
|
|
|
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
///Definition of equal operator of Option |
73 |
|
|
/** @param other : class to copy |
74 |
|
|
* @return copied class |
75 |
|
|
*/ |
76 |
|
62 |
Option & Option::operator = (const Option & other){ |
77 |
|
62 |
copyOption(other); |
78 |
|
62 |
return *this; |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
///Parse the current option with the given parser |
82 |
|
|
/** @param[out] parser : parser of the given arguments to the program |
83 |
|
|
* @return true on success, false otherwise |
84 |
|
|
*/ |
85 |
|
84 |
bool Option::parseOption(ArgParser & parser){ |
86 |
✓✓✓✓
|
84 |
if(parsePartOption(parser, "--", p_longName)){return true;} |
87 |
✓✓✓✓
|
55 |
else if(parsePartOption(parser, "-", p_shortName)){return true;} |
88 |
|
36 |
return false; |
89 |
|
|
} |
90 |
|
|
|
91 |
|
|
///Print a vector of value |
92 |
|
|
/** @param vecValue : vector of value to be ploted |
93 |
|
|
*/ |
94 |
|
8 |
void printVecString(const VecValue & vecValue){ |
95 |
✗✓ |
8 |
if(vecValue.size() == 0lu){return;} |
96 |
|
8 |
VecValue::const_iterator it(vecValue.begin()); |
97 |
✓ |
8 |
cout << *it; |
98 |
|
8 |
++it; |
99 |
✗✓ |
8 |
while(it != vecValue.end()){ |
100 |
|
|
cout << ", " << *it; |
101 |
|
|
++it; |
102 |
|
|
} |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
///Print an option |
106 |
|
|
/** @param indentation : indentation to print the option |
107 |
|
|
*/ |
108 |
|
34 |
void Option::print(const std::string & indentation) const{ |
109 |
|
34 |
OptionType::OptionType type(p_value.getType()); |
110 |
|
34 |
cout << indentation; |
111 |
✓✗ |
34 |
if(p_longName != ""){ |
112 |
|
34 |
cout << "--" << p_longName; |
113 |
✓✗ |
34 |
if(type != OptionType::NONE){ |
114 |
✓ |
34 |
cout << "=" << convertOptionTypeToString(type); |
115 |
|
|
} |
116 |
|
|
} |
117 |
✓✗ |
34 |
if(p_shortName != ""){ |
118 |
✓✗ |
34 |
if(p_longName != ""){cout << " , ";} |
119 |
|
34 |
cout << "-" << p_shortName; |
120 |
✓✗ |
34 |
if(type != OptionType::NONE){ |
121 |
✓ |
34 |
cout << " " << convertOptionTypeToString(type); |
122 |
|
|
} |
123 |
|
|
} |
124 |
✓✓ |
34 |
if(p_docString != ""){ |
125 |
|
8 |
cout << " : " << p_docString; |
126 |
|
|
} |
127 |
|
34 |
cout << endl; |
128 |
|
34 |
const VecValue & vecDefaultValue = p_value.getDefaultValue(); |
129 |
✓✓ |
34 |
if(vecDefaultValue.size()){ |
130 |
|
8 |
cout << indentation << "\tDefault value : "; |
131 |
|
8 |
printVecString(vecDefaultValue); |
132 |
|
8 |
cout << endl; |
133 |
|
|
} |
134 |
|
34 |
const VecValue & vecPossibleValue = p_value.getPossibleValue(); |
135 |
✗✓ |
34 |
if(vecPossibleValue.size()){ |
136 |
|
|
cout << indentation << "\tPossible values : "; |
137 |
|
|
printVecString(vecPossibleValue); |
138 |
|
|
cout << endl; |
139 |
|
|
} |
140 |
✓✓ |
34 |
if(p_isRequired){cout << indentation << "\tThis argument has to be set" << endl;} |
141 |
|
12 |
else{cout << indentation << "\tThis argument is optional" << endl;} |
142 |
|
34 |
} |
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 |
|
155 |
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 |
|
341 |
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 |
|
200 |
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 |
|
63 |
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 |
|
32 |
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 |
|
40 |
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 |
|
124 |
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 |
|
84 |
bool Option::checkArgument() const{ |
253 |
✓✓ |
84 |
if(p_isRequired){ |
254 |
✗✓ |
24 |
if(!p_isParsed){ |
255 |
|
|
OptionType::OptionType type(p_value.getType()); |
256 |
|
|
cerr << termRed() << "Missing arguement "; |
257 |
|
|
if(p_longName != ""){ |
258 |
|
|
cerr << "--" << p_longName; |
259 |
|
|
if(type != OptionType::NONE){ |
260 |
|
|
cout << "=" << convertOptionTypeToString(type); |
261 |
|
|
} |
262 |
|
|
} |
263 |
|
|
if(p_shortName != ""){ |
264 |
|
|
if(p_longName != ""){cerr << " , ";} |
265 |
|
|
cerr << "-" << p_shortName; |
266 |
|
|
if(type != OptionType::NONE){ |
267 |
|
|
cout << " " << convertOptionTypeToString(type); |
268 |
|
|
} |
269 |
|
|
} |
270 |
|
|
cerr << termDefault() << endl; |
271 |
|
|
} |
272 |
|
24 |
return p_isParsed; |
273 |
|
60 |
}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 |
|
525 |
void Option::copyOption(const Option & other){ |
316 |
|
525 |
p_longName = other.p_longName; |
317 |
|
525 |
p_shortName = other.p_shortName; |
318 |
|
525 |
p_value = other.p_value; |
319 |
|
525 |
p_isRequired = other.p_isRequired; |
320 |
|
525 |
p_docString = other.p_docString; |
321 |
|
525 |
p_isParsed = other.p_isParsed; |
322 |
|
525 |
p_firstPartParsedOption = other.p_firstPartParsedOption; |
323 |
|
525 |
p_isAllowEmpty = other.p_isAllowEmpty; |
324 |
|
525 |
} |
325 |
|
|
|
326 |
|
|
///Initialisation function of the class Option |
327 |
|
262 |
void Option::initialisationOption(){ |
328 |
|
262 |
p_isParsed = false; |
329 |
|
262 |
p_firstPartParsedOption = ""; |
330 |
|
262 |
p_isAllowEmpty = false; |
331 |
|
262 |
} |
332 |
|
|
|
333 |
|
|
///Parse the given option with the parser |
334 |
|
|
/** @param[out] parser : parser to be used |
335 |
|
|
* @param prefix : option prefix (- or -- or nothing) |
336 |
|
|
* @param optionName : name of hte option to be parsed |
337 |
|
|
* @return true on success, false otherwise |
338 |
|
|
*/ |
339 |
|
139 |
bool Option::parsePartOption(ArgParser & parser, const std::string & prefix, const std::string & optionName){ |
340 |
✓✗✓ |
139 |
if(parser.isEndOfOption()){return true;} |
341 |
✗✓ |
139 |
if(optionName == ""){return false;} |
342 |
✓ |
139 |
std::string & currentOption = parser.getCurrentOption(); |
343 |
✓ |
278 |
std::string longOption(prefix + optionName); |
344 |
|
139 |
size_t sizeLongOption(longOption.size()); |
345 |
✓ |
139 |
OptionType::OptionType optionType = p_value.getType(); |
346 |
✓✓ |
139 |
if(currentOption == longOption){ |
347 |
✓ |
35 |
checkAlreadyParsed(longOption); |
348 |
|
35 |
p_isParsed = true; |
349 |
✓✓ |
35 |
if(optionType == OptionType::NONE){ //No value expected |
350 |
✓ |
6 |
parser.getNextOption(); |
351 |
|
6 |
return true; //Option found |
352 |
|
|
} |
353 |
|
29 |
bool valueOk(true), isInitialised(false); |
354 |
✓ |
29 |
parser.getNextOption(); |
355 |
✓✓✓✓ ✓✓✓ |
60 |
while(!parser.isEndOfOption() && valueOk){ |
356 |
✓ |
31 |
std::string & currentOption = parser.getCurrentOption(); |
357 |
✓✓ |
31 |
if(currentOption == ""){ |
358 |
✓✗ |
1 |
if(optionType == OptionType::STRING){ |
359 |
✓✓ |
1 |
p_value.addValue(""); |
360 |
✓ |
1 |
parser.getNextOption(); |
361 |
|
1 |
valueOk = true; |
362 |
|
1 |
isInitialised = true; |
363 |
|
|
}else{ |
364 |
|
|
throw std::runtime_error("Option::parsePartOption : pass empty value to option '" + longOption + "' which does not expect STRING"); |
365 |
|
|
} |
366 |
|
|
}else{ |
367 |
✓✓✓ |
30 |
if(currentOption[0] == '-'){ |
368 |
|
4 |
valueOk = false; |
369 |
|
|
}else{ |
370 |
✓ |
26 |
p_value.addValue(currentOption); |
371 |
✓ |
26 |
parser.getNextOption(); |
372 |
|
26 |
valueOk = true; |
373 |
|
26 |
isInitialised = true; |
374 |
|
|
} |
375 |
|
|
} |
376 |
|
|
} |
377 |
✓✓✗✓
|
29 |
if(!isInitialised && !p_isAllowEmpty){ |
378 |
|
|
throw std::runtime_error("Option::parsePartOption : expect value after option '" + longOption + "'"); |
379 |
|
|
} |
380 |
✓✓✓✗
|
29 |
return isInitialised || p_isAllowEmpty; |
381 |
✓✓✓ |
104 |
}else if(isSameBegining(currentOption, longOption)){ |
382 |
✓✓✗ |
13 |
if(currentOption[sizeLongOption] == '='){ |
383 |
✗✓ |
13 |
if(optionType == OptionType::NONE){ //No value expected |
384 |
|
|
throw std::runtime_error("Option::parsePartOption : the option '"+currentOption+"' does not have value"); |
385 |
|
|
} |
386 |
✗✓ |
13 |
if(currentOption.size() == sizeLongOption + 1lu){ |
387 |
|
|
p_firstPartParsedOption = longOption + "="; |
388 |
|
|
throw std::runtime_error("Option::parsePartOption : problem with the option '"+currentOption+"' because it ends with a '=' and not a value"); |
389 |
|
|
//Ici il faut un mode qui renvoie quand même les valeurs possibles quand on a --option=... |
390 |
|
|
} |
391 |
✓ |
13 |
checkAlreadyParsed(longOption); |
392 |
✓ |
13 |
std::string value(currentOption.substr(sizeLongOption + 1lu)); |
393 |
✓ |
13 |
p_value.addValue(value); |
394 |
|
13 |
p_isParsed = true; |
395 |
✓ |
13 |
parser.getNextOption(); |
396 |
|
13 |
return true; |
397 |
|
|
}else{ |
398 |
|
|
return false; //It is an option with a longer name |
399 |
|
|
} |
400 |
|
|
} |
401 |
|
91 |
return false; |
402 |
|
|
} |
403 |
|
|
|
404 |
|
|
///Check if the Option has been already parsed |
405 |
|
|
/** @param longOption : used option |
406 |
|
|
*/ |
407 |
|
48 |
void Option::checkAlreadyParsed(const std::string & longOption){ |
408 |
✗✓ |
48 |
if(p_isParsed){ //The option has already been parsed, there is a mistake |
409 |
|
|
throw std::runtime_error("Option::checkAlreadyParsed : option '" + longOption + "' already exists"); |
410 |
|
|
} |
411 |
|
48 |
} |
412 |
|
|
|
413 |
|
|
|
414 |
|
|
|
415 |
|
|
|