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