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