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