GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
History.cpp
Go to the documentation of this file.
1/*
2 This file is part of Konsole, an X terminal.
3 Copyright (C) 1997-1998, 2013 by Lars Doelle <lars.doelle@on-line.de>
4
5 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21*/
22
23#include <algorithm>
24
25// Own
26#include "unix/History.h"
27
28// System
29#include <stdlib.h>
30#include <assert.h>
31#include <stdio.h>
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <unistd.h>
35#include <errno.h>
36
37
38// Reasonable line size
39#define LINE_SIZE 1024
40
41/*
42 An arbitrary long scroll.
43
44 One can modify the scroll only by adding either cells
45 or newlines, but access it randomly.
46
47 The model is that of an arbitrary wide typewriter scroll
48 in that the scroll is a serie of lines and each line is
49 a serie of cells with no overwriting permitted.
50
51 The implementation provides arbitrary length and numbers
52 of cells and line/column indexed read access to the scroll
53 at constant costs.
54
55KDE4: Can we use QTemporaryFile here, instead of KTempFile?
56
57FIXME: some complain about the history buffer comsuming the
58 memory of their machines. This problem is critical
59 since the history does not behave gracefully in cases
60 where the memory is used up completely.
61
62 I put in a workaround that should handle it problem
63 now gracefully. I'm not satisfied with the solution.
64
65FIXME: Terminating the history is not properly indicated
66 in the menu. We should throw a signal.
67
68FIXME: There is noticeable decrease in speed, also. Perhaps,
69 there whole feature needs to be revisited therefore.
70 Disadvantage of a more elaborated, say block-oriented
71 scheme with wrap around would be it's complexity.
72*/
73
74//FIXME: tempory replacement for tmpfile
75// this is here one for debugging purpose.
76
77//#define tmpfile xTmpFile
78
79// History File ///////////////////////////////////////////
80
81/*
82 A Row(X) data type which allows adding elements to the end.
83*/
84
86 : ion(-1),
87 length(0),
88 fileMap(nullptr)
89{
90 if (tmpFile.open())
91 {
92 tmpFile.setAutoRemove(true);
93 ion = tmpFile.handle();
94 }
95}
96
98{
99 if (fileMap)
100 unmap();
101}
102
103//TODO: Mapping the entire file in will cause problems if the history file becomes exceedingly large,
104//(ie. larger than available memory). HistoryFile::map() should only map in sections of the file at a time,
105//to avoid this.
107{
108 assert( fileMap == nullptr );
109
110 fileMap = (char*)mmap( nullptr , length , PROT_READ , MAP_PRIVATE , ion , 0 );
111
112 //if mmap'ing fails, fall back to the read-lseek combination
113 if ( fileMap == MAP_FAILED )
114 {
116 fileMap = nullptr;
117 qDebug() << ": mmap'ing history failed. errno = " << errno;
118 }
119}
120
122{
123 int result = munmap( fileMap , length );
124 assert( result == 0 );
125
126 fileMap = nullptr;
127}
128
130{
131 return (fileMap != nullptr);
132}
133
134void HistoryFile::add(const unsigned char* bytes, int len)
135{
136 if ( fileMap )
137 unmap();
138
140
141 int rc = 0;
142
143 rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
144 rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryFile::add.write"); return; }
145 length += rc;
146}
147
148void HistoryFile::get(unsigned char* bytes, int len, int loc)
149{
150 //count number of get() calls vs. number of add() calls.
151 //If there are many more get() calls compared with add()
152 //calls (decided by using MAP_THRESHOLD) then mmap the log
153 //file to improve performance.
156 map();
157
158 if ( fileMap )
159 {
160 for (int i=0;i<len;i++)
161 bytes[i]=fileMap[loc+i];
162 }
163 else
164 {
165 int rc = 0;
166
167 if (loc < 0 || len < 0 || loc + len > length)
168 fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
169 rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
170 rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryFile::get.read"); return; }
171 }
172}
173
175{
176 return length;
177}
178
179
180// History Scroll abstract base class //////////////////////////////////////
181
182
184 : m_histType(t)
185{
186}
187
189{
190 delete m_histType;
191}
192
194{
195 return true;
196}
197
198// History Scroll File //////////////////////////////////////
199
200/*
201 The history scroll makes a Row(Row(Cell)) from
202 two history buffers. The index buffer contains
203 start of line positions which refere to the cells
204 buffer.
205
206 Note that index[0] addresses the second line
207 (line #1), while the first line (line #0) starts
208 at 0 in cells.
209*/
210
211HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
212 : HistoryScroll(new HistoryTypeFile(logFileName)),
213 m_logFileName(logFileName)
214{
215}
216
218{
219}
220
222{
223 return index.len() / sizeof(int);
224}
225
227{
228 return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
229}
230
232{
233 if (lineno>=0 && lineno <= getLines()) {
234 unsigned char flag;
235 lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
236 return flag;
237 }
238 return false;
239}
240
242{
243 if (lineno <= 0) return 0;
244 if (lineno <= getLines())
245 {
246
247 if (!index.isMapped())
248 index.map();
249
250 int res = 0;
251 index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
252 return res;
253 }
254 return cells.len();
255}
256
257void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
258{
259 cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
260}
261
262void HistoryScrollFile::addCells(const Character text[], int count)
263{
264 cells.add((unsigned char*)text,count*sizeof(Character));
265}
266
267void HistoryScrollFile::addLine(bool previousWrapped)
268{
269 if (index.isMapped())
270 index.unmap();
271
272 int locn = cells.len();
273 index.add((unsigned char*)&locn,sizeof(int));
274 unsigned char flags = previousWrapped ? 0x01 : 0x00;
275 lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
276}
277
278
279// History Scroll Buffer //////////////////////////////////////
281 : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
282 ,_historyBuffer()
283 ,_maxLineCount(0)
284 ,_usedLines(0)
285 ,_head(0)
286{
287 setMaxNbLines(maxLineCount);
288}
289
291{
292 delete[] _historyBuffer;
293}
294
295void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
296{
297 _head++;
299 _usedLines++;
300
301 if ( _head >= _maxLineCount )
302 {
303 _head = 0;
304 }
305
308}
309void HistoryScrollBuffer::addCells(const Character a[], int count)
310{
311 HistoryLine newLine(count);
312 std::copy(a,a+count,newLine.begin());
313
314 addCellsVector(newLine);
315}
316
317void HistoryScrollBuffer::addLine(bool previousWrapped)
318{
319 _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
320}
321
323{
324 return _usedLines;
325}
326
328{
329 Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
330
331 if ( lineNumber < _usedLines )
332 {
333 return _historyBuffer[bufferIndex(lineNumber)].size();
334 }
335 else
336 {
337 return 0;
338 }
339}
340
342{
343 Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
344
345 if (lineNumber < _usedLines)
346 {
347 //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
348 return _wrappedLine[bufferIndex(lineNumber)];
349 }
350 else
351 return false;
352}
353
354void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character* buffer)
355{
356 if ( count == 0 ) return;
357
358 Q_ASSERT( lineNumber < _maxLineCount );
359
360 if (lineNumber >= _usedLines)
361 {
362 memset(buffer, 0, count * sizeof(Character));
363 return;
364 }
365
366 const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
367
368 //kDebug() << "startCol " << startColumn;
369 //kDebug() << "line.size() " << line.size();
370 //kDebug() << "count " << count;
371
372 Q_ASSERT( startColumn <= line.size() - count );
373
374 memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
375}
376
377void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
378{
379 HistoryLine* oldBuffer = _historyBuffer;
380 HistoryLine* newBuffer = new HistoryLine[lineCount];
381
382 for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
383 {
384 newBuffer[i] = oldBuffer[bufferIndex(i)];
385 }
386
387 _usedLines = qMin(_usedLines,(int)lineCount);
388 _maxLineCount = lineCount;
389 _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
390
391 _historyBuffer = newBuffer;
392 delete[] oldBuffer;
393
394 _wrappedLine.resize(lineCount);
395}
396
398{
399 Q_ASSERT( lineNumber >= 0 );
400 Q_ASSERT( lineNumber < _maxLineCount );
401 Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
402
403 if ( _usedLines == _maxLineCount )
404 {
405 return (_head+lineNumber+1) % _maxLineCount;
406 }
407 else
408 {
409 return lineNumber;
410 }
411}
412
413
414// History Scroll None //////////////////////////////////////
415
418{
419}
420
422{
423}
424
426{
427 return false;
428}
429
431{
432 return 0;
433}
434
436{
437 return 0;
438}
439
441{
442 return false;
443}
444
446{
447}
448
450{
451}
452
454{
455}
456
457// History Scroll BlockArray //////////////////////////////////////
458
461{
462 m_blockArray.setHistorySize(size); // nb. of lines.
463}
464
466{
467}
468
470{
471 return m_lineLengths.count();
472}
473
475{
476 if ( m_lineLengths.contains(lineno) )
477 return m_lineLengths[lineno];
478 else
479 return 0;
480}
481
483{
484 return false;
485}
486
487void HistoryScrollBlockArray::getCells(int lineno, int colno,
488 int count, Character res[])
489{
490 if (!count) return;
491
492 const Block *b = m_blockArray.at(lineno);
493
494 if (!b) {
495 memset(res, 0, count * sizeof(Character)); // still better than random data
496 return;
497 }
498
499 assert(((colno + count) * sizeof(Character)) < ENTRIES);
500 memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
501}
502
504{
506
507 if (!b) return;
508
509 // put cells in block's data
510 assert((count * sizeof(Character)) < ENTRIES);
511
512 memset(b->data, 0, ENTRIES);
513
514 memcpy(b->data, a, count * sizeof(Character));
515 b->size = count * sizeof(Character);
516
517 size_t res = m_blockArray.newBlock();
518 assert (res > 0);
519 Q_UNUSED( res );
520
521 m_lineLengths.insert(m_blockArray.getCurrent(), count);
522}
523
525{
526}
527
528//////////////////////////////////////////////////////////////////////
529// History Types
530//////////////////////////////////////////////////////////////////////
531
533{
534}
535
537{
538}
539
540//////////////////////////////
541
543{
544}
545
547{
548 return false;
549}
550
552{
553 delete old;
554 return new HistoryScrollNone();
555}
556
558{
559 return 0;
560}
561
562//////////////////////////////
563
565 : m_size(size)
566{
567}
568
570{
571 return true;
572}
573
575{
576 return m_size;
577}
578
580{
581 delete old;
583}
584
585
586//////////////////////////////
587
589 : m_nbLines(nbLines)
590{
591}
592
594{
595 return true;
596}
597
599{
600 return m_nbLines;
601}
602
604{
605 if (old)
606 {
607 HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
608 if (oldBuffer)
609 {
610 oldBuffer->setMaxNbLines(m_nbLines);
611 return oldBuffer;
612 }
613
615 int lines = old->getLines();
616 int startLine = 0;
617 if (lines > (int) m_nbLines)
618 startLine = lines - m_nbLines;
619
620 Character line[LINE_SIZE];
621 for(int i = startLine; i < lines; i++)
622 {
623 int size = old->getLineLen(i);
624 if (size > LINE_SIZE)
625 {
626 Character *tmp_line = new Character[size];
627 old->getCells(i, 0, size, tmp_line);
628 newScroll->addCells(tmp_line, size);
629 newScroll->addLine(old->isWrappedLine(i));
630 delete [] tmp_line;
631 }
632 else
633 {
634 old->getCells(i, 0, size, line);
635 newScroll->addCells(line, size);
636 newScroll->addLine(old->isWrappedLine(i));
637 }
638 }
639 delete old;
640 return newScroll;
641 }
642 return new HistoryScrollBuffer(m_nbLines);
643}
644
645//////////////////////////////
646
647HistoryTypeFile::HistoryTypeFile(const QString& fileName)
648 : m_fileName(fileName)
649{
650}
651
653{
654 return true;
655}
656
657const QString& HistoryTypeFile::getFileName() const
658{
659 return m_fileName;
660}
661
663{
664 if (dynamic_cast<HistoryFile *>(old))
665 return old; // Unchanged.
666
668
669 Character line[LINE_SIZE];
670 int lines = (old != nullptr) ? old->getLines() : 0;
671 for(int i = 0; i < lines; i++)
672 {
673 int size = old->getLineLen(i);
674 if (size > LINE_SIZE)
675 {
676 Character *tmp_line = new Character[size];
677 old->getCells(i, 0, size, tmp_line);
678 newScroll->addCells(tmp_line, size);
679 newScroll->addLine(old->isWrappedLine(i));
680 delete [] tmp_line;
681 }
682 else
683 {
684 old->getCells(i, 0, size, line);
685 newScroll->addCells(line, size);
686 newScroll->addLine(old->isWrappedLine(i));
687 }
688 }
689
690 delete old;
691 return newScroll;
692}
693
695{
696 return 0;
697}
#define ENTRIES
Definition: BlockArray.h:29
#define LINE_SIZE
Definition: History.cpp:39
#define loc(X, Y)
Definition: Screen.cpp:56
#define SEEK_SET
size_t getCurrent() const
Definition: BlockArray.h:97
size_t newBlock()
Definition: BlockArray.cpp:81
const Block * at(size_t index)
gets the block at the index.
Definition: BlockArray.cpp:108
Block * lastBlock() const
Definition: BlockArray.cpp:91
bool setHistorySize(size_t newsize)
reorders blocks as needed.
Definition: BlockArray.cpp:156
A single character in the terminal which consists of a unicode character value, foreground and backgr...
Definition: Character.h:56
void map()
Definition: History.cpp:106
QTemporaryFile tmpFile
Definition: History.h:57
int ion
Definition: History.h:55
virtual ~HistoryFile()
Definition: History.cpp:97
char * fileMap
Definition: History.h:60
static const int MAP_THRESHOLD
Definition: History.h:69
virtual void get(unsigned char *bytes, int len, int loc)
Definition: History.cpp:148
int readWriteBalance
Definition: History.h:66
bool isMapped()
Definition: History.cpp:129
virtual int len()
Definition: History.cpp:174
void unmap()
Definition: History.cpp:121
int length
Definition: History.h:56
virtual void add(const unsigned char *bytes, int len)
Definition: History.cpp:134
HistoryScrollBlockArray(size_t size)
Definition: History.cpp:459
virtual bool isWrappedLine(int lineno)
Definition: History.cpp:482
QHash< int, size_t > m_lineLengths
Definition: History.h:243
virtual int getLines()
Definition: History.cpp:469
virtual ~HistoryScrollBlockArray()
Definition: History.cpp:465
virtual void addCells(const Character a[], int count)
Definition: History.cpp:503
virtual void getCells(int lineno, int colno, int count, Character res[])
Definition: History.cpp:487
virtual int getLineLen(int lineno)
Definition: History.cpp:474
virtual void addLine(bool previousWrapped=false)
Definition: History.cpp:524
BlockArray m_blockArray
Definition: History.h:242
virtual ~HistoryScrollBuffer()
Definition: History.cpp:290
virtual bool isWrappedLine(int lineno)
Definition: History.cpp:341
HistoryLine * _historyBuffer
Definition: History.h:175
QBitArray _wrappedLine
Definition: History.h:176
virtual void getCells(int lineno, int colno, int count, Character res[])
Definition: History.cpp:354
virtual void addCells(const Character a[], int count)
Definition: History.cpp:309
HistoryScrollBuffer(unsigned int maxNbLines=1000)
Definition: History.cpp:280
virtual int getLineLen(int lineno)
Definition: History.cpp:327
void setMaxNbLines(unsigned int nbLines)
Definition: History.cpp:377
int bufferIndex(int lineNumber)
Definition: History.cpp:397
virtual int getLines()
Definition: History.cpp:322
virtual void addCellsVector(const QVector< Character > &cells)
Definition: History.cpp:295
QVector< Character > HistoryLine
Definition: History.h:154
virtual void addLine(bool previousWrapped=false)
Definition: History.cpp:317
virtual bool isWrappedLine(int lineno)
Definition: History.cpp:231
virtual void addLine(bool previousWrapped=false)
Definition: History.cpp:267
virtual ~HistoryScrollFile()
Definition: History.cpp:217
HistoryScrollFile(const QString &logFileName)
Definition: History.cpp:211
virtual int getLineLen(int lineno)
Definition: History.cpp:226
HistoryFile lineflags
Definition: History.h:144
virtual void addCells(const Character a[], int count)
Definition: History.cpp:262
HistoryFile index
Definition: History.h:142
virtual int getLines()
Definition: History.cpp:221
HistoryFile cells
Definition: History.h:143
virtual void getCells(int lineno, int colno, int count, Character res[])
Definition: History.cpp:257
int startOfLine(int lineno)
Definition: History.cpp:241
virtual bool hasScroll()
Definition: History.cpp:425
virtual bool isWrappedLine(int lineno)
Definition: History.cpp:440
virtual int getLineLen(int lineno)
Definition: History.cpp:435
virtual ~HistoryScrollNone()
Definition: History.cpp:421
virtual int getLines()
Definition: History.cpp:430
virtual void addCells(const Character a[], int count)
Definition: History.cpp:449
virtual void getCells(int lineno, int colno, int count, Character res[])
Definition: History.cpp:445
virtual void addLine(bool previousWrapped=false)
Definition: History.cpp:453
virtual void addCells(const Character a[], int count)=0
virtual void addLine(bool previousWrapped=false)=0
virtual bool hasScroll()
Definition: History.cpp:193
virtual int getLines()=0
HistoryType * m_histType
Definition: History.h:115
virtual bool isWrappedLine(int lineno)=0
virtual ~HistoryScroll()
Definition: History.cpp:188
virtual int getLineLen(int lineno)=0
virtual void getCells(int lineno, int colno, int count, Character res[])=0
HistoryScroll(HistoryType *)
Definition: History.cpp:183
HistoryTypeBlockArray(size_t size)
Definition: History.cpp:564
virtual bool isEnabled() const
Returns true if the history is enabled ( can store lines of output ) or false otherwise.
Definition: History.cpp:569
virtual HistoryScroll * scroll(HistoryScroll *) const
Definition: History.cpp:579
virtual int maximumLineCount() const
Returns the maximum number of lines which this history type can store or 0 if the history can store a...
Definition: History.cpp:574
virtual int maximumLineCount() const
Returns the maximum number of lines which this history type can store or 0 if the history can store a...
Definition: History.cpp:598
HistoryTypeBuffer(unsigned int nbLines)
Definition: History.cpp:588
virtual bool isEnabled() const
Returns true if the history is enabled ( can store lines of output ) or false otherwise.
Definition: History.cpp:593
virtual HistoryScroll * scroll(HistoryScroll *) const
Definition: History.cpp:603
unsigned int m_nbLines
Definition: History.h:327
virtual HistoryScroll * scroll(HistoryScroll *) const
Definition: History.cpp:662
virtual const QString & getFileName() const
Definition: History.cpp:657
virtual bool isEnabled() const
Returns true if the history is enabled ( can store lines of output ) or false otherwise.
Definition: History.cpp:652
virtual int maximumLineCount() const
Returns the maximum number of lines which this history type can store or 0 if the history can store a...
Definition: History.cpp:694
QString m_fileName
Definition: History.h:312
HistoryTypeFile(const QString &fileName=QString())
Definition: History.cpp:647
virtual bool isEnabled() const
Returns true if the history is enabled ( can store lines of output ) or false otherwise.
Definition: History.cpp:546
virtual HistoryScroll * scroll(HistoryScroll *) const
Definition: History.cpp:551
virtual int maximumLineCount() const
Returns the maximum number of lines which this history type can store or 0 if the history can store a...
Definition: History.cpp:557
virtual ~HistoryType()
Definition: History.cpp:536
unsigned char data[(((1<< 12) - sizeof(size_t))/sizeof(unsigned char))]
Definition: BlockArray.h:33
size_t size
Definition: BlockArray.h:34
F77_RET_T len
Definition: xerbla.cc:61