chiark / gitweb /
*** empty log message ***
[sympathy.git] / src / ansi.c
1 /*
2  * ansi.c:
3  *
4  * Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id$";
10
11 /*
12  * $Log$
13  * Revision 1.35  2008/02/28 16:57:51  james
14  * *** empty log message ***
15  *
16  * Revision 1.34  2008/02/27 09:42:53  james
17  * *** empty log message ***
18  *
19  * Revision 1.33  2008/02/27 09:42:21  james
20  * *** empty log message ***
21  *
22  * Revision 1.32  2008/02/26 23:56:12  james
23  * *** empty log message ***
24  *
25  * Revision 1.31  2008/02/26 23:23:17  james
26  * *** empty log message ***
27  *
28  * Revision 1.30  2008/02/24 00:42:53  james
29  * *** empty log message ***
30  *
31  * Revision 1.29  2008/02/23 11:48:37  james
32  * *** empty log message ***
33  *
34  * Revision 1.28  2008/02/22 17:07:00  james
35  * *** empty log message ***
36  *
37  * Revision 1.27  2008/02/20 22:54:22  staffcvs
38  * *** empty log message ***
39  *
40  * Revision 1.26  2008/02/20 20:16:07  james
41  * *** empty log message ***
42  *
43  * Revision 1.25  2008/02/20 19:44:37  james
44  * @@
45  *
46  * Revision 1.24  2008/02/20 19:36:06  james
47  * @@
48  *
49  * Revision 1.23  2008/02/20 19:25:09  james
50  * *** empty log message ***
51  *
52  * Revision 1.22  2008/02/15 03:32:07  james
53  * *** empty log message ***
54  *
55  * Revision 1.21  2008/02/14 02:46:44  james
56  * *** empty log message ***
57  *
58  * Revision 1.20  2008/02/14 01:55:57  james
59  * *** empty log message ***
60  *
61  * Revision 1.19  2008/02/13 16:57:29  james
62  * *** empty log message ***
63  *
64  * Revision 1.18  2008/02/13 09:12:21  james
65  * *** empty log message ***
66  *
67  * Revision 1.17  2008/02/13 01:08:18  james
68  * *** empty log message ***
69  *
70  * Revision 1.16  2008/02/07 13:22:51  james
71  * *** empty log message ***
72  *
73  * Revision 1.15  2008/02/07 13:19:48  james
74  * *** empty log message ***
75  *
76  * Revision 1.14  2008/02/07 12:21:16  james
77  * *** empty log message ***
78  *
79  * Revision 1.13  2008/02/07 12:16:04  james
80  * *** empty log message ***
81  *
82  * Revision 1.12  2008/02/07 11:32:41  james
83  * *** empty log message ***
84  *
85  * Revision 1.11  2008/02/07 11:11:14  staffcvs
86  * *** empty log message ***
87  *
88  * Revision 1.10  2008/02/07 01:02:52  james
89  * *** empty log message ***
90  *
91  * Revision 1.9  2008/02/07 00:43:27  james
92  * *** empty log message ***
93  *
94  * Revision 1.8  2008/02/07 00:39:13  james
95  * *** empty log message ***
96  *
97  * Revision 1.7  2008/02/06 20:26:57  james
98  * *** empty log message ***
99  *
100  * Revision 1.6  2008/02/06 17:53:28  james
101  * *** empty log message ***
102  *
103  * Revision 1.5  2008/02/06 15:53:22  james
104  * *** empty log message ***
105  *
106  * Revision 1.4  2008/02/04 20:23:55  james
107  * *** empty log message ***
108  *
109  * Revision 1.3  2008/02/04 05:45:55  james
110  * ::
111  *
112  * Revision 1.2  2008/02/04 02:05:06  james
113  * *** empty log message ***
114  *
115  * Revision 1.1  2008/02/03 23:31:25  james
116  * *** empty log message ***
117  *
118  */
119 #include "project.h"
120
121
122 static void
123 ansi_move (ANSI * a, CRT_Pos p)
124 {
125   char buf[16];
126   int n;
127   int dx = p.x - a->pos.x;
128   int dy = p.y - a->pos.y;
129
130 //  a->pos.x = ANSI_INVAL;
131
132   if (a->pos.x != ANSI_INVAL)
133     {
134
135       if ((!dx) && (!dy))
136         return;
137
138       if (!dy)
139         {
140           if (dx == 1)
141             {
142               a->terminal->xmit (a->terminal, "\033[C", 3);
143             }
144           else if (dx == -1)
145             {
146               a->terminal->xmit (a->terminal, "\033[D", 3);
147             }
148           else
149             {
150               n = snprintf (buf, sizeof (buf), "\033[%dG", p.x + 1);
151               a->terminal->xmit (a->terminal, buf, n);
152             }
153         }
154       else if (!dx)
155         {
156           if (dy == -1)
157             {
158               a->terminal->xmit (a->terminal, "\033[A", 3);
159             }
160           else if (dy == 1)
161             {
162               a->terminal->xmit (a->terminal, "\033[B", 3);
163             }
164           else if (dy < 0)
165             {
166               n = snprintf (buf, sizeof (buf), "\033[%dA", -dy);
167               a->terminal->xmit (a->terminal, buf, n);
168             }
169           else
170             {
171               n = snprintf (buf, sizeof (buf), "\033[%dB", dy);
172               a->terminal->xmit (a->terminal, buf, n);
173             }
174         }
175       else if (!p.x)
176         {
177           if (dy == 1)
178             {
179               a->terminal->xmit (a->terminal, "\033[E", 3);
180             }
181           else if (dy == -1)
182             {
183               a->terminal->xmit (a->terminal, "\033[F", 3);
184             }
185           else if (dy > 0)
186             {
187               n = snprintf (buf, sizeof (buf), "\033[%dE", dy);
188               a->terminal->xmit (a->terminal, buf, n);
189             }
190           else
191             {
192               n = snprintf (buf, sizeof (buf), "\033[%dF", -dy);
193               a->terminal->xmit (a->terminal, buf, n);
194             }
195         }
196       else
197         {
198           n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
199           a->terminal->xmit (a->terminal, buf, n);
200         }
201     }
202   else
203     {
204       n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
205       a->terminal->xmit (a->terminal, buf, n);
206     }
207
208   a->pos = p;
209 }
210
211
212 static void
213 ansi_showhide_cursor (ANSI * a, int hide)
214 {
215   if (a->hide_cursor == hide)
216     return;
217
218   if (hide)
219     {
220       a->terminal->xmit (a->terminal, "\033[?25l", 6);
221     }
222   else
223     {
224       a->terminal->xmit (a->terminal, "\033[?25h", 6);
225     }
226
227   a->hide_cursor = hide;
228 }
229
230
231 static void
232 ansi_force_attr_normal (ANSI * a)
233 {
234   a->terminal->xmit (a->terminal, "\033[0m", 4);
235   a->attr = CRT_ATTR_NORMAL;
236   a->color = ANSI_INVAL;
237 }
238
239 static void
240 ansi_set_color (ANSI * a, int color)
241 {
242   int dif;
243   char buf[16];
244   int i;
245   int fg, bg;
246
247   if ((a->color == ANSI_INVAL) || (color != a->color))
248     {
249       fg = CRT_COLOR_FG (color);
250       bg = CRT_COLOR_BG (color);
251
252       if (fg & CRT_COLOR_INTENSITY)
253         {
254           fg += 90;
255         }
256       else
257         {
258           fg += 30;
259         }
260
261       if (bg & CRT_COLOR_INTENSITY)
262         {
263           bg += 100;
264         }
265       else
266         {
267           bg += 40;
268         }
269
270       i = sprintf (buf, "\033[%d;%dm", fg, bg);
271 #if 0
272       fprintf (stderr, "Color set to %d %d %x\n", fg, bg, color);
273 #endif
274
275       a->terminal->xmit (a->terminal, buf, i);
276       a->color = color;
277     }
278 }
279
280 static void
281 ansi_set_attr (ANSI * a, int attr)
282 {
283   int dif;
284
285   dif = attr ^ a->attr;
286
287   if (!dif)
288     return;
289
290   a->attr = attr;
291
292 #if 0
293   if (attr == CRT_ATTR_NORMAL)
294     {
295       ansi_force_attr_normal (a);
296       return;
297     }
298 #endif
299
300   if (dif & CRT_ATTR_UNDERLINE)
301     {
302       if (attr & CRT_ATTR_UNDERLINE)
303         {
304           a->terminal->xmit (a->terminal, "\033[4m", 4);
305         }
306       else
307         {
308           a->terminal->xmit (a->terminal, "\033[24m", 5);
309         }
310     }
311   if (dif & CRT_ATTR_REVERSE)
312     {
313       if (attr & CRT_ATTR_REVERSE)
314         {
315           a->terminal->xmit (a->terminal, "\033[7m", 4);
316         }
317       else
318         {
319           a->terminal->xmit (a->terminal, "\033[27m", 5);
320         }
321     }
322   if (dif & CRT_ATTR_BOLD)
323     {
324       if (attr & CRT_ATTR_BOLD)
325         {
326           a->terminal->xmit (a->terminal, "\033[1m", 4);
327         }
328       else
329         {
330           a->terminal->xmit (a->terminal, "\033[21m", 5);
331           a->terminal->xmit (a->terminal, "\033[22m", 5);
332         }
333     }
334
335 }
336
337 static void
338 ascii_emit (TTY * t, uint32_t ch)
339 {
340   int i;
341
342 /*Some quick obvious subsititons for quotation marks*/
343   switch (ch)
344     {
345     case 0x2018:
346       ch = '`';
347       break;
348     case 0x2019:
349       ch = '\'';
350       break;
351     case 0x201c:
352     case 0x201d:
353       ch = '"';
354       break;
355     }
356
357 /*Short cut the easy stuff*/
358   if (ch < 0x7f)
359     {
360       uint8_t c = ch;
361       t->xmit (t, &c, 1);
362       return;
363     }
364
365   for (i = 0; i < VT102_CHARSET_SIZE; ++i)
366     {
367       if (vt102_charset_gl[i] == ch)
368         {
369           uint8_t c[3] = { 016, i, 017 };
370           t->xmit (t, &c, 3);
371           return;
372         }
373     }
374
375   t->xmit (t, "?", 1);
376
377 }
378
379 static void
380 ansi_render (ANSI * a, CRT_CA ca)
381 {
382   int dif;
383
384   if ((ca.chr < VT102_CHARSET_SIZE) && (vt102_charset_c0[ca.chr]))
385     ca.chr = vt102_charset_c0[ca.chr];
386
387   if ((ca.chr >= 0x80) && (ca.chr < 0xa0))
388     ca.chr = ' ';
389
390   ansi_set_attr (a, ca.attr);
391   ansi_set_color (a, ca.color);
392
393   if (a->utf8)
394     utf8_emit (a->terminal, ca.chr);
395   else
396     ascii_emit (a->terminal, ca.chr);
397
398   a->pos.x++;
399
400 /*Can't easily wrap round here as don't know size of destination screen*/
401 /*so invalidate the cached cursor position*/
402
403   if (a->pos.x >= a->size.x)
404     a->pos.x = ANSI_INVAL;
405
406 }
407
408 static void
409 ansi_cls (ANSI * a)
410 {
411   CRT_Pos p = { 0 };
412
413   crt_cls (&a->crt);
414
415   ansi_set_attr (a, CRT_ATTR_NORMAL);
416   ansi_set_color (a, CRT_COLOR_NORMAL);
417   ansi_move (a, p);
418   a->terminal->xmit (a->terminal, "\033[2J", 4);
419 /*different emulators leave cursor in different places after cls differently*/
420   a->pos.x = ANSI_INVAL;
421 }
422
423 #if 0
424 int
425 ansi_scroll_up (ANSI * a, CRT_Pos s, CRT_Pos e)
426 {
427   char buf[16];
428   int i;
429   if (s.x)
430     return -1;
431   if (e.x != (CRT_COLS - 1))
432     return -1;
433   if (s.y)
434     return -1;
435   if (s.y >= a->size.y)
436     return -1;
437
438   ansi_showhide_cursor (a, 1);
439   i = sprintf (buf, "\033[%d;%dr", s.y + 1, e.y + 1);
440   a->terminal->xmit (a->terminal, buf, i);
441   i = sprintf (buf, "\033[%d;%dH", e.y + 1, 0);
442   a->terminal->xmit (a->terminal, buf, i);
443   a->terminal->xmit (a->terminal, "\033D", 2);
444   a->terminal->xmit (a->terminal, "\033[r", 3);
445
446   s.y = e.y;
447   crt_erase (&a->crt, s, e, 1);
448
449   a->pos.x = ANSI_INVAL;
450
451   return 0;
452 }
453
454
455 static void
456 ansi_spot_scroll_up (ANSI * a, CRT * c)
457 {
458   int l, n, p;
459
460   l = c->sh.e.x - c->sh.s.x;
461   l++;
462   l *= sizeof (CRT_CA);
463
464   n = c->sh.e.y - c->sh.s.y;
465   p = CRT_ADDR_POS (&c->sh.s);
466
467   while (n--)
468     {
469       if (memcmp (&c->screen[p], &a->crt.screen[p + CRT_COLS], l))
470         return;
471       p += CRT_COLS;
472     }
473
474   if (ansi_scroll_up (a, c->sh.s, c->sh.e))
475     return;
476
477   n = c->sh.e.y - c->sh.s.y;
478   p = CRT_ADDR_POS (&c->sh.s);
479
480   while (n--)
481     {
482       memcpy (&a->crt.screen[p], &a->crt.screen[p + CRT_COLS], l);
483       p += CRT_COLS;
484     }
485
486   c->sh.dir = 0;                //FIXME: horrid hack
487
488 }
489
490 static void
491 ansi_spot_scroll (ANSI * a, CRT * c)
492 {
493
494   switch (c->sh.dir)
495     {
496     case -1:
497 /*we only care about up for the moment */
498       ansi_spot_scroll_up (a, c);
499       break;
500     }
501
502   return;
503 }
504
505 #endif
506
507
508 static void
509 ansi_draw_line (ANSI * a, CRT_CA * cap, int y)
510 {
511   CRT_Pos p = { 0, y };
512   CRT_CA *acap = &a->crt.screen[CRT_ADDR_POS (&p)];
513
514   for (p.x = 0; p.x < a->crt.size.x; ++p.x)
515     {
516       if (p.x >= a->size.x)
517         continue;
518
519       if (crt_ca_cmp (*acap, *cap))
520         {
521           ansi_showhide_cursor (a, 1);
522           *acap = *cap;
523
524           ansi_move (a, p);
525           ansi_render (a, *acap);
526         }
527
528       acap++;
529       cap++;
530     }
531 }
532
533 static void
534 ansi_resize_check (ANSI * a, CRT_Pos * size)
535 {
536
537   if ((size && crt_pos_cmp (a->crt.size, *size))
538       || crt_pos_cmp (a->terminal->size, a->size))
539     {
540
541       terminal_getsize (a->terminal);
542
543       a->size = a->terminal->size;
544
545       a->pos.x = ANSI_INVAL;
546       a->hide_cursor = ANSI_INVAL;
547
548       crt_reset (&a->crt);
549
550       if (size)
551         a->crt.size = *size;
552
553 // FIXME: -- echos back crap?
554 //  a->terminal->xmit (a->terminal, "\033[c", 3);
555
556 // maybe - issue 132 column command if we're 132?
557
558       ansi_cls (a);
559       a->terminal->xmit (a->terminal, "\033=", 2);
560       a->terminal->xmit (a->terminal, "\033[?6l", 5);
561       a->terminal->xmit (a->terminal, "\033[r", 3);
562       if (a->utf8)
563         {
564           a->terminal->xmit (a->terminal, "\033%G", 3);
565         }
566       else
567         {
568           a->terminal->xmit (a->terminal, "\033(B", 3);
569           a->terminal->xmit (a->terminal, "\033)0", 3);
570           a->terminal->xmit (a->terminal, "\017", 1);
571         }
572
573     }
574 }
575
576 /*if they haven't then ansi_draw will patch it up*/
577
578 static void
579 ansi_history (ANSI * a, History * h)
580 {
581   char buf[32];
582   int i;
583   int guess_scroll;
584 /*Do we need to catch up on history?*/
585
586   if (a->history_ptr == h->wptr)
587     return;
588   ansi_resize_check (a, NULL);
589
590   if ((a->size.x < a->crt.size.x) || (a->size.y < a->crt.size.y))
591     return;
592
593   guess_scroll = a->crt.size.y - 1; /*Bototm line should be a status line */
594
595
596   ansi_force_attr_normal (a);
597   ansi_set_color (a, CRT_COLOR_NORMAL);
598
599   i = sprintf (buf, "\033[%d;%dr", 1, guess_scroll);
600   a->terminal->xmit (a->terminal, buf, i);
601
602
603   while (a->history_ptr != h->wptr)
604     {
605
606       History_ent *e = &h->lines[a->history_ptr];
607
608       HISTORY_INC (h, a->history_ptr);
609
610       if (!e->valid)
611         continue;
612
613       /*If so write the line ot the top of the screen */
614       ansi_draw_line (a, e->line, 0);
615
616
617       /*Roll guess_scroll lines up putting the top line into the xterm's history */
618
619
620       /*Make extra lines a predictable colour */
621       ansi_set_color (a, CRT_COLOR_NORMAL);
622
623       ansi_showhide_cursor (a, 1);
624       i = sprintf (buf, "\033[%d;%dH", guess_scroll, 1);
625       a->terminal->xmit (a->terminal, buf, i);
626       a->terminal->xmit (a->terminal, "\033D", 2);
627       a->pos.x = ANSI_INVAL;
628
629       /*now do the same in our image of the screen */
630
631       {
632         CRT_Pos s = { 0 }
633         , e =
634         {
635         0};
636
637         /*scroll lines up */
638         for (s.y++; s.y < guess_scroll; s.y++, e.y++)
639           {
640             memcpy (&a->crt.screen[CRT_ADDR_POS (&e)],
641                     &a->crt.screen[CRT_ADDR_POS (&s)],
642                     sizeof (CRT_CA) * a->crt.size.x);
643           }
644
645         /* erase new line */
646         s.y = e.y;
647         e.x = CRT_COLS - 1;
648         crt_erase (&a->crt, s, e, 1, CRT_COLOR_NORMAL);
649       }
650
651     }
652 /*reset margins*/
653   a->terminal->xmit (a->terminal, "\033[r", 3);
654   a->pos.x = ANSI_INVAL;
655
656 }
657
658
659
660
661 static void
662 ansi_draw (ANSI * a, CRT * c)
663 {
664   CRT_Pos p;
665   int o;
666   int hidden_cursor = 0;
667
668   ansi_resize_check (a, &c->size);
669
670
671   for (p.y = 0; p.y < a->crt.size.y; ++p.y)
672     {
673       if (p.y >= a->size.y)
674         continue;
675
676       ansi_draw_line (a, &c->screen[CRT_ADDR (p.y, 0)], p.y);
677
678     }
679
680
681   if ((c->size.x > a->size.x) || (c->size.y > a->size.y))
682     {
683       char msg[1024];           // = "Window is too small";
684       int i;
685       p.x = 0;
686       p.y = 0;
687
688       i =
689         sprintf (msg, "Window too small (%dx%d need %dx%d)", a->size.x,
690                  a->size.y, c->size.x, c->size.y);
691
692       ansi_showhide_cursor (a, 1);
693       ansi_set_attr (a, CRT_ATTR_REVERSE);
694       ansi_set_color (a, CRT_MAKE_COLOR (CRT_COLOR_WHITE, CRT_COLOR_RED));
695       ansi_move (a, p);
696
697       a->terminal->xmit (a->terminal, msg, i);
698       a->pos.x = ANSI_INVAL;
699     }
700
701
702   if ((c->pos.x >= a->size.x) || (c->pos.y >= a->size.y))
703     {
704       ansi_showhide_cursor (a, 1);
705       return;
706     }
707
708   a->crt.pos = c->pos;
709   ansi_move (a, a->crt.pos);
710
711   a->crt.hide_cursor = c->hide_cursor;
712   ansi_showhide_cursor (a, a->crt.hide_cursor);
713 }
714
715 static void
716 ansi_reset (ANSI * a, CRT * c)
717 {
718   a->size.x = -1;
719   ansi_draw (a, c ? c : &a->crt);
720 }
721
722 static void
723 ansi_terminal_reset (ANSI * a)
724 {
725   CRT_Pos p = { 0, a->crt.size.y };
726   ansi_force_attr_normal (a);
727
728   ansi_move (a, p);
729 }
730
731 static void
732 ansi_flush_escape (ANSI * a, Context * c)
733 {
734   ANSI_Parser *p = &a->parser;
735   int i;
736
737   for (i = 0; i < p->escape_ptr; ++i)
738     {
739       keydis_key (c->k, c, p->escape_buf[i]);
740     }
741
742   p->escape_ptr = 0;
743   p->in_escape = 0;
744 }
745
746 static void
747 ansi_parse_deckey (ANSI * a, Context * c)
748 {
749   ANSI_Parser *p = &a->parser;
750   if ((p->escape_buf[1] != '[') && (p->escape_buf[1] != 'O'))
751     {
752       ansi_flush_escape (a, c);
753       return;
754     }
755
756   if ((p->escape_buf[2] >= 'A') || (p->escape_buf[2] <= 'Z'))
757     {
758       keydis_key (c->k, c, KEY_UP + (p->escape_buf[2] - 'A'));
759     }
760   else if ((p->escape_buf[2] >= 'a') || (p->escape_buf[2] <= 'z'))
761     {
762       keydis_key (c->k, c, KEY_154 + (p->escape_buf[2] - 'a'));
763     }
764   else
765     {
766       ansi_flush_escape (a, c);
767       return;
768     }
769   p->in_escape = 0;
770   p->escape_ptr = 0;
771 }
772
773 static void
774 ansi_parse_ansikey (ANSI * a, Context * c)
775 {
776   ANSI_Parser *p = &a->parser;
777
778   if ((p->escape_buf[1] != '[') || (p->escape_buf[3] != '~'))
779     {
780       ansi_flush_escape (a, c);
781       return;
782     }
783   if ((p->escape_buf[2] >= '0') || (p->escape_buf[2] <= '9'))
784     {
785       keydis_key (c->k, c, KEY_180 + (p->escape_buf[2] - '0'));
786     }
787   else
788     {
789       ansi_flush_escape (a, c);
790       return;
791     }
792
793   p->in_escape = 0;
794   p->escape_ptr = 0;
795 }
796
797
798
799 static void
800 ansi_parse_escape (ANSI * a, Context * c)
801 {
802   ANSI_Parser *p = &a->parser;
803   switch (p->escape_ptr)
804     {
805     case 0:
806     case 1:
807       return;
808     case 2:
809       switch (p->escape_buf[1])
810         {
811         case '[':
812         case 'O':
813           break;
814         default:
815           ansi_flush_escape (a, c);
816         }
817       break;
818     case 3:
819       switch (p->escape_buf[1])
820         {
821         case 'O':
822           ansi_parse_deckey (a, c);
823           break;
824         case '[':
825           if ((p->escape_buf[2] >= 'A') && (p->escape_buf[2] <= 'Z'))
826             ansi_parse_deckey (a, c);
827           break;
828         default:
829           ansi_flush_escape (a, c);
830         }
831       break;
832     case 4:
833       switch (p->escape_buf[1])
834         {
835         case '[':
836           ansi_parse_ansikey (a, c);
837           break;
838         default:
839           ansi_flush_escape (a, c);
840         }
841       break;
842     case 5:
843       ansi_flush_escape (a, c);
844     }
845 }
846
847
848 static void
849 ansi_check_escape (ANSI * a, Context * c)
850 {
851   ANSI_Parser *p = &a->parser;
852   struct timeval now, diff;
853   gettimeofday (&now, NULL);
854   timersub (&now, &p->last_escape, &diff);
855
856 #if 0
857   fprintf (stderr, "ie %d tl %d.%06d eb %d\n",
858            p->in_escape, diff.tv_sec, diff.tv_usec, p->escape_ptr);
859 #endif
860
861   if (!p->in_escape)
862     return;
863
864
865   /*Time up? */
866   if (diff.tv_sec || (diff.tv_usec > ANSI_ESCAPE_TIMEOUT))
867     ansi_flush_escape (a, c);
868
869 }
870
871
872 static void
873 ansi_parse_char (ANSI * a, Context * c, int ch)
874 {
875   ANSI_Parser *p = &a->parser;
876
877
878 /*See if it's time to flush the escape*/
879   ansi_check_escape (a, c);
880
881   if (ch == 033)
882     {
883       if (p->in_escape)
884         ansi_flush_escape (a, c);
885
886       p->in_escape++;
887       p->escape_ptr = 0;
888       gettimeofday (&p->last_escape, NULL);
889     }
890
891   if (p->in_escape)
892     {
893       p->escape_buf[p->escape_ptr++] = ch;
894       ansi_parse_escape (a, c);
895     }
896   else
897     {
898       keydis_key (c->k, c, ch);
899     }
900
901 }
902
903 static void
904 ansi_parse (ANSI * a, Context * c, char *buf, int len)
905 {
906   while (len--)
907     ansi_parse_char (a, c, *(buf++));
908 }
909
910 int
911 ansi_dispatch (ANSI * a, Context * c)
912 {
913   char buf[1024];
914   int red;
915
916   ansi_check_escape (a, c);
917
918
919   if (!a->terminal)
920     return 0;
921
922   red = a->terminal->recv (a->terminal, buf, sizeof (buf));
923   if (red <= 0)
924     return red;
925
926 #if 0
927   if (*buf == 3)
928     return -1;
929 #endif
930
931 #if 0
932   if (*buf == 2)
933     {
934 #if  0
935       a->history_ptr = c->h->wptr;
936       HISTORY_INC (c->h, a->history_ptr);
937 #endif
938       return -1;
939     }
940 #endif
941
942
943   ansi_parse (a, c, buf, red);
944
945   return 0;
946 }
947
948
949 static void
950 ansi_update (ANSI * a, Context * c)
951 {
952   ansi_history (a, c->h);
953   ansi_draw (a, &c->v->crt);
954   tty_length(a->terminal,c->v->crt.size.y);
955 }
956
957 static void
958 ansi_free (ANSI * a)
959 {
960   a->terminal_reset (a);
961   if (a->terminal)
962     a->terminal->close (a->terminal);
963
964   free (a);
965
966 }
967
968 ANSI *
969 ansi_new_from_terminal (TTY * t, int utf8)
970 {
971   ANSI *ret;
972
973   ret = malloc (sizeof (ANSI));
974   memset (ret, 0, sizeof (ANSI));
975
976   ret->terminal = t;
977
978   ret->utf8 = utf8;
979   ret->update = ansi_update;
980   ret->reset = ansi_reset;
981   ret->terminal_reset = ansi_terminal_reset;
982   ret->close = ansi_free;
983   ret->dispatch = ansi_dispatch;
984
985   return ret;
986 }