comparison gui/src/terminal/KPtyDevice.h @ 13647:ac3d9480292d

Renamed file.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Tue, 23 Aug 2011 18:22:27 +0200
parents gui/src/terminal/kptydevice.h@2e1f54803758
children 9b74f97919e1
comparison
equal deleted inserted replaced
13646:2e1f54803758 13647:ac3d9480292d
1 /* This file is part of the KDE libraries
2
3 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 #ifndef kptydev_h
22 #define kptydev_h
23
24 struct KPtyDevicePrivate;
25
26 #include "KPty.h"
27 #include <QtCore/QIODevice>
28 #include <QSocketNotifier>
29
30 #define Q_DECLARE_PRIVATE_MI(Class, SuperClass) \
31 inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(SuperClass::d_ptr); } \
32 inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(SuperClass::d_ptr); } \
33 friend class Class##Private;
34
35 /**
36 * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc.
37 */
38 class KPtyDevice:public QIODevice, public KPty
39 {
40 Q_OBJECT Q_DECLARE_PRIVATE_MI (KPtyDevice, KPty) public:
41
42 /**
43 * Constructor
44 */
45 KPtyDevice (QObject * parent = 0);
46
47 /**
48 * Destructor:
49 *
50 * If the pty is still open, it will be closed. Note, however, that
51 * an utmp registration is @em not undone.
52 */
53 virtual ~ KPtyDevice ();
54
55 /**
56 * Create a pty master/slave pair.
57 *
58 * @return true if a pty pair was successfully opened
59 */
60 virtual bool open (OpenMode mode = ReadWrite | Unbuffered);
61
62 /**
63 * Open using an existing pty master. The ownership of the fd
64 * remains with the caller, i.e., close() will not close the fd.
65 *
66 * This is useful if you wish to attach a secondary "controller" to an
67 * existing pty device such as a terminal widget.
68 * Note that you will need to use setSuspended() on both devices to
69 * control which one gets the incoming data from the pty.
70 *
71 * @param fd an open pty master file descriptor.
72 * @param mode the device mode to open the pty with.
73 * @return true if a pty pair was successfully opened
74 */
75 bool open (int fd, OpenMode mode = ReadWrite | Unbuffered);
76
77 /**
78 * Close the pty master/slave pair.
79 */
80 virtual void close ();
81
82 /**
83 * @reimp
84 */
85 bool canReadLine () const;
86
87 /**
88 * @reimp
89 */
90 bool atEnd () const;
91
92 /**
93 * @reimp
94 */
95 qint64 bytesAvailable () const;
96
97 /**
98 * @reimp
99 */
100 qint64 bytesToWrite () const;
101
102 protected:
103 virtual qint64 readData (char *data, qint64 maxSize);
104 virtual qint64 readLineData (char *data, qint64 maxSize);
105 virtual qint64 writeData (const char *data, qint64 maxSize);
106
107 private:
108 Q_PRIVATE_SLOT (d_func (), bool _k_canRead ())
109 Q_PRIVATE_SLOT (d_func (), bool _k_canWrite ())};
110
111 #define KMAXINT ((int)(~0U >> 1))
112
113 /////////////////////////////////////////////////////
114 // Helper. Remove when QRingBuffer becomes public. //
115 /////////////////////////////////////////////////////
116
117 #include <QtCore/qbytearray.h>
118 #include <QtCore/qlinkedlist.h>
119
120 #define CHUNKSIZE 4096
121
122 class KRingBuffer
123 {
124 public:
125 KRingBuffer ()
126 {
127 clear ();
128 }
129
130 void clear ()
131 {
132 buffers.clear ();
133 QByteArray tmp;
134 tmp.resize (CHUNKSIZE);
135 buffers << tmp;
136 head = tail = 0;
137 totalSize = 0;
138 }
139
140 inline bool isEmpty () const
141 {
142 return buffers.count () == 1 && !tail;
143 }
144
145 inline int size () const
146 {
147 return totalSize;
148 }
149
150 inline int readSize () const
151 {
152 return (buffers.count () == 1 ? tail : buffers.first ().size ()) - head;
153 }
154
155 inline const char *readPointer () const
156 {
157 Q_ASSERT (totalSize > 0);
158 return buffers.first ().constData () + head;
159 }
160
161 void free (int bytes)
162 {
163 totalSize -= bytes;
164 Q_ASSERT (totalSize >= 0);
165
166 forever
167 {
168 int nbs = readSize ();
169
170 if (bytes < nbs)
171 {
172 head += bytes;
173 if (head == tail && buffers.count () == 1)
174 {
175 buffers.first ().resize (CHUNKSIZE);
176 head = tail = 0;
177 }
178 break;
179 }
180
181 bytes -= nbs;
182 if (buffers.count () == 1)
183 {
184 buffers.first ().resize (CHUNKSIZE);
185 head = tail = 0;
186 break;
187 }
188
189 buffers.removeFirst ();
190 head = 0;
191 }
192 }
193
194 char *reserve (int bytes)
195 {
196 totalSize += bytes;
197
198 char *ptr;
199 if (tail + bytes <= buffers.last ().size ())
200 {
201 ptr = buffers.last ().data () + tail;
202 tail += bytes;
203 }
204 else
205 {
206 buffers.last ().resize (tail);
207 QByteArray tmp;
208 tmp.resize (qMax (CHUNKSIZE, bytes));
209 ptr = tmp.data ();
210 buffers << tmp;
211 tail = bytes;
212 }
213 return ptr;
214 }
215
216 // release a trailing part of the last reservation
217 inline void unreserve (int bytes)
218 {
219 totalSize -= bytes;
220 tail -= bytes;
221 }
222
223 inline void write (const char *data, int len)
224 {
225 memcpy (reserve (len), data, len);
226 }
227
228 // Find the first occurrence of c and return the index after it.
229 // If c is not found until maxLength, maxLength is returned, provided
230 // it is smaller than the buffer size. Otherwise -1 is returned.
231 int indexAfter (char c, int maxLength = KMAXINT) const
232 {
233 int index = 0;
234 int start = head;
235 QLinkedList < QByteArray >::ConstIterator it = buffers.begin ();
236 forever
237 {
238 if (!maxLength)
239 return index;
240 if (index == size ())
241 return -1;
242 const QByteArray & buf = *it;
243 ++it;
244 int len = qMin ((it == buffers.end ()? tail : buf.size ()) - start,
245 maxLength);
246 const char *ptr = buf.data () + start;
247 if (const char *rptr = (const char *)memchr (ptr, c, len))
248 return index + (rptr - ptr) + 1;
249 index += len;
250 maxLength -= len;
251 start = 0;
252 }
253 }
254
255 inline int lineSize (int maxLength = KMAXINT) const
256 {
257 return indexAfter ('\n', maxLength);
258 }
259
260 inline bool canReadLine () const
261 {
262 return lineSize () != -1;
263 }
264
265 int read (char *data, int maxLength)
266 {
267 int bytesToRead = qMin (size (), maxLength);
268 int readSoFar = 0;
269 while (readSoFar < bytesToRead)
270 {
271 const char *ptr = readPointer ();
272 int bs = qMin (bytesToRead - readSoFar, readSize ());
273 memcpy (data + readSoFar, ptr, bs);
274 readSoFar += bs;
275 free (bs);
276 }
277 return readSoFar;
278 }
279
280 int readLine (char *data, int maxLength)
281 {
282 return read (data, lineSize (qMin (maxLength, size ())));
283 }
284
285 private:
286 QLinkedList < QByteArray > buffers;
287 int head, tail;
288 int totalSize;
289 };
290
291 struct KPtyDevicePrivate:public KPtyPrivate
292 {
293 Q_DECLARE_PUBLIC (KPtyDevice)
294 KPtyDevicePrivate (KPty * parent):KPtyPrivate (parent),
295 emittedReadyRead (false), emittedBytesWritten (false),
296 readNotifier (0), writeNotifier (0)
297 {
298 }
299
300 bool _k_canRead ();
301 bool _k_canWrite ();
302
303 bool doWait (int msecs, bool reading);
304 void finishOpen (QIODevice::OpenMode mode);
305
306 bool emittedReadyRead;
307 bool emittedBytesWritten;
308 QSocketNotifier *readNotifier;
309 QSocketNotifier *writeNotifier;
310 KRingBuffer readBuffer;
311 KRingBuffer writeBuffer;
312 };
313
314 #endif