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