add more spacing
[personal-kdebase.git] / apps / konsole / src / BlockArray.cpp
blobb5560b2d77b5499251c247d51f70027c7ca3f231
1 /*
2 This file is part of Konsole, an X terminal.
3 Copyright 2000 by Stephan Kulow <coolo@kde.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301 USA.
21 // Own
22 #include "BlockArray.h"
24 // System
25 #include <assert.h>
26 #include <sys/mman.h>
27 #include <sys/param.h>
28 #include <unistd.h>
29 #include <stdio.h>
31 // KDE
32 #include <kde_file.h>
33 #include <kdebug.h>
35 using namespace Konsole;
37 static int blocksize = 0;
39 BlockArray::BlockArray()
40 : size(0),
41 current(size_t(-1)),
42 index(size_t(-1)),
43 lastmap(0),
44 lastmap_index(size_t(-1)),
45 lastblock(0), ion(-1),
46 length(0)
48 // lastmap_index = index = current = size_t(-1);
49 if (blocksize == 0)
50 blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
54 BlockArray::~BlockArray()
56 setHistorySize(0);
57 assert(!lastblock);
60 size_t BlockArray::append(Block *block)
62 if (!size)
63 return size_t(-1);
65 ++current;
66 if (current >= size) current = 0;
68 int rc;
69 rc = KDE_lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); }
70 rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); }
72 length++;
73 if (length > size) length = size;
75 ++index;
77 delete block;
78 return current;
81 size_t BlockArray::newBlock()
83 if (!size)
84 return size_t(-1);
85 append(lastblock);
87 lastblock = new Block();
88 return index + 1;
91 Block *BlockArray::lastBlock() const
93 return lastblock;
96 bool BlockArray::has(size_t i) const
98 if (i == index + 1)
99 return true;
101 if (i > index)
102 return false;
103 if (index - i >= length)
104 return false;
105 return true;
108 const Block* BlockArray::at(size_t i)
110 if (i == index + 1)
111 return lastblock;
113 if (i == lastmap_index)
114 return lastmap;
116 if (i > index) {
117 kDebug(1211) << "BlockArray::at() i > index\n";
118 return 0;
121 // if (index - i >= length) {
122 // kDebug(1211) << "BlockArray::at() index - i >= length\n";
123 // return 0;
124 // }
126 size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
128 assert(j < size);
129 unmap();
131 Block *block = (Block*)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
133 if (block == (Block*)-1) { perror("mmap"); return 0; }
135 lastmap = block;
136 lastmap_index = i;
138 return block;
141 void BlockArray::unmap()
143 if (lastmap) {
144 int res = munmap((char*)lastmap, blocksize);
145 if (res < 0) perror("munmap");
147 lastmap = 0;
148 lastmap_index = size_t(-1);
151 bool BlockArray::setSize(size_t newsize)
153 return setHistorySize(newsize * 1024 / blocksize);
156 bool BlockArray::setHistorySize(size_t newsize)
158 // kDebug(1211) << "setHistorySize " << size << " " << newsize;
160 if (size == newsize)
161 return false;
163 unmap();
165 if (!newsize) {
166 delete lastblock;
167 lastblock = 0;
168 if (ion >= 0) close(ion);
169 ion = -1;
170 current = size_t(-1);
171 return true;
174 if (!size) {
175 FILE* tmp = tmpfile();
176 if (!tmp) {
177 perror("konsole: cannot open temp file.\n");
178 } else {
179 ion = dup(fileno(tmp));
180 if (ion<0) {
181 perror("konsole: cannot dup temp file.\n");
182 fclose(tmp);
185 if (ion < 0)
186 return false;
188 assert(!lastblock);
190 lastblock = new Block();
191 size = newsize;
192 return false;
195 if (newsize > size) {
196 increaseBuffer();
197 size = newsize;
198 return false;
199 } else {
200 decreaseBuffer(newsize);
201 ftruncate(ion, length*blocksize);
202 size = newsize;
204 return true;
208 void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
210 int res = KDE_fseek(fion, cursor * blocksize, SEEK_SET);
211 if (res)
212 perror("fseek");
213 res = fread(buffer2, blocksize, 1, fion);
214 if (res != 1)
215 perror("fread");
217 res = KDE_fseek(fion, newpos * blocksize, SEEK_SET);
218 if (res)
219 perror("fseek");
220 res = fwrite(buffer2, blocksize, 1, fion);
221 if (res != 1)
222 perror("fwrite");
223 // printf("moving block %d to %d\n", cursor, newpos);
226 void BlockArray::decreaseBuffer(size_t newsize)
228 if (index < newsize) // still fits in whole
229 return;
231 int offset = (current - (newsize - 1) + size) % size;
233 if (!offset)
234 return;
236 // The Block constructor could do somthing in future...
237 char *buffer1 = new char[blocksize];
239 FILE *fion = fdopen(dup(ion), "w+b");
240 if (!fion) {
241 delete [] buffer1;
242 perror("fdopen/dup");
243 return;
246 int firstblock;
247 if (current <= newsize) {
248 firstblock = current + 1;
249 } else {
250 firstblock = 0;
253 size_t oldpos;
254 for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
255 oldpos = (size + cursor + offset) % size;
256 moveBlock(fion, oldpos, cursor, buffer1);
257 if (oldpos < newsize) {
258 cursor = oldpos;
259 } else
260 cursor++;
263 current = newsize - 1;
264 length = newsize;
266 delete [] buffer1;
268 fclose(fion);
272 void BlockArray::increaseBuffer()
274 if (index < size) // not even wrapped once
275 return;
277 int offset = (current + size + 1) % size;
278 if (!offset) // no moving needed
279 return;
281 // The Block constructor could do somthing in future...
282 char *buffer1 = new char[blocksize];
283 char *buffer2 = new char[blocksize];
285 int runs = 1;
286 int bpr = size; // blocks per run
288 if (size % offset == 0) {
289 bpr = size / offset;
290 runs = offset;
293 FILE *fion = fdopen(dup(ion), "w+b");
294 if (!fion) {
295 perror("fdopen/dup");
296 delete [] buffer1;
297 delete [] buffer2;
298 return;
301 int res;
302 for (int i = 0; i < runs; i++)
304 // free one block in chain
305 int firstblock = (offset + i) % size;
306 res = KDE_fseek(fion, firstblock * blocksize, SEEK_SET);
307 if (res)
308 perror("fseek");
309 res = fread(buffer1, blocksize, 1, fion);
310 if (res != 1)
311 perror("fread");
312 int newpos = 0;
313 for (int j = 1, cursor=firstblock; j < bpr; j++)
315 cursor = (cursor + offset) % size;
316 newpos = (cursor - offset + size) % size;
317 moveBlock(fion, cursor, newpos, buffer2);
319 res = KDE_fseek(fion, i * blocksize, SEEK_SET);
320 if (res)
321 perror("fseek");
322 res = fwrite(buffer1, blocksize, 1, fion);
323 if (res != 1)
324 perror("fwrite");
326 current = size - 1;
327 length = size;
329 delete [] buffer1;
330 delete [] buffer2;
332 fclose(fion);