00001 #ifndef _ots_String_Macros_h_
00002 #define _ots_String_Macros_h_
00003
00004 #include "otsdaq-core/Macros/CoutMacros.h"
00005
00006 #include <vector>
00007 #include <set>
00008 #include <map>
00009 #include <typeinfo>
00010
00011 namespace ots
00012 {
00013
00014 struct StringMacros
00015 {
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 static bool wildCardMatch (const std::string& needle, const std::string& haystack, unsigned int* priorityIndex = 0);
00040 static bool inWildCardSet (const std::string needle, const std::set<std::string>& haystack);
00041
00042
00043
00044
00045
00046
00047 template<class T>
00048 static const T& getWildCardMatchFromMap (const std::string needle, const std::map<std::string,T>& haystack)
00049 {
00050 unsigned int matchPriority, bestMatchPriority = 0;
00051
00052 if(!haystack.size())
00053 {
00054 __SS__ << "Needle '" << needle << "' not found in EMPTY wildcard haystack:" << __E__;
00055 throw std::runtime_error(ss.str());
00056 }
00057
00058
00059
00060 std::string bestMatchKey;
00061 for(const auto& haystackPair : haystack)
00062
00063
00064 if(StringMacros::wildCardMatch(haystackPair.first,needle,
00065 &matchPriority))
00066 {
00067 if(matchPriority == 1)
00068 return haystackPair.second;
00069
00070 if(!bestMatchPriority || matchPriority < bestMatchPriority)
00071 {
00072
00073 bestMatchPriority = matchPriority;
00074 bestMatchKey = haystackPair.first;
00075 }
00076 }
00077
00078 if(bestMatchPriority)
00079 {
00080
00081
00082
00083 return haystack.at(bestMatchKey);
00084 }
00085
00086 __SS__ << "Needle '" << needle << "' not found in wildcard haystack:" << __E__;
00087 bool first = true;
00088 for(const auto& haystackPair : haystack)
00089 if(first)
00090 {
00091 ss << ", " << haystackPair.first;
00092 first = false;
00093 }
00094 else
00095 ss << ", " << haystackPair.first;
00096 throw std::runtime_error(ss.str());
00097 }
00098
00099 static std::string decodeURIComponent (const std::string& data);
00100 static std::string convertEnvironmentVariables (const std::string& data);
00101 static bool isNumber (const std::string& s);
00102
00103 template<class T>
00104 static bool getNumber (const std::string& s, T& retValue)
00105 {
00106
00107 std::vector<std::string> numbers;
00108 std::vector<char> ops;
00109
00110 StringMacros::getVectorFromString(s,numbers,
00111 std::set<char>({'+','-','*','/'}),
00112 std::set<char>({' ','\t','\n','\r'}),
00113 &ops);
00114
00115 retValue = 0;
00116
00117 T tmpValue;
00118 unsigned int i = 0;
00119 bool verified;
00120 for(const auto& number:numbers)
00121 {
00122 if(number.size() == 0) continue;
00123
00124
00125
00126
00127
00128 verified = false;
00129
00130
00131 if(typeid(unsigned int) == typeid(retValue) ||
00132 typeid(int) == typeid(retValue) ||
00133 typeid(unsigned long long) == typeid(retValue) ||
00134 typeid(long long) == typeid(retValue) ||
00135 typeid(unsigned long) == typeid(retValue) ||
00136 typeid(long) == typeid(retValue) ||
00137 typeid(unsigned short) == typeid(retValue) ||
00138 typeid(short) == typeid(retValue) ||
00139 typeid(uint8_t) == typeid(retValue))
00140 {
00141 if(number.find("0x") == 0)
00142 {
00143
00144 for(unsigned int i=2;i<number.size();++i)
00145 {
00146 if(!((number[i] >= '0' && number[i] <= '9') ||
00147 (number[i] >= 'A' && number[i] <= 'F') ||
00148 (number[i] >= 'a' && number[i] <= 'f')
00149 ))
00150 {
00151
00152 return false;
00153 }
00154 }
00155 verified = true;
00156 }
00157 else if(number[0] == 'b')
00158 {
00159
00160
00161 for(unsigned int i=1;i<number.size();++i)
00162 {
00163 if(!((number[i] >= '0' && number[i] <= '1')
00164 ))
00165 {
00166
00167 return false;
00168 }
00169 }
00170 verified = true;
00171 }
00172 }
00173
00174
00175 if(!verified)
00176 for(unsigned int i=0;i<number.size();++i)
00177 if(!((number[i] >= '0' && number[i] <= '9') ||
00178 number[i] == '.' ||
00179 number[i] == '+' ||
00180 number[i] == '-'))
00181 return false;
00182
00183
00184
00185 if(typeid(double) == typeid(retValue))
00186 tmpValue = strtod(number.c_str(),0);
00187 else if(typeid(float) == typeid(retValue))
00188 tmpValue = strtof(number.c_str(),0);
00189 else if(typeid(unsigned int) == typeid(retValue) ||
00190 typeid(int) == typeid(retValue) ||
00191 typeid(unsigned long long) == typeid(retValue) ||
00192 typeid(long long) == typeid(retValue) ||
00193 typeid(unsigned long) == typeid(retValue) ||
00194 typeid(long) == typeid(retValue) ||
00195 typeid(unsigned short) == typeid(retValue) ||
00196 typeid(short) == typeid(retValue) ||
00197 typeid(uint8_t) == typeid(retValue))
00198 {
00199 if(number.size() > 2 && number[1] == 'x')
00200 tmpValue = (T)strtol(number.c_str(),0,16);
00201 else if(number.size() > 1 && number[0] == 'b')
00202 tmpValue = (T)strtol(number.substr(1).c_str(),0,2);
00203 else
00204 tmpValue = (T)strtol(number.c_str(),0,10);
00205 }
00206 else
00207 {
00208 __SS__ << "Invalid type '" <<
00209 StringMacros::demangleTypeName(typeid(retValue).name()) <<
00210 "' requested for a numeric string. Data was '" <<
00211 number << "'" << __E__;
00212 __SS_THROW__;
00213 }
00214
00215
00216 if(i == 0)
00217 retValue = tmpValue;
00218 else
00219 {
00220 if(0 && i==1)
00221 {
00222 __COUTV__(StringMacros::vectorToString(numbers));
00223 __COUTV__(StringMacros::vectorToString(ops));
00224 }
00225
00226
00227 switch(ops[i-1])
00228 {
00229 case '+':
00230 retValue += tmpValue;
00231 break;
00232 case '-':
00233 retValue -= tmpValue;
00234 break;
00235 case '*':
00236 retValue *= tmpValue;
00237 break;
00238 case '/':
00239 retValue /= tmpValue;
00240 break;
00241 default:
00242 __SS__ << "Unrecognized operation '" << ops[i-1] << "' found!" << __E__ <<
00243 "Numbers: " <<
00244 StringMacros::vectorToString(numbers) << __E__ <<
00245 "Operations: " <<
00246 StringMacros::vectorToString(ops) << __E__;
00247 __SS_THROW__;
00248 }
00249
00250 }
00251
00252 ++i;
00253 }
00254
00255 return true;
00256 }
00257
00258
00259
00260 template<class T>
00261 static T validateValueForDefaultStringDataType (const std::string& value, bool doConvertEnvironmentVariables=true)
00262 {
00263 T retValue;
00264 try
00265 {
00266
00267 std::string data = doConvertEnvironmentVariables?convertEnvironmentVariables(value):
00268 value;
00269
00270
00271 if(StringMacros::getNumber(data,retValue))
00272 return retValue;
00273 else
00274 {
00275 __SS__ << "Invalid type '" <<
00276 StringMacros::demangleTypeName(typeid(retValue).name()) <<
00277 "' requested for a non-numeric string (must request std::string). Data was '" <<
00278 data << "'" << __E__;
00279 __SS_THROW__;
00280 }
00281 }
00282 catch(const std::runtime_error& e)
00283 {
00284 __SS__ << "Failed to validate the string value for the data type '" <<
00285 StringMacros::demangleTypeName(typeid(retValue).name()) <<
00286 "' requested. " << __E__ << e.what() << __E__;
00287 __SS_THROW__;
00288 }
00289 }
00290 static std::string validateValueForDefaultStringDataType (const std::string& value, bool doConvertEnvironmentVariables=true);
00291
00292
00293 static void getSetFromString (const std::string& inputString, std::set<std::string>& setToReturn, const std::set<char>& delimiter = {',','|','&'}, const std::set<char>& whitespace = {' ','\t','\n','\r'});
00294 static void getVectorFromString (const std::string& inputString, std::vector<std::string>& listToReturn, const std::set<char>& delimiter = {',','|','&'}, const std::set<char>& whitespace = {' ','\t','\n','\r'}, std::vector<char>* listOfDelimiters = 0);
00295 template<class T>
00296 static void getMapFromString (const std::string& inputString, std::map<std::string,T>& mapToReturn, const std::set<char>& pairPairDelimiter = {',','|','&'}, const std::set<char>& nameValueDelimiter = {'=',':'}, const std::set<char>& whitespace = {' ','\t','\n','\r'})
00297 try
00298 {
00299 unsigned int i=0;
00300 unsigned int j=0;
00301 std::string name;
00302 bool needValue = false;
00303
00304
00305
00306 for(;j<inputString.size();++j)
00307 if(!needValue)
00308 {
00309 if((whitespace.find(inputString[j]) != whitespace.end() ||
00310 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end())
00311 && i == j)
00312 ++i;
00313 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00314 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end())
00315 && i != j)
00316 {
00317
00318
00319
00320 name = inputString.substr(i,j-i);
00321
00322 needValue = true;
00323
00324
00325 i = j+1;
00326 }
00327 }
00328 else
00329 {
00330 if((whitespace.find(inputString[j]) != whitespace.end() ||
00331 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end())
00332 && i == j)
00333 ++i;
00334 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00335 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end())
00336 && i != j)
00337 {
00338
00339
00340
00341 auto emplaceReturn = mapToReturn.emplace(std::pair<std::string,T>(
00342 name,
00343 validateValueForDefaultStringDataType<T>(
00344 inputString.substr(i,j-i))
00345 ));
00346
00347 if(!emplaceReturn.second)
00348 {
00349 __COUT__ << "Ignoring repetitive value ('" << inputString.substr(i,j-i) <<
00350 "') and keeping current value ('" << emplaceReturn.first->second << "'). " << __E__;
00351 }
00352
00353 needValue = false;
00354
00355
00356 i = j+1;
00357 }
00358 }
00359
00360 if(i != j)
00361 {
00362 auto emplaceReturn = mapToReturn.emplace(std::pair<std::string,T>(
00363 name,
00364 validateValueForDefaultStringDataType<T>(
00365 inputString.substr(i,j-i))
00366 ));
00367
00368 if(!emplaceReturn.second)
00369 {
00370 __COUT__ << "Ignoring repetitive value ('" << inputString.substr(i,j-i) <<
00371 "') and keeping current value ('" << emplaceReturn.first->second << "'). " << __E__;
00372 }
00373 }
00374 }
00375 catch(const std::runtime_error &e)
00376 {
00377 __SS__ << "Error while extracting a map from the string '" <<
00378 inputString << "'... is it a valid map?" << __E__ << e.what() << __E__;
00379 __SS_THROW__;
00380 }
00381
00382 static void getMapFromString (const std::string& inputString, std::map<std::string,std::string>& mapToReturn, const std::set<char>& pairPairDelimiter = {',','|','&'}, const std::set<char>& nameValueDelimiter = {'=',':'}, const std::set<char>& whitespace = {' ','\t','\n','\r'});
00383 template<class T>
00384 static std::string mapToString (const std::map<std::string,T>& mapToReturn, const std::string& primaryDelimeter = ",", const std::string& secondaryDelimeter = ": ")
00385 {
00386 std::stringstream ss;
00387 bool first = true;
00388 for(auto& mapPair:mapToReturn)
00389 {
00390 if(first) first = false;
00391 else ss << primaryDelimeter;
00392 ss << mapPair.first << secondaryDelimeter <<
00393 mapPair.second;
00394 }
00395 return ss.str();
00396 }
00397 static std::string mapToString (const std::map<std::string,uint8_t>& mapToReturn, const std::string& primaryDelimeter = ",", const std::string& secondaryDelimeter = ": ");
00398 template<class T>
00399 static std::string setToString (const std::set<T>& setToReturn, const std::string& delimeter = ",")
00400 {
00401 std::stringstream ss;
00402 bool first = true;
00403 for(auto& setValue:setToReturn)
00404 {
00405 if(first) first = false;
00406 else ss << delimeter;
00407 ss << setValue;
00408 }
00409 return ss.str();
00410 }
00411 static std::string setToString (const std::set<uint8_t>& setToReturn, const std::string& delimeter = ",");
00412 template<class T>
00413 static std::string vectorToString (const std::vector<T>& setToReturn, const std::string& delimeter = ",")
00414 {
00415 std::stringstream ss;
00416 bool first = true;
00417 for(auto& setValue:setToReturn)
00418 {
00419 if(first) first = false;
00420 else ss << delimeter;
00421 ss << setValue;
00422 }
00423 return ss.str();
00424 }
00425 static std::string vectorToString (const std::vector<uint8_t>& setToReturn, const std::string& delimeter = ",");
00426
00427 static std::string demangleTypeName (const char* name);
00428
00429 };
00430 }
00431 #endif