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.
2489df05fbbSSean Callanan             bool inlines_okay = true;
249f3277750SJim Ingham             bool append = false;
2509df05fbbSSean 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);
336*d804d285SGreg Clayton                         m_file_spec = 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             {
344*d804d285SGreg Clayton                 FileSpec new_file_spec;
345*d804d285SGreg Clayton                 // Check target specific source remappings first, then fall back to
346*d804d285SGreg Clayton                 // modules objects can have individual path remappings that were detected
347*d804d285SGreg Clayton                 // when the debug info for a module was found.
348*d804d285SGreg Clayton                 // then
349*d804d285SGreg Clayton                 if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) ||
350*d804d285SGreg Clayton                     target->GetImages().FindSourceFile (m_file_spec, new_file_spec))
35164bab489SJohnny Chen                 {
352*d804d285SGreg Clayton                     m_file_spec = new_file_spec;
35364bab489SJohnny Chen                     m_mod_time = m_file_spec.GetModificationTime();
35464bab489SJohnny Chen                 }
3557e14f91dSGreg Clayton             }
356e37d605eSJim Ingham         }
357e37d605eSJim Ingham     }
3587e14f91dSGreg Clayton 
3597e14f91dSGreg Clayton     if (m_mod_time.IsValid())
3607e14f91dSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
36130fdc8d8SChris Lattner }
36230fdc8d8SChris Lattner 
36330fdc8d8SChris Lattner SourceManager::File::~File()
36430fdc8d8SChris Lattner {
36530fdc8d8SChris Lattner }
36630fdc8d8SChris Lattner 
36730fdc8d8SChris Lattner uint32_t
36830fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line)
36930fdc8d8SChris Lattner {
37030fdc8d8SChris Lattner     if (line == 0)
37130fdc8d8SChris Lattner         return UINT32_MAX;
37230fdc8d8SChris Lattner 
37330fdc8d8SChris Lattner     if (line == 1)
37430fdc8d8SChris Lattner         return 0;
37530fdc8d8SChris Lattner 
37630fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
37730fdc8d8SChris Lattner     {
37830fdc8d8SChris Lattner         if (line < m_offsets.size())
37930fdc8d8SChris Lattner             return m_offsets[line - 1]; // yes we want "line - 1" in the index
38030fdc8d8SChris Lattner     }
38130fdc8d8SChris Lattner     return UINT32_MAX;
38230fdc8d8SChris Lattner }
38330fdc8d8SChris Lattner 
38430fdc8d8SChris Lattner bool
38530fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line)
38630fdc8d8SChris Lattner {
38730fdc8d8SChris Lattner     if (line == 0)
38830fdc8d8SChris Lattner         return false;
38930fdc8d8SChris Lattner 
39030fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
39130fdc8d8SChris Lattner         return line < m_offsets.size();
39230fdc8d8SChris Lattner     return false;
39330fdc8d8SChris Lattner }
39430fdc8d8SChris Lattner 
39530fdc8d8SChris Lattner size_t
39630fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
39730fdc8d8SChris Lattner {
3989625d08cSGreg Clayton     // TODO: use host API to sign up for file modifications to anything in our
3999625d08cSGreg Clayton     // source cache and only update when we determine a file has been updated.
4009625d08cSGreg Clayton     // For now we check each time we want to display info for the file.
4019625d08cSGreg Clayton     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
40264bab489SJohnny Chen 
40364bab489SJohnny Chen     if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
4049625d08cSGreg Clayton     {
4059625d08cSGreg Clayton         m_mod_time = curr_mod_time;
4069625d08cSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
4079625d08cSGreg Clayton         m_offsets.clear();
4089625d08cSGreg Clayton     }
4099625d08cSGreg Clayton 
41064bab489SJohnny Chen     // Sanity check m_data_sp before proceeding.
41164bab489SJohnny Chen     if (!m_data_sp)
41264bab489SJohnny Chen         return 0;
41364bab489SJohnny Chen 
41430fdc8d8SChris Lattner     const uint32_t start_line = line <= context_before ? 1 : line - context_before;
41530fdc8d8SChris Lattner     const uint32_t start_line_offset = GetLineOffset (start_line);
41630fdc8d8SChris Lattner     if (start_line_offset != UINT32_MAX)
41730fdc8d8SChris Lattner     {
41830fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
41930fdc8d8SChris Lattner         uint32_t end_line_offset = GetLineOffset (end_line + 1);
42030fdc8d8SChris Lattner         if (end_line_offset == UINT32_MAX)
42130fdc8d8SChris Lattner             end_line_offset = m_data_sp->GetByteSize();
42230fdc8d8SChris Lattner 
42330fdc8d8SChris Lattner         assert (start_line_offset <= end_line_offset);
42430fdc8d8SChris Lattner         size_t bytes_written = 0;
42530fdc8d8SChris Lattner         if (start_line_offset < end_line_offset)
42630fdc8d8SChris Lattner         {
42730fdc8d8SChris Lattner             size_t count = end_line_offset - start_line_offset;
42830fdc8d8SChris Lattner             const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
42930fdc8d8SChris Lattner             bytes_written = s->Write(cstr, count);
43030fdc8d8SChris Lattner             if (!is_newline_char(cstr[count-1]))
43130fdc8d8SChris Lattner                 bytes_written += s->EOL();
43230fdc8d8SChris Lattner         }
43330fdc8d8SChris Lattner         return bytes_written;
43430fdc8d8SChris Lattner     }
43530fdc8d8SChris Lattner     return 0;
43630fdc8d8SChris Lattner }
43730fdc8d8SChris Lattner 
438969795f1SJim Ingham void
439969795f1SJim Ingham SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
440969795f1SJim Ingham {
441969795f1SJim Ingham     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
442969795f1SJim Ingham     if (m_mod_time != curr_mod_time)
443969795f1SJim Ingham     {
444969795f1SJim Ingham         m_mod_time = curr_mod_time;
445969795f1SJim Ingham         m_data_sp = m_file_spec.ReadFileContents ();
446969795f1SJim Ingham         m_offsets.clear();
447969795f1SJim Ingham     }
448969795f1SJim Ingham 
449969795f1SJim Ingham     match_lines.clear();
450969795f1SJim Ingham 
451969795f1SJim Ingham     if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
452969795f1SJim Ingham         return;
453969795f1SJim Ingham     if (start_line > end_line)
454969795f1SJim Ingham         return;
455969795f1SJim Ingham 
456969795f1SJim Ingham     for (uint32_t line_no = start_line; line_no < end_line; line_no++)
457969795f1SJim Ingham     {
458969795f1SJim Ingham         std::string buffer;
459969795f1SJim Ingham         if (!GetLine (line_no, buffer))
460969795f1SJim Ingham             break;
461969795f1SJim Ingham         if (regex.Execute(buffer.c_str()))
462969795f1SJim Ingham         {
463969795f1SJim Ingham             match_lines.push_back(line_no);
464969795f1SJim Ingham         }
465969795f1SJim Ingham     }
466969795f1SJim Ingham }
467969795f1SJim Ingham 
46830fdc8d8SChris Lattner bool
46930fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
47030fdc8d8SChris Lattner {
471644247c1SGreg Clayton     return FileSpec::Equal (m_file_spec, file_spec, false);
47230fdc8d8SChris Lattner }
47330fdc8d8SChris Lattner 
474e37d605eSJim Ingham bool
475e37d605eSJim Ingham lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
476e37d605eSJim Ingham {
477e37d605eSJim Ingham     if (lhs.m_file_spec == rhs.m_file_spec)
478e37d605eSJim Ingham     {
479e37d605eSJim Ingham         if (lhs.m_mod_time.IsValid())
480e37d605eSJim Ingham         {
481e37d605eSJim Ingham             if (rhs.m_mod_time.IsValid())
482e37d605eSJim Ingham                 return lhs.m_mod_time == rhs.m_mod_time;
483e37d605eSJim Ingham             else
484e37d605eSJim Ingham                 return false;
485e37d605eSJim Ingham         }
486e37d605eSJim Ingham         else if (rhs.m_mod_time.IsValid())
487e37d605eSJim Ingham             return false;
488e37d605eSJim Ingham         else
489e37d605eSJim Ingham             return true;
490e37d605eSJim Ingham     }
491e37d605eSJim Ingham     else
492e37d605eSJim Ingham         return false;
493e37d605eSJim Ingham }
49430fdc8d8SChris Lattner 
49530fdc8d8SChris Lattner bool
49630fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line)
49730fdc8d8SChris Lattner {
49830fdc8d8SChris Lattner     line = UINT32_MAX;  // TODO: take this line out when we support partial indexing
49930fdc8d8SChris Lattner     if (line == UINT32_MAX)
50030fdc8d8SChris Lattner     {
50130fdc8d8SChris Lattner         // Already done?
50230fdc8d8SChris Lattner         if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
50330fdc8d8SChris Lattner             return true;
50430fdc8d8SChris Lattner 
50530fdc8d8SChris Lattner         if (m_offsets.empty())
50630fdc8d8SChris Lattner         {
50730fdc8d8SChris Lattner             if (m_data_sp.get() == NULL)
50830fdc8d8SChris Lattner                 return false;
50930fdc8d8SChris Lattner 
51030fdc8d8SChris Lattner             const char *start = (char *)m_data_sp->GetBytes();
51130fdc8d8SChris Lattner             if (start)
51230fdc8d8SChris Lattner             {
51330fdc8d8SChris Lattner                 const char *end = start + m_data_sp->GetByteSize();
51430fdc8d8SChris Lattner 
51530fdc8d8SChris Lattner                 // Calculate all line offsets from scratch
51630fdc8d8SChris Lattner 
51730fdc8d8SChris Lattner                 // Push a 1 at index zero to indicate the file has been completely indexed.
51830fdc8d8SChris Lattner                 m_offsets.push_back(UINT32_MAX);
51930fdc8d8SChris Lattner                 register const char *s;
52030fdc8d8SChris Lattner                 for (s = start; s < end; ++s)
52130fdc8d8SChris Lattner                 {
52230fdc8d8SChris Lattner                     register char curr_ch = *s;
52330fdc8d8SChris Lattner                     if (is_newline_char (curr_ch))
52430fdc8d8SChris Lattner                     {
52530fdc8d8SChris Lattner                         register char next_ch = s[1];
52630fdc8d8SChris Lattner                         if (is_newline_char (next_ch))
52730fdc8d8SChris Lattner                         {
52830fdc8d8SChris Lattner                             if (curr_ch != next_ch)
52930fdc8d8SChris Lattner                                 ++s;
53030fdc8d8SChris Lattner                         }
53130fdc8d8SChris Lattner                         m_offsets.push_back(s + 1 - start);
53230fdc8d8SChris Lattner                     }
53330fdc8d8SChris Lattner                 }
53430fdc8d8SChris Lattner                 if (!m_offsets.empty())
53530fdc8d8SChris Lattner                 {
53630fdc8d8SChris Lattner                     if (m_offsets.back() < end - start)
53730fdc8d8SChris Lattner                         m_offsets.push_back(end - start);
53830fdc8d8SChris Lattner                 }
53930fdc8d8SChris Lattner                 return true;
54030fdc8d8SChris Lattner             }
54130fdc8d8SChris Lattner         }
54230fdc8d8SChris Lattner         else
54330fdc8d8SChris Lattner         {
54430fdc8d8SChris Lattner             // Some lines have been populated, start where we last left off
54530fdc8d8SChris Lattner             assert(!"Not implemented yet");
54630fdc8d8SChris Lattner         }
54730fdc8d8SChris Lattner 
54830fdc8d8SChris Lattner     }
54930fdc8d8SChris Lattner     else
55030fdc8d8SChris Lattner     {
55130fdc8d8SChris Lattner         // Calculate all line offsets up to "line"
55230fdc8d8SChris Lattner         assert(!"Not implemented yet");
55330fdc8d8SChris Lattner     }
55430fdc8d8SChris Lattner     return false;
55530fdc8d8SChris Lattner }
556e37d605eSJim Ingham 
557969795f1SJim Ingham bool
558969795f1SJim Ingham SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
559969795f1SJim Ingham {
560969795f1SJim Ingham     if (!LineIsValid(line_no))
561969795f1SJim Ingham         return false;
562969795f1SJim Ingham 
563969795f1SJim Ingham     uint32_t start_offset = GetLineOffset (line_no);
564969795f1SJim Ingham     uint32_t end_offset = GetLineOffset (line_no + 1);
565969795f1SJim Ingham     if (end_offset == UINT32_MAX)
566969795f1SJim Ingham     {
567969795f1SJim Ingham         end_offset = m_data_sp->GetByteSize();
568969795f1SJim Ingham     }
569969795f1SJim Ingham     buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
570969795f1SJim Ingham 
571969795f1SJim Ingham     return true;
572969795f1SJim Ingham }
573969795f1SJim Ingham 
574e37d605eSJim Ingham void
575e37d605eSJim Ingham SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
576e37d605eSJim Ingham {
577e37d605eSJim Ingham     FileSpec file_spec;
578e37d605eSJim Ingham     FileCache::iterator pos = m_file_cache.find(file_spec);
579e37d605eSJim Ingham     if (pos == m_file_cache.end())
580e37d605eSJim Ingham         m_file_cache[file_spec] = file_sp;
581e37d605eSJim Ingham     else
582e37d605eSJim Ingham     {
583e37d605eSJim Ingham         if (file_sp != pos->second)
584e37d605eSJim Ingham             m_file_cache[file_spec] = file_sp;
585e37d605eSJim Ingham     }
586e37d605eSJim Ingham }
587e37d605eSJim Ingham 
588e37d605eSJim Ingham SourceManager::FileSP
589e37d605eSJim Ingham SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
590e37d605eSJim Ingham {
591e37d605eSJim Ingham     FileSP file_sp;
592e37d605eSJim Ingham     FileCache::const_iterator pos = m_file_cache.find(file_spec);
593e37d605eSJim Ingham     if (pos != m_file_cache.end())
594e37d605eSJim Ingham         file_sp = pos->second;
595e37d605eSJim Ingham     return file_sp;
596e37d605eSJim Ingham }
597e37d605eSJim Ingham 
598