~larryprice/acolyterm/release-0.1

« back to all changes in this revision

Viewing changes to src/plugin/konsole/BlockArray.cpp

  • Committer: Larry Price
  • Date: 2016-06-15 14:47:59 UTC
  • Revision ID: larry.price@canonical.com-20160615144759-6wopn0gxwgta3x1n
Updating QMLTermWidget and removing unnecessary konsole codebase

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
// Own
25
 
#include "BlockArray.h"
26
 
 
27
 
#include <QtCore>
28
 
 
29
 
// System
30
 
#include <assert.h>
31
 
#include <sys/mman.h>
32
 
#include <sys/param.h>
33
 
#include <unistd.h>
34
 
#include <stdio.h>
35
 
 
36
 
 
37
 
static int blocksize = 0;
38
 
 
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)
47
 
{
48
 
    // lastmap_index = index = current = size_t(-1);
49
 
    if (blocksize == 0) {
50
 
        blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
51
 
    }
52
 
 
53
 
}
54
 
 
55
 
BlockArray::~BlockArray()
56
 
{
57
 
    setHistorySize(0);
58
 
    assert(!lastblock);
59
 
}
60
 
 
61
 
size_t BlockArray::append(Block * block)
62
 
{
63
 
    if (!size) {
64
 
        return size_t(-1);
65
 
    }
66
 
 
67
 
    ++current;
68
 
    if (current >= size) {
69
 
        current = 0;
70
 
    }
71
 
 
72
 
    int rc;
73
 
    rc = lseek(ion, current * blocksize, SEEK_SET);
74
 
    if (rc < 0) {
75
 
        perror("HistoryBuffer::add.seek");
76
 
        setHistorySize(0);
77
 
        return size_t(-1);
78
 
    }
79
 
    rc = write(ion, block, blocksize);
80
 
    if (rc < 0) {
81
 
        perror("HistoryBuffer::add.write");
82
 
        setHistorySize(0);
83
 
        return size_t(-1);
84
 
    }
85
 
 
86
 
    length++;
87
 
    if (length > size) {
88
 
        length = size;
89
 
    }
90
 
 
91
 
    ++index;
92
 
 
93
 
    delete block;
94
 
    return current;
95
 
}
96
 
 
97
 
size_t BlockArray::newBlock()
98
 
{
99
 
    if (!size) {
100
 
        return size_t(-1);
101
 
    }
102
 
    append(lastblock);
103
 
 
104
 
    lastblock = new Block();
105
 
    return index + 1;
106
 
}
107
 
 
108
 
Block * BlockArray::lastBlock() const
109
 
{
110
 
    return lastblock;
111
 
}
112
 
 
113
 
bool BlockArray::has(size_t i) const
114
 
{
115
 
    if (i == index + 1) {
116
 
        return true;
117
 
    }
118
 
 
119
 
    if (i > index) {
120
 
        return false;
121
 
    }
122
 
    if (index - i >= length) {
123
 
        return false;
124
 
    }
125
 
    return true;
126
 
}
127
 
 
128
 
const Block * BlockArray::at(size_t i)
129
 
{
130
 
    if (i == index + 1) {
131
 
        return lastblock;
132
 
    }
133
 
 
134
 
    if (i == lastmap_index) {
135
 
        return lastmap;
136
 
    }
137
 
 
138
 
    if (i > index) {
139
 
        qDebug() << "BlockArray::at() i > index\n";
140
 
        return 0;
141
 
    }
142
 
 
143
 
//     if (index - i >= length) {
144
 
//         kDebug(1211) << "BlockArray::at() index - i >= length\n";
145
 
//         return 0;
146
 
//     }
147
 
 
148
 
    size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
149
 
 
150
 
    assert(j < size);
151
 
    unmap();
152
 
 
153
 
    Block * block = (Block *)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
154
 
 
155
 
    if (block == (Block *)-1) {
156
 
        perror("mmap");
157
 
        return 0;
158
 
    }
159
 
 
160
 
    lastmap = block;
161
 
    lastmap_index = i;
162
 
 
163
 
    return block;
164
 
}
165
 
 
166
 
void BlockArray::unmap()
167
 
{
168
 
    if (lastmap) {
169
 
        int res = munmap((char *)lastmap, blocksize);
170
 
        if (res < 0) {
171
 
            perror("munmap");
172
 
        }
173
 
    }
174
 
    lastmap = 0;
175
 
    lastmap_index = size_t(-1);
176
 
}
177
 
 
178
 
bool BlockArray::setSize(size_t newsize)
179
 
{
180
 
    return setHistorySize(newsize * 1024 / blocksize);
181
 
}
182
 
 
183
 
bool BlockArray::setHistorySize(size_t newsize)
184
 
{
185
 
//    kDebug(1211) << "setHistorySize " << size << " " << newsize;
186
 
 
187
 
    if (size == newsize) {
188
 
        return false;
189
 
    }
190
 
 
191
 
    unmap();
192
 
 
193
 
    if (!newsize) {
194
 
        delete lastblock;
195
 
        lastblock = 0;
196
 
        if (ion >= 0) {
197
 
            close(ion);
198
 
        }
199
 
        ion = -1;
200
 
        current = size_t(-1);
201
 
        return true;
202
 
    }
203
 
 
204
 
    if (!size) {
205
 
        FILE * tmp = tmpfile();
206
 
        if (!tmp) {
207
 
            perror("konsole: cannot open temp file.\n");
208
 
        } else {
209
 
            ion = dup(fileno(tmp));
210
 
            if (ion<0) {
211
 
                perror("konsole: cannot dup temp file.\n");
212
 
                fclose(tmp);
213
 
            }
214
 
        }
215
 
        if (ion < 0) {
216
 
            return false;
217
 
        }
218
 
 
219
 
        assert(!lastblock);
220
 
 
221
 
        lastblock = new Block();
222
 
        size = newsize;
223
 
        return false;
224
 
    }
225
 
 
226
 
    if (newsize > size) {
227
 
        increaseBuffer();
228
 
        size = newsize;
229
 
        return false;
230
 
    } else {
231
 
        decreaseBuffer(newsize);
232
 
        ftruncate(ion, length*blocksize);
233
 
        size = newsize;
234
 
 
235
 
        return true;
236
 
    }
237
 
}
238
 
 
239
 
void moveBlock(FILE * fion, int cursor, int newpos, char * buffer2)
240
 
{
241
 
    int res = fseek(fion, cursor * blocksize, SEEK_SET);
242
 
    if (res) {
243
 
        perror("fseek");
244
 
    }
245
 
    res = fread(buffer2, blocksize, 1, fion);
246
 
    if (res != 1) {
247
 
        perror("fread");
248
 
    }
249
 
 
250
 
    res = fseek(fion, newpos * blocksize, SEEK_SET);
251
 
    if (res) {
252
 
        perror("fseek");
253
 
    }
254
 
    res = fwrite(buffer2, blocksize, 1, fion);
255
 
    if (res != 1) {
256
 
        perror("fwrite");
257
 
    }
258
 
    //    printf("moving block %d to %d\n", cursor, newpos);
259
 
}
260
 
 
261
 
void BlockArray::decreaseBuffer(size_t newsize)
262
 
{
263
 
    if (index < newsize) { // still fits in whole
264
 
        return;
265
 
    }
266
 
 
267
 
    int offset = (current - (newsize - 1) + size) % size;
268
 
 
269
 
    if (!offset) {
270
 
        return;
271
 
    }
272
 
 
273
 
    // The Block constructor could do somthing in future...
274
 
    char * buffer1 = new char[blocksize];
275
 
 
276
 
    FILE * fion = fdopen(dup(ion), "w+b");
277
 
    if (!fion) {
278
 
        delete [] buffer1;
279
 
        perror("fdopen/dup");
280
 
        return;
281
 
    }
282
 
 
283
 
    int firstblock;
284
 
    if (current <= newsize) {
285
 
        firstblock = current + 1;
286
 
    } else {
287
 
        firstblock = 0;
288
 
    }
289
 
 
290
 
    size_t oldpos;
291
 
    for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
292
 
        oldpos = (size + cursor + offset) % size;
293
 
        moveBlock(fion, oldpos, cursor, buffer1);
294
 
        if (oldpos < newsize) {
295
 
            cursor = oldpos;
296
 
        } else {
297
 
            cursor++;
298
 
        }
299
 
    }
300
 
 
301
 
    current = newsize - 1;
302
 
    length = newsize;
303
 
 
304
 
    delete [] buffer1;
305
 
 
306
 
    fclose(fion);
307
 
 
308
 
}
309
 
 
310
 
void BlockArray::increaseBuffer()
311
 
{
312
 
    if (index < size) { // not even wrapped once
313
 
        return;
314
 
    }
315
 
 
316
 
    int offset = (current + size + 1) % size;
317
 
    if (!offset) { // no moving needed
318
 
        return;
319
 
    }
320
 
 
321
 
    // The Block constructor could do somthing in future...
322
 
    char * buffer1 = new char[blocksize];
323
 
    char * buffer2 = new char[blocksize];
324
 
 
325
 
    int runs = 1;
326
 
    int bpr = size; // blocks per run
327
 
 
328
 
    if (size % offset == 0) {
329
 
        bpr = size / offset;
330
 
        runs = offset;
331
 
    }
332
 
 
333
 
    FILE * fion = fdopen(dup(ion), "w+b");
334
 
    if (!fion) {
335
 
        perror("fdopen/dup");
336
 
        delete [] buffer1;
337
 
        delete [] buffer2;
338
 
        return;
339
 
    }
340
 
 
341
 
    int res;
342
 
    for (int i = 0; i < runs; i++) {
343
 
        // free one block in chain
344
 
        int firstblock = (offset + i) % size;
345
 
        res = fseek(fion, firstblock * blocksize, SEEK_SET);
346
 
        if (res) {
347
 
            perror("fseek");
348
 
        }
349
 
        res = fread(buffer1, blocksize, 1, fion);
350
 
        if (res != 1) {
351
 
            perror("fread");
352
 
        }
353
 
        int newpos = 0;
354
 
        for (int j = 1, cursor=firstblock; j < bpr; j++) {
355
 
            cursor = (cursor + offset) % size;
356
 
            newpos = (cursor - offset + size) % size;
357
 
            moveBlock(fion, cursor, newpos, buffer2);
358
 
        }
359
 
        res = fseek(fion, i * blocksize, SEEK_SET);
360
 
        if (res) {
361
 
            perror("fseek");
362
 
        }
363
 
        res = fwrite(buffer1, blocksize, 1, fion);
364
 
        if (res != 1) {
365
 
            perror("fwrite");
366
 
        }
367
 
    }
368
 
    current = size - 1;
369
 
    length = size;
370
 
 
371
 
    delete [] buffer1;
372
 
    delete [] buffer2;
373
 
 
374
 
    fclose(fion);
375
 
 
376
 
}
377