1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "runes.h"
static void runes_pty_backend_read(uv_work_t *req);
static void runes_pty_backend_got_data(uv_work_t *req, int status);
void runes_pty_backend_spawn_subprocess(RunesTerm *t)
{
RunesPtyBackend *pty = &t->pty;
pty->master = posix_openpt(O_RDWR);
grantpt(pty->master);
unlockpt(pty->master);
pty->slave = open(ptsname(pty->master), O_RDWR);
pty->child_pid = fork();
if (pty->child_pid) {
close(pty->slave);
pty->slave = -1;
}
else {
char *shell;
setsid();
ioctl(pty->slave, TIOCSCTTY, NULL);
close(pty->master);
dup2(pty->slave, 0);
dup2(pty->slave, 1);
dup2(pty->slave, 2);
close(pty->slave);
shell = getenv("SHELL");
if (!shell) {
shell = "/bin/sh";
}
/* XXX should use a different TERM value eventually, but for right now
* screen is compatible enough */
setenv("TERM", "screen", 1);
unsetenv("LINES");
unsetenv("COLUMNS");
execl(shell, shell, (char *)NULL);
}
}
void runes_pty_backend_start_loop(RunesTerm *t)
{
void *data;
data = malloc(sizeof(RunesPtyLoopData));
((RunesLoopData *)data)->req.data = data;
((RunesLoopData *)data)->t = t;
uv_queue_work(
t->loop, data, runes_pty_backend_read, runes_pty_backend_got_data);
}
void runes_pty_backend_set_window_size(RunesTerm *t)
{
struct winsize size;
size.ws_row = t->rows;
size.ws_col = t->cols;
size.ws_xpixel = t->xpixel;
size.ws_ypixel = t->ypixel;
ioctl(t->pty.master, TIOCSWINSZ, &size);
}
void runes_pty_backend_write(RunesTerm *t, char *buf, size_t len)
{
write(t->pty.master, buf, len);
}
void runes_pty_backend_request_close(RunesTerm *t)
{
RunesPtyBackend *pty = &t->pty;
kill(pty->child_pid, SIGHUP);
}
void runes_pty_backend_cleanup(RunesTerm *t)
{
RunesPtyBackend *pty = &t->pty;
close(pty->master);
}
static void runes_pty_backend_read(uv_work_t *req)
{
RunesPtyLoopData *data;
data = (RunesPtyLoopData *)req->data;
runes_window_backend_request_flush(data->data.t);
data->len = read(
data->data.t->pty.master, data->buf, RUNES_PTY_BUFFER_LENGTH);
}
static void runes_pty_backend_got_data(uv_work_t *req, int status)
{
RunesPtyLoopData *data = req->data;
RunesTerm *t = data->data.t;
UNUSED(status);
if (data->len > 0) {
runes_parser_process_string(t, data->buf, data->len);
uv_queue_work(
t->loop, req, runes_pty_backend_read, runes_pty_backend_got_data);
}
else {
runes_window_backend_request_close(t);
free(req);
}
}
|