Added a primitive guess of the executable's language.
[kdbg.git] / kdbg / ttywnd.cpp
blob5a99efc0e77024d08dc294ccfe2139e458f84134
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 #include <errno.h>
33 #include "mydebug.h"
36 STTY::STTY() :
37 QObject(),
38 m_masterfd(-1),
39 m_slavefd(-1),
40 m_outNotifier(0)
42 if (findTTY())
44 ::fcntl(m_masterfd, F_SETFL, O_NDELAY);
45 m_outNotifier = new QSocketNotifier(m_masterfd, QSocketNotifier::Read);
46 connect(m_outNotifier, SIGNAL(activated(int)), SLOT(outReceived(int)));
47 } else {
48 m_slavetty = QString();
52 STTY::~STTY()
54 if (m_outNotifier) {
55 ::close(m_masterfd);
56 if (m_slavefd >= 0)
57 ::close(m_slavefd);
58 delete m_outNotifier;
62 bool STTY::findTTY()
64 m_masterfd = -1;
66 #ifdef HAVE_FUNC_OPENPTY
67 /* use glibc2's openpty */
68 if (m_masterfd < 0)
70 if (::openpty(&m_masterfd, &m_slavefd, 0, 0, 0) == 0) {
71 const char* tname = ::ttyname(m_slavefd);
72 if (tname != 0) {
73 m_slavetty = tname;
74 } else {
75 ::close(m_slavefd);
76 ::close(m_masterfd);
77 m_masterfd = m_slavefd = -1;
81 #endif
83 // resort to BSD-style terminals
84 if (m_masterfd < 0)
86 const char* s3;
87 const char* s4;
89 char ptynam[] = "/dev/ptyxx";
90 char ttynam[] = "/dev/ttyxx";
91 static const char ptyc3[] = "pqrstuvwxyzabcde";
92 static const char ptyc4[] = "0123456789abcdef";
94 // Find a master pty that we can open
95 for (s3 = ptyc3; *s3 != 0 && m_masterfd < 0; s3++)
97 for (s4 = ptyc4; *s4 != 0; s4++)
99 ptynam[8] = ttynam[8] = *s3;
100 ptynam[9] = ttynam[9] = *s4;
101 if ((m_masterfd = ::open(ptynam,O_RDWR)) >= 0)
103 if (::geteuid() == 0 || ::access(ttynam,R_OK|W_OK) == 0)
105 m_slavetty = ttynam;
106 break;
108 ::close(m_masterfd);
109 m_masterfd = -1;
115 return m_masterfd >= 0;
118 void STTY::outReceived(int f)
120 for (;;) {
121 char buf[1024];
122 int n = ::read(f, buf, sizeof(buf));
123 if (n < 0) {
124 if (errno != EAGAIN) { /* this is not an error */
125 // ugh! error! somebody disconnect this signal please!
126 int e = errno;
127 TRACE(QString().sprintf("error reading tty: %d", e));
129 break;
131 emit output(buf, n);
132 if (n == 0)
133 break;
139 TTYWindow::TTYWindow(QWidget* parent, const char* name) :
140 KTextView(parent, name),
141 m_tty(0)
143 setFont(KGlobalSettings::fixedFont());
144 setFocusPolicy(WheelFocus);
145 clear();
147 // create a context menu
148 m_popmenu = new QPopupMenu;
149 m_popmenu->insertItem(i18n("&Clear"), this, SLOT(clear()));
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;
182 void TTYWindow::slotAppend(char* buffer, int count)
184 // is last line visible?
185 bool bottomVisible = lastRowVisible() == m_texts.size()-1;
187 // parse off lines
188 char* start = buffer;
189 while (count > 0) {
190 int len = 0;
191 while (count > 0 && start[len] != '\n') {
192 --count;
193 ++len;
195 if (len > 0) {
196 QString str = QString::fromLatin1(start, len);
197 // update last line
198 str = m_texts[m_texts.size()-1] + str;
199 replaceLine(m_texts.size()-1, str);
200 start += len;
201 len = 0;
203 if (count > 0 && *start == '\n') {
204 insertLine(QString());
205 ++start;
206 --count;
210 // if last row was visible, scroll down to make it visible again
211 if (bottomVisible)
212 setTopCell(m_texts.size()-1);
215 void TTYWindow::clear()
217 m_texts.setSize(0);
218 m_width = 300; m_height = 14; /* Same as in KTextView::KTextView */
219 insertLine(QString());
222 void TTYWindow::mousePressEvent(QMouseEvent* mouseEvent)
224 // Check if right button was clicked.
225 if (mouseEvent->button() == RightButton)
227 if (m_popmenu->isVisible()) {
228 m_popmenu->hide();
229 } else {
230 m_popmenu->popup(mapToGlobal(mouseEvent->pos()));
232 } else {
233 QWidget::mousePressEvent(mouseEvent);
237 #include "ttywnd.moc"