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