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