~verzegnassi-stefano/+junk/ubuntu-terminal-app-uitk13

« back to all changes in this revision

Viewing changes to src/plugin/qmltermwidget/qtermwidget/lib/History.cpp

  • Committer: Filippo Scognamiglio
  • Date: 2014-10-25 04:42:31 UTC
  • Revision ID: flscogna@gmail.com-20141025044231-javjhusbqa171127
Initial reboot commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <iostream>
 
26
#include <stdlib.h>
 
27
#include <assert.h>
 
28
#include <stdio.h>
 
29
#include <sys/types.h>
 
30
#include <sys/mman.h>
 
31
#include <unistd.h>
 
32
#include <errno.h>
 
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
 
 
44
using 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
 
 
60
KDE4: Can we use QTemporaryFile here, instead of KTempFile?
 
61
 
 
62
FIXME: some complain about the history buffer comsuming 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
 
 
70
FIXME: Terminating the history is not properly indicated
 
71
       in the menu. We should throw a signal.
 
72
 
 
73
FIXME: 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: tempory 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
 
 
90
HistoryFile::HistoryFile()
 
91
  : ion(-1),
 
92
    length(0),
 
93
    fileMap(0)
 
94
{
 
95
  if (tmpFile.open())
 
96
  { 
 
97
    tmpFile.setAutoRemove(true);
 
98
    ion = tmpFile.handle();
 
99
  }
 
100
}
 
101
 
 
102
HistoryFile::~HistoryFile()
 
103
{
 
104
    if (fileMap)
 
105
        unmap();
 
106
}
 
107
 
 
108
//TODO:  Mapping the entire file in will cause problems if the history file becomes exceedingly large,
 
109
//(ie. larger than available memory).  HistoryFile::map() should only map in sections of the file at a time,
 
110
//to avoid this.
 
111
void HistoryFile::map()
 
112
{
 
113
    assert( fileMap == 0 );
 
114
 
 
115
    fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
 
116
 
 
117
    //if mmap'ing fails, fall back to the read-lseek combination
 
118
    if ( fileMap == MAP_FAILED )
 
119
    {
 
120
            readWriteBalance = 0; 
 
121
            fileMap = 0;
 
122
            qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed.  errno = " << errno;
 
123
    }
 
124
}
 
125
 
 
126
void HistoryFile::unmap()
 
127
{
 
128
    int result = munmap( fileMap , length );
 
129
    assert( result == 0 ); Q_UNUSED( result );
 
130
 
 
131
    fileMap = 0;
 
132
}
 
133
 
 
134
bool HistoryFile::isMapped()
 
135
{
 
136
    return (fileMap != 0);
 
137
}
 
138
 
 
139
void HistoryFile::add(const unsigned char* bytes, int len)
 
140
{
 
141
  if ( fileMap )
 
142
          unmap();
 
143
        
 
144
  readWriteBalance++;
 
145
 
 
146
  int rc = 0;
 
147
 
 
148
  rc = KDE_lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
 
149
  rc = write(ion,bytes,len);       if (rc < 0) { perror("HistoryFile::add.write"); return; }
 
150
  length += rc;
 
151
}
 
152
 
 
153
void HistoryFile::get(unsigned char* bytes, int len, int loc)
 
154
{
 
155
  //count number of get() calls vs. number of add() calls.  
 
156
  //If there are many more get() calls compared with add() 
 
157
  //calls (decided by using MAP_THRESHOLD) then mmap the log
 
158
  //file to improve performance.
 
159
  readWriteBalance--;
 
160
  if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
 
161
          map();
 
162
 
 
163
  if ( fileMap )
 
164
  {
 
165
    for (int i=0;i<len;i++)
 
166
            bytes[i]=fileMap[loc+i];
 
167
  }
 
168
  else
 
169
  {    
 
170
      int rc = 0;
 
171
 
 
172
      if (loc < 0 || len < 0 || loc + len > length)
 
173
        fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
 
174
      rc = KDE_lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
 
175
      rc = read(ion,bytes,len);     if (rc < 0) { perror("HistoryFile::get.read"); return; }
 
176
  }
 
177
}
 
178
 
 
179
int HistoryFile::len()
 
180
{
 
181
  return length;
 
182
}
 
183
 
 
184
 
 
185
// History Scroll abstract base class //////////////////////////////////////
 
186
 
 
187
 
 
188
HistoryScroll::HistoryScroll(HistoryType* t)
 
189
  : m_histType(t)
 
190
{
 
191
}
 
192
 
 
193
HistoryScroll::~HistoryScroll()
 
194
{
 
195
  delete m_histType;
 
196
}
 
197
 
 
198
bool HistoryScroll::hasScroll()
 
199
{
 
200
  return true;
 
201
}
 
202
 
 
203
// History Scroll File //////////////////////////////////////
 
204
 
 
205
/* 
 
206
   The history scroll makes a Row(Row(Cell)) from
 
207
   two history buffers. The index buffer contains
 
208
   start of line positions which refere to the cells
 
209
   buffer.
 
210
 
 
211
   Note that index[0] addresses the second line
 
212
   (line #1), while the first line (line #0) starts
 
213
   at 0 in cells.
 
214
*/
 
215
 
 
216
HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
 
217
  : HistoryScroll(new HistoryTypeFile(logFileName)),
 
218
  m_logFileName(logFileName)
 
219
{
 
220
}
 
221
 
 
222
HistoryScrollFile::~HistoryScrollFile()
 
223
{
 
224
}
 
225
 
 
226
int HistoryScrollFile::getLines()
 
227
{
 
228
  return index.len() / sizeof(int);
 
229
}
 
230
 
 
231
int HistoryScrollFile::getLineLen(int lineno)
 
232
{
 
233
  return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
 
234
}
 
235
 
 
236
bool HistoryScrollFile::isWrappedLine(int lineno)
 
237
{
 
238
  if (lineno>=0 && lineno <= getLines()) {
 
239
    unsigned char flag;
 
240
    lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
 
241
    return flag;
 
242
  }
 
243
  return false;
 
244
}
 
245
 
 
246
int HistoryScrollFile::startOfLine(int lineno)
 
247
{
 
248
  if (lineno <= 0) return 0;
 
249
  if (lineno <= getLines())
 
250
    { 
 
251
    
 
252
    if (!index.isMapped())
 
253
            index.map();
 
254
    
 
255
    int res;
 
256
    index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
 
257
    return res;
 
258
    }
 
259
  return cells.len();
 
260
}
 
261
 
 
262
void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
 
263
{
 
264
  cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
 
265
}
 
266
 
 
267
void HistoryScrollFile::addCells(const Character text[], int count)
 
268
{
 
269
  cells.add((unsigned char*)text,count*sizeof(Character));
 
270
}
 
271
 
 
272
void HistoryScrollFile::addLine(bool previousWrapped)
 
273
{
 
274
  if (index.isMapped())
 
275
          index.unmap();
 
276
 
 
277
  int locn = cells.len();
 
278
  index.add((unsigned char*)&locn,sizeof(int));
 
279
  unsigned char flags = previousWrapped ? 0x01 : 0x00;
 
280
  lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
 
281
}
 
282
 
 
283
 
 
284
// History Scroll Buffer //////////////////////////////////////
 
285
HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
 
286
  : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
 
287
   ,_historyBuffer()
 
288
   ,_maxLineCount(0)
 
289
   ,_usedLines(0)
 
290
   ,_head(0)
 
291
{
 
292
  setMaxNbLines(maxLineCount);
 
293
}
 
294
 
 
295
HistoryScrollBuffer::~HistoryScrollBuffer()
 
296
{
 
297
    delete[] _historyBuffer;
 
298
}
 
299
 
 
300
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
 
301
{
 
302
    _head++;
 
303
    if ( _usedLines < _maxLineCount )
 
304
        _usedLines++;
 
305
 
 
306
    if ( _head >= _maxLineCount )
 
307
    {
 
308
        _head = 0;
 
309
    }
 
310
 
 
311
    _historyBuffer[bufferIndex(_usedLines-1)] = cells;
 
312
    _wrappedLine[bufferIndex(_usedLines-1)] = false;
 
313
}
 
314
void HistoryScrollBuffer::addCells(const Character a[], int count)
 
315
{
 
316
  HistoryLine newLine(count);
 
317
  qCopy(a,a+count,newLine.begin());
 
318
 
 
319
  addCellsVector(newLine);
 
320
}
 
321
 
 
322
void HistoryScrollBuffer::addLine(bool previousWrapped)
 
323
{
 
324
    _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
 
325
}
 
326
 
 
327
int HistoryScrollBuffer::getLines()
 
328
{
 
329
    return _usedLines;
 
330
}
 
331
 
 
332
int HistoryScrollBuffer::getLineLen(int lineNumber)
 
333
{
 
334
  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
 
335
 
 
336
  if ( lineNumber < _usedLines )
 
337
  {
 
338
    return _historyBuffer[bufferIndex(lineNumber)].size();
 
339
  }
 
340
  else
 
341
  {
 
342
    return 0;
 
343
  }
 
344
}
 
345
 
 
346
bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
 
347
{
 
348
  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
 
349
    
 
350
  if (lineNumber < _usedLines)
 
351
  {
 
352
    //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
 
353
    return _wrappedLine[bufferIndex(lineNumber)];
 
354
  }
 
355
  else
 
356
    return false;
 
357
}
 
358
 
 
359
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character buffer[])
 
360
{
 
361
  if ( count == 0 ) return;
 
362
 
 
363
  Q_ASSERT( lineNumber < _maxLineCount );
 
364
 
 
365
  if (lineNumber >= _usedLines) 
 
366
  {
 
367
    memset(buffer, 0, count * sizeof(Character));
 
368
    return;
 
369
  }
 
370
  
 
371
  const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
 
372
 
 
373
  //kDebug() << "startCol " << startColumn;
 
374
  //kDebug() << "line.size() " << line.size();
 
375
  //kDebug() << "count " << count;
 
376
 
 
377
  Q_ASSERT( startColumn <= line.size() - count );
 
378
    
 
379
  memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
 
380
}
 
381
 
 
382
void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
 
383
{
 
384
    HistoryLine* oldBuffer = _historyBuffer;
 
385
    HistoryLine* newBuffer = new HistoryLine[lineCount];
 
386
    
 
387
    for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
 
388
    {
 
389
        newBuffer[i] = oldBuffer[bufferIndex(i)];
 
390
    }
 
391
    
 
392
    _usedLines = qMin(_usedLines,(int)lineCount);
 
393
    _maxLineCount = lineCount;
 
394
    _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
 
395
 
 
396
    _historyBuffer = newBuffer;
 
397
    delete[] oldBuffer;
 
398
 
 
399
    _wrappedLine.resize(lineCount);
 
400
    dynamic_cast<HistoryTypeBuffer*>(m_histType)->m_nbLines = lineCount;
 
401
}
 
402
 
 
403
int HistoryScrollBuffer::bufferIndex(int lineNumber)
 
404
{
 
405
    Q_ASSERT( lineNumber >= 0 );
 
406
    Q_ASSERT( lineNumber < _maxLineCount );
 
407
    Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
 
408
 
 
409
    if ( _usedLines == _maxLineCount )
 
410
    {
 
411
        return (_head+lineNumber+1) % _maxLineCount;
 
412
    }
 
413
    else
 
414
    {   
 
415
        return lineNumber;
 
416
    }
 
417
}
 
418
 
 
419
 
 
420
// History Scroll None //////////////////////////////////////
 
421
 
 
422
HistoryScrollNone::HistoryScrollNone()
 
423
  : HistoryScroll(new HistoryTypeNone())
 
424
{
 
425
}
 
426
 
 
427
HistoryScrollNone::~HistoryScrollNone()
 
428
{
 
429
}
 
430
 
 
431
bool HistoryScrollNone::hasScroll()
 
432
{
 
433
  return false;
 
434
}
 
435
 
 
436
int  HistoryScrollNone::getLines()
 
437
{
 
438
  return 0;
 
439
}
 
440
 
 
441
int  HistoryScrollNone::getLineLen(int)
 
442
{
 
443
  return 0;
 
444
}
 
445
 
 
446
bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
 
447
{
 
448
  return false;
 
449
}
 
450
 
 
451
void HistoryScrollNone::getCells(int, int, int, Character [])
 
452
{
 
453
}
 
454
 
 
455
void HistoryScrollNone::addCells(const Character [], int)
 
456
{
 
457
}
 
458
 
 
459
void HistoryScrollNone::addLine(bool)
 
460
{
 
461
}
 
462
 
 
463
// History Scroll BlockArray //////////////////////////////////////
 
464
 
 
465
HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
 
466
  : HistoryScroll(new HistoryTypeBlockArray(size))
 
467
{
 
468
  m_blockArray.setHistorySize(size); // nb. of lines.
 
469
}
 
470
 
 
471
HistoryScrollBlockArray::~HistoryScrollBlockArray()
 
472
{
 
473
}
 
474
 
 
475
int  HistoryScrollBlockArray::getLines()
 
476
{
 
477
  return m_lineLengths.count();
 
478
}
 
479
 
 
480
int  HistoryScrollBlockArray::getLineLen(int lineno)
 
481
{
 
482
    if ( m_lineLengths.contains(lineno) )
 
483
        return m_lineLengths[lineno];
 
484
    else
 
485
        return 0;
 
486
}
 
487
 
 
488
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
 
489
{
 
490
  return false;
 
491
}
 
492
 
 
493
void HistoryScrollBlockArray::getCells(int lineno, int colno,
 
494
                                       int count, Character res[])
 
495
{
 
496
  if (!count) return;
 
497
 
 
498
  const Block *b = m_blockArray.at(lineno);
 
499
 
 
500
  if (!b) {
 
501
    memset(res, 0, count * sizeof(Character)); // still better than random data
 
502
    return;
 
503
  }
 
504
 
 
505
  assert(((colno + count) * sizeof(Character)) < ENTRIES);
 
506
  memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
 
507
}
 
508
 
 
509
void HistoryScrollBlockArray::addCells(const Character a[], int count)
 
510
{
 
511
  Block *b = m_blockArray.lastBlock();
 
512
  
 
513
  if (!b) return;
 
514
 
 
515
  // put cells in block's data
 
516
  assert((count * sizeof(Character)) < ENTRIES);
 
517
 
 
518
  memset(b->data, 0, ENTRIES);
 
519
 
 
520
  memcpy(b->data, a, count * sizeof(Character));
 
521
  b->size = count * sizeof(Character);
 
522
 
 
523
  size_t res = m_blockArray.newBlock();
 
524
  assert (res > 0);
 
525
  Q_UNUSED( res );
 
526
 
 
527
  m_lineLengths.insert(m_blockArray.getCurrent(), count);
 
528
}
 
529
 
 
530
void HistoryScrollBlockArray::addLine(bool)
 
531
{
 
532
}
 
533
 
 
534
////////////////////////////////////////////////////////////////
 
535
// Compact History Scroll //////////////////////////////////////
 
536
////////////////////////////////////////////////////////////////
 
537
void* CompactHistoryBlock::allocate ( size_t length )
 
538
{
 
539
 Q_ASSERT ( length > 0 );
 
540
  if ( tail-blockStart+length > blockLength )
 
541
    return NULL;
 
542
 
 
543
  void* block = tail;
 
544
  tail += length;
 
545
  //kDebug() << "allocated " << length << " bytes at address " << block;
 
546
  allocCount++;
 
547
  return block;
 
548
}
 
549
 
 
550
void CompactHistoryBlock::deallocate ( )
 
551
{
 
552
  allocCount--;
 
553
  Q_ASSERT ( allocCount >= 0 );
 
554
}
 
555
 
 
556
void* CompactHistoryBlockList::allocate(size_t size)
 
557
{
 
558
  CompactHistoryBlock* block;
 
559
  if ( list.isEmpty() || list.last()->remaining() < size)
 
560
  {
 
561
    block = new CompactHistoryBlock();
 
562
    list.append ( block );
 
563
    //kDebug() << "new block created, remaining " << block->remaining() << "number of blocks=" << list.size();
 
564
  }
 
565
  else
 
566
  {
 
567
    block = list.last();
 
568
    //kDebug() << "old block used, remaining " << block->remaining();
 
569
  }
 
570
  return block->allocate(size);
 
571
}
 
572
 
 
573
void CompactHistoryBlockList::deallocate(void* ptr)
 
574
{
 
575
  Q_ASSERT( !list.isEmpty());
 
576
  
 
577
  int i=0;  
 
578
  CompactHistoryBlock *block = list.at(i);
 
579
  while ( i<list.size() && !block->contains(ptr) )
 
580
  { 
 
581
    i++;
 
582
    block=list.at(i);
 
583
  }
 
584
 
 
585
  Q_ASSERT( i<list.size() );
 
586
  
 
587
  block->deallocate();
 
588
 
 
589
  if (!block->isInUse())
 
590
  {
 
591
    list.removeAt(i);
 
592
    delete block;
 
593
    //kDebug() << "block deleted, new size = " << list.size();
 
594
  }
 
595
}
 
596
 
 
597
CompactHistoryBlockList::~CompactHistoryBlockList()
 
598
{
 
599
  qDeleteAll ( list.begin(), list.end() );
 
600
  list.clear();
 
601
}
 
602
 
 
603
void* CompactHistoryLine::operator new (size_t size, CompactHistoryBlockList& blockList)
 
604
{
 
605
  return blockList.allocate(size);
 
606
}
 
607
 
 
608
CompactHistoryLine::CompactHistoryLine ( const TextLine& line, CompactHistoryBlockList& bList ) 
 
609
  : blockList(bList),
 
610
    formatLength(0)
 
611
{
 
612
  length=line.size();
 
613
      
 
614
  if (line.size() > 0) {
 
615
    formatLength=1;
 
616
    int k=1;
 
617
  
 
618
    // count number of different formats in this text line
 
619
    Character c = line[0];
 
620
    while ( k<length )
 
621
    {
 
622
      if ( !(line[k].equalsFormat(c)))
 
623
      {
 
624
        formatLength++; // format change detected
 
625
        c=line[k];
 
626
      }
 
627
      k++;
 
628
    }
 
629
  
 
630
    //kDebug() << "number of different formats in string: " << formatLength;
 
631
    formatArray = (CharacterFormat*) blockList.allocate(sizeof(CharacterFormat)*formatLength);
 
632
    Q_ASSERT (formatArray!=NULL);
 
633
    text = (quint16*) blockList.allocate(sizeof(quint16)*line.size());
 
634
    Q_ASSERT (text!=NULL);
 
635
  
 
636
    length=line.size();
 
637
    formatLength=formatLength;
 
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
 
 
670
CompactHistoryLine::~CompactHistoryLine()
 
671
{
 
672
  //kDebug() << "~CHL";
 
673
  if (length>0) {
 
674
    blockList.deallocate(text);
 
675
    blockList.deallocate(formatArray);
 
676
  }
 
677
  blockList.deallocate(this);  
 
678
}
 
679
 
 
680
void 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
 
 
693
void 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
 
 
704
CompactHistoryScroll::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
 
 
713
CompactHistoryScroll::~CompactHistoryScroll()
 
714
{
 
715
  qDeleteAll ( lines.begin(), lines.end() );
 
716
  lines.clear();
 
717
}
 
718
 
 
719
void 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
 
 
731
void CompactHistoryScroll::addCells ( const Character a[], int count )
 
732
{
 
733
  TextLine newLine ( count );
 
734
  qCopy ( a,a+count,newLine.begin() );
 
735
  addCellsVector ( newLine );
 
736
}
 
737
 
 
738
void CompactHistoryScroll::addLine ( bool previousWrapped )
 
739
{
 
740
  CompactHistoryLine *line = lines.last();
 
741
  //kDebug() << "last line at address " << line;
 
742
  line->setWrapped(previousWrapped);
 
743
}
 
744
 
 
745
int CompactHistoryScroll::getLines()
 
746
{
 
747
  return lines.size();
 
748
}
 
749
 
 
750
int 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
 
 
759
void 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
 
 
769
void 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
 
 
779
bool 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
 
 
790
HistoryType::HistoryType()
 
791
{
 
792
}
 
793
 
 
794
HistoryType::~HistoryType()
 
795
{
 
796
}
 
797
 
 
798
//////////////////////////////
 
799
 
 
800
HistoryTypeNone::HistoryTypeNone()
 
801
{
 
802
}
 
803
 
 
804
bool HistoryTypeNone::isEnabled() const
 
805
{
 
806
  return false;
 
807
}
 
808
 
 
809
HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
 
810
{
 
811
  delete old;
 
812
  return new HistoryScrollNone();
 
813
}
 
814
 
 
815
int HistoryTypeNone::maximumLineCount() const
 
816
{
 
817
  return 0;
 
818
}
 
819
 
 
820
//////////////////////////////
 
821
 
 
822
HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
 
823
  : m_size(size)
 
824
{
 
825
}
 
826
 
 
827
bool HistoryTypeBlockArray::isEnabled() const
 
828
{
 
829
  return true;
 
830
}
 
831
 
 
832
int HistoryTypeBlockArray::maximumLineCount() const
 
833
{
 
834
  return m_size;
 
835
}
 
836
 
 
837
HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
 
838
{
 
839
  delete old;
 
840
  return new HistoryScrollBlockArray(m_size);
 
841
}
 
842
 
 
843
 
 
844
//////////////////////////////
 
845
 
 
846
HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
 
847
  : m_nbLines(nbLines)
 
848
{
 
849
}
 
850
 
 
851
bool HistoryTypeBuffer::isEnabled() const
 
852
{
 
853
  return true;
 
854
}
 
855
 
 
856
int HistoryTypeBuffer::maximumLineCount() const
 
857
{
 
858
  return m_nbLines;
 
859
}
 
860
 
 
861
HistoryScroll* 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
 
 
905
HistoryTypeFile::HistoryTypeFile(const QString& fileName)
 
906
  : m_fileName(fileName)
 
907
{
 
908
}
 
909
 
 
910
bool HistoryTypeFile::isEnabled() const
 
911
{
 
912
  return true;
 
913
}
 
914
 
 
915
const QString& HistoryTypeFile::getFileName() const
 
916
{
 
917
  return m_fileName;
 
918
}
 
919
 
 
920
HistoryScroll* 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 != 0) ? 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
 
 
952
int HistoryTypeFile::maximumLineCount() const
 
953
{
 
954
  return 0;
 
955
}
 
956
 
 
957
//////////////////////////////
 
958
 
 
959
CompactHistoryType::CompactHistoryType ( unsigned int nbLines )
 
960
    : m_nbLines ( nbLines )
 
961
{
 
962
}
 
963
 
 
964
bool CompactHistoryType::isEnabled() const
 
965
{
 
966
  return true;
 
967
}
 
968
 
 
969
int CompactHistoryType::maximumLineCount() const
 
970
{
 
971
  return m_nbLines;
 
972
}
 
973
 
 
974
HistoryScroll* 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
}