1254721Semaste//===-- SourceManager.cpp ---------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/Core/SourceManager.h"
11254721Semaste
12254721Semaste// C Includes
13254721Semaste// C++ Includes
14254721Semaste// Other libraries and framework includes
15254721Semaste// Project includes
16254721Semaste#include "lldb/Core/DataBuffer.h"
17254721Semaste#include "lldb/Core/Debugger.h"
18254721Semaste#include "lldb/Core/Module.h"
19288943Sdim#include "lldb/Core/RegularExpression.h"
20254721Semaste#include "lldb/Core/Stream.h"
21254721Semaste#include "lldb/Symbol/CompileUnit.h"
22254721Semaste#include "lldb/Symbol/Function.h"
23254721Semaste#include "lldb/Symbol/SymbolContext.h"
24254721Semaste#include "lldb/Target/Target.h"
25254721Semaste
26254721Semasteusing namespace lldb;
27254721Semasteusing namespace lldb_private;
28254721Semaste
29254721Semaste
30254721Semastestatic inline bool is_newline_char(char ch)
31254721Semaste{
32254721Semaste    return ch == '\n' || ch == '\r';
33254721Semaste}
34254721Semaste
35254721Semaste
36254721Semaste//----------------------------------------------------------------------
37254721Semaste// SourceManager constructor
38254721Semaste//----------------------------------------------------------------------
39254721SemasteSourceManager::SourceManager(const TargetSP &target_sp) :
40254721Semaste    m_last_file_sp (),
41254721Semaste    m_last_line (0),
42254721Semaste    m_last_count (0),
43254721Semaste    m_default_set(false),
44254721Semaste    m_target_wp (target_sp),
45254721Semaste    m_debugger_wp(target_sp->GetDebugger().shared_from_this())
46254721Semaste{
47254721Semaste}
48254721Semaste
49254721SemasteSourceManager::SourceManager(const DebuggerSP &debugger_sp) :
50254721Semaste    m_last_file_sp (),
51254721Semaste    m_last_line (0),
52254721Semaste    m_last_count (0),
53254721Semaste    m_default_set(false),
54254721Semaste    m_target_wp (),
55254721Semaste    m_debugger_wp (debugger_sp)
56254721Semaste{
57254721Semaste}
58254721Semaste
59254721Semaste//----------------------------------------------------------------------
60254721Semaste// Destructor
61254721Semaste//----------------------------------------------------------------------
62254721SemasteSourceManager::~SourceManager()
63254721Semaste{
64254721Semaste}
65254721Semaste
66254721SemasteSourceManager::FileSP
67254721SemasteSourceManager::GetFile (const FileSpec &file_spec)
68254721Semaste{
69254721Semaste    bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
70254721Semaste
71254721Semaste    DebuggerSP debugger_sp (m_debugger_wp.lock());
72254721Semaste    FileSP file_sp;
73254721Semaste    if (same_as_previous)
74254721Semaste        file_sp = m_last_file_sp;
75254721Semaste    else if (debugger_sp)
76254721Semaste        file_sp = debugger_sp->GetSourceFileCache().FindSourceFile (file_spec);
77254721Semaste
78254721Semaste    TargetSP target_sp (m_target_wp.lock());
79254721Semaste
80254721Semaste    // It the target source path map has been updated, get this file again so we
81254721Semaste    // can successfully remap the source file
82254721Semaste    if (target_sp && file_sp && file_sp->GetSourceMapModificationID() != target_sp->GetSourcePathMap().GetModificationID())
83254721Semaste        file_sp.reset();
84254721Semaste
85296417Sdim    // Update the file contents if needed if we found a file
86296417Sdim    if (file_sp)
87296417Sdim        file_sp->UpdateIfNeeded();
88296417Sdim
89254721Semaste    // If file_sp is no good or it points to a non-existent file, reset it.
90254721Semaste    if (!file_sp || !file_sp->GetFileSpec().Exists())
91254721Semaste    {
92254721Semaste        file_sp.reset (new File (file_spec, target_sp.get()));
93254721Semaste
94254721Semaste        if (debugger_sp)
95254721Semaste            debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
96254721Semaste    }
97254721Semaste    return file_sp;
98254721Semaste}
99254721Semaste
100254721Semastesize_t
101254721SemasteSourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line,
102254721Semaste                                                               uint32_t count,
103254721Semaste                                                               uint32_t curr_line,
104254721Semaste                                                               const char* current_line_cstr,
105254721Semaste                                                               Stream *s,
106254721Semaste                                                               const SymbolContextList *bp_locs)
107254721Semaste{
108254721Semaste    if (count == 0)
109254721Semaste        return 0;
110254721Semaste    size_t return_value = 0;
111254721Semaste    if (start_line == 0)
112254721Semaste    {
113254721Semaste        if (m_last_line != 0 && m_last_line != UINT32_MAX)
114254721Semaste            start_line = m_last_line + m_last_count;
115254721Semaste        else
116254721Semaste            start_line = 1;
117254721Semaste    }
118254721Semaste
119254721Semaste    if (!m_default_set)
120254721Semaste    {
121254721Semaste        FileSpec tmp_spec;
122254721Semaste        uint32_t tmp_line;
123254721Semaste        GetDefaultFileAndLine(tmp_spec, tmp_line);
124254721Semaste    }
125254721Semaste
126254721Semaste    m_last_line = start_line;
127254721Semaste    m_last_count = count;
128254721Semaste
129254721Semaste    if (m_last_file_sp.get())
130254721Semaste    {
131254721Semaste        const uint32_t end_line = start_line + count - 1;
132254721Semaste        for (uint32_t line = start_line; line <= end_line; ++line)
133254721Semaste        {
134254721Semaste            if (!m_last_file_sp->LineIsValid (line))
135254721Semaste            {
136254721Semaste                m_last_line = UINT32_MAX;
137254721Semaste                break;
138254721Semaste            }
139254721Semaste
140254721Semaste            char prefix[32] = "";
141254721Semaste            if (bp_locs)
142254721Semaste            {
143254721Semaste                uint32_t bp_count = bp_locs->NumLineEntriesWithLine (line);
144254721Semaste
145254721Semaste                if (bp_count > 0)
146254721Semaste                    ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
147254721Semaste                else
148254721Semaste                    ::snprintf (prefix, sizeof (prefix), "    ");
149254721Semaste            }
150254721Semaste
151254721Semaste            return_value += s->Printf("%s%2.2s %-4u\t",
152254721Semaste                                      prefix,
153254721Semaste                                      line == curr_line ? current_line_cstr : "",
154254721Semaste                                      line);
155254721Semaste            size_t this_line_size = m_last_file_sp->DisplaySourceLines (line, 0, 0, s);
156254721Semaste            if (this_line_size == 0)
157254721Semaste            {
158254721Semaste                m_last_line = UINT32_MAX;
159254721Semaste                break;
160254721Semaste            }
161254721Semaste            else
162254721Semaste                return_value += this_line_size;
163254721Semaste        }
164254721Semaste    }
165254721Semaste    return return_value;
166254721Semaste}
167254721Semaste
168254721Semastesize_t
169254721SemasteSourceManager::DisplaySourceLinesWithLineNumbers
170254721Semaste(
171254721Semaste    const FileSpec &file_spec,
172254721Semaste    uint32_t line,
173254721Semaste    uint32_t context_before,
174254721Semaste    uint32_t context_after,
175254721Semaste    const char* current_line_cstr,
176254721Semaste    Stream *s,
177254721Semaste    const SymbolContextList *bp_locs
178254721Semaste)
179254721Semaste{
180254721Semaste    FileSP file_sp (GetFile (file_spec));
181254721Semaste
182254721Semaste    uint32_t start_line;
183254721Semaste    uint32_t count = context_before + context_after + 1;
184254721Semaste    if (line > context_before)
185254721Semaste        start_line = line - context_before;
186254721Semaste    else
187254721Semaste        start_line = 1;
188254721Semaste
189254721Semaste    if (m_last_file_sp.get() != file_sp.get())
190254721Semaste    {
191254721Semaste        if (line == 0)
192254721Semaste            m_last_line = 0;
193254721Semaste        m_last_file_sp = file_sp;
194254721Semaste    }
195254721Semaste    return DisplaySourceLinesWithLineNumbersUsingLastFile (start_line, count, line, current_line_cstr, s, bp_locs);
196254721Semaste}
197254721Semaste
198254721Semastesize_t
199254721SemasteSourceManager::DisplayMoreWithLineNumbers (Stream *s,
200254721Semaste                                           uint32_t count,
201254721Semaste                                           bool reverse,
202254721Semaste                                           const SymbolContextList *bp_locs)
203254721Semaste{
204254721Semaste    // If we get called before anybody has set a default file and line, then try to figure it out here.
205254721Semaste    const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
206254721Semaste    if (!m_default_set)
207254721Semaste    {
208254721Semaste        FileSpec tmp_spec;
209254721Semaste        uint32_t tmp_line;
210254721Semaste        GetDefaultFileAndLine(tmp_spec, tmp_line);
211254721Semaste    }
212254721Semaste
213254721Semaste    if (m_last_file_sp)
214254721Semaste    {
215254721Semaste        if (m_last_line == UINT32_MAX)
216254721Semaste            return 0;
217254721Semaste
218254721Semaste        if (reverse && m_last_line == 1)
219254721Semaste            return 0;
220254721Semaste
221254721Semaste        if (count > 0)
222254721Semaste            m_last_count = count;
223254721Semaste        else if (m_last_count == 0)
224254721Semaste            m_last_count = 10;
225254721Semaste
226254721Semaste        if (m_last_line > 0)
227254721Semaste        {
228254721Semaste            if (reverse)
229254721Semaste            {
230254721Semaste                // If this is the first time we've done a reverse, then back up one more time so we end
231254721Semaste                // up showing the chunk before the last one we've shown:
232254721Semaste                if (m_last_line > m_last_count)
233254721Semaste                    m_last_line -= m_last_count;
234254721Semaste                else
235254721Semaste                    m_last_line = 1;
236254721Semaste            }
237254721Semaste            else if (have_default_file_line)
238254721Semaste                m_last_line += m_last_count;
239254721Semaste        }
240254721Semaste        else
241254721Semaste            m_last_line = 1;
242254721Semaste
243254721Semaste        return DisplaySourceLinesWithLineNumbersUsingLastFile (m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs);
244254721Semaste    }
245254721Semaste    return 0;
246254721Semaste}
247254721Semaste
248254721Semastebool
249254721SemasteSourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
250254721Semaste{
251254721Semaste    FileSP old_file_sp = m_last_file_sp;
252254721Semaste    m_last_file_sp = GetFile (file_spec);
253254721Semaste
254254721Semaste    m_default_set = true;
255254721Semaste    if (m_last_file_sp)
256254721Semaste    {
257254721Semaste        m_last_line = line;
258254721Semaste        return true;
259254721Semaste    }
260254721Semaste    else
261254721Semaste    {
262254721Semaste        m_last_file_sp = old_file_sp;
263254721Semaste        return false;
264254721Semaste    }
265254721Semaste}
266254721Semaste
267254721Semastebool
268254721SemasteSourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
269254721Semaste{
270254721Semaste    if (m_last_file_sp)
271254721Semaste    {
272254721Semaste        file_spec = m_last_file_sp->GetFileSpec();
273254721Semaste        line = m_last_line;
274254721Semaste        return true;
275254721Semaste    }
276254721Semaste    else if (!m_default_set)
277254721Semaste    {
278254721Semaste        TargetSP target_sp (m_target_wp.lock());
279254721Semaste
280254721Semaste        if (target_sp)
281254721Semaste        {
282254721Semaste            // If nobody has set the default file and line then try here.  If there's no executable, then we
283254721Semaste            // will try again later when there is one.  Otherwise, if we can't find it we won't look again,
284254721Semaste            // somebody will have to set it (for instance when we stop somewhere...)
285254721Semaste            Module *executable_ptr = target_sp->GetExecutableModulePointer();
286254721Semaste            if (executable_ptr)
287254721Semaste            {
288254721Semaste                SymbolContextList sc_list;
289254721Semaste                ConstString main_name("main");
290254721Semaste                bool symbols_okay = false;  // Force it to be a debug symbol.
291254721Semaste                bool inlines_okay = true;
292254721Semaste                bool append = false;
293254721Semaste                size_t num_matches = executable_ptr->FindFunctions (main_name,
294254721Semaste                                                                    NULL,
295254721Semaste                                                                    lldb::eFunctionNameTypeBase,
296254721Semaste                                                                    inlines_okay,
297254721Semaste                                                                    symbols_okay,
298254721Semaste                                                                    append,
299254721Semaste                                                                    sc_list);
300254721Semaste                for (size_t idx = 0; idx < num_matches; idx++)
301254721Semaste                {
302254721Semaste                    SymbolContext sc;
303254721Semaste                    sc_list.GetContextAtIndex(idx, sc);
304254721Semaste                    if (sc.function)
305254721Semaste                    {
306254721Semaste                        lldb_private::LineEntry line_entry;
307254721Semaste                        if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
308254721Semaste                        {
309254721Semaste                            SetDefaultFileAndLine (line_entry.file,
310254721Semaste                                                   line_entry.line);
311254721Semaste                            file_spec = m_last_file_sp->GetFileSpec();
312254721Semaste                            line = m_last_line;
313254721Semaste                            return true;
314254721Semaste                        }
315254721Semaste                    }
316254721Semaste                }
317254721Semaste            }
318254721Semaste        }
319254721Semaste    }
320254721Semaste    return false;
321254721Semaste}
322254721Semaste
323254721Semastevoid
324254721SemasteSourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
325254721Semaste                                       RegularExpression& regex,
326254721Semaste                                       uint32_t start_line,
327254721Semaste                                       uint32_t end_line,
328254721Semaste                                       std::vector<uint32_t> &match_lines)
329254721Semaste{
330254721Semaste    match_lines.clear();
331254721Semaste    FileSP file_sp = GetFile (file_spec);
332254721Semaste    if (!file_sp)
333254721Semaste        return;
334254721Semaste    return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
335254721Semaste}
336254721Semaste
337254721SemasteSourceManager::File::File(const FileSpec &file_spec, Target *target) :
338254721Semaste    m_file_spec_orig (file_spec),
339254721Semaste    m_file_spec(file_spec),
340254721Semaste    m_mod_time (file_spec.GetModificationTime()),
341254721Semaste    m_source_map_mod_id (0),
342254721Semaste    m_data_sp(),
343254721Semaste    m_offsets()
344254721Semaste{
345254721Semaste    if (!m_mod_time.IsValid())
346254721Semaste    {
347254721Semaste        if (target)
348254721Semaste        {
349254721Semaste            m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
350254721Semaste
351254721Semaste            if (!file_spec.GetDirectory() && file_spec.GetFilename())
352254721Semaste            {
353254721Semaste                // If this is just a file name, lets see if we can find it in the target:
354254721Semaste                bool check_inlines = false;
355254721Semaste                SymbolContextList sc_list;
356254721Semaste                size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
357254721Semaste                                                                                          0,
358254721Semaste                                                                                          check_inlines,
359254721Semaste                                                                                          lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
360254721Semaste                                                                                          sc_list);
361254721Semaste                bool got_multiple = false;
362254721Semaste                if (num_matches != 0)
363254721Semaste                {
364254721Semaste                    if (num_matches > 1)
365254721Semaste                    {
366254721Semaste                        SymbolContext sc;
367254721Semaste                        FileSpec *test_cu_spec = NULL;
368254721Semaste
369254721Semaste                        for (unsigned i = 0; i < num_matches; i++)
370254721Semaste                        {
371254721Semaste                            sc_list.GetContextAtIndex(i, sc);
372254721Semaste                            if (sc.comp_unit)
373254721Semaste                            {
374254721Semaste                                if (test_cu_spec)
375254721Semaste                                {
376254721Semaste                                    if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
377254721Semaste                                        got_multiple = true;
378276479Sdim                                    break;
379254721Semaste                                }
380254721Semaste                                else
381254721Semaste                                    test_cu_spec = sc.comp_unit;
382254721Semaste                            }
383254721Semaste                        }
384254721Semaste                    }
385254721Semaste                    if (!got_multiple)
386254721Semaste                    {
387254721Semaste                        SymbolContext sc;
388254721Semaste                        sc_list.GetContextAtIndex (0, sc);
389254721Semaste                        m_file_spec = sc.comp_unit;
390254721Semaste                        m_mod_time = m_file_spec.GetModificationTime();
391254721Semaste                    }
392254721Semaste                }
393254721Semaste            }
394254721Semaste            // Try remapping if m_file_spec does not correspond to an existing file.
395254721Semaste            if (!m_file_spec.Exists())
396254721Semaste            {
397254721Semaste                FileSpec new_file_spec;
398254721Semaste                // Check target specific source remappings first, then fall back to
399254721Semaste                // modules objects can have individual path remappings that were detected
400254721Semaste                // when the debug info for a module was found.
401254721Semaste                // then
402254721Semaste                if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) ||
403254721Semaste                    target->GetImages().FindSourceFile (m_file_spec, new_file_spec))
404254721Semaste                {
405254721Semaste                    m_file_spec = new_file_spec;
406254721Semaste                    m_mod_time = m_file_spec.GetModificationTime();
407254721Semaste                }
408254721Semaste            }
409254721Semaste        }
410254721Semaste    }
411254721Semaste
412254721Semaste    if (m_mod_time.IsValid())
413254721Semaste        m_data_sp = m_file_spec.ReadFileContents ();
414254721Semaste}
415254721Semaste
416254721SemasteSourceManager::File::~File()
417254721Semaste{
418254721Semaste}
419254721Semaste
420254721Semasteuint32_t
421254721SemasteSourceManager::File::GetLineOffset (uint32_t line)
422254721Semaste{
423254721Semaste    if (line == 0)
424254721Semaste        return UINT32_MAX;
425254721Semaste
426254721Semaste    if (line == 1)
427254721Semaste        return 0;
428254721Semaste
429254721Semaste    if (CalculateLineOffsets (line))
430254721Semaste    {
431254721Semaste        if (line < m_offsets.size())
432254721Semaste            return m_offsets[line - 1]; // yes we want "line - 1" in the index
433254721Semaste    }
434254721Semaste    return UINT32_MAX;
435254721Semaste}
436254721Semaste
437262528Semasteuint32_t
438262528SemasteSourceManager::File::GetNumLines ()
439262528Semaste{
440262528Semaste    CalculateLineOffsets();
441262528Semaste    return m_offsets.size();
442262528Semaste}
443262528Semaste
444262528Semasteconst char *
445262528SemasteSourceManager::File::PeekLineData (uint32_t line)
446262528Semaste{
447262528Semaste    if (!LineIsValid(line))
448262528Semaste        return NULL;
449262528Semaste
450262528Semaste    size_t line_offset = GetLineOffset (line);
451262528Semaste    if (line_offset < m_data_sp->GetByteSize())
452262528Semaste        return (const char *)m_data_sp->GetBytes() + line_offset;
453262528Semaste    return NULL;
454262528Semaste}
455262528Semaste
456262528Semasteuint32_t
457262528SemasteSourceManager::File::GetLineLength (uint32_t line, bool include_newline_chars)
458262528Semaste{
459262528Semaste    if (!LineIsValid(line))
460262528Semaste        return false;
461262528Semaste
462262528Semaste    size_t start_offset = GetLineOffset (line);
463262528Semaste    size_t end_offset = GetLineOffset (line + 1);
464262528Semaste    if (end_offset == UINT32_MAX)
465262528Semaste        end_offset = m_data_sp->GetByteSize();
466262528Semaste
467262528Semaste    if (end_offset > start_offset)
468262528Semaste    {
469262528Semaste        uint32_t length = end_offset - start_offset;
470262528Semaste        if (include_newline_chars == false)
471262528Semaste        {
472262528Semaste            const char *line_start = (const char *)m_data_sp->GetBytes() + start_offset;
473262528Semaste            while (length > 0)
474262528Semaste            {
475262528Semaste                const char last_char = line_start[length-1];
476262528Semaste                if ((last_char == '\r') || (last_char == '\n'))
477262528Semaste                    --length;
478262528Semaste                else
479262528Semaste                    break;
480262528Semaste            }
481262528Semaste        }
482262528Semaste        return length;
483262528Semaste    }
484262528Semaste    return 0;
485262528Semaste}
486262528Semaste
487254721Semastebool
488254721SemasteSourceManager::File::LineIsValid (uint32_t line)
489254721Semaste{
490254721Semaste    if (line == 0)
491254721Semaste        return false;
492254721Semaste
493254721Semaste    if (CalculateLineOffsets (line))
494254721Semaste        return line < m_offsets.size();
495254721Semaste    return false;
496254721Semaste}
497254721Semaste
498296417Sdimvoid
499296417SdimSourceManager::File::UpdateIfNeeded ()
500254721Semaste{
501254721Semaste    // TODO: use host API to sign up for file modifications to anything in our
502254721Semaste    // source cache and only update when we determine a file has been updated.
503254721Semaste    // For now we check each time we want to display info for the file.
504254721Semaste    TimeValue curr_mod_time (m_file_spec.GetModificationTime());
505254721Semaste
506254721Semaste    if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
507254721Semaste    {
508254721Semaste        m_mod_time = curr_mod_time;
509254721Semaste        m_data_sp = m_file_spec.ReadFileContents ();
510254721Semaste        m_offsets.clear();
511254721Semaste    }
512296417Sdim}
513254721Semaste
514296417Sdimsize_t
515296417SdimSourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
516296417Sdim{
517254721Semaste    // Sanity check m_data_sp before proceeding.
518254721Semaste    if (!m_data_sp)
519254721Semaste        return 0;
520254721Semaste
521254721Semaste    const uint32_t start_line = line <= context_before ? 1 : line - context_before;
522254721Semaste    const uint32_t start_line_offset = GetLineOffset (start_line);
523254721Semaste    if (start_line_offset != UINT32_MAX)
524254721Semaste    {
525254721Semaste        const uint32_t end_line = line + context_after;
526254721Semaste        uint32_t end_line_offset = GetLineOffset (end_line + 1);
527254721Semaste        if (end_line_offset == UINT32_MAX)
528254721Semaste            end_line_offset = m_data_sp->GetByteSize();
529254721Semaste
530254721Semaste        assert (start_line_offset <= end_line_offset);
531254721Semaste        size_t bytes_written = 0;
532254721Semaste        if (start_line_offset < end_line_offset)
533254721Semaste        {
534254721Semaste            size_t count = end_line_offset - start_line_offset;
535254721Semaste            const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
536254721Semaste            bytes_written = s->Write(cstr, count);
537254721Semaste            if (!is_newline_char(cstr[count-1]))
538254721Semaste                bytes_written += s->EOL();
539254721Semaste        }
540254721Semaste        return bytes_written;
541254721Semaste    }
542254721Semaste    return 0;
543254721Semaste}
544254721Semaste
545254721Semastevoid
546254721SemasteSourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
547254721Semaste{
548254721Semaste    match_lines.clear();
549254721Semaste
550254721Semaste    if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
551254721Semaste        return;
552254721Semaste    if (start_line > end_line)
553254721Semaste        return;
554254721Semaste
555254721Semaste    for (uint32_t line_no = start_line; line_no < end_line; line_no++)
556254721Semaste    {
557254721Semaste        std::string buffer;
558254721Semaste        if (!GetLine (line_no, buffer))
559254721Semaste            break;
560254721Semaste        if (regex.Execute(buffer.c_str()))
561254721Semaste        {
562254721Semaste            match_lines.push_back(line_no);
563254721Semaste        }
564254721Semaste    }
565254721Semaste}
566254721Semaste
567254721Semastebool
568254721SemasteSourceManager::File::FileSpecMatches (const FileSpec &file_spec)
569254721Semaste{
570254721Semaste    return FileSpec::Equal (m_file_spec, file_spec, false);
571254721Semaste}
572254721Semaste
573254721Semastebool
574254721Semastelldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
575254721Semaste{
576254721Semaste    if (lhs.m_file_spec == rhs.m_file_spec)
577254721Semaste    {
578254721Semaste        if (lhs.m_mod_time.IsValid())
579254721Semaste        {
580254721Semaste            if (rhs.m_mod_time.IsValid())
581254721Semaste                return lhs.m_mod_time == rhs.m_mod_time;
582254721Semaste            else
583254721Semaste                return false;
584254721Semaste        }
585254721Semaste        else if (rhs.m_mod_time.IsValid())
586254721Semaste            return false;
587254721Semaste        else
588254721Semaste            return true;
589254721Semaste    }
590254721Semaste    else
591254721Semaste        return false;
592254721Semaste}
593254721Semaste
594254721Semastebool
595254721SemasteSourceManager::File::CalculateLineOffsets (uint32_t line)
596254721Semaste{
597254721Semaste    line = UINT32_MAX;  // TODO: take this line out when we support partial indexing
598254721Semaste    if (line == UINT32_MAX)
599254721Semaste    {
600254721Semaste        // Already done?
601254721Semaste        if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
602254721Semaste            return true;
603254721Semaste
604254721Semaste        if (m_offsets.empty())
605254721Semaste        {
606254721Semaste            if (m_data_sp.get() == NULL)
607254721Semaste                return false;
608254721Semaste
609254721Semaste            const char *start = (char *)m_data_sp->GetBytes();
610254721Semaste            if (start)
611254721Semaste            {
612254721Semaste                const char *end = start + m_data_sp->GetByteSize();
613254721Semaste
614254721Semaste                // Calculate all line offsets from scratch
615254721Semaste
616254721Semaste                // Push a 1 at index zero to indicate the file has been completely indexed.
617254721Semaste                m_offsets.push_back(UINT32_MAX);
618258054Semaste                const char *s;
619254721Semaste                for (s = start; s < end; ++s)
620254721Semaste                {
621258054Semaste                    char curr_ch = *s;
622254721Semaste                    if (is_newline_char (curr_ch))
623254721Semaste                    {
624254721Semaste                        if (s + 1 < end)
625254721Semaste                        {
626258054Semaste                            char next_ch = s[1];
627254721Semaste                            if (is_newline_char (next_ch))
628254721Semaste                            {
629254721Semaste                                if (curr_ch != next_ch)
630254721Semaste                                    ++s;
631254721Semaste                            }
632254721Semaste                        }
633254721Semaste                        m_offsets.push_back(s + 1 - start);
634254721Semaste                    }
635254721Semaste                }
636254721Semaste                if (!m_offsets.empty())
637254721Semaste                {
638254721Semaste                    if (m_offsets.back() < end - start)
639254721Semaste                        m_offsets.push_back(end - start);
640254721Semaste                }
641254721Semaste                return true;
642254721Semaste            }
643254721Semaste        }
644254721Semaste        else
645254721Semaste        {
646254721Semaste            // Some lines have been populated, start where we last left off
647296417Sdim            assert("Not implemented yet" && false);
648254721Semaste        }
649254721Semaste
650254721Semaste    }
651254721Semaste    else
652254721Semaste    {
653254721Semaste        // Calculate all line offsets up to "line"
654296417Sdim        assert("Not implemented yet" && false);
655254721Semaste    }
656254721Semaste    return false;
657254721Semaste}
658254721Semaste
659254721Semastebool
660254721SemasteSourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
661254721Semaste{
662254721Semaste    if (!LineIsValid(line_no))
663254721Semaste        return false;
664254721Semaste
665254721Semaste    size_t start_offset = GetLineOffset (line_no);
666254721Semaste    size_t end_offset = GetLineOffset (line_no + 1);
667254721Semaste    if (end_offset == UINT32_MAX)
668254721Semaste    {
669254721Semaste        end_offset = m_data_sp->GetByteSize();
670254721Semaste    }
671254721Semaste    buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
672254721Semaste
673254721Semaste    return true;
674254721Semaste}
675254721Semaste
676254721Semastevoid
677254721SemasteSourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
678254721Semaste{
679254721Semaste    FileSpec file_spec;
680254721Semaste    FileCache::iterator pos = m_file_cache.find(file_spec);
681254721Semaste    if (pos == m_file_cache.end())
682254721Semaste        m_file_cache[file_spec] = file_sp;
683254721Semaste    else
684254721Semaste    {
685254721Semaste        if (file_sp != pos->second)
686254721Semaste            m_file_cache[file_spec] = file_sp;
687254721Semaste    }
688254721Semaste}
689254721Semaste
690254721SemasteSourceManager::FileSP
691254721SemasteSourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
692254721Semaste{
693254721Semaste    FileSP file_sp;
694254721Semaste    FileCache::const_iterator pos = m_file_cache.find(file_spec);
695254721Semaste    if (pos != m_file_cache.end())
696254721Semaste        file_sp = pos->second;
697254721Semaste    return file_sp;
698254721Semaste}
699254721Semaste
700