source: ogBrowser-Git/qtermwidget/lib/BlockArray.cpp @ c0cec9d

jenkinsmain
Last change on this file since c0cec9d was 64efc22, checked in by Vadim Troshchinskiy <vtroshchinskiy@…>, 19 months ago

Update qtermwidget to modern version

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