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 static void setsize(void)
163 size
.ws_col
= pad_cols();
164 size
.ws_row
= pad_rows();
167 ioctl(term
->fd
, TIOCSWINSZ
, &size
);
170 #define PTYBUFSIZE (1 << 13)
171 static char ptybuf
[PTYBUFSIZE
];
174 static void waitpty(void)
176 struct pollfd ufds
[1];
177 ufds
[0].fd
= term
->fd
;
178 ufds
[0].events
= POLLIN
;
182 static int readpty(void)
185 return ptybuf
[ptycur
++];
188 ptylen
= read(term
->fd
, ptybuf
, PTYBUFSIZE
);
189 if (ptylen
== -1 && errno
== EAGAIN
) {
191 ptylen
= read(term
->fd
, ptybuf
, PTYBUFSIZE
);
200 static void screen_move(int dst
, int src
, int n
)
202 memmove(screen
+ dst
, screen
+ src
, n
* sizeof(*screen
));
203 memmove(fgs
+ dst
, fgs
+ src
, n
);
204 memmove(bgs
+ dst
, bgs
+ src
, n
);
207 static void screen_reset(int i
, int n
)
209 memset(screen
+ i
, 0, n
* sizeof(*screen
));
210 memset(fgs
+ i
, fg
, n
);
211 memset(bgs
+ i
, bg
, n
);
214 static void empty_rows(int sr
, int er
)
216 screen_reset(OFFSET(sr
, 0), (er
- sr
) * pad_cols());
219 static void blank_rows(int sr
, int er
)
226 static void scroll_screen(int sr
, int nr
, int n
)
229 screen_move(OFFSET(sr
+ n
, 0), OFFSET(sr
, 0), nr
* pad_cols());
231 empty_rows(sr
, sr
+ n
);
233 empty_rows(sr
+ nr
+ n
, sr
+ nr
);
234 lazy_draw(MIN(sr
, sr
+ n
), MAX(sr
+ nr
, sr
+ nr
+ n
));
238 static void insert_lines(int n
)
240 int sr
= MAX(top
, row
);
241 int nr
= bot
- row
- n
;
243 scroll_screen(sr
, nr
, n
);
246 static void delete_lines(int n
)
248 int r
= MAX(top
, row
);
250 int nr
= bot
- r
- n
;
252 scroll_screen(sr
, nr
, -n
);
255 static void move_cursor(int r
, int c
)
259 t
= origin() ? top
: 0;
260 b
= origin() ? bot
: pad_rows();
261 row
= MAX(t
, MIN(r
, b
- 1));
262 col
= MAX(0, MIN(c
, pad_cols() - 1));
264 mode
= BIT_SET(mode
, MODE_WRAPREADY
, 0);
267 static void advance(int dr
, int dc
, int scrl
)
271 if (r
>= bot
&& scrl
) {
273 int nr
= (bot
- top
) + n
;
274 scroll_screen(top
+ -n
, nr
, n
);
276 if (r
< top
&& scrl
) {
278 int nr
= (bot
- top
) - n
;
279 scroll_screen(top
, nr
, n
);
281 r
= MIN(bot
- 1, MAX(top
, r
));
282 c
= MIN(pad_cols() - 1, MAX(0, c
));
286 static void insertchar(int c
)
289 if (mode
& MODE_WRAPREADY
)
291 lazy_put(c
, row
, col
);
292 wrapready
= col
== pad_cols() - 1;
295 mode
= BIT_SET(mode
, MODE_WRAPREADY
, 1);
298 void term_send(int c
)
300 unsigned char b
= (unsigned char) c
;
302 write(term
->fd
, &b
, 1);
305 static void term_sendstr(char *s
)
308 write(term
->fd
, s
, strlen(s
));
311 static void setattr(int m
)
333 fg
= m
> 37 ? FGCOLOR
: m
- 30;
335 bg
= m
> 47 ? BGCOLOR
: m
- 40;
339 static void kill_chars(int sc
, int ec
)
342 for (i
= sc
; i
< ec
; i
++)
343 lazy_put(' ', row
, i
);
347 static void move_chars(int sc
, int nc
, int n
)
350 screen_move(OFFSET(row
, sc
+ n
), OFFSET(row
, sc
), nc
);
352 screen_reset(OFFSET(row
, sc
), n
);
354 screen_reset(OFFSET(row
, pad_cols() + n
), -n
);
355 lazy_drawcols(row
, MIN(sc
, sc
+ n
), pad_cols());
359 static void delete_chars(int n
)
362 int nc
= pad_cols() - sc
;
363 move_chars(sc
, nc
, -n
);
366 static void insert_chars(int n
)
368 int nc
= pad_cols() - col
- n
;
369 move_chars(col
, nc
, n
);
372 static void term_blank(void)
374 screen_reset(0, pad_rows() * pad_cols());
376 pad_blank(bgcolor());
381 static void ctlseq(void);
385 while (ptycur
< ptylen
) {
386 if (ptylen
- ptycur
> 15)
395 static void term_reset(void)
405 void term_exec(char *cmd
)
407 memset(term
, 0, sizeof(*term
));
408 if ((term
->pid
= forkpty(&term
->fd
, NULL
, NULL
, NULL
)) == -1) {
409 perror("failed to fork");
414 setenv("TERM", "linux", 1);
415 execlp(cmd
, cmd
, NULL
);
418 fcntl(term
->fd
, F_SETFD
, fcntl(term
->fd
, F_GETFD
) | FD_CLOEXEC
);
419 fcntl(term
->fd
, F_SETFL
, fcntl(term
->fd
, F_GETFL
) | O_NONBLOCK
);
424 static void misc_save(struct term_state
*state
)
433 static void misc_load(struct term_state
*state
)
442 void term_save(struct term
*term
)
445 misc_save(&term
->cur
);
450 void term_load(struct term
*t
, int flags
)
453 misc_load(&term
->cur
);
454 screen
= term
->screen
;
460 if (flags
== TERM_REDRAW
) {
472 memset(term
, 0, sizeof(*term
));
473 term_load(term
, visible
? TERM_REDRAW
: TERM_HIDDEN
);
476 static void set_region(int t
, int b
)
478 top
= MIN(pad_rows(), MAX(0, t
- 1));
479 bot
= MIN(pad_rows(), MAX(0, b
? b
: pad_rows()));
484 void term_screenshot(void)
486 FILE *fp
= fopen(SCREENSHOT
, "w");
488 for (i
= 0; i
< pad_rows(); i
++) {
489 for (j
= 0; j
< pad_cols(); j
++) {
490 int c
= screen
[OFFSET(i
, j
)];
491 fputc(c
? c
: ' ', fp
);