Xinqi Bao's Git

1b918f557096f6273fdb14a2a1e4caa088da7915
[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 parseesc(void);
29 void scroll(int l);
30 void shell(void);
31 void sigchld(int n);
32 char unbuffer(void);
33
34 typedef struct {
35 unsigned char data[BUFSIZ];
36 int s, e;
37 int n;
38 } RingBuffer;
39
40 int cols = 80, lines = 25;
41 int cx = 0, cy = 0;
42 int c;
43 FILE *fptm = NULL;
44 int ptm, pts;
45 _Bool bold, digit, qmark;
46 pid_t pid;
47 RingBuffer buf;
48
49 void
50 buffer(char c) {
51 if(buf.n < LENGTH(buf.data))
52 buf.n++;
53 else
54 buf.s = (buf.s + 1) % LENGTH(buf.data);
55 buf.data[buf.e++] = c;
56 buf.e %= LENGTH(buf.data);
57 }
58
59 void
60 cmd(const char *cmdstr, ...) {
61 va_list ap;
62
63 putchar('\n');
64 putchar(':');
65 va_start(ap, cmdstr);
66 vfprintf(stdout, cmdstr, ap);
67 va_end(ap);
68 }
69
70 void *
71 emallocz(unsigned int size) {
72 void *res = calloc(1, size);
73
74 if(!res)
75 eprint("fatal: could not malloc() %u bytes\n", size);
76 return res;
77 }
78
79 void
80 eprint(const char *errstr, ...) {
81 va_list ap;
82
83 va_start(ap, errstr);
84 vfprintf(stderr, errstr, ap);
85 va_end(ap);
86 exit(EXIT_FAILURE);
87 }
88
89 void
90 eprintn(const char *errstr, ...) {
91 va_list ap;
92
93 va_start(ap, errstr);
94 vfprintf(stderr, errstr, ap);
95 va_end(ap);
96 fprintf(stderr, ": %s\n", strerror(errno));
97 exit(EXIT_FAILURE);
98 }
99
100 void
101 movea(int x, int y) {
102 x = MAX(x, cols);
103 y = MAX(y, lines);
104 cx = x;
105 cy = y;
106 cmd("s %d,%d", x, y);
107 }
108
109 void
110 mover(int x, int y) {
111 movea(cx + x, cy + y);
112 }
113
114 void
115 parseesc(void) {
116 int i, j;
117 int arg[16];
118
119 memset(arg, 0, LENGTH(arg));
120 c = getc(fptm);
121 switch(c) {
122 case '[':
123 c = getc(fptm);
124 for(j = 0; j < LENGTH(arg);) {
125 if(isdigit(c)) {
126 digit = 1;
127 arg[j] *= 10;
128 arg[j] += c - '0';
129 }
130 else if(c == '?')
131 qmark = 1;
132 else if(c == ';') {
133 if(!digit)
134 eprint("syntax error\n");
135 digit = 0;
136 j++;
137 }
138 else {
139 if(digit) {
140 digit = 0;
141 j++;
142 }
143 break;
144 }
145 c = getc(fptm);
146 }
147 switch(c) {
148 case '@':
149 break;
150 case 'A':
151 mover(0, j ? arg[0] : 1);
152 break;
153 case 'B':
154 mover(0, j ? -arg[0] : -1);
155 break;
156 case 'C':
157 mover(j ? arg[0] : 1, 0);
158 break;
159 case 'D':
160 mover(j ? -arg[0] : -1, 0);
161 break;
162 case 'E':
163 /* movel(j ? arg[0] : 1); */
164 break;
165 case 'F':
166 /* movel(j ? -arg[0] : -1); */
167 break;
168 case '`':
169 case 'G':
170 movea(j ? arg[0] : 1, cy);
171 break;
172 case 'f':
173 case 'H':
174 movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1);
175 case 'L':
176 /* insline(j ? arg[0] : 1); */
177 break;
178 case 'M':
179 /* delline(j ? arg[0] : 1); */
180 break;
181 case 'P':
182 break;
183 case 'S':
184 scroll(j ? arg[0] : 1);
185 break;
186 case 'T':
187 scroll(j ? -arg[0] : -1);
188 break;
189 case 'd':
190 movea(cx, j ? arg[0] : 1);
191 break;
192 case 'm':
193 for(i = 0; i < j; i++) {
194 if(arg[i] >= 30 && arg[i] <= 37)
195 cmd("#%d", arg[i] - 30);
196 if(arg[i] >= 40 && arg[i] <= 47)
197 cmd("|%d", arg[i] - 40);
198 /* xterm bright colors */
199 if(arg[i] >= 90 && arg[i] <= 97)
200 cmd("#%d", arg[i] - 90);
201 if(arg[i] >= 100 && arg[i] <= 107)
202 cmd("|%d", arg[i] - 100);
203 switch(arg[i]) {
204 case 0:
205 case 22:
206 if(bold)
207 cmd("b");
208 case 1:
209 if(!bold)
210 cmd("b");
211 break;
212 }
213 }
214 break;
215 }
216 break;
217 default:
218 putchar('\033');
219 ungetc(c, fptm);
220 }
221 }
222
223 void
224 scroll(int l) {
225 cmd("s %d, %d", cx, cy + l);
226 }
227
228 void
229 shell(void) {
230 static char *shell = NULL;
231
232 if(!shell && !(shell = getenv("SHELL")))
233 shell = "/bin/sh";
234 pid = fork();
235 switch(pid) {
236 case -1:
237 eprint("error, cannot fork\n");
238 case 0:
239 setsid();
240 dup2(pts, STDIN_FILENO);
241 dup2(pts, STDOUT_FILENO);
242 dup2(pts, STDERR_FILENO);
243 close(ptm);
244 putenv("TERM=vt102");
245 execvp(shell, NULL);
246 break;
247 default:
248 close(pts);
249 signal(SIGCHLD, sigchld);
250 }
251 }
252
253 void
254 sigchld(int n) {
255 int ret;
256
257 if(waitpid(pid, &ret, 0) == -1)
258 eprintn("error, waiting for child failed");
259 if(WIFEXITED(ret))
260 exit(WEXITSTATUS(ret));
261 else
262 exit(EXIT_SUCCESS);
263 }
264
265 char
266 unbuffer(void) {
267 char c;
268
269 c = buf.data[buf.s++];
270 buf.s %= LENGTH(buf.data);
271 buf.n--;
272 return c;
273 }
274
275 int
276 main(int argc, char *argv[]) {
277 if(argc == 2 && !strcmp("-v", argv[1]))
278 eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n");
279 else if(argc == 1)
280 eprint("usage: st [-v]\n");
281 getpty();
282 shell();
283 fptm = fdopen(ptm, "r+");
284 if(!fptm)
285 eprintn("cannot open slave pty");
286 for(;;) {
287 c = getc(fptm);
288 switch(c) {
289 case '\033':
290 parseesc();
291 break;
292 default:
293 putchar(c);
294 }
295 }
296 return 0;
297 }