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 }
00397
00398 int HistoryScrollBuffer::bufferIndex(int lineNumber)
00399 {
00400 Q_ASSERT( lineNumber >= 0 );
00401 Q_ASSERT( lineNumber < _maxLineCount );
00402 Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
00403
00404 if ( _usedLines == _maxLineCount )
00405 {
00406 return (_head+lineNumber+1) % _maxLineCount;
00407 }
00408 else
00409 {
00410 return lineNumber;
00411 }
00412 }
00413
00414
00415
00416
00417 HistoryScrollNone::HistoryScrollNone()
00418 : HistoryScroll(new HistoryTypeNone())
00419 {
00420 }
00421
00422 HistoryScrollNone::~HistoryScrollNone()
00423 {
00424 }
00425
00426 bool HistoryScrollNone::hasScroll()
00427 {
00428 return false;
00429 }
00430
00431 int HistoryScrollNone::getLines()
00432 {
00433 return 0;
00434 }
00435
00436 int HistoryScrollNone::getLineLen(int)
00437 {
00438 return 0;
00439 }
00440
00441 bool HistoryScrollNone::isWrappedLine(int )
00442 {
00443 return false;
00444 }
00445
00446 void HistoryScrollNone::getCells(int, int, int, Character [])
00447 {
00448 }
00449
00450 void HistoryScrollNone::addCells(const Character [], int)
00451 {
00452 }
00453
00454 void HistoryScrollNone::addLine(bool)
00455 {
00456 }
00457
00458
00459
00460 HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
00461 : HistoryScroll(new HistoryTypeBlockArray(size))
00462 {
00463 m_blockArray.setHistorySize(size);
00464 }
00465
00466 HistoryScrollBlockArray::~HistoryScrollBlockArray()
00467 {
00468 }
00469
00470 int HistoryScrollBlockArray::getLines()
00471 {
00472 return m_lineLengths.count();
00473 }
00474
00475 int HistoryScrollBlockArray::getLineLen(int lineno)
00476 {
00477 if ( m_lineLengths.contains(lineno) )
00478 return m_lineLengths[lineno];
00479 else
00480 return 0;
00481 }
00482
00483 bool HistoryScrollBlockArray::isWrappedLine(int )
00484 {
00485 return false;
00486 }
00487
00488 void HistoryScrollBlockArray::getCells(int lineno, int colno,
00489 int count, Character res[])
00490 {
00491 if (!count) return;
00492
00493 const Block *b = m_blockArray.at(lineno);
00494
00495 if (!b) {
00496 memset(res, 0, count * sizeof(Character));
00497 return;
00498 }
00499
00500 assert(((colno + count) * sizeof(Character)) < ENTRIES);
00501 memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
00502 }
00503
00504 void HistoryScrollBlockArray::addCells(const Character a[], int count)
00505 {
00506 Block *b = m_blockArray.lastBlock();
00507
00508 if (!b) return;
00509
00510
00511 assert((count * sizeof(Character)) < ENTRIES);
00512
00513 memset(b->data, 0, ENTRIES);
00514
00515 memcpy(b->data, a, count * sizeof(Character));
00516 b->size = count * sizeof(Character);
00517
00518 size_t res = m_blockArray.newBlock();
00519 assert (res > 0);
00520 Q_UNUSED( res );
00521
00522 m_lineLengths.insert(m_blockArray.getCurrent(), count);
00523 }
00524
00525 void HistoryScrollBlockArray::addLine(bool)
00526 {
00527 }
00528
00530
00532
00533 HistoryType::HistoryType()
00534 {
00535 }
00536
00537 HistoryType::~HistoryType()
00538 {
00539 }
00540
00542
00543 HistoryTypeNone::HistoryTypeNone()
00544 {
00545 }
00546
00547 bool HistoryTypeNone::isEnabled() const
00548 {
00549 return false;
00550 }
00551
00552 HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
00553 {
00554 delete old;
00555 return new HistoryScrollNone();
00556 }
00557
00558 int HistoryTypeNone::maximumLineCount() const
00559 {
00560 return 0;
00561 }
00562
00564
00565 HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
00566 : m_size(size)
00567 {
00568 }
00569
00570 bool HistoryTypeBlockArray::isEnabled() const
00571 {
00572 return true;
00573 }
00574
00575 int HistoryTypeBlockArray::maximumLineCount() const
00576 {
00577 return m_size;
00578 }
00579
00580 HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
00581 {
00582 delete old;
00583 return new HistoryScrollBlockArray(m_size);
00584 }
00585
00586
00588
00589 HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
00590 : m_nbLines(nbLines)
00591 {
00592 }
00593
00594 bool HistoryTypeBuffer::isEnabled() const
00595 {
00596 return true;
00597 }
00598
00599 int HistoryTypeBuffer::maximumLineCount() const
00600 {
00601 return m_nbLines;
00602 }
00603
00604 HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
00605 {
00606 if (old)
00607 {
00608 HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
00609 if (oldBuffer)
00610 {
00611 oldBuffer->setMaxNbLines(m_nbLines);
00612 return oldBuffer;
00613 }
00614
00615 HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
00616 int lines = old->getLines();
00617 int startLine = 0;
00618 if (lines > (int) m_nbLines)
00619 startLine = lines - m_nbLines;
00620
00621 Character line[LINE_SIZE];
00622 for(int i = startLine; i < lines; i++)
00623 {
00624 int size = old->getLineLen(i);
00625 if (size > LINE_SIZE)
00626 {
00627 Character *tmp_line = new Character[size];
00628 old->getCells(i, 0, size, tmp_line);
00629 newScroll->addCells(tmp_line, size);
00630 newScroll->addLine(old->isWrappedLine(i));
00631 delete [] tmp_line;
00632 }
00633 else
00634 {
00635 old->getCells(i, 0, size, line);
00636 newScroll->addCells(line, size);
00637 newScroll->addLine(old->isWrappedLine(i));
00638 }
00639 }
00640 delete old;
00641 return newScroll;
00642 }
00643 return new HistoryScrollBuffer(m_nbLines);
00644 }
00645
00647
00648 HistoryTypeFile::HistoryTypeFile(const QString& fileName)
00649 : m_fileName(fileName)
00650 {
00651 }
00652
00653 bool HistoryTypeFile::isEnabled() const
00654 {
00655 return true;
00656 }
00657
00658 const QString& HistoryTypeFile::getFileName() const
00659 {
00660 return m_fileName;
00661 }
00662
00663 HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
00664 {
00665 if (dynamic_cast<HistoryFile *>(old))
00666 return old;
00667
00668 HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
00669
00670 Character line[LINE_SIZE];
00671 int lines = (old != 0) ? old->getLines() : 0;
00672 for(int i = 0; i < lines; i++)
00673 {
00674 int size = old->getLineLen(i);
00675 if (size > LINE_SIZE)
00676 {
00677 Character *tmp_line = new Character[size];
00678 old->getCells(i, 0, size, tmp_line);
00679 newScroll->addCells(tmp_line, size);
00680 newScroll->addLine(old->isWrappedLine(i));
00681 delete [] tmp_line;
00682 }
00683 else
00684 {
00685 old->getCells(i, 0, size, line);
00686 newScroll->addCells(line, size);
00687 newScroll->addLine(old->isWrappedLine(i));
00688 }
00689 }
00690
00691 delete old;
00692 return newScroll;
00693 }
00694
00695 int HistoryTypeFile::maximumLineCount() const
00696 {
00697 return 0;
00698 }