1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include "SourceFile.h" 7 8#include <errno.h> 9#include <fcntl.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <sys/stat.h> 14#include <unistd.h> 15 16#include <new> 17 18 19static const int32 kMaxSourceFileSize = 10 * 1024 * 1024; 20 21 22// #pragma mark - SourceFileOwner 23 24 25SourceFileOwner::~SourceFileOwner() 26{ 27} 28 29 30// #pragma mark - SourceFile 31 32 33SourceFile::SourceFile(SourceFileOwner* owner) 34 : 35 fOwner(owner), 36 fFileContent(NULL), 37 fLineOffsets(NULL), 38 fLineCount(0) 39{ 40} 41 42 43SourceFile::~SourceFile() 44{ 45 free(fFileContent); 46 delete[] fLineOffsets; 47 fOwner->SourceFileDeleted(this); 48} 49 50 51status_t 52SourceFile::Init(const char* path) 53{ 54 // open the file 55 int fd = open(path, O_RDONLY); 56 if (fd < 0) 57 return errno; 58 59 // stat the file to get its size 60 struct stat st; 61 if (fstat(fd, &st) < 0) { 62 close(fd); 63 return errno; 64 } 65 66 if (st.st_size > kMaxSourceFileSize) { 67 close(fd); 68 return B_FILE_TOO_LARGE; 69 } 70 size_t fileSize = st.st_size; 71 72 if (fileSize == 0) { 73 close(fd); 74 return B_BAD_VALUE; 75 } 76 77 // allocate the content buffer 78 fFileContent = (char*)malloc(fileSize + 1); 79 // one more byte for a terminating null 80 if (fFileContent == NULL) { 81 close(fd); 82 return B_NO_MEMORY; 83 } 84 85 // read the file 86 ssize_t bytesRead = read(fd, fFileContent, fileSize); 87 close(fd); 88 if (bytesRead < 0 || (size_t)bytesRead != fileSize) 89 return bytesRead < 0 ? errno : B_FILE_ERROR; 90 91 // null-terminate 92 fFileContent[fileSize] = '\0'; 93 94 // count lines 95 fLineCount = 1; 96 for (size_t i = 0; i < fileSize; i++) { 97 if (fFileContent[i] == '\n') 98 fLineCount++; 99 } 100 101 // allocate line offset array 102 fLineOffsets = new(std::nothrow) int32[fLineCount + 1]; 103 if (fLineOffsets == NULL) 104 return B_NO_MEMORY; 105 106 // get the line offsets and null-terminate the lines 107 int32 lineIndex = 0; 108 fLineOffsets[lineIndex++] = 0; 109 for (size_t i = 0; i < fileSize; i++) { 110 if (fFileContent[i] == '\n') { 111 fFileContent[i] = '\0'; 112 fLineOffsets[lineIndex++] = i + 1; 113 } 114 } 115 fLineOffsets[fLineCount] = fileSize + 1; 116 117 return B_OK; 118} 119 120 121int32 122SourceFile::CountLines() const 123{ 124 return fLineCount; 125} 126 127 128const char* 129SourceFile::LineAt(int32 index) const 130{ 131 return index >= 0 && index < fLineCount 132 ? fFileContent + fLineOffsets[index] : NULL; 133} 134 135 136int32 137SourceFile::LineLengthAt(int32 index) const 138{ 139 return index >= 0 && index < fLineCount 140 ? fLineOffsets[index + 1] - fLineOffsets[index] - 1: 0; 141} 142 143void 144SourceFile::LastReferenceReleased() 145{ 146 fOwner->SourceFileUnused(this); 147 delete this; 148} 149