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 |
|
80 |
bool createNestedCallFromStr(PNestedCall & call, const std::string & value, const std::string varName, const std::string & varBegin, const std::string & varEnd){ |
90 |
✓ |
80 |
call.setName(varName); |
91 |
✓ |
80 |
PFileParser parser; |
92 |
✓ |
80 |
parser.setFileContent(value); |
93 |
|
80 |
bool hasNestedCall(false); |
94 |
✓✓✓ |
182 |
while(!parser.isEndOfFile()){ |
95 |
✓ |
204 |
std::string prevCall(parser.getUntilKeyWithoutPatern(varBegin)); |
96 |
✓✓✓ |
102 |
if(prevCall != ""){ |
97 |
✓ |
190 |
PNestedStr str; |
98 |
✓ |
95 |
str.setValue(prevCall); |
99 |
✓ |
95 |
str.setIsVarCall(false); |
100 |
✓✓ |
95 |
call.getVecNestedStr().push_back(str); |
101 |
|
|
} |
102 |
✓ |
204 |
std::string varNameCall(parser.getUntilKeyWithoutPatern(varEnd)); |
103 |
✓✓✓ |
102 |
if(varNameCall != ""){ |
104 |
✓ |
45 |
PNestedStr str; |
105 |
✓ |
45 |
str.setValue(varNameCall); |
106 |
✓ |
45 |
str.setIsVarCall(true); |
107 |
✓✓ |
45 |
call.getVecNestedStr().push_back(str); |
108 |
|
45 |
hasNestedCall = true; |
109 |
|
|
} |
110 |
|
|
} |
111 |
|
160 |
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 dico : DicoValue to be used |
119 |
|
|
*/ |
120 |
|
124 |
void dico_find_all_var(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall, DicoValue & dico){ |
121 |
✓✓ |
124 |
if(dico.hasMap()){ |
122 |
|
28 |
MapDicoValue & mapDico = dico.getMapChild(); |
123 |
✓✓ |
132 |
for(MapDicoValue::iterator it(mapDico.begin()); it != mapDico.end(); ++it){ |
124 |
✓ |
104 |
dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, it->second); |
125 |
|
|
} |
126 |
✓✓ |
96 |
}else if(dico.hasVec()){ |
127 |
|
7 |
VecDicoValue & vecDico = dico.getVecChild(); |
128 |
✓✓ |
19 |
for(VecDicoValue::iterator it(vecDico.begin()); it != vecDico.end(); ++it){ |
129 |
✓ |
12 |
dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, *it); |
130 |
|
|
} |
131 |
✓✓ |
89 |
}else if(dico.hasKey()){ //No map, no vector but a key, this is a string variable |
132 |
✓✓✓ |
160 |
std::string strValue(dico.getString()), varName(dico.getKey()); |
133 |
|
|
//Let's check is the value contains nested calls |
134 |
|
|
//We will create a class to handle the split between string part and nested calls |
135 |
✓ |
160 |
PNestedCall call; |
136 |
|
|
//We add the class in the proper map |
137 |
✓✓✓✓ ✓✓ |
80 |
if((createNestedCallFromStr(call, strValue, varName, "${", "}"))){ //There is (at least) one nested call |
138 |
✓✓ |
29 |
mapNestedVar.push_back(std::pair<PNestedCall, DicoValue*>(call, &dico)); |
139 |
✓✓✓ |
29 |
mapVarWithNestedCall[varName] = std::pair<PNestedCall, DicoValue*>(call, &dico); |
140 |
|
|
}else{ //There is no nested call |
141 |
✓✓ |
51 |
mapReadyVar[varName] = strValue; |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
124 |
} |
145 |
|
|
|
146 |
|
|
|
147 |
|
|
///Update variables with nested calls |
148 |
|
|
/** @param[out] mapReadyVar : map of variables with values only |
149 |
|
|
* @param[out] mapNestedVar : map of variables with nested calls |
150 |
|
|
* @param nestedCall : nested call which is the split value of the dico |
151 |
|
|
* @param mapVarWithNestedCall : map of the variables which use nested calls |
152 |
|
|
* @param dico : DicoValue to be used |
153 |
|
|
*/ |
154 |
|
45 |
void dico_update_all_nestedCall(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall, |
155 |
|
|
PNestedCall & nestedCall, DicoValue * dico) |
156 |
|
|
{ |
157 |
|
|
//For each call, we check if it comes from the mapReadyVar, from the mapNestedVar or from nowhere |
158 |
✓ |
90 |
std::string outputValue(""); |
159 |
✓ |
45 |
std::vector<PNestedStr> & vecNestedStr = nestedCall.getVecNestedStr(); |
160 |
✓✓ |
189 |
for(std::vector<PNestedStr>::iterator it(vecNestedStr.begin()); it != vecNestedStr.end(); ++it){ |
161 |
✓✓✓ |
144 |
if(!it->getIsVarCall()){ //If it is not a var call, we skip it |
162 |
✓✓ |
72 |
outputValue += it->getValue(); |
163 |
|
72 |
continue; |
164 |
|
|
} |
165 |
✓✓ |
144 |
std::string varName(it->getValue()); |
166 |
|
|
//If the var comes from mapNestedVar, we have to resolve this one first |
167 |
✓ |
72 |
MapVarWithNestedCall::iterator itNested = mapVarWithNestedCall.find(varName); |
168 |
✓✓ |
72 |
if(itNested != mapVarWithNestedCall.end()){ |
169 |
✓ |
16 |
dico_update_all_nestedCall(mapReadyVar, mapNestedVar, mapVarWithNestedCall, itNested->second.first, itNested->second.second); |
170 |
✓ |
16 |
mapVarWithNestedCall.erase(varName); //We solve varName, so we erase it from the mapNestedVar |
171 |
|
|
//But now, the varName entry does exist in the mapReadyVar |
172 |
|
|
} |
173 |
|
|
//If the var comes from mapReadyVar, we replace it |
174 |
✓ |
72 |
PMapKnownVar::iterator itReady = mapReadyVar.find(varName); |
175 |
✓✓ |
72 |
if(itReady != mapReadyVar.end()){ |
176 |
✓ |
46 |
outputValue += itReady->second; |
177 |
|
|
}else{ |
178 |
|
|
//If we cannot find it, let's keep it unsolved (it can we a global variable) |
179 |
✓✓✓ |
26 |
outputValue += "${" + varName + "}"; |
180 |
|
|
} |
181 |
|
|
} |
182 |
|
|
//Finally, we can update the dico value, but we deal with the quotation |
183 |
✓✓✓ |
135 |
std::string firstQuote(""), prevValue(dico->getValue()); |
184 |
✓✗ |
45 |
if(prevValue.size() != 0lu){ |
185 |
✓✓✓ |
45 |
if(prevValue.front() == '\''){firstQuote = "'";} |
186 |
✓✗✓ |
38 |
else if(prevValue.front() == '"'){firstQuote = "\"";} |
187 |
|
|
} |
188 |
✓✓✓ |
45 |
dico->setValue(firstQuote + outputValue + firstQuote); |
189 |
|
|
|
190 |
|
|
//And put its value into the mapReadyVar, because we solve it |
191 |
✓✓✓ |
45 |
mapReadyVar[nestedCall.getName()] = outputValue; |
192 |
|
45 |
} |
193 |
|
|
|
194 |
|
|
///Update the variable which contains nested calls |
195 |
|
|
/** @param[out] mapReadyVar : map of variables with values only |
196 |
|
|
* @param[out] mapNestedVar : map of variables with nested calls |
197 |
|
|
* @param mapVarWithNestedCall : map of variable with nested call |
198 |
|
|
*/ |
199 |
|
8 |
void dico_update_all_var(PMapKnownVar & mapReadyVar, PVecReplaceVar & mapNestedVar, MapVarWithNestedCall & mapVarWithNestedCall){ |
200 |
|
|
//Let's try to complete the nested call |
201 |
✓✓ |
37 |
for(PVecReplaceVar::iterator itNested(mapNestedVar.begin()); itNested != mapNestedVar.end(); ++itNested){ |
202 |
|
29 |
PNestedCall & nestedCall = itNested->first; |
203 |
|
29 |
DicoValue * dico = itNested->second; |
204 |
|
|
|
205 |
✓ |
29 |
dico_update_all_nestedCall(mapReadyVar, mapNestedVar, mapVarWithNestedCall, nestedCall, dico); |
206 |
|
|
} |
207 |
|
8 |
} |
208 |
|
|
|
209 |
|
|
///Replace all the variables which are string in the given DicoValue, when ${variable} apprears in the value |
210 |
|
|
/** @param dico : DicoValue to be updated |
211 |
|
|
*/ |
212 |
|
8 |
void dico_replace_var(DicoValue & dico){ |
213 |
|
|
//Let's find all the defined variables, linked to the DicoValue, string only |
214 |
|
16 |
PMapKnownVar mapReadyVar; |
215 |
|
16 |
PVecReplaceVar mapNestedVar; |
216 |
|
16 |
MapVarWithNestedCall mapVarWithNestedCall; |
217 |
✓ |
8 |
dico_find_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall, dico); |
218 |
|
|
|
219 |
|
|
//Update variables with nested call, separate those with nested call from the other |
220 |
✓ |
8 |
dico_update_all_var(mapReadyVar, mapNestedVar, mapVarWithNestedCall); |
221 |
|
8 |
} |
222 |
|
|
|
223 |
|
|
|