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