File indexing completed on 2024-04-28 05:48:33

0001 //
0002 // configview.cpp
0003 //
0004 // Description: View for configuring the set of targets to be used with the debugger
0005 //
0006 //
0007 // SPDX-FileCopyrightText: 2010 Kåre Särs <kare.sars@iki.fi>
0008 //
0009 //  SPDX-License-Identifier: LGPL-2.0-only
0010 
0011 #include "ioview.h"
0012 
0013 #include <QDir>
0014 #include <QFontDatabase>
0015 #include <QLineEdit>
0016 #include <QScrollBar>
0017 #include <QSocketNotifier>
0018 #include <QString>
0019 #include <QTextEdit>
0020 #include <QVBoxLayout>
0021 
0022 #include <KColorScheme>
0023 #include <KRandom>
0024 
0025 #include <fcntl.h>
0026 #include <sys/stat.h>
0027 #include <sys/types.h>
0028 #include <unistd.h>
0029 
0030 IOView::IOView(QWidget *parent)
0031     : QWidget(parent)
0032 {
0033     m_output = new QTextEdit();
0034     m_output->setReadOnly(true);
0035     m_output->setUndoRedoEnabled(false);
0036     m_output->setAcceptRichText(false);
0037     // fixed wide font, like konsole
0038     m_output->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
0039     // alternate color scheme, like konsole
0040     KColorScheme schemeView(QPalette::Active, KColorScheme::Complementary);
0041     m_output->setTextBackgroundColor(schemeView.background().color());
0042     m_output->setTextColor(schemeView.foreground().color());
0043     QPalette p = m_output->palette();
0044     p.setColor(QPalette::Base, schemeView.background().color());
0045     m_output->setPalette(p);
0046 
0047     m_input = new QLineEdit();
0048     m_output->setFocusProxy(m_input); // take the focus from the output
0049 
0050     QVBoxLayout *layout = new QVBoxLayout(this);
0051     layout->addWidget(m_output, 10);
0052     layout->addWidget(m_input, 0);
0053     layout->setContentsMargins(0, 0, 0, 0);
0054     layout->setSpacing(0);
0055 
0056     connect(m_input, &QLineEdit::returnPressed, this, &IOView::returnPressed);
0057     createFifos();
0058 }
0059 
0060 IOView::~IOView()
0061 {
0062     m_stdin.close();
0063 
0064     m_stdout.close();
0065     m_stdout.setFileName(m_stdoutFifo);
0066     ::close(m_stdoutFD);
0067 
0068     m_stderr.close();
0069     m_stderr.setFileName(m_stderrFifo);
0070     ::close(m_stderrFD);
0071 
0072     m_stdin.remove();
0073     m_stdout.remove();
0074     m_stderr.remove();
0075 }
0076 
0077 void IOView::createFifos()
0078 {
0079     m_stdinFifo = createFifo(QStringLiteral("stdInFifo"));
0080     m_stdoutFifo = createFifo(QStringLiteral("stdOutFifo"));
0081     m_stderrFifo = createFifo(QStringLiteral("stdErrFifo"));
0082 
0083     m_stdin.setFileName(m_stdinFifo);
0084     if (!m_stdin.open(QIODevice::ReadWrite)) {
0085         return;
0086     }
0087 
0088     m_stdoutD.setFileName(m_stdoutFifo);
0089     m_stdoutD.open(QIODevice::ReadWrite);
0090 
0091     m_stdout.setFileName(m_stdoutFifo);
0092     m_stdoutFD = ::open(m_stdoutFifo.toLocal8Bit().data(), O_RDWR | O_NONBLOCK);
0093     if (m_stdoutFD == -1) {
0094         return;
0095     }
0096     if (!m_stdout.open(m_stdoutFD, QIODevice::ReadWrite)) {
0097         return;
0098     }
0099 
0100     m_stdoutNotifier = new QSocketNotifier(m_stdoutFD, QSocketNotifier::Read, this);
0101     connect(m_stdoutNotifier, &QSocketNotifier::activated, this, &IOView::readOutput);
0102     m_stdoutNotifier->setEnabled(true);
0103 
0104     m_stderrD.setFileName(m_stderrFifo);
0105     m_stderrD.open(QIODevice::ReadWrite);
0106 
0107     m_stderr.setFileName(m_stderrFifo);
0108     m_stderrFD = ::open(m_stderrFifo.toLocal8Bit().data(), O_RDONLY | O_NONBLOCK);
0109     if (m_stderrFD == -1) {
0110         return;
0111     }
0112     if (!m_stderr.open(m_stderrFD, QIODevice::ReadOnly)) {
0113         return;
0114     }
0115 
0116     m_stderrNotifier = new QSocketNotifier(m_stderrFD, QSocketNotifier::Read, this);
0117     connect(m_stderrNotifier, &QSocketNotifier::activated, this, &IOView::readErrors);
0118     m_stderrNotifier->setEnabled(true);
0119 
0120     return;
0121 }
0122 
0123 void IOView::returnPressed()
0124 {
0125     m_stdin.write(m_input->text().toLocal8Bit());
0126     m_stdin.write("\n");
0127     m_stdin.flush();
0128     m_input->clear();
0129 }
0130 
0131 void IOView::readOutput()
0132 {
0133     m_stdoutNotifier->setEnabled(false);
0134     qint64 res;
0135     char chData[256];
0136     QByteArray data;
0137 
0138     do {
0139         res = m_stdout.read(chData, 255);
0140         if (res <= 0) {
0141             m_stdoutD.flush();
0142         } else {
0143             data.append(chData, res);
0144         }
0145 
0146     } while (res == 255);
0147 
0148     if (data.size() > 0) {
0149         Q_EMIT stdOutText(QString::fromLocal8Bit(data));
0150     }
0151     m_stdoutNotifier->setEnabled(true);
0152 }
0153 
0154 void IOView::readErrors()
0155 {
0156     m_stderrNotifier->setEnabled(false);
0157     qint64 res;
0158     char chData[256];
0159     QByteArray data;
0160 
0161     do {
0162         res = m_stderr.read(chData, 255);
0163         if (res <= 0) {
0164             m_stderrD.flush();
0165         } else {
0166             data.append(chData, res);
0167         }
0168     } while (res == 255);
0169 
0170     if (data.size() > 0) {
0171         Q_EMIT stdErrText(QString::fromLocal8Bit(data));
0172     }
0173     m_stderrNotifier->setEnabled(true);
0174 }
0175 
0176 void IOView::addStdOutText(const QString &text)
0177 {
0178     QScrollBar *scrollb = m_output->verticalScrollBar();
0179     if (!scrollb) {
0180         return;
0181     }
0182     bool atEnd = (scrollb->value() == scrollb->maximum());
0183 
0184     QTextCursor cursor = m_output->textCursor();
0185     if (!cursor.atEnd()) {
0186         cursor.movePosition(QTextCursor::End);
0187     }
0188     cursor.insertText(text);
0189 
0190     if (atEnd) {
0191         scrollb->setValue(scrollb->maximum());
0192     }
0193 }
0194 
0195 void IOView::addStdErrText(const QString &text)
0196 {
0197     m_output->setFontItalic(true);
0198     addStdOutText(text);
0199     m_output->setFontItalic(false);
0200 }
0201 
0202 QString IOView::createFifo(const QString &prefix)
0203 {
0204     QString fifo = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + prefix + KRandom::randomString(3);
0205     int result = mkfifo(QFile::encodeName(fifo).data(), 0666);
0206     if (result != 0) {
0207         return QString();
0208     }
0209     return fifo;
0210 }
0211 
0212 const QString IOView::stdinFifo()
0213 {
0214     return m_stdinFifo;
0215 }
0216 const QString IOView::stdoutFifo()
0217 {
0218     return m_stdoutFifo;
0219 }
0220 const QString IOView::stderrFifo()
0221 {
0222     return m_stderrFifo;
0223 }
0224 
0225 void IOView::enableInput(bool enable)
0226 {
0227     m_input->setEnabled(enable);
0228 }
0229 
0230 void IOView::clearOutput()
0231 {
0232     m_output->clear();
0233 }
0234 
0235 #include "moc_ioview.cpp"