1 #include "otsdaq/Macros/StringMacros.h"
18 bool StringMacros::wildCardMatch(
const std::string& needle,
const std::string& haystack,
unsigned int* priorityIndex)
try
25 if(needle.size() == 0)
41 if(needle == haystack)
49 if(needle[needle.size() - 1] ==
'*' && needle.substr(0, needle.size() - 1) == haystack.substr(0, needle.size() - 1))
57 if(needle[0] ==
'*' && needle.substr(1) == haystack.substr(haystack.size() - (needle.size() - 1)))
65 if(needle[0] ==
'*' && needle[needle.size() - 1] ==
'*' && std::string::npos != haystack.find(needle.substr(1, needle.size() - 2)))
87 bool StringMacros::inWildCardSet(
const std::string& needle,
const std::set<std::string>& haystack)
89 for(
const auto& haystackString : haystack)
92 if(StringMacros::wildCardMatch(haystackString, needle))
100 std::string StringMacros::decodeURIComponent(
const std::string& data)
102 std::string decodeURIString(data.size(), 0);
104 for(
unsigned int i = 0; i < data.size(); ++i, ++j)
109 if(data[i + 1] >
'9')
110 decodeURIString[j] += (data[i + 1] - 55) * 16;
112 decodeURIString[j] += (data[i + 1] - 48) * 16;
115 if(data[i + 2] >
'9')
116 decodeURIString[j] += (data[i + 2] - 55);
118 decodeURIString[j] += (data[i + 2] - 48);
123 decodeURIString[j] = data[i];
125 decodeURIString.resize(j);
126 return decodeURIString;
130 std::string StringMacros::encodeURIComponent(
const std::string& sourceStr)
132 std::string retStr =
"";
134 for(
const auto& c : sourceStr)
135 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9'))
139 sprintf(encodeStr,
"%%%2.2X", c);
150 std::string StringMacros::convertEnvironmentVariables(
const std::string& data)
152 size_t begin = data.find(
"$");
153 if(begin != std::string::npos)
156 std::string envVariable;
157 std::string converted = data;
159 if(data[begin + 1] ==
'{')
161 end = data.find(
"}", begin + 2);
162 envVariable = data.substr(begin + 2, end - begin - 2);
168 for(end = begin + 1; end < data.size(); ++end)
169 if(!((data[end] >=
'0' && data[end] <=
'9') || (data[end] >=
'A' && data[end] <=
'Z') || (data[end] >=
'a' && data[end] <=
'z') ||
170 data[end] ==
'-' || data[end] ==
'_' || data[end] ==
'.' || data[end] ==
':'))
172 envVariable = data.substr(begin + 1, end - begin - 1);
176 char* envResult = __ENV__(envVariable.c_str());
181 return convertEnvironmentVariables(converted.replace(begin, end - begin, envResult));
185 __SS__ << (
"The environmental variable '" + envVariable +
"' is not set! Please make sure you set it before continuing!") << std::endl;
199 bool StringMacros::isNumber(
const std::string& s)
202 std::vector<std::string> numbers;
203 std::vector<char> ops;
205 StringMacros::getVectorFromString(s,
207 std::set<char>({
'+',
'-',
'*',
'/'}),
208 std::set<char>({
' ',
'\t',
'\n',
'\r'}),
214 for(
const auto& number : numbers)
216 if(number.size() == 0)
219 if(number.find(
"0x") == 0)
222 for(
unsigned int i = 2; i < number.size(); ++i)
224 if(!((number[i] >=
'0' && number[i] <=
'9') || (number[i] >=
'A' && number[i] <=
'F') || (number[i] >=
'a' && number[i] <=
'f')))
232 else if(number[0] ==
'b')
236 for(
unsigned int i = 1; i < number.size(); ++i)
238 if(!((number[i] >=
'0' && number[i] <=
'1')))
248 for(
unsigned int i = 0; i < number.size(); ++i)
249 if(!((number[i] >=
'0' && number[i] <=
'9') || number[i] ==
'.' || number[i] ==
'+' || number[i] ==
'-'))
269 std::string StringMacros::getNumberType(
const std::string& s)
272 std::vector<std::string> numbers;
273 std::vector<char> ops;
275 bool hasDecimal =
false;
277 StringMacros::getVectorFromString(s,
279 std::set<char>({
'+',
'-',
'*',
'/'}),
280 std::set<char>({
' ',
'\t',
'\n',
'\r'}),
286 for(
const auto& number : numbers)
288 if(number.size() == 0)
291 if(number.find(
"0x") == 0)
294 for(
unsigned int i = 2; i < number.size(); ++i)
296 if(!((number[i] >=
'0' && number[i] <=
'9') || (number[i] >=
'A' && number[i] <=
'F') || (number[i] >=
'a' && number[i] <=
'f')))
304 else if(number[0] ==
'b')
308 for(
unsigned int i = 1; i < number.size(); ++i)
310 if(!((number[i] >=
'0' && number[i] <=
'1')))
320 for(
unsigned int i = 0; i < number.size(); ++i)
321 if(!((number[i] >=
'0' && number[i] <=
'9') || number[i] ==
'.' || number[i] ==
'+' || number[i] ==
'-'))
323 else if(number[i] ==
'.')
336 return "unsigned long long";
345 bool StringMacros::getNumber(
const std::string& s,
bool& retValue)
349 __COUT_ERR__ <<
"Invalid empty bool string " << s << __E__;
354 if(s.find(
"1") != std::string::npos || s ==
"true" || s ==
"True" || s ==
"TRUE")
361 if(s.find(
"0") != std::string::npos || s ==
"false" || s ==
"False" || s ==
"FALSE")
367 __COUT_ERR__ <<
"Invalid bool string " << s << __E__;
376 std::string StringMacros::getTimestampString(
const std::string& linuxTimeInSeconds)
378 time_t timestamp(strtol(linuxTimeInSeconds.c_str(), 0, 10));
379 return getTimestampString(timestamp);
386 std::string StringMacros::getTimestampString(
const time_t& linuxTimeInSeconds)
388 std::string retValue(30,
'\0');
391 ::localtime_r(&linuxTimeInSeconds, &tmstruct);
392 ::strftime(&retValue[0], 30,
"%c %Z", &tmstruct);
393 retValue.resize(strlen(retValue.c_str()));
401 std::string StringMacros::validateValueForDefaultStringDataType(
const std::string& value,
bool doConvertEnvironmentVariables)
try
403 return doConvertEnvironmentVariables ? StringMacros::convertEnvironmentVariables(value) : value;
405 catch(
const std::runtime_error& e)
407 __SS__ <<
"Failed to validate value for default string data type. " << __E__ << e.what() << __E__;
415 void StringMacros::getSetFromString(
const std::string& inputString,
416 std::set<std::string>& setToReturn,
417 const std::set<char>& delimiter,
418 const std::set<char>& whitespace)
425 for(; j < inputString.size(); ++j)
426 if((whitespace.find(inputString[j]) != whitespace.end() ||
427 delimiter.find(inputString[j]) != delimiter.end()) &&
430 else if((whitespace.find(inputString[j]) != whitespace.end() ||
431 delimiter.find(inputString[j]) != delimiter.end()) &&
437 setToReturn.emplace(inputString.substr(i, j - i));
444 setToReturn.emplace(inputString.substr(i, j - i));
459 void StringMacros::getVectorFromString(
const std::string& inputString,
460 std::vector<std::string>& listToReturn,
461 const std::set<char>& delimiter,
462 const std::set<char>& whitespace,
463 std::vector<char>* listOfDelimiters)
468 std::set<char>::iterator delimeterSearchIt;
469 char lastDelimiter = 0;
478 for(; c < inputString.size(); ++c)
482 delimeterSearchIt = delimiter.find(inputString[c]);
483 isDelimiter = delimeterSearchIt != delimiter.end();
488 if(whitespace.find(inputString[c]) != whitespace.end()
496 else if(whitespace.find(inputString[c]) != whitespace.end() && i != j)
505 if(listOfDelimiters && listToReturn.size())
512 listOfDelimiters->push_back(lastDelimiter);
514 listToReturn.push_back(inputString.substr(i, j - i));
524 lastDelimiter = *delimeterSearchIt;
533 if(listOfDelimiters && listToReturn.size())
539 listOfDelimiters->push_back(lastDelimiter);
541 listToReturn.push_back(inputString.substr(i, j - i));
545 if(listOfDelimiters && listToReturn.size() - 1 != listOfDelimiters->size() && listToReturn.size() != listOfDelimiters->size())
547 __SS__ <<
"There is a mismatch in delimiters to entries (should be equal or one "
549 << listOfDelimiters->size() <<
" vs " << listToReturn.size() << __E__ <<
"Entries: " << StringMacros::vectorToString(listToReturn) << __E__
550 <<
"Delimiters: " << StringMacros::vectorToString(*listOfDelimiters) << __E__;
568 std::vector<std::string> StringMacros::getVectorFromString(
const std::string& inputString,
569 const std::set<char>& delimiter,
570 const std::set<char>& whitespace,
571 std::vector<char>* listOfDelimiters)
573 std::vector<std::string> listToReturn;
575 StringMacros::getVectorFromString(inputString, listToReturn, delimiter, whitespace, listOfDelimiters);
583 void StringMacros::getMapFromString(
const std::string& inputString,
584 std::map<std::string, std::string>& mapToReturn,
585 const std::set<char>& pairPairDelimiter,
586 const std::set<char>& nameValueDelimiter,
587 const std::set<char>& whitespace)
try
592 bool needValue =
false;
596 for(; j < inputString.size(); ++j)
599 if((whitespace.find(inputString[j]) != whitespace.end() ||
600 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end()) &&
603 else if((whitespace.find(inputString[j]) != whitespace.end() ||
604 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end()) &&
610 name = inputString.substr(i, j - i);
620 if((whitespace.find(inputString[j]) != whitespace.end() ||
621 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end()) &&
624 else if(whitespace.find(inputString[j]) != whitespace.end() ||
625 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end())
632 mapToReturn.emplace(std::pair<std::string, std::string>(name, validateValueForDefaultStringDataType(inputString.substr(i, j - i))
635 if(!emplaceReturn.second)
637 __COUT__ <<
"Ignoring repetitive value ('" << inputString.substr(i, j - i) <<
"') and keeping current value ('"
638 << emplaceReturn.first->second <<
"'). " << __E__;
651 mapToReturn.emplace(std::pair<std::string, std::string>(name, validateValueForDefaultStringDataType(inputString.substr(i, j - i))
654 if(!emplaceReturn.second)
656 __COUT__ <<
"Ignoring repetitive value ('" << inputString.substr(i, j - i) <<
"') and keeping current value ('" << emplaceReturn.first->second
661 catch(
const std::runtime_error& e)
663 __SS__ <<
"Error while extracting a map from the string '" << inputString <<
"'... is it a valid map?" << __E__ << e.what() << __E__;
669 std::string StringMacros::mapToString(
const std::map<std::string, uint8_t>& mapToReturn,
670 const std::string& primaryDelimeter,
671 const std::string& secondaryDelimeter)
673 std::stringstream ss;
675 for(
auto& mapPair : mapToReturn)
680 ss << primaryDelimeter;
681 ss << mapPair.first << secondaryDelimeter << (
unsigned int)mapPair.second;
688 std::string StringMacros::setToString(
const std::set<uint8_t>& setToReturn,
const std::string& delimeter)
690 std::stringstream ss;
692 for(
auto& setValue : setToReturn)
698 ss << (
unsigned int)setValue;
705 std::string StringMacros::vectorToString(
const std::vector<uint8_t>& setToReturn,
const std::string& delimeter)
707 std::stringstream ss;
709 for(
auto& setValue : setToReturn)
715 ss << (
unsigned int)setValue;
730 bool StringMacros::extractCommonChunks(
const std::vector<std::string>& haystack,
731 std::vector<std::string>& commonChunksToReturn,
732 std::vector<std::string>& wildcardStringsToReturn,
733 unsigned int& fixedWildcardLength)
735 fixedWildcardLength = 0;
759 std::pair<
unsigned int ,
unsigned int > wildcardBounds(std::make_pair(-1, 0));
762 for(
unsigned int n = 1; n < haystack.size(); ++n)
763 for(
unsigned int i = 0, j = 0; i < haystack[0].length() && j < haystack[n].length(); ++i, ++j)
765 if(i < wildcardBounds.first)
767 if(haystack[0][i] != haystack[1][j])
769 wildcardBounds.first = i;
776 __COUT__ <<
"Low side = " << wildcardBounds.first <<
" " << haystack[0].substr(0, wildcardBounds.first) << __E__;
779 for(
unsigned int n = 1; n < haystack.size(); ++n)
780 for(
int i = haystack[0].length() - 1, j = haystack[n].length() - 1; i >= (int)wildcardBounds.first && j >= (
int)wildcardBounds.first; --i, --j)
782 if(i > (
int)wildcardBounds.second)
784 if(haystack[0][i] != haystack[n][j])
786 wildcardBounds.second = i + 1;
794 __COUT__ <<
"High side = " << wildcardBounds.second <<
" " << haystack[0].substr(wildcardBounds.second) << __E__;
797 commonChunksToReturn.push_back(haystack[0].substr(0, wildcardBounds.first));
799 if(wildcardBounds.first != (
unsigned int)-1)
802 for(
int i = (wildcardBounds.first + wildcardBounds.second) / 2 + 1; i < (
int)wildcardBounds.second; ++i)
803 if(haystack[0][wildcardBounds.first] == haystack[0][i] &&
804 haystack[0].substr(wildcardBounds.first, wildcardBounds.second - i) == haystack[0].substr(i, wildcardBounds.second - i))
806 std::string multiWildcardString = haystack[0].substr(i, wildcardBounds.second - i);
807 __COUT__ <<
"Multi-wildcard found: " << multiWildcardString << __E__;
809 std::vector<
unsigned int > wildCardInstances;
811 wildCardInstances.push_back(wildcardBounds.first);
813 unsigned int offset = wildCardInstances[0] + multiWildcardString.size() + 1;
814 std::string middleString = haystack[0].substr(offset, (i - 1) - offset);
815 __COUTV__(middleString);
819 while((k = middleString.find(multiWildcardString)) != std::string::npos)
821 __COUT__ <<
"Multi-wildcard found at " << k << __E__;
823 wildCardInstances.push_back(offset + k);
825 middleString = middleString.substr(k + multiWildcardString.size() + 1);
826 offset += k + multiWildcardString.size() + 1;
827 __COUTV__(middleString);
831 wildCardInstances.push_back(i);
833 for(
unsigned int w = 0; w < wildCardInstances.size() - 1; ++w)
835 commonChunksToReturn.push_back(haystack[0].substr(wildCardInstances[w] + wildCardInstances.size(),
836 wildCardInstances[w + 1] - (wildCardInstances[w] + wildCardInstances.size())));
842 for(
unsigned int i = 0; i < commonChunksToReturn[0].size(); ++i)
843 if(commonChunksToReturn[0][commonChunksToReturn[0].size() - 1 - i] ==
'0')
844 ++fixedWildcardLength;
849 for(
unsigned int c = 0; c < commonChunksToReturn.size(); ++c)
851 unsigned int cnt = 0;
852 for(
unsigned int i = 0; i < commonChunksToReturn[c].size(); ++i)
853 if(commonChunksToReturn[c][commonChunksToReturn[c].size() - 1 - i] ==
'0')
858 if(fixedWildcardLength < cnt)
859 fixedWildcardLength = cnt;
860 else if(fixedWildcardLength > cnt)
862 __SS__ <<
"Invalid fixed length found, please simplify indexing between these common chunks: "
863 << StringMacros::vectorToString(commonChunksToReturn) << __E__;
867 __COUTV__(fixedWildcardLength);
869 if(fixedWildcardLength)
870 for(
unsigned int c = 0; c < commonChunksToReturn.size(); ++c)
871 commonChunksToReturn[c] = commonChunksToReturn[c].substr(0, commonChunksToReturn[c].size() - fixedWildcardLength);
874 commonChunksToReturn.push_back(haystack[0].substr(wildcardBounds.second));
880 unsigned int ioff = fixedWildcardLength;
881 bool wildcardsNeeded =
false;
883 for(
unsigned int n = 0; n < haystack.size(); ++n)
885 std::string wildcard =
"";
887 i = ioff + commonChunksToReturn[0].size();
889 if(commonChunksToReturn.size() == 1)
890 wildcard = haystack[n].substr(i);
892 for(
unsigned int c = 1; c < commonChunksToReturn.size(); ++c)
894 if(c == commonChunksToReturn.size() - 1)
895 k = haystack[n].rfind(commonChunksToReturn[c]);
897 k = haystack[n].find(commonChunksToReturn[c], i + 1);
906 wildcard = haystack[n].substr(i, k - i);
907 if(fixedWildcardLength && n == 0)
908 fixedWildcardLength += wildcard.size();
910 __COUT__ <<
"name[" << n <<
"] = " << wildcard <<
" fixed @ " << fixedWildcardLength << __E__;
914 else if(0 && wildcard != haystack[n].substr(i, k - i))
916 __SS__ <<
"Invalid wildcard! for name[" << n <<
"] = " << haystack[n]
917 <<
" - the extraction algorithm is confused, please simplify your naming convention." << __E__;
925 wildcardsNeeded =
true;
926 wildcardStringsToReturn.push_back(wildcard);
930 __COUTV__(StringMacros::vectorToString(commonChunksToReturn));
931 __COUTV__(StringMacros::vectorToString(wildcardStringsToReturn));
933 if(wildcardStringsToReturn.size() != haystack.size())
935 __SS__ <<
"There was a problem during common chunk extraction!" << __E__;
939 return wildcardsNeeded;
947 bool StringMacros::IgnoreCaseCompareStruct::operator()(
const std::string& lhs,
const std::string& rhs)
const
953 for(
unsigned int i = 0; i < lhs.size() && i < rhs.size(); ++i)
956 if((lhs[i] >=
'A' && lhs[i] <=
'Z' && rhs[i] >=
'A' && rhs[i] <=
'Z') || (lhs[i] >=
'a' && lhs[i] <=
'z' && rhs[i] >=
'a' && rhs[i] <=
'z'))
960 return (lhs[i] < rhs[i]);
963 else if(lhs[i] >=
'A' && lhs[i] <=
'Z')
965 if(lhs[i] + 32 == rhs[i])
967 return (lhs[i] + 32 < rhs[i]);
969 else if(rhs[i] >=
'A' && rhs[i] <=
'Z')
971 if(lhs[i] == rhs[i] + 32)
973 return (lhs[i] < rhs[i] + 32);
979 return (lhs[i] < rhs[i]);
984 return lhs.size() < rhs.size();
990 std::string StringMacros::exec(
const char* cmd)
994 std::array<char, 128> buffer;
996 std::shared_ptr<FILE> pipe(popen(cmd,
"r"), pclose);
998 __THROW__(
"popen() failed!");
999 while(!feof(pipe.get()))
1001 if(fgets(buffer.data(), 128, pipe.get()) !=
nullptr)
1002 result += buffer.data();
1013 #include <execinfo.h>
1015 std::string StringMacros::stackTrace()
1017 __SS__ <<
"ots::stackTrace:\n";
1023 size = backtrace(array, 10);
1027 char** messages = backtrace_symbols(array, size);
1031 for(
unsigned int i = 1; i < size && messages != NULL; ++i)
1044 char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
1047 for(
char* p = messages[i]; *p; ++p)
1065 if(mangled_name && offset_begin && offset_end && mangled_name < offset_begin)
1067 *mangled_name++ =
'\0';
1068 *offset_begin++ =
'\0';
1069 *offset_end++ =
'\0';
1072 char* real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
1077 ss <<
"[" << i <<
"] " << messages[i] <<
" : " << real_name <<
"+" << offset_begin << offset_end << std::endl;
1082 ss <<
"[" << i <<
"] " << messages[i] <<
" : " << mangled_name <<
"+" << offset_begin << offset_end << std::endl;
1089 ss <<
"[" << i <<
"] " << messages[i] << std::endl;
1107 char* StringMacros::otsGetEnvironmentVarable(
const char* name,
const std::string& location,
const unsigned int& line)
1109 char* environmentVariablePtr = getenv(name);
1110 if(!environmentVariablePtr)
1112 __SS__ <<
"Environment variable '" << name <<
"' not defined at " << location <<
"[" << line <<
"]" << __E__;
1113 ss <<
"\n\n" << StringMacros::stackTrace() << __E__;
1116 return environmentVariablePtr;
1126 std::string StringMacros::demangleTypeName(
const char* name)
1131 std::unique_ptr<char, void (*)(void*)> res{abi::__cxa_demangle(name, NULL, NULL, &status), std::free};
1133 return (status == 0) ? res.get() : name;
1136 #else // does nothing if not g++
1140 std::string StringMacros::demangleTypeName(
const char* name) {
return name; }