GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/FileParser/src/parser_yml.cpp Lines: 182 197 92.4 %
Date: 2023-10-11 10:52:07 Branches: 244 367 66.5 %

Line Branch Exec Source
1
/***************************************
2
	Auteur : Pierre Aubert
3
	Mail : pierre.aubert@lapp.in2p3.fr
4
	Licence : CeCILL-C
5
****************************************/
6
7
#include "PFileParser.h"
8
#include "vec_value_utils.h"
9
10
#include "parser_yml.h"
11
12
///Convert the configuration of the cleaning type into a bool
13
/**	@param strConfig : configuration string
14
 * 	@return corresponding value
15
*/
16
1
bool phoenix_convertBoolType(const std::string & strConfig){
17
1
	std::string config(strToLower(strConfig));
18

2
	return config == "true" || strConfig == "1" || config == "yes";
19
}
20
21
///Get bool value from a dictionnary
22
/**	@param dico : dictionnary to be used
23
 * 	@param varName : name of the variable to be used
24
 * 	@param defaultValue : default value
25
 * 	@return loaded value or default value
26
*/
27
template<>
28
2
bool phoenix_load_value_from_config<bool>(const DicoValue & dico, const std::string & varName, bool defaultValue){
29
2
	const DicoValue * param = dico.getMap(varName);
30
2
	if(param == NULL){
31
1
		return defaultValue;
32
	}else{
33
1
		return phoenix_convertBoolType(param->getString());
34
	}
35
}
36
37
///Get the string from a dictionnary
38
/**	@param dico : dictionnary to be used
39
 * 	@param varName : name of the variable to be used
40
 * 	@param defaultValue : default value
41
 * 	@return loaded string or default value
42
*/
43
199
std::string phoenix_get_string(const DicoValue & dico, const std::string & varName, const std::string & defaultValue){
44
199
	const DicoValue * param = dico.getMap(varName);
45
199
	if(param == NULL){
46
37
		return defaultValue;
47
	}else{
48
162
		return param->getString();
49
	}
50
}
51
52
///Get the string from a dictionnary
53
/**	@param dico : dictionnary to be used
54
 * 	@param varName : name of the variable to be used
55
 * 	@param defaultValue : default value
56
 * 	@param defaultValue2 : default value to be used if the first defaultValue is empty
57
 * 	@return loaded string or default value
58
*/
59
3
std::string phoenix_get_string(const DicoValue & dico, const std::string & varName, const std::string & defaultValue, const std::string & defaultValue2){
60
3
	const DicoValue * param = dico.getMap(varName);
61
3
	if(param == NULL){
62
2
		if(defaultValue != ""){
63
1
			return defaultValue;
64
		}else{
65
1
			return defaultValue2;
66
		}
67
	}else{
68
1
		return param->getString();
69
	}
70
}
71
72
///Load a vector of string from a dictionnary
73
/**	@param[out] vecValue : loaded vector of values
74
 * 	@param dico : dictionnary to be used
75
 * 	@param varName : name of the variable to be used
76
*/
77
23
void phoenix_get_vecstring(std::vector<std::string> & vecValue, const DicoValue & dico, const std::string & varName){
78
23
	const DicoValue * param = dico.getMap(varName);
79
23
	if(param == NULL){
80
11
		return;
81
	}
82
12
	const VecDicoValue & vecChildValue = param->getVecChild();
83
26
	for(VecDicoValue::const_iterator it(vecChildValue.begin()); it != vecChildValue.end(); ++it){
84
14
		vecValue.push_back(it->getString());
85
	}
86
}
87
88
///Load a vector of string from a dictionnary
89
/**	@param dico : dictionnary to be used
90
 * 	@param varName : name of the variable to be used
91
 * 	@return loaded vector of values
92
*/
93
23
std::vector<std::string> phoenix_get_vecstring(const DicoValue & dico, const std::string & varName){
94
23
	std::vector<std::string> out;
95
23
	phoenix_get_vecstring(out, dico, varName);
96
23
	return out;
97
}
98
99
///@brief Data used to parse a yml file
100
struct PYmlParserData{
101
	///True to continue the parsing, false to stop
102
	bool isRun;
103
	///True if the compact mode is activated
104
	bool compactMode;
105
	///Current line number
106
	size_t currentLine;
107
	///Vector of previous line indentations
108
	std::vector<size_t> vecIndentation;
109
	///Current parsed text
110
	std::string currentText;
111
	///Currently parsed key value
112
	VecValue * currentlyParsedKeyValue;
113
};
114
115
///Default value of PYmlParserData
116
/**	@return default PYmlParserData
117
*/
118
15
PYmlParserData default_PYmlParserData(){
119
15
	PYmlParserData data;
120
15
	data.isRun = true;
121
15
	data.compactMode = false;
122
15
	data.currentLine = 1lu;
123
15
	data.currentText = "";
124
15
	data.currentlyParsedKeyValue = NULL;
125
15
	return data;
126
}
127
128
bool parse_yml_all(VecValue & parent, PFileParser & parser, PYmlParserData & data);
129
130
///Stop the file parsing
131
/**	@param[out] data : parsing data
132
*/
133
void parse_yml_stopParsing(PYmlParserData & data){
134
	data.isRun = false;
135
}
136
137
///Say if the file parsing is enable
138
/**	@param data : parsing data
139
*/
140
2371
bool parse_yml_isParse(const PYmlParserData & data){
141
2371
	return data.isRun;
142
}
143
144
///Update the indentation vector by respect to the given indentation
145
/**	@param[out] vecIndentation : vector of indentation to be updated
146
 * 	@param currentIndentation : current indentation
147
*/
148
197
void parse_yml_updateIndentation(std::vector<size_t> & vecIndentation, size_t currentIndentation){
149

197
	if(currentIndentation == 0lu || vecIndentation.size() == 0lu){		//If there is no indentation
150
90
		vecIndentation.clear();
151
90
		vecIndentation.push_back(currentIndentation);
152
90
		return;
153
	}
154
214
	std::vector<size_t> vecOutIndentation;
155
107
	std::vector<size_t>::const_iterator it(vecIndentation.begin());
156
107
	bool isCurrentLower(true);
157

335
	while(isCurrentLower && it != vecIndentation.end()){		//Get previous indentation until the current one
158
228
		isCurrentLower = *it < currentIndentation;
159
228
		if(isCurrentLower){
160
164
			vecOutIndentation.push_back(*it);
161
		}
162
228
		++it;
163
	}
164
107
	vecOutIndentation.push_back(currentIndentation);	//Add the current indentation
165
107
	vecIndentation = vecOutIndentation;
166
}
167
168
///Increment the current character
169
/**	@param[out] parser : parser to be used
170
 * 	@param data : parsing data
171
*/
172
2020
void parse_yml_incrementCurrentChar(PFileParser & parser, PYmlParserData & data){
173
	//If nothing is known I need to save the current char in the MACRO TEXT
174
2020
	char ch = parser.getCurrentCh();
175
2020
	data.currentText += ch;
176
2020
	parser.getNextChar();
177
2020
}
178
179
///Play the current parsed text
180
/**	@param[out] data : parsing data
181
*/
182
224
void parse_yml_playCurrentText(PYmlParserData & data){
183
672
	std::string value(eraseFirstLastChars(data.currentText, " \t\n"));
184
185

224
	if(data.currentlyParsedKeyValue != NULL && value != ""){
186
76
		data.currentlyParsedKeyValue->setValue(value);
187
	}
188
224
	data.currentText = "";
189
224
}
190
191
///Parse key
192
/**	@param[out] key : parsed key
193
 * 	@param[out] keyIndentation : indentation of the key
194
 * 	@param[out] parser : PFileParser to be used
195
*/
196
2044
bool parse_yml_key(std::string & key, size_t & keyIndentation, PFileParser & parser){
197
2044
	parser.pushPosition();
198
6132
	std::string possibleKey(parser.getStrComposedOf("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));
199




2044
	if(possibleKey != "" && parser.isMatch(":")){
200
183
		key = possibleKey;
201
183
		keyIndentation = parser.getColumn() - possibleKey.size() - 1lu;
202
183
		return true;
203
	}
204
1861
	parser.popPosition();
205
1861
	return false;
206
}
207
208
///Parse string value
209
/**	@param[out] str : parsed string value
210
 * 	@param[out] parser : PFileParser to be used
211
*/
212
257
bool parse_yml_string(std::string & str, PFileParser & parser){
213

257
	if(parser.isMatch("\"")){
214
185
		str = "\"" + parser.getUntilKey("\"");
215

72
	}else if(parser.isMatch("'")){
216
3
		str = "'" + parser.getUntilKey("'");
217
	}else{
218
69
		return false;
219
	}
220
188
	return true;
221
}
222
223
///Set a value into a VecValue
224
/**	@param[out] vecVal : vector of value
225
 * 	@param value : value to be used
226
*/
227
67
void parse_yml_dicoSetValue(VecValue * vecVal, const std::string & value){
228
67
	if(vecVal == NULL){return;}
229
67
	vecVal->setValue(value);
230
}
231
232
///Parse compact dico content
233
/**	@param[out] parser : PFileParser to be used
234
 * 	@param[out] data : extra parser data to be used
235
*/
236
2137
bool parse_yml_stringValue(PFileParser & parser, PYmlParserData & data){
237

2137
	if(parser.isMatch("\'")){
238
42
		std::string str("\'" + parser.getUntilKey("\'"));
239
14
		parse_yml_dicoSetValue(data.currentlyParsedKeyValue, str);
240

2123
	}else if(parser.isMatch("\"")){
241
159
		std::string str("\"" + parser.getUntilKey("\""));
242
53
		parse_yml_dicoSetValue(data.currentlyParsedKeyValue, str);
243
	}else{
244
2070
		return false;
245
	}
246
67
	return true;
247
}
248
249
///Parse compact dico content
250
/**	@param[out] parent : parent VecValue
251
 * 	@param[out] parser : PFileParser to be used
252
 * 	@param[out] data : extra parser data to be used
253
*/
254
2045
bool parse_yml_compactDicoContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
255

2045
	if(!parser.isMatch("{")){return false;}
256
1
	std::vector<size_t> saveVecIndentation = data.vecIndentation;
257
258
1
	bool oldMode = data.compactMode;
259
1
	data.compactMode = true;
260
261
1
	VecValue & dico = *data.currentlyParsedKeyValue;
262
1
	data.vecIndentation.clear();
263
1
	data.vecIndentation.push_back(0lu);
264
1
	parser.getStrComposedOf(" \t\n");				//Skip all blank characters
265




14
	while(parse_yml_isParse(data) && !parser.isMatch("}")){
266
13
		if(!parse_yml_all(dico, parser, data)){
267
			std::cerr << "parse_yml_compactDicoContent : error at " << parser.getLocation() << std::endl;
268
			std::cerr << "\tunexpected token '"<<parser.getNextToken()<<"'" << std::endl;
269
			parse_yml_stopParsing(data);
270
		}
271
13
		parser.isMatch(",");			//Skip comma if there is one
272
	}
273
1
	parse_yml_playCurrentText(data);
274
1
	data.vecIndentation = saveVecIndentation;
275
1
	data.compactMode = oldMode;
276
1
	return true;
277
}
278
279
///Parse dico content
280
/**	@param[out] parent : parent VecValue
281
 * 	@param[out] parser : PFileParser to be used
282
 * 	@param[out] data : extra parser data to be used
283
*/
284
2044
bool parse_yml_dicoContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
285
2044
	parser.pushPosition();
286
4088
	std::string keyName("");
287
2044
	size_t keyIndentation(0lu);
288
2044
	if(!parse_yml_key(keyName, keyIndentation, parser)){	//Check if there is a key
289
1861
		parser.popPosition();	//This is not a key
290
1861
		return false;
291
	}
292
183
	parse_yml_playCurrentText(data);
293
183
	VecValue dico;
294
183
	dico.setKey(keyName);
295
183
	if(data.compactMode){
296
2
		keyIndentation = -1lu;
297
	}
298
	//Add the dico into its parent and get back the pointer of the current dico we want to fill
299
183
	VecValue * ptrDico = addChildToParentVecValue(parent, data.vecIndentation, data.compactMode, dico, keyIndentation);
300
301
	//Update indentation to be used to fill the VecValue in the current dico
302
183
	parse_yml_updateIndentation(data.vecIndentation, keyIndentation);
303
304
	///Let's update the current VecValue to be completd with values and lists
305
183
	data.currentlyParsedKeyValue = ptrDico;
306
307
	//We do not need to parse the dico content, because its content will depend on what comes next (key, value, list)
308
309
	//OK, on pourrait dire que les dicos se regroupent par leur indentation donc ça fonctionne
310
	//Et que les valeurs associée (string, listes) sont ajoutées en utilisant data.currentlyParsedKeyValue
311
312
183
	return true;
313
}
314
315
///Parse compact dico content
316
/**	@param[out] parent : parent VecValue
317
 * 	@param[out] parser : PFileParser to be used
318
 * 	@param[out] data : extra parser data to be used
319
*/
320
2070
bool parse_yml_compactListContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
321

2070
	if(!parser.isMatch("[")){return false;}
322
11
	parse_yml_playCurrentText(data);
323
11
	VecVecValue & listValue = data.currentlyParsedKeyValue->getVecChild();
324
325




33
	while(parse_yml_isParse(data) && !parser.isMatch("]")){
326
22
		std::string tmpStr("");
327
22
		if(parse_yml_string(tmpStr, parser)){
328
4
			VecValue vecTmp;
329
2
			vecTmp.setValue(tmpStr);
330
2
			listValue.push_back(vecTmp);
331
		}else{
332







179
			while(parse_yml_isParse(data) && !parser.isMatchRewind("]") && !parser.isMatchRewind(",")){
333
159
				parse_yml_incrementCurrentChar(parser, data);
334
			}
335
40
			VecValue vecTmp;
336
20
			vecTmp.setValue(eraseFirstCharsInStr(data.currentText, " \t\n"));
337
20
			listValue.push_back(vecTmp);
338
20
			data.currentText = "";
339
		}
340






22
		if(!parser.isMatch(",") && !parser.isMatchRewind("]")){
341
			parse_yml_stopParsing(data);
342
			std::cerr << "parser_yml_fileParser : error at " << parser.getLocation() << std::endl;
343
			std::cerr << "\tunexpected token '"<<parser.getNextToken()<<"'" << std::endl;
344
			std::cerr << "\texpect token ',' or ']'" << std::endl;
345
			return true;
346
		}
347
	}
348
11
	return true;
349
}
350
351
///Parse dico content
352
/**	@param[out] parent : parent VecValue
353
 * 	@param[out] parser : PFileParser to be used
354
 * 	@param[out] data : extra parser data to be used
355
*/
356
2059
bool parse_yml_listContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
357

2059
	if(!parser.isMatch("- ")){return false;}		//There is no extra space, this is exactly the syntax
358
14
	size_t currentIndentation(parser.getColumn() - 2lu);
359
14
	parse_yml_playCurrentText(data);
360
14
	VecValue dashList;
361
14
	dashList.setKey("");
362
	//Add the dico into its parent and get back the pointer of the current dico we want to fill
363
14
	VecValue * ptrDashList = addChildToParentVecValue(parent, data.vecIndentation, data.compactMode, dashList, currentIndentation);
364
365
	//Update indentation to be used to fill the VecValue in the current dico
366
14
	parse_yml_updateIndentation(data.vecIndentation, currentIndentation);
367
368
	///Let's update the current VecValue to be completd with values and lists
369
14
	data.currentlyParsedKeyValue = ptrDashList;
370
14
	return true;
371
}
372
373
///Parse all yml features
374
/**	@param[out] parent : parent VecValue
375
 * 	@param[out] parser : PFileParser to be used
376
 * 	@param[out] data : extra parser data to be used
377
*/
378
2158
bool parse_yml_all(VecValue & parent, PFileParser & parser, PYmlParserData & data){
379

2158
	if(parser.isMatch("#")){parser.getUntilKeyWithoutPatern("\n");}		//Skip the comment
380
2137
	else if(parse_yml_stringValue(parser, data)){}
381
2070
	else if(parse_yml_compactListContent(parent, parser, data)){}
382
2059
	else if(parse_yml_listContent(parent, parser, data)){}
383
2045
	else if(parse_yml_compactDicoContent(parent, parser, data)){}
384
2044
	else if(parse_yml_dicoContent(parent, parser, data)){}
385
	else{
386
1861
		parse_yml_incrementCurrentChar(parser, data);
387
	}
388
2158
	return true;
389
}
390
391
///Parse a yml file and update the given VecValue
392
/**	@param[out] dico : dictionnary of values
393
 * 	@param parser : PFileParser to be used
394
 * 	@return true on success, false otherwise
395
*/
396
15
bool parser_yml_fileParser(VecValue & dico, PFileParser & parser){
397
15
	PYmlParserData data(default_PYmlParserData());
398
15
	data.currentlyParsedKeyValue = &dico;
399
15
	parser.getStrComposedOf(" \t\n");		//Skip all blank characters
400


2160
	while(!parser.isEndOfFile() && parse_yml_isParse(data)){
401
2145
		if(!parse_yml_all(dico, parser, data)){
402
			std::cerr << "parser_yml_fileParser : error at " << parser.getLocation() << std::endl;
403
			std::cerr << "\tunexpected token '"<<parser.getNextToken()<<"'" << std::endl;
404
			parse_yml_stopParsing(data);
405
		}
406
	}
407
15
	parse_yml_playCurrentText(data);
408
30
	return data.isRun;
409
}
410
411
412
///Parse a yml file and update the given DicoValue
413
/**	@param[out] dico : dictionnary of values
414
 * 	@param fileName : name of the file to be parsed
415
 * 	@return true on success, false otherwise
416
*/
417
15
bool parser_yml(DicoValue & dico, const std::string & fileName){
418
30
	PFileParser parser;
419
15
	parser.setWhiteSpace("");
420
15
	parser.setSeparator(":-'\",{}[]>|#");
421
15
	parser.setEscapeChar('\\');
422
15
	if(!parser.open(fileName)){
423
		std::cerr << "parser_yml : cannot open file '"<<fileName<<"'" << std::endl;
424
		return false;
425
	}
426
15
	VecValue vecValue;
427
15
	bool b(parser_yml_fileParser(vecValue, parser));
428
15
	vecValueToDicoValue(dico, vecValue);
429
15
	return b;
430
}
431
432