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