1 //===-- PathMappingList.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <climits> 13 #include <cstring> 14 15 // Other libraries and framework includes 16 // Project includes 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/Stream.h" 19 #include "lldb/Host/FileSpec.h" 20 #include "lldb/Target/PathMappingList.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 //---------------------------------------------------------------------- 26 // PathMappingList constructor 27 //---------------------------------------------------------------------- 28 PathMappingList::PathMappingList () : 29 m_pairs(), 30 m_callback(nullptr), 31 m_callback_baton(nullptr), 32 m_mod_id(0) 33 { 34 } 35 36 PathMappingList::PathMappingList (ChangedCallback callback, 37 void *callback_baton) : 38 m_pairs (), 39 m_callback (callback), 40 m_callback_baton (callback_baton), 41 m_mod_id (0) 42 { 43 } 44 45 PathMappingList::PathMappingList (const PathMappingList &rhs) : 46 m_pairs(rhs.m_pairs), 47 m_callback(nullptr), 48 m_callback_baton(nullptr), 49 m_mod_id(0) 50 { 51 } 52 53 const PathMappingList & 54 PathMappingList::operator =(const PathMappingList &rhs) 55 { 56 if (this != &rhs) 57 { 58 m_pairs = rhs.m_pairs; 59 m_callback = nullptr; 60 m_callback_baton = nullptr; 61 m_mod_id = rhs.m_mod_id; 62 } 63 return *this; 64 } 65 66 PathMappingList::~PathMappingList() = default; 67 68 void 69 PathMappingList::Append (const ConstString &path, 70 const ConstString &replacement, 71 bool notify) 72 { 73 ++m_mod_id; 74 m_pairs.push_back(pair(path, replacement)); 75 if (notify && m_callback) 76 m_callback (*this, m_callback_baton); 77 } 78 79 void 80 PathMappingList::Append (const PathMappingList &rhs, bool notify) 81 { 82 ++m_mod_id; 83 if (!rhs.m_pairs.empty()) 84 { 85 const_iterator pos, end = rhs.m_pairs.end(); 86 for (pos = rhs.m_pairs.begin(); pos != end; ++pos) 87 m_pairs.push_back(*pos); 88 if (notify && m_callback) 89 m_callback (*this, m_callback_baton); 90 } 91 } 92 93 void 94 PathMappingList::Insert (const ConstString &path, 95 const ConstString &replacement, 96 uint32_t index, 97 bool notify) 98 { 99 ++m_mod_id; 100 iterator insert_iter; 101 if (index >= m_pairs.size()) 102 insert_iter = m_pairs.end(); 103 else 104 insert_iter = m_pairs.begin() + index; 105 m_pairs.insert(insert_iter, pair(path, replacement)); 106 if (notify && m_callback) 107 m_callback (*this, m_callback_baton); 108 } 109 110 bool 111 PathMappingList::Replace (const ConstString &path, 112 const ConstString &replacement, 113 uint32_t index, 114 bool notify) 115 { 116 iterator insert_iter; 117 if (index >= m_pairs.size()) 118 return false; 119 ++m_mod_id; 120 m_pairs[index] = pair(path, replacement); 121 if (notify && m_callback) 122 m_callback (*this, m_callback_baton); 123 return true; 124 } 125 126 bool 127 PathMappingList::Remove (size_t index, bool notify) 128 { 129 if (index >= m_pairs.size()) 130 return false; 131 132 ++m_mod_id; 133 iterator iter = m_pairs.begin() + index; 134 m_pairs.erase(iter); 135 if (notify && m_callback) 136 m_callback (*this, m_callback_baton); 137 return true; 138 } 139 140 // For clients which do not need the pair index dumped, pass a pair_index >= 0 141 // to only dump the indicated pair. 142 void 143 PathMappingList::Dump (Stream *s, int pair_index) 144 { 145 unsigned int numPairs = m_pairs.size(); 146 147 if (pair_index < 0) 148 { 149 unsigned int index; 150 for (index = 0; index < numPairs; ++index) 151 s->Printf("[%d] \"%s\" -> \"%s\"\n", 152 index, m_pairs[index].first.GetCString(), m_pairs[index].second.GetCString()); 153 } 154 else 155 { 156 if (static_cast<unsigned int>(pair_index) < numPairs) 157 s->Printf("%s -> %s", 158 m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString()); 159 } 160 } 161 162 void 163 PathMappingList::Clear (bool notify) 164 { 165 if (!m_pairs.empty()) 166 ++m_mod_id; 167 m_pairs.clear(); 168 if (notify && m_callback) 169 m_callback (*this, m_callback_baton); 170 } 171 172 bool 173 PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) const 174 { 175 const char *path_cstr = path.GetCString(); 176 177 if (!path_cstr) 178 return false; 179 180 const_iterator pos, end = m_pairs.end(); 181 for (pos = m_pairs.begin(); pos != end; ++pos) 182 { 183 const size_t prefixLen = pos->first.GetLength(); 184 185 if (::strncmp (pos->first.GetCString(), path_cstr, prefixLen) == 0) 186 { 187 std::string new_path_str (pos->second.GetCString()); 188 new_path_str.append(path.GetCString() + prefixLen); 189 new_path.SetCString(new_path_str.c_str()); 190 return true; 191 } 192 } 193 return false; 194 } 195 196 bool 197 PathMappingList::RemapPath (const char *path, std::string &new_path) const 198 { 199 if (m_pairs.empty() || path == nullptr || path[0] == '\0') 200 return false; 201 202 const_iterator pos, end = m_pairs.end(); 203 for (pos = m_pairs.begin(); pos != end; ++pos) 204 { 205 const size_t prefix_len = pos->first.GetLength(); 206 207 if (::strncmp (pos->first.GetCString(), path, prefix_len) == 0) 208 { 209 new_path = pos->second.GetCString(); 210 new_path.append(path + prefix_len); 211 return true; 212 } 213 } 214 return false; 215 } 216 217 bool 218 PathMappingList::ReverseRemapPath (const ConstString &path, ConstString &new_path) const 219 { 220 const char *path_cstr = path.GetCString(); 221 if (!path_cstr) 222 return false; 223 224 for (const auto& it : m_pairs) 225 { 226 const size_t prefixLen = it.second.GetLength(); 227 if (::strncmp (it.second.GetCString(), path_cstr, prefixLen) == 0) 228 { 229 std::string new_path_str (it.first.GetCString()); 230 new_path_str.append(path.GetCString() + prefixLen); 231 new_path.SetCString(new_path_str.c_str()); 232 return true; 233 } 234 } 235 return false; 236 } 237 238 bool 239 PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const 240 { 241 if (!m_pairs.empty()) 242 { 243 char orig_path[PATH_MAX]; 244 char new_path[PATH_MAX]; 245 const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path)); 246 if (orig_path_len > 0) 247 { 248 const_iterator pos, end = m_pairs.end(); 249 for (pos = m_pairs.begin(); pos != end; ++pos) 250 { 251 const size_t prefix_len = pos->first.GetLength(); 252 253 if (orig_path_len >= prefix_len) 254 { 255 if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0) 256 { 257 const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len); 258 if (new_path_len < sizeof(new_path)) 259 { 260 new_spec.SetFile (new_path, true); 261 if (new_spec.Exists()) 262 return true; 263 } 264 } 265 } 266 } 267 } 268 } 269 new_spec.Clear(); 270 return false; 271 } 272 273 bool 274 PathMappingList::Replace (const ConstString &path, const ConstString &new_path, bool notify) 275 { 276 uint32_t idx = FindIndexForPath (path); 277 if (idx < m_pairs.size()) 278 { 279 ++m_mod_id; 280 m_pairs[idx].second = new_path; 281 if (notify && m_callback) 282 m_callback (*this, m_callback_baton); 283 return true; 284 } 285 return false; 286 } 287 288 bool 289 PathMappingList::Remove (const ConstString &path, bool notify) 290 { 291 iterator pos = FindIteratorForPath (path); 292 if (pos != m_pairs.end()) 293 { 294 ++m_mod_id; 295 m_pairs.erase (pos); 296 if (notify && m_callback) 297 m_callback (*this, m_callback_baton); 298 return true; 299 } 300 return false; 301 } 302 303 PathMappingList::const_iterator 304 PathMappingList::FindIteratorForPath (const ConstString &path) const 305 { 306 const_iterator pos; 307 const_iterator begin = m_pairs.begin(); 308 const_iterator end = m_pairs.end(); 309 310 for (pos = begin; pos != end; ++pos) 311 { 312 if (pos->first == path) 313 break; 314 } 315 return pos; 316 } 317 318 PathMappingList::iterator 319 PathMappingList::FindIteratorForPath (const ConstString &path) 320 { 321 iterator pos; 322 iterator begin = m_pairs.begin(); 323 iterator end = m_pairs.end(); 324 325 for (pos = begin; pos != end; ++pos) 326 { 327 if (pos->first == path) 328 break; 329 } 330 return pos; 331 } 332 333 bool 334 PathMappingList::GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const 335 { 336 if (idx < m_pairs.size()) 337 { 338 path = m_pairs[idx].first; 339 new_path = m_pairs[idx].second; 340 return true; 341 } 342 return false; 343 } 344 345 uint32_t 346 PathMappingList::FindIndexForPath (const ConstString &path) const 347 { 348 const_iterator pos; 349 const_iterator begin = m_pairs.begin(); 350 const_iterator end = m_pairs.end(); 351 352 for (pos = begin; pos != end; ++pos) 353 { 354 if (pos->first == path) 355 return std::distance (begin, pos); 356 } 357 return UINT32_MAX; 358 } 359