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