File indexing completed on 2025-01-19 04:23:24
0001 /* 0002 This file is part of Konsole, an X terminal. 0003 Copyright (C) 2000 by Stephan Kulow <coolo@kde.org> 0004 0005 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008 0006 0007 This program is free software; you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation; either version 2 of the License, or 0010 (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with this program; if not, write to the Free Software 0019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0020 02110-1301 USA. 0021 0022 */ 0023 0024 #include <QtDebug> 0025 0026 // Own 0027 #include "BlockArray.h" 0028 0029 // System 0030 #include <sys/mman.h> 0031 #include <sys/param.h> 0032 #include <unistd.h> 0033 #include <stdio.h> 0034 0035 0036 using namespace Konsole; 0037 0038 static int blocksize = 0; 0039 0040 BlockArray::BlockArray() 0041 : size(0), 0042 current(size_t(-1)), 0043 index(size_t(-1)), 0044 lastmap(0), 0045 lastmap_index(size_t(-1)), 0046 lastblock(0), ion(-1), 0047 length(0) 0048 { 0049 // lastmap_index = index = current = size_t(-1); 0050 if (blocksize == 0) { 0051 blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize(); 0052 } 0053 0054 } 0055 0056 BlockArray::~BlockArray() 0057 { 0058 setHistorySize(0); 0059 Q_ASSERT(!lastblock); 0060 } 0061 0062 size_t BlockArray::append(Block * block) 0063 { 0064 if (!size) { 0065 return size_t(-1); 0066 } 0067 0068 ++current; 0069 if (current >= size) { 0070 current = 0; 0071 } 0072 0073 int rc; 0074 rc = lseek(ion, current * blocksize, SEEK_SET); 0075 if (rc < 0) { 0076 perror("HistoryBuffer::add.seek"); 0077 setHistorySize(0); 0078 return size_t(-1); 0079 } 0080 rc = write(ion, block, blocksize); 0081 if (rc < 0) { 0082 perror("HistoryBuffer::add.write"); 0083 setHistorySize(0); 0084 return size_t(-1); 0085 } 0086 0087 length++; 0088 if (length > size) { 0089 length = size; 0090 } 0091 0092 ++index; 0093 0094 delete block; 0095 return current; 0096 } 0097 0098 size_t BlockArray::newBlock() 0099 { 0100 if (!size) { 0101 return size_t(-1); 0102 } 0103 append(lastblock); 0104 0105 lastblock = new Block(); 0106 return index + 1; 0107 } 0108 0109 Block * BlockArray::lastBlock() const 0110 { 0111 return lastblock; 0112 } 0113 0114 bool BlockArray::has(size_t i) const 0115 { 0116 if (i == index + 1) { 0117 return true; 0118 } 0119 0120 if (i > index) { 0121 return false; 0122 } 0123 if (index - i >= length) { 0124 return false; 0125 } 0126 return true; 0127 } 0128 0129 const Block * BlockArray::at(size_t i) 0130 { 0131 if (i == index + 1) { 0132 return lastblock; 0133 } 0134 0135 if (i == lastmap_index) { 0136 return lastmap; 0137 } 0138 0139 if (i > index) { 0140 qDebug() << "BlockArray::at() i > index\n"; 0141 return 0; 0142 } 0143 0144 // if (index - i >= length) { 0145 // kDebug(1211) << "BlockArray::at() index - i >= length\n"; 0146 // return 0; 0147 // } 0148 0149 size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ; 0150 0151 Q_ASSERT(j < size); 0152 unmap(); 0153 0154 Block * block = (Block *)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize); 0155 0156 if (block == (Block *)-1) { 0157 perror("mmap"); 0158 return 0; 0159 } 0160 0161 lastmap = block; 0162 lastmap_index = i; 0163 0164 return block; 0165 } 0166 0167 void BlockArray::unmap() 0168 { 0169 if (lastmap) { 0170 int res = munmap((char *)lastmap, blocksize); 0171 if (res < 0) { 0172 perror("munmap"); 0173 } 0174 } 0175 lastmap = 0; 0176 lastmap_index = size_t(-1); 0177 } 0178 0179 bool BlockArray::setSize(size_t newsize) 0180 { 0181 return setHistorySize(newsize * 1024 / blocksize); 0182 } 0183 0184 bool BlockArray::setHistorySize(size_t newsize) 0185 { 0186 // kDebug(1211) << "setHistorySize " << size << " " << newsize; 0187 0188 if (size == newsize) { 0189 return false; 0190 } 0191 0192 unmap(); 0193 0194 if (!newsize) { 0195 delete lastblock; 0196 lastblock = 0; 0197 if (ion >= 0) { 0198 close(ion); 0199 } 0200 ion = -1; 0201 current = size_t(-1); 0202 return true; 0203 } 0204 0205 if (!size) { 0206 FILE * tmp = tmpfile(); 0207 if (!tmp) { 0208 perror("konsole: cannot open temp file.\n"); 0209 } else { 0210 ion = dup(fileno(tmp)); 0211 if (ion<0) { 0212 perror("konsole: cannot dup temp file.\n"); 0213 fclose(tmp); 0214 } 0215 } 0216 if (ion < 0) { 0217 return false; 0218 } 0219 0220 Q_ASSERT(!lastblock); 0221 0222 lastblock = new Block(); 0223 size = newsize; 0224 return false; 0225 } 0226 0227 if (newsize > size) { 0228 increaseBuffer(); 0229 size = newsize; 0230 return false; 0231 } else { 0232 decreaseBuffer(newsize); 0233 ftruncate(ion, length*blocksize); 0234 size = newsize; 0235 0236 return true; 0237 } 0238 } 0239 0240 void moveBlock(FILE * fion, int cursor, int newpos, char * buffer2) 0241 { 0242 int res = fseek(fion, cursor * blocksize, SEEK_SET); 0243 if (res) { 0244 perror("fseek"); 0245 } 0246 res = fread(buffer2, blocksize, 1, fion); 0247 if (res != 1) { 0248 perror("fread"); 0249 } 0250 0251 res = fseek(fion, newpos * blocksize, SEEK_SET); 0252 if (res) { 0253 perror("fseek"); 0254 } 0255 res = fwrite(buffer2, blocksize, 1, fion); 0256 if (res != 1) { 0257 perror("fwrite"); 0258 } 0259 // printf("moving block %d to %d\n", cursor, newpos); 0260 } 0261 0262 void BlockArray::decreaseBuffer(size_t newsize) 0263 { 0264 if (index < newsize) { // still fits in whole 0265 return; 0266 } 0267 0268 int offset = (current - (newsize - 1) + size) % size; 0269 0270 if (!offset) { 0271 return; 0272 } 0273 0274 // The Block constructor could do somthing in future... 0275 char * buffer1 = new char[blocksize]; 0276 0277 FILE * fion = fdopen(dup(ion), "w+b"); 0278 if (!fion) { 0279 delete [] buffer1; 0280 perror("fdopen/dup"); 0281 return; 0282 } 0283 0284 int firstblock; 0285 if (current <= newsize) { 0286 firstblock = current + 1; 0287 } else { 0288 firstblock = 0; 0289 } 0290 0291 size_t oldpos; 0292 for (size_t i = 0, cursor=firstblock; i < newsize; i++) { 0293 oldpos = (size + cursor + offset) % size; 0294 moveBlock(fion, oldpos, cursor, buffer1); 0295 if (oldpos < newsize) { 0296 cursor = oldpos; 0297 } else { 0298 cursor++; 0299 } 0300 } 0301 0302 current = newsize - 1; 0303 length = newsize; 0304 0305 delete [] buffer1; 0306 0307 fclose(fion); 0308 0309 } 0310 0311 void BlockArray::increaseBuffer() 0312 { 0313 if (index < size) { // not even wrapped once 0314 return; 0315 } 0316 0317 int offset = (current + size + 1) % size; 0318 if (!offset) { // no moving needed 0319 return; 0320 } 0321 0322 // The Block constructor could do somthing in future... 0323 char * buffer1 = new char[blocksize]; 0324 char * buffer2 = new char[blocksize]; 0325 0326 int runs = 1; 0327 int bpr = size; // blocks per run 0328 0329 if (size % offset == 0) { 0330 bpr = size / offset; 0331 runs = offset; 0332 } 0333 0334 FILE * fion = fdopen(dup(ion), "w+b"); 0335 if (!fion) { 0336 perror("fdopen/dup"); 0337 delete [] buffer1; 0338 delete [] buffer2; 0339 return; 0340 } 0341 0342 int res; 0343 for (int i = 0; i < runs; i++) { 0344 // free one block in chain 0345 int firstblock = (offset + i) % size; 0346 res = fseek(fion, firstblock * blocksize, SEEK_SET); 0347 if (res) { 0348 perror("fseek"); 0349 } 0350 res = fread(buffer1, blocksize, 1, fion); 0351 if (res != 1) { 0352 perror("fread"); 0353 } 0354 int newpos = 0; 0355 for (int j = 1, cursor=firstblock; j < bpr; j++) { 0356 cursor = (cursor + offset) % size; 0357 newpos = (cursor - offset + size) % size; 0358 moveBlock(fion, cursor, newpos, buffer2); 0359 } 0360 res = fseek(fion, i * blocksize, SEEK_SET); 0361 if (res) { 0362 perror("fseek"); 0363 } 0364 res = fwrite(buffer1, blocksize, 1, fion); 0365 if (res != 1) { 0366 perror("fwrite"); 0367 } 0368 } 0369 current = size - 1; 0370 length = size; 0371 0372 delete [] buffer1; 0373 delete [] buffer2; 0374 0375 fclose(fion); 0376 0377 } 0378