MauiKit Terminal

BlockArray.cpp
1/*
2 This file is part of Konsole, an X terminal.
3 SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
4
5 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301 USA.
18
19*/
20
21#include <QDebug>
22
23// Own
24#include "BlockArray.h"
25
26// System
27#include <cstdio>
28#include <sys/mman.h>
29#include <sys/param.h>
30#include <unistd.h>
31
32using namespace Konsole;
33
34BlockArray::BlockArray()
35 : size(0)
36 , current(size_t(-1))
37 , index(size_t(-1))
38 , lastmap(nullptr)
39 , lastmap_index(size_t(-1))
40 , lastblock(nullptr)
41 , ion(-1)
42 , length(0)
43{
44 // lastmap_index = index = current = size_t(-1);
45 if (blocksize == 0) {
46 blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
47 }
48}
49
50BlockArray::~BlockArray()
51{
52 setHistorySize(0);
53 Q_ASSERT(!lastblock);
54}
55
56size_t BlockArray::append(Block *block)
57{
58 if (!size) {
59 return size_t(-1);
60 }
61
62 ++current;
63 if (current >= size) {
64 current = 0;
65 }
66
67 int rc;
68 rc = lseek(ion, current * blocksize, SEEK_SET);
69 if (rc < 0) {
70 perror("HistoryBuffer::add.seek");
71 setHistorySize(0);
72 return size_t(-1);
73 }
74 rc = write(ion, block, blocksize);
75 if (rc < 0) {
76 perror("HistoryBuffer::add.write");
77 setHistorySize(0);
78 return size_t(-1);
79 }
80
81 length++;
82 if (length > size) {
83 length = size;
84 }
85
86 ++index;
87
88 delete block;
89 return current;
90}
91
92size_t BlockArray::newBlock()
93{
94 if (!size) {
95 return size_t(-1);
96 }
97 append(lastblock);
98
99 lastblock = new Block();
100 return index + 1;
101}
102
103Block *BlockArray::lastBlock() const
104{
105 return lastblock;
106}
107
108bool BlockArray::has(size_t i) const
109{
110 if (i == index + 1) {
111 return true;
112 }
113
114 if (i > index) {
115 return false;
116 }
117 if (index - i >= length) {
118 return false;
119 }
120 return true;
121}
122
123const Block *BlockArray::at(size_t i)
124{
125 if (i == index + 1) {
126 return lastblock;
127 }
128
129 if (i == lastmap_index) {
130 return lastmap;
131 }
132
133 if (i > index) {
134 qDebug() << "BlockArray::at() i > index\n";
135 return nullptr;
136 }
137
138 size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
139
140 Q_ASSERT(j < size);
141 unmap();
142
143 Block *block = (Block *)mmap(nullptr, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
144
145 if (block == (Block *)-1) {
146 perror("mmap");
147 return nullptr;
148 }
149
150 lastmap = block;
151 lastmap_index = i;
152
153 return block;
154}
155
156void BlockArray::unmap()
157{
158 if (lastmap) {
159 int res = munmap((char *)lastmap, blocksize);
160 if (res < 0) {
161 perror("munmap");
162 }
163 }
164 lastmap = nullptr;
165 lastmap_index = size_t(-1);
166}
167
168bool BlockArray::setSize(size_t newsize)
169{
170 return setHistorySize(newsize * 1024 / blocksize);
171}
172
173bool BlockArray::setHistorySize(size_t newsize)
174{
175 if (size == newsize) {
176 return false;
177 }
178
179 unmap();
180
181 if (!newsize) {
182 delete lastblock;
183 lastblock = nullptr;
184 if (ion >= 0) {
185 close(ion);
186 }
187 ion = -1;
188 current = size_t(-1);
189 return true;
190 }
191
192 if (!size) {
193 FILE *tmp = tmpfile();
194 if (!tmp) {
195 perror("konsole: cannot open temp file.\n");
196 } else {
197 ion = dup(fileno(tmp));
198 if (ion < 0) {
199 perror("konsole: cannot dup temp file.\n");
200 fclose(tmp);
201 }
202 }
203 if (ion < 0) {
204 return false;
205 }
206
207 Q_ASSERT(!lastblock);
208
209 lastblock = new Block();
210 size = newsize;
211 return false;
212 }
213
214 if (newsize > size) {
215 increaseBuffer();
216 size = newsize;
217 return false;
218 } else {
219 decreaseBuffer(newsize);
220 ftruncate(ion, length * blocksize);
221 size = newsize;
222
223 return true;
224 }
225}
226
227void BlockArray::moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
228{
229 int res = fseek(fion, cursor * blocksize, SEEK_SET);
230 if (res) {
231 perror("fseek");
232 }
233 res = fread(buffer2, blocksize, 1, fion);
234 if (res != 1) {
235 perror("fread");
236 }
237
238 res = fseek(fion, newpos * blocksize, SEEK_SET);
239 if (res) {
240 perror("fseek");
241 }
242 res = fwrite(buffer2, blocksize, 1, fion);
243 if (res != 1) {
244 perror("fwrite");
245 }
246 // printf("moving block %d to %d\n", cursor, newpos);
247}
248
249void BlockArray::decreaseBuffer(size_t newsize)
250{
251 if (index < newsize) { // still fits in whole
252 return;
253 }
254
255 int offset = (current - (newsize - 1) + size) % size;
256
257 if (!offset) {
258 return;
259 }
260
261 // The Block constructor could do somthing in future...
262 char *buffer1 = new char[blocksize];
263
264 FILE *fion = fdopen(dup(ion), "w+b");
265 if (!fion) {
266 delete[] buffer1;
267 perror("fdopen/dup");
268 return;
269 }
270
271 int firstblock;
272 if (current <= newsize) {
273 firstblock = current + 1;
274 } else {
275 firstblock = 0;
276 }
277
278 size_t oldpos;
279 for (size_t i = 0, cursor = firstblock; i < newsize; i++) {
280 oldpos = (size + cursor + offset) % size;
281 moveBlock(fion, oldpos, cursor, buffer1);
282 if (oldpos < newsize) {
283 cursor = oldpos;
284 } else {
285 cursor++;
286 }
287 }
288
289 current = newsize - 1;
290 length = newsize;
291
292 delete[] buffer1;
293
294 fclose(fion);
295}
296
297void BlockArray::increaseBuffer()
298{
299 if (index < size) { // not even wrapped once
300 return;
301 }
302
303 int offset = (current + size + 1) % size;
304 if (!offset) { // no moving needed
305 return;
306 }
307
308 // The Block constructor could do somthing in future...
309 char *buffer1 = new char[blocksize];
310 char *buffer2 = new char[blocksize];
311
312 int runs = 1;
313 int bpr = size; // blocks per run
314
315 if (size % offset == 0) {
316 bpr = size / offset;
317 runs = offset;
318 }
319
320 FILE *fion = fdopen(dup(ion), "w+b");
321 if (!fion) {
322 perror("fdopen/dup");
323 delete[] buffer1;
324 delete[] buffer2;
325 return;
326 }
327
328 int res;
329 for (int i = 0; i < runs; i++) {
330 // free one block in chain
331 int firstblock = (offset + i) % size;
332 res = fseek(fion, firstblock * blocksize, SEEK_SET);
333 if (res) {
334 perror("fseek");
335 }
336 res = fread(buffer1, blocksize, 1, fion);
337 if (res != 1) {
338 perror("fread");
339 }
340 int newpos = 0;
341 for (int j = 1, cursor = firstblock; j < bpr; j++) {
342 cursor = (cursor + offset) % size;
343 newpos = (cursor - offset + size) % size;
344 moveBlock(fion, cursor, newpos, buffer2);
345 }
346 res = fseek(fion, i * blocksize, SEEK_SET);
347 if (res) {
348 perror("fseek");
349 }
350 res = fwrite(buffer1, blocksize, 1, fion);
351 if (res != 1) {
352 perror("fwrite");
353 }
354 }
355 current = size - 1;
356 length = size;
357
358 delete[] buffer1;
359 delete[] buffer2;
360
361 fclose(fion);
362}
KGuiItem close()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:57:30 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.