Warning, file /multimedia/kid3/src/app/cli/standardiohandler.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /** 0002 * \file standardiohandler.cpp 0003 * CLI I/O Handler for standard I/O. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 10 Aug 2013 0008 * 0009 * Copyright (C) 2013-2018 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "standardiohandler.h" 0028 #include "cliconfig.h" 0029 #include <QThread> 0030 #include <QIODevice> 0031 #ifdef Q_OS_WIN32 0032 #include <windows.h> 0033 #else 0034 #include <unistd.h> 0035 #endif 0036 #ifdef HAVE_READLINE 0037 #include <cstdio> 0038 #include <readline/readline.h> 0039 #include <readline/history.h> 0040 #if RL_READLINE_VERSION < 0x0600 0041 #include <cstdlib> 0042 #endif 0043 #else 0044 #include <QTextStream> 0045 #endif 0046 0047 /** 0048 * Constructor. 0049 * @param prompt command line prompt 0050 */ 0051 StandardIOHandler::StandardIOHandler(const char* prompt) 0052 : m_prompt(prompt), m_conInThread(nullptr), 0053 m_cout(stdout, QIODevice::WriteOnly), m_cerr(stderr, QIODevice::WriteOnly) 0054 { 0055 #ifdef Q_OS_WIN32 0056 DWORD mode; 0057 m_consoleMode = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode); 0058 #else 0059 m_consoleMode = isatty(fileno(stdout)); 0060 #endif 0061 } 0062 0063 /** 0064 * Restore terminal on cleanup. 0065 */ 0066 void StandardIOHandler::cleanup() 0067 { 0068 #ifdef HAVE_READLINE 0069 ::rl_cleanup_after_signal(); 0070 #endif 0071 } 0072 0073 /** 0074 * Start processing. 0075 */ 0076 void StandardIOHandler::start() 0077 { 0078 m_conInThread = new QThread; 0079 m_conInThread->setObjectName(QLatin1String("conInThread")); 0080 0081 connect(m_conInThread, &QThread::started, this, &StandardIOHandler::blockingReadLine); 0082 connect(m_conInThread, &QThread::finished, this, &QObject::deleteLater); 0083 connect(m_conInThread, &QThread::finished, m_conInThread, &QObject::deleteLater); 0084 moveToThread(m_conInThread); 0085 0086 m_conInThread->start(); 0087 } 0088 0089 /** 0090 * Stop processing. 0091 */ 0092 void StandardIOHandler::stop() 0093 { 0094 QMetaObject::invokeMethod(m_conInThread, "quit", 0095 Qt::QueuedConnection); 0096 } 0097 0098 /** 0099 * Read the next line. 0100 * This method will asynchronously invoke reading of a line from standard 0101 * input in the read thread. 0102 * When the line is ready, lineReady() is emitted. 0103 */ 0104 void StandardIOHandler::readLine() 0105 { 0106 QMetaObject::invokeMethod(this, "blockingReadLine", 0107 Qt::QueuedConnection); 0108 } 0109 0110 /** 0111 * Read the next line. 0112 */ 0113 void StandardIOHandler::blockingReadLine() 0114 { 0115 if (!m_consoleMode) { 0116 QTextStream stdIn(stdin, QIODevice::ReadOnly); 0117 QString line = stdIn.readLine(); 0118 emit lineReady(line); 0119 return; 0120 } 0121 #ifdef HAVE_READLINE 0122 char* lineRead = ::readline(m_prompt); 0123 if (!lineRead) { 0124 // EOF 0125 emit lineReady(QString()); 0126 return; 0127 } 0128 if (*lineRead) { 0129 ::add_history(lineRead); 0130 } 0131 QString line = QString::fromLocal8Bit(lineRead); 0132 #if RL_READLINE_VERSION >= 0x0600 0133 ::rl_free(lineRead); 0134 #else 0135 ::free(lineRead); 0136 #endif 0137 #elif defined Q_OS_WIN32 0138 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), 0139 m_prompt, qstrlen(m_prompt), 0, 0); 0140 const int numCharsInBuf = 512; 0141 wchar_t buf[numCharsInBuf]; 0142 DWORD numCharsRead; 0143 QString line; 0144 do { 0145 ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), 0146 buf, numCharsInBuf, &numCharsRead, 0); 0147 line += QString::fromWCharArray(buf, numCharsRead); 0148 } while (numCharsRead > 0 && line[line.length() - 1] != QLatin1Char('\n')); 0149 while (line.length() > 0 && 0150 (line[line.length() - 1] == QLatin1Char('\r') || 0151 line[line.length() - 1] == QLatin1Char('\n'))) { 0152 line.truncate(line.length() - 1); 0153 } 0154 #else 0155 QTextStream stdOut(stdout, QIODevice::WriteOnly); 0156 stdOut << m_prompt; 0157 stdOut.flush(); 0158 QTextStream stdIn(stdin, QIODevice::ReadOnly); 0159 QString line = stdIn.readLine(); 0160 #endif 0161 emit lineReady(line); 0162 } 0163 0164 /** 0165 * Write a line to standard output. 0166 * @param line line to write 0167 */ 0168 void StandardIOHandler::writeLine(const QString& line) 0169 { 0170 #ifdef Q_OS_WIN32 0171 if (m_consoleMode) { 0172 QString str = line + QLatin1Char('\n'); 0173 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), 0174 str.utf16(), str.size(), 0, 0); 0175 return; 0176 } 0177 #endif 0178 m_cout << line; 0179 m_cout << QLatin1Char('\n'); 0180 m_cout.flush(); 0181 } 0182 0183 /** 0184 * Write a line to standard error. 0185 * @param line line to write 0186 */ 0187 void StandardIOHandler::writeErrorLine(const QString& line) 0188 { 0189 #ifdef Q_OS_WIN32 0190 if (m_consoleMode) { 0191 QString str = line + QLatin1Char('\n'); 0192 WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), 0193 str.utf16(), str.size(), 0, 0); 0194 return; 0195 } 0196 #endif 0197 m_cerr << line; 0198 m_cerr << QLatin1Char('\n'); 0199 m_cerr.flush(); 0200 } 0201 0202 /** 0203 * Flush the standard output. 0204 */ 0205 void StandardIOHandler::flushStandardOutput() 0206 { 0207 #ifdef Q_OS_WIN32 0208 if (m_consoleMode) { 0209 return; 0210 } 0211 #endif 0212 m_cout.flush(); 0213 }