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