"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/terminal.c" (16 Nov 2011, 21979 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "terminal.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

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