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