root/src/kits/debugger/model/FileSourceCode.cpp
/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "FileSourceCode.h"

#include <string.h>

#include "LocatableFile.h"
#include "SourceFile.h"
#include "SourceLanguage.h"
#include "SourceLocation.h"


FileSourceCode::FileSourceCode(LocatableFile* file, SourceFile* sourceFile,
        SourceLanguage* language)
        :
        fLock("source code"),
        fFile(file),
        fSourceFile(sourceFile),
        fLanguage(language)
{
        fFile->AcquireReference();
        fSourceFile->AcquireReference();
        fLanguage->AcquireReference();
}


FileSourceCode::~FileSourceCode()
{
        fLanguage->ReleaseReference();
        fSourceFile->ReleaseReference();
        fFile->ReleaseReference();
}


status_t
FileSourceCode::Init()
{
        return fLock.InitCheck();
}


status_t
FileSourceCode::AddSourceLocation(const SourceLocation& location)
{
        // Find the insertion index; don't insert twice.
        bool foundMatch;
        int32 index = _FindSourceLocationIndex(location, foundMatch);
        if (foundMatch)
                return B_OK;

        return fSourceLocations.Insert(location, index) ? B_OK : B_NO_MEMORY;
}


bool
FileSourceCode::Lock()
{
        return fLock.Lock();
}


void
FileSourceCode::Unlock()
{
        fLock.Unlock();
}


SourceLanguage*
FileSourceCode::GetSourceLanguage() const
{
        return fLanguage;
}


int32
FileSourceCode::CountLines() const
{
        return fSourceFile->CountLines();
}


const char*
FileSourceCode::LineAt(int32 index) const
{
        return fSourceFile->LineAt(index);
}


int32
FileSourceCode::LineLengthAt(int32 index) const
{
        return fSourceFile->LineLengthAt(index);
}


bool
FileSourceCode::GetStatementLocationRange(const SourceLocation& location,
        SourceLocation& _start, SourceLocation& _end) const
{
        int32 lineCount = CountLines();
        if (location.Line() >= lineCount)
                return false;

        bool foundMatch;
        int32 index = _FindSourceLocationIndex(location, foundMatch);

        if (!foundMatch) {
                if (index == 0)
                        return false;
                index--;
        }

        _start = fSourceLocations[index];
        _end = index + 1 < lineCount
                ? fSourceLocations[index + 1] : SourceLocation(lineCount);
        return true;
}


LocatableFile*
FileSourceCode::GetSourceFile() const
{
        return fFile;
}


int32
FileSourceCode::_FindSourceLocationIndex(const SourceLocation& location,
        bool& _foundMatch) const
{
        int32 lower = 0;
        int32 upper = fSourceLocations.Size();
        while (lower < upper) {
                int32 mid = (lower + upper) / 2;
                if (location <= fSourceLocations[mid])
                        upper = mid;
                else
                        lower = mid + 1;
        }

        _foundMatch = lower < fSourceLocations.Size()
                && location == fSourceLocations[lower];
        return lower;
}