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