130fdc8d8SChris Lattner //===-- SourceManager.cpp ---------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner #include "lldb/Core/SourceManager.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
1630fdc8d8SChris Lattner #include "lldb/Core/DataBuffer.h"
17e37d605eSJim Ingham #include "lldb/Core/Debugger.h"
1830fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
19b6d70ebcSSean Callanan #include "lldb/Symbol/ClangNamespaceDecl.h"
20176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
217e14f91dSGreg Clayton #include "lldb/Target/Target.h"
2230fdc8d8SChris Lattner 
2330fdc8d8SChris Lattner using namespace lldb_private;
2430fdc8d8SChris Lattner 
2530fdc8d8SChris Lattner static inline bool is_newline_char(char ch)
2630fdc8d8SChris Lattner {
2730fdc8d8SChris Lattner     return ch == '\n' || ch == '\r';
2830fdc8d8SChris Lattner }
2930fdc8d8SChris Lattner 
3030fdc8d8SChris Lattner 
3130fdc8d8SChris Lattner //----------------------------------------------------------------------
3230fdc8d8SChris Lattner // SourceManager constructor
3330fdc8d8SChris Lattner //----------------------------------------------------------------------
34e37d605eSJim Ingham SourceManager::SourceManager(Target &target) :
3530fdc8d8SChris Lattner     m_last_file_sp (),
3630fdc8d8SChris Lattner     m_last_file_line (0),
3730fdc8d8SChris Lattner     m_last_file_context_before (0),
38b7f6b2faSJim Ingham     m_last_file_context_after (10),
39f3277750SJim Ingham     m_default_set(false),
40e37d605eSJim Ingham     m_target (&target),
41e37d605eSJim Ingham     m_debugger(NULL)
42e37d605eSJim Ingham {
43e37d605eSJim Ingham     m_debugger = &(m_target->GetDebugger());
44e37d605eSJim Ingham }
45e37d605eSJim Ingham 
46e37d605eSJim Ingham SourceManager::SourceManager(Debugger &debugger) :
47e37d605eSJim Ingham     m_last_file_sp (),
48e37d605eSJim Ingham     m_last_file_line (0),
49e37d605eSJim Ingham     m_last_file_context_before (0),
50e37d605eSJim Ingham     m_last_file_context_after (10),
51f3277750SJim Ingham     m_default_set(false),
52e37d605eSJim Ingham     m_target (NULL),
53e37d605eSJim Ingham     m_debugger (&debugger)
5430fdc8d8SChris Lattner {
5530fdc8d8SChris Lattner }
5630fdc8d8SChris Lattner 
5730fdc8d8SChris Lattner //----------------------------------------------------------------------
5830fdc8d8SChris Lattner // Destructor
5930fdc8d8SChris Lattner //----------------------------------------------------------------------
6030fdc8d8SChris Lattner SourceManager::~SourceManager()
6130fdc8d8SChris Lattner {
6230fdc8d8SChris Lattner }
6330fdc8d8SChris Lattner 
6430fdc8d8SChris Lattner size_t
6530fdc8d8SChris Lattner SourceManager::DisplaySourceLines
6630fdc8d8SChris Lattner (
6730fdc8d8SChris Lattner     const FileSpec &file_spec,
6830fdc8d8SChris Lattner     uint32_t line,
6930fdc8d8SChris Lattner     uint32_t context_before,
7030fdc8d8SChris Lattner     uint32_t context_after,
7130fdc8d8SChris Lattner     Stream *s
7230fdc8d8SChris Lattner )
7330fdc8d8SChris Lattner {
74b7f6b2faSJim Ingham     m_last_file_sp = GetFile (file_spec);
7530fdc8d8SChris Lattner     m_last_file_line = line + context_after + 1;
7630fdc8d8SChris Lattner     m_last_file_context_before = context_before;
7730fdc8d8SChris Lattner     m_last_file_context_after = context_after;
7830fdc8d8SChris Lattner     if (m_last_file_sp.get())
7930fdc8d8SChris Lattner         return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
8030fdc8d8SChris Lattner 
8130fdc8d8SChris Lattner     return 0;
8230fdc8d8SChris Lattner }
8330fdc8d8SChris Lattner 
8430fdc8d8SChris Lattner SourceManager::FileSP
85b7f6b2faSJim Ingham SourceManager::GetFile (const FileSpec &file_spec)
8630fdc8d8SChris Lattner {
8730fdc8d8SChris Lattner     FileSP file_sp;
88e37d605eSJim Ingham     file_sp = m_debugger->GetSourceFileCache().FindSourceFile (file_spec);
8964bab489SJohnny Chen     // If file_sp is no good or it points to a non-existent file, reset it.
9064bab489SJohnny Chen     if (!file_sp || !file_sp->GetFileSpec().Exists())
9130fdc8d8SChris Lattner     {
92b7f6b2faSJim Ingham         file_sp.reset (new File (file_spec, m_target));
93e37d605eSJim Ingham 
94e37d605eSJim Ingham         m_debugger->GetSourceFileCache().AddSourceFile(file_sp);
9530fdc8d8SChris Lattner     }
9630fdc8d8SChris Lattner     return file_sp;
9730fdc8d8SChris Lattner }
9830fdc8d8SChris Lattner 
9930fdc8d8SChris Lattner size_t
10030fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
10130fdc8d8SChris Lattner (
10230fdc8d8SChris Lattner     uint32_t line,
10330fdc8d8SChris Lattner     uint32_t context_before,
10430fdc8d8SChris Lattner     uint32_t context_after,
10530fdc8d8SChris Lattner     const char* current_line_cstr,
106176761e5SGreg Clayton     Stream *s,
107176761e5SGreg Clayton     const SymbolContextList *bp_locs
10830fdc8d8SChris Lattner )
10930fdc8d8SChris Lattner {
110e37d605eSJim Ingham     size_t return_value = 0;
11130fdc8d8SChris Lattner     if (line == 0)
11230fdc8d8SChris Lattner     {
11330fdc8d8SChris Lattner         if (m_last_file_line != 0
11430fdc8d8SChris Lattner             && m_last_file_line != UINT32_MAX)
11530fdc8d8SChris Lattner             line = m_last_file_line + context_before;
11630fdc8d8SChris Lattner         else
11730fdc8d8SChris Lattner             line = 1;
11830fdc8d8SChris Lattner     }
11930fdc8d8SChris Lattner 
12030fdc8d8SChris Lattner     m_last_file_line = line + context_after + 1;
12130fdc8d8SChris Lattner     m_last_file_context_before = context_before;
12230fdc8d8SChris Lattner     m_last_file_context_after = context_after;
12330fdc8d8SChris Lattner 
12430fdc8d8SChris Lattner     if (context_before == UINT32_MAX)
12530fdc8d8SChris Lattner         context_before = 0;
12630fdc8d8SChris Lattner     if (context_after == UINT32_MAX)
12730fdc8d8SChris Lattner         context_after = 10;
12830fdc8d8SChris Lattner 
12930fdc8d8SChris Lattner     if (m_last_file_sp.get())
13030fdc8d8SChris Lattner     {
13130fdc8d8SChris Lattner         const uint32_t start_line = line <= context_before ? 1 : line - context_before;
13230fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
13330fdc8d8SChris Lattner         uint32_t curr_line;
13430fdc8d8SChris Lattner         for (curr_line = start_line; curr_line <= end_line; ++curr_line)
13530fdc8d8SChris Lattner         {
13630fdc8d8SChris Lattner             if (!m_last_file_sp->LineIsValid (curr_line))
13730fdc8d8SChris Lattner             {
13830fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
13930fdc8d8SChris Lattner                 break;
14030fdc8d8SChris Lattner             }
14130fdc8d8SChris Lattner 
142176761e5SGreg Clayton             char prefix[32] = "";
143176761e5SGreg Clayton             if (bp_locs)
144176761e5SGreg Clayton             {
145176761e5SGreg Clayton                 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
146176761e5SGreg Clayton 
147176761e5SGreg Clayton                 if (bp_count > 0)
148176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
149176761e5SGreg Clayton                 else
150176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "    ");
151176761e5SGreg Clayton             }
152176761e5SGreg Clayton 
153e37d605eSJim Ingham             return_value += s->Printf("%s%2.2s %-4u\t",
154176761e5SGreg Clayton                       prefix,
155176761e5SGreg Clayton                       curr_line == line ? current_line_cstr : "",
156176761e5SGreg Clayton                       curr_line);
157e37d605eSJim Ingham             size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s);
158e37d605eSJim Ingham             if (this_line_size == 0)
15930fdc8d8SChris Lattner             {
16030fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
16130fdc8d8SChris Lattner                 break;
16230fdc8d8SChris Lattner             }
163e37d605eSJim Ingham             else
164e37d605eSJim Ingham                 return_value += this_line_size;
16530fdc8d8SChris Lattner         }
16630fdc8d8SChris Lattner     }
167e37d605eSJim Ingham     return return_value;
16830fdc8d8SChris Lattner }
16930fdc8d8SChris Lattner 
17030fdc8d8SChris Lattner size_t
17130fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbers
17230fdc8d8SChris Lattner (
17330fdc8d8SChris Lattner     const FileSpec &file_spec,
17430fdc8d8SChris Lattner     uint32_t line,
17530fdc8d8SChris Lattner     uint32_t context_before,
17630fdc8d8SChris Lattner     uint32_t context_after,
17730fdc8d8SChris Lattner     const char* current_line_cstr,
178176761e5SGreg Clayton     Stream *s,
179176761e5SGreg Clayton     const SymbolContextList *bp_locs
18030fdc8d8SChris Lattner )
18130fdc8d8SChris Lattner {
18230fdc8d8SChris Lattner     bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
18330fdc8d8SChris Lattner 
18430fdc8d8SChris Lattner     if (!same_as_previous)
185b7f6b2faSJim Ingham         m_last_file_sp = GetFile (file_spec);
18630fdc8d8SChris Lattner 
18730fdc8d8SChris Lattner     if (line == 0)
18830fdc8d8SChris Lattner     {
18930fdc8d8SChris Lattner         if (!same_as_previous)
19030fdc8d8SChris Lattner             m_last_file_line = 0;
19130fdc8d8SChris Lattner     }
19230fdc8d8SChris Lattner 
193176761e5SGreg Clayton     return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
19430fdc8d8SChris Lattner }
19530fdc8d8SChris Lattner 
19630fdc8d8SChris Lattner size_t
197176761e5SGreg Clayton SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs)
19830fdc8d8SChris Lattner {
19930fdc8d8SChris Lattner     if (m_last_file_sp)
20030fdc8d8SChris Lattner     {
20130fdc8d8SChris Lattner         if (m_last_file_line == UINT32_MAX)
20230fdc8d8SChris Lattner             return 0;
203e37d605eSJim Ingham         return DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
20430fdc8d8SChris Lattner     }
20530fdc8d8SChris Lattner     return 0;
20630fdc8d8SChris Lattner }
20730fdc8d8SChris Lattner 
208b7f6b2faSJim Ingham bool
209b7f6b2faSJim Ingham SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
210b7f6b2faSJim Ingham {
211b7f6b2faSJim Ingham     FileSP old_file_sp = m_last_file_sp;
212b7f6b2faSJim Ingham     m_last_file_sp = GetFile (file_spec);
213f3277750SJim Ingham 
214f3277750SJim Ingham     m_default_set = true;
215b7f6b2faSJim Ingham     if (m_last_file_sp)
216b7f6b2faSJim Ingham     {
217b7f6b2faSJim Ingham         m_last_file_line = line;
218b7f6b2faSJim Ingham         return true;
219b7f6b2faSJim Ingham     }
220b7f6b2faSJim Ingham     else
221b7f6b2faSJim Ingham     {
222b7f6b2faSJim Ingham         m_last_file_sp = old_file_sp;
223b7f6b2faSJim Ingham         return false;
224b7f6b2faSJim Ingham     }
225b7f6b2faSJim Ingham }
226b7f6b2faSJim Ingham 
227b7f6b2faSJim Ingham bool
228b7f6b2faSJim Ingham SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
229b7f6b2faSJim Ingham {
230b7f6b2faSJim Ingham     if (m_last_file_sp)
231b7f6b2faSJim Ingham     {
232b7f6b2faSJim Ingham         file_spec = m_last_file_sp->GetFileSpec();
233b7f6b2faSJim Ingham         line = m_last_file_line;
234b7f6b2faSJim Ingham         return true;
235b7f6b2faSJim Ingham     }
236f3277750SJim Ingham     else if (!m_default_set)
237f3277750SJim Ingham     {
238f3277750SJim Ingham         // If nobody has set the default file and line then try here.  If there's no executable, then we
239f3277750SJim Ingham         // will try again later when there is one.  Otherwise, if we can't find it we won't look again,
240f3277750SJim Ingham         // somebody will have to set it (for instance when we stop somewhere...)
241f3277750SJim Ingham         Module *executable_ptr = m_target->GetExecutableModulePointer();
242f3277750SJim Ingham         if (executable_ptr)
243f3277750SJim Ingham         {
244f3277750SJim Ingham             SymbolContextList sc_list;
245f3277750SJim Ingham             uint32_t num_matches;
246f3277750SJim Ingham             ConstString main_name("main");
247f3277750SJim Ingham             bool symbols_okay = false;  // Force it to be a debug symbol.
248*9df05fbbSSean Callanan             bool inlines_okay = true;
249f3277750SJim Ingham             bool append = false;
250*9df05fbbSSean Callanan             num_matches = executable_ptr->FindFunctions (main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay, symbols_okay, append, sc_list);
251f3277750SJim Ingham             for (uint32_t idx = 0; idx < num_matches; idx++)
252f3277750SJim Ingham             {
253f3277750SJim Ingham                 SymbolContext sc;
254f3277750SJim Ingham                 sc_list.GetContextAtIndex(idx, sc);
2556f6bf26aSGreg Clayton                 if (sc.function)
256f3277750SJim Ingham                 {
2576f6bf26aSGreg Clayton                     lldb_private::LineEntry line_entry;
2586f6bf26aSGreg Clayton                     if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
2596f6bf26aSGreg Clayton                     {
2606f6bf26aSGreg Clayton                         SetDefaultFileAndLine (line_entry.file,
2616f6bf26aSGreg Clayton                                                line_entry.line);
2626f6bf26aSGreg Clayton                         file_spec = m_last_file_sp->GetFileSpec();
2636f6bf26aSGreg Clayton                         line = m_last_file_line;
2646f6bf26aSGreg Clayton                         return true;
265f3277750SJim Ingham                     }
266f3277750SJim Ingham                 }
267f3277750SJim Ingham             }
268f3277750SJim Ingham         }
2696f6bf26aSGreg Clayton     }
270b7f6b2faSJim Ingham     return false;
271b7f6b2faSJim Ingham }
27230fdc8d8SChris Lattner 
273969795f1SJim Ingham void
274969795f1SJim Ingham SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
275969795f1SJim Ingham                         RegularExpression& regex,
276969795f1SJim Ingham                         uint32_t start_line,
277969795f1SJim Ingham                         uint32_t end_line,
278969795f1SJim Ingham                         std::vector<uint32_t> &match_lines)
279969795f1SJim Ingham {
280969795f1SJim Ingham     match_lines.clear();
281969795f1SJim Ingham     FileSP file_sp = GetFile (file_spec);
282969795f1SJim Ingham     if (!file_sp)
283969795f1SJim Ingham         return;
284969795f1SJim Ingham     return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
285969795f1SJim Ingham }
28630fdc8d8SChris Lattner 
2877e14f91dSGreg Clayton SourceManager::File::File(const FileSpec &file_spec, Target *target) :
2887e14f91dSGreg Clayton     m_file_spec_orig (file_spec),
28930fdc8d8SChris Lattner     m_file_spec(file_spec),
2907e14f91dSGreg Clayton     m_mod_time (file_spec.GetModificationTime()),
2917e14f91dSGreg Clayton     m_data_sp(),
29230fdc8d8SChris Lattner     m_offsets()
29330fdc8d8SChris Lattner {
2947e14f91dSGreg Clayton     if (!m_mod_time.IsValid())
2957e14f91dSGreg Clayton     {
296e37d605eSJim Ingham         if (target)
297e37d605eSJim Ingham         {
298e37d605eSJim Ingham             if (!file_spec.GetDirectory() && file_spec.GetFilename())
299e37d605eSJim Ingham             {
300e37d605eSJim Ingham                 // If this is just a file name, lets see if we can find it in the target:
301e37d605eSJim Ingham                 bool check_inlines = false;
302e37d605eSJim Ingham                 SymbolContextList sc_list;
303e37d605eSJim Ingham                 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
304e37d605eSJim Ingham                                                                                           0,
305e37d605eSJim Ingham                                                                                           check_inlines,
306e37d605eSJim Ingham                                                                                           lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
307e37d605eSJim Ingham                                                                                           sc_list);
308e37d605eSJim Ingham                 bool got_multiple = false;
309e37d605eSJim Ingham                 if (num_matches != 0)
310e37d605eSJim Ingham                 {
311e37d605eSJim Ingham                     if (num_matches > 1)
312e37d605eSJim Ingham                     {
313e37d605eSJim Ingham                         SymbolContext sc;
314e37d605eSJim Ingham                         FileSpec *test_cu_spec = NULL;
315e37d605eSJim Ingham 
316e37d605eSJim Ingham                         for (unsigned i = 0; i < num_matches; i++)
317e37d605eSJim Ingham                         {
318e37d605eSJim Ingham                             sc_list.GetContextAtIndex(i, sc);
319e37d605eSJim Ingham                             if (sc.comp_unit)
320e37d605eSJim Ingham                             {
321e37d605eSJim Ingham                                 if (test_cu_spec)
322e37d605eSJim Ingham                                 {
323e37d605eSJim Ingham                                     if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
324e37d605eSJim Ingham                                         got_multiple = true;
325e37d605eSJim Ingham                                         break;
326e37d605eSJim Ingham                                 }
327e37d605eSJim Ingham                                 else
328e37d605eSJim Ingham                                     test_cu_spec = sc.comp_unit;
329e37d605eSJim Ingham                             }
330e37d605eSJim Ingham                         }
331e37d605eSJim Ingham                     }
332e37d605eSJim Ingham                     if (!got_multiple)
333e37d605eSJim Ingham                     {
334e37d605eSJim Ingham                         SymbolContext sc;
335e37d605eSJim Ingham                         sc_list.GetContextAtIndex (0, sc);
336e37d605eSJim Ingham                         m_file_spec = static_cast<FileSpec *>(sc.comp_unit);
337e37d605eSJim Ingham                         m_mod_time = m_file_spec.GetModificationTime();
338e37d605eSJim Ingham                     }
339e37d605eSJim Ingham                 }
340e37d605eSJim Ingham             }
34164bab489SJohnny Chen             // Try remapping if m_file_spec does not correspond to an existing file.
34264bab489SJohnny Chen             if (!m_file_spec.Exists())
343e37d605eSJim Ingham             {
34464bab489SJohnny Chen                 ConstString new_path;
34564bab489SJohnny Chen                 if (target->GetSourcePathMap().RemapPath(m_file_spec.GetDirectory(), new_path))
34664bab489SJohnny Chen                 {
34764bab489SJohnny Chen                     char resolved_path[PATH_MAX];
34864bab489SJohnny Chen                     ::snprintf(resolved_path, PATH_MAX, "%s/%s", new_path.AsCString(), m_file_spec.GetFilename().AsCString());
34964bab489SJohnny Chen                     m_file_spec = new FileSpec(resolved_path, true);
35064bab489SJohnny Chen                     m_mod_time = m_file_spec.GetModificationTime();
35164bab489SJohnny Chen                 }
3527e14f91dSGreg Clayton             }
353e37d605eSJim Ingham         }
354e37d605eSJim Ingham     }
3557e14f91dSGreg Clayton 
3567e14f91dSGreg Clayton     if (m_mod_time.IsValid())
3577e14f91dSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
35830fdc8d8SChris Lattner }
35930fdc8d8SChris Lattner 
36030fdc8d8SChris Lattner SourceManager::File::~File()
36130fdc8d8SChris Lattner {
36230fdc8d8SChris Lattner }
36330fdc8d8SChris Lattner 
36430fdc8d8SChris Lattner uint32_t
36530fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line)
36630fdc8d8SChris Lattner {
36730fdc8d8SChris Lattner     if (line == 0)
36830fdc8d8SChris Lattner         return UINT32_MAX;
36930fdc8d8SChris Lattner 
37030fdc8d8SChris Lattner     if (line == 1)
37130fdc8d8SChris Lattner         return 0;
37230fdc8d8SChris Lattner 
37330fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
37430fdc8d8SChris Lattner     {
37530fdc8d8SChris Lattner         if (line < m_offsets.size())
37630fdc8d8SChris Lattner             return m_offsets[line - 1]; // yes we want "line - 1" in the index
37730fdc8d8SChris Lattner     }
37830fdc8d8SChris Lattner     return UINT32_MAX;
37930fdc8d8SChris Lattner }
38030fdc8d8SChris Lattner 
38130fdc8d8SChris Lattner bool
38230fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line)
38330fdc8d8SChris Lattner {
38430fdc8d8SChris Lattner     if (line == 0)
38530fdc8d8SChris Lattner         return false;
38630fdc8d8SChris Lattner 
38730fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
38830fdc8d8SChris Lattner         return line < m_offsets.size();
38930fdc8d8SChris Lattner     return false;
39030fdc8d8SChris Lattner }
39130fdc8d8SChris Lattner 
39230fdc8d8SChris Lattner size_t
39330fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
39430fdc8d8SChris Lattner {
3959625d08cSGreg Clayton     // TODO: use host API to sign up for file modifications to anything in our
3969625d08cSGreg Clayton     // source cache and only update when we determine a file has been updated.
3979625d08cSGreg Clayton     // For now we check each time we want to display info for the file.
3989625d08cSGreg Clayton     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
39964bab489SJohnny Chen 
40064bab489SJohnny Chen     if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
4019625d08cSGreg Clayton     {
4029625d08cSGreg Clayton         m_mod_time = curr_mod_time;
4039625d08cSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
4049625d08cSGreg Clayton         m_offsets.clear();
4059625d08cSGreg Clayton     }
4069625d08cSGreg Clayton 
40764bab489SJohnny Chen     // Sanity check m_data_sp before proceeding.
40864bab489SJohnny Chen     if (!m_data_sp)
40964bab489SJohnny Chen         return 0;
41064bab489SJohnny Chen 
41130fdc8d8SChris Lattner     const uint32_t start_line = line <= context_before ? 1 : line - context_before;
41230fdc8d8SChris Lattner     const uint32_t start_line_offset = GetLineOffset (start_line);
41330fdc8d8SChris Lattner     if (start_line_offset != UINT32_MAX)
41430fdc8d8SChris Lattner     {
41530fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
41630fdc8d8SChris Lattner         uint32_t end_line_offset = GetLineOffset (end_line + 1);
41730fdc8d8SChris Lattner         if (end_line_offset == UINT32_MAX)
41830fdc8d8SChris Lattner             end_line_offset = m_data_sp->GetByteSize();
41930fdc8d8SChris Lattner 
42030fdc8d8SChris Lattner         assert (start_line_offset <= end_line_offset);
42130fdc8d8SChris Lattner         size_t bytes_written = 0;
42230fdc8d8SChris Lattner         if (start_line_offset < end_line_offset)
42330fdc8d8SChris Lattner         {
42430fdc8d8SChris Lattner             size_t count = end_line_offset - start_line_offset;
42530fdc8d8SChris Lattner             const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
42630fdc8d8SChris Lattner             bytes_written = s->Write(cstr, count);
42730fdc8d8SChris Lattner             if (!is_newline_char(cstr[count-1]))
42830fdc8d8SChris Lattner                 bytes_written += s->EOL();
42930fdc8d8SChris Lattner         }
43030fdc8d8SChris Lattner         return bytes_written;
43130fdc8d8SChris Lattner     }
43230fdc8d8SChris Lattner     return 0;
43330fdc8d8SChris Lattner }
43430fdc8d8SChris Lattner 
435969795f1SJim Ingham void
436969795f1SJim Ingham SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
437969795f1SJim Ingham {
438969795f1SJim Ingham     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
439969795f1SJim Ingham     if (m_mod_time != curr_mod_time)
440969795f1SJim Ingham     {
441969795f1SJim Ingham         m_mod_time = curr_mod_time;
442969795f1SJim Ingham         m_data_sp = m_file_spec.ReadFileContents ();
443969795f1SJim Ingham         m_offsets.clear();
444969795f1SJim Ingham     }
445969795f1SJim Ingham 
446969795f1SJim Ingham     match_lines.clear();
447969795f1SJim Ingham 
448969795f1SJim Ingham     if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
449969795f1SJim Ingham         return;
450969795f1SJim Ingham     if (start_line > end_line)
451969795f1SJim Ingham         return;
452969795f1SJim Ingham 
453969795f1SJim Ingham     for (uint32_t line_no = start_line; line_no < end_line; line_no++)
454969795f1SJim Ingham     {
455969795f1SJim Ingham         std::string buffer;
456969795f1SJim Ingham         if (!GetLine (line_no, buffer))
457969795f1SJim Ingham             break;
458969795f1SJim Ingham         if (regex.Execute(buffer.c_str()))
459969795f1SJim Ingham         {
460969795f1SJim Ingham             match_lines.push_back(line_no);
461969795f1SJim Ingham         }
462969795f1SJim Ingham     }
463969795f1SJim Ingham }
464969795f1SJim Ingham 
46530fdc8d8SChris Lattner bool
46630fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
46730fdc8d8SChris Lattner {
468644247c1SGreg Clayton     return FileSpec::Equal (m_file_spec, file_spec, false);
46930fdc8d8SChris Lattner }
47030fdc8d8SChris Lattner 
471e37d605eSJim Ingham bool
472e37d605eSJim Ingham lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
473e37d605eSJim Ingham {
474e37d605eSJim Ingham     if (lhs.m_file_spec == rhs.m_file_spec)
475e37d605eSJim Ingham     {
476e37d605eSJim Ingham         if (lhs.m_mod_time.IsValid())
477e37d605eSJim Ingham         {
478e37d605eSJim Ingham             if (rhs.m_mod_time.IsValid())
479e37d605eSJim Ingham                 return lhs.m_mod_time == rhs.m_mod_time;
480e37d605eSJim Ingham             else
481e37d605eSJim Ingham                 return false;
482e37d605eSJim Ingham         }
483e37d605eSJim Ingham         else if (rhs.m_mod_time.IsValid())
484e37d605eSJim Ingham             return false;
485e37d605eSJim Ingham         else
486e37d605eSJim Ingham             return true;
487e37d605eSJim Ingham     }
488e37d605eSJim Ingham     else
489e37d605eSJim Ingham         return false;
490e37d605eSJim Ingham }
49130fdc8d8SChris Lattner 
49230fdc8d8SChris Lattner bool
49330fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line)
49430fdc8d8SChris Lattner {
49530fdc8d8SChris Lattner     line = UINT32_MAX;  // TODO: take this line out when we support partial indexing
49630fdc8d8SChris Lattner     if (line == UINT32_MAX)
49730fdc8d8SChris Lattner     {
49830fdc8d8SChris Lattner         // Already done?
49930fdc8d8SChris Lattner         if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
50030fdc8d8SChris Lattner             return true;
50130fdc8d8SChris Lattner 
50230fdc8d8SChris Lattner         if (m_offsets.empty())
50330fdc8d8SChris Lattner         {
50430fdc8d8SChris Lattner             if (m_data_sp.get() == NULL)
50530fdc8d8SChris Lattner                 return false;
50630fdc8d8SChris Lattner 
50730fdc8d8SChris Lattner             const char *start = (char *)m_data_sp->GetBytes();
50830fdc8d8SChris Lattner             if (start)
50930fdc8d8SChris Lattner             {
51030fdc8d8SChris Lattner                 const char *end = start + m_data_sp->GetByteSize();
51130fdc8d8SChris Lattner 
51230fdc8d8SChris Lattner                 // Calculate all line offsets from scratch
51330fdc8d8SChris Lattner 
51430fdc8d8SChris Lattner                 // Push a 1 at index zero to indicate the file has been completely indexed.
51530fdc8d8SChris Lattner                 m_offsets.push_back(UINT32_MAX);
51630fdc8d8SChris Lattner                 register const char *s;
51730fdc8d8SChris Lattner                 for (s = start; s < end; ++s)
51830fdc8d8SChris Lattner                 {
51930fdc8d8SChris Lattner                     register char curr_ch = *s;
52030fdc8d8SChris Lattner                     if (is_newline_char (curr_ch))
52130fdc8d8SChris Lattner                     {
52230fdc8d8SChris Lattner                         register char next_ch = s[1];
52330fdc8d8SChris Lattner                         if (is_newline_char (next_ch))
52430fdc8d8SChris Lattner                         {
52530fdc8d8SChris Lattner                             if (curr_ch != next_ch)
52630fdc8d8SChris Lattner                                 ++s;
52730fdc8d8SChris Lattner                         }
52830fdc8d8SChris Lattner                         m_offsets.push_back(s + 1 - start);
52930fdc8d8SChris Lattner                     }
53030fdc8d8SChris Lattner                 }
53130fdc8d8SChris Lattner                 if (!m_offsets.empty())
53230fdc8d8SChris Lattner                 {
53330fdc8d8SChris Lattner                     if (m_offsets.back() < end - start)
53430fdc8d8SChris Lattner                         m_offsets.push_back(end - start);
53530fdc8d8SChris Lattner                 }
53630fdc8d8SChris Lattner                 return true;
53730fdc8d8SChris Lattner             }
53830fdc8d8SChris Lattner         }
53930fdc8d8SChris Lattner         else
54030fdc8d8SChris Lattner         {
54130fdc8d8SChris Lattner             // Some lines have been populated, start where we last left off
54230fdc8d8SChris Lattner             assert(!"Not implemented yet");
54330fdc8d8SChris Lattner         }
54430fdc8d8SChris Lattner 
54530fdc8d8SChris Lattner     }
54630fdc8d8SChris Lattner     else
54730fdc8d8SChris Lattner     {
54830fdc8d8SChris Lattner         // Calculate all line offsets up to "line"
54930fdc8d8SChris Lattner         assert(!"Not implemented yet");
55030fdc8d8SChris Lattner     }
55130fdc8d8SChris Lattner     return false;
55230fdc8d8SChris Lattner }
553e37d605eSJim Ingham 
554969795f1SJim Ingham bool
555969795f1SJim Ingham SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
556969795f1SJim Ingham {
557969795f1SJim Ingham     if (!LineIsValid(line_no))
558969795f1SJim Ingham         return false;
559969795f1SJim Ingham 
560969795f1SJim Ingham     uint32_t start_offset = GetLineOffset (line_no);
561969795f1SJim Ingham     uint32_t end_offset = GetLineOffset (line_no + 1);
562969795f1SJim Ingham     if (end_offset == UINT32_MAX)
563969795f1SJim Ingham     {
564969795f1SJim Ingham         end_offset = m_data_sp->GetByteSize();
565969795f1SJim Ingham     }
566969795f1SJim Ingham     buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
567969795f1SJim Ingham 
568969795f1SJim Ingham     return true;
569969795f1SJim Ingham }
570969795f1SJim Ingham 
571e37d605eSJim Ingham void
572e37d605eSJim Ingham SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
573e37d605eSJim Ingham {
574e37d605eSJim Ingham     FileSpec file_spec;
575e37d605eSJim Ingham     FileCache::iterator pos = m_file_cache.find(file_spec);
576e37d605eSJim Ingham     if (pos == m_file_cache.end())
577e37d605eSJim Ingham         m_file_cache[file_spec] = file_sp;
578e37d605eSJim Ingham     else
579e37d605eSJim Ingham     {
580e37d605eSJim Ingham         if (file_sp != pos->second)
581e37d605eSJim Ingham             m_file_cache[file_spec] = file_sp;
582e37d605eSJim Ingham     }
583e37d605eSJim Ingham }
584e37d605eSJim Ingham 
585e37d605eSJim Ingham SourceManager::FileSP
586e37d605eSJim Ingham SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
587e37d605eSJim Ingham {
588e37d605eSJim Ingham     FileSP file_sp;
589e37d605eSJim Ingham     FileCache::const_iterator pos = m_file_cache.find(file_spec);
590e37d605eSJim Ingham     if (pos != m_file_cache.end())
591e37d605eSJim Ingham         file_sp = pos->second;
592e37d605eSJim Ingham     return file_sp;
593e37d605eSJim Ingham }
594e37d605eSJim Ingham 
595