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