diff options
Diffstat (limited to 'std.c')
-rw-r--r-- | std.c | 363 |
1 files changed, 0 insertions, 363 deletions
@@ -1,363 +0,0 @@ | |||
1 | /* See LICENSE file for copyright and license details. | ||
2 | * | ||
3 | * Simple terminal daemon is a terminal emulator. It can be used in | ||
4 | * combination with simple terminal to emulate a mostly VT100-compatible | ||
5 | * terminal. | ||
6 | * | ||
7 | * In this process std works like a filter. It reads data from a | ||
8 | * pseudo-terminal and parses the escape sequences and transforms them | ||
9 | * into an ed(1)-like language. The resulting data is buffered and | ||
10 | * written to stdout. | ||
11 | * Parallely it reads data from stdin and parses and executes the | ||
12 | * commands. The resulting data is written to the pseudo-terminal. | ||
13 | */ | ||
14 | #include <sys/types.h> | ||
15 | #include <sys/wait.h> | ||
16 | #include <ctype.h> | ||
17 | #include <err.h> | ||
18 | #include <errno.h> | ||
19 | #include <fcntl.h> | ||
20 | #if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) | ||
21 | #include <pty.h> | ||
22 | #endif | ||
23 | #include <signal.h> | ||
24 | #include <stdarg.h> | ||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <unistd.h> | ||
29 | |||
30 | #define LENGTH(x) (sizeof(x) / sizeof((x)[0])) | ||
31 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) | ||
32 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) | ||
33 | |||
34 | typedef struct { | ||
35 | unsigned char data[BUFSIZ]; | ||
36 | int s, e; | ||
37 | int n; | ||
38 | } RingBuffer; | ||
39 | |||
40 | static void buffer(char c); | ||
41 | static void cmd(const char *cmdstr, ...); | ||
42 | static void getpty(void); | ||
43 | static void movea(int x, int y); | ||
44 | static void mover(int x, int y); | ||
45 | static void parsecmd(void); | ||
46 | static void parseesc(void); | ||
47 | static void scroll(int l); | ||
48 | static void shell(void); | ||
49 | static void sigchld(int n); | ||
50 | static char unbuffer(void); | ||
51 | |||
52 | static int cols = 80, lines = 25; | ||
53 | static int cx = 0, cy = 0; | ||
54 | static int c; | ||
55 | static int ptm, pts; | ||
56 | static _Bool bold, digit, qmark; | ||
57 | static pid_t pid; | ||
58 | static RingBuffer buf; | ||
59 | static FILE *fptm; | ||
60 | |||
61 | void | ||
62 | buffer(char c) { | ||
63 | if(buf.n < LENGTH(buf.data)) | ||
64 | buf.n++; | ||
65 | else | ||
66 | buf.s = (buf.s + 1) % LENGTH(buf.data); | ||
67 | buf.data[buf.e++] = c; | ||
68 | buf.e %= LENGTH(buf.data); | ||
69 | } | ||
70 | |||
71 | void | ||
72 | cmd(const char *cmdstr, ...) { | ||
73 | va_list ap; | ||
74 | |||
75 | putchar('\n'); | ||
76 | putchar(':'); | ||
77 | va_start(ap, cmdstr); | ||
78 | vfprintf(stdout, cmdstr, ap); | ||
79 | va_end(ap); | ||
80 | } | ||
81 | |||
82 | void | ||
83 | movea(int x, int y) { | ||
84 | x = MAX(x, cols); | ||
85 | y = MAX(y, lines); | ||
86 | cx = x; | ||
87 | cy = y; | ||
88 | cmd("seek(%d,%d)", x, y); | ||
89 | } | ||
90 | |||
91 | void | ||
92 | mover(int x, int y) { | ||
93 | movea(cx + x, cy + y); | ||
94 | } | ||
95 | |||
96 | void | ||
97 | parsecmd(void) { | ||
98 | } | ||
99 | |||
100 | void | ||
101 | parseesc(void) { | ||
102 | int i, j; | ||
103 | int arg[16]; | ||
104 | |||
105 | memset(arg, 0, LENGTH(arg)); | ||
106 | c = getc(fptm); | ||
107 | switch(c) { | ||
108 | case '[': | ||
109 | c = getc(fptm); | ||
110 | for(j = 0; j < LENGTH(arg);) { | ||
111 | if(isdigit(c)) { | ||
112 | digit = 1; | ||
113 | arg[j] *= 10; | ||
114 | arg[j] += c - '0'; | ||
115 | } | ||
116 | else if(c == '?') | ||
117 | qmark = 1; | ||
118 | else if(c == ';') { | ||
119 | if(!digit) | ||
120 | errx(EXIT_FAILURE, "syntax error"); | ||
121 | digit = 0; | ||
122 | j++; | ||
123 | } | ||
124 | else { | ||
125 | if(digit) { | ||
126 | digit = 0; | ||
127 | j++; | ||
128 | } | ||
129 | break; | ||
130 | } | ||
131 | c = getc(fptm); | ||
132 | } | ||
133 | switch(c) { | ||
134 | case '@': | ||
135 | break; | ||
136 | case 'A': | ||
137 | mover(0, j ? arg[0] : 1); | ||
138 | break; | ||
139 | case 'B': | ||
140 | mover(0, j ? -arg[0] : -1); | ||
141 | break; | ||
142 | case 'C': | ||
143 | mover(j ? arg[0] : 1, 0); | ||
144 | break; | ||
145 | case 'D': | ||
146 | mover(j ? -arg[0] : -1, 0); | ||
147 | break; | ||
148 | case 'E': | ||
149 | /* movel(j ? arg[0] : 1); */ | ||
150 | break; | ||
151 | case 'F': | ||
152 | /* movel(j ? -arg[0] : -1); */ | ||
153 | break; | ||
154 | case '`': | ||
155 | case 'G': | ||
156 | movea(j ? arg[0] : 1, cy); | ||
157 | break; | ||
158 | case 'f': | ||
159 | case 'H': | ||
160 | movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1); | ||
161 | case 'L': | ||
162 | /* insline(j ? arg[0] : 1); */ | ||
163 | break; | ||
164 | case 'M': | ||
165 | /* delline(j ? arg[0] : 1); */ | ||
166 | break; | ||
167 | case 'P': | ||
168 | break; | ||
169 | case 'S': | ||
170 | scroll(j ? arg[0] : 1); | ||
171 | break; | ||
172 | case 'T': | ||
173 | scroll(j ? -arg[0] : -1); | ||
174 | break; | ||
175 | case 'd': | ||
176 | movea(cx, j ? arg[0] : 1); | ||
177 | break; | ||
178 | case 'm': | ||
179 | for(i = 0; i < j; i++) { | ||
180 | if(arg[i] >= 30 && arg[i] <= 37) | ||
181 | cmd("#%d", arg[i] - 30); | ||
182 | if(arg[i] >= 40 && arg[i] <= 47) | ||
183 | cmd("|%d", arg[i] - 40); | ||
184 | /* xterm bright colors */ | ||
185 | if(arg[i] >= 90 && arg[i] <= 97) | ||
186 | cmd("#%d", arg[i] - 90); | ||
187 | if(arg[i] >= 100 && arg[i] <= 107) | ||
188 | cmd("|%d", arg[i] - 100); | ||
189 | switch(arg[i]) { | ||
190 | case 0: | ||
191 | case 22: | ||
192 | if(bold) | ||
193 | cmd("bold"); | ||
194 | case 1: | ||
195 | if(!bold) | ||
196 | cmd("bold"); | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | break; | ||
201 | } | ||
202 | break; | ||
203 | default: | ||
204 | putchar('\033'); | ||
205 | ungetc(c, fptm); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | void | ||
210 | scroll(int l) { | ||
211 | cmd("seek(%d,%d)", cx, cy + l); | ||
212 | } | ||
213 | |||
214 | void | ||
215 | getpty(void) { | ||
216 | char *ptsdev; | ||
217 | |||
218 | #if defined(_GNU_SOURCE) | ||
219 | ptm = getpt(); | ||
220 | #elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 | ||
221 | ptm = posix_openpt(O_RDWR); | ||
222 | #else | ||
223 | ptm = open("/dev/ptmx", O_RDWR); | ||
224 | if(ptm == -1) | ||
225 | if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) | ||
226 | err(EXIT_FAILURE, "cannot open pty"); | ||
227 | #endif | ||
228 | #if defined(_XOPEN_SOURCE) | ||
229 | if(ptm != -1) { | ||
230 | if(grantpt(ptm) == -1) | ||
231 | err(EXIT_FAILURE, "cannot grant access to pty"); | ||
232 | if(unlockpt(ptm) == -1) | ||
233 | err(EXIT_FAILURE, "cannot unlock pty"); | ||
234 | ptsdev = ptsname(ptm); | ||
235 | if(!ptsdev) | ||
236 | err(EXIT_FAILURE, "slave pty name undefined"); | ||
237 | pts = open(ptsdev, O_RDWR); | ||
238 | if(pts == -1) | ||
239 | err(EXIT_FAILURE, "cannot open slave pty"); | ||
240 | } | ||
241 | else | ||
242 | err(EXIT_FAILURE, "cannot open pty"); | ||
243 | #endif | ||
244 | } | ||
245 | |||
246 | void | ||
247 | shell(void) { | ||
248 | static char *shell = NULL; | ||
249 | |||
250 | if(!shell && !(shell = getenv("SHELL"))) | ||
251 | shell = "/bin/sh"; | ||
252 | pid = fork(); | ||
253 | switch(pid) { | ||
254 | case -1: | ||
255 | err(EXIT_FAILURE, "cannot fork"); | ||
256 | case 0: | ||
257 | setsid(); | ||
258 | dup2(pts, STDIN_FILENO); | ||
259 | dup2(pts, STDOUT_FILENO); | ||
260 | dup2(pts, STDERR_FILENO); | ||
261 | close(ptm); | ||
262 | putenv("TERM=vt102"); | ||
263 | execvp(shell, NULL); | ||
264 | break; | ||
265 | default: | ||
266 | close(pts); | ||
267 | signal(SIGCHLD, sigchld); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | void | ||
272 | sigchld(int n) { | ||
273 | int ret; | ||
274 | |||
275 | if(waitpid(pid, &ret, 0) == -1) | ||
276 | err(EXIT_FAILURE, "waiting for child failed"); | ||
277 | if(WIFEXITED(ret)) | ||
278 | exit(WEXITSTATUS(ret)); | ||
279 | else | ||
280 | exit(EXIT_SUCCESS); | ||
281 | } | ||
282 | |||
283 | char | ||
284 | unbuffer(void) { | ||
285 | char c; | ||
286 | |||
287 | c = buf.data[buf.s++]; | ||
288 | buf.s %= LENGTH(buf.data); | ||
289 | buf.n--; | ||
290 | return c; | ||
291 | } | ||
292 | |||
293 | int | ||
294 | main(int argc, char *argv[]) { | ||
295 | fd_set rfds; | ||
296 | |||
297 | if(argc == 2 && !strcmp("-v", argv[1])) | ||
298 | errx(EXIT_SUCCESS, "std-"VERSION", © 2008 Matthias-Christian Ott"); | ||
299 | else if(argc == 1) | ||
300 | errx(EXIT_FAILURE, "usage: std [-v]"); | ||
301 | getpty(); | ||
302 | shell(); | ||
303 | FD_ZERO(&rfds); | ||
304 | FD_SET(STDIN_FILENO, &rfds); | ||
305 | FD_SET(ptm, &rfds); | ||
306 | if(!(fptm = fdopen(ptm, "r+"))) | ||
307 | err(EXIT_FAILURE, "cannot open pty"); | ||
308 | if(fcntl(ptm, F_SETFL, O_NONBLOCK) == -1) | ||
309 | err(EXIT_FAILURE, "cannot set pty to non-blocking mode"); | ||
310 | if(fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) | ||
311 | err(EXIT_FAILURE, "cannot set stdin to non-blocking mode"); | ||
312 | for(;;) { | ||
313 | if(select(MAX(ptm, STDIN_FILENO) + 1, &rfds, NULL, NULL, NULL) == -1) | ||
314 | err(EXIT_FAILURE, "cannot select"); | ||
315 | if(FD_ISSET(ptm, &rfds)) { | ||
316 | for(;;) { | ||
317 | if((c = getc(fptm)) == EOF) { | ||
318 | if(feof(fptm)) { | ||
319 | FD_CLR(ptm, &rfds); | ||
320 | fflush(fptm); | ||
321 | break; | ||
322 | } | ||
323 | if(errno != EAGAIN) | ||
324 | err(EXIT_FAILURE, "cannot read from pty"); | ||
325 | fflush(stdout); | ||
326 | break; | ||
327 | } | ||
328 | switch(c) { | ||
329 | case '\033': | ||
330 | parseesc(); | ||
331 | break; | ||
332 | default: | ||
333 | putchar(c); | ||
334 | } | ||
335 | } | ||
336 | fflush(stdout); | ||
337 | } | ||
338 | if(FD_ISSET(STDIN_FILENO, &rfds)) { | ||
339 | for(;;) { | ||
340 | if((c = getchar()) == EOF) { | ||
341 | if(feof(stdin)) { | ||
342 | FD_CLR(STDIN_FILENO, &rfds); | ||
343 | fflush(fptm); | ||
344 | break; | ||
345 | } | ||
346 | if(errno != EAGAIN) | ||
347 | err(EXIT_FAILURE, "cannot read from stdin"); | ||
348 | fflush(fptm); | ||
349 | break; | ||
350 | } | ||
351 | switch(c) { | ||
352 | case ':': | ||
353 | parsecmd(); | ||
354 | break; | ||
355 | default: | ||
356 | putc(c, fptm); | ||
357 | } | ||
358 | } | ||
359 | fflush(fptm); | ||
360 | } | ||
361 | } | ||
362 | return 0; | ||
363 | } | ||