Update my email address.
[kdbg.git] / kdbg / ttywnd.cpp
blob89a803547830be9375562ae3eb287ebe070f10c9
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <qsocketnotifier.h>
7 #include <qpopupmenu.h>
8 #include "ttywnd.h"
9 #include <kglobalsettings.h>
10 #include <klocale.h>
12 #include "config.h"
13 #ifdef HAVE_FCNTL_H
14 #include <fcntl.h>
15 #endif
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h> /* open, close, etc. */
18 #endif
19 #ifdef HAVE_SYS_IOCTL_H
20 #include <sys/ioctl.h>
21 #endif
22 #ifdef HAVE_SYS_STAT_H
23 #include <sys/stat.h>
24 #endif
25 #ifdef HAVE_PTY_H
26 #include <pty.h> /* openpty on Linux */
27 #endif
28 #ifdef HAVE_LIBUTIL_H
29 #include <libutil.h> /* openpty on FreeBSD */
30 #endif
31 #ifdef HAVE_UTIL_H /* openpty on NetBSD, OpenBSD */
32 #include <util.h>
33 #endif
34 #include <errno.h>
36 #include "mydebug.h"
39 STTY::STTY() :
40 QObject(),
41 m_masterfd(-1),
42 m_slavefd(-1),
43 m_outNotifier(0)
45 if (findTTY())
47 ::fcntl(m_masterfd, F_SETFL, O_NDELAY);
48 m_outNotifier = new QSocketNotifier(m_masterfd, QSocketNotifier::Read);
49 connect(m_outNotifier, SIGNAL(activated(int)), SLOT(outReceived(int)));
50 } else {
51 m_slavetty = QString();
55 STTY::~STTY()
57 if (m_outNotifier) {
58 ::close(m_masterfd);
59 if (m_slavefd >= 0)
60 ::close(m_slavefd);
61 delete m_outNotifier;
65 bool STTY::findTTY()
67 m_masterfd = -1;
69 #ifdef HAVE_FUNC_OPENPTY
70 /* use glibc2's openpty */
71 if (m_masterfd < 0)
73 if (::openpty(&m_masterfd, &m_slavefd, 0, 0, 0) == 0) {
74 const char* tname = ::ttyname(m_slavefd);
75 if (tname != 0) {
76 m_slavetty = tname;
77 } else {
78 ::close(m_slavefd);
79 ::close(m_masterfd);
80 m_masterfd = m_slavefd = -1;
84 #endif
86 // resort to BSD-style terminals
87 if (m_masterfd < 0)
89 const char* s3;
90 const char* s4;
92 char ptynam[] = "/dev/ptyxx";
93 char ttynam[] = "/dev/ttyxx";
94 static const char ptyc3[] = "pqrstuvwxyzabcde";
95 static const char ptyc4[] = "0123456789abcdef";
97 // Find a master pty that we can open
98 for (s3 = ptyc3; *s3 != 0 && m_masterfd < 0; s3++)
100 for (s4 = ptyc4; *s4 != 0; s4++)
102 ptynam[8] = ttynam[8] = *s3;
103 ptynam[9] = ttynam[9] = *s4;
104 if ((m_masterfd = ::open(ptynam,O_RDWR)) >= 0)
106 if (::geteuid() == 0 || ::access(ttynam,R_OK|W_OK) == 0)
108 m_slavetty = ttynam;
109 break;
111 ::close(m_masterfd);
112 m_masterfd = -1;
118 return m_masterfd >= 0;
121 void STTY::outReceived(int f)
123 for (;;) {
124 char buf[1024];
125 int n = ::read(f, buf, sizeof(buf));
126 if (n < 0) {
127 if (errno != EAGAIN) { /* this is not an error */
128 // ugh! error! somebody disconnect this signal please!
130 break;
132 emit output(buf, n);
133 if (n == 0)
134 break;
140 TTYWindow::TTYWindow(QWidget* parent, const char* name) :
141 QTextEdit(parent, name),
142 m_tty(0),
143 m_hPos(0)
145 setFont(KGlobalSettings::fixedFont());
146 setReadOnly(true);
147 setAutoFormatting(AutoNone);
148 setTextFormat(PlainText);
149 setWordWrap(NoWrap);
152 TTYWindow::~TTYWindow()
154 if (m_tty)
155 deactivate();
159 QString TTYWindow::activate()
161 // allocate a pseudo terminal
162 m_tty = new STTY;
164 QString ttyName = m_tty->slaveTTY();
165 if (ttyName.isEmpty()) {
166 // failed to allocate terminal
167 delete m_tty;
168 m_tty = 0;
169 return QString();
170 } else {
171 connect(m_tty, SIGNAL(output(char*,int)), SLOT(slotAppend(char*,int)));
172 return ttyName;
176 void TTYWindow::deactivate()
178 delete m_tty;
179 m_tty = 0;
183 * Note that it is necessary to track the horizontal position explicitly
184 * since if the user modifies the selected text in the window, the cursor
185 * position changes, too.
187 void TTYWindow::slotAppend(char* buffer, int count)
189 // parse off lines
190 char* start = buffer;
191 while (count > 0) {
192 int len = 0;
193 while (count > 0 && start[len] != '\n' && start[len] != '\r') {
194 --count;
195 ++len;
197 if (len > 0) {
198 QString str = QString::fromLatin1(start, len);
199 // replace text in the last line
200 int para = paragraphs()-1;
201 // this selection is non-empty only after a '\r' that was not
202 // followed by a '\n'
203 setSelection(para, m_hPos, para, m_hPos+len, 1);
204 removeSelectedText(1);
205 insertAt(str, para, m_hPos);
206 m_hPos += len;
207 start += len;
208 len = 0;
210 if (count > 0 && *start == '\r') {
211 ++start;
212 --count;
213 m_hPos = 0;
215 if (count > 0 && *start == '\n') {
216 ++start;
217 --count;
218 append(QString());
219 m_hPos = 0;
224 QPopupMenu* TTYWindow::createPopupMenu(const QPoint& pos)
226 QPopupMenu* menu = QTextEdit::createPopupMenu(pos);
227 menu->insertSeparator();
228 menu->insertItem(i18n("&Clear"), this, SLOT(slotClear()));
229 return menu;
232 void TTYWindow::slotClear()
234 clear();
235 m_hPos = 0;
238 #include "ttywnd.moc"