Xinqi Bao's Git

slight changes
[st.git] / std.c
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>
15
16 #define LENGTH(x) (sizeof (x) / sizeof (x)[0])
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 }