GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/FileParser/src/parser_yml.cpp Lines: 190 205 92.7 %
Date: 2024-09-10 03:06:26 Branches: 255 378 67.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
7
std::string phoenix_get_string(const DicoValue & dico, const std::string & varName, const std::string & defaultValue){
44
7
	const DicoValue * param = dico.getMap(varName);
45
7
	if(param == NULL){
46
2
		return defaultValue;
47
	}else{
48
5
		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
4
void phoenix_get_vecstring(std::vector<std::string> & vecValue, const DicoValue & dico, const std::string & varName){
78
4
	const DicoValue * param = dico.getMap(varName);
79
4
	if(param == NULL){
80
2
		return;
81
	}
82
2
	const VecDicoValue & vecChildValue = param->getVecChild();
83
8
	for(VecDicoValue::const_iterator it(vecChildValue.begin()); it != vecChildValue.end(); ++it){
84
6
		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
4
std::vector<std::string> phoenix_get_vecstring(const DicoValue & dico, const std::string & varName){
94
4
	std::vector<std::string> out;
95
4
	phoenix_get_vecstring(out, dico, varName);
96
4
	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
18
PYmlParserData default_PYmlParserData(){
119
18
	PYmlParserData data;
120
18
	data.isRun = true;
121
18
	data.compactMode = false;
122
18
	data.currentLine = 1lu;
123
18
	data.currentText = "";
124
18
	data.currentlyParsedKeyValue = NULL;
125
18
	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
3899
bool parse_yml_isParse(const PYmlParserData & data){
141
3899
	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
299
void parse_yml_updateIndentation(std::vector<size_t> & vecIndentation, size_t currentIndentation){
149

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

527
	while(isCurrentLower && it != vecIndentation.end()){		//Get previous indentation until the current one
158
360
		isCurrentLower = *it < currentIndentation;
159
360
		if(isCurrentLower){
160
261
			vecOutIndentation.push_back(*it);
161
		}
162
360
		++it;
163
	}
164
167
	vecOutIndentation.push_back(currentIndentation);	//Add the current indentation
165
167
	vecIndentation = vecOutIndentation;
166
}
167
168
///Increment the current character
169
/**	@param[out] parser : parser to be used
170
 * 	@param data : parsing data
171
*/
172
3377
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
3377
	char ch = parser.getCurrentCh();
175
3377
	data.currentText += ch;
176
3377
	parser.getNextChar();
177
3377
}
178
179
///Play the current parsed text
180
/**	@param[out] data : parsing data
181
*/
182
334
void parse_yml_playCurrentText(PYmlParserData & data){
183
1002
	std::string value(eraseFirstLastChars(data.currentText, " \t\n"));
184
185

334
	if(data.currentlyParsedKeyValue != NULL && value != ""){
186
121
		data.currentlyParsedKeyValue->setValue(value);
187
	}
188
334
	data.currentText = "";
189
334
}
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
3546
bool parse_yml_key(std::string & key, size_t & keyIndentation, PFileParser & parser){
197
3546
	parser.pushPosition();
198
10638
	std::string possibleKey(parser.getStrComposedOf("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));
199




3546
	if(possibleKey != "" && parser.isMatch(":")){
200
273
		key = possibleKey;
201
273
		keyIndentation = parser.getColumn() - possibleKey.size() - 1lu;
202
273
		return true;
203
	}
204
3273
	parser.popPosition();
205
3273
	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
63
bool parse_yml_string(std::string & str, PFileParser & parser){
213

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

50
	}else if(parser.isMatch("'")){
216
3
		str = "'" + parser.getUntilKey("'");
217
	}else{
218
47
		return false;
219
	}
220
16
	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
95
void parse_yml_dicoSetValue(VecValue * vecVal, const std::string & value){
228
95
	if(vecVal == NULL){return;}
229
95
	vecVal->setValue(value);
230
95
	vecVal->setType(VecValueType::VALUE);
231
}
232
233
///Parse compact dico content
234
/**	@param[out] parser : PFileParser to be used
235
 * 	@param[out] data : extra parser data to be used
236
*/
237
3273
bool parse_yml_stringValue(PFileParser & parser, PYmlParserData & data){
238

3273
	if(parser.isMatch("\'")){
239
75
		std::string str("\'" + parser.getUntilKey("\'"));
240
25
		parse_yml_dicoSetValue(data.currentlyParsedKeyValue, str);
241

3248
	}else if(parser.isMatch("\"")){
242
210
		std::string str("\"" + parser.getUntilKey("\""));
243
70
		parse_yml_dicoSetValue(data.currentlyParsedKeyValue, str);
244
	}else{
245
// 		std::string strValue(parser.getStrComposedOf("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%$£?.*/+=-&~#(){}[]|!<>@°"));
246
// 		parser.skipWhiteSpace();
247
// 		std::string strValue(parser.getStrComposedOf("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}§"));
248
// 		if(strValue != ""){
249
// 			parse_yml_dicoSetValue(data.currentlyParsedKeyValue, strValue);
250
// 		}else{
251
3178
			return false;
252
// 		}
253
	}
254
95
	return true;
255
}
256
257
///Parse compact dico content
258
/**	@param[out] parent : parent VecValue
259
 * 	@param[out] parser : PFileParser to be used
260
 * 	@param[out] data : extra parser data to be used
261
*/
262
3573
bool parse_yml_compactDicoContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
263

3573
	if(!parser.isMatch("{", "$§_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/*+-.")){return false;}
264
1
	std::vector<size_t> saveVecIndentation = data.vecIndentation;
265
1
	parse_yml_playCurrentText(data);
266
1
	bool oldMode = data.compactMode;
267
1
	data.compactMode = true;
268
269
1
	VecValue & dico = *data.currentlyParsedKeyValue;
270
1
	data.vecIndentation.clear();
271
1
	data.vecIndentation.push_back(0lu);
272
1
	parser.getStrComposedOf(" \t\n");				//Skip all blank characters
273




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

3588
	if(!parser.isMatch("[")){return false;}
332
15
	parse_yml_playCurrentText(data);
333
15
	VecVecValue & listValue = data.currentlyParsedKeyValue->getVecChild();
334
335




43
	while(parse_yml_isParse(data) && !parser.isMatch("]")){
336
28
		std::string tmpStr("");
337
28
		if(parse_yml_string(tmpStr, parser)){
338
4
			VecValue vecTmp;
339
2
			vecTmp.setValue(tmpStr);
340
2
			listValue.push_back(vecTmp);
341
		}else{
342







225
			while(parse_yml_isParse(data) && !parser.isMatchRewind("]") && !parser.isMatchRewind(",")){
343
199
				parse_yml_incrementCurrentChar(parser, data);
344
			}
345
52
			VecValue vecTmp;
346
26
			vecTmp.setValue(eraseFirstCharsInStr(data.currentText, " \t\n"));
347
26
			listValue.push_back(vecTmp);
348
26
			data.currentText = "";
349
		}
350






28
		if(!parser.isMatch(",") && !parser.isMatchRewind("]")){
351
			parse_yml_stopParsing(data);
352
			std::cerr << "parser_yml_fileParser : error at " << parser.getLocation() << std::endl;
353
			std::cerr << "\tunexpected token '"<<parser.getNextToken()<<"'" << std::endl;
354
			std::cerr << "\texpect token ',' or ']'" << std::endl;
355
			return true;
356
		}
357
	}
358
15
	return true;
359
}
360
361
///Parse dico content
362
/**	@param[out] parent : parent VecValue
363
 * 	@param[out] parser : PFileParser to be used
364
 * 	@param[out] data : extra parser data to be used
365
*/
366
3572
bool parse_yml_listContent(VecValue & parent, PFileParser & parser, PYmlParserData & data){
367

3572
	if(!parser.isMatch("- ")){return false;}		//There is no extra space, this is exactly the syntax
368
26
	size_t currentIndentation(parser.getColumn() - 1lu);
369
26
	parse_yml_playCurrentText(data);
370
26
	VecValue dashList;
371
26
	dashList.setKey("");
372
26
	dashList.setType(VecValueType::LIST_ITEM);
373
26
	dashList.setIndentation(currentIndentation);
374
// 	std::cerr << "parse_yml_listContent : Add LIST_ITEM at " << parser.getLocation() << std::endl;
375
	//Add the dico into its parent and get back the pointer of the current dico we want to fill
376
26
	VecValue * ptrDashList = addChildToParentVecValueAddListItem(parent, data.vecIndentation, data.compactMode, dashList, currentIndentation);
377
378
	//Update indentation to be used to fill the VecValue in the current dico
379
26
	parse_yml_updateIndentation(data.vecIndentation, currentIndentation);
380
381
	///Let's update the current VecValue to be completd with values and lists
382
26
	data.currentlyParsedKeyValue = ptrDashList;
383
26
	return true;
384
}
385
386
///Parse all yml features
387
/**	@param[out] parent : parent VecValue
388
 * 	@param[out] parser : PFileParser to be used
389
 * 	@param[out] data : extra parser data to be used
390
*/
391
3630
bool parse_yml_all(VecValue & parent, PFileParser & parser, PYmlParserData & data){
392

3630
	if(parser.isMatch("#")){parser.getUntilKeyWithoutPatern("\n");}		//Skip the comment
393
3588
	else if(parse_yml_compactListContent(parent, parser, data)){}
394
3573
	else if(parse_yml_compactDicoContent(parent, parser, data)){}
395
3572
	else if(parse_yml_listContent(parent, parser, data)){}
396
3546
	else if(parse_yml_dicoContent(parent, parser, data)){}
397
3273
	else if(parse_yml_stringValue(parser, data)){}
398
	else{
399
3178
		parse_yml_incrementCurrentChar(parser, data);
400
	}
401
3630
	return true;
402
}
403
404
///Parse a yml file and update the given VecValue
405
/**	@param[out] dico : dictionnary of values
406
 * 	@param parser : PFileParser to be used
407
 * 	@return true on success, false otherwise
408
*/
409
18
bool parser_yml_fileParser(VecValue & dico, PFileParser & parser){
410
18
	PYmlParserData data(default_PYmlParserData());
411
18
	data.currentlyParsedKeyValue = &dico;
412
18
	parser.getStrComposedOf(" \t\n");		//Skip all blank characters
413


3635
	while(!parser.isEndOfFile() && parse_yml_isParse(data)){
414
3617
		if(!parse_yml_all(dico, parser, data)){
415
			std::cerr << "parser_yml_fileParser : error at " << parser.getLocation() << std::endl;
416
			std::cerr << "\tunexpected token '"<<parser.getNextToken()<<"'" << std::endl;
417
			parse_yml_stopParsing(data);
418
		}
419
	}
420
18
	parse_yml_playCurrentText(data);
421
36
	return data.isRun;
422
}
423
424
425
///Parse a yml file and update the given DicoValue
426
/**	@param[out] dico : dictionnary of values
427
 * 	@param fileName : name of the file to be parsed
428
 * 	@return true on success, false otherwise
429
*/
430
18
bool parser_yml(DicoValue & dico, const std::string & fileName){
431
36
	PFileParser parser;
432
18
	parser.setWhiteSpace("");
433
18
	parser.setSeparator(":-'\",{}[]>|#");
434
18
	parser.setEscapeChar('\\');
435
18
	if(!parser.open(fileName)){
436
		std::cerr << "parser_yml : cannot open file '"<<fileName<<"'" << std::endl;
437
		return false;
438
	}
439
18
	VecValue vecValue;
440
18
	vecValue.setType(VecValueType::MAIN);
441
18
	vecValue.setIndentation(parser.getLocation().getColumn());
442
18
	bool b(parser_yml_fileParser(vecValue, parser));
443
18
	vecValueToDicoValue(dico, vecValue);
444
18
	return b;
445
}
446
447