1 #include "otsdaq/Macros/StringMacros.h"
12 std::map<std::string ,
13 std::map<std::string , std::string >>
14 StringMacros::systemVariables_;
15 const std::string StringMacros::TBD =
"To-be-defined";
18 unsigned int StringMacros::getConcurrencyCount(
void)
22 return std::stoul(systemVariables_.at(
"System").at(
"logicalCores"));
29 if(sched_getaffinity(0,
sizeof(mask), &mask) == 0)
30 hw = CPU_COUNT(&mask);
31 systemVariables_[
"System"][
"logicalCores"] = std::to_string(hw);
39 std::string StringMacros::getPersistentSystemVariablesFilePath(
void)
41 return std::string(__ENV__(
"USER_DATA")) +
"/ServiceData/ArtdaqSystemVariables.dat";
55 static std::mutex loadMutex;
56 std::lock_guard<std::mutex> lock(loadMutex);
58 std::ifstream file(getPersistentSystemVariablesFilePath());
62 auto& ns = systemVariables_[
"artdaq"];
64 while(std::getline(file, line))
66 size_t eqPos = line.find(
'=');
67 if(eqPos == std::string::npos)
69 ns[line.substr(0, eqPos)] = line.substr(eqPos + 1);
78 #define TLVL_EscapeString 30
79 #define TLVL_EnvMath 49
80 #define TLVL_EnvSub 50
95 const std::string& haystack,
96 unsigned int* priorityIndex)
99 __COUTT__ <<
"\t\t wildCardMatch: " << needle <<
" =in= " << haystack <<
" ??? "
103 if(needle.size() == 0)
119 if(needle == haystack)
126 const bool hasWildcard = (needle.find(
'*') != std::string::npos);
135 if(needle[needle.size() - 1] ==
'*' &&
136 needle.substr(0, needle.size() - 1) == haystack.substr(0, needle.size() - 1))
144 if(needle[0] ==
'*' &&
145 needle.substr(1) == haystack.substr(haystack.size() - (needle.size() - 1)))
154 std::size_t patternPos = 0;
155 std::size_t textPos = 0;
156 std::size_t lastStarPattern = std::string::npos;
157 std::size_t lastStarTextPos = std::string::npos;
158 while(textPos < haystack.size())
160 if(patternPos < needle.size() && needle[patternPos] == haystack[textPos])
165 else if(patternPos < needle.size() && needle[patternPos] ==
'*')
167 lastStarPattern = patternPos++;
168 lastStarTextPos = textPos;
170 else if(lastStarPattern != std::string::npos)
172 patternPos = lastStarPattern + 1;
173 textPos = ++lastStarTextPos;
183 while(patternPos < needle.size() && needle[patternPos] ==
'*')
186 if(patternPos == needle.size())
210 const std::set<std::string>& haystack)
212 for(
const auto& haystackString : haystack)
215 if(haystackString.size() && haystackString[0] ==
'!')
232 std::string decodeURIString(data.size(), 0);
234 for(
unsigned int i = 0; i < data.size(); ++i, ++j)
239 if(data[i + 1] >
'9')
240 decodeURIString[j] += (data[i + 1] - 55) * 16;
242 decodeURIString[j] += (data[i + 1] - 48) * 16;
245 if(data[i + 2] >
'9')
246 decodeURIString[j] += (data[i + 2] - 55);
248 decodeURIString[j] += (data[i + 2] - 48);
253 decodeURIString[j] = data[i];
255 decodeURIString.resize(j);
256 return decodeURIString;
260 std::string StringMacros::encodeURIComponent(
const std::string& sourceStr)
262 std::string retStr =
"";
264 for(
const auto& c : sourceStr)
265 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9'))
269 sprintf(encodeStr,
"%%%2.2X", (uint8_t)c);
279 std::map<char, std::string> replacements = {
287 while(pos < str.size())
289 auto it = replacements.find(str[pos]);
290 if(it != replacements.end())
292 str.replace(pos, 1, it->second);
293 pos += it->second.size();
314 bool allowWhiteSpace ,
317 unsigned int ws = -1;
320 __COUTVS__(TLVL_EscapeString, allowWhiteSpace);
321 __COUTVS__(TLVL_EscapeString, forHtml);
323 for(
unsigned int i = 0; i < inString.length(); i++)
324 if(inString[i] !=
' ')
326 __COUTS__(TLVL_EscapeString)
327 << i <<
". " << inString[i] <<
":" << (int)inString[i] << std::endl;
330 if(inString[i] ==
'\r' || inString[i] ==
'\n' ||
331 inString[i] ==
'\t' ||
334 (inString[i] >
char(126) &&
335 inString[i] <
char(161)))
342 if(i + 2 < inString.size() && inString[i] == char(0xE2) &&
343 inString[i + 1] == char(0x80) &&
362 if(inString[i] ==
'\n')
366 sprintf(htmlTmp,
"&#%3.3d", inString[i]);
368 i, std::string(htmlTmp));
377 else if(inString[i] ==
'\t')
385 "        ");
387 i, std::string(htmlTmp));
395 sprintf(htmlTmp,
"	");
397 i, std::string(htmlTmp));
409 inString.erase(i, 1);
412 __COUTS__(31) << inString << std::endl;
416 __COUTS__(31) << inString << std::endl;
419 if(inString[i] ==
'\"' || inString[i] ==
'\'')
424 unsigned int backslashCount = 0;
425 for(
unsigned int j = i; j > 0 && inString[j - 1] ==
'\\'; --j)
428 if(backslashCount % 2 == 1)
431 inString.erase(i - 1, 1);
437 (inString[i] ==
'\'')
440 inString.replace(i + 5, 1, 1,
';');
444 else if(inString[i] ==
'&')
446 inString.insert(i,
"&");
447 inString.replace(i + 4, 1, 1,
';');
450 else if(inString[i] ==
'<' || inString[i] ==
'>')
475 else if(inString[i] >=
char(161) &&
476 inString[i] <=
char(255))
478 sprintf(htmlTmp,
"&#%3.3d", inString[i]);
479 inString.insert(i, std::string(htmlTmp));
480 inString.replace(i + 5, 1, 1,
';');
484 __COUTS__(TLVL_EscapeString) << inString << std::endl;
488 else if(allowWhiteSpace)
496 inString.insert(i,
" ");
499 inString.insert(i,
" ");
500 inString.replace(i + 5, 1, 1,
';');
505 __COUTS__(TLVL_EscapeString) << inString.size() <<
" " << ws << std::endl;
509 __COUTS__(TLVL_EscapeString) << inString.size() <<
" " << inString << std::endl;
515 if(ws == (
unsigned int)-1)
517 return inString.substr(0, ws + 1);
527 unsigned int sz = str.size();
531 std::string retStr =
"";
532 retStr.reserve(str.size() * 2);
533 for(
unsigned int i = 0; i < sz; ++i)
565 unsigned int sz = str.size();
569 std::string retStr =
"";
570 retStr.reserve(str.size());
572 for(; i < sz - 1; ++i)
604 retStr += str[sz - 1];
615 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](
unsigned char ch) {
616 return !std::isspace(ch);
620 s.erase(std::find_if(
621 s.rbegin(), s.rend(), [](
unsigned char ch) { return !std::isspace(ch); })
640 size_t begin = data.find(
"$");
641 if(begin != std::string::npos && begin + 1 < data.size())
644 std::string envVariable;
645 std::string converted = data;
646 bool usedBraces =
false;
648 while(begin && begin != std::string::npos &&
649 converted[begin - 1] ==
652 converted.replace(begin - 1, 1,
"");
653 begin = converted.find(
"$", begin + 1);
654 if(begin == std::string::npos)
656 __COUTS__(TLVL_EnvSub)
657 <<
"Only found escaped $'s that will not be converted: " << converted
666 if(begin + 2 < data.size() && data[begin + 1] ==
'(' && data[begin + 2] ==
'(')
668 end = data.find(
"))", begin + 3);
669 if(end == std::string::npos)
671 __SS__ <<
"Arithmetic expansion '$((...)),' at pos " << begin
672 <<
" in value, is missing closing '))'! Here was the value: "
677 std::string expression = data.substr(begin + 3, end - begin - 3);
678 __COUTVS__(TLVL_EnvMath, expression);
682 __COUTVS__(TLVL_EnvMath, expression);
689 __SS__ <<
"Arithmetic expansion '$((...)),' at pos " << begin
690 <<
" in value, does not evaluate to a number! Here was the value: "
695 __COUTS__(TLVL_EnvMath) <<
"Arithmetic result: " << result << __E__;
699 converted.replace(begin, end - begin + 2, std::to_string(result)));
701 else if(data[begin + 1] ==
'{')
703 end = data.find(
"}", begin + 2);
704 envVariable = data.substr(begin + 2, end - begin - 2);
711 for(end = begin + 1; end < data.size(); ++end)
712 if(!((data[end] >=
'0' && data[end] <=
'9') ||
713 (data[end] >=
'A' && data[end] <=
'Z') ||
714 (data[end] >=
'a' && data[end] <=
'z') || data[end] ==
'-' ||
715 data[end] ==
'_' || data[end] ==
'.' || data[end] ==
':'))
717 envVariable = data.substr(begin + 1, end - begin - 1);
720 __COUTVS__(TLVL_EnvSub, data);
721 __COUTVS__(TLVL_EnvSub, envVariable);
722 if(usedBraces && envVariable.starts_with(
"OTS."))
724 __COUTS__(TLVL_EnvSub) <<
"OTS system variable detected!" << __E__;
728 if(sysVarSplit.size() != 3 ||
729 systemVariables_.find(sysVarSplit[1]) == systemVariables_.end() ||
730 systemVariables_.at(sysVarSplit[1]).find(sysVarSplit[2]) ==
731 systemVariables_.at(sysVarSplit[1]).end())
734 <<
"System variable ${" << envVariable
735 <<
"} is not valid or was not found!"
737 <<
"If you were trying to access an ots System Variable, the correct "
739 <<
"${OTS.<variable>.<property>}, e.g. "
740 "${OTS.ActiveStateMachine.name}"
742 <<
"If you were trying to insert an arithmetic operation, the "
744 "syntax is $((4 - 3)) or $(($ENVVAR1 - $ENVVAR2))"
746 <<
"Available system variables:" << __E__;
749 for(
const auto& varPair : systemVariables_)
751 ss <<
"\n OTS." << varPair.first <<
".*";
752 for(
const auto& propPair : varPair.second)
753 ss <<
"\n - OTS." << varPair.first <<
"." << propPair.first;
763 systemVariables_.at(sysVarSplit[1]).at(sysVarSplit[2])));
767 char* envResult =
nullptr;
770 envResult = __ENV__(envVariable.c_str());
772 catch(
const std::runtime_error& e)
775 << (
"The environmental variable '" + envVariable +
776 "' is not set! Please make sure you set it before continuing!" +
778 "If you were trying to access an ots System Variable, the "
779 "correct syntax is " +
780 "${OTS.<variable>.<property>}, e.g. "
781 "${OTS.ActiveStateMachine.name}")
783 ss <<
"\n" << e.what() << __E__;
789 converted.replace(begin, end - begin, envResult));
793 __COUTS__(TLVL_EnvSub) <<
"Result: " << data << __E__;
805 std::vector<std::string> numbers;
806 std::vector<char> ops;
814 std::set<char>({
'+',
'-',
'*',
'/'}),
815 std::set<char>({
' ',
'\t',
'\n',
'\r'}),
821 for(
const auto& number : numbers)
823 if(number.size() == 0)
826 if(number.find(
"0x") == 0)
829 for(
unsigned int i = 2; i < number.size(); ++i)
831 if(!((number[i] >=
'0' && number[i] <=
'9') ||
832 (number[i] >=
'A' && number[i] <=
'F') ||
833 (number[i] >=
'a' && number[i] <=
'f')))
841 else if(number[0] ==
'b')
845 for(
unsigned int i = 1; i < number.size(); ++i)
847 if(!((number[i] >=
'0' && number[i] <=
'1')))
857 for(
unsigned int i = 0; i < number.size(); ++i)
858 if(!((number[i] >=
'0' && number[i] <=
'9') || number[i] ==
'.' ||
859 number[i] ==
'+' || number[i] ==
'-'))
882 std::vector<std::string> numbers;
883 std::vector<char> ops;
885 bool hasDecimal =
false;
890 std::set<char>({
'+',
'-',
'*',
'/'}),
891 std::set<char>({
' ',
'\t',
'\n',
'\r'}),
897 for(
const auto& number : numbers)
899 if(number.size() == 0)
902 if(number.find(
"0x") == 0)
905 for(
unsigned int i = 2; i < number.size(); ++i)
907 if(!((number[i] >=
'0' && number[i] <=
'9') ||
908 (number[i] >=
'A' && number[i] <=
'F') ||
909 (number[i] >=
'a' && number[i] <=
'f')))
917 else if(number[0] ==
'b')
921 for(
unsigned int i = 1; i < number.size(); ++i)
923 if(!((number[i] >=
'0' && number[i] <=
'1')))
933 for(
unsigned int i = 0; i < number.size(); ++i)
934 if(!((number[i] >=
'0' && number[i] <=
'9') || number[i] ==
'.' ||
935 number[i] ==
'+' || number[i] ==
'-'))
937 else if(number[i] ==
'.')
950 return "unsigned long long";
963 __COUT_ERR__ <<
"Invalid empty bool string " << s << __E__;
968 if(s.find(
"1") != std::string::npos || s ==
"true" || s ==
"True" || s ==
"TRUE")
975 if(s.find(
"0") != std::string::npos || s ==
"false" || s ==
"False" || s ==
"FALSE")
981 __COUT_ERR__ <<
"Invalid bool string " << s << __E__;
992 time_t timestamp(strtol(linuxTimeInSeconds.c_str(), 0, 10));
1012 std::stringstream ss;
1013 int days = t / 60 / 60 / 24;
1016 ss << days <<
" day" << (days > 1 ?
"s" :
"") <<
", ";
1017 t -= days * 60 * 60 * 24;
1021 ss << std::setw(2) << std::setfill(
'0') << (t / 60 / 60) <<
":" << std::setw(2)
1022 << std::setfill(
'0') << ((t % (60 * 60)) / 60) <<
":" << std::setw(2)
1023 << std::setfill(
'0') << (t % 60);
1028 uint64_t StringMacros::nowEpochMs()
1030 return std::chrono::duration_cast<std::chrono::milliseconds>(
1031 std::chrono::system_clock::now().time_since_epoch())
1039 const std::string& value,
bool doConvertEnvironmentVariables)
1042 return doConvertEnvironmentVariables
1046 catch(
const std::runtime_error& e)
1048 __SS__ <<
"Failed to validate value for default string data type. " << __E__
1049 << e.what() << __E__;
1058 std::set<std::string>& setToReturn,
1059 const std::set<char>& delimiter,
1060 const std::set<char>& whitespace)
1067 for(; j < inputString.size(); ++j)
1068 if((whitespace.find(inputString[j]) !=
1070 delimiter.find(inputString[j]) != delimiter.end()) &&
1073 else if((whitespace.find(inputString[j]) !=
1076 delimiter.find(inputString[j]) != delimiter.end()) &&
1082 setToReturn.emplace(inputString.substr(i, j - i));
1089 setToReturn.emplace(inputString.substr(i, j - i));
1105 std::vector<std::string>& listToReturn,
1106 const std::set<char>& delimiter,
1107 const std::set<char>& whitespace,
1108 std::vector<char>* listOfDelimiters,
1109 bool decodeURIComponents)
1114 std::set<char>::iterator delimeterSearchIt;
1115 char lastDelimiter = 0;
1124 for(; c < inputString.size(); ++c)
1128 delimeterSearchIt = delimiter.find(inputString[c]);
1129 isDelimiter = delimeterSearchIt != delimiter.end();
1134 if(whitespace.find(inputString[c]) !=
1143 else if(whitespace.find(inputString[c]) != whitespace.end() &&
1148 else if(isDelimiter)
1153 if(listOfDelimiters && listToReturn.size())
1160 listOfDelimiters->push_back(lastDelimiter);
1163 inputString.substr(i, j - i))
1164 : inputString.substr(i, j - i));
1174 lastDelimiter = *delimeterSearchIt;
1183 if(listOfDelimiters && listToReturn.size())
1189 listOfDelimiters->push_back(lastDelimiter);
1192 inputString.substr(i, j - i))
1193 : inputString.substr(i, j - i));
1197 if(listOfDelimiters && listToReturn.size() - 1 != listOfDelimiters->size() &&
1198 listToReturn.size() != listOfDelimiters->size())
1200 __SS__ <<
"There is a mismatch in delimiters to entries (should be equal or one "
1202 << listOfDelimiters->size() <<
" vs " << listToReturn.size() << __E__
1224 const std::string& inputString,
1225 const std::set<char>& delimiter,
1226 const std::set<char>& whitespace,
1227 std::vector<char>* listOfDelimiters,
1228 bool decodeURIComponents)
1230 std::vector<std::string> listToReturn;
1237 decodeURIComponents);
1238 return listToReturn;
1244 std::string& initValue,
1245 std::string& stepValue,
1248 size_t stepPos = inputString.rfind(delimiter);
1249 if(stepPos == std::string::npos || stepPos == 0)
1251 size_t initPos = inputString.rfind(delimiter, stepPos - 1);
1252 if(initPos == std::string::npos)
1255 auto trim = [](std::string s) {
1256 size_t b = s.find_first_not_of(
" \t\n\r");
1257 size_t e = s.find_last_not_of(
" \t\n\r");
1258 return b == std::string::npos ? std::string() : s.substr(b, e - b + 1);
1260 name =
trim(inputString.substr(0, initPos));
1261 initValue =
trim(inputString.substr(initPos + 1, stepPos - initPos - 1));
1262 stepValue =
trim(inputString.substr(stepPos + 1));
1263 return name.size() > 0;
1271 std::map<std::string, std::string>& mapToReturn,
1272 const std::set<char>& pairPairDelimiter,
1273 const std::set<char>& nameValueDelimiter,
1274 const std::set<char>& whitespace)
1280 bool needValue =
false;
1284 for(; j < inputString.size(); ++j)
1287 if((whitespace.find(inputString[j]) !=
1289 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end()) &&
1292 else if((whitespace.find(inputString[j]) !=
1295 nameValueDelimiter.find(inputString[j]) !=
1296 nameValueDelimiter.end()) &&
1302 name = inputString.substr(i, j - i);
1312 if((whitespace.find(inputString[j]) !=
1314 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end()) &&
1317 else if(whitespace.find(inputString[j]) !=
1320 pairPairDelimiter.find(inputString[j]) !=
1321 pairPairDelimiter.end())
1327 auto emplaceReturn =
1328 mapToReturn.emplace(std::pair<std::string, std::string>(
1331 inputString.substr(i, j - i))
1334 if(!emplaceReturn.second)
1336 __COUT__ <<
"Ignoring repetitive value ('"
1337 << inputString.substr(i, j - i)
1338 <<
"') and keeping current value ('"
1339 << emplaceReturn.first->second <<
"'). " << __E__;
1351 auto emplaceReturn =
1352 mapToReturn.emplace(std::pair<std::string, std::string>(
1355 inputString.substr(i, j - i))
1358 if(!emplaceReturn.second)
1360 __COUT__ <<
"Ignoring repetitive value ('" << inputString.substr(i, j - i)
1361 <<
"') and keeping current value ('" << emplaceReturn.first->second
1366 catch(
const std::runtime_error& e)
1368 __SS__ <<
"Error while extracting a map from the string '" << inputString
1369 <<
"'... is it a valid map?" << __E__ << e.what() << __E__;
1376 const std::string& primaryDelimeter,
1377 const std::string& secondaryDelimeter)
1379 std::stringstream ss;
1381 for(
auto& mapPair : mapToReturn)
1386 ss << primaryDelimeter;
1387 ss << mapPair.first << secondaryDelimeter << (
unsigned int)mapPair.second;
1395 const std::string& delimeter)
1397 std::stringstream ss;
1399 for(
auto& setValue : setToReturn)
1405 ss << (
unsigned int)setValue;
1413 const std::string& delimeter)
1415 std::stringstream ss;
1417 if(delimeter ==
"\n")
1419 for(
auto& setValue : setToReturn)
1425 ss << (
unsigned int)setValue;
1441 std::vector<std::string>& commonChunksToReturn,
1442 std::vector<std::string>& wildcardStringsToReturn,
1443 unsigned int& fixedWildcardLength)
1445 fixedWildcardLength = 0;
1470 std::pair<
unsigned int ,
unsigned int > wildcardBounds(
1471 std::make_pair(-1, 0));
1474 for(
unsigned int n = 1; n < haystack.size(); ++n)
1475 for(
unsigned int i = 0, j = 0;
1476 i < haystack[0].length() && j < haystack[n].length();
1479 if(i < wildcardBounds.first)
1481 if(haystack[0][i] != haystack[n][j])
1483 wildcardBounds.first = i;
1490 __COUTS__(3) <<
"Low side = " << wildcardBounds.first <<
" "
1491 << haystack[0].substr(0, wildcardBounds.first) << __E__;
1494 for(
unsigned int n = 1; n < haystack.size(); ++n)
1495 for(
int i = haystack[0].length() - 1, j = haystack[n].length() - 1;
1496 i >= (int)wildcardBounds.first && j >= (
int)wildcardBounds.first;
1499 if(i > (
int)wildcardBounds.second)
1501 if(haystack[0][i] != haystack[n][j])
1503 wildcardBounds.second = i + 1;
1511 __COUTS__(3) <<
"High side = " << wildcardBounds.second <<
" "
1512 << haystack[0].substr(wildcardBounds.second) << __E__;
1515 commonChunksToReturn.push_back(haystack[0].substr(0, wildcardBounds.first));
1517 if(wildcardBounds.first != (
unsigned int)-1)
1520 for(
int i = (wildcardBounds.first + wildcardBounds.second) / 2 + 1;
1521 i < (
int)wildcardBounds.second;
1523 if(haystack[0][wildcardBounds.first] == haystack[0][i] &&
1524 haystack[0].substr(wildcardBounds.first, wildcardBounds.second - i) ==
1525 haystack[0].substr(i, wildcardBounds.second - i))
1527 std::string multiWildcardString =
1528 haystack[0].substr(i, wildcardBounds.second - i);
1529 __COUT__ <<
"Potential multi-wildcard found: " << multiWildcardString
1530 <<
" at position i=" << i << __E__;
1532 std::vector<
unsigned int > wildCardInstances;
1534 wildCardInstances.push_back(wildcardBounds.first);
1536 unsigned int offset =
1537 wildCardInstances[0] + multiWildcardString.size() + 1;
1538 std::string middleString = haystack[0].substr(offset, (i - 1) - offset);
1539 __COUTV__(middleString);
1543 while((k = middleString.find(multiWildcardString)) != std::string::npos)
1545 __COUT__ <<
"Multi-wildcard found at " << k << __E__;
1547 wildCardInstances.push_back(offset + k);
1550 middleString.substr(k + multiWildcardString.size() + 1);
1551 offset += k + multiWildcardString.size() + 1;
1552 __COUTV__(middleString);
1556 wildCardInstances.push_back(i);
1558 for(
unsigned int w = 0; w < wildCardInstances.size() - 1; ++w)
1560 __COUTV__(wildCardInstances[w]);
1561 __COUTV__(wildCardInstances[w + 1]);
1562 __COUTV__(wildCardInstances.size());
1563 commonChunksToReturn.push_back(haystack[0].substr(
1564 wildCardInstances[w] + multiWildcardString.size(),
1565 wildCardInstances[w + 1] -
1566 (wildCardInstances[w] + multiWildcardString.size())));
1572 for(
unsigned int c = 1; c < commonChunksToReturn.size(); ++c)
1574 __COUT__ <<
"Checking [" << c <<
"]: " << commonChunksToReturn[c] << __E__;
1575 for(
unsigned int n = 1; n < haystack.size(); ++n)
1577 __COUT__ <<
"Checking chunks work with haystack [" << n
1578 <<
"]: " << haystack[n] << __E__;
1579 __COUTV__(commonChunksToReturn[0].size());
1580 std::string wildCardValue = haystack[n].substr(
1581 commonChunksToReturn[0].size(),
1582 haystack[n].find(commonChunksToReturn[1],
1583 commonChunksToReturn[0].size() + 1) -
1584 commonChunksToReturn[0].size());
1585 __COUTTV__(wildCardValue);
1587 std::string builtString =
"";
1588 for(
unsigned int cc = 0; cc < commonChunksToReturn.size(); ++cc)
1589 builtString += commonChunksToReturn[cc] + wildCardValue;
1590 __COUTTV__(builtString);
1591 __COUTTV__(wildCardValue);
1593 if(haystack[n].find(builtString) != 0)
1595 __COUT__ <<
"Dropping common chunk " << commonChunksToReturn[c]
1596 <<
", built '" << builtString <<
"' not found in "
1597 << haystack[n] << __E__;
1598 commonChunksToReturn.erase(commonChunksToReturn.begin() + c);
1603 __COUTT__ <<
"Found built '" << builtString <<
"' in " << haystack[n]
1609 __COUTTV__(commonChunksToReturn[0].size());
1611 __COUTTV__(fixedWildcardLength);
1613 for(
unsigned int i = 0; i < commonChunksToReturn[0].size(); ++i)
1614 if(commonChunksToReturn[0][commonChunksToReturn[0].size() - 1 - i] ==
'0')
1616 ++fixedWildcardLength;
1617 __COUTT__ <<
"Trying for added fixed length +1 to " << fixedWildcardLength
1624 for(
unsigned int c = 0; c < commonChunksToReturn.size(); ++c)
1626 unsigned int cnt = 0;
1627 for(
unsigned int i = 0; i < commonChunksToReturn[c].size(); ++i)
1628 if(commonChunksToReturn[c][commonChunksToReturn[c].size() - 1 - i] ==
'0')
1633 if(fixedWildcardLength < cnt)
1634 fixedWildcardLength = cnt;
1635 else if(fixedWildcardLength > cnt)
1637 __SS__ <<
"Invalid fixed length found, please simplify indexing between "
1638 "these common chunks: "
1643 __COUTTV__(fixedWildcardLength);
1645 if(fixedWildcardLength)
1646 for(
unsigned int c = 0; c < commonChunksToReturn.size(); ++c)
1647 commonChunksToReturn[c] = commonChunksToReturn[c].substr(
1648 0, commonChunksToReturn[c].size() - fixedWildcardLength);
1651 commonChunksToReturn.push_back(haystack[0].substr(wildcardBounds.second));
1658 unsigned int ioff = fixedWildcardLength;
1659 bool wildcardsNeeded =
false;
1660 bool someLeadingZeros =
false;
1661 bool allWildcardsSameSize =
true;
1663 for(
unsigned int n = 0; n < haystack.size(); ++n)
1665 std::string wildcard =
"";
1667 i = ioff + commonChunksToReturn[0].size();
1669 if(commonChunksToReturn.size() == 1)
1670 wildcard = haystack[n].substr(i);
1672 for(
unsigned int c = 1; c < commonChunksToReturn.size(); ++c)
1674 if(c == commonChunksToReturn.size() - 1)
1675 k = haystack[n].rfind(commonChunksToReturn[c]);
1677 k = haystack[n].find(commonChunksToReturn[c], i + 1);
1684 __COUTVS__(3, k - i);
1686 wildcard = haystack[n].substr(i, k - i);
1687 if(fixedWildcardLength && n == 0)
1688 fixedWildcardLength += wildcard.size();
1690 __COUTS__(3) <<
"name[" << n <<
"] = " << wildcard <<
" fixed @ "
1691 << fixedWildcardLength << __E__;
1696 wildcard != haystack[n].substr(i, k - i))
1698 __SS__ <<
"Invalid wildcard! for name[" << n <<
"] = " << haystack[n]
1699 <<
" - the extraction algorithm is confused, please simplify "
1700 "your naming convention."
1710 wildcardsNeeded =
true;
1713 if(wildcard[0] ==
'0' && !fixedWildcardLength)
1715 someLeadingZeros =
true;
1716 if(wildcardStringsToReturn.size() &&
1717 wildcard.size() != wildcardStringsToReturn[0].size())
1718 allWildcardsSameSize =
false;
1721 wildcardStringsToReturn.push_back(wildcard);
1728 if(someLeadingZeros && allWildcardsSameSize)
1730 __COUTTV__(fixedWildcardLength);
1731 fixedWildcardLength = wildcardStringsToReturn[0].size();
1732 __COUT__ <<
"Enforce wildcard size of " << fixedWildcardLength << __E__;
1735 if(wildcardStringsToReturn.size() != haystack.size())
1737 __SS__ <<
"There was a problem during common chunk extraction!" << __E__;
1741 return wildcardsNeeded;
1750 const std::string& rhs)
const
1756 for(
unsigned int i = 0; i < lhs.size() && i < rhs.size(); ++i)
1759 if((lhs[i] >=
'A' && lhs[i] <=
'Z' && rhs[i] >=
'A' && rhs[i] <=
'Z') ||
1760 (lhs[i] >=
'a' && lhs[i] <=
'z' && rhs[i] >=
'a' && rhs[i] <=
'z'))
1762 if(lhs[i] == rhs[i])
1764 return (lhs[i] < rhs[i]);
1767 else if(lhs[i] >=
'A' && lhs[i] <=
'Z')
1769 if(lhs[i] + 32 == rhs[i])
1771 return (lhs[i] + 32 < rhs[i]);
1773 else if(rhs[i] >=
'A' && rhs[i] <=
'Z')
1775 if(lhs[i] == rhs[i] + 32)
1777 return (lhs[i] < rhs[i] + 32);
1781 if(lhs[i] == rhs[i])
1783 return (lhs[i] < rhs[i]);
1788 return lhs.size() < rhs.size();
1798 std::array<char, 128> buffer;
1803 std::string cmdWithRedirect = std::string(cmd) +
" 2>&1";
1804 FILE* rawPipe = popen(cmdWithRedirect.c_str(),
"r");
1806 __THROW__(
"popen() failed!");
1811 std::unique_ptr<FILE, int (*)(FILE*)> pipe(rawPipe, pclose);
1813 while(fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr)
1814 result += buffer.data();
1816 int status = pclose(pipe.release());
1818 __COUT_WARN__ <<
"pclose() failed for command: " << cmd << __E__;
1830 uintptr_t find_library_base(
const std::string& libname)
1832 std::ifstream maps(
"/proc/self/maps");
1835 while(std::getline(maps, line))
1837 if(line.find(libname) != std::string::npos &&
1838 line.find(
"r-xp") != std::string::npos)
1841 std::stringstream ss(line);
1842 ss >> std::hex >> base;
1850 void resolve_stack_entry(
const std::string& so_path,
1851 const std::string& real_name,
1852 const std::string& offset_begin,
1853 const std::string& offset_end
1858 const std::size_t pos0x = offset_end.find(
"0x");
1859 if(pos0x == std::string::npos)
1861 __COUTS__(52) <<
"resolve_stack_entry: could not find \"0x\" in offset_end: '"
1862 << offset_end <<
"'" << __E__;
1866 const std::size_t posBracket = offset_end.find(
']', pos0x);
1867 if(posBracket == std::string::npos || posBracket < pos0x + 3)
1869 __COUTS__(52) <<
"resolve_stack_entry: could not find closing ']' with at least "
1870 "one hex digit after \"0x\" "
1872 << offset_end <<
"'" << __E__;
1876 const std::string addr_str = offset_end.substr(pos0x, posBracket - pos0x);
1878 uintptr_t runtime_addr = 0;
1881 runtime_addr = std::stoull(addr_str,
nullptr, 16);
1883 catch(
const std::exception& e)
1885 __COUTS__(52) <<
"resolve_stack_entry: failed to parse runtime address from '"
1886 << addr_str <<
"': " << e.what() << __E__;
1890 std::string so_name = so_path.substr(so_path.find_last_of(
'/') + 1);
1892 uintptr_t base = find_library_base(so_name);
1895 std::cerr <<
"Could not find base for " << so_name <<
"\n";
1899 uintptr_t file_addr = runtime_addr - base;
1901 std::ostringstream cmd;
1902 cmd <<
"addr2line -f -C -e " << so_path <<
" 0x" << std::hex << file_addr;
1904 __COUT__ <<
"\nResolving:\n"
1905 << so_path <<
" : " << real_name << offset_begin <<
" [" << std::hex
1906 << runtime_addr <<
"]\n\n";
1917 #include <execinfo.h>
1921 __SS__ <<
"ots::stackTrace:\n";
1927 size = backtrace(array, 10);
1931 char** messages = backtrace_symbols(array, size);
1935 for(
unsigned int i = 1; i < size && messages != NULL; ++i)
1948 char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
1951 for(
char* p = messages[i]; *p; ++p)
1969 if(mangled_name && offset_begin && offset_end && mangled_name < offset_begin)
1971 *mangled_name++ =
'\0';
1972 *offset_begin++ =
'\0';
1973 *offset_end++ =
'\0';
1976 char* real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
1981 ss <<
"[" << i <<
"] " << messages[i] <<
" : " << real_name <<
"+"
1982 << offset_begin << offset_end << std::endl;
1989 ss <<
"[" << i <<
"] " << messages[i] <<
" : " << mangled_name <<
"+"
1990 << offset_begin << offset_end << std::endl;
1997 ss <<
"[" << i <<
"] " << messages[i] << std::endl;
2017 const std::string& location,
2018 const unsigned int& line)
2020 char* environmentVariablePtr = getenv(name);
2021 if(!environmentVariablePtr)
2023 __SS__ <<
"Environment variable '$" << name <<
"' not defined at " << location
2024 <<
":" << line << __E__;
2028 return environmentVariablePtr;
2035 const std::string& field,
2036 uint32_t occurrence,
2038 size_t* returnFindPos ,
2039 const std::string& valueField ,
2040 const std::string& quoteType )
2043 *returnFindPos = std::string::npos;
2045 __COUTVS__(41, xml);
2047 size_t lo, findpos = after, hi;
2048 for(uint32_t i = 0; i <= occurrence; ++i)
2050 bool anyFound =
false;
2052 xml.find(
"<" + field,
2053 findpos)) != std::string::npos &&
2054 findpos + 1 + field.size() < xml.size())
2056 __COUTS__(40) <<
"find: ---- '<" << field <<
" findpos=" << findpos
2057 <<
"findpos " << findpos <<
" " << xml[findpos] <<
" "
2058 << xml[findpos + 1 + field.size()] <<
" "
2059 << (int)xml[findpos + 1 + field.size()] << __E__;
2067 if((quoteType ==
">" && xml[findpos] ==
'>') || xml[findpos] ==
' ' ||
2068 xml[findpos] ==
'\n' || xml[findpos] ==
'\t')
2077 __COUTS__(40) <<
"Field '" << field <<
"' not found" << __E__;
2082 lo = xml.find(valueField + quoteType, findpos) + valueField.size() + quoteType.size();
2084 if(TTEST(40) && quoteType.size())
2086 __COUTS__(40) <<
"Neighbors of field '" << field <<
"' and value '" << valueField
2087 <<
"' w/quote = " << quoteType << __E__;
2088 for(
size_t i = lo - valueField.size(); i < lo + 10 && i < xml.size(); ++i)
2089 __COUTS__(40) <<
"xml[" << i <<
"] " << xml[i] <<
" vs " << quoteType <<
" ? "
2090 << (int)xml[i] <<
" vs " << (
int)quoteType[0] << __E__;
2094 quoteType ==
">" ?
"<" : quoteType,
2095 lo)) == std::string::npos)
2097 __COUTS__(40) <<
"Value closing not found" << __E__;
2102 *returnFindPos = findpos - (1 + field.size());
2104 __COUTS__(40) <<
"after: " << after <<
", findpos: " << findpos <<
", hi/lo: " << hi
2105 <<
"/" << lo <<
", size: " << xml.size() << __E__;
2106 __COUTVS__(40, xml.substr(lo, hi - lo));
2107 return xml.substr(lo, hi - lo);
2114 const std::string& field,
2115 uint32_t occurrence,
2117 size_t* returnFindPos ,
2118 const std::string& valueField ,
2119 const std::string& quoteType )
2122 *returnFindPos = std::string::npos;
2124 __COUTVS__(41, xml);
2126 size_t lo = 0, hi, findpos = before;
2127 for(uint32_t i = 0; i <= occurrence; ++i)
2129 bool anyFound =
false;
2131 xml.rfind(
"<" + field,
2132 findpos)) != std::string::npos &&
2133 findpos + 1 + field.size() < xml.size())
2135 __COUTS__(40) <<
"rfind: ---- '<" << field <<
" findpos=" << findpos <<
" "
2136 << xml[findpos] <<
" " << xml[findpos + 1 + field.size()] <<
" "
2137 << (int)xml[findpos + 1 + field.size()] << __E__;
2139 findpos += 1 + field.size();
2142 if((quoteType ==
">" && xml[findpos] ==
'>') || xml[findpos] ==
' ' ||
2143 xml[findpos] ==
'\n' || xml[findpos] ==
'\t')
2149 findpos -= 1 + field.size() + 1;
2153 __COUTS__(40) <<
"Field '" << field <<
"' not found" << __E__;
2158 lo = xml.find(valueField + quoteType, findpos) + valueField.size() + quoteType.size();
2160 if(TTEST(40) && quoteType.size())
2162 __COUTS__(40) <<
"Neighbors?" << __E__;
2163 for(
size_t i = findpos; i < lo + 10 && i < xml.size(); ++i)
2164 __COUTS__(40) <<
"xml[" << i <<
"] " << xml[i] <<
" vs " << quoteType <<
" ? "
2165 << (int)xml[i] <<
" vs " << (
int)quoteType[0] << __E__;
2169 quoteType ==
">" ?
"<" : quoteType,
2170 lo)) == std::string::npos)
2172 __COUTS__(40) <<
"Value closing not found" << __E__;
2178 findpos - (1 + field.size());
2180 __COUTS__(40) <<
"before: " << before <<
", findpos: " << findpos <<
", hi/lo: " << hi
2181 <<
"/" << lo <<
", size: " << xml.size() << __E__;
2182 __COUTVS__(40, xml.substr(lo, hi - lo));
2183 return xml.substr(lo, hi - lo);
2191 const std::set<char>& delimiter )
2195 __COUTV__(splitArr.size());
2196 __COUTVS__(lvl, splitArr.size());
2197 for(
const auto& split : splitArr)
2198 __COUTS__(lvl) << split;
2213 std::unique_ptr<char, void (*)(
void*)> res{
2214 abi::__cxa_demangle(name, NULL, NULL, &status), std::free};
2216 return (status == 0) ? res.get() : name;
defines used also by OtsConfigurationWizardSupervisor
bool operator()(const std::string &lhs, const std::string &rhs) const
<get string in order ignoring letter case
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static const std::string & trim(std::string &s)
static std::string extractXmlField(const std::string &xml, const std::string &field, uint32_t occurrence, size_t after, size_t *returnFindPos=nullptr, const std::string &valueField="value=", const std::string "eType="'")
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, bool decodeURIComponents=false)
static bool splitMacroArgTriple(const std::string &inputString, std::string &name, std::string &initValue, std::string &stepValue, char delimiter=':')
static std::string exec(const char *cmd)
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'})
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string escapeString(std::string inString, bool allowWhiteSpace=false, bool forHtml=false)
static T validateValueForDefaultStringDataType(const std::string &value, bool doConvertEnvironmentVariables=true)
static char * otsGetEnvironmentVarable(const char *name, const std::string &location, const unsigned int &line)
static void sanitizeForSQL(std::string &data)
StringMacros::sanitizeForSQL.
static void coutSplit(const std::string &str, uint8_t traceLevel=TLVL_DEBUG, const std::set< char > &delimiter={',', '\n', ';'})
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static std::string convertEnvironmentVariables(const std::string &data)
static std::string getNumberType(const std::string &stringToCheck)
Note: before call consider use of stringToCheck = StringMacros::convertEnvironmentVariables(stringToC...
static std::string escapeJSONStringEntities(const std::string &str)
static std::string demangleTypeName(const char *name)
static std::string rextractXmlField(const std::string &xml, const std::string &field, uint32_t occurrence, size_t before, size_t *returnFindPos=nullptr, const std::string &valueField="value=", const std::string "eType="'")
static bool extractCommonChunks(const std::vector< std::string > &haystack, std::vector< std::string > &commonChunksToReturn, std::vector< std::string > &wildcardStrings, unsigned int &fixedWildcardLength)
static bool inWildCardSet(const std::string &needle, const std::set< std::string > &haystack)
static bool loadPersistentSystemVariables(void)
loads persisted 'artdaq' namespace systemVariables_; returns false if no file found
static bool isNumber(const std::string &stringToCheck)
Note: before call consider use of stringToCheck = StringMacros::convertEnvironmentVariables(stringToC...
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static void getMapFromString(const std::string &inputString, std::map< S, T > &mapToReturn, const std::set< char > &pairPairDelimiter={',', '|', '&'}, const std::set< char > &nameValueDelimiter={'=', ':'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'})
getMapFromString ~
static std::string restoreJSONStringEntities(const std::string &str)
static std::string getTimeDurationString(const time_t durationInSeconds=time(0))
static bool wildCardMatch(const std::string &needle, const std::string &haystack, unsigned int *priorityIndex=0)
static std::string decodeURIComponent(const std::string &data)
static std::string stackTrace(void)
static bool getNumber(const std::string &s, T &retValue)