[companion] Adjust GVAR not possible in global functions (fix #5425)
[opentx.git] / companion / src / simulation / filteredtextbuffer.cpp
blob61d30d911e93e4bfd17d663904ef6b10595d4970
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "filteredtextbuffer.h"
23 #include <QDebug>
24 #include <QElapsedTimer>
28 * FIFOBufferDevice
32 FIFOBufferDevice::FIFOBufferDevice(QObject * parent) :
33 QBuffer(parent),
34 m_dataBufferMaxSize(20 * 1024),
35 m_hasOverflow(false)
39 qint64 FIFOBufferDevice::getDataBufferMaxSize() const
41 return m_dataBufferMaxSize;
44 void FIFOBufferDevice::setDataBufferMaxSize(qint64 size)
46 if (m_dataBufferMaxSize > size)
47 trimData(m_dataBufferMaxSize - size);
49 m_dataBufferMaxSize = size;
52 // Remove data from beginning of storage array.
53 // NOT thread-safe, lock data before use (this avoids needing a recursive mutex)
54 qint64 FIFOBufferDevice::trimData(qint64 len)
56 if (!isWritable())
57 return 0;
59 qint64 count = 0;
60 if (len > 0) {
61 count = qMin(len, (qint64)buffer().size());
62 buffer().remove(0, count);
63 seek(0);
65 return count;
68 qint64 FIFOBufferDevice::writeData(const char * data, qint64 len)
70 if (!isWritable())
71 return -1;
73 QWriteLocker locker(&m_dataRWLock);
75 // Handle overflow
76 if (size() + len > m_dataBufferMaxSize) {
77 m_hasOverflow = true;
78 qint64 tlen = trimData(size() + len - m_dataBufferMaxSize);
79 emit bufferOverflow(tlen);
81 else if (m_hasOverflow) {
82 m_hasOverflow = false;
83 emit bufferOverflow(0);
86 // Always write to end of stream.
87 if (!seek(size()))
88 return -1;
90 // Save the data
91 len = QBuffer::writeData(data, len);
92 // Make sure we're always ready for reading, this makes bytesAvailable() (et.al.) return correct result.
93 seek(0);
95 return len;
98 qint64 FIFOBufferDevice::readData(char * data, qint64 len)
100 if (!isReadable())
101 return 0;
103 // Do not block
104 if (m_dataRWLock.tryLockForRead()) {
105 // Always take data from top
106 if (seek(0)) {
107 len = QBuffer::readData(data, len);
108 trimData(len);
110 m_dataRWLock.unlock();
113 return len;
116 qint64 FIFOBufferDevice::readLine(char * data, qint64 maxSize)
118 m_dataRWLock.lockForRead();
119 qint64 len = buffer().indexOf('\n', 0);
120 m_dataRWLock.unlock();
122 if (len < 0 || maxSize <= 0)
123 return 0;
125 ++len;
126 len = qMin(len, maxSize);
127 return readData(data, len);
130 QByteArray FIFOBufferDevice::readLine(qint64 maxSize)
132 QByteArray ba;
133 m_dataRWLock.lockForRead();
134 qint64 len = buffer().indexOf('\n', 0);
135 m_dataRWLock.unlock();
137 if (len < 0)
138 return ba;
140 ++len;
141 if (maxSize > 0)
142 len = qMin(len, maxSize);
144 ba.fill(0, len);
145 len = readData(ba.data(), len);
147 if (len < 0)
148 len = 0;
149 if (len < ba.size())
150 ba.resize(len);
152 return ba;
158 * FilteredTextBuffer
162 FilteredTextBuffer::FilteredTextBuffer(QObject * parent) :
163 FIFOBufferDevice(parent),
164 m_inBuffer(new FIFOBufferDevice(this)),
165 m_bufferFlushTimer(new QTimer(this)),
166 m_lineFilter(QRegularExpression()),
167 m_inBuffMaxSize(5 * 1024),
168 m_inBuffFlushTimeout(1500),
169 m_lineFilterEnable(false),
170 m_lineFilterExclusive(false)
172 m_bufferFlushTimer->setSingleShot(true);
173 setInputBufferMaxSize(m_inBuffMaxSize);
174 setInputBufferTimeout(m_inBuffFlushTimeout);
176 connect(m_inBuffer, &FIFOBufferDevice::readyRead, this, &FilteredTextBuffer::processInputBuffer, Qt::QueuedConnection);
177 connect(m_inBuffer, &FIFOBufferDevice::bytesWritten, this, &FilteredTextBuffer::onInputBufferWrite, Qt::QueuedConnection);
178 connect(m_inBuffer, &FIFOBufferDevice::bufferOverflow, this, &FilteredTextBuffer::onInputBufferOverflow, Qt::QueuedConnection);
179 connect(m_bufferFlushTimer, &QTimer::timeout, this, &FilteredTextBuffer::processInputBuffer);
180 connect(this, &FilteredTextBuffer::timerStart, m_bufferFlushTimer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
181 connect(this, &FilteredTextBuffer::timerStop, m_bufferFlushTimer, &QTimer::stop);
184 FilteredTextBuffer::~FilteredTextBuffer()
186 if (m_bufferFlushTimer) {
187 disconnect(m_bufferFlushTimer, 0, this, 0);
188 disconnect(this, 0, m_bufferFlushTimer, 0);
189 m_bufferFlushTimer->deleteLater();
190 m_bufferFlushTimer = Q_NULLPTR;
192 if (m_inBuffer) {
193 closeInputBuffer();
194 disconnect(m_inBuffer, 0, this, 0);
195 m_inBuffer->deleteLater();
196 m_inBuffer = Q_NULLPTR;
200 qint64 FilteredTextBuffer::getInputBufferMaxSize() const
202 return m_inBuffMaxSize;
205 quint32 FilteredTextBuffer::getInputBufferTimeout() const
207 return m_inBuffFlushTimeout;
210 void FilteredTextBuffer::setInputBufferMaxSize(qint64 size)
212 m_inBuffMaxSize = size;
213 if (m_inBuffer)
214 m_inBuffer->setDataBufferMaxSize(size);
217 void FilteredTextBuffer::setInputBufferTimeout(quint32 ms)
219 m_inBuffFlushTimeout = ms;
220 if (m_bufferFlushTimer)
221 m_bufferFlushTimer->setInterval(ms);
224 void FilteredTextBuffer::setLineFilterExpr(const QRegularExpression & expr)
226 if (expr.isValid())
227 m_lineFilter = expr;
228 else
229 setLineFilterEnabled(false);
232 void FilteredTextBuffer::setLineFilterEnabled(bool enable)
234 if (!enable && m_lineFilterEnable)
235 closeInputBuffer();
237 m_lineFilterEnable = enable;
240 void FilteredTextBuffer::setLineFilterExclusive(bool exclusive)
242 m_lineFilterExclusive = exclusive;
245 void FilteredTextBuffer::setLineFilter(bool enable, bool exclusive, const QRegularExpression & expr)
247 setLineFilterEnabled(enable);
248 setLineFilterExclusive(exclusive);
249 setLineFilterExpr(expr);
252 qint64 FilteredTextBuffer::writeDataSuper(const char * data, qint64 len)
254 if (len == -1)
255 len = qstrlen(data);
257 return FIFOBufferDevice::writeData(data, len);
260 qint64 FilteredTextBuffer::writeData(const char * data, qint64 len)
262 if (!isWritable())
263 return -1;
265 // if filter is disabled, invalid, or input buffer failure, write directly to output buffer
266 if (!m_lineFilterEnable || !m_inBuffer || len > m_inBuffMaxSize || (!m_inBuffer->isOpen() && !openInputBuffer()))
267 return writeDataSuper(data, len);
269 // check for input buffer overflow
270 if (m_inBuffer->bytesAvailable() + len > m_inBuffMaxSize) {
271 flushInputBuffer();
272 onInputBufferOverflow(m_inBuffer->bytesAvailable() + len - m_inBuffMaxSize);
275 return m_inBuffer->write(data, len);
278 void FilteredTextBuffer::flushInputBuffer()
280 emit timerStop();
282 if (m_inBuffer && m_inBuffer->bytesAvailable()) {
283 // qDebug() << "Flushing input buffer.";
284 writeDataSuper(m_inBuffer->readAll().constData());
288 void FilteredTextBuffer::closeInputBuffer()
290 if (!m_inBuffer || !m_inBuffer->isOpen())
291 return;
293 flushInputBuffer();
294 m_inBuffer->close();
297 bool FilteredTextBuffer::openInputBuffer()
299 if (m_inBuffer && m_inBuffer->isOpen())
300 closeInputBuffer();
302 return m_inBuffer->open(ReadWrite);
305 void FilteredTextBuffer::processInputBuffer()
307 if (m_lineFilterEnable && m_inBuffer && m_inBuffer->canReadLine()) {
308 emit timerStop();
309 while (m_inBuffer && m_inBuffer->canReadLine()) {
310 QByteArray text = m_inBuffer->readLine();
311 bool fltMatch = QString(text).contains(m_lineFilter);
312 // check line against filter
313 if ((m_lineFilterExclusive && !fltMatch) || (!m_lineFilterExclusive && fltMatch)) {
314 // Write line to output buffer
315 writeDataSuper(text.constData());
318 // restart timer if unread bytes still remain
319 if (m_inBuffer && m_inBuffer->bytesAvailable() > 0)
320 emit timerStart();
322 else if (!m_lineFilterEnable || !m_inBuffer) {
323 closeInputBuffer();
325 else if (m_bufferFlushTimer && !m_bufferFlushTimer->remainingTime()) {
326 flushInputBuffer();
327 //qDebug() << "Input buffer timeout.";
330 void FilteredTextBuffer::onInputBufferWrite(qint64)
332 emit timerStart();
335 void FilteredTextBuffer::onInputBufferOverflow(const qint64 len)
337 static QElapsedTimer reportTimer;
339 if (len <= 0) {
340 reportTimer.invalidate();
342 else if (!reportTimer.isValid() || reportTimer.elapsed() > 1000 * 15) {
343 qWarning("Input data buffer overflow by %lld bytes!", len);
344 reportTimer.start();