btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / textview_support / TextGapBuffer.cpp
blobdc7ed189771fec96e0f52056866d5a42818cde43
1 /*
2 * Copyright 2001-2006, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
8 */
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
15 #include <utf8_functions.h>
17 #include <File.h>
18 #include <InterfaceDefs.h> // for B_UTF8_BULLET
20 #include "TextGapBuffer.h"
23 namespace BPrivate {
26 static const int32 kTextGapBufferBlockSize = 2048;
29 TextGapBuffer::TextGapBuffer()
31 fItemCount(0),
32 fBuffer(NULL),
33 fBufferCount(kTextGapBufferBlockSize + fItemCount),
34 fGapIndex(fItemCount),
35 fGapCount(fBufferCount - fGapIndex),
36 fScratchBuffer(NULL),
37 fScratchSize(0),
38 fPasswordMode(false)
40 fBuffer = (char*)malloc(kTextGapBufferBlockSize + fItemCount);
41 fScratchBuffer = NULL;
45 TextGapBuffer::~TextGapBuffer()
47 free(fBuffer);
48 free(fScratchBuffer);
52 void
53 TextGapBuffer::InsertText(const char* inText, int32 inNumItems, int32 inAtIndex)
55 if (inNumItems < 1)
56 return;
58 inAtIndex = (inAtIndex > fItemCount) ? fItemCount : inAtIndex;
59 inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
61 if (inAtIndex != fGapIndex)
62 _MoveGapTo(inAtIndex);
64 if (fGapCount < inNumItems)
65 _EnlargeGapTo(inNumItems + kTextGapBufferBlockSize);
67 memcpy(fBuffer + fGapIndex, inText, inNumItems);
69 fGapCount -= inNumItems;
70 fGapIndex += inNumItems;
71 fItemCount += inNumItems;
75 bool
76 TextGapBuffer::InsertText(BFile* file, int32 fileOffset, int32 inNumItems,
77 int32 inAtIndex)
79 off_t fileSize;
81 if (file->GetSize(&fileSize) != B_OK
82 || !file->IsReadable())
83 return false;
85 // Clamp the text length to the file size
86 fileSize -= fileOffset;
88 if (fileSize < inNumItems)
89 inNumItems = fileSize;
91 if (inNumItems < 1)
92 return false;
94 inAtIndex = (inAtIndex > fItemCount) ? fItemCount : inAtIndex;
95 inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
97 if (inAtIndex != fGapIndex)
98 _MoveGapTo(inAtIndex);
100 if (fGapCount < inNumItems)
101 _EnlargeGapTo(inNumItems + kTextGapBufferBlockSize);
103 // Finally, read the data and put it into the buffer
104 if (file->ReadAt(fileOffset, fBuffer + fGapIndex, inNumItems) > 0) {
105 fGapCount -= inNumItems;
106 fGapIndex += inNumItems;
107 fItemCount += inNumItems;
110 return true;
114 void
115 TextGapBuffer::RemoveRange(int32 start, int32 end)
117 int32 inAtIndex = start;
118 int32 inNumItems = end - start;
120 if (inNumItems < 1)
121 return;
123 inAtIndex = (inAtIndex > fItemCount - 1) ? (fItemCount - 1) : inAtIndex;
124 inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
126 _MoveGapTo(inAtIndex);
128 fGapCount += inNumItems;
129 fItemCount -= inNumItems;
131 if (fGapCount > kTextGapBufferBlockSize)
132 _ShrinkGapTo(kTextGapBufferBlockSize / 2);
136 const char*
137 TextGapBuffer::GetString(int32 fromOffset, int32* _numBytes)
139 const char* result = "";
140 if (_numBytes == NULL)
141 return result;
143 int32 numBytes = *_numBytes;
144 if (numBytes < 1)
145 return result;
147 bool isStartBeforeGap = fromOffset < fGapIndex;
148 bool isEndBeforeGap = (fromOffset + numBytes - 1) < fGapIndex;
150 if (isStartBeforeGap == isEndBeforeGap) {
151 result = fBuffer + fromOffset;
152 if (!isStartBeforeGap)
153 result += fGapCount;
154 } else {
155 if (fScratchSize < numBytes) {
156 fScratchBuffer = (char*)realloc(fScratchBuffer, numBytes);
157 fScratchSize = numBytes;
160 for (int32 i = 0; i < numBytes; i++)
161 fScratchBuffer[i] = RealCharAt(fromOffset + i);
163 result = fScratchBuffer;
166 // TODO: this could be improved. We are overwriting what we did some lines
167 // ago, we could just avoid to do that.
168 if (fPasswordMode) {
169 uint32 numChars = UTF8CountChars(result, numBytes);
170 uint32 charLen = UTF8CountBytes(B_UTF8_BULLET, 1);
171 uint32 newSize = numChars * charLen;
173 if ((uint32)fScratchSize < newSize) {
174 fScratchBuffer = (char*)realloc(fScratchBuffer, newSize);
175 fScratchSize = newSize;
177 result = fScratchBuffer;
179 char* scratchPtr = fScratchBuffer;
180 for (uint32 i = 0; i < numChars; i++) {
181 memcpy(scratchPtr, B_UTF8_BULLET, charLen);
182 scratchPtr += charLen;
185 *_numBytes = newSize;
188 return result;
192 bool
193 TextGapBuffer::FindChar(char inChar, int32 fromIndex, int32* ioDelta)
195 int32 numChars = *ioDelta;
196 for (int32 i = 0; i < numChars; i++) {
197 char realChar = RealCharAt(fromIndex + i);
198 if ((realChar & 0xc0) == 0x80)
199 continue;
200 if (realChar == inChar) {
201 *ioDelta = i;
202 return true;
206 return false;
210 const char*
211 TextGapBuffer::Text()
213 const char* realText = RealText();
215 if (fPasswordMode) {
216 const uint32 numChars = UTF8CountChars(realText, Length());
217 const uint32 bulletCharLen = UTF8CountBytes(B_UTF8_BULLET, 1);
218 uint32 newSize = numChars * bulletCharLen + 1;
220 if ((uint32)fScratchSize < newSize) {
221 fScratchBuffer = (char*)realloc(fScratchBuffer, newSize);
222 fScratchSize = newSize;
225 char* scratchPtr = fScratchBuffer;
226 for (uint32 i = 0; i < numChars; i++) {
227 memcpy(scratchPtr, B_UTF8_BULLET, bulletCharLen);
228 scratchPtr += bulletCharLen;
230 *scratchPtr = '\0';
232 return fScratchBuffer;
235 return realText;
239 const char*
240 TextGapBuffer::RealText()
242 _MoveGapTo(fItemCount);
244 if (fGapCount == 0)
245 _EnlargeGapTo(kTextGapBufferBlockSize);
247 fBuffer[fItemCount] = '\0';
248 return fBuffer;
252 void
253 TextGapBuffer::GetString(int32 offset, int32 length, char* buffer)
255 if (buffer == NULL)
256 return;
258 int32 textLen = Length();
260 if (offset < 0 || offset > (textLen - 1) || length < 1) {
261 buffer[0] = '\0';
262 return;
265 length = ((offset + length) > textLen) ? textLen - offset : length;
267 bool isStartBeforeGap = (offset < fGapIndex);
268 bool isEndBeforeGap = ((offset + length - 1) < fGapIndex);
270 if (isStartBeforeGap == isEndBeforeGap) {
271 char* source = fBuffer + offset;
272 if (!isStartBeforeGap)
273 source += fGapCount;
275 memcpy(buffer, source, length);
277 } else {
278 // if we are here, it can only be that start is before gap,
279 // and the end is after gap.
281 int32 beforeLen = fGapIndex - offset;
282 int32 afterLen = length - beforeLen;
284 memcpy(buffer, fBuffer + offset, beforeLen);
285 memcpy(buffer + beforeLen, fBuffer + fGapIndex + fGapCount, afterLen);
289 buffer[length] = '\0';
293 bool
294 TextGapBuffer::PasswordMode() const
296 return fPasswordMode;
300 void
301 TextGapBuffer::SetPasswordMode(bool state)
303 fPasswordMode = state;
307 void
308 TextGapBuffer::_MoveGapTo(int32 toIndex)
310 if (toIndex == fGapIndex)
311 return;
312 if (toIndex > fItemCount) {
313 debugger("MoveGapTo: invalid toIndex supplied");
314 return;
317 int32 srcIndex = 0;
318 int32 dstIndex = 0;
319 int32 count = 0;
320 if (toIndex > fGapIndex) {
321 srcIndex = fGapIndex + fGapCount;
322 dstIndex = fGapIndex;
323 count = toIndex - fGapIndex;
324 } else {
325 srcIndex = toIndex;
326 dstIndex = toIndex + fGapCount;
327 count = fGapIndex- toIndex;
330 if (count > 0)
331 memmove(fBuffer + dstIndex, fBuffer + srcIndex, count);
333 fGapIndex = toIndex;
337 void
338 TextGapBuffer::_EnlargeGapTo(int32 inCount)
340 if (inCount == fGapCount)
341 return;
343 fBuffer = (char*)realloc(fBuffer, fItemCount + inCount);
344 memmove(fBuffer + fGapIndex + inCount, fBuffer + fGapIndex + fGapCount,
345 fBufferCount - (fGapIndex + fGapCount));
347 fGapCount = inCount;
348 fBufferCount = fItemCount + fGapCount;
352 void
353 TextGapBuffer::_ShrinkGapTo(int32 inCount)
355 if (inCount == fGapCount)
356 return;
358 memmove(fBuffer + fGapIndex + inCount, fBuffer + fGapIndex + fGapCount,
359 fBufferCount - (fGapIndex + fGapCount));
360 fBuffer = (char*)realloc(fBuffer, fItemCount + inCount);
362 fGapCount = inCount;
363 fBufferCount = fItemCount + fGapCount;
367 } // namespace BPrivate