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