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