You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
11 KiB
388 lines
11 KiB
/* |
|
This file is part of Konsole, an X terminal. |
|
Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de> |
|
|
|
This program is free software; you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program; if not, write to the Free Software |
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
02110-1301 USA. |
|
*/ |
|
|
|
#ifndef HISTORY_H |
|
#define HISTORY_H |
|
|
|
// System |
|
#include <sys/mman.h> |
|
|
|
// Qt |
|
#include <QtCore/QList> |
|
#include <QtCore/QVector> |
|
#include <QtCore/QTemporaryFile> |
|
|
|
#include "konsole_export.h" |
|
|
|
// Konsole |
|
#include "Character.h" |
|
|
|
namespace Konsole |
|
{ |
|
/* |
|
An extendable tmpfile(1) based buffer. |
|
*/ |
|
|
|
class HistoryFile |
|
{ |
|
public: |
|
HistoryFile(); |
|
virtual ~HistoryFile(); |
|
|
|
virtual void add(const unsigned char* bytes, int len); |
|
virtual void get(unsigned char* bytes, int len, int loc); |
|
virtual int len() const; |
|
|
|
//mmaps the file in read-only mode |
|
void map(); |
|
//un-mmaps the file |
|
void unmap(); |
|
//returns true if the file is mmap'ed |
|
bool isMapped() const; |
|
|
|
|
|
private: |
|
int _fd; |
|
int _length; |
|
QTemporaryFile _tmpFile; |
|
|
|
//pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed |
|
char* _fileMap; |
|
|
|
//incremented whenever 'add' is called and decremented whenever |
|
//'get' is called. |
|
//this is used to detect when a large number of lines are being read and processed from the history |
|
//and automatically mmap the file for better performance (saves the overhead of many lseek-read calls). |
|
int _readWriteBalance; |
|
|
|
//when _readWriteBalance goes below this threshold, the file will be mmap'ed automatically |
|
static const int MAP_THRESHOLD = -1000; |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// Abstract base class for file and buffer versions |
|
////////////////////////////////////////////////////////////////////// |
|
class HistoryType; |
|
|
|
class HistoryScroll |
|
{ |
|
public: |
|
explicit HistoryScroll(HistoryType*); |
|
virtual ~HistoryScroll(); |
|
|
|
virtual bool hasScroll(); |
|
|
|
// access to history |
|
virtual int getLines() = 0; |
|
virtual int getLineLen(int lineno) = 0; |
|
virtual void getCells(int lineno, int colno, int count, Character res[]) = 0; |
|
virtual bool isWrappedLine(int lineno) = 0; |
|
|
|
// adding lines. |
|
virtual void addCells(const Character a[], int count) = 0; |
|
// convenience method - this is virtual so that subclasses can take advantage |
|
// of QVector's implicit copying |
|
virtual void addCellsVector(const QVector<Character>& cells) { |
|
addCells(cells.data(), cells.size()); |
|
} |
|
|
|
virtual void addLine(bool previousWrapped = false) = 0; |
|
|
|
// |
|
// FIXME: Passing around constant references to HistoryType instances |
|
// is very unsafe, because those references will no longer |
|
// be valid if the history scroll is deleted. |
|
// |
|
const HistoryType& getType() const { |
|
return *_historyType; |
|
} |
|
|
|
protected: |
|
HistoryType* _historyType; |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// File-based history (e.g. file log, no limitation in length) |
|
////////////////////////////////////////////////////////////////////// |
|
|
|
class KONSOLEPRIVATE_EXPORT HistoryScrollFile : public HistoryScroll |
|
{ |
|
public: |
|
explicit HistoryScrollFile(const QString& logFileName); |
|
virtual ~HistoryScrollFile(); |
|
|
|
virtual int getLines(); |
|
virtual int getLineLen(int lineno); |
|
virtual void getCells(int lineno, int colno, int count, Character res[]); |
|
virtual bool isWrappedLine(int lineno); |
|
|
|
virtual void addCells(const Character a[], int count); |
|
virtual void addLine(bool previousWrapped = false); |
|
|
|
private: |
|
int startOfLine(int lineno); |
|
|
|
HistoryFile _index; // lines Row(int) |
|
HistoryFile _cells; // text Row(Character) |
|
HistoryFile _lineflags; // flags Row(unsigned char) |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// Nothing-based history (no history :-) |
|
////////////////////////////////////////////////////////////////////// |
|
class KONSOLEPRIVATE_EXPORT HistoryScrollNone : public HistoryScroll |
|
{ |
|
public: |
|
HistoryScrollNone(); |
|
virtual ~HistoryScrollNone(); |
|
|
|
virtual bool hasScroll(); |
|
|
|
virtual int getLines(); |
|
virtual int getLineLen(int lineno); |
|
virtual void getCells(int lineno, int colno, int count, Character res[]); |
|
virtual bool isWrappedLine(int lineno); |
|
|
|
virtual void addCells(const Character a[], int count); |
|
virtual void addLine(bool previousWrapped = false); |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// History using compact storage |
|
// This implementation uses a list of fixed-sized blocks |
|
// where history lines are allocated in (avoids heap fragmentation) |
|
////////////////////////////////////////////////////////////////////// |
|
typedef QVector<Character> TextLine; |
|
|
|
class CharacterFormat |
|
{ |
|
public: |
|
bool equalsFormat(const CharacterFormat& other) const { |
|
return (other.rendition & ~RE_EXTENDED_CHAR) == (rendition & ~RE_EXTENDED_CHAR) && other.fgColor == fgColor && other.bgColor == bgColor; |
|
} |
|
|
|
bool equalsFormat(const Character& c) const { |
|
return (c.rendition & ~RE_EXTENDED_CHAR) == (rendition & ~RE_EXTENDED_CHAR) && c.foregroundColor == fgColor && c.backgroundColor == bgColor; |
|
} |
|
|
|
void setFormat(const Character& c) { |
|
rendition = c.rendition; |
|
fgColor = c.foregroundColor; |
|
bgColor = c.backgroundColor; |
|
isRealCharacter = c.isRealCharacter; |
|
} |
|
|
|
CharacterColor fgColor, bgColor; |
|
quint16 startPos; |
|
quint8 rendition; |
|
bool isRealCharacter; |
|
}; |
|
|
|
class CompactHistoryBlock |
|
{ |
|
public: |
|
CompactHistoryBlock() { |
|
_blockLength = 4096 * 64; // 256kb |
|
_head = (quint8*) mmap(0, _blockLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
|
//_head = (quint8*) malloc(_blockLength); |
|
Q_ASSERT(_head != MAP_FAILED); |
|
_tail = _blockStart = _head; |
|
_allocCount = 0; |
|
} |
|
|
|
virtual ~CompactHistoryBlock() { |
|
//free(_blockStart); |
|
munmap(_blockStart, _blockLength); |
|
} |
|
|
|
virtual unsigned int remaining() { |
|
return _blockStart + _blockLength - _tail; |
|
} |
|
virtual unsigned length() { |
|
return _blockLength; |
|
} |
|
virtual void* allocate(size_t length); |
|
virtual bool contains(void* addr) { |
|
return addr >= _blockStart && addr < (_blockStart + _blockLength); |
|
} |
|
virtual void deallocate(); |
|
virtual bool isInUse() { |
|
return _allocCount != 0; |
|
}; |
|
|
|
private: |
|
size_t _blockLength; |
|
quint8* _head; |
|
quint8* _tail; |
|
quint8* _blockStart; |
|
int _allocCount; |
|
}; |
|
|
|
class CompactHistoryBlockList |
|
{ |
|
public: |
|
CompactHistoryBlockList() {} |
|
~CompactHistoryBlockList(); |
|
|
|
void* allocate(size_t size); |
|
void deallocate(void *); |
|
int length() { |
|
return list.size(); |
|
} |
|
private: |
|
QList<CompactHistoryBlock*> list; |
|
}; |
|
|
|
class CompactHistoryLine |
|
{ |
|
public: |
|
CompactHistoryLine(const TextLine&, CompactHistoryBlockList& blockList); |
|
virtual ~CompactHistoryLine(); |
|
|
|
// custom new operator to allocate memory from custom pool instead of heap |
|
static void* operator new(size_t size, CompactHistoryBlockList& blockList); |
|
static void operator delete(void *) { |
|
/* do nothing, deallocation from pool is done in destructor*/ |
|
}; |
|
|
|
virtual void getCharacters(Character* array, int length, int startColumn); |
|
virtual void getCharacter(int index, Character& r); |
|
virtual bool isWrapped() const { |
|
return _wrapped; |
|
}; |
|
virtual void setWrapped(bool value) { |
|
_wrapped = value; |
|
}; |
|
virtual unsigned int getLength() const { |
|
return _length; |
|
}; |
|
|
|
protected: |
|
CompactHistoryBlockList& _blockListRef; |
|
CharacterFormat* _formatArray; |
|
quint16 _length; |
|
quint16* _text; |
|
quint16 _formatLength; |
|
bool _wrapped; |
|
}; |
|
|
|
class KONSOLEPRIVATE_EXPORT CompactHistoryScroll : public HistoryScroll |
|
{ |
|
typedef QList<CompactHistoryLine*> HistoryArray; |
|
|
|
public: |
|
explicit CompactHistoryScroll(unsigned int maxNbLines = 1000); |
|
virtual ~CompactHistoryScroll(); |
|
|
|
virtual int getLines(); |
|
virtual int getLineLen(int lineno); |
|
virtual void getCells(int lineno, int colno, int count, Character res[]); |
|
virtual bool isWrappedLine(int lineno); |
|
|
|
virtual void addCells(const Character a[], int count); |
|
virtual void addCellsVector(const TextLine& cells); |
|
virtual void addLine(bool previousWrapped = false); |
|
|
|
void setMaxNbLines(unsigned int nbLines); |
|
|
|
private: |
|
bool hasDifferentColors(const TextLine& line) const; |
|
HistoryArray _lines; |
|
CompactHistoryBlockList _blockList; |
|
|
|
unsigned int _maxLineCount; |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// History type |
|
////////////////////////////////////////////////////////////////////// |
|
|
|
class KONSOLEPRIVATE_EXPORT HistoryType |
|
{ |
|
public: |
|
HistoryType(); |
|
virtual ~HistoryType(); |
|
|
|
/** |
|
* Returns true if the history is enabled ( can store lines of output ) |
|
* or false otherwise. |
|
*/ |
|
virtual bool isEnabled() const = 0; |
|
/** |
|
* Returns the maximum number of lines which this history type |
|
* can store or -1 if the history can store an unlimited number of lines. |
|
*/ |
|
virtual int maximumLineCount() const = 0; |
|
/** |
|
* Converts from one type of HistoryScroll to another or if given the |
|
* same type, returns it. |
|
*/ |
|
virtual HistoryScroll* scroll(HistoryScroll *) const = 0; |
|
/** |
|
* Returns true if the history size is unlimited. |
|
*/ |
|
bool isUnlimited() const { |
|
return maximumLineCount() == -1; |
|
} |
|
}; |
|
|
|
class KONSOLEPRIVATE_EXPORT HistoryTypeNone : public HistoryType |
|
{ |
|
public: |
|
HistoryTypeNone(); |
|
|
|
virtual bool isEnabled() const; |
|
virtual int maximumLineCount() const; |
|
|
|
virtual HistoryScroll* scroll(HistoryScroll *) const; |
|
}; |
|
|
|
class KONSOLEPRIVATE_EXPORT HistoryTypeFile : public HistoryType |
|
{ |
|
public: |
|
explicit HistoryTypeFile(const QString& fileName = QString()); |
|
|
|
virtual bool isEnabled() const; |
|
virtual int maximumLineCount() const; |
|
|
|
virtual HistoryScroll* scroll(HistoryScroll *) const; |
|
|
|
protected: |
|
QString _fileName; |
|
}; |
|
|
|
class KONSOLEPRIVATE_EXPORT CompactHistoryType : public HistoryType |
|
{ |
|
public: |
|
explicit CompactHistoryType(unsigned int size); |
|
|
|
virtual bool isEnabled() const; |
|
virtual int maximumLineCount() const; |
|
|
|
virtual HistoryScroll* scroll(HistoryScroll *) const; |
|
|
|
protected: |
|
unsigned int _maxLines; |
|
}; |
|
} |
|
|
|
#endif // HISTORY_H
|
|
|