chiark / gitweb /
40bef8eb7deda2d6a9c85e2e935519a3fed5a118
[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.13  2008/02/07 00:39:59  james
14  * *** empty log message ***
15  *
16  * Revision 1.12  2008/02/07 00:39:13  james
17  * *** empty log message ***
18  *
19  * Revision 1.11  2008/02/06 20:26:58  james
20  * *** empty log message ***
21  *
22  * Revision 1.10  2008/02/06 17:53:28  james
23  * *** empty log message ***
24  *
25  * Revision 1.9  2008/02/06 15:53:22  james
26  * *** empty log message ***
27  *
28  * Revision 1.8  2008/02/06 11:49:47  james
29  * *** empty log message ***
30  *
31  * Revision 1.7  2008/02/06 11:30:37  james
32  * *** empty log message ***
33  *
34  * Revision 1.6  2008/02/05 01:11:46  james
35  * *** empty log message ***
36  *
37  * Revision 1.5  2008/02/04 20:23:55  james
38  * *** empty log message ***
39  *
40  * Revision 1.4  2008/02/04 05:45:55  james
41  * ::
42  *
43  * Revision 1.3  2008/02/04 02:05:06  james
44  * *** empty log message ***
45  *
46  * Revision 1.2  2008/02/04 01:32:39  james
47  * *** empty log message ***
48  *
49  * Revision 1.1  2008/02/03 23:36:41  james
50  * *** empty log message ***
51  *
52  */
53
54
55 /* Termcap he say:
56
57 vt102|dec vt102:\
58         :mi:\
59         :al=\E[L:dc=\E[P:dl=\E[M:ei=\E[4l:im=\E[4h:tc=vt100:
60
61 vt100|vt100-am|dec vt100 (w/advanced video):\
62         :am:bs:ms:xn:xo:\
63         :co#80:it#8:li#24:vt#3:\
64         :DO=\E[%dB:LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:\
65         :UP=\E[%dA:\
66         :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:\
67         :ae=^O:as=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
68         :cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:\
69         :eA=\E(B\E)0:ho=\E[H:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:\
70         :kr=\EOC:ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:\
71         :me=\E[m\017:mr=\E[7m:nd=\E[C:rc=\E8:\
72         :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:sc=\E7:se=\E[m:\
73         :sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:\
74         :us=\E[4m:tc=vt100+fnkeys:
75
76 vt100+fnkeys|dec vt100 numeric keypad:\
77         :k0=\EOy:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:\
78         :tc=vt100+pfkeys:
79
80 vt100+pfkeys|dec vt100 numeric keypad:\
81         :@8=\EOM:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:tc=vt100+keypad:
82
83 vt100+keypad|dec vt100 numeric keypad no fkeys:\
84         :K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:
85
86 */
87
88 /*
89 so the parser needs to be able to at least do
90 CTRL-G
91 CTRL-H
92 CTRL-I
93 CTRL-J
94 CTRL-M
95 CTRL-N
96
97 CTRL-O
98 ESC7
99 ESC8
100 ESCH
101 ESCM
102 ESC> 
103
104 ESC[%dA
105 ESC[%dB
106 ESC[%dC
107 ESC[%dD
108 ESC[H
109 ESC[%d;%dH
110 ESC[J
111 ESC[K
112 ESC[1K
113 ESC[L
114 ESC[M
115 ESC[P
116
117 ESC[3g
118 ESC[4h
119 ESC[4l
120 ESC[m 
121 ESC[1m
122 ESC[4m
123 ESC[5m
124 ESC[7m
125 ESC[%d;%dr
126
127
128 ESC[?3l 
129 ESC[?4l 
130 ESC[?5l
131 ESC[?7h
132 ESC[?7h
133 ESC[?7l
134 ESC[?8h
135
136 ESC(B
137 ESC)0
138
139
140 TODO:
141
142 ESC(B
143 ESC)0
144
145 CTRL-O
146
147 ESC7
148 ESC8
149 ESCH
150 ESCM
151 ESC> 
152
153 */
154
155 #include "project.h"
156
157
158
159 static inline int
160 csi_ender (int c)
161 {
162   if ((c >= 'a') && (c <= 'z'))
163     return 1;
164   if ((c >= 'A') && (c <= 'Z'))
165     return 1;
166   return 0;
167 }
168
169 static inline int
170 csi_starter (int c)
171 {
172   switch (c)
173     {
174     case '[':
175     case '(':
176     case ')':
177       return 1;
178     }
179   return 0;
180 }
181
182 static inline int
183 in_margins (VT102 * v, CRT_Pos p)
184 {
185   if (v->pos.x < v->top_margin.x)
186     return 0;
187   if (v->pos.y < v->top_margin.y)
188     return 0;
189
190   if (v->pos.x > v->bottom_margin.x)
191     return 0;
192   if (v->pos.y > v->bottom_margin.y)
193     return 0;
194
195   return 1;
196 }
197
198 void
199 vt102_log_line (VT102 * v, int line)
200 {
201   static FILE *log;
202   CRT_Pos e = { VT102_COLS - 1, line };
203   CRT_Pos p = { 0, line };
204
205   if (!log)
206     log = fopen ("log", "a+");
207
208   if (!log)
209     return;
210
211
212   for (; e.x > 0; --e.x)
213     {
214       if (v->crt.screen[CRT_ADDR_POS (&e)].chr != ' ')
215         break;
216     }
217
218   for (; p.x <= e.x; ++p.x)
219     {
220       int c = v->crt.screen[CRT_ADDR_POS (&p)].chr;
221       if (c < 32)
222         c = ' ';
223       if (c > 126)
224         c = ' ';
225       fputc (c, log);
226     }
227   fputc ('\n', log);
228 }
229
230 void
231 vt102_clip_cursor (VT102 * v, CRT_Pos tl, CRT_Pos br)
232 {
233   if (v->pos.x < tl.x)
234     v->pos.x = tl.x;
235   if (v->pos.y < tl.y)
236     v->pos.y = tl.y;
237
238   if (v->pos.x > br.x)
239     v->pos.x = br.x;
240   if (v->pos.y > br.y)
241     v->pos.y = br.y;
242 }
243
244
245 void
246 vt102_cursor_normalize (VT102 * v)
247 {
248   CRT_Pos *top, *bottom;
249
250   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
251     {
252       vt102_clip_cursor (v, v->top_margin, v->bottom_margin);
253     }
254   else
255     {
256       vt102_clip_cursor (v, v->screen_start, v->screen_end);
257     }
258 }
259
260
261 void
262 vt102_cursor_carriage_return (VT102 * v)
263 {
264    /*FISH*/ v->pos.x = v->top_margin.x;
265   v->pending_wrap = 0;
266 }
267
268 void
269 vt102_cursor_advance_line (VT102 * v)
270 {
271   int couldscroll = in_margins (v, v->pos);
272
273 /*have wraped off end of last line in scrolling region */
274 /* (|| not necessary, but shuts compiler up */
275   if (((v->pos.y == v->bottom_margin.y) || (v->pos.y == v->screen_end.y)) &&
276       (couldscroll))
277     {
278       vt102_log_line (v, v->pos.y);
279       crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1);
280       return;
281     }
282
283   v->pos.y++;
284   v->pending_wrap = 0;
285 }
286
287
288 void
289 vt102_cursor_advance (VT102 * v)
290 {
291
292   if (v->pos.x < v->bottom_margin.x)
293     {
294 /*Normal advance*/
295       v->pos.x++;
296       v->pending_wrap = 0;
297       return;
298     }
299   v->pending_wrap++;
300 }
301
302
303 void
304 vt102_do_pending_wrap (VT102 * v)
305 {
306   int couldscroll = in_margins (v, v->pos);
307   int autowrap = v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP];
308
309   if (!v->pending_wrap)
310     return;
311
312 #if 0
313   fprintf (stderr, "ca: (%d,%d) autowrap %d couldscroll %d\n", v->pos.x,
314            v->pos.y, autowrap, couldscroll);
315 #endif
316
317 /*End of line but no autowrap, nothing to do*/
318   if (!autowrap)
319     return;
320
321 /*End of screen and not allowed to scroll, nothing to do*/
322   if ((v->pos.y == v->screen_end.y) && (!couldscroll))
323     return;
324
325   if (couldscroll)
326     {
327       v->pos.x = v->top_margin.x;
328     }
329   else
330     {
331       v->pos.x = 0;
332     }
333
334   vt102_cursor_advance_line (v);
335 }
336
337
338 void
339 vt102_cursor_retard (VT102 * v)
340 {
341   if (v->pos.x != v->top_margin.x)
342     v->pos.x--;
343
344   v->pending_wrap = 0;
345 }
346
347 void
348 vt102_reset_tabs (VT102 * v)
349 {
350   int i;
351
352   memset (v->tabs, 0, sizeof (v->tabs));
353
354   for (i = 0; i < VT102_COLS; i += 8)
355     {
356       v->tabs[i]++;
357     }
358 }
359 void
360 vt102_cursor_advance_tab (VT102 * v)
361 {
362   if (v->pos.x == v->bottom_margin.x)
363     return;
364   while (v->pos.x < v->bottom_margin.x)
365     {
366       v->pos.x++;
367       if (v->tabs[v->pos.x])
368         break;
369     }
370   v->pending_wrap = 0;
371 }
372
373 vt102_cursor_home (VT102 * v)
374 {
375   v->pos = v->top_margin;
376   vt102_cursor_normalize (v);
377   v->pending_wrap = 0;
378
379 }
380
381 vt102_cursor_absolute (VT102 * v, int x, int y)
382 {
383   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
384     {
385       v->pos.x = x + v->top_margin.x;
386       v->pos.y = y + v->top_margin.x;
387     }
388   else
389     {
390       v->pos.x = x;
391       v->pos.y = y;
392     }
393   vt102_cursor_normalize (v);
394   v->pending_wrap = 0;
395 }
396
397 vt102_cursor_relative (VT102 * v, int x, int y)
398 {
399   v->pos.x += x;
400   v->pos.y += y;
401   vt102_cursor_normalize (v);
402   v->pending_wrap = 0;
403 }
404
405
406
407 void
408 vt102_delete_from_line (VT102 * v, CRT_Pos p)
409 {
410   int n = v->bottom_margin.x - p.x;
411
412   if (n < 0)
413     return;
414
415   if (n)
416     {
417
418       memmove (&v->crt.screen[CRT_ADDR_POS (&p)],
419                &v->crt.screen[CRT_ADDR_POS (&p) + 1], sizeof (CRT_CA) * n);
420     }
421
422   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
423 /*But not attr due to vt102 bug*/
424 }
425
426 void
427 vt102_insert_into_line (VT102 * v, CRT_Pos p)
428 {
429   int n = v->bottom_margin.x - p.x;
430
431   if (n < 0)
432     return;
433
434   if (n)
435     {
436
437       memmove (&v->crt.screen[CRT_ADDR_POS (&p) + 1],
438                &v->crt.screen[CRT_ADDR_POS (&p)], sizeof (CRT_CA) * n);
439     }
440
441   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
442   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].attr = CRT_ATTR_NORMAL;
443 }
444
445
446
447 void
448 vt102_change_mode (VT102 * v, int private, char *ns, int set)
449 {
450   int m;
451
452
453   if (*ns)
454     {
455       m = atoi (ns);
456     }
457   else
458     {
459       m = 1;
460     }
461
462   if (m < 0)
463     return;
464   if (m >= VT102_NMODES)
465     return;
466
467   if (private)
468     {
469       v->private_modes[m] = set;
470       switch (m)
471         {
472         case VT102_PRIVATE_MODE_CURSOR_MODE:
473           if (v->application_keypad_mode)
474             v->private_modes[m] = 0;
475           fprintf (stderr, "APPLICATION CURSOR MODE %d\n",
476                    v->private_modes[m]);
477           break;
478         case VT102_PRIVATE_MODE_ORIGIN_MODE:
479           vt102_cursor_home (v);
480           break;
481         }
482
483     }
484   else
485     v->modes[m] = set;
486
487 #if 0
488   fprintf (stderr, "mode set=%d private=%d num=%d\n", set, private, m);
489 #endif
490 }
491
492 void
493 vt102_parse_mode_string (VT102 * v, char *buf, int len)
494 {
495   int private = 0;
496   char last = buf[len - 1];
497   char num[4];
498   int o;
499
500   memset (num, 0, sizeof (num));
501   o = sizeof (num) - 1;
502
503   len--;
504
505   if (*buf == '?')
506     {
507       private++;
508       buf++;
509       len--;
510     }
511
512   if (len < 0)
513     return;
514
515   while (len--)
516     {
517       if (*buf == ';')
518         {
519           vt102_change_mode (v, private, &num[o], last == 'h');
520           memset (num, 0, sizeof (num));
521           o = sizeof (num) - 1;
522           buf++;
523           continue;
524         }
525
526       num[0] = num[1];
527       num[1] = num[2];
528       num[2] = *buf;
529
530       if (o)
531         o--;
532
533       buf++;
534     }
535
536   vt102_change_mode (v, private, &num[o], last == 'h');
537
538 }
539
540
541 void
542 vt102_change_attr (VT102 * v, char *na)
543 {
544   int a;
545
546
547   if (*na)
548     {
549       a = atoi (na);
550     }
551   else
552     {
553       a = 0;
554     }
555
556   switch (a)
557     {
558     case 0:
559       v->attr = CRT_ATTR_NORMAL;
560       break;
561     case 1:
562       v->attr |= CRT_ATTR_BOLD;
563       break;
564     case 21:
565     case 22:
566       v->attr &= ~CRT_ATTR_BOLD;
567       break;
568     case 4:
569       v->attr |= CRT_ATTR_UNDERLINE;
570       break;
571     case 24:
572       v->attr &= ~CRT_ATTR_UNDERLINE;
573       break;
574     case 5:
575       v->attr |= CRT_ATTR_BLINK;
576       break;
577     case 25:
578       v->attr &= ~CRT_ATTR_BLINK;
579       break;
580     case 7:
581       v->attr |= CRT_ATTR_REVERSE;
582       break;
583     case 27:
584       v->attr &= ~CRT_ATTR_REVERSE;
585       break;
586     default:
587       ;
588 #if 0
589       fprintf (stderr, "unhandled SGR %d\n", a);
590 #endif
591     }
592
593 }
594
595
596 void
597 vt102_parse_attr_string (VT102 * v, char *buf, int len)
598 {
599   int private = 0;
600   char last = buf[len - 1];
601   char num[4];
602   int o;
603
604   memset (num, 0, sizeof (num));
605   o = sizeof (num) - 1;
606
607   len--;
608
609   if (len < 0)
610     return;
611
612   while (len--)
613     {
614       if (*buf == ';')
615         {
616           vt102_change_attr (v, &num[o]);
617           memset (num, 0, sizeof (num));
618           o = sizeof (num) - 1;
619           buf++;
620           continue;
621         }
622
623       num[0] = num[1];
624       num[1] = num[2];
625       num[2] = *buf;
626
627       if (o)
628         o--;
629
630       buf++;
631     }
632   vt102_change_attr (v, &num[o]);
633 }
634
635 void
636 vt102_save_state (VT102 * v)
637 {
638   v->saved.pos = v->pos;
639   v->saved.attr = v->attr;
640   v->saved.origin_mode = v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE];
641 }
642
643 void
644 vt102_restore_state (VT102 * v)
645 {
646   v->pos = v->saved.pos;
647   v->attr = v->saved.attr;
648   v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE] = v->saved.origin_mode;
649   vt102_cursor_normalize (v);
650   v->pending_wrap = 0;
651 }
652
653 void
654 vt102_parse_esc (VT102 * v, int c)
655 {
656   switch (c)
657     {
658     case 'E':
659       if (v->pos.y == v->bottom_margin.y)
660         {
661           vt102_log_line (v, v->pos.y);
662           crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1);
663         }
664       else
665         {
666           vt102_cursor_relative (v, 0, 1);
667         }
668       break;
669     case 'H':
670       v->tabs[v->pos.x]++;
671       break;
672     case 'M':
673       if (v->pos.y == v->top_margin.y)
674         {
675           crt_scroll_down (&v->crt, v->top_margin, v->bottom_margin, 1);
676         }
677       else
678         {
679           vt102_cursor_relative (v, 0, -1);
680         }
681       break;
682     case '7':
683       vt102_save_state (v);
684       break;
685     case '8':
686       vt102_restore_state (v);
687       break;
688     case '=':
689       v->application_keypad_mode = 1;
690       break;
691     case '>':
692       v->application_keypad_mode = 0;
693       break;
694     default:
695 #if 0
696       fprintf (stderr, "unhandled ESC \\033 \\%03o (ESC %c)\n", c,
697                (c < 32) ? '?' : c);
698 #endif
699       ;
700     }
701 }
702 void
703 vt102_parse_csi (VT102 * v, char *buf, int len)
704 {
705   char last;
706   char *ptr;
707   char *arg = buf + 1;
708   int narg;
709
710   buf[len] = 0;
711
712   last = buf[len - 1];
713 #if 0
714   buf[len - 1] = 0;
715 #endif
716
717   if (len > 2)
718     {
719       narg = atoi (arg);
720     }
721   else
722     {
723       narg = 1;
724     }
725
726   switch (buf[0])
727     {
728     case '[':
729       switch (last)
730         {
731         case 'A':
732           vt102_cursor_relative (v, 0, -narg);
733           break;
734         case 'B':
735           vt102_cursor_relative (v, 0, narg);
736           break;
737         case 'C':
738           vt102_cursor_relative (v, narg, 0);
739           break;
740         case 'D':
741           vt102_cursor_relative (v, -narg, 0);
742           break;
743         case 'E':
744           vt102_cursor_relative (v, 0, narg);
745           vt102_cursor_carriage_return (v);
746           break;
747         case 'F':
748           vt102_cursor_relative (v, 0, -narg);
749           vt102_cursor_carriage_return (v);
750           break;
751         case 'G':
752           vt102_cursor_absolute (v, narg - 1, v->pos.y);
753           break;
754         case 'H':
755         case 'f':
756           {
757             int x, y;
758
759             y = narg - 1;
760
761             ptr = index (arg, ';');
762             if (ptr)
763               x = atoi (ptr + 1) - 1;
764             else
765               x = 0;
766
767             vt102_cursor_absolute (v, x, y);
768           }
769           break;
770         case 'J':
771           switch (narg)
772             {
773             case 1:
774               crt_erase (&v->crt, v->pos, v->screen_end, 1);
775               break;
776             case 2:
777               crt_erase (&v->crt, v->screen_start, v->screen_end, 1);
778               break;
779             }
780           break;
781         case 'K':
782           {
783             CRT_Pos ls = { 0, v->pos.y };
784             CRT_Pos le = { VT102_COLS - 1, v->pos.y };
785             if (len == 2)
786               narg = 0;         /*Different default */
787
788             switch (narg)
789               {
790               case 0:
791                 crt_erase (&v->crt, v->pos, le, 1);
792                 break;
793               case 1:
794                 crt_erase (&v->crt, ls, v->pos, 1);
795                 break;
796               case 2:
797                 crt_erase (&v->crt, ls, le, 1);
798                 break;
799               }
800           }
801           break;
802
803         case 'P':
804           while (narg--)
805             vt102_delete_from_line (v, v->pos);
806           break;
807         case 'L':
808           if ((v->pos.y >= v->top_margin.y)
809               && (v->pos.y <= v->bottom_margin.y))
810             {
811               while (narg--)
812                 crt_scroll_down (&v->crt, v->pos, v->bottom_margin, 1);
813             }
814           break;
815
816         case 'M':
817           if ((v->pos.y >= v->top_margin.y)
818               && (v->pos.y <= v->bottom_margin.y))
819             {
820               while (narg--)
821                 crt_scroll_up (&v->crt, v->pos, v->bottom_margin, 0);
822             }
823           break;
824
825         case 'g':
826           if (len == 2)
827             narg = 0;           /*Different default */
828
829           switch (narg)
830             {
831             case 0:
832               v->tabs[v->pos.x] = 0;
833               break;
834             case 3:
835               memset (v->tabs, 0, sizeof (v->tabs));
836               break;
837             }
838           break;
839
840         case 'h':
841         case 'l':
842           vt102_parse_mode_string (v, &buf[1], len - 1);
843           break;
844
845         case 'm':
846           vt102_parse_attr_string (v, &buf[1], len - 1);
847           break;
848         case 'r':
849           v->top_margin = v->screen_start;
850           v->bottom_margin = v->screen_end;
851
852           if ((len > 2) && (ptr = index (arg, ';')))
853             {
854               ptr++;
855               v->top_margin.y = narg - 1;
856               v->bottom_margin.y = atoi (ptr) - 1;
857             }
858
859           if (v->top_margin.y < v->screen_start.y)
860             v->top_margin.y = v->screen_start.y;
861           if (v->top_margin.y > v->screen_end.y)
862             v->top_margin.y = v->screen_end.y;
863           if (v->bottom_margin.y < v->screen_start.y)
864             v->bottom_margin.y = v->screen_start.y;
865           if (v->bottom_margin.y > v->screen_end.y)
866             v->bottom_margin.y = v->screen_end.y;
867
868           vt102_cursor_home (v);
869           break;
870         case 's':
871           v->saved.pos = v->pos;
872           break;
873         case 'u':
874           v->pos = v->saved.pos;
875           vt102_cursor_normalize (v);
876           v->pending_wrap = 0;
877           break;
878
879         default:
880 #if 0
881           fprintf (stderr, "unhandled CSI  \\033%s\n", buf, buf[0]);
882 #endif
883           ;
884         }
885       break;
886     default:
887 #if 0
888       fprintf (stderr, "unhandled CSI  \\033%s\n", buf, buf[0]);
889 #endif
890       ;
891     }
892
893
894
895 }
896
897 void
898 vt102_status_line (VT102 * v, char *str)
899 {
900   int i = VT102_COLS;
901   CRT_CA *ca = &v->crt.screen[CRT_ADDR (VT102_STATUS_ROW, 0)];
902
903   while (i--)
904     {
905       ca->attr = CRT_ATTR_REVERSE;
906       ca->chr = *str;
907       if (*str)
908         str++;
909       ca++;
910     }
911
912 }
913
914
915 void
916 vt102_parse_char (VT102 * v, int c)
917 {
918   VT102_parser *p = &v->parser;
919
920
921 #if 0
922   fprintf (stderr, "char %c pc %d %d %d   %d %d\n", (c < 32) ? 32 : c, c,
923            p->in_csi, p->in_escape, v->pos.x, v->pos.y);
924 #endif
925   if (p->in_csi)
926     {
927       p->csi_buf[p->csi_ptr++] = c;
928       if (csi_ender (c) || (p->csi_ptr == VT102_CSI_LEN))
929         {
930           vt102_parse_csi (v, p->csi_buf, p->csi_ptr);
931           p->in_csi = 0;
932         }
933     }
934   else if (p->in_escape)
935     {
936       if (csi_starter (c))
937         {
938           p->csi_ptr = 0;
939           p->csi_buf[p->csi_ptr++] = c;
940           p->in_csi++;
941           p->in_escape = 0;
942         }
943       else
944         {
945           p->in_escape = 0;
946           vt102_parse_esc (v, c);
947         }
948     }
949   else
950     {
951
952       switch (c)
953         {
954          /*NUL*/ case 0:
955          /*SOH*/ case 1:
956          /*STX*/ case 2:
957          /*ETX*/ case 3:
958          /*EOT*/ case 4:
959           break;
960          /*ENQ*/ case 5:
961           tty_write (v->tty, "vt102", 5);
962           break;
963          /*ACK*/ case 6:
964          /*BEL*/ case 7:
965           break;
966          /*BS*/ case 8:
967           vt102_cursor_retard (v);
968           break;
969          /*HT*/ case 9:
970           vt102_cursor_advance_tab (v);
971           break;
972          /*LF*/ case 10:
973          /*VT*/ case 11:
974          /*FF*/ case 12:
975           vt102_cursor_advance_line (v);
976           if (!v->modes[VT102_MODE_NEWLINE_MODE])
977             break;
978          /*CR*/ case 13:
979           vt102_cursor_carriage_return (v);
980           break;
981          /*SO*/ case 14:
982          /*SI*/ case 15:
983          /*DLE*/ case 16:
984         /*DC1 */ case 17:
985         /*DC2 */ case 18:
986         /*DC3 */ case 19:
987         /*DC4 */ case 20:
988          /*NAK*/ case 21:
989          /*SYN*/ case 22:
990          /*ETB*/ case 23:
991          /*CAN*/ case 24:
992          /*EM*/ case 25:
993          /*SUB*/ case 26:
994           break;
995          /*ESC*/ case 27:
996           p->in_escape++;
997           return;
998          /*FS*/ case 28:
999          /*GS*/ case 29:
1000          /*RS*/ case 30:
1001          /*US*/ case 31:
1002          /*DEL*/ case 127:
1003           break;
1004         /*regular character */ default:
1005           vt102_do_pending_wrap (v);
1006
1007           if (v->modes[VT102_MODE_INSERT])
1008             vt102_insert_into_line (v, v->pos);
1009
1010           v->crt.screen[CRT_ADDR_POS (&v->pos)].chr = c;
1011           v->crt.screen[CRT_ADDR_POS (&v->pos)].attr = v->attr;
1012           vt102_cursor_advance (v);
1013         }
1014     }
1015
1016   v->crt.pos = v->pos;
1017   v->crt.hide_cursor =
1018     v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] ? 0 : 1;
1019
1020   if (v->current_line.y != v->pos.y)
1021     {
1022       vt102_log_line (v, v->current_line.y);
1023       v->current_line = v->pos;
1024     }
1025
1026   vt102_status_line (v, "VT102 foo bar baz I'm the urban spaceman baby");
1027 }
1028
1029 vt102_parse (VT102 * v, char *buf, int len)
1030 {
1031   while (len--)
1032     vt102_parse_char (v, *(buf++));
1033 }
1034
1035
1036 void
1037 vt102_parser_reset (VT102_parser * p)
1038 {
1039   p->in_csi = 0;
1040   p->in_escape = 0;
1041   p->csi_ptr = 0;
1042 }
1043
1044
1045 void
1046 vt102_send (VT102 * v, uint8_t key)
1047 {
1048   uint8_t c;
1049 #if 0
1050   fprintf(stderr,"vts: %d(%c)\n",key,(key>31)?key:' ');
1051 #endif
1052   if ((key > 31) && (key < 127))
1053     {
1054       tty_write (v->tty, &key, 1);
1055       return;
1056     }
1057
1058   switch (key)
1059     {
1060      /*NUL*/ case 0:
1061      /*SOH*/ case 1:
1062      /*STX*/ case 2:
1063      /*ETX*/ case 3:
1064      /*EOT*/ case 4:
1065      /*ENQ*/ case 5:
1066      /*ACK*/ case 6:
1067      /*BEL*/ case 7:
1068      /*BS*/ case 8:
1069      /*HT*/ case 9:
1070      /*LF*/ case 10:
1071      /*VT*/ case 11:
1072      /*FF*/ case 12:
1073       tty_write (v->tty, &key, 1);
1074       break;
1075      /*CR*/ case 13:
1076       tty_write (v->tty, &key, 1);
1077       if (v->modes[VT102_MODE_NEWLINE_MODE])
1078         {
1079           c = 10;
1080           tty_write (v->tty, &c, 1);
1081         }
1082       break;
1083      /*SO*/ case 14:
1084      /*SI*/ case 15:
1085      /*DLE*/ case 16:
1086     /*DC1 */ case 17:
1087     /*DC2 */ case 18:
1088     /*DC3 */ case 19:
1089     /*DC4 */ case 20:
1090      /*NAK*/ case 21:
1091      /*SYN*/ case 22:
1092      /*ETB*/ case 23:
1093      /*CAN*/ case 24:
1094      /*EM*/ case 25:
1095      /*SUB*/ case 26:
1096       tty_write (v->tty, &key, 1);
1097       break;
1098      /*ESC*/ case 27:
1099      /*FS*/ case 28:
1100      /*GS*/ case 29:
1101      /*RS*/ case 30:
1102      /*US*/ case 31:
1103      /*DEL*/ case 127:
1104       tty_write (v->tty, &key, 1);
1105       break;
1106
1107     case KEY_UP:
1108     case KEY_DOWN:
1109     case KEY_RIGHT:
1110     case KEY_LEFT:
1111     case KEY_HOME:
1112     case KEY_MIDDLE:
1113     case KEY_END:
1114
1115       if (v->private_modes[VT102_PRIVATE_MODE_CURSOR_MODE])
1116         {
1117           uint8_t buf[] = { 033, 'O', 'A' + (key - KEY_UP) };
1118           tty_write (v->tty, &buf, sizeof (buf));
1119         }
1120       else
1121         {
1122           uint8_t buf[] = { 033, '[', 'A' + (key - KEY_UP) };
1123           tty_write (v->tty, &buf, sizeof (buf));
1124         }
1125       break;
1126     case KEY_STAR:
1127     case KEY_PLUS:
1128     case KEY_COMMA:
1129     case KEY_PERIOD:
1130     case KEY_DIVIDE:
1131     case KEY_0:
1132     case KEY_1:
1133     case KEY_2:
1134     case KEY_3:
1135     case KEY_4:
1136     case KEY_5:
1137     case KEY_6:
1138     case KEY_7:
1139     case KEY_8:
1140     case KEY_9:
1141       if (v->application_keypad_mode)
1142         {
1143           uint8_t buf[] = { 033, 'O', 'a' + (key - KEY_154) };
1144           tty_write (v->tty, &buf, sizeof (buf));
1145         }
1146       else
1147         {
1148           static char kpoff[KEY_NUM] = {
1149             [KEY_STAR] = '*',
1150             [KEY_PLUS] = '+',
1151             [KEY_COMMA] = ',',
1152             [KEY_MINUS] = '-',
1153             [KEY_PERIOD] = '.',
1154             [KEY_DIVIDE] = '/',
1155             [KEY_0] = '0',
1156             [KEY_1] = '1',
1157             [KEY_2] = '2',
1158             [KEY_3] = '3',
1159             [KEY_4] = '4',
1160             [KEY_5] = '5',
1161             [KEY_6] = '6',
1162             [KEY_7] = '7',
1163             [KEY_8] = '8',
1164             [KEY_9] = '9'
1165           };
1166
1167           tty_write (v->tty, &kpoff[key], 1);
1168         }
1169       break;
1170     case KEY_ENTER:
1171       if (v->application_keypad_mode)
1172         {
1173           uint8_t buf[] = { 033, 'O', 'M' };
1174           tty_write (v->tty, &buf, sizeof (buf));
1175         }
1176       else
1177         {
1178           c = 13;
1179           tty_write (v->tty, &c, 1);
1180           if (v->modes[VT102_MODE_NEWLINE_MODE])
1181             {
1182               c = 10;
1183               tty_write (v->tty, &c, 1);
1184             }
1185         }
1186       break;
1187     case KEY_PF1:
1188     case KEY_PF2:
1189     case KEY_PF3:
1190     case KEY_PF4:
1191       {
1192         uint8_t buf[] = { 033, 'O', 'P' + (key - KEY_PF1) };
1193         tty_write (v->tty, &buf, sizeof (buf));
1194       }
1195       break;
1196     case KEY_INSERT:
1197     case KEY_DELETE:
1198     case KEY_PGUP:
1199     case KEY_PGDN:
1200       {
1201         uint8_t buf[] = { 033, '[', '0' + (key - KEY_180), '~' };
1202         tty_write (v->tty, &buf, sizeof (buf));
1203       }
1204       break;
1205     }
1206
1207 }
1208
1209 void
1210 vt102_reset (VT102 * v)
1211 {
1212   VT102_parser *p = &v->parser;
1213
1214   vt102_parser_reset (p);
1215   crt_cls (&v->crt);
1216
1217
1218   v->application_keypad_mode = 0;
1219
1220   v->current_line = v->pos;
1221   v->pending_wrap = 0;
1222
1223   v->screen_start.x = 0;
1224   v->screen_start.y = 0;
1225   v->screen_end.x = VT102_COLS - 1;
1226   v->screen_end.y = VT102_ROWS - 1;
1227
1228   v->top_margin = v->screen_start;
1229   v->bottom_margin = v->screen_end;
1230
1231   memset (v->modes, 0, VT102_NMODES);
1232   memset (v->private_modes, 0, VT102_NMODES);
1233
1234   v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP] = 1;
1235   v->private_modes[VT102_PRIVATE_MODE_AUTO_REPEAT] = 1;
1236   v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] = 1;
1237   v->modes[VT102_MODE_LOCAL_ECHO_OFF] = 1;
1238
1239   vt102_cursor_home (v);
1240   vt102_reset_tabs (v);
1241   v->current_line = v->pos;
1242
1243   vt102_save_state (v);
1244
1245   vt102_status_line (v, "VT102 foo bar baz I'm the urban spaceman baby");
1246
1247 }
1248
1249 int
1250 vt102_dispatch (VT102 * v)
1251 {
1252   char buf[1024];
1253   int red;
1254
1255   red = tty_read (v->tty, buf, sizeof (buf));
1256
1257   if (red < 0)
1258     return -1;
1259   if (!red)
1260     return 0;
1261
1262
1263   vt102_parse (v, buf, red);
1264
1265   return 0;
1266 }
1267
1268 VT102 *
1269 vt102_new (TTY * t)
1270 {
1271   VT102 *v;
1272
1273   v = (VT102 *) malloc (sizeof (VT102));
1274
1275   vt102_reset (v);
1276
1277   v->tty = t;
1278
1279   return v;
1280 }
1281
1282 void
1283 vt102_free (VT102 * v)
1284 {
1285   free (v);
1286 }