GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/OptionParser/src/Option.cpp Lines: 157 184 85.3 %
Date: 2023-10-11 10:52:07 Branches: 117 203 57.6 %

Line Branch Exec Source
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