* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "SourceFile.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <new>
static const int32 kMaxSourceFileSize = 10 * 1024 * 1024;
SourceFileOwner::~SourceFileOwner()
{
}
SourceFile::SourceFile(SourceFileOwner* owner)
:
fOwner(owner),
fFileContent(NULL),
fLineOffsets(NULL),
fLineCount(0)
{
}
SourceFile::~SourceFile()
{
free(fFileContent);
delete[] fLineOffsets;
fOwner->SourceFileDeleted(this);
}
status_t
SourceFile::Init(const char* path)
{
int fd = open(path, O_RDONLY);
if (fd < 0)
return errno;
struct stat st;
if (fstat(fd, &st) < 0) {
close(fd);
return errno;
}
if (st.st_size > kMaxSourceFileSize) {
close(fd);
return B_FILE_TOO_LARGE;
}
size_t fileSize = st.st_size;
if (fileSize == 0) {
close(fd);
return B_BAD_VALUE;
}
fFileContent = (char*)malloc(fileSize + 1);
if (fFileContent == NULL) {
close(fd);
return B_NO_MEMORY;
}
ssize_t bytesRead = read(fd, fFileContent, fileSize);
close(fd);
if (bytesRead < 0 || (size_t)bytesRead != fileSize)
return bytesRead < 0 ? errno : B_FILE_ERROR;
fFileContent[fileSize] = '\0';
fLineCount = 1;
for (size_t i = 0; i < fileSize; i++) {
if (fFileContent[i] == '\n')
fLineCount++;
}
fLineOffsets = new(std::nothrow) int32[fLineCount + 1];
if (fLineOffsets == NULL)
return B_NO_MEMORY;
int32 lineIndex = 0;
fLineOffsets[lineIndex++] = 0;
for (size_t i = 0; i < fileSize; i++) {
if (fFileContent[i] == '\n') {
fFileContent[i] = '\0';
fLineOffsets[lineIndex++] = i + 1;
}
}
fLineOffsets[fLineCount] = fileSize + 1;
return B_OK;
}
int32
SourceFile::CountLines() const
{
return fLineCount;
}
const char*
SourceFile::LineAt(int32 index) const
{
return index >= 0 && index < fLineCount
? fFileContent + fLineOffsets[index] : NULL;
}
int32
SourceFile::LineLengthAt(int32 index) const
{
return index >= 0 && index < fLineCount
? fLineOffsets[index + 1] - fLineOffsets[index] - 1: 0;
}
void
SourceFile::LastReferenceReleased()
{
fOwner->SourceFileUnused(this);
delete this;
}