source: trunk/tools/neercs/term/pty.cpp @ 2090

Last change on this file since 2090 was 2090, checked in by sam, 7 years ago

neercs: added a better check for forkpty(), and moved the GL_POINTS
size and texture logic to the vertex shader.

File size: 4.5 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006-2012 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  This program is free software. It comes without any warranty, to
7 *  the extent permitted by applicable law. You can redistribute it
8 *  and/or modify it under the terms of the Do What The Fuck You Want
9 *  To Public License, Version 2, as published by Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
11 */
12
13#if defined HAVE_CONFIG_H
14#   include "config.h"
15#endif
16
17#if defined HAVE_FORKPTY
18#   define _XOPEN_SOURCE
19#   include <stdlib.h>
20#   include <stdio.h>
21#   include <string.h>
22#   include <sys/ioctl.h>
23#   include <sys/types.h>
24#   include <termios.h>
25#   if defined HAVE_PTY_H
26#       include <pty.h>             /* for openpty and forkpty */
27#   elif defined HAVE_UTIL_H
28#       include <util.h>            /* for OS X, OpenBSD and NetBSD */
29#   elif defined HAVE_LIBUTIL_H
30#       include <libutil.h>         /* for FreeBSD */
31#   endif
32#   include <unistd.h>
33#   include <fcntl.h>
34#endif
35
36#include "core.h"
37#include "loldebug.h"
38
39using namespace std;
40using namespace lol;
41
42#include "../neercs.h"
43
44Pty::Pty()
45  : m_fd(-1),
46    m_pid(-1),
47    m_eof(false),
48    m_unread_data(0),
49    m_unread_len(0)
50{
51    ;
52}
53
54Pty::~Pty()
55{
56#if defined HAVE_FORKPTY
57    delete[] m_unread_data;
58
59    if (m_fd >= 0)
60    {
61        close((int)m_fd);
62    }
63#endif
64}
65
66void Pty::Run(char const *command, ivec2 size)
67{
68#if defined HAVE_FORKPTY
69    int fd;
70    pid_t pid;
71
72    m_pid = -1;
73    m_fd = -1;
74
75    pid = forkpty(&fd, NULL, NULL, NULL);
76    if (pid < 0)
77    {
78        fprintf(stderr, "forkpty() error\n");
79        return;
80    }
81    else if (pid == 0)
82    {
83        SetWindowSize(size, 0);
84
85        /* putenv() eats the string, they need to be writable */
86        static char tmp1[] = "CACA_DRIVER=slang";
87        static char tmp2[] = "TERM=xterm";
88        putenv(tmp1);
89        putenv(tmp2);
90
91        m_argv[0] = command;
92        m_argv[1] = NULL;
93        /* The following const cast is valid. The Open Group Base
94         * Specification guarantees that the objects are completely
95         * constant. */
96        execvp(command, const_cast<char * const *>(m_argv));
97        fprintf(stderr, "execvp() error\n");
98        return;
99    }
100
101    fcntl(fd, F_SETFL, O_NDELAY);
102
103    m_pid = pid;
104    m_fd = fd;
105#endif
106}
107
108bool Pty::IsEof() const
109{
110    return m_eof;
111}
112
113size_t Pty::ReadData(char *data, size_t maxlen)
114{
115#if defined HAVE_FORKPTY
116    /* Do we have data from previous call? */
117    if (m_unread_len)
118    {
119        /* FIXME: check that m_unread_len < maxlen */
120        memcpy(data, m_unread_data, m_unread_len);
121
122        data += m_unread_len;
123        maxlen -= m_unread_len;
124
125        delete[] m_unread_data;
126        m_unread_data = 0;
127        m_unread_len = 0;
128    }
129
130    fd_set fdset;
131    int maxfd = -1;
132
133    FD_ZERO(&fdset);
134    if (m_fd >= 0)
135    {
136        FD_SET((int)m_fd, &fdset);
137        maxfd = std::max(maxfd, (int)m_fd);
138    }
139
140    if (maxfd >= 0)
141    {
142        struct timeval tv;
143        tv.tv_sec = 0;
144        tv.tv_usec = 50000;
145        int ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
146
147        if (ret < 0)
148        {
149            Log::Error("cannot read from PTY\n");
150            m_eof = true;
151            return 0;
152        }
153        else if (ret)
154        {
155            if (FD_ISSET((int)m_fd, &fdset))
156            {
157                ssize_t nr = read((int)m_fd, data, maxlen);
158
159                /* Data available but zero-length read: EOF */
160                if (nr <= 0)
161                    m_eof = true;
162
163                if (nr >= 0)
164                    return nr;
165            }
166        }
167    }
168#endif
169
170    return 0;
171}
172
173void Pty::UnreadData(char *data, size_t len)
174{
175#if defined HAVE_FORKPTY
176    char *new_data;
177
178    if (m_unread_data)
179    {
180        new_data = new char[m_unread_len + len];
181        memcpy(new_data + len, m_unread_data, m_unread_len);
182        delete[] m_unread_data;
183    }
184    else
185    {
186        new_data = new char[len];
187    }
188
189    memcpy(new_data, data, len);
190    m_unread_data = new_data;
191#endif
192}
193
194size_t Pty::WriteData(char const *data, size_t len)
195{
196#if defined HAVE_FORKPTY
197    /* FIXME: can we be more naive than that? */
198    return write((int)m_fd, data, len);
199#endif
200
201    return 0;
202}
203
204void Pty::SetWindowSize(ivec2 size, int64_t fd /* = -1 */)
205{
206#if defined HAVE_FORKPTY
207    if (m_size == size)
208        return;
209
210    if (fd < 0)
211        fd = m_fd;
212
213    m_size = size;
214
215    struct winsize ws;
216
217    memset(&ws, 0, sizeof(ws));
218    ws.ws_row = size.y;
219    ws.ws_col = size.x;
220    ioctl((int)fd, TIOCSWINSZ, (char *)&ws);
221#endif
222}
Note: See TracBrowser for help on using the repository browser.