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