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