vt102: make readutf8() simpler
[fbpad.git] / term.c
blob6f697e92d449a05a38124617de4be5a9c0abb744
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <poll.h>
5 #include <pty.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "config.h"
12 #include "pad.h"
13 #include "util.h"
14 #include "term.h"
16 #define MODE_CURSOR 0x01
17 #define MODE_WRAP 0x02
18 #define MODE_ORIGIN 0x04
19 #define MODE_AUTOCR 0x08
20 #define MODE_DEFAULT (MODE_CURSOR | MODE_WRAP)
21 #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b)))
22 #define SQRADDR(r, c) (screen + (r) * pad_cols() + (c))
24 static struct term *term;
25 static struct square *screen;
26 static int row, col;
27 static int fg, bg;
28 static int top, bot;
29 static int mode;
30 static int visible;
32 #define MAXLINES (1 << 13)
33 static int dirty[MAXLINES];
34 static int lazy;
36 static void _term_show(int r, int c, int cursor)
38 struct square *sqr = SQRADDR(r, c);
39 int fgcolor = sqr->c ? sqr->fg : fg;
40 int bgcolor = sqr->c ? sqr->bg : bg;
41 if (cursor && mode & MODE_CURSOR) {
42 int t = fgcolor;
43 fgcolor = bgcolor;
44 bgcolor = t;
46 if (visible)
47 pad_put(sqr->c, r, c, fgcolor, bgcolor);
50 static void _draw_row(int r)
52 int i;
53 pad_blankrow(r, bg);
54 for (i = 0; i < pad_cols(); i++)
55 if (SQRADDR(r, i)->c)
56 _term_show(r, i, 0);
59 static void lazy_draw(int sr, int er)
61 int i;
62 if (!visible)
63 return;
64 for (i = sr; i < er; i++) {
65 if (lazy)
66 dirty[i] = 1;
67 else
68 _draw_row(i);
72 static void lazy_drawcols(int r, int sc, int ec)
74 int i;
75 if (!visible)
76 return;
77 if (lazy) {
78 dirty[r] = 1;
79 } else {
80 for (i = sc; i < ec; i++)
81 _term_show(r, i, 0);
85 static void lazy_put(int ch, int r, int c)
87 struct square *sqr = SQRADDR(r, c);
88 sqr->c = ch;
89 sqr->fg = fg;
90 sqr->bg = bg;
91 if (!visible)
92 return;
93 if (lazy)
94 dirty[r] = 1;
95 else
96 _term_show(r, c, 0);
99 static void lazy_cursor(int put)
101 if (!visible)
102 return;
103 if (lazy)
104 dirty[row] = 1;
105 else
106 _term_show(row, col, put);
109 static void lazy_clean()
111 if (visible)
112 memset(dirty, 0, sizeof(*dirty) * MAXLINES);
115 static void lazy_flush()
117 int i;
118 if (!visible)
119 return;
120 _term_show(row, col, 0);
121 for (i = 0; i < pad_rows(); i++)
122 if (dirty[i])
123 _draw_row(i);
124 lazy_clean();
125 _term_show(row, col, 1);
128 static void term_redraw(void)
130 int i;
131 for (i = 0; i < pad_rows(); i++)
132 _draw_row(i);
133 _term_show(row, col, 1);
136 static int origin(void)
138 return mode & MODE_ORIGIN;
141 static void setsize(void)
143 struct winsize size;
144 size.ws_col = pad_cols();
145 size.ws_row = pad_rows();
146 size.ws_xpixel = 0;
147 size.ws_ypixel = 0;
148 ioctl(term->fd, TIOCSWINSZ, &size);
151 #define PTYBUFSIZE (1 << 13)
152 static char ptybuf[PTYBUFSIZE];
153 static int ptylen;
154 static int ptycur;
155 static void waitpty(void)
157 struct pollfd ufds[1];
158 ufds[0].fd = term->fd;
159 ufds[0].events = POLLIN;
160 poll(ufds, 1, -1);
163 static int readpty(void)
165 if (ptycur < ptylen)
166 return ptybuf[ptycur++];
167 if (!term->fd)
168 return -1;
169 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
170 if (ptylen == -1 && errno == EAGAIN) {
171 waitpty();
172 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
174 if (ptylen > 0) {
175 ptycur = 1;
176 return ptybuf[0];
178 return -1;
181 static void empty_rows(int sr, int er)
183 memset(SQRADDR(sr, 0), 0, (er - sr) * sizeof(*screen) * pad_cols());
186 static void blank_rows(int sr, int er)
188 empty_rows(sr, er);
189 lazy_draw(sr, er);
190 lazy_cursor(1);
193 static void scroll_screen(int sr, int nr, int n)
195 lazy_cursor(0);
196 memmove(SQRADDR(sr + n, 0), SQRADDR(sr, 0),
197 nr * pad_cols() * sizeof(*screen));
198 if (n > 0)
199 empty_rows(sr, sr + n);
200 else
201 empty_rows(sr + nr + n, sr + nr);
202 lazy_draw(MIN(sr, sr + n), MAX(sr + nr, sr + nr + n));
203 lazy_cursor(1);
206 static void insert_lines(int n)
208 int sr = MAX(top, row);
209 int nr = bot - row - n;
210 if (nr > 0)
211 scroll_screen(sr, nr, n);
214 static void delete_lines(int n)
216 int r = MAX(top, row);
217 int sr = r + n;
218 int nr = bot - r - n;
219 if (nr > 0)
220 scroll_screen(sr, nr, -n);
223 static void move_cursor(int r, int c)
225 int t, b;
226 lazy_cursor(0);
227 t = origin() ? top : 0;
228 b = origin() ? bot : pad_rows();
229 row = MAX(t, MIN(r, b - 1));
230 col = MAX(0, MIN(c, pad_cols() - 1));
231 lazy_cursor(1);
234 static void advance(int dr, int dc, int scrl)
236 int r = row + dr;
237 int c = col + dc;
238 if (c >= pad_cols()) {
239 if (scrl && mode & MODE_WRAP) {
240 r++;
241 c = 0;
242 } else {
243 c = pad_cols() - 1;
246 if (r >= bot && scrl) {
247 int n = bot - r - 1;
248 int nr = (bot - top) + n;
249 scroll_screen(top + -n, nr, n);
251 if (r < top && scrl) {
252 int n = top - r;
253 int nr = (bot - top) - n;
254 scroll_screen(top, nr, n);
256 r = MIN(bot - 1, MAX(top, r));
257 move_cursor(r, MAX(0, c));
260 void term_send(int c)
262 unsigned char b = (unsigned char) c;
263 if (term->fd)
264 write(term->fd, &b, 1);
267 static void term_sendstr(char *s)
269 if (term->fd)
270 write(term->fd, s, strlen(s));
273 static void setmode(int m)
275 if (m == 0) {
276 fg = FGCOLOR;
277 bg = BGCOLOR;
279 if (m == 1)
280 fg = fg | 0x08;
281 if (m == 7) {
282 int t = fg;
283 fg = bg;
284 bg = t;
286 if (m >= 30 && m <= 37)
287 fg = m - 30;
288 if (m >= 40 && m <= 47)
289 bg = m - 40;
292 static void kill_chars(int sc, int ec)
294 int i;
295 for (i = sc; i < ec; i++)
296 lazy_put(' ', row, i);
297 lazy_cursor(1);
300 static void move_chars(int sc, int nc, int n)
302 lazy_cursor(0);
303 memmove(SQRADDR(row, sc + n), SQRADDR(row, sc), nc * sizeof(*screen));
304 if (n > 0)
305 memset(SQRADDR(row, sc), 0, n * sizeof(*screen));
306 else
307 memset(SQRADDR(row, pad_cols() + n), 0, -n * sizeof(*screen));
308 lazy_drawcols(row, MIN(sc, sc + n), pad_cols());
309 lazy_cursor(1);
312 static void delete_chars(int n)
314 int sc = col + n;
315 int nc = pad_cols() - sc;
316 move_chars(sc, nc, -n);
319 static void insert_chars(int n)
321 int nc = pad_cols() - col - n;
322 move_chars(col, nc, n);
325 static void term_blank(void)
327 memset(screen, 0, MAXCHARS * sizeof(*screen));
328 if (visible) {
329 pad_blank(bg);
330 lazy_clean();
334 static void ctlseq(void);
335 void term_read(void)
337 ctlseq();
338 lazy = 1;
339 while (ptycur < ptylen)
340 ctlseq();
341 lazy_flush();
342 lazy = 0;
345 void term_exec(char *cmd)
347 memset(term, 0, sizeof(*term));
348 term->cur.bot = term->sav.bot = pad_rows();
349 term->cur.mode = MODE_DEFAULT;
350 term_load(term, visible);
351 if ((term->pid = forkpty(&term->fd, NULL, NULL, NULL)) == -1) {
352 perror("failed to fork");
353 term->fd = 0;
354 return;
356 if (!term->pid) {
357 setenv("TERM", "linux", 1);
358 execlp(cmd, cmd, NULL);
359 exit(1);
361 fcntl(term->fd, F_SETFD, fcntl(term->fd, F_GETFD) | FD_CLOEXEC);
362 fcntl(term->fd, F_SETFL, fcntl(term->fd, F_GETFL) | O_NONBLOCK);
363 setsize();
364 setmode(0);
365 term_blank();
368 static void misc_save(struct term_state *state)
370 state->row = row;
371 state->col = col;
372 state->fg = fg;
373 state->bg = bg;
374 state->top = top;
375 state->bot = bot;
376 state->mode = mode;
379 static void misc_load(struct term_state *state)
381 row = state->row;
382 col = state->col;
383 fg = state->fg;
384 bg = state->bg;
385 top = state->top;
386 bot = state->bot;
387 mode = state->mode;
390 void term_save(struct term *term)
392 visible = 0;
393 misc_save(&term->cur);
396 void term_load(struct term *t, int flags)
398 term = t;
399 misc_load(&term->cur);
400 screen = term->screen;
401 visible = flags;
402 if (flags == TERM_REDRAW) {
403 if (term->fd)
404 term_redraw();
405 else
406 pad_blank(0);
410 void term_end(void)
412 if (term->fd)
413 close(term->fd);
414 term->fd = 0;
415 row = col = 0;
416 fg = 0;
417 bg = 0;
418 term_blank();
421 static void set_region(int t, int b)
423 top = MIN(pad_rows(), MAX(0, t - 1));
424 bot = MIN(pad_rows(), MAX(0, b ? b : pad_rows()));
425 if (origin())
426 move_cursor(top, 0);
429 #include "vt102.c"