00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "History.h"
00023
00024
00025 #include <iostream>
00026 #include <stdlib.h>
00027 #include <assert.h>
00028 #include <stdio.h>
00029 #include <sys/types.h>
00030 #include <sys/mman.h>
00031 #include <unistd.h>
00032 #include <errno.h>
00033
00034
00035 #include <kdebug.h>
00036
00037
00038 #define LINE_SIZE 1024
00039
00040 using namespace Konsole;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 HistoryFile::HistoryFile()
00087 : ion(-1),
00088 length(0),
00089 fileMap(0)
00090 {
00091 if (tmpFile.open())
00092 {
00093 tmpFile.setAutoRemove(true);
00094 ion = tmpFile.handle();
00095 }
00096 }
00097
00098 HistoryFile::~HistoryFile()
00099 {
00100 if (fileMap)
00101 unmap();
00102 }
00103
00104
00105
00106
00107 void HistoryFile::map()
00108 {
00109 assert( fileMap == 0 );
00110
00111 fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
00112
00113
00114 if ( fileMap == MAP_FAILED )
00115 {
00116 readWriteBalance = 0;
00117 fileMap = 0;
00118 kDebug() << k_funcinfo << ": mmap'ing history failed. errno = " << errno;
00119 }
00120 }
00121
00122 void HistoryFile::unmap()
00123 {
00124 int result = munmap( fileMap , length );
00125 assert( result == 0 );
00126
00127 fileMap = 0;
00128 }
00129
00130 bool HistoryFile::isMapped()
00131 {
00132 return (fileMap != 0);
00133 }
00134
00135 void HistoryFile::add(const unsigned char* bytes, int len)
00136 {
00137 if ( fileMap )
00138 unmap();
00139
00140 readWriteBalance++;
00141
00142 int rc = 0;
00143
00144 rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
00145 rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryFile::add.write"); return; }
00146 length += rc;
00147 }
00148
00149 void HistoryFile::get(unsigned char* bytes, int len, int loc)
00150 {
00151
00152
00153
00154
00155 readWriteBalance--;
00156 if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
00157 map();
00158
00159 if ( fileMap )
00160 {
00161 for (int i=0;i<len;i++)
00162 bytes[i]=fileMap[loc+i];
00163 }
00164 else
00165 {
00166 int rc = 0;
00167
00168 if (loc < 0 || len < 0 || loc + len > length)
00169 fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
00170 rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
00171 rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryFile::get.read"); return; }
00172 }
00173 }
00174
00175 int HistoryFile::len()
00176 {
00177 return length;
00178 }
00179
00180
00181
00182
00183
00184 HistoryScroll::HistoryScroll(HistoryType* t)
00185 : m_histType(t)
00186 {
00187 }
00188
00189 HistoryScroll::~HistoryScroll()
00190 {
00191 delete m_histType;
00192 }
00193
00194 bool HistoryScroll::hasScroll()
00195 {
00196 return true;
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
00213 : HistoryScroll(new HistoryTypeFile(logFileName)),
00214 m_logFileName(logFileName)
00215 {
00216 }
00217
00218 HistoryScrollFile::~HistoryScrollFile()
00219 {
00220 }
00221
00222 int HistoryScrollFile::getLines()
00223 {
00224 return index.len() / sizeof(int);
00225 }
00226
00227 int HistoryScrollFile::getLineLen(int lineno)
00228 {
00229 return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
00230 }
00231
00232 bool HistoryScrollFile::isWrappedLine(int lineno)
00233 {
00234 if (lineno>=0 && lineno <= getLines()) {
00235 unsigned char flag;
00236 lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
00237 return flag;
00238 }
00239 return false;
00240 }
00241
00242 int HistoryScrollFile::startOfLine(int lineno)
00243 {
00244 if (lineno <= 0) return 0;
00245 if (lineno <= getLines())
00246 {
00247
00248 if (!index.isMapped())
00249 index.map();
00250
00251 int res;
00252 index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
00253 return res;
00254 }
00255 return cells.len();
00256 }
00257
00258 void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
00259 {
00260 cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
00261 }
00262
00263 void HistoryScrollFile::addCells(const Character text[], int count)
00264 {
00265 cells.add((unsigned char*)text,count*sizeof(Character));
00266 }
00267
00268 void HistoryScrollFile::addLine(bool previousWrapped)
00269 {
00270 if (index.isMapped())
00271 index.unmap();
00272
00273 int locn = cells.len();
00274 index.add((unsigned char*)&locn,sizeof(int));
00275 unsigned char flags = previousWrapped ? 0x01 : 0x00;
00276 lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
00277 }
00278
00279
00280
00281 HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
00282 : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
00283 ,_historyBuffer()
00284 ,_maxLineCount(0)
00285 ,_usedLines(0)
00286 ,_head(0)
00287 {
00288 setMaxNbLines(maxLineCount);
00289 }
00290
00291 HistoryScrollBuffer::~HistoryScrollBuffer()
00292 {
00293 delete[] _historyBuffer;
00294 }
00295
00296 void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
00297 {
00298 _head++;
00299 if ( _usedLines < _maxLineCount )
00300 _usedLines++;
00301
00302 if ( _head >= _maxLineCount )
00303 {
00304 _head = 0;
00305 }
00306
00307 _historyBuffer[bufferIndex(_usedLines-1)] = cells;
00308 _wrappedLine[bufferIndex(_usedLines-1)] = false;
00309 }
00310 void HistoryScrollBuffer::addCells(const Character a[], int count)
00311 {
00312 HistoryLine newLine(count);
00313 qCopy(a,a+count,newLine.begin());
00314
00315 addCellsVector(newLine);
00316 }
00317
00318 void HistoryScrollBuffer::addLine(bool previousWrapped)
00319 {
00320 _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
00321 }
00322
00323 int HistoryScrollBuffer::getLines()
00324 {
00325 return _usedLines;
00326 }
00327
00328 int HistoryScrollBuffer::getLineLen(int lineNumber)
00329 {
00330 Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
00331
00332 if ( lineNumber < _usedLines )
00333 {
00334 return _historyBuffer[bufferIndex(lineNumber)].size();
00335 }
00336 else
00337 {
00338 return 0;
00339 }
00340 }
00341
00342 bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
00343 {
00344 Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
00345
00346 if (lineNumber < _usedLines)
00347 {
00348
00349 return _wrappedLine[bufferIndex(lineNumber)];
00350 }
00351 else
00352 return false;
00353 }
00354
00355 void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character* buffer)
00356 {
00357 if ( count == 0 ) return;
00358
00359 Q_ASSERT( lineNumber < _maxLineCount );
00360
00361 if (lineNumber >= _usedLines)
00362 {
00363 memset(buffer, 0, count * sizeof(Character));
00364 return;
00365 }
00366
00367 const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
00368
00369
00370
00371
00372
00373 Q_ASSERT( startColumn <= line.size() - count );
00374
00375 memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
00376 }
00377
00378 void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
00379 {
00380 HistoryLine* oldBuffer = _historyBuffer;
00381 HistoryLine* newBuffer = new HistoryLine[lineCount];
00382
00383 for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
00384 {
00385 newBuffer[i] = oldBuffer[bufferIndex(i)];
00386 }
00387
00388 _usedLines = qMin(_usedLines,(int)lineCount);
00389 _maxLineCount = lineCount;
00390 _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
00391
00392 _historyBuffer = newBuffer;
00393 delete[] oldBuffer;
00394
00395 _wrappedLine.resize(lineCount);
00396 dynamic_cast<HistoryTypeBuffer*>(m_histType)->m_nbLines = lineCount;
00397 }
00398
00399 int HistoryScrollBuffer::bufferIndex(int lineNumber)
00400 {
00401 Q_ASSERT( lineNumber >= 0 );
00402 Q_ASSERT( lineNumber < _maxLineCount );
00403 Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
00404
00405 if ( _usedLines == _maxLineCount )
00406 {
00407 return (_head+lineNumber+1) % _maxLineCount;
00408 }
00409 else
00410 {
00411 return lineNumber;
00412 }
00413 }
00414
00415
00416
00417
00418 HistoryScrollNone::HistoryScrollNone()
00419 : HistoryScroll(new HistoryTypeNone())
00420 {
00421 }
00422
00423 HistoryScrollNone::~HistoryScrollNone()
00424 {
00425 }
00426
00427 bool HistoryScrollNone::hasScroll()
00428 {
00429 return false;
00430 }
00431
00432 int HistoryScrollNone::getLines()
00433 {
00434 return 0;
00435 }
00436
00437 int HistoryScrollNone::getLineLen(int)
00438 {
00439 return 0;
00440 }
00441
00442 bool HistoryScrollNone::isWrappedLine(int )
00443 {
00444 return false;
00445 }
00446
00447 void HistoryScrollNone::getCells(int, int, int, Character [])
00448 {
00449 }
00450
00451 void HistoryScrollNone::addCells(const Character [], int)
00452 {
00453 }
00454
00455 void HistoryScrollNone::addLine(bool)
00456 {
00457 }
00458
00459
00460
00461 HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
00462 : HistoryScroll(new HistoryTypeBlockArray(size))
00463 {
00464 m_blockArray.setHistorySize(size);
00465 }
00466
00467 HistoryScrollBlockArray::~HistoryScrollBlockArray()
00468 {
00469 }
00470
00471 int HistoryScrollBlockArray::getLines()
00472 {
00473 return m_lineLengths.count();
00474 }
00475
00476 int HistoryScrollBlockArray::getLineLen(int lineno)
00477 {
00478 if ( m_lineLengths.contains(lineno) )
00479 return m_lineLengths[lineno];
00480 else
00481 return 0;
00482 }
00483
00484 bool HistoryScrollBlockArray::isWrappedLine(int )
00485 {
00486 return false;
00487 }
00488
00489 void HistoryScrollBlockArray::getCells(int lineno, int colno,
00490 int count, Character res[])
00491 {
00492 if (!count) return;
00493
00494 const Block *b = m_blockArray.at(lineno);
00495
00496 if (!b) {
00497 memset(res, 0, count * sizeof(Character));
00498 return;
00499 }
00500
00501 assert(((colno + count) * sizeof(Character)) < ENTRIES);
00502 memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
00503 }
00504
00505 void HistoryScrollBlockArray::addCells(const Character a[], int count)
00506 {
00507 Block *b = m_blockArray.lastBlock();
00508
00509 if (!b) return;
00510
00511
00512 assert((count * sizeof(Character)) < ENTRIES);
00513
00514 memset(b->data, 0, ENTRIES);
00515
00516 memcpy(b->data, a, count * sizeof(Character));
00517 b->size = count * sizeof(Character);
00518
00519 size_t res = m_blockArray.newBlock();
00520 assert (res > 0);
00521 Q_UNUSED( res );
00522
00523 m_lineLengths.insert(m_blockArray.getCurrent(), count);
00524 }
00525
00526 void HistoryScrollBlockArray::addLine(bool)
00527 {
00528 }
00529
00531
00533
00534 HistoryType::HistoryType()
00535 {
00536 }
00537
00538 HistoryType::~HistoryType()
00539 {
00540 }
00541
00543
00544 HistoryTypeNone::HistoryTypeNone()
00545 {
00546 }
00547
00548 bool HistoryTypeNone::isEnabled() const
00549 {
00550 return false;
00551 }
00552
00553 HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
00554 {
00555 delete old;
00556 return new HistoryScrollNone();
00557 }
00558
00559 int HistoryTypeNone::maximumLineCount() const
00560 {
00561 return 0;
00562 }
00563
00565
00566 HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
00567 : m_size(size)
00568 {
00569 }
00570
00571 bool HistoryTypeBlockArray::isEnabled() const
00572 {
00573 return true;
00574 }
00575
00576 int HistoryTypeBlockArray::maximumLineCount() const
00577 {
00578 return m_size;
00579 }
00580
00581 HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
00582 {
00583 delete old;
00584 return new HistoryScrollBlockArray(m_size);
00585 }
00586
00587
00589
00590 HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
00591 : m_nbLines(nbLines)
00592 {
00593 }
00594
00595 bool HistoryTypeBuffer::isEnabled() const
00596 {
00597 return true;
00598 }
00599
00600 int HistoryTypeBuffer::maximumLineCount() const
00601 {
00602 return m_nbLines;
00603 }
00604
00605 HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
00606 {
00607 if (old)
00608 {
00609 HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
00610 if (oldBuffer)
00611 {
00612 oldBuffer->setMaxNbLines(m_nbLines);
00613 return oldBuffer;
00614 }
00615
00616 HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
00617 int lines = old->getLines();
00618 int startLine = 0;
00619 if (lines > (int) m_nbLines)
00620 startLine = lines - m_nbLines;
00621
00622 Character line[LINE_SIZE];
00623 for(int i = startLine; i < lines; i++)
00624 {
00625 int size = old->getLineLen(i);
00626 if (size > LINE_SIZE)
00627 {
00628 Character *tmp_line = new Character[size];
00629 old->getCells(i, 0, size, tmp_line);
00630 newScroll->addCells(tmp_line, size);
00631 newScroll->addLine(old->isWrappedLine(i));
00632 delete [] tmp_line;
00633 }
00634 else
00635 {
00636 old->getCells(i, 0, size, line);
00637 newScroll->addCells(line, size);
00638 newScroll->addLine(old->isWrappedLine(i));
00639 }
00640 }
00641 delete old;
00642 return newScroll;
00643 }
00644 return new HistoryScrollBuffer(m_nbLines);
00645 }
00646
00648
00649 HistoryTypeFile::HistoryTypeFile(const QString& fileName)
00650 : m_fileName(fileName)
00651 {
00652 }
00653
00654 bool HistoryTypeFile::isEnabled() const
00655 {
00656 return true;
00657 }
00658
00659 const QString& HistoryTypeFile::getFileName() const
00660 {
00661 return m_fileName;
00662 }
00663
00664 HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
00665 {
00666 if (dynamic_cast<HistoryFile *>(old))
00667 return old;
00668
00669 HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
00670
00671 Character line[LINE_SIZE];
00672 int lines = (old != 0) ? old->getLines() : 0;
00673 for(int i = 0; i < lines; i++)
00674 {
00675 int size = old->getLineLen(i);
00676 if (size > LINE_SIZE)
00677 {
00678 Character *tmp_line = new Character[size];
00679 old->getCells(i, 0, size, tmp_line);
00680 newScroll->addCells(tmp_line, size);
00681 newScroll->addLine(old->isWrappedLine(i));
00682 delete [] tmp_line;
00683 }
00684 else
00685 {
00686 old->getCells(i, 0, size, line);
00687 newScroll->addCells(line, size);
00688 newScroll->addLine(old->isWrappedLine(i));
00689 }
00690 }
00691
00692 delete old;
00693 return newScroll;
00694 }
00695
00696 int HistoryTypeFile::maximumLineCount() const
00697 {
00698 return 0;
00699 }