term: use MODE_DEFAULT and set auto wrap
[fbpad.git] / term.c
blob91cebbed381c519cd08f9f9f5dd4fa1fb4868765
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 for (i = 0; i < pad_cols(); i++)
54 _term_show(r, i, 0);
57 static void lazy_draw(int sr, int er)
59 int i;
60 if (!visible)
61 return;
62 for (i = sr; i < er; i++) {
63 if (lazy)
64 dirty[i] = 1;
65 else
66 _draw_row(i);
70 static void lazy_drawcols(int r, int sc, int ec)
72 int i;
73 if (!visible)
74 return;
75 if (lazy) {
76 dirty[r] = 1;
77 } else {
78 for (i = sc; i < ec; i++)
79 _term_show(r, i, 0);
83 static void lazy_put(int ch, int r, int c)
85 struct square *sqr = SQRADDR(r, c);
86 sqr->c = ch;
87 sqr->fg = fg;
88 sqr->bg = bg;
89 if (!visible)
90 return;
91 if (lazy)
92 dirty[r] = 1;
93 else
94 _term_show(r, c, 0);
97 static void lazy_cursor(int put)
99 if (!visible)
100 return;
101 if (lazy)
102 dirty[row] = 1;
103 else
104 _term_show(row, col, put);
107 static void lazy_clean()
109 if (visible)
110 memset(dirty, 0, sizeof(*dirty) * MAXLINES);
113 static void lazy_flush()
115 int i;
116 if (!visible)
117 return;
118 _term_show(row, col, 0);
119 for (i = 0; i < pad_rows(); i++)
120 if (dirty[i])
121 _draw_row(i);
122 lazy_clean();
123 _term_show(row, col, 1);
126 static int origin(void)
128 return mode & MODE_ORIGIN;
131 static void setsize(void)
133 struct winsize size;
134 size.ws_col = pad_cols();
135 size.ws_row = pad_rows();
136 size.ws_xpixel = 0;
137 size.ws_ypixel = 0;
138 ioctl(term->fd, TIOCSWINSZ, &size);
141 #define PTYBUFSIZE (1 << 13)
142 static char ptybuf[PTYBUFSIZE];
143 static int ptylen;
144 static int ptycur;
145 static void waitpty(void)
147 struct pollfd ufds[1];
148 ufds[0].fd = term->fd;
149 ufds[0].events = POLLIN;
150 poll(ufds, 1, -1);
153 static int readpty(void)
155 if (ptycur < ptylen)
156 return ptybuf[ptycur++];
157 if (!term->fd)
158 return -1;
159 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
160 if (ptylen == -1 && errno == EAGAIN) {
161 waitpty();
162 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
164 if (ptylen > 0) {
165 ptycur = 1;
166 return ptybuf[0];
168 return -1;
171 static void empty_rows(int sr, int er)
173 memset(SQRADDR(sr, 0), 0, (er - sr) * sizeof(*screen) * pad_cols());
176 static void blank_rows(int sr, int er)
178 empty_rows(sr, er);
179 lazy_draw(sr, er);
180 lazy_cursor(1);
183 static void scroll_screen(int sr, int nr, int n)
185 lazy_cursor(0);
186 memmove(SQRADDR(sr + n, 0), SQRADDR(sr, 0),
187 nr * pad_cols() * sizeof(*screen));
188 if (n > 0)
189 empty_rows(sr, sr + n);
190 else
191 empty_rows(sr + nr + n, sr + nr);
192 lazy_draw(MIN(sr, sr + n), MAX(sr + nr, sr + nr + n));
193 lazy_cursor(1);
196 static void insert_lines(int n)
198 int sr = MAX(top, row);
199 int nr = bot - row - n;
200 if (nr > 0)
201 scroll_screen(sr, nr, n);
204 static void delete_lines(int n)
206 int r = MAX(top, row);
207 int sr = r + n;
208 int nr = bot - r - n;
209 if (nr > 0)
210 scroll_screen(sr, nr, -n);
213 static void move_cursor(int r, int c)
215 int t, b;
216 lazy_cursor(0);
217 t = origin() ? top : 0;
218 b = origin() ? bot : pad_rows();
219 row = MAX(t, MIN(r, b - 1));
220 col = MAX(0, MIN(c, pad_cols() - 1));
221 lazy_cursor(1);
224 static void advance(int dr, int dc, int scrl)
226 int r = row + dr;
227 int c = col + dc;
228 if (c >= pad_cols()) {
229 if (scrl && mode & MODE_WRAP) {
230 r++;
231 c = 0;
232 } else {
233 c = pad_cols() - 1;
236 if (r >= bot && scrl) {
237 int n = bot - r - 1;
238 int nr = (bot - top) + n;
239 scroll_screen(top + -n, nr, n);
241 if (r < top && scrl) {
242 int n = top - r;
243 int nr = (bot - top) - n;
244 scroll_screen(top, nr, n);
246 r = MIN(bot - 1, MAX(top, r));
247 move_cursor(r, MAX(0, c));
250 void term_send(int c)
252 unsigned char b = (unsigned char) c;
253 if (term->fd)
254 write(term->fd, &b, 1);
257 static void term_sendstr(char *s)
259 if (term->fd)
260 write(term->fd, s, strlen(s));
263 static void setmode(int m)
265 if (m == 0) {
266 fg = FGCOLOR;
267 bg = BGCOLOR;
269 if (m == 1)
270 fg = fg | 0x08;
271 if (m == 7) {
272 int t = fg;
273 fg = bg;
274 bg = t;
276 if (m >= 30 && m <= 37)
277 fg = m - 30;
278 if (m >= 40 && m <= 47)
279 bg = m - 40;
282 static void kill_chars(int sc, int ec)
284 int i;
285 for (i = sc; i < ec; i++)
286 lazy_put(' ', row, i);
287 lazy_cursor(1);
290 static void move_chars(int sc, int nc, int n)
292 lazy_cursor(0);
293 memmove(SQRADDR(row, sc + n), SQRADDR(row, sc), nc * sizeof(*screen));
294 if (n > 0)
295 memset(SQRADDR(row, sc), 0, n * sizeof(*screen));
296 else
297 memset(SQRADDR(row, pad_cols() + n), 0, -n * sizeof(*screen));
298 lazy_drawcols(row, MIN(sc, sc + n), pad_cols());
299 lazy_cursor(1);
302 static void delete_chars(int n)
304 int sc = col + n;
305 int nc = pad_cols() - sc;
306 move_chars(sc, nc, -n);
309 static void insert_chars(int n)
311 int nc = pad_cols() - col - n;
312 move_chars(col, nc, n);
315 static void term_blank(void)
317 memset(screen, 0, MAXCHARS * sizeof(*screen));
318 if (visible) {
319 pad_blank(bg);
320 lazy_clean();
324 static void ctlseq(void);
325 void term_read(void)
327 ctlseq();
328 lazy = 1;
329 while (ptycur < ptylen)
330 ctlseq();
331 lazy_flush();
332 lazy = 0;
335 void term_exec(char *cmd)
337 memset(term, 0, sizeof(*term));
338 term->cur.bot = term->sav.bot = pad_rows();
339 term->cur.mode = MODE_DEFAULT;
340 term_load(term, visible);
341 if ((term->pid = forkpty(&term->fd, NULL, NULL, NULL)) == -1) {
342 perror("failed to fork");
343 term->fd = 0;
344 return;
346 if (!term->pid) {
347 setenv("TERM", "linux", 1);
348 execlp(cmd, cmd, NULL);
349 exit(1);
351 fcntl(term->fd, F_SETFD, fcntl(term->fd, F_GETFD) | FD_CLOEXEC);
352 fcntl(term->fd, F_SETFL, fcntl(term->fd, F_GETFL) | O_NONBLOCK);
353 setsize();
354 setmode(0);
355 term_blank();
358 static void misc_save(struct term_state *state)
360 state->row = row;
361 state->col = col;
362 state->fg = fg;
363 state->bg = bg;
364 state->top = top;
365 state->bot = bot;
366 state->mode = mode;
369 static void misc_load(struct term_state *state)
371 row = state->row;
372 col = state->col;
373 fg = state->fg;
374 bg = state->bg;
375 top = state->top;
376 bot = state->bot;
377 mode = state->mode;
380 void term_save(struct term *term)
382 visible = 0;
383 misc_save(&term->cur);
386 void term_load(struct term *t, int flags)
388 term = t;
389 misc_load(&term->cur);
390 screen = term->screen;
391 visible = flags;
392 if (flags == TERM_REDRAW) {
393 if (term->fd) {
394 lazy_draw(0, pad_rows());
395 lazy_cursor(1);
396 } else {
397 pad_blank(0);
402 void term_end(void)
404 if (term->fd)
405 close(term->fd);
406 term->fd = 0;
407 row = col = 0;
408 fg = 0;
409 bg = 0;
410 term_blank();
413 static void set_region(int t, int b)
415 top = MIN(pad_rows(), MAX(0, t - 1));
416 bot = MIN(pad_rows(), MAX(0, b ? b : pad_rows()));
417 if (origin())
418 move_cursor(top, 0);
421 #include "vt102.c"