Xinqi Bao's Git

source utility functions out to util.c
[st.git] / std.c
1 /* See LICENSE file for copyright and license details. */
2 #include "util.h"
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <ctype.h>
6 #include <signal.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
14 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
15 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
16
17 void buffer(char c);
18 void cmd(const char *cmdstr, ...);
19 void getpty(void);
20 void movea(int x, int y);
21 void mover(int x, int y);
22 void parseesc(void);
23 void scroll(int l);
24 void shell(void);
25 void sigchld(int n);
26 char unbuffer(void);
27
28 typedef struct {
29 unsigned char data[BUFSIZ];
30 int s, e;
31 int n;
32 } RingBuffer;
33
34 int cols = 80, lines = 25;
35 int cx = 0, cy = 0;
36 int c;
37 FILE *fptm = NULL;
38 int ptm, pts;
39 _Bool bold, digit, qmark;
40 pid_t pid;
41 RingBuffer buf;
42
43 void
44 buffer(char c) {
45 if(buf.n < LENGTH(buf.data))
46 buf.n++;
47 else
48 buf.s = (buf.s + 1) % LENGTH(buf.data);
49 buf.data[buf.e++] = c;
50 buf.e %= LENGTH(buf.data);
51 }
52
53 void
54 cmd(const char *cmdstr, ...) {
55 va_list ap;
56
57 putchar('\n');
58 putchar(':');
59 va_start(ap, cmdstr);
60 vfprintf(stdout, cmdstr, ap);
61 va_end(ap);
62 }
63
64 void
65 movea(int x, int y) {
66 x = MAX(x, cols);
67 y = MAX(y, lines);
68 cx = x;
69 cy = y;
70 cmd("s %d,%d", x, y);
71 }
72
73 void
74 mover(int x, int y) {
75 movea(cx + x, cy + y);
76 }
77
78 void
79 parseesc(void) {
80 int i, j;
81 int arg[16];
82
83 memset(arg, 0, LENGTH(arg));
84 c = getc(fptm);
85 switch(c) {
86 case '[':
87 c = getc(fptm);
88 for(j = 0; j < LENGTH(arg);) {
89 if(isdigit(c)) {
90 digit = 1;
91 arg[j] *= 10;
92 arg[j] += c - '0';
93 }
94 else if(c == '?')
95 qmark = 1;
96 else if(c == ';') {
97 if(!digit)
98 eprint("syntax error\n");
99 digit = 0;
100 j++;
101 }
102 else {
103 if(digit) {
104 digit = 0;
105 j++;
106 }
107 break;
108 }
109 c = getc(fptm);
110 }
111 switch(c) {
112 case '@':
113 break;
114 case 'A':
115 mover(0, j ? arg[0] : 1);
116 break;
117 case 'B':
118 mover(0, j ? -arg[0] : -1);
119 break;
120 case 'C':
121 mover(j ? arg[0] : 1, 0);
122 break;
123 case 'D':
124 mover(j ? -arg[0] : -1, 0);
125 break;
126 case 'E':
127 /* movel(j ? arg[0] : 1); */
128 break;
129 case 'F':
130 /* movel(j ? -arg[0] : -1); */
131 break;
132 case '`':
133 case 'G':
134 movea(j ? arg[0] : 1, cy);
135 break;
136 case 'f':
137 case 'H':
138 movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1);
139 case 'L':
140 /* insline(j ? arg[0] : 1); */
141 break;
142 case 'M':
143 /* delline(j ? arg[0] : 1); */
144 break;
145 case 'P':
146 break;
147 case 'S':
148 scroll(j ? arg[0] : 1);
149 break;
150 case 'T':
151 scroll(j ? -arg[0] : -1);
152 break;
153 case 'd':
154 movea(cx, j ? arg[0] : 1);
155 break;
156 case 'm':
157 for(i = 0; i < j; i++) {
158 if(arg[i] >= 30 && arg[i] <= 37)
159 cmd("#%d", arg[i] - 30);
160 if(arg[i] >= 40 && arg[i] <= 47)
161 cmd("|%d", arg[i] - 40);
162 /* xterm bright colors */
163 if(arg[i] >= 90 && arg[i] <= 97)
164 cmd("#%d", arg[i] - 90);
165 if(arg[i] >= 100 && arg[i] <= 107)
166 cmd("|%d", arg[i] - 100);
167 switch(arg[i]) {
168 case 0:
169 case 22:
170 if(bold)
171 cmd("b");
172 case 1:
173 if(!bold)
174 cmd("b");
175 break;
176 }
177 }
178 break;
179 }
180 break;
181 default:
182 putchar('\033');
183 ungetc(c, fptm);
184 }
185 }
186
187 void
188 scroll(int l) {
189 cmd("s %d, %d", cx, cy + l);
190 }
191
192 void
193 shell(void) {
194 static char *shell = NULL;
195
196 if(!shell && !(shell = getenv("SHELL")))
197 shell = "/bin/sh";
198 pid = fork();
199 switch(pid) {
200 case -1:
201 eprint("error, cannot fork\n");
202 case 0:
203 setsid();
204 dup2(pts, STDIN_FILENO);
205 dup2(pts, STDOUT_FILENO);
206 dup2(pts, STDERR_FILENO);
207 close(ptm);
208 putenv("TERM=vt102");
209 execvp(shell, NULL);
210 break;
211 default:
212 close(pts);
213 signal(SIGCHLD, sigchld);
214 }
215 }
216
217 void
218 sigchld(int n) {
219 int ret;
220
221 if(waitpid(pid, &ret, 0) == -1)
222 eprintn("error, waiting for child failed");
223 if(WIFEXITED(ret))
224 exit(WEXITSTATUS(ret));
225 else
226 exit(EXIT_SUCCESS);
227 }
228
229 char
230 unbuffer(void) {
231 char c;
232
233 c = buf.data[buf.s++];
234 buf.s %= LENGTH(buf.data);
235 buf.n--;
236 return c;
237 }
238
239 int
240 main(int argc, char *argv[]) {
241 if(argc == 2 && !strcmp("-v", argv[1]))
242 eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n");
243 else if(argc == 1)
244 eprint("usage: st [-v]\n");
245 getpty();
246 shell();
247 fptm = fdopen(ptm, "r+");
248 if(!fptm)
249 eprintn("cannot open slave pty");
250 for(;;) {
251 c = getc(fptm);
252 switch(c) {
253 case '\033':
254 parseesc();
255 break;
256 default:
257 putchar(c);
258 }
259 }
260 return 0;
261 }