1 #include "links.h"
2 
hard_write(int fd,unsigned char * p,int l)3 int hard_write(int fd, unsigned char *p, int l)
4 {
5 	int t = 0;
6 	while (l > 0) {
7 		int w;
8 		EINTRLOOP(w, write(fd, p, l));
9 		if (w < 0)
10 			return -1;
11 		if (!w) {
12 			errno = ENOSPC;
13 			break;
14 		}
15 		t += w;
16 		p += w;
17 		l -= w;
18 	}
19 	return t;
20 }
21 
hard_read(int fd,unsigned char * p,int l)22 int hard_read(int fd, unsigned char *p, int l)
23 {
24 	int r = 1;
25 	int t = 0;
26 	while (l > 0 && r) {
27 		EINTRLOOP(r, read(fd, p, l));
28 		if (r < 0)
29 			return -1;
30 		t += r;
31 		p += r;
32 		l -= r;
33 	}
34 	return t;
35 }
36 
get_cwd()37 unsigned char *get_cwd()
38 {
39 	int bufsize = 128;
40 	unsigned char *buf;
41 	unsigned char *gcr;
42 	while (1) {
43 		buf = mem_alloc(bufsize);
44 		ENULLLOOP(gcr, getcwd(buf, bufsize));
45 		if (gcr) return buf;
46 		mem_free(buf);
47 		if (errno != ERANGE) return NULL;
48 		if ((unsigned)bufsize > MAXINT - 128) overalloc();
49 		bufsize += 128;
50 	}
51 	return NULL;
52 }
53 
set_cwd(unsigned char * path)54 void set_cwd(unsigned char *path)
55 {
56 	int rs;
57 	if (path)
58 		EINTRLOOP(rs, chdir(path));
59 }
60 
61 struct list_head terminals = {&terminals, &terminals};
62 
alloc_term_screen(struct terminal * term,int x,int y)63 void alloc_term_screen(struct terminal *term, int x, int y)
64 {
65 	unsigned *s, *t;
66 	if (x < 0) x = 0;
67 	if (y < 0) y = 0;
68 	if (x && (unsigned)x * (unsigned)y / (unsigned)x != (unsigned)y) overalloc();
69 	if ((unsigned)x * (unsigned)y > MAXINT / sizeof(unsigned)) overalloc();
70 	s = mem_realloc(term->screen, x * y * sizeof(unsigned));
71 	t = mem_realloc(term->last_screen, x * y * sizeof(unsigned));
72 	memset(t, -1, x * y * sizeof(unsigned));
73 	term->x = x;
74 	term->y = y;
75 	term->last_screen = t;
76 	memset(s, 0, x * y * sizeof(unsigned));
77 	term->screen = s;
78 	term->dirty = 1;
79 }
80 
81 void in_term(struct terminal *);
82 void destroy_terminal(struct terminal *);
83 void check_if_no_terminal();
84 
clear_terminal(struct terminal * term)85 void clear_terminal(struct terminal *term)
86 {
87 	fill_area(term, 0, 0, term->x, term->y, ' ' | COL(007));
88 	set_cursor(term, 0, 0, 0, 0);
89 }
90 
redraw_terminal_ev(struct terminal * term,int e)91 void redraw_terminal_ev(struct terminal *term, int e)
92 {
93 	struct window *win;
94 	struct event ev = {0, 0, 0, 0};
95 	ev.ev = e;
96 	ev.x = term->x;
97 	ev.y = term->y;
98 	clear_terminal(term);
99 	term->redrawing = 2;
100 	foreachback(win, term->windows) win->handler(win, &ev, 0);
101 	term->redrawing = 0;
102 }
103 
redraw_terminal(struct terminal * term)104 void redraw_terminal(struct terminal *term)
105 {
106 	redraw_terminal_ev(term, EV_REDRAW);
107 }
108 
redraw_terminal_all(struct terminal * term)109 void redraw_terminal_all(struct terminal *term)
110 {
111 	redraw_terminal_ev(term, EV_RESIZE);
112 }
113 
erase_screen(struct terminal * term)114 void erase_screen(struct terminal *term)
115 {
116 	if (!term->master || !is_blocked()) {
117 		if (term->master) want_draw();
118 		hard_write(term->fdout, "\033[2J\033[1;1H", 10);
119 		if (term->master) done_draw();
120 	}
121 }
122 
redraw_terminal_cls(struct terminal * term)123 void redraw_terminal_cls(struct terminal *term)
124 {
125 	erase_screen(term);
126 	alloc_term_screen(term, term->x, term->y);
127 	redraw_terminal_all(term);
128 }
129 
cls_redraw_all_terminals()130 void cls_redraw_all_terminals()
131 {
132 	struct terminal *term;
133 	foreach(term, terminals) redraw_terminal_cls(term);
134 }
135 
redraw_from_window(struct window * win)136 void redraw_from_window(struct window *win)
137 {
138 	struct terminal *term = win->term;
139 	struct window *end = (void *)&term->windows;
140 	struct event ev = {EV_REDRAW, 0, 0, 0};
141 	ev.x = term->x;
142 	ev.y = term->y;
143 	if (term->redrawing) return;
144 	term->redrawing = 1;
145 	for (win = win->prev; win != end; win = win->prev) {
146 		win->handler(win, &ev, 0);
147 	}
148 	term->redrawing = 0;
149 }
150 
redraw_below_window(struct window * win)151 void redraw_below_window(struct window *win)
152 {
153 	int tr;
154 	struct terminal *term = win->term;
155 	struct window *end = win;
156 	struct event ev = {EV_REDRAW, 0, 0, 0};
157 	ev.x = term->x;
158 	ev.y = term->y;
159 	if (term->redrawing >= 2) return;
160 	tr = term->redrawing;
161 	win->term->redrawing = 2;
162 	for (win = term->windows.prev; win != end; win = win->prev) {
163 		win->handler(win, &ev, 0);
164 	}
165 	term->redrawing = tr;
166 }
167 
add_window_at_pos(struct terminal * term,void (* handler)(struct window *,struct event *,int),void * data,struct window * at)168 void add_window_at_pos(struct terminal *term, void (*handler)(struct window *, struct event *, int), void *data, struct window *at)
169 {
170 	struct event ev = {EV_INIT, 0, 0, 0};
171 	struct window *win;
172 	ev.x = term->x;
173 	ev.y = term->y;
174 	win = mem_alloc(sizeof (struct window));
175 	win->handler = handler;
176 	win->data = data;
177 	win->term = term;
178 	win->xp = win->yp = 0;
179 	add_at_pos(at, win);
180 	win->handler(win, &ev, 0);
181 }
182 
add_window(struct terminal * term,void (* handler)(struct window *,struct event *,int),void * data)183 void add_window(struct terminal *term, void (*handler)(struct window *, struct event *, int), void *data)
184 {
185 	add_window_at_pos(term, handler, data, (struct window *)(void *)&term->windows);
186 }
187 
delete_window(struct window * win)188 void delete_window(struct window *win)
189 {
190 	struct event ev = {EV_ABORT, 0, 0, 0};
191 	win->handler(win, &ev, 1);
192 	del_from_list(win);
193 	if (win->data) mem_free(win->data);
194 	redraw_terminal(win->term);
195 	mem_free(win);
196 }
197 
delete_window_ev(struct window * win,struct event * ev)198 void delete_window_ev(struct window *win, struct event *ev)
199 {
200 	struct window *w = win->next;
201 	if ((void *)w == &win->term->windows) w = NULL;
202 	delete_window(win);
203 	if (ev && w && w->next != w) w->handler(w, ev, 1);
204 }
205 
set_window_ptr(struct window * win,int x,int y)206 void set_window_ptr(struct window *win, int x, int y)
207 {
208 	win->xp = x;
209 	win->yp = y;
210 }
211 
get_parent_ptr(struct window * win,int * x,int * y)212 void get_parent_ptr(struct window *win, int *x, int *y)
213 {
214 	if ((void *)win->next != &win->term->windows) {
215 		*x = win->next->xp;
216 		*y = win->next->yp;
217 	} else {
218 		*x = *y = 0;
219 	}
220 }
221 
get_root_window(struct terminal * term)222 struct window *get_root_window(struct terminal *term)
223 {
224 	if (list_empty(term->windows)) {
225 		internal("terminal has no windows");
226 		return NULL;
227 	}
228 	return (struct window *)term->windows.prev;
229 }
230 
231 struct ewd {
232 	void (*fn)(void *);
233 	void *data;
234 	int b;
235 };
236 
empty_window_handler(struct window * win,struct event * ev,int fwd)237 void empty_window_handler(struct window *win, struct event *ev, int fwd)
238 {
239 	struct window *n;
240 	struct ewd *ewd = win->data;
241 	int x, y;
242 	void (*fn)(void *) = ewd->fn;
243 	void *data = ewd->data;
244 	if (ewd->b) return;
245 	switch ((int)ev->ev) {
246 		case EV_INIT:
247 		case EV_RESIZE:
248 		case EV_REDRAW:
249 			get_parent_ptr(win, &x, &y);
250 			set_window_ptr(win, x, y);
251 			return;
252 		case EV_ABORT:
253 			fn(data);
254 			return;
255 	}
256 	ewd->b = 1;
257 	n = win->next;
258 	delete_window(win);
259 	fn(data);
260 	if (n->next != n) n->handler(n, ev, fwd);
261 }
262 
add_empty_window(struct terminal * term,void (* fn)(void *),void * data)263 void add_empty_window(struct terminal *term, void (*fn)(void *), void *data)
264 {
265 	struct ewd *ewd;
266 	ewd = mem_alloc(sizeof(struct ewd));
267 	ewd->fn = fn;
268 	ewd->data = data;
269 	ewd->b = 0;
270 	add_window(term, empty_window_handler, ewd);
271 }
272 
free_term_specs()273 void free_term_specs()
274 {
275 	free_list(term_specs);
276 }
277 
278 struct list_head term_specs = {&term_specs, &term_specs};
279 
280 struct term_spec dumb_term = { NULL, NULL, "", 0, 1, 0, 0, 0, 0 };
281 
get_term_spec(unsigned char * term)282 struct term_spec *get_term_spec(unsigned char *term)
283 {
284 	struct term_spec *t;
285 	foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t;
286 	return &dumb_term;
287 }
288 
new_term_spec(unsigned char * term)289 struct term_spec *new_term_spec(unsigned char *term)
290 {
291 	struct term_spec *t;
292 	foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t;
293 	t = mem_alloc(sizeof(struct term_spec));
294 	memcpy(t, &dumb_term, sizeof(struct term_spec));
295 	if (strlen(term) < MAX_TERM_LEN) strcpy(t->term, term);
296 	else memcpy(t->term, term, MAX_TERM_LEN - 1), t->term[MAX_TERM_LEN - 1] = 0;
297 	add_to_list(term_specs, t);
298 	sync_term_specs();
299 	return t;
300 }
301 
sync_term_specs()302 void sync_term_specs()
303 {
304 	struct terminal *term;
305 	foreach (term, terminals) term->spec = get_term_spec(term->term);
306 }
307 
init_term(int fdin,int fdout,void (* root_window)(struct window *,struct event *,int))308 struct terminal *init_term(int fdin, int fdout, void (*root_window)(struct window *, struct event *, int))
309 {
310 	struct terminal *term;
311 	struct window *win;
312 	term = mem_alloc(sizeof (struct terminal));
313 	memset(term, 0, sizeof(struct terminal));
314 	term->fdin = fdin;
315 	term->fdout = fdout;
316 	term->master = term->fdout == get_output_handle();
317 	/*term->x = 0;
318 	term->y = 0;
319 	term->cx = 0;
320 	term->cy = 0;*/
321 	term->lcx = -1;
322 	term->lcy = -1;
323 	term->dirty = 1;
324 	term->redrawing = 0;
325 	term->blocked = -1;
326 	term->screen = DUMMY;
327 	term->last_screen = DUMMY;
328 	term->spec = &dumb_term;
329 	term->term[0] = 0;
330 	term->cwd[0] = 0;
331 	term->input_queue = DUMMY;
332 	term->qlen = 0;
333 	init_list(term->windows);
334 	win = mem_alloc(sizeof (struct window));
335 	win->handler = root_window;
336 	win->data = NULL;
337 	win->term = term;
338 	add_to_list(term->windows, win);
339 	/*alloc_term_screen(term, 80, 25);*/
340 	add_to_list(terminals, term);
341 	set_handlers(fdin, (void (*)(void *))in_term, NULL, (void (*)(void *))destroy_terminal, term);
342 	return term;
343 }
344 
in_term(struct terminal * term)345 void in_term(struct terminal *term)
346 {
347 	struct event *ev;
348 	int r;
349 	unsigned char *iq;
350 	if ((unsigned)term->qlen + ALLOC_GR > MAXINT) overalloc();
351 	iq = mem_realloc(term->input_queue, term->qlen + ALLOC_GR);
352 	term->input_queue = iq;
353 	EINTRLOOP(r, read(term->fdin, iq + term->qlen, ALLOC_GR));
354 	if (r <= 0) {
355 		if (r == -1 && errno != ECONNRESET) error("ERROR: error %d on terminal: could not read event", errno);
356 		destroy_terminal(term);
357 		return;
358 	}
359 	term->qlen += r;
360 	test_queue:
361 	if ((size_t)term->qlen < sizeof(struct event)) return;
362 	ev = (struct event *)iq;
363 	r = sizeof(struct event);
364 	if (ev->ev != EV_INIT && ev->ev != EV_RESIZE && ev->ev != EV_REDRAW && ev->ev != EV_KBD && ev->ev != EV_MOUSE && ev->ev != EV_ABORT) {
365 		error("ERROR: error on terminal: bad event %d", (int)ev->ev);
366 		goto mm;
367 	}
368 	if (ev->ev == EV_INIT) {
369 		int init_len;
370 		if ((size_t)term->qlen < sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int)) return;
371 		init_len = *(int *)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + sizeof(int));
372 		if ((size_t)term->qlen < sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int) + init_len) return;
373 		memcpy(term->term, iq + sizeof(struct event), MAX_TERM_LEN);
374 		term->term[MAX_TERM_LEN - 1] = 0;
375 		memcpy(term->cwd, iq + sizeof(struct event) + MAX_TERM_LEN, MAX_CWD_LEN);
376 		term->cwd[MAX_CWD_LEN - 1] = 0;
377 		term->environment = *(int *)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN);
378 		ev->b = (my_intptr_t)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + sizeof(int));
379 		r = sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int) + init_len;
380 		sync_term_specs();
381 	}
382 	if (ev->ev == EV_REDRAW || ev->ev == EV_RESIZE || ev->ev == EV_INIT) {
383 		struct window *win;
384 		send_redraw:
385 		if (ev->x < 0 || ev->y < 0) {
386 			error("ERROR: bad terminal size: %d, %d", (int)ev->x, (int)ev->y);
387 			goto mm;
388 		}
389 		alloc_term_screen(term, ev->x, ev->y);
390 		clear_terminal(term);
391 		erase_screen(term);
392 		term->redrawing = 1;
393 		foreachback(win, term->windows) win->handler(win, ev, 0);
394 		term->redrawing = 0;
395 	}
396 	if (ev->ev == EV_KBD || ev->ev == EV_MOUSE) {
397 		if (ev->ev == EV_KBD && upcase(ev->x) == 'L' && ev->y == KBD_CTRL) {
398 			ev->ev = EV_REDRAW;
399 			ev->x = term->x;
400 			ev->y = term->y;
401 			goto send_redraw;
402 		}
403 		else if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C) ((struct window *)term->windows.prev)->handler(term->windows.prev, ev, 0);
404 		else ((struct window *)term->windows.next)->handler(term->windows.next, ev, 0);
405 	}
406 	if (ev->ev == EV_ABORT) {
407 		destroy_terminal(term);
408 		return;
409 	}
410 	/*redraw_screen(term);*/
411 	mm:
412 	if (term->qlen == r) term->qlen = 0;
413 	else memmove(iq, iq + r, term->qlen -= r);
414 	goto test_queue;
415 }
416 
getcompcode(int c)417 static inline int getcompcode(int c)
418 {
419 	return (c<<1 | (c&4)>>2) & 7;
420 }
421 
422 unsigned char frame_dumb[48] =	"   ||||++||++++++--|-+||++--|-+----++++++++     ";
423 unsigned char frame_vt100[48] =	"aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla    ";
424 unsigned char frame_koi[48] = {
425 	144,145,146,129,135,178,180,167,
426 	166,181,161,168,174,173,172,131,
427 	132,137,136,134,128,138,175,176,
428 	171,165,187,184,177,160,190,185,
429 	186,182,183,170,169,162,164,189,
430 	188,133,130,141,140,142,143,139,
431 };
432 unsigned char frame_freebsd[48] = {
433 	130,138,128,153,150,150,150,140,
434 	140,150,153,140,139,139,139,140,
435 	142,151,152,149,146,143,149,149,
436 	142,141,151,152,149,146,143,151,
437 	151,152,152,142,142,141,141,143,
438 	143,139,141,128,128,128,128,128,
439 };
440 unsigned char frame_restrict[48] = {
441 	0, 0, 0, 0, 0, 179, 186, 186,
442 	205, 0, 0, 0, 0, 186, 205, 0,
443 	0, 0, 0, 0, 0, 0, 179, 186,
444 	0, 0, 0, 0, 0, 0, 0, 205,
445 	196, 205, 196, 186, 205, 205, 186, 186,
446 	179, 0, 0, 0, 0, 0, 0, 0,
447 };
448 
449 #define PRINT_CHAR(p)									\
450 {											\
451 	unsigned ch = term->screen[p];							\
452 	unsigned char c = ch & 0xff;							\
453 	unsigned char A = ch >> 8 & 0x7f;						\
454 	if (s->mode == TERM_LINUX) {							\
455 		if (s->m11_hack) {							\
456 			if ((int)(ch >> 15) != mode) {					\
457 				if (!(mode = ch >> 15)) add_to_str(&a, &l, "\033[10m");	\
458 				else add_to_str(&a, &l, "\033[11m");			\
459 			}								\
460 		}									\
461 		if (s->restrict_852 && (ch >> 15) && c >= 176 && c < 224) {		\
462 			if (frame_restrict[c - 176]) c = frame_restrict[c - 176];	\
463 		}									\
464 	} else if (s->mode == TERM_VT100) {						\
465 		if ((int)(ch >> 15) != mode) {						\
466 			if (!(mode = ch >> 15)) add_to_str(&a, &l, "\x0f");		\
467 			else add_to_str(&a, &l, "\x0e");				\
468 		}									\
469 		if (mode && c >= 176 && c < 224) c = frame_vt100[c - 176];		\
470 	} else if (s->mode == TERM_KOI8 && (ch >> 15) && c >= 176 && c < 224) { c = frame_koi[c - 176];\
471 	} else if (s->mode == TERM_FREEBSD && (ch >> 15) && c >= 176 && c < 224) { c = frame_freebsd[c - 176];\
472 	} else if (s->mode == TERM_DUMB && (ch >> 15) && c >= 176 && c < 224) c = frame_dumb[c - 176];\
473 	if (!(A & 0100) && (A >> 3) == (A & 7)) A = (A & 070) | 7 * !(A & 020);		\
474 	if (A != attrib) {								\
475 		attrib = A;								\
476 		add_to_str(&a, &l, "\033[0");						\
477 		if (s->col) {								\
478 			unsigned char m[4];						\
479 			m[0] = ';'; m[1] = '3'; m[3] = 0;				\
480 			m[2] = (attrib & 7) + '0';					\
481 			add_to_str(&a, &l, m);						\
482 			m[1] = '4';							\
483 			m[2] = (attrib >> 3 & 7) + '0';					\
484 			add_to_str(&a, &l, m);						\
485 		} else if (getcompcode(attrib & 7) < getcompcode(attrib >> 3 & 7))	\
486 			add_to_str(&a, &l, ";7");					\
487 		if (attrib & 0100) add_to_str(&a, &l, ";1");				\
488 		add_to_str(&a, &l, "m");						\
489 	}										\
490 	if (c >= ' ' && c != 127 && (c != 155 || cp2u(155, term->spec->charset) != -1)) add_chr_to_str(&a, &l, c);\
491 	else if (!c || c == 1) add_chr_to_str(&a, &l, ' ');				\
492 	else add_chr_to_str(&a, &l, '.');						\
493 	cx++;										\
494 }											\
495 
redraw_all_terminals()496 void redraw_all_terminals()
497 {
498 	struct terminal *term;
499 	foreach(term, terminals) redraw_screen(term);
500 }
501 
redraw_screen(struct terminal * term)502 void redraw_screen(struct terminal *term)
503 {
504 	int x, y, p = 0;
505 	int cx = term->lcx, cy = term->lcy;
506 	unsigned char *a;
507 	int attrib = -1;
508 	int mode = -1;
509 	int l = 0;
510 	struct term_spec *s;
511 	if (!term->dirty || (term->master && is_blocked())) return;
512 	a = init_str();
513 	s = term->spec;
514 	for (y = 0; y < term->y; y++) {
515 		if (!memcmp(&term->screen[p], &term->last_screen[p], sizeof(unsigned) * term->x)) {
516 			p += term->x;
517 			continue;
518 		}
519 		for (x = 0; x < term->x; x++, p++) {
520 			if (y == term->y - 1 && x == term->x - 1) break;
521 			if (term->screen[p] == term->last_screen[p]) continue;
522 			/*if ((term->screen[p] & 0x3800) == (term->last_screen[p] & 0x3800) && ((term->screen[p] & 0xff) == 0 || (term->screen[p] & 0xff) == 1 || (term->screen[p] & 0xff) == ' ') && ((term->last_screen[p] & 0xff) == 0 || (term->last_screen[p] & 0xff) == 1 || (term->last_screen[p] & 0xff) == ' ') && (x != term->cx || y != term->cy)) continue;*/
523 			/*fprintf(stderr, "%d.%d : %04x -> %04x\n", x, y, term->last_screen[p] & 0xffff, term->screen[p] & 0xffff);*/
524 			term->last_screen[p] = term->screen[p];
525 			if (cx == x && cy == y) goto pc;/*PRINT_CHAR(p)*/
526 			else if (cy == y && x - cx < 10 && x - cx > 0) {
527 				int i;
528 				for (i = x - cx; i >= 0; i--) PRINT_CHAR(p - i);
529 			} else {
530 				add_to_str(&a, &l, "\033[");
531 				add_num_to_str(&a, &l, y + 1);
532 				add_to_str(&a, &l, ";");
533 				add_num_to_str(&a, &l, x + 1);
534 				add_to_str(&a, &l, "H");
535 				cx = x; cy = y;
536 				pc:
537 				PRINT_CHAR(p);
538 			}
539 		}
540 	}
541 	if (l) {
542 		if (s->col) add_to_str(&a, &l, "\033[37;40m");
543 		add_to_str(&a, &l, "\033[0m");
544 		if (s->mode == TERM_LINUX && s->m11_hack) add_to_str(&a, &l, "\033[10m");
545 		if (s->mode == TERM_VT100) add_to_str(&a, &l, "\x0f");
546 	}
547 	term->lcx = cx;
548 	term->lcy = cy;
549 	if (term->cx != term->lcx || term->cy != term->lcy) {
550 		term->lcx = term->cx;
551 		term->lcy = term->cy;
552 		add_to_str(&a, &l, "\033[");
553 		add_num_to_str(&a, &l, term->cy + 1);
554 		add_to_str(&a, &l, ";");
555 		add_num_to_str(&a, &l, term->cx + 1);
556 		add_to_str(&a, &l, "H");
557 	}
558 	if (l && term->master) want_draw();
559 	hard_write(term->fdout, a, l);
560 	if (l && term->master) done_draw();
561 	mem_free(a);
562 	term->dirty = 0;
563 }
564 
destroy_terminal(struct terminal * term)565 void destroy_terminal(struct terminal *term)
566 {
567 	int rs;
568 	unregister_bottom_half((void (*)(void *))destroy_terminal, term);
569 	while ((term->windows.next) != &term->windows) delete_window(term->windows.next);
570 	/*if (term->cwd) mem_free(term->cwd);*/
571 	if (term->title) mem_free(term->title);
572 	mem_free(term->screen);
573 	mem_free(term->last_screen);
574 	set_handlers(term->fdin, NULL, NULL, NULL, NULL);
575 	mem_free(term->input_queue);
576 	if (term->blocked != -1) {
577 		EINTRLOOP(rs, close(term->blocked));
578 		set_handlers(term->blocked, NULL, NULL, NULL, NULL);
579 	}
580 	del_from_list(term);
581 	EINTRLOOP(rs, close(term->fdin));
582 	if (!term->master) {
583 		if (term->fdout != term->fdin)
584 			EINTRLOOP(rs, close(term->fdout));
585 	} else {
586 		unhandle_terminal_signals(term);
587 		free_all_itrms();
588 #ifndef NO_FORK_ON_EXIT
589 		if (!list_empty(terminals)) {
590 			pid_t rp;
591 			EINTRLOOP(rp, fork());
592 			if (rp > 0) _exit(0);
593 		}
594 #endif
595 	}
596 	mem_free(term);
597 	check_if_no_terminal();
598 }
599 
destroy_all_terminals()600 void destroy_all_terminals()
601 {
602 	struct terminal *term;
603 	while ((void *)(term = terminals.next) != &terminals) destroy_terminal(term);
604 }
605 
check_if_no_terminal()606 void check_if_no_terminal()
607 {
608 	if (!list_empty(terminals)) return;
609 	terminate_loop = 1;
610 }
611 
set_char(struct terminal * t,int x,int y,unsigned c)612 void set_char(struct terminal *t, int x, int y, unsigned c)
613 {
614 	t->dirty = 1;
615 	if (x >= 0 && x < t->x && y >= 0 && y < t->y) t->screen[x + t->x * y] = c;
616 }
617 
get_char(struct terminal * t,int x,int y)618 unsigned get_char(struct terminal *t, int x, int y)
619 {
620 	if (!t->x || !t->y) return 070 * 256 + ' ';
621 	if (x >= t->x) x = t->x - 1;
622 	if (x < 0) x = 0;
623 	if (y >= t->y) y = t->y - 1;
624 	if (y < 0) y = 0;
625 	return t->screen[x + t->x * y];
626 }
627 
set_color(struct terminal * t,int x,int y,unsigned c)628 void set_color(struct terminal *t, int x, int y, unsigned c)
629 {
630 	t->dirty = 1;
631 	if (x >= 0 && x < t->x && y >= 0 && y < t->y) t->screen[x + t->x * y] = (t->screen[x + t->x * y] & 0x80ff) | (c & ~0x80ff);
632 }
633 
set_only_char(struct terminal * t,int x,int y,unsigned c)634 void set_only_char(struct terminal *t, int x, int y, unsigned c)
635 {
636 	t->dirty = 1;
637 	if (x >= 0 && x < t->x && y >= 0 && y < t->y) t->screen[x + t->x * y] = (t->screen[x + t->x * y] & ~0x80ff) | (c & 0x80ff);
638 }
639 
set_line(struct terminal * t,int x,int y,int l,chr * line)640 void set_line(struct terminal *t, int x, int y, int l, chr *line)
641 {
642 	int i;
643 	t->dirty = 1;
644 	for (i = x >= 0 ? 0 : -x; i < (x+l <= t->x ? l : t->x-x); i++)
645 		t->screen[x+i + t->x * y] = line[i];
646 }
647 
set_line_color(struct terminal * t,int x,int y,int l,unsigned c)648 void set_line_color(struct terminal *t, int x, int y, int l, unsigned c)
649 {
650 	int i;
651 	t->dirty = 1;
652 	for (i = x >= 0 ? 0 : -x; i < (x+l <= t->x ? l : t->x-x); i++)
653 		t->screen[x+i + t->x * y] = (t->screen[x+i + t->x * y] & 0x80ff) | (c & ~0x80ff);
654 }
655 
fill_area(struct terminal * t,int x,int y,int xw,int yw,unsigned c)656 void fill_area(struct terminal *t, int x, int y, int xw, int yw, unsigned c)
657 {
658 	int i;
659 	unsigned *p, *ps;
660 	if (x < 0) xw += x, x = 0;
661 	if (x + xw > t->x) xw = t->x - x;
662 	if (xw <= 0) return;
663 	if (y < 0) yw += y, y = 0;
664 	if (y + yw > t->y) yw = t->y - y;
665 	if (yw <= 0) return;
666 	t->dirty = 1;
667 	p = ps = &t->screen[x + t->x * y];
668 	for (i = 0; i < xw; i++)
669 		*p++ = c;
670 	p = ps;
671 	for (i = 1; i < yw; i++) {
672 		p += t->x;
673 		memcpy(p, ps, xw * sizeof(unsigned));
674 	}
675 }
676 
677 int p1[] = { 218, 191, 192, 217, 179, 196 };
678 int p2[] = { 201, 187, 200, 188, 186, 205 };
679 
draw_frame(struct terminal * t,int x,int y,int xw,int yw,unsigned c,int w)680 void draw_frame(struct terminal *t, int x, int y, int xw, int yw, unsigned c, int w)
681 {
682 	int *p = w > 1 ? p2 : p1;
683 	c |= ATTR_FRAME;
684 	set_char(t, x, y, c+p[0]);
685 	set_char(t, x+xw-1, y, c+p[1]);
686 	set_char(t, x, y+yw-1, c+p[2]);
687 	set_char(t, x+xw-1, y+yw-1, c+p[3]);
688 	fill_area(t, x, y+1, 1, yw-2, c+p[4]);
689 	fill_area(t, x+xw-1, y+1, 1, yw-2, c+p[4]);
690 	fill_area(t, x+1, y, xw-2, 1, c+p[5]);
691 	fill_area(t, x+1, y+yw-1, xw-2, 1, c+p[5]);
692 }
693 
print_text(struct terminal * t,int x,int y,int l,unsigned char * text,unsigned c)694 void print_text(struct terminal *t, int x, int y, int l, unsigned char *text, unsigned c)
695 {
696 	for (; l-- && *text; text++, x++) set_char(t, x, y, *text + c);
697 }
698 
set_cursor(struct terminal * term,int x,int y,int altx,int alty)699 void set_cursor(struct terminal *term, int x, int y, int altx, int alty)
700 {
701 	term->dirty = 1;
702 	if (term->spec->block_cursor) x = altx, y = alty;
703 	if (x >= term->x) x = term->x - 1;
704 	if (y >= term->y) y = term->y - 1;
705 	if (x < 0) x = 0;
706 	if (y < 0) y = 0;
707 	term->cx = x;
708 	term->cy = y;
709 }
710 
exec_thread(unsigned char * path,int p)711 void exec_thread(unsigned char *path, int p)
712 {
713 	int rs;
714 #if defined(HAVE_SETPGID) && !defined(EXEC_IN_THREADS)
715 	if (path[0] == 2)
716 		EINTRLOOP(rs, setpgid(0, 0));
717 #endif
718 	exe(path + 1);
719 	if (path[1 + strlen(path + 1) + 1])
720 		EINTRLOOP(rs, unlink(path + 1 + strlen(path + 1) + 1));
721 }
722 
close_handle(void * p)723 void close_handle(void *p)
724 {
725 	int h = (int)(my_uintptr_t)p;
726 	int rs;
727 	EINTRLOOP(rs, close(h));
728 	set_handlers(h, NULL, NULL, NULL, NULL);
729 }
730 
unblock_terminal(struct terminal * term)731 void unblock_terminal(struct terminal *term)
732 {
733 	close_handle((void *)(my_uintptr_t)term->blocked);
734 	term->blocked = -1;
735 	set_handlers(term->fdin, (void (*)(void *))in_term, NULL, (void (*)(void *))destroy_terminal, term);
736 	unblock_itrm(term->fdin);
737 	/* clear the dirty flag because unblock_itrm queued a resize
738 	   event - so avoid double redraw */
739 	term->dirty = 0;
740 	/*redraw_terminal_cls(term);*/
741 }
742 
exec_on_terminal(struct terminal * term,unsigned char * path,unsigned char * delete,int fg)743 void exec_on_terminal(struct terminal *term, unsigned char *path, unsigned char *delete, int fg)
744 {
745 	int rs;
746 	if (path && !*path) return;
747 	if (!path) path="";
748 #ifdef NO_FG_EXEC
749 	fg = 0;
750 #endif
751 	if (term->master) {
752 		if (!*path) dispatch_special(delete);
753 		else {
754 			int blockh;
755 			unsigned char *param;
756 			if (is_blocked() && fg) {
757 				if (*delete)
758 					EINTRLOOP(rs, unlink(delete));
759 				return;
760 			}
761 			param = mem_alloc(strlen(path) + strlen(delete) + 3);
762 			param[0] = fg;
763 			strcpy(param + 1, path);
764 			strcpy(param + 1 + strlen(path) + 1, delete);
765 			if (fg == 1) block_itrm(term->fdin);
766 			if ((blockh = start_thread((void (*)(void *, int))exec_thread, param, strlen(path) + strlen(delete) + 3)) == -1) {
767 				if (fg == 1) unblock_itrm(term->fdin);
768 				mem_free(param);
769 				return;
770 			}
771 			mem_free(param);
772 			if (fg == 1) {
773 				term->blocked = blockh;
774 				set_handlers(blockh, (void (*)(void *))unblock_terminal, NULL, (void (*)(void *))unblock_terminal, term);
775 				set_handlers(term->fdin, NULL, NULL, (void (*)(void *))destroy_terminal, term);
776 				/*block_itrm(term->fdin);*/
777 			} else {
778 				set_handlers(blockh, close_handle, NULL, close_handle, (void *)(my_uintptr_t)blockh);
779 			}
780 		}
781 	} else {
782 		unsigned char *data;
783 		data = mem_alloc(strlen(path) + strlen(delete) + 4);
784 		data[0] = 0;
785 		data[1] = fg;
786 		strcpy(data + 2, path);
787 		strcpy(data + 3 + strlen(path), delete);
788 		hard_write(term->fdout, data, strlen(path) + strlen(delete) + 4);
789 		mem_free(data);
790 		/*char x = 0;
791 		hard_write(term->fdout, &x, 1);
792 		x = fg;
793 		hard_write(term->fdout, &x, 1);
794 		hard_write(term->fdout, path, strlen(path) + 1);
795 		hard_write(term->fdout, delete, strlen(delete) + 1);*/
796 	}
797 }
798 
do_terminal_function(struct terminal * term,unsigned char code,unsigned char * data)799 void do_terminal_function(struct terminal *term, unsigned char code, unsigned char *data)
800 {
801 	unsigned char *x_data;
802 	x_data = mem_alloc(strlen(data) + 2);
803 	x_data[0] = code;
804 	strcpy(x_data + 1, data);
805 	exec_on_terminal(term, NULL, x_data, 0);
806 	mem_free(x_data);
807 }
808 
set_terminal_title(struct terminal * term,unsigned char * title)809 void set_terminal_title(struct terminal *term, unsigned char *title)
810 {
811 	if (strlen(cast_const_char title) > 10000) title[10000] = 0;
812 	if (strchr(title, 1)) {
813 		unsigned char *a, *b;
814 		for (a = title, b = title; *a; a++) if (*a != 1) *b++ = *a;
815 		*b = 0;
816 	}
817 	if (term->title && !strcmp(title, term->title)) goto ret;
818 	if (term->title) mem_free(term->title);
819 	term->title = stracpy(title);
820 #ifdef SET_WINDOW_TITLE_UTF_8
821 	{
822 		struct conv_table *table;
823 		mem_free(title);
824 		table = get_translation_table(term->spec->charset, get_cp_index("utf-8"));
825 		title = convert_string(table, term->title, strlen(term->title));
826 	}
827 #endif
828 	do_terminal_function(term, TERM_FN_TITLE, title);
829 	ret:
830 	mem_free(title);
831 }
832