GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/OptionParser/src/Option.cpp Lines: 159 187 85.0 %
Date: 2024-12-09 15:30:52 Branches: 117 202 57.9 %

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
///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