xref: /haiku/src/kits/debugger/files/SourceFile.cpp (revision aa3083e086e5a929c061c72983e09d916c548a38)
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 
19 static const int32 kMaxSourceFileSize = 10 * 1024 * 1024;
20 
21 
22 // #pragma mark - SourceFileOwner
23 
24 
25 SourceFileOwner::~SourceFileOwner()
26 {
27 }
28 
29 
30 // #pragma mark - SourceFile
31 
32 
33 SourceFile::SourceFile(SourceFileOwner* owner)
34 	:
35 	fOwner(owner),
36 	fFileContent(NULL),
37 	fLineOffsets(NULL),
38 	fLineCount(0)
39 {
40 }
41 
42 
43 SourceFile::~SourceFile()
44 {
45 	free(fFileContent);
46 	delete[] fLineOffsets;
47 	fOwner->SourceFileDeleted(this);
48 }
49 
50 
51 status_t
52 SourceFile::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 
121 int32
122 SourceFile::CountLines() const
123 {
124 	return fLineCount;
125 }
126 
127 
128 const char*
129 SourceFile::LineAt(int32 index) const
130 {
131 	return index >= 0 && index < fLineCount
132 		? fFileContent + fLineOffsets[index] : NULL;
133 }
134 
135 
136 int32
137 SourceFile::LineLengthAt(int32 index) const
138 {
139 	return index >= 0 && index < fLineCount
140 		? fLineOffsets[index + 1] - fLineOffsets[index] - 1: 0;
141 }
142 
143 void
144 SourceFile::LastReferenceReleased()
145 {
146 	fOwner->SourceFileUnused(this);
147 	delete this;
148 }
149