Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "Exception.h" 23 : 24 : #if defined(__PLUMED_HAS_EXECINFO) 25 : #include <execinfo.h> 26 : #endif 27 : 28 : #include <cstdio> 29 : #include <cstring> 30 : #include <cstdlib> 31 : #include <vector> 32 : 33 : namespace PLMD { 34 : 35 : namespace { 36 : // see https://www.geeksforgeeks.org/simplify-directory-path-unix-like/ 37 : 38 : // function to simplify a Unix - styled 39 : // absolute path 40 55 : std::string simplify(const std::string & path) 41 : { 42 : // using vector in place of stack 43 : std::vector<std::string> v; 44 55 : int n = path.length(); 45 : std::string ans; 46 179 : for (int i = 0; i < n; i++) { 47 124 : std::string dir = ""; 48 : // forming the current directory. 49 1095 : while (i < n && path[i] != '/') { 50 971 : dir += path[i]; 51 971 : i++; 52 : } 53 : 54 : // if ".." , we pop. 55 124 : if (dir == "..") { 56 4 : if (!v.empty()) 57 : v.pop_back(); 58 : } 59 240 : else if (dir == "." || dir == "") { 60 : // do nothing (added for better understanding.) 61 : } 62 : else { 63 : // push the current directory into the vector. 64 119 : v.push_back(dir); 65 : } 66 : } 67 : 68 : // forming the ans 69 : bool first=true; 70 170 : for (const auto & i : v) { 71 115 : if(!first) ans += "/"; 72 : first=false; 73 : ans += i; 74 : } 75 : 76 : // vector is empty 77 55 : if (ans == "") 78 0 : return "/"; 79 : 80 : return ans; 81 55 : } 82 : 83 : } 84 : 85 140 : Exception::Exception() 86 : { 87 : callstack.fill(nullptr); 88 : #ifdef __PLUMED_HAS_EXECINFO 89 140 : callstack_n = backtrace(&callstack[0], callstack.size()-1); 90 140 : const char* env=std::getenv("PLUMED_STACK_TRACE"); 91 140 : if(env && !std::strcmp(env,"yes")) { 92 : msg+="\n\n********** STACK DUMP **********\n"; 93 4 : msg+=stack(); 94 : msg+="\n********** END STACK DUMP **********\n"; 95 : } 96 : #endif 97 140 : } 98 : 99 397 : Exception& Exception::operator<<(const std::string&msg) 100 : { 101 397 : if(msg.length()>0) { 102 397 : if(note) this->msg +="\n"; 103 397 : this->msg +=msg; 104 397 : note=false; 105 : } 106 397 : return *this; 107 : } 108 : 109 55 : Exception& Exception::operator<<(const Location&loc) 110 : { 111 55 : if(loc.file) { 112 : const std::size_t clinelen=1000; 113 : char cline[clinelen]; 114 55 : std::snprintf(cline,clinelen,"%u",loc.line); 115 55 : this->msg += "\n("; 116 : try { 117 110 : this->msg += simplify(loc.file); 118 0 : } catch(...) { 119 : // ignore 120 0 : } 121 : this->msg += ":"; 122 : this->msg += cline; 123 : this->msg += ")"; 124 55 : if(loc.pretty && loc.pretty[0]) { 125 : this->msg += " "; 126 55 : this->msg += loc.pretty; 127 : } 128 : } 129 55 : note=true; 130 55 : return *this; 131 : } 132 : 133 11 : Exception& Exception::operator<<(const Assertion&as) 134 : { 135 11 : if(as.assertion) { 136 11 : this->msg += "\n+++ assertion failed: "; 137 11 : this->msg += as.assertion; 138 : } 139 11 : note=true; 140 11 : return *this; 141 : } 142 : 143 4 : const char* Exception::stack() const { 144 : #ifdef __PLUMED_HAS_EXECINFO 145 4 : if(stackTrace.length()==0) { 146 4 : char** strs = backtrace_symbols(&callstack[0], callstack_n); 147 39 : for (int i = 0; i < callstack_n; ++i) {stackTrace+=strs[i]; stackTrace+="\n";} 148 4 : free(strs); 149 : } 150 : #endif 151 4 : return stackTrace.c_str(); 152 : } 153 : 154 : } 155 : 156 :