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