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 ATTR_BOLD 0x10
23 #define ATTR_ALL (ATTR_BOLD | ATTR_REV)
24 #define MODE_WRAPREADY 0x80
26 #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b)))
27 #define OFFSET(r, c) ((r) * pad_cols() + (c))
29 static struct term
*term
;
30 static unsigned int *screen
;
31 static unsigned char *fgs
, *bgs
;
33 static unsigned char fg
, bg
;
35 static unsigned int mode
;
38 #define MAXLINES (1 << 13)
39 static int dirty
[MAXLINES
];
42 static unsigned char fgcolor(void)
44 int c
= mode
& ATTR_REV
? bg
: fg
;
45 return mode
& ATTR_BOLD
? c
| 0x08 : c
;
48 static unsigned char bgcolor(void)
50 return mode
& ATTR_REV
? fg
: bg
;
53 static void _term_show(int r
, int c
, int cursor
)
56 unsigned char fg
= screen
[i
] ? fgs
[i
] : fgcolor();
57 unsigned char bg
= screen
[i
] ? bgs
[i
] : bgcolor();
58 if (cursor
&& mode
& MODE_CURSOR
) {
64 pad_put(screen
[i
], r
, c
, fg
, bg
);
67 static void _draw_row(int r
)
70 pad_blankrow(r
, bgcolor());
71 for (i
= 0; i
< pad_cols(); i
++) {
72 unsigned int c
= screen
[OFFSET(r
, i
)];
73 if (c
&& (c
!= ' ' || bgs
[OFFSET(r
, i
)] != bgcolor()))
78 static void lazy_draw(int sr
, int er
)
83 for (i
= sr
; i
< er
; i
++) {
91 static void lazy_drawcols(int r
, int sc
, int ec
)
99 for (i
= sc
; i
< ec
; i
++)
104 static void lazy_put(int ch
, int r
, int c
)
106 int i
= OFFSET(r
, c
);
118 static void lazy_cursor(int put
)
125 _term_show(row
, col
, put
);
128 static void lazy_clean()
131 memset(dirty
, 0, sizeof(*dirty
) * MAXLINES
);
134 static void lazy_flush()
139 _term_show(row
, col
, 0);
140 for (i
= 0; i
< pad_rows(); i
++)
144 _term_show(row
, col
, 1);
147 static void term_redraw(void)
150 for (i
= 0; i
< pad_rows(); i
++)
152 _term_show(row
, col
, 1);
155 static int origin(void)
157 return mode
& MODE_ORIGIN
;
160 #define PTYBUFSIZE (1 << 13)
161 static char ptybuf
[PTYBUFSIZE
];
164 static void waitpty(void)
166 struct pollfd ufds
[1];
167 ufds
[0].fd
= term
->fd
;
168 ufds
[0].events
= POLLIN
;
172 static int readpty(void)
175 return ptybuf
[ptycur
++];
178 ptylen
= read(term
->fd
, ptybuf
, PTYBUFSIZE
);
179 if (ptylen
== -1 && errno
== EAGAIN
) {
181 ptylen
= read(term
->fd
, ptybuf
, PTYBUFSIZE
);
190 static void screen_move(int dst
, int src
, int n
)
192 memmove(screen
+ dst
, screen
+ src
, n
* sizeof(*screen
));
193 memmove(fgs
+ dst
, fgs
+ src
, n
);
194 memmove(bgs
+ dst
, bgs
+ src
, n
);
197 static void screen_reset(int i
, int n
)
199 memset(screen
+ i
, 0, n
* sizeof(*screen
));
200 memset(fgs
+ i
, fg
, n
);
201 memset(bgs
+ i
, bg
, n
);
204 static void empty_rows(int sr
, int er
)
206 screen_reset(OFFSET(sr
, 0), (er
- sr
) * pad_cols());
209 static void blank_rows(int sr
, int er
)
216 static void scroll_screen(int sr
, int nr
, int n
)
219 screen_move(OFFSET(sr
+ n
, 0), OFFSET(sr
, 0), nr
* pad_cols());
221 empty_rows(sr
, sr
+ n
);
223 empty_rows(sr
+ nr
+ n
, sr
+ nr
);
224 lazy_draw(MIN(sr
, sr
+ n
), MAX(sr
+ nr
, sr
+ nr
+ n
));
228 static void insert_lines(int n
)
230 int sr
= MAX(top
, row
);
231 int nr
= bot
- row
- n
;
233 scroll_screen(sr
, nr
, n
);
236 static void delete_lines(int n
)
238 int r
= MAX(top
, row
);
240 int nr
= bot
- r
- n
;
242 scroll_screen(sr
, nr
, -n
);
245 static void move_cursor(int r
, int c
)
249 t
= origin() ? top
: 0;
250 b
= origin() ? bot
: pad_rows();
251 row
= MAX(t
, MIN(r
, b
- 1));
252 col
= MAX(0, MIN(c
, pad_cols() - 1));
254 mode
= BIT_SET(mode
, MODE_WRAPREADY
, 0);
257 static void advance(int dr
, int dc
, int scrl
)
261 if (r
>= bot
&& scrl
) {
263 int nr
= (bot
- top
) + n
;
264 scroll_screen(top
+ -n
, nr
, n
);
266 if (r
< top
&& scrl
) {
268 int nr
= (bot
- top
) - n
;
269 scroll_screen(top
, nr
, n
);
271 r
= MIN(bot
- 1, MAX(top
, r
));
272 c
= MIN(pad_cols() - 1, MAX(0, c
));
276 static void insertchar(int c
)
279 if (mode
& MODE_WRAPREADY
)
281 lazy_put(c
, row
, col
);
282 wrapready
= col
== pad_cols() - 1;
285 mode
= BIT_SET(mode
, MODE_WRAPREADY
, 1);
288 void term_send(int c
)
290 unsigned char b
= (unsigned char) c
;
292 write(term
->fd
, &b
, 1);
295 static void term_sendstr(char *s
)
298 write(term
->fd
, s
, strlen(s
));
301 static void setattr(int m
)
323 fg
= m
> 37 ? FGCOLOR
: m
- 30;
325 bg
= m
> 47 ? BGCOLOR
: m
- 40;
329 static void kill_chars(int sc
, int ec
)
332 for (i
= sc
; i
< ec
; i
++)
333 lazy_put(' ', row
, i
);
337 static void move_chars(int sc
, int nc
, int n
)
340 screen_move(OFFSET(row
, sc
+ n
), OFFSET(row
, sc
), nc
);
342 screen_reset(OFFSET(row
, sc
), n
);
344 screen_reset(OFFSET(row
, pad_cols() + n
), -n
);
345 lazy_drawcols(row
, MIN(sc
, sc
+ n
), pad_cols());
349 static void delete_chars(int n
)
352 int nc
= pad_cols() - sc
;
353 move_chars(sc
, nc
, -n
);
356 static void insert_chars(int n
)
358 int nc
= pad_cols() - col
- n
;
359 move_chars(col
, nc
, n
);
362 static void term_blank(void)
364 screen_reset(0, pad_rows() * pad_cols());
366 pad_blank(bgcolor());
371 static void ctlseq(void);
375 while (ptycur
< ptylen
) {
376 if (ptylen
- ptycur
> 15)
385 static void term_reset(void)
395 void term_exec(char *cmd
)
398 size
.ws_col
= pad_cols();
399 size
.ws_row
= pad_rows();
402 memset(term
, 0, sizeof(*term
));
403 if ((term
->pid
= forkpty(&term
->fd
, NULL
, NULL
, &size
)) == -1) {
404 perror("failed to fork");
409 setenv("TERM", "linux", 1);
410 execlp(cmd
, cmd
, NULL
);
413 fcntl(term
->fd
, F_SETFD
, fcntl(term
->fd
, F_GETFD
) | FD_CLOEXEC
);
414 fcntl(term
->fd
, F_SETFL
, fcntl(term
->fd
, F_GETFL
) | O_NONBLOCK
);
418 static void misc_save(struct term_state
*state
)
427 static void misc_load(struct term_state
*state
)
436 void term_save(struct term
*term
)
439 misc_save(&term
->cur
);
444 void term_load(struct term
*t
, int flags
)
447 misc_load(&term
->cur
);
448 screen
= term
->screen
;
454 if (flags
== TERM_REDRAW
) {
466 memset(term
, 0, sizeof(*term
));
467 term_load(term
, visible
? TERM_REDRAW
: TERM_HIDDEN
);
470 static void set_region(int t
, int b
)
472 top
= MIN(pad_rows(), MAX(0, t
- 1));
473 bot
= MIN(pad_rows(), MAX(0, b
? b
: pad_rows()));
478 void term_screenshot(void)
480 FILE *fp
= fopen(SCREENSHOT
, "w");
482 for (i
= 0; i
< pad_rows(); i
++) {
483 for (j
= 0; j
< pad_cols(); j
++) {
484 int c
= screen
[OFFSET(i
, j
)];
485 fputc(c
? c
: ' ', fp
);