File indexing completed on 2025-01-19 04:23:27
0001 /* 0002 * This file is a part of QTerminal - http://gitorious.org/qterminal 0003 * 0004 * This file was un-linked from KDE and modified 0005 * by Maxim Bourmistrov <maxim@unixconn.com> 0006 * 0007 */ 0008 0009 /* This file is part of the KDE libraries 0010 0011 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org> 0012 0013 This library is free software; you can redistribute it and/or 0014 modify it under the terms of the GNU Library General Public 0015 License as published by the Free Software Foundation; either 0016 version 2 of the License, or (at your option) any later version. 0017 0018 This library 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 GNU 0021 Library General Public License for more details. 0022 0023 You should have received a copy of the GNU Library General Public License 0024 along with this library; see the file COPYING.LIB. If not, write to 0025 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0026 Boston, MA 02110-1301, USA. 0027 */ 0028 0029 #ifndef kptydev_h 0030 #define kptydev_h 0031 0032 #include "kpty_p.h" 0033 0034 #include <QIODevice> 0035 0036 #define KMAXINT ((int)(~0U >> 1)) 0037 0038 struct KPtyDevicePrivate; 0039 class QSocketNotifier; 0040 0041 #define Q_DECLARE_PRIVATE_MI(Class, SuperClass) \ 0042 inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(SuperClass::d_ptr); } \ 0043 inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(SuperClass::d_ptr); } \ 0044 friend struct Class##Private; 0045 0046 /** 0047 * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc. 0048 */ 0049 class KPtyDevice : public QIODevice, public KPty { 0050 Q_OBJECT 0051 Q_DECLARE_PRIVATE_MI(KPtyDevice, KPty) 0052 0053 public: 0054 0055 /** 0056 * Constructor 0057 */ 0058 KPtyDevice(QObject *parent = 0); 0059 0060 /** 0061 * Destructor: 0062 * 0063 * If the pty is still open, it will be closed. Note, however, that 0064 * an utmp registration is @em not undone. 0065 */ 0066 virtual ~KPtyDevice(); 0067 0068 /** 0069 * Create a pty master/slave pair. 0070 * 0071 * @return true if a pty pair was successfully opened 0072 */ 0073 virtual bool open(OpenMode mode = ReadWrite | Unbuffered); 0074 0075 /** 0076 * Open using an existing pty master. The ownership of the fd 0077 * remains with the caller, i.e., close() will not close the fd. 0078 * 0079 * This is useful if you wish to attach a secondary "controller" to an 0080 * existing pty device such as a terminal widget. 0081 * Note that you will need to use setSuspended() on both devices to 0082 * control which one gets the incoming data from the pty. 0083 * 0084 * @param fd an open pty master file descriptor. 0085 * @param mode the device mode to open the pty with. 0086 * @return true if a pty pair was successfully opened 0087 */ 0088 bool open(int fd, OpenMode mode = ReadWrite | Unbuffered); 0089 0090 /** 0091 * Close the pty master/slave pair. 0092 */ 0093 virtual void close(); 0094 0095 /** 0096 * Sets whether the KPtyDevice monitors the pty for incoming data. 0097 * 0098 * When the KPtyDevice is suspended, it will no longer attempt to buffer 0099 * data that becomes available from the pty and it will not emit any 0100 * Q_SIGNALS. 0101 * 0102 * Do not use on closed ptys. 0103 * After a call to open(), the pty is not suspended. If you need to 0104 * ensure that no data is read, call this function before the main loop 0105 * is entered again (i.e., immediately after opening the pty). 0106 */ 0107 void setSuspended(bool suspended); 0108 0109 /** 0110 * Returns true if the KPtyDevice is not monitoring the pty for incoming 0111 * data. 0112 * 0113 * Do not use on closed ptys. 0114 * 0115 * See setSuspended() 0116 */ 0117 bool isSuspended() const; 0118 0119 /** 0120 * @return always true 0121 */ 0122 virtual bool isSequential() const; 0123 0124 /** 0125 * @reimp 0126 */ 0127 bool canReadLine() const; 0128 0129 /** 0130 * @reimp 0131 */ 0132 bool atEnd() const; 0133 0134 /** 0135 * @reimp 0136 */ 0137 qint64 bytesAvailable() const; 0138 0139 /** 0140 * @reimp 0141 */ 0142 qint64 bytesToWrite() const; 0143 0144 bool waitForBytesWritten(int msecs = -1); 0145 bool waitForReadyRead(int msecs = -1); 0146 0147 0148 Q_SIGNALS: 0149 /** 0150 * Emitted when EOF is read from the PTY. 0151 * 0152 * Data may still remain in the buffers. 0153 */ 0154 void readEof(); 0155 0156 protected: 0157 virtual qint64 readData(char *data, qint64 maxSize); 0158 virtual qint64 readLineData(char *data, qint64 maxSize); 0159 virtual qint64 writeData(const char *data, qint64 maxSize); 0160 0161 private: 0162 Q_PRIVATE_SLOT(d_func(), bool _k_canRead()) 0163 Q_PRIVATE_SLOT(d_func(), bool _k_canWrite()) 0164 }; 0165 0166 ///////////////////////////////////////////////////// 0167 // Helper. Remove when QRingBuffer becomes public. // 0168 ///////////////////////////////////////////////////// 0169 0170 #include <QByteArray> 0171 #include <QLinkedList> 0172 0173 #define CHUNKSIZE 4096 0174 0175 class KRingBuffer 0176 { 0177 public: 0178 KRingBuffer() 0179 { 0180 clear(); 0181 } 0182 0183 void clear() 0184 { 0185 buffers.clear(); 0186 QByteArray tmp; 0187 tmp.resize(CHUNKSIZE); 0188 buffers << tmp; 0189 head = tail = 0; 0190 totalSize = 0; 0191 } 0192 0193 inline bool isEmpty() const 0194 { 0195 return buffers.count() == 1 && !tail; 0196 } 0197 0198 inline int size() const 0199 { 0200 return totalSize; 0201 } 0202 0203 inline int readSize() const 0204 { 0205 return (buffers.count() == 1 ? tail : buffers.first().size()) - head; 0206 } 0207 0208 inline const char *readPointer() const 0209 { 0210 Q_ASSERT(totalSize > 0); 0211 return buffers.first().constData() + head; 0212 } 0213 0214 void free(int bytes) 0215 { 0216 totalSize -= bytes; 0217 Q_ASSERT(totalSize >= 0); 0218 0219 forever { 0220 int nbs = readSize(); 0221 0222 if (bytes < nbs) { 0223 head += bytes; 0224 if (head == tail && buffers.count() == 1) { 0225 buffers.first().resize(CHUNKSIZE); 0226 head = tail = 0; 0227 } 0228 break; 0229 } 0230 0231 bytes -= nbs; 0232 if (buffers.count() == 1) { 0233 buffers.first().resize(CHUNKSIZE); 0234 head = tail = 0; 0235 break; 0236 } 0237 0238 buffers.removeFirst(); 0239 head = 0; 0240 } 0241 } 0242 0243 char *reserve(int bytes) 0244 { 0245 totalSize += bytes; 0246 0247 char *ptr; 0248 if (tail + bytes <= buffers.last().size()) { 0249 ptr = buffers.last().data() + tail; 0250 tail += bytes; 0251 } else { 0252 buffers.last().resize(tail); 0253 QByteArray tmp; 0254 tmp.resize(qMax(CHUNKSIZE, bytes)); 0255 ptr = tmp.data(); 0256 buffers << tmp; 0257 tail = bytes; 0258 } 0259 return ptr; 0260 } 0261 0262 // release a trailing part of the last reservation 0263 inline void unreserve(int bytes) 0264 { 0265 totalSize -= bytes; 0266 tail -= bytes; 0267 } 0268 0269 inline void write(const char *data, int len) 0270 { 0271 memcpy(reserve(len), data, len); 0272 } 0273 0274 // Find the first occurrence of c and return the index after it. 0275 // If c is not found until maxLength, maxLength is returned, provided 0276 // it is smaller than the buffer size. Otherwise -1 is returned. 0277 int indexAfter(char c, int maxLength = KMAXINT) const 0278 { 0279 int index = 0; 0280 int start = head; 0281 QLinkedList<QByteArray>::ConstIterator it = buffers.constBegin(); 0282 forever { 0283 if (!maxLength) 0284 return index; 0285 if (index == size()) 0286 return -1; 0287 const QByteArray &buf = *it; 0288 ++it; 0289 int len = qMin((it == buffers.end() ? tail : buf.size()) - start, 0290 maxLength); 0291 const char *ptr = buf.data() + start; 0292 if (const char *rptr = (const char *)memchr(ptr, c, len)) 0293 return index + (rptr - ptr) + 1; 0294 index += len; 0295 maxLength -= len; 0296 start = 0; 0297 } 0298 } 0299 0300 inline int lineSize(int maxLength = KMAXINT) const 0301 { 0302 return indexAfter('\n', maxLength); 0303 } 0304 0305 inline bool canReadLine() const 0306 { 0307 return lineSize() != -1; 0308 } 0309 0310 int read(char *data, int maxLength) 0311 { 0312 int bytesToRead = qMin(size(), maxLength); 0313 int readSoFar = 0; 0314 while (readSoFar < bytesToRead) { 0315 const char *ptr = readPointer(); 0316 int bs = qMin(bytesToRead - readSoFar, readSize()); 0317 memcpy(data + readSoFar, ptr, bs); 0318 readSoFar += bs; 0319 free(bs); 0320 } 0321 return readSoFar; 0322 } 0323 0324 int readLine(char *data, int maxLength) 0325 { 0326 return read(data, lineSize(qMin(maxLength, size()))); 0327 } 0328 0329 private: 0330 QLinkedList<QByteArray> buffers; 0331 int head, tail; 0332 int totalSize; 0333 }; 0334 0335 struct KPtyDevicePrivate : public KPtyPrivate { 0336 0337 Q_DECLARE_PUBLIC(KPtyDevice) 0338 0339 KPtyDevicePrivate(KPty* parent) : 0340 KPtyPrivate(parent), 0341 emittedReadyRead(false), emittedBytesWritten(false), 0342 readNotifier(0), writeNotifier(0) 0343 { 0344 } 0345 0346 bool _k_canRead(); 0347 bool _k_canWrite(); 0348 0349 bool doWait(int msecs, bool reading); 0350 void finishOpen(QIODevice::OpenMode mode); 0351 0352 bool emittedReadyRead; 0353 bool emittedBytesWritten; 0354 QSocketNotifier *readNotifier; 0355 QSocketNotifier *writeNotifier; 0356 KRingBuffer readBuffer; 0357 KRingBuffer writeBuffer; 0358 }; 0359 0360 #endif 0361