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 #include <limits.h>
12 #include <string.h>
13 
14 // C++ Includes
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 (NULL),
31     m_callback_baton (NULL)
32 {
33 }
34 
35 PathMappingList::PathMappingList
36 (
37     ChangedCallback callback,
38     void *callback_baton
39 ) :
40     m_pairs (),
41     m_callback (callback),
42     m_callback_baton (callback_baton)
43 {
44 }
45 
46 
47 PathMappingList::PathMappingList (const PathMappingList &rhs) :
48     m_pairs (rhs.m_pairs),
49     m_callback (NULL),
50     m_callback_baton (NULL)
51 {
52 
53 }
54 
55 const PathMappingList &
56 PathMappingList::operator =(const PathMappingList &rhs)
57 {
58     if (this != &rhs)
59     {
60         m_pairs = rhs.m_pairs;
61         m_callback = NULL;
62         m_callback_baton = NULL;
63     }
64     return *this;
65 }
66 
67 
68 //----------------------------------------------------------------------
69 // Destructor
70 //----------------------------------------------------------------------
71 PathMappingList::~PathMappingList ()
72 {
73 }
74 
75 void
76 PathMappingList::Append (const ConstString &path,
77                          const ConstString &replacement,
78                          bool notify)
79 {
80     m_pairs.push_back(pair(path, replacement));
81     if (notify && m_callback)
82         m_callback (*this, m_callback_baton);
83 }
84 
85 void
86 PathMappingList::Append (const PathMappingList &rhs, bool notify)
87 {
88     if (!rhs.m_pairs.empty())
89     {
90         const_iterator pos, end = rhs.m_pairs.end();
91         for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
92             m_pairs.push_back(*pos);
93         if (notify && m_callback)
94             m_callback (*this, m_callback_baton);
95     }
96 }
97 
98 void
99 PathMappingList::Insert (const ConstString &path,
100                          const ConstString &replacement,
101                          uint32_t index,
102                          bool notify)
103 {
104     iterator insert_iter;
105     if (index >= m_pairs.size())
106         insert_iter = m_pairs.end();
107     else
108         insert_iter = m_pairs.begin() + index;
109     m_pairs.insert(insert_iter, pair(path, replacement));
110     if (notify && m_callback)
111         m_callback (*this, m_callback_baton);
112 }
113 
114 bool
115 PathMappingList::Remove (off_t index, bool notify)
116 {
117     if (index >= m_pairs.size())
118         return false;
119 
120     iterator iter = m_pairs.begin() + index;
121     m_pairs.erase(iter);
122     if (notify && m_callback)
123         m_callback (*this, m_callback_baton);
124     return true;
125 }
126 
127 // For clients which do not need the pair index dumped, pass a pair_index >= 0
128 // to only dump the indicated pair.
129 void
130 PathMappingList::Dump (Stream *s, int pair_index)
131 {
132     unsigned int numPairs = m_pairs.size();
133 
134     if (pair_index < 0)
135     {
136         unsigned int index;
137         for (index = 0; index < numPairs; ++index)
138             s->Printf("[%d] \"%s\" -> \"%s\"\n",
139                       index, m_pairs[index].first.GetCString(), m_pairs[index].second.GetCString());
140     }
141     else
142     {
143         if (pair_index < numPairs)
144             s->Printf("%s -> %s",
145                       m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString());
146     }
147 }
148 
149 void
150 PathMappingList::Clear (bool notify)
151 {
152     m_pairs.clear();
153     if (notify && m_callback)
154         m_callback (*this, m_callback_baton);
155 }
156 
157 bool
158 PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) const
159 {
160     const_iterator pos, end = m_pairs.end();
161     for (pos = m_pairs.begin(); pos != end; ++pos)
162     {
163         const size_t prefixLen = pos->first.GetLength();
164 
165         if (::strncmp (pos->first.GetCString(), path.GetCString(), prefixLen) == 0)
166         {
167             std::string new_path_str (pos->second.GetCString());
168             new_path_str.append(path.GetCString() + prefixLen);
169             new_path.SetCString(new_path_str.c_str());
170             return true;
171         }
172     }
173     return false;
174 }
175 
176 bool
177 PathMappingList::RemapPath (const char *path, std::string &new_path) const
178 {
179     if (m_pairs.empty() || path == NULL || path[0] == '\0')
180         return false;
181 
182     const_iterator pos, end = m_pairs.end();
183     for (pos = m_pairs.begin(); pos != end; ++pos)
184     {
185         const size_t prefix_len = pos->first.GetLength();
186 
187         if (::strncmp (pos->first.GetCString(), path, prefix_len) == 0)
188         {
189             new_path = pos->second.GetCString();
190             new_path.append(path + prefix_len);
191             return true;
192         }
193     }
194     return false;
195 }
196 
197 bool
198 PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const
199 {
200     if (!m_pairs.empty())
201     {
202         char orig_path[PATH_MAX];
203         char new_path[PATH_MAX];
204         const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path));
205         if (orig_path_len > 0)
206         {
207             const_iterator pos, end = m_pairs.end();
208             for (pos = m_pairs.begin(); pos != end; ++pos)
209             {
210                 const size_t prefix_len = pos->first.GetLength();
211 
212                 if (orig_path_len >= prefix_len)
213                 {
214                     if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0)
215                     {
216                         const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len);
217                         if (new_path_len < sizeof(new_path))
218                         {
219                             new_spec.SetFile (new_path, true);
220                             if (new_spec.Exists())
221                                 return true;
222                         }
223                     }
224                 }
225             }
226         }
227     }
228     new_spec.Clear();
229     return false;
230 }
231 
232 bool
233 PathMappingList::Replace (const ConstString &path, const ConstString &new_path, bool notify)
234 {
235     uint32_t idx = FindIndexForPath (path);
236     if (idx < m_pairs.size())
237     {
238         m_pairs[idx].second = new_path;
239         if (notify && m_callback)
240             m_callback (*this, m_callback_baton);
241         return true;
242     }
243     return false;
244 }
245 
246 bool
247 PathMappingList::Remove (const ConstString &path, bool notify)
248 {
249     iterator pos = FindIteratorForPath (path);
250     if (pos != m_pairs.end())
251     {
252         m_pairs.erase (pos);
253         if (notify && m_callback)
254             m_callback (*this, m_callback_baton);
255         return true;
256     }
257     return false;
258 }
259 
260 PathMappingList::const_iterator
261 PathMappingList::FindIteratorForPath (const ConstString &path) const
262 {
263     const_iterator pos;
264     const_iterator begin = m_pairs.begin();
265     const_iterator end = m_pairs.end();
266 
267     for (pos = begin; pos != end; ++pos)
268     {
269         if (pos->first == path)
270             break;
271     }
272     return pos;
273 }
274 
275 PathMappingList::iterator
276 PathMappingList::FindIteratorForPath (const ConstString &path)
277 {
278     iterator pos;
279     iterator begin = m_pairs.begin();
280     iterator end = m_pairs.end();
281 
282     for (pos = begin; pos != end; ++pos)
283     {
284         if (pos->first == path)
285             break;
286     }
287     return pos;
288 }
289 
290 bool
291 PathMappingList::GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const
292 {
293     if (idx < m_pairs.size())
294     {
295         path = m_pairs[idx].first;
296         new_path = m_pairs[idx].second;
297         return true;
298     }
299     return false;
300 }
301 
302 
303 
304 uint32_t
305 PathMappingList::FindIndexForPath (const ConstString &path) const
306 {
307     const_iterator pos;
308     const_iterator begin = m_pairs.begin();
309     const_iterator end = m_pairs.end();
310 
311     for (pos = begin; pos != end; ++pos)
312     {
313         if (pos->first == path)
314             return std::distance (begin, pos);
315     }
316     return UINT32_MAX;
317 }
318 
319