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