GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tmp_project/FileParser/src/dico_replace_var.cpp Lines: 107 107 100.0 %
Date: 2024-12-09 15:41:43 Branches: 150 151 99.3 %

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 "dico_replace_var.h"
9
10
///Map used to replace variable value in nested calls (VariableName, PNestedCall)
11
typedef std::vector<std::pair<PNestedCall, DicoValue*> > PVecReplaceVar;
12
///Map of the variables which uses nested call
13
typedef std::map<std::string, std::pair<PNestedCall, DicoValue*> > MapVarWithNestedCall;
14
15
///Create the nested calls of the input base string
16
/**	@param[out] call : PNestedCall to be created
17
 * 	@param baseStr : basic suffix to be used
18
 * 	@param varBegin : characters which announce the begining of a variable (example ${)
19
 * 	@param varEnd : characters which announce the ending of a variable (example })
20
*/
21
4
void dico_create_nested_call(PNestedCall & call, const std::string & baseStr, const std::string & varBegin, const std::string & varEnd){
22
8
	PFileParser parser;
23
4
	parser.setFileContent(baseStr);
24
9
	while(!parser.isEndOfFile()){
25
10
		std::string prevCall(parser.getUntilKeyWithoutPatern(varBegin));
26
5
		if(prevCall != ""){
27
8
			PNestedStr str;
28
4
			str.setValue(prevCall);
29
4
			str.setIsVarCall(false);
30
4
			call.getVecNestedStr().push_back(str);
31
		}
32
10
		std::string varNameCall(parser.getUntilKeyWithoutPatern(varEnd));
33
5
		if(varNameCall != ""){
34
8
			PNestedStr str;
35
4
			str.setValue(varNameCall);
36
4
			str.setIsVarCall(true);
37
4
			call.getVecNestedStr().push_back(str);
38
		}
39
	}
40
4
}
41
42
///Replace the nested call by the variables in map
43
/**	@param[out] out : output string with replaced variables
44
 * 	@param call : nested call to create the output string
45
 * 	@param mapKeyVariable : map of all defined variabled to be used
46
 * 	@param varBegin : characters which announce the begining of a variable (example ${) (in case variable is not found)
47
 * 	@param varEnd : characters which announce the ending of a variable (example }) (in case variable is not found)
48
*/
49
4
void dico_replace_nested_call(std::string & out, const PNestedCall & call, const PMapKnownVar & mapKeyVariable, const std::string & varBegin, const std::string & varEnd){
50
4
	const std::vector<PNestedStr> & vecNestedStr = call.getVecNestedStr();
51
12
	for(std::vector<PNestedStr>::const_iterator it(vecNestedStr.begin()); it != vecNestedStr.end(); ++it){
52
8
		if(it->getIsVarCall()){
53

4
			PMapKnownVar::const_iterator itCall(mapKeyVariable.find(varBegin + it->getValue() + varEnd));
54
4
			if(itCall != mapKeyVariable.end()){
55
3
				out += itCall->second;
56
			}else{
57

1
				out += varBegin + it->getValue() + varEnd;
58
			}
59
		}else{
60
4
			out += it->getValue();
61
		}
62
	}
63
4
}
64
65
///Update the suffix of the file
66
/**	@param baseStr : basic suffix to be used
67
 * 	@param mapKeyVariable : map of all defined variabled to be used
68
 * 	@param varBegin : characters which announce the begining of a variable (example ${)
69
 * 	@param varEnd : characters which announce the ending of a variable (example })
70
 * 	@return updated string
71
*/
72
7
std::string dico_replace_var_str(const std::string & baseStr, const PMapKnownVar & mapKeyVariable, const std::string & varBegin, const std::string & varEnd){
73

7
	if(varBegin == "" || varEnd == ""){return baseStr;}
74
8
	PNestedCall call;
75
4
	dico_create_nested_call(call, baseStr, varBegin, varEnd);
76
8
	std::string out("");
77
4
	dico_replace_nested_call(out, call, mapKeyVariable, varBegin, varEnd);
78
4
	return out;
79
}
80
81
///Create the PNestedCall from the given value
82
/**	@param[out] call : PNestedCall
83
 * 	@param value : value to be used
84
 * 	@param varName : name of the variable to be defined
85
 * 	@param varBegin : characters which announce the begining of a variable (example ${)
86
 * 	@param varEnd : characters which announce the ending of a variable (example })
87
 * 	@return true if the value contains a nested call, false otherwise
88
*/
89
141
bool createNestedCallFromStr(PNestedCall & call, const std::string & value, const std::string varName, const std::string & varBegin, const std::string & varEnd){
90
141
	call.setName(varName);
91
141
	PFileParser parser;
92
141
	parser.setFileContent(value);
93
141
	bool hasNestedCall(false);
94
324
	while(!parser.isEndOfFile()){
95
366
		std::string prevCall(parser.getUntilKeyWithoutPatern(varBegin));
96
183
		if(prevCall != ""){
97
338
			PNestedStr str;
98
169
			str.setValue(prevCall);
99
169
			str.setIsVarCall(false);
100
169
			call.getVecNestedStr().push_back(str);
101
		}
102
366
		std::string varNameCall(parser.getUntilKeyWithoutPatern(varEnd));
103
183
		if(varNameCall != ""){
104
72
			PNestedStr str;
105
72
			str.setValue(varNameCall);
106
72
			str.setIsVarCall(true);
107
72
			call.getVecNestedStr().push_back(str);
108
72
			hasNestedCall = true;
109
		}
110
	}
111
282
	return hasNestedCall;
112
}
113
114
///Get the variable which contains only a value and those with nested calls
115
/**	@param[out] mapReadyVar : map of variables with values only
116
 * 	@param[out] mapNestedVar : map of variables with nested calls
117
 * 	@param[out] mapVarWithNestedCall : map of the variables which use nested calls
118
 *  @param varIdentifier : String used to detect the variable names (example: '$' for ${varName}, § for §{varName})
119
 * 	@param dico : DicoValue to be used
120
*/
121
210
void dico_find_all_var(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall, DicoValue & dico, const std::string & varIdentifier){
122
210
	if(dico.hasMap()){
123
42
		MapDicoValue & mapDico = dico.getMapChild();
124
224
		for(MapDicoValue::iterator it(mapDico.begin()); it != mapDico.end(); ++it){
125
182
			dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, it->second, varIdentifier);
126
		}
127
168
	}else if(dico.hasVec()){
128
12
		VecDicoValue & vecDico = dico.getVecChild();
129
31
		for(VecDicoValue::iterator it(vecDico.begin()); it != vecDico.end(); ++it){
130
19
			dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, *it, varIdentifier);
131
		}
132
156
	}else if(dico.hasKey()){	//No map, no vector but a key, this is a string variable
133
282
		std::string strValue(dico.getString()), varName(dico.getKey());
134
		//Let's check is the value contains nested calls
135
		//We will create a class to handle the split between string part and nested calls
136
282
		PNestedCall call;
137
		//We add the class in the proper map
138

141
		if((createNestedCallFromStr(call, strValue, varName, varIdentifier + "{", "}"))){	//There is (at least) one nested call
139
43
			mapNestedVar.push_back(std::pair<PNestedCall, DicoValue*>(call, &dico));
140
43
			mapVarWithNestedCall[varName] = std::pair<PNestedCall, DicoValue*>(call, &dico);
141
		}else{								//There is no nested call
142
98
			mapReadyVar[varName] = strValue;
143
		}
144
	}
145
210
}
146
147
148
///Update variables with nested calls
149
/**	@param[out] mapReadyVar : map of variables with values only
150
 * 	@param[out] mapNestedVar : map of variables with nested calls
151
 * 	@param nestedCall : nested call which is the split value of the dico
152
 * 	@param mapVarWithNestedCall : map of the variables which use nested calls
153
 * 	@param dico : DicoValue to be used
154
 * 	@param varIdentifier : String used to detect the variable names (example: '$' for ${varName}, § for §{varName})
155
*/
156
65
void dico_update_all_nestedCall(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall,
157
				PNestedCall & nestedCall, DicoValue * dico, const std::string & varIdentifier)
158
{
159
	//For each call, we check if it comes from the mapReadyVar, from the mapNestedVar or from nowhere
160
130
	std::string outputValue("");
161
65
	std::vector<PNestedStr> & vecNestedStr = nestedCall.getVecNestedStr();
162
288
	for(std::vector<PNestedStr>::iterator it(vecNestedStr.begin()); it != vecNestedStr.end(); ++it){
163
223
		if(!it->getIsVarCall()){	//If it is not a var call, we skip it
164
112
			outputValue += it->getValue();
165
112
			continue;
166
		}
167
222
		std::string varName(it->getValue());
168
		//If the var comes from mapNestedVar, we have to resolve this one first
169
111
		MapVarWithNestedCall::iterator itNested = mapVarWithNestedCall.find(varName);
170
111
		if(itNested != mapVarWithNestedCall.end()){
171
22
			dico_update_all_nestedCall(mapReadyVar, mapNestedVar, mapVarWithNestedCall, itNested->second.first, itNested->second.second, varIdentifier);
172
22
			mapVarWithNestedCall.erase(varName);	//We solve varName, so we erase it from the mapNestedVar
173
			//But now, the varName entry does exist in the mapReadyVar
174
		}
175
		//If the var comes from mapReadyVar, we replace it
176
111
		PMapKnownVar::iterator itReady = mapReadyVar.find(varName);
177
111
		if(itReady != mapReadyVar.end()){
178
75
			outputValue += itReady->second;
179
		}else{
180
			//If we cannot find it, let's keep it unsolved (it can we a global variable)
181

36
			outputValue += varIdentifier + "{" + varName + "}";
182
		}
183
	}
184
	//Finally, we can update the dico value, but we deal with the quotation
185
195
	std::string firstQuote(""), prevValue(dico->getValue());
186
65
	if(prevValue.size() != 0lu){
187
65
		if(prevValue.front() == '\''){firstQuote = "'";}
188
51
		else if(prevValue.front() == '"'){firstQuote = "\"";}
189
	}
190
65
	dico->setValue(firstQuote + outputValue + firstQuote);
191
192
	//And put its value into the mapReadyVar, because we solve it
193
65
	mapReadyVar[nestedCall.getName()] = outputValue;
194
65
}
195
196
///Update the variable which contains nested calls
197
/**	@param[out] mapReadyVar : map of variables with values only
198
 * 	@param[out] mapNestedVar : map of variables with nested calls
199
 * 	@param mapVarWithNestedCall : map of variable with nested call
200
 * 	@param varIdentifier : String used to detect the variable names (example: '$' for ${varName}, § for §{varName})
201
*/
202
9
void dico_update_all_var(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall,
203
			const std::string & varIdentifier)
204
{
205
	//Let's try to complete the nested call
206
52
	for(PVecReplaceVar::iterator itNested(mapNestedVar.begin()); itNested != mapNestedVar.end(); ++itNested){
207
43
		PNestedCall & nestedCall = itNested->first;
208
43
		DicoValue * dico = itNested->second;
209
210
43
		dico_update_all_nestedCall(mapReadyVar, mapNestedVar, mapVarWithNestedCall, nestedCall, dico, varIdentifier);
211
	}
212
9
}
213
214
///Replace all the variables which are string in the given DicoValue, when ${variable} apprears in the value
215
/**	@param dico : DicoValue to be updated
216
 * 	@param varIdentifier : String used to detect the variable names (example: '$' for ${varName}, § for §{varName})
217
*/
218
9
void dico_replace_var(DicoValue & dico, const std::string & varIdentifier){
219
	//Let's find all the defined variables, linked to the DicoValue, string only
220
18
	PMapKnownVar mapReadyVar;
221
18
	PVecReplaceVar mapNestedVar;
222
18
	MapVarWithNestedCall mapVarWithNestedCall;
223
9
	dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, dico, varIdentifier);
224
225
	//Update variables with nested call, separate those with nested call from the other
226
9
	dico_update_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, varIdentifier);
227
9
}
228
229