chiark / gitweb /
*** empty log message ***
[sympathy.git] / src / vt102.c
1 /*
2  * vt102.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/22 17:07:00  james
14  * *** empty log message ***
15  *
16  * Revision 1.30  2008/02/22 14:51:54  james
17  * *** empty log message ***
18  *
19  * Revision 1.29  2008/02/15 03:32:07  james
20  * *** empty log message ***
21  *
22  * Revision 1.28  2008/02/14 10:34:30  james
23  * *** empty log message ***
24  *
25  * Revision 1.27  2008/02/14 02:46:45  james
26  * *** empty log message ***
27  *
28  * Revision 1.26  2008/02/14 01:55:57  james
29  * *** empty log message ***
30  *
31  * Revision 1.25  2008/02/13 16:57:29  james
32  * *** empty log message ***
33  *
34  * Revision 1.24  2008/02/13 09:12:21  james
35  * *** empty log message ***
36  *
37  * Revision 1.23  2008/02/07 13:26:35  james
38  * *** empty log message ***
39  *
40  * Revision 1.22  2008/02/07 13:22:51  james
41  * *** empty log message ***
42  *
43  * Revision 1.21  2008/02/07 12:21:16  james
44  * *** empty log message ***
45  *
46  * Revision 1.20  2008/02/07 12:16:04  james
47  * *** empty log message ***
48  *
49  * Revision 1.19  2008/02/07 11:27:02  james
50  * *** empty log message ***
51  *
52  * Revision 1.18  2008/02/07 01:59:25  james
53  * *** empty log message ***
54  *
55  * Revision 1.17  2008/02/07 01:58:28  james
56  * *** empty log message ***
57  *
58  * Revision 1.16  2008/02/07 01:57:46  james
59  * *** empty log message ***
60  *
61  * Revision 1.15  2008/02/07 00:43:27  james
62  * *** empty log message ***
63  *
64  * Revision 1.14  2008/02/07 00:40:23  james
65  * *** empty log message ***
66  *
67  * Revision 1.13  2008/02/07 00:39:59  james
68  * *** empty log message ***
69  *
70  * Revision 1.12  2008/02/07 00:39:13  james
71  * *** empty log message ***
72  *
73  * Revision 1.11  2008/02/06 20:26:58  james
74  * *** empty log message ***
75  *
76  * Revision 1.10  2008/02/06 17:53:28  james
77  * *** empty log message ***
78  *
79  * Revision 1.9  2008/02/06 15:53:22  james
80  * *** empty log message ***
81  *
82  * Revision 1.8  2008/02/06 11:49:47  james
83  * *** empty log message ***
84  *
85  * Revision 1.7  2008/02/06 11:30:37  james
86  * *** empty log message ***
87  *
88  * Revision 1.6  2008/02/05 01:11:46  james
89  * *** empty log message ***
90  *
91  * Revision 1.5  2008/02/04 20:23:55  james
92  * *** empty log message ***
93  *
94  * Revision 1.4  2008/02/04 05:45:55  james
95  * ::
96  *
97  * Revision 1.3  2008/02/04 02:05:06  james
98  * *** empty log message ***
99  *
100  * Revision 1.2  2008/02/04 01:32:39  james
101  * *** empty log message ***
102  *
103  * Revision 1.1  2008/02/03 23:36:41  james
104  * *** empty log message ***
105  *
106  */
107
108
109 /* Termcap he say:
110
111 VT102:
112
113 vt102|dec vt102:\
114         :mi:\
115         :al=\E[L:dc=\E[P:dl=\E[M:ei=\E[4l:im=\E[4h:tc=vt100:
116
117 vt100|vt100-am|dec vt100 (w/advanced video):\
118         :am:bs:ms:xn:xo:\
119         :co#80:it#8:li#24:vt#3:\
120         :DO=\E[%dB:LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:\
121         :UP=\E[%dA:\
122         :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:\
123         :ae=^O:as=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
124         :cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:\
125         :eA=\E(B\E)0:ho=\E[H:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:\
126         :kr=\EOC:ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:\
127         :me=\E[m\017:mr=\E[7m:nd=\E[C:rc=\E8:\
128         :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:sc=\E7:se=\E[m:\
129         :sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:\
130         :us=\E[4m:tc=vt100+fnkeys:
131
132 vt100+fnkeys|dec vt100 numeric keypad:\
133         :k0=\EOy:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:\
134         :tc=vt100+pfkeys:
135
136 vt100+pfkeys|dec vt100 numeric keypad:\
137         :@8=\EOM:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:tc=vt100+keypad:
138
139 vt100+keypad|dec vt100 numeric keypad no fkeys:\
140         :K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:
141
142 */
143
144 /*
145 so the parser needs to be able to at least do
146 CTRL-G
147 CTRL-H
148 CTRL-I
149 CTRL-J
150 CTRL-M
151 CTRL-N
152
153 CTRL-O
154 ESC7
155 ESC8
156 ESCH
157 ESCM
158 ESC> 
159
160 ESC[%dA
161 ESC[%dB
162 ESC[%dC
163 ESC[%dD
164 ESC[H
165 ESC[%d;%dH
166 ESC[J
167 ESC[K
168 ESC[1K
169 ESC[L
170 ESC[M
171 ESC[P
172
173 ESC[3g
174 ESC[4h
175 ESC[4l
176 ESC[m 
177 ESC[1m
178 ESC[4m
179 ESC[5m
180 ESC[7m
181 ESC[%d;%dr
182
183
184 ESC[?3l 
185 ESC[?4l 
186 ESC[?5l
187 ESC[?7h
188 ESC[?7h
189 ESC[?7l
190 ESC[?8h
191
192 ESC(B
193 ESC)0
194
195
196 TODO:
197
198 ESC(B
199 ESC)0
200
201 CTRL-O
202
203 ANSI:
204
205
206
207 ansi|ansi/pc-term compatible with color:\
208         :u6=\E[%i%d;%dR:u7=\E[6n:u9=\E[c:tc=ecma+color:\
209         :tc=klone+sgr:tc=ansi-m:
210 ansi-m|ansi-mono|ANSI X3.64-1979 terminal with ANSI.SYS compatible attributes:\
211         :5i:\
212         :AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:IC=\E[%d@:\
213         :LE=\E[%dD:RI=\E[%dC:SF=\E[%dS:SR=\E[%dT:UP=\E[%dA:\
214         :cb=\E[1K:ch=\E[%i%dG:ct=\E[2g:cv=\E[%i%dd:ec=\E[%dX:ei=:\
215         :im=:kB=\E[Z:kI=\E[L:kb=^H:kd=\E[B:kl=\E[D:kr=\E[C:ku=\E[A:\
216         :nw=\r\E[S:pf=\E[4i:po=\E[5i:s0=\E(B:s1=\E)B:s2=\E*B:\
217         :s3=\E+B:ta=\E[I:tc=pcansi-m:
218 pcansi-m|pcansi-mono|ibm-pc terminal programs claiming to be ansi (mono mode):\
219         :am:bs:mi:ms:\
220         :co#80:it#8:li#24:\
221         :al=\E[L:bl=^G:bt=\E[Z:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
222         :cm=\E[%i%d;%dH:cr=^M:ct=\E[2g:dc=\E[P:dl=\E[M:do=\E[B:\
223         :ho=\E[H:kb=^H:kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:\
224         :le=\E[D:nd=\E[C:sf=^J:st=\EH:ta=^I:up=\E[A:\
225         :tc=klone+sgr-dumb:
226 klone+sgr-dumb|attribute control for ansi.sys displays (no ESC [ 11 m):\
227         :as=\E[12m:mb=\E[5m:md=\E[1m:me=\E[0;10m:mk=\E[8m:\
228         :mr=\E[7m:se=\E[m:so=\E[7m:ue=\E[m:us=\E[4m:tc=klone+acs:
229 klone+acs|alternate character set for ansi.sys displays:\
230         :ac=+\020,\021-\030.^Y0\333`\004a\261f\370g\361h\260j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376:\
231         :ae=\E[10m:as=\E[11m:
232 ecma+color|color control for ECMA-48-compatible terminals:\
233         :Co#8:NC#3:pa#64:\
234         :AB=\E[4%dm:AF=\E[3%dm:op=\E[39;49m:
235
236
237 Ignoreing ones in the VT102 spec
238
239 ESC[%d@
240 ESC[I
241 ESC[....R
242 ESC[%dS
243 ESC[%dT
244 ESC[X
245 ESC[Z
246
247 ESC[c
248 *ESC[%db
249 ESC[....d
250 ESC[....f
251 ESC[2g
252 ESC[4i
253 ESC[5i
254 ESC[6n
255
256 ESC(B
257 ESC)B
258 ESC*B
259 ESC+B
260
261
262 */
263
264 #include "project.h"
265 #include "syslog.h"
266
267
268 static inline int
269 safe_ch(int c) {
270 if (c<32) return ' ';
271 if (c>126) return ' ';
272 return c;
273 }
274
275 static inline int
276 csi_ender (int c)
277 {
278   if ((c >= 'a') && (c <= 'z'))
279     return 1;
280   if ((c >= 'A') && (c <= 'Z'))
281     return 1;
282   return 0;
283 }
284
285 static inline int
286 scs_starter (int c)
287 {
288   switch (c)
289     {
290     case '(':
291     case ')':
292     case '+':
293     case '*':
294       return 1;
295     }
296   return 0;
297 }
298
299 static inline int
300 csi_starter (int c)
301 {
302   switch (c)
303     {
304     case '[':
305       return 1;
306     }
307   return 0;
308 }
309
310 static inline int
311 in_margins (VT102 * v, CRT_Pos p)
312 {
313   if (v->pos.x < v->top_margin.x)
314     return 0;
315   if (v->pos.y < v->top_margin.y)
316     return 0;
317
318   if (v->pos.x > v->bottom_margin.x)
319     return 0;
320   if (v->pos.y > v->bottom_margin.y)
321     return 0;
322
323   return 1;
324 }
325
326 void
327 vt102_log_line (Context * c, int line)
328 {
329   CRT_Pos e = { VT102_COLS - 1, line };
330   CRT_Pos p = { 0, line };
331   char logbuf[VT102_COLS + 1];
332
333   if (!c->l)
334     return;
335
336
337   for (; e.x > 0; --e.x)
338     {
339       if (c->v->crt.screen[CRT_ADDR_POS (&e)].chr != ' ')
340         break;
341     }
342
343   for (; p.x <= e.x; ++p.x)
344     {
345       int ch = c->v->crt.screen[CRT_ADDR_POS (&p)].chr;
346       if (ch < 32)
347         ch = ' ';
348       if (ch > 126)
349         ch = ' ';
350       logbuf[p.x] = ch;
351     }
352   logbuf[p.x] = 0;
353
354   c->l->log (c->l, logbuf);
355 }
356
357 /*Called for every upward scroll with same args*/
358 void
359 vt102_history (Context * c, CRT_Pos t, CRT_Pos b)
360 {
361 /*Only log if it scrolls off the top*/
362   if (t.y)
363     return;
364
365   t.x = 0;
366   history_add (c->h, &(c->v->crt.screen[CRT_ADDR_POS (&t)]));
367 }
368
369 void
370 vt102_clip_cursor (VT102 * v, CRT_Pos tl, CRT_Pos br)
371 {
372   if (v->pos.x < tl.x)
373     v->pos.x = tl.x;
374   if (v->pos.y < tl.y)
375     v->pos.y = tl.y;
376
377   if (v->pos.x > br.x)
378     v->pos.x = br.x;
379   if (v->pos.y > br.y)
380     v->pos.y = br.y;
381 }
382
383
384 void
385 vt102_cursor_normalize (VT102 * v)
386 {
387   CRT_Pos *top, *bottom;
388
389   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
390     {
391       vt102_clip_cursor (v, v->top_margin, v->bottom_margin);
392     }
393   else
394     {
395       vt102_clip_cursor (v, v->screen_start, v->screen_end);
396     }
397 }
398
399
400 void
401 vt102_cursor_carriage_return (VT102 * v)
402 {
403    /*FISH*/ v->pos.x = v->top_margin.x;
404   v->pending_wrap = 0;
405 }
406
407 void
408 vt102_cursor_advance_line (Context * c)
409 {
410   VT102 *v = c->v;
411   int couldscroll = in_margins (v, v->pos);
412
413 /*have wraped off end of last line in scrolling region */
414 /* (|| not necessary, but shuts compiler up */
415   if (((v->pos.y == v->bottom_margin.y) || (v->pos.y == v->screen_end.y)) &&
416       (couldscroll))
417     {
418       vt102_log_line (c, v->pos.y);
419
420       vt102_history (c, v->top_margin, v->bottom_margin);
421
422       crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1, v->color);
423       return;
424     }
425
426   if (v->pos.y!=v->screen_end.y) v->pos.y++;
427   v->pending_wrap = 0;
428 }
429
430
431 void
432 vt102_do_pending_wrap (Context * c)
433 {
434   VT102 *v = c->v;
435   int couldscroll = in_margins (v, v->pos);
436   int autowrap = v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP];
437
438   if (!v->pending_wrap)
439     return;
440
441 #if 0
442   fprintf (stderr, "ca: (%d,%d) autowrap %d couldscroll %d\n", v->pos.x,
443            v->pos.y, autowrap, couldscroll);
444 #endif
445
446 /*End of line but no autowrap, nothing to do*/
447   if (!autowrap)
448     return;
449
450 /*End of screen and not allowed to scroll, nothing to do*/
451   if ((v->pos.y == v->screen_end.y) && (!couldscroll))
452     return;
453
454   if (couldscroll)
455     {
456       v->pos.x = v->top_margin.x;
457     }
458   else
459     {
460       v->pos.x = 0;
461     }
462
463   vt102_cursor_advance_line (c);
464 }
465
466 void
467 vt102_cursor_advance (Context * c)
468 {
469   VT102 *v = c->v;
470
471   if (v->pos.x < v->bottom_margin.x)
472     {
473 /*Normal advance*/
474       v->pos.x++;
475       v->pending_wrap = 0;
476       return;
477     }
478   v->pending_wrap++;
479   if (!c->v->xn_glitch)
480         vt102_do_pending_wrap(c);
481 }
482
483
484
485 void
486 vt102_cursor_retard (VT102 * v)
487 {
488   if (v->pos.x != v->top_margin.x)
489     v->pos.x--;
490
491   v->pending_wrap = 0;
492 }
493
494 void
495 vt102_reset_tabs (VT102 * v)
496 {
497   int i;
498
499   memset (v->tabs, 0, sizeof (v->tabs));
500
501   for (i = 0; i < VT102_COLS; i += 8)
502     {
503       v->tabs[i]++;
504     }
505 }
506 void
507 vt102_cursor_advance_tab (VT102 * v)
508 {
509   if (v->pos.x == v->bottom_margin.x)
510     return;
511   while (v->pos.x < v->bottom_margin.x)
512     {
513       v->pos.x++;
514       if (v->tabs[v->pos.x])
515         break;
516     }
517   v->pending_wrap = 0;
518 }
519
520 void
521 vt102_cursor_retard_tab (VT102 * v)
522 {
523   if (v->pos.x == v->top_margin.x)
524     return;
525   while (v->pos.x > v->top_margin.x)
526     {
527       v->pos.x--;
528       if (v->tabs[v->pos.x])
529         break;
530     }
531   v->pending_wrap = 0;
532 }
533
534 vt102_cursor_home (VT102 * v)
535 {
536   v->pos = v->top_margin;
537   vt102_cursor_normalize (v);
538   v->pending_wrap = 0;
539
540 }
541
542 vt102_cursor_absolute (VT102 * v, int x, int y)
543 {
544   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
545     {
546       v->pos.x = x + v->top_margin.x;
547       v->pos.y = y + v->top_margin.x;
548     }
549   else
550     {
551       v->pos.x = x;
552       v->pos.y = y;
553     }
554   vt102_cursor_normalize (v);
555   v->pending_wrap = 0;
556 }
557
558 vt102_cursor_relative (VT102 * v, int x, int y)
559 {
560   v->pos.x += x;
561   v->pos.y += y;
562   vt102_cursor_normalize (v);
563   v->pending_wrap = 0;
564 }
565
566
567
568 void
569 vt102_delete_from_line (VT102 * v, CRT_Pos p)
570 {
571   int n = v->bottom_margin.x - p.x;
572
573   if (n < 0)
574     return;
575
576   if (n)
577     {
578
579       memmove (&v->crt.screen[CRT_ADDR_POS (&p)],
580                &v->crt.screen[CRT_ADDR_POS (&p) + 1], sizeof (CRT_CA) * n);
581     }
582
583   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
584 /*But not attr due to vt102 bug*/
585 }
586
587 void
588 vt102_insert_into_line (VT102 * v, CRT_Pos p)
589 {
590   int n = v->bottom_margin.x - p.x;
591
592   if (n < 0)
593     return;
594
595   if (n)
596     {
597
598       memmove (&v->crt.screen[CRT_ADDR_POS (&p) + 1],
599                &v->crt.screen[CRT_ADDR_POS (&p)], sizeof (CRT_CA) * n);
600     }
601
602   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
603   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].attr = CRT_ATTR_NORMAL;
604   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].color = CRT_COLOR_NORMAL;
605 }
606
607
608
609 void
610 vt102_change_mode (VT102 * v, int private, char *ns, int set)
611 {
612   int m;
613
614
615   if (*ns)
616     {
617       m = atoi (ns);
618     }
619   else
620     {
621       m = 1;
622     }
623
624   if (m < 0)
625     return;
626   if (m >= VT102_NMODES)
627     return;
628
629   if (private)
630     {
631       v->private_modes[m] = set;
632       switch (m)
633         {
634         case VT102_PRIVATE_MODE_CURSOR_MODE:
635           if (v->application_keypad_mode)
636             v->private_modes[m] = 0;
637 #if 0
638           fprintf (stderr, "APPLICATION CURSOR MODE %d wanted %d\n",
639                    v->private_modes[m], set);
640 #endif
641           break;
642         case VT102_PRIVATE_MODE_ORIGIN_MODE:
643           vt102_cursor_home (v);
644           break;
645         }
646
647     }
648   else
649     v->modes[m] = set;
650
651 #if 0
652   fprintf (stderr, "mode set=%d private=%d num=%d\n", set, private, m);
653 #endif
654 }
655
656 void
657 vt102_parse_mode_string (VT102 * v, char *buf, int len)
658 {
659   int private = 0;
660   char last = buf[len - 1];
661   char num[4];
662   int o;
663
664   memset (num, 0, sizeof (num));
665   o = sizeof (num) - 1;
666
667   len--;
668
669   if (*buf == '?')
670     {
671       private++;
672       buf++;
673       len--;
674     }
675
676   if (len < 0)
677     return;
678
679   while (len--)
680     {
681       if (*buf == ';')
682         {
683           vt102_change_mode (v, private, &num[o], last == 'h');
684           memset (num, 0, sizeof (num));
685           o = sizeof (num) - 1;
686           buf++;
687           continue;
688         }
689
690       num[0] = num[1];
691       num[1] = num[2];
692       num[2] = *buf;
693
694       if (o)
695         o--;
696
697       buf++;
698     }
699
700   vt102_change_mode (v, private, &num[o], last == 'h');
701
702 }
703
704
705 void
706 vt102_change_attr (VT102 * v, char *na)
707 {
708   int a;
709
710
711   if (*na)
712     {
713       a = atoi (na);
714     }
715   else
716     {
717       a = 0;
718     }
719
720   switch (a)
721     {
722     case 0:
723       v->attr = CRT_ATTR_NORMAL;
724       v->color = CRT_COLOR_NORMAL;
725       break;
726     case 1:
727       v->attr |= CRT_ATTR_BOLD;
728       break;
729     case 21:
730     case 22:
731       v->attr &= ~CRT_ATTR_BOLD;
732       break;
733     case 4:
734       v->attr |= CRT_ATTR_UNDERLINE;
735       break;
736     case 24:
737       v->attr &= ~CRT_ATTR_UNDERLINE;
738       break;
739     case 5:
740       v->attr |= CRT_ATTR_BLINK;
741       break;
742     case 25:
743       v->attr &= ~CRT_ATTR_BLINK;
744       break;
745     case 7:
746       v->attr |= CRT_ATTR_REVERSE;
747       break;
748     case 27:
749       v->attr &= ~CRT_ATTR_REVERSE;
750       break;
751     case 30:
752     case 31:
753     case 32:
754     case 33:
755     case 34:
756     case 35:
757     case 36:
758     case 37:
759       v->color &= ~CRT_COLOR_FG_MASK;
760       v->color |= ((a - 30) << CRT_COLOR_FG_SHIFT) & CRT_COLOR_FG_MASK;
761       break;
762     case 90:
763     case 91:
764     case 92:
765     case 93:
766     case 94:
767     case 95:
768     case 96:
769     case 97:
770       v->color &= ~CRT_COLOR_FG_MASK;
771       v->color |=
772         (((a -
773            90) | CRT_COLOR_INTENSITY) << CRT_COLOR_FG_SHIFT) &
774         CRT_COLOR_FG_MASK;
775       break;
776     case 39:
777     case 99:
778       v->color &= ~CRT_COLOR_FG_MASK;
779       v->color |=
780         (CRT_FGCOLOR_NORMAL << CRT_COLOR_FG_SHIFT) & CRT_COLOR_FG_MASK;
781       break;
782     case 40:
783     case 41:
784     case 42:
785     case 43:
786     case 44:
787     case 45:
788     case 46:
789     case 47:
790       v->color &= ~CRT_COLOR_BG_MASK;
791       v->color |= ((a - 40) << CRT_COLOR_BG_SHIFT) & CRT_COLOR_BG_MASK;
792       break;
793     case 100:
794     case 101:
795     case 102:
796     case 103:
797     case 104:
798     case 105:
799     case 106:
800     case 107:
801       v->color &= ~CRT_COLOR_BG_MASK;
802       v->color |=
803         (((a -
804            100) | CRT_COLOR_INTENSITY) << CRT_COLOR_BG_SHIFT) &
805         CRT_COLOR_BG_MASK;
806       break;
807     case 49:
808     case 109:
809       v->color &= ~CRT_COLOR_BG_MASK;
810       v->color |=
811         (CRT_BGCOLOR_NORMAL << CRT_COLOR_BG_SHIFT) & CRT_COLOR_BG_MASK;
812       break;
813
814     default:
815       ;
816 #if 0
817       fprintf (stderr, "unhandled SGR %d\n", a);
818 #endif
819     }
820
821 }
822
823
824 void
825 vt102_parse_attr_string (VT102 * v, char *buf, int len)
826 {
827   int private = 0;
828   char last = buf[len - 1];
829   char num[4];
830   int o;
831
832   memset (num, 0, sizeof (num));
833   o = sizeof (num) - 1;
834
835   len--;
836
837   if (len < 0)
838     return;
839
840   while (len--)
841     {
842       if (*buf == ';')
843         {
844           vt102_change_attr (v, &num[o]);
845           memset (num, 0, sizeof (num));
846           o = sizeof (num) - 1;
847           buf++;
848           continue;
849         }
850
851       num[0] = num[1];
852       num[1] = num[2];
853       num[2] = *buf;
854
855       if (o)
856         o--;
857
858       buf++;
859     }
860   vt102_change_attr (v, &num[o]);
861 }
862
863 void
864 vt102_save_state (VT102 * v)
865 {
866   v->saved.pos = v->pos;
867   v->saved.attr = v->attr;
868   v->saved.color = v->color;
869   v->saved.origin_mode = v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE];
870 }
871
872 void
873 vt102_restore_state (VT102 * v)
874 {
875   v->pos = v->saved.pos;
876   v->attr = v->saved.attr;
877   v->color = v->saved.color;
878   v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE] = v->saved.origin_mode;
879   vt102_cursor_normalize (v);
880   v->pending_wrap = 0;
881 }
882
883 void
884 vt102_regular_char (Context * c, VT102 * v, char ch)
885 {
886
887   vt102_do_pending_wrap (c);
888
889   if (v->modes[VT102_MODE_INSERT])
890     vt102_insert_into_line (v, v->pos);
891
892   v->crt.screen[CRT_ADDR_POS (&v->pos)].chr = ch;
893   v->crt.screen[CRT_ADDR_POS (&v->pos)].attr = v->attr;
894   v->crt.screen[CRT_ADDR_POS (&v->pos)].color = v->color;
895   vt102_cursor_advance (c);
896
897   v->last_reg_char = ch;
898 }
899
900 void
901 vt102_scs (Context * c, int g, int s)
902 {
903 /*Ignoring charsets*/
904 }
905
906 void
907 vt102_parse_esc (Context * c, int ch)
908 {
909   VT102 *v = c->v;
910   switch (ch)
911     {
912     case 'E':
913       if (v->pos.y == v->bottom_margin.y)
914         {
915           vt102_log_line (c, v->pos.y);
916           vt102_history (c, v->top_margin, v->bottom_margin);
917           crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1,v->color);
918         }
919       else
920         {
921           vt102_cursor_relative (v, 0, 1);
922         }
923       break;
924     case 'H':
925       v->tabs[v->pos.x]++;
926       break;
927     case 'M':
928       if (v->pos.y == v->top_margin.y)
929         {
930           crt_scroll_down (&v->crt, v->top_margin, v->bottom_margin, 1,v->color);
931         }
932       else
933         {
934           vt102_cursor_relative (v, 0, -1);
935         }
936       break;
937     case '7':
938       vt102_save_state (v);
939       break;
940     case '8':
941       vt102_restore_state (v);
942       break;
943     case '=':
944       v->application_keypad_mode = 1;
945       break;
946     case '>':
947       v->application_keypad_mode = 0;
948       break;
949     default:
950       log_f (c->l, "<%s:%d unhandled ESC: \\033 \\%03o (ESC %c)>", __FILE__,__LINE__,ch,safe_ch(ch));
951
952       ;
953     }
954 }
955 void
956 vt102_parse_csi (Context * c, char *buf, int len)
957 {
958   char last;
959   char *ptr;
960   char *arg = buf + 1;
961   int narg;
962
963   VT102 *v = c->v;
964
965   buf[len] = 0;
966
967   last = buf[len - 1];
968 #if 0
969   buf[len - 1] = 0;
970 #endif
971
972   if (len > 2)
973     {
974       narg = atoi (arg);
975     }
976   else
977     {
978       narg = 1;
979     }
980
981   switch (buf[0])
982     {
983     case '[':
984       switch (last)
985         {
986         case '@':
987           while (narg--)
988             vt102_insert_into_line (v, v->pos);
989           break;
990         case 'A':
991           vt102_cursor_relative (v, 0, -narg);
992           break;
993         case 'e':
994         case 'B':
995           vt102_cursor_relative (v, 0, narg);
996           break;
997         case 'a':
998         case 'C':
999           vt102_cursor_relative (v, narg, 0);
1000           break;
1001         case 'D':
1002           vt102_cursor_relative (v, -narg, 0);
1003           break;
1004         case 'E':
1005           vt102_cursor_relative (v, 0, narg);
1006           vt102_cursor_carriage_return (v);
1007           break;
1008         case 'F':
1009           vt102_cursor_relative (v, 0, -narg);
1010           vt102_cursor_carriage_return (v);
1011           break;
1012         case 'G':
1013           vt102_cursor_absolute (v, narg - 1, v->pos.y);
1014           break;
1015         case 'H':
1016         case 'f':
1017           {
1018             int x, y;
1019
1020             y = narg - 1;
1021
1022             ptr = index (arg, ';');
1023             if (ptr)
1024               x = atoi (ptr + 1) - 1;
1025             else
1026               x = 0;
1027
1028             vt102_cursor_absolute (v, x, y);
1029           }
1030           break;
1031         case 'I':
1032           while (narg--)
1033             vt102_cursor_advance_tab (c->v);
1034           break;
1035         case 'J':
1036             if (len == 2)
1037               narg = 0;         /*Different default */
1038           switch (narg)
1039             {
1040             case 0:
1041               crt_erase (&v->crt, v->pos, v->screen_end, 1,v->color);
1042               break;
1043             case 1:
1044               crt_erase (&v->crt, v->screen_start, v->pos, 1,v->color);
1045               break;
1046             case 2:
1047               crt_erase (&v->crt, v->screen_start, v->screen_end, 1,v->color);
1048               break;
1049             }
1050           break;
1051         case 'K':
1052           {
1053             CRT_Pos ls = { 0, v->pos.y };
1054             CRT_Pos le = { VT102_COLS - 1, v->pos.y };
1055             if (len == 2)
1056               narg = 0;         /*Different default */
1057
1058             switch (narg)
1059               {
1060               case 0:
1061                 crt_erase (&v->crt, v->pos, le, 1,v->color);
1062                 break;
1063               case 1:
1064                 crt_erase (&v->crt, ls, v->pos, 1,v->color);
1065                 break;
1066               case 2:
1067                 crt_erase (&v->crt, ls, le, 1,v->color);
1068                 break;
1069               }
1070           }
1071           break;
1072
1073         case 'L':
1074           if ((v->pos.y >= v->top_margin.y)
1075               && (v->pos.y <= v->bottom_margin.y))
1076             {
1077               while (narg--)
1078                 crt_scroll_down (&v->crt, v->pos, v->bottom_margin, 1,v->color);
1079             }
1080           break;
1081
1082         case 'M':
1083           if ((v->pos.y >= v->top_margin.y)
1084               && (v->pos.y <= v->bottom_margin.y))
1085             {
1086               while (narg--)
1087                 {
1088                   vt102_history (c, v->pos, v->bottom_margin);
1089                   crt_scroll_up (&v->crt, v->pos, v->bottom_margin, 1,v->color);
1090                 }
1091             }
1092           break;
1093         case 'P':
1094           while (narg--)
1095             vt102_delete_from_line (v, v->pos);
1096           break;
1097         case 'R':
1098           //FIXME: cursor position report - does anything use that?
1099           break;
1100         case 'S':
1101           while (narg--)
1102             {
1103               vt102_history (c, v->top_margin, v->bottom_margin);
1104               crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1,v->color);
1105             }
1106           break;
1107         case 'T':
1108           while (narg--)
1109             crt_scroll_down (&v->crt, v->top_margin, v->bottom_margin, 1,v->color);
1110           break;
1111         case 'X':
1112           {
1113             CRT_Pos end = v->pos;
1114             if (!narg) narg++;
1115
1116             end.x += narg-1;
1117             if (end.x > v->bottom_margin.x)
1118               end.x = v->bottom_margin.x;
1119
1120             crt_erase (&v->crt, v->pos, end, 1,v->color);
1121           }
1122           break;
1123         case 'Z':
1124           while (narg--)
1125             vt102_cursor_retard_tab (c->v);
1126           break;
1127         case '`':
1128           vt102_cursor_absolute (v, narg - 1, v->pos.y);
1129           break;
1130         case 'b':
1131           while (narg--)
1132             vt102_regular_char (c, v, v->last_reg_char);
1133           break;
1134         case 'c':
1135           //FIXME:
1136           break;
1137         case 'd':
1138           vt102_cursor_absolute (v, v->pos.x, narg - 1);
1139           break;
1140         case 'g':
1141           if (len == 2)
1142             narg = 0;           /*Different default */
1143
1144           switch (narg)
1145             {
1146             case 0:
1147               v->tabs[v->pos.x] = 0;
1148               break;
1149             case 2:            //FIXME: - LA120 says current line only WTF?
1150             case 3:
1151               memset (v->tabs, 0, sizeof (v->tabs));
1152               break;
1153             }
1154           break;
1155
1156         case 'i':              //4,5 Turn printer on and off WTF?
1157           //FIXME
1158           break;
1159         case 'h':
1160         case 'l':
1161           vt102_parse_mode_string (v, &buf[1], len - 1);
1162           break;
1163
1164
1165         case 'm':
1166           vt102_parse_attr_string (v, &buf[1], len - 1);
1167           break;
1168         case 'n':              // 6 request cursor position
1169           //FIXME 
1170           break;
1171         case 'r':
1172           v->top_margin = v->screen_start;
1173           v->bottom_margin = v->screen_end;
1174
1175           if ((len > 2) && (ptr = index (arg, ';')))
1176             {
1177               ptr++;
1178               v->top_margin.y = narg - 1;
1179               v->bottom_margin.y = atoi (ptr) - 1;
1180             }
1181
1182           if (v->top_margin.y < v->screen_start.y)
1183             v->top_margin.y = v->screen_start.y;
1184           if (v->top_margin.y > v->screen_end.y)
1185             v->top_margin.y = v->screen_end.y;
1186           if (v->bottom_margin.y < v->screen_start.y)
1187             v->bottom_margin.y = v->screen_start.y;
1188           if (v->bottom_margin.y > v->screen_end.y)
1189             v->bottom_margin.y = v->screen_end.y;
1190
1191           vt102_cursor_home (v);
1192           break;
1193         case 's':
1194           v->saved.pos = v->pos;
1195           break;
1196         case 'u':
1197           v->pos = v->saved.pos;
1198           vt102_cursor_normalize (v);
1199           v->pending_wrap = 0;
1200           break;
1201
1202         default:
1203       log_f (c->l, "<%s:%d unhandled CSI: \\033%s>", __FILE__,__LINE__,buf);
1204
1205           ;
1206         }
1207       break;
1208     default:
1209       log_f (c->l, "<%s:%d unhandled sequence: \\033%s>", __FILE__,__LINE__,buf);
1210       ;
1211     }
1212
1213
1214
1215 }
1216
1217 void
1218 vt102_status_line (VT102 * v, char *str)
1219 {
1220   int i = VT102_COLS;
1221   CRT_CA *ca = &v->crt.screen[CRT_ADDR (VT102_STATUS_ROW, 0)];
1222
1223   while (i--)
1224     {
1225       ca->attr = CRT_ATTR_REVERSE;
1226       ca->color = CRT_COLOR_NORMAL;
1227       ca->chr = *str;
1228       if (*str)
1229         str++;
1230       ca++;
1231     }
1232
1233 }
1234
1235
1236 void
1237 vt102_parse_char (Context * c, int ch)
1238 {
1239   VT102 *v = c->v;
1240   VT102_parser *p = &v->parser;
1241
1242 #if 1
1243   log_f (c->l, "char %3d %c pc %d %d %d     %2d %2d %d",ch,safe_ch(ch),
1244            p->in_utf8,p->in_escape, p->in_csi, v->pos.x, v->pos.y,v->pending_wrap);
1245 #endif
1246
1247   if ((ch>=0xc0) && (ch<0xe0)) /*Start of two byte unicode sequence*/
1248   {
1249         p->in_utf8=2;
1250   } else if ((ch>=0xe0) && (ch<0xf0)) /*Start of three byte unicode sequence*/
1251   {
1252         p->in_utf8=3;
1253   } else if ((ch>=0xf0) && (ch<0xf7)) /*Start of four byte unicode sequence*/
1254         p->in_utf8=4;
1255   }
1256
1257   if (p->utf_8) {
1258         p->in_utf8--;
1259         ch='?';
1260   }  
1261
1262   if (p->utf_8) {
1263         /*Not first or last byte in sequence*/
1264   }else if (p->in_csi)
1265     {
1266       p->csi_buf[p->csi_ptr++] = ch;
1267       if (csi_ender (ch) || (p->csi_ptr == VT102_CSI_LEN))
1268         {
1269           if (csi_starter (p->csi_buf[0]))
1270             {
1271               vt102_parse_csi (c, p->csi_buf, p->csi_ptr);
1272             }
1273           else if (scs_starter (p->csi_buf[0]))
1274             {
1275               vt102_scs (c, p->csi_buf[0], p->csi_buf[1]);
1276             }
1277           else
1278             {
1279       log_f (c->l, "<%s:%d no dispatcher for sequence starting \\033 \\%03o (ESC %c)>", __FILE__,__LINE__,p->csi_buf[0],safe_ch(p->csi_buf[0]));
1280             }
1281           p->in_csi = 0;
1282         }
1283     }
1284   else if (p->in_escape)
1285     {
1286       if (csi_starter (ch) || scs_starter (ch))
1287         {
1288           p->csi_ptr = 0;
1289           p->csi_buf[p->csi_ptr++] = ch;
1290           p->in_csi++;
1291           p->in_escape = 0;
1292         }
1293       else
1294         {
1295           p->in_escape = 0;
1296           vt102_parse_esc (c, ch);
1297         }
1298     }
1299   else if (ch==0x9b) /*One byte CSI*/
1300     {
1301           p->csi_ptr = 0;
1302           p->csi_buf[p->csi_ptr++] = '[';
1303           p->in_csi++;
1304    }
1305   else
1306     {
1307
1308       switch (ch)
1309         {
1310          /*NUL*/ case 0:
1311          /*SOH*/ case 1:
1312          /*STX*/ case 2:
1313          /*ETX*/ case 3:
1314          /*EOT*/ case 4:
1315           break;
1316          /*ENQ*/ case 5:
1317           if (c->t)
1318           c->t->xmit (c->t, "vt102", 5);
1319           break;
1320          /*ACK*/ case 6:
1321          /*BEL*/ case 7:
1322           break;
1323          /*BS*/ case 8:
1324           vt102_cursor_retard (c->v);
1325           break;
1326          /*HT*/ case 9:
1327           vt102_cursor_advance_tab (c->v);
1328           break;
1329          /*LF*/ case 10:
1330          /*VT*/ case 11:
1331          /*FF*/ case 12:
1332           vt102_cursor_advance_line (c);
1333           if (!v->modes[VT102_MODE_NEWLINE_MODE])
1334             break;
1335          /*CR*/ case 13:
1336           vt102_cursor_carriage_return (v);
1337           break;
1338          /*SO*/ case 14:
1339           /*select G1 */
1340           /*Ignoring charsets */
1341           break;
1342          /*SI*/ case 15:
1343           /*select G0 */
1344           /*Ignoring charsets */
1345           break;
1346          /*DLE*/ case 16:
1347         /*DC1 */ case 17:
1348         /*DC2 */ case 18:
1349         /*DC3 */ case 19:
1350         /*DC4 */ case 20:
1351          /*NAK*/ case 21:
1352          /*SYN*/ case 22:
1353          /*ETB*/ case 23:
1354          /*CAN*/ case 24:
1355          /*EM*/ case 25:
1356          /*SUB*/ case 26:
1357           break;
1358          /*ESC*/ case 27:
1359           p->in_escape++;
1360           return;
1361          /*FS*/ case 28:
1362          /*GS*/ case 29:
1363          /*RS*/ case 30:
1364          /*US*/ case 31:
1365          /*DEL*/ case 127:
1366           break;
1367         /*regular character */ default:
1368           vt102_regular_char (c, v, ch);
1369         }
1370     }
1371
1372   v->crt.pos = v->pos;
1373   v->crt.hide_cursor =
1374     v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] ? 0 : 1;
1375
1376   if (v->current_line.y != v->pos.y)
1377     {
1378       vt102_log_line (c, v->current_line.y);
1379       v->current_line = v->pos;
1380     }
1381
1382   if (c->d)
1383     cmd_show_status (c->d, c);
1384 }
1385
1386 vt102_parse (Context * c, char *buf, int len)
1387 {
1388   while (len--)
1389     vt102_parse_char (c, *(buf++));
1390 }
1391
1392
1393 void
1394 vt102_parser_reset (VT102_parser * p)
1395 {
1396   p->in_csi = 0;
1397   p->in_escape = 0;
1398   p->csi_ptr = 0;
1399 }
1400
1401
1402 void
1403 vt102_send (Context * c, uint8_t key)
1404 {
1405   uint8_t ch;
1406
1407   if (!c->t)
1408     return;
1409
1410 #if 0
1411   fprintf (stderr, "vts: %d(%c)\n", key, (key > 31) ? key : ' ');
1412 #endif
1413   if ((key > 31) && (key < 127))
1414     {
1415       c->t->xmit (c->t, &key, 1);
1416       return;
1417     }
1418
1419   switch (key)
1420     {
1421      /*NUL*/ case 0:
1422      /*SOH*/ case 1:
1423      /*STX*/ case 2:
1424      /*ETX*/ case 3:
1425      /*EOT*/ case 4:
1426      /*ENQ*/ case 5:
1427      /*ACK*/ case 6:
1428      /*BEL*/ case 7:
1429      /*BS*/ case 8:
1430      /*HT*/ case 9:
1431      /*LF*/ case 10:
1432      /*VT*/ case 11:
1433      /*FF*/ case 12:
1434       c->t->xmit (c->t, &key, 1);
1435       break;
1436      /*CR*/ case 13:
1437       c->t->xmit (c->t, &key, 1);
1438       if (c->v->modes[VT102_MODE_NEWLINE_MODE])
1439         {
1440           ch = 10;
1441           c->t->xmit (c->t, &ch, 1);
1442         }
1443       break;
1444      /*SO*/ case 14:
1445      /*SI*/ case 15:
1446      /*DLE*/ case 16:
1447     /*DC1 */ case 17:
1448     /*DC2 */ case 18:
1449     /*DC3 */ case 19:
1450     /*DC4 */ case 20:
1451      /*NAK*/ case 21:
1452      /*SYN*/ case 22:
1453      /*ETB*/ case 23:
1454      /*CAN*/ case 24:
1455      /*EM*/ case 25:
1456      /*SUB*/ case 26:
1457       c->t->xmit (c->t, &key, 1);
1458       break;
1459      /*ESC*/ case 27:
1460      /*FS*/ case 28:
1461      /*GS*/ case 29:
1462      /*RS*/ case 30:
1463      /*US*/ case 31:
1464      /*DEL*/ case 127:
1465       c->t->xmit (c->t, &key, 1);
1466       break;
1467
1468     case KEY_UP:
1469     case KEY_DOWN:
1470     case KEY_RIGHT:
1471     case KEY_LEFT:
1472     case KEY_HOME:
1473     case KEY_MIDDLE:
1474     case KEY_END:
1475
1476       if (c->v->private_modes[VT102_PRIVATE_MODE_CURSOR_MODE])
1477         {
1478           uint8_t buf[] = { 033, 'O', 'A' + (key - KEY_UP) };
1479           c->t->xmit (c->t, &buf, sizeof (buf));
1480         }
1481       else
1482         {
1483           uint8_t buf[] = { 033, '[', 'A' + (key - KEY_UP) };
1484           c->t->xmit (c->t, &buf, sizeof (buf));
1485         }
1486       break;
1487     case KEY_STAR:
1488     case KEY_PLUS:
1489     case KEY_COMMA:
1490     case KEY_PERIOD:
1491     case KEY_DIVIDE:
1492     case KEY_0:
1493     case KEY_1:
1494     case KEY_2:
1495     case KEY_3:
1496     case KEY_4:
1497     case KEY_5:
1498     case KEY_6:
1499     case KEY_7:
1500     case KEY_8:
1501     case KEY_9:
1502       if (c->v->application_keypad_mode)
1503         {
1504           uint8_t buf[] = { 033, 'O', 'a' + (key - KEY_154) };
1505           c->t->xmit (c->t, &buf, sizeof (buf));
1506         }
1507       else
1508         {
1509           static char kpoff[KEY_NUM] = {
1510             [KEY_STAR] = '*',
1511             [KEY_PLUS] = '+',
1512             [KEY_COMMA] = ',',
1513             [KEY_MINUS] = '-',
1514             [KEY_PERIOD] = '.',
1515             [KEY_DIVIDE] = '/',
1516             [KEY_0] = '0',
1517             [KEY_1] = '1',
1518             [KEY_2] = '2',
1519             [KEY_3] = '3',
1520             [KEY_4] = '4',
1521             [KEY_5] = '5',
1522             [KEY_6] = '6',
1523             [KEY_7] = '7',
1524             [KEY_8] = '8',
1525             [KEY_9] = '9'
1526           };
1527
1528           c->t->xmit (c->t, &kpoff[key], 1);
1529         }
1530       break;
1531     case KEY_ENTER:
1532       if (c->v->application_keypad_mode)
1533         {
1534           uint8_t buf[] = { 033, 'O', 'M' };
1535           c->t->xmit (c->t, &buf, sizeof (buf));
1536         }
1537       else
1538         {
1539           ch = 13;
1540           c->t->xmit (c->t, &ch, 1);
1541           if (c->v->modes[VT102_MODE_NEWLINE_MODE])
1542             {
1543               ch = 10;
1544               c->t->xmit (c->t, &ch, 1);
1545             }
1546         }
1547       break;
1548     case KEY_PF1:
1549     case KEY_PF2:
1550     case KEY_PF3:
1551     case KEY_PF4:
1552       {
1553         uint8_t buf[] = { 033, 'O', 'P' + (key - KEY_PF1) };
1554         c->t->xmit (c->t, &buf, sizeof (buf));
1555       }
1556       break;
1557     case KEY_INSERT:
1558     case KEY_DELETE:
1559     case KEY_PGUP:
1560     case KEY_PGDN:
1561       {
1562         uint8_t buf[] = { 033, '[', '0' + (key - KEY_180), '~' };
1563         c->t->xmit (c->t, &buf, sizeof (buf));
1564       }
1565       break;
1566     }
1567
1568 }
1569
1570 void
1571 vt102_reset (VT102 * v)
1572 {
1573   VT102_parser *p = &v->parser;
1574
1575   vt102_parser_reset (p);
1576   crt_cls (&v->crt);
1577
1578   v->attr = CRT_ATTR_NORMAL;
1579   v->color = CRT_COLOR_NORMAL;
1580
1581   v->application_keypad_mode = 0;
1582
1583   v->current_line = v->pos;
1584   v->pending_wrap = 0;
1585
1586   v->screen_start.x = 0;
1587   v->screen_start.y = 0;
1588   v->screen_end.x = VT102_COLS - 1;
1589   v->screen_end.y = VT102_ROWS - 1;
1590
1591   v->top_margin = v->screen_start;
1592   v->bottom_margin = v->screen_end;
1593
1594   memset (v->modes, 0, VT102_NMODES);
1595   memset (v->private_modes, 0, VT102_NMODES);
1596
1597   v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP] = 1;
1598   v->private_modes[VT102_PRIVATE_MODE_AUTO_REPEAT] = 1;
1599   v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] = 1;
1600   v->modes[VT102_MODE_LOCAL_ECHO_OFF] = 1;
1601
1602   vt102_cursor_home (v);
1603   vt102_reset_tabs (v);
1604   v->current_line = v->pos;
1605
1606   vt102_save_state (v);
1607
1608   vt102_status_line (v, "");
1609
1610   v->last_reg_char = ' ';
1611
1612
1613 }
1614
1615 int
1616 vt102_dispatch (Context * c)
1617 {
1618   char buf[1024];
1619   int red;
1620
1621   red = c->t->recv (c->t, buf, sizeof (buf));
1622
1623   if (red < 0)
1624     return -1;
1625   if (!red)
1626     return 0;
1627
1628
1629   vt102_parse (c, buf, red);
1630
1631   return 0;
1632 }
1633
1634
1635 int
1636 vt102_dispatch_one (Context * c)
1637 {
1638   char buf;
1639   int red;
1640
1641   red = c->t->recv (c->t, &buf, sizeof (buf));
1642
1643   if (red < 0)
1644     return -1;
1645   if (!red)
1646     return 0;
1647
1648   vt102_parse_char (c, buf);
1649
1650   return 0;
1651 }
1652
1653 VT102 *
1654 vt102_new (void)
1655 {
1656   VT102 *v;
1657
1658   v = (VT102 *) malloc (sizeof (VT102));
1659   v->xn_glitch=1;
1660
1661   vt102_reset (v);
1662
1663
1664   return v;
1665 }
1666
1667 void vt102_set_ansi(VT102 *v,int ansi)
1668 {
1669 v->xn_glitch=ansi ? 0:1;
1670 }
1671
1672 void
1673 vt102_free (VT102 * v)
1674 {
1675   free (v);
1676 }