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