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