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