File indexing completed on 2025-01-19 04:23:26
0001 /* 0002 This file is part of Konsole, an X terminal. 0003 Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de> 0004 0005 This program is free software; you can redistribute it and/or modify 0006 it under the terms of the GNU General Public License as published by 0007 the Free Software Foundation; either version 2 of the License, or 0008 (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; if not, write to the Free Software 0017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0018 02110-1301 USA. 0019 */ 0020 0021 #ifndef TEHISTORY_H 0022 #define TEHISTORY_H 0023 0024 // Qt 0025 #include <QBitRef> 0026 #include <QHash> 0027 #include <QVector> 0028 #include <QTemporaryFile> 0029 0030 // KDE 0031 //#include <ktemporaryfile.h> 0032 0033 // Konsole 0034 #include "BlockArray.h" 0035 #include "Character.h" 0036 0037 // map 0038 #include <sys/mman.h> 0039 0040 namespace Konsole 0041 { 0042 0043 #if 1 0044 /* 0045 An extendable tmpfile(1) based buffer. 0046 */ 0047 0048 class HistoryFile 0049 { 0050 public: 0051 HistoryFile(); 0052 virtual ~HistoryFile(); 0053 0054 virtual void add(const unsigned char* bytes, int len); 0055 virtual void get(unsigned char* bytes, int len, int loc); 0056 virtual int len(); 0057 0058 //mmaps the file in read-only mode 0059 void map(); 0060 //un-mmaps the file 0061 void unmap(); 0062 //returns true if the file is mmap'ed 0063 bool isMapped() const; 0064 0065 0066 private: 0067 int ion; 0068 int length; 0069 QTemporaryFile tmpFile; 0070 0071 //pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed 0072 char* fileMap; 0073 0074 //incremented whenver 'add' is called and decremented whenever 0075 //'get' is called. 0076 //this is used to detect when a large number of lines are being read and processed from the history 0077 //and automatically mmap the file for better performance (saves the overhead of many lseek-read calls). 0078 int readWriteBalance; 0079 0080 //when readWriteBalance goes below this threshold, the file will be mmap'ed automatically 0081 static const int MAP_THRESHOLD = -1000; 0082 }; 0083 #endif 0084 0085 ////////////////////////////////////////////////////////////////////// 0086 0087 ////////////////////////////////////////////////////////////////////// 0088 // Abstract base class for file and buffer versions 0089 ////////////////////////////////////////////////////////////////////// 0090 class HistoryType; 0091 0092 class HistoryScroll 0093 { 0094 public: 0095 HistoryScroll(HistoryType*); 0096 virtual ~HistoryScroll(); 0097 0098 virtual bool hasScroll(); 0099 0100 // access to history 0101 virtual int getLines() = 0; 0102 virtual int getLineLen(int lineno) = 0; 0103 virtual void getCells(int lineno, int colno, int count, Character res[]) = 0; 0104 virtual bool isWrappedLine(int lineno) = 0; 0105 0106 // backward compatibility (obsolete) 0107 Character getCell(int lineno, int colno) { Character res; getCells(lineno,colno,1,&res); return res; } 0108 0109 // adding lines. 0110 virtual void addCells(const Character a[], int count) = 0; 0111 // convenience method - this is virtual so that subclasses can take advantage 0112 // of QVector's implicit copying 0113 virtual void addCellsVector(const QVector<Character>& cells) 0114 { 0115 addCells(cells.data(),cells.size()); 0116 } 0117 0118 virtual void addLine(bool previousWrapped=false) = 0; 0119 0120 // 0121 // FIXME: Passing around constant references to HistoryType instances 0122 // is very unsafe, because those references will no longer 0123 // be valid if the history scroll is deleted. 0124 // 0125 const HistoryType& getType() { return *m_histType; } 0126 0127 protected: 0128 HistoryType* m_histType; 0129 0130 }; 0131 0132 #if 1 0133 0134 ////////////////////////////////////////////////////////////////////// 0135 // File-based history (e.g. file log, no limitation in length) 0136 ////////////////////////////////////////////////////////////////////// 0137 0138 class HistoryScrollFile : public HistoryScroll 0139 { 0140 public: 0141 HistoryScrollFile(const QString &logFileName); 0142 virtual ~HistoryScrollFile(); 0143 0144 virtual int getLines(); 0145 virtual int getLineLen(int lineno); 0146 virtual void getCells(int lineno, int colno, int count, Character res[]); 0147 virtual bool isWrappedLine(int lineno); 0148 0149 virtual void addCells(const Character a[], int count); 0150 virtual void addLine(bool previousWrapped=false); 0151 0152 private: 0153 int startOfLine(int lineno); 0154 0155 QString m_logFileName; 0156 HistoryFile index; // lines Row(int) 0157 HistoryFile cells; // text Row(Character) 0158 HistoryFile lineflags; // flags Row(unsigned char) 0159 }; 0160 0161 0162 ////////////////////////////////////////////////////////////////////// 0163 // Buffer-based history (limited to a fixed nb of lines) 0164 ////////////////////////////////////////////////////////////////////// 0165 class HistoryScrollBuffer : public HistoryScroll 0166 { 0167 public: 0168 typedef QVector<Character> HistoryLine; 0169 0170 HistoryScrollBuffer(unsigned int maxNbLines = 1000); 0171 virtual ~HistoryScrollBuffer(); 0172 0173 virtual int getLines(); 0174 virtual int getLineLen(int lineno); 0175 virtual void getCells(int lineno, int colno, int count, Character res[]); 0176 virtual bool isWrappedLine(int lineno); 0177 0178 virtual void addCells(const Character a[], int count); 0179 virtual void addCellsVector(const QVector<Character>& cells); 0180 virtual void addLine(bool previousWrapped=false); 0181 0182 void setMaxNbLines(unsigned int nbLines); 0183 unsigned int maxNbLines() const { return _maxLineCount; } 0184 0185 0186 private: 0187 int bufferIndex(int lineNumber); 0188 0189 HistoryLine* _historyBuffer; 0190 QBitArray _wrappedLine; 0191 int _maxLineCount; 0192 int _usedLines; 0193 int _head; 0194 0195 //QVector<histline*> m_histBuffer; 0196 //QBitArray m_wrappedLine; 0197 //unsigned int m_maxNbLines; 0198 //unsigned int m_nbLines; 0199 //unsigned int m_arrayIndex; 0200 //bool m_buffFilled; 0201 }; 0202 0203 /*class HistoryScrollBufferV2 : public HistoryScroll 0204 { 0205 public: 0206 virtual int getLines(); 0207 virtual int getLineLen(int lineno); 0208 virtual void getCells(int lineno, int colno, int count, Character res[]); 0209 virtual bool isWrappedLine(int lineno); 0210 0211 virtual void addCells(const Character a[], int count); 0212 virtual void addCells(const QVector<Character>& cells); 0213 virtual void addLine(bool previousWrapped=false); 0214 0215 };*/ 0216 0217 #endif 0218 0219 ////////////////////////////////////////////////////////////////////// 0220 // Nothing-based history (no history :-) 0221 ////////////////////////////////////////////////////////////////////// 0222 class HistoryScrollNone : public HistoryScroll 0223 { 0224 public: 0225 HistoryScrollNone(); 0226 virtual ~HistoryScrollNone(); 0227 0228 virtual bool hasScroll(); 0229 0230 virtual int getLines(); 0231 virtual int getLineLen(int lineno); 0232 virtual void getCells(int lineno, int colno, int count, Character res[]); 0233 virtual bool isWrappedLine(int lineno); 0234 0235 virtual void addCells(const Character a[], int count); 0236 virtual void addLine(bool previousWrapped=false); 0237 }; 0238 0239 ////////////////////////////////////////////////////////////////////// 0240 // BlockArray-based history 0241 ////////////////////////////////////////////////////////////////////// 0242 class HistoryScrollBlockArray : public HistoryScroll 0243 { 0244 public: 0245 HistoryScrollBlockArray(size_t size); 0246 virtual ~HistoryScrollBlockArray(); 0247 0248 virtual int getLines(); 0249 virtual int getLineLen(int lineno); 0250 virtual void getCells(int lineno, int colno, int count, Character res[]); 0251 virtual bool isWrappedLine(int lineno); 0252 0253 virtual void addCells(const Character a[], int count); 0254 virtual void addLine(bool previousWrapped=false); 0255 0256 protected: 0257 BlockArray m_blockArray; 0258 QHash<int,size_t> m_lineLengths; 0259 }; 0260 0261 ////////////////////////////////////////////////////////////////////// 0262 // History using compact storage 0263 // This implementation uses a list of fixed-sized blocks 0264 // where history lines are allocated in (avoids heap fragmentation) 0265 ////////////////////////////////////////////////////////////////////// 0266 typedef QVector<Character> TextLine; 0267 0268 class CharacterFormat 0269 { 0270 public: 0271 bool equalsFormat(const CharacterFormat &other) const { 0272 return other.rendition==rendition && other.fgColor==fgColor && other.bgColor==bgColor; 0273 } 0274 0275 bool equalsFormat(const Character &c) const { 0276 return c.rendition==rendition && c.foregroundColor==fgColor && c.backgroundColor==bgColor; 0277 } 0278 0279 void setFormat(const Character& c) { 0280 rendition=c.rendition; 0281 fgColor=c.foregroundColor; 0282 bgColor=c.backgroundColor; 0283 } 0284 0285 CharacterColor fgColor, bgColor; 0286 quint16 startPos; 0287 quint8 rendition; 0288 }; 0289 0290 class CompactHistoryBlock 0291 { 0292 public: 0293 0294 CompactHistoryBlock(){ 0295 blockLength = 4096*64; // 256kb 0296 head = (quint8*) mmap(0, blockLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 0297 //head = (quint8*) malloc(blockLength); 0298 Q_ASSERT(head != MAP_FAILED); 0299 tail = blockStart = head; 0300 allocCount=0; 0301 } 0302 0303 virtual ~CompactHistoryBlock(){ 0304 //free(blockStart); 0305 munmap(blockStart, blockLength); 0306 } 0307 0308 virtual unsigned int remaining(){ return blockStart+blockLength-tail;} 0309 virtual unsigned length() { return blockLength; } 0310 virtual void* allocate(size_t length); 0311 virtual bool contains(void *addr) {return addr>=blockStart && addr<(blockStart+blockLength);} 0312 virtual void deallocate(); 0313 virtual bool isInUse(){ return allocCount!=0; } ; 0314 0315 private: 0316 size_t blockLength; 0317 quint8* head; 0318 quint8* tail; 0319 quint8* blockStart; 0320 int allocCount; 0321 }; 0322 0323 class CompactHistoryBlockList { 0324 public: 0325 CompactHistoryBlockList() {}; 0326 ~CompactHistoryBlockList(); 0327 0328 void *allocate( size_t size ); 0329 void deallocate(void *); 0330 int length() {return list.size();} 0331 private: 0332 QList<CompactHistoryBlock*> list; 0333 }; 0334 0335 class CompactHistoryLine 0336 { 0337 public: 0338 CompactHistoryLine(const TextLine&, CompactHistoryBlockList& blockList); 0339 virtual ~CompactHistoryLine(); 0340 0341 // custom new operator to allocate memory from custom pool instead of heap 0342 static void *operator new( size_t size, CompactHistoryBlockList& blockList); 0343 static void operator delete( void *) { /* do nothing, deallocation from pool is done in destructor*/ } ; 0344 0345 virtual void getCharacters(Character* array, int length, int startColumn) ; 0346 virtual void getCharacter(int index, Character &r) ; 0347 virtual bool isWrapped() const {return wrapped;}; 0348 virtual void setWrapped(bool isWrapped) { wrapped=isWrapped;}; 0349 virtual unsigned int getLength() const {return length;}; 0350 0351 protected: 0352 CompactHistoryBlockList& blockList; 0353 CharacterFormat* formatArray; 0354 quint16 length; 0355 quint16* text; 0356 quint16 formatLength; 0357 bool wrapped; 0358 }; 0359 0360 class CompactHistoryScroll : public HistoryScroll 0361 { 0362 typedef QList<CompactHistoryLine*> HistoryArray; 0363 0364 public: 0365 CompactHistoryScroll(unsigned int maxNbLines = 1000); 0366 virtual ~CompactHistoryScroll(); 0367 0368 virtual int getLines(); 0369 virtual int getLineLen(int lineno); 0370 virtual void getCells(int lineno, int colno, int count, Character res[]); 0371 virtual bool isWrappedLine(int lineno); 0372 0373 virtual void addCells(const Character a[], int count); 0374 virtual void addCellsVector(const TextLine& cells); 0375 virtual void addLine(bool previousWrapped=false); 0376 0377 void setMaxNbLines(unsigned int nbLines); 0378 unsigned int maxNbLines() const { return _maxLineCount; } 0379 0380 private: 0381 bool hasDifferentColors(const TextLine& line) const; 0382 HistoryArray lines; 0383 CompactHistoryBlockList blockList; 0384 0385 unsigned int _maxLineCount; 0386 }; 0387 0388 ////////////////////////////////////////////////////////////////////// 0389 // History type 0390 ////////////////////////////////////////////////////////////////////// 0391 0392 class HistoryType 0393 { 0394 public: 0395 HistoryType(); 0396 virtual ~HistoryType(); 0397 0398 /** 0399 * Returns true if the history is enabled ( can store lines of output ) 0400 * or false otherwise. 0401 */ 0402 virtual bool isEnabled() const = 0; 0403 /** 0404 * Returns true if the history size is unlimited. 0405 */ 0406 bool isUnlimited() const { return maximumLineCount() == 0; } 0407 /** 0408 * Returns the maximum number of lines which this history type 0409 * can store or 0 if the history can store an unlimited number of lines. 0410 */ 0411 virtual int maximumLineCount() const = 0; 0412 0413 virtual HistoryScroll* scroll(HistoryScroll *) const = 0; 0414 }; 0415 0416 class HistoryTypeNone : public HistoryType 0417 { 0418 public: 0419 HistoryTypeNone(); 0420 0421 virtual bool isEnabled() const; 0422 virtual int maximumLineCount() const; 0423 0424 virtual HistoryScroll* scroll(HistoryScroll *) const; 0425 }; 0426 0427 class HistoryTypeBlockArray : public HistoryType 0428 { 0429 public: 0430 HistoryTypeBlockArray(size_t size); 0431 0432 virtual bool isEnabled() const; 0433 virtual int maximumLineCount() const; 0434 0435 virtual HistoryScroll* scroll(HistoryScroll *) const; 0436 0437 protected: 0438 size_t m_size; 0439 }; 0440 0441 #if 1 0442 class HistoryTypeFile : public HistoryType 0443 { 0444 public: 0445 HistoryTypeFile(const QString& fileName=QString()); 0446 0447 virtual bool isEnabled() const; 0448 virtual const QString& getFileName() const; 0449 virtual int maximumLineCount() const; 0450 0451 virtual HistoryScroll* scroll(HistoryScroll *) const; 0452 0453 protected: 0454 QString m_fileName; 0455 }; 0456 0457 0458 class HistoryTypeBuffer : public HistoryType 0459 { 0460 friend class HistoryScrollBuffer; 0461 0462 public: 0463 HistoryTypeBuffer(unsigned int nbLines); 0464 0465 virtual bool isEnabled() const; 0466 virtual int maximumLineCount() const; 0467 0468 virtual HistoryScroll* scroll(HistoryScroll *) const; 0469 0470 protected: 0471 unsigned int m_nbLines; 0472 }; 0473 0474 class CompactHistoryType : public HistoryType 0475 { 0476 public: 0477 CompactHistoryType(unsigned int size); 0478 0479 virtual bool isEnabled() const; 0480 virtual int maximumLineCount() const; 0481 0482 virtual HistoryScroll* scroll(HistoryScroll *) const; 0483 0484 protected: 0485 unsigned int m_nbLines; 0486 }; 0487 0488 0489 #endif 0490 0491 } 0492 0493 #endif // TEHISTORY_H