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