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