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