$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/Macros/StringMacros.h" 00002 00003 using namespace ots; 00004 00005 //============================================================================== 00006 // wildCardMatch 00007 // find needle in haystack 00008 // allow needle to have leading and/or trailing wildcard '*' 00009 // consider priority in matching, no matter the order in the haystack: 00010 // - 0: no match! 00011 // - 1: highest priority is exact match 00012 // - 2: next highest is partial TRAILING-wildcard match 00013 // - 3: next highest is partial LEADING-wildcard match 00014 // - 4: lowest priority is partial full-wildcard match 00015 // return priority found by reference 00016 bool StringMacros::wildCardMatch(const std::string& needle, 00017 const std::string& haystack, 00018 unsigned int* priorityIndex) try 00019 { 00020 // __COUT__ << "\t\t wildCardMatch: " << needle << 00021 // " =in= " << haystack << " ??? " << 00022 // std::endl; 00023 00024 // empty needle 00025 if(needle.size() == 0) 00026 { 00027 if(priorityIndex) 00028 *priorityIndex = 1; // consider an exact match, to stop higher level loops 00029 return true; // if empty needle, always "found" 00030 } 00031 00032 // only wildcard 00033 if(needle == "*") 00034 { 00035 if(priorityIndex) 00036 *priorityIndex = 5; // only wildcard, is lowest priority 00037 return true; // if empty needle, always "found" 00038 } 00039 00040 // no wildcards 00041 if(needle == haystack) 00042 { 00043 if(priorityIndex) 00044 *priorityIndex = 1; // an exact match 00045 return true; 00046 } 00047 00048 // trailing wildcard 00049 if(needle[needle.size() - 1] == '*' && 00050 needle.substr(0, needle.size() - 1) == haystack.substr(0, needle.size() - 1)) 00051 { 00052 if(priorityIndex) 00053 *priorityIndex = 2; // trailing wildcard match 00054 return true; 00055 } 00056 00057 // leading wildcard 00058 if(needle[0] == '*' && 00059 needle.substr(1) == haystack.substr(haystack.size() - (needle.size() - 1))) 00060 { 00061 if(priorityIndex) 00062 *priorityIndex = 3; // leading wildcard match 00063 return true; 00064 } 00065 00066 // leading wildcard and trailing wildcard 00067 if(needle[0] == '*' && needle[needle.size() - 1] == '*' && 00068 std::string::npos != haystack.find(needle.substr(1, needle.size() - 2))) 00069 { 00070 if(priorityIndex) 00071 *priorityIndex = 4; // leading and trailing wildcard match 00072 return true; 00073 } 00074 00075 // else no match 00076 if(priorityIndex) 00077 *priorityIndex = 0; // no match 00078 return false; 00079 } 00080 catch(...) 00081 { 00082 if(priorityIndex) 00083 *priorityIndex = 0; // no match 00084 return false; // if out of range 00085 } 00086 00087 //======================================================================================================================== 00088 // inWildCardSet ~ 00089 // returns true if needle is in haystack (considering wildcards) 00090 bool StringMacros::inWildCardSet(const std::string& needle, 00091 const std::set<std::string>& haystack) 00092 { 00093 for(const auto& haystackString : haystack) 00094 // use wildcard match, flip needle parameter.. because we want haystack to have 00095 // the wildcards 00096 if(StringMacros::wildCardMatch(haystackString, needle)) 00097 return true; 00098 return false; 00099 } 00100 00101 //============================================================================== 00102 // decodeURIComponent 00103 // converts all %## to the ascii character 00104 std::string StringMacros::decodeURIComponent(const std::string& data) 00105 { 00106 std::string decodeURIString(data.size(), 0); // init to same size 00107 unsigned int j = 0; 00108 for(unsigned int i = 0; i < data.size(); ++i, ++j) 00109 { 00110 if(data[i] == '%') 00111 { 00112 // high order hex nibble digit 00113 if(data[i + 1] > '9') // then ABCDEF 00114 decodeURIString[j] += (data[i + 1] - 55) * 16; 00115 else 00116 decodeURIString[j] += (data[i + 1] - 48) * 16; 00117 00118 // low order hex nibble digit 00119 if(data[i + 2] > '9') // then ABCDEF 00120 decodeURIString[j] += (data[i + 2] - 55); 00121 else 00122 decodeURIString[j] += (data[i + 2] - 48); 00123 00124 i += 2; // skip to next char 00125 } 00126 else 00127 decodeURIString[j] = data[i]; 00128 } 00129 decodeURIString.resize(j); 00130 return decodeURIString; 00131 } 00132 00133 //============================================================================== 00134 // convertEnvironmentVariables ~ 00135 // static recursive function 00136 // 00137 // allows environment variables entered as $NAME or ${NAME} 00138 std::string StringMacros::convertEnvironmentVariables(const std::string& data) 00139 { 00140 size_t begin = data.find("$"); 00141 if(begin != std::string::npos) 00142 { 00143 size_t end; 00144 std::string envVariable; 00145 std::string converted = data; // make copy to modify 00146 00147 if(data[begin + 1] == '{') // check if using ${NAME} syntax 00148 { 00149 end = data.find("}", begin + 2); 00150 envVariable = data.substr(begin + 2, end - begin - 2); 00151 ++end; // replace the closing } too! 00152 } 00153 else // else using $NAME syntax 00154 { 00155 // end is first non environment variable character 00156 for(end = begin + 1; end < data.size(); ++end) 00157 if(!((data[end] >= '0' && data[end] <= '9') || 00158 (data[end] >= 'A' && data[end] <= 'Z') || 00159 (data[end] >= 'a' && data[end] <= 'z') || data[end] == '-' || 00160 data[end] == '_' || data[end] == '.' || data[end] == ':')) 00161 break; // found end 00162 envVariable = data.substr(begin + 1, end - begin - 1); 00163 } 00164 //__COUTV__(data); 00165 //__COUTV__(envVariable); 00166 char* envResult = getenv(envVariable.c_str()); 00167 00168 if(envResult) 00169 { 00170 // proceed recursively 00171 return convertEnvironmentVariables( 00172 converted.replace(begin, end - begin, envResult)); 00173 } 00174 else 00175 { 00176 __SS__ << ("The environmental variable '" + envVariable + 00177 "' is not set! Please make sure you set it before continuing!") 00178 << std::endl; 00179 __SS_THROW__; 00180 } 00181 } 00182 // else no environment variables found in string 00183 //__COUT__ << "Result: " << data << __E__; 00184 return data; 00185 } 00186 00187 //============================================================================== 00188 // isNumber ~~ 00189 // returns true if one or many numbers separated by operations (+,-,/,*) is 00190 // present in the string. 00191 // Numbers can be hex ("0x.."), binary("b..."), or base10. 00192 bool StringMacros::isNumber(const std::string& s) 00193 { 00194 // extract set of potential numbers and operators 00195 std::vector<std::string> numbers; 00196 std::vector<char> ops; 00197 00198 StringMacros::getVectorFromString( 00199 s, 00200 numbers, 00201 /*delimiter*/ std::set<char>({'+', '-', '*', '/'}), 00202 /*whitespace*/ std::set<char>({' ', '\t', '\n', '\r'}), 00203 &ops); 00204 00205 //__COUTV__(StringMacros::vectorToString(numbers)); 00206 //__COUTV__(StringMacros::vectorToString(ops)); 00207 00208 for(const auto& number : numbers) 00209 { 00210 if(number.size() == 0) 00211 continue; // skip empty numbers 00212 00213 if(number.find("0x") == 0) // indicates hex 00214 { 00215 //__COUT__ << "0x found" << std::endl; 00216 for(unsigned int i = 2; i < number.size(); ++i) 00217 { 00218 if(!((number[i] >= '0' && number[i] <= '9') || 00219 (number[i] >= 'A' && number[i] <= 'F') || 00220 (number[i] >= 'a' && number[i] <= 'f'))) 00221 { 00222 //__COUT__ << "prob " << number[i] << std::endl; 00223 return false; 00224 } 00225 } 00226 // return std::regex_match(number.substr(2), std::regex("^[0-90-9a-fA-F]+")); 00227 } 00228 else if(number[0] == 'b') // indicates binary 00229 { 00230 //__COUT__ << "b found" << std::endl; 00231 00232 for(unsigned int i = 1; i < number.size(); ++i) 00233 { 00234 if(!((number[i] >= '0' && number[i] <= '1'))) 00235 { 00236 //__COUT__ << "prob " << number[i] << std::endl; 00237 return false; 00238 } 00239 } 00240 } 00241 else 00242 { 00243 //__COUT__ << "base 10 " << std::endl; 00244 for(unsigned int i = 0; i < number.size(); ++i) 00245 if(!((number[i] >= '0' && number[i] <= '9') || number[i] == '.' || 00246 number[i] == '+' || number[i] == '-')) 00247 return false; 00248 // Note: std::regex crashes in unresolvable ways (says Ryan.. also, stop using 00249 // libraries) return std::regex_match(s, 00250 // std::regex("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?")); 00251 } 00252 } 00253 00254 //__COUT__ << "yes " << std::endl; 00255 00256 // all numbers are numbers 00257 return true; 00258 } // end isNumber() 00259 00260 //============================================================================== 00261 // getTimestampString ~~ 00262 // returns ots style timestamp string 00263 // of known fixed size: Thu Aug 23 14:55:02 2001 CST 00264 std::string StringMacros::getTimestampString(const std::string& linuxTimeInSeconds) 00265 { 00266 time_t timestamp(strtol(linuxTimeInSeconds.c_str(), 0, 10)); 00267 return getTimestampString(timestamp); 00268 } // end getTimestampString() 00269 00270 //============================================================================== 00271 // getTimestampString ~~ 00272 // returns ots style timestamp string 00273 // of known fixed size: Thu Aug 23 14:55:02 2001 CST 00274 std::string StringMacros::getTimestampString(const time_t& linuxTimeInSeconds) 00275 { 00276 std::string retValue(30, '\0'); // known fixed size: Thu Aug 23 14:55:02 2001 CST 00277 00278 struct tm tmstruct; 00279 ::localtime_r(&linuxTimeInSeconds, &tmstruct); 00280 ::strftime(&retValue[0], 30, "%c %Z", &tmstruct); 00281 retValue.resize(strlen(retValue.c_str())); 00282 00283 return retValue; 00284 } // end getTimestampString() 00285 00286 //============================================================================== 00287 // validateValueForDefaultStringDataType 00288 // 00289 std::string StringMacros::validateValueForDefaultStringDataType( 00290 const std::string& value, bool doConvertEnvironmentVariables) try 00291 { 00292 return doConvertEnvironmentVariables 00293 ? StringMacros::convertEnvironmentVariables(value) 00294 : value; 00295 } 00296 catch(const std::runtime_error& e) 00297 { 00298 __SS__ << "Failed to validate value for default string data type. " << __E__ 00299 << e.what() << __E__; 00300 __SS_THROW__; 00301 } 00302 00303 //============================================================================== 00304 // getSetFromString 00305 // extracts the set of elements from string that uses a delimiter 00306 // ignoring whitespace 00307 void StringMacros::getSetFromString(const std::string& inputString, 00308 std::set<std::string>& setToReturn, 00309 const std::set<char>& delimiter, 00310 const std::set<char>& whitespace) 00311 { 00312 unsigned int i = 0; 00313 unsigned int j = 0; 00314 00315 // go through the full string extracting elements 00316 // add each found element to set 00317 for(; j < inputString.size(); ++j) 00318 if((whitespace.find(inputString[j]) != 00319 whitespace.end() || // ignore leading white space or delimiter 00320 delimiter.find(inputString[j]) != delimiter.end()) && 00321 i == j) 00322 ++i; 00323 else if((whitespace.find(inputString[j]) != 00324 whitespace 00325 .end() || // trailing white space or delimiter indicates end 00326 delimiter.find(inputString[j]) != delimiter.end()) && 00327 i != j) // assume end of element 00328 { 00329 //__COUT__ << "Set element found: " << 00330 // inputString.substr(i,j-i) << std::endl; 00331 00332 setToReturn.emplace(inputString.substr(i, j - i)); 00333 00334 // setup i and j for next find 00335 i = j + 1; 00336 } 00337 00338 if(i != j) // last element check (for case when no concluding ' ' or delimiter) 00339 setToReturn.emplace(inputString.substr(i, j - i)); 00340 } // end getSetFromString() 00341 00342 //============================================================================== 00343 // getVectorFromString 00344 // extracts the list of elements from string that uses a delimiter 00345 // ignoring whitespace 00346 // optionally returns the list of delimiters encountered, which may be useful 00347 // for extracting which operator was used. 00348 // 00349 // 00350 // Note: lists are returned as vectors 00351 // Note: the size() of delimiters will be one less than the size() of the returned values 00352 // unless there is a leading delimiter, in which case vectors will have the same 00353 // size. 00354 void StringMacros::getVectorFromString(const std::string& inputString, 00355 std::vector<std::string>& listToReturn, 00356 const std::set<char>& delimiter, 00357 const std::set<char>& whitespace, 00358 std::vector<char>* listOfDelimiters) 00359 { 00360 unsigned int i = 0; 00361 unsigned int j = 0; 00362 unsigned int c = 0; 00363 std::set<char>::iterator delimeterSearchIt; 00364 char lastDelimiter; 00365 bool isDelimiter; 00366 // bool foundLeadingDelimiter = false; 00367 00368 //__COUT__ << inputString << __E__; 00369 //__COUTV__(inputString.length()); 00370 00371 // go through the full string extracting elements 00372 // add each found element to set 00373 for(; c < inputString.size(); ++c) 00374 { 00375 //__COUT__ << (char)inputString[c] << __E__; 00376 00377 delimeterSearchIt = delimiter.find(inputString[c]); 00378 isDelimiter = delimeterSearchIt != delimiter.end(); 00379 00380 //__COUT__ << (char)inputString[c] << " " << isDelimiter << 00381 //__E__;//char)lastDelimiter << __E__; 00382 00383 if(whitespace.find(inputString[c]) != 00384 whitespace.end() // ignore leading white space 00385 && i == j) 00386 { 00387 ++i; 00388 ++j; 00389 // if(isDelimiter) 00390 // foundLeadingDelimiter = true; 00391 } 00392 else if(whitespace.find(inputString[c]) != whitespace.end() && 00393 i != j) // trailing white space, assume possible end of element 00394 { 00395 // do not change j or i 00396 } 00397 else if(isDelimiter) // delimiter is end of element 00398 { 00399 //__COUT__ << "Set element found: " << 00400 // inputString.substr(i,j-i) << std::endl; 00401 00402 if(listOfDelimiters && listToReturn.size()) // || foundLeadingDelimiter)) 00403 // //accept leading delimiter 00404 // (especially for case of 00405 // leading negative in math 00406 // parsing) 00407 { 00408 //__COUTV__(lastDelimiter); 00409 listOfDelimiters->push_back(lastDelimiter); 00410 } 00411 listToReturn.push_back(inputString.substr(i, j - i)); 00412 00413 // setup i and j for next find 00414 i = c + 1; 00415 j = c + 1; 00416 } 00417 else // part of element, so move j, not i 00418 j = c + 1; 00419 00420 if(isDelimiter) 00421 lastDelimiter = *delimeterSearchIt; 00422 //__COUTV__(lastDelimiter); 00423 } 00424 00425 if(1) // i != j) //last element check (for case when no concluding ' ' or delimiter) 00426 { 00427 //__COUT__ << "Last element found: " << 00428 // inputString.substr(i,j-i) << std::endl; 00429 00430 if(listOfDelimiters && listToReturn.size()) // || foundLeadingDelimiter)) 00431 // //accept leading delimiter 00432 // (especially for case of leading 00433 // negative in math parsing) 00434 { 00435 //__COUTV__(lastDelimiter); 00436 listOfDelimiters->push_back(lastDelimiter); 00437 } 00438 listToReturn.push_back(inputString.substr(i, j - i)); 00439 } 00440 00441 // assert that there is one less delimiter than values 00442 if(listOfDelimiters && listToReturn.size() - 1 != listOfDelimiters->size() && 00443 listToReturn.size() != listOfDelimiters->size()) 00444 { 00445 __SS__ << "There is a mismatch in delimiters to entries (should be equal or one " 00446 "less delimiter): " 00447 << listOfDelimiters->size() << " vs " << listToReturn.size() << __E__ 00448 << "Entries: " << StringMacros::vectorToString(listToReturn) << __E__ 00449 << "Delimiters: " << StringMacros::vectorToString(*listOfDelimiters) 00450 << __E__; 00451 __SS_THROW__; 00452 } 00453 00454 } // end getVectorFromString() 00455 00456 //============================================================================== 00457 // getMapFromString 00458 // extracts the map of name-value pairs from string that uses two s 00459 // ignoring whitespace 00460 void StringMacros::getMapFromString(const std::string& inputString, 00461 std::map<std::string, std::string>& mapToReturn, 00462 const std::set<char>& pairPairDelimiter, 00463 const std::set<char>& nameValueDelimiter, 00464 const std::set<char>& whitespace) try 00465 { 00466 unsigned int i = 0; 00467 unsigned int j = 0; 00468 std::string name; 00469 bool needValue = false; 00470 00471 // go through the full string extracting map pairs 00472 // add each found pair to map 00473 for(; j < inputString.size(); ++j) 00474 if(!needValue) // finding name 00475 { 00476 if((whitespace.find(inputString[j]) != 00477 whitespace.end() || // ignore leading white space or delimiter 00478 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end()) && 00479 i == j) 00480 ++i; 00481 else if((whitespace.find(inputString[j]) != 00482 whitespace 00483 .end() || // trailing white space or delimiter indicates end 00484 nameValueDelimiter.find(inputString[j]) != 00485 nameValueDelimiter.end()) && 00486 i != j) // assume end of map name 00487 { 00488 //__COUT__ << "Map name found: " << 00489 // inputString.substr(i,j-i) << std::endl; 00490 00491 name = inputString.substr(i, j - i); // save name, for concluding pair 00492 00493 needValue = true; // need value now 00494 00495 // setup i and j for next find 00496 i = j + 1; 00497 } 00498 } 00499 else // finding value 00500 { 00501 if((whitespace.find(inputString[j]) != 00502 whitespace.end() || // ignore leading white space or delimiter 00503 nameValueDelimiter.find(inputString[j]) != nameValueDelimiter.end()) && 00504 i == j) 00505 ++i; 00506 else if((whitespace.find(inputString[j]) != 00507 whitespace 00508 .end() || // trailing white space or delimiter indicates end 00509 pairPairDelimiter.find(inputString[j]) != pairPairDelimiter.end()) && 00510 i != j) // assume end of value name 00511 { 00512 //__COUT__ << "Map value found: " << 00513 // inputString.substr(i,j-i) << std::endl; 00514 00515 auto /*pair<it,success>*/ emplaceReturn = 00516 mapToReturn.emplace(std::pair<std::string, std::string>( 00517 name, 00518 validateValueForDefaultStringDataType( 00519 inputString.substr(i, j - i)) // value 00520 )); 00521 00522 if(!emplaceReturn.second) 00523 { 00524 __COUT__ << "Ignoring repetitive value ('" 00525 << inputString.substr(i, j - i) 00526 << "') and keeping current value ('" 00527 << emplaceReturn.first->second << "'). " << __E__; 00528 } 00529 00530 needValue = false; // need name now 00531 00532 // setup i and j for next find 00533 i = j + 1; 00534 } 00535 } 00536 00537 if(i != j) // last value (for case when no concluding ' ' or delimiter) 00538 { 00539 auto /*pair<it,success>*/ emplaceReturn = 00540 mapToReturn.emplace(std::pair<std::string, std::string>( 00541 name, 00542 validateValueForDefaultStringDataType( 00543 inputString.substr(i, j - i)) // value 00544 )); 00545 00546 if(!emplaceReturn.second) 00547 { 00548 __COUT__ << "Ignoring repetitive value ('" << inputString.substr(i, j - i) 00549 << "') and keeping current value ('" << emplaceReturn.first->second 00550 << "'). " << __E__; 00551 } 00552 } 00553 } 00554 catch(const std::runtime_error& e) 00555 { 00556 __SS__ << "Error while extracting a map from the string '" << inputString 00557 << "'... is it a valid map?" << __E__ << e.what() << __E__; 00558 __SS_THROW__; 00559 } 00560 00561 //============================================================================== 00562 // mapToString 00563 std::string StringMacros::mapToString(const std::map<std::string, uint8_t>& mapToReturn, 00564 const std::string& primaryDelimeter, 00565 const std::string& secondaryDelimeter) 00566 { 00567 std::stringstream ss; 00568 bool first = true; 00569 for(auto& mapPair : mapToReturn) 00570 { 00571 if(first) 00572 first = false; 00573 else 00574 ss << primaryDelimeter; 00575 ss << mapPair.first << secondaryDelimeter << (unsigned int)mapPair.second; 00576 } 00577 return ss.str(); 00578 } 00579 00580 //============================================================================== 00581 // setToString 00582 std::string StringMacros::setToString(const std::set<uint8_t>& setToReturn, 00583 const std::string& delimeter) 00584 { 00585 std::stringstream ss; 00586 bool first = true; 00587 for(auto& setValue : setToReturn) 00588 { 00589 if(first) 00590 first = false; 00591 else 00592 ss << delimeter; 00593 ss << (unsigned int)setValue; 00594 } 00595 return ss.str(); 00596 } 00597 //============================================================================== 00598 // vectorToString 00599 std::string StringMacros::vectorToString(const std::vector<uint8_t>& setToReturn, 00600 const std::string& delimeter) 00601 { 00602 std::stringstream ss; 00603 bool first = true; 00604 for(auto& setValue : setToReturn) 00605 { 00606 if(first) 00607 first = false; 00608 else 00609 ss << delimeter; 00610 ss << (unsigned int)setValue; 00611 } 00612 return ss.str(); 00613 } 00614 00615 //======================================================================================================================== 00616 // exec 00617 // run linux command and get result back in string 00618 std::string StringMacros::exec(const char* cmd) 00619 { 00620 __COUTV__(cmd); 00621 00622 std::array<char, 128> buffer; 00623 std::string result; 00624 std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); 00625 if(!pipe) 00626 __THROW__("popen() failed!"); 00627 while(!feof(pipe.get())) 00628 { 00629 if(fgets(buffer.data(), 128, pipe.get()) != nullptr) 00630 result += buffer.data(); 00631 } 00632 return result; 00633 } // end exec 00634 00635 //============================================================================== 00636 // stackTrace 00637 // static function 00638 // https://gist.github.com/fmela/591333/c64f4eb86037bb237862a8283df70cdfc25f01d3 00639 #include <cxxabi.h> //for abi::__cxa_demangle 00640 #include <execinfo.h> //for back trace of stack 00641 std::string StringMacros::stackTrace() 00642 { 00643 __SS__ << "ots::stackTrace:\n"; 00644 00645 void* array[10]; 00646 size_t size; 00647 00648 // get void*'s for all entries on the stack 00649 size = backtrace(array, 10); 00650 // backtrace_symbols_fd(array, size, STDERR_FILENO); 00651 00652 // https://stackoverflow.com/questions/77005/how-to-automatically-generate-a-stacktrace-when-my-program-crashes 00653 char** messages = backtrace_symbols(array, size); 00654 00655 // skip first stack frame (points here) 00656 char syscom[256]; 00657 for(unsigned int i = 1; i < size && messages != NULL; ++i) 00658 { 00659 // mangled name needs to be converted to get nice name and line number 00660 // line number not working... FIXME 00661 00662 // sprintf(syscom,"addr2line %p -e %s", 00663 // array[i], 00664 // messages[i]); //last parameter is the name of this app 00665 // ss << StringMacros::exec(syscom) << __E__; 00666 // system(syscom); 00667 00668 // continue; 00669 00670 char *mangled_name = 0, *offset_begin = 0, *offset_end = 0; 00671 00672 // find parentheses and +address offset surrounding mangled name 00673 for(char* p = messages[i]; *p; ++p) 00674 { 00675 if(*p == '(') 00676 { 00677 mangled_name = p; 00678 } 00679 else if(*p == '+') 00680 { 00681 offset_begin = p; 00682 } 00683 else if(*p == ')') 00684 { 00685 offset_end = p; 00686 break; 00687 } 00688 } 00689 00690 // if the line could be processed, attempt to demangle the symbol 00691 if(mangled_name && offset_begin && offset_end && mangled_name < offset_begin) 00692 { 00693 *mangled_name++ = '\0'; 00694 *offset_begin++ = '\0'; 00695 *offset_end++ = '\0'; 00696 00697 int status; 00698 char* real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status); 00699 00700 // if demangling is successful, output the demangled function name 00701 if(status == 0) 00702 { 00703 ss << "[" << i << "] " << messages[i] << " : " << real_name << "+" 00704 << offset_begin << offset_end << std::endl; 00705 } 00706 // otherwise, output the mangled function name 00707 else 00708 { 00709 ss << "[" << i << "] " << messages[i] << " : " << mangled_name << "+" 00710 << offset_begin << offset_end << std::endl; 00711 } 00712 free(real_name); 00713 } 00714 // otherwise, print the whole line 00715 else 00716 { 00717 ss << "[" << i << "] " << messages[i] << std::endl; 00718 } 00719 } 00720 ss << std::endl; 00721 00722 free(messages); 00723 00724 return ss.str(); 00725 } // end stackTrace 00726 00727 #ifdef __GNUG__ 00728 #include <cxxabi.h> 00729 #include <cstdlib> 00730 #include <memory> 00731 00732 //============================================================================== 00733 // demangleTypeName 00734 std::string StringMacros::demangleTypeName(const char* name) 00735 { 00736 int status = -4; // some arbitrary value to eliminate the compiler warning 00737 00738 // enable c++11 by passing the flag -std=c++11 to g++ 00739 std::unique_ptr<char, void (*)(void*)> res{ 00740 abi::__cxa_demangle(name, NULL, NULL, &status), std::free}; 00741 00742 return (status == 0) ? res.get() : name; 00743 } // end demangleTypeName() 00744 00745 #else // does nothing if not g++ 00746 //============================================================================== 00747 // demangleTypeName 00748 // 00749 std::string StringMacros::demangleTypeName(const char* name) { return name; } 00750 #endif