00001 #include "otsdaq-core/Macros/StringMacros.h"
00002
00003
00004 using namespace ots;
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 bool StringMacros::wildCardMatch(const std::string& needle, const std::string& haystack,
00018 unsigned int* priorityIndex)
00019 try
00020 {
00021
00022
00023
00024
00025
00026 if(needle.size() == 0)
00027 {
00028 if(priorityIndex) *priorityIndex = 1;
00029 return true;
00030 }
00031
00032
00033 if(needle == "*")
00034 {
00035 if(priorityIndex) *priorityIndex = 5;
00036 return true;
00037 }
00038
00039
00040 if(needle == haystack)
00041 {
00042 if(priorityIndex) *priorityIndex = 1;
00043 return true;
00044 }
00045
00046
00047 if(needle[needle.size()-1] == '*' &&
00048 needle.substr(0,needle.size()-1) ==
00049 haystack.substr(0,needle.size()-1))
00050 {
00051 if(priorityIndex) *priorityIndex = 2;
00052 return true;
00053 }
00054
00055
00056 if(needle[0] == '*' && needle.substr(1) ==
00057 haystack.substr(haystack.size() - (needle.size()-1)))
00058 {
00059 if(priorityIndex) *priorityIndex = 3;
00060 return true;
00061 }
00062
00063
00064 if(needle[0] == '*' &&
00065 needle[needle.size()-1] == '*' &&
00066 std::string::npos != haystack.find(needle.substr(1,needle.size()-2)))
00067 {
00068 if(priorityIndex) *priorityIndex = 4;
00069 return true;
00070 }
00071
00072
00073 if(priorityIndex) *priorityIndex = 0;
00074 return false;
00075 }
00076 catch(...)
00077 {
00078 if(priorityIndex) *priorityIndex = 0;
00079 return false;
00080 }
00081
00082
00083
00084
00085
00086 bool StringMacros::inWildCardSet(const std::string needle, const std::set<std::string>& haystack)
00087 {
00088 for(const auto& haystackString : haystack)
00089
00090 if(StringMacros::wildCardMatch(haystackString,needle)) return true;
00091 return false;
00092 }
00093
00094
00095
00096
00097 std::string StringMacros::decodeURIComponent(const std::string &data)
00098 {
00099 std::string decodeURIString(data.size(),0);
00100 unsigned int j=0;
00101 for(unsigned int i=0;i<data.size();++i,++j)
00102 {
00103 if(data[i] == '%')
00104 {
00105
00106 if(data[i+1] > '9')
00107 decodeURIString[j] += (data[i+1]-55)*16;
00108 else
00109 decodeURIString[j] += (data[i+1]-48)*16;
00110
00111
00112 if(data[i+2] > '9')
00113 decodeURIString[j] += (data[i+2]-55);
00114 else
00115 decodeURIString[j] += (data[i+2]-48);
00116
00117 i+=2;
00118 }
00119 else
00120 decodeURIString[j] = data[i];
00121 }
00122 decodeURIString.resize(j);
00123 return decodeURIString;
00124 }
00125
00126
00127
00128
00129
00130
00131 std::string StringMacros::convertEnvironmentVariables(const std::string& data)
00132 {
00133 size_t begin = data.find("$");
00134 if(begin != std::string::npos)
00135 {
00136 size_t end;
00137 std::string envVariable;
00138 std::string converted = data;
00139
00140 if(data[begin+1] == '{')
00141 {
00142 end = data.find("}",begin+2);
00143 envVariable = data.substr(begin+2, end-begin-2);
00144 ++end;
00145 }
00146 else
00147 {
00148
00149 for(end = begin+1; end < data.size(); ++end)
00150 if(!((data[end] >= '0' && data[end] <= '9') ||
00151 (data[end] >= 'A' && data[end] <= 'Z') ||
00152 (data[end] >= 'a' && data[end] <= 'z') ||
00153 data[end] == '-' || data[end] == '_' ||
00154 data[end] == '.' || data[end] == ':'))
00155 break;
00156 envVariable = data.substr(begin+1, end-begin-1);
00157 }
00158
00159
00160 char *envResult = getenv(envVariable.c_str());
00161
00162 if(envResult)
00163 {
00164
00165 return convertEnvironmentVariables(converted.replace(begin,end-begin,envResult));
00166 }
00167 else
00168 {
00169 __SS__ <<
00170 ("The environmental variable '" + envVariable +
00171 "' is not set! Please make sure you set it before continuing!") << std::endl;
00172 __SS_THROW__;
00173 }
00174 }
00175
00176
00177 return data;
00178 }
00179
00180
00181
00182
00183
00184
00185 bool StringMacros::isNumber(const std::string& s)
00186 {
00187
00188 std::vector<std::string> numbers;
00189 std::vector<char> ops;
00190
00191 StringMacros::getVectorFromString(s,numbers,
00192 std::set<char>({'+','-','*','/'}),
00193 std::set<char>({' ','\t','\n','\r'}),
00194 &ops);
00195
00196
00197
00198
00199 for(const auto& number:numbers)
00200 {
00201 if(number.size() == 0) continue;
00202
00203 if(number.find("0x") == 0)
00204 {
00205
00206 for(unsigned int i=2;i<number.size();++i)
00207 {
00208 if(!((number[i] >= '0' && number[i] <= '9') ||
00209 (number[i] >= 'A' && number[i] <= 'F') ||
00210 (number[i] >= 'a' && number[i] <= 'f')
00211 ))
00212 {
00213
00214 return false;
00215 }
00216 }
00217
00218 }
00219 else if(number[0] == 'b')
00220 {
00221
00222
00223 for(unsigned int i=1;i<number.size();++i)
00224 {
00225 if(!((number[i] >= '0' && number[i] <= '1')
00226 ))
00227 {
00228
00229 return false;
00230 }
00231 }
00232 }
00233 else
00234 {
00235
00236 for(unsigned int i=0;i<number.size();++i)
00237 if(!((number[i] >= '0' && number[i] <= '9') ||
00238 number[i] == '.' ||
00239 number[i] == '+' ||
00240 number[i] == '-'))
00241 return false;
00242
00243
00244 }
00245 }
00246
00247
00248
00249
00250 return true;
00251 }
00252
00253
00254
00255
00256 std::string StringMacros::validateValueForDefaultStringDataType(const std::string& value,
00257 bool doConvertEnvironmentVariables)
00258 try
00259 {
00260 return doConvertEnvironmentVariables?
00261 StringMacros::convertEnvironmentVariables(value):
00262 value;
00263 }
00264 catch(const std::runtime_error& e)
00265 {
00266 __SS__ << "Failed to validate value for default string data type. " << __E__ << e.what() << __E__;
00267 __SS_THROW__;
00268 }
00269
00270
00271
00272
00273
00274 void StringMacros::getSetFromString(const std::string& inputString,
00275 std::set<std::string>& setToReturn, const std::set<char>& delimiter,
00276 const std::set<char>& whitespace)
00277 {
00278 unsigned int i=0;
00279 unsigned int j=0;
00280
00281
00282
00283 for(;j<inputString.size();++j)
00284 if((whitespace.find(inputString[j]) != whitespace.end() ||
00285 delimiter.find(inputString[j]) != delimiter.end())
00286 && i == j)
00287 ++i;
00288 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00289 delimiter.find(inputString[j]) != delimiter.end())
00290 && i != j)
00291 {
00292
00293
00294
00295 setToReturn.emplace(inputString.substr(i,j-i));
00296
00297
00298 i = j+1;
00299 }
00300
00301 if(i != j)
00302 setToReturn.emplace(inputString.substr(i,j-i));
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 void StringMacros::getVectorFromString(const std::string& inputString,
00315 std::vector<std::string>& listToReturn, const std::set<char>& delimiter,
00316 const std::set<char>& whitespace, std::vector<char>* listOfDelimiters)
00317 {
00318 unsigned int i=0;
00319 unsigned int j=0;
00320 std::set<char>::iterator delimeterSearchIt;
00321 char lastDelimiter;
00322 bool isDelimiter;
00323
00324
00325
00326
00327
00328 for(;j<inputString.size();++j)
00329 {
00330
00331
00332 delimeterSearchIt = delimiter.find(inputString[j]);
00333 isDelimiter = delimeterSearchIt != delimiter.end();
00334
00335
00336
00337 if((whitespace.find(inputString[j]) != whitespace.end() ||
00338 isDelimiter)
00339 && i == j)
00340 ++i;
00341 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00342 isDelimiter)
00343 && i != j)
00344 {
00345
00346
00347
00348 if(listOfDelimiters && listToReturn.size())
00349 listOfDelimiters->push_back(lastDelimiter);
00350 listToReturn.push_back(inputString.substr(i,j-i));
00351
00352
00353
00354 i = j+1;
00355 }
00356
00357 if(isDelimiter)
00358 lastDelimiter = *delimeterSearchIt;
00359 }
00360
00361 if(i != j)
00362 {
00363 if(listOfDelimiters && listToReturn.size())
00364 listOfDelimiters->push_back(lastDelimiter);
00365 listToReturn.push_back(inputString.substr(i,j-i));
00366 }
00367
00368
00369 if(listOfDelimiters && listToReturn.size() - 1 != listOfDelimiters->size())
00370 {
00371 __SS__ << "There is a mismatch in delimiters to entries (should be one less delimiter): " <<
00372 listOfDelimiters->size() <<
00373 " vs " << listToReturn.size() << __E__ <<
00374 "Entries: " <<
00375 StringMacros::vectorToString(listToReturn) << __E__ <<
00376 "Delimiters: " <<
00377 StringMacros::vectorToString(*listOfDelimiters) << __E__;
00378 __SS_THROW__;
00379 }
00380
00381 }
00382
00383
00384
00385
00386
00387 void StringMacros::getMapFromString(const std::string& inputString,
00388 std::map<std::string,std::string>& mapToReturn,
00389 const std::set<char>& pairPairDelimiter, const std::set<char>& nameValueDelimiter,
00390 const std::set<char>& whitespace)
00391 try
00392 {
00393 unsigned int i=0;
00394 unsigned int j=0;
00395 std::string name;
00396 bool needValue = false;
00397
00398
00399
00400 for(;j<inputString.size();++j)
00401 if(!needValue)
00402 {
00403 if((whitespace.find(inputString[j]) != whitespace.end() ||
00404 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end())
00405 && i == j)
00406 ++i;
00407 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00408 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end())
00409 && i != j)
00410 {
00411
00412
00413
00414 name = inputString.substr(i,j-i);
00415
00416 needValue = true;
00417
00418
00419 i = j+1;
00420 }
00421 }
00422 else
00423 {
00424 if((whitespace.find(inputString[j]) != whitespace.end() ||
00425 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end())
00426 && i == j)
00427 ++i;
00428 else if((whitespace.find(inputString[j]) != whitespace.end() ||
00429 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end())
00430 && i != j)
00431 {
00432
00433
00434
00435 auto emplaceReturn = mapToReturn.emplace(std::pair<std::string,std::string>(
00436 name,
00437 validateValueForDefaultStringDataType(
00438 inputString.substr(i,j-i))
00439 ));
00440
00441 if(!emplaceReturn.second)
00442 {
00443 __COUT__ << "Ignoring repetitive value ('" << inputString.substr(i,j-i) <<
00444 "') and keeping current value ('" << emplaceReturn.first->second << "'). " << __E__;
00445 }
00446
00447 needValue = false;
00448
00449
00450 i = j+1;
00451 }
00452 }
00453
00454 if(i != j)
00455 {
00456 auto emplaceReturn = mapToReturn.emplace(std::pair<std::string,std::string>(
00457 name,
00458 validateValueForDefaultStringDataType(
00459 inputString.substr(i,j-i))
00460 ));
00461
00462 if(!emplaceReturn.second)
00463 {
00464 __COUT__ << "Ignoring repetitive value ('" << inputString.substr(i,j-i) <<
00465 "') and keeping current value ('" << emplaceReturn.first->second << "'). " << __E__;
00466 }
00467 }
00468 }
00469 catch(const std::runtime_error &e)
00470 {
00471 __SS__ << "Error while extracting a map from the string '" <<
00472 inputString << "'... is it a valid map?" << __E__ << e.what() << __E__;
00473 __SS_THROW__;
00474 }
00475
00476
00477
00478
00479 std::string StringMacros::mapToString(const std::map<std::string,uint8_t>& mapToReturn,
00480 const std::string& primaryDelimeter, const std::string& secondaryDelimeter)
00481 {
00482 std::stringstream ss;
00483 bool first = true;
00484 for(auto& mapPair:mapToReturn)
00485 {
00486 if(first) first = false;
00487 else ss << primaryDelimeter;
00488 ss << mapPair.first << secondaryDelimeter << (unsigned int)mapPair.second;
00489 }
00490 return ss.str();
00491 }
00492
00493
00494
00495 std::string StringMacros::setToString(const std::set<uint8_t>& setToReturn, const std::string& delimeter)
00496 {
00497 std::stringstream ss;
00498 bool first = true;
00499 for(auto& setValue:setToReturn)
00500 {
00501 if(first) first = false;
00502 else ss << delimeter;
00503 ss << (unsigned int)setValue;
00504 }
00505 return ss.str();
00506 }
00507
00508
00509
00510 std::string StringMacros::vectorToString(const std::vector<uint8_t>& setToReturn, const std::string& delimeter)
00511 {
00512 std::stringstream ss;
00513 bool first = true;
00514 for(auto& setValue:setToReturn)
00515 {
00516 if(first) first = false;
00517 else ss << delimeter;
00518 ss << (unsigned int)setValue;
00519 }
00520 return ss.str();
00521 }
00522
00523
00524 #ifdef __GNUG__
00525 #include <cstdlib>
00526 #include <memory>
00527 #include <cxxabi.h>
00528
00529
00530
00531
00532 std::string StringMacros::demangleTypeName(const char* name)
00533 {
00534 int status = -4;
00535
00536
00537 std::unique_ptr<char, void(*)(void*)> res {
00538 abi::__cxa_demangle(name, NULL, NULL, &status),
00539 std::free
00540 };
00541
00542 return (status==0) ? res.get() : name ;
00543 }
00544
00545 #else //does nothing if not g++
00546
00547
00548
00549 std::string StringMacros::demangleTypeName(const char* name)
00550 {
00551 return name;
00552 }
00553
00554
00555 #endif
00556
00557
00558
00559
00560
00561
00562