X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fansi.c;h=215441321e7015db5c69bacf9b5cbf3f62e15446;hb=9df8b9cc93fa29a848634af76e71fce6ddda67f0;hp=5d6105eb83437fb366cd78d0db48a60a70219a05;hpb=a1766d2d378710f924391784d0ffc736d59678db;p=sympathy.git diff --git a/src/ansi.c b/src/ansi.c index 5d6105e..2154413 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -10,17 +10,100 @@ static char rcsid[] = "$Id$"; /* * $Log$ + * Revision 1.10 2008/02/07 01:02:52 james + * *** empty log message *** + * + * Revision 1.9 2008/02/07 00:43:27 james + * *** empty log message *** + * + * Revision 1.8 2008/02/07 00:39:13 james + * *** empty log message *** + * + * Revision 1.7 2008/02/06 20:26:57 james + * *** empty log message *** + * + * Revision 1.6 2008/02/06 17:53:28 james + * *** empty log message *** + * + * Revision 1.5 2008/02/06 15:53:22 james + * *** empty log message *** + * + * Revision 1.4 2008/02/04 20:23:55 james + * *** empty log message *** + * + * Revision 1.3 2008/02/04 05:45:55 james + * :: + * + * Revision 1.2 2008/02/04 02:05:06 james + * *** empty log message *** + * * Revision 1.1 2008/02/03 23:31:25 james * *** empty log message *** * */ +#include "project.h" + +static void +set_nonblocking (int fd) +{ + long arg; + arg = fcntl (fd, F_GETFL, arg); + arg |= O_NONBLOCK; + fcntl (fd, F_SETFL, arg); +} + +static void +set_blocking (int fd) +{ + long arg; + arg = fcntl (fd, F_GETFL, arg); + arg &= ~O_NONBLOCK; + fcntl (fd, F_SETFL, arg); +} + + +int +ansi_read (ANSI * a, void *buf, int n) +{ + int red; + + set_nonblocking (a->fd); + red = read (a->fd, buf, n); + + if (!red) + return -1; + + if ((red == -1) && (errno == EAGAIN)) + { + return 0; + } + + return red; +} void ansi_write (ANSI * a, char *buf, int n) { + set_blocking (a->fd); write (a->fd, buf, n); } +void +ansi_getsize (ANSI * a) +{ + struct winsize sz = { 0 }; + if (ioctl (a->fd, TIOCGWINSZ, &sz)) + { + a->size.x = CRT_COLS; + a->size.y = CRT_ROWS; + } + else + { + a->size.x = sz.ws_col; + a->size.y = sz.ws_row; + } + +} void @@ -28,9 +111,10 @@ ansi_move (ANSI * a, CRT_Pos p) { char buf[16]; int n; - int dx = a->pos.x - p.x; - int dy = a->pos.y - p.y; + int dx = p.x - a->pos.x; + int dy = p.y - a->pos.y; +// a->pos.x = ANSI_INVAL; if (a->pos.x != ANSI_INVAL) { @@ -87,24 +171,24 @@ ansi_move (ANSI * a, CRT_Pos p) } else if (dy > 0) { - n = snprintf (buf, sizeof (buf), "\033[%dE", -dy); + n = snprintf (buf, sizeof (buf), "\033[%dE", dy); ansi_write (a, buf, n); } else { - n = snprintf (buf, sizeof (buf), "\033[%dF", dy); + n = snprintf (buf, sizeof (buf), "\033[%dF", -dy); ansi_write (a, buf, n); } } else { - n = snprintf (buf, sizeof (buf), "\033[%d;%dHF", p.y + 1, p.x + 1); + n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1); ansi_write (a, buf, n); } } else { - n = snprintf (buf, sizeof (buf), "\033[%d;%dHF", p.y + 1, p.x + 1); + n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1); ansi_write (a, buf, n); } @@ -120,71 +204,77 @@ ansi_showhide_cursor (ANSI * a, int hide) if (hide) { - ansi_write (a, "\033[?25h", 6); + ansi_write (a, "\033[?25l", 6); } else { - ansi_write (a, "\033[?25l", 6); + ansi_write (a, "\033[?25h", 6); } a->hide_cursor = hide; } -void ansi_force_attr_normal(ANSI *a) +void +ansi_force_attr_normal (ANSI * a) { ansi_write (a, "\033[0m", 4); - a->attr=CRT_ATTR_NORMAL; + a->attr = CRT_ATTR_NORMAL; } void ansi_set_attr (ANSI * a, int attr) { + int dif; dif = attr ^ a->attr; if (!dif) return; - if (attr == ATTR_NORMAL) + a->attr = attr; + + if (attr == CRT_ATTR_NORMAL) { - ansi_force_attr_normal(a); - return; + ansi_force_attr_normal (a); + return; } - if (dif & CRT_ATTR_UNDERLINE) + if (dif & CRT_ATTR_UNDERLINE) + { + if (attr & CRT_ATTR_UNDERLINE) { - if (attr & CRT_ATTR_UNDERLINE) - { - ansi_write (a, "\033[4m", 4); - } - else - { - ansi_write (a, "\033[24m", 5); - } + ansi_write (a, "\033[4m", 4); } - if (dif & CRT_ATTR_REVERSE) + else { - if (attr & CRT_ATTR_REVERSE) - { - ansi_write (a, "\033[7m", 4); - } - else - { - ansi_write (a, "\033[27m", 5); - } + ansi_write (a, "\033[24m", 5); } - if (dif & CRT_ATTR_BOLD) + } + if (dif & CRT_ATTR_REVERSE) + { + if (attr & CRT_ATTR_REVERSE) { - if (attr & CRT_ATTR_REVERSE) - { - ansi_write (a, "\033[1m", 4); - } - else - { - ansi_write (a, "\033[22m", 5); - } + ansi_write (a, "\033[7m", 4); + } + else + { + ansi_write (a, "\033[27m", 5); + } + } + if (dif & CRT_ATTR_BOLD) + { + if (attr & CRT_ATTR_BOLD) + { + ansi_write (a, "\033[1m", 4); } + else + { + ansi_write (a, "\033[21m", 5); + ansi_write (a, "\033[22m", 5); + } + } + } @@ -218,7 +308,8 @@ ansi_cls (ANSI * a) CRT_Pos p = { 0 }; crt_cls (&a->crt); - ansi_force_attr_normal(a); + + ansi_force_attr_normal (a); ansi_move (a, p); ansi_write (a, "\033[2J", 4); /*different emulators leave cursor in different places after cls differently*/ @@ -231,39 +322,63 @@ ansi_draw (ANSI * a, CRT * c) { CRT_Pos p; int o; - - ansi_showhide_cursor (a, 1); + int hidden_cursor = 0; for (p.y = 0; p.y < CRT_ROWS; ++p.y) { if (p.y >= a->size.y) continue; - o = CRT_ADDR (r, 0); + o = CRT_ADDR (p.y, 0); for (p.x = 0; p.x < CRT_COLS; ++p.x, ++o) { if (p.x >= a->size.x) continue; - if (crt_ca_cmp (a->crt.screen[p], c->screen[p])) + if (crt_ca_cmp (a->crt.screen[o], c->screen[o])) { - a->crt.screen[p] = c->screen[p]; + ansi_showhide_cursor (a, 1); + a->crt.screen[o] = c->screen[o]; ansi_move (a, p); - ansi_render (a, a->crt.screen[p]); + ansi_render (a, a->crt.screen[o]); } } } + + if ((CRT_COLS > a->size.x) || (CRT_ROWS > a->size.y)) + { + char msg[] = "Window is too small"; + p.x = 0; + p.y = 0; + + ansi_showhide_cursor (a, 1); + ansi_set_attr (a, CRT_ATTR_REVERSE); + ansi_move (a, p); + + ansi_write (a, msg, sizeof (msg)); + a->pos.x = ANSI_INVAL; + } + + + if ((c->pos.x >= a->size.x) || (c->pos.y >= a->size.y)) + { + ansi_showhide_cursor (a, 1); + return; + } + a->crt.pos = c->pos; ansi_move (a, a->crt.pos); a->crt.hide_cursor = c->hide_cursor; - ansi_showhide_cursor (a, ci->crt.hide_cursor); + ansi_showhide_cursor (a, a->crt.hide_cursor); } void ansi_reset (ANSI * a) { - ansi_write (a, "\033[c", 3); +// FIXME: -- echos back crap? +// ansi_write (a, "\033[c", 3); + ansi_getsize (a); a->pos.x = ANSI_INVAL; a->hide_cursor = ANSI_INVAL; @@ -271,5 +386,208 @@ ansi_reset (ANSI * a) crt_reset (&a->crt); ansi_cls (a); + ansi_write (a, "\033=", 2); ansi_draw (a, &a->crt); } + +void +ansi_flush_escape (ANSI * a, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + int i; + + for (i = 0; i < p->escape_ptr; ++i) + { + vt102_send (v, p->escape_buf[i]); + } + + p->escape_ptr = 0; + p->in_escape = 0; +} + +void +ansi_parse_deckey (ANSI * a, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + if ((p->escape_buf[1] != '[') && (p->escape_buf[1] != 'O')) + { + ansi_flush_escape (a, v); + return; + } + + if ((p->escape_buf[2] >= 'A') || (p->escape_buf[2] <= 'Z')) + { + vt102_send (v, KEY_UP + (p->escape_buf[2] - 'A')); + } + else if ((p->escape_buf[2] >= 'a') || (p->escape_buf[2] <= 'z')) + { + vt102_send (v, KEY_154 + (p->escape_buf[2] - 'a')); + } + else + { + ansi_flush_escape (a, v); + return; + } + p->in_escape = 0; + p->escape_ptr = 0; +} + +void +ansi_parse_ansikey (ANSI * a, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + + if ((p->escape_buf[1] != '[') || (p->escape_buf[3] != '~')) + { + ansi_flush_escape (a, v); + return; + } + if ((p->escape_buf[2] >= '0') || (p->escape_buf[2] <= '9')) + { + vt102_send (v, KEY_180 + (p->escape_buf[2] - '0')); + } + else + { + ansi_flush_escape (a, v); + return; + } + + p->in_escape = 0; + p->escape_ptr = 0; +} + + + +void +ansi_parse_escape (ANSI * a, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + switch (p->escape_ptr) + { + case 0: + case 1: + return; + case 2: + switch (p->escape_buf[1]) + { + case '[': + case 'O': + break; + default: + ansi_flush_escape (a, v); + } + break; + case 3: + switch (p->escape_buf[1]) + { + case 'O': + ansi_parse_deckey (a, v); + break; + case '[': + if ((p->escape_buf[2] >= 'A') && (p->escape_buf[2] <= 'Z')) + ansi_parse_deckey (a, v); + break; + default: + ansi_flush_escape (a, v); + } + break; + case 4: + switch (p->escape_buf[1]) + { + case '[': + ansi_parse_ansikey (a, v); + break; + default: + ansi_flush_escape (a, v); + } + break; + case 5: + ansi_flush_escape (a, v); + } +} + + +void +ansi_check_escape (ANSI * a, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + struct timeval now, diff; + gettimeofday (&now, NULL); + timersub (&now, &p->last_escape, &diff); + +#if 0 + fprintf (stderr, "ie %d tl %d.%06d eb %d\n", + p->in_escape, diff.tv_sec, diff.tv_usec, p->escape_ptr); +#endif + + if (!p->in_escape) + return; + + + /*Time up? */ + if (diff.tv_sec || (diff.tv_usec > ANSI_ESCAPE_TIMEOUT)) + ansi_flush_escape (a, v); + +} + + +void +ansi_parse_char (ANSI * a, int c, VT102 * v) +{ + ANSI_Parser *p = &a->parser; + + +/*See if it's time to flush the escape*/ + ansi_check_escape (a, v); + + if (c == 033) + { + if (p->in_escape) + ansi_flush_escape (a, v); + + p->in_escape++; + p->escape_ptr = 0; + gettimeofday (&p->last_escape, NULL); + } + + if (p->in_escape) + { + p->escape_buf[p->escape_ptr++] = c; + ansi_parse_escape (a, v); + } + else + { + vt102_send (v, c); + } + +} + +void +ansi_parse (ANSI * a, char *buf, int len, VT102 * v) +{ + while (len--) + ansi_parse_char (a, *(buf++), v); +} + +int +ansi_dispatch (ANSI * a, VT102 * v) +{ + char buf[1024]; + int red; + + ansi_check_escape (a, v); + + + red = ansi_read (a, buf, sizeof (buf)); + if (red <= 0) + return red; + +#if 0 + if (*buf == 3) + return -1; +#endif + + ansi_parse (a, buf, red, v); + + return 0; +}