source: ogBrowser-Git/qtermwidget/lib/History.cpp @ c0cec9d

jenkinsmain
Last change on this file since c0cec9d was fedf2a2, checked in by Vadim Troshchinskiy Shmelev <vtroshchinskiy@…>, 18 months ago

Update Qtermwidget to Qt6 version
Remove build files

  • Property mode set to 100644
File size: 22.8 KB
Line 
1/*
2    This file is part of Konsole, an X terminal.
3    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301  USA.
19*/
20
21// Own
22#include "History.h"
23
24// System
25#include <algorithm>
26#include <iostream>
27#include <cstdlib>
28#include <cstdio>
29#include <sys/types.h>
30#include <sys/mman.h>
31#include <unistd.h>
32#include <cerrno>
33
34#include <QtDebug>
35
36// KDE
37//#include <kde_file.h>
38//#include <kdebug.h>
39
40// Reasonable line size
41#define LINE_SIZE    1024
42#define KDE_lseek lseek
43
44using namespace Konsole;
45
46/*
47   An arbitrary long scroll.
48
49   One can modify the scroll only by adding either cells
50   or newlines, but access it randomly.
51
52   The model is that of an arbitrary wide typewriter scroll
53   in that the scroll is a serie of lines and each line is
54   a serie of cells with no overwriting permitted.
55
56   The implementation provides arbitrary length and numbers
57   of cells and line/column indexed read access to the scroll
58   at constant costs.
59
60KDE4: Can we use QTemporaryFile here, instead of KTempFile?
61
62FIXME: some complain about the history buffer consuming the
63       memory of their machines. This problem is critical
64       since the history does not behave gracefully in cases
65       where the memory is used up completely.
66
67       I put in a workaround that should handle it problem
68       now gracefully. I'm not satisfied with the solution.
69
70FIXME: Terminating the history is not properly indicated
71       in the menu. We should throw a signal.
72
73FIXME: There is noticeable decrease in speed, also. Perhaps,
74       there whole feature needs to be revisited therefore.
75       Disadvantage of a more elaborated, say block-oriented
76       scheme with wrap around would be it's complexity.
77*/
78
79//FIXME: temporary replacement for tmpfile
80//       this is here one for debugging purpose.
81
82//#define tmpfile xTmpFile
83
84// History File ///////////////////////////////////////////
85
86/*
87  A Row(X) data type which allows adding elements to the end.
88*/
89
90HistoryFile::HistoryFile()
91  : ion(-1),
92    length(0),
93    fileMap(nullptr),
94    readWriteBalance(0)
95{
96  if (tmpFile.open())
97  {
98    tmpFile.setAutoRemove(true);
99    ion = tmpFile.handle();
100  }
101}
102
103HistoryFile::~HistoryFile()
104{
105    if (fileMap)
106        unmap();
107}
108
109//TODO:  Mapping the entire file in will cause problems if the history file becomes exceedingly large,
110//(ie. larger than available memory).  HistoryFile::map() should only map in sections of the file at a time,
111//to avoid this.
112void HistoryFile::map()
113{
114    Q_ASSERT( fileMap == nullptr );
115
116    fileMap = (char*)mmap( nullptr , length , PROT_READ , MAP_PRIVATE , ion , 0 );
117
118    //if mmap'ing fails, fall back to the read-lseek combination
119    if ( fileMap == MAP_FAILED )
120    {
121            readWriteBalance = 0;
122            fileMap = nullptr;
123            //qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed.  errno = " << errno;
124    }
125}
126
127void HistoryFile::unmap()
128{
129    int result = munmap( fileMap , length );
130    Q_ASSERT( result == 0 ); Q_UNUSED( result );
131
132    fileMap = nullptr;
133}
134
135bool HistoryFile::isMapped() const
136{
137    return (fileMap != nullptr);
138}
139
140void HistoryFile::add(const unsigned char* bytes, int len)
141{
142  if ( fileMap )
143          unmap();
144
145  readWriteBalance++;
146
147  int rc = 0;
148
149  rc = KDE_lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
150  rc = write(ion,bytes,len);       if (rc < 0) { perror("HistoryFile::add.write"); return; }
151  length += rc;
152}
153
154void HistoryFile::get(unsigned char* bytes, int len, int loc)
155{
156  //count number of get() calls vs. number of add() calls.
157  //If there are many more get() calls compared with add()
158  //calls (decided by using MAP_THRESHOLD) then mmap the log
159  //file to improve performance.
160  readWriteBalance--;
161  if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
162          map();
163
164  if ( fileMap )
165  {
166    for (int i=0;i<len;i++)
167            bytes[i]=fileMap[loc+i];
168  }
169  else
170  {
171      int rc = 0;
172
173      if (loc < 0 || len < 0 || loc + len > length)
174        fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
175      rc = KDE_lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
176      rc = read(ion,bytes,len);     if (rc < 0) { perror("HistoryFile::get.read"); return; }
177  }
178}
179
180int HistoryFile::len()
181{
182  return length;
183}
184
185
186// History Scroll abstract base class //////////////////////////////////////
187
188
189HistoryScroll::HistoryScroll(HistoryType* t)
190  : m_histType(t)
191{
192}
193
194HistoryScroll::~HistoryScroll()
195{
196  delete m_histType;
197}
198
199bool HistoryScroll::hasScroll()
200{
201  return true;
202}
203
204// History Scroll File //////////////////////////////////////
205
206/*
207   The history scroll makes a Row(Row(Cell)) from
208   two history buffers. The index buffer contains
209   start of line positions which refers to the cells
210   buffer.
211
212   Note that index[0] addresses the second line
213   (line #1), while the first line (line #0) starts
214   at 0 in cells.
215*/
216
217HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
218  : HistoryScroll(new HistoryTypeFile(logFileName)),
219  m_logFileName(logFileName)
220{
221}
222
223HistoryScrollFile::~HistoryScrollFile()
224{
225}
226
227int HistoryScrollFile::getLines()
228{
229  return index.len() / sizeof(int);
230}
231
232int HistoryScrollFile::getLineLen(int lineno)
233{
234  return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
235}
236
237bool HistoryScrollFile::isWrappedLine(int lineno)
238{
239  if (lineno>=0 && lineno <= getLines()) {
240    unsigned char flag;
241    lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
242    return flag;
243  }
244  return false;
245}
246
247int HistoryScrollFile::startOfLine(int lineno)
248{
249  if (lineno <= 0) return 0;
250  if (lineno <= getLines())
251    {
252
253    if (!index.isMapped())
254            index.map();
255
256    int res = 0;
257    index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
258    return res;
259    }
260  return cells.len();
261}
262
263void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
264{
265  cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
266}
267
268void HistoryScrollFile::addCells(const Character text[], int count)
269{
270  cells.add((unsigned char*)text,count*sizeof(Character));
271}
272
273void HistoryScrollFile::addLine(bool previousWrapped)
274{
275  if (index.isMapped())
276          index.unmap();
277
278  int locn = cells.len();
279  index.add((unsigned char*)&locn,sizeof(int));
280  unsigned char flags = previousWrapped ? 0x01 : 0x00;
281  lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
282}
283
284
285// History Scroll Buffer //////////////////////////////////////
286HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
287  : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
288   ,_historyBuffer()
289   ,_maxLineCount(0)
290   ,_usedLines(0)
291   ,_head(0)
292{
293  setMaxNbLines(maxLineCount);
294}
295
296HistoryScrollBuffer::~HistoryScrollBuffer()
297{
298    delete[] _historyBuffer;
299}
300
301void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
302{
303    _head++;
304    if ( _usedLines < _maxLineCount )
305        _usedLines++;
306
307    if ( _head >= _maxLineCount )
308    {
309        _head = 0;
310    }
311
312    _historyBuffer[bufferIndex(_usedLines-1)] = cells;
313    _wrappedLine[bufferIndex(_usedLines-1)] = false;
314}
315void HistoryScrollBuffer::addCells(const Character a[], int count)
316{
317  HistoryLine newLine(count);
318  std::copy(a,a+count,newLine.begin());
319
320  addCellsVector(newLine);
321}
322
323void HistoryScrollBuffer::addLine(bool previousWrapped)
324{
325    _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
326}
327
328int HistoryScrollBuffer::getLines()
329{
330    return _usedLines;
331}
332
333int HistoryScrollBuffer::getLineLen(int lineNumber)
334{
335  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
336
337  if ( lineNumber < _usedLines )
338  {
339    return _historyBuffer[bufferIndex(lineNumber)].size();
340  }
341  else
342  {
343    return 0;
344  }
345}
346
347bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
348{
349  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
350
351  if (lineNumber < _usedLines)
352  {
353    //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
354    return _wrappedLine[bufferIndex(lineNumber)];
355  }
356  else
357    return false;
358}
359
360void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character buffer[])
361{
362  if ( count == 0 ) return;
363
364  Q_ASSERT( lineNumber < _maxLineCount );
365
366  if (lineNumber >= _usedLines)
367  {
368    memset(static_cast<void*>(buffer), 0, count * sizeof(Character));
369    return;
370  }
371
372  const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
373
374  //kDebug() << "startCol " << startColumn;
375  //kDebug() << "line.size() " << line.size();
376  //kDebug() << "count " << count;
377
378  Q_ASSERT( startColumn <= line.size() - count );
379
380  memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
381}
382
383void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
384{
385    HistoryLine* oldBuffer = _historyBuffer;
386    HistoryLine* newBuffer = new HistoryLine[lineCount];
387
388    for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
389    {
390        newBuffer[i] = oldBuffer[bufferIndex(i)];
391    }
392
393    _usedLines = qMin(_usedLines,(int)lineCount);
394    _maxLineCount = lineCount;
395    _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
396
397    _historyBuffer = newBuffer;
398    delete[] oldBuffer;
399
400    _wrappedLine.resize(lineCount);
401    dynamic_cast<HistoryTypeBuffer*>(m_histType)->m_nbLines = lineCount;
402}
403
404int HistoryScrollBuffer::bufferIndex(int lineNumber) const
405{
406    Q_ASSERT( lineNumber >= 0 );
407    Q_ASSERT( lineNumber < _maxLineCount );
408    Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
409
410    if ( _usedLines == _maxLineCount )
411    {
412        return (_head+lineNumber+1) % _maxLineCount;
413    }
414    else
415    {
416        return lineNumber;
417    }
418}
419
420
421// History Scroll None //////////////////////////////////////
422
423HistoryScrollNone::HistoryScrollNone()
424  : HistoryScroll(new HistoryTypeNone())
425{
426}
427
428HistoryScrollNone::~HistoryScrollNone()
429{
430}
431
432bool HistoryScrollNone::hasScroll()
433{
434  return false;
435}
436
437int  HistoryScrollNone::getLines()
438{
439  return 0;
440}
441
442int  HistoryScrollNone::getLineLen(int)
443{
444  return 0;
445}
446
447bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
448{
449  return false;
450}
451
452void HistoryScrollNone::getCells(int, int, int, Character [])
453{
454}
455
456void HistoryScrollNone::addCells(const Character [], int)
457{
458}
459
460void HistoryScrollNone::addLine(bool)
461{
462}
463
464// History Scroll BlockArray //////////////////////////////////////
465
466HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
467  : HistoryScroll(new HistoryTypeBlockArray(size))
468{
469  m_blockArray.setHistorySize(size); // nb. of lines.
470}
471
472HistoryScrollBlockArray::~HistoryScrollBlockArray()
473{
474}
475
476int  HistoryScrollBlockArray::getLines()
477{
478  return m_lineLengths.count();
479}
480
481int  HistoryScrollBlockArray::getLineLen(int lineno)
482{
483    if ( m_lineLengths.contains(lineno) )
484        return m_lineLengths[lineno];
485    else
486        return 0;
487}
488
489bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
490{
491  return false;
492}
493
494void HistoryScrollBlockArray::getCells(int lineno, int colno,
495                                       int count, Character res[])
496{
497  if (!count) return;
498
499  const Block *b = m_blockArray.at(lineno);
500
501  if (!b) {
502    memset(static_cast<void*>(res), 0, count * sizeof(Character)); // still better than random data
503    return;
504  }
505
506  Q_ASSERT(((colno + count) * sizeof(Character)) < ENTRIES);
507  memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
508}
509
510void HistoryScrollBlockArray::addCells(const Character a[], int count)
511{
512  Block *b = m_blockArray.lastBlock();
513
514  if (!b) return;
515
516  // put cells in block's data
517  Q_ASSERT((count * sizeof(Character)) < ENTRIES);
518
519  memset(b->data, 0, sizeof(b->data));
520
521  memcpy(b->data, a, count * sizeof(Character));
522  b->size = count * sizeof(Character);
523
524  size_t res = m_blockArray.newBlock();
525  Q_ASSERT(res > 0);
526  Q_UNUSED( res );
527
528  m_lineLengths.insert(m_blockArray.getCurrent(), count);
529}
530
531void HistoryScrollBlockArray::addLine(bool)
532{
533}
534
535////////////////////////////////////////////////////////////////
536// Compact History Scroll //////////////////////////////////////
537////////////////////////////////////////////////////////////////
538void* CompactHistoryBlock::allocate ( size_t length )
539{
540 Q_ASSERT ( length > 0 );
541  if ( tail-blockStart+length > blockLength )
542    return nullptr;
543
544  void* block = tail;
545  tail += length;
546  //kDebug() << "allocated " << length << " bytes at address " << block;
547  allocCount++;
548  return block;
549}
550
551void CompactHistoryBlock::deallocate ( )
552{
553  allocCount--;
554  Q_ASSERT ( allocCount >= 0 );
555}
556
557void* CompactHistoryBlockList::allocate(size_t size)
558{
559  CompactHistoryBlock* block;
560  if ( list.isEmpty() || list.last()->remaining() < size)
561  {
562    block = new CompactHistoryBlock();
563    list.append ( block );
564    //kDebug() << "new block created, remaining " << block->remaining() << "number of blocks=" << list.size();
565  }
566  else
567  {
568    block = list.last();
569    //kDebug() << "old block used, remaining " << block->remaining();
570  }
571  return block->allocate(size);
572}
573
574void CompactHistoryBlockList::deallocate(void* ptr)
575{
576  Q_ASSERT( !list.isEmpty());
577
578  int i=0;
579  CompactHistoryBlock *block = list.at(i);
580  while ( i<list.size() && !block->contains(ptr) )
581  {
582    i++;
583    block=list.at(i);
584  }
585
586  Q_ASSERT( i<list.size() );
587
588  block->deallocate();
589
590  if (!block->isInUse())
591  {
592    list.removeAt(i);
593    delete block;
594    //kDebug() << "block deleted, new size = " << list.size();
595  }
596}
597
598CompactHistoryBlockList::~CompactHistoryBlockList()
599{
600  qDeleteAll ( list.begin(), list.end() );
601  list.clear();
602}
603
604void* CompactHistoryLine::operator new (size_t size, CompactHistoryBlockList& blockList)
605{
606  return blockList.allocate(size);
607}
608
609CompactHistoryLine::CompactHistoryLine ( const TextLine& line, CompactHistoryBlockList& bList )
610  : blockList(bList),
611    formatLength(0)
612{
613  length=line.size();
614
615  if (!line.empty()) {
616    formatLength=1;
617    int k=1;
618
619    // count number of different formats in this text line
620    Character c = line[0];
621    while ( k<length )
622    {
623      if ( !(line[k].equalsFormat(c)))
624      {
625        formatLength++; // format change detected
626        c=line[k];
627      }
628      k++;
629    }
630
631    //kDebug() << "number of different formats in string: " << formatLength;
632    formatArray = (CharacterFormat*) blockList.allocate(sizeof(CharacterFormat)*formatLength);
633    Q_ASSERT (formatArray!=nullptr);
634    text = (quint16*) blockList.allocate(sizeof(quint16)*line.size());
635    Q_ASSERT (text!=nullptr);
636
637    length=line.size();
638    wrapped=false;
639
640    // record formats and their positions in the format array
641    c=line[0];
642    formatArray[0].setFormat ( c );
643    formatArray[0].startPos=0;                        // there's always at least 1 format (for the entire line, unless a change happens)
644
645    k=1;                                              // look for possible format changes
646    int j=1;
647    while ( k<length && j<formatLength )
648    {
649      if (!(line[k].equalsFormat(c)))
650      {
651        c=line[k];
652        formatArray[j].setFormat(c);
653        formatArray[j].startPos=k;
654        //kDebug() << "format entry " << j << " at pos " << formatArray[j].startPos << " " << &(formatArray[j].startPos) ;
655        j++;
656      }
657      k++;
658    }
659
660    // copy character values
661    for ( int i=0; i<line.size(); i++ )
662    {
663      text[i]=line[i].character;
664      //kDebug() << "char " << i << " at mem " << &(text[i]);
665    }
666  }
667  //kDebug() << "line created, length " << length << " at " << &(length);
668}
669
670CompactHistoryLine::~CompactHistoryLine()
671{
672  //kDebug() << "~CHL";
673  if (length>0) {
674    blockList.deallocate(text);
675    blockList.deallocate(formatArray);
676  }
677  blockList.deallocate(this);
678}
679
680void CompactHistoryLine::getCharacter ( int index, Character &r )
681{
682  Q_ASSERT ( index < length );
683  int formatPos=0;
684  while ( ( formatPos+1 ) < formatLength && index >= formatArray[formatPos+1].startPos )
685    formatPos++;
686
687  r.character=text[index];
688  r.rendition = formatArray[formatPos].rendition;
689  r.foregroundColor = formatArray[formatPos].fgColor;
690  r.backgroundColor = formatArray[formatPos].bgColor;
691}
692
693void CompactHistoryLine::getCharacters ( Character* array, int length, int startColumn )
694{
695  Q_ASSERT ( startColumn >= 0 && length >= 0 );
696  Q_ASSERT ( startColumn+length <= ( int ) getLength() );
697
698  for ( int i=startColumn; i<length+startColumn; i++ )
699  {
700    getCharacter ( i, array[i-startColumn] );
701  }
702}
703
704CompactHistoryScroll::CompactHistoryScroll ( unsigned int maxLineCount )
705    : HistoryScroll ( new CompactHistoryType ( maxLineCount ) )
706    ,lines()
707    ,blockList()
708{
709  //kDebug() << "scroll of length " << maxLineCount << " created";
710  setMaxNbLines ( maxLineCount );
711}
712
713CompactHistoryScroll::~CompactHistoryScroll()
714{
715  qDeleteAll ( lines.begin(), lines.end() );
716  lines.clear();
717}
718
719void CompactHistoryScroll::addCellsVector ( const TextLine& cells )
720{
721  CompactHistoryLine *line;
722  line = new(blockList) CompactHistoryLine ( cells, blockList );
723
724  if ( lines.size() > ( int ) _maxLineCount )
725  {
726    delete lines.takeAt ( 0 );
727  }
728  lines.append ( line );
729}
730
731void CompactHistoryScroll::addCells ( const Character a[], int count )
732{
733  TextLine newLine ( count );
734  std::copy ( a,a+count,newLine.begin() );
735  addCellsVector ( newLine );
736}
737
738void CompactHistoryScroll::addLine ( bool previousWrapped )
739{
740  CompactHistoryLine *line = lines.last();
741  //kDebug() << "last line at address " << line;
742  line->setWrapped(previousWrapped);
743}
744
745int CompactHistoryScroll::getLines()
746{
747  return lines.size();
748}
749
750int CompactHistoryScroll::getLineLen ( int lineNumber )
751{
752  Q_ASSERT ( lineNumber >= 0 && lineNumber < lines.size() );
753  CompactHistoryLine* line = lines[lineNumber];
754  //kDebug() << "request for line at address " << line;
755  return line->getLength();
756}
757
758
759void CompactHistoryScroll::getCells ( int lineNumber, int startColumn, int count, Character buffer[] )
760{
761  if ( count == 0 ) return;
762  Q_ASSERT ( lineNumber < lines.size() );
763  CompactHistoryLine* line = lines[lineNumber];
764  Q_ASSERT ( startColumn >= 0 );
765  Q_ASSERT ( (unsigned int)startColumn <= line->getLength() - count );
766  line->getCharacters ( buffer, count, startColumn );
767}
768
769void CompactHistoryScroll::setMaxNbLines ( unsigned int lineCount )
770{
771  _maxLineCount = lineCount;
772
773  while (lines.size() > (int) lineCount) {
774    delete lines.takeAt(0);
775  }
776  //kDebug() << "set max lines to: " << _maxLineCount;
777}
778
779bool CompactHistoryScroll::isWrappedLine ( int lineNumber )
780{
781  Q_ASSERT ( lineNumber < lines.size() );
782  return lines[lineNumber]->isWrapped();
783}
784
785
786//////////////////////////////////////////////////////////////////////
787// History Types
788//////////////////////////////////////////////////////////////////////
789
790HistoryType::HistoryType()
791{
792}
793
794HistoryType::~HistoryType()
795{
796}
797
798//////////////////////////////
799
800HistoryTypeNone::HistoryTypeNone()
801{
802}
803
804bool HistoryTypeNone::isEnabled() const
805{
806  return false;
807}
808
809HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
810{
811  delete old;
812  return new HistoryScrollNone();
813}
814
815int HistoryTypeNone::maximumLineCount() const
816{
817  return 0;
818}
819
820//////////////////////////////
821
822HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
823  : m_size(size)
824{
825}
826
827bool HistoryTypeBlockArray::isEnabled() const
828{
829  return true;
830}
831
832int HistoryTypeBlockArray::maximumLineCount() const
833{
834  return m_size;
835}
836
837HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
838{
839  delete old;
840  return new HistoryScrollBlockArray(m_size);
841}
842
843
844//////////////////////////////
845
846HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
847  : m_nbLines(nbLines)
848{
849}
850
851bool HistoryTypeBuffer::isEnabled() const
852{
853  return true;
854}
855
856int HistoryTypeBuffer::maximumLineCount() const
857{
858  return m_nbLines;
859}
860
861HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
862{
863  if (old)
864  {
865    HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
866    if (oldBuffer)
867    {
868       oldBuffer->setMaxNbLines(m_nbLines);
869       return oldBuffer;
870    }
871
872    HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
873    int lines = old->getLines();
874    int startLine = 0;
875    if (lines > (int) m_nbLines)
876       startLine = lines - m_nbLines;
877
878    Character line[LINE_SIZE];
879    for(int i = startLine; i < lines; i++)
880    {
881       int size = old->getLineLen(i);
882       if (size > LINE_SIZE)
883       {
884          Character *tmp_line = new Character[size];
885          old->getCells(i, 0, size, tmp_line);
886          newScroll->addCells(tmp_line, size);
887          newScroll->addLine(old->isWrappedLine(i));
888          delete [] tmp_line;
889       }
890       else
891       {
892          old->getCells(i, 0, size, line);
893          newScroll->addCells(line, size);
894          newScroll->addLine(old->isWrappedLine(i));
895       }
896    }
897    delete old;
898    return newScroll;
899  }
900  return new HistoryScrollBuffer(m_nbLines);
901}
902
903//////////////////////////////
904
905HistoryTypeFile::HistoryTypeFile(const QString& fileName)
906  : m_fileName(fileName)
907{
908}
909
910bool HistoryTypeFile::isEnabled() const
911{
912  return true;
913}
914
915const QString& HistoryTypeFile::getFileName() const
916{
917  return m_fileName;
918}
919
920HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
921{
922  if (dynamic_cast<HistoryFile *>(old))
923     return old; // Unchanged.
924
925  HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
926
927  Character line[LINE_SIZE];
928  int lines = (old != nullptr) ? old->getLines() : 0;
929  for(int i = 0; i < lines; i++)
930  {
931     int size = old->getLineLen(i);
932     if (size > LINE_SIZE)
933     {
934        Character *tmp_line = new Character[size];
935        old->getCells(i, 0, size, tmp_line);
936        newScroll->addCells(tmp_line, size);
937        newScroll->addLine(old->isWrappedLine(i));
938        delete [] tmp_line;
939     }
940     else
941     {
942        old->getCells(i, 0, size, line);
943        newScroll->addCells(line, size);
944        newScroll->addLine(old->isWrappedLine(i));
945     }
946  }
947
948  delete old;
949  return newScroll;
950}
951
952int HistoryTypeFile::maximumLineCount() const
953{
954  return 0;
955}
956
957//////////////////////////////
958
959CompactHistoryType::CompactHistoryType ( unsigned int nbLines )
960    : m_nbLines ( nbLines )
961{
962}
963
964bool CompactHistoryType::isEnabled() const
965{
966  return true;
967}
968
969int CompactHistoryType::maximumLineCount() const
970{
971  return m_nbLines;
972}
973
974HistoryScroll* CompactHistoryType::scroll ( HistoryScroll *old ) const
975{
976  if ( old )
977  {
978    CompactHistoryScroll *oldBuffer = dynamic_cast<CompactHistoryScroll*> ( old );
979    if ( oldBuffer )
980    {
981      oldBuffer->setMaxNbLines ( m_nbLines );
982      return oldBuffer;
983    }
984    delete old;
985  }
986  return new CompactHistoryScroll ( m_nbLines );
987}
Note: See TracBrowser for help on using the repository browser.